Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

taiko

Package Overview
Dependencies
Maintainers
1
Versions
73
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

taiko - npm Package Compare versions

Comparing version 0.0.4 to 0.0.5

docs/_config.yml

7

package.json
{
"name": "taiko",
"version": "0.0.4",
"version": "0.0.5",
"description": "An easy to use wrapper over Google Chrome's Puppeteer library.",

@@ -12,2 +12,3 @@ "main": "taiko.js",

"lint": "./node_modules/.bin/eslint *.js",
"doc": "./node_modules/documentation/bin/documentation.js build taiko.js -f md -o docs/index.md && ./node_modules/documentation/bin/documentation.js build taiko.js -f json -o docs/api.json",
"test": "npm run lint"

@@ -30,3 +31,2 @@ },

"babylon": "^6.18.0",
"figlet": "^1.2.0",
"puppeteer": "^0.12.0",

@@ -38,4 +38,5 @@ "recast": "^0.12.8",

"eslint": "^4.10.0",
"js-beautify": "^1.7.4"
"js-beautify": "^1.7.4",
"documentation": "^5.3.3"
}
}

@@ -11,4 +11,6 @@ ```

[**API**](https://getgauge.github.io/Taiko/)
An easy to use wrapper over Google Chrome's Puppeteer library.
[![NPM](https://nodei.co/npm/taiko.png)](https://npmjs.org/package/taiko)

@@ -5,15 +5,19 @@ #! /usr/bin/env node

const util = require('util');
const path = require('path');
const puppeteer = require('puppeteer');
const { spawnSync } = require('child_process');
const { aEval } = require('./awaitEval');
const taiko = require('./taiko');
let version = '';
let browserVersion = '';
let doc = '';
try {
const figlet = require('figlet');
const fonts = ['Graffiti', '3D Diagonal', 'Acrobatic', 'Avatar', 'Big Money-ne', 'Big Money-nw', 'Big Money-se', 'Graffiti', 'Big Money-sw', 'Big', 'Blocks', 'Bulbhead', 'Cards', 'Chiseled', 'Crawford2', 'Crazy', 'Dancing Font', 'Doh', 'Doom', 'Epic', 'Graffiti', 'Fire Font-k', 'Fire Font-s', 'Flower Power', 'Ghost', 'Graceful', 'Graffiti', 'Impossible', 'Isometric1', 'Isometric2', 'Graffiti', 'Isometric3', 'Isometric4', 'JS Bracket Letters', 'Lil Devil', 'Merlin1', 'Modular', 'Ogre', 'Patorjk\'s Cheese', 'Patorjk-HeX', 'Rectangles', 'Slant', 'Slant Relief', 'Small', 'Small Slant', 'Small Isometric1', 'Soft', 'Standard', 'Star Wars', 'Sub-Zero', 'Swamp Land', 'Sweet', 'Train', 'Twisted', 'Wet Letter', 'Varsity', '3D-ASCII', 'ANSI Shadow', 'Bloody', 'Calvin S', 'Delta Corps Priest 1', 'Electronic', 'Elite', 'Stronger Than All', 'THIS', 'The Edge', '4Max', '5 Line Oblique', 'AMC 3 Line', 'AMC AAA01', 'AMC Neko', 'AMC Razor', 'AMC Razor2', 'AMC Slash', 'AMC Slider', 'AMC Thin', 'AMC Tubes', 'AMC Untitled', 'ASCII New Roman', 'Alligator', 'Alligator2', 'Alphabet', 'Arrows', 'Banner', 'Banner3-D', 'Banner3', 'Banner4', 'Basic', 'Bear', 'Bell', 'Bigfig', 'Block', 'Bolger', 'Braced', 'Bright', 'Broadway KB', 'Broadway', 'Bubble', 'Caligraphy', 'Caligraphy2', 'Chunky', 'Coinstak', 'Cola', 'Colossal', 'Computer', 'Contessa', 'Contrast', 'Cosmike', 'Crawford', 'Cricket', 'Cursive', 'Cyberlarge', 'Cybermedium', 'Cybersmall', 'Cygnet', 'Def Leppard', 'Diamond', 'Diet Cola', 'Digital', 'Dot Matrix', 'Double Shorts', 'Double', 'Dr Pepper', 'Efti Font', 'Efti Italic', 'Efti Robot', 'Efti Water', 'Fender', 'Flipped', 'Four Tops', 'Fraktur', 'Fuzzy', 'Georgi16', 'Georgia11', 'Ghoulish', 'Glenyn', 'Goofy', 'Gothic', 'Greek', 'Heart Left', 'Heart Right', 'Henry 3D', 'Hollywood', 'Horizontal Left', 'Horizontal Right', 'Invita', 'Italic', 'Ivrit', 'JS Block Letters', 'JS Capital Curves', 'JS Cursive', 'JS Stick Letters', 'Jacky', 'Jazmine', 'Kban', 'Keyboard', 'Knob', 'LCD', 'Larry 3D', 'Lean', 'Letters', 'Line Blocks', 'Linux', 'Lockergnome', 'Madrid', 'Marquee', 'Maxfour', 'Mini', 'Muzzle', 'NScript', 'NT Greek', 'NV Script', 'Nancyj-Fancy', 'Nancyj-Underlined', 'Nancyj', 'Nipples', 'O8', 'OS2', 'Old Banner', 'Pawp', 'Peaks', 'Pebbles', 'Poison', 'Puffy', 'Puzzle', 'Pyramid', 'Rammstein', 'Roman', 'Rounded', 'Rowan Cap', 'Rozzo', 'S Blood', 'Santa Clara', 'Script', 'Serifcap', 'Shadow', 'Shimrod', 'Short', 'Small Caps', 'Small Keyboard', 'Small Poison', 'Small Script', 'Graffiti', 'Small Shadow', 'Speed', 'Spliff', 'Stacey', 'Stampate', 'Graffiti', 'Stampatello', 'Star Strips', 'Stellar', 'Graffiti', 'Stforek', 'Stick Letters', 'Stop', 'Graffiti', 'Straight', 'Swan', 'Tanja', 'Thick', 'Thin', 'Graffiti', 'Thorned', 'Three Point', 'Tiles', 'Tinker-Toy', 'Tombstone', 'Tubular', 'Two Point', 'Univers', 'Graffiti', 'Weird', 'Whimsy'];
console.log(figlet.textSync('Taiko', {
font: fonts[Math.floor(Math.random() * fonts.length)],
horizontalLayout: 'default',
verticalLayout: 'default'
}).trimRight() + '\n');
} catch (e) {}
version = 'Version: ' + JSON.parse(fs.readFileSync(path.join(__dirname, 'package.json'))).version;
browserVersion = spawnSync(puppeteer.executablePath(), ['--version']).stdout.toString().trim();
doc = JSON.parse(fs.readFileSync(path.join(__dirname, 'docs', 'api.json')));
} catch (_) {}
displayTaiko();
const repl = require('repl').start({ prompt: '> ', ignoreUndefined: true });

@@ -25,3 +29,14 @@ const dWrite = repl.writer;

const openBrowser = taiko.openBrowser;
let taikoCommands = {};
let lastStack = '';
repl.writer = output => {
if (util.isError(output)) return output.message;
else if (typeof(output) === 'object' && 'description' in output)
return removeQuotes(util.inspect(' ✔ ' + output.description, { colors: true }), ' ✔ ' + output.description);
else return dWrite(output);
};
aEval(repl, (cmd, res) => !util.isError(res) && commands.push(cmd.trim()));
taiko.openBrowser = async (options = {}) => {

@@ -32,45 +47,20 @@ if (!options.headless) options.headless = false;

let lastStack = '';
for (let func in taiko) {
if (taiko[func].constructor.name === 'AsyncFunction') {
repl.context[func] = async function(...args) {
repl.context[func] = async function() {
try {
lastStack = '';
try {
return await taiko[func].call(this, ...args);
} catch (e) {
return handleError(e);
} finally {
util.inspect.styles.string = stringColor;
}
};
} else {
repl.context[func] = function(...args) {
lastStack = '';
try {
return taiko[func].call(this, ...args);
} catch (e) {
return handleError(e);
} finally {
util.inspect.styles.string = stringColor;
}
};
}
const args = await Promise.all(Object.values(arguments));
taikoCommands[func] = true;
return taiko[func].constructor.name === 'AsyncFunction' ?
await taiko[func].apply(this, args) : taiko[func].apply(this, args);
} catch (e) {
delete taikoCommands[func];
return handleError(e);
} finally {
util.inspect.styles.string = stringColor;
}
};
funcs[func] = true;
}
aEval(repl, (cmd, res) => {
if (!util.isError(res)) commands.push(cmd.trim());
});
const handleError = (e) => {
util.inspect.styles.string = 'red';
lastStack = removeQuotes(util.inspect(e.stack, { colors: true }).replace(/\\n/g, '\n'), e.stack);
e.message = ' ✘ Error: ' + e.message + ', run `.trace` for more info.';
return new Error(removeQuotes(util.inspect(e.message, { colors: true }), e.message));
};
const isTaikoFunc = (keyword) => keyword.split('(')[0] in funcs;
repl.defineCommand('trace', {

@@ -86,2 +76,3 @@ help: 'Show last error stack trace',

commands.length = 0;
taikoCommands = {};
lastStack = '';

@@ -97,3 +88,5 @@ });

}).join('\n');
const content = `const { ${Object.keys(funcs).join(', ')} } = require('taiko');\n\n(async () => {\n${text}\n})();`;
const cmds = Object.keys(taikoCommands);
const importTaiko = cmds.length > 0 ? `const { ${cmds.join(', ')} } = require('taiko');\n\n` : '';
const content = importTaiko + `(async () => {\n${text}\n})();`;
if (!file) console.log(content);

@@ -105,9 +98,74 @@ else fs.writeFileSync(file, content);

repl.writer = output => {
if (util.isError(output)) return output.message;
else if (typeof(output) === 'object' && 'description' in output)
return removeQuotes(util.inspect(' ✔ ' + output.description, { colors: true }), ' ✔ ' + output.description);
else return dWrite(output);
repl.defineCommand('version', {
help: 'Prints version info',
action() {
displayTaiko();
this.displayPrompt();
}
});
repl.defineCommand('api', {
help: 'Prints api info',
action(name) {
if (!doc) console.log('API usage not available.');
else if (name) displayUsageFor(name);
else displayUsage();
this.displayPrompt();
}
});
function displayTaiko() {
console.log('___________ .__ __ Interactive browser automation.');
console.log('\\__ ___/____ |__| | ______ ');
console.log(' | | \\__ \\ | | |/ / _ \\ ' + version);
console.log(' | | / __ \\| | < <_> ) ' + browserVersion);
console.log(' |____| (____ /__|__|_ \\____/ Documentation: https://getgauge.github.io/Taiko/');
console.log(' \\/ \\/ Type .api for help and .exit to quit');
console.log();
}
const removeQuotes = (textWithQuotes, textWithoutQuotes) => textWithQuotes.replace(`'${textWithoutQuotes}'`, () => textWithoutQuotes);
const handleError = e => {
util.inspect.styles.string = 'red';
lastStack = removeQuotes(util.inspect(e.stack, { colors: true }).replace(/\\n/g, '\n'), e.stack);
e.message = ' ✘ Error: ' + e.message + ', run `.trace` for more info.';
return new Error(removeQuotes(util.inspect(e.message, { colors: true }), e.message));
};
const removeQuotes = (textWithQuotes, textWithoutQuotes) => textWithQuotes.replace(`'${textWithoutQuotes}'`, textWithoutQuotes);
const displayUsageFor = name => {
const e = doc.find(e => e.name === name);
if (!e) {
console.log(`Function ${name} doesn't exist.`);
return;
}
console.log();
console.log(desc(e.description));
if (e.examples.length > 0) {
console.log();
console.log(e.examples.length > 1 ? 'Examples:' : 'Example:');
console.log(e.examples
.map(e => e.description.split('\n').map(e => '\t' + e).join('\n'))
.join('\n'));
console.log();
}
};
const displayUsage = () => {
const max = Math.max(...(doc.map(e => e.name.length))) + 4;
doc.forEach(e => {
const api = e.name + ' '.repeat(max - e.name.length);
let description = desc(e.description);
if (e.summary) description = e.tags.find(t => t.title === 'summary').description;
console.log(removeQuotes(util.inspect(api, { colors: true }), api) + description);
});
console.log('\nRun `.api <name>` for more info on a specific function. For Example: `.api click`.');
};
const desc = d => d.children
.map(c => (c.children || [])
.map((c1) => (c1.type === 'link' ? c1.children[0].value : c1.value).trim())
.join(' '))
.join(' ');
const isTaikoFunc = keyword => keyword.split('(')[0] in funcs;

