chore: throw on context.close() if it was closed externally (#21347)

This commit is contained in:
Pavel Feldman 2023-03-02 13:46:54 -08:00 committed by GitHub
parent 57624bc01b
commit 09ff7eaaf2
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 23 additions and 49 deletions

View file

@ -30,7 +30,6 @@ import { Waiter } from './waiter';
import type { URLMatch, Headers, WaitForEventOptions, BrowserContextOptions, StorageState, LaunchOptions } from './types'; import type { URLMatch, Headers, WaitForEventOptions, BrowserContextOptions, StorageState, LaunchOptions } from './types';
import { headersObjectToArray, isRegExp, isString } from '../utils'; import { headersObjectToArray, isRegExp, isString } from '../utils';
import { mkdirIfNeeded } from '../utils/fileUtils'; import { mkdirIfNeeded } from '../utils/fileUtils';
import { isSafeCloseError } from '../common/errors';
import type * as api from '../../types/types'; import type * as api from '../../types/types';
import type * as structs from '../../types/structs'; import type * as structs from '../../types/structs';
import { CDPSession } from './cdpSession'; import { CDPSession } from './cdpSession';
@ -59,6 +58,7 @@ export class BrowserContext extends ChannelOwner<channels.BrowserContextChannel>
readonly _serviceWorkers = new Set<Worker>(); readonly _serviceWorkers = new Set<Worker>();
readonly _isChromium: boolean; readonly _isChromium: boolean;
private _harRecorders = new Map<string, { path: string, content: 'embed' | 'attach' | 'omit' | undefined }>(); private _harRecorders = new Map<string, { path: string, content: 'embed' | 'attach' | 'omit' | undefined }>();
private _closeWasCalled = false;
static from(context: channels.BrowserContextChannel): BrowserContext { static from(context: channels.BrowserContextChannel): BrowserContext {
return (context as any)._object; return (context as any)._object;
@ -344,31 +344,28 @@ export class BrowserContext extends ChannelOwner<channels.BrowserContextChannel>
} }
async close(): Promise<void> { async close(): Promise<void> {
try { if (this._closeWasCalled)
await this._wrapApiCall(async () => { return;
await this._browserType?._onWillCloseContext?.(this); this._closeWasCalled = true;
for (const [harId, harParams] of this._harRecorders) { await this._wrapApiCall(async () => {
const har = await this._channel.harExport({ harId }); await this._browserType?._onWillCloseContext?.(this);
const artifact = Artifact.from(har.artifact); for (const [harId, harParams] of this._harRecorders) {
// Server side will compress artifact if content is attach or if file is .zip. const har = await this._channel.harExport({ harId });
const isCompressed = harParams.content === 'attach' || harParams.path.endsWith('.zip'); const artifact = Artifact.from(har.artifact);
const needCompressed = harParams.path.endsWith('.zip'); // Server side will compress artifact if content is attach or if file is .zip.
if (isCompressed && !needCompressed) { const isCompressed = harParams.content === 'attach' || harParams.path.endsWith('.zip');
await artifact.saveAs(harParams.path + '.tmp'); const needCompressed = harParams.path.endsWith('.zip');
await this._connection.localUtils()._channel.harUnzip({ zipFile: harParams.path + '.tmp', harFile: harParams.path }); if (isCompressed && !needCompressed) {
} else { await artifact.saveAs(harParams.path + '.tmp');
await artifact.saveAs(harParams.path); await this._connection.localUtils()._channel.harUnzip({ zipFile: harParams.path + '.tmp', harFile: harParams.path });
} } else {
await artifact.delete(); await artifact.saveAs(harParams.path);
} }
}, true); await artifact.delete();
await this._channel.close(); }
await this._closedPromise; }, true);
} catch (e) { await this._channel.close();
if (isSafeCloseError(e)) await this._closedPromise;
return;
throw e;
}
} }
async _enableRecorder(params: { async _enableRecorder(params: {

View file

@ -532,7 +532,7 @@ export class Page extends ChannelOwner<channels.PageChannel> implements api.Page
else else
await this._channel.close(options); await this._channel.close(options);
} catch (e) { } catch (e) {
if (isSafeCloseError(e)) if (isSafeCloseError(e) && !options.runBeforeUnload)
return; return;
throw e; throw e;
} }

View file

@ -426,29 +426,6 @@ for (const kind of ['launchServer', 'run-server'] as const) {
await browser.close(); await browser.close();
}); });
test('should not throw on context.close after disconnect', async ({ connect, startRemoteServer }) => {
const remoteServer = await startRemoteServer(kind);
const browser = await connect(remoteServer.wsEndpoint());
const context = await browser.newContext();
await context.newPage();
await Promise.all([
new Promise(f => browser.on('disconnected', f)),
remoteServer.close()
]);
await context.close();
});
test('should not throw on page.close after disconnect', async ({ connect, startRemoteServer }) => {
const remoteServer = await startRemoteServer(kind);
const browser = await connect(remoteServer.wsEndpoint());
const page = await browser.newPage();
await Promise.all([
new Promise(f => browser.on('disconnected', f)),
remoteServer.close()
]);
await page.close();
});
test('should saveAs videos from remote browser', async ({ connect, startRemoteServer }, testInfo) => { test('should saveAs videos from remote browser', async ({ connect, startRemoteServer }, testInfo) => {
const remoteServer = await startRemoteServer(kind); const remoteServer = await startRemoteServer(kind);
const browser = await connect(remoteServer.wsEndpoint()); const browser = await connect(remoteServer.wsEndpoint());