463 lines
17 KiB
JavaScript
463 lines
17 KiB
JavaScript
/* eslint no-invalid-this: "off" */
|
|
import {url as defaultURL} from './config';
|
|
|
|
let actions = {
|
|
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;
|
|
},
|
|
|
|
parsedUrl: async function() {
|
|
return new URL(await this.url());
|
|
},
|
|
|
|
waitUntilNotPresent: async function(selector) {
|
|
await this.wait(selector => {
|
|
return document.querySelector(selector) == null;
|
|
}, selector);
|
|
},
|
|
|
|
changeLanguageToEnglish: async function() {
|
|
let langSelector = '.user-popover vn-autocomplete[ng-model="$ctrl.lang"]';
|
|
|
|
await this.waitToClick('#user');
|
|
await this.wait(langSelector);
|
|
let lang = await this.waitToGetProperty(`${langSelector} input`, 'value');
|
|
|
|
if (lang !== 'English')
|
|
await this.autocompleteSearch(langSelector, 'English');
|
|
|
|
await this.keyboard.press('Escape');
|
|
await this.waitForSelector(langSelector, {hidden: true});
|
|
},
|
|
|
|
doLogin: async function(userName, password = 'nightmare') {
|
|
await this.wait(`vn-login [ng-model="$ctrl.user"]`);
|
|
await this.clearInput(`vn-login [ng-model="$ctrl.user"]`);
|
|
await this.write(`vn-login [ng-model="$ctrl.user"]`, userName);
|
|
await this.clearInput(`vn-login [ng-model="$ctrl.password"]`);
|
|
await this.write(`vn-login [ng-model="$ctrl.password"]`, password);
|
|
await this.click('vn-login button[type=submit]');
|
|
},
|
|
|
|
login: async function(userName) {
|
|
try {
|
|
await this.waitForURL('#!/login');
|
|
} catch (e) {
|
|
await this.goto(`${defaultURL}/#!/login`);
|
|
}
|
|
|
|
await this.doLogin(userName);
|
|
await this.wait(() => {
|
|
return document.location.hash === '#!/';
|
|
}, {});
|
|
await this.changeLanguageToEnglish();
|
|
},
|
|
|
|
selectModule: async function(moduleName) {
|
|
let snakeName = moduleName.replace(/[\w]([A-Z])/g, m => {
|
|
return m[0] + '-' + m[1];
|
|
}).toLowerCase();
|
|
|
|
let selector = `vn-home a[ui-sref="${moduleName}.index"]`;
|
|
await this.waitToClick(selector);
|
|
await this.waitForURL(snakeName);
|
|
},
|
|
|
|
loginAndModule: async function(userName, moduleName) {
|
|
await this.login(userName);
|
|
await this.selectModule(moduleName);
|
|
},
|
|
|
|
datePicker: async function(selector, changeMonth, day) {
|
|
let date = new Date();
|
|
if (changeMonth) date.setMonth(date.getMonth() + changeMonth);
|
|
date.setDate(day ? day : 16);
|
|
date = date.toISOString().substr(0, 10);
|
|
|
|
await this.wait(selector);
|
|
await this.evaluate((selector, date) => {
|
|
let input = document.querySelector(selector).$ctrl.input;
|
|
input.value = date;
|
|
input.dispatchEvent(new Event('change'));
|
|
}, selector, date);
|
|
},
|
|
|
|
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);
|
|
},
|
|
|
|
clearTextarea: async function(selector) {
|
|
await this.wait(selector);
|
|
await this.input.evaluate(inputSelector => {
|
|
return document.querySelector(inputSelector).value = '';
|
|
}, selector);
|
|
},
|
|
|
|
clearInput: async function(selector) {
|
|
await this.wait(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.waitFor(1000);
|
|
await this.waitToClick(`${selector} [icon="clear"]`);
|
|
}
|
|
},
|
|
|
|
getProperty: async function(selector, property) {
|
|
return await this.evaluate((selector, property) => {
|
|
return document.querySelector(selector)[property].replace(/\s+/g, ' ').trim();
|
|
}, selector, property);
|
|
},
|
|
|
|
waitPropertyLength: async function(selector, property, minLength) {
|
|
await this.wait((selector, property, minLength) => {
|
|
const element = document.querySelector(selector);
|
|
return element && element[property] != null && element[property] !== '' && element[property].length >= minLength;
|
|
}, {}, selector, property, minLength);
|
|
return await this.getProperty(selector, property);
|
|
},
|
|
|
|
waitPropertyValue: async function(selector, property, status) {
|
|
await this.wait(selector);
|
|
return await this.wait((selector, property, status) => {
|
|
const element = document.querySelector(selector);
|
|
return element[property] === status;
|
|
}, {}, selector, property, status);
|
|
},
|
|
|
|
waitToGetProperty: async function(selector, property) {
|
|
await this.wait((selector, property) => {
|
|
const element = document.querySelector(selector);
|
|
|
|
return element && element[property] != null && element[property] !== '';
|
|
}, {}, selector, property);
|
|
return await this.getProperty(selector, property);
|
|
},
|
|
|
|
write: async function(selector, text) {
|
|
await this.wait(selector, {});
|
|
await this.type(`${selector} input`, text);
|
|
},
|
|
|
|
waitToClick: async function(selector) {
|
|
await this.wait(selector);
|
|
await this.click(selector);
|
|
},
|
|
|
|
focusElement: async function(selector) {
|
|
await this.wait(selector);
|
|
return await this.evaluate(selector => {
|
|
let element = document.querySelector(selector);
|
|
element.focus();
|
|
}, selector);
|
|
},
|
|
|
|
isVisible: async function(selector) {
|
|
await this.wait(selector);
|
|
return await this.evaluate(elementSelector => {
|
|
let selectorMatches = document.querySelectorAll(elementSelector);
|
|
let element = selectorMatches[0];
|
|
|
|
if (selectorMatches.length > 1)
|
|
throw new Error(`Multiple matches of ${elementSelector} 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;
|
|
}, selector);
|
|
},
|
|
|
|
waitImgLoad: async function(selector) {
|
|
await this.wait(selector);
|
|
return await this.wait(selector => {
|
|
const imageReady = document.querySelector(selector).complete;
|
|
return imageReady;
|
|
}, {}, selector);
|
|
},
|
|
|
|
clickIfVisible: async function(selector) {
|
|
await this.wait(selector);
|
|
let isVisible = await this.isVisible(selector);
|
|
|
|
if (isVisible)
|
|
return await this.click(selector);
|
|
|
|
throw new Error(`invisible selector: ${selector}`);
|
|
},
|
|
|
|
countElement: async function(selector) {
|
|
return await this.evaluate(selector => {
|
|
return document.querySelectorAll(selector).length;
|
|
}, selector);
|
|
},
|
|
|
|
waitForNumberOfElements: async function(selector, count) {
|
|
return await this.wait((selector, count) => {
|
|
return document.querySelectorAll(selector).length === count;
|
|
}, {}, selector, count);
|
|
},
|
|
|
|
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);
|
|
},
|
|
|
|
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);
|
|
},
|
|
|
|
waitForTextInElement: async function(selector, text) {
|
|
await this.wait(selector);
|
|
return await this.wait((selector, text) => {
|
|
return document.querySelector(selector).innerText.toLowerCase().includes(text.toLowerCase());
|
|
}, {}, selector, text);
|
|
},
|
|
|
|
waitForTextInInput: async function(selector, text) {
|
|
await this.wait(selector);
|
|
return await this.wait((selector, text) => {
|
|
return document.querySelector(`${selector} input`).value.toLowerCase().includes(text.toLowerCase());
|
|
}, {}, selector, text);
|
|
},
|
|
|
|
waitForInnerText: async function(selector) {
|
|
await this.wait(selector);
|
|
await this.wait(selector => {
|
|
const innerText = document.querySelector(selector).innerText;
|
|
return innerText != null && innerText != '';
|
|
}, selector);
|
|
return await this.evaluate(selector => {
|
|
return document.querySelector(selector).innerText;
|
|
}, selector);
|
|
},
|
|
|
|
waitForEmptyInnerText: async function(selector) {
|
|
return await this.wait(selector => {
|
|
return document.querySelector(selector).innerText == '';
|
|
}, selector);
|
|
},
|
|
|
|
waitForURL: async function(hashURL) {
|
|
await this.wait(expectedHash => {
|
|
return document.location.hash.includes(expectedHash);
|
|
}, {}, hashURL);
|
|
},
|
|
|
|
hideSnackbar: async function() {
|
|
await this.waitToClick('#shapes .shown button');
|
|
},
|
|
|
|
waitForLastShape: async function(selector) {
|
|
await this.wait(selector);
|
|
let snackBarText = await this.evaluate(selector => {
|
|
const shape = document.querySelector(selector);
|
|
|
|
return shape.innerText;
|
|
}, selector);
|
|
await this.hideSnackbar();
|
|
return snackBarText;
|
|
},
|
|
|
|
waitForLastSnackbar: async function() {
|
|
await this.wait(2000); // this needs a refactor to be somehow dynamic ie: page.waitForResponse(urlOrPredicate[, options]) or something to fire waitForLastShape once the request is completed
|
|
await this.waitForSpinnerLoad();
|
|
return await this.waitForLastShape('vn-snackbar .shown .text');
|
|
},
|
|
|
|
accessToSearchResult: async function(searchValue) {
|
|
await this.clearInput('vn-searchbar');
|
|
await this.write('vn-searchbar', searchValue);
|
|
await this.waitToClick('vn-searchbar vn-icon[icon="search"]');
|
|
await this.waitForNumberOfElements('.search-result', 1);
|
|
|
|
return await this.waitToClick('ui-view vn-card a');
|
|
},
|
|
|
|
accessToSection: async function(sectionRoute) {
|
|
await this.wait(`vn-left-menu`);
|
|
let nested = await this.evaluate(sectionRoute => {
|
|
return document.querySelector(`vn-left-menu li li > a[ui-sref="${sectionRoute}"]`) != null;
|
|
}, sectionRoute);
|
|
|
|
|
|
if (nested) {
|
|
await this.waitToClick('vn-left-menu vn-item-section > vn-icon[icon=keyboard_arrow_down]');
|
|
await this.wait('vn-left-menu .expanded');
|
|
}
|
|
|
|
await this.evaluate(sectionRoute => {
|
|
let navButton = document.querySelector(`vn-left-menu li > a[ui-sref="${sectionRoute}"]`);
|
|
navButton.scrollIntoViewIfNeeded();
|
|
return navButton.click();
|
|
}, sectionRoute);
|
|
},
|
|
|
|
autocompleteSearch: async function(autocompleteSelector, searchValue) {
|
|
await this.waitFor(100); // time in which the autocomplete data loads
|
|
await this.waitToClick(`${autocompleteSelector} input`);
|
|
await this.write(`.vn-drop-down.shown`, searchValue);
|
|
await this.waitFor(100); // ul to repaint
|
|
await this.waitToClick(`.vn-drop-down.shown li.active`);
|
|
await this.waitFor(200); // input to asign value
|
|
await this.wait((autocompleteSelector, searchValue) => {
|
|
return document.querySelector(`${autocompleteSelector} input`).value
|
|
.toLowerCase()
|
|
.includes(searchValue.toLowerCase());
|
|
}, {}, autocompleteSelector, searchValue);
|
|
await this.wait(() => {
|
|
return !document.querySelector('.vn-drop-down');
|
|
}, {});
|
|
},
|
|
|
|
reloadSection: async function(sectionRoute) {
|
|
await this.evaluate(() => {
|
|
let summayButton = document.querySelector('vn-icon[icon="desktop_windows"]');
|
|
summayButton.scrollIntoViewIfNeeded();
|
|
return summayButton.click();
|
|
});
|
|
await this.wait('vn-card.summary');
|
|
await this.waitToClick(`vn-left-menu li > a[ui-sref="${sectionRoute}"]`);
|
|
},
|
|
|
|
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}"]`);
|
|
},
|
|
|
|
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);
|
|
},
|
|
|
|
isDisabled: async function(selector) {
|
|
await this.wait(selector);
|
|
return await this.evaluate(selector => {
|
|
let element = document.querySelector(selector);
|
|
return element.$ctrl.disabled;
|
|
}, selector);
|
|
},
|
|
|
|
waitForStylePresent: async function(selector, property, value) {
|
|
return await this.wait((selector, property, value) => {
|
|
const element = document.querySelector(selector);
|
|
return element.style[property] == value;
|
|
}, {}, selector, property, value);
|
|
},
|
|
|
|
waitForSpinnerLoad: async function() {
|
|
await this.waitUntilNotPresent('vn-topbar vn-spinner');
|
|
},
|
|
|
|
waitForWatcherData: async function(selector) {
|
|
await this.wait(selector);
|
|
await this.wait(selector => {
|
|
let watcher = document.querySelector(selector);
|
|
let orgData = watcher.$ctrl.orgData;
|
|
return !angular.equals({}, orgData) && orgData != null;
|
|
}, {}, selector);
|
|
await this.waitForSpinnerLoad();
|
|
},
|
|
|
|
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);
|
|
},
|
|
|
|
waitForContentLoaded: async function() {
|
|
await this.evaluate(() => {
|
|
return new Promise(resolve => {
|
|
const $rootScope = angular.element(document.body).injector().get('$rootScope');
|
|
$rootScope.$on('$viewContentLoaded', resolve());
|
|
});
|
|
});
|
|
}
|
|
};
|
|
|
|
export function extendPage(page) {
|
|
for (let name in actions) {
|
|
page[name] = async(...args) => {
|
|
return await actions[name].call(page, ...args);
|
|
};
|
|
}
|
|
|
|
page.wait = page.waitFor;
|
|
|
|
return page;
|
|
}
|
|
|
|
export default actions;
|