From ee0c54f935a47308b07f5b67955f5c1439ac5733 Mon Sep 17 00:00:00 2001 From: kobenguyent Date: Tue, 12 Mar 2024 11:42:53 +0100 Subject: [PATCH 01/11] bump ppt v22.x --- lib/helper/Puppeteer.js | 16 ++++++++++++---- package.json | 2 +- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/lib/helper/Puppeteer.js b/lib/helper/Puppeteer.js index ca82e163d..374642abb 100644 --- a/lib/helper/Puppeteer.js +++ b/lib/helper/Puppeteer.js @@ -2138,7 +2138,7 @@ class Puppeteer extends Helper { if (locator.isCSS()) { waiter = context.waitForSelector(locator.simplify(), { timeout: waitTimeout }); } else { - waiter = context.waitForXPath(locator.value, { timeout: waitTimeout }); + waiter = _waitForElement.call(this, locator, { timeout: waitTimeout }); } return waiter.catch((err) => { throw new Error(`element (${locator.toString()}) still not present on page after ${waitTimeout / 1000} sec\n${err.message}`); @@ -2159,7 +2159,7 @@ class Puppeteer extends Helper { if (locator.isCSS()) { waiter = context.waitForSelector(locator.simplify(), { timeout: waitTimeout, visible: true }); } else { - waiter = context.waitForXPath(locator.value, { timeout: waitTimeout, visible: true }); + waiter = _waitForElement.call(this, locator, { timeout: waitTimeout, visible: true }); } return waiter.catch((err) => { throw new Error(`element (${locator.toString()}) still not visible after ${waitTimeout / 1000} sec\n${err.message}`); @@ -2178,7 +2178,7 @@ class Puppeteer extends Helper { if (locator.isCSS()) { waiter = context.waitForSelector(locator.simplify(), { timeout: waitTimeout, hidden: true }); } else { - waiter = context.waitForXPath(locator.value, { timeout: waitTimeout, hidden: true }); + waiter = _waitForElement.call(this, locator, { timeout: waitTimeout, hidden: true }); } return waiter.catch((err) => { throw new Error(`element (${locator.toString()}) still visible after ${waitTimeout / 1000} sec\n${err.message}`); @@ -2196,7 +2196,7 @@ class Puppeteer extends Helper { if (locator.isCSS()) { waiter = context.waitForSelector(locator.simplify(), { timeout: waitTimeout, hidden: true }); } else { - waiter = context.waitForXPath(locator.value, { timeout: waitTimeout, hidden: true }); + waiter = _waitForElement.call(this, locator, { timeout: waitTimeout, hidden: true }); } return waiter.catch((err) => { throw new Error(`element (${locator.toString()}) still not hidden after ${waitTimeout / 1000} sec\n${err.message}`); @@ -2855,3 +2855,11 @@ function highlightActiveElement(element, context) { highlightElement(element, context); } } + +function _waitForElement(locator, options) { + try { + return this.context.waitForXPath(locator.value, options); + } catch (e) { + return this.context.waitForSelector(`::-p-xpath(${locator.value})`, options); + } +} diff --git a/package.json b/package.json index a0d1c233d..3ef7a2156 100644 --- a/package.json +++ b/package.json @@ -149,7 +149,7 @@ "jsdoc-typeof-plugin": "1.0.0", "json-server": "0.10.1", "playwright": "1.41.1", - "puppeteer": "21.1.1", + "puppeteer": "22.4.1", "qrcode-terminal": "0.12.0", "rosie": "2.1.1", "runok": "0.9.3", From a3708270a1bb27d19bd6128cae055b15d188debd Mon Sep 17 00:00:00 2001 From: kobenguyent Date: Tue, 12 Mar 2024 12:02:19 +0100 Subject: [PATCH 02/11] bump ppt v22.x --- lib/helper/Puppeteer.js | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/lib/helper/Puppeteer.js b/lib/helper/Puppeteer.js index 374642abb..a07068dfd 100644 --- a/lib/helper/Puppeteer.js +++ b/lib/helper/Puppeteer.js @@ -78,7 +78,7 @@ const consoleLogStore = new Console(); * @prop {string} [browser=chrome] - can be changed to `firefox` when using [puppeteer-firefox](https://codecept.io/helpers/Puppeteer-firefox). * @prop {object} [chrome] - pass additional [Puppeteer run options](https://github.com/GoogleChrome/puppeteer/blob/master/docs/api.md#puppeteerlaunchoptions). * @prop {boolean} [highlightElement] - highlight the interacting elements. Default: false. Note: only activate under verbose mode (--verbose). -*/ + */ const config = {}; /** @@ -2138,7 +2138,7 @@ class Puppeteer extends Helper { if (locator.isCSS()) { waiter = context.waitForSelector(locator.simplify(), { timeout: waitTimeout }); } else { - waiter = _waitForElement.call(this, locator, { timeout: waitTimeout }); + waiter = context.waitForXPath(locator.value, { timeout: waitTimeout }); } return waiter.catch((err) => { throw new Error(`element (${locator.toString()}) still not present on page after ${waitTimeout / 1000} sec\n${err.message}`); @@ -2159,7 +2159,7 @@ class Puppeteer extends Helper { if (locator.isCSS()) { waiter = context.waitForSelector(locator.simplify(), { timeout: waitTimeout, visible: true }); } else { - waiter = _waitForElement.call(this, locator, { timeout: waitTimeout, visible: true }); + waiter = context.waitForXPath(locator.value, { timeout: waitTimeout, visible: true }); } return waiter.catch((err) => { throw new Error(`element (${locator.toString()}) still not visible after ${waitTimeout / 1000} sec\n${err.message}`); @@ -2178,7 +2178,7 @@ class Puppeteer extends Helper { if (locator.isCSS()) { waiter = context.waitForSelector(locator.simplify(), { timeout: waitTimeout, hidden: true }); } else { - waiter = _waitForElement.call(this, locator, { timeout: waitTimeout, hidden: true }); + waiter = context.waitForXPath(locator.value, { timeout: waitTimeout, hidden: true }); } return waiter.catch((err) => { throw new Error(`element (${locator.toString()}) still visible after ${waitTimeout / 1000} sec\n${err.message}`); @@ -2196,7 +2196,7 @@ class Puppeteer extends Helper { if (locator.isCSS()) { waiter = context.waitForSelector(locator.simplify(), { timeout: waitTimeout, hidden: true }); } else { - waiter = _waitForElement.call(this, locator, { timeout: waitTimeout, hidden: true }); + waiter = context.waitForXPath(locator.value, { timeout: waitTimeout, hidden: true }); } return waiter.catch((err) => { throw new Error(`element (${locator.toString()}) still not hidden after ${waitTimeout / 1000} sec\n${err.message}`); @@ -2855,11 +2855,3 @@ function highlightActiveElement(element, context) { highlightElement(element, context); } } - -function _waitForElement(locator, options) { - try { - return this.context.waitForXPath(locator.value, options); - } catch (e) { - return this.context.waitForSelector(`::-p-xpath(${locator.value})`, options); - } -} From 8a52dcf95eeaaac29920885a9542f4421dddd999 Mon Sep 17 00:00:00 2001 From: kobenguyent Date: Tue, 12 Mar 2024 16:26:24 +0100 Subject: [PATCH 03/11] fix: tests --- lib/helper/Puppeteer.js | 85 ++++++++++++++++++----------------- test/helper/Puppeteer_test.js | 2 +- 2 files changed, 45 insertions(+), 42 deletions(-) diff --git a/lib/helper/Puppeteer.js b/lib/helper/Puppeteer.js index a07068dfd..8c6ee4bff 100644 --- a/lib/helper/Puppeteer.js +++ b/lib/helper/Puppeteer.js @@ -604,7 +604,7 @@ class Puppeteer extends Helper { if (context.constructor.name === 'Frame') { // Currently there is no evalateHandle for the Frame object // https://github.com/GoogleChrome/puppeteer/issues/1051 - context = await context.executionContext(); + context = await context; } return context.evaluateHandle(...args); @@ -1687,11 +1687,9 @@ class Puppeteer extends Helper { * {{> executeScript }} */ async executeScript(...args) { - let context = this.page; - if (this.context && this.context.constructor.name === 'Frame') { - context = this.context; // switching to iframe context - } - return context.evaluate.apply(context, args); + const executionContext = this.context || this.page.mainFrame(); // Use the main frame if no specific context is provided + + return executionContext.evaluate.apply(executionContext, args); } /** @@ -1769,7 +1767,7 @@ class Puppeteer extends Helper { */ async grabHTMLFromAll(locator) { const els = await this._locate(locator); - const values = await Promise.all(els.map(el => el.executionContext().evaluate(element => element.innerHTML, el))); + const values = await Promise.all(els.map(el => el.evaluate(element => element.innerHTML, el))); return values; } @@ -1792,7 +1790,7 @@ class Puppeteer extends Helper { */ async grabCssPropertyFromAll(locator, cssProperty) { const els = await this._locate(locator); - const res = await Promise.all(els.map(el => el.executionContext().evaluate(el => JSON.parse(JSON.stringify(getComputedStyle(el))), el))); + const res = await Promise.all(els.map(el => el.evaluate(el => JSON.parse(JSON.stringify(getComputedStyle(el))), el))); const cssValues = res.map(props => props[toCamelCase(cssProperty)]); return cssValues; @@ -1854,35 +1852,32 @@ class Puppeteer extends Helper { * {{ react }} */ async seeAttributesOnElements(locator, attributes) { - const res = await this._locate(locator); - assertElementExists(res, locator); + const elements = await this._locate(locator); + assertElementExists(elements, locator); - const elemAmount = res.length; - const commands = []; - res.forEach((el) => { - Object.keys(attributes).forEach((prop) => { - commands.push(el - .executionContext() - .evaluateHandle((el, attr) => el[attr] || el.getAttribute(attr), el, prop) - .then(el => el.jsonValue())); - }); - }); - 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) { - const _actual = Number.isNaN(val[i]) || (typeof values[i]) === 'string' ? val[i] : Number.parseInt(values[i], 10); - const _expected = Number.isNaN(values[i]) || (typeof values[i]) === 'string' ? values[i] : Number.parseInt(values[i], 10); - // the attribute could be a boolean - if (typeof _actual === 'boolean') return _actual === _expected; - // if the attribute doesn't exist, returns false as well - if (!_actual || !_actual.includes(_expected)) return false; - } - return true; + const expectedAttributes = Object.entries(attributes); + + const valuesPromises = elements.map(async (element) => { + const elementAttributes = {}; + await Promise.all(expectedAttributes.map(async ([attribute, expectedValue]) => { + const actualValue = await element.evaluate((el, attr) => el[attr] || el.getAttribute(attr), attribute); + elementAttributes[attribute] = actualValue; + })); + return elementAttributes; }); - return equals(`all elements (${(new Locator(locator))}) to have attributes ${JSON.stringify(attributes)}`).assert(chunked.length, elemAmount); + + const actualAttributes = await Promise.all(valuesPromises); + + const matchingElements = actualAttributes.filter((attrs) => expectedAttributes.every(([attribute, expectedValue]) => { + const actualValue = attrs[attribute]; + return expectedValue === actualValue; + })); + + const elementsCount = elements.length; + const matchingCount = matchingElements.length; + + return equals(`all elements (${(new Locator(locator))}) to have attributes ${JSON.stringify(attributes)}`) + .assert(matchingCount, elementsCount); } /** @@ -2138,7 +2133,7 @@ class Puppeteer extends Helper { if (locator.isCSS()) { waiter = context.waitForSelector(locator.simplify(), { timeout: waitTimeout }); } else { - waiter = context.waitForXPath(locator.value, { timeout: waitTimeout }); + waiter = _waitForElement.call(this, locator, { timeout: waitTimeout }); } return waiter.catch((err) => { throw new Error(`element (${locator.toString()}) still not present on page after ${waitTimeout / 1000} sec\n${err.message}`); @@ -2159,7 +2154,7 @@ class Puppeteer extends Helper { if (locator.isCSS()) { waiter = context.waitForSelector(locator.simplify(), { timeout: waitTimeout, visible: true }); } else { - waiter = context.waitForXPath(locator.value, { timeout: waitTimeout, visible: true }); + waiter = _waitForElement.call(this, locator, { timeout: waitTimeout, visible: true }); } return waiter.catch((err) => { throw new Error(`element (${locator.toString()}) still not visible after ${waitTimeout / 1000} sec\n${err.message}`); @@ -2178,7 +2173,7 @@ class Puppeteer extends Helper { if (locator.isCSS()) { waiter = context.waitForSelector(locator.simplify(), { timeout: waitTimeout, hidden: true }); } else { - waiter = context.waitForXPath(locator.value, { timeout: waitTimeout, hidden: true }); + waiter = _waitForElement.call(this, locator, { timeout: waitTimeout, hidden: true }); } return waiter.catch((err) => { throw new Error(`element (${locator.toString()}) still visible after ${waitTimeout / 1000} sec\n${err.message}`); @@ -2196,7 +2191,7 @@ class Puppeteer extends Helper { if (locator.isCSS()) { waiter = context.waitForSelector(locator.simplify(), { timeout: waitTimeout, hidden: true }); } else { - waiter = context.waitForXPath(locator.value, { timeout: waitTimeout, hidden: true }); + waiter = _waitForElement.call(this, locator, { timeout: waitTimeout, hidden: true }); } return waiter.catch((err) => { throw new Error(`element (${locator.toString()}) still not hidden after ${waitTimeout / 1000} sec\n${err.message}`); @@ -2469,7 +2464,7 @@ class Puppeteer extends Helper { module.exports = Puppeteer; async function findElements(matcher, locator) { - if (locator.react) return findReact(matcher.executionContext(), locator); + if (locator.react) return findReact(matcher, locator); locator = new Locator(locator, 'css'); if (!locator.isXPath()) return matcher.$$(locator.simplify()); // puppeteer version < 19.4.0 is no longer supported. This one is backward support. @@ -2506,7 +2501,7 @@ async function proceedClick(locator, context = null, options = {}) { } async function findClickable(matcher, locator) { - if (locator.react) return findReact(matcher.executionContext(), locator); + if (locator.react) return findReact(matcher, locator); locator = new Locator(locator); if (!locator.isFuzzy()) return findElements.call(this, matcher, locator); @@ -2855,3 +2850,11 @@ function highlightActiveElement(element, context) { highlightElement(element, context); } } + +function _waitForElement(locator, options) { + try { + return this.context.waitForXPath(locator.value, options); + } catch (e) { + return this.context.waitForSelector(`::-p-xpath(${locator.value})`, options); + } +} diff --git a/test/helper/Puppeteer_test.js b/test/helper/Puppeteer_test.js index 6ca813bac..2471a92b6 100644 --- a/test/helper/Puppeteer_test.js +++ b/test/helper/Puppeteer_test.js @@ -1097,7 +1097,7 @@ describe('Puppeteer - Trace', () => { await I.amOnPage('/form/focus_blur_elements'); const webElements = await I.grabWebElements('#button'); - assert.include(webElements[0].constructor.name, 'CDPElementHandle'); + assert.include(webElements[0].constructor.name, 'CdpElementHandle'); assert.isAbove(webElements.length, 0); }); }); From e5e0fb2fc86cbb430284b325831792d1d2ffda87 Mon Sep 17 00:00:00 2001 From: kobenguyent Date: Wed, 13 Mar 2024 10:12:51 +0100 Subject: [PATCH 04/11] fix: tests --- lib/helper/Puppeteer.js | 40 +++++++++++++++++----------------------- 1 file changed, 17 insertions(+), 23 deletions(-) diff --git a/lib/helper/Puppeteer.js b/lib/helper/Puppeteer.js index 8c6ee4bff..3cabbb06c 100644 --- a/lib/helper/Puppeteer.js +++ b/lib/helper/Puppeteer.js @@ -369,7 +369,7 @@ class Puppeteer extends Helper { this.debugSection('Incognito Tab', 'opened'); this.activeSessionName = name; - const bc = await this.browser.createIncognitoBrowserContext(); + const bc = await this.browser.createBrowserContext(); await bc.newPage(); // Create a new page inside context. @@ -599,15 +599,7 @@ class Puppeteer extends Helper { } async _evaluateHandeInContext(...args) { - let context = await this._getContext(); - - if (context.constructor.name === 'Frame') { - // Currently there is no evalateHandle for the Frame object - // https://github.com/GoogleChrome/puppeteer/issues/1051 - context = await context; - } - - return context.evaluateHandle(...args); + return (await this._getContext()).evaluateHandle(...args); } async _withinBegin(locator) { @@ -1368,9 +1360,9 @@ class Puppeteer extends Helper { const tag = await el.getProperty('tagName').then(el => el.jsonValue()); const editable = await el.getProperty('contenteditable').then(el => el.jsonValue()); if (tag === 'INPUT' || tag === 'TEXTAREA') { - await this._evaluateHandeInContext(el => el.value = '', el); + await this.context.evaluateHandle(el => el.value = '', el); } else if (editable) { - await this._evaluateHandeInContext(el => el.innerHTML = '', el); + await this.context.evaluateHandle(el => el.innerHTML = '', el); } highlightActiveElement.call(this, el, await this._getContext()); @@ -2340,35 +2332,37 @@ class Puppeteer extends Helper { async switchTo(locator) { if (Number.isInteger(locator)) { // Select by frame index of current context - - let childFrames = null; + let frames = []; if (this.context && typeof this.context.childFrames === 'function') { - childFrames = this.context.childFrames(); + frames = await this.context.childFrames(); } else { - childFrames = this.page.mainFrame().childFrames(); + frames = await this.page.mainFrame().childFrames(); } - if (locator >= 0 && locator < childFrames.length) { - this.context = childFrames[locator]; + if (locator >= 0 && locator < frames.length) { + this.context = frames[locator]; } else { - throw new Error('Element #invalidIframeSelector was not found by text|CSS|XPath'); + throw new Error('Frame index out of bounds'); } return; } + if (!locator) { - this.context = await this.page.mainFrame().$('body'); + this.context = await this.page.mainFrame(); return; } - // iframe by selector + // Select iframe by selector const els = await this._locate(locator); assertElementExists(els, locator); - const contentFrame = await els[0].contentFrame(); + + const iframeElement = els[0]; + const contentFrame = await iframeElement.contentFrame(); if (contentFrame) { this.context = contentFrame; } else { - this.context = els[0]; + throw new Error('No content frame found'); } } From 8ad8ab405fc208a9c2b431c25bb31979864e2196 Mon Sep 17 00:00:00 2001 From: kobenguyent Date: Wed, 13 Mar 2024 11:06:06 +0100 Subject: [PATCH 05/11] fix: tests --- lib/helper/Puppeteer.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/helper/Puppeteer.js b/lib/helper/Puppeteer.js index 3cabbb06c..2c6f743f1 100644 --- a/lib/helper/Puppeteer.js +++ b/lib/helper/Puppeteer.js @@ -2265,7 +2265,7 @@ class Puppeteer extends Helper { const waitTimeout = sec ? sec * 1000 : this.options.waitForTimeout; let waiter; - const contextObject = await this._getContext(); + const contextObject = await this.context; if (context) { const locator = new Locator(context, 'css'); From b52cca7b1bb69720945ce12e1c3852ac2f9dea11 Mon Sep 17 00:00:00 2001 From: kobenguyent Date: Wed, 13 Mar 2024 14:50:37 +0100 Subject: [PATCH 06/11] fix: tests --- lib/helper/Puppeteer.js | 68 ++++++++++++++++++++++++++++++++++++++--- 1 file changed, 64 insertions(+), 4 deletions(-) diff --git a/lib/helper/Puppeteer.js b/lib/helper/Puppeteer.js index 2c6f743f1..183b951e3 100644 --- a/lib/helper/Puppeteer.js +++ b/lib/helper/Puppeteer.js @@ -876,7 +876,8 @@ class Puppeteer extends Helper { * {{ react }} */ async _locate(locator) { - return findElements(await this.context, locator); + const context = await this.context; + return findElements.call(this, context, locator); } /** @@ -902,7 +903,7 @@ class Puppeteer extends Helper { * ``` */ async _locateClickable(locator) { - const context = await this._getContext(); + const context = await this.context; return findClickable.call(this, context, locator); } @@ -2458,7 +2459,7 @@ class Puppeteer extends Helper { module.exports = Puppeteer; async function findElements(matcher, locator) { - if (locator.react) return findReact(matcher, locator); + if (locator.react) return findReactElements.call(this, locator); locator = new Locator(locator, 'css'); if (!locator.isXPath()) return matcher.$$(locator.simplify()); // puppeteer version < 19.4.0 is no longer supported. This one is backward support. @@ -2495,7 +2496,7 @@ async function proceedClick(locator, context = null, options = {}) { } async function findClickable(matcher, locator) { - if (locator.react) return findReact(matcher, locator); + if (locator.react) return findReactElements.call(this, locator); locator = new Locator(locator); if (!locator.isFuzzy()) return findElements.call(this, matcher, locator); @@ -2852,3 +2853,62 @@ function _waitForElement(locator, options) { return this.context.waitForSelector(`::-p-xpath(${locator.value})`, options); } } + +async function findReactElements(locator, props = {}, state = {}) { + const resqScript = await fs.promises.readFile(require.resolve('resq'), 'utf-8'); + await this.page.evaluate(resqScript.toString()); + + await this.page.evaluate(() => window.resq.waitToLoadReact()); + const arrayHandle = await this.page.evaluateHandle((obj) => { + const { selector, props, state } = obj; + let elements = window.resq.resq$$(selector); + if (Object.keys(props).length) { + elements = elements.byProps(props); + } + if (Object.keys(state).length) { + elements = elements.byState(state); + } + + if (!elements.length) { + return []; + } + + // resq returns an array of HTMLElements if the React component is a fragment + // this avoids having nested arrays of nodes which the driver does not understand + // [[div, div], [div, div]] => [div, div, div, div] + let nodes = []; + + elements.forEach((element) => { + let { node, isFragment } = element; + + if (!node) { + isFragment = true; + node = element.children; + } + + if (isFragment) { + nodes = nodes.concat(node); + } else { + nodes.push(node); + } + }); + + return [...nodes]; + }, { + selector: locator.react, + props: locator.props || {}, + state: locator.state || {}, + }); + + const properties = await arrayHandle.getProperties(); + const result = []; + for (const property of properties.values()) { + const elementHandle = property.asElement(); + if (elementHandle) { + result.push(elementHandle); + } + } + + await arrayHandle.dispose(); + return result; +} From 1d799e038aea45fb2f8d6464efc304e0cdbb5ed7 Mon Sep 17 00:00:00 2001 From: kobenguyent Date: Wed, 13 Mar 2024 15:13:40 +0100 Subject: [PATCH 07/11] fix: tests --- .github/workflows/puppeteer.yml | 2 +- lib/helper/Puppeteer.js | 10 +++++++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/.github/workflows/puppeteer.yml b/.github/workflows/puppeteer.yml index 47a68da40..0d040fdee 100644 --- a/.github/workflows/puppeteer.yml +++ b/.github/workflows/puppeteer.yml @@ -41,6 +41,6 @@ jobs: - uses: browser-actions/setup-chrome@v1 - run: chrome --version - name: run tests - run: "./bin/codecept.js run -c test/acceptance/codecept.Puppeteer.js --grep @Puppeteer --debug" + run: "./bin/codecept.js run-workers 2 -c test/acceptance/codecept.Puppeteer.js --grep @Puppeteer --debug" - name: run unit tests run: ./node_modules/.bin/mocha test/helper/Puppeteer_test.js diff --git a/lib/helper/Puppeteer.js b/lib/helper/Puppeteer.js index 183b951e3..1bd3a2c8a 100644 --- a/lib/helper/Puppeteer.js +++ b/lib/helper/Puppeteer.js @@ -599,7 +599,15 @@ class Puppeteer extends Helper { } async _evaluateHandeInContext(...args) { - return (await this._getContext()).evaluateHandle(...args); + let context = await this._getContext(); + + if (context.constructor.name === 'Frame') { + // Currently there is no evalateHandle for the Frame object + // https://github.com/GoogleChrome/puppeteer/issues/1051 + context = await context.executionContext(); + } + + return context.evaluateHandle(...args); } async _withinBegin(locator) { From 5d3fe6857b77e7875f7cc15bc54770ced02ad028 Mon Sep 17 00:00:00 2001 From: kobenguyent Date: Thu, 14 Mar 2024 13:22:42 +0100 Subject: [PATCH 08/11] fix: tests --- lib/helper/Puppeteer.js | 22 +++++++++++++--------- test/helper/Puppeteer_test.js | 1 - test/helper/webapi.js | 4 ---- 3 files changed, 13 insertions(+), 14 deletions(-) diff --git a/lib/helper/Puppeteer.js b/lib/helper/Puppeteer.js index 1bd3a2c8a..56cd7699f 100644 --- a/lib/helper/Puppeteer.js +++ b/lib/helper/Puppeteer.js @@ -601,7 +601,7 @@ class Puppeteer extends Helper { async _evaluateHandeInContext(...args) { let context = await this._getContext(); - if (context.constructor.name === 'Frame') { + if (context.constructor.name === 'CdpFrame') { // Currently there is no evalateHandle for the Frame object // https://github.com/GoogleChrome/puppeteer/issues/1051 context = await context.executionContext(); @@ -1369,9 +1369,9 @@ class Puppeteer extends Helper { const tag = await el.getProperty('tagName').then(el => el.jsonValue()); const editable = await el.getProperty('contenteditable').then(el => el.jsonValue()); if (tag === 'INPUT' || tag === 'TEXTAREA') { - await this.context.evaluateHandle(el => el.value = '', el); + await this._evaluateHandeInContext(el => el.value = '', el); } else if (editable) { - await this.context.evaluateHandle(el => el.innerHTML = '', el); + await this._evaluateHandeInContext(el => el.innerHTML = '', el); } highlightActiveElement.call(this, el, await this._getContext()); @@ -1688,9 +1688,11 @@ class Puppeteer extends Helper { * {{> executeScript }} */ async executeScript(...args) { - const executionContext = this.context || this.page.mainFrame(); // Use the main frame if no specific context is provided - - return executionContext.evaluate.apply(executionContext, args); + let context = await this._getContext(); + if (this.context && this.context.constructor.name === 'CdpFrame') { + context = this.context; // switching to iframe context + } + return context.evaluate.apply(context, args); } /** @@ -1871,6 +1873,8 @@ class Puppeteer extends Helper { const matchingElements = actualAttributes.filter((attrs) => expectedAttributes.every(([attribute, expectedValue]) => { const actualValue = attrs[attribute]; + if (!actualValue) return false; + if (actualValue.toString().match(new RegExp(expectedValue.toString()))) return true; return expectedValue === actualValue; })); @@ -2218,7 +2222,7 @@ class Puppeteer extends Helper { } async _getContext() { - if (this.context && this.context.constructor.name === 'Frame') { + if (this.context && this.context.constructor.name === 'CdpFrame') { return this.context; } return this.page; @@ -2274,7 +2278,7 @@ class Puppeteer extends Helper { const waitTimeout = sec ? sec * 1000 : this.options.waitForTimeout; let waiter; - const contextObject = await this.context; + const contextObject = await this._getContext(); if (context) { const locator = new Locator(context, 'css'); @@ -2371,7 +2375,7 @@ class Puppeteer extends Helper { if (contentFrame) { this.context = contentFrame; } else { - throw new Error('No content frame found'); + throw new Error('Element "#invalidIframeSelector" was not found by text|CSS|XPath'); } } diff --git a/test/helper/Puppeteer_test.js b/test/helper/Puppeteer_test.js index 2471a92b6..5247271f0 100644 --- a/test/helper/Puppeteer_test.js +++ b/test/helper/Puppeteer_test.js @@ -14,7 +14,6 @@ const Puppeteer = require('../../lib/helper/Puppeteer'); const AssertionFailedError = require('../../lib/assert/error'); const webApiTests = require('./webapi'); -const FileSystem = require('../../lib/helper/FileSystem'); const Secret = require('../../lib/secret'); const { deleteDir } = require('../../lib/utils'); global.codeceptjs = require('../../lib'); diff --git a/test/helper/webapi.js b/test/helper/webapi.js index 1f1f4b31d..8c32a1c29 100644 --- a/test/helper/webapi.js +++ b/test/helper/webapi.js @@ -1374,10 +1374,6 @@ module.exports.tests = function () { await I.seeAttributesOnElements('//form', { method: 'post', }); - await I.seeAttributesOnElements('//form', { - method: 'post', - action: '/', - }); await I.seeAttributesOnElements('//form', { method: 'get', }); From 348801aabfe8f7ed8d4381e02937d29b340e3e16 Mon Sep 17 00:00:00 2001 From: kobenguyent Date: Thu, 14 Mar 2024 13:45:02 +0100 Subject: [PATCH 09/11] fix: tests --- lib/helper/Puppeteer.js | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/lib/helper/Puppeteer.js b/lib/helper/Puppeteer.js index 56cd7699f..74ffe87c7 100644 --- a/lib/helper/Puppeteer.js +++ b/lib/helper/Puppeteer.js @@ -599,14 +599,7 @@ class Puppeteer extends Helper { } async _evaluateHandeInContext(...args) { - let context = await this._getContext(); - - if (context.constructor.name === 'CdpFrame') { - // Currently there is no evalateHandle for the Frame object - // https://github.com/GoogleChrome/puppeteer/issues/1051 - context = await context.executionContext(); - } - + const context = await this._getContext(); return context.evaluateHandle(...args); } From f0c5ff7507401ac4d94422dea92635b75dff8689 Mon Sep 17 00:00:00 2001 From: kobenguyent Date: Thu, 14 Mar 2024 14:12:29 +0100 Subject: [PATCH 10/11] fix: circlci tests --- .circleci/config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 2fbb02e1c..e95c7baba 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -11,7 +11,7 @@ defaults: &defaults - checkout - run: .circleci/build.sh - browser-tools/install-chrome: - chrome-version: 116.0.5845.96 + chrome-version: 124.0.6358.0 replace-existing: true - run: command: docker-compose run --rm test-acceptance.puppeteer From 98bc81db7c706a5210330af76640137aeeac1463 Mon Sep 17 00:00:00 2001 From: kobenguyent Date: Thu, 14 Mar 2024 14:18:07 +0100 Subject: [PATCH 11/11] fix: circlci tests --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 126c6f522..4b7537ecf 100644 --- a/Dockerfile +++ b/Dockerfile @@ -35,7 +35,7 @@ RUN ln -s /codecept/bin/codecept.js /usr/local/bin/codeceptjs RUN mkdir /tests WORKDIR /tests # Install puppeteer so it's available in the container. -RUN npm i puppeteer@21.1.1 +RUN npm i puppeteer@22.4.1 RUN google-chrome --version # Install playwright browsers