Comparing version 0.0.2 to 0.0.3
{ | ||
"name": "taiko", | ||
"version": "0.0.2", | ||
"version": "0.0.3", | ||
"description": "An easy to use wrapper over Google Chrome's Puppeteer library.", | ||
"main": "taiko.js", | ||
"scripts": {}, | ||
"bin": { | ||
"taiko": "repl.js" | ||
}, | ||
"scripts": { | ||
"format": "./node_modules/.bin/js-beautify *.js -r -b collapse,preserve-inline && npm run lint", | ||
"lint": "./node_modules/.bin/eslint *.js", | ||
"test": "npm run lint" | ||
}, | ||
"repository": { | ||
@@ -19,4 +26,11 @@ "type": "git", | ||
"dependencies": { | ||
"puppeteer": "^0.12.0" | ||
"puppeteer": "^0.12.0", | ||
"babylon": "^6.18.0", | ||
"recast": "^0.12.8", | ||
"repl.history": "^0.1.4" | ||
}, | ||
"devDependencies": { | ||
"eslint": "^4.10.0", | ||
"js-beautify": "^1.7.4" | ||
} | ||
} |
269
taiko.js
@@ -5,18 +5,35 @@ const puppeteer = require('puppeteer'); | ||
const browser = () => b; | ||
const browser = () => { | ||
validate(); | ||
return b; | ||
}; | ||
const page = () => p; | ||
const page = () => { | ||
validate(); | ||
return p; | ||
}; | ||
const openBrowser = async(options) => { | ||
const openBrowser = async (options) => { | ||
b = await puppeteer.launch(options); | ||
p = await b.newPage(); | ||
} | ||
}; | ||
const closeBrowser = async(options) => b.close(); | ||
const closeBrowser = async () => { | ||
validate(); | ||
await b.close(); | ||
b, p = null; | ||
}; | ||
const goto = async(url, options) => p.goto(url, options); | ||
const goto = async (url, options) => { | ||
validate(); | ||
await p.goto(url, options); | ||
}; | ||
const reload = async(options) => p.reload(options); | ||
const reload = async (options) => { | ||
validate(); | ||
await p.reload(options); | ||
}; | ||
const click = async(selector, waitForNavigation = true, options = {}) => { | ||
const click = async (selector, waitForNavigation = true, options = {}) => { | ||
validate(); | ||
const e = await element(selector); | ||
@@ -26,111 +43,137 @@ await e.click(options); | ||
if (waitForNavigation) await p.waitForNavigation(); | ||
} | ||
}; | ||
const doubleClick = async(selector, waitForNavigation = true, options = {}) => { | ||
const doubleClick = async (selector, waitForNavigation = true, options = {}) => { | ||
validate(); | ||
await click(selector, waitForNavigation, Object.assign({ clickCount: 2, }, options)); | ||
} | ||
}; | ||
const rightClick = async(selector, waitForNavigation = true, options = {}) => { | ||
const rightClick = async (selector, waitForNavigation = true, options = {}) => { | ||
validate(); | ||
await click(selector, waitForNavigation, Object.assign({ button: 'right', }, options)); | ||
} | ||
}; | ||
const hover = async(selector) => { | ||
const hover = async (selector) => { | ||
validate(); | ||
const e = await element(selector); | ||
await e.hover(); | ||
await e.dispose(); | ||
} | ||
}; | ||
const focus = async(selector) => await (await _focus(selector)).dispose(); | ||
const focus = async (selector) => { | ||
validate(); | ||
await (await _focus(selector)).dispose(); | ||
}; | ||
const write = async(text, into) => { | ||
const e = await _focus(into); | ||
const write = async (text, into) => { | ||
validate(); | ||
const e = await _focus(isString(into) ? textField(into) : into); | ||
await e.type(text); | ||
await e.dispose(); | ||
} | ||
}; | ||
const upload = async(filepath, to) => { | ||
const upload = async (filepath, to) => { | ||
validate(); | ||
let e; | ||
if (isString(to)) e = await $xpath(`//input[@type='file'][@id=(//label[contains(text(),'${to}')]/@for)]`); | ||
else if (isSelector(to)) e = await to.get(); | ||
else throw Error("Invalid element passed as paramenter"); | ||
else throw Error('Invalid element passed as paramenter'); | ||
await e.uploadFile(filepath); | ||
await e.dispose(); | ||
} | ||
}; | ||
const press = async(key, options) => p.keyboard.press(key); | ||
const press = async (key, options) => { | ||
validate(); | ||
await p.keyboard.press(key, options); | ||
}; | ||
const highlight = async(selector) => evaluate(selector, e => e.style.border = '0.5em solid red'); | ||
const highlight = async (selector) => { | ||
validate(); | ||
await evaluate(selector, e => e.style.border = '0.5em solid red'); | ||
}; | ||
const scrollTo = async(selector) => evaluate(selector, e => e.scrollIntoViewIfNeeded()); | ||
const scrollTo = async (selector) => { | ||
validate(); | ||
await evaluate(selector, e => e.scrollIntoViewIfNeeded()); | ||
}; | ||
const scrollRight = async(selector, px = 100) => { | ||
await (Number.isInteger(selector) ? p.evaluate(px => window.scrollBy(px, 0), px) : | ||
evaluate(selector, (e, px) => e.scrollLeft += px, px)); | ||
} | ||
const scrollRight = async (e, px = 100) => { | ||
validate(); | ||
await scroll(e, px, px => window.scrollBy(px, 0), (e, px) => e.scrollLeft += px); | ||
}; | ||
const scrollLeft = async(selector, px = 100) => { | ||
await (Number.isInteger(selector) ? p.evaluate(px => window.scrollBy(px * -1, 0), px) : | ||
evaluate(selector, (e, px) => e.scrollLeft -= px, px)); | ||
} | ||
const scrollLeft = async (e, px = 100) => { | ||
validate(); | ||
await scroll(e, px, px => window.scrollBy(px * -1, 0), (e, px) => e.scrollLeft -= px); | ||
}; | ||
const scrollUp = async(selector, px = 100) => { | ||
await (Number.isInteger(selector) ? p.evaluate(px => window.scrollBy(0, px * -1), px) : | ||
evaluate(selector, (e, px) => e.scrollTop -= px, px)); | ||
} | ||
const scrollUp = async (e, px = 100) => { | ||
validate(); | ||
await scroll(e, px, px => window.scrollBy(0, px * -1), (e, px) => e.scrollTop -= px); | ||
}; | ||
const scrollDown = async(selector, px = 100) => { | ||
await (Number.isInteger(selector) ? p.evaluate(px => window.scrollBy(0, px), px) : | ||
evaluate(selector, (e, px) => e.scrollTop += px, px)); | ||
} | ||
const scrollDown = async (e, px = 100) => { | ||
validate(); | ||
await scroll(e, px, px => window.scrollBy(0, px), (e, px) => e.scrollTop += px); | ||
}; | ||
const $ = (selector) => { | ||
const get = async() => selector.startsWith('//') ? $xpath(selector) : p.$(selector); | ||
validate(); | ||
const get = async () => selector.startsWith('//') ? $xpath(selector) : p.$(selector); | ||
return { get: get, exists: exists(get), }; | ||
} | ||
}; | ||
const $$ = (selector) => { | ||
const get = async() => selector.startsWith('//') ? $$xpath(selector) : p.$$(selector); | ||
return { get: get, exists: async() => (await get()).length > 0, }; | ||
} | ||
validate(); | ||
const get = async () => selector.startsWith('//') ? $$xpath(selector) : p.$$(selector); | ||
return { get: get, exists: async () => (await get()).length > 0, }; | ||
}; | ||
const image = (selector) => { | ||
validate(); | ||
assertType(selector); | ||
const get = async() => p.$(`img[alt='${selector}']`); | ||
const get = async () => p.$(`img[alt='${selector}']`); | ||
return { get: get, exists: exists(get), }; | ||
} | ||
}; | ||
const link = (selector) => { | ||
const get = async() => getElementByTag(selector, 'a'); | ||
validate(); | ||
const get = async () => getElementByTag(selector, 'a'); | ||
return { get: get, exists: exists(get), }; | ||
} | ||
}; | ||
const listItem = (selector) => { | ||
const get = async() => getElementByTag(selector, 'li'); | ||
validate(); | ||
const get = async () => getElementByTag(selector, 'li'); | ||
return { get: get, exists: exists(get), }; | ||
} | ||
}; | ||
const button = (selector) => { | ||
const get = async() => getElementByTag(selector, 'button'); | ||
validate(); | ||
const get = async () => getElementByTag(selector, 'button'); | ||
return { get: get, exists: exists(get), }; | ||
} | ||
}; | ||
const inputField = (attribute, selector) => { | ||
validate(); | ||
assertType(selector); | ||
const get = async() => p.$(`input[${attribute}='${selector}']`); | ||
return { get: get, exists: exists(get), value: async() => p.evaluate(e => e.value, await get()), } | ||
} | ||
const get = async () => p.$(`input[${attribute}='${selector}']`); | ||
return { get: get, exists: exists(get), value: async () => p.evaluate(e => e.value, await get()), }; | ||
}; | ||
const textField = (selector) => { | ||
validate(); | ||
assertType(selector); | ||
const get = async() => $xpath(`//input[@type='text'][@id=(//label[contains(text(),'${selector}')]/@for)]`); | ||
return { get: get, exists: exists(get), value: async() => p.evaluate(e => e.value, await get()), } | ||
} | ||
const get = async () => $xpath(`//input[@type='text'][@id=(//label[contains(text(),'${selector}')]/@for)]`); | ||
return { get: get, exists: exists(get), value: async () => p.evaluate(e => e.value, await get()), }; | ||
}; | ||
const comboBox = (selector) => { | ||
validate(); | ||
assertType(selector); | ||
const get = async() => $xpath(`//select[@id=(//label[contains(text(),'${selector}')]/@for)]`); | ||
const get = async () => $xpath(`//select[@id=(//label[contains(text(),'${selector}')]/@for)]`); | ||
return { | ||
get: get, | ||
exists: exists(get), | ||
select: async(value) => { | ||
select: async (value) => { | ||
const box = await get(); | ||
@@ -140,27 +183,29 @@ if (!box) throw new Error('Combo Box not found'); | ||
Array.from(box.options).filter(o => o.text === value).forEach(o => o.selected = true); | ||
}, box, value) | ||
}, box, value); | ||
}, | ||
value: async() => p.evaluate(e => e.value, await get()) | ||
} | ||
} | ||
value: async () => p.evaluate(e => e.value, await get()) | ||
}; | ||
}; | ||
const checkBox = (selector) => { | ||
validate(); | ||
assertType(selector); | ||
const get = async() => $xpath(`//input[@type='checkbox'][@id=(//label[contains(text(),'${selector}')]/@for)]`); | ||
const get = async () => $xpath(`//input[@type='checkbox'][@id=(//label[contains(text(),'${selector}')]/@for)]`); | ||
return { | ||
get: get, | ||
exists: exists(get), | ||
isChecked: async() => p.evaluate(e => e.checked, await get()) | ||
} | ||
} | ||
isChecked: async () => p.evaluate(e => e.checked, await get()) | ||
}; | ||
}; | ||
const radioButton = (selector) => { | ||
validate(); | ||
assertType(selector); | ||
const get = async() => $xpath(`//input[@type='radio'][@id=(//label[contains(text(),'${selector}')]/@for)]`); | ||
const get = async () => $xpath(`//input[@type='radio'][@id=(//label[contains(text(),'${selector}')]/@for)]`); | ||
return { | ||
get: get, | ||
exists: exists(get), | ||
isSelected: async() => p.evaluate(e => e.checked, await get()) | ||
} | ||
} | ||
isSelected: async () => p.evaluate(e => e.checked, await get()) | ||
}; | ||
}; | ||
@@ -176,14 +221,16 @@ const alert = (message, callback) => dialog('alert', message, callback); | ||
const text = (text) => { | ||
validate(); | ||
assertType(text); | ||
const get = async(e = '*') => $xpath('//' + e + `[text()='${text}']`); | ||
const get = async (e = '*') => $xpath('//' + e + `[text()='${text}']`); | ||
return { get: get, exists: exists(get), }; | ||
} | ||
}; | ||
const contains = (text) => { | ||
validate(); | ||
assertType(text); | ||
const get = async(e = '*') => $xpath('//' + e + `[contains(text(),'${text}')]`); | ||
const get = async (e = '*') => $xpath('//' + e + `[contains(text(),'${text}')]`); | ||
return { get: get, exists: exists(get), }; | ||
} | ||
}; | ||
const element = async(selector) => { | ||
const element = async (selector) => { | ||
const e = await (() => { | ||
@@ -194,19 +241,25 @@ if (isString(selector)) return contains(selector).get(); | ||
})(); | ||
if (!e) throw new Error("Element not found"); | ||
if (!e) throw new Error('Element not found'); | ||
return e; | ||
} | ||
}; | ||
const getElementByTag = async(selector, tag) => { | ||
const getElementByTag = async (selector, tag) => { | ||
if (isString(selector)) return contains(selector).get(tag); | ||
else if (isSelector(selector)) return selector.get(tag); | ||
return null; | ||
} | ||
}; | ||
const _focus = async(selector) => { | ||
const _focus = async (selector) => { | ||
const e = await element(selector); | ||
await p.evaluate(e => e.focus(), e); | ||
return e; | ||
} | ||
}; | ||
const scroll = async (e, px, scrollPage, scrollElement) => { | ||
e = e || 100; | ||
await (Number.isInteger(e) ? p.evaluate(scrollPage, e) : evaluate(e, scrollElement, px)); | ||
}; | ||
const dialog = (type, message, callback) => { | ||
validate(); | ||
p.on('dialog', async dialog => { | ||
@@ -216,5 +269,5 @@ if (dialog.type === type && dialog.message() === message) | ||
}); | ||
} | ||
}; | ||
const screenshot = async(options) => p.screenshot(options); | ||
const screenshot = async (options) => p.screenshot(options); | ||
@@ -225,13 +278,16 @@ const isString = (obj) => typeof obj === 'string' || obj instanceof String; | ||
const $xpath = async(selector) => { | ||
const $xpath = async (selector) => { | ||
const result = await $$xpath(selector); | ||
return result.length > 0 ? result[0] : null; | ||
} | ||
}; | ||
const $$xpath = async(selector) => { | ||
const $$xpath = async (selector) => { | ||
const arrayHandle = await p.mainFrame()._context.evaluateHandle(selector => { | ||
let node, results = []; | ||
let result = document.evaluate(selector, document, null, XPathResult.ANY_TYPE, null); | ||
while (node = result.iterateNext()) | ||
let result = document.evaluate(selector, document, null, XPathResult.ANY_TYPE, null), | ||
node = result.iterateNext(), | ||
results = []; | ||
while (node) { | ||
results.push(node); | ||
node = result.iterateNext(); | ||
} | ||
return results; | ||
@@ -247,7 +303,11 @@ }, selector); | ||
return result; | ||
} | ||
}; | ||
const validate = () => { | ||
if (!b || !p) throw new Error('Browser or Page not initialized. Call openBrowser() before using this API.'); | ||
}; | ||
const assertType = (obj, condition = isString, message = 'String parameter expected') => { | ||
if (!condition(obj)) throw new Error(message); | ||
} | ||
}; | ||
@@ -258,8 +318,8 @@ const sleep = (milliseconds) => { | ||
if ((new Date().getTime() - start) > milliseconds) break; | ||
} | ||
}; | ||
const exists = (get) => { | ||
return async(intervalTime = 1000, timeout = 10000) => { | ||
return async (intervalTime = 1000, timeout = 10000) => { | ||
try { | ||
await waitUntil(async() => (await get()) != null, intervalTime, timeout); | ||
await waitUntil(async () => (await get()) != null, intervalTime, timeout); | ||
return true; | ||
@@ -269,6 +329,6 @@ } catch (e) { | ||
} | ||
} | ||
}; | ||
}; | ||
const waitUntil = async(condition, intervalTime, timeout) => { | ||
const waitUntil = async (condition, intervalTime, timeout) => { | ||
var start = new Date().getTime(); | ||
@@ -283,9 +343,9 @@ while (true) { | ||
} | ||
} | ||
}; | ||
const evaluate = async(selector, callback, ...args) => { | ||
const evaluate = async (selector, callback, ...args) => { | ||
const e = await element(selector); | ||
await p.evaluate(callback, e, ...args); | ||
await e.dispose(); | ||
} | ||
}; | ||
@@ -323,2 +383,3 @@ module.exports = { | ||
highlight, | ||
focus, | ||
scrollTo, | ||
@@ -336,2 +397,2 @@ scrollRight, | ||
into: e => e, | ||
} | ||
}; |
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Debug access
Supply chain riskUses debug, reflection and dynamic code execution features.
Found 2 instances in 1 package
17171
8
449
4
2
2
1
+ Addedbabylon@^6.18.0
+ Addedrecast@^0.12.8
+ Addedrepl.history@^0.1.4
+ Addedast-types@0.10.1(transitive)
+ Addedbabylon@6.18.0(transitive)
+ Addedcore-js@2.6.12(transitive)
+ Addedesprima@4.0.1(transitive)
+ Addedprivate@0.1.8(transitive)
+ Addedrecast@0.12.9(transitive)
+ Addedrepl.history@0.1.4(transitive)
+ Addedsource-map@0.6.1(transitive)