Skip to content
9 changes: 9 additions & 0 deletions .github/copilot-instructions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
## PR Review Guidelines

When reviewing pull requests:

- Only comment on semantically meaningful issues: bugs, incorrect logic, security problems, or API contract violations.
- Skip style, formatting, naming, and whitespace observations unless they cause functional problems.
- Keep each comment short — one or two sentences maximum.
- Do not write long descriptions or summaries of what the code does.
- Do not suggest refactors or improvements unrelated to the PR's stated goal.
3 changes: 3 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,8 @@ When creating or moving files, update the relevant `DEPS.list` to declare allowe

## Commit Convention

Before committing, run `npm run flint` and fix errors.

Semantic commit messages: `label(scope): description`

Labels: `fix`, `feat`, `chore`, `docs`, `test`, `devops`
Expand Down Expand Up @@ -123,6 +125,7 @@ EOF
```

Never add Co-Authored-By agents in commit message.
Never add "Generated with" in commit message.
Branch naming for issue fixes: `fix-<issue-number>`

## Development Guides
Expand Down
8 changes: 8 additions & 0 deletions docs/src/api/class-browsercontext.md
Original file line number Diff line number Diff line change
Expand Up @@ -1004,6 +1004,14 @@ named `page`, but it can be a `Page` or `Frame` type.

Creates a new page in the browser context.

## method: BrowserContext.contextOptions
* since: v1.59
* langs: js
- returns: <[Object]>

Returns the context options that were used to create this browser context. The return type matches the options
accepted by [`method: Browser.newContext`].

## method: BrowserContext.pages
* since: v1.8
- returns: <[Array]<[Page]>>
Expand Down
1 change: 1 addition & 0 deletions docs/src/api/class-screencast.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ await screencast.stop();

## async method: Screencast.start
* since: v1.59
- returns: <[Disposable]>

Starts capturing screencast frames. Frames are emitted as [`event: Screencast.screencastFrame`] events.

Expand Down
1 change: 1 addition & 0 deletions docs/src/api/class-tracing.md
Original file line number Diff line number Diff line change
Expand Up @@ -305,6 +305,7 @@ To specify the final trace zip file name, you need to pass `path` option to

## async method: Tracing.group
* since: v1.49
- returns: <[Disposable]>

:::caution
Use `test.step` instead when available.
Expand Down
53 changes: 27 additions & 26 deletions docs/src/api/class-video.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,33 +26,33 @@ Console.WriteLine(await page.Video.GetPathAsync());
Alternatively, you can use [`method: Video.start`] and [`method: Video.stop`] to record video manually. This approach is mutually exclusive with the `recordVideo` option.

```js
await page.video().start();
await page.video().start({ path: 'video.webm' });
// ... perform actions ...
await page.video().stop({ path: 'video.webm' });
await page.video().stop();
```

```java
page.video().start();
page.video().start(new Video.StartOptions().setPath(Paths.get("video.webm")));
// ... perform actions ...
page.video().stop(new Video.StopOptions().setPath(Paths.get("video.webm")));
page.video().stop();
```

```python async
await page.video.start()
await page.video.start(path="video.webm")
# ... perform actions ...
await page.video.stop(path="video.webm")
await page.video.stop()
```

```python sync
page.video.start()
page.video.start(path="video.webm")
# ... perform actions ...
page.video.stop(path="video.webm")
page.video.stop()
```

```csharp
await page.Video.StartAsync();
await page.Video.StartAsync(new() { Path = "video.webm" });
// ... perform actions ...
await page.Video.StopAsync(new() { Path = "video.webm" });
await page.Video.StopAsync();
```

## async method: Video.delete
Expand Down Expand Up @@ -94,41 +94,48 @@ Path where the video should be saved.

## async method: Video.start
* since: v1.59
- returns: <[Disposable]>

Starts video recording. This method is mutually exclusive with the `recordVideo` context option.

**Usage**

```js
await page.video().start();
await page.video().start({ path: 'video.webm' });
// ... perform actions ...
await page.video().stop({ path: 'video.webm' });
await page.video().stop();
```

```java
page.video().start();
page.video().start(new Video.StartOptions().setPath(Paths.get("video.webm")));
// ... perform actions ...
page.video().stop(new Video.StopOptions().setPath(Paths.get("video.webm")));
page.video().stop();
```

```python async
await page.video.start()
await page.video.start(path="video.webm")
# ... perform actions ...
await page.video.stop(path="video.webm")
await page.video.stop()
```

```python sync
page.video.start()
page.video.start(path="video.webm")
# ... perform actions ...
page.video.stop(path="video.webm")
page.video.stop()
```

```csharp
await page.Video.StartAsync();
await page.Video.StartAsync(new() { Path = "video.webm" });
// ... perform actions ...
await page.Video.StopAsync(new() { Path = "video.webm" });
await page.Video.StopAsync();
```

### option: Video.start.path
* since: v1.59
- `path` <[path]>

Path where the video should be saved when the recording is stopped.

### option: Video.start.size
* since: v1.59
- `size` ?<[Object]>
Expand All @@ -141,9 +148,3 @@ Optional dimensions of the recorded video. If not specified the size will be equ
* since: v1.59

Stops video recording started with [`method: Video.start`].

### option: Video.stop.path
* since: v1.59
- `path` <[path]>

Path where the video should be saved.
8 changes: 0 additions & 8 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 0 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,6 @@
"@types/codemirror": "^5.60.7",
"@types/formidable": "^2.0.4",
"@types/mdast": "^4.0.4",
"@types/minimist": "^1.2.5",
"@types/node": "18.19.76",
"@types/react": "^19.2.1",
"@types/react-dom": "^19.2.1",
Expand Down
53 changes: 29 additions & 24 deletions packages/playwright-client/types/types.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4805,8 +4805,8 @@ export interface Page {
/**
* Video object associated with this page. Can be used to control video recording with
* [video.start([options])](https://playwright.dev/docs/api/class-video#video-start) and
* [video.stop([options])](https://playwright.dev/docs/api/class-video#video-stop), or to access the video file when
* using the `recordVideo` context option.
* [video.stop()](https://playwright.dev/docs/api/class-video#video-stop), or to access the video file when using the
* `recordVideo` context option.
*/
video(): Video;

Expand Down Expand Up @@ -8323,6 +8323,12 @@ export interface BrowserContext {
*/
behavior?: 'wait'|'ignoreErrors'|'default'
}): Promise<void>;

/**
* Returns the context options that were used to create this browser context. The return type matches the options
* accepted by [browser.newContext([options])](https://playwright.dev/docs/api/class-browser#browser-new-context).
*/
contextOptions(): BrowserContextOptions;
/**
* This event is not emitted.
*/
Expand Down Expand Up @@ -9750,6 +9756,12 @@ export interface Browser {
*/
behavior?: 'wait'|'ignoreErrors'|'default'
}): Promise<void>;

/**
* Returns the launch options that were used to launch this browser. The return type matches the options accepted by
* [browserType.launch([options])](https://playwright.dev/docs/api/class-browsertype#browser-type-launch).
*/
launchOptions(): LaunchOptions;
/**
* Emitted when Browser gets disconnected from the browser application. This might happen because of one of the
* following:
Expand Down Expand Up @@ -9841,12 +9853,6 @@ export interface Browser {
*/
isConnected(): boolean;

/**
* Returns the launch options that were used to launch this browser. The return type matches the options accepted by
* [browserType.launch([options])](https://playwright.dev/docs/api/class-browsertype#browser-type-launch).
*/
launchOptions(): Object;

/**
* **NOTE** CDP Sessions are only supported on Chromium-based browsers.
*
Expand Down Expand Up @@ -21778,7 +21784,7 @@ export interface Screencast {
*/
height: number;
};
}): Promise<void>;
}): Promise<Disposable>;

/**
* Stops the screencast started with
Expand Down Expand Up @@ -21957,7 +21963,7 @@ export interface Tracing {

column?: number;
};
}): Promise<void>;
}): Promise<Disposable>;

/**
* Closes the last group created by
Expand Down Expand Up @@ -22110,13 +22116,13 @@ export interface Tracing {
* ```
*
* Alternatively, you can use [video.start([options])](https://playwright.dev/docs/api/class-video#video-start) and
* [video.stop([options])](https://playwright.dev/docs/api/class-video#video-stop) to record video manually. This
* approach is mutually exclusive with the `recordVideo` option.
* [video.stop()](https://playwright.dev/docs/api/class-video#video-stop) to record video manually. This approach is
* mutually exclusive with the `recordVideo` option.
*
* ```js
* await page.video().start();
* await page.video().start({ path: 'video.webm' });
* // ... perform actions ...
* await page.video().stop({ path: 'video.webm' });
* await page.video().stop();
* ```
*
*/
Expand Down Expand Up @@ -22145,14 +22151,19 @@ export interface Video {
* **Usage**
*
* ```js
* await page.video().start();
* await page.video().start({ path: 'video.webm' });
* // ... perform actions ...
* await page.video().stop({ path: 'video.webm' });
* await page.video().stop();
* ```
*
* @param options
*/
start(options?: {
/**
* Path where the video should be saved when the recording is stopped.
*/
path?: string;

/**
* Optional dimensions of the recorded video. If not specified the size will be equal to page viewport scaled down to
* fit into 800x800. Actual picture of the page will be scaled down if necessary to fit the specified size.
Expand All @@ -22168,19 +22179,13 @@ export interface Video {
*/
height: number;
};
}): Promise<void>;
}): Promise<Disposable>;

/**
* Stops video recording started with
* [video.start([options])](https://playwright.dev/docs/api/class-video#video-start).
* @param options
*/
stop(options?: {
/**
* Path where the video should be saved.
*/
path?: string;
}): Promise<void>;
stop(): Promise<void>;
}

