diff --git a/.github/workflows/playwright.yml b/.github/workflows/playwright.yml index 96d8fa5c3..c309f8978 100644 --- a/.github/workflows/playwright.yml +++ b/.github/workflows/playwright.yml @@ -37,7 +37,7 @@ jobs: env: PUPPETEER_SKIP_CHROMIUM_DOWNLOAD: true - name: Install deps - run: npm install playwright@1.32.3 & npx playwright install-deps + run: npm install playwright@1.35.1 & npx playwright install-deps - name: start a server run: "php -S 127.0.0.1:8000 -t test/data/app &" - name: run chromium tests diff --git a/lib/helper/Playwright.js b/lib/helper/Playwright.js index a1b7837e9..9338fddc2 100644 --- a/lib/helper/Playwright.js +++ b/lib/helper/Playwright.js @@ -827,8 +827,9 @@ class Playwright extends Helper { async _stopBrowser() { this.withinLocator = null; - this._setPage(null); + await this._setPage(null); this.context = null; + this.frame = null; popupStore.clear(); await this.browser.close(); } @@ -867,6 +868,7 @@ class Playwright extends Helper { this.withinLocator = null; this.context = await this.page; this.contextLocator = null; + this.frame = null; } _extractDataFromPerformanceTiming(timing, ...dataNames) { @@ -1156,6 +1158,9 @@ class Playwright extends Helper { */ async _locate(locator) { const context = await this.context || await this._getContext(); + + if (this.frame) return findElements(this.frame, locator); + return findElements(context, locator); } @@ -1882,11 +1887,11 @@ class Playwright extends Helper { * @returns {Promise} */ async executeScript(fn, arg) { - let context = this.page; - if (this.context && this.context.constructor.name === 'Frame') { - context = this.context; // switching to iframe context + if (this.context && this.context.constructor.name === 'FrameLocator') { + // switching to iframe context + return this.context.locator(':root').evaluate(fn, arg); } - return context.evaluate.apply(context, [fn, arg]); + return this.page.evaluate.apply(this.page, [fn, arg]); } /** @@ -2408,7 +2413,7 @@ class Playwright extends Helper { } async _getContext() { - if (this.context && this.context.constructor.name === 'Frame') { + if (this.context && this.context.constructor.name === 'FrameLocator') { return this.context; } return this.page; @@ -2481,6 +2486,14 @@ class Playwright extends Helper { }, [locator.value, text, $XPath.toString()], { timeout: waitTimeout }); } } else { + // we have this as https://github.com/microsoft/playwright/issues/26829 is not yet implemented + if (this.frame) { + const { setTimeout } = require('timers/promises'); + await setTimeout(waitTimeout); + waiter = await this.frame.locator(`:has-text('${text}')`).first().isVisible(); + if (!waiter) throw new Error(`Text "${text}" was not found on page after ${waitTimeout / 1000} sec`); + return; + } waiter = contextObject.waitForFunction(text => document.body && document.body.innerText.indexOf(text) > -1, text, { timeout: waitTimeout }); } return waiter.catch((err) => { @@ -2535,37 +2548,37 @@ class Playwright extends Helper { } if (locator >= 0 && locator < childFrames.length) { - this.context = childFrames[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'); } return; } - let contentFrame; if (!locator) { - this.context = await this.page.frames()[0]; + this.context = this.page; this.contextLocator = null; + this.frame = null; return; } // iframe by selector - const els = await this._locate(locator); - if (!els[0]) { - throw new Error(`Element ${JSON.stringify(locator)} was not found by text|CSS|XPath`); + 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`); } - // get content of the first iframe - locator = new Locator(locator, 'css'); - if ((locator.frame && locator.frame === 'iframe') || locator.value.toLowerCase() === 'iframe') { - contentFrame = await this.page.frames()[1]; - // get content of the iframe using its name - } else if (locator.value.toLowerCase().includes('name=')) { - const frameName = locator.value.split('=')[1].replace(/"/g, '').replaceAll(/]/g, ''); - contentFrame = await this.page.frame(frameName); + if (this.frame) { + this.frame = await this.frame.frameLocator(locator); + } else { + this.frame = await this.page.frameLocator(locator); } + const contentFrame = this.frame; + if (contentFrame) { this.context = contentFrame; this.contextLocator = null; @@ -3340,13 +3353,9 @@ async function proceedSee(assertType, text, context, strict = false) { let allText; if (!context) { - let el = await this.context; - if (el && !el.getProperty) { - // Fallback to body - el = await this.page.$('body'); - } + const el = await this.context; - allText = [await el.innerText()]; + allText = [await el.locator('body').innerText()]; description = 'web application'; } else { const locator = new Locator(context, 'css'); @@ -3519,8 +3528,7 @@ async function elementSelected(element) { function isFrameLocator(locator) { locator = new Locator(locator); if (locator.isFrame()) { - const _locator = new Locator(locator.value); - return _locator.value; + return locator.value; } return false; } diff --git a/package.json b/package.json index 9fd6a19fc..b8857f012 100644 --- a/package.json +++ b/package.json @@ -40,8 +40,8 @@ "lint": "eslint bin/ examples/ lib/ test/ translations/ runok.js", "lint-fix": "eslint bin/ examples/ lib/ test/ translations/ runok.js --fix", "docs": "./runok.js docs", - "test:unit": "mocha test/unit --recursive --timeout 5000", - "test:runner": "mocha test/runner --recursive --timeout 5000", + "test:unit": "mocha test/unit --recursive --timeout 10000", + "test:runner": "mocha test/runner --recursive --timeout 10000", "test": "npm run test:unit && npm run test:runner", "test:appium-quick": "mocha test/helper/Appium_test.js --grep 'quick'", "test:appium-other": "mocha test/helper/Appium_test.js --grep 'second'", diff --git a/test/acceptance/within_test.js b/test/acceptance/within_test.js index 9931c984b..726c75253 100644 --- a/test/acceptance/within_test.js +++ b/test/acceptance/within_test.js @@ -47,9 +47,9 @@ Scenario('within on iframe without iframe navigation @WebDriverIO @Puppeteer @Pl Scenario('within on nested iframe without iframe navigation depth 2 @WebDriverIO @Puppeteer @Playwright', ({ I }) => { I.amOnPage('/iframe_nested'); - within({ frame: ['[name=wrapper]', '[name=content]'] }, async () => { - await I.fillField('rus', 'Updated'); - await I.see('Sign in!'); + within({ frame: ['[name=wrapper]', '[name=content]'] }, () => { + I.fillField('rus', 'Updated'); + I.see('Sign in!'); }); I.see('Nested Iframe test'); I.dontSee('Sign in!'); @@ -57,10 +57,10 @@ Scenario('within on nested iframe without iframe navigation depth 2 @WebDriverIO Scenario('within on nested iframe depth 1 @WebDriverIO @Puppeteer @Playwright', ({ I }) => { I.amOnPage('/iframe'); - within({ frame: ['[name=content]'] }, async () => { - await I.fillField('rus', 'Updated'); - await I.click('Sign in!'); - await I.waitForText('Email Address'); + within({ frame: ['[name=content]'] }, () => { + I.fillField('rus', 'Updated'); + I.click('Sign in!'); + I.waitForText('Email Address'); }); I.see('Iframe test'); I.dontSee('Email Address'); @@ -68,10 +68,10 @@ Scenario('within on nested iframe depth 1 @WebDriverIO @Puppeteer @Playwright', Scenario('within on nested iframe depth 2 @WebDriverIO @Puppeteer @Playwright', ({ I }) => { I.amOnPage('/iframe_nested'); - within({ frame: ['[name=wrapper]', '[name=content]'] }, async () => { - await I.fillField('rus', 'Updated'); - await I.click('Sign in!'); - await I.see('Email Address'); + within({ frame: ['[name=wrapper]', '[name=content]'] }, () => { + I.fillField('rus', 'Updated'); + I.click('Sign in!'); + I.see('Email Address'); }); I.see('Nested Iframe test'); I.dontSee('Email Address'); @@ -79,10 +79,10 @@ Scenario('within on nested iframe depth 2 @WebDriverIO @Puppeteer @Playwright', Scenario('within on nested iframe depth 2 and mixed id and xpath selector @WebDriverIO @Puppeteer @Playwright', ({ I }) => { I.amOnPage('/iframe_nested'); - within({ frame: ['#wrapperId', '[name=content]'] }, async () => { - await I.fillField('rus', 'Updated'); - await I.click('Sign in!'); - await I.see('Email Address'); + within({ frame: ['#wrapperId', '[name=content]'] }, () => { + I.fillField('rus', 'Updated'); + I.click('Sign in!'); + I.see('Email Address'); }); I.see('Nested Iframe test'); I.dontSee('Email Address'); @@ -90,10 +90,10 @@ Scenario('within on nested iframe depth 2 and mixed id and xpath selector @WebDr Scenario('within on nested iframe depth 2 and mixed class and xpath selector @WebDriverIO @Puppeteer @Playwright', ({ I }) => { I.amOnPage('/iframe_nested'); - within({ frame: ['.wrapperClass', '[name=content]'] }, async () => { - await I.fillField('rus', 'Updated'); - await I.click('Sign in!'); - await I.see('Email Address'); + within({ frame: ['.wrapperClass', '[name=content]'] }, () => { + I.fillField('rus', 'Updated'); + I.click('Sign in!'); + I.see('Email Address'); }); I.see('Nested Iframe test'); I.dontSee('Email Address'); diff --git a/test/data/app/controllers.php b/test/data/app/controllers.php index 4e2b6e472..2dea9b435 100755 --- a/test/data/app/controllers.php +++ b/test/data/app/controllers.php @@ -138,7 +138,7 @@ function GET() { include __DIR__ . '/view/image.php'; } } - + class cookies { @@ -177,6 +177,13 @@ public function GET() } } +class iframes { + public function GET() + { + include __DIR__.'/view/iframes.php'; + } +} + class iframe_nested { public function GET() { @@ -311,4 +318,4 @@ class basic_auth { function GET() { include __DIR__.'/view/basic_auth.php'; } -} \ No newline at end of file +} diff --git a/test/data/app/index.php b/test/data/app/index.php index d963a6fb3..6ab0b28a6 100755 --- a/test/data/app/index.php +++ b/test/data/app/index.php @@ -39,6 +39,7 @@ '/external_url' => 'external_url', '/spinner' => 'spinner', '/iframe' => 'iframe', + '/iframes' => 'iframes', '/iframe_nested' => 'iframe_nested', '/dynamic' => 'dynamic', '/timeout' => 'timeout', diff --git a/test/data/app/view/iframes.php b/test/data/app/view/iframes.php new file mode 100755 index 000000000..4d097d939 --- /dev/null +++ b/test/data/app/view/iframes.php @@ -0,0 +1,12 @@ + + + + + + + +
+