fix(screencast): replace ScreencastStopped event with async path() (#3612)

This commit is contained in:
Yury Semikhatsky 2020-08-25 13:07:32 -07:00 committed by GitHub
parent aaff8456c5
commit a38564b7ca
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 69 additions and 29 deletions

View File

@ -13,7 +13,7 @@
}, },
{ {
"name": "webkit", "name": "webkit",
"revision": "1330", "revision": "1332",
"download": true "download": true
} }
] ]

View File

@ -31,11 +31,19 @@ import { DebugController } from './debug/debugController';
import { isDebugMode } from '../utils/utils'; import { isDebugMode } from '../utils/utils';
export class Screencast { export class Screencast {
readonly path: string;
readonly page: Page; readonly page: Page;
private readonly _path: string;
_finishCallback: () => void = () => {};
private readonly _finishedPromise: Promise<void>;
constructor(path: string, page: Page) { constructor(path: string, page: Page) {
this.path = path; this._path = path;
this.page = page; this.page = page;
this._finishedPromise = new Promise(fulfill => this._finishCallback = fulfill);
}
async path(): Promise<string | null> {
await this._finishedPromise;
return this._path;
} }
} }
@ -58,6 +66,7 @@ export abstract class BrowserContext extends EventEmitter {
private _closePromiseFulfill: ((error: Error) => void) | undefined; private _closePromiseFulfill: ((error: Error) => void) | undefined;
readonly _permissions = new Map<string, string[]>(); readonly _permissions = new Map<string, string[]>();
readonly _downloads = new Set<Download>(); readonly _downloads = new Set<Download>();
readonly _idToScreencast = new Map<string, Screencast>();
readonly _browser: Browser; readonly _browser: Browser;
constructor(browser: Browser, options: types.BrowserContextOptions, isPersistentContext: boolean) { constructor(browser: Browser, options: types.BrowserContextOptions, isPersistentContext: boolean) {

View File

@ -267,10 +267,8 @@ export class FFPage implements PageDelegate {
_onScreencastStopped(event: Protocol.Page.screencastStoppedPayload) { _onScreencastStopped(event: Protocol.Page.screencastStoppedPayload) {
const screencast = this._idToScreencast.get(event.uid); const screencast = this._idToScreencast.get(event.uid);
if (!screencast)
return;
this._idToScreencast.delete(event.uid); this._idToScreencast.delete(event.uid);
this._browserContext.emit(BrowserContext.Events.ScreencastStopped, screencast); screencast!._finishCallback();
} }
async exposeBinding(binding: PageBinding) { async exposeBinding(binding: PageBinding) {

View File

@ -6818,6 +6818,16 @@ Left=1, Right=2, Middle=4, Back=8, Forward=16, None=0.
uuid: string; uuid: string;
error: string; error: string;
} }
export type screencastFinishedPayload = {
/**
* Unique identifier of the context.
*/
browserContextId: ContextID;
/**
* Unique identifier of the screencast.
*/
screencastId: Screencast.ScreencastId;
}
export type enableParameters = { export type enableParameters = {
} }
@ -7835,12 +7845,16 @@ Left=1, Right=2, Middle=4, Back=8, Forward=16, None=0.
} }
export module Screencast { export module Screencast {
/**
* Unique identifier of the screencast.
*/
export type ScreencastId = string;
/** /**
* Starts recoring video to speified file. * Starts recoring video to speified file.
*/ */
export type startVideoRecordingParameters = { export type startParameters = {
/** /**
* Output file location. * Output file location.
*/ */
@ -7849,14 +7863,18 @@ Left=1, Right=2, Middle=4, Back=8, Forward=16, None=0.
height: number; height: number;
scale?: number; scale?: number;
} }
export type startVideoRecordingReturnValue = { export type startReturnValue = {
/**
* Unique identifier of the screencast.
*/
screencastId: ScreencastId;
} }
/** /**
* Stops recoding video. Returns after the file has been closed. * Stops recoding video. Returns after the file has been closed.
*/ */
export type stopVideoRecordingParameters = { export type stopParameters = {
} }
export type stopVideoRecordingReturnValue = { export type stopReturnValue = {
} }
} }
@ -8411,6 +8429,7 @@ Left=1, Right=2, Middle=4, Back=8, Forward=16, None=0.
"Playwright.downloadCreated": Playwright.downloadCreatedPayload; "Playwright.downloadCreated": Playwright.downloadCreatedPayload;
"Playwright.downloadFilenameSuggested": Playwright.downloadFilenameSuggestedPayload; "Playwright.downloadFilenameSuggested": Playwright.downloadFilenameSuggestedPayload;
"Playwright.downloadFinished": Playwright.downloadFinishedPayload; "Playwright.downloadFinished": Playwright.downloadFinishedPayload;
"Playwright.screencastFinished": Playwright.screencastFinishedPayload;
"Runtime.executionContextCreated": Runtime.executionContextCreatedPayload; "Runtime.executionContextCreated": Runtime.executionContextCreatedPayload;
"ScriptProfiler.trackingStart": ScriptProfiler.trackingStartPayload; "ScriptProfiler.trackingStart": ScriptProfiler.trackingStartPayload;
"ScriptProfiler.trackingUpdate": ScriptProfiler.trackingUpdatePayload; "ScriptProfiler.trackingUpdate": ScriptProfiler.trackingUpdatePayload;
@ -8689,8 +8708,8 @@ Left=1, Right=2, Middle=4, Back=8, Forward=16, None=0.
"Runtime.enableControlFlowProfiler": Runtime.enableControlFlowProfilerParameters; "Runtime.enableControlFlowProfiler": Runtime.enableControlFlowProfilerParameters;
"Runtime.disableControlFlowProfiler": Runtime.disableControlFlowProfilerParameters; "Runtime.disableControlFlowProfiler": Runtime.disableControlFlowProfilerParameters;
"Runtime.getBasicBlocks": Runtime.getBasicBlocksParameters; "Runtime.getBasicBlocks": Runtime.getBasicBlocksParameters;
"Screencast.startVideoRecording": Screencast.startVideoRecordingParameters; "Screencast.start": Screencast.startParameters;
"Screencast.stopVideoRecording": Screencast.stopVideoRecordingParameters; "Screencast.stop": Screencast.stopParameters;
"ScriptProfiler.startTracking": ScriptProfiler.startTrackingParameters; "ScriptProfiler.startTracking": ScriptProfiler.startTrackingParameters;
"ScriptProfiler.stopTracking": ScriptProfiler.stopTrackingParameters; "ScriptProfiler.stopTracking": ScriptProfiler.stopTrackingParameters;
"ServiceWorker.getInitializationInfo": ServiceWorker.getInitializationInfoParameters; "ServiceWorker.getInitializationInfo": ServiceWorker.getInitializationInfoParameters;
@ -8972,8 +8991,8 @@ Left=1, Right=2, Middle=4, Back=8, Forward=16, None=0.
"Runtime.enableControlFlowProfiler": Runtime.enableControlFlowProfilerReturnValue; "Runtime.enableControlFlowProfiler": Runtime.enableControlFlowProfilerReturnValue;
"Runtime.disableControlFlowProfiler": Runtime.disableControlFlowProfilerReturnValue; "Runtime.disableControlFlowProfiler": Runtime.disableControlFlowProfilerReturnValue;
"Runtime.getBasicBlocks": Runtime.getBasicBlocksReturnValue; "Runtime.getBasicBlocks": Runtime.getBasicBlocksReturnValue;
"Screencast.startVideoRecording": Screencast.startVideoRecordingReturnValue; "Screencast.start": Screencast.startReturnValue;
"Screencast.stopVideoRecording": Screencast.stopVideoRecordingReturnValue; "Screencast.stop": Screencast.stopReturnValue;
"ScriptProfiler.startTracking": ScriptProfiler.startTrackingReturnValue; "ScriptProfiler.startTracking": ScriptProfiler.startTrackingReturnValue;
"ScriptProfiler.stopTracking": ScriptProfiler.stopTrackingReturnValue; "ScriptProfiler.stopTracking": ScriptProfiler.stopTrackingReturnValue;
"ServiceWorker.getInitializationInfo": ServiceWorker.getInitializationInfoReturnValue; "ServiceWorker.getInitializationInfo": ServiceWorker.getInitializationInfoReturnValue;

View File

@ -62,6 +62,7 @@ export class WKBrowser extends Browser {
helper.addEventListener(this._browserSession, 'Playwright.downloadCreated', this._onDownloadCreated.bind(this)), helper.addEventListener(this._browserSession, 'Playwright.downloadCreated', this._onDownloadCreated.bind(this)),
helper.addEventListener(this._browserSession, 'Playwright.downloadFilenameSuggested', this._onDownloadFilenameSuggested.bind(this)), helper.addEventListener(this._browserSession, 'Playwright.downloadFilenameSuggested', this._onDownloadFilenameSuggested.bind(this)),
helper.addEventListener(this._browserSession, 'Playwright.downloadFinished', this._onDownloadFinished.bind(this)), helper.addEventListener(this._browserSession, 'Playwright.downloadFinished', this._onDownloadFinished.bind(this)),
helper.addEventListener(this._browserSession, 'Playwright.screencastFinished', this._onScreencastFinished.bind(this)),
helper.addEventListener(this._browserSession, kPageProxyMessageReceived, this._onPageProxyMessageReceived.bind(this)), helper.addEventListener(this._browserSession, kPageProxyMessageReceived, this._onPageProxyMessageReceived.bind(this)),
]; ];
} }
@ -124,6 +125,13 @@ export class WKBrowser extends Browser {
this._downloadFinished(payload.uuid, payload.error); this._downloadFinished(payload.uuid, payload.error);
} }
_onScreencastFinished(payload: Protocol.Playwright.screencastFinishedPayload) {
const context = this._contexts.get(payload.browserContextId);
if (!context)
return;
context._screencastFinished(payload.screencastId);
}
_onPageProxyCreated(event: Protocol.Playwright.pageProxyCreatedPayload) { _onPageProxyCreated(event: Protocol.Playwright.pageProxyCreatedPayload) {
const pageProxyId = event.pageProxyId; const pageProxyId = event.pageProxyId;
let context: WKBrowserContext | null = null; let context: WKBrowserContext | null = null;
@ -326,6 +334,12 @@ export class WKBrowserContext extends BrowserContext {
await (page._delegate as WKPage).updateRequestInterception(); await (page._delegate as WKPage).updateRequestInterception();
} }
_screencastFinished(uid: string) {
const screencast = this._idToScreencast.get(uid);
this._idToScreencast.delete(uid);
screencast!._finishCallback();
}
async _doClose() { async _doClose() {
assert(this._browserContextId); assert(this._browserContextId);
await this._browser._browserSession.send('Playwright.deleteContext', { browserContextId: this._browserContextId }); await this._browser._browserSession.send('Playwright.deleteContext', { browserContextId: this._browserContextId });

View File

@ -718,13 +718,15 @@ export class WKPage implements PageDelegate {
throw new Error('Already recording'); throw new Error('Already recording');
this._recordingVideoFile = options.outputFile; this._recordingVideoFile = options.outputFile;
try { try {
await this._pageProxySession.send('Screencast.startVideoRecording', { const {screencastId} = await this._pageProxySession.send('Screencast.start', {
file: options.outputFile, file: options.outputFile,
width: options.width, width: options.width,
height: options.height, height: options.height,
scale: options.scale, scale: options.scale,
}); }) as any;
this._browserContext.emit(BrowserContext.Events.ScreencastStarted, new Screencast(options.outputFile, this._page)); const screencast = new Screencast(options.outputFile, this._page);
this._browserContext._idToScreencast.set(screencastId, screencast);
this._browserContext.emit(BrowserContext.Events.ScreencastStarted, screencast);
} catch (e) { } catch (e) {
this._recordingVideoFile = null; this._recordingVideoFile = null;
throw e; throw e;
@ -734,10 +736,8 @@ export class WKPage implements PageDelegate {
async stopScreencast(): Promise<void> { async stopScreencast(): Promise<void> {
if (!this._recordingVideoFile) if (!this._recordingVideoFile)
throw new Error('No video recording in progress'); throw new Error('No video recording in progress');
const fileName = this._recordingVideoFile;
this._recordingVideoFile = null; this._recordingVideoFile = null;
await this._pageProxySession.send('Screencast.stopVideoRecording'); await this._pageProxySession.send('Screencast.stop');
this._browserContext.emit(BrowserContext.Events.ScreencastStopped, new Screencast(fileName, this._initializedPage!));
} }
async takeScreenshot(format: string, documentRect: types.Rect | undefined, viewportRect: types.Rect | undefined, quality: number | undefined): Promise<Buffer> { async takeScreenshot(format: string, documentRect: types.Rect | undefined, viewportRect: types.Rect | undefined, quality: number | undefined): Promise<Buffer> {

View File

@ -21,6 +21,7 @@ import { Page } from '..';
import fs from 'fs'; import fs from 'fs';
import path from 'path'; import path from 'path';
import url from 'url'; import url from 'url';
import { tmpdir } from 'os';
declare global { declare global {
@ -265,18 +266,17 @@ it.fail(options.CHROMIUM)('should fire start/stop events when page created/close
await context._enableScreencast({width: 640, height: 480, dir: tmpDir}); await context._enableScreencast({width: 640, height: 480, dir: tmpDir});
expect(context._screencastOptions).toBeTruthy(); expect(context._screencastOptions).toBeTruthy();
const [startEvent, newPage] = await Promise.all([ const [screencast, newPage] = await Promise.all([
new Promise(resolve => context.on('screencaststarted', resolve)) as Promise<any>, new Promise(resolve => context.on('screencaststarted', resolve)) as Promise<any>,
context.newPage(), context.newPage(),
]); ]);
expect(startEvent.page === newPage).toBe(true); expect(screencast.page === newPage).toBe(true);
expect(startEvent.path).toBeTruthy();
const [stopEvent] = await Promise.all([ const [videoFile] = await Promise.all([
new Promise(resolve => context.on('screencaststopped', resolve)) as Promise<any>, screencast.path(),
newPage.close(), newPage.close(),
]); ]);
expect(stopEvent.page === newPage).toBe(true); expect(path.dirname(videoFile)).toBe(tmpDir);
await context.close(); await context.close();
}); });
@ -290,7 +290,7 @@ it.fail(options.CHROMIUM)('should fire start event for popups', async({browser,
const page = await context.newPage(); const page = await context.newPage();
await page.mainFrame().goto(server.EMPTY_PAGE); await page.mainFrame().goto(server.EMPTY_PAGE);
const [startEvent, popup] = await Promise.all([ const [screencast, popup] = await Promise.all([
new Promise(resolve => context.on('screencaststarted', resolve)) as Promise<any>, new Promise(resolve => context.on('screencaststarted', resolve)) as Promise<any>,
new Promise(resolve => context.on('page', resolve)) as Promise<any>, new Promise(resolve => context.on('page', resolve)) as Promise<any>,
page.mainFrame()._evaluateExpression(() => { page.mainFrame()._evaluateExpression(() => {
@ -298,7 +298,7 @@ it.fail(options.CHROMIUM)('should fire start event for popups', async({browser,
win.close(); win.close();
}, true) }, true)
]); ]);
expect(startEvent.path).toBeTruthy(); expect(screencast.page === popup).toBe(true);
expect(startEvent.page === popup).toBe(true); expect(path.dirname(await screencast.path())).toBe(tmpDir);
await context.close(); await context.close();
}); });