Skip to content

Commit

Permalink
fix(screencast): use viewport as default size (#3844)
Browse files Browse the repository at this point in the history
  • Loading branch information
yury-s authored Sep 11, 2020
1 parent c4adeb6 commit 40323aa
Show file tree
Hide file tree
Showing 10 changed files with 75 additions and 24 deletions.
12 changes: 8 additions & 4 deletions docs/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -220,7 +220,8 @@ Indicates that the browser is connected.
- `password` <[string]>
- `colorScheme` <"light"|"dark"|"no-preference"> Emulates `'prefers-colors-scheme'` media feature, supported values are `'light'`, `'dark'`, `'no-preference'`. See [page.emulateMedia(options)](#pageemulatemediaoptions) for more details. Defaults to '`light`'.
- `logger` <[Logger]> Logger sink for Playwright logging.
- `_recordVideos` <[Object]> **experimental** Enables automatic video recording for new pages. The video will have frames with the provided dimensions. Actual picture of the page will be scaled down if necessary to fit specified size.
- `_recordVideos` <[boolean]> **experimental** Enables automatic video recording for new pages.
- `_videoSize` <[Object]> **experimental** Specifies dimensions of the automatically recorded video. Can only be used if `_recordVideos` is true. If not specified the size will be equal to `viewport`. If `viewport` is not configured explicitly the video size defaults to 1280x720. Actual picture of the page will be scaled down if necessary to fit specified size.
- `width` <[number]> Video frame width.
- `height` <[number]> Video frame height.
- returns: <[Promise]<[BrowserContext]>>
Expand Down Expand Up @@ -265,7 +266,8 @@ Creates a new browser context. It won't share cookies/cache with other browser c
- `password` <[string]>
- `colorScheme` <"light"|"dark"|"no-preference"> Emulates `'prefers-colors-scheme'` media feature, supported values are `'light'`, `'dark'`, `'no-preference'`. See [page.emulateMedia(options)](#pageemulatemediaoptions) for more details. Defaults to '`light`'.
- `logger` <[Logger]> Logger sink for Playwright logging.
- `_recordVideos` <[Object]> **experimental** Enables automatic video recording for the new page. The video will have frames with the provided dimensions. Actual picture of the page will be scaled down if necessary to fit specified size.
- `_recordVideos` <[boolean]> **experimental** Enables automatic video recording for the new page.
- `_videoSize` <[Object]> **experimental** Specifies dimensions of the automatically recorded video. Can only be used if `_recordVideos` is true. If not specified the size will be equal to `viewport`. If `viewport` is not configured explicitly the video size defaults to 1280x720. Actual picture of the page will be scaled down if necessary to fit specified size.
- `width` <[number]> Video frame width.
- `height` <[number]> Video frame height.
- returns: <[Promise]<[Page]>>
Expand Down Expand Up @@ -792,7 +794,8 @@ const { webkit } = require('playwright'); // Or 'chromium' or 'firefox'.
_videosPath: __dirname // Save videos to custom directory
});
const context = await browser.newContext({
_recordVideos: { width: 640, height: 360 }
_recordVideos: true,
_videoSize: { width: 640, height: 360 }
});
const page = await context.newPage();
const video = await page.waitForEvent('_videostarted');
Expand Down Expand Up @@ -4268,7 +4271,8 @@ const browser = await chromium.launch({ // Or 'firefox' or 'webkit'.
- `password` <[string]>
- `colorScheme` <"light"|"dark"|"no-preference"> Emulates `'prefers-colors-scheme'` media feature, supported values are `'light'`, `'dark'`, `'no-preference'`. See [page.emulateMedia(options)](#pageemulatemediaoptions) for more details. Defaults to '`light`'.
- `_videosPath` <[string]> **experimental** If specified, recorded videos are saved into this folder. Otherwise, temporary folder is created and is deleted when browser is closed.
- `_recordVideos` <[Object]> **experimental** Enables automatic video recording for the new page. The video will have frames with the provided dimensions. Actual picture of the page will be scaled down if necessary to fit specified size.
- `_recordVideos` <[boolean]> **experimental** Enables automatic video recording for new pages.
- `_videoSize` <[Object]> **experimental** Specifies dimensions of the automatically recorded video. Can only be used if `_recordVideos` is true. If not specified the size will be equal to `viewport`. If `viewport` is not configured explicitly the video size defaults to 1280x720. Actual picture of the page will be scaled down if necessary to fit specified size.
- `width` <[number]> Video frame width.
- `height` <[number]> Video frame height.
- returns: <[Promise]<[BrowserContext]>> Promise that resolves to the persistent browser context instance.
Expand Down
3 changes: 2 additions & 1 deletion packages/installation-tests/screencast.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,8 @@ const fs = require('fs');
_videosPath: __dirname,
});
const context = await browser.newContext({
_recordVideos: {width: 320, height: 240},
_recordVideos: true,
_videoSize: {width: 320, height: 240},
});
const page = await context.newPage();
const video = await page.waitForEvent('_videostarted');
Expand Down
6 changes: 4 additions & 2 deletions src/protocol/channels.ts
Original file line number Diff line number Diff line change
Expand Up @@ -371,7 +371,8 @@ export type BrowserNewContextParams = {
hasTouch?: boolean,
colorScheme?: 'dark' | 'light' | 'no-preference',
acceptDownloads?: boolean,
_recordVideos?: {
_recordVideos?: boolean,
_videoSize?: {
width: number,
height: number,
},
Expand Down Expand Up @@ -408,7 +409,8 @@ export type BrowserNewContextOptions = {
hasTouch?: boolean,
colorScheme?: 'dark' | 'light' | 'no-preference',
acceptDownloads?: boolean,
_recordVideos?: {
_recordVideos?: boolean,
_videoSize?: {
width: number,
height: number,
},
Expand Down
3 changes: 2 additions & 1 deletion src/protocol/protocol.yml
Original file line number Diff line number Diff line change
Expand Up @@ -367,7 +367,8 @@ Browser:
- light
- no-preference
acceptDownloads: boolean?
_recordVideos:
_recordVideos: boolean?
_videoSize:
type: object?
properties:
width: number
Expand Down
3 changes: 2 additions & 1 deletion src/protocol/validator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -217,7 +217,8 @@ export function createScheme(tChannel: (name: string) => Validator): Scheme {
hasTouch: tOptional(tBoolean),
colorScheme: tOptional(tEnum(['dark', 'light', 'no-preference'])),
acceptDownloads: tOptional(tBoolean),
_recordVideos: tOptional(tObject({
_recordVideos: tOptional(tBoolean),
_videoSize: tOptional(tObject({
width: tNumber,
height: tNumber,
})),
Expand Down
8 changes: 5 additions & 3 deletions src/server/chromium/crPage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -459,11 +459,13 @@ class FrameSession {
for (const source of this._crPage._page._evaluateOnNewDocumentSources)
promises.push(this._evaluateOnNewDocument(source));
if (this._crPage._browserContext._options._recordVideos) {
const contextOptions = this._crPage._browserContext._options._recordVideos;
const size = this._crPage._browserContext._options._videoSize || this._crPage._browserContext._options.viewport || { width: 1280, height: 720 };
const screencastId = createGuid();
const outputFile = path.join(this._crPage._browserContext._browser._options._videosPath!, screencastId + '.webm');
const options = Object.assign({}, contextOptions, {outputFile});
promises.push(this._startScreencast(screencastId, options));
promises.push(this._startScreencast(screencastId, {
...size,
outputFile,
}));
}
promises.push(this._client.send('Runtime.runIfWaitingForDebugger'));
promises.push(this._firstNonInitialNavigationCommittedPromise);
Expand Down
3 changes: 2 additions & 1 deletion src/server/firefox/ffBrowser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -223,8 +223,9 @@ export class FFBrowserContext extends BrowserContext {
if (this._options.colorScheme)
promises.push(this._browser._connection.send('Browser.setColorScheme', { browserContextId, colorScheme: this._options.colorScheme }));
if (this._options._recordVideos) {
const size = this._options._videoSize || this._options.viewport || { width: 1280, height: 720 };
await this._browser._connection.send('Browser.setScreencastOptions', {
...this._options._recordVideos,
...size,
dir: this._browser._options._videosPath!,
browserContextId: this._browserContextId
});
Expand Down
6 changes: 2 additions & 4 deletions src/server/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -238,10 +238,8 @@ export type BrowserContextOptions = {
hasTouch?: boolean,
colorScheme?: ColorScheme,
acceptDownloads?: boolean,
_recordVideos?: {
width: number,
height: number
}
_recordVideos?: boolean,
_videoSize?: Size,
};

export type EnvArray = { name: string, value: string }[];
Expand Down
8 changes: 5 additions & 3 deletions src/server/webkit/wkPage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -114,10 +114,12 @@ export class WKPage implements PageDelegate {
this._grantPermissions(key, value);
}
if (this._browserContext._options._recordVideos) {
const contextOptions = this._browserContext._options._recordVideos;
const size = this._browserContext._options._videoSize || this._browserContext._options.viewport || { width: 1280, height: 720 };
const outputFile = path.join(this._browserContext._browser._options._videosPath!, createGuid() + '.webm');
const options = Object.assign({}, contextOptions, {outputFile});
promises.push(this.startScreencast(options));
promises.push(this.startScreencast({
...size,
outputFile,
}));
}
await Promise.all(promises);
}
Expand Down
47 changes: 43 additions & 4 deletions test/screencast.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -235,7 +235,7 @@ describe('screencast', suite => {

it('should automatically start/finish when new page is created/closed', async ({browserType, defaultBrowserOptions, tmpDir}) => {
const browser = await browserType.launch({ ...defaultBrowserOptions, _videosPath: tmpDir });
const context = await browser.newContext({_recordVideos: {width: 320, height: 240}});
const context = await browser.newContext({ _recordVideos: true, _videoSize: { width: 320, height: 240 }});
const [screencast, newPage] = await Promise.all([
new Promise<any>(r => context.on('page', page => page.on('_videostarted', r))),
context.newPage(),
Expand All @@ -252,7 +252,7 @@ describe('screencast', suite => {

it('should finish when contex closes', async ({browserType, defaultBrowserOptions, tmpDir}) => {
const browser = await browserType.launch({ ...defaultBrowserOptions, _videosPath: tmpDir });
const context = await browser.newContext({_recordVideos: {width: 320, height: 240}});
const context = await browser.newContext({ _recordVideos: true, _videoSize: { width: 320, height: 240 } });

const [video] = await Promise.all([
new Promise<any>(r => context.on('page', page => page.on('_videostarted', r))),
Expand All @@ -269,7 +269,7 @@ describe('screencast', suite => {
});

it('should fire striclty after context.newPage', async ({browser}) => {
const context = await browser.newContext({_recordVideos: {width: 320, height: 240}});
const context = await browser.newContext({ _recordVideos: true, _videoSize: { width: 320, height: 240 } });
const page = await context.newPage();
// Should not hang.
await page.waitForEvent('_videostarted');
Expand All @@ -278,7 +278,7 @@ describe('screencast', suite => {

it('should fire start event for popups', async ({browserType, defaultBrowserOptions, tmpDir, server}) => {
const browser = await browserType.launch({ ...defaultBrowserOptions, _videosPath: tmpDir });
const context = await browser.newContext({_recordVideos: {width: 320, height: 240}});
const context = await browser.newContext({ _recordVideos: true, _videoSize: { width: 320, height: 240 } });

const [page] = await Promise.all([
context.newPage(),
Expand Down Expand Up @@ -339,4 +339,43 @@ describe('screencast', suite => {
expectAll(pixels, almostRed);
}
});

it('should use viewport as default size', async ({browser, page, tmpDir, videoPlayer, toImpl}) => {
const size = {width: 800, height: 600};
const context = await browser.newContext({_recordVideos: true, viewport: size});

const [video] = await Promise.all([
new Promise<any>(r => context.on('page', page => page.on('_videostarted', r))),
context.newPage(),
]);
await new Promise(r => setTimeout(r, 1000));
const [videoFile] = await Promise.all([
video.path(),
context.close(),
]);

expect(fs.existsSync(videoFile)).toBe(true);
await videoPlayer.load(videoFile);
expect(await videoPlayer.videoWidth()).toBe(size.width);
expect(await videoPlayer.videoHeight()).toBe(size.height);
});

it('should be 1280x720 by default', async ({browser, page, tmpDir, videoPlayer, toImpl}) => {
const context = await browser.newContext({_recordVideos: true});

const [video] = await Promise.all([
new Promise<any>(r => context.on('page', page => page.on('_videostarted', r))),
context.newPage(),
]);
await new Promise(r => setTimeout(r, 1000));
const [videoFile] = await Promise.all([
video.path(),
context.close(),
]);

expect(fs.existsSync(videoFile)).toBe(true);
await videoPlayer.load(videoFile);
expect(await videoPlayer.videoWidth()).toBe(1280);
expect(await videoPlayer.videoHeight()).toBe(720);
});
});

0 comments on commit 40323aa

Please sign in to comment.