/**
Expand Down
2 changes: 1 addition & 1 deletion packages/playwright-core/browsers.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@
},
{
"name": "webkit",
"revision": "2269",
"revision": "2270",
"installByDefault": true,
"revisionOverrides": {
"mac14": "2251",
Expand Down
24 changes: 23 additions & 1 deletion packages/playwright-core/src/client/browserContext.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ import { WebError } from './webError';
import { Worker } from './worker';
import { TimeoutSettings } from './timeoutSettings';
import { mkdirIfNeeded } from './fileUtils';
import { headersObjectToArray } from '../utils/isomorphic/headers';
import { headersArrayToObject, headersObjectToArray } from '../utils/isomorphic/headers';
import { urlMatchesEqual } from '../utils/isomorphic/urlMatch';
import { isRegExp, isString } from '../utils/isomorphic/rtti';
import { rewriteErrorMessage } from '../utils/isomorphic/stackTrace';
Expand Down Expand Up @@ -290,6 +290,10 @@ export class BrowserContext extends ChannelOwner<channels.BrowserContextChannel>
return this._browser;
}

contextOptions() {
return contextParamsToPublicOptions(this._options);
}

pages(): Page[] {
return [...this._pages];
}
Expand Down Expand Up @@ -603,6 +607,24 @@ export async function prepareBrowserContextParams(platform: Platform, options: B
return contextParams;
}

function contextParamsToPublicOptions(params: channels.BrowserNewContextParams): api.BrowserContextOptions {
const result = {
...params,
viewport: params.noDefaultViewport ? null : params.viewport,
extraHTTPHeaders: params.extraHTTPHeaders ? headersArrayToObject(params.extraHTTPHeaders, false) : undefined,
colorScheme: params.colorScheme === 'no-override' ? null : params.colorScheme,
reducedMotion: params.reducedMotion === 'no-override' ? null : params.reducedMotion,
forcedColors: params.forcedColors === 'no-override' ? null : params.forcedColors,
contrast: params.contrast === 'no-override' ? null : params.contrast,
acceptDownloads: params.acceptDownloads === 'accept' ? true : params.acceptDownloads === 'deny' ? false : undefined,
storageState: undefined,
};
delete result.clientCertificates;
delete result.noDefaultViewport;
delete result.selectorEngines;
return result;
}

function toAcceptDownloadsProtocol(acceptDownloads?: boolean) {
if (acceptDownloads === undefined)
return undefined;
Expand Down
Loading
Loading