salix/e2e/helpers/extensions.js

487 lines
17 KiB
JavaScript

/* eslint no-invalid-this: "off" */
import Nightmare from 'nightmare';
import {URL} from 'url';
import config from './config.js';
let currentUser;
Nightmare.asyncAction = function(name, func) {
Nightmare.action(name, function(...args) {
let done = args[arguments.length - 1];
func.apply(this, args)
.then(result => done(null, result))
.catch(done);
});
};
Nightmare.asyncAction('clearInput', async function(selector) {
const backSpaces = [];
for (let i = 0; i < 50; i += 1)
backSpaces.push('\u0008');
await this.write(selector, backSpaces.join(''));
});
let actions = {
login: function(userName, done) {
if (currentUser)
this.waitToClick('#logout');
let doLogin = () => {
this.wait(`vn-login input[name=user]`)
.write(`vn-login input[name=user]`, userName)
.write(`vn-login input[name=password]`, 'nightmare')
.click(`vn-login input[type=submit]`)
.then(() => {
currentUser = userName;
done();
})
.catch(done);
};
this.waitForURL('#!/login')
.then(doLogin)
.catch(() => {
this.goto(`${config.url}/#!/login`)
.then(doLogin)
.catch(done);
});
},
waitForLogin: function(userName, done) {
if (currentUser === userName) {
return this.waitToClick('vn-topbar a[ui-sref="home"]')
.waitForURL('#!/')
.changeLanguageToEnglish()
.then(done)
.catch(done);
}
return this.login(userName)
.waitForURL('#!/')
.url()
.changeLanguageToEnglish()
.then(done)
.catch(done);
},
resetLogin: function(done) {
this.then(() => {
currentUser = undefined;
done();
})
.catch(done);
},
changeLanguageToEnglish: function(done) {
let langSelector = 'vn-user-configuration-popover vn-autocomplete[field="$ctrl.lang"]';
this.waitToClick('#user')
.wait(langSelector)
.waitToGetProperty(`${langSelector} input`, 'value')
.then(lang => {
if (lang === 'English') {
this.then(done)
.catch(done);
} else {
this.autocompleteSearch(langSelector, 'English')
.then(done)
.catch(done);
}
});
},
selectModule: function(moduleName, done) {
this.waitToClick(`vn-home a[ui-sref="${moduleName}.index"]`)
.waitForURL(moduleName)
.then(done)
.catch(done);
},
loginAndModule: function(userName, moduleName, done) {
this.waitForLogin(userName)
.selectModule(moduleName)
.then(done)
.catch(done);
},
parsedUrl: function(done) {
this.url()
.then(url => {
done(null, new URL(url));
}).catch(done);
},
getProperty: function(selector, property, done) {
this.evaluate_now((selector, property) => {
return document.querySelector(selector)[property].replace(/\s+/g, ' ').trim();
}, done, selector, property);
},
waitPropertyLength: function(selector, property, minLength, done) {
this.wait((selector, property, minLength) => {
const element = document.querySelector(selector);
return element && element[property] != null && element[property] !== '' && element[property].length >= minLength;
}, selector, property, minLength)
.getProperty(selector, property)
.then(result => done(null, result), done);
},
waitPropertyValue: function(selector, property, status, done) {
this.wait(selector)
.wait((selector, property, status) => {
const element = document.querySelector(selector);
return element[property] === status;
}, selector, property, status)
.then(done)
.catch(done);
},
waitToGetProperty: function(selector, property, done) {
this.wait((selector, property) => {
const element = document.querySelector(selector);
return element && element[property] != null && element[property] !== '';
}, selector, property)
.getProperty(selector, property)
.then(result => done(null, result), done);
},
write: function(selector, text, done) {
this.wait(selector)
.type(selector, text)
.then(done)
.catch(done);
},
waitToClick: function(selector, done) {
this.wait(selector)
.click(selector)
.then(done)
.catch(done);
},
waitToFocus: function(selector, done) {
this.wait(selector)
.evaluate_now(selector => {
let element = document.querySelector(selector);
element.focus();
}, done, selector)
.then(done)
.catch(done);
},
isVisible: function(selector, done) {
this.wait(selector)
.evaluate_now(elementSelector => {
const selectorMatches = document.querySelectorAll(elementSelector);
const element = selectorMatches[0];
if (selectorMatches.length > 1)
throw new Error(`multiple matches of ${elementSelector} found`);
let isVisible = false;
if (element) {
const eventHandler = event => {
event.preventDefault();
isVisible = true;
};
element.addEventListener('mouseover', eventHandler);
const elementBoundaries = element.getBoundingClientRect();
const x = elementBoundaries.left + element.offsetWidth / 2;
const y = elementBoundaries.top + element.offsetHeight / 2;
const elementInCenter = document.elementFromPoint(x, y);
const elementInTopLeft = document.elementFromPoint(elementBoundaries.left, elementBoundaries.top);
const elementInBottomRight = document.elementFromPoint(elementBoundaries.right, elementBoundaries.bottom);
const 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;
}, done, selector);
},
waitImgLoad: function(selector, done) {
this.wait(selector)
.wait(selector => {
const imageReady = document.querySelector(selector).complete;
return imageReady;
}, selector)
.then(done)
.catch(() => {
done(new Error(`image ${selector}, load timed out`));
});
},
clickIfVisible: function(selector, done) {
this.wait(selector)
.isVisible(selector)
.then(visible => {
if (visible)
return this.click(selector);
throw new Error(`invisible selector: ${selector}`);
})
.then(done)
.catch(done);
},
countElement: function(selector, done) {
this.evaluate_now(selector => {
return document.querySelectorAll(selector).length;
}, done, selector);
},
waitForNumberOfElements: function(selector, count, done) {
this.wait((selector, count) => {
return document.querySelectorAll(selector).length === count;
}, selector, count)
.then(done)
.catch(() => {
done(new Error(`.waitForNumberOfElements() for ${selector}, count ${count} timed out`));
});
},
waitForClassNotPresent: function(selector, className, done) {
this.wait(selector)
.wait((selector, className) => {
if (!document.querySelector(selector).classList.contains(className))
return true;
}, selector, className)
.then(done)
.catch(() => {
done(new Error(`.waitForClassNotPresent() for ${selector}, class ${className} timed out`));
});
},
waitForClassPresent: function(selector, className, done) {
this.wait(selector)
.wait((selector, className) => {
if (document.querySelector(selector).classList.contains(className))
return true;
}, selector, className)
.then(done)
.catch(() => {
done(new Error(`.waitForClassPresent() for ${selector}, class ${className} timed out`));
});
},
waitForTextInElement: function(selector, text, done) {
this.wait(selector)
.wait((selector, text) => {
return document.querySelector(selector).innerText.toLowerCase().includes(text.toLowerCase());
}, selector, text)
.then(done)
.catch(done);
},
waitForTextInInput: function(selector, text, done) {
this.wait(selector)
.wait((selector, text) => {
return document.querySelector(selector).value.toLowerCase().includes(text.toLowerCase());
}, selector, text)
.then(done)
.catch(done);
},
waitForInnerText: function(selector, done) {
this.wait(selector)
.wait(selector => {
const innerText = document.querySelector(selector).innerText;
return innerText != null && innerText != '';
}, selector)
.evaluate_now(selector => {
return document.querySelector(selector).innerText;
}, done, selector);
},
waitForEmptyInnerText: function(selector, done) {
this.wait(selector => {
return document.querySelector(selector).innerText == '';
}, selector)
.then(done)
.catch(done);
},
waitForURL: function(hashURL, done) {
this.wait(hash => {
return document.location.hash.includes(hash);
}, hashURL)
.then(done)
.catch(done);
},
waitForShapes: function(selector, done) {
this.wait(selector)
.evaluate_now(selector => {
const shapes = document.querySelectorAll(selector);
const shapesList = [];
for (const shape of shapes)
shapesList.push(shape.innerText);
return shapesList;
}, done, selector);
},
waitForSnackbar: function(done) {
this.wait(500).waitForShapes('vn-snackbar .shape .text')
.then(shapes => {
done(null, shapes);
}).catch(done);
},
waitForLastShape: function(selector, done) {
this.wait(selector)
.evaluate_now(selector => {
const shape = document.querySelector(selector);
return shape.innerText;
}, done, selector);
},
waitForLastSnackbar: function(done) {
this.wait(500).waitForLastShape('vn-snackbar .shape .text')
.then(shapes => {
done(null, shapes);
}).catch(done);
},
accessToSearchResult: function(searchValue, done) {
this.write(`vn-searchbar input`, searchValue)
.click(`vn-searchbar vn-icon[icon="search"]`)
.wait(100)
.waitForNumberOfElements('.searchResult', 1)
.evaluate(() => {
return document.querySelector('ui-view vn-card vn-table') != null;
})
.then(result => {
if (result)
return this.waitToClick('ui-view vn-card vn-td');
return this.waitToClick('ui-view vn-card a');
})
.then(done)
.catch(done);
},
accessToSection: function(sectionRoute, done) {
this.wait(`vn-left-menu`)
.evaluate(sectionRoute => {
return document.querySelector(`vn-left-menu ul li ul li > a[ui-sref="${sectionRoute}"]`) != null;
}, sectionRoute)
.then(nested => {
if (!nested)
return this.waitToClick(`vn-left-menu li > a[ui-sref="${sectionRoute}"]`);
return this.waitToClick('vn-left-menu .collapsed')
.wait('vn-left-menu .expanded')
.waitToClick(`vn-left-menu li > a[ui-sref="${sectionRoute}"]`);
})
.then(done)
.catch(done);
},
autocompleteSearch: function(autocompleteSelector, searchValue, done) {
this.wait(autocompleteSelector)
.waitToClick(`${autocompleteSelector} input`)
.write(`${autocompleteSelector} vn-drop-down input`, searchValue)
.waitToClick(`${autocompleteSelector} li.active`)
.wait((autocompleteSelector, searchValue) => {
return document.querySelector(`${autocompleteSelector} input`).value.toLowerCase().includes(searchValue.toLowerCase());
}, autocompleteSelector, searchValue)
.then(done)
.catch(() => {
done(new Error(`.autocompleteSearch() for ${autocompleteSelector}, timed out`));
});
},
datePicker: function(datePickerSelector, changeMonth, done) {
this.wait(datePickerSelector)
.mousedown(datePickerSelector)
.wait('div.flatpickr-calendar.open');
if (changeMonth > 0)
this.mousedown('body > div > div.flatpickr-months > span.flatpickr-next-month > svg');
if (changeMonth < 0)
this.mousedown('body > div > div.flatpickr-months > span.flatpickr-prev-month > svg');
const daySelector = 'div.flatpickr-calendar.open span.flatpickr-day:nth-child(16)';
this.wait(selector => {
return document.querySelector(selector);
}, daySelector)
.evaluate(selector => {
let event = new MouseEvent('mousedown', {
bubbles: true,
cancelable: true,
view: window
});
document.querySelector(selector).dispatchEvent(event);
}, daySelector)
.then(done)
.catch(() => {
done(new Error(`.datePicker(), for ${daySelector} timed out`));
});
},
reloadSection: function(sectionRoute, done) {
this.waitToClick('vn-icon[icon="desktop_windows"]')
.wait('vn-card.summary')
.waitToClick(`vn-left-menu li > a[ui-sref="${sectionRoute}"]`)
.then(done)
.catch(done);
},
forceReloadSection: function(sectionRoute, done) {
this.waitToClick('vn-icon[icon="desktop_windows"]')
.waitToClick('button[response="ACCEPT"]')
.wait('vn-card.summary')
.waitToClick(`vn-left-menu li > a[ui-sref="${sectionRoute}"]`)
.then(done)
.catch(done);
},
checkboxState: function(selector, done) {
this.wait(selector)
.evaluate(checkboxSelector => {
return document.querySelector(checkboxSelector).getAttribute('class');
}, selector)
.then(elementClass => {
let classList = elementClass.split(' ');
let className;
if (classList.includes('md-checked'))
className = 'checked';
if (classList.includes('md-intermediate'))
className = 'intermediate';
if (!classList.includes('md-intermediate') && !classList.includes('md-checked'))
className = 'unchecked';
if (!className)
throw new Error(`selector: ${selector} is not a md-checkbox`);
done(null, className);
})
.then(done)
.catch(done);
}
};
Object.keys(actions).forEach(function(name) {
let fn = actions[name];
Nightmare.action(name, fn);
});