2020-03-17 10:00:16 +00:00
|
|
|
|
2020-03-23 23:54:12 +00:00
|
|
|
function checkVisibility(selector) {
|
|
|
|
let selectorMatches = document.querySelectorAll(selector);
|
|
|
|
let element = selectorMatches[0];
|
|
|
|
|
|
|
|
if (selectorMatches.length > 1)
|
|
|
|
throw new Error(`Multiple matches of ${selector} found`);
|
|
|
|
|
|
|
|
let isVisible = false;
|
|
|
|
if (element) {
|
|
|
|
let eventHandler = event => {
|
|
|
|
event.preventDefault();
|
|
|
|
isVisible = true;
|
|
|
|
};
|
|
|
|
element.addEventListener('mouseover', eventHandler);
|
|
|
|
let rect = element.getBoundingClientRect();
|
|
|
|
let x = rect.left + rect.width / 2;
|
|
|
|
let y = rect.top + rect.height / 2;
|
|
|
|
let elementInCenter = document.elementFromPoint(x, y);
|
|
|
|
let elementInTopLeft = document.elementFromPoint(rect.left, rect.top);
|
|
|
|
let elementInBottomRight = document.elementFromPoint(rect.right, rect.bottom);
|
|
|
|
|
|
|
|
let e = new MouseEvent('mouseover', {
|
|
|
|
view: window,
|
|
|
|
bubbles: true,
|
|
|
|
cancelable: true,
|
|
|
|
});
|
|
|
|
|
|
|
|
if (elementInCenter)
|
|
|
|
elementInCenter.dispatchEvent(e);
|
|
|
|
|
|
|
|
if (elementInTopLeft)
|
|
|
|
elementInTopLeft.dispatchEvent(e);
|
|
|
|
|
|
|
|
if (elementInBottomRight)
|
|
|
|
elementInBottomRight.dispatchEvent(e);
|
|
|
|
|
|
|
|
element.removeEventListener('mouseover', eventHandler);
|
|
|
|
}
|
|
|
|
return isVisible;
|
|
|
|
}
|
|
|
|
|
2019-10-28 16:31:33 +00:00
|
|
|
let actions = {
|
2019-12-31 11:00:16 +00:00
|
|
|
clickIfExists: async function(selector) {
|
|
|
|
let exists;
|
|
|
|
try {
|
|
|
|
exists = await this.waitForSelector(selector, {timeout: 500});
|
|
|
|
} catch (error) {
|
|
|
|
exists = false;
|
|
|
|
}
|
|
|
|
if (exists) await this.waitToClick(selector);
|
|
|
|
return exists;
|
|
|
|
},
|
|
|
|
|
2020-02-04 15:21:10 +00:00
|
|
|
expectURL: async function(expectedHash) {
|
|
|
|
try {
|
|
|
|
await this.waitForFunction(expectedHash => {
|
|
|
|
return document.location.hash.includes(expectedHash);
|
|
|
|
}, {}, expectedHash);
|
|
|
|
} catch (error) {
|
2020-03-24 10:12:59 +00:00
|
|
|
throw new Error(`Failed to reach URL containing: ${expectedHash}`);
|
2020-02-04 15:21:10 +00:00
|
|
|
}
|
2020-03-24 10:12:59 +00:00
|
|
|
await this.waitForSpinnerLoad();
|
2020-02-04 15:21:10 +00:00
|
|
|
return true;
|
2019-10-18 19:36:30 +00:00
|
|
|
},
|
|
|
|
|
2019-12-12 07:37:35 +00:00
|
|
|
doLogin: async function(userName, password = 'nightmare') {
|
2020-03-23 22:57:11 +00:00
|
|
|
let state = await this.getState();
|
|
|
|
|
|
|
|
if (state != 'login') {
|
|
|
|
try {
|
|
|
|
await this.gotoState('login');
|
|
|
|
} catch (err) {
|
|
|
|
let dialog = await this.evaluate(
|
|
|
|
() => document.querySelector('button[response="accept"]'));
|
|
|
|
|
|
|
|
if (dialog)
|
|
|
|
await this.waitToClick('button[response="accept"]');
|
|
|
|
else
|
|
|
|
throw err;
|
|
|
|
}
|
|
|
|
}
|
2020-01-14 08:20:14 +00:00
|
|
|
|
2020-03-23 22:57:11 +00:00
|
|
|
await this.waitForState('login');
|
2020-03-25 19:44:59 +00:00
|
|
|
|
|
|
|
await this.waitForSelector(`vn-login vn-textfield[ng-model="$ctrl.user"]`, {visible: true});
|
|
|
|
await this.clearInput(`vn-login vn-textfield[ng-model="$ctrl.user"]`);
|
|
|
|
await this.write(`vn-login vn-textfield[ng-model="$ctrl.user"]`, userName);
|
|
|
|
await this.clearInput(`vn-login vn-textfield[ng-model="$ctrl.password"]`);
|
|
|
|
await this.write(`vn-login vn-textfield[ng-model="$ctrl.password"]`, password);
|
|
|
|
await this.waitToClick('vn-login button[type=submit]');
|
|
|
|
},
|
|
|
|
|
|
|
|
login: async function(userName) {
|
2020-01-14 08:20:14 +00:00
|
|
|
await this.doLogin(userName);
|
2020-03-23 22:57:11 +00:00
|
|
|
await this.waitForState('home');
|
2021-10-20 09:23:55 +00:00
|
|
|
await this.addStyleTag({
|
|
|
|
content: `
|
|
|
|
*,
|
|
|
|
*::after,
|
|
|
|
*::before {
|
|
|
|
transition-delay: 0s !important;
|
|
|
|
transition-duration: 0s !important;
|
|
|
|
animation-delay: -0.0001s !important;
|
|
|
|
animation-duration: 0s !important;
|
|
|
|
animation-play-state: paused !important;
|
|
|
|
caret-color: transparent !important;
|
|
|
|
}`
|
|
|
|
});
|
2019-10-15 14:19:35 +00:00
|
|
|
},
|
|
|
|
|
|
|
|
selectModule: async function(moduleName) {
|
2020-03-23 22:57:11 +00:00
|
|
|
let state = `${moduleName}.index`;
|
|
|
|
await this.waitToClick(`vn-home a[ui-sref="${state}"]`);
|
|
|
|
await this.waitForState(state);
|
2019-10-15 14:19:35 +00:00
|
|
|
},
|
|
|
|
|
|
|
|
loginAndModule: async function(userName, moduleName) {
|
2019-12-12 07:37:35 +00:00
|
|
|
await this.login(userName);
|
|
|
|
await this.selectModule(moduleName);
|
2019-10-15 14:19:35 +00:00
|
|
|
},
|
|
|
|
|
2020-03-23 22:57:11 +00:00
|
|
|
getState: async function() {
|
2021-10-11 09:19:20 +00:00
|
|
|
return this.evaluate(() => {
|
2020-03-23 22:57:11 +00:00
|
|
|
let $state = angular.element(document.body).injector().get('$state');
|
|
|
|
return $state.current.name;
|
|
|
|
});
|
2019-10-15 14:19:35 +00:00
|
|
|
},
|
|
|
|
|
2020-03-23 22:57:11 +00:00
|
|
|
gotoState: async function(state, params) {
|
2020-03-25 19:44:59 +00:00
|
|
|
await this.evaluate((state, params) => {
|
2020-03-23 22:57:11 +00:00
|
|
|
let $state = angular.element(document.body).injector().get('$state');
|
|
|
|
return $state.go(state, params);
|
|
|
|
}, state, params);
|
2020-03-25 19:44:59 +00:00
|
|
|
await this.waitForSpinnerLoad();
|
2019-12-12 07:37:35 +00:00
|
|
|
},
|
|
|
|
|
2020-03-23 22:57:11 +00:00
|
|
|
waitForState: async function(state) {
|
2020-11-02 16:42:46 +00:00
|
|
|
await this.waitForFunction(state => {
|
2020-03-23 22:57:11 +00:00
|
|
|
let $state = angular.element(document.body).injector().get('$state');
|
2020-03-24 10:12:59 +00:00
|
|
|
return !$state.transition && $state.is(state);
|
2020-03-23 22:57:11 +00:00
|
|
|
}, {}, state);
|
2020-11-02 16:42:46 +00:00
|
|
|
await this.waitForFunction(() => {
|
|
|
|
return angular.element(() => {
|
|
|
|
return true;
|
|
|
|
});
|
|
|
|
});
|
2020-03-25 19:44:59 +00:00
|
|
|
await this.waitForSpinnerLoad();
|
2019-05-03 15:49:38 +00:00
|
|
|
},
|
2018-10-31 10:58:10 +00:00
|
|
|
|
2020-03-23 22:57:11 +00:00
|
|
|
waitForTransition: async function() {
|
2020-11-02 16:42:46 +00:00
|
|
|
await this.waitForFunction(() => {
|
2020-03-23 22:57:11 +00:00
|
|
|
const $state = angular.element(document.body).injector().get('$state');
|
|
|
|
return !$state.transition;
|
|
|
|
});
|
2020-03-31 16:33:48 +00:00
|
|
|
await this.waitForSpinnerLoad();
|
2020-03-23 22:57:11 +00:00
|
|
|
},
|
2020-03-17 10:00:16 +00:00
|
|
|
|
2023-04-18 13:16:59 +00:00
|
|
|
accessToSection: async function(state, name = 'Others') {
|
2020-03-23 22:57:11 +00:00
|
|
|
await this.waitForSelector('vn-left-menu');
|
|
|
|
let nested = await this.evaluate(state => {
|
|
|
|
return document.querySelector(`vn-left-menu li li > a[ui-sref="${state}"]`) != null;
|
|
|
|
}, state);
|
2020-03-17 10:00:16 +00:00
|
|
|
|
2020-03-23 22:57:11 +00:00
|
|
|
if (nested) {
|
2023-04-18 13:16:59 +00:00
|
|
|
let selector = `vn-left-menu li[name="${name}"]`;
|
2020-04-02 16:55:07 +00:00
|
|
|
await this.evaluate(selector => {
|
|
|
|
document.querySelector(selector).scrollIntoViewIfNeeded();
|
|
|
|
}, selector);
|
|
|
|
await this.waitToClick(selector);
|
2020-11-23 17:27:32 +00:00
|
|
|
await this.waitForSelector('vn-left-menu .expanded');
|
2019-12-31 11:00:16 +00:00
|
|
|
}
|
2020-03-17 10:00:16 +00:00
|
|
|
|
2020-03-23 22:57:11 +00:00
|
|
|
await this.evaluate(state => {
|
|
|
|
let navButton = document.querySelector(`vn-left-menu li > a[ui-sref="${state}"]`);
|
|
|
|
navButton.scrollIntoViewIfNeeded();
|
|
|
|
return navButton.click();
|
|
|
|
}, state);
|
|
|
|
|
|
|
|
await this.waitForState(state);
|
|
|
|
},
|
|
|
|
|
|
|
|
reloadSection: async function(state) {
|
2022-04-11 06:02:05 +00:00
|
|
|
await this.click('vn-icon[icon="launch"]');
|
2020-03-23 22:57:11 +00:00
|
|
|
await this.accessToSection(state);
|
|
|
|
},
|
|
|
|
|
|
|
|
forceReloadSection: async function(sectionRoute) {
|
2022-04-11 06:02:05 +00:00
|
|
|
await this.waitToClick('vn-icon[icon="launch"]');
|
2020-03-23 22:57:11 +00:00
|
|
|
await this.waitToClick('button[response="accept"]');
|
2020-11-23 17:27:32 +00:00
|
|
|
await this.waitForSelector('vn-card.summary');
|
2020-03-23 22:57:11 +00:00
|
|
|
await this.waitToClick(`vn-left-menu li > a[ui-sref="${sectionRoute}"]`);
|
|
|
|
},
|
|
|
|
|
2020-03-31 16:33:48 +00:00
|
|
|
doSearch: async function(searchValue) {
|
2020-03-23 22:57:11 +00:00
|
|
|
await this.clearInput('vn-searchbar');
|
2020-03-31 16:33:48 +00:00
|
|
|
if (searchValue)
|
|
|
|
await this.write('vn-searchbar', searchValue);
|
|
|
|
|
2020-03-23 22:57:11 +00:00
|
|
|
await this.waitToClick('vn-searchbar vn-icon[icon="search"]');
|
|
|
|
await this.waitForTransition();
|
2020-03-31 16:33:48 +00:00
|
|
|
},
|
|
|
|
|
|
|
|
accessToSearchResult: async function(searchValue) {
|
|
|
|
await this.doSearch(searchValue);
|
2020-11-23 17:27:32 +00:00
|
|
|
await this.waitForSelector('.vn-descriptor');
|
2019-05-03 15:49:38 +00:00
|
|
|
},
|
2017-09-15 10:24:37 +00:00
|
|
|
|
2019-12-12 07:37:35 +00:00
|
|
|
getProperty: async function(selector, property) {
|
2021-10-11 09:19:20 +00:00
|
|
|
return this.evaluate((selector, property) => {
|
2018-11-22 11:34:20 +00:00
|
|
|
return document.querySelector(selector)[property].replace(/\s+/g, ' ').trim();
|
2019-10-28 18:52:54 +00:00
|
|
|
}, selector, property);
|
2018-11-22 11:34:20 +00:00
|
|
|
},
|
|
|
|
|
2020-03-25 19:44:59 +00:00
|
|
|
getClassName: async function(selector) {
|
|
|
|
const element = await this.$(selector);
|
|
|
|
const handle = await element.getProperty('className');
|
2021-10-11 09:19:20 +00:00
|
|
|
return handle.jsonValue();
|
2020-03-25 19:44:59 +00:00
|
|
|
},
|
|
|
|
|
2019-12-12 07:37:35 +00:00
|
|
|
waitPropertyLength: async function(selector, property, minLength) {
|
2020-01-29 13:54:07 +00:00
|
|
|
await this.waitForFunction((selector, property, minLength) => {
|
2018-11-22 11:34:20 +00:00
|
|
|
const element = document.querySelector(selector);
|
2021-10-20 09:23:55 +00:00
|
|
|
const isValidElement = element && element[property] != null && element[property] !== '';
|
|
|
|
return isValidElement && element[property].length >= minLength;
|
2019-12-12 07:37:35 +00:00
|
|
|
}, {}, selector, property, minLength);
|
2021-10-11 09:19:20 +00:00
|
|
|
return this.getProperty(selector, property);
|
2018-11-22 11:34:20 +00:00
|
|
|
},
|
|
|
|
|
2020-02-03 14:55:11 +00:00
|
|
|
expectPropertyValue: async function(selector, property, value) {
|
|
|
|
let builtSelector = selector;
|
|
|
|
if (property != 'innerText')
|
|
|
|
builtSelector = await this.selectorFormater(selector);
|
|
|
|
|
|
|
|
try {
|
2021-10-11 09:19:20 +00:00
|
|
|
return this.waitForFunction((selector, property, value) => {
|
2020-02-03 14:55:11 +00:00
|
|
|
const element = document.querySelector(selector);
|
|
|
|
return element[property] == value;
|
|
|
|
}, {}, builtSelector, property, value);
|
|
|
|
} catch (error) {
|
|
|
|
throw new Error(`${value} wasn't the value of ${builtSelector}, ${error}`);
|
|
|
|
}
|
2019-02-07 13:33:52 +00:00
|
|
|
},
|
|
|
|
|
2019-12-12 07:37:35 +00:00
|
|
|
waitToGetProperty: async function(selector, property) {
|
2020-01-29 13:54:07 +00:00
|
|
|
let builtSelector = selector;
|
2020-02-12 06:21:53 +00:00
|
|
|
if (selector.includes('vn-input-file') || property != 'innerText')
|
2020-01-29 13:54:07 +00:00
|
|
|
builtSelector = await this.selectorFormater(selector);
|
|
|
|
|
2020-01-23 15:01:29 +00:00
|
|
|
try {
|
|
|
|
await this.waitForFunction((selector, property) => {
|
|
|
|
const element = document.querySelector(selector);
|
2019-07-01 11:41:38 +00:00
|
|
|
|
2020-01-23 15:01:29 +00:00
|
|
|
return element && element[property] != null && element[property] !== '';
|
2020-01-29 13:54:07 +00:00
|
|
|
}, {}, builtSelector, property);
|
2021-10-11 09:19:20 +00:00
|
|
|
return this.getProperty(builtSelector, property);
|
2020-01-23 15:01:29 +00:00
|
|
|
} catch (error) {
|
2020-01-29 13:54:07 +00:00
|
|
|
throw new Error(`couldn't get property: ${property} of ${builtSelector}, ${error}`);
|
2020-01-23 15:01:29 +00:00
|
|
|
}
|
2018-11-22 11:34:20 +00:00
|
|
|
},
|
|
|
|
|
2019-12-12 07:37:35 +00:00
|
|
|
write: async function(selector, text) {
|
2020-01-29 13:54:07 +00:00
|
|
|
let builtSelector = await this.selectorFormater(selector);
|
2020-11-09 17:25:02 +00:00
|
|
|
await this.waitForSelector(selector);
|
2020-01-29 13:54:07 +00:00
|
|
|
await this.type(builtSelector, text);
|
|
|
|
await this.waitForTextInField(selector, text);
|
2018-11-22 11:34:20 +00:00
|
|
|
},
|
2017-09-15 10:24:37 +00:00
|
|
|
|
2020-03-30 15:30:03 +00:00
|
|
|
overwrite: async function(selector, text) {
|
|
|
|
await this.clearInput(selector);
|
|
|
|
await this.write(selector, text);
|
|
|
|
},
|
|
|
|
|
2019-12-12 07:37:35 +00:00
|
|
|
waitToClick: async function(selector) {
|
2020-02-21 09:26:40 +00:00
|
|
|
await this.waitForSelector(selector);
|
2020-03-23 23:54:12 +00:00
|
|
|
await this.waitForFunction(checkVisibility, {}, selector);
|
2020-03-17 10:00:16 +00:00
|
|
|
|
2021-10-11 09:19:20 +00:00
|
|
|
return this.click(selector);
|
2018-11-22 11:34:20 +00:00
|
|
|
},
|
|
|
|
|
2020-02-14 13:52:47 +00:00
|
|
|
writeOnEditableTD: async function(selector, text) {
|
|
|
|
let builtSelector = await this.selectorFormater(selector);
|
|
|
|
await this.waitToClick(selector);
|
2020-11-23 17:35:57 +00:00
|
|
|
await this.waitForSelector(builtSelector, {visible: true});
|
2020-02-14 13:52:47 +00:00
|
|
|
await this.type(builtSelector, text);
|
|
|
|
await this.keyboard.press('Enter');
|
|
|
|
},
|
|
|
|
|
2019-12-12 07:37:35 +00:00
|
|
|
focusElement: async function(selector) {
|
2020-11-23 17:27:32 +00:00
|
|
|
await this.waitForSelector(selector);
|
2021-10-11 09:19:20 +00:00
|
|
|
return this.evaluate(selector => {
|
2019-12-12 07:37:35 +00:00
|
|
|
let element = document.querySelector(selector);
|
|
|
|
element.focus();
|
|
|
|
}, selector);
|
2019-02-26 16:32:32 +00:00
|
|
|
},
|
|
|
|
|
2019-12-12 07:37:35 +00:00
|
|
|
isVisible: async function(selector) {
|
2020-03-17 10:00:16 +00:00
|
|
|
await this.waitForSelector(selector);
|
2021-10-11 09:19:20 +00:00
|
|
|
return this.evaluate(checkVisibility, selector);
|
2018-11-22 11:34:20 +00:00
|
|
|
},
|
|
|
|
|
2019-12-12 07:37:35 +00:00
|
|
|
waitImgLoad: async function(selector) {
|
2020-11-23 17:27:32 +00:00
|
|
|
await this.waitForSelector(selector);
|
2021-10-11 09:19:20 +00:00
|
|
|
return this.waitForFunction(selector => {
|
2019-12-12 07:37:35 +00:00
|
|
|
const imageReady = document.querySelector(selector).complete;
|
|
|
|
return imageReady;
|
2020-01-09 12:07:16 +00:00
|
|
|
}, {}, selector);
|
2019-02-07 08:07:00 +00:00
|
|
|
},
|
|
|
|
|
2019-12-12 07:37:35 +00:00
|
|
|
countElement: async function(selector) {
|
2021-10-11 09:19:20 +00:00
|
|
|
return this.evaluate(selector => {
|
2018-11-22 11:34:20 +00:00
|
|
|
return document.querySelectorAll(selector).length;
|
2019-10-28 18:52:54 +00:00
|
|
|
}, selector);
|
2018-11-22 11:34:20 +00:00
|
|
|
},
|
|
|
|
|
2019-12-12 07:37:35 +00:00
|
|
|
waitForNumberOfElements: async function(selector, count) {
|
2020-12-24 15:48:56 +00:00
|
|
|
try {
|
|
|
|
await this.waitForFunction((selector, count) => {
|
|
|
|
return document.querySelectorAll(selector).length == count;
|
|
|
|
}, {}, selector, count);
|
|
|
|
} catch (error) {
|
|
|
|
const amount = await this.countElement(selector);
|
|
|
|
throw new Error(`actual amount of elements was: ${amount} instead of ${count}, ${error}`);
|
|
|
|
}
|
2018-11-22 11:34:20 +00:00
|
|
|
},
|
|
|
|
|
2019-12-12 07:37:35 +00:00
|
|
|
waitForClassNotPresent: async function(selector, className) {
|
2020-11-23 17:27:32 +00:00
|
|
|
await this.waitForSelector(selector);
|
2021-10-11 09:19:20 +00:00
|
|
|
return this.waitForFunction((selector, className) => {
|
2019-12-12 07:37:35 +00:00
|
|
|
if (!document.querySelector(selector).classList.contains(className))
|
|
|
|
return true;
|
|
|
|
}, {}, selector, className);
|
2018-11-22 11:34:20 +00:00
|
|
|
},
|
|
|
|
|
2019-12-12 07:37:35 +00:00
|
|
|
waitForClassPresent: async function(selector, className) {
|
2020-11-23 17:27:32 +00:00
|
|
|
await this.waitForSelector(selector);
|
2021-10-11 09:19:20 +00:00
|
|
|
return this.waitForFunction((elementSelector, targetClass) => {
|
2019-12-12 07:37:35 +00:00
|
|
|
if (document.querySelector(elementSelector).classList.contains(targetClass))
|
|
|
|
return true;
|
|
|
|
}, {}, selector, className);
|
2018-11-22 11:34:20 +00:00
|
|
|
},
|
|
|
|
|
2019-12-12 07:37:35 +00:00
|
|
|
waitForTextInElement: async function(selector, text) {
|
2021-11-12 14:17:09 +00:00
|
|
|
await this.waitForFunction((selector, text) => {
|
|
|
|
if (document.querySelector(selector)) {
|
|
|
|
const innerText = document.querySelector(selector).innerText.toLowerCase();
|
|
|
|
const expectedText = text.toLowerCase();
|
|
|
|
if (innerText.includes(expectedText))
|
|
|
|
return innerText;
|
|
|
|
}
|
|
|
|
}, {}, selector, text);
|
2018-11-22 11:34:20 +00:00
|
|
|
},
|
|
|
|
|
2020-11-09 17:25:02 +00:00
|
|
|
waitForTextInField: async function(selector, text) {
|
2021-11-12 14:17:09 +00:00
|
|
|
const builtSelector = await this.selectorFormater(selector);
|
|
|
|
const expectedValue = text.toLowerCase();
|
2020-11-09 17:25:02 +00:00
|
|
|
|
2021-11-12 14:17:09 +00:00
|
|
|
try {
|
|
|
|
await this.waitForFunction((selector, text) => {
|
|
|
|
const element = document.querySelector(selector);
|
|
|
|
if (element) {
|
|
|
|
const value = element.value.toLowerCase();
|
|
|
|
if (value.includes(text))
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}, {}, builtSelector, expectedValue);
|
|
|
|
} catch (error) {
|
|
|
|
throw new Error(`${text} wasn't the value of ${builtSelector}, ${error}`);
|
|
|
|
}
|
2020-11-09 17:25:02 +00:00
|
|
|
},
|
|
|
|
|
2020-02-14 13:52:47 +00:00
|
|
|
selectorFormater: function(selector) {
|
2020-01-29 13:54:07 +00:00
|
|
|
if (selector.includes('vn-textarea'))
|
2020-02-14 13:52:47 +00:00
|
|
|
return `${selector} textarea`;
|
2020-01-29 13:54:07 +00:00
|
|
|
|
2020-02-12 06:21:53 +00:00
|
|
|
if (selector.includes('vn-input-file'))
|
2020-02-14 13:52:47 +00:00
|
|
|
return `${selector} section`;
|
2020-02-12 06:21:53 +00:00
|
|
|
|
2020-02-14 13:52:47 +00:00
|
|
|
return `${selector} input`;
|
2020-01-29 13:54:07 +00:00
|
|
|
},
|
|
|
|
|
2019-12-12 07:37:35 +00:00
|
|
|
waitForInnerText: async function(selector) {
|
2020-01-23 15:01:29 +00:00
|
|
|
await this.waitForSelector(selector, {});
|
|
|
|
await this.waitForFunction(selector => {
|
2019-12-12 07:37:35 +00:00
|
|
|
const innerText = document.querySelector(selector).innerText;
|
|
|
|
return innerText != null && innerText != '';
|
2020-01-23 15:01:29 +00:00
|
|
|
}, {}, selector);
|
2021-10-11 09:19:20 +00:00
|
|
|
return this.evaluate(selector => {
|
2019-12-12 07:37:35 +00:00
|
|
|
return document.querySelector(selector).innerText;
|
|
|
|
}, selector);
|
2018-11-22 11:34:20 +00:00
|
|
|
},
|
|
|
|
|
2019-12-12 07:37:35 +00:00
|
|
|
waitForEmptyInnerText: async function(selector) {
|
2021-10-11 09:19:20 +00:00
|
|
|
return this.waitFunction(selector => {
|
2018-11-22 11:34:20 +00:00
|
|
|
return document.querySelector(selector).innerText == '';
|
2019-10-28 16:31:33 +00:00
|
|
|
}, selector);
|
2018-11-22 11:34:20 +00:00
|
|
|
},
|
2018-09-10 08:23:26 +00:00
|
|
|
|
2019-12-31 11:00:16 +00:00
|
|
|
hideSnackbar: async function() {
|
2020-03-24 10:12:59 +00:00
|
|
|
// Holds up for the snackbar to be visible for a small period of time.
|
2020-04-03 13:14:53 +00:00
|
|
|
if (process.env.E2E_DEBUG)
|
2020-11-23 17:27:32 +00:00
|
|
|
await this.waitForTimeout(300);
|
2020-03-24 10:12:59 +00:00
|
|
|
|
2020-02-21 09:26:40 +00:00
|
|
|
await this.evaluate(() => {
|
2020-03-25 19:44:59 +00:00
|
|
|
let hideButton = document
|
|
|
|
.querySelector('vn-snackbar .shape.shown button');
|
2020-02-21 09:26:40 +00:00
|
|
|
if (hideButton)
|
2020-03-25 19:44:59 +00:00
|
|
|
return hideButton.click();
|
2020-02-21 09:26:40 +00:00
|
|
|
});
|
2020-11-23 17:27:32 +00:00
|
|
|
await this.waitForSelector('vn-snackbar .shape.shown', {hidden: true});
|
2018-12-02 23:45:34 +00:00
|
|
|
},
|
2018-11-23 07:05:57 +00:00
|
|
|
|
2020-03-25 19:44:59 +00:00
|
|
|
waitForSnackbar: async function() {
|
|
|
|
const selector = 'vn-snackbar .shape.shown';
|
2020-02-21 09:26:40 +00:00
|
|
|
await this.waitForSelector(selector);
|
2020-03-25 19:44:59 +00:00
|
|
|
|
2023-05-05 06:12:38 +00:00
|
|
|
const message = await this.evaluate(selector => {
|
2019-12-12 07:37:35 +00:00
|
|
|
const shape = document.querySelector(selector);
|
2020-03-25 19:44:59 +00:00
|
|
|
const message = {
|
|
|
|
text: shape.querySelector('.text').innerText
|
|
|
|
};
|
|
|
|
|
|
|
|
const types = ['error', 'success'];
|
|
|
|
for (let type of types) {
|
|
|
|
if (shape.classList.contains(type)) {
|
|
|
|
message.type = type;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2019-01-07 08:33:07 +00:00
|
|
|
|
2020-03-25 19:44:59 +00:00
|
|
|
return message;
|
2019-12-12 07:37:35 +00:00
|
|
|
}, selector);
|
2020-03-25 19:44:59 +00:00
|
|
|
|
2023-05-05 06:12:38 +00:00
|
|
|
message.isSuccess = message.type == 'success';
|
|
|
|
|
2019-12-31 11:00:16 +00:00
|
|
|
await this.hideSnackbar();
|
2020-03-25 19:44:59 +00:00
|
|
|
return message;
|
|
|
|
},
|
|
|
|
|
2020-03-23 22:57:11 +00:00
|
|
|
pickDate: async function(selector, date) {
|
2023-01-16 14:18:24 +00:00
|
|
|
date = date || Date.vnNew();
|
2020-03-23 23:54:12 +00:00
|
|
|
|
2020-10-21 12:25:40 +00:00
|
|
|
const timeZoneOffset = date.getTimezoneOffset() * 60000;
|
|
|
|
const localDate = (new Date(date.getTime() - timeZoneOffset))
|
|
|
|
.toISOString().substr(0, 10);
|
2020-03-23 22:57:11 +00:00
|
|
|
|
2020-11-23 17:27:32 +00:00
|
|
|
await this.waitForSelector(selector);
|
2020-10-21 12:25:40 +00:00
|
|
|
await this.evaluate((selector, localDate) => {
|
2020-03-23 22:57:11 +00:00
|
|
|
let input = document.querySelector(selector).$ctrl.input;
|
2020-10-21 12:25:40 +00:00
|
|
|
input.value = localDate;
|
2020-03-23 22:57:11 +00:00
|
|
|
input.dispatchEvent(new Event('change'));
|
2020-10-21 12:25:40 +00:00
|
|
|
}, selector, localDate);
|
2019-12-12 07:37:35 +00:00
|
|
|
},
|
|
|
|
|
2020-03-23 22:57:11 +00:00
|
|
|
pickTime: async function(selector, time) {
|
2020-11-23 17:27:32 +00:00
|
|
|
await this.waitForSelector(selector);
|
2020-03-23 22:57:11 +00:00
|
|
|
await this.evaluate((selector, time) => {
|
|
|
|
let input = document.querySelector(selector).$ctrl.input;
|
|
|
|
input.value = time;
|
|
|
|
input.dispatchEvent(new Event('change'));
|
|
|
|
}, selector, time);
|
|
|
|
},
|
2019-12-12 07:37:35 +00:00
|
|
|
|
2020-03-23 22:57:11 +00:00
|
|
|
clearTextarea: async function(selector) {
|
|
|
|
await this.waitForSelector(selector, {visible: true});
|
|
|
|
await this.evaluate(inputSelector => {
|
|
|
|
return document.querySelector(`${inputSelector} textarea`).value = '';
|
|
|
|
}, selector);
|
|
|
|
},
|
|
|
|
|
2020-01-16 12:40:51 +00:00
|
|
|
autocompleteSearch: async function(selector, searchValue) {
|
2020-01-29 13:54:07 +00:00
|
|
|
let builtSelector = await this.selectorFormater(selector);
|
2020-01-16 12:40:51 +00:00
|
|
|
|
2020-02-06 12:00:41 +00:00
|
|
|
await this.waitToClick(selector);
|
2020-03-23 23:54:12 +00:00
|
|
|
await this.write('.vn-drop-down.shown vn-textfield', searchValue);
|
2020-02-06 12:00:41 +00:00
|
|
|
|
|
|
|
try {
|
2020-01-23 15:01:29 +00:00
|
|
|
await this.waitForFunction((selector, searchValue) => {
|
|
|
|
let element = document
|
2020-01-16 12:40:51 +00:00
|
|
|
.querySelector(`${selector} vn-drop-down`).$ctrl.content
|
|
|
|
.querySelector('li.active');
|
2020-01-23 15:01:29 +00:00
|
|
|
if (element)
|
|
|
|
return element.innerText.toLowerCase().includes(searchValue.toLowerCase());
|
|
|
|
}, {}, selector, searchValue);
|
2020-01-16 12:40:51 +00:00
|
|
|
} catch (error) {
|
2020-02-06 12:00:41 +00:00
|
|
|
let inputValue = await this.evaluate(() => {
|
2020-03-23 23:54:12 +00:00
|
|
|
return document.querySelector('.vn-drop-down.shown vn-textfield input').value;
|
2020-02-06 12:00:41 +00:00
|
|
|
});
|
|
|
|
throw new Error(`${builtSelector} value is ${inputValue}! ${error}`);
|
2020-01-16 12:40:51 +00:00
|
|
|
}
|
2020-02-06 12:00:41 +00:00
|
|
|
await this.keyboard.press('Enter');
|
|
|
|
await this.waitForFunction((selector, searchValue) => {
|
|
|
|
return document.querySelector(selector).value.toLowerCase()
|
|
|
|
.includes(searchValue.toLowerCase());
|
|
|
|
}, {}, builtSelector, searchValue);
|
|
|
|
|
2020-11-23 17:27:32 +00:00
|
|
|
await this.waitForSelector('.vn-drop-down', {hidden: true});
|
2019-12-12 07:37:35 +00:00
|
|
|
},
|
|
|
|
|
|
|
|
checkboxState: async function(selector) {
|
2020-11-23 17:27:32 +00:00
|
|
|
await this.waitForSelector(selector);
|
2023-05-05 06:12:38 +00:00
|
|
|
const value = await this.getInputValue(selector);
|
|
|
|
switch (value) {
|
|
|
|
case null:
|
|
|
|
return 'intermediate';
|
|
|
|
case true:
|
|
|
|
return 'checked';
|
|
|
|
default:
|
|
|
|
return 'unchecked';
|
|
|
|
}
|
2019-01-30 10:09:53 +00:00
|
|
|
},
|
|
|
|
|
2019-12-12 07:37:35 +00:00
|
|
|
isDisabled: async function(selector) {
|
2020-02-04 15:21:10 +00:00
|
|
|
await this.waitForSelector(selector);
|
2021-10-11 09:19:20 +00:00
|
|
|
return this.evaluate(selector => {
|
2019-12-12 07:37:35 +00:00
|
|
|
let element = document.querySelector(selector);
|
|
|
|
return element.$ctrl.disabled;
|
|
|
|
}, selector);
|
2019-02-14 19:17:22 +00:00
|
|
|
},
|
|
|
|
|
2019-12-12 07:37:35 +00:00
|
|
|
waitForStylePresent: async function(selector, property, value) {
|
2021-10-11 09:19:20 +00:00
|
|
|
return this.waitForFunction((selector, property, value) => {
|
2019-11-12 07:51:50 +00:00
|
|
|
const element = document.querySelector(selector);
|
|
|
|
return element.style[property] == value;
|
2019-12-12 07:37:35 +00:00
|
|
|
}, {}, selector, property, value);
|
2019-06-27 13:33:15 +00:00
|
|
|
},
|
2019-11-12 07:51:50 +00:00
|
|
|
|
2019-12-12 07:37:35 +00:00
|
|
|
waitForSpinnerLoad: async function() {
|
2020-11-02 16:42:46 +00:00
|
|
|
await this.waitForSelector('vn-topbar vn-spinner', {hidden: true});
|
2019-11-19 13:33:25 +00:00
|
|
|
},
|
|
|
|
|
2019-12-12 07:37:35 +00:00
|
|
|
waitForWatcherData: async function(selector) {
|
2020-11-23 17:27:32 +00:00
|
|
|
await this.waitForSelector(selector);
|
|
|
|
await this.waitForFunction(selector => {
|
2019-12-31 11:00:16 +00:00
|
|
|
let watcher = document.querySelector(selector);
|
2019-12-12 07:37:35 +00:00
|
|
|
let orgData = watcher.$ctrl.orgData;
|
|
|
|
return !angular.equals({}, orgData) && orgData != null;
|
2019-12-31 11:00:16 +00:00
|
|
|
}, {}, selector);
|
2019-12-12 07:37:35 +00:00
|
|
|
await this.waitForSpinnerLoad();
|
2020-01-09 12:07:16 +00:00
|
|
|
},
|
|
|
|
|
2020-01-16 12:40:51 +00:00
|
|
|
waitForMutation: async function(selector, type) {
|
|
|
|
try {
|
|
|
|
await this.evaluate((selector, type) => {
|
|
|
|
return new Promise(resolve => {
|
|
|
|
const config = {attributes: true, childList: true, subtree: true};
|
|
|
|
const target = document.querySelector(selector);
|
|
|
|
|
|
|
|
const onEnd = function(mutationsList, observer) {
|
|
|
|
resolve();
|
|
|
|
|
|
|
|
observer.disconnect();
|
|
|
|
};
|
|
|
|
const observer = new MutationObserver(onEnd);
|
|
|
|
observer.expectedType = type;
|
|
|
|
|
|
|
|
observer.observe(target, config);
|
|
|
|
});
|
|
|
|
}, selector, type);
|
|
|
|
} catch (error) {
|
|
|
|
throw new Error(`failed to wait for mutation type: ${type}`);
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
2020-01-09 12:07:16 +00:00
|
|
|
waitForTransitionEnd: async function(selector) {
|
|
|
|
await this.evaluate(selector => {
|
|
|
|
return new Promise(resolve => {
|
|
|
|
const transition = document.querySelector(selector);
|
|
|
|
const onEnd = function() {
|
|
|
|
transition.removeEventListener('transitionend', onEnd);
|
|
|
|
resolve();
|
|
|
|
};
|
|
|
|
transition.addEventListener('transitionend', onEnd);
|
|
|
|
});
|
|
|
|
}, selector);
|
2020-01-14 08:20:14 +00:00
|
|
|
},
|
|
|
|
|
2020-06-30 09:15:20 +00:00
|
|
|
closePopup: async function() {
|
2020-02-12 13:36:05 +00:00
|
|
|
await Promise.all([
|
|
|
|
this.keyboard.press('Escape'),
|
2020-11-23 17:27:32 +00:00
|
|
|
this.waitForSelector('.vn-popup', {hidden: true}),
|
2020-02-12 13:36:05 +00:00
|
|
|
]);
|
|
|
|
},
|
|
|
|
|
2020-02-28 08:59:32 +00:00
|
|
|
respondToDialog: async function(response) {
|
2020-03-23 23:54:12 +00:00
|
|
|
await this.waitForSelector('.vn-dialog.shown');
|
2020-03-17 10:00:16 +00:00
|
|
|
const firstCount = await this.evaluate(text => {
|
2020-03-23 23:54:12 +00:00
|
|
|
const dialogs = document.querySelectorAll('.vn-dialog');
|
2020-02-28 08:59:32 +00:00
|
|
|
const dialogOnTop = dialogs[dialogs.length - 1];
|
2020-03-17 10:00:16 +00:00
|
|
|
const button = dialogOnTop.querySelector(`div.buttons [response="${text}"]`);
|
2020-02-28 08:59:32 +00:00
|
|
|
button.click();
|
|
|
|
return dialogs.length;
|
|
|
|
}, response);
|
|
|
|
|
2020-03-24 16:27:21 +00:00
|
|
|
await this.waitForFunction(firstCount => {
|
2020-03-23 23:54:12 +00:00
|
|
|
const dialogs = document.querySelectorAll('.vn-dialog');
|
2020-03-17 10:00:16 +00:00
|
|
|
return dialogs.length < firstCount;
|
2020-02-28 08:59:32 +00:00
|
|
|
}, {}, firstCount);
|
2020-03-23 22:57:11 +00:00
|
|
|
},
|
|
|
|
|
|
|
|
waitForContentLoaded: async function() {
|
2020-03-31 13:30:57 +00:00
|
|
|
await this.waitForSpinnerLoad();
|
2023-05-05 06:12:38 +00:00
|
|
|
},
|
|
|
|
|
|
|
|
async getInputValue(selector) {
|
|
|
|
return this.evaluate(selector => {
|
|
|
|
const input = document.querySelector(selector);
|
|
|
|
return input.$ctrl.field;
|
|
|
|
}, selector);
|
|
|
|
},
|
|
|
|
|
|
|
|
async getValue(selector) {
|
|
|
|
return await this.waitToGetProperty(selector, 'value');
|
|
|
|
},
|
|
|
|
|
|
|
|
async innerText(selector) {
|
|
|
|
const element = await this.$(selector);
|
|
|
|
const handle = await element.getProperty('innerText');
|
|
|
|
return handle.jsonValue();
|
|
|
|
},
|
|
|
|
|
|
|
|
async setInput(selector, value) {
|
|
|
|
const input = await this.$(selector);
|
|
|
|
const tagName = (await input.evaluate(e => e.tagName)).toLowerCase();
|
|
|
|
|
|
|
|
switch (tagName) {
|
|
|
|
case 'vn-textfield':
|
2023-07-06 11:15:54 +00:00
|
|
|
case 'vn-account-number':
|
2023-05-05 06:12:38 +00:00
|
|
|
case 'vn-datalist':
|
|
|
|
case 'vn-input-number':
|
|
|
|
await this.clearInput(selector);
|
|
|
|
if (value)
|
|
|
|
await this.write(selector, value.toString());
|
|
|
|
break;
|
|
|
|
case 'vn-autocomplete':
|
2023-07-20 09:26:48 +00:00
|
|
|
case 'vn-worker-autocomplete':
|
2023-05-05 06:12:38 +00:00
|
|
|
if (value)
|
|
|
|
await this.autocompleteSearch(selector, value.toString());
|
|
|
|
else
|
|
|
|
await this.clearInput(selector);
|
|
|
|
break;
|
|
|
|
case 'vn-date-picker':
|
|
|
|
if (value)
|
|
|
|
await this.pickDate(selector, value);
|
|
|
|
else
|
|
|
|
await this.clearInput(selector);
|
|
|
|
break;
|
|
|
|
case 'vn-input-time':
|
|
|
|
if (value)
|
|
|
|
await this.pickTime(selector, value);
|
|
|
|
else
|
|
|
|
await this.clearInput(selector);
|
|
|
|
break;
|
|
|
|
case 'vn-check':
|
|
|
|
for (let i = 0; i < 3; i++) {
|
|
|
|
if (await this.getInput(selector) == value) break;
|
|
|
|
await this.click(selector);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
async getInput(selector) {
|
|
|
|
const input = await this.$(selector);
|
|
|
|
const tagName = (await input.evaluate(e => e.tagName)).toLowerCase();
|
|
|
|
let el;
|
|
|
|
let value;
|
|
|
|
|
|
|
|
switch (tagName) {
|
|
|
|
case 'vn-textfield':
|
2023-07-06 11:15:54 +00:00
|
|
|
case 'vn-account-number':
|
2023-05-05 06:12:38 +00:00
|
|
|
case 'vn-autocomplete':
|
2023-07-20 09:26:48 +00:00
|
|
|
case 'vn-worker-autocomplete':
|
2023-05-05 06:12:38 +00:00
|
|
|
case 'vn-input-time':
|
|
|
|
case 'vn-datalist':
|
|
|
|
el = await input.$('input');
|
|
|
|
value = await el.getProperty('value');
|
|
|
|
return value.jsonValue();
|
|
|
|
case 'vn-check':
|
|
|
|
case 'vn-input-number':
|
|
|
|
return await this.getInputValue(selector);
|
|
|
|
case 'vn-textarea':
|
|
|
|
el = await input.$('textarea');
|
|
|
|
value = await el.getProperty('value');
|
|
|
|
return value.jsonValue();
|
|
|
|
case 'vn-date-picker':
|
|
|
|
el = await input.$('input');
|
|
|
|
value = await el.getProperty('value');
|
|
|
|
if (value) {
|
|
|
|
const date = new Date(await value.jsonValue());
|
|
|
|
date.setUTCHours(0, 0, 0, 0);
|
|
|
|
return date;
|
|
|
|
} else
|
|
|
|
return null;
|
|
|
|
default:
|
|
|
|
value = await this.innerText(selector);
|
|
|
|
return value.jsonValue();
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
async clearInput(selector) {
|
|
|
|
await this.waitForSelector(selector);
|
|
|
|
|
|
|
|
let field = await this.evaluate(selector => {
|
|
|
|
return document.querySelector(`${selector} input`).closest('.vn-field').$ctrl.field;
|
|
|
|
}, selector);
|
|
|
|
|
|
|
|
if ((field != null && field != '') || field == '0') {
|
|
|
|
let coords = await this.evaluate(selector => {
|
|
|
|
let rect = document.querySelector(selector).getBoundingClientRect();
|
|
|
|
return {x: rect.x + (rect.width / 2), y: rect.y + (rect.height / 2), width: rect.width};
|
|
|
|
}, selector);
|
|
|
|
await this.mouse.move(coords.x, coords.y);
|
|
|
|
await this.waitForSelector(`${selector} [icon="clear"]`, {visible: true});
|
|
|
|
await this.waitToClick(`${selector} [icon="clear"]`);
|
|
|
|
}
|
|
|
|
|
|
|
|
await this.evaluate(selector => {
|
|
|
|
return document.querySelector(`${selector} input`).closest('.vn-field').$ctrl.field == '';
|
|
|
|
}, selector);
|
|
|
|
},
|
|
|
|
|
|
|
|
async fetchForm(selector, inputNames) {
|
|
|
|
const values = {};
|
|
|
|
for (const inputName of inputNames)
|
|
|
|
values[inputName] = await this.getInput(`${selector} [vn-name="${inputName}"]`);
|
|
|
|
return values;
|
|
|
|
},
|
|
|
|
|
|
|
|
async fillForm(selector, values) {
|
|
|
|
for (const inputName in values)
|
|
|
|
await this.setInput(`${selector} [vn-name="${inputName}"]`, values[inputName]);
|
|
|
|
},
|
|
|
|
|
|
|
|
async sendForm(selector, values) {
|
|
|
|
if (values) await this.fillForm(selector, values);
|
|
|
|
await this.click(`${selector} button[type=submit]`);
|
|
|
|
return await this.waitForSnackbar();
|
2019-11-12 07:51:50 +00:00
|
|
|
}
|
2018-11-22 11:34:20 +00:00
|
|
|
};
|
2018-09-10 08:23:26 +00:00
|
|
|
|
2019-12-12 07:37:35 +00:00
|
|
|
export function extendPage(page) {
|
|
|
|
for (let name in actions) {
|
|
|
|
page[name] = async(...args) => {
|
2020-03-24 16:27:21 +00:00
|
|
|
try {
|
2023-05-05 06:12:38 +00:00
|
|
|
return await actions[name].apply(page, args);
|
2020-03-24 16:27:21 +00:00
|
|
|
} catch (err) {
|
|
|
|
let stringArgs = args
|
2023-05-05 06:12:38 +00:00
|
|
|
.map(i => typeof i == 'function' ? 'Function' : `'${i}'`)
|
2020-03-24 16:27:21 +00:00
|
|
|
.join(', ');
|
2023-05-05 06:12:38 +00:00
|
|
|
const myErr = new Error(`${err.message}\n at Page.${name}(${stringArgs})`);
|
|
|
|
myErr.stack = err.stack;
|
|
|
|
throw myErr;
|
2020-03-24 16:27:21 +00:00
|
|
|
}
|
2019-12-12 07:37:35 +00:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
page.wait = page.waitFor;
|
|
|
|
|
|
|
|
return page;
|
|
|
|
}
|
2019-11-25 08:13:20 +00:00
|
|
|
|
|
|
|
export default actions;
|