salix/e2e/helpers/extensions.js

609 lines
22 KiB
JavaScript
Raw Normal View History

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;
}
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') {
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;
}
}
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) {
await this.doLogin(userName);
await this.waitForState('home');
2019-10-15 14:19:35 +00:00
},
selectModule: async function(moduleName) {
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
},
getState: async function() {
return await this.evaluate(() => {
let $state = angular.element(document.body).injector().get('$state');
return $state.current.name;
});
2019-10-15 14:19:35 +00:00
},
gotoState: async function(state, params) {
2020-03-25 19:44:59 +00:00
await this.evaluate((state, params) => {
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
},
waitForState: async function(state) {
await this.waitFor(state => {
let $state = angular.element(document.body).injector().get('$state');
2020-03-24 10:12:59 +00:00
return !$state.transition && $state.is(state);
}, {}, state);
2020-03-25 19:44:59 +00:00
await this.waitForSpinnerLoad();
2019-05-03 15:49:38 +00:00
},
waitForTransition: async function() {
await this.waitFor(() => {
const $state = angular.element(document.body).injector().get('$state');
return !$state.transition;
});
await this.waitForSpinnerLoad();
},
2020-03-17 10:00:16 +00:00
accessToSection: async function(state) {
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
if (nested) {
2020-04-02 16:55:07 +00:00
let selector = 'vn-left-menu vn-item-section > vn-icon[icon=keyboard_arrow_down]';
await this.evaluate(selector => {
document.querySelector(selector).scrollIntoViewIfNeeded();
}, selector);
await this.waitToClick(selector);
await this.wait('vn-left-menu .expanded');
2019-12-31 11:00:16 +00:00
}
2020-03-17 10:00:16 +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) {
await this.click('vn-icon[icon="desktop_windows"]');
await this.accessToSection(state);
},
forceReloadSection: async function(sectionRoute) {
await this.waitToClick('vn-icon[icon="desktop_windows"]');
await this.waitToClick('button[response="accept"]');
await this.wait('vn-card.summary');
await this.waitToClick(`vn-left-menu li > a[ui-sref="${sectionRoute}"]`);
},
doSearch: async function(searchValue) {
await this.clearInput('vn-searchbar');
if (searchValue)
await this.write('vn-searchbar', searchValue);
await this.waitToClick('vn-searchbar vn-icon[icon="search"]');
await this.waitForTransition();
},
accessToSearchResult: async function(searchValue) {
await this.doSearch(searchValue);
2020-03-24 10:12:59 +00:00
await this.waitFor('.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) {
return await this.evaluate((selector, property) => {
return document.querySelector(selector)[property].replace(/\s+/g, ' ').trim();
2019-10-28 18:52:54 +00:00
}, selector, property);
},
2020-03-25 19:44:59 +00:00
getClassName: async function(selector) {
const element = await this.$(selector);
const handle = await element.getProperty('className');
return await handle.jsonValue();
},
2019-12-12 07:37:35 +00:00
waitPropertyLength: async function(selector, property, minLength) {
await this.waitForFunction((selector, property, minLength) => {
const element = document.querySelector(selector);
return element && element[property] != null && element[property] !== '' && element[property].length >= minLength;
2019-12-12 07:37:35 +00:00
}, {}, selector, property, minLength);
return await this.getProperty(selector, property);
},
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 {
return await this.waitForFunction((selector, property, value) => {
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) {
let builtSelector = selector;
if (selector.includes('vn-input-file') || property != 'innerText')
builtSelector = await this.selectorFormater(selector);
try {
await this.waitForFunction((selector, property) => {
const element = document.querySelector(selector);
2019-07-01 11:41:38 +00:00
return element && element[property] != null && element[property] !== '';
}, {}, builtSelector, property);
return await this.getProperty(builtSelector, property);
} catch (error) {
throw new Error(`couldn't get property: ${property} of ${builtSelector}, ${error}`);
}
},
2019-12-12 07:37:35 +00:00
write: async function(selector, text) {
let builtSelector = await this.selectorFormater(selector);
await this.waitForSelector(selector, {});
await this.type(builtSelector, text);
await this.waitForTextInField(selector, text);
},
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) {
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
return await this.click(selector);
},
2020-02-14 13:52:47 +00:00
writeOnEditableTD: async function(selector, text) {
let builtSelector = await this.selectorFormater(selector);
await this.waitToClick(selector);
await this.type(builtSelector, text);
await this.keyboard.press('Enter');
},
2019-12-12 07:37:35 +00:00
focusElement: async function(selector) {
await this.wait(selector);
return await this.evaluate(selector => {
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);
2020-03-23 23:54:12 +00:00
return await this.evaluate(checkVisibility, selector);
},
2019-12-12 07:37:35 +00:00
waitImgLoad: async function(selector) {
await this.wait(selector);
return await this.wait(selector => {
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) {
return await this.evaluate(selector => {
return document.querySelectorAll(selector).length;
2019-10-28 18:52:54 +00:00
}, selector);
},
2019-12-12 07:37:35 +00:00
waitForNumberOfElements: async function(selector, count) {
2020-01-26 23:48:00 +00:00
return await this.waitForFunction((selector, count) => {
2020-02-04 15:21:10 +00:00
return document.querySelectorAll(selector).length == count;
2019-12-12 07:37:35 +00:00
}, {}, selector, count);
},
2019-12-12 07:37:35 +00:00
waitForClassNotPresent: async function(selector, className) {
await this.wait(selector);
return await this.wait((selector, className) => {
if (!document.querySelector(selector).classList.contains(className))
return true;
}, {}, selector, className);
},
2019-12-12 07:37:35 +00:00
waitForClassPresent: async function(selector, className) {
await this.wait(selector);
return await this.wait((elementSelector, targetClass) => {
if (document.querySelector(elementSelector).classList.contains(targetClass))
return true;
}, {}, selector, className);
},
2019-12-12 07:37:35 +00:00
waitForTextInElement: async function(selector, text) {
2020-02-04 15:21:10 +00:00
await this.waitForSelector(selector);
return await this.waitForFunction((selector, text) => {
2019-12-12 07:37:35 +00:00
return document.querySelector(selector).innerText.toLowerCase().includes(text.toLowerCase());
}, {}, selector, text);
},
2020-02-14 13:52:47 +00:00
selectorFormater: function(selector) {
if (selector.includes('vn-textarea'))
2020-02-14 13:52:47 +00:00
return `${selector} textarea`;
if (selector.includes('vn-input-file'))
2020-02-14 13:52:47 +00:00
return `${selector} section`;
2020-02-14 13:52:47 +00:00
return `${selector} input`;
},
waitForTextInField: async function(selector, text) {
let builtSelector = await this.selectorFormater(selector);
await this.waitForSelector(builtSelector);
return await this.waitForFunction((selector, text) => {
return document.querySelector(selector).value.toLowerCase().includes(text.toLowerCase());
}, {}, builtSelector, text);
},
2019-12-12 07:37:35 +00:00
waitForInnerText: async function(selector) {
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 != '';
}, {}, selector);
2019-12-12 07:37:35 +00:00
return await this.evaluate(selector => {
return document.querySelector(selector).innerText;
}, selector);
},
2019-12-12 07:37:35 +00:00
waitForEmptyInnerText: async function(selector) {
return await this.wait(selector => {
return document.querySelector(selector).innerText == '';
}, selector);
},
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.
if (process.env.E2E_DEBUG)
2020-03-24 10:12:59 +00:00
await this.waitFor(300);
await this.evaluate(() => {
2020-03-25 19:44:59 +00:00
let hideButton = document
.querySelector('vn-snackbar .shape.shown button');
if (hideButton)
2020-03-25 19:44:59 +00:00
return hideButton.click();
});
2020-03-25 19:44:59 +00:00
await this.waitFor('vn-snackbar .shape.shown', {hidden: true});
},
2020-03-25 19:44:59 +00:00
waitForSnackbar: async function() {
const selector = 'vn-snackbar .shape.shown';
await this.waitForSelector(selector);
2020-03-25 19:44:59 +00:00
let 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
2019-12-31 11:00:16 +00:00
await this.hideSnackbar();
2020-03-25 19:44:59 +00:00
return message;
},
pickDate: async function(selector, date) {
date = date || new Date();
2020-03-23 23:54:12 +00:00
const tzoffset = date.getTimezoneOffset() * 60000;
const localIso = (new Date(date.getTime() - tzoffset))
.toISOString();
await this.wait(selector);
2020-03-23 23:54:12 +00:00
await this.evaluate((selector, localIso) => {
let input = document.querySelector(selector).$ctrl.input;
2020-03-23 23:54:12 +00:00
input.value = localIso.substr(0, 10);
input.dispatchEvent(new Event('change'));
2020-03-23 23:54:12 +00:00
}, selector, localIso);
2019-12-12 07:37:35 +00:00
},
pickTime: async function(selector, time) {
await this.wait(selector);
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
clearTextarea: async function(selector) {
await this.waitForSelector(selector, {visible: true});
await this.evaluate(inputSelector => {
return document.querySelector(`${inputSelector} textarea`).value = '';
}, selector);
},
clearInput: async function(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"]`);
2019-12-12 07:37:35 +00:00
}
await this.evaluate(selector => {
return document.querySelector(`${selector} input`).closest('.vn-field').$ctrl.field == '';
}, selector);
2019-12-12 07:37:35 +00:00
},
autocompleteSearch: async function(selector, searchValue) {
let builtSelector = await this.selectorFormater(selector);
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 {
await this.waitForFunction((selector, searchValue) => {
let element = document
.querySelector(`${selector} vn-drop-down`).$ctrl.content
.querySelector('li.active');
if (element)
return element.innerText.toLowerCase().includes(searchValue.toLowerCase());
}, {}, selector, searchValue);
} 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-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);
await this.waitFor('.vn-drop-down', {hidden: true});
2019-12-12 07:37:35 +00:00
},
checkboxState: async function(selector) {
await this.wait(selector);
return await this.evaluate(selector => {
let checkbox = document.querySelector(selector);
switch (checkbox.$ctrl.field) {
case null:
return 'intermediate';
case true:
return 'checked';
default:
return 'unchecked';
}
}, selector);
},
2019-12-12 07:37:35 +00:00
isDisabled: async function(selector) {
2020-02-04 15:21:10 +00:00
await this.waitForSelector(selector);
2019-12-12 07:37:35 +00:00
return await this.evaluate(selector => {
let element = document.querySelector(selector);
return element.$ctrl.disabled;
}, selector);
},
2019-12-12 07:37:35 +00:00
waitForStylePresent: async function(selector, property, value) {
return await this.wait((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() {
await this.waitFor('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) {
await this.wait(selector);
await this.wait(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
},
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-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'),
this.waitFor('.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);
},
waitForContentLoaded: async function() {
await this.waitForSpinnerLoad();
2019-11-12 07:51:50 +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 {
return await actions[name].apply(page, args);
} catch (err) {
let stringArgs = args
.map(i => typeof i == 'function' ? 'Function' : i)
.join(', ');
throw new Error(`.${name}(${stringArgs}): ${err.message}`);
}
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;