@@ -5,13 +5,14 @@ const puppeteer = require('puppeteer');

const browser = () => {
validate();
return b;
};
const page = () => {
validate();
return p;
};
const openBrowser = async options => {
/**
* Launches a browser with a tab. The browser will be closed when the parent node.js process is closed.
* @summary Launches a browser.
*
* @example
* openBrowser()
* openBrowser({ headless: false })
*
* @param {Object} options - Set of configurable [options](https://github.com/GoogleChrome/puppeteer/blob/master/docs/api.md#puppeteerlaunchoptions) to set on the browser.
* @returns {Promise<Object>} - Object with the description of the action performed.
*/
module.exports.openBrowser = async options => {
b = await puppeteer.launch(options);

@@ -22,3 +23,12 @@ p = await b.newPage();

const closeBrowser = async () => {
/**
* Closes the browser and all of its tabs (if any were opened).
* @summary Closes the browser.
*
* @example
* closeBrowser()
*
* @returns {Promise<Object>} - Object with the description of the action performed.
*/
module.exports.closeBrowser = async () => {
validate();

@@ -30,4 +40,17 @@ await b.close();

const goto = async (url, options) => {
/**
* Opens the specified URL in the browser's tab. Adds `http` protocol to the URL if not present.
* @summary Opens the specified URL in the browser's tab.
*
* @example
* goto('https://google.com')
* goto('google.com')
*
* @param {string} url - URL to navigate page to.
* @param {Object} options - [Navigation parameters](https://github.com/GoogleChrome/puppeteer/blob/master/docs/api.md#pagegotourl-options)
* @returns {Promise<Object>} - Object with the description of the action performed and the final URL.
*/
module.exports.goto = async (url, options) => {
validate();
if (!/^https?:\/\//i.test(url)) url = 'http://' + url;
await p.goto(url, options);

@@ -37,3 +60,13 @@ return { description: `Navigated to url "${p.url()}"`, url: p.url() };

const reload = async options => {
/**
* Reloads the page.
*
* @example
* reload('https://google.com')
* reload('https://google.com', { timeout: 10000 })
*
* @param {Object} options - [Navigation parameters](https://github.com/GoogleChrome/puppeteer/blob/master/docs/api.md#pagereloadoptions)
* @returns {Promise<Object>} - Object with the description of the action performed and the final URL.
*/
module.exports.reload = async options => {
validate();

@@ -44,3 +77,20 @@ await p.reload(options);

const click = async (selector, waitForNavigation = true, options = {}) => {
/**
* Fetches an element with the given selector, scrolls it into view if needed, and then clicks in the center of the element. If there's no element matching selector, the method throws an error.
* @summary Clicks on an element.
*
* @example
* click('Get Started')
* click(link('Get Started'))
* click('Get Started', waitForNavigation(false))
*
* @param {selector|string} selector - A selector to search for element to click. If there are multiple elements satisfying the selector, the first will be clicked.
* @param {boolean} [waitForNavigation=true] - wait for navigation after the click.
* @param {Object} options - click options.
* @param {string} [options.button='left'] - `left`, `right`, or `middle`.
* @param {number} [options.number=1] - number of times to click on the element.
* @param {number} [options.delay=0] - Time to wait between mousedown and mouseup in milliseconds.
* @returns {Promise<Object>} - Object with the description of the action performed.
*/
module.exports.click = async (selector, waitForNavigation = true, options = {}) => {
validate();

@@ -54,15 +104,51 @@ const e = await element(selector);

const doubleClick = async (selector, waitForNavigation = true, options = {}) => {
/**
* Fetches an element with the given selector, scrolls it into view if needed, and then double clicks the element. If there's no element matching selector, the method throws an error.
* @summary Double clicks on an element.
*
* @example
* doubleClick('Get Started')
* doubleClick(button('Get Started'))
* doubleClick('Get Started', waitForNavigation(false))
*
* @param {selector|string} selector - A selector to search for element to click. If there are multiple elements satisfying the selector, the first will be double clicked.
* @param {boolean} [waitForNavigation=true] - wait for navigation after the click.
* @returns {Promise<Object>} - Object with the description of the action performed.
*/
module.exports.doubleClick = async (selector, waitForNavigation = true) => {
validate();
await click(selector, waitForNavigation, Object.assign({ clickCount: 2, }, options));
await module.exports.click(selector, waitForNavigation, { clickCount: 2, });
return { description: 'Double clicked ' + description(selector, true) };
};
const rightClick = async (selector, waitForNavigation = true, options = {}) => {
/**
* Fetches an element with the given selector, scrolls it into view if needed, and then right clicks the element. If there's no element matching selector, the method throws an error.
* @summary Right clicks on an element.
*
* @example
* rightClick('Get Started')
* rightClick(text('Get Started'))
*
* @param {selector|string} selector - A selector to search for element to right click. If there are multiple elements satisfying the selector, the first will be double clicked.
* @param {boolean} [waitForNavigation=true] - wait for navigation after the click.
* @returns {Promise<Object>} - Object with the description of the action performed.
*/
module.exports.rightClick = async (selector) => {
validate();
await click(selector, waitForNavigation, Object.assign({ button: 'right', }, options));
await module.exports.click(selector, false, { button: 'right', });
return { description: 'Right clicked ' + description(selector, true) };
};
const hover = async selector => {
/**
* Fetches an element with the given selector, scrolls it into view if needed, and then hovers over the center of the element. If there's no element matching selector, the method throws an error.
* @summary Hovers over an element.
*
* @example
* hover('Get Started')
* hover(link('Get Started'))
*
* @param {selector|string} selector - A selector to search for element to right click. If there are multiple elements satisfying the selector, the first will be hovered.
* @returns {Promise<Object>} - Object with the description of the action performed.
*/
module.exports.hover = async selector => {
validate();

@@ -75,3 +161,13 @@ const e = await element(selector);

const focus = async selector => {
/**
* Fetches an element with the given selector and focuses it. If there's no element matching selector, the method throws an error.
* @summary Focus on an element.
*
* @example
* focus(textField('Username:'))
*
* @param {selector|string} selector - A selector of an element to focus. If there are multiple elements satisfying the selector, the first will be focused.
* @returns {Promise<Object>} - Object with the description of the action performed.
*/
module.exports.focus = async selector => {
validate();

@@ -82,15 +178,43 @@ await (await _focus(selector)).dispose();

const write = async (text, into) => {
/**
* Types the given text into the focused or given element.
*
* @example
* write('admin', into('Username:'))
* write('admin', 'Username:')
* write('admin')
*
* @param {string} text - Text to type into the element.
* @param {selector|string} [into] - A selector of an element to write into.
* @returns {Promise<Object>} - Object with the description of the action performed.
*/
module.exports.write = async (text, into) => {
validate();
const selector = isString(into) ? textField(into) : into;
const e = await _focus(selector);
await e.type(text);
await e.dispose();
return { description: `Wrote ${text} in the ` + description(selector, true) };
if (into) {
const selector = isString(into) ? module.exports.textField(into) : into;
const e = await _focus(selector);
await e.type(text);
await e.dispose();
return { description: `Wrote ${text} into the ` + description(selector, true) };
} else {
p.keyboard.type(text);
return { description: `Wrote ${text} into the focused element.` };
}
};
const upload = async (filepath, to) => {
/**
* Uploads a file to a file input element.
*
* @example
* upload('c:/abc.txt', to('Please select a file:'))
* upload('c:/abc.txt', 'Please select a file:')
*
* @param {string} filepath - The path of the file to be attached.
* @param {selector|string} to - The file input element to which to upload the file.
* @returns {Promise<Object>} - Object with the description of the action performed.
*/
module.exports.upload = async (filepath, to) => {
validate();
if (isString(to)) to = {
get: async () => $xpath(`//input[@type='file'][@id=(//label[contains(text(),'${to}')]/@for)]`),
get: async () => $xpath(`//input[@type='file'][@id=(//label[contains(text(),"${to}")]/@for)]`),
description: `File input field with label containing "${to}"`,

@@ -105,3 +229,16 @@ };

const press = async (key, options) => {
/**
* Presses the given key.
*
* @example
* press('Enter')
* press('a')
*
* @param {string} key - Name of key to press, such as ArrowLeft. See [USKeyboardLayout](https://github.com/GoogleChrome/puppeteer/blob/master/lib/USKeyboardLayout.js) for a list of all key names.
* @param {Object} options
* @param {string} options.text - If specified, generates an input event with this text.
* @param {number} [options.delay=0] - Time to wait between keydown and keyup in milliseconds.
* @returns {Promise<Object>} - Object with the description of the action performed.
*/
module.exports.press = async (key, options) => {
validate();

@@ -112,3 +249,14 @@ await p.keyboard.press(key, options);

const highlight = async selector => {
/**
* Highlights the given element on the page by drawing a red rectangle around it. This is useful for debugging purposes.
* @summary Highlights the given element.
*
* @example
* highlight('Get Started')
* highlight(link('Get Started'))
*
* @param {selector|string} selector - A selector of an element to highlight. If there are multiple elements satisfying the selector, the first will be highlighted.
* @returns {Promise<Object>} - Object with the description of the action performed.
*/
module.exports.highlight = async selector => {
validate();

@@ -119,3 +267,13 @@ await evaluate(selector, e => e.style.border = '0.5em solid red');

const scrollTo = async selector => {
/**
* Scrolls the page to the given element.
*
* @example
* scrollTo('Get Started')
* scrollTo(link('Get Started'))
*
* @param {selector|string} selector - A selector of an element to scroll to.
* @returns {Promise<Object>} - Object with the description of the action performed.
*/
module.exports.scrollTo = async selector => {
validate();

@@ -126,3 +284,16 @@ await evaluate(selector, e => e.scrollIntoViewIfNeeded());

const scrollRight = async (e, px = 100) => {
/**
* Scrolls the page/element to the right.
*
* @example
* scrollRight()
* scrollRight(1000)
* scrollRight('Element containing text')
* scrollRight('Element containing text', 1000)
*
* @param {selector|string|number} [e='Window']
* @param {number} [px=100]
* @returns {Promise<Object>} - Object with the description of the action performed.
*/
module.exports.scrollRight = async (e, px = 100) => {
validate();

@@ -132,3 +303,16 @@ return await scroll(e, px, px => window.scrollBy(px, 0), (e, px) => e.scrollLeft += px, 'right');

const scrollLeft = async (e, px = 100) => {
/**
* Scrolls the page/element to the left.
*
* @example
* scrollLeft()
* scrollLeft(1000)
* scrollLeft('Element containing text')
* scrollLeft('Element containing text', 1000)
*
* @param {selector|string|number} [e='Window']
* @param {number} [px=100]
* @returns {Promise<Object>} - Object with the description of the action performed.
*/
module.exports.scrollLeft = async (e, px = 100) => {
validate();

@@ -138,3 +322,16 @@ return await scroll(e, px, px => window.scrollBy(px * -1, 0), (e, px) => e.scrollLeft -= px, 'left');

const scrollUp = async (e, px = 100) => {
/**
* Scrolls up the page/element.
*
* @example
* scrollUp()
* scrollUp(1000)
* scrollUp('Element containing text')
* scrollUp('Element containing text', 1000)
*
* @param {selector|string|number} [e='Window']
* @param {number} [px=100]
* @returns {Promise<Object>} - Object with the description of the action performed.
*/
module.exports.scrollUp = async (e, px = 100) => {
validate();

@@ -144,3 +341,16 @@ return await scroll(e, px, px => window.scrollBy(0, px * -1), (e, px) => e.scrollTop -= px), 'top';

const scrollDown = async (e, px = 100) => {
/**
* Scrolls down the page/element.
*
* @example
* scrollDown()
* scrollDown(1000)
* scrollDown('Element containing text')
* scrollDown('Element containing text', 1000)
*
* @param {selector|string|number} [e='Window']
* @param {number} [px=100]
* @returns {Promise<Object>} - Object with the description of the action performed.
*/
module.exports.scrollDown = async (e, px = 100) => {
validate();

@@ -150,47 +360,136 @@ return await scroll(e, px, px => window.scrollBy(0, px), (e, px) => e.scrollTop += px, 'down');

const $ = selector => {
/**
* Captures a screenshot of the page.
*
* @example
* screenshot({path: 'screenshot.png'});
*
* @param {Object} options - Options object with properties mentioned [here](https://github.com/GoogleChrome/puppeteer/blob/master/docs/api.md#pagescreenshotoptions).
* @returns {Promise<Buffer>} - Promise which resolves to buffer with captured screenshot.
*/
module.exports.screenshot = async options => p.screenshot(options);
/**
* Lets you identify an element on the web page via XPath or CSS selector.
*
* @example
* click($('.class'))
* $('.class').exists()
*
* @param {string} selector - XPath or CSS selector.
* @returns {ElementWrapper}
*/
module.exports.$ = selector => {
validate();
const get = async () => selector.startsWith('//') ? $xpath(selector) : p.$(selector);
const get = async () => selector.startsWith('//') || selector.startsWith('(') ? $xpath(selector) : p.$(selector);
return { get: get, exists: exists(get), description: `Custom selector "$(${selector})"` };
};
const $$ = selector => {
/**
* Lets you identify elements on the web page via XPath or CSS selector.
*
* @example
* highlight($$(`//*[text()='text']`)[1])
* $$(`//*[text()='text']`).exists()
*
* @param {string} selector - XPath or CSS selector.
* @returns {ElementWrapper}
*/
module.exports.$$ = selector => {
validate();
const get = async () => selector.startsWith('//') ? $$xpath(selector) : p.$$(selector);
const get = async () => selector.startsWith('//') || selector.startsWith('(') ? $$xpath(selector) : p.$$(selector);
return { get: get, exists: async () => (await get()).length > 0, description: `Custom selector $$(${selector})` };
};
const image = selector => {
/**
* Lets you identify an image (HTML <img> element) on a web page. Typically, this is done via the image's alt text.
* @summary Lets you identify an image on a web page.
*
* @example
* click(image('alt'))
* image('alt').exists()
*
* @param {string} alt - The image's alt text.
* @returns {ElementWrapper}
*/
module.exports.image = alt => {
validate();
assertType(selector);
const get = async () => p.$(`img[alt='${selector}']`);
return { get: get, exists: exists(get), description: `Image with "alt=${selector}"` };
assertType(alt);
const get = async () => p.$(`img[alt="${alt}"]`);
return { get: get, exists: exists(get), description: `Image with "alt=${alt}"` };
};
const link = selector => {
/**
* Lets you identify a link on a web page.
*
* @example
* click(link('Get Started'))
* link('Get Started').exists()
*
* @param {string} text - The link text.
* @returns {ElementWrapper}
*/
module.exports.link = text => {
validate();
const get = async () => element(selector, 'a');
return { get: get, exists: exists(get), description: description(selector).replace('Element', 'Link') };
const get = async () => element(text, 'a');
return { get: get, exists: exists(get), description: description(text).replace('Element', 'Link') };
};
const listItem = selector => {
/**
* Lets you identify a list item (HTML <li> element) on a web page.
* @summary Lets you identify a list item on a web page.
*
* @example
* highlight(listItem('Get Started'))
* listItem('Get Started').exists()
*
* @param {string} label - The label of the list item.
* @returns {ElementWrapper}
*/
module.exports.listItem = label => {
validate();
const get = async () => element(selector, 'li');
return { get: get, exists: exists(get), description: description(selector).replace('Element', 'List item') };
const get = async () => element(label, 'li');
return { get: get, exists: exists(get), description: description(label).replace('Element', 'List item') };
};
const button = selector => {
/**
* Lets you identify a button on a web page.
*
* @example
* highlight(button('Get Started'))
* button('Get Started').exists()
*
* @param {string} label - The button label.
* @returns {ElementWrapper}
*/
module.exports.button = label => {
validate();
const get = async () => element(selector, 'button');
return { get: get, exists: exists(get), description: description(selector).replace('Element', 'Button') };
const get = async () => element(label, 'button');
return { get: get, exists: exists(get), description: description(label).replace('Element', 'Button') };
};
const inputField = (attribute, selector) => {
/**
* Lets you identify an input field on a web page.
*
* @example
* focus(inputField('id', 'name'))
* inputField('id', 'name').exists()
*
* @param {string} [attribute='value'] - The input field's attribute.
* @param {string} value - Value of the attribute specified in the first parameter.
* @returns {ElementWrapper}
*/
module.exports.inputField = (attribute = 'value', value) => {
validate();
assertType(selector);
const get = async () => p.$(`input[${attribute}='${selector}']`);
if (!value) {
value = attribute;
attribute = 'value';
}
assertType(value);
assertType(attribute);
const get = async () => p.$(`input[${attribute}="${value}"]`);
return {
get: get,
exists: exists(get),
description: `Input field with "${attribute} = ${selector}"`,
description: `Input field with "${attribute} = ${value}"`,
value: async () => p.evaluate(e => e.value, await get()),

@@ -200,10 +499,20 @@ };

const textField = selector => {
/**
* Lets you identify a text field on a web page.
*
* @example
* focus(textField('Username:'))
* textField('Username:').exists()
*
* @param {string} label - The label (human-visible name) of the text field.
* @returns {ElementWrapper}
*/
module.exports.textField = label => {
validate();
assertType(selector);
const get = async () => $xpath(`//input[@type='text'][@id=(//label[contains(text(),'${selector}')]/@for)]`);
assertType(label);
const get = async () => $xpath(`//input[@type='text'][@id=(//label[contains(text(),"${label}")]/@for)]`);
return {
get: get,
exists: exists(get),
description: `Text field with label containing "${selector}"`,
description: `Text field with label containing "${label}"`,
value: async () => p.evaluate(e => e.value, await get()),

@@ -213,10 +522,21 @@ };

const comboBox = selector => {
/**
* Lets you identify a combo box on a web page.
*
* @example
* comboBox('Vehicle:').select('Car')
* comboBox('Vehicle:').value()
* comboBox('Vehicle:').exists()
*
* @param {string} label - The label (human-visible name) of the combo box.
* @returns {ElementWrapper}
*/
module.exports.comboBox = label => {
validate();
assertType(selector);
const get = async () => $xpath(`//select[@id=(//label[contains(text(),'${selector}')]/@for)]`);
assertType(label);
const get = async () => $xpath(`//select[@id=(//label[contains(text(),"${label}")]/@for)]`);
return {
get: get,
exists: exists(get),
description: `Combo box with label containing "${selector}"`,
description: `Combo box with label containing "${label}"`,
select: async (value) => {

@@ -233,51 +553,214 @@ const box = await get();

const checkBox = selector => {
/**
* Lets you identify a checkbox on a web page.
*
* @example
* checkBox('Vehicle').check()
* checkBox('Vehicle').uncheck()
* checkBox('Vehicle').isChecked()
* checkBox('Vehicle').exists()
*
* @param {string} label - The label (human-visible name) of the check box.
* @returns {ElementWrapper}
*/
module.exports.checkBox = label => {
validate();
assertType(selector);
const get = async () => $xpath(`//input[@type='checkbox'][@id=(//label[contains(text(),'${selector}')]/@for)]`);
assertType(label);
const get = async () => $xpath(`//input[@type='checkbox'][@id=(//label[contains(text(),"${label}")]/@for)]`);
return {
get: get,
exists: exists(get),
description: `Checkbox with label containing "${selector}"`,
description: `Checkbox with label containing "${label}"`,
isChecked: async () => p.evaluate(e => e.checked, await get()),
check: async () => p.evaluate(e => e.checked = true, await get()),
uncheck: async () => p.evaluate(e => e.checked = false, await get()),
};
};
const radioButton = selector => {
/**
* Lets you identify a radio button on a web page.
*
* @example
* radioButton('Vehicle').select()
* radioButton('Vehicle').deselect()
* radioButton('Vehicle').isSelected()
* radioButton('Vehicle').exists()
*
* @param {string} label - The label (human-visible name) of the radio button.
* @returns {ElementWrapper}
*/
module.exports.radioButton = label => {
validate();
assertType(selector);
const get = async () => $xpath(`//input[@type='radio'][@id=(//label[contains(text(),'${selector}')]/@for)]`);
assertType(label);
const get = async () => $xpath(`//input[@type='radio'][@id=(//label[contains(text(),"${label}")]/@for)]`);
return {
get: get,
exists: exists(get),
description: `Radio button with label containing "${selector}"`,
isSelected: async () => p.evaluate(e => e.checked, await get())
description: `Radio button with label containing "${label}"`,
isSelected: async () => p.evaluate(e => e.checked, await get()),
select: async () => p.evaluate(e => e.checked = true, await get()),
deselect: async () => p.evaluate(e => e.checked = false, await get()),
};
};
const text = text => {
/**
* Lets you identify an element with text.
*
* @example
* highlight(text('Vehicle'))
* text('Vehicle').exists()
*
* @param {string} text - Text to match.
* @returns {ElementWrapper}
*/
module.exports.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), description: `Element with text "${text}"` };
};
const contains = text => {
/**
* Lets you identify an element containing the text.
*
* @example
* contains('Vehicle').exists()
*
* @param {string} text - Text to match.
* @returns {ElementWrapper}
*/
module.exports.contains = text => {
validate();
assertType(text);
const get = async (e = '*') => $xpath('//' + e + `[contains(text(),'${text}')]`);
const get = async (e = '*') => {
const element = await $xpath('//' + e + `[contains(@value,"${text}")]`);
return element ? element : await $xpath('//' + e + `[contains(text(),"${text}")]`);
};
return { get: get, exists: exists(get), description: `Element containing text "${text}"` };
};
const alert = (message, callback) => dialog('alert', message, callback);
/**
* Lets you perform an operation when an `alert` with given text is shown.
*
* @example
* alert('Message', async alert => await alert.dismiss());
*
* @param {string} message - Identify alert based on this message.
* @param {function(alert)} callback - Operation to perform.
*/
module.exports.alert = (message, callback) => dialog('alert', message, callback);
const prompt = (message, callback) => dialog('prompt', message, callback);
/**
* Lets you perform an operation when a `prompt` with given text is shown.
*
* @example
* prompt('Message', async prompt => await prompt.dismiss());
*
* @param {string} message - Identify prompt based on this message.
* @param {function(prompt)} callback - Operation to perform.
*/
module.exports.prompt = (message, callback) => dialog('prompt', message, callback);
const confirm = (message, callback) => dialog('confirm', message, callback);
/**
* Lets you perform an operation when a `confirm` with given text is shown.
*
* @example
* confirm('Message', async confirm => await confirm.dismiss());
*
* @param {string} message - Identify confirm based on this message.
* @param {function(confirm)} callback - Operation to perform.
*/
module.exports.confirm = (message, callback) => dialog('confirm', message, callback);
const beforeunload = (message, callback) => dialog('beforeunload', message, callback);
/**
* Lets you perform an operation when a `beforeunload` with given text is shown.
*
* @example
* beforeunload('Message', async beforeunload => await beforeunload.dismiss());
*
* @param {string} message - Identify beforeunload based on this message.
* @param {function(beforeunload)} callback - Operation to perform.
*/
module.exports.beforeunload = (message, callback) => dialog('beforeunload', message, callback);
/**
* Converts seconds to milliseconds.
*
* @example
* link('Plugins').exists(intervalSecs(1))
*
* @param {number} secs - Seconds to convert.
* @return {number} - Milliseconds.
*/
module.exports.intervalSecs = secs => secs * 1000;
/**
* Converts seconds to milliseconds.
*
* @example
* link('Plugins').exists(intervalSecs(1), timeoutSecs(10))
*
* @param {number} secs - Seconds to convert.
* @return {number} - Milliseconds.
*/
module.exports.timeoutSecs = secs => secs * 1000;
/**
* This function is used to improve the readability. It simply returns the parameter passed into it.
* @summary Improves the readability and returns the parameter passed into it.
* @example
* click('Get Started', waitForNavigation(false))
*
* @param {boolean} e
* @return {boolean}
*/
module.exports.waitForNavigation = e => e;
/**
* This function is used to improve the readability. It simply returns the parameter passed into it.
* @summary Improves the readability and returns the parameter passed into it.
*
* @example
* upload('c:/abc.txt', to('Please select a file:'))
*
* @param {string|selector}
* @return {string|selector}
*/
module.exports.to = e => e;
/**
* This function is used to improve the readability. It simply returns the parameter passed into it.
* @summary Improves the readability and returns the parameter passed into it.
*
* @example
* write("user", into('Username:'))
*
* @param {string|selector}
* @return {string|selector}
*/
module.exports.into = e => e;
/**
* Returns the browser created using openBrowser.
*
* @returns {Browser} - [Browser](https://github.com/GoogleChrome/puppeteer/blob/master/docs/api.md#class-browser).
*/
module.exports.browser = () => {
validate();
return b;
};
/**
* Returns the page instance.
*
* @returns {Page} - [Page](https://github.com/GoogleChrome/puppeteer/blob/master/docs/api.md#class-page).
*/
module.exports.page = () => {
validate();
return p;
};
const element = async (selector, tag) => {
const e = await (() => {
if (isString(selector)) return contains(selector).get(tag);
if (isString(selector)) return module.exports.contains(selector).get(tag);
else if (isSelector(selector)) return selector.get(tag);

@@ -292,3 +775,3 @@ return null;

const d = (() => {
if (isString(selector)) return contains(selector).description;
if (isString(selector)) return module.exports.contains(selector).description;
else if (isSelector(selector)) return selector.description;

@@ -324,4 +807,2 @@ return '';

const screenshot = async options => p.screenshot(options);
const isString = obj => typeof obj === 'string' || obj instanceof String;

@@ -400,46 +881,33 @@

module.exports = {
browser,
page,
openBrowser,
closeBrowser,
goto,
reload,
$,
$$,
link,
listItem,
inputField,
textField,
image,
button,
comboBox,
checkBox,
radioButton,
alert,
prompt,
confirm,
beforeunload,
text,
contains,
click,
doubleClick,
rightClick,
write,
press,
upload,
highlight,
focus,
scrollTo,
scrollRight,
scrollLeft,
scrollUp,
scrollDown,
hover,
screenshot,
timeoutSecs: secs => secs * 1000,
intervalSecs: secs => secs * 1000,
waitForNavigation: e => e,
to: e => e,
into: e => e,
};
/**
* Identifies an element on the page.
*
* @example
* link('Sign in')
* button('Get Started')
* $('#id')
* text('Home')
*
* @typedef {function(string, ...string)} selector
*/
/**
* Wrapper object for the element present on the web page. There might be extra properties/methods avaliable based on the element type.
* @summary Wrapper object for the element present on the web page.
*
* @typedef {Object} ElementWrapper
* @property {function} get - DOM element getter.
* @property {function(number, number)} exists - Checks existence for element.
* @property {string} description - Describing the operation performed.
*
*/
/**
* Puppeteer's [Browser](https://github.com/GoogleChrome/puppeteer/blob/master/docs/api.md#class-browser) instance.
* @typedef {Object} Browser
*/
/**
* Puppeteer's [Page](https://github.com/GoogleChrome/puppeteer/blob/master/docs/api.md#class-page) instance.
* @typedef {Object} Page
*/
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc