UNPKG

wp-e2e-webdriver

Version:

Webdriver manager and helper for WP end-to-end tests

620 lines (564 loc) 22.4 kB
'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); exports.defaultWaitMs = undefined; exports.waitTillPresentAndDisplayed = waitTillPresentAndDisplayed; exports.isEventuallyPresentAndDisplayed = isEventuallyPresentAndDisplayed; exports.waitTillNotPresent = waitTillNotPresent; exports.clickWhenClickable = clickWhenClickable; exports.setCheckbox = setCheckbox; exports.unsetCheckbox = unsetCheckbox; exports.waitForFieldClearable = waitForFieldClearable; exports.setWhenSettable = setWhenSettable; exports.selectOption = selectOption; exports.clearCookiesAndDeleteLocalStorage = clearCookiesAndDeleteLocalStorage; exports.deleteLocalStorage = deleteLocalStorage; exports.scrollUp = scrollUp; exports.mouseMoveTo = mouseMoveTo; exports.scrollDown = scrollDown; exports.writeImage = writeImage; exports.writeText = writeText; exports.getMediaWithFilename = getMediaWithFilename; exports.takeScreenshot = takeScreenshot; var _seleniumWebdriver = require('selenium-webdriver'); var _fsExtra = require('fs-extra'); var _fsExtra2 = _interopRequireDefault(_fsExtra); var _path = require('path'); var _path2 = _interopRequireDefault(_path); var _slugs = require('slugs'); var _slugs2 = _interopRequireDefault(_slugs); var _temp = require('temp'); var _temp2 = _interopRequireDefault(_temp); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } var defaultWaitMs = exports.defaultWaitMs = 10000; // 10s /** * WebDriver helper. * * @module WebDriverHelper */ /** * External dependencies */ function returnFalse() { return false; } function returnTrue() { return true; } /** * Wait for element, located by `selector`, until present and displayed. Timeout * occurs after `waitMs` if element located by `selector` is not present and * displayed. * * @param {object} driver - Instance of WebDriver. * @param {object} selector - Instance of locator, mechanism for locating an element * on the page. For example `By.css( '#content' )`. * @param {number} waitMs - How long to wait in millisecond. Defaults to 10000. * * @example * * import { By } from 'selenium-webdriver'; * import { WebDriverManager, WebDriverHelper as helper } from 'wp-e2e-webdriver'; * * const manager = new WebDriverManager( 'chrome' ); * const driver = manager.getDriver(); * * helper.waitTillPresentAndDisplayed( driver, By.css( '#content' ) ) * .then( ... ); * * @return {Promise} A promise that will be resolved with `true` value if element * located `selector` is present and displayed, or rejected if * times out waiting element to present and displayed. */ function waitTillPresentAndDisplayed(driver, selector) { var waitMs = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : defaultWaitMs; return driver.wait(function () { return driver.findElement(selector).then(function (element) { return element.isDisplayed().then(returnTrue, returnFalse); }, returnFalse); }, waitMs, 'Timed out waiting for element with ' + selector.using + ' of \'' + selector.value + '\' to be present and displayed'); } /** * Checks whether an element located by `selector` is eventually present and displayed. * Timeout occurs after `waitMs` if element located by `selector` is not present and * displayed. * * @param {object} driver - Instance of WebDriver. * @param {object} selector - Instance of locator, mechanism for locating an element * on the page. For example `By.css( '#content' )`. * @param {number} waitMs - How long to wait in millisecond. Defaults to 10000. * * @example * * import { By } from 'selenium-webdriver'; * import { WebDriverManager, WebDriverHelper as helper } from 'wp-e2e-webdriver'; * * const manager = new WebDriverManager( 'chrome' ); * const driver = manager.getDriver(); * * helper.isEventuallyPresentAndDisplayed( driver, By.css( '#content' ) ) * .then( ... ); * * @return {Promise} A promise that will be resolved with `true` value if element * located `selector` is eventually present and displayed, or * rejected if times out waiting the element to be present * and displayed. */ function isEventuallyPresentAndDisplayed(driver, selector) { var waitMs = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : defaultWaitMs; return driver.wait(function () { return driver.findElement(selector).then(function (element) { return element.isDisplayed().then(returnTrue, returnFalse); }, returnFalse); }, waitMs).then(function (shown) { return shown; }, returnFalse); } /** * Wait for element, located by `selector`, until not present. Timeout occurs * after `waitMs` if element located by `selector` still present. * * @param {object} driver - Instance of WebDriver. * @param {object} selector - Instance of locator, mechanism for locating an element * on the page. For example `By.css( '#content' )`. * @param {number} waitMs - How long to wait in millisecond. Defaults to 10000. * * @example * * import { By } from 'selenium-webdriver'; * import { WebDriverManager, WebDriverHelper as helper } from 'wp-e2e-webdriver'; * * const manager = new WebDriverManager( 'chrome' ); * const driver = manager.getDriver(); * * helper.waitTillNotPresent( driver, By.css( '#content' ) ) * .then( ... ); * * @return {Promise} A promise that will be resolved with `true` value if element * located `selector` is eventually not present, or rejected * if times out waiting the element to be not present. */ function waitTillNotPresent(driver, selector) { var waitMs = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : defaultWaitMs; return driver.wait(function () { return driver.findElement(selector).then(function (element) { return element.isDisplayed().then(returnFalse, returnTrue); }, returnTrue); }, waitMs, 'Timed out waiting for element with ' + selector.using + ' of \'' + selector.value + '\' to be not present'); } /** * Wait for the clickable element then click it. Timeout occurs after `waitMs` * if clickable element located by `selector` is not present. * * @param {object} driver - Instance of WebDriver. * @param {object} selector - Instance of locator, mechanism for locating an element * on the page. For example `By.css( '#submit' )`. * @param {number} waitMs - How long to wait in millisecond. Defaults to 10000. * * @example * * import { By } from 'selenium-webdriver'; * import { WebDriverManager, WebDriverHelper as helper } from 'wp-e2e-webdriver'; * * const manager = new WebDriverManager( 'chrome' ); * const driver = manager.getDriver(); * * helper.clickWhenClickable( driver, By.css( 'a.button' ) ) * .then( ... ); * * @return {Promise} A promise that will be resolved with `true` if element * located by `selector` is successfully clicked, `false` if * element is not clickable, or rejected if times out waiting * clickable element to present and displayed. */ function clickWhenClickable(driver, selector) { var waitMs = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : defaultWaitMs; return driver.wait(function () { return driver.findElement(selector).then(function (element) { return element.click().then(returnTrue, returnFalse); }, returnFalse); }, waitMs, 'Timed out waiting for element with ' + selector.using + ' of \'' + selector.value + '\' to be clickable'); } /** * Check the checkbox element located by `selector`. * * @param {object} driver - Instance of WebDriver. * @param {object} selector - Instance of locator, mechanism for locating an element * on the page. For example `By.css( 'input[type="checkbox"]' )`. * * @example * * import { By } from 'selenium-webdriver'; * import { WebDriverManager, WebDriverHelper as helper } from 'wp-e2e-webdriver'; * * const manager = new WebDriverManager( 'chrome' ); * const driver = manager.getDriver(); * * helper.setCheckbox( driver, By.css( 'input[type="checkbox"]' ) ) * .then( ... ); * * @return {Promise} A promise that will be resolved with `true` if checkbox * element located by `selector` is checked. */ function setCheckbox(driver, selector) { var _this = this; return driver.findElement(selector).then(function (checkbox) { return checkbox.getAttribute('checked').then(function (checked) { if (checked !== 'true') { return _this.clickWhenClickable(driver, selector); } return true; }); }); } /** * Uncheck the checkbox element located by `selector`. * * @param {object} driver - Instance of WebDriver. * @param {object} selector - Instance of locator, mechanism for locating an element * on the page. For example `By.css( 'input[type="checkbox"]' )`. * * @example * * import { By } from 'selenium-webdriver'; * import { WebDriverManager, WebDriverHelper as helper } from 'wp-e2e-webdriver'; * * const manager = new WebDriverManager( 'chrome' ); * const driver = manager.getDriver(); * * helper.unsetCheckbox( driver, By.css( 'input[type="checkbox"]' ) ) * .then( ... ); * * @return {Promise} A promise that will be resolved with `true` if checkbox * element located by `selector` is unchecked. */ function unsetCheckbox(driver, selector) { var _this2 = this; return driver.findElement(selector).then(function (checkbox) { checkbox.getAttribute('checked').then(function (checked) { if (checked === 'true') { return _this2.clickWhenClickable(driver, selector); } }); }); } /** * Wait for the element value is cleared. Timeout occurs after `waitMs` if * the element located by `selector` is not present and displayed. * * @param {object} driver - Instance of WebDriver. * @param {object} selector - Instance of locator, mechanism for locating an element * on the page. For example `By.css( 'input[name="username"]' )`. * @param {number} waitMs - How long to wait in millisecond. Defaults to 10000. * * @example * * import { By } from 'selenium-webdriver'; * import { WebDriverManager, WebDriverHelper as helper } from 'wp-e2e-webdriver'; * * const manager = new WebDriverManager( 'chrome' ); * const driver = manager.getDriver(); * * helper.waitForFieldClearable( driver, By.css( 'input[name="username"]' ) ) * .then( ... ); * * @return {Promise} A promise that will be resolved with `true` if element's value, * located by `selector`, is successfully cleared, `false` if * element's value is not cleared, or rejected if times out waiting * the element to present and displayed. */ function waitForFieldClearable(driver, selector) { var waitMs = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : defaultWaitMs; return driver.wait(function () { return driver.findElement(selector).then(function (element) { return element.clear().then(function () { return element.getAttribute('value').then(function (value) { return value === ''; }); }, returnFalse); }, returnFalse); }, waitMs, 'Timed out waiting for element with ' + selector.using + ' of \'' + selector.value + '\' to be clearable'); } /** * Set the element's value, located by `selector`, with `value`. Timeout occurs * after `waitMs` if the element located by `selector` is not present and displayed. * * @param {object} driver - Instance of WebDriver. * @param {object} selector - Instance of locator, mechanism for locating an element * on the page. For example `By.css( 'input[name="username"]' )`. * @param {string} value - Value to set to the element. * @param {object} options - Optional object where `secureValue` is a boolea * indicating the element's value shouldn't be exposed * in the log ( e.g input[type="password"] ), `waitMs` * is time in millisecond to wait for the element * to be settable. * * @example * * import { By } from 'selenium-webdriver'; * import { WebDriverManager, WebDriverHelper as helper } from 'wp-e2e-webdriver'; * * const manager = new WebDriverManager( 'chrome' ); * const driver = manager.getDriver(); * * helper.setWhenSettable( driver, By.css( 'input[name="username"]' ) ) * .then( ... ); * * @return {Promise} A promise that will be resolved with `true` if element's value, * located by `selector`, is successfully set, `false` if * element's value is not set, or rejected if times out waiting * the element to present and displayed. */ function setWhenSettable(driver, selector, value) { var _ref = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {}, _ref$secureValue = _ref.secureValue, secureValue = _ref$secureValue === undefined ? false : _ref$secureValue, _ref$waitMs = _ref.waitMs, waitMs = _ref$waitMs === undefined ? defaultWaitMs : _ref$waitMs; var logValue = secureValue === true ? '*********' : value; var self = this; return driver.wait(function () { return driver.findElement(selector).then(function (element) { self.waitForFieldClearable(driver, selector); return element.sendKeys(value).then(function () { return element.getAttribute('value').then(function (actualValue) { return actualValue === value; }); }, returnFalse); }, returnFalse); }, waitMs, 'Timed out waiting for element with ' + selector.using + ' of \'' + selector.value + '\' to be settable to: \'' + logValue + '\''); } /** * Select option with text `optionText` in select element lcoated by `dropdownSelector`. * * @param {object} driver - Instance of WebDriver. * @param {object} dropdownSelector - Instance of locator, mechanism for locating * an element on the page. For example * `By.css( 'select[name="country"]' )`. * @param {string} optionText - Option text. * * @return {Promise} A promise that will be resolved to `true` if option can * be selected, or `false` if not. */ function selectOption(driver, dropdownSelector, optionText) { var dropdown = driver.findElement(dropdownSelector); return dropdown.then(function (select) { return select.click().then(function () { var option = select.findElement(_seleniumWebdriver.By.xpath('.//option[contains(text(),"' + optionText + '")]')); return option.then(function (opt) { return opt.click().then(returnTrue, returnFalse); }, returnFalse); }, returnFalse); }, returnFalse); } /** * Clear cookies and delete localStorage. * * @param {object} driver - Instance of WebDriver. * * @return {boolean} Returns true once localStorage is cleared. */ function clearCookiesAndDeleteLocalStorage(driver) { driver.manage().deleteAllCookies(); return this.deleteLocalStorage(driver); } /** * Empty all keys out of the `localStorage`. * * Under the hood invoke `window.localStorage.clear()`. * * @param {object} driver - Instance of WebDriver. */ function deleteLocalStorage(driver) { driver.getCurrentUrl().then(function (url) { if (url.startsWith('data:') === false && url !== 'about:blank') { return driver.executeScript('window.localStorage.clear();'); } }); } /** * Scroll up once by pressing page up key. * * @param {object} driver - Instance of WebDriver. * @param {number} waitMs - Sleep for `waitMs` after pressing page up. */ function scrollUp(driver) { var waitMs = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 2000; driver.actions().sendKeys(_seleniumWebdriver.Key.PAGE_UP).perform(); driver.sleep(waitMs); } /** * Mouse move into element located by `selector`. * * @param {object} driver - Instance of WebDriver. * @param {object} selector - Instance of locator, mechanism for locating an element * on the page. For example `By.css( 'input[name="username"]' )`. * * @example * * import { By } from 'selenium-webdriver'; * import { WebDriverManager, WebDriverHelper as helper } from 'wp-e2e-webdriver'; * * const manager = new WebDriverManager( 'chrome' ); * const driver = manager.getDriver(); * const selector = By.css( '#submit' ); * * helper.mouseMoveTo( driver, selector ).then( () => { * helper.clickWhenClickable( driver, selector ); * } ); * * @return {Promise} A promise that will be resolved to `true` if mouse can * be moved to the element located by `selector`, `false` * if can not be moved. */ function mouseMoveTo(driver, selector) { return driver.actions().mouseMove(driver.findElement(selector)).perform().then(function () { return true; }, function () { return false; }); } /** * Scroll down once by pressing page down key. * * @param {object} driver - Instance of WebDriver. * @param {number} waitMs - Sleep for `waitMs` after pressing page down. */ function scrollDown(driver) { var waitMs = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 2000; driver.actions().sendKeys(_seleniumWebdriver.Key.PAGE_DOWN).perform(); driver.sleep(waitMs); } /** * Write image `data` to `dst`. * * @param {string|Buffer|Uint8Array} data - Date to write. * @param {string} dst - Path of the file where data being * written into. * * @example * * import path from 'path'; * import { WebDriverManager, WebDriverHelper as helper } from 'wp-e2e-webdriver'; * * const manager = new WebDriverManager( 'chrome' ); * const driver = manager.getDriver(); * * driver.takeScreenshot().then( data => { * const dst = path.resolve( manager.config.screenshotsDir, 'screenshot.png' ); * helper.writeImage( data, dst ); * } ); * * @return {undefined} Returns value from `fs.writeFileSync` which is `undefined`. */ function writeImage(data, dst) { _fsExtra2.default.ensureFileSync(dst); return _fsExtra2.default.writeFileSync(dst, data, 'base64'); } /** * Write text `data` to `dst`. * * @param {string|Buffer|Uint8Array} content - Date to write. * @param {string} dst - Path of the file where data being * written into. * * @example * * import path from 'path'; * import { WebDriverManager, WebDriverHelper as helper } from 'wp-e2e-webdriver'; * * const manager = new WebDriverManager( 'chrome' ); * const driver = manager.getDriver(); * const dst = path.resolve( process.cwd(), 'browser-log.txt' ); * * driver.manage().logs().get( 'browser' ).then( logs => { * logs.forEach( log => { * helper.writeText( log.message, dst ); * } ); * } ); * * @return {undefined} Returns value from `fs.writeFileSync` which is `undefined`. */ function writeText(content, dst) { _fsExtra2.default.ensureFileSync(dst); return _fsExtra2.default.writeFileSync(dst, content); } /** * Get path of example media where filename is `filename` and media type is `type`. * * This function can be used for testing file upload of various where various * media types is allowed to be uploaded. Under the hood it copies pre-defined * media in this package into `filename` and returns the file details. * * @param {string} filename - Full path of filename where new media is going * to be created. * @param {string} type - Media type. * * @example * * import { By } from 'selenium-webdriver'; * import path from 'path'; * import { WebDriverManager, WebDriverHelper as helper } from 'wp-e2e-webdriver'; * * const manager = new WebDriverManager( 'chrome' ); * const driver = manager.getDriver(); * * helper.getMediaWithFilename( 'test-upload-image.jpg', 'jpg' ).then( data => { * driver.findElement( By.css( 'input[type="file"]' ) ).sendKeys( data.file ); * helper.clickWhenClickable( driver, By.css( '#submit' ) ); * } ); * * @returns {Promise} Promise of file details. */ function getMediaWithFilename(filename) { var type = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'jpg'; var src = _path2.default.resolve(__dirname, '../media/media.' + type); if (!_fsExtra2.default.existsSync(src)) { throw new Error('Source media ' + src + ' does not exist'); } var dst = _path2.default.resolve(_temp2.default.mkdirSync('media'), filename); var d = _seleniumWebdriver.promise.defer(); _fsExtra2.default.copySync(src, dst); d.fulfill({ imageName: filename, fileName: filename, file: dst }); return d.promise; } /** * Take a screenshot from `currentTest`. * * The best place to use this is in `test.afterEach` hook where all tests * are captured. * * @param {object} manager - Instance of `WebDriverManager`. * @param {object} currentTest - Current test. * * @example * * import test from 'selenium-webdriver/testing'; * import { WebDriverHelper as helper } from 'wp-e2e-webdriver'; * * test.afterEach( 'Take screenshot', function() { * return helper.takeScreenshot( global.__MANAGER__, this.currentTest ); * } ); * * @return {Promise} A promise that will be resolved with `undefined` once * screenshot is written to `manager.config.screenshotsDir`. */ function takeScreenshot(manager, currentTest) { if (!currentTest) { return; } var driver = manager.getDriver(); var title = (0, _slugs2.default)(currentTest.title); var state = currentTest.state; var screenSize = manager.getConfigScreenSize(); var filename = state + '-' + screenSize + '-' + title + '.png'; return driver.takeScreenshot().then(function (data) { var dst = _path2.default.resolve(manager.config.screenshotsDir, filename); return writeImage(data, dst); }); }