mirror of
https://github.com/puppeteer/puppeteer
synced 2024-06-14 14:02:48 +00:00
refactor: turn Frame into EventEmitter (#10711)
This commit is contained in:
parent
854d488693
commit
f70048c84f
@ -11,9 +11,11 @@ To understand frames, you can think of frames as `<iframe>` elements. Just like
|
|||||||
#### Signature:
|
#### Signature:
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
export declare class Frame
|
export declare class Frame extends EventEmitter
|
||||||
```
|
```
|
||||||
|
|
||||||
|
**Extends:** [EventEmitter](./puppeteer.eventemitter.md)
|
||||||
|
|
||||||
## Remarks
|
## Remarks
|
||||||
|
|
||||||
Frame lifecycles are controlled by three events that are all dispatched on the parent [page](./puppeteer.frame.page.md):
|
Frame lifecycles are controlled by three events that are all dispatched on the parent [page](./puppeteer.frame.page.md):
|
||||||
|
@ -19,6 +19,7 @@ import {HTTPResponse} from '../api/HTTPResponse.js';
|
|||||||
import {Page, WaitTimeoutOptions} from '../api/Page.js';
|
import {Page, WaitTimeoutOptions} from '../api/Page.js';
|
||||||
import {CDPSession} from '../common/Connection.js';
|
import {CDPSession} from '../common/Connection.js';
|
||||||
import {DeviceRequestPrompt} from '../common/DeviceRequestPrompt.js';
|
import {DeviceRequestPrompt} from '../common/DeviceRequestPrompt.js';
|
||||||
|
import {EventEmitter} from '../common/EventEmitter.js';
|
||||||
import {ExecutionContext} from '../common/ExecutionContext.js';
|
import {ExecutionContext} from '../common/ExecutionContext.js';
|
||||||
import {getQueryHandlerAndSelector} from '../common/GetQueryHandler.js';
|
import {getQueryHandlerAndSelector} from '../common/GetQueryHandler.js';
|
||||||
import {
|
import {
|
||||||
@ -223,7 +224,7 @@ export interface FrameAddStyleTagOptions {
|
|||||||
*
|
*
|
||||||
* @public
|
* @public
|
||||||
*/
|
*/
|
||||||
export class Frame {
|
export class Frame extends EventEmitter {
|
||||||
/**
|
/**
|
||||||
* @internal
|
* @internal
|
||||||
*/
|
*/
|
||||||
@ -251,7 +252,9 @@ export class Frame {
|
|||||||
/**
|
/**
|
||||||
* @internal
|
* @internal
|
||||||
*/
|
*/
|
||||||
constructor() {}
|
constructor() {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The page associated with the frame.
|
* The page associated with the frame.
|
||||||
|
@ -37,6 +37,20 @@ import {LifecycleWatcher, PuppeteerLifeCycleEvent} from './LifecycleWatcher.js';
|
|||||||
import {EvaluateFunc, EvaluateFuncWith, HandleFor, NodeFor} from './types.js';
|
import {EvaluateFunc, EvaluateFuncWith, HandleFor, NodeFor} from './types.js';
|
||||||
import {withSourcePuppeteerURLIfNone} from './util.js';
|
import {withSourcePuppeteerURLIfNone} from './util.js';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* We use symbols to prevent external parties listening to these events.
|
||||||
|
* They are internal to Puppeteer.
|
||||||
|
*
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
export const FrameEmittedEvents = {
|
||||||
|
FrameNavigated: Symbol('Frame.FrameNavigated'),
|
||||||
|
FrameSwapped: Symbol('Frame.FrameSwapped'),
|
||||||
|
LifecycleEvent: Symbol('Frame.LifecycleEvent'),
|
||||||
|
FrameNavigatedWithinDocument: Symbol('Frame.FrameNavigatedWithinDocument'),
|
||||||
|
FrameDetached: Symbol('Frame.FrameDetached'),
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @internal
|
* @internal
|
||||||
*/
|
*/
|
||||||
@ -106,7 +120,7 @@ export class Frame extends BaseFrame {
|
|||||||
|
|
||||||
let ensureNewDocumentNavigation = false;
|
let ensureNewDocumentNavigation = false;
|
||||||
const watcher = new LifecycleWatcher(
|
const watcher = new LifecycleWatcher(
|
||||||
this._frameManager,
|
this._frameManager.networkManager,
|
||||||
this,
|
this,
|
||||||
waitUntil,
|
waitUntil,
|
||||||
timeout
|
timeout
|
||||||
@ -180,7 +194,7 @@ export class Frame extends BaseFrame {
|
|||||||
timeout = this._frameManager.timeoutSettings.navigationTimeout(),
|
timeout = this._frameManager.timeoutSettings.navigationTimeout(),
|
||||||
} = options;
|
} = options;
|
||||||
const watcher = new LifecycleWatcher(
|
const watcher = new LifecycleWatcher(
|
||||||
this._frameManager,
|
this._frameManager.networkManager,
|
||||||
this,
|
this,
|
||||||
waitUntil,
|
waitUntil,
|
||||||
timeout
|
timeout
|
||||||
|
@ -20,12 +20,15 @@ import {Page} from '../api/Page.js';
|
|||||||
import {assert} from '../util/assert.js';
|
import {assert} from '../util/assert.js';
|
||||||
import {isErrorLike} from '../util/ErrorLike.js';
|
import {isErrorLike} from '../util/ErrorLike.js';
|
||||||
|
|
||||||
import {CDPSession, isTargetClosedError} from './Connection.js';
|
import {
|
||||||
|
CDPSession,
|
||||||
|
CDPSessionEmittedEvents,
|
||||||
|
isTargetClosedError,
|
||||||
|
} from './Connection.js';
|
||||||
import {DeviceRequestPromptManager} from './DeviceRequestPrompt.js';
|
import {DeviceRequestPromptManager} from './DeviceRequestPrompt.js';
|
||||||
import {EventEmitter} from './EventEmitter.js';
|
import {EventEmitter} from './EventEmitter.js';
|
||||||
import {ExecutionContext} from './ExecutionContext.js';
|
import {ExecutionContext} from './ExecutionContext.js';
|
||||||
import {Frame} from './Frame.js';
|
import {Frame, FrameEmittedEvents} from './Frame.js';
|
||||||
import {Frame as CDPFrame} from './Frame.js';
|
|
||||||
import {FrameTree} from './FrameTree.js';
|
import {FrameTree} from './FrameTree.js';
|
||||||
import {IsolatedWorld} from './IsolatedWorld.js';
|
import {IsolatedWorld} from './IsolatedWorld.js';
|
||||||
import {MAIN_WORLD, PUPPETEER_WORLD} from './IsolatedWorlds.js';
|
import {MAIN_WORLD, PUPPETEER_WORLD} from './IsolatedWorlds.js';
|
||||||
@ -54,8 +57,6 @@ export const FrameManagerEmittedEvents = {
|
|||||||
FrameNavigatedWithinDocument: Symbol(
|
FrameNavigatedWithinDocument: Symbol(
|
||||||
'FrameManager.FrameNavigatedWithinDocument'
|
'FrameManager.FrameNavigatedWithinDocument'
|
||||||
),
|
),
|
||||||
ExecutionContextCreated: Symbol('FrameManager.ExecutionContextCreated'),
|
|
||||||
ExecutionContextDestroyed: Symbol('FrameManager.ExecutionContextDestroyed'),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -111,6 +112,12 @@ export class FrameManager extends EventEmitter {
|
|||||||
this.#networkManager = new NetworkManager(client, ignoreHTTPSErrors, this);
|
this.#networkManager = new NetworkManager(client, ignoreHTTPSErrors, this);
|
||||||
this.#timeoutSettings = timeoutSettings;
|
this.#timeoutSettings = timeoutSettings;
|
||||||
this.setupEventListeners(this.#client);
|
this.setupEventListeners(this.#client);
|
||||||
|
client.once(CDPSessionEmittedEvents.Disconnected, () => {
|
||||||
|
const mainFrame = this._frameTree.getMainFrame();
|
||||||
|
if (mainFrame) {
|
||||||
|
this.#removeFramesRecursively(mainFrame);
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private setupEventListeners(session: CDPSession) {
|
private setupEventListeners(session: CDPSession) {
|
||||||
@ -248,6 +255,7 @@ export class FrameManager extends EventEmitter {
|
|||||||
}
|
}
|
||||||
frame._onLifecycleEvent(event.loaderId, event.name);
|
frame._onLifecycleEvent(event.loaderId, event.name);
|
||||||
this.emit(FrameManagerEmittedEvents.LifecycleEvent, frame);
|
this.emit(FrameManagerEmittedEvents.LifecycleEvent, frame);
|
||||||
|
frame.emit(FrameEmittedEvents.LifecycleEvent);
|
||||||
}
|
}
|
||||||
|
|
||||||
#onFrameStartedLoading(frameId: string): void {
|
#onFrameStartedLoading(frameId: string): void {
|
||||||
@ -265,6 +273,7 @@ export class FrameManager extends EventEmitter {
|
|||||||
}
|
}
|
||||||
frame._onLoadingStopped();
|
frame._onLoadingStopped();
|
||||||
this.emit(FrameManagerEmittedEvents.LifecycleEvent, frame);
|
this.emit(FrameManagerEmittedEvents.LifecycleEvent, frame);
|
||||||
|
frame.emit(FrameEmittedEvents.LifecycleEvent);
|
||||||
}
|
}
|
||||||
|
|
||||||
#handleFrameTree(
|
#handleFrameTree(
|
||||||
@ -309,7 +318,7 @@ export class FrameManager extends EventEmitter {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
frame = new CDPFrame(this, frameId, parentFrameId, session);
|
frame = new Frame(this, frameId, parentFrameId, session);
|
||||||
this._frameTree.addFrame(frame);
|
this._frameTree.addFrame(frame);
|
||||||
this.emit(FrameManagerEmittedEvents.FrameAttached, frame);
|
this.emit(FrameManagerEmittedEvents.FrameAttached, frame);
|
||||||
}
|
}
|
||||||
@ -335,7 +344,7 @@ export class FrameManager extends EventEmitter {
|
|||||||
frame._id = frameId;
|
frame._id = frameId;
|
||||||
} else {
|
} else {
|
||||||
// Initial main frame navigation.
|
// Initial main frame navigation.
|
||||||
frame = new CDPFrame(this, frameId, undefined, this.#client);
|
frame = new Frame(this, frameId, undefined, this.#client);
|
||||||
}
|
}
|
||||||
this._frameTree.addFrame(frame);
|
this._frameTree.addFrame(frame);
|
||||||
}
|
}
|
||||||
@ -343,6 +352,7 @@ export class FrameManager extends EventEmitter {
|
|||||||
frame = await this._frameTree.waitForFrame(frameId);
|
frame = await this._frameTree.waitForFrame(frameId);
|
||||||
frame._navigated(framePayload);
|
frame._navigated(framePayload);
|
||||||
this.emit(FrameManagerEmittedEvents.FrameNavigated, frame);
|
this.emit(FrameManagerEmittedEvents.FrameNavigated, frame);
|
||||||
|
frame.emit(FrameEmittedEvents.FrameNavigated);
|
||||||
}
|
}
|
||||||
|
|
||||||
async #createIsolatedWorld(session: CDPSession, name: string): Promise<void> {
|
async #createIsolatedWorld(session: CDPSession, name: string): Promise<void> {
|
||||||
@ -385,7 +395,9 @@ export class FrameManager extends EventEmitter {
|
|||||||
}
|
}
|
||||||
frame._navigatedWithinDocument(url);
|
frame._navigatedWithinDocument(url);
|
||||||
this.emit(FrameManagerEmittedEvents.FrameNavigatedWithinDocument, frame);
|
this.emit(FrameManagerEmittedEvents.FrameNavigatedWithinDocument, frame);
|
||||||
|
frame.emit(FrameEmittedEvents.FrameNavigatedWithinDocument);
|
||||||
this.emit(FrameManagerEmittedEvents.FrameNavigated, frame);
|
this.emit(FrameManagerEmittedEvents.FrameNavigated, frame);
|
||||||
|
frame.emit(FrameEmittedEvents.FrameNavigated);
|
||||||
}
|
}
|
||||||
|
|
||||||
#onFrameDetached(
|
#onFrameDetached(
|
||||||
@ -402,6 +414,7 @@ export class FrameManager extends EventEmitter {
|
|||||||
}
|
}
|
||||||
} else if (reason === 'swap') {
|
} else if (reason === 'swap') {
|
||||||
this.emit(FrameManagerEmittedEvents.FrameSwapped, frame);
|
this.emit(FrameManagerEmittedEvents.FrameSwapped, frame);
|
||||||
|
frame?.emit(FrameEmittedEvents.FrameSwapped);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -478,5 +491,6 @@ export class FrameManager extends EventEmitter {
|
|||||||
frame._detach();
|
frame._detach();
|
||||||
this._frameTree.removeFrame(frame);
|
this._frameTree.removeFrame(frame);
|
||||||
this.emit(FrameManagerEmittedEvents.FrameDetached, frame);
|
this.emit(FrameManagerEmittedEvents.FrameDetached, frame);
|
||||||
|
frame.emit(FrameEmittedEvents.FrameDetached, frame);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -293,7 +293,7 @@ export class IsolatedWorld implements Realm {
|
|||||||
await setPageContent(this, html);
|
await setPageContent(this, html);
|
||||||
|
|
||||||
const watcher = new LifecycleWatcher(
|
const watcher = new LifecycleWatcher(
|
||||||
this.#frameManager,
|
this.#frameManager.networkManager,
|
||||||
this.#frame,
|
this.#frame,
|
||||||
waitUntil,
|
waitUntil,
|
||||||
timeout
|
timeout
|
||||||
|
@ -18,12 +18,10 @@ import {HTTPResponse} from '../api/HTTPResponse.js';
|
|||||||
import {assert} from '../util/assert.js';
|
import {assert} from '../util/assert.js';
|
||||||
import {Deferred} from '../util/Deferred.js';
|
import {Deferred} from '../util/Deferred.js';
|
||||||
|
|
||||||
import {CDPSessionEmittedEvents} from './Connection.js';
|
|
||||||
import {TimeoutError} from './Errors.js';
|
import {TimeoutError} from './Errors.js';
|
||||||
import {Frame} from './Frame.js';
|
import {Frame, FrameEmittedEvents} from './Frame.js';
|
||||||
import {FrameManager, FrameManagerEmittedEvents} from './FrameManager.js';
|
|
||||||
import {HTTPRequest} from './HTTPRequest.js';
|
import {HTTPRequest} from './HTTPRequest.js';
|
||||||
import {NetworkManagerEmittedEvents} from './NetworkManager.js';
|
import {NetworkManager, NetworkManagerEmittedEvents} from './NetworkManager.js';
|
||||||
import {
|
import {
|
||||||
addEventListener,
|
addEventListener,
|
||||||
PuppeteerEventListener,
|
PuppeteerEventListener,
|
||||||
@ -62,7 +60,6 @@ const puppeteerToProtocolLifecycle = new Map<
|
|||||||
*/
|
*/
|
||||||
export class LifecycleWatcher {
|
export class LifecycleWatcher {
|
||||||
#expectedLifecycle: ProtocolLifeCycleEvent[];
|
#expectedLifecycle: ProtocolLifeCycleEvent[];
|
||||||
#frameManager: FrameManager;
|
|
||||||
#frame: Frame;
|
#frame: Frame;
|
||||||
#timeout: number;
|
#timeout: number;
|
||||||
#navigationRequest: HTTPRequest | null = null;
|
#navigationRequest: HTTPRequest | null = null;
|
||||||
@ -80,7 +77,7 @@ export class LifecycleWatcher {
|
|||||||
#navigationResponseReceived?: Deferred<void>;
|
#navigationResponseReceived?: Deferred<void>;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
frameManager: FrameManager,
|
networkManager: NetworkManager,
|
||||||
frame: Frame,
|
frame: Frame,
|
||||||
waitUntil: PuppeteerLifeCycleEvent | PuppeteerLifeCycleEvent[],
|
waitUntil: PuppeteerLifeCycleEvent | PuppeteerLifeCycleEvent[],
|
||||||
timeout: number
|
timeout: number
|
||||||
@ -97,55 +94,46 @@ export class LifecycleWatcher {
|
|||||||
return protocolEvent as ProtocolLifeCycleEvent;
|
return protocolEvent as ProtocolLifeCycleEvent;
|
||||||
});
|
});
|
||||||
|
|
||||||
this.#frameManager = frameManager;
|
|
||||||
this.#frame = frame;
|
this.#frame = frame;
|
||||||
this.#timeout = timeout;
|
this.#timeout = timeout;
|
||||||
this.#eventListeners = [
|
this.#eventListeners = [
|
||||||
addEventListener(
|
addEventListener(
|
||||||
frameManager.client,
|
frame,
|
||||||
CDPSessionEmittedEvents.Disconnected,
|
FrameEmittedEvents.LifecycleEvent,
|
||||||
this.#terminate.bind(
|
|
||||||
this,
|
|
||||||
new Error('Navigation failed because browser has disconnected!')
|
|
||||||
)
|
|
||||||
),
|
|
||||||
addEventListener(
|
|
||||||
this.#frameManager,
|
|
||||||
FrameManagerEmittedEvents.LifecycleEvent,
|
|
||||||
this.#checkLifecycleComplete.bind(this)
|
this.#checkLifecycleComplete.bind(this)
|
||||||
),
|
),
|
||||||
addEventListener(
|
addEventListener(
|
||||||
this.#frameManager,
|
frame,
|
||||||
FrameManagerEmittedEvents.FrameNavigatedWithinDocument,
|
FrameEmittedEvents.FrameNavigatedWithinDocument,
|
||||||
this.#navigatedWithinDocument.bind(this)
|
this.#navigatedWithinDocument.bind(this)
|
||||||
),
|
),
|
||||||
addEventListener(
|
addEventListener(
|
||||||
this.#frameManager,
|
frame,
|
||||||
FrameManagerEmittedEvents.FrameNavigated,
|
FrameEmittedEvents.FrameNavigated,
|
||||||
this.#navigated.bind(this)
|
this.#navigated.bind(this)
|
||||||
),
|
),
|
||||||
addEventListener(
|
addEventListener(
|
||||||
this.#frameManager,
|
frame,
|
||||||
FrameManagerEmittedEvents.FrameSwapped,
|
FrameEmittedEvents.FrameSwapped,
|
||||||
this.#frameSwapped.bind(this)
|
this.#frameSwapped.bind(this)
|
||||||
),
|
),
|
||||||
addEventListener(
|
addEventListener(
|
||||||
this.#frameManager,
|
frame,
|
||||||
FrameManagerEmittedEvents.FrameDetached,
|
FrameEmittedEvents.FrameDetached,
|
||||||
this.#onFrameDetached.bind(this)
|
this.#onFrameDetached.bind(this)
|
||||||
),
|
),
|
||||||
addEventListener(
|
addEventListener(
|
||||||
this.#frameManager.networkManager,
|
networkManager,
|
||||||
NetworkManagerEmittedEvents.Request,
|
NetworkManagerEmittedEvents.Request,
|
||||||
this.#onRequest.bind(this)
|
this.#onRequest.bind(this)
|
||||||
),
|
),
|
||||||
addEventListener(
|
addEventListener(
|
||||||
this.#frameManager.networkManager,
|
networkManager,
|
||||||
NetworkManagerEmittedEvents.Response,
|
NetworkManagerEmittedEvents.Response,
|
||||||
this.#onResponse.bind(this)
|
this.#onResponse.bind(this)
|
||||||
),
|
),
|
||||||
addEventListener(
|
addEventListener(
|
||||||
this.#frameManager.networkManager,
|
networkManager,
|
||||||
NetworkManagerEmittedEvents.RequestFailed,
|
NetworkManagerEmittedEvents.RequestFailed,
|
||||||
this.#onRequestFailed.bind(this)
|
this.#onRequestFailed.bind(this)
|
||||||
),
|
),
|
||||||
@ -204,10 +192,6 @@ export class LifecycleWatcher {
|
|||||||
return this.#navigationRequest ? this.#navigationRequest.response() : null;
|
return this.#navigationRequest ? this.#navigationRequest.response() : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
#terminate(error: Error): void {
|
|
||||||
this.#terminationDeferred.resolve(error);
|
|
||||||
}
|
|
||||||
|
|
||||||
sameDocumentNavigationPromise(): Promise<Error | undefined> {
|
sameDocumentNavigationPromise(): Promise<Error | undefined> {
|
||||||
return this.#sameDocumentNavigationDeferred.valueOrThrow();
|
return this.#sameDocumentNavigationDeferred.valueOrThrow();
|
||||||
}
|
}
|
||||||
@ -224,25 +208,16 @@ export class LifecycleWatcher {
|
|||||||
return this.#terminationDeferred.valueOrThrow();
|
return this.#terminationDeferred.valueOrThrow();
|
||||||
}
|
}
|
||||||
|
|
||||||
#navigatedWithinDocument(frame: Frame): void {
|
#navigatedWithinDocument(): void {
|
||||||
if (frame !== this.#frame) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.#hasSameDocumentNavigation = true;
|
this.#hasSameDocumentNavigation = true;
|
||||||
this.#checkLifecycleComplete();
|
this.#checkLifecycleComplete();
|
||||||
}
|
}
|
||||||
|
|
||||||
#navigated(frame: Frame): void {
|
#navigated(): void {
|
||||||
if (frame !== this.#frame) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.#checkLifecycleComplete();
|
this.#checkLifecycleComplete();
|
||||||
}
|
}
|
||||||
|
|
||||||
#frameSwapped(frame: Frame): void {
|
#frameSwapped(): void {
|
||||||
if (frame !== this.#frame) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.#swapped = true;
|
this.#swapped = true;
|
||||||
this.#checkLifecycleComplete();
|
this.#checkLifecycleComplete();
|
||||||
}
|
}
|
||||||
|
@ -59,7 +59,7 @@ describe('Launcher specs', function () {
|
|||||||
const error = await navigationPromise;
|
const error = await navigationPromise;
|
||||||
expect(
|
expect(
|
||||||
[
|
[
|
||||||
'Navigation failed because browser has disconnected!',
|
'Navigating frame was detached',
|
||||||
'Protocol error (Page.navigate): Target closed.',
|
'Protocol error (Page.navigate): Target closed.',
|
||||||
].includes(error.message)
|
].includes(error.message)
|
||||||
).toBeTruthy();
|
).toBeTruthy();
|
||||||
@ -82,7 +82,7 @@ describe('Launcher specs', function () {
|
|||||||
});
|
});
|
||||||
remote.disconnect();
|
remote.disconnect();
|
||||||
const error = await watchdog;
|
const error = await watchdog;
|
||||||
expect(error.message).toContain('Protocol error');
|
expect(error.message).toContain('frame got detached');
|
||||||
} finally {
|
} finally {
|
||||||
await close();
|
await close();
|
||||||
}
|
}
|
||||||
@ -766,11 +766,6 @@ describe('Launcher specs', function () {
|
|||||||
|
|
||||||
const pages = await remoteBrowser.pages();
|
const pages = await remoteBrowser.pages();
|
||||||
|
|
||||||
await page2.close();
|
|
||||||
await page1.close();
|
|
||||||
remoteBrowser.disconnect();
|
|
||||||
await browser.close();
|
|
||||||
|
|
||||||
expect(
|
expect(
|
||||||
pages
|
pages
|
||||||
.map((p: Page) => {
|
.map((p: Page) => {
|
||||||
@ -778,6 +773,11 @@ describe('Launcher specs', function () {
|
|||||||
})
|
})
|
||||||
.sort()
|
.sort()
|
||||||
).toEqual(['about:blank', server.EMPTY_PAGE]);
|
).toEqual(['about:blank', server.EMPTY_PAGE]);
|
||||||
|
|
||||||
|
await page2.close();
|
||||||
|
await page1.close();
|
||||||
|
remoteBrowser.disconnect();
|
||||||
|
await browser.close();
|
||||||
} finally {
|
} finally {
|
||||||
await close();
|
await close();
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user