Skip to content

fix: switchTo - within block #3892

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 13 commits into from
Oct 9, 2023
Merged
2 changes: 1 addition & 1 deletion .github/workflows/playwright.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
64 changes: 36 additions & 28 deletions lib/helper/Playwright.js
Original file line number Diff line number Diff line change
Expand Up @@ -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();
}
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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);
}

Expand Down Expand Up @@ -1882,11 +1887,11 @@ class Playwright extends Helper {
* @returns {Promise<any>}
*/
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]);
}

/**
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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) => {
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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');
Expand Down Expand Up @@ -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;
}
Expand Down
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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'",
Expand Down
38 changes: 19 additions & 19 deletions test/acceptance/within_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,53 +47,53 @@ 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!');
});

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');
});

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');
});

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');
});

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');
Expand Down
11 changes: 9 additions & 2 deletions test/data/app/controllers.php
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ function GET() {
include __DIR__ . '/view/image.php';
}
}


class cookies {

Expand Down Expand Up @@ -177,6 +177,13 @@ public function GET()
}
}

class iframes {
public function GET()
{
include __DIR__.'/view/iframes.php';
}
}

class iframe_nested {
public function GET()
{
Expand Down Expand Up @@ -311,4 +318,4 @@ class basic_auth {
function GET() {
include __DIR__.'/view/basic_auth.php';
}
}
}
1 change: 1 addition & 0 deletions test/data/app/index.php
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
'/external_url' => 'external_url',
'/spinner' => 'spinner',
'/iframe' => 'iframe',
'/iframes' => 'iframes',
'/iframe_nested' => 'iframe_nested',
'/dynamic' => 'dynamic',
'/timeout' => 'timeout',
Expand Down
12 changes: 12 additions & 0 deletions test/data/app/view/iframes.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<!DOCTYPE HTML>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
</head>
<body>

<div class="box"><iframe name="content1" src="https://codecept.io" id="number-frame-5678" width="100%"> </iframe> </div>
<div class="box"><iframe name="content2" src="info" id="number-frame-1234" width="100%"/></div>

</body>
</html>
13 changes: 13 additions & 0 deletions test/helper/Playwright_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -335,6 +335,19 @@ describe('Playwright', function () {
I.switchTo(null);
I.see('Iframe test');
});

it('should switch to iframe using css', () => {
I.amOnPage('/iframe');
I.switchTo('iframe#number-frame-1234');
I.see('Information');
I.see('Lots of valuable data here');
});

it('should switch to iframe using css when there are more than one iframes', () => {
I.amOnPage('/iframes');
I.switchTo('iframe#number-frame-1234');
I.see('Information');
});
});

describe('#seeInSource, #grabSource', () => {
Expand Down