Last active
December 17, 2018 21:52
-
-
Save rhythnic/fb6d4f0f5ec0d9c1266e827f145a62f6 to your computer and use it in GitHub Desktop.
Helpers for composing Selenium tests into functional pipelines.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Usage with Jest | |
// | |
// const loginForm = [ | |
// { | |
// selector: '#login_username', | |
// property: 'username' | |
// }, | |
// { | |
// selector: '#login_password', | |
// property: 'password' | |
// } | |
// ] | |
// const user = { | |
// username: 'admin', | |
// password: 'password' | |
// } | |
// | |
// test('User can login', () => seq( | |
// ctx => ctx.driver.get(LOGIN_URL).then(() => {}), | |
// fillForm(loginForm, user), | |
// click('button[type="submit"]') | |
// )({ driver, timeout: 2000 })) | |
const { until, By } = require('selenium-webdriver') | |
const { curry, merge } = require('ramda') | |
function normalizeArg (x, ctx) { | |
return typeof x === 'function' ? x(ctx) : x | |
} | |
function normalizeSelector (x, ctx) { | |
return typeof x === 'string' ? By.css(x) : x | |
} | |
const seq = (...fns) => async function seq (ctx) { | |
for (let i = 0; i < fns.length; i++) { | |
ctx = merge(ctx, await fns[i](ctx)) | |
} | |
return ctx | |
} | |
const tap = fn => async ctx => { | |
await fn(ctx) | |
return null | |
} | |
const sleep = ms => async ctx => { | |
await ctx.driver.sleep(ms) | |
return null | |
} | |
const getElement = curry(async function getElement (selector, ctx) { | |
selector = normalizeArg(selector, ctx) | |
const element = await ctx.driver.wait( | |
until.elementLocated(normalizeSelector(selector)), | |
ctx.timeout | |
) | |
await ctx.driver.wait(until.elementIsVisible(element), ctx.timeout) | |
return { selector, element } | |
}) | |
const click = selector => async function click (ctx) { | |
if (selector) { | |
ctx = await getElement(selector, ctx) | |
} | |
await ctx.element.click() | |
return ctx | |
} | |
const getText = (selector, prop = 'text') => async function getText (ctx) { | |
if (selector) { | |
ctx = await getElement(selector, ctx) | |
} | |
ctx[prop] = await ctx.element.getText() | |
return ctx | |
} | |
const sendKeys = (selector, text) => async function sendKeys (ctx) { | |
text = normalizeArg(text, ctx) | |
if (selector) { | |
ctx = await getElement(selector, ctx) | |
} | |
await ctx.element.sendKeys(text) | |
return ctx | |
} | |
const fillForm = curry(async function fillForm (fields, data, ctx) { | |
for (let i = 0; i < fields.length; i++) { | |
let { selector, property, type } = fields[i] | |
if (selector.includes('{{value}}')) { | |
selector = selector.replace('{{value}}', data[property]) | |
} | |
let { element } = await getElement(selector, ctx) | |
switch ((type || '').toLowerCase()) { | |
case 'select': | |
await element.click() | |
break | |
default: | |
await element.sendKeys(data[property]) | |
} | |
} | |
return | |
}) | |
module.exports = { | |
seq, | |
tap, | |
sleep, | |
getElement, | |
getText, | |
sendKeys, | |
click, | |
fillForm | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment