Polishing e2e test API. Added option to parse links and extract parameters from them. Added option to construct parameterizedlinks in "navigate".

This commit is contained in:
Tomas Bures 2017-05-23 19:34:01 +02:00
parent 328034bae0
commit ccd37ac792
12 changed files with 308 additions and 147 deletions

View file

@ -1,14 +1,14 @@
'use strict';
const config = require('../helpers/config');
const driver = require('../helpers/mocha-e2e').driver;
const page = require('./page');
module.exports = (driver, ...extras) => page(driver, {
module.exports = (...extras) => page({
async fetchMail(address) {
await this.driver.sleep(1000);
await this.driver.navigate().to(`${config.mailUrl}/${address}`);
await driver.sleep(1000);
await driver.navigate().to(`${config.mailUrl}/${address}`);
await this.waitUntilVisible();
},

View file

@ -5,77 +5,84 @@ const webdriver = require('selenium-webdriver');
const By = webdriver.By;
const until = webdriver.until;
const fs = require('fs-extra');
const driver = require('../helpers/mocha-e2e').driver;
const url = require('url');
const UrlPattern = require('url-pattern');
module.exports = (driver, ...extras) => Object.assign({
driver,
module.exports = (...extras) => Object.assign({
elements: {},
async element(key) {
return await this.driver.findElement(By.css(this.elements[key] || key));
async getElement(key) {
return await driver.findElement(By.css(this.elements[key]));
},
async getLinkParams(key) {
const elem = await driver.findElement(By.css(this.elements[key]));
const linkUrl = await elem.getAttribute('href');
const linkPath = url.parse(linkUrl).path;
const urlPattern = new UrlPattern(this.links[key]);
const params = urlPattern.match(linkPath);
if (!params) {
throw new Error(`Cannot match URL pattern ${this.links[key]}`);
}
return params;
},
async waitUntilVisible(selector) {
// This is left here to ease debugging
// await this.sleep(2000);
// await this.takeScreenshot('image.png');
// console.log(await this.source());
const sel = selector || this.elements[this.elementToWaitFor] || 'body';
await this.driver.wait(until.elementLocated(By.css(sel)), 10000);
await driver.wait(until.elementLocated(By.css(sel)), 10000);
if (this.url) {
await this.ensureUrl();
}
},
async link(key) {
const elem = await this.element(key);
return await elem.getAttribute('href');
},
async submit() {
const submitButton = await this.element('submitButton');
await submitButton.click();
},
async click(key) {
const elem = await this.element(key);
const elem = await this.getElement(key);
await elem.click();
},
async getHref(key) {
const elem = await this.getElement(key);
return await elem.getAttribute('href');
},
async getText(key) {
const elem = await this.element(key);
const elem = await this.getElement(key);
return await elem.getText();
},
async getValue(key) {
const elem = await this.element(key);
const elem = await this.getElement(key);
return await elem.getAttribute('value');
},
async setValue(key, value) {
const elem = await this.element(key);
await elem.sendKeys(value);
},
async containsText(str) {
return await this.driver.executeScript(`
return await driver.executeScript(`
return (document.documentElement.textContent || document.documentElement.innerText).indexOf('${str}') > -1;
`);
},
async source() {
return await this.driver.getPageSource();
async getSource() {
return await driver.getPageSource();
},
async saveSource(destPath) {
const src = await this.getSource();
await fs.writeFile(destPath, src);
},
async takeScreenshot(destPath) {
const pngData = await this.driver.takeScreenshot();
const pngData = await driver.takeScreenshot();
const buf = new Buffer(pngData, 'base64');
await fs.writeFile(destPath, buf);
},
async sleep(ms) {
await this.driver.sleep(ms);
await driver.sleep(ms);
}
}, ...extras);

View file

@ -4,17 +4,10 @@ const config = require('../helpers/config');
const webBase = require('./web');
const mailBase = require('./mail');
module.exports = (driver, list) => {
module.exports = list => {
const web = params => webBase(driver, {
async enterEmail(value) {
const emailInput = await this.element('emailInput');
await emailInput.clear();
await emailInput.sendKeys(value);
},
}, params);
const mail = params => mailBase(driver, params);
const web = params => webBase(params);
const mail = params => mailBase(params);
return {
webSubscribe: web({
@ -23,6 +16,8 @@ module.exports = (driver, list) => {
elements: {
form: `form[action="/subscription/${list.cid}/subscribe"]`,
emailInput: '#main-form input[name="email"]',
firstNameInput: '#main-form input[name="first-name"]',
lastNameInput: '#main-form input[name="last-name"]',
submitButton: 'a[href="#submit"]'
}
}),
@ -55,17 +50,40 @@ module.exports = (driver, list) => {
elements: {
unsubscribeLink: `a[href^="${config.settings['service-url']}subscription/${list.cid}/unsubscribe/"]`,
manageLink: `a[href^="${config.settings['service-url']}subscription/${list.cid}/manage/"]`
},
links: {
unsubscribeLink: `/subscription/${list.cid}/unsubscribe/:ucid`,
manageLink: `/subscription/${list.cid}/manage/:ucid`
}
}),
/*
webManage: web({
url: `/subscription/${list.cid}/manage/:ucid`,
elementToWaitFor: 'form',
elements: {
form: `form[action="/subscription/${list.cid}/manage"]`,
emailInput: '#main-form input[name="email"]',
firstNameInput: '#main-form input[name="first-name"]',
lastNameInput: '#main-form input[name="last-name"]',
submitButton: 'a[href="#submit"]'
}
}),
webUpdatedNotice: web({
url: `/subscription/${list.cid}/updated-notice`,
elementToWaitFor: 'homepageButton',
elements: {
homepageButton: `a[href="${config.settings['default-homepage']}"]`
}
}),
/*
webUnsubscribe: web({ // FIXME
elementToWaitFor: 'submitButton',
elements: {
submitButton: 'a[href="#submit"]'
}
}),
*/
webUnsubscribedNotice: web({
url: `/subscription/${list.cid}/unsubscribed-notice`,
@ -81,14 +99,8 @@ module.exports = (driver, list) => {
resubscribeLink: `a[href^="${config.settings['service-url']}subscription/${list.cid}"]`
}
}),
/* TODO
webManage: web({
url: `/subscription/${list.cid}/manage`,
elementToWaitFor: 'homepageButton',
elements: {
homepageButton: `a[href="${config.settings['default-homepage']}"]`
}
}),
*/
*/
};
};

View file

@ -3,13 +3,30 @@
const config = require('../helpers/config');
const By = require('selenium-webdriver').By;
const url = require('url');
const UrlPattern = require('url-pattern');
const driver = require('../helpers/mocha-e2e').driver;
const page = require('./page');
module.exports = (driver, ...extras) => page(driver, {
module.exports = (...extras) => page({
async navigate(path) {
await this.driver.navigate().to(config.baseUrl + (path || this.url));
async navigate(pathOrParams) {
let path;
if (typeof pathOrParams === 'string') {
path = pathOrParams;
} else {
const urlPattern = new UrlPattern(this.url);
path = urlPattern.stringify(pathOrParams)
}
const parsedUrl = url.parse(path);
let absolutePath;
if (parsedUrl.host) {
absolutePath = path;
} else {
absolutePath = config.baseUrl + path;
}
await driver.navigate().to(absolutePath);
await this.waitUntilVisible();
},
@ -17,28 +34,44 @@ module.exports = (driver, ...extras) => page(driver, {
const desiredUrl = path || this.url;
if (desiredUrl) {
const currentUrl = url.parse(await this.driver.getCurrentUrl());
if (this.url !== currentUrl.pathname || config.baseUrl !== `${currentUrl.protocol}//${currentUrl.host}`) {
const currentUrl = url.parse(await driver.getCurrentUrl());
const urlPattern = new UrlPattern(desiredUrl);
const params = urlPattern.match(currentUrl.pathname);
if (!params || config.baseUrl !== `${currentUrl.protocol}//${currentUrl.host}`) {
throw new Error(`Unexpected URL. Expecting ${config.baseUrl}${this.url} got ${currentUrl.protocol}//${currentUrl.host}/${currentUrl.pathname}`);
}
this.params = params;
}
},
async submit() {
const submitButton = await this.getElement('submitButton');
await submitButton.click();
},
async waitForFlash() {
await this.waitUntilVisible('div.alert:not(.js-warning)');
},
async getFlash() {
const elem = await this.driver.findElement(By.css('div.alert:not(.js-warning)'));
async flash() {
const elem = await driver.findElement(By.css('div.alert:not(.js-warning)'));
return await elem.getText();
},
async clearFlash() {
await this.driver.executeScript(`
await driver.executeScript(`
var elements = document.getElementsByClassName('alert');
while(elements.length > 0){
elements[0].parentNode.removeChild(elements[0]);
}
`);
},
async setValue(key, value) {
const elem = await this.getElement(key);
await elem.clear();
await elem.sendKeys(value);
}
}, ...extras);