From 3164a7c16c16eea664aa92345d11aa2033b2d311 Mon Sep 17 00:00:00 2001 From: kobenguyent Date: Thu, 2 Jan 2025 16:48:30 +0100 Subject: [PATCH] fix: style no semi colon --- lib/helper/Playwright.js | 2218 +++++++++++++++++++------------------- 1 file changed, 1109 insertions(+), 1109 deletions(-) diff --git a/lib/helper/Playwright.js b/lib/helper/Playwright.js index 9de8cc70a..fae77d8d0 100644 --- a/lib/helper/Playwright.js +++ b/lib/helper/Playwright.js @@ -1,17 +1,17 @@ -const path = require('path'); -const fs = require('fs'); - -const Helper = require('@codeceptjs/helper'); -const { v4: uuidv4 } = require('uuid'); -const assert = require('assert'); -const promiseRetry = require('promise-retry'); -const Locator = require('../locator'); -const recorder = require('../recorder'); -const stringIncludes = require('../assert/include').includes; -const { urlEquals } = require('../assert/equal'); -const { equals } = require('../assert/equal'); -const { empty } = require('../assert/empty'); -const { truth } = require('../assert/truth'); +const path = require('path') +const fs = require('fs') + +const Helper = require('@codeceptjs/helper') +const { v4: uuidv4 } = require('uuid') +const assert = require('assert') +const promiseRetry = require('promise-retry') +const Locator = require('../locator') +const recorder = require('../recorder') +const stringIncludes = require('../assert/include').includes +const { urlEquals } = require('../assert/equal') +const { equals } = require('../assert/equal') +const { empty } = require('../assert/empty') +const { truth } = require('../assert/truth') const { xpathLocator, ucfirst, @@ -24,28 +24,28 @@ const { clearString, requireWithFallback, normalizeSpacesInString, -} = require('../utils'); -const { isColorProperty, convertColorToRGBA } = require('../colorUtils'); -const ElementNotFound = require('./errors/ElementNotFound'); -const RemoteBrowserConnectionRefused = require('./errors/RemoteBrowserConnectionRefused'); -const Popup = require('./extras/Popup'); -const Console = require('./extras/Console'); -const { findReact, findVue, findByPlaywrightLocator } = require('./extras/PlaywrightReactVueLocator'); +} = require('../utils') +const { isColorProperty, convertColorToRGBA } = require('../colorUtils') +const ElementNotFound = require('./errors/ElementNotFound') +const RemoteBrowserConnectionRefused = require('./errors/RemoteBrowserConnectionRefused') +const Popup = require('./extras/Popup') +const Console = require('./extras/Console') +const { findReact, findVue, findByPlaywrightLocator } = require('./extras/PlaywrightReactVueLocator') -let playwright; -let perfTiming; -let defaultSelectorEnginesInitialized = false; +let playwright +let perfTiming +let defaultSelectorEnginesInitialized = false -const popupStore = new Popup(); -const consoleLogStore = new Console(); -const availableBrowsers = ['chromium', 'webkit', 'firefox', 'electron']; +const popupStore = new Popup() +const consoleLogStore = new Console() +const availableBrowsers = ['chromium', 'webkit', 'firefox', 'electron'] -const { setRestartStrategy, restartsSession, restartsContext, restartsBrowser } = require('./extras/PlaywrightRestartOpts'); -const { createValueEngine, createDisabledEngine } = require('./extras/PlaywrightPropEngine'); -const { seeElementError, dontSeeElementError, dontSeeElementInDOMError, seeElementInDOMError } = require('./errors/ElementAssertion'); -const { dontSeeTraffic, seeTraffic, grabRecordedNetworkTraffics, stopRecordingTraffic, flushNetworkTraffics } = require('./network/actions'); +const { setRestartStrategy, restartsSession, restartsContext, restartsBrowser } = require('./extras/PlaywrightRestartOpts') +const { createValueEngine, createDisabledEngine } = require('./extras/PlaywrightPropEngine') +const { seeElementError, dontSeeElementError, dontSeeElementInDOMError, seeElementInDOMError } = require('./errors/ElementAssertion') +const { dontSeeTraffic, seeTraffic, grabRecordedNetworkTraffics, stopRecordingTraffic, flushNetworkTraffics } = require('./network/actions') -const pathSeparator = path.sep; +const pathSeparator = path.sep /** * ## Configuration @@ -94,7 +94,7 @@ const pathSeparator = path.sep; * @prop {object} [recordHar] - record HAR and will be saved to `output/har`. See more of [HAR options](https://playwright.dev/docs/api/class-browser#browser-new-context-option-record-har). * @prop {string} [testIdAttribute=data-testid] - locate elements based on the testIdAttribute. See more of [locate by test id](https://playwright.dev/docs/locators#locate-by-test-id). */ -const config = {}; +const config = {} /** * Uses [Playwright](https://github.com/microsoft/playwright) library to run tests inside: @@ -316,34 +316,34 @@ const config = {}; */ class Playwright extends Helper { constructor(config) { - super(config); + super(config) - playwright = requireWithFallback('playwright', 'playwright-core'); + playwright = requireWithFallback('playwright', 'playwright-core') // set defaults - this.isRemoteBrowser = false; - this.isRunning = false; - this.isAuthenticated = false; - this.sessionPages = {}; - this.activeSessionName = ''; - this.isElectron = false; - this.isCDPConnection = false; - this.electronSessions = []; - this.storageState = null; + this.isRemoteBrowser = false + this.isRunning = false + this.isAuthenticated = false + this.sessionPages = {} + this.activeSessionName = '' + this.isElectron = false + this.isCDPConnection = false + this.electronSessions = [] + this.storageState = null // for network stuff - this.requests = []; - this.recording = false; - this.recordedAtLeastOnce = false; + this.requests = [] + this.recording = false + this.recordedAtLeastOnce = false // for websocket messages - this.webSocketMessages = []; - this.recordingWebSocketMessages = false; - this.recordedWebSocketMessagesAtLeastOnce = false; - this.cdpSession = null; + this.webSocketMessages = [] + this.recordingWebSocketMessages = false + this.recordedWebSocketMessagesAtLeastOnce = false + this.cdpSession = null // override defaults with config - this._setConfig(config); + this._setConfig(config) } _validateConfig(config) { @@ -370,61 +370,61 @@ class Playwright extends Helper { use: { actionTimeout: 0 }, ignoreHTTPSErrors: false, // Adding it here o that context can be set up to ignore the SSL errors, highlightElement: false, - }; + } - process.env.testIdAttribute = 'data-testid'; - config = Object.assign(defaults, config); + process.env.testIdAttribute = 'data-testid' + config = Object.assign(defaults, config) if (availableBrowsers.indexOf(config.browser) < 0) { - throw new Error(`Invalid config. Can't use browser "${config.browser}". Accepted values: ${availableBrowsers.join(', ')}`); + throw new Error(`Invalid config. Can't use browser "${config.browser}". Accepted values: ${availableBrowsers.join(', ')}`) } - return config; + return config } _getOptionsForBrowser(config) { if (config[config.browser]) { if (config[config.browser].browserWSEndpoint && config[config.browser].browserWSEndpoint.wsEndpoint) { - config[config.browser].browserWSEndpoint = config[config.browser].browserWSEndpoint.wsEndpoint; + config[config.browser].browserWSEndpoint = config[config.browser].browserWSEndpoint.wsEndpoint } return { ...config[config.browser], wsEndpoint: config[config.browser].browserWSEndpoint, - }; + } } - return {}; + return {} } _setConfig(config) { - this.options = this._validateConfig(config); - setRestartStrategy(this.options); + this.options = this._validateConfig(config) + setRestartStrategy(this.options) this.playwrightOptions = { headless: !this.options.show, ...this._getOptionsForBrowser(config), - }; + } if (this.options.channel && this.options.browser === 'chromium') { - this.playwrightOptions.channel = this.options.channel; + this.playwrightOptions.channel = this.options.channel } if (this.options.video) { // set the video resolution with window size - let size = parseWindowSize(this.options.windowSize); + let size = parseWindowSize(this.options.windowSize) // if the video resolution is passed, set the record resoultion with that resolution if (this.options.recordVideo && this.options.recordVideo.size) { - size = parseWindowSize(this.options.recordVideo.size); + size = parseWindowSize(this.options.recordVideo.size) } - this.options.recordVideo = { size }; + this.options.recordVideo = { size } } if (this.options.recordVideo && !this.options.recordVideo.dir) { - this.options.recordVideo.dir = `${global.output_dir}/videos/`; + this.options.recordVideo.dir = `${global.output_dir}/videos/` } - this.isRemoteBrowser = !!this.playwrightOptions.browserWSEndpoint; - this.isElectron = this.options.browser === 'electron'; - this.userDataDir = this.playwrightOptions.userDataDir ? `${this.playwrightOptions.userDataDir}_${Date.now().toString()}` : undefined; - this.isCDPConnection = this.playwrightOptions.cdpConnection; - popupStore.defaultAction = this.options.defaultPopupAction; + this.isRemoteBrowser = !!this.playwrightOptions.browserWSEndpoint + this.isElectron = this.options.browser === 'electron' + this.userDataDir = this.playwrightOptions.userDataDir ? `${this.playwrightOptions.userDataDir}_${Date.now().toString()}` : undefined + this.isCDPConnection = this.playwrightOptions.cdpConnection + popupStore.defaultAction = this.options.defaultPopupAction } static _config() { @@ -447,216 +447,216 @@ class Playwright extends Helper { type: 'confirm', when: answers => answers.Playwright_browser !== 'electron', }, - ]; + ] } static _checkRequirements() { try { - requireWithFallback('playwright', 'playwright-core'); + requireWithFallback('playwright', 'playwright-core') } catch (e) { - return ['playwright@^1.18']; + return ['playwright@^1.18'] } } async _init() { // register an internal selector engine for reading value property of elements in a selector - if (defaultSelectorEnginesInitialized) return; - defaultSelectorEnginesInitialized = true; + if (defaultSelectorEnginesInitialized) return + defaultSelectorEnginesInitialized = true try { - await playwright.selectors.register('__value', createValueEngine); - await playwright.selectors.register('__disabled', createDisabledEngine); - if (process.env.testIdAttribute) await playwright.selectors.setTestIdAttribute(process.env.testIdAttribute); + await playwright.selectors.register('__value', createValueEngine) + await playwright.selectors.register('__disabled', createDisabledEngine) + if (process.env.testIdAttribute) await playwright.selectors.setTestIdAttribute(process.env.testIdAttribute) } catch (e) { - console.warn(e); + console.warn(e) } } _beforeSuite() { if ((restartsSession() || restartsContext()) && !this.options.manualStart && !this.isRunning) { - this.debugSection('Session', 'Starting singleton browser session'); - return this._startBrowser(); + this.debugSection('Session', 'Starting singleton browser session') + return this._startBrowser() } } async _before(test) { - this.currentRunningTest = test; + this.currentRunningTest = test recorder.retry({ retries: process.env.FAILED_STEP_RETRIES || 3, when: err => { if (!err || typeof err.message !== 'string') { - return false; + return false } // ignore context errors - return err.message.includes('context'); + return err.message.includes('context') }, - }); + }) - if (restartsBrowser() && !this.options.manualStart) await this._startBrowser(); - if (!this.isRunning && !this.options.manualStart) await this._startBrowser(); + if (restartsBrowser() && !this.options.manualStart) await this._startBrowser() + if (!this.isRunning && !this.options.manualStart) await this._startBrowser() - this.isAuthenticated = false; + this.isAuthenticated = false if (this.isElectron) { - this.browserContext = this.browser.context(); + this.browserContext = this.browser.context() } else if (this.playwrightOptions.userDataDir) { - this.browserContext = this.browser; + this.browserContext = this.browser } else { const contextOptions = { ignoreHTTPSErrors: this.options.ignoreHTTPSErrors, acceptDownloads: true, ...this.options.emulate, - }; + } if (this.options.basicAuth) { - contextOptions.httpCredentials = this.options.basicAuth; - this.isAuthenticated = true; + contextOptions.httpCredentials = this.options.basicAuth + this.isAuthenticated = true } - if (this.options.bypassCSP) contextOptions.bypassCSP = this.options.bypassCSP; - if (this.options.recordVideo) contextOptions.recordVideo = this.options.recordVideo; + if (this.options.bypassCSP) contextOptions.bypassCSP = this.options.bypassCSP + if (this.options.recordVideo) contextOptions.recordVideo = this.options.recordVideo if (this.options.recordHar) { - const harExt = this.options.recordHar.content && this.options.recordHar.content === 'attach' ? 'zip' : 'har'; - const fileName = `${`${global.output_dir}${path.sep}har${path.sep}${uuidv4()}_${clearString(this.currentRunningTest.title)}`.slice(0, 245)}.${harExt}`; - const dir = path.dirname(fileName); - if (!fileExists(dir)) fs.mkdirSync(dir); - this.options.recordHar.path = fileName; - this.currentRunningTest.artifacts.har = fileName; - contextOptions.recordHar = this.options.recordHar; + const harExt = this.options.recordHar.content && this.options.recordHar.content === 'attach' ? 'zip' : 'har' + const fileName = `${`${global.output_dir}${path.sep}har${path.sep}${uuidv4()}_${clearString(this.currentRunningTest.title)}`.slice(0, 245)}.${harExt}` + const dir = path.dirname(fileName) + if (!fileExists(dir)) fs.mkdirSync(dir) + this.options.recordHar.path = fileName + this.currentRunningTest.artifacts.har = fileName + contextOptions.recordHar = this.options.recordHar } - if (this.storageState) contextOptions.storageState = this.storageState; - if (this.options.userAgent) contextOptions.userAgent = this.options.userAgent; - if (this.options.locale) contextOptions.locale = this.options.locale; - if (this.options.colorScheme) contextOptions.colorScheme = this.options.colorScheme; - this.contextOptions = contextOptions; + if (this.storageState) contextOptions.storageState = this.storageState + if (this.options.userAgent) contextOptions.userAgent = this.options.userAgent + if (this.options.locale) contextOptions.locale = this.options.locale + if (this.options.colorScheme) contextOptions.colorScheme = this.options.colorScheme + this.contextOptions = contextOptions if (!this.browserContext || !restartsSession()) { - this.browserContext = await this.browser.newContext(this.contextOptions); // Adding the HTTPSError ignore in the context so that we can ignore those errors + this.browserContext = await this.browser.newContext(this.contextOptions) // Adding the HTTPSError ignore in the context so that we can ignore those errors } } - let mainPage; + let mainPage if (this.isElectron) { - mainPage = await this.browser.firstWindow(); + mainPage = await this.browser.firstWindow() } else { try { - const existingPages = await this.browserContext.pages(); - mainPage = existingPages[0] || (await this.browserContext.newPage()); + const existingPages = await this.browserContext.pages() + mainPage = existingPages[0] || (await this.browserContext.newPage()) } catch (e) { if (this.playwrightOptions.userDataDir) { - this.browser = await playwright[this.options.browser].launchPersistentContext(this.userDataDir, this.playwrightOptions); - this.browserContext = this.browser; - const existingPages = await this.browserContext.pages(); - mainPage = existingPages[0]; + this.browser = await playwright[this.options.browser].launchPersistentContext(this.userDataDir, this.playwrightOptions) + this.browserContext = this.browser + const existingPages = await this.browserContext.pages() + mainPage = existingPages[0] } } } - await targetCreatedHandler.call(this, mainPage); + await targetCreatedHandler.call(this, mainPage) - await this._setPage(mainPage); + await this._setPage(mainPage) - if (this.options.trace) await this.browserContext.tracing.start({ screenshots: true, snapshots: true }); + if (this.options.trace) await this.browserContext.tracing.start({ screenshots: true, snapshots: true }) - return this.browser; + return this.browser } async _after() { - if (!this.isRunning) return; + if (!this.isRunning) return if (this.isElectron) { - this.browser.close(); - this.electronSessions.forEach(session => session.close()); - return; + this.browser.close() + this.electronSessions.forEach(session => session.close()) + return } if (restartsSession()) { - return refreshContextSession.bind(this)(); + return refreshContextSession.bind(this)() } if (restartsBrowser()) { - this.isRunning = false; - return this._stopBrowser(); + this.isRunning = false + return this._stopBrowser() } // close other sessions try { if ((await this.browser)._type === 'Browser') { - const contexts = await this.browser.contexts(); - const currentContext = contexts[0]; + const contexts = await this.browser.contexts() + const currentContext = contexts[0] if (currentContext && (this.options.keepCookies || this.options.keepBrowserState)) { - this.storageState = await currentContext.storageState(); + this.storageState = await currentContext.storageState() } - await Promise.all(contexts.map(c => c.close())); + await Promise.all(contexts.map(c => c.close())) } } catch (e) { - console.log(e); + console.log(e) } // await this.closeOtherTabs(); - return this.browser; + return this.browser } _afterSuite() {} async _finishTest() { - if ((restartsSession() || restartsContext()) && this.isRunning) return this._stopBrowser(); + if ((restartsSession() || restartsContext()) && this.isRunning) return this._stopBrowser() } _session() { - const defaultContext = this.browserContext; + const defaultContext = this.browserContext return { start: async (sessionName = '', config) => { - this.debugSection('New Context', config ? JSON.stringify(config) : 'opened'); - this.activeSessionName = sessionName; + this.debugSection('New Context', config ? JSON.stringify(config) : 'opened') + this.activeSessionName = sessionName - let browserContext; - let page; + let browserContext + let page if (this.isElectron) { - const browser = await playwright._electron.launch(this.playwrightOptions); - this.electronSessions.push(browser); - browserContext = browser.context(); - page = await browser.firstWindow(); + const browser = await playwright._electron.launch(this.playwrightOptions) + this.electronSessions.push(browser) + browserContext = browser.context() + page = await browser.firstWindow() } else { try { - browserContext = await this.browser.newContext(Object.assign(this.contextOptions, config)); - page = await browserContext.newPage(); + browserContext = await this.browser.newContext(Object.assign(this.contextOptions, config)) + page = await browserContext.newPage() } catch (e) { if (this.playwrightOptions.userDataDir) { - browserContext = await playwright[this.options.browser].launchPersistentContext(`${this.userDataDir}_${this.activeSessionName}`, this.playwrightOptions); - this.browser = browserContext; - page = await browserContext.pages()[0]; + browserContext = await playwright[this.options.browser].launchPersistentContext(`${this.userDataDir}_${this.activeSessionName}`, this.playwrightOptions) + this.browser = browserContext + page = await browserContext.pages()[0] } } } - if (this.options.trace) await browserContext.tracing.start({ screenshots: true, snapshots: true }); - await targetCreatedHandler.call(this, page); - await this._setPage(page); + if (this.options.trace) await browserContext.tracing.start({ screenshots: true, snapshots: true }) + await targetCreatedHandler.call(this, page) + await this._setPage(page) // Create a new page inside context. - return browserContext; + return browserContext }, stop: async () => { // is closed by _after }, loadVars: async context => { if (context) { - this.browserContext = context; - const existingPages = await context.pages(); - this.sessionPages[this.activeSessionName] = existingPages[0]; - return this._setPage(this.sessionPages[this.activeSessionName]); + this.browserContext = context + const existingPages = await context.pages() + this.sessionPages[this.activeSessionName] = existingPages[0] + return this._setPage(this.sessionPages[this.activeSessionName]) } }, restoreVars: async session => { - this.withinLocator = null; - this.browserContext = defaultContext; + this.withinLocator = null + this.browserContext = defaultContext if (!session) { - this.activeSessionName = ''; + this.activeSessionName = '' } else { - this.activeSessionName = session; + this.activeSessionName = session } - const existingPages = await this.browserContext.pages(); - await this._setPage(existingPages[0]); + const existingPages = await this.browserContext.pages() + await this._setPage(existingPages[0]) - return this._waitForAction(); + return this._waitForAction() }, - }; + } } /** @@ -677,7 +677,7 @@ class Playwright extends Helper { * @param {function} fn async function that executed with Playwright helper as arguments */ usePlaywrightTo(description, fn) { - return this._useTo(...arguments); + return this._useTo(...arguments) } /** @@ -691,7 +691,7 @@ class Playwright extends Helper { * ``` */ amAcceptingPopups() { - popupStore.actionType = 'accept'; + popupStore.actionType = 'accept' } /** @@ -700,7 +700,7 @@ class Playwright extends Helper { * libraries](http://jster.net/category/windows-modals-popups). */ acceptPopup() { - popupStore.assertPopupActionType('accept'); + popupStore.assertPopupActionType('accept') } /** @@ -714,23 +714,23 @@ class Playwright extends Helper { * ``` */ amCancellingPopups() { - popupStore.actionType = 'cancel'; + popupStore.actionType = 'cancel' } /** * Dismisses the active JavaScript popup, as created by window.alert|window.confirm|window.prompt. */ cancelPopup() { - popupStore.assertPopupActionType('cancel'); + popupStore.assertPopupActionType('cancel') } /** * {{> seeInPopup }} */ async seeInPopup(text) { - popupStore.assertPopupVisible(); - const popupText = await popupStore.popup.message(); - stringIncludes('text in popup').assert(text, popupText); + popupStore.assertPopupVisible() + const popupText = await popupStore.popup.message() + stringIncludes('text in popup').assert(text, popupText) } /** @@ -738,21 +738,21 @@ class Playwright extends Helper { * @param {object} page page to set */ async _setPage(page) { - page = await page; - this._addPopupListener(page); - this.page = page; - if (!page) return; - this.browserContext.setDefaultTimeout(0); - page.setDefaultNavigationTimeout(this.options.getPageTimeout); - page.setDefaultTimeout(this.options.timeout); + page = await page + this._addPopupListener(page) + this.page = page + if (!page) return + this.browserContext.setDefaultTimeout(0) + page.setDefaultNavigationTimeout(this.options.getPageTimeout) + page.setDefaultTimeout(this.options.timeout) page.on('crash', async () => { - console.log('ERROR: Page has crashed, closing page!'); - await page.close(); - }); - this.context = await this.page; - this.contextLocator = null; - await page.bringToFront(); + console.log('ERROR: Page has crashed, closing page!') + await page.close() + }) + this.context = await this.page + this.contextLocator = null + await page.bringToFront() } /** @@ -764,33 +764,33 @@ class Playwright extends Helper { */ _addPopupListener(page) { if (!page) { - return; + return } - page.removeAllListeners('dialog'); + page.removeAllListeners('dialog') page.on('dialog', async dialog => { - popupStore.popup = dialog; - const action = popupStore.actionType || this.options.defaultPopupAction; - await this._waitForAction(); + popupStore.popup = dialog + const action = popupStore.actionType || this.options.defaultPopupAction + await this._waitForAction() switch (action) { case 'accept': - return dialog.accept(); + return dialog.accept() case 'cancel': - return dialog.dismiss(); + return dialog.dismiss() default: { - throw new Error('Unknown popup action type. Only "accept" or "cancel" are accepted'); + throw new Error('Unknown popup action type. Only "accept" or "cancel" are accepted') } } - }); + }) } /** * Gets page URL including hash. */ async _getPageUrl() { - return this.executeScript(() => window.location.href); + return this.executeScript(() => window.location.href) } /** @@ -803,45 +803,45 @@ class Playwright extends Helper { */ async grabPopupText() { if (popupStore.popup) { - return popupStore.popup.message(); + return popupStore.popup.message() } - return null; + return null } async _startBrowser() { if (this.isElectron) { - this.browser = await playwright._electron.launch(this.playwrightOptions); + this.browser = await playwright._electron.launch(this.playwrightOptions) } else if (this.isRemoteBrowser && this.isCDPConnection) { try { - this.browser = await playwright[this.options.browser].connectOverCDP(this.playwrightOptions); + this.browser = await playwright[this.options.browser].connectOverCDP(this.playwrightOptions) } catch (err) { if (err.toString().indexOf('ECONNREFUSED')) { - throw new RemoteBrowserConnectionRefused(err); + throw new RemoteBrowserConnectionRefused(err) } - throw err; + throw err } } else if (this.isRemoteBrowser) { try { - this.browser = await playwright[this.options.browser].connect(this.playwrightOptions); + this.browser = await playwright[this.options.browser].connect(this.playwrightOptions) } catch (err) { if (err.toString().indexOf('ECONNREFUSED')) { - throw new RemoteBrowserConnectionRefused(err); + throw new RemoteBrowserConnectionRefused(err) } - throw err; + throw err } } else if (this.playwrightOptions.userDataDir) { - this.browser = await playwright[this.options.browser].launchPersistentContext(this.userDataDir, this.playwrightOptions); + this.browser = await playwright[this.options.browser].launchPersistentContext(this.userDataDir, this.playwrightOptions) } else { - this.browser = await playwright[this.options.browser].launch(this.playwrightOptions); + this.browser = await playwright[this.options.browser].launch(this.playwrightOptions) } // works only for Chromium this.browser.on('targetchanged', target => { - this.debugSection('Url', target.url()); - }); + this.debugSection('Url', target.url()) + }) - this.isRunning = true; - return this.browser; + this.isRunning = true + return this.browser } /** @@ -850,72 +850,72 @@ class Playwright extends Helper { * @param {object} [contextOptions] See https://playwright.dev/docs/api/class-browser#browser-new-context */ async _createContextPage(contextOptions) { - this.browserContext = await this.browser.newContext(contextOptions); - const page = await this.browserContext.newPage(); - targetCreatedHandler.call(this, page); - await this._setPage(page); + this.browserContext = await this.browser.newContext(contextOptions) + const page = await this.browserContext.newPage() + targetCreatedHandler.call(this, page) + await this._setPage(page) } _getType() { - return this.browser._type; + return this.browser._type } async _stopBrowser() { - this.withinLocator = null; - await this._setPage(null); - this.context = null; - this.frame = null; - popupStore.clear(); - if (this.options.recordHar) await this.browserContext.close(); - await this.browser.close(); + this.withinLocator = null + await this._setPage(null) + this.context = null + this.frame = null + popupStore.clear() + if (this.options.recordHar) await this.browserContext.close() + await this.browser.close() } async _evaluateHandeInContext(...args) { - const context = await this._getContext(); - return context.evaluateHandle(...args); + const context = await this._getContext() + return context.evaluateHandle(...args) } async _withinBegin(locator) { if (this.withinLocator) { - throw new Error("Can't start within block inside another within block"); + throw new Error("Can't start within block inside another within block") } - const frame = isFrameLocator(locator); + const frame = isFrameLocator(locator) if (frame) { if (Array.isArray(frame)) { - await this.switchTo(null); - return frame.reduce((p, frameLocator) => p.then(() => this.switchTo(frameLocator)), Promise.resolve()); + await this.switchTo(null) + return frame.reduce((p, frameLocator) => p.then(() => this.switchTo(frameLocator)), Promise.resolve()) } - await this.switchTo(frame); - this.withinLocator = new Locator(frame); - return; + await this.switchTo(frame) + this.withinLocator = new Locator(frame) + return } - const el = await this._locateElement(locator); - assertElementExists(el, locator); - this.context = el; - this.contextLocator = locator; + const el = await this._locateElement(locator) + assertElementExists(el, locator) + this.context = el + this.contextLocator = locator - this.withinLocator = new Locator(locator); + this.withinLocator = new Locator(locator) } async _withinEnd() { - this.withinLocator = null; - this.context = await this.page; - this.contextLocator = null; - this.frame = null; + this.withinLocator = null + this.context = await this.page + this.contextLocator = null + this.frame = null } _extractDataFromPerformanceTiming(timing, ...dataNames) { - const navigationStart = timing.navigationStart; + const navigationStart = timing.navigationStart - const extractedData = {}; + const extractedData = {} dataNames.forEach(name => { - extractedData[name] = timing[name] - navigationStart; - }); + extractedData[name] = timing[name] - navigationStart + }) - return extractedData; + return extractedData } /** @@ -923,26 +923,26 @@ class Playwright extends Helper { */ async amOnPage(url) { if (this.isElectron) { - throw new Error('Cannot open pages inside an Electron container'); + throw new Error('Cannot open pages inside an Electron container') } if (!/^\w+\:(\/\/|.+)/.test(url)) { - url = this.options.url + (url.startsWith('/') ? url : `/${url}`); + url = this.options.url + (url.startsWith('/') ? url : `/${url}`) } if (this.options.basicAuth && this.isAuthenticated !== true) { if (url.includes(this.options.url)) { - await this.browserContext.setHTTPCredentials(this.options.basicAuth); - this.isAuthenticated = true; + await this.browserContext.setHTTPCredentials(this.options.basicAuth) + this.isAuthenticated = true } } - await this.page.goto(url, { waitUntil: this.options.waitForNavigation }); + await this.page.goto(url, { waitUntil: this.options.waitForNavigation }) - const performanceTiming = JSON.parse(await this.page.evaluate(() => JSON.stringify(window.performance.timing))); + const performanceTiming = JSON.parse(await this.page.evaluate(() => JSON.stringify(window.performance.timing))) - perfTiming = this._extractDataFromPerformanceTiming(performanceTiming, 'responseEnd', 'domInteractive', 'domContentLoadedEventEnd', 'loadEventEnd'); + perfTiming = this._extractDataFromPerformanceTiming(performanceTiming, 'responseEnd', 'domInteractive', 'domContentLoadedEventEnd', 'loadEventEnd') - return this._waitForAction(); + return this._waitForAction() } /** @@ -963,11 +963,11 @@ class Playwright extends Helper { */ async resizeWindow(width, height) { if (width === 'maximize') { - throw new Error("Playwright can't control windows, so it can't maximize it"); + throw new Error("Playwright can't control windows, so it can't maximize it") } - await this.page.setViewportSize({ width, height }); - return this._waitForAction(); + await this.page.setViewportSize({ width, height }) + return this._waitForAction() } /** @@ -983,9 +983,9 @@ class Playwright extends Helper { */ async setPlaywrightRequestHeaders(customHeaders) { if (!customHeaders) { - throw new Error('Cannot send empty headers.'); + throw new Error('Cannot send empty headers.') } - return this.browserContext.setExtraHTTPHeaders(customHeaders); + return this.browserContext.setExtraHTTPHeaders(customHeaders) } /** @@ -993,13 +993,13 @@ class Playwright extends Helper { * */ async moveCursorTo(locator, offsetX = 0, offsetY = 0) { - const el = await this._locateElement(locator); - assertElementExists(el, locator); + const el = await this._locateElement(locator) + assertElementExists(el, locator) // Use manual mouse.move instead of .hover() so the offset can be added to the coordinates - const { x, y } = await clickablePoint(el); - await this.page.mouse.move(x + offsetX, y + offsetY); - return this._waitForAction(); + const { x, y } = await clickablePoint(el) + await this.page.mouse.move(x + offsetX, y + offsetY) + return this._waitForAction() } /** @@ -1007,11 +1007,11 @@ class Playwright extends Helper { * */ async focus(locator, options = {}) { - const el = await this._locateElement(locator); - assertElementExists(el, locator, 'Element to focus'); + const el = await this._locateElement(locator) + assertElementExists(el, locator, 'Element to focus') - await el.focus(options); - return this._waitForAction(); + await el.focus(options) + return this._waitForAction() } /** @@ -1019,11 +1019,11 @@ class Playwright extends Helper { * */ async blur(locator, options = {}) { - const el = await this._locateElement(locator); - assertElementExists(el, locator, 'Element to blur'); + const el = await this._locateElement(locator) + assertElementExists(el, locator, 'Element to blur') - await el.blur(options); - return this._waitForAction(); + await el.blur(options) + return this._waitForAction() } /** * Return the checked status of given element. @@ -1035,14 +1035,14 @@ class Playwright extends Helper { */ async grabCheckedElementStatus(locator, options = {}) { - const supportedTypes = ['checkbox', 'radio']; - const el = await this._locateElement(locator); - const type = await el.getAttribute('type'); + const supportedTypes = ['checkbox', 'radio'] + const el = await this._locateElement(locator) + const type = await el.getAttribute('type') if (supportedTypes.includes(type)) { - return el.isChecked(options); + return el.isChecked(options) } - throw new Error(`Element is not a ${supportedTypes.join(' or ')} input`); + throw new Error(`Element is not a ${supportedTypes.join(' or ')} input`) } /** * Return the disabled status of given element. @@ -1054,8 +1054,8 @@ class Playwright extends Helper { */ async grabDisabledElementStatus(locator, options = {}) { - const el = await this._locateElement(locator); - return el.isDisabled(options); + const el = await this._locateElement(locator) + return el.isDisabled(options) } /** @@ -1072,24 +1072,24 @@ class Playwright extends Helper { * */ async dragAndDrop(srcElement, destElement, options) { - const src = new Locator(srcElement); - const dst = new Locator(destElement); + const src = new Locator(srcElement) + const dst = new Locator(destElement) if (options) { - return this.page.dragAndDrop(buildLocatorString(src), buildLocatorString(dst), options); + return this.page.dragAndDrop(buildLocatorString(src), buildLocatorString(dst), options) } - const _smallWaitInMs = 600; - await this.page.locator(buildLocatorString(src)).hover(); - await this.page.mouse.down(); - await this.page.waitForTimeout(_smallWaitInMs); + const _smallWaitInMs = 600 + await this.page.locator(buildLocatorString(src)).hover() + await this.page.mouse.down() + await this.page.waitForTimeout(_smallWaitInMs) - const destElBox = await this.page.locator(buildLocatorString(dst)).boundingBox(); + const destElBox = await this.page.locator(buildLocatorString(dst)).boundingBox() - await this.page.mouse.move(destElBox.x + destElBox.width / 2, destElBox.y + destElBox.height / 2); - await this.page.locator(buildLocatorString(dst)).hover({ position: { x: 10, y: 10 } }); - await this.page.waitForTimeout(_smallWaitInMs); - await this.page.mouse.up(); + await this.page.mouse.move(destElBox.x + destElBox.width / 2, destElBox.y + destElBox.height / 2) + await this.page.locator(buildLocatorString(dst)).hover({ position: { x: 10, y: 10 } }) + await this.page.waitForTimeout(_smallWaitInMs) + await this.page.mouse.up() } /** @@ -1107,16 +1107,16 @@ class Playwright extends Helper { * @param {object} [contextOptions] [Options for browser context](https://playwright.dev/docs/api/class-browser#browser-new-context) when starting new browser */ async restartBrowser(contextOptions) { - await this._stopBrowser(); - await this._startBrowser(); - await this._createContextPage(contextOptions); + await this._stopBrowser() + await this._startBrowser() + await this._createContextPage(contextOptions) } /** * {{> refreshPage }} */ async refreshPage() { - return this.page.reload({ timeout: this.options.getPageTimeout, waitUntil: this.options.waitForNavigation }); + return this.page.reload({ timeout: this.options.getPageTimeout, waitUntil: this.options.waitForNavigation }) } /** @@ -1137,13 +1137,13 @@ class Playwright extends Helper { * @returns Promise */ async replayFromHar(harFilePath, opts) { - const file = path.join(global.codecept_dir, harFilePath); + const file = path.join(global.codecept_dir, harFilePath) if (!fileExists(file)) { - throw new Error(`File at ${file} cannot be found on local system`); + throw new Error(`File at ${file} cannot be found on local system`) } - await this.page.routeFromHAR(harFilePath, opts); + await this.page.routeFromHAR(harFilePath, opts) } /** @@ -1151,8 +1151,8 @@ class Playwright extends Helper { */ scrollPageToTop() { return this.executeScript(() => { - window.scrollTo(0, 0); - }); + window.scrollTo(0, 0) + }) } /** @@ -1160,10 +1160,10 @@ class Playwright extends Helper { */ async scrollPageToBottom() { return this.executeScript(() => { - const body = document.body; - const html = document.documentElement; - window.scrollTo(0, Math.max(body.scrollHeight, body.offsetHeight, html.clientHeight, html.scrollHeight, html.offsetHeight)); - }); + const body = document.body + const html = document.documentElement + window.scrollTo(0, Math.max(body.scrollHeight, body.offsetHeight, html.clientHeight, html.scrollHeight, html.offsetHeight)) + }) } /** @@ -1171,32 +1171,32 @@ class Playwright extends Helper { */ async scrollTo(locator, offsetX = 0, offsetY = 0) { if (typeof locator === 'number' && typeof offsetX === 'number') { - offsetY = offsetX; - offsetX = locator; - locator = null; + offsetY = offsetX + offsetX = locator + locator = null } if (locator) { - const el = await this._locateElement(locator); - assertElementExists(el, locator, 'Element'); - await el.scrollIntoViewIfNeeded(); - const elementCoordinates = await clickablePoint(el); + const el = await this._locateElement(locator) + assertElementExists(el, locator, 'Element') + await el.scrollIntoViewIfNeeded() + const elementCoordinates = await clickablePoint(el) await this.executeScript((offsetX, offsetY) => window.scrollBy(offsetX, offsetY), { offsetX: elementCoordinates.x + offsetX, offsetY: elementCoordinates.y + offsetY, - }); + }) } else { - await this.executeScript(({ offsetX, offsetY }) => window.scrollTo(offsetX, offsetY), { offsetX, offsetY }); + await this.executeScript(({ offsetX, offsetY }) => window.scrollTo(offsetX, offsetY), { offsetX, offsetY }) } - return this._waitForAction(); + return this._waitForAction() } /** * {{> seeInTitle }} */ async seeInTitle(text) { - const title = await this.page.title(); - stringIncludes('web page title').assert(text, title); + const title = await this.page.title() + stringIncludes('web page title').assert(text, title) } /** @@ -1207,33 +1207,33 @@ class Playwright extends Helper { return { x: window.pageXOffset, y: window.pageYOffset, - }; + } } - return this.executeScript(getScrollPosition); + return this.executeScript(getScrollPosition) } /** * {{> seeTitleEquals }} */ async seeTitleEquals(text) { - const title = await this.page.title(); - return equals('web page title').assert(title, text); + const title = await this.page.title() + return equals('web page title').assert(title, text) } /** * {{> dontSeeInTitle }} */ async dontSeeInTitle(text) { - const title = await this.page.title(); - stringIncludes('web page title').negate(text, title); + const title = await this.page.title() + stringIncludes('web page title').negate(text, title) } /** * {{> grabTitle }} */ async grabTitle() { - return this.page.title(); + return this.page.title() } /** @@ -1245,11 +1245,11 @@ class Playwright extends Helper { * ``` */ async _locate(locator) { - const context = await this._getContext(); + const context = await this._getContext() - if (this.frame) return findElements(this.frame, locator); + if (this.frame) return findElements(this.frame, locator) - return findElements(context, locator); + return findElements(context, locator) } /** @@ -1261,8 +1261,8 @@ class Playwright extends Helper { * ``` */ async _locateElement(locator) { - const context = await this._getContext(); - return findElement(context, locator); + const context = await this._getContext() + return findElement(context, locator) } /** @@ -1274,10 +1274,10 @@ class Playwright extends Helper { * ``` */ async _locateCheckable(locator, providedContext = null) { - const context = providedContext || (await this._getContext()); - const els = await findCheckable.call(this, locator, context); - assertElementExists(els[0], locator, 'Checkbox or radio'); - return els[0]; + const context = providedContext || (await this._getContext()) + const els = await findCheckable.call(this, locator, context) + assertElementExists(els[0], locator, 'Checkbox or radio') + return els[0] } /** @@ -1288,8 +1288,8 @@ class Playwright extends Helper { * ``` */ async _locateClickable(locator) { - const context = await this._getContext(); - return findClickable.call(this, context, locator); + const context = await this._getContext() + return findClickable.call(this, context, locator) } /** @@ -1300,7 +1300,7 @@ class Playwright extends Helper { * ``` */ async _locateFields(locator) { - return findFields.call(this, locator); + return findFields.call(this, locator) } /** @@ -1308,7 +1308,7 @@ class Playwright extends Helper { * */ async grabWebElements(locator) { - return this._locate(locator); + return this._locate(locator) } /** @@ -1316,7 +1316,7 @@ class Playwright extends Helper { * */ async grabWebElement(locator) { - return this._locateElement(locator); + return this._locateElement(locator) } /** @@ -1331,20 +1331,20 @@ class Playwright extends Helper { */ async switchToNextTab(num = 1) { if (this.isElectron) { - throw new Error('Cannot switch tabs inside an Electron container'); + throw new Error('Cannot switch tabs inside an Electron container') } - const pages = await this.browserContext.pages(); + const pages = await this.browserContext.pages() - const index = pages.indexOf(this.page); - this.withinLocator = null; - const page = pages[index + num]; + const index = pages.indexOf(this.page) + this.withinLocator = null + const page = pages[index + num] if (!page) { - throw new Error(`There is no ability to switch to next tab with offset ${num}`); + throw new Error(`There is no ability to switch to next tab with offset ${num}`) } - await targetCreatedHandler.call(this, page); - await this._setPage(page); - return this._waitForAction(); + await targetCreatedHandler.call(this, page) + await this._setPage(page) + return this._waitForAction() } /** @@ -1358,19 +1358,19 @@ class Playwright extends Helper { */ async switchToPreviousTab(num = 1) { if (this.isElectron) { - throw new Error('Cannot switch tabs inside an Electron container'); + throw new Error('Cannot switch tabs inside an Electron container') } - const pages = await this.browserContext.pages(); - const index = pages.indexOf(this.page); - this.withinLocator = null; - const page = pages[index - num]; + const pages = await this.browserContext.pages() + const index = pages.indexOf(this.page) + this.withinLocator = null + const page = pages[index - num] if (!page) { - throw new Error(`There is no ability to switch to previous tab with offset ${num}`); + throw new Error(`There is no ability to switch to previous tab with offset ${num}`) } - await this._setPage(page); - return this._waitForAction(); + await this._setPage(page) + return this._waitForAction() } /** @@ -1382,12 +1382,12 @@ class Playwright extends Helper { */ async closeCurrentTab() { if (this.isElectron) { - throw new Error('Cannot close current tab inside an Electron container'); + throw new Error('Cannot close current tab inside an Electron container') } - const oldPage = this.page; - await this.switchToPreviousTab(); - await oldPage.close(); - return this._waitForAction(); + const oldPage = this.page + await this.switchToPreviousTab() + await oldPage.close() + return this._waitForAction() } /** @@ -1398,13 +1398,13 @@ class Playwright extends Helper { * ``` */ async closeOtherTabs() { - const pages = await this.browserContext.pages(); - const otherPages = pages.filter(page => page !== this.page); + const pages = await this.browserContext.pages() + const otherPages = pages.filter(page => page !== this.page) if (otherPages.length) { - this.debug(`Closing ${otherPages.length} tabs`); - return Promise.all(otherPages.map(p => p.close())); + this.debug(`Closing ${otherPages.length} tabs`) + return Promise.all(otherPages.map(p => p.close())) } - return Promise.resolve(); + return Promise.resolve() } /** @@ -1423,20 +1423,20 @@ class Playwright extends Helper { */ async openNewTab(options) { if (this.isElectron) { - throw new Error('Cannot open new tabs inside an Electron container'); + throw new Error('Cannot open new tabs inside an Electron container') } - const page = await this.browserContext.newPage(options); - await targetCreatedHandler.call(this, page); - await this._setPage(page); - return this._waitForAction(); + const page = await this.browserContext.newPage(options) + await targetCreatedHandler.call(this, page) + await this._setPage(page) + return this._waitForAction() } /** * {{> grabNumberOfOpenTabs }} */ async grabNumberOfOpenTabs() { - const pages = await this.browserContext.pages(); - return pages.length; + const pages = await this.browserContext.pages() + return pages.length } /** @@ -1444,12 +1444,12 @@ class Playwright extends Helper { * */ async seeElement(locator) { - let els = await this._locate(locator); - els = await Promise.all(els.map(el => el.isVisible())); + let els = await this._locate(locator) + els = await Promise.all(els.map(el => el.isVisible())) try { - return empty('visible elements').negate(els.filter(v => v).fill('ELEMENT')); + return empty('visible elements').negate(els.filter(v => v).fill('ELEMENT')) } catch (e) { - dontSeeElementError(locator); + dontSeeElementError(locator) } } @@ -1458,12 +1458,12 @@ class Playwright extends Helper { * */ async dontSeeElement(locator) { - let els = await this._locate(locator); - els = await Promise.all(els.map(el => el.isVisible())); + let els = await this._locate(locator) + els = await Promise.all(els.map(el => el.isVisible())) try { - return empty('visible elements').assert(els.filter(v => v).fill('ELEMENT')); + return empty('visible elements').assert(els.filter(v => v).fill('ELEMENT')) } catch (e) { - seeElementError(locator); + seeElementError(locator) } } @@ -1471,11 +1471,11 @@ class Playwright extends Helper { * {{> seeElementInDOM }} */ async seeElementInDOM(locator) { - const els = await this._locate(locator); + const els = await this._locate(locator) try { - return empty('elements on page').negate(els.filter(v => v).fill('ELEMENT')); + return empty('elements on page').negate(els.filter(v => v).fill('ELEMENT')) } catch (e) { - dontSeeElementInDOMError(locator); + dontSeeElementInDOMError(locator) } } @@ -1483,11 +1483,11 @@ class Playwright extends Helper { * {{> dontSeeElementInDOM }} */ async dontSeeElementInDOM(locator) { - const els = await this._locate(locator); + const els = await this._locate(locator) try { - return empty('elements on a page').assert(els.filter(v => v).fill('ELEMENT')); + return empty('elements on a page').assert(els.filter(v => v).fill('ELEMENT')) } catch (e) { - seeElementInDOMError(locator); + seeElementInDOMError(locator) } } @@ -1510,18 +1510,18 @@ class Playwright extends Helper { */ async handleDownloads(fileName) { this.page.waitForEvent('download').then(async download => { - const filePath = await download.path(); - fileName = fileName || `downloads/${path.basename(filePath)}`; + const filePath = await download.path() + fileName = fileName || `downloads/${path.basename(filePath)}` - const downloadPath = path.join(global.output_dir, fileName); + const downloadPath = path.join(global.output_dir, fileName) if (!fs.existsSync(path.dirname(downloadPath))) { - fs.mkdirSync(path.dirname(downloadPath), '0777'); + fs.mkdirSync(path.dirname(downloadPath), '0777') } - fs.copyFileSync(filePath, downloadPath); - this.debug('Download completed'); - this.debugSection('Downloaded From', await download.url()); - this.debugSection('Downloaded To', downloadPath); - }); + fs.copyFileSync(filePath, downloadPath) + this.debug('Download completed') + this.debugSection('Downloaded From', await download.url()) + this.debugSection('Downloaded To', downloadPath) + }) } /** @@ -1541,37 +1541,37 @@ class Playwright extends Helper { * */ async click(locator, context = null, options = {}) { - return proceedClick.call(this, locator, context, options); + return proceedClick.call(this, locator, context, options) } /** * Clicks link and waits for navigation (deprecated) */ async clickLink(locator, context = null) { - console.log('clickLink deprecated: Playwright automatically waits for navigation to happen.'); - console.log('Replace I.clickLink with I.click'); - return this.click(locator, context); + console.log('clickLink deprecated: Playwright automatically waits for navigation to happen.') + console.log('Replace I.clickLink with I.click') + return this.click(locator, context) } /** * {{> forceClick }} */ async forceClick(locator, context = null) { - return proceedClick.call(this, locator, context, { force: true }); + return proceedClick.call(this, locator, context, { force: true }) } /** * {{> doubleClick }} */ async doubleClick(locator, context = null) { - return proceedClick.call(this, locator, context, { clickCount: 2 }); + return proceedClick.call(this, locator, context, { clickCount: 2 }) } /** * {{> rightClick }} */ async rightClick(locator, context = null) { - return proceedClick.call(this, locator, context, { button: 'right' }); + return proceedClick.call(this, locator, context, { button: 'right' }) } /** @@ -1590,9 +1590,9 @@ class Playwright extends Helper { * */ async checkOption(field, context = null, options = { force: true }) { - const elm = await this._locateCheckable(field, context); - await elm.check(options); - return this._waitForAction(); + const elm = await this._locateCheckable(field, context) + await elm.check(options) + return this._waitForAction() } /** @@ -1610,41 +1610,41 @@ class Playwright extends Helper { * {{> uncheckOption }} */ async uncheckOption(field, context = null, options = { force: true }) { - const elm = await this._locateCheckable(field, context); - await elm.uncheck(options); - return this._waitForAction(); + const elm = await this._locateCheckable(field, context) + await elm.uncheck(options) + return this._waitForAction() } /** * {{> seeCheckboxIsChecked }} */ async seeCheckboxIsChecked(field) { - return proceedIsChecked.call(this, 'assert', field); + return proceedIsChecked.call(this, 'assert', field) } /** * {{> dontSeeCheckboxIsChecked }} */ async dontSeeCheckboxIsChecked(field) { - return proceedIsChecked.call(this, 'negate', field); + return proceedIsChecked.call(this, 'negate', field) } /** * {{> pressKeyDown }} */ async pressKeyDown(key) { - key = getNormalizedKey.call(this, key); - await this.page.keyboard.down(key); - return this._waitForAction(); + key = getNormalizedKey.call(this, key) + await this.page.keyboard.down(key) + return this._waitForAction() } /** * {{> pressKeyUp }} */ async pressKeyUp(key) { - key = getNormalizedKey.call(this, key); - await this.page.keyboard.up(key); - return this._waitForAction(); + key = getNormalizedKey.call(this, key) + await this.page.keyboard.up(key) + return this._waitForAction() } /** @@ -1654,28 +1654,28 @@ class Playwright extends Helper { * {{> pressKeyWithKeyNormalization }} */ async pressKey(key) { - const modifiers = []; + const modifiers = [] if (Array.isArray(key)) { for (let k of key) { - k = getNormalizedKey.call(this, k); + k = getNormalizedKey.call(this, k) if (isModifierKey(k)) { - modifiers.push(k); + modifiers.push(k) } else { - key = k; - break; + key = k + break } } } else { - key = getNormalizedKey.call(this, key); + key = getNormalizedKey.call(this, key) } for (const modifier of modifiers) { - await this.page.keyboard.down(modifier); + await this.page.keyboard.down(modifier) } - await this.page.keyboard.press(key); + await this.page.keyboard.press(key) for (const modifier of modifiers) { - await this.page.keyboard.up(modifier); + await this.page.keyboard.up(modifier) } - return this._waitForAction(); + return this._waitForAction() } /** @@ -1683,13 +1683,13 @@ class Playwright extends Helper { */ async type(keys, delay = null) { if (!Array.isArray(keys)) { - keys = keys.toString(); - keys = keys.split(''); + keys = keys.toString() + keys = keys.split('') } for (const key of keys) { - await this.page.keyboard.press(key); - if (delay) await this.wait(delay / 1000); + await this.page.keyboard.press(key) + if (delay) await this.wait(delay / 1000) } } @@ -1698,17 +1698,17 @@ class Playwright extends Helper { * */ async fillField(field, value) { - const els = await findFields.call(this, field); - assertElementExists(els, field, 'Field'); - const el = els[0]; + const els = await findFields.call(this, field) + assertElementExists(els, field, 'Field') + const el = els[0] - await el.clear(); + await el.clear() - await highlightActiveElement.call(this, el); + await highlightActiveElement.call(this, el) - await el.type(value.toString(), { delay: this.options.pressKeyDelay }); + await el.type(value.toString(), { delay: this.options.pressKeyDelay }) - return this._waitForAction(); + return this._waitForAction() } /** @@ -1729,44 +1729,44 @@ class Playwright extends Helper { * @param {any} [options] [Additional options](https://playwright.dev/docs/api/class-locator#locator-clear) for available options object as 2nd argument. */ async clearField(locator, options = {}) { - const els = await findFields.call(this, locator); - assertElementExists(els, locator, 'Field to clear'); + const els = await findFields.call(this, locator) + assertElementExists(els, locator, 'Field to clear') - const el = els[0]; + const el = els[0] - await highlightActiveElement.call(this, el); + await highlightActiveElement.call(this, el) - await el.clear(); + await el.clear() - return this._waitForAction(); + return this._waitForAction() } /** * {{> appendField }} */ async appendField(field, value) { - const els = await findFields.call(this, field); - assertElementExists(els, field, 'Field'); - await highlightActiveElement.call(this, els[0]); - await els[0].press('End'); - await els[0].type(value.toString(), { delay: this.options.pressKeyDelay }); - return this._waitForAction(); + const els = await findFields.call(this, field) + assertElementExists(els, field, 'Field') + await highlightActiveElement.call(this, els[0]) + await els[0].press('End') + await els[0].type(value.toString(), { delay: this.options.pressKeyDelay }) + return this._waitForAction() } /** * {{> seeInField }} */ async seeInField(field, value) { - const _value = typeof value === 'boolean' ? value : value.toString(); - return proceedSeeInField.call(this, 'assert', field, _value); + const _value = typeof value === 'boolean' ? value : value.toString() + return proceedSeeInField.call(this, 'assert', field, _value) } /** * {{> dontSeeInField }} */ async dontSeeInField(field, value) { - const _value = typeof value === 'boolean' ? value : value.toString(); - return proceedSeeInField.call(this, 'negate', field, _value); + const _value = typeof value === 'boolean' ? value : value.toString() + return proceedSeeInField.call(this, 'negate', field, _value) } /** @@ -1774,38 +1774,38 @@ class Playwright extends Helper { * */ async attachFile(locator, pathToFile) { - const file = path.join(global.codecept_dir, pathToFile); + const file = path.join(global.codecept_dir, pathToFile) if (!fileExists(file)) { - throw new Error(`File at ${file} can not be found on local system`); + throw new Error(`File at ${file} can not be found on local system`) } - const els = await findFields.call(this, locator); - assertElementExists(els, locator, 'Field'); - await els[0].setInputFiles(file); - return this._waitForAction(); + const els = await findFields.call(this, locator) + assertElementExists(els, locator, 'Field') + await els[0].setInputFiles(file) + return this._waitForAction() } /** * {{> selectOption }} */ async selectOption(select, option) { - const els = await findFields.call(this, select); - assertElementExists(els, select, 'Selectable field'); - const el = els[0]; + const els = await findFields.call(this, select) + assertElementExists(els, select, 'Selectable field') + const el = els[0] - await highlightActiveElement.call(this, el); - let optionToSelect = ''; + await highlightActiveElement.call(this, el) + let optionToSelect = '' try { - optionToSelect = (await el.locator('option', { hasText: option }).textContent()).trim(); + optionToSelect = (await el.locator('option', { hasText: option }).textContent()).trim() } catch (e) { - optionToSelect = option; + optionToSelect = option } - if (!Array.isArray(option)) option = [optionToSelect]; + if (!Array.isArray(option)) option = [optionToSelect] - await el.selectOption(option); - return this._waitForAction(); + await el.selectOption(option) + return this._waitForAction() } /** @@ -1813,37 +1813,37 @@ class Playwright extends Helper { * */ async grabNumberOfVisibleElements(locator) { - let els = await this._locate(locator); - els = await Promise.all(els.map(el => el.isVisible())); - return els.filter(v => v).length; + let els = await this._locate(locator) + els = await Promise.all(els.map(el => el.isVisible())) + return els.filter(v => v).length } /** * {{> seeInCurrentUrl }} */ async seeInCurrentUrl(url) { - stringIncludes('url').assert(url, await this._getPageUrl()); + stringIncludes('url').assert(url, await this._getPageUrl()) } /** * {{> dontSeeInCurrentUrl }} */ async dontSeeInCurrentUrl(url) { - stringIncludes('url').negate(url, await this._getPageUrl()); + stringIncludes('url').negate(url, await this._getPageUrl()) } /** * {{> seeCurrentUrlEquals }} */ async seeCurrentUrlEquals(url) { - urlEquals(this.options.url).assert(url, await this._getPageUrl()); + urlEquals(this.options.url).assert(url, await this._getPageUrl()) } /** * {{> dontSeeCurrentUrlEquals }} */ async dontSeeCurrentUrlEquals(url) { - urlEquals(this.options.url).negate(url, await this._getPageUrl()); + urlEquals(this.options.url).negate(url, await this._getPageUrl()) } /** @@ -1852,14 +1852,14 @@ class Playwright extends Helper { * */ async see(text, context = null) { - return proceedSee.call(this, 'assert', text, context); + return proceedSee.call(this, 'assert', text, context) } /** * {{> seeTextEquals }} */ async seeTextEquals(text, context = null) { - return proceedSee.call(this, 'assert', text, context, true); + return proceedSee.call(this, 'assert', text, context, true) } /** @@ -1868,14 +1868,14 @@ class Playwright extends Helper { * */ async dontSee(text, context = null) { - return proceedSee.call(this, 'negate', text, context); + return proceedSee.call(this, 'negate', text, context) } /** * {{> grabSource }} */ async grabSource() { - return this.page.content(); + return this.page.content() } /** @@ -1890,32 +1890,32 @@ class Playwright extends Helper { * @return {Promise} */ async grabBrowserLogs() { - const logs = consoleLogStore.entries; - consoleLogStore.clear(); - return logs; + const logs = consoleLogStore.entries + consoleLogStore.clear() + return logs } /** * {{> grabCurrentUrl }} */ async grabCurrentUrl() { - return this._getPageUrl(); + return this._getPageUrl() } /** * {{> seeInSource }} */ async seeInSource(text) { - const source = await this.page.content(); - stringIncludes('HTML source of a page').assert(text, source); + const source = await this.page.content() + stringIncludes('HTML source of a page').assert(text, source) } /** * {{> dontSeeInSource }} */ async dontSeeInSource(text) { - const source = await this.page.content(); - stringIncludes('HTML source of a page').negate(text, source); + const source = await this.page.content() + stringIncludes('HTML source of a page').negate(text, source) } /** @@ -1924,8 +1924,8 @@ class Playwright extends Helper { * */ async seeNumberOfElements(locator, num) { - const elements = await this._locate(locator); - return equals(`expected number of elements (${new Locator(locator)}) is ${num}, but found ${elements.length}`).assert(elements.length, num); + const elements = await this._locate(locator) + return equals(`expected number of elements (${new Locator(locator)}) is ${num}, but found ${elements.length}`).assert(elements.length, num) } /** @@ -1934,8 +1934,8 @@ class Playwright extends Helper { * */ async seeNumberOfVisibleElements(locator, num) { - const res = await this.grabNumberOfVisibleElements(locator); - return equals(`expected number of visible elements (${new Locator(locator)}) is ${num}, but found ${res}`).assert(res, num); + const res = await this.grabNumberOfVisibleElements(locator) + return equals(`expected number of visible elements (${new Locator(locator)}) is ${num}, but found ${res}`).assert(res, num) } /** @@ -1943,9 +1943,9 @@ class Playwright extends Helper { */ async setCookie(cookie) { if (Array.isArray(cookie)) { - return this.browserContext.addCookies(cookie); + return this.browserContext.addCookies(cookie) } - return this.browserContext.addCookies([cookie]); + return this.browserContext.addCookies([cookie]) } /** @@ -1953,16 +1953,16 @@ class Playwright extends Helper { * */ async seeCookie(name) { - const cookies = await this.browserContext.cookies(); - empty(`cookie ${name} to be set`).negate(cookies.filter(c => c.name === name)); + const cookies = await this.browserContext.cookies() + empty(`cookie ${name} to be set`).negate(cookies.filter(c => c.name === name)) } /** * {{> dontSeeCookie }} */ async dontSeeCookie(name) { - const cookies = await this.browserContext.cookies(); - empty(`cookie ${name} not to be set`).assert(cookies.filter(c => c.name === name)); + const cookies = await this.browserContext.cookies() + empty(`cookie ${name} not to be set`).assert(cookies.filter(c => c.name === name)) } /** @@ -1971,10 +1971,10 @@ class Playwright extends Helper { * {{> grabCookie }} */ async grabCookie(name) { - const cookies = await this.browserContext.cookies(); - if (!name) return cookies; - const cookie = cookies.filter(c => c.name === name); - if (cookie[0]) return cookie[0]; + const cookies = await this.browserContext.cookies() + if (!name) return cookies + const cookie = cookies.filter(c => c.name === name) + if (cookie[0]) return cookie[0] } /** @@ -1983,8 +1983,8 @@ class Playwright extends Helper { async clearCookie() { // Playwright currently doesn't support to delete a certain cookie // https://github.com/microsoft/playwright/blob/main/docs/src/api/class-browsercontext.md#async-method-browsercontextclearcookies - if (!this.browserContext) return; - return this.browserContext.clearCookies(); + if (!this.browserContext) return + return this.browserContext.clearCookies() } /** @@ -2014,9 +2014,9 @@ class Playwright extends Helper { async executeScript(fn, arg) { if (this.context && this.context.constructor.name === 'FrameLocator') { // switching to iframe context - return this.context.locator(':root').evaluate(fn, arg); + return this.context.locator(':root').evaluate(fn, arg) } - return this.page.evaluate.apply(this.page, [fn, arg]); + return this.page.evaluate.apply(this.page, [fn, arg]) } /** @@ -2025,14 +2025,14 @@ class Playwright extends Helper { * @param {*} locator */ _contextLocator(locator) { - locator = buildLocatorString(new Locator(locator, 'css')); + locator = buildLocatorString(new Locator(locator, 'css')) if (this.contextLocator) { - const contextLocator = buildLocatorString(new Locator(this.contextLocator, 'css')); - locator = `${contextLocator} >> ${locator}`; + const contextLocator = buildLocatorString(new Locator(this.contextLocator, 'css')) + locator = `${contextLocator} >> ${locator}` } - return locator; + return locator } /** @@ -2040,11 +2040,11 @@ class Playwright extends Helper { * */ async grabTextFrom(locator) { - locator = this._contextLocator(locator); - const text = await this.page.textContent(locator); - assertElementExists(text, locator); - this.debugSection('Text', text); - return text; + locator = this._contextLocator(locator) + const text = await this.page.textContent(locator) + assertElementExists(text, locator) + this.debugSection('Text', text) + return text } /** @@ -2052,51 +2052,51 @@ class Playwright extends Helper { * */ async grabTextFromAll(locator) { - const els = await this._locate(locator); - const texts = []; + const els = await this._locate(locator) + const texts = [] for (const el of els) { - texts.push(await el.innerText()); + texts.push(await el.innerText()) } - this.debug(`Matched ${els.length} elements`); - return texts; + this.debug(`Matched ${els.length} elements`) + return texts } /** * {{> grabValueFrom }} */ async grabValueFrom(locator) { - const values = await this.grabValueFromAll(locator); - assertElementExists(values, locator); - this.debugSection('Value', values[0]); - return values[0]; + const values = await this.grabValueFromAll(locator) + assertElementExists(values, locator) + this.debugSection('Value', values[0]) + return values[0] } /** * {{> grabValueFromAll }} */ async grabValueFromAll(locator) { - const els = await findFields.call(this, locator); - this.debug(`Matched ${els.length} elements`); - return Promise.all(els.map(el => el.inputValue())); + const els = await findFields.call(this, locator) + this.debug(`Matched ${els.length} elements`) + return Promise.all(els.map(el => el.inputValue())) } /** * {{> grabHTMLFrom }} */ async grabHTMLFrom(locator) { - const html = await this.grabHTMLFromAll(locator); - assertElementExists(html, locator); - this.debugSection('HTML', html[0]); - return html[0]; + const html = await this.grabHTMLFromAll(locator) + assertElementExists(html, locator) + this.debugSection('HTML', html[0]) + return html[0] } /** * {{> grabHTMLFromAll }} */ async grabHTMLFromAll(locator) { - const els = await this._locate(locator); - this.debug(`Matched ${els.length} elements`); - return Promise.all(els.map(el => el.innerHTML())); + const els = await this._locate(locator) + this.debug(`Matched ${els.length} elements`) + return Promise.all(els.map(el => el.innerHTML())) } /** @@ -2104,10 +2104,10 @@ class Playwright extends Helper { * */ async grabCssPropertyFrom(locator, cssProperty) { - const cssValues = await this.grabCssPropertyFromAll(locator, cssProperty); - assertElementExists(cssValues, locator); - this.debugSection('CSS', cssValues[0]); - return cssValues[0]; + const cssValues = await this.grabCssPropertyFromAll(locator, cssProperty) + assertElementExists(cssValues, locator) + this.debugSection('CSS', cssValues[0]) + return cssValues[0] } /** @@ -2115,11 +2115,11 @@ class Playwright extends Helper { * */ async grabCssPropertyFromAll(locator, cssProperty) { - const els = await this._locate(locator); - this.debug(`Matched ${els.length} elements`); - const cssValues = await Promise.all(els.map(el => el.evaluate((el, cssProperty) => getComputedStyle(el).getPropertyValue(cssProperty), cssProperty))); + const els = await this._locate(locator) + this.debug(`Matched ${els.length} elements`) + const cssValues = await Promise.all(els.map(el => el.evaluate((el, cssProperty) => getComputedStyle(el).getPropertyValue(cssProperty), cssProperty))) - return cssValues; + return cssValues } /** @@ -2127,35 +2127,35 @@ class Playwright extends Helper { * */ async seeCssPropertiesOnElements(locator, cssProperties) { - const res = await this._locate(locator); - assertElementExists(res, locator); + const res = await this._locate(locator) + assertElementExists(res, locator) - const cssPropertiesCamelCase = convertCssPropertiesToCamelCase(cssProperties); - const elemAmount = res.length; - let props = []; + const cssPropertiesCamelCase = convertCssPropertiesToCamelCase(cssProperties) + const elemAmount = res.length + let props = [] for (const element of res) { for (const prop of Object.keys(cssProperties)) { - const cssProp = await this.grabCssPropertyFrom(locator, prop); + const cssProp = await this.grabCssPropertyFrom(locator, prop) if (isColorProperty(prop)) { - props.push(convertColorToRGBA(cssProp)); + props.push(convertColorToRGBA(cssProp)) } else { - props.push(cssProp); + props.push(cssProp) } } } - const values = Object.keys(cssPropertiesCamelCase).map(key => cssPropertiesCamelCase[key]); - if (!Array.isArray(props)) props = [props]; - let chunked = chunkArray(props, values.length); + const values = Object.keys(cssPropertiesCamelCase).map(key => cssPropertiesCamelCase[key]) + if (!Array.isArray(props)) props = [props] + let chunked = chunkArray(props, values.length) chunked = chunked.filter(val => { for (let i = 0; i < val.length; ++i) { // eslint-disable-next-line eqeqeq - if (val[i] != values[i]) return false; + if (val[i] != values[i]) return false } - return true; - }); - return equals(`all elements (${new Locator(locator)}) to have CSS property ${JSON.stringify(cssProperties)}`).assert(chunked.length, elemAmount); + return true + }) + return equals(`all elements (${new Locator(locator)}) to have CSS property ${JSON.stringify(cssProperties)}`).assert(chunked.length, elemAmount) } /** @@ -2163,30 +2163,30 @@ class Playwright extends Helper { * */ async seeAttributesOnElements(locator, attributes) { - const res = await this._locate(locator); - assertElementExists(res, locator); + const res = await this._locate(locator) + assertElementExists(res, locator) - const elemAmount = res.length; - const commands = []; + const elemAmount = res.length + const commands = [] res.forEach(el => { Object.keys(attributes).forEach(prop => { - commands.push(el.evaluate((el, attr) => el[attr] || el.getAttribute(attr), prop)); - }); - }); - let attrs = await Promise.all(commands); - const values = Object.keys(attributes).map(key => attributes[key]); - if (!Array.isArray(attrs)) attrs = [attrs]; - let chunked = chunkArray(attrs, values.length); + commands.push(el.evaluate((el, attr) => el[attr] || el.getAttribute(attr), prop)) + }) + }) + let attrs = await Promise.all(commands) + const values = Object.keys(attributes).map(key => attributes[key]) + if (!Array.isArray(attrs)) attrs = [attrs] + let chunked = chunkArray(attrs, values.length) chunked = chunked.filter(val => { for (let i = 0; i < val.length; ++i) { // the attribute could be a boolean - if (typeof val[i] === 'boolean') return val[i] === values[i]; + if (typeof val[i] === 'boolean') return val[i] === values[i] // if the attribute doesn't exist, returns false as well - if (!val[i] || !val[i].includes(values[i])) return false; + if (!val[i] || !val[i].includes(values[i])) return false } - return true; - }); - return equals(`all elements (${new Locator(locator)}) to have attributes ${JSON.stringify(attributes)}`).assert(chunked.length, elemAmount); + return true + }) + return equals(`all elements (${new Locator(locator)}) to have attributes ${JSON.stringify(attributes)}`).assert(chunked.length, elemAmount) } /** @@ -2194,21 +2194,21 @@ class Playwright extends Helper { * */ async dragSlider(locator, offsetX = 0) { - const src = await this._locateElement(locator); - assertElementExists(src, locator, 'Slider Element'); + const src = await this._locateElement(locator) + assertElementExists(src, locator, 'Slider Element') // Note: Using clickablePoint private api because the .BoundingBox does not take into account iframe offsets! - const sliderSource = await clickablePoint(src); + const sliderSource = await clickablePoint(src) // Drag start point - await this.page.mouse.move(sliderSource.x, sliderSource.y, { steps: 5 }); - await this.page.mouse.down(); + await this.page.mouse.move(sliderSource.x, sliderSource.y, { steps: 5 }) + await this.page.mouse.down() // Drag destination - await this.page.mouse.move(sliderSource.x + offsetX, sliderSource.y, { steps: 5 }); - await this.page.mouse.up(); + await this.page.mouse.move(sliderSource.x + offsetX, sliderSource.y, { steps: 5 }) + await this.page.mouse.up() - return this._waitForAction(); + return this._waitForAction() } /** @@ -2216,10 +2216,10 @@ class Playwright extends Helper { * */ async grabAttributeFrom(locator, attr) { - const attrs = await this.grabAttributeFromAll(locator, attr); - assertElementExists(attrs, locator); - this.debugSection('Attribute', attrs[0]); - return attrs[0]; + const attrs = await this.grabAttributeFromAll(locator, attr) + assertElementExists(attrs, locator) + this.debugSection('Attribute', attrs[0]) + return attrs[0] } /** @@ -2227,15 +2227,15 @@ class Playwright extends Helper { * */ async grabAttributeFromAll(locator, attr) { - const els = await this._locate(locator); - this.debug(`Matched ${els.length} elements`); - const array = []; + const els = await this._locate(locator) + this.debug(`Matched ${els.length} elements`) + const array = [] for (let index = 0; index < els.length; index++) { - array.push(await els[index].getAttribute(attr)); + array.push(await els[index].getAttribute(attr)) } - return array; + return array } /** @@ -2243,43 +2243,43 @@ class Playwright extends Helper { * */ async saveElementScreenshot(locator, fileName) { - const outputFile = screenshotOutputFolder(fileName); + const outputFile = screenshotOutputFolder(fileName) - const res = await this._locateElement(locator); - assertElementExists(res, locator); - const elem = res; - this.debug(`Screenshot of ${new Locator(locator)} element has been saved to ${outputFile}`); - return elem.screenshot({ path: outputFile, type: 'png' }); + const res = await this._locateElement(locator) + assertElementExists(res, locator) + const elem = res + this.debug(`Screenshot of ${new Locator(locator)} element has been saved to ${outputFile}`) + return elem.screenshot({ path: outputFile, type: 'png' }) } /** * {{> saveScreenshot }} */ async saveScreenshot(fileName, fullPage) { - const fullPageOption = fullPage || this.options.fullPageScreenshots; - let outputFile = screenshotOutputFolder(fileName); + const fullPageOption = fullPage || this.options.fullPageScreenshots + let outputFile = screenshotOutputFolder(fileName) - this.debug(`Screenshot is saving to ${outputFile}`); + this.debug(`Screenshot is saving to ${outputFile}`) await this.page.screenshot({ path: outputFile, fullPage: fullPageOption, type: 'png', - }); + }) if (this.activeSessionName) { for (const sessionName in this.sessionPages) { - const activeSessionPage = this.sessionPages[sessionName]; - outputFile = screenshotOutputFolder(`${sessionName}_${fileName}`); + const activeSessionPage = this.sessionPages[sessionName] + outputFile = screenshotOutputFolder(`${sessionName}_${fileName}`) - this.debug(`${sessionName} - Screenshot is saving to ${outputFile}`); + this.debug(`${sessionName} - Screenshot is saving to ${outputFile}`) if (activeSessionPage) { await activeSessionPage.screenshot({ path: outputFile, fullPage: fullPageOption, type: 'png', - }); + }) } } } @@ -2303,21 +2303,21 @@ class Playwright extends Helper { * @returns {Promise} response */ async makeApiRequest(method, url, options) { - method = method.toLowerCase(); - const allowedMethods = ['get', 'post', 'patch', 'head', 'fetch', 'delete']; + method = method.toLowerCase() + const allowedMethods = ['get', 'post', 'patch', 'head', 'fetch', 'delete'] if (!allowedMethods.includes(method)) { - throw new Error(`Method ${method} is not allowed, use the one from a list ${allowedMethods} or switch to using REST helper`); + throw new Error(`Method ${method} is not allowed, use the one from a list ${allowedMethods} or switch to using REST helper`) } if (url.startsWith('/')) { // local url - url = this.options.url + url; - this.debugSection('URL', url); + url = this.options.url + url + this.debugSection('URL', url) } - const response = await this.page.request[method](url, options); - this.debugSection('Status', response.status()); - this.debugSection('Response', await response.text()); + const response = await this.page.request[method](url, options) + this.debugSection('Status', response.status()) + this.debugSection('Response', await response.text()) // hook to allow JSON response handle this if (this.config.onResponse) { @@ -2326,71 +2326,71 @@ class Playwright extends Helper { status: response.status(), statusText: response.statusText(), headers: response.headers(), - }; - this.config.onResponse(axiosResponse); + } + this.config.onResponse(axiosResponse) } - return response; + return response } async _failed(test) { - await this._withinEnd(); + await this._withinEnd() if (!test.artifacts) { - test.artifacts = {}; + test.artifacts = {} } if (this.options.recordVideo && this.page && this.page.video()) { - test.artifacts.video = saveVideoForPage(this.page, `${test.title}.failed`); + test.artifacts.video = saveVideoForPage(this.page, `${test.title}.failed`) for (const sessionName in this.sessionPages) { - test.artifacts[`video_${sessionName}`] = saveVideoForPage(this.sessionPages[sessionName], `${test.title}_${sessionName}.failed`); + test.artifacts[`video_${sessionName}`] = saveVideoForPage(this.sessionPages[sessionName], `${test.title}_${sessionName}.failed`) } } if (this.options.trace) { - test.artifacts.trace = await saveTraceForContext(this.browserContext, `${test.title}.failed`); + test.artifacts.trace = await saveTraceForContext(this.browserContext, `${test.title}.failed`) for (const sessionName in this.sessionPages) { - if (!this.sessionPages[sessionName].context) continue; - test.artifacts[`trace_${sessionName}`] = await saveTraceForContext(this.sessionPages[sessionName].context, `${test.title}_${sessionName}.failed`); + if (!this.sessionPages[sessionName].context) continue + test.artifacts[`trace_${sessionName}`] = await saveTraceForContext(this.sessionPages[sessionName].context, `${test.title}_${sessionName}.failed`) } } if (this.options.recordHar) { - test.artifacts.har = this.currentRunningTest.artifacts.har; + test.artifacts.har = this.currentRunningTest.artifacts.har } } async _passed(test) { if (this.options.recordVideo && this.page && this.page.video()) { if (this.options.keepVideoForPassedTests) { - test.artifacts.video = saveVideoForPage(this.page, `${test.title}.passed`); + test.artifacts.video = saveVideoForPage(this.page, `${test.title}.passed`) for (const sessionName of Object.keys(this.sessionPages)) { - test.artifacts[`video_${sessionName}`] = saveVideoForPage(this.sessionPages[sessionName], `${test.title}_${sessionName}.passed`); + test.artifacts[`video_${sessionName}`] = saveVideoForPage(this.sessionPages[sessionName], `${test.title}_${sessionName}.passed`) } } else { this.page .video() .delete() - .catch(e => {}); + .catch(e => {}) } } if (this.options.trace) { if (this.options.keepTraceForPassedTests) { if (this.options.trace) { - test.artifacts.trace = await saveTraceForContext(this.browserContext, `${test.title}.passed`); + test.artifacts.trace = await saveTraceForContext(this.browserContext, `${test.title}.passed`) for (const sessionName in this.sessionPages) { - if (!this.sessionPages[sessionName].context) continue; - test.artifacts[`trace_${sessionName}`] = await saveTraceForContext(this.sessionPages[sessionName].context, `${test.title}_${sessionName}.passed`); + if (!this.sessionPages[sessionName].context) continue + test.artifacts[`trace_${sessionName}`] = await saveTraceForContext(this.sessionPages[sessionName].context, `${test.title}_${sessionName}.passed`) } } } else { - await this.browserContext.tracing.stop(); + await this.browserContext.tracing.stop() } } if (this.options.recordHar) { - test.artifacts.har = this.currentRunningTest.artifacts.har; + test.artifacts.har = this.currentRunningTest.artifacts.har } } @@ -2399,89 +2399,89 @@ class Playwright extends Helper { */ async wait(sec) { return new Promise(done => { - setTimeout(done, sec * 1000); - }); + setTimeout(done, sec * 1000) + }) } /** * {{> waitForEnabled }} */ async waitForEnabled(locator, sec) { - const waitTimeout = sec ? sec * 1000 : this.options.waitForTimeout; - locator = new Locator(locator, 'css'); + const waitTimeout = sec ? sec * 1000 : this.options.waitForTimeout + locator = new Locator(locator, 'css') - let waiter; - const context = await this._getContext(); + let waiter + const context = await this._getContext() if (!locator.isXPath()) { const valueFn = function ([locator]) { - return Array.from(document.querySelectorAll(locator)).filter(el => !el.disabled).length > 0; - }; - waiter = context.waitForFunction(valueFn, [locator.value], { timeout: waitTimeout }); + return Array.from(document.querySelectorAll(locator)).filter(el => !el.disabled).length > 0 + } + waiter = context.waitForFunction(valueFn, [locator.value], { timeout: waitTimeout }) } else { const enabledFn = function ([locator, $XPath]) { - eval($XPath); // eslint-disable-line no-eval - return $XPath(null, locator).filter(el => !el.disabled).length > 0; - }; - waiter = context.waitForFunction(enabledFn, [locator.value, $XPath.toString()], { timeout: waitTimeout }); + eval($XPath) // eslint-disable-line no-eval + return $XPath(null, locator).filter(el => !el.disabled).length > 0 + } + waiter = context.waitForFunction(enabledFn, [locator.value, $XPath.toString()], { timeout: waitTimeout }) } return waiter.catch(err => { - throw new Error(`element (${locator.toString()}) still not enabled after ${waitTimeout / 1000} sec\n${err.message}`); - }); + throw new Error(`element (${locator.toString()}) still not enabled after ${waitTimeout / 1000} sec\n${err.message}`) + }) } /** * {{> waitForDisabled }} */ async waitForDisabled(locator, sec) { - const waitTimeout = sec ? sec * 1000 : this.options.waitForTimeout; - locator = new Locator(locator, 'css'); + const waitTimeout = sec ? sec * 1000 : this.options.waitForTimeout + locator = new Locator(locator, 'css') - let waiter; - const context = await this._getContext(); + let waiter + const context = await this._getContext() if (!locator.isXPath()) { const valueFn = function ([locator]) { - return Array.from(document.querySelectorAll(locator)).filter(el => el.disabled).length > 0; - }; - waiter = context.waitForFunction(valueFn, [locator.value], { timeout: waitTimeout }); + return Array.from(document.querySelectorAll(locator)).filter(el => el.disabled).length > 0 + } + waiter = context.waitForFunction(valueFn, [locator.value], { timeout: waitTimeout }) } else { const disabledFn = function ([locator, $XPath]) { - eval($XPath); // eslint-disable-line no-eval - return $XPath(null, locator).filter(el => el.disabled).length > 0; - }; - waiter = context.waitForFunction(disabledFn, [locator.value, $XPath.toString()], { timeout: waitTimeout }); + eval($XPath) // eslint-disable-line no-eval + return $XPath(null, locator).filter(el => el.disabled).length > 0 + } + waiter = context.waitForFunction(disabledFn, [locator.value, $XPath.toString()], { timeout: waitTimeout }) } return waiter.catch(err => { - throw new Error(`element (${locator.toString()}) is still enabled after ${waitTimeout / 1000} sec\n${err.message}`); - }); + throw new Error(`element (${locator.toString()}) is still enabled after ${waitTimeout / 1000} sec\n${err.message}`) + }) } /** * {{> waitForValue }} */ async waitForValue(field, value, sec) { - const waitTimeout = sec ? sec * 1000 : this.options.waitForTimeout; - const locator = new Locator(field, 'css'); - const matcher = await this.context; - let waiter; - const context = await this._getContext(); + const waitTimeout = sec ? sec * 1000 : this.options.waitForTimeout + const locator = new Locator(field, 'css') + const matcher = await this.context + let waiter + const context = await this._getContext() if (!locator.isXPath()) { const valueFn = function ([locator, value]) { - return Array.from(document.querySelectorAll(locator)).filter(el => (el.value || '').indexOf(value) !== -1).length > 0; - }; - waiter = context.waitForFunction(valueFn, [locator.value, value], { timeout: waitTimeout }); + return Array.from(document.querySelectorAll(locator)).filter(el => (el.value || '').indexOf(value) !== -1).length > 0 + } + waiter = context.waitForFunction(valueFn, [locator.value, value], { timeout: waitTimeout }) } else { const valueFn = function ([locator, $XPath, value]) { - eval($XPath); // eslint-disable-line no-eval - return $XPath(null, locator).filter(el => (el.value || '').indexOf(value) !== -1).length > 0; - }; + eval($XPath) // eslint-disable-line no-eval + return $XPath(null, locator).filter(el => (el.value || '').indexOf(value) !== -1).length > 0 + } waiter = context.waitForFunction(valueFn, [locator.value, $XPath.toString(), value], { timeout: waitTimeout, - }); + }) } return waiter.catch(err => { - const loc = locator.toString(); - throw new Error(`element (${loc}) is not in DOM or there is no element(${loc}) with value "${value}" after ${waitTimeout / 1000} sec\n${err.message}`); - }); + const loc = locator.toString() + throw new Error(`element (${loc}) is not in DOM or there is no element(${loc}) with value "${value}" after ${waitTimeout / 1000} sec\n${err.message}`) + }) } /** @@ -2489,40 +2489,40 @@ class Playwright extends Helper { * */ async waitNumberOfVisibleElements(locator, num, sec) { - const waitTimeout = sec ? sec * 1000 : this.options.waitForTimeout; - locator = new Locator(locator, 'css'); + const waitTimeout = sec ? sec * 1000 : this.options.waitForTimeout + locator = new Locator(locator, 'css') - let waiter; - const context = await this._getContext(); + let waiter + const context = await this._getContext() if (locator.isCSS()) { const visibleFn = function ([locator, num]) { - const els = document.querySelectorAll(locator); + const els = document.querySelectorAll(locator) if (!els || els.length === 0) { - return false; + return false } - return Array.prototype.filter.call(els, el => el.offsetParent !== null).length === num; - }; - waiter = context.waitForFunction(visibleFn, [locator.value, num], { timeout: waitTimeout }); + return Array.prototype.filter.call(els, el => el.offsetParent !== null).length === num + } + waiter = context.waitForFunction(visibleFn, [locator.value, num], { timeout: waitTimeout }) } else { const visibleFn = function ([locator, $XPath, num]) { - eval($XPath); // eslint-disable-line no-eval - return $XPath(null, locator).filter(el => el.offsetParent !== null).length === num; - }; + eval($XPath) // eslint-disable-line no-eval + return $XPath(null, locator).filter(el => el.offsetParent !== null).length === num + } waiter = context.waitForFunction(visibleFn, [locator.value, $XPath.toString(), num], { timeout: waitTimeout, - }); + }) } return waiter.catch(err => { - throw new Error(`The number of elements (${locator.toString()}) is not ${num} after ${waitTimeout / 1000} sec\n${err.message}`); - }); + throw new Error(`The number of elements (${locator.toString()}) is not ${num} after ${waitTimeout / 1000} sec\n${err.message}`) + }) } /** * {{> waitForClickable }} */ async waitForClickable(locator, waitTimeout) { - console.log('I.waitForClickable is DEPRECATED: This is no longer needed, Playwright automatically waits for element to be clickable'); - console.log('Remove usage of this function'); + console.log('I.waitForClickable is DEPRECATED: This is no longer needed, Playwright automatically waits for element to be clickable') + console.log('Remove usage of this function') } /** @@ -2530,14 +2530,14 @@ class Playwright extends Helper { * */ async waitForElement(locator, sec) { - const waitTimeout = sec ? sec * 1000 : this.options.waitForTimeout; - locator = new Locator(locator, 'css'); + const waitTimeout = sec ? sec * 1000 : this.options.waitForTimeout + locator = new Locator(locator, 'css') - const context = await this._getContext(); + const context = await this._getContext() try { - await context.locator(buildLocatorString(locator)).first().waitFor({ timeout: waitTimeout, state: 'attached' }); + await context.locator(buildLocatorString(locator)).first().waitFor({ timeout: waitTimeout, state: 'attached' }) } catch (e) { - throw new Error(`element (${locator.toString()}) still not present on page after ${waitTimeout / 1000} sec\n${e.message}`); + throw new Error(`element (${locator.toString()}) still not present on page after ${waitTimeout / 1000} sec\n${e.message}`) } } @@ -2547,28 +2547,28 @@ class Playwright extends Helper { * {{> waitForVisible }} */ async waitForVisible(locator, sec) { - const waitTimeout = sec ? sec * 1000 : this.options.waitForTimeout; - locator = new Locator(locator, 'css'); - const context = await this._getContext(); - let count = 0; + const waitTimeout = sec ? sec * 1000 : this.options.waitForTimeout + locator = new Locator(locator, 'css') + const context = await this._getContext() + let count = 0 // we have this as https://github.com/microsoft/playwright/issues/26829 is not yet implemented - let waiter; + let waiter if (this.frame) { do { - waiter = await this.frame.locator(buildLocatorString(locator)).first().isVisible(); - await this.wait(1); - count += 1000; - if (waiter) break; - } while (count <= waitTimeout); + waiter = await this.frame.locator(buildLocatorString(locator)).first().isVisible() + await this.wait(1) + count += 1000 + if (waiter) break + } while (count <= waitTimeout) - if (!waiter) throw new Error(`element (${locator.toString()}) still not visible after ${waitTimeout / 1000} sec.`); + if (!waiter) throw new Error(`element (${locator.toString()}) still not visible after ${waitTimeout / 1000} sec.`) } try { - await context.locator(buildLocatorString(locator)).first().waitFor({ timeout: waitTimeout, state: 'visible' }); + await context.locator(buildLocatorString(locator)).first().waitFor({ timeout: waitTimeout, state: 'visible' }) } catch (e) { - throw new Error(`element (${locator.toString()}) still not visible after ${waitTimeout / 1000} sec\n${e.message}`); + throw new Error(`element (${locator.toString()}) still not visible after ${waitTimeout / 1000} sec\n${e.message}`) } } @@ -2576,29 +2576,29 @@ class Playwright extends Helper { * {{> waitForInvisible }} */ async waitForInvisible(locator, sec) { - const waitTimeout = sec ? sec * 1000 : this.options.waitForTimeout; - locator = new Locator(locator, 'css'); - const context = await this._getContext(); - let waiter; - let count = 0; + const waitTimeout = sec ? sec * 1000 : this.options.waitForTimeout + locator = new Locator(locator, 'css') + const context = await this._getContext() + let waiter + let count = 0 // we have this as https://github.com/microsoft/playwright/issues/26829 is not yet implemented if (this.frame) { do { - waiter = await this.frame.locator(buildLocatorString(locator)).first().isHidden(); - await this.wait(1); - count += 1000; - if (waiter) break; - } while (count <= waitTimeout); + waiter = await this.frame.locator(buildLocatorString(locator)).first().isHidden() + await this.wait(1) + count += 1000 + if (waiter) break + } while (count <= waitTimeout) - if (!waiter) throw new Error(`element (${locator.toString()}) still visible after ${waitTimeout / 1000} sec.`); - return; + if (!waiter) throw new Error(`element (${locator.toString()}) still visible after ${waitTimeout / 1000} sec.`) + return } try { - await context.locator(buildLocatorString(locator)).first().waitFor({ timeout: waitTimeout, state: 'hidden' }); + await context.locator(buildLocatorString(locator)).first().waitFor({ timeout: waitTimeout, state: 'hidden' }) } catch (e) { - throw new Error(`element (${locator.toString()}) still visible after ${waitTimeout / 1000} sec\n${e.message}`); + throw new Error(`element (${locator.toString()}) still visible after ${waitTimeout / 1000} sec\n${e.message}`) } } @@ -2606,23 +2606,23 @@ class Playwright extends Helper { * {{> waitToHide }} */ async waitToHide(locator, sec) { - const waitTimeout = sec ? sec * 1000 : this.options.waitForTimeout; - locator = new Locator(locator, 'css'); - const context = await this._getContext(); - let waiter; - let count = 0; + const waitTimeout = sec ? sec * 1000 : this.options.waitForTimeout + locator = new Locator(locator, 'css') + const context = await this._getContext() + let waiter + let count = 0 // we have this as https://github.com/microsoft/playwright/issues/26829 is not yet implemented if (this.frame) { do { - waiter = await this.frame.locator(buildLocatorString(locator)).first().isHidden(); - await this.wait(1); - count += 1000; - if (waiter) break; - } while (count <= waitTimeout); + waiter = await this.frame.locator(buildLocatorString(locator)).first().isHidden() + await this.wait(1) + count += 1000 + if (waiter) break + } while (count <= waitTimeout) - if (!waiter) throw new Error(`element (${locator.toString()}) still not hidden after ${waitTimeout / 1000} sec.`); - return; + if (!waiter) throw new Error(`element (${locator.toString()}) still not hidden after ${waitTimeout / 1000} sec.`) + return } return context @@ -2630,110 +2630,110 @@ class Playwright extends Helper { .first() .waitFor({ timeout: waitTimeout, state: 'hidden' }) .catch(err => { - throw new Error(`element (${locator.toString()}) still not hidden after ${waitTimeout / 1000} sec\n${err.message}`); - }); + throw new Error(`element (${locator.toString()}) still not hidden after ${waitTimeout / 1000} sec\n${err.message}`) + }) } /** * {{> waitForNumberOfTabs }} */ async waitForNumberOfTabs(expectedTabs, sec) { - const waitTimeout = sec ? sec * 1000 : this.options.waitForTimeout; - let currentTabs; - let count = 0; + const waitTimeout = sec ? sec * 1000 : this.options.waitForTimeout + let currentTabs + let count = 0 do { - currentTabs = await this.grabNumberOfOpenTabs(); - await this.wait(1); - count += 1000; - if (currentTabs >= expectedTabs) return; - } while (count <= waitTimeout); + currentTabs = await this.grabNumberOfOpenTabs() + await this.wait(1) + count += 1000 + if (currentTabs >= expectedTabs) return + } while (count <= waitTimeout) - throw new Error(`Expected ${expectedTabs} tabs are not met after ${waitTimeout / 1000} sec.`); + throw new Error(`Expected ${expectedTabs} tabs are not met after ${waitTimeout / 1000} sec.`) } async _getContext() { if ((this.context && this.context.constructor.name === 'FrameLocator') || this.context) { - return this.context; + return this.context } - return this.page; + return this.page } /** * {{> waitInUrl }} */ async waitInUrl(urlPart, sec = null) { - const waitTimeout = sec ? sec * 1000 : this.options.waitForTimeout; + const waitTimeout = sec ? sec * 1000 : this.options.waitForTimeout return this.page .waitForFunction( urlPart => { - const currUrl = decodeURIComponent(decodeURIComponent(decodeURIComponent(window.location.href))); - return currUrl.indexOf(urlPart) > -1; + const currUrl = decodeURIComponent(decodeURIComponent(decodeURIComponent(window.location.href))) + return currUrl.indexOf(urlPart) > -1 }, urlPart, { timeout: waitTimeout }, ) .catch(async e => { - const currUrl = await this._getPageUrl(); // Required because the waitForFunction can't return data. + const currUrl = await this._getPageUrl() // Required because the waitForFunction can't return data. if (/Timeout/i.test(e.message)) { - throw new Error(`expected url to include ${urlPart}, but found ${currUrl}`); + throw new Error(`expected url to include ${urlPart}, but found ${currUrl}`) } else { - throw e; + throw e } - }); + }) } /** * {{> waitUrlEquals }} */ async waitUrlEquals(urlPart, sec = null) { - const waitTimeout = sec ? sec * 1000 : this.options.waitForTimeout; + const waitTimeout = sec ? sec * 1000 : this.options.waitForTimeout - const baseUrl = this.options.url; + const baseUrl = this.options.url if (urlPart.indexOf('http') < 0) { - urlPart = baseUrl + urlPart; + urlPart = baseUrl + urlPart } return this.page .waitForFunction( urlPart => { - const currUrl = decodeURIComponent(decodeURIComponent(decodeURIComponent(window.location.href))); - return currUrl.indexOf(urlPart) > -1; + const currUrl = decodeURIComponent(decodeURIComponent(decodeURIComponent(window.location.href))) + return currUrl.indexOf(urlPart) > -1 }, urlPart, { timeout: waitTimeout }, ) .catch(async e => { - const currUrl = await this._getPageUrl(); // Required because the waitForFunction can't return data. + const currUrl = await this._getPageUrl() // Required because the waitForFunction can't return data. if (/Timeout/i.test(e.message)) { - throw new Error(`expected url to be ${urlPart}, but found ${currUrl}`); + throw new Error(`expected url to be ${urlPart}, but found ${currUrl}`) } else { - throw e; + throw e } - }); + }) } /** * {{> waitForText }} */ async waitForText(text, sec = null, context = null) { - const waitTimeout = sec ? sec * 1000 : this.options.waitForTimeout; - const errorMessage = `Text "${text}" was not found on page after ${waitTimeout / 1000} sec.`; - let waiter; + const waitTimeout = sec ? sec * 1000 : this.options.waitForTimeout + const errorMessage = `Text "${text}" was not found on page after ${waitTimeout / 1000} sec.` + let waiter - const contextObject = await this._getContext(); + const contextObject = await this._getContext() if (context) { - const locator = new Locator(context, 'css'); + const locator = new Locator(context, 'css') if (!locator.isXPath()) { try { await contextObject .locator(`${locator.isCustom() ? `${locator.type}=${locator.value}` : locator.simplify()} >> text=${text}`) .first() - .waitFor({ timeout: waitTimeout, state: 'visible' }); + .waitFor({ timeout: waitTimeout, state: 'visible' }) } catch (e) { - throw new Error(`${errorMessage}\n${e.message}`); + throw new Error(`${errorMessage}\n${e.message}`) } } @@ -2741,34 +2741,34 @@ class Playwright extends Helper { try { await contextObject.waitForFunction( ([locator, text, $XPath]) => { - eval($XPath); // eslint-disable-line no-eval - const el = $XPath(null, locator); - if (!el.length) return false; - return el[0].innerText.indexOf(text) > -1; + eval($XPath) // eslint-disable-line no-eval + const el = $XPath(null, locator) + if (!el.length) return false + return el[0].innerText.indexOf(text) > -1 }, [locator.value, text, $XPath.toString()], { timeout: waitTimeout }, - ); + ) } catch (e) { - throw new Error(`${errorMessage}\n${e.message}`); + throw new Error(`${errorMessage}\n${e.message}`) } } } else { // we have this as https://github.com/microsoft/playwright/issues/26829 is not yet implemented - const _contextObject = this.frame ? this.frame : contextObject; - let count = 0; + const _contextObject = this.frame ? this.frame : contextObject + let count = 0 do { waiter = await _contextObject .locator(`:has-text(${JSON.stringify(text)})`) .first() - .isVisible(); - if (waiter) break; - await this.wait(1); - count += 1000; - } while (count <= waitTimeout); + .isVisible() + if (waiter) break + await this.wait(1) + count += 1000 + } while (count <= waitTimeout) - if (!waiter) throw new Error(`${errorMessage}`); + if (!waiter) throw new Error(`${errorMessage}`) } } @@ -2784,8 +2784,8 @@ class Playwright extends Helper { * @param {?number} [sec=null] seconds to wait */ async waitForRequest(urlOrPredicate, sec = null) { - const timeout = sec ? sec * 1000 : this.options.waitForTimeout; - return this.page.waitForRequest(urlOrPredicate, { timeout }); + const timeout = sec ? sec * 1000 : this.options.waitForTimeout + return this.page.waitForRequest(urlOrPredicate, { timeout }) } /** @@ -2800,8 +2800,8 @@ class Playwright extends Helper { * @param {?number} [sec=null] number of seconds to wait */ async waitForResponse(urlOrPredicate, sec = null) { - const timeout = sec ? sec * 1000 : this.options.waitForTimeout; - return this.page.waitForResponse(urlOrPredicate, { timeout }); + const timeout = sec ? sec * 1000 : this.options.waitForTimeout + return this.page.waitForResponse(urlOrPredicate, { timeout }) } /** @@ -2811,51 +2811,51 @@ class Playwright extends Helper { if (Number.isInteger(locator)) { // Select by frame index of current context - let childFrames = null; + let childFrames = null if (this.context && typeof this.context.childFrames === 'function') { - childFrames = this.context.childFrames(); + childFrames = this.context.childFrames() } else { - childFrames = this.page.mainFrame().childFrames(); + childFrames = this.page.mainFrame().childFrames() } if (locator >= 0 && locator < childFrames.length) { - this.context = await this.page.frameLocator('iframe').nth(locator); - this.contextLocator = locator; + this.context = await this.page.frameLocator('iframe').nth(locator) + this.contextLocator = locator } else { - throw new Error('Element #invalidIframeSelector was not found by text|CSS|XPath'); + throw new Error('Element #invalidIframeSelector was not found by text|CSS|XPath') } - return; + return } if (!locator) { - this.context = this.page; - this.contextLocator = null; - this.frame = null; - return; + this.context = this.page + this.contextLocator = null + this.frame = null + return } // iframe by selector - locator = buildLocatorString(new Locator(locator, 'css')); - const frame = await this._locateElement(locator); + locator = buildLocatorString(new Locator(locator, 'css')) + const frame = await this._locateElement(locator) if (!frame) { - throw new Error(`Frame ${JSON.stringify(locator)} was not found by text|CSS|XPath`); + throw new Error(`Frame ${JSON.stringify(locator)} was not found by text|CSS|XPath`) } if (this.frame) { - this.frame = await this.frame.frameLocator(locator); + this.frame = await this.frame.frameLocator(locator) } else { - this.frame = await this.page.frameLocator(locator); + this.frame = await this.page.frameLocator(locator) } - const contentFrame = this.frame; + const contentFrame = this.frame if (contentFrame) { - this.context = contentFrame; - this.contextLocator = null; + this.context = contentFrame + this.contextLocator = null } else { - this.context = this.page.frame(this.page.frames()[1].name()); - this.contextLocator = locator; + this.context = this.page.frame(this.page.frames()[1].name()) + this.contextLocator = locator } } @@ -2863,17 +2863,17 @@ class Playwright extends Helper { * {{> waitForFunction }} */ async waitForFunction(fn, argsOrSec = null, sec = null) { - let args = []; + let args = [] if (argsOrSec) { if (Array.isArray(argsOrSec)) { - args = argsOrSec; + args = argsOrSec } else if (typeof argsOrSec === 'number') { - sec = argsOrSec; + sec = argsOrSec } } - const waitTimeout = sec ? sec * 1000 : this.options.waitForTimeout; - const context = await this._getContext(); - return context.waitForFunction(fn, args, { timeout: waitTimeout }); + const waitTimeout = sec ? sec * 1000 : this.options.waitForTimeout + const context = await this._getContext() + return context.waitForFunction(fn, args, { timeout: waitTimeout }) } /** @@ -2885,13 +2885,13 @@ class Playwright extends Helper { */ async waitForNavigation(options = {}) { console.log(`waitForNavigation deprecated: - * This method is inherently racy, please use 'waitForURL' instead.`); + * This method is inherently racy, please use 'waitForURL' instead.`) options = { timeout: this.options.getPageTimeout, waitUntil: this.options.waitForNavigation, ...options, - }; - return this.page.waitForNavigation(options); + } + return this.page.waitForNavigation(options) } /** @@ -2907,44 +2907,44 @@ class Playwright extends Helper { timeout: this.options.getPageTimeout, waitUntil: this.options.waitForNavigation, ...options, - }; - return this.page.waitForURL(url, options); + } + return this.page.waitForURL(url, options) } async waitUntilExists(locator, sec) { console.log(`waitUntilExists deprecated: * use 'waitForElement' to wait for element to be attached - * use 'waitForDetached to wait for element to be removed'`); - return this.waitForDetached(locator, sec); + * use 'waitForDetached to wait for element to be removed'`) + return this.waitForDetached(locator, sec) } /** * {{> waitForDetached }} */ async waitForDetached(locator, sec) { - const waitTimeout = sec ? sec * 1000 : this.options.waitForTimeout; - locator = new Locator(locator, 'css'); + const waitTimeout = sec ? sec * 1000 : this.options.waitForTimeout + locator = new Locator(locator, 'css') - let waiter; - const context = await this._getContext(); + let waiter + const context = await this._getContext() if (!locator.isXPath()) { try { await context .locator(`${locator.isCustom() ? `${locator.type}=${locator.value}` : locator.simplify()}`) .first() - .waitFor({ timeout: waitTimeout, state: 'detached' }); + .waitFor({ timeout: waitTimeout, state: 'detached' }) } catch (e) { - throw new Error(`element (${locator.toString()}) still on page after ${waitTimeout / 1000} sec\n${e.message}`); + throw new Error(`element (${locator.toString()}) still on page after ${waitTimeout / 1000} sec\n${e.message}`) } } else { const visibleFn = function ([locator, $XPath]) { - eval($XPath); // eslint-disable-line no-eval - return $XPath(null, locator).length === 0; - }; - waiter = context.waitForFunction(visibleFn, [locator.value, $XPath.toString()], { timeout: waitTimeout }); + eval($XPath) // eslint-disable-line no-eval + return $XPath(null, locator).length === 0 + } + waiter = context.waitForFunction(visibleFn, [locator.value, $XPath.toString()], { timeout: waitTimeout }) return waiter.catch(err => { - throw new Error(`element (${locator.toString()}) still on page after ${waitTimeout / 1000} sec\n${err.message}`); - }); + throw new Error(`element (${locator.toString()}) still on page after ${waitTimeout / 1000} sec\n${err.message}`) + }) } } @@ -2953,56 +2953,56 @@ class Playwright extends Helper { */ async waitForCookie(name, sec) { // by default, we will retry 3 times - let retries = 3; - const waitTimeout = sec ? sec * 1000 : this.options.waitForTimeout; + let retries = 3 + const waitTimeout = sec ? sec * 1000 : this.options.waitForTimeout if (sec) { - retries = sec; + retries = sec } else { - retries = Math.ceil(waitTimeout / 1000) - 1; + retries = Math.ceil(waitTimeout / 1000) - 1 } return promiseRetry( async (retry, number) => { const _grabCookie = async name => { - const cookies = await this.browserContext.cookies(); - const cookie = cookies.filter(c => c.name === name); - if (cookie.length === 0) throw Error(`Cookie ${name} is not found after ${retries}s`); - }; + const cookies = await this.browserContext.cookies() + const cookie = cookies.filter(c => c.name === name) + if (cookie.length === 0) throw Error(`Cookie ${name} is not found after ${retries}s`) + } - this.debugSection('Wait for cookie: ', name); - if (number > 1) this.debugSection('Retrying... Attempt #', number); + this.debugSection('Wait for cookie: ', name) + if (number > 1) this.debugSection('Retrying... Attempt #', number) try { - await _grabCookie(name); + await _grabCookie(name) } catch (e) { - retry(e); + retry(e) } }, { retries, maxTimeout: 1000 }, - ); + ) } async _waitForAction() { - return this.wait(this.options.waitForAction / 1000); + return this.wait(this.options.waitForAction / 1000) } /** * {{> grabDataFromPerformanceTiming }} */ async grabDataFromPerformanceTiming() { - return perfTiming; + return perfTiming } /** * {{> grabElementBoundingRect }} */ async grabElementBoundingRect(locator, prop) { - const el = await this._locateElement(locator); - assertElementExists(el, locator); - const rect = await el.boundingBox(); - if (prop) return rect[prop]; - return rect; + const el = await this._locateElement(locator) + assertElementExists(el, locator) + const rect = await el.boundingBox() + if (prop) return rect[prop] + return rect } /** @@ -3017,7 +3017,7 @@ class Playwright extends Helper { * @param {function} [handler] a function to process request */ async mockRoute(url, handler) { - return this.browserContext.route(...arguments); + return this.browserContext.route(...arguments) } /** @@ -3033,7 +3033,7 @@ class Playwright extends Helper { * @param {function} [handler] a function to process request */ async stopMockingRoute(url, handler) { - return this.browserContext.unroute(...arguments); + return this.browserContext.unroute(...arguments) } /** @@ -3041,9 +3041,9 @@ class Playwright extends Helper { * */ startRecordingTraffic() { - this.flushNetworkTraffics(); - this.recording = true; - this.recordedAtLeastOnce = true; + this.flushNetworkTraffics() + this.recording = true + this.recordedAtLeastOnce = true this.page.on('requestfinished', async request => { const information = { @@ -3052,16 +3052,16 @@ class Playwright extends Helper { requestHeaders: request.headers(), requestPostData: request.postData(), response: request.response(), - }; + } - this.debugSection('REQUEST: ', JSON.stringify(information)); + this.debugSection('REQUEST: ', JSON.stringify(information)) if (typeof information.requestPostData === 'object') { - information.requestPostData = JSON.parse(information.requestPostData); + information.requestPostData = JSON.parse(information.requestPostData) } - this.requests.push(information); - }); + this.requests.push(information) + }) } /** @@ -3089,16 +3089,16 @@ class Playwright extends Helper { route .abort() // Sometimes it happens that browser has been closed in the meantime. It is ok to ignore error then. - .catch(e => {}); - }); - }); + .catch(e => {}) + }) + }) } else { this.page.route(urls, route => { route .abort() // Sometimes it happens that browser has been closed in the meantime. It is ok to ignore error then. - .catch(e => {}); - }); + .catch(e => {}) + }) } } @@ -3120,10 +3120,10 @@ class Playwright extends Helper { */ mockTraffic(urls, responseString, contentType = 'application/json') { // Required to mock cross-domain requests - const headers = { 'access-control-allow-origin': '*' }; + const headers = { 'access-control-allow-origin': '*' } if (typeof urls === 'string') { - urls = [urls]; + urls = [urls] } urls.forEach(url => { @@ -3131,15 +3131,15 @@ class Playwright extends Helper { if (this.page.isClosed()) { // Sometimes it happens that browser has been closed in the meantime. // In this case we just don't fulfill to prevent error in test scenario. - return; + return } route.fulfill({ contentType, headers, body: responseString, - }); - }); - }); + }) + }) + }) } /** @@ -3147,7 +3147,7 @@ class Playwright extends Helper { * {{> flushNetworkTraffics }} */ flushNetworkTraffics() { - flushNetworkTraffics.call(this); + flushNetworkTraffics.call(this) } /** @@ -3155,7 +3155,7 @@ class Playwright extends Helper { * {{> stopRecordingTraffic }} */ stopRecordingTraffic() { - stopRecordingTraffic.call(this); + stopRecordingTraffic.call(this) } /** @@ -3173,21 +3173,21 @@ class Playwright extends Helper { */ grabTrafficUrl(urlMatch) { if (!this.recordedAtLeastOnce) { - throw new Error('Failure in test automation. You use "I.grabTrafficUrl", but "I.startRecordingTraffic" was never called before.'); + throw new Error('Failure in test automation. You use "I.grabTrafficUrl", but "I.startRecordingTraffic" was never called before.') } for (const i in this.requests) { // eslint-disable-next-line no-prototype-builtins if (this.requests.hasOwnProperty(i)) { - const request = this.requests[i]; + const request = this.requests[i] if (request.url && request.url.match(new RegExp(urlMatch))) { - return request.url; + return request.url } } } - assert.fail(`Method "getTrafficUrl" failed: No request found in traffic that matches ${urlMatch}`); + assert.fail(`Method "getTrafficUrl" failed: No request found in traffic that matches ${urlMatch}`) } /** @@ -3195,7 +3195,7 @@ class Playwright extends Helper { * {{> grabRecordedNetworkTraffics }} */ async grabRecordedNetworkTraffics() { - return grabRecordedNetworkTraffics.call(this); + return grabRecordedNetworkTraffics.call(this) } /** @@ -3203,7 +3203,7 @@ class Playwright extends Helper { * {{> seeTraffic }} */ async seeTraffic({ name, url, parameters, requestPostData, timeout = 10 }) { - await seeTraffic.call(this, ...arguments); + await seeTraffic.call(this, ...arguments) } /** @@ -3212,42 +3212,42 @@ class Playwright extends Helper { * */ dontSeeTraffic({ name, url }) { - dontSeeTraffic.call(this, ...arguments); + dontSeeTraffic.call(this, ...arguments) } /** * {{> startRecordingWebSocketMessages }} */ async startRecordingWebSocketMessages() { - this.flushWebSocketMessages(); - this.recordingWebSocketMessages = true; - this.recordedWebSocketMessagesAtLeastOnce = true; + this.flushWebSocketMessages() + this.recordingWebSocketMessages = true + this.recordedWebSocketMessagesAtLeastOnce = true - this.cdpSession = await this.getNewCDPSession(); - await this.cdpSession.send('Network.enable'); - await this.cdpSession.send('Page.enable'); + this.cdpSession = await this.getNewCDPSession() + await this.cdpSession.send('Network.enable') + await this.cdpSession.send('Page.enable') this.cdpSession.on('Network.webSocketFrameReceived', payload => { - this._logWebsocketMessages(this._getWebSocketLog('RECEIVED', payload)); - }); + this._logWebsocketMessages(this._getWebSocketLog('RECEIVED', payload)) + }) this.cdpSession.on('Network.webSocketFrameSent', payload => { - this._logWebsocketMessages(this._getWebSocketLog('SENT', payload)); - }); + this._logWebsocketMessages(this._getWebSocketLog('SENT', payload)) + }) this.cdpSession.on('Network.webSocketFrameError', payload => { - this._logWebsocketMessages(this._getWebSocketLog('ERROR', payload)); - }); + this._logWebsocketMessages(this._getWebSocketLog('ERROR', payload)) + }) } /** * {{> stopRecordingWebSocketMessages }} */ async stopRecordingWebSocketMessages() { - await this.cdpSession.send('Network.disable'); - await this.cdpSession.send('Page.disable'); - this.page.removeAllListeners('Network'); - this.recordingWebSocketMessages = false; + await this.cdpSession.send('Network.disable') + await this.cdpSession.send('Page.disable') + this.page.removeAllListeners('Network') + this.recordingWebSocketMessages = false } /** @@ -3259,17 +3259,17 @@ class Playwright extends Helper { grabWebSocketMessages() { if (!this.recordingWebSocketMessages) { if (!this.recordedWebSocketMessagesAtLeastOnce) { - throw new Error('Failure in test automation. You use "I.grabWebSocketMessages", but "I.startRecordingWebSocketMessages" was never called before.'); + throw new Error('Failure in test automation. You use "I.grabWebSocketMessages", but "I.startRecordingWebSocketMessages" was never called before.') } } - return this.webSocketMessages; + return this.webSocketMessages } /** * Resets all recorded WS messages. */ flushWebSocketMessages() { - this.webSocketMessages = []; + this.webSocketMessages = [] } /** @@ -3327,344 +3327,344 @@ class Playwright extends Helper { * @return {Promise>} */ async grabMetrics() { - const client = await this.page.context().newCDPSession(this.page); - await client.send('Performance.enable'); - const perfMetricObject = await client.send('Performance.getMetrics'); - return perfMetricObject?.metrics; + const client = await this.page.context().newCDPSession(this.page) + await client.send('Performance.enable') + const perfMetricObject = await client.send('Performance.getMetrics') + return perfMetricObject?.metrics } _getWebSocketMessage(payload) { if (payload.errorMessage) { - return payload.errorMessage; + return payload.errorMessage } - return payload.response.payloadData; + return payload.response.payloadData } _getWebSocketLog(prefix, payload) { - return `${prefix} ID: ${payload.requestId} TIMESTAMP: ${payload.timestamp} (${new Date().toISOString()})\n\n${this._getWebSocketMessage(payload)}\n\n`; + return `${prefix} ID: ${payload.requestId} TIMESTAMP: ${payload.timestamp} (${new Date().toISOString()})\n\n${this._getWebSocketMessage(payload)}\n\n` } async getNewCDPSession() { - return this.page.context().newCDPSession(this.page); + return this.page.context().newCDPSession(this.page) } _logWebsocketMessages(message) { - this.webSocketMessages.push(message); + this.webSocketMessages.push(message) } } -module.exports = Playwright; +module.exports = Playwright function buildLocatorString(locator) { if (locator.isCustom()) { - return `${locator.type}=${locator.value}`; + return `${locator.type}=${locator.value}` } if (locator.isXPath()) { - return `xpath=${locator.value}`; + return `xpath=${locator.value}` } - return locator.simplify(); + return locator.simplify() } async function findElements(matcher, locator) { - if (locator.react) return findReact(matcher, locator); - if (locator.vue) return findVue(matcher, locator); - if (locator.pw) return findByPlaywrightLocator.call(this, matcher, locator); - locator = new Locator(locator, 'css'); + if (locator.react) return findReact(matcher, locator) + if (locator.vue) return findVue(matcher, locator) + if (locator.pw) return findByPlaywrightLocator.call(this, matcher, locator) + locator = new Locator(locator, 'css') - return matcher.locator(buildLocatorString(locator)).all(); + return matcher.locator(buildLocatorString(locator)).all() } async function findElement(matcher, locator) { - if (locator.react) return findReact(matcher, locator); - if (locator.vue) return findVue(matcher, locator); - if (locator.pw) return findByPlaywrightLocator.call(this, matcher, locator); - locator = new Locator(locator, 'css'); + if (locator.react) return findReact(matcher, locator) + if (locator.vue) return findVue(matcher, locator) + if (locator.pw) return findByPlaywrightLocator.call(this, matcher, locator) + locator = new Locator(locator, 'css') - return matcher.locator(buildLocatorString(locator)).first(); + return matcher.locator(buildLocatorString(locator)).first() } async function getVisibleElements(elements) { - const visibleElements = []; + const visibleElements = [] for (const element of elements) { if (await element.isVisible()) { - visibleElements.push(element); + visibleElements.push(element) } } if (visibleElements.length === 0) { - return elements; + return elements } - return visibleElements; + return visibleElements } async function proceedClick(locator, context = null, options = {}) { - let matcher = await this._getContext(); + let matcher = await this._getContext() if (context) { - const els = await this._locate(context); - assertElementExists(els, context); - matcher = els[0]; + const els = await this._locate(context) + assertElementExists(els, context) + matcher = els[0] } - const els = await findClickable.call(this, matcher, locator); + const els = await findClickable.call(this, matcher, locator) if (context) { - assertElementExists(els, locator, 'Clickable element', `was not found inside element ${new Locator(context).toString()}`); + assertElementExists(els, locator, 'Clickable element', `was not found inside element ${new Locator(context).toString()}`) } else { - assertElementExists(els, locator, 'Clickable element'); + assertElementExists(els, locator, 'Clickable element') } - await highlightActiveElement.call(this, els[0]); + await highlightActiveElement.call(this, els[0]) /* using the force true options itself but instead dispatching a click */ if (options.force) { - await els[0].dispatchEvent('click'); + await els[0].dispatchEvent('click') } else { - const element = els.length > 1 ? (await getVisibleElements(els))[0] : els[0]; - await element.click(options); + const element = els.length > 1 ? (await getVisibleElements(els))[0] : els[0] + await element.click(options) } - const promises = []; + const promises = [] if (options.waitForNavigation) { - promises.push(this.waitForURL(/.*/, { waitUntil: options.waitForNavigation })); + promises.push(this.waitForURL(/.*/, { waitUntil: options.waitForNavigation })) } - promises.push(this._waitForAction()); + promises.push(this._waitForAction()) - return Promise.all(promises); + return Promise.all(promises) } async function findClickable(matcher, locator) { - if (locator.react) return findReact(matcher, locator); - if (locator.vue) return findVue(matcher, locator); - if (locator.pw) return findByPlaywrightLocator.call(this, matcher, locator); + if (locator.react) return findReact(matcher, locator) + if (locator.vue) return findVue(matcher, locator) + if (locator.pw) return findByPlaywrightLocator.call(this, matcher, locator) - locator = new Locator(locator); - if (!locator.isFuzzy()) return findElements.call(this, matcher, locator); + locator = new Locator(locator) + if (!locator.isFuzzy()) return findElements.call(this, matcher, locator) - let els; - const literal = xpathLocator.literal(locator.value); + let els + const literal = xpathLocator.literal(locator.value) - els = await findElements.call(this, matcher, Locator.clickable.narrow(literal)); - if (els.length) return els; + els = await findElements.call(this, matcher, Locator.clickable.narrow(literal)) + if (els.length) return els - els = await findElements.call(this, matcher, Locator.clickable.wide(literal)); - if (els.length) return els; + els = await findElements.call(this, matcher, Locator.clickable.wide(literal)) + if (els.length) return els try { - els = await findElements.call(this, matcher, Locator.clickable.self(literal)); - if (els.length) return els; + els = await findElements.call(this, matcher, Locator.clickable.self(literal)) + if (els.length) return els } catch (err) { // Do nothing } - return findElements.call(this, matcher, locator.value); // by css or xpath + return findElements.call(this, matcher, locator.value) // by css or xpath } async function proceedSee(assertType, text, context, strict = false) { - let description; - let allText; + let description + let allText if (!context) { - const el = await this.context; + const el = await this.context - allText = el.constructor.name !== 'Locator' ? [await el.locator('body').innerText()] : [await el.innerText()]; + allText = el.constructor.name !== 'Locator' ? [await el.locator('body').innerText()] : [await el.innerText()] - description = 'web application'; + description = 'web application' } else { - const locator = new Locator(context, 'css'); - description = `element ${locator.toString()}`; - const els = await this._locate(locator); - assertElementExists(els, locator.toString()); - allText = await Promise.all(els.map(el => el.innerText())); + const locator = new Locator(context, 'css') + description = `element ${locator.toString()}` + const els = await this._locate(locator) + assertElementExists(els, locator.toString()) + allText = await Promise.all(els.map(el => el.innerText())) } if (strict) { - return allText.map(elText => equals(description)[assertType](text, elText)); + return allText.map(elText => equals(description)[assertType](text, elText)) } - return stringIncludes(description)[assertType](normalizeSpacesInString(text), normalizeSpacesInString(allText.join(' | '))); + return stringIncludes(description)[assertType](normalizeSpacesInString(text), normalizeSpacesInString(allText.join(' | '))) } async function findCheckable(locator, context) { - let contextEl = await this.context; + let contextEl = await this.context if (typeof context === 'string') { - contextEl = await findElements.call(this, contextEl, new Locator(context, 'css').simplify()); - contextEl = contextEl[0]; + contextEl = await findElements.call(this, contextEl, new Locator(context, 'css').simplify()) + contextEl = contextEl[0] } - const matchedLocator = new Locator(locator); + const matchedLocator = new Locator(locator) if (!matchedLocator.isFuzzy()) { - return findElements.call(this, contextEl, matchedLocator.simplify()); + return findElements.call(this, contextEl, matchedLocator.simplify()) } - const literal = xpathLocator.literal(locator); - let els = await findElements.call(this, contextEl, Locator.checkable.byText(literal)); + const literal = xpathLocator.literal(locator) + let els = await findElements.call(this, contextEl, Locator.checkable.byText(literal)) if (els.length) { - return els; + return els } - els = await findElements.call(this, contextEl, Locator.checkable.byName(literal)); + els = await findElements.call(this, contextEl, Locator.checkable.byName(literal)) if (els.length) { - return els; + return els } - return findElements.call(this, contextEl, locator); + return findElements.call(this, contextEl, locator) } async function proceedIsChecked(assertType, option) { - let els = await findCheckable.call(this, option); - assertElementExists(els, option, 'Checkable'); - els = await Promise.all(els.map(el => el.isChecked())); - const selected = els.reduce((prev, cur) => prev || cur); - return truth(`checkable ${option}`, 'to be checked')[assertType](selected); + let els = await findCheckable.call(this, option) + assertElementExists(els, option, 'Checkable') + els = await Promise.all(els.map(el => el.isChecked())) + const selected = els.reduce((prev, cur) => prev || cur) + return truth(`checkable ${option}`, 'to be checked')[assertType](selected) } async function findFields(locator) { - const matchedLocator = new Locator(locator); + const matchedLocator = new Locator(locator) if (!matchedLocator.isFuzzy()) { - return this._locate(matchedLocator); + return this._locate(matchedLocator) } - const literal = xpathLocator.literal(locator); + const literal = xpathLocator.literal(locator) - let els = await this._locate({ xpath: Locator.field.labelEquals(literal) }); + let els = await this._locate({ xpath: Locator.field.labelEquals(literal) }) if (els.length) { - return els; + return els } - els = await this._locate({ xpath: Locator.field.labelContains(literal) }); + els = await this._locate({ xpath: Locator.field.labelContains(literal) }) if (els.length) { - return els; + return els } - els = await this._locate({ xpath: Locator.field.byName(literal) }); + els = await this._locate({ xpath: Locator.field.byName(literal) }) if (els.length) { - return els; + return els } - return this._locate({ css: locator }); + return this._locate({ css: locator }) } async function proceedSeeInField(assertType, field, value) { - const els = await findFields.call(this, field); - assertElementExists(els, field, 'Field'); - const el = els[0]; - const tag = await el.evaluate(e => e.tagName); - const fieldType = await el.getAttribute('type'); + const els = await findFields.call(this, field) + assertElementExists(els, field, 'Field') + const el = els[0] + const tag = await el.evaluate(e => e.tagName) + const fieldType = await el.getAttribute('type') const proceedMultiple = async elements => { - const fields = Array.isArray(elements) ? elements : [elements]; + const fields = Array.isArray(elements) ? elements : [elements] - const elementValues = []; + const elementValues = [] for (const element of fields) { - elementValues.push(await element.inputValue()); + elementValues.push(await element.inputValue()) } if (typeof value === 'boolean') { - equals(`no. of items matching > 0: ${field}`)[assertType](value, !!elementValues.length); + equals(`no. of items matching > 0: ${field}`)[assertType](value, !!elementValues.length) } else { if (assertType === 'assert') { - equals(`select option by ${field}`)[assertType](true, elementValues.length > 0); + equals(`select option by ${field}`)[assertType](true, elementValues.length > 0) } - elementValues.forEach(val => stringIncludes(`fields by ${field}`)[assertType](value, val)); + elementValues.forEach(val => stringIncludes(`fields by ${field}`)[assertType](value, val)) } - }; + } if (tag === 'SELECT') { if (await el.getAttribute('multiple')) { - const selectedOptions = await el.all('option:checked'); - if (!selectedOptions.length) return null; + const selectedOptions = await el.all('option:checked') + if (!selectedOptions.length) return null - const options = await filterFieldsByValue(selectedOptions, value, true); - return proceedMultiple(options); + const options = await filterFieldsByValue(selectedOptions, value, true) + return proceedMultiple(options) } - return el.inputValue(); + return el.inputValue() } if (tag === 'INPUT') { if (fieldType === 'checkbox' || fieldType === 'radio') { if (typeof value === 'boolean') { // Filter by values - const options = await filterFieldsBySelectionState(els, true); - return proceedMultiple(options); + const options = await filterFieldsBySelectionState(els, true) + return proceedMultiple(options) } - const options = await filterFieldsByValue(els, value, true); - return proceedMultiple(options); + const options = await filterFieldsByValue(els, value, true) + return proceedMultiple(options) } - return proceedMultiple(els[0]); + return proceedMultiple(els[0]) } - let fieldVal; + let fieldVal try { - fieldVal = await el.inputValue(); + fieldVal = await el.inputValue() } catch (e) { if (e.message.includes('Error: Node is not an ,