diff --git a/src/server/browserContext.ts b/src/server/browserContext.ts index 475d1169f5..802b769be8 100644 --- a/src/server/browserContext.ts +++ b/src/server/browserContext.ts @@ -93,10 +93,6 @@ export abstract class BrowserContext extends SdkObject { } this._closedStatus = 'closed'; this._downloads.clear(); - for (const [id, video] of this._browser._idToVideo) { - if (video.context === this) - this._browser._idToVideo.delete(id); - } this._closePromiseFulfill!(new Error('Context closed')); this.emit(BrowserContext.Events.Close); } diff --git a/src/server/chromium/crPage.ts b/src/server/chromium/crPage.ts index fa46cf2891..7826bcffe4 100644 --- a/src/server/chromium/crPage.ts +++ b/src/server/chromium/crPage.ts @@ -157,7 +157,6 @@ export class CRPage implements PageDelegate { for (const session of this._sessions.values()) session.dispose(); this._page._didClose(); - this._mainFrameSession._stopVideoRecording().catch(() => {}); } async navigateFrame(frame: frames.Frame, url: string, referrer: string | undefined): Promise { @@ -444,6 +443,10 @@ class FrameSession { // Note: it is important to start video recorder before sending Page.startScreencast, // and it is equally important to send Page.startScreencast before sending Runtime.runIfWaitingForDebugger. await this._createVideoRecorder(screencastId, screencastOptions); + this._crPage.pageOrError().then(p => { + if (p instanceof Error) + this._stopVideoRecording().catch(() => {}); + }); } let lifecycleEventsEnabled: Promise; @@ -876,6 +879,7 @@ class FrameSession { async _startVideoRecording(options: types.PageScreencastOptions) { const screencastId = this._screencastId; assert(screencastId); + this._page.once(Page.Events.Close, () => this._stopVideoRecording().catch(() => {})); const gotFirstFrame = new Promise(f => this._client.once('Page.screencastFrame', f)); await this._startScreencast(this._videoRecorder, { format: 'jpeg', @@ -892,11 +896,11 @@ class FrameSession { async _stopVideoRecording(): Promise { if (!this._screencastId) return; - const recorder = this._videoRecorder!; - await this._stopScreencast(recorder); const screencastId = this._screencastId; - this._videoRecorder = null; this._screencastId = null; + const recorder = this._videoRecorder!; + this._videoRecorder = null; + await this._stopScreencast(recorder); await recorder.stop().catch(() => {}); this._crPage._browserContext._browser._videoFinished(screencastId); } diff --git a/tests/screencast.spec.ts b/tests/screencast.spec.ts index b3020ceb4d..8dc65c7771 100644 --- a/tests/screencast.spec.ts +++ b/tests/screencast.spec.ts @@ -570,4 +570,25 @@ it.describe('screencast', () => { expect(videoPlayer.videoWidth).toBe(374); expect(videoPlayer.videoHeight).toBe(666); }); + + it('should throw on browser close', async ({browserType, browserOptions, contextOptions}, testInfo) => { + const size = { width: 320, height: 240 }; + const browser = await browserType.launch(browserOptions); + const context = await browser.newContext({ + ...contextOptions, + recordVideo: { + dir: testInfo.outputPath(''), + size, + }, + viewport: size, + }); + + const page = await context.newPage(); + await new Promise(r => setTimeout(r, 1000)); + await browser.close(); + + const file = testInfo.outputPath('saved-video-'); + const saveResult = await page.video().saveAs(file).catch(e => e); + expect(saveResult.message).toContain('browser has been closed'); + }); });