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
8 changes: 6 additions & 2 deletions docs/src/api/class-screencast.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,9 @@ await page.screencast.stop();
```js
// Capture frames
await page.screencast.start({
onFrame: ({ data }) => console.log(`frame size: ${data.length}`),
onFrame: ({ data, viewportWidth, viewportHeight }) => {
console.log(`frame size: ${data.length} (${viewportWidth}x${viewportHeight})`);
},
size: { width: 800, height: 600 },
});
// ... perform actions ...
Expand All @@ -34,8 +36,10 @@ await page.screencast.stop();
- `onFrame` <[function]\([Object]\): [Promise]>
- alias: ScreencastFrame
- `data` <[Buffer]> JPEG-encoded frame data.
- `viewportWidth` <[int]> Width of the page viewport at the time the frame was captured.
- `viewportHeight` <[int]> Height of the page viewport at the time the frame was captured.

Callback that receives JPEG-encoded frame data.
Callback that receives JPEG-encoded frame data along with the page viewport size at the time of capture.

### option: Screencast.start.path
* since: v1.59
Expand Down
5 changes: 3 additions & 2 deletions docs/src/api/params.md
Original file line number Diff line number Diff line change
Expand Up @@ -128,15 +128,16 @@ Defaults to `left`.

## input-files
- `files` <[path]|[Array]<[path]>|[Object]|[Array]<[Object]>>
- alias-csharp: FilePayload
- alias-java: FilePayload
- alias: FilePayload
- `name` <[string]> File name
- `mimeType` <[string]> File type
- `buffer` <[Buffer]> File content

## drop-payload
- `payload` <[Object]>
- alias: DropPayload
- `files` ?<[path]|[Array]<[path]>|[Object]|[Array]<[Object]>>
- alias: FilePayload
- `name` <[string]> File name
- `mimeType` <[string]> File type
- `buffer` <[Buffer]> File content
Expand Down
6 changes: 4 additions & 2 deletions packages/playwright-client/types/types.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16557,7 +16557,9 @@ export interface Screencast {
* ```js
* // Capture frames
* await page.screencast.start({
* onFrame: ({ data }) => console.log(`frame size: ${data.length}`),
* onFrame: ({ data, viewportWidth, viewportHeight }) => {
* console.log(`frame size: ${data.length} (${viewportWidth}x${viewportHeight})`);
* },
* size: { width: 800, height: 600 },
* });
* // ... perform actions ...
Expand All @@ -16567,7 +16569,7 @@ export interface Screencast {
* @param options
*/
start(options?: {
onFrame?: (frame: { data: Buffer }) => Promise<any>|any;
onFrame?: (frame: { data: Buffer, viewportWidth: number, viewportHeight: number }) => Promise<any>|any;
path?: string;
size?: {
width: number;
Expand Down
8 changes: 4 additions & 4 deletions packages/playwright-core/browsers.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,16 @@
},
{
"name": "chromium-tip-of-tree",
"revision": "1426",
"revision": "1427",
"installByDefault": false,
"browserVersion": "149.0.7816.0",
"browserVersion": "149.0.7827.0",
"title": "Chrome Canary for Testing"
},
{
"name": "chromium-tip-of-tree-headless-shell",
"revision": "1426",
"revision": "1427",
"installByDefault": false,
"browserVersion": "149.0.7816.0",
"browserVersion": "149.0.7827.0",
"title": "Chrome Canary Headless Shell"
},
{
Expand Down
8 changes: 4 additions & 4 deletions packages/playwright-core/src/client/screencast.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,17 +24,17 @@ export class Screencast implements api.Screencast {
private _page: Page;
private _started = false;
private _savePath: string | undefined;
private _onFrame: ((frame: { data: Buffer }) => Promise<any>) | null = null;
private _onFrame: ((frame: { data: Buffer, viewportWidth: number, viewportHeight: number }) => Promise<any>) | null = null;
private _artifact: Artifact | undefined;

constructor(page: Page) {
this._page = page;
this._page._channel.on('screencastFrame', ({ data }) => {
void this._onFrame?.({ data });
this._page._channel.on('screencastFrame', ({ data, viewportWidth, viewportHeight }) => {
void this._onFrame?.({ data, viewportWidth, viewportHeight });
});
}

async start(options: { onFrame?: (frame: { data: Buffer }) => Promise<any>|any, path?: string, size?: { width: number, height: number }, quality?: number } = {}): Promise<DisposableStub> {
async start(options: { onFrame?: (frame: { data: Buffer, viewportWidth: number, viewportHeight: number }) => Promise<any>|any, path?: string, size?: { width: number, height: number }, quality?: number } = {}): Promise<DisposableStub> {
if (this._started)
throw new Error('Screencast is already started');
this._started = true;
Expand Down
2 changes: 2 additions & 0 deletions packages/playwright-core/src/protocol/validator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2189,6 +2189,8 @@ scheme.PageRouteEvent = tObject({
});
scheme.PageScreencastFrameEvent = tObject({
data: tBinary,
viewportWidth: tInt,
viewportHeight: tInt,
});
scheme.PageWebSocketRouteEvent = tObject({
webSocketRoute: tChannel(['WebSocketRoute']),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -396,7 +396,7 @@ export class PageDispatcher extends Dispatcher<Page, channels.PageChannel, Brows
if (params.sendFrames) {
this._screencastClient = {
onFrame: (frame: ScreencastFrame) => {
this._dispatchEvent('screencastFrame', { data: frame.buffer });
this._dispatchEvent('screencastFrame', { data: frame.buffer, viewportWidth: frame.viewportWidth, viewportHeight: frame.viewportHeight });
},
dispose: () => {},
size: params.size,
Expand Down
3 changes: 2 additions & 1 deletion packages/playwright-core/src/tools/backend/screenshot.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,8 @@ const screenshot = defineTabTool({
response.addCode(`await page.screenshot(${formatObject({ ...options, path: resolvedFile.relativeName })});`);

await response.addFileResult(resolvedFile, data);
await response.registerImageResult(data, fileType);
if (!params.filename)
await response.registerImageResult(data, fileType);
}
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -448,11 +448,10 @@ class AttachedPage {

private async _startScreencast(page: api.Page) {
await page.screencast.start({
onFrame: ({ data }: { data: Buffer }) => {
onFrame: ({ data, viewportWidth, viewportHeight }) => {
if (this._disposed)
return;
const vp = page.viewportSize();
this._owner.emitFrame(data.toString('base64'), vp?.width ?? 0, vp?.height ?? 0);
this._owner.emitFrame(data.toString('base64'), viewportWidth, viewportHeight);
},
size: { width: 1280, height: 800 },
...(this._recordingPath ? { path: this._recordingPath } : {}),
Expand Down
6 changes: 4 additions & 2 deletions packages/playwright-core/types/types.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16557,7 +16557,9 @@ export interface Screencast {
* ```js
* // Capture frames
* await page.screencast.start({
* onFrame: ({ data }) => console.log(`frame size: ${data.length}`),
* onFrame: ({ data, viewportWidth, viewportHeight }) => {
* console.log(`frame size: ${data.length} (${viewportWidth}x${viewportHeight})`);
* },
* size: { width: 800, height: 600 },
* });
* // ... perform actions ...
Expand All @@ -16567,7 +16569,7 @@ export interface Screencast {
* @param options
*/
start(options?: {
onFrame?: (frame: { data: Buffer }) => Promise<any>|any;
onFrame?: (frame: { data: Buffer, viewportWidth: number, viewportHeight: number }) => Promise<any>|any;
path?: string;
size?: {
width: number;
Expand Down
2 changes: 2 additions & 0 deletions packages/protocol/spec/page.yml
Original file line number Diff line number Diff line change
Expand Up @@ -652,6 +652,8 @@ Page:
screencastFrame:
parameters:
data: binary
viewportWidth: int
viewportHeight: int

webSocketRoute:
parameters:
Expand Down
2 changes: 2 additions & 0 deletions packages/protocol/src/channels.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3908,6 +3908,8 @@ export type PageRouteEvent = {
};
export type PageScreencastFrameEvent = {
data: Binary,
viewportWidth: number,
viewportHeight: number,
};
export type PageWebSocketRouteEvent = {
webSocketRoute: WebSocketRouteChannel,
Expand Down
4 changes: 2 additions & 2 deletions tests/config/remoteServer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
*/

import path from 'path';
import { inheritAndCleanEnv } from './utils';
import type { BrowserType, Browser } from 'playwright-core';
import type { CommonFixtures, TestChildProcess } from './commonFixtures';

Expand All @@ -36,7 +35,7 @@ export class RunServer implements PlaywrightServer {
command.push(`--artifacts-dir=${options.artifactsDir}`);
this._process = childProcess({
command,
env: inheritAndCleanEnv(options?.env),
env: { NODE_OPTIONS: process.env.NODE_OPTIONS, ...options?.env },
});

let wsEndpointCallback: (value: string) => void;
Expand Down Expand Up @@ -108,6 +107,7 @@ export class RemoteServer implements PlaywrightServer {
};
this._process = childProcess({
command: ['node', path.join(__dirname, 'remote-server-impl.js'), JSON.stringify(options)],
env: { NODE_OPTIONS: process.env.NODE_OPTIONS },
});

let index = 0;
Expand Down
23 changes: 23 additions & 0 deletions tests/library/screencast.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,29 @@ test('screencast.start delivers frames via onFrame callback', async ({ browser,
await context.close();
});

test('onFrame receives viewport size', async ({ browser, server, trace }) => {
test.skip(trace === 'on', 'trace=on has different screencast image configuration');
const context = await browser.newContext({ viewport: { width: 1000, height: 400 } });
const page = await context.newPage();

const frames: { viewportWidth: number, viewportHeight: number }[] = [];
await page.screencast.start({
onFrame: ({ viewportWidth, viewportHeight }) => frames.push({ viewportWidth, viewportHeight }),
size: { width: 500, height: 400 },
});
await page.goto(server.EMPTY_PAGE);
await ensureSomeFrames(page);
await page.screencast.stop();

expect(frames.length).toBeGreaterThan(0);
for (const frame of frames) {
expect(frame.viewportWidth).toBe(1000);
expect(frame.viewportHeight).toBe(400);
}

await context.close();
});

test('start throws if screencast is already started', async ({ browser }) => {
const context = await browser.newContext({ viewport: { width: 500, height: 400 } });
const page = await context.newPage();
Expand Down
5 changes: 0 additions & 5 deletions tests/mcp/screenshot.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -238,11 +238,6 @@ test('browser_take_screenshot (filename: "output.png")', async ({ client, server
text: expect.stringContaining(`output.png`),
type: 'text',
},
{
data: expect.any(String),
mimeType: 'image/png',
type: 'image',
},
],
});

Expand Down
2 changes: 1 addition & 1 deletion utils/generate_types/overrides.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -245,7 +245,7 @@ export interface WebSocketRoute {

export interface Screencast {
start(options?: {
onFrame?: (frame: { data: Buffer }) => Promise<any>|any;
onFrame?: (frame: { data: Buffer, viewportWidth: number, viewportHeight: number }) => Promise<any>|any;
path?: string;
size?: {
width: number;
Expand Down
Loading