mirror of
https://github.com/microsoft/playwright.git
synced 2024-11-30 23:45:33 +03:00
feat: enterFrame/exitFrame (#29992)
This introduces `Locator.enterFrame()` and `FrameLocator.exitFrame()` to convert between locator and frame locator. Fixes #29336.
This commit is contained in:
parent
a6d1fb93de
commit
70e6cdac57
@ -74,28 +74,59 @@ await page.FrameLocator(".result-frame").First.getByRole(AriaRole.Button).ClickA
|
||||
|
||||
**Converting Locator to FrameLocator**
|
||||
|
||||
If you have a [Locator] object pointing to an `iframe` it can be converted to [FrameLocator] using [`:scope`](https://developer.mozilla.org/en-US/docs/Web/CSS/:scope) CSS selector:
|
||||
If you have a [Locator] object pointing to an `iframe` it can be converted to [FrameLocator] using [`method: Locator.enterFrame`].
|
||||
|
||||
**Converting FrameLocator to Locator**
|
||||
|
||||
If you have a [FrameLocator] object it can be converted to [Locator] pointing to the same `iframe` using [`method: FrameLocator.exitFrame`].
|
||||
|
||||
|
||||
## method: FrameLocator.exitFrame
|
||||
* since: v1.43
|
||||
- returns: <[Locator]>
|
||||
|
||||
Returns a [Locator] object pointing to the same `iframe` as this frame locator.
|
||||
|
||||
Useful when you have a [FrameLocator] object obtained somewhere, and later on would like to interact with the `iframe` element.
|
||||
|
||||
**Usage**
|
||||
|
||||
```js
|
||||
const frameLocator = locator.frameLocator(':scope');
|
||||
const frameLocator = page.frameLocator('iframe[name="embedded"]');
|
||||
// ...
|
||||
const locator = frameLocator.exitFrame();
|
||||
await expect(locator).toBeVisible();
|
||||
```
|
||||
|
||||
```java
|
||||
Locator frameLocator = locator.frameLocator(':scope');
|
||||
FrameLocator frameLocator = page.frameLocator("iframe[name=\"embedded\"]");
|
||||
// ...
|
||||
Locator locator = frameLocator.exitFrame();
|
||||
assertThat(locator).isVisible();
|
||||
```
|
||||
|
||||
```python async
|
||||
frameLocator = locator.frame_locator(":scope")
|
||||
frame_locator = page.frame_locator("iframe[name=\"embedded\"]")
|
||||
# ...
|
||||
locator = frame_locator.exit_frame
|
||||
await expect(locator).to_be_visible()
|
||||
```
|
||||
|
||||
```python sync
|
||||
frameLocator = locator.frame_locator(":scope")
|
||||
frame_locator = page.frame_locator("iframe[name=\"embedded\"]")
|
||||
# ...
|
||||
locator = frame_locator.exit_frame
|
||||
expect(locator).to_be_visible()
|
||||
```
|
||||
|
||||
```csharp
|
||||
var frameLocator = locator.FrameLocator(":scope");
|
||||
var frameLocator = Page.FrameLocator("iframe[name=\"embedded\"]");
|
||||
// ...
|
||||
var locator = frameLocator.ExitFrame;
|
||||
await Expect(locator).ToBeVisibleAsync();
|
||||
```
|
||||
|
||||
|
||||
## method: FrameLocator.first
|
||||
* since: v1.17
|
||||
- returns: <[FrameLocator]>
|
||||
|
@ -747,6 +747,51 @@ Resolves given locator to the first matching DOM element. If there are no matchi
|
||||
|
||||
Resolves given locator to all matching DOM elements. If there are no matching elements, returns an empty list.
|
||||
|
||||
## method: Locator.enterFrame
|
||||
* since: v1.43
|
||||
- returns: <[FrameLocator]>
|
||||
|
||||
Returns a [FrameLocator] object pointing to the same `iframe` as this locator.
|
||||
|
||||
Useful when you have a [Locator] object obtained somewhere, and later on would like to interact with the content inside the frame.
|
||||
|
||||
**Usage**
|
||||
|
||||
```js
|
||||
const locator = page.locator('iframe[name="embedded"]');
|
||||
// ...
|
||||
const frameLocator = locator.enterFrame();
|
||||
await frameLocator.getByRole('button').click();
|
||||
```
|
||||
|
||||
```java
|
||||
Locator locator = page.locator("iframe[name=\"embedded\"]");
|
||||
// ...
|
||||
FrameLocator frameLocator = locator.enterFrame();
|
||||
frameLocator.getByRole(AriaRole.BUTTON).click();
|
||||
```
|
||||
|
||||
```python async
|
||||
locator = page.locator("iframe[name=\"embedded\"]")
|
||||
# ...
|
||||
frame_locator = locator.enter_frame
|
||||
await frame_locator.get_by_role("button").click()
|
||||
```
|
||||
|
||||
```python sync
|
||||
locator = page.locator("iframe[name=\"embedded\"]")
|
||||
# ...
|
||||
frame_locator = locator.enter_frame
|
||||
frame_locator.get_by_role("button").click()
|
||||
```
|
||||
|
||||
```csharp
|
||||
var locator = Page.Locator("iframe[name=\"embedded\"]");
|
||||
// ...
|
||||
var frameLocator = locator.EnterFrame;
|
||||
await frameLocator.GetByRole(AriaRole.Button).ClickAsync();
|
||||
```
|
||||
|
||||
## async method: Locator.evaluate
|
||||
* since: v1.14
|
||||
- returns: <[Serializable]>
|
||||
|
@ -192,6 +192,10 @@ export class Locator implements api.Locator {
|
||||
return await this._frame.$$(this._selector);
|
||||
}
|
||||
|
||||
enterFrame() {
|
||||
return new FrameLocator(this._frame, this._selector);
|
||||
}
|
||||
|
||||
first(): Locator {
|
||||
return new Locator(this._frame, this._selector + ' >> nth=0');
|
||||
}
|
||||
@ -404,6 +408,10 @@ export class FrameLocator implements api.FrameLocator {
|
||||
return this.locator(getByRoleSelector(role, options));
|
||||
}
|
||||
|
||||
exitFrame() {
|
||||
return new Locator(this._frame, this._frameSelector);
|
||||
}
|
||||
|
||||
frameLocator(selector: string): FrameLocator {
|
||||
return new FrameLocator(this._frame, this._frameSelector + ' >> internal:control=enter-frame >> ' + selector);
|
||||
}
|
||||
|
44
packages/playwright-core/types/types.d.ts
vendored
44
packages/playwright-core/types/types.d.ts
vendored
@ -11460,6 +11460,24 @@ export interface Locator {
|
||||
*/
|
||||
elementHandles(): Promise<Array<ElementHandle>>;
|
||||
|
||||
/**
|
||||
* Returns a {@link FrameLocator} object pointing to the same `iframe` as this locator.
|
||||
*
|
||||
* Useful when you have a {@link Locator} object obtained somewhere, and later on would like to interact with the
|
||||
* content inside the frame.
|
||||
*
|
||||
* **Usage**
|
||||
*
|
||||
* ```js
|
||||
* const locator = page.locator('iframe[name="embedded"]');
|
||||
* // ...
|
||||
* const frameLocator = locator.enterFrame();
|
||||
* await frameLocator.getByRole('button').click();
|
||||
* ```
|
||||
*
|
||||
*/
|
||||
enterFrame(): FrameLocator;
|
||||
|
||||
/**
|
||||
* Set a value to the input field.
|
||||
*
|
||||
@ -17761,14 +17779,32 @@ export interface FileChooser {
|
||||
* **Converting Locator to FrameLocator**
|
||||
*
|
||||
* If you have a {@link Locator} object pointing to an `iframe` it can be converted to {@link FrameLocator} using
|
||||
* [`:scope`](https://developer.mozilla.org/en-US/docs/Web/CSS/:scope) CSS selector:
|
||||
* [locator.enterFrame()](https://playwright.dev/docs/api/class-locator#locator-enter-frame).
|
||||
*
|
||||
* ```js
|
||||
* const frameLocator = locator.frameLocator(':scope');
|
||||
* ```
|
||||
* **Converting FrameLocator to Locator**
|
||||
*
|
||||
* If you have a {@link FrameLocator} object it can be converted to {@link Locator} pointing to the same `iframe`
|
||||
* using [frameLocator.exitFrame()](https://playwright.dev/docs/api/class-framelocator#frame-locator-exit-frame).
|
||||
*/
|
||||
export interface FrameLocator {
|
||||
/**
|
||||
* Returns a {@link Locator} object pointing to the same `iframe` as this frame locator.
|
||||
*
|
||||
* Useful when you have a {@link FrameLocator} object obtained somewhere, and later on would like to interact with the
|
||||
* `iframe` element.
|
||||
*
|
||||
* **Usage**
|
||||
*
|
||||
* ```js
|
||||
* const frameLocator = page.frameLocator('iframe[name="embedded"]');
|
||||
* // ...
|
||||
* const locator = frameLocator.exitFrame();
|
||||
* await expect(locator).toBeVisible();
|
||||
* ```
|
||||
*
|
||||
*/
|
||||
exitFrame(): Locator;
|
||||
|
||||
/**
|
||||
* Returns locator to the first matching frame.
|
||||
*/
|
||||
|
@ -21,7 +21,7 @@ import { test as it, expect } from './pageTest';
|
||||
async function routeIframe(page: Page) {
|
||||
await page.route('**/empty.html', route => {
|
||||
route.fulfill({
|
||||
body: '<iframe src="iframe.html"></iframe>',
|
||||
body: '<iframe src="iframe.html" name="frame1"></iframe>',
|
||||
contentType: 'text/html'
|
||||
}).catch(() => {});
|
||||
});
|
||||
@ -298,3 +298,23 @@ it('should work with COEP/COOP/CORP isolated iframe', async ({ page, server, bro
|
||||
await page.frameLocator('iframe').getByRole('button').click();
|
||||
expect(await page.frames()[1].evaluate(() => window['__clicked'])).toBe(true);
|
||||
});
|
||||
|
||||
it('locator.enterFrame should work', async ({ page, server }) => {
|
||||
await routeIframe(page);
|
||||
await page.goto(server.EMPTY_PAGE);
|
||||
const locator = page.locator('iframe');
|
||||
const frameLocator = locator.enterFrame();
|
||||
const button = frameLocator.locator('button');
|
||||
expect(await button.innerText()).toBe('Hello iframe');
|
||||
await expect(button).toHaveText('Hello iframe');
|
||||
await button.click();
|
||||
});
|
||||
|
||||
it('frameLocator.exitFrame should work', async ({ page, server }) => {
|
||||
await routeIframe(page);
|
||||
await page.goto(server.EMPTY_PAGE);
|
||||
const frameLocator = page.frameLocator('iframe');
|
||||
const locator = frameLocator.exitFrame();
|
||||
await expect(locator).toBeVisible();
|
||||
expect(await locator.getAttribute('name')).toBe('frame1');
|
||||
});
|
||||
|
Loading…
Reference in New Issue
Block a user