Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions docs/src/api/class-frame.md
Original file line number Diff line number Diff line change
Expand Up @@ -1479,6 +1479,13 @@ var locator = frame.PierceFrames.GetByRole(AriaRole.Button);
await locator.ClickAsync();
```

### option: Frame.pierceFrames.pierce
* since: v1.63
- `pierce` <[boolean]>

Whether to pierce frames. Pass `false` to opt out of frame piercing enabled
by the [`option: Browser.newContext.pierceFrames`] context option. Defaults to `true`.

## async method: Frame.press
* since: v1.8
* discouraged: Use locator-based [`method: Locator.press`] instead. Read more about [locators](../locators.md).
Expand Down
7 changes: 7 additions & 0 deletions docs/src/api/class-page.md
Original file line number Diff line number Diff line change
Expand Up @@ -3208,6 +3208,13 @@ var locator = page.PierceFrames.GetByRole(AriaRole.Button);
await locator.ClickAsync();
```

### option: Page.pierceFrames.pierce
* since: v1.63
- `pierce` <[boolean]>

Whether to pierce frames. Pass `false` to opt out of frame piercing enabled
by the [`option: Browser.newContext.pierceFrames`] context option. Defaults to `true`.

## async method: Page.press
* since: v1.8
* discouraged: Use locator-based [`method: Locator.press`] instead. Read more about [locators](../locators.md).
Expand Down
7 changes: 7 additions & 0 deletions docs/src/api/params.md
Original file line number Diff line number Diff line change
Expand Up @@ -885,6 +885,12 @@ Actual picture of each page will be scaled down if necessary to fit the specifie

Network proxy settings to use with this context. Defaults to none.

## context-option-pierce-frames
- `pierceFrames` <[boolean]>

If set to true, all selectors in this context will pierce frames by default, as if every locator
was created through [`method: Page.pierceFrames`]. Defaults to `false`.

## context-option-strict
- `strictSelectors` <[boolean]>

Expand Down Expand Up @@ -1124,6 +1130,7 @@ between the same pixel in compared images, between zero (strict) and one (lax),
- %%-context-option-recordvideo-%%
- %%-context-option-recordvideo-dir-%%
- %%-context-option-recordvideo-size-%%
- %%-context-option-pierce-frames-%%
- %%-context-option-strict-%%
- %%-context-option-service-worker-policy-%%

Expand Down
33 changes: 33 additions & 0 deletions docs/src/release-notes-csharp.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,39 @@ toc_max_heading_level: 2

import LiteYouTube from '@site/src/components/LiteYouTube';

## Version 1.62

### 🖼️ WebP screenshots

[`method: Page.screenshot`] and [`method: Locator.screenshot`] can now capture screenshots in the WebP format — Playwright infers the format from a `.webp` file extension, or you can set the `type` explicitly. Quality `100` (the default) is lossless, while lower values use lossy compression:

```csharp
await page.ScreenshotAsync(new() { Path = "homepage.webp", Quality = 50 });
```

### New APIs

- New `scroll` option (`"auto"` | `"none"`) on actions to opt out of Playwright's automatic scroll-into-view.
- New [`method: Locator.waitForFunction`] waits until a function — called with the matching element — returns a truthy value.
- New [`method: APIResponse.timing`] returns resource timing information for an API response.

### Announcements

* 📋 The clipboard is now isolated from the operating system in headless mode, so tests that use `navigator.clipboard` no longer read or overwrite the clipboard of the machine running them.
* ⚠️ Debian 11 is not supported anymore.

### Browser Versions

- Chromium 151.0.7922.34
- Mozilla Firefox 153.0
- WebKit 26.5

This version was also tested against the following stable channels:

- Google Chrome 151
- Microsoft Edge 151


## Version 1.61

### 🔑 WebAuthn passkeys
Expand Down
35 changes: 35 additions & 0 deletions docs/src/release-notes-java.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,41 @@ toc_max_heading_level: 2

import LiteYouTube from '@site/src/components/LiteYouTube';

## Version 1.62

### 🖼️ WebP screenshots

[`method: Page.screenshot`] and [`method: Locator.screenshot`] can now capture screenshots in the WebP format — Playwright infers the format from a `.webp` file extension, or you can set the `type` explicitly. Quality `100` (the default) is lossless, while lower values use lossy compression:

```java
page.screenshot(new Page.ScreenshotOptions()
.setPath(Paths.get("homepage.webp"))
.setQuality(50));
```

### New APIs

- New `scroll` option (`"auto"` | `"none"`) on actions to opt out of Playwright's automatic scroll-into-view.
- New [`method: Locator.waitForFunction`] waits until a function — called with the matching element — returns a truthy value.
- New [`method: APIResponse.timing`] returns resource timing information for an API response.

### Announcements

* 📋 The clipboard is now isolated from the operating system in headless mode, so tests that use `navigator.clipboard` no longer read or overwrite the clipboard of the machine running them.
* ⚠️ Debian 11 is not supported anymore.

### Browser Versions

- Chromium 151.0.7922.34
- Mozilla Firefox 153.0
- WebKit 26.5

This version was also tested against the following stable channels:

- Google Chrome 151
- Microsoft Edge 151


## Version 1.61

### 🔑 WebAuthn passkeys
Expand Down
1 change: 1 addition & 0 deletions docs/src/release-notes-js.md
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,7 @@ export default defineConfig({

### Announcements

* 📋 The clipboard is now isolated from the operating system in headless mode, so tests that use `navigator.clipboard` no longer read or overwrite the clipboard of the machine running them.
* ⚠️ Debian 11 is not supported anymore.

### Browser Versions
Expand Down
33 changes: 33 additions & 0 deletions docs/src/release-notes-python.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,39 @@ toc_max_heading_level: 2

import LiteYouTube from '@site/src/components/LiteYouTube';

## Version 1.62

### 🖼️ WebP screenshots

[`method: Page.screenshot`] and [`method: Locator.screenshot`] can now capture screenshots in the WebP format — Playwright infers the format from a `.webp` file extension, or you can set the `type` explicitly. Quality `100` (the default) is lossless, while lower values use lossy compression:

```python
page.screenshot(path="homepage.webp", quality=50)
```

### New APIs

- New `scroll` option (`"auto"` | `"none"`) on actions to opt out of Playwright's automatic scroll-into-view.
- New [`method: Locator.waitForFunction`] waits until a function — called with the matching element — returns a truthy value.
- New [`method: APIResponse.timing`] returns resource timing information for an API response.

### Announcements

* 📋 The clipboard is now isolated from the operating system in headless mode, so tests that use `navigator.clipboard` no longer read or overwrite the clipboard of the machine running them.
* ⚠️ Debian 11 is not supported anymore.

### Browser Versions

- Chromium 151.0.7922.34
- Mozilla Firefox 153.0
- WebKit 26.5

This version was also tested against the following stable channels:

- Google Chrome 151
- Microsoft Edge 151


## Version 1.61

### 🔑 WebAuthn passkeys
Expand Down
15 changes: 15 additions & 0 deletions docs/src/test-api/class-testoptions.md
Original file line number Diff line number Diff line change
Expand Up @@ -462,6 +462,21 @@ export default defineConfig({
});
```

## property: TestOptions.pierceFrames = %%-context-option-pierce-frames-%%
* since: v1.63

**Usage**

```js title="playwright.config.ts"
import { defineConfig } from '@playwright/test';

export default defineConfig({
use: {
pierceFrames: true,
}
});
```

## property: TestOptions.proxy = %%-browser-option-proxy-%%
* since: v1.10

Expand Down
14 changes: 11 additions & 3 deletions packages/isomorphic/locatorGenerators.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import type { NestedSelectorBody } from './selectorParser';
import type { ParsedSelector } from './selectorParser';

export type Language = 'javascript' | 'python' | 'java' | 'csharp' | 'jsonl';
export type LocatorType = 'default' | 'role' | 'text' | 'label' | 'placeholder' | 'alt' | 'title' | 'test-id' | 'nth' | 'first' | 'last' | 'visible' | 'has-text' | 'has-not-text' | 'has' | 'hasNot' | 'frame' | 'frame-locator' | 'pierce-frames' | 'and' | 'or' | 'chain';
export type LocatorType = 'default' | 'role' | 'text' | 'label' | 'placeholder' | 'alt' | 'title' | 'test-id' | 'nth' | 'first' | 'last' | 'visible' | 'has-text' | 'has-not-text' | 'has' | 'hasNot' | 'frame' | 'frame-locator' | 'pierce-frames' | 'no-pierce-frames' | 'and' | 'or' | 'chain';
export type LocatorBase = 'page' | 'locator' | 'frame-locator';
export type Quote = '\'' | '"' | '`';

Expand Down Expand Up @@ -205,8 +205,8 @@ function innerAsLocators(factory: LocatorFactory, parsed: ParsedSelector, isFram
continue;
}
}
if (part.name === 'internal:control' && (part.body as string) === 'pierce-frames') {
tokens.push([factory.generateLocator(base, 'pierce-frames', '')]);
if (part.name === 'internal:control' && ((part.body as string) === 'pierce-frames' || (part.body as string) === 'no-pierce-frames')) {
tokens.push([factory.generateLocator(base, part.body as LocatorType, '')]);
nextBase = 'frame-locator';
continue;
}
Expand Down Expand Up @@ -322,6 +322,8 @@ export class JavaScriptLocatorFactory implements LocatorFactory {
return `contentFrame()`;
case 'pierce-frames':
return `pierceFrames()`;
case 'no-pierce-frames':
return `pierceFrames({ pierce: false })`;
case 'nth':
return `nth(${body})`;
case 'first':
Expand Down Expand Up @@ -423,6 +425,8 @@ export class PythonLocatorFactory implements LocatorFactory {
return `content_frame`;
case 'pierce-frames':
return `pierce_frames`;
case 'no-pierce-frames':
return `pierce_frames(pierce=False)`;
case 'nth':
return `nth(${body})`;
case 'first':
Expand Down Expand Up @@ -537,6 +541,8 @@ export class JavaLocatorFactory implements LocatorFactory {
return `contentFrame()`;
case 'pierce-frames':
return `pierceFrames()`;
case 'no-pierce-frames':
return `pierceFrames(new ${clazz}.PierceFramesOptions().setPierce(false))`;
case 'nth':
return `nth(${body})`;
case 'first':
Expand Down Expand Up @@ -641,6 +647,8 @@ export class CSharpLocatorFactory implements LocatorFactory {
return `ContentFrame`;
case 'pierce-frames':
return `PierceFrames`;
case 'no-pierce-frames':
return `PierceFrames(new() { Pierce = false })`;
case 'nth':
return `Nth(${body})`;
case 'first':
Expand Down
21 changes: 11 additions & 10 deletions packages/isomorphic/selectorParser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -91,24 +91,25 @@ export function parseSelector(selector: string): ParsedSelector {
};
}

// Splits a selector into per-frame chunks separated by "enter-frame" boundaries. When the selector
// starts with the "pierce-frames" token, `pierce` is set globally and "enter-frame" tokens are
// preserved, so `chunks` holds a single chunk.
export function splitSelectorByFrame(selectorText: string): { pierce: boolean, chunks: ParsedSelector[] } {
// Splits a selector into per-frame chunks separated by "enter-frame" boundaries in non-piercing mode.
// In piercing mode, "enter-frame" tokens are preserved, so `chunks` holds a single chunk.
export function splitSelectorByFrame(selectorText: string, pierceByDefault?: boolean): { pierce: boolean, chunks: ParsedSelector[] } {
const selector = parseSelector(selectorText);
const chunks: ParsedSelector[] = [];
let chunk: ParsedSelector = {
parts: [],
};
let pierce = false;
let pierce = !!pierceByDefault;
let pierceToken = false;
let chunkStartIndex = 0;
for (let i = 0; i < selector.parts.length; ++i) {
const part = selector.parts[i];
if (part.name === 'internal:control' && part.body === 'pierce-frames') {
// Piercing is a whole-page operation, so it only makes sense as the very first token.
if (part.name === 'internal:control' && (part.body === 'pierce-frames' || part.body === 'no-pierce-frames')) {
// Piercing applies to the whole selector, so the token only makes sense as the very first one.
if (i !== 0)
throw new InvalidSelectorError(`"pierce-frames" is only allowed as the first selector token, while parsing selector ${selectorText}`);
pierce = true;
throw new InvalidSelectorError(`"${part.body}" is only allowed as the first selector token, while parsing selector ${selectorText}`);
pierce = part.body === 'pierce-frames';
pierceToken = true;
chunkStartIndex = i + 1;
continue;
}
Expand All @@ -130,7 +131,7 @@ export function splitSelectorByFrame(selectorText: string): { pierce: boolean, c
chunk.parts.push(part);
}
if (!chunk.parts.length) {
if (pierce)
if (pierceToken)
throw new InvalidSelectorError(`Selector cannot be empty when piercing frames, while parsing selector ${selectorText}`);
throw new InvalidSelectorError(`Selector cannot end with entering frame, while parsing selector ${selectorText}`);
}
Expand Down
48 changes: 46 additions & 2 deletions packages/playwright-client/types/types.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4188,8 +4188,16 @@ export interface Page {
* await locator.click();
* ```
*
* @param options
*/
pierceFrames(): FrameLocator;
pierceFrames(options?: {
/**
* Whether to pierce frames. Pass `false` to opt out of frame piercing enabled by the
* [`pierceFrames`](https://playwright.dev/docs/api/class-browser#browser-new-context-option-pierce-frames) context
* option. Defaults to `true`.
*/
pierce?: boolean;
}): FrameLocator;

/**
* **NOTE** Use locator-based [locator.press(key[, options])](https://playwright.dev/docs/api/class-locator#locator-press)
Expand Down Expand Up @@ -8229,8 +8237,16 @@ export interface Frame {
* await locator.click();
* ```
*
* @param options
*/
pierceFrames(): FrameLocator;
pierceFrames(options?: {
/**
* Whether to pierce frames. Pass `false` to opt out of frame piercing enabled by the
* [`pierceFrames`](https://playwright.dev/docs/api/class-browser#browser-new-context-option-pierce-frames) context
* option. Defaults to `true`.
*/
pierce?: boolean;
}): FrameLocator;

/**
* **NOTE** Use locator-based [locator.press(key[, options])](https://playwright.dev/docs/api/class-locator#locator-press)
Expand Down Expand Up @@ -11424,6 +11440,13 @@ export interface Browser {
*/
permissions?: Array<string>;

/**
* If set to true, all selectors in this context will pierce frames by default, as if every locator was created
* through [page.pierceFrames([options])](https://playwright.dev/docs/api/class-page#page-pierce-frames). Defaults to
* `false`.
*/
pierceFrames?: boolean;

/**
* Network proxy settings to use with this context. Defaults to none.
*/
Expand Down Expand Up @@ -17494,6 +17517,13 @@ export interface BrowserType<Unused = {}> {
*/
permissions?: Array<string>;

/**
* If set to true, all selectors in this context will pierce frames by default, as if every locator was created
* through [page.pierceFrames([options])](https://playwright.dev/docs/api/class-page#page-pierce-frames). Defaults to
* `false`.
*/
pierceFrames?: boolean;

/**
* Network proxy settings.
*/
Expand Down Expand Up @@ -24504,6 +24534,13 @@ export interface AndroidDevice {
*/
permissions?: Array<string>;

/**
* If set to true, all selectors in this context will pierce frames by default, as if every locator was created
* through [page.pierceFrames([options])](https://playwright.dev/docs/api/class-page#page-pierce-frames). Defaults to
* `false`.
*/
pierceFrames?: boolean;

/**
* Optional package name to launch instead of default Chrome for Android.
*/
Expand Down Expand Up @@ -25721,6 +25758,13 @@ export interface BrowserContextOptions {
*/
permissions?: Array<string>;

/**
* If set to true, all selectors in this context will pierce frames by default, as if every locator was created
* through [page.pierceFrames([options])](https://playwright.dev/docs/api/class-page#page-pierce-frames). Defaults to
* `false`.
*/
pierceFrames?: boolean;

/**
* Network proxy settings to use with this context. Defaults to none.
*/
Expand Down
Loading
Loading