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
75 changes: 26 additions & 49 deletions docs/src/api/class-screencast.md
Original file line number Diff line number Diff line change
@@ -1,91 +1,68 @@
# class: Screencast
* since: v1.59
* langs: js

Interface for capturing screencast frames from a page.

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

Starts capturing screencast frames.
Starts the screencast. When [`option: Screencast.start.path`] is provided, it saves video recording to the specified file.
When [`option: Screencast.start.onFrame`] is provided, delivers JPEG-encoded frames to the callback. Both can be used together.

**Usage**

```js
await page.screencast.start(({ data }) => {
console.log(`frame size: ${data.length}`);
}, { size: { width: 800, height: 600 } });
// Record video
await page.screencast.start({ path: 'video.webm', size: { width: 1280, height: 800 } });
// ... perform actions ...
await page.screencast.stop();
```

```js
// Capture frames
await page.screencast.start({
onFrame: ({ data }) => console.log(`frame size: ${data.length}`),
size: { width: 800, height: 600 },
});
// ... perform actions ...
await page.screencast.stop();
```

### param: Screencast.start.onFrame
### option: Screencast.start.onFrame
* since: v1.59
* langs: js
- `onFrame` <[function]\([Object]\): [Promise]>
- `data` <[Buffer]> JPEG-encoded frame data.

Callback that receives JPEG-encoded frame data.

### option: Screencast.start.size
### option: Screencast.start.path
* since: v1.59
* langs: js
- `size` ?<[Object=ScreencastSize]>
- `width` <[int]> Max frame width in pixels.
- `height` <[int]> Max frame height in pixels.
- `path` <[path]>

Specifies the dimensions of screencast frames. The actual frame is scaled to preserve the page’s aspect ratio and may be smaller than these bounds.
If a screencast is already active (e.g. started by tracing or video recording), the existing configuration takes precedence and the frame size may exceed these bounds or this option may be ignored.
If not specified the size will be equal to page viewport scaled down to fit into 800×800.
Path where the video should be saved when the screencast is stopped. When provided, video recording is started.

### option: Screencast.start.quality
* since: v1.59
* langs: js
- `quality` <[int]>

The quality of the image, between 0-100.

## async method: Screencast.stop
### option: Screencast.start.size
* since: v1.59
* langs: js

Stops the screencast started with [`method: Screencast.start`].

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

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

### param: Screencast.startRecording.path
* since: v1.59
- `path` <[path]>

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

### option: Screencast.startRecording.size
* since: v1.59
- `size` ?<[Object=ScreencastSize]>
- `width` <[int]> Video frame width.
- `height` <[int]> Video frame height.

Optional dimensions of the recorded video. If not specified the size will be equal to page viewport scaled down to fit into 800×800. Actual picture of the page will be scaled down if necessary to fit the specified size.

### option: Screencast.startRecording.annotate
* since: v1.59
- `annotate` ?<[Object=ScreencastAnnotation]>
- `duration` ?<[float]> How long each annotation is displayed in milliseconds. Defaults to `500`.
- `position` ?<[AnnotatePosition]<"top-left"|"top"|"top-right"|"bottom-left"|"bottom"|"bottom-right">> Position of the action title overlay. Defaults to `"top-right"`.
- `fontSize` ?<[int]> Font size of the action title in pixels. Defaults to `24`.
- `width` <[int]> Max frame width in pixels.
- `height` <[int]> Max frame height in pixels.

If specified, enables visual annotations on interacted elements during video recording. Interacted elements are highlighted with a semi-transparent blue box and click points are shown as red circles.
Specifies the dimensions of screencast frames. The actual frame is scaled to preserve the page's aspect ratio and may be smaller than these bounds.
If a screencast is already active (e.g. started by tracing or video recording), the existing configuration takes precedence and the frame size may exceed these bounds or this option may be ignored.
If not specified the size will be equal to page viewport scaled down to fit into 800×800.

## async method: Screencast.stopRecording
## async method: Screencast.stop
* since: v1.59

Stops video recording started with [`method: Screencast.startRecording`].
Stops the screencast and video recording if active. If a video was being recorded, saves it to the path specified in [`method: Screencast.start`].

## async method: Screencast.showOverlay
* since: v1.59
Expand Down
79 changes: 21 additions & 58 deletions packages/playwright-client/types/types.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16185,22 +16185,35 @@ export interface WebSocketRoute {
*/
export interface Screencast {
/**
* Starts capturing screencast frames.
* Starts the screencast. When [`path`](https://playwright.dev/docs/api/class-screencast#screencast-start-option-path)
* is provided, it saves video recording to the specified file. When
* [`onFrame`](https://playwright.dev/docs/api/class-screencast#screencast-start-option-on-frame) is provided,
* delivers JPEG-encoded frames to the callback. Both can be used together.
*
* **Usage**
*
* ```js
* await page.screencast.start(({ data }) => {
* console.log(`frame size: ${data.length}`);
* }, { size: { width: 800, height: 600 } });
* // Record video
* await page.screencast.start({ path: 'video.webm', size: { width: 1280, height: 800 } });
* // ... perform actions ...
* await page.screencast.stop();
* ```
*
* ```js
* // Capture frames
* await page.screencast.start({
* onFrame: ({ data }) => console.log(`frame size: ${data.length}`),
* size: { width: 800, height: 600 },
* });
* // ... perform actions ...
* await page.screencast.stop();
* ```
*
* @param onFrame Callback that receives JPEG-encoded frame data.
* @param options
*/
start(onFrame: ((frame: { data: Buffer }) => Promise<any>|any), options?: {
start(options?: {
onFrame?: (frame: { data: Buffer }) => Promise<any>|any;
path?: string;
size?: {
width: number;
height: number;
Expand Down Expand Up @@ -16255,60 +16268,10 @@ export interface Screencast {
showOverlays(): Promise<void>;

/**
* Starts video recording. This method is mutually exclusive with the `recordVideo` context option.
* @param path Path where the video should be saved when the recording is stopped.
* @param options
*/
startRecording(path: string, options?: {
/**
* If specified, enables visual annotations on interacted elements during video recording. Interacted elements are
* highlighted with a semi-transparent blue box and click points are shown as red circles.
*/
annotate?: {
/**
* How long each annotation is displayed in milliseconds. Defaults to `500`.
*/
duration?: number;

/**
* Position of the action title overlay. Defaults to `"top-right"`.
*/
position?: "top-left"|"top"|"top-right"|"bottom-left"|"bottom"|"bottom-right";

/**
* Font size of the action title in pixels. Defaults to `24`.
*/
fontSize?: number;
};

/**
* Optional dimensions of the recorded video. If not specified the size will be equal to page viewport scaled down to
* fit into 800×800. Actual picture of the page will be scaled down if necessary to fit the specified size.
*/
size?: {
/**
* Video frame width.
*/
width: number;

/**
* Video frame height.
*/
height: number;
};
}): Promise<Disposable>;

/**
* Stops the screencast started with
* [screencast.start(onFrame[, options])](https://playwright.dev/docs/api/class-screencast#screencast-start).
* Stops the screencast and video recording if active. If a video was being recorded, saves it to the path specified
* in [screencast.start([options])](https://playwright.dev/docs/api/class-screencast#screencast-start).
*/
stop(): Promise<void>;

/**
* Stops video recording started with
* [screencast.startRecording(path[, options])](https://playwright.dev/docs/api/class-screencast#screencast-start-recording).
*/
stopRecording(): Promise<void>;
}

type DeviceDescriptor = {
Expand Down
39 changes: 22 additions & 17 deletions packages/playwright-core/src/client/screencast.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import type { AnnotateOptions } from './types';

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 _artifact: Artifact | undefined;
Expand All @@ -34,31 +35,35 @@ export class Screencast implements api.Screencast {
});
}

async start(onFrame: (frame: { data: Buffer }) => Promise<any>|any, options: { size?: { width: number, height: number }, quality?: number } = {}): Promise<DisposableStub> {
if (this._onFrame)
async start(options: { onFrame?: (frame: { data: Buffer }) => Promise<any>|any, path?: string, size?: { width: number, height: number }, quality?: number, annotate?: AnnotateOptions } = {}): Promise<DisposableStub> {
if (this._started)
throw new Error('Screencast is already started');
this._onFrame = onFrame;
await this._page._channel.startScreencast(options);
this._started = true;
if (options.onFrame)
this._onFrame = options.onFrame;
const result = await this._page._channel.screencastStart({
size: options.size,
quality: options.quality,
sendFrames: !!options.onFrame,
record: !!options.path,
annotate: options.annotate,
});
if (result.artifact) {
this._artifact = Artifact.from(result.artifact);
this._savePath = options.path;
}
return new DisposableStub(() => this.stop());
}

async stop(): Promise<void> {
this._onFrame = null;
await this._page._channel.stopScreencast();
}

async startRecording(path: string, options: { size?: { width: number, height: number }, annotate?: AnnotateOptions } = {}) {
const result = await this._page._channel.videoStart({ size: options.size, annotate: options.annotate });
this._artifact = Artifact.from(result.artifact);
this._savePath = path;
return new DisposableStub(() => this.stopRecording());
}

async stopRecording(): Promise<void> {
await this._page._wrapApiCall(async () => {
await this._page._channel.videoStop();
this._started = false;
this._onFrame = null;
await this._page._channel.screencastStop();
if (this._savePath)
await this._artifact?.saveAs(this._savePath);
this._artifact = undefined;
this._savePath = undefined;
});
}

Expand Down
21 changes: 7 additions & 14 deletions packages/playwright-core/src/protocol/validator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1569,28 +1569,21 @@ scheme.PageOverlaySetVisibleParams = tObject({
visible: tBoolean,
});
scheme.PageOverlaySetVisibleResult = tOptional(tObject({}));
scheme.PageStartScreencastParams = tObject({
scheme.PageScreencastStartParams = tObject({
size: tOptional(tObject({
width: tInt,
height: tInt,
})),
quality: tOptional(tInt),
});
scheme.PageStartScreencastResult = tOptional(tObject({}));
scheme.PageStopScreencastParams = tOptional(tObject({}));
scheme.PageStopScreencastResult = tOptional(tObject({}));
scheme.PageVideoStartParams = tObject({
size: tOptional(tObject({
width: tInt,
height: tInt,
})),
sendFrames: tOptional(tBoolean),
record: tOptional(tBoolean),
annotate: tOptional(tType('AnnotateOptions')),
});
scheme.PageVideoStartResult = tObject({
artifact: tChannel(['Artifact']),
scheme.PageScreencastStartResult = tObject({
artifact: tOptional(tChannel(['Artifact'])),
});
scheme.PageVideoStopParams = tOptional(tObject({}));
scheme.PageVideoStopResult = tOptional(tObject({}));
scheme.PageScreencastStopParams = tOptional(tObject({}));
scheme.PageScreencastStopResult = tOptional(tObject({}));
scheme.PageUpdateSubscriptionParams = tObject({
event: tEnum(['console', 'dialog', 'fileChooser', 'request', 'response', 'requestFinished', 'requestFailed']),
enabled: tBoolean,
Expand Down
5 changes: 2 additions & 3 deletions packages/playwright-core/src/server/browserContext.ts
Original file line number Diff line number Diff line change
Expand Up @@ -530,9 +530,7 @@ export abstract class BrowserContext<EM extends EventMap = EventMap> extends Sdk
for (const harRecorder of this._harRecorders.values())
await harRecorder.flush();
await this.tracing.flush();

// Cleanup.
const promises: Promise<void>[] = this.pages().map(page => page.screencast.handlePageOrContextClose());
await Promise.all(this.pages().map(page => page.screencast.handlePageOrContextClose()));

if (this._customCloseHandler) {
await this._customCloseHandler();
Expand All @@ -543,6 +541,7 @@ export abstract class BrowserContext<EM extends EventMap = EventMap> extends Sdk

// We delete downloads after context closure
// so that browser does not write to the download file anymore.
const promises: Promise<void>[] = [];
promises.push(this._deleteAllDownloads());
promises.push(this._deleteAllTempDirs());
await Promise.all(promises);
Expand Down
Loading
Loading