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:
parent
328034bae0
commit
ccd37ac792
12 changed files with 308 additions and 147 deletions
4
.gitignore
vendored
4
.gitignore
vendored
|
@ -1,4 +1,6 @@
|
||||||
.idea
|
/.idea
|
||||||
|
/last-failed-e2e-test.*
|
||||||
|
|
||||||
node_modules
|
node_modules
|
||||||
npm-debug.log
|
npm-debug.log
|
||||||
.DS_Store
|
.DS_Store
|
||||||
|
|
|
@ -148,7 +148,6 @@ function updateMenu(res) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function validateEmail(address, checkBlocked, callback) {
|
function validateEmail(address, checkBlocked, callback) {
|
||||||
|
|
||||||
let user = (address || '').toString().split('@').shift().toLowerCase().replace(/[^a-z0-9]/g, '');
|
let user = (address || '').toString().split('@').shift().toLowerCase().replace(/[^a-z0-9]/g, '');
|
||||||
if (checkBlocked && blockedUsers.indexOf(user) >= 0) {
|
if (checkBlocked && blockedUsers.indexOf(user) >= 0) {
|
||||||
return callback(new Error(util.format(_('Blocked email address "%s"'), address)));
|
return callback(new Error(util.format(_('Blocked email address "%s"'), address)));
|
||||||
|
|
|
@ -42,7 +42,8 @@
|
||||||
"mailparser": "^2.0.5",
|
"mailparser": "^2.0.5",
|
||||||
"mocha": "^3.3.0",
|
"mocha": "^3.3.0",
|
||||||
"phantomjs": "^2.1.7",
|
"phantomjs": "^2.1.7",
|
||||||
"selenium-webdriver": "^3.4.0"
|
"selenium-webdriver": "^3.4.0",
|
||||||
|
"url-pattern": "^1.0.3"
|
||||||
},
|
},
|
||||||
"optionalDependencies": {
|
"optionalDependencies": {
|
||||||
"posix": "^4.1.1"
|
"posix": "^4.1.1"
|
||||||
|
|
|
@ -1,15 +0,0 @@
|
||||||
'use strict';
|
|
||||||
|
|
||||||
const config = require('./config');
|
|
||||||
const webdriver = require('selenium-webdriver');
|
|
||||||
|
|
||||||
const driver = new webdriver.Builder()
|
|
||||||
.forBrowser(config.app.seleniumwebdriver.browser || 'phantomjs')
|
|
||||||
.build();
|
|
||||||
|
|
||||||
if (global.USE_SHARED_DRIVER === true) {
|
|
||||||
driver.originalQuit = driver.quit;
|
|
||||||
driver.quit = () => {};
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = driver;
|
|
|
@ -2,6 +2,18 @@
|
||||||
|
|
||||||
const Mocha = require('mocha');
|
const Mocha = require('mocha');
|
||||||
const color = Mocha.reporters.Base.color;
|
const color = Mocha.reporters.Base.color;
|
||||||
|
const Semaphore = require('./semaphore');
|
||||||
|
const fs = require('fs-extra');
|
||||||
|
const config = require('./config');
|
||||||
|
const webdriver = require('selenium-webdriver');
|
||||||
|
|
||||||
|
const driver = new webdriver.Builder()
|
||||||
|
.forBrowser(config.app.seleniumwebdriver.browser || 'phantomjs')
|
||||||
|
.build();
|
||||||
|
|
||||||
|
|
||||||
|
const failHandlerRunning = new Semaphore();
|
||||||
|
|
||||||
|
|
||||||
function UseCaseReporter(runner) {
|
function UseCaseReporter(runner) {
|
||||||
Mocha.reporters.Base.call(this, runner);
|
Mocha.reporters.Base.call(this, runner);
|
||||||
|
@ -37,9 +49,6 @@ function UseCaseReporter(runner) {
|
||||||
|
|
||||||
runner.on('use-case end', () => {
|
runner.on('use-case end', () => {
|
||||||
--indents;
|
--indents;
|
||||||
if (indents === 1) {
|
|
||||||
console.log();
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
runner.on('step pass', step => {
|
runner.on('step pass', step => {
|
||||||
|
@ -71,8 +80,22 @@ function UseCaseReporter(runner) {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
runner.on('fail', test => {
|
runner.on('fail', (test, err) => {
|
||||||
|
failHandlerRunning.enter();
|
||||||
|
(async () => {
|
||||||
|
const currentUrl = await driver.getCurrentUrl();
|
||||||
|
const info = `URL: ${currentUrl}`;
|
||||||
|
await fs.writeFile('last-failed-e2e-test.info', info);
|
||||||
|
await fs.writeFile('last-failed-e2e-test.html', await driver.getPageSource());
|
||||||
|
await fs.writeFile('last-failed-e2e-test.png', new Buffer(await driver.takeScreenshot(), 'base64'));
|
||||||
|
failHandlerRunning.exit();
|
||||||
|
})();
|
||||||
|
|
||||||
console.log(indent() + color('fail', ' %s'), test.title);
|
console.log(indent() + color('fail', ' %s'), test.title);
|
||||||
|
console.log();
|
||||||
|
console.log(err);
|
||||||
|
console.log();
|
||||||
|
console.log(`Snaphot of and info about the current page are in last-failed-e2e-test.*`);
|
||||||
});
|
});
|
||||||
|
|
||||||
runner.on('end', () => {
|
runner.on('end', () => {
|
||||||
|
@ -101,39 +124,61 @@ function UseCaseReporter(runner) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const mocha = new Mocha()
|
const mocha = new Mocha()
|
||||||
.timeout(120000)
|
.timeout(120000)
|
||||||
.reporter(UseCaseReporter);
|
.reporter(UseCaseReporter)
|
||||||
|
.ui('tdd');
|
||||||
|
|
||||||
mocha._originalRun = mocha.run;
|
mocha._originalRun = mocha.run;
|
||||||
|
|
||||||
|
|
||||||
let runner;
|
let runner;
|
||||||
mocha.run = fn => {
|
mocha.run = fn => {
|
||||||
runner = mocha._originalRun(fn);
|
runner = mocha._originalRun(async () => {
|
||||||
}
|
await failHandlerRunning.waitForEmpty();
|
||||||
|
await driver.quit();
|
||||||
|
|
||||||
async function useCase(name, asyncFn) {
|
fn();
|
||||||
it('Use case: ' + name, async () => {
|
|
||||||
runner.emit('use-case', {title: name});
|
|
||||||
|
|
||||||
try {
|
|
||||||
await asyncFn();
|
|
||||||
runner.emit('use-case end');
|
|
||||||
} catch (err) {
|
|
||||||
runner.emit('use-case end');
|
|
||||||
console.err(err);
|
|
||||||
throw err;
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
async function useCaseExec(name, asyncFn) {
|
||||||
|
runner.emit('use-case', {title: name});
|
||||||
|
|
||||||
|
try {
|
||||||
|
await asyncFn();
|
||||||
|
runner.emit('use-case end');
|
||||||
|
} catch (err) {
|
||||||
|
runner.emit('use-case end');
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function useCase(name, asyncFn) {
|
||||||
|
if (asyncFn) {
|
||||||
|
return test('Use case: ' + name, () => useCaseExec(name, asyncFn));
|
||||||
|
} else {
|
||||||
|
// Pending test
|
||||||
|
return test('Use case: ' + name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
useCase.only = (name, asyncFn) => {
|
||||||
|
return test.only('Use case: ' + name, () => useCaseExec(name, asyncFn));
|
||||||
|
};
|
||||||
|
|
||||||
|
useCase.skip = (name, asyncFn) => {
|
||||||
|
return test.skip('Use case: ' + name, () => useCaseExec(name, asyncFn));
|
||||||
|
};
|
||||||
|
|
||||||
async function step(name, asyncFn) {
|
async function step(name, asyncFn) {
|
||||||
try {
|
try {
|
||||||
await asyncFn();
|
await asyncFn();
|
||||||
runner.emit('step pass', {title: name});
|
runner.emit('step pass', {title: name});
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
runner.emit('step fail', {title: name});
|
runner.emit('step fail', {title: name});
|
||||||
console.err(err);
|
|
||||||
throw err;
|
throw err;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -141,5 +186,6 @@ async function step(name, asyncFn) {
|
||||||
module.exports = {
|
module.exports = {
|
||||||
mocha,
|
mocha,
|
||||||
useCase,
|
useCase,
|
||||||
step
|
step,
|
||||||
|
driver
|
||||||
};
|
};
|
35
test/e2e/helpers/semaphore.js
Normal file
35
test/e2e/helpers/semaphore.js
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
const Promise = require('bluebird');
|
||||||
|
|
||||||
|
class Semaphore {
|
||||||
|
constructor() {
|
||||||
|
this.counter = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
enter() {
|
||||||
|
this.counter++;
|
||||||
|
}
|
||||||
|
|
||||||
|
exit() {
|
||||||
|
this.counter--;
|
||||||
|
}
|
||||||
|
|
||||||
|
async waitForEmpty() {
|
||||||
|
const self = this;
|
||||||
|
|
||||||
|
function wait(resolve) {
|
||||||
|
if (self.counter == 0) {
|
||||||
|
resolve();
|
||||||
|
} else {
|
||||||
|
setTimeout(wait, 500, resolve);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Promise(resolve => {
|
||||||
|
setTimeout(wait, 500, resolve);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = Semaphore;
|
|
@ -1,13 +1,11 @@
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
require('./helpers/exit-unless-test');
|
require('./helpers/exit-unless-test');
|
||||||
const mocha = require('./helpers/mocha-e2e').mocha;
|
const { mocha, driver } = require('./helpers/mocha-e2e');
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
|
|
||||||
global.USE_SHARED_DRIVER = true;
|
global.USE_SHARED_DRIVER = true;
|
||||||
|
|
||||||
const driver = require('./helpers/driver');
|
|
||||||
|
|
||||||
const only = 'only';
|
const only = 'only';
|
||||||
const skip = 'skip';
|
const skip = 'skip';
|
||||||
|
|
||||||
|
@ -29,6 +27,5 @@ for (const testSpec of tests) {
|
||||||
}
|
}
|
||||||
|
|
||||||
mocha.run(failures => {
|
mocha.run(failures => {
|
||||||
driver.originalQuit();
|
|
||||||
process.exit(failures); // exit with non-zero status if there were failures
|
process.exit(failures); // exit with non-zero status if there were failures
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,14 +1,14 @@
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
const config = require('../helpers/config');
|
const config = require('../helpers/config');
|
||||||
|
const driver = require('../helpers/mocha-e2e').driver;
|
||||||
const page = require('./page');
|
const page = require('./page');
|
||||||
|
|
||||||
module.exports = (driver, ...extras) => page(driver, {
|
module.exports = (...extras) => page({
|
||||||
|
|
||||||
async fetchMail(address) {
|
async fetchMail(address) {
|
||||||
await this.driver.sleep(1000);
|
await driver.sleep(1000);
|
||||||
await this.driver.navigate().to(`${config.mailUrl}/${address}`);
|
await driver.navigate().to(`${config.mailUrl}/${address}`);
|
||||||
await this.waitUntilVisible();
|
await this.waitUntilVisible();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
@ -5,77 +5,84 @@ const webdriver = require('selenium-webdriver');
|
||||||
const By = webdriver.By;
|
const By = webdriver.By;
|
||||||
const until = webdriver.until;
|
const until = webdriver.until;
|
||||||
const fs = require('fs-extra');
|
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({
|
module.exports = (...extras) => Object.assign({
|
||||||
driver,
|
|
||||||
|
|
||||||
elements: {},
|
elements: {},
|
||||||
|
|
||||||
async element(key) {
|
async getElement(key) {
|
||||||
return await this.driver.findElement(By.css(this.elements[key] || 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) {
|
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';
|
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) {
|
if (this.url) {
|
||||||
await this.ensureUrl();
|
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) {
|
async click(key) {
|
||||||
const elem = await this.element(key);
|
const elem = await this.getElement(key);
|
||||||
await elem.click();
|
await elem.click();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
async getHref(key) {
|
||||||
|
const elem = await this.getElement(key);
|
||||||
|
return await elem.getAttribute('href');
|
||||||
|
},
|
||||||
|
|
||||||
async getText(key) {
|
async getText(key) {
|
||||||
const elem = await this.element(key);
|
const elem = await this.getElement(key);
|
||||||
return await elem.getText();
|
return await elem.getText();
|
||||||
},
|
},
|
||||||
|
|
||||||
async getValue(key) {
|
async getValue(key) {
|
||||||
const elem = await this.element(key);
|
const elem = await this.getElement(key);
|
||||||
return await elem.getAttribute('value');
|
return await elem.getAttribute('value');
|
||||||
},
|
},
|
||||||
|
|
||||||
async setValue(key, value) {
|
|
||||||
const elem = await this.element(key);
|
|
||||||
await elem.sendKeys(value);
|
|
||||||
},
|
|
||||||
|
|
||||||
async containsText(str) {
|
async containsText(str) {
|
||||||
return await this.driver.executeScript(`
|
return await driver.executeScript(`
|
||||||
return (document.documentElement.textContent || document.documentElement.innerText).indexOf('${str}') > -1;
|
return (document.documentElement.textContent || document.documentElement.innerText).indexOf('${str}') > -1;
|
||||||
`);
|
`);
|
||||||
},
|
},
|
||||||
|
|
||||||
async source() {
|
async getSource() {
|
||||||
return await this.driver.getPageSource();
|
return await driver.getPageSource();
|
||||||
|
},
|
||||||
|
|
||||||
|
async saveSource(destPath) {
|
||||||
|
const src = await this.getSource();
|
||||||
|
await fs.writeFile(destPath, src);
|
||||||
},
|
},
|
||||||
|
|
||||||
async takeScreenshot(destPath) {
|
async takeScreenshot(destPath) {
|
||||||
const pngData = await this.driver.takeScreenshot();
|
const pngData = await driver.takeScreenshot();
|
||||||
const buf = new Buffer(pngData, 'base64');
|
const buf = new Buffer(pngData, 'base64');
|
||||||
await fs.writeFile(destPath, buf);
|
await fs.writeFile(destPath, buf);
|
||||||
},
|
},
|
||||||
|
|
||||||
async sleep(ms) {
|
async sleep(ms) {
|
||||||
await this.driver.sleep(ms);
|
await driver.sleep(ms);
|
||||||
}
|
}
|
||||||
}, ...extras);
|
}, ...extras);
|
||||||
|
|
|
@ -4,17 +4,10 @@ const config = require('../helpers/config');
|
||||||
const webBase = require('./web');
|
const webBase = require('./web');
|
||||||
const mailBase = require('./mail');
|
const mailBase = require('./mail');
|
||||||
|
|
||||||
module.exports = (driver, list) => {
|
module.exports = list => {
|
||||||
|
|
||||||
const web = params => webBase(driver, {
|
const web = params => webBase(params);
|
||||||
async enterEmail(value) {
|
const mail = params => mailBase(params);
|
||||||
const emailInput = await this.element('emailInput');
|
|
||||||
await emailInput.clear();
|
|
||||||
await emailInput.sendKeys(value);
|
|
||||||
},
|
|
||||||
}, params);
|
|
||||||
|
|
||||||
const mail = params => mailBase(driver, params);
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
webSubscribe: web({
|
webSubscribe: web({
|
||||||
|
@ -23,6 +16,8 @@ module.exports = (driver, list) => {
|
||||||
elements: {
|
elements: {
|
||||||
form: `form[action="/subscription/${list.cid}/subscribe"]`,
|
form: `form[action="/subscription/${list.cid}/subscribe"]`,
|
||||||
emailInput: '#main-form input[name="email"]',
|
emailInput: '#main-form input[name="email"]',
|
||||||
|
firstNameInput: '#main-form input[name="first-name"]',
|
||||||
|
lastNameInput: '#main-form input[name="last-name"]',
|
||||||
submitButton: 'a[href="#submit"]'
|
submitButton: 'a[href="#submit"]'
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
|
@ -55,17 +50,40 @@ module.exports = (driver, list) => {
|
||||||
elements: {
|
elements: {
|
||||||
unsubscribeLink: `a[href^="${config.settings['service-url']}subscription/${list.cid}/unsubscribe/"]`,
|
unsubscribeLink: `a[href^="${config.settings['service-url']}subscription/${list.cid}/unsubscribe/"]`,
|
||||||
manageLink: `a[href^="${config.settings['service-url']}subscription/${list.cid}/manage/"]`
|
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
|
webUnsubscribe: web({ // FIXME
|
||||||
elementToWaitFor: 'submitButton',
|
elementToWaitFor: 'submitButton',
|
||||||
elements: {
|
elements: {
|
||||||
submitButton: 'a[href="#submit"]'
|
submitButton: 'a[href="#submit"]'
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
*/
|
|
||||||
|
|
||||||
webUnsubscribedNotice: web({
|
webUnsubscribedNotice: web({
|
||||||
url: `/subscription/${list.cid}/unsubscribed-notice`,
|
url: `/subscription/${list.cid}/unsubscribed-notice`,
|
||||||
|
@ -81,14 +99,8 @@ module.exports = (driver, list) => {
|
||||||
resubscribeLink: `a[href^="${config.settings['service-url']}subscription/${list.cid}"]`
|
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']}"]`
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
*/
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -3,13 +3,30 @@
|
||||||
const config = require('../helpers/config');
|
const config = require('../helpers/config');
|
||||||
const By = require('selenium-webdriver').By;
|
const By = require('selenium-webdriver').By;
|
||||||
const url = require('url');
|
const url = require('url');
|
||||||
|
const UrlPattern = require('url-pattern');
|
||||||
|
const driver = require('../helpers/mocha-e2e').driver;
|
||||||
const page = require('./page');
|
const page = require('./page');
|
||||||
|
|
||||||
module.exports = (driver, ...extras) => page(driver, {
|
module.exports = (...extras) => page({
|
||||||
|
|
||||||
async navigate(path) {
|
async navigate(pathOrParams) {
|
||||||
await this.driver.navigate().to(config.baseUrl + (path || this.url));
|
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();
|
await this.waitUntilVisible();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -17,28 +34,44 @@ module.exports = (driver, ...extras) => page(driver, {
|
||||||
const desiredUrl = path || this.url;
|
const desiredUrl = path || this.url;
|
||||||
|
|
||||||
if (desiredUrl) {
|
if (desiredUrl) {
|
||||||
const currentUrl = url.parse(await this.driver.getCurrentUrl());
|
const currentUrl = url.parse(await driver.getCurrentUrl());
|
||||||
if (this.url !== currentUrl.pathname || config.baseUrl !== `${currentUrl.protocol}//${currentUrl.host}`) {
|
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}`);
|
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() {
|
async waitForFlash() {
|
||||||
await this.waitUntilVisible('div.alert:not(.js-warning)');
|
await this.waitUntilVisible('div.alert:not(.js-warning)');
|
||||||
},
|
},
|
||||||
|
|
||||||
async getFlash() {
|
async flash() {
|
||||||
const elem = await this.driver.findElement(By.css('div.alert:not(.js-warning)'));
|
const elem = await driver.findElement(By.css('div.alert:not(.js-warning)'));
|
||||||
return await elem.getText();
|
return await elem.getText();
|
||||||
},
|
},
|
||||||
|
|
||||||
async clearFlash() {
|
async clearFlash() {
|
||||||
await this.driver.executeScript(`
|
await driver.executeScript(`
|
||||||
var elements = document.getElementsByClassName('alert');
|
var elements = document.getElementsByClassName('alert');
|
||||||
while(elements.length > 0){
|
while(elements.length > 0){
|
||||||
elements[0].parentNode.removeChild(elements[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);
|
}, ...extras);
|
||||||
|
|
|
@ -1,61 +1,74 @@
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
const config = require('../helpers/config');
|
const config = require('../helpers/config');
|
||||||
const { useCase, step } = require('../helpers/mocha-e2e');
|
const { useCase, step, driver } = require('../helpers/mocha-e2e');
|
||||||
const shortid = require('shortid');
|
const shortid = require('shortid');
|
||||||
const expect = require('chai').expect;
|
const expect = require('chai').expect;
|
||||||
const driver = require('../helpers/driver');
|
|
||||||
|
|
||||||
const page = require('../page-objects/subscription')(driver, config.lists.one);
|
const page = require('../page-objects/subscription')(config.lists.one);
|
||||||
|
|
||||||
function generateEmail() {
|
function generateEmail() {
|
||||||
return 'keep.' + shortid.generate() + '@mailtrain.org';
|
return 'keep.' + shortid.generate() + '@mailtrain.org';
|
||||||
}
|
}
|
||||||
|
|
||||||
async function subscribe(testUserEmail) {
|
async function subscribe(subscription) {
|
||||||
const subscription = {
|
await step('User navigates to list subscription page.', async () => {
|
||||||
email: testUserEmail
|
|
||||||
};
|
|
||||||
|
|
||||||
await step('User navigates to list subscription page', async () => {
|
|
||||||
await page.webSubscribe.navigate();
|
await page.webSubscribe.navigate();
|
||||||
});
|
});
|
||||||
|
|
||||||
await step('User submits a valid email', async () => {
|
await step('User submits a valid email and other subscription info.', async () => {
|
||||||
await page.webSubscribe.enterEmail(testUserEmail);
|
await page.webSubscribe.setValue('emailInput', subscription.email);
|
||||||
|
|
||||||
|
if (subscription.firstName) {
|
||||||
|
await page.webSubscribe.setValue('firstNameInput', subscription.firstName);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (subscription.lastName) {
|
||||||
|
await page.webSubscribe.setValue('lastNameInput', subscription.lastName);
|
||||||
|
}
|
||||||
|
|
||||||
await page.webSubscribe.submit();
|
await page.webSubscribe.submit();
|
||||||
});
|
});
|
||||||
|
|
||||||
await step('System shows a notice that further instructions are in the email', async () => {
|
await step('System shows a notice that further instructions are in the email.', async () => {
|
||||||
await page.webConfirmSubscriptionNotice.waitUntilVisible();
|
await page.webConfirmSubscriptionNotice.waitUntilVisible();
|
||||||
});
|
});
|
||||||
|
|
||||||
await step('System sends an email with a link to confirm the subscription', async () => {
|
await step('System sends an email with a link to confirm the subscription.', async () => {
|
||||||
await page.mailConfirmSubscription.fetchMail(testUserEmail);
|
await page.mailConfirmSubscription.fetchMail(subscription.email);
|
||||||
});
|
});
|
||||||
|
|
||||||
await step('User clicks confirm subscription in the email', async () => {
|
await step('User clicks confirm subscription in the email', async () => {
|
||||||
await page.mailConfirmSubscription.click('confirmLink');
|
await page.mailConfirmSubscription.click('confirmLink');
|
||||||
});
|
});
|
||||||
|
|
||||||
await step('System shows a notice that subscription has been confirmed', async () => {
|
await step('System shows a notice that subscription has been confirmed.', async () => {
|
||||||
await page.webSubscribedNotice.waitUntilVisible();
|
await page.webSubscribedNotice.waitUntilVisible();
|
||||||
});
|
});
|
||||||
|
|
||||||
await step('System sends an email with subscription confirmation', async () => {
|
await step('System sends an email with subscription confirmation.', async () => {
|
||||||
await page.mailSubscriptionConfirmed.fetchMail(testUserEmail);
|
await page.mailSubscriptionConfirmed.fetchMail(subscription.email);
|
||||||
subscription.unsubscribeLink = await page.mailSubscriptionConfirmed.link('unsubscribeLink');
|
subscription.unsubscribeLink = await page.mailSubscriptionConfirmed.getHref('unsubscribeLink');
|
||||||
subscription.manageLink = await page.mailSubscriptionConfirmed.link('manageLink');
|
subscription.manageLink = await page.mailSubscriptionConfirmed.getHref('manageLink');
|
||||||
|
|
||||||
|
const unsubscribeParams = await page.mailSubscriptionConfirmed.getLinkParams('unsubscribeLink');
|
||||||
|
const manageParams = await page.mailSubscriptionConfirmed.getLinkParams('manageLink');
|
||||||
|
console.log(unsubscribeParams);
|
||||||
|
console.log(manageParams);
|
||||||
|
expect(unsubscribeParams.ucid).to.equal(manageParams.ucid);
|
||||||
|
subscription.ucid = unsubscribeParams.ucid;
|
||||||
});
|
});
|
||||||
|
|
||||||
return subscription;
|
return subscription;
|
||||||
}
|
}
|
||||||
|
|
||||||
describe('Subscription use-cases', function() {
|
suite('Subscription use-cases', function() {
|
||||||
before(() => driver.manage().deleteAllCookies());
|
before(() => driver.manage().deleteAllCookies());
|
||||||
|
|
||||||
useCase('Subscription to a public list (main scenario)', async () => {
|
useCase('Subscription to a public list (main scenario)', async () => {
|
||||||
await subscribe(generateEmail());
|
await subscribe({
|
||||||
|
email: generateEmail()
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
useCase('Subscription to a public list (invalid email)', async () => {
|
useCase('Subscription to a public list (invalid email)', async () => {
|
||||||
|
@ -63,44 +76,75 @@ describe('Subscription use-cases', function() {
|
||||||
await page.webSubscribe.navigate();
|
await page.webSubscribe.navigate();
|
||||||
});
|
});
|
||||||
|
|
||||||
await step('User submits an invalid email', async () => {
|
await step('User submits an invalid email.', async () => {
|
||||||
await page.webSubscribe.enterEmail('foo@bar.nope');
|
await page.webSubscribe.setValue('emailInput', 'foo@bar.nope');
|
||||||
await page.webSubscribe.submit();
|
await page.webSubscribe.submit();
|
||||||
});
|
});
|
||||||
|
|
||||||
await step('System shows a flash notice that email is invalid', async () => {
|
await step('System shows a flash notice that email is invalid.', async () => {
|
||||||
await page.webSubscribe.waitForFlash();
|
await page.webSubscribe.waitForFlash();
|
||||||
expect(await page.webSubscribe.getFlash()).to.contain('Invalid email address');
|
expect(await page.webSubscribe.getFlash()).to.contain('Invalid email address');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
useCase('Unsubscription from list #1 (one-step, no form)', async () => {
|
useCase('Unsubscription from list #1 (one-step, no form).', async () => {
|
||||||
const subscription = await subscribe(generateEmail());
|
const subscription = await subscribe({
|
||||||
|
email: generateEmail()
|
||||||
|
});
|
||||||
|
|
||||||
await step('User clicks the unsubscribe button', async () => {
|
await step('User clicks the unsubscribe button.', async () => {
|
||||||
await page.mailSubscriptionConfirmed.click('unsubscribeLink');
|
await page.mailSubscriptionConfirmed.click('unsubscribeLink');
|
||||||
});
|
});
|
||||||
|
|
||||||
await step('System show a notice that confirms unsubscription', async () => {
|
await step('System show a notice that confirms unsubscription.', async () => {
|
||||||
await page.webUnsubscribedNotice.waitUntilVisible();
|
await page.webUnsubscribedNotice.waitUntilVisible();
|
||||||
});
|
});
|
||||||
|
|
||||||
await step('System sends an email that confirms unsubscription', async () => {
|
await step('System sends an email that confirms unsubscription.', async () => {
|
||||||
await page.mailUnsubscriptionConfirmed.fetchMail(subscription.email);
|
await page.mailUnsubscriptionConfirmed.fetchMail(subscription.email);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
/*
|
|
||||||
useCase('Change email in list #1 (one-step, no form)', async () => {
|
|
||||||
const subscription = await subscribe(generateEmail());
|
|
||||||
|
|
||||||
await step('User clicks the manage subscription button', async () => {
|
useCase.only('Change email in list #1 (one-step, no form)', async () => {
|
||||||
|
const subscription = await subscribe({
|
||||||
|
email: generateEmail(),
|
||||||
|
firstName: 'John',
|
||||||
|
lastName: 'Doe'
|
||||||
|
});
|
||||||
|
|
||||||
|
await step('User clicks the manage subscription button.', async () => {
|
||||||
await page.mailSubscriptionConfirmed.click('manageLink');
|
await page.mailSubscriptionConfirmed.click('manageLink');
|
||||||
});
|
});
|
||||||
|
|
||||||
await step('System show a notice that confirms unsubscription', async () => {
|
await step('Systems shows a form to change subscription details. The form contains data entered during subscription.', async () => {
|
||||||
await page.webManage.waitUntilVisible();
|
await page.webManage.waitUntilVisible();
|
||||||
|
expect(await page.webManage.getValue('emailInput')).to.equal(subscription.email);
|
||||||
|
expect(await page.webManage.getValue('firstNameInput')).to.equal(subscription.firstName);
|
||||||
|
expect(await page.webManage.getValue('lastNameInput')).to.equal(subscription.lastName);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
await step('User enters another name and submits the form.', async () => {
|
||||||
|
subscription.firstName = 'Adam';
|
||||||
|
subscription.lastName = 'B';
|
||||||
|
await page.webManage.setValue('firstNameInput', subscription.firstName);
|
||||||
|
await page.webManage.setValue('lastNameInput', subscription.lastName);
|
||||||
|
await page.webManage.submit();
|
||||||
|
});
|
||||||
|
|
||||||
|
await step('Systems shows a notice that profile has been updated.', async () => {
|
||||||
|
await page.webUpdatedNotice.waitUntilVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
await step('User navigates to manage subscription again.', async () => {
|
||||||
|
await page.webManage.navigate(subscription.manageLink);
|
||||||
|
// await page.webManage.navigate({ ucid: subscription.ucid });
|
||||||
|
});
|
||||||
|
|
||||||
|
await step('Systems shows a form with the changes made previously.', async () => {
|
||||||
|
expect(await page.webManage.getValue('emailInput')).to.equal(subscription.email);
|
||||||
|
expect(await page.webManage.getValue('firstNameInput')).to.equal(subscription.firstName);
|
||||||
|
expect(await page.webManage.getValue('lastNameInput')).to.equal(subscription.lastName);
|
||||||
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
*/
|
|
||||||
after(() => driver.quit());
|
|
||||||
});
|
});
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue