Using object composition instead of class inheritance for page objects

This commit is contained in:
witzig 2017-05-10 16:18:35 +02:00
parent f106cd2850
commit c3e9781dc4
6 changed files with 60 additions and 80 deletions

View file

@ -1,11 +1,15 @@
'use strict'; 'use strict';
const Page = require('./page'); const page = require('./page');
class Flash extends Page { module.exports = driver => Object.assign(page(driver), {
elementToWaitFor: 'alert',
elements: {
alert: 'div.alert:not(.js-warning)'
},
getText() { getText() {
return this.element('alert').getText(); return this.element('alert').getText();
} },
clear() { clear() {
return this.driver.executeScript(` return this.driver.executeScript(`
var elements = document.getElementsByClassName('alert'); var elements = document.getElementsByClassName('alert');
@ -14,11 +18,4 @@ class Flash extends Page {
} }
`); `);
} }
}
module.exports = driver => new Flash(driver, {
elementToWaitFor: 'alert',
elements: {
alert: 'div.alert:not(.js-warning)'
}
}); });

View file

@ -1,8 +1,8 @@
'use strict'; 'use strict';
const Page = require('./page'); const page = require('./page');
module.exports = driver => new Page(driver, { module.exports = driver => Object.assign(page(driver), {
url: '/', url: '/',
elementToWaitFor: 'body', elementToWaitFor: 'body',
elements: { elements: {

View file

@ -5,50 +5,47 @@ const webdriver = require('selenium-webdriver');
const By = webdriver.By; const By = webdriver.By;
const until = webdriver.until; const until = webdriver.until;
class Page { module.exports = driver => ({
constructor(driver, props) { driver,
this.driver = driver; url: '/',
this.props = props || { elements: {},
elements: {}
};
}
element(key) { element(key) {
return this.driver.findElement(By.css(this.props.elements[key] || key)); return this.driver.findElement(By.css(this.elements[key] || key));
} },
navigate() { navigate() {
this.driver.navigate().to(config.baseUrl + this.props.url); this.driver.navigate().to(config.baseUrl + this.url);
return this.waitUntilVisible(); return this.waitUntilVisible();
} },
waitUntilVisible() { waitUntilVisible() {
let selector = this.props.elements[this.props.elementToWaitFor]; let selector = this.elements[this.elementToWaitFor];
if (!selector && this.props.url) { if (!selector && this.url) {
selector = 'body.page--' + (this.props.url.substring(1).replace(/\//g, '--') || 'home'); selector = 'body.page--' + (this.url.substring(1).replace(/\//g, '--') || 'home');
} }
return selector ? this.driver.wait(until.elementLocated(By.css(selector))) : this.driver.sleep(1000); return selector ? this.driver.wait(until.elementLocated(By.css(selector))) : this.driver.sleep(1000);
} },
submit() { submit() {
return this.element('submitButton').click(); return this.element('submitButton').click();
} },
click(key) { click(key) {
return this.element(key).click(); return this.element(key).click();
} },
getText(key) { getText(key) {
return this.element(key).getText(); return this.element(key).getText();
} },
getValue(key) { getValue(key) {
return this.element(key).getAttribute('value'); return this.element(key).getAttribute('value');
} },
setValue(key, value) { setValue(key, value) {
return this.element(key).sendKeys(value); return this.element(key).sendKeys(value);
} },
containsText(str) { containsText(str) {
// let text = await driver.findElement({ css: 'body' }).getText(); // let text = await driver.findElement({ css: 'body' }).getText();
@ -56,6 +53,4 @@ class Page {
return (document.documentElement.textContent || document.documentElement.innerText).indexOf('${str}') > -1; return (document.documentElement.textContent || document.documentElement.innerText).indexOf('${str}') > -1;
`); `);
} }
} });
module.exports = Page;

View file

@ -1,45 +1,36 @@
'use strict'; 'use strict';
const config = require('../helpers/config'); const config = require('../helpers/config');
const Page = require('./page'); const page = require('./page');
class Web extends Page { const web = {
enterEmail(value) { enterEmail(value) {
this.element('emailInput').clear(); this.element('emailInput').clear();
return this.element('emailInput').sendKeys(value); return this.element('emailInput').sendKeys(value);
} }
} };
class Mail extends Page { const mail = {
navigate(address) { navigate(address) {
this.driver.sleep(100); this.driver.sleep(100);
this.driver.navigate().to(`http://localhost:${config.app.testserver.mailboxserverport}/${address}`); this.driver.navigate().to(`http://localhost:${config.app.testserver.mailboxserverport}/${address}`);
return this.waitUntilVisible(); return this.waitUntilVisible();
} }
} };
class WebSubscribe extends Web {
constructor(driver, list) {
super(driver, {
url: `/subscription/${list.cid}`,
elementToWaitFor: 'form',
elements: {
form: `form[action="/subscription/${list.cid}/subscribe"]`,
emailInput: '#main-form input[name="email"]',
submitButton: 'a[href="#submit"]'
}
});
}
foo() {
// ...
}
}
module.exports = (driver, list) => ({ module.exports = (driver, list) => ({
webSubscribe: new WebSubscribe(driver, list), webSubscribe: Object.assign(page(driver), web, {
url: `/subscription/${list.cid}`,
elementToWaitFor: 'form',
elements: {
form: `form[action="/subscription/${list.cid}/subscribe"]`,
emailInput: '#main-form input[name="email"]',
submitButton: 'a[href="#submit"]'
}
}),
webConfirmSubscriptionNotice: new Web(driver, { webConfirmSubscriptionNotice: Object.assign(page(driver), web, {
url: `/subscription/${list.cid}/confirm-notice`, url: `/subscription/${list.cid}/confirm-notice`,
elementToWaitFor: 'homepageButton', elementToWaitFor: 'homepageButton',
elements: { elements: {
@ -47,21 +38,21 @@ module.exports = (driver, list) => ({
} }
}), }),
mailConfirmSubscription: new Mail(driver, { mailConfirmSubscription: Object.assign(page(driver), mail, {
elementToWaitFor: 'confirmLink', elementToWaitFor: 'confirmLink',
elements: { elements: {
confirmLink: `a[href^="${config.settings['service-url']}subscription/subscribe/"]` confirmLink: `a[href^="${config.settings['service-url']}subscription/subscribe/"]`
} }
}), }),
webSubscribedNotice: new Web(driver, { webSubscribedNotice: Object.assign(page(driver), web, {
elementToWaitFor: 'homepageButton', elementToWaitFor: 'homepageButton',
elements: { elements: {
homepageButton: 'a[href^="https://mailtrain.org"]' homepageButton: 'a[href^="https://mailtrain.org"]'
} }
}), }),
mailSubscriptionConfirmed: new Mail(driver, { mailSubscriptionConfirmed: Object.assign(page(driver), mail, {
elementToWaitFor: 'unsubscribeLink', elementToWaitFor: 'unsubscribeLink',
elements: { elements: {
unsubscribeLink: 'a[href*="/unsubscribe/"]', unsubscribeLink: 'a[href*="/unsubscribe/"]',
@ -69,21 +60,21 @@ module.exports = (driver, list) => ({
} }
}), }),
webUnsubscribe: new Web(driver, { webUnsubscribe: Object.assign(page(driver), web, {
elementToWaitFor: 'submitButton', elementToWaitFor: 'submitButton',
elements: { elements: {
submitButton: 'a[href="#submit"]' submitButton: 'a[href="#submit"]'
} }
}), }),
webUnsubscribedNotice: new Web(driver, { webUnsubscribedNotice: Object.assign(page(driver), web, {
elementToWaitFor: 'homepageButton', elementToWaitFor: 'homepageButton',
elements: { elements: {
homepageButton: 'a[href^="https://mailtrain.org"]' homepageButton: 'a[href^="https://mailtrain.org"]'
} }
}), }),
mailUnsubscriptionConfirmed: new Mail(driver, { mailUnsubscriptionConfirmed: Object.assign(page(driver), mail, {
elementToWaitFor: 'resubscribeLink', elementToWaitFor: 'resubscribeLink',
elements: { elements: {
resubscribeLink: `a[href^="${config.settings['service-url']}subscription/${list.cid}"]` resubscribeLink: `a[href^="${config.settings['service-url']}subscription/${list.cid}"]`

View file

@ -1,30 +1,27 @@
'use strict'; 'use strict';
const Page = require('./page'); const page = require('./page');
class Login extends Page {
enterUsername(value) {
// this.element('usernameInput').clear();
return this.element('usernameInput').sendKeys(value);
}
enterPassword(value) {
return this.element('passwordInput').sendKeys(value);
}
}
module.exports = driver => ({ module.exports = driver => ({
login: new Login(driver, { login: Object.assign(page(driver), {
url: '/users/login', url: '/users/login',
elementToWaitFor: 'submitButton', elementToWaitFor: 'submitButton',
elements: { elements: {
usernameInput: 'form[action="/users/login"] input[name="username"]', usernameInput: 'form[action="/users/login"] input[name="username"]',
passwordInput: 'form[action="/users/login"] input[name="password"]', passwordInput: 'form[action="/users/login"] input[name="password"]',
submitButton: 'form[action="/users/login"] [type=submit]' submitButton: 'form[action="/users/login"] [type=submit]'
},
enterUsername(value) {
// this.element('usernameInput').clear();
return this.element('usernameInput').sendKeys(value);
},
enterPassword(value) {
return this.element('passwordInput').sendKeys(value);
} }
}), }),
account: new Page(driver, { account: Object.assign(page(driver), {
url: '/users/account', url: '/users/account',
elementToWaitFor: 'emailInput', elementToWaitFor: 'emailInput',
elements: { elements: {

View file

@ -4,10 +4,10 @@ const config = require('../helpers/config');
const shortid = require('shortid'); const shortid = require('shortid');
const expect = require('chai').expect; const expect = require('chai').expect;
const driver = require('../helpers/driver'); const driver = require('../helpers/driver');
const Page = require('../page-objects/page');
const page = new Page(driver); const page = require('../page-objects/page')(driver);
const flash = require('../page-objects/flash')(driver); const flash = require('../page-objects/flash')(driver);
const { const {
webSubscribe, webSubscribe,
webConfirmSubscriptionNotice, webConfirmSubscriptionNotice,