mirror of
https://github.com/microsoft/playwright.git
synced 2024-12-15 06:02:57 +03:00
chore: introduce FrameManager to be reused between browsers (#261)
This commit is contained in:
parent
6b9f475217
commit
4b7a017456
@ -9,7 +9,7 @@
|
||||
"main": "index.js",
|
||||
"playwright": {
|
||||
"chromium_revision": "724623",
|
||||
"firefox_revision": "1005",
|
||||
"firefox_revision": "1007",
|
||||
"webkit_revision": "1038"
|
||||
},
|
||||
"scripts": {
|
||||
|
@ -49,10 +49,8 @@ export class FrameManager extends EventEmitter implements PageDelegate {
|
||||
_client: CDPSession;
|
||||
private _page: Page;
|
||||
private _networkManager: NetworkManager;
|
||||
private _frames = new Map<string, frames.Frame>();
|
||||
private _contextIdToContext = new Map<number, js.ExecutionContext>();
|
||||
private _isolatedWorlds = new Set<string>();
|
||||
private _mainFrame: frames.Frame;
|
||||
rawMouse: RawMouseImpl;
|
||||
rawKeyboard: RawKeyboardImpl;
|
||||
|
||||
@ -61,8 +59,8 @@ export class FrameManager extends EventEmitter implements PageDelegate {
|
||||
this._client = client;
|
||||
this.rawKeyboard = new RawKeyboardImpl(client);
|
||||
this.rawMouse = new RawMouseImpl(client);
|
||||
this._networkManager = new NetworkManager(client, ignoreHTTPSErrors, this);
|
||||
this._page = new Page(this, browserContext);
|
||||
this._networkManager = new NetworkManager(client, ignoreHTTPSErrors, this._page);
|
||||
(this._page as any).accessibility = new Accessibility(client);
|
||||
(this._page as any).coverage = new Coverage(client);
|
||||
(this._page as any).pdf = new PDF(client);
|
||||
@ -77,7 +75,6 @@ export class FrameManager extends EventEmitter implements PageDelegate {
|
||||
|
||||
this._client.on('Inspector.targetCrashed', event => this._onTargetCrashed());
|
||||
this._client.on('Log.entryAdded', event => this._onLogEntryAdded(event));
|
||||
this._client.on('Page.domContentEventFired', event => this._page.emit(Events.Page.DOMContentLoaded));
|
||||
this._client.on('Page.fileChooserOpened', event => this._onFileChooserOpened(event));
|
||||
this._client.on('Page.frameAttached', event => this._onFrameAttached(event.frameId, event.parentFrameId));
|
||||
this._client.on('Page.frameDetached', event => this._onFrameDetached(event.frameId));
|
||||
@ -85,7 +82,6 @@ export class FrameManager extends EventEmitter implements PageDelegate {
|
||||
this._client.on('Page.frameStoppedLoading', event => this._onFrameStoppedLoading(event.frameId));
|
||||
this._client.on('Page.javascriptDialogOpening', event => this._onDialog(event));
|
||||
this._client.on('Page.lifecycleEvent', event => this._onLifecycleEvent(event));
|
||||
this._client.on('Page.loadEventFired', event => this._page.emit(Events.Page.Load));
|
||||
this._client.on('Page.navigatedWithinDocument', event => this._onFrameNavigatedWithinDocument(event.frameId, event.url));
|
||||
this._client.on('Runtime.bindingCalled', event => this._onBindingCalled(event));
|
||||
this._client.on('Runtime.consoleAPICalled', event => this._onConsoleAPI(event));
|
||||
@ -196,28 +192,20 @@ export class FrameManager extends EventEmitter implements PageDelegate {
|
||||
}
|
||||
|
||||
_onLifecycleEvent(event: Protocol.Page.lifecycleEventPayload) {
|
||||
const frame = this._frames.get(event.frameId);
|
||||
if (!frame)
|
||||
return;
|
||||
if (event.name === 'init')
|
||||
frame._firedLifecycleEvents.clear();
|
||||
this._page._frameManager.frameLifecycleEvent(event.frameId, 'clear');
|
||||
else if (event.name === 'load')
|
||||
frame._lifecycleEvent('load');
|
||||
this._page._frameManager.frameLifecycleEvent(event.frameId, 'load');
|
||||
else if (event.name === 'DOMContentLoaded')
|
||||
frame._lifecycleEvent('domcontentloaded');
|
||||
this._page._frameManager.frameLifecycleEvent(event.frameId, 'domcontentloaded');
|
||||
}
|
||||
|
||||
_onFrameStoppedLoading(frameId: string) {
|
||||
const frame = this._frames.get(frameId);
|
||||
if (!frame)
|
||||
return;
|
||||
frame._lifecycleEvent('domcontentloaded');
|
||||
frame._lifecycleEvent('load');
|
||||
this._page._frameManager.frameStoppedLoading(frameId);
|
||||
}
|
||||
|
||||
_handleFrameTree(frameTree: Protocol.Page.FrameTree) {
|
||||
if (frameTree.frame.parentId)
|
||||
this._onFrameAttached(frameTree.frame.id, frameTree.frame.parentId);
|
||||
this._onFrameAttached(frameTree.frame.id, frameTree.frame.parentId);
|
||||
this._onFrameNavigated(frameTree.frame, true);
|
||||
if (!frameTree.childFrames)
|
||||
return;
|
||||
@ -230,56 +218,12 @@ export class FrameManager extends EventEmitter implements PageDelegate {
|
||||
return this._page;
|
||||
}
|
||||
|
||||
mainFrame(): frames.Frame {
|
||||
return this._mainFrame;
|
||||
}
|
||||
|
||||
frames(): frames.Frame[] {
|
||||
return Array.from(this._frames.values());
|
||||
}
|
||||
|
||||
frame(frameId: string): frames.Frame | null {
|
||||
return this._frames.get(frameId) || null;
|
||||
}
|
||||
|
||||
_onFrameAttached(frameId: string, parentFrameId: string | null) {
|
||||
if (this._frames.has(frameId))
|
||||
return;
|
||||
assert(parentFrameId);
|
||||
const parentFrame = this._frames.get(parentFrameId);
|
||||
const frame = new frames.Frame(this._page, frameId, parentFrame);
|
||||
this._frames.set(frameId, frame);
|
||||
this._page.emit(Events.Page.FrameAttached, frame);
|
||||
this._page._frameManager.frameAttached(frameId, parentFrameId);
|
||||
}
|
||||
|
||||
_onFrameNavigated(framePayload: Protocol.Page.Frame, initial: boolean) {
|
||||
const isMainFrame = !framePayload.parentId;
|
||||
let frame = isMainFrame ? this._mainFrame : this._frames.get(framePayload.id);
|
||||
assert(isMainFrame || frame, 'We either navigate top level or have old version of the navigated frame');
|
||||
|
||||
// Detach all child frames first.
|
||||
if (frame) {
|
||||
for (const child of frame.childFrames())
|
||||
this._removeFramesRecursively(child);
|
||||
}
|
||||
|
||||
// Update or create main frame.
|
||||
if (isMainFrame) {
|
||||
if (frame) {
|
||||
// Update frame id to retain frame identity on cross-process navigation.
|
||||
this._frames.delete(frame._id);
|
||||
frame._id = framePayload.id;
|
||||
} else {
|
||||
// Initial main frame navigation.
|
||||
frame = new frames.Frame(this._page, framePayload.id, null);
|
||||
}
|
||||
this._frames.set(framePayload.id, frame);
|
||||
this._mainFrame = frame;
|
||||
}
|
||||
|
||||
frame._onCommittedNewDocumentNavigation(framePayload.url, framePayload.name, framePayload.loaderId, initial);
|
||||
|
||||
this._page.emit(Events.Page.FrameNavigated, frame);
|
||||
this._page._frameManager.frameCommittedNewDocumentNavigation(framePayload.id, framePayload.url, framePayload.name || '', framePayload.loaderId, initial);
|
||||
}
|
||||
|
||||
async _ensureIsolatedWorld(name: string) {
|
||||
@ -290,7 +234,7 @@ export class FrameManager extends EventEmitter implements PageDelegate {
|
||||
source: `//# sourceURL=${EVALUATION_SCRIPT_URL}`,
|
||||
worldName: name,
|
||||
});
|
||||
await Promise.all(this.frames().map(frame => this._client.send('Page.createIsolatedWorld', {
|
||||
await Promise.all(this._page.frames().map(frame => this._client.send('Page.createIsolatedWorld', {
|
||||
frameId: frame._id,
|
||||
grantUniveralAccess: true,
|
||||
worldName: name,
|
||||
@ -298,22 +242,16 @@ export class FrameManager extends EventEmitter implements PageDelegate {
|
||||
}
|
||||
|
||||
_onFrameNavigatedWithinDocument(frameId: string, url: string) {
|
||||
const frame = this._frames.get(frameId);
|
||||
if (!frame)
|
||||
return;
|
||||
frame._onCommittedSameDocumentNavigation(url);
|
||||
this._page.emit(Events.Page.FrameNavigated, frame);
|
||||
this._page._frameManager.frameCommittedSameDocumentNavigation(frameId, url);
|
||||
}
|
||||
|
||||
_onFrameDetached(frameId: string) {
|
||||
const frame = this._frames.get(frameId);
|
||||
if (frame)
|
||||
this._removeFramesRecursively(frame);
|
||||
this._page._frameManager.frameDetached(frameId);
|
||||
}
|
||||
|
||||
_onExecutionContextCreated(contextPayload: Protocol.Runtime.ExecutionContextDescription) {
|
||||
const frameId = contextPayload.auxData ? contextPayload.auxData.frameId : null;
|
||||
const frame = this._frames.get(frameId) || null;
|
||||
const frame = this._page._frameManager.frame(frameId);
|
||||
if (contextPayload.auxData && contextPayload.auxData.type === 'isolated')
|
||||
this._isolatedWorlds.add(contextPayload.name);
|
||||
const delegate = new ExecutionContextDelegate(this._client, contextPayload);
|
||||
@ -349,14 +287,6 @@ export class FrameManager extends EventEmitter implements PageDelegate {
|
||||
return context;
|
||||
}
|
||||
|
||||
_removeFramesRecursively(frame: frames.Frame) {
|
||||
for (const child of frame.childFrames())
|
||||
this._removeFramesRecursively(child);
|
||||
frame._onDetached();
|
||||
this._frames.delete(frame._id);
|
||||
this._page.emit(Events.Page.FrameDetached, frame);
|
||||
}
|
||||
|
||||
async _onConsoleAPI(event: Protocol.Runtime.consoleAPICalledPayload) {
|
||||
if (event.executionContextId === 0) {
|
||||
// DevTools protocol stores the last 1000 console messages. These
|
||||
@ -382,7 +312,7 @@ export class FrameManager extends EventEmitter implements PageDelegate {
|
||||
async exposeBinding(name: string, bindingFunction: string) {
|
||||
await this._client.send('Runtime.addBinding', {name: name});
|
||||
await this._client.send('Page.addScriptToEvaluateOnNewDocument', {source: bindingFunction});
|
||||
await Promise.all(this.frames().map(frame => frame.evaluate(bindingFunction).catch(debugError)));
|
||||
await Promise.all(this._page.frames().map(frame => frame.evaluate(bindingFunction).catch(debugError)));
|
||||
}
|
||||
|
||||
_onBindingCalled(event: Protocol.Runtime.bindingCalledPayload) {
|
||||
@ -417,7 +347,7 @@ export class FrameManager extends EventEmitter implements PageDelegate {
|
||||
}
|
||||
|
||||
async _onFileChooserOpened(event: Protocol.Page.fileChooserOpenedPayload) {
|
||||
const frame = this.frame(event.frameId);
|
||||
const frame = this._page._frameManager.frame(event.frameId);
|
||||
const utilityContext = await frame._utilityContext();
|
||||
const handle = await this.adoptBackendNodeId(event.backendNodeId, utilityContext);
|
||||
this._page._onFileChooserOpened(handle);
|
||||
@ -539,7 +469,7 @@ export class FrameManager extends EventEmitter implements PageDelegate {
|
||||
});
|
||||
if (typeof nodeInfo.node.frameId !== 'string')
|
||||
return null;
|
||||
return this.frame(nodeInfo.node.frameId);
|
||||
return this._page._frameManager.frame(nodeInfo.node.frameId);
|
||||
}
|
||||
|
||||
isElementHandle(remoteObject: any): boolean {
|
||||
|
@ -17,7 +17,7 @@
|
||||
|
||||
import { EventEmitter } from 'events';
|
||||
import { CDPSession } from './Connection';
|
||||
import { FrameManager } from './FrameManager';
|
||||
import { Page } from '../page';
|
||||
import { assert, debugError, helper } from '../helper';
|
||||
import { Protocol } from './protocol';
|
||||
import * as network from '../network';
|
||||
@ -33,7 +33,7 @@ export const NetworkManagerEvents = {
|
||||
export class NetworkManager extends EventEmitter {
|
||||
private _client: CDPSession;
|
||||
private _ignoreHTTPSErrors: boolean;
|
||||
private _frameManager: FrameManager;
|
||||
private _page: Page;
|
||||
private _requestIdToRequest = new Map<string, InterceptableRequest>();
|
||||
private _requestIdToRequestWillBeSentEvent = new Map<string, Protocol.Network.requestWillBeSentPayload>();
|
||||
private _extraHTTPHeaders: network.Headers = {};
|
||||
@ -45,11 +45,11 @@ export class NetworkManager extends EventEmitter {
|
||||
private _userCacheDisabled = false;
|
||||
private _requestIdToInterceptionId = new Map<string, string>();
|
||||
|
||||
constructor(client: CDPSession, ignoreHTTPSErrors: boolean, frameManager: FrameManager) {
|
||||
constructor(client: CDPSession, ignoreHTTPSErrors: boolean, page: Page) {
|
||||
super();
|
||||
this._client = client;
|
||||
this._ignoreHTTPSErrors = ignoreHTTPSErrors;
|
||||
this._frameManager = frameManager;
|
||||
this._page = page;
|
||||
|
||||
this._client.on('Fetch.requestPaused', this._onRequestPaused.bind(this));
|
||||
this._client.on('Fetch.authRequired', this._onAuthRequired.bind(this));
|
||||
@ -198,7 +198,7 @@ export class NetworkManager extends EventEmitter {
|
||||
}
|
||||
}
|
||||
// TODO: how can frame be null here?
|
||||
const frame = event.frameId ? this._frameManager.frame(event.frameId) : null;
|
||||
const frame = event.frameId ? this._page._frameManager.frame(event.frameId) : null;
|
||||
const isNavigationRequest = event.requestId === event.loaderId && event.type === 'Document';
|
||||
const documentId = isNavigationRequest ? event.loaderId : undefined;
|
||||
const request = new InterceptableRequest(this._client, frame, interceptionId, documentId, this._userRequestInterceptionEnabled, event, redirectChain);
|
||||
|
@ -41,8 +41,6 @@ export class FrameManager extends EventEmitter implements PageDelegate {
|
||||
readonly _session: JugglerSession;
|
||||
readonly _page: Page;
|
||||
private readonly _networkManager: NetworkManager;
|
||||
private _mainFrame: frames.Frame;
|
||||
private readonly _frames: Map<string, frames.Frame>;
|
||||
private readonly _contextIdToContext: Map<string, js.ExecutionContext>;
|
||||
private _eventListeners: RegisteredListener[];
|
||||
|
||||
@ -51,10 +49,9 @@ export class FrameManager extends EventEmitter implements PageDelegate {
|
||||
this._session = session;
|
||||
this.rawKeyboard = new RawKeyboardImpl(session);
|
||||
this.rawMouse = new RawMouseImpl(session);
|
||||
this._networkManager = new NetworkManager(session, this);
|
||||
this._mainFrame = null;
|
||||
this._frames = new Map();
|
||||
this._contextIdToContext = new Map();
|
||||
this._page = new Page(this, browserContext);
|
||||
this._networkManager = new NetworkManager(session, this._page);
|
||||
this._eventListeners = [
|
||||
helper.addEventListener(this._session, 'Page.eventFired', this._onEventFired.bind(this)),
|
||||
helper.addEventListener(this._session, 'Page.frameAttached', this._onFrameAttached.bind(this)),
|
||||
@ -75,7 +72,6 @@ export class FrameManager extends EventEmitter implements PageDelegate {
|
||||
helper.addEventListener(this._networkManager, NetworkManagerEvents.RequestFinished, request => this._page.emit(Events.Page.RequestFinished, request)),
|
||||
helper.addEventListener(this._networkManager, NetworkManagerEvents.RequestFailed, request => this._page.emit(Events.Page.RequestFailed, request)),
|
||||
];
|
||||
this._page = new Page(this, browserContext);
|
||||
(this._page as any).interception = new Interception(this._networkManager);
|
||||
(this._page as any).accessibility = new Accessibility(session);
|
||||
}
|
||||
@ -95,7 +91,7 @@ export class FrameManager extends EventEmitter implements PageDelegate {
|
||||
|
||||
_onExecutionContextCreated({executionContextId, auxData}) {
|
||||
const frameId = auxData ? auxData.frameId : null;
|
||||
const frame = this._frames.get(frameId) || null;
|
||||
const frame = this._page._frameManager.frame(frameId);
|
||||
const delegate = new ExecutionContextDelegate(this._session, executionContextId);
|
||||
if (frame) {
|
||||
const context = new dom.FrameExecutionContext(delegate, frame);
|
||||
@ -116,76 +112,36 @@ export class FrameManager extends EventEmitter implements PageDelegate {
|
||||
context.frame()._contextDestroyed(context as dom.FrameExecutionContext);
|
||||
}
|
||||
|
||||
frame(frameId: string): frames.Frame {
|
||||
return this._frames.get(frameId);
|
||||
}
|
||||
|
||||
mainFrame(): frames.Frame {
|
||||
return this._mainFrame;
|
||||
}
|
||||
|
||||
frames() {
|
||||
const frames: Array<frames.Frame> = [];
|
||||
collect(this._mainFrame);
|
||||
return frames;
|
||||
|
||||
function collect(frame: frames.Frame) {
|
||||
frames.push(frame);
|
||||
for (const subframe of frame.childFrames())
|
||||
collect(subframe);
|
||||
}
|
||||
}
|
||||
|
||||
_onNavigationStarted(params) {
|
||||
}
|
||||
|
||||
_onNavigationAborted(params) {
|
||||
const frame = this._frames.get(params.frameId);
|
||||
frame._onAbortedNewDocumentNavigation(params.navigationId, params.errorText);
|
||||
const frame = this._page._frameManager.frame(params.frameId);
|
||||
for (const watcher of this._page._frameManager._lifecycleWatchers)
|
||||
watcher._onAbortedNewDocumentNavigation(frame, params.navigationId, params.errorText);
|
||||
}
|
||||
|
||||
_onNavigationCommitted(params) {
|
||||
const frame = this._frames.get(params.frameId);
|
||||
frame._onCommittedNewDocumentNavigation(params.url, params.name, params.navigationId, false);
|
||||
this._page.emit(Events.Page.FrameNavigated, frame);
|
||||
_onNavigationCommitted(params: Protocol.Page.navigationCommittedPayload) {
|
||||
this._page._frameManager.frameCommittedNewDocumentNavigation(params.frameId, params.url, params.name || '', params.navigationId, false);
|
||||
}
|
||||
|
||||
_onSameDocumentNavigation(params) {
|
||||
const frame = this._frames.get(params.frameId);
|
||||
frame._onCommittedSameDocumentNavigation(params.url);
|
||||
this._page.emit(Events.Page.FrameNavigated, frame);
|
||||
_onSameDocumentNavigation(params: Protocol.Page.sameDocumentNavigationPayload) {
|
||||
this._page._frameManager.frameCommittedSameDocumentNavigation(params.frameId, params.url);
|
||||
}
|
||||
|
||||
_onFrameAttached(params) {
|
||||
const parentFrame = this._frames.get(params.parentFrameId) || null;
|
||||
const frame = new frames.Frame(this._page, params.frameId, parentFrame);
|
||||
if (!parentFrame) {
|
||||
assert(!this._mainFrame, 'INTERNAL ERROR: re-attaching main frame!');
|
||||
this._mainFrame = frame;
|
||||
}
|
||||
this._frames.set(params.frameId, frame);
|
||||
this._page.emit(Events.Page.FrameAttached, frame);
|
||||
_onFrameAttached(params: Protocol.Page.frameAttachedPayload) {
|
||||
this._page._frameManager.frameAttached(params.frameId, params.parentFrameId);
|
||||
}
|
||||
|
||||
_onFrameDetached(params) {
|
||||
const frame = this._frames.get(params.frameId);
|
||||
this._frames.delete(params.frameId);
|
||||
frame._onDetached();
|
||||
this._page.emit(Events.Page.FrameDetached, frame);
|
||||
_onFrameDetached(params: Protocol.Page.frameDetachedPayload) {
|
||||
this._page._frameManager.frameDetached(params.frameId);
|
||||
}
|
||||
|
||||
_onEventFired({frameId, name}) {
|
||||
const frame = this._frames.get(frameId);
|
||||
if (name === 'load') {
|
||||
frame._lifecycleEvent('load');
|
||||
if (frame === this._mainFrame)
|
||||
this._page.emit(Events.Page.Load);
|
||||
}
|
||||
if (name === 'DOMContentLoaded') {
|
||||
frame._lifecycleEvent('domcontentloaded');
|
||||
if (frame === this._mainFrame)
|
||||
this._page.emit(Events.Page.DOMContentLoaded);
|
||||
}
|
||||
if (name === 'load')
|
||||
this._page._frameManager.frameLifecycleEvent(frameId, 'load');
|
||||
if (name === 'DOMContentLoaded')
|
||||
this._page._frameManager.frameLifecycleEvent(frameId, 'domcontentloaded');
|
||||
}
|
||||
|
||||
_onUncaughtError(params) {
|
||||
@ -223,7 +179,7 @@ export class FrameManager extends EventEmitter implements PageDelegate {
|
||||
async exposeBinding(name: string, bindingFunction: string): Promise<void> {
|
||||
await this._session.send('Page.addBinding', {name: name});
|
||||
await this._session.send('Page.addScriptToEvaluateOnNewDocument', {script: bindingFunction});
|
||||
await Promise.all(this.frames().map(frame => frame.evaluate(bindingFunction).catch(debugError)));
|
||||
await Promise.all(this._page.frames().map(frame => frame.evaluate(bindingFunction).catch(debugError)));
|
||||
}
|
||||
|
||||
didClose() {
|
||||
@ -340,7 +296,7 @@ export class FrameManager extends EventEmitter implements PageDelegate {
|
||||
timeout = this._page._timeoutSettings.navigationTimeout(),
|
||||
waitUntil = (['load'] as frames.LifecycleEvent[]),
|
||||
} = options;
|
||||
const frame = this.mainFrame();
|
||||
const frame = this._page.mainFrame();
|
||||
const watcher = new frames.LifecycleWatcher(frame, waitUntil, timeout);
|
||||
const { navigationId } = await action();
|
||||
if (navigationId === null) {
|
||||
@ -360,15 +316,15 @@ export class FrameManager extends EventEmitter implements PageDelegate {
|
||||
}
|
||||
|
||||
reload(options?: frames.NavigateOptions): Promise<network.Response | null> {
|
||||
return this._go(() => this._session.send('Page.reload', { frameId: this.mainFrame()._id }), options);
|
||||
return this._go(() => this._session.send('Page.reload', { frameId: this._page.mainFrame()._id }), options);
|
||||
}
|
||||
|
||||
goBack(options?: frames.NavigateOptions): Promise<network.Response | null> {
|
||||
return this._go(() => this._session.send('Page.goBack', { frameId: this.mainFrame()._id }), options);
|
||||
return this._go(() => this._session.send('Page.goBack', { frameId: this._page.mainFrame()._id }), options);
|
||||
}
|
||||
|
||||
goForward(options?: frames.NavigateOptions): Promise<network.Response | null> {
|
||||
return this._go(() => this._session.send('Page.goForward', { frameId: this.mainFrame()._id }), options);
|
||||
return this._go(() => this._session.send('Page.goForward', { frameId: this._page.mainFrame()._id }), options);
|
||||
}
|
||||
|
||||
async evaluateOnNewDocument(source: string): Promise<void> {
|
||||
@ -416,7 +372,7 @@ export class FrameManager extends EventEmitter implements PageDelegate {
|
||||
});
|
||||
if (!frameId)
|
||||
return null;
|
||||
return this.frame(frameId);
|
||||
return this._page._frameManager.frame(frameId);
|
||||
}
|
||||
|
||||
isElementHandle(remoteObject: any): boolean {
|
||||
|
@ -18,7 +18,7 @@
|
||||
import { EventEmitter } from 'events';
|
||||
import { assert, debugError, helper, RegisteredListener } from '../helper';
|
||||
import { JugglerSession } from './Connection';
|
||||
import { FrameManager } from './FrameManager';
|
||||
import { Page } from '../page';
|
||||
import * as network from '../network';
|
||||
import * as frames from '../frames';
|
||||
|
||||
@ -32,15 +32,15 @@ export const NetworkManagerEvents = {
|
||||
export class NetworkManager extends EventEmitter {
|
||||
private _session: JugglerSession;
|
||||
private _requests: Map<string, InterceptableRequest>;
|
||||
private _frameManager: FrameManager;
|
||||
private _page: Page;
|
||||
private _eventListeners: RegisteredListener[];
|
||||
|
||||
constructor(session: JugglerSession, frameManager: FrameManager) {
|
||||
constructor(session: JugglerSession, page: Page) {
|
||||
super();
|
||||
this._session = session;
|
||||
|
||||
this._requests = new Map();
|
||||
this._frameManager = frameManager;
|
||||
this._page = page;
|
||||
|
||||
this._eventListeners = [
|
||||
helper.addEventListener(session, 'Network.requestWillBeSent', this._onRequestWillBeSent.bind(this)),
|
||||
@ -69,7 +69,7 @@ export class NetworkManager extends EventEmitter {
|
||||
|
||||
_onRequestWillBeSent(event) {
|
||||
const redirected = event.redirectedFrom ? this._requests.get(event.redirectedFrom) : null;
|
||||
const frame = redirected ? redirected.request.frame() : (this._frameManager && event.frameId ? this._frameManager.frame(event.frameId) : null);
|
||||
const frame = redirected ? redirected.request.frame() : (event.frameId ? this._page._frameManager.frame(event.frameId) : null);
|
||||
if (!frame)
|
||||
return;
|
||||
let redirectChain: network.Request[] = [];
|
||||
|
172
src/frames.ts
172
src/frames.ts
@ -50,17 +50,144 @@ export type LifecycleEvent = 'load' | 'domcontentloaded';
|
||||
|
||||
export type WaitForOptions = types.TimeoutOptions & { waitFor?: boolean };
|
||||
|
||||
export class FrameManager {
|
||||
private _page: Page;
|
||||
private _frames = new Map<string, Frame>();
|
||||
private _mainFrame: Frame;
|
||||
readonly _lifecycleWatchers = new Set<LifecycleWatcher>();
|
||||
|
||||
constructor(page: Page) {
|
||||
this._page = page;
|
||||
}
|
||||
|
||||
mainFrame(): Frame {
|
||||
return this._mainFrame;
|
||||
}
|
||||
|
||||
frames() {
|
||||
const frames: Frame[] = [];
|
||||
collect(this._mainFrame);
|
||||
return frames;
|
||||
|
||||
function collect(frame: Frame) {
|
||||
frames.push(frame);
|
||||
for (const subframe of frame.childFrames())
|
||||
collect(subframe);
|
||||
}
|
||||
}
|
||||
|
||||
frame(frameId: string): Frame | null {
|
||||
return this._frames.get(frameId) || null;
|
||||
}
|
||||
|
||||
frameAttached(frameId: string, parentFrameId: string | null | undefined): Frame {
|
||||
const parentFrame = parentFrameId ? this._frames.get(parentFrameId) : null;
|
||||
if (!parentFrame) {
|
||||
if (this._mainFrame) {
|
||||
// Update frame id to retain frame identity on cross-process navigation.
|
||||
this._frames.delete(this._mainFrame._id);
|
||||
this._mainFrame._id = frameId;
|
||||
} else {
|
||||
assert(!this._frames.has(frameId));
|
||||
this._mainFrame = new Frame(this._page, frameId, parentFrame);
|
||||
}
|
||||
this._frames.set(frameId, this._mainFrame);
|
||||
return this._mainFrame;
|
||||
} else {
|
||||
assert(!this._frames.has(frameId));
|
||||
const frame = new Frame(this._page, frameId, parentFrame);
|
||||
this._frames.set(frameId, frame);
|
||||
this._page.emit(Events.Page.FrameAttached, frame);
|
||||
return frame;
|
||||
}
|
||||
}
|
||||
|
||||
frameCommittedNewDocumentNavigation(frameId: string, url: string, name: string, documentId: string, initial: boolean) {
|
||||
const frame = this._frames.get(frameId);
|
||||
for (const child of frame.childFrames())
|
||||
this._removeFramesRecursively(child);
|
||||
frame._url = url;
|
||||
frame._name = name;
|
||||
frame._lastDocumentId = documentId;
|
||||
frame._firedLifecycleEvents.clear();
|
||||
if (!initial) {
|
||||
for (const watcher of this._lifecycleWatchers)
|
||||
watcher._onCommittedNewDocumentNavigation(frame);
|
||||
}
|
||||
this._page.emit(Events.Page.FrameNavigated, frame);
|
||||
}
|
||||
|
||||
frameCommittedSameDocumentNavigation(frameId: string, url: string) {
|
||||
const frame = this._frames.get(frameId);
|
||||
if (!frame)
|
||||
return;
|
||||
frame._url = url;
|
||||
for (const watcher of this._lifecycleWatchers)
|
||||
watcher._onNavigatedWithinDocument(frame);
|
||||
this._page.emit(Events.Page.FrameNavigated, frame);
|
||||
}
|
||||
|
||||
frameDetached(frameId: string) {
|
||||
const frame = this._frames.get(frameId);
|
||||
if (frame)
|
||||
this._removeFramesRecursively(frame);
|
||||
}
|
||||
|
||||
frameStoppedLoading(frameId: string) {
|
||||
const frame = this._frames.get(frameId);
|
||||
if (!frame)
|
||||
return;
|
||||
const hasDOMContentLoaded = frame._firedLifecycleEvents.has('domcontentloaded');
|
||||
const hasLoad = frame._firedLifecycleEvents.has('load');
|
||||
frame._firedLifecycleEvents.add('domcontentloaded');
|
||||
frame._firedLifecycleEvents.add('load');
|
||||
for (const watcher of this._lifecycleWatchers)
|
||||
watcher._onLifecycleEvent(frame);
|
||||
if (frame === this.mainFrame() && !hasDOMContentLoaded)
|
||||
this._page.emit(Events.Page.DOMContentLoaded);
|
||||
if (frame === this.mainFrame() && !hasLoad)
|
||||
this._page.emit(Events.Page.Load);
|
||||
}
|
||||
|
||||
frameLifecycleEvent(frameId: string, event: LifecycleEvent | 'clear') {
|
||||
const frame = this._frames.get(frameId);
|
||||
if (!frame)
|
||||
return;
|
||||
if (event === 'clear') {
|
||||
frame._firedLifecycleEvents.clear();
|
||||
} else {
|
||||
frame._firedLifecycleEvents.add(event);
|
||||
for (const watcher of this._lifecycleWatchers)
|
||||
watcher._onLifecycleEvent(frame);
|
||||
}
|
||||
if (frame === this._mainFrame && event === 'load')
|
||||
this._page.emit(Events.Page.Load);
|
||||
if (frame === this._mainFrame && event === 'domcontentloaded')
|
||||
this._page.emit(Events.Page.DOMContentLoaded);
|
||||
}
|
||||
|
||||
private _removeFramesRecursively(frame: Frame) {
|
||||
for (const child of frame.childFrames())
|
||||
this._removeFramesRecursively(child);
|
||||
frame._onDetached();
|
||||
this._frames.delete(frame._id);
|
||||
for (const watcher of this._lifecycleWatchers)
|
||||
watcher._onFrameDetached(frame);
|
||||
this._page.emit(Events.Page.FrameDetached, frame);
|
||||
}
|
||||
}
|
||||
|
||||
export class Frame {
|
||||
_id: string;
|
||||
readonly _firedLifecycleEvents: Set<LifecycleEvent>;
|
||||
_lastDocumentId: string;
|
||||
readonly _page: Page;
|
||||
private _parentFrame: Frame;
|
||||
private _url = '';
|
||||
_url = '';
|
||||
private _detached = false;
|
||||
private _contextData = new Map<ContextType, ContextData>();
|
||||
private _childFrames = new Set<Frame>();
|
||||
private _name: string;
|
||||
_name: string;
|
||||
|
||||
constructor(page: Page, id: string, parentFrame: Frame | null) {
|
||||
this._id = id;
|
||||
@ -387,7 +514,7 @@ export class Frame {
|
||||
handle = await this._waitForSelectorInUtilityContext(selector, options);
|
||||
} else {
|
||||
const context = await this._utilityContext();
|
||||
handle = await context._$(types.clearSelector(selector));
|
||||
handle = await context._$(types.clearSelector(selector));
|
||||
}
|
||||
assert(handle, 'No node found for selector: ' + types.selectorToString(selector));
|
||||
return handle;
|
||||
@ -431,39 +558,6 @@ export class Frame {
|
||||
return context.evaluate(() => document.title);
|
||||
}
|
||||
|
||||
_onNavigationRequest(request: network.Request) {
|
||||
for (const watcher of this._page._lifecycleWatchers)
|
||||
watcher._onNavigationRequest(this, request);
|
||||
}
|
||||
|
||||
_onAbortedNewDocumentNavigation(documentId: string, errorText: string) {
|
||||
for (const watcher of this._page._lifecycleWatchers)
|
||||
watcher._onAbortedNewDocumentNavigation(this, documentId, errorText);
|
||||
}
|
||||
|
||||
_onCommittedNewDocumentNavigation(url: string, name: string, documentId: string, initial: boolean) {
|
||||
this._url = url;
|
||||
this._name = name;
|
||||
this._lastDocumentId = documentId;
|
||||
this._firedLifecycleEvents.clear();
|
||||
if (!initial) {
|
||||
for (const watcher of this._page._lifecycleWatchers)
|
||||
watcher._onCommittedNewDocumentNavigation(this);
|
||||
}
|
||||
}
|
||||
|
||||
_onCommittedSameDocumentNavigation(url: string) {
|
||||
this._url = url;
|
||||
for (const watcher of this._page._lifecycleWatchers)
|
||||
watcher._onNavigatedWithinDocument(this);
|
||||
}
|
||||
|
||||
_lifecycleEvent(event: LifecycleEvent) {
|
||||
this._firedLifecycleEvents.add(event);
|
||||
for (const watcher of this._page._lifecycleWatchers)
|
||||
watcher._onLifecycleEvent(this);
|
||||
}
|
||||
|
||||
_onDetached() {
|
||||
this._detached = true;
|
||||
for (const data of this._contextData.values()) {
|
||||
@ -473,8 +567,6 @@ export class Frame {
|
||||
if (this._parentFrame)
|
||||
this._parentFrame._childFrames.delete(this);
|
||||
this._parentFrame = null;
|
||||
for (const watcher of this._page._lifecycleWatchers)
|
||||
watcher._onFrameDetached(this);
|
||||
}
|
||||
|
||||
private _scheduleRerunnableTask(task: dom.Task, contextType: ContextType, timeout?: number, title?: string): Promise<js.JSHandle> {
|
||||
@ -634,7 +726,7 @@ export class LifecycleWatcher {
|
||||
new Promise<Error>(f => this._navigationAbortedCallback = f),
|
||||
this._frame._page._disconnectedPromise.then(() => new Error('Navigation failed because browser has disconnected!')),
|
||||
]);
|
||||
frame._page._lifecycleWatchers.add(this);
|
||||
frame._page._frameManager._lifecycleWatchers.add(this);
|
||||
this._checkLifecycleComplete();
|
||||
}
|
||||
|
||||
@ -718,7 +810,7 @@ export class LifecycleWatcher {
|
||||
}
|
||||
|
||||
dispose() {
|
||||
this._frame._page._lifecycleWatchers.delete(this);
|
||||
this._frame._page._frameManager._lifecycleWatchers.delete(this);
|
||||
clearTimeout(this._maximumTimer);
|
||||
}
|
||||
}
|
||||
|
@ -101,19 +101,23 @@ export class Request {
|
||||
this._headers = headers;
|
||||
this._waitForResponsePromise = new Promise(f => this._waitForResponsePromiseCallback = f);
|
||||
this._waitForFinishedPromise = new Promise(f => this._waitForFinishedPromiseCallback = f);
|
||||
if (documentId && frame)
|
||||
frame._onNavigationRequest(this);
|
||||
if (documentId && frame) {
|
||||
for (const watcher of frame._page._frameManager._lifecycleWatchers)
|
||||
watcher._onNavigationRequest(frame, this);
|
||||
}
|
||||
}
|
||||
|
||||
_setFailureText(failureText: string, canceled: boolean) {
|
||||
this._failureText = failureText;
|
||||
if (this._documentId && this._frame) {
|
||||
const isCurrentDocument = this._frame._lastDocumentId === this._documentId;
|
||||
let errorText = failureText;
|
||||
if (canceled)
|
||||
errorText += '; maybe frame was detached?';
|
||||
if (!isCurrentDocument)
|
||||
this._frame._onAbortedNewDocumentNavigation(this._documentId, errorText);
|
||||
if (!isCurrentDocument) {
|
||||
let errorText = failureText;
|
||||
if (canceled)
|
||||
errorText += '; maybe frame was detached?';
|
||||
for (const watcher of this._frame._page._frameManager._lifecycleWatchers)
|
||||
watcher._onAbortedNewDocumentNavigation(this._frame, this._documentId, errorText);
|
||||
}
|
||||
}
|
||||
this._waitForFinishedPromiseCallback();
|
||||
}
|
||||
|
@ -43,8 +43,6 @@ export interface PageDelegate {
|
||||
// TODO: reverse didClose call sequence.
|
||||
didClose(): void;
|
||||
|
||||
mainFrame(): frames.Frame;
|
||||
frames(): frames.Frame[];
|
||||
navigateFrame(frame: frames.Frame, url: string, options?: frames.GotoOptions): Promise<network.Response | null>;
|
||||
waitForFrameNavigation(frame: frames.Frame, options?: frames.NavigateOptions): Promise<network.Response | null>;
|
||||
setFrameContent(frame: frames.Frame, html: string, options?: frames.NavigateOptions): Promise<void>;
|
||||
@ -104,7 +102,7 @@ export class Page extends EventEmitter {
|
||||
private _pageBindings = new Map<string, Function>();
|
||||
readonly _screenshotter: Screenshotter;
|
||||
private _fileChooserInterceptors = new Set<(chooser: FileChooser) => void>();
|
||||
readonly _lifecycleWatchers = new Set<frames.LifecycleWatcher>();
|
||||
readonly _frameManager: frames.FrameManager;
|
||||
|
||||
constructor(delegate: PageDelegate, browserContext: BrowserContext) {
|
||||
super();
|
||||
@ -126,6 +124,7 @@ export class Page extends EventEmitter {
|
||||
this.mouse = new input.Mouse(delegate.rawMouse, this.keyboard);
|
||||
this._timeoutSettings = new TimeoutSettings();
|
||||
this._screenshotter = new Screenshotter(this);
|
||||
this._frameManager = new frames.FrameManager(this);
|
||||
}
|
||||
|
||||
_didClose() {
|
||||
@ -178,11 +177,11 @@ export class Page extends EventEmitter {
|
||||
}
|
||||
|
||||
mainFrame(): frames.Frame {
|
||||
return this._delegate.mainFrame();
|
||||
return this._frameManager.mainFrame();
|
||||
}
|
||||
|
||||
frames(): frames.Frame[] {
|
||||
return this._delegate.frames();
|
||||
return this._frameManager.frames();
|
||||
}
|
||||
|
||||
setDefaultNavigationTimeout(timeout: number) {
|
||||
|
@ -45,22 +45,19 @@ export class FrameManager extends EventEmitter implements PageDelegate {
|
||||
_session: TargetSession;
|
||||
readonly _page: Page;
|
||||
private readonly _networkManager: NetworkManager;
|
||||
private readonly _frames: Map<string, frames.Frame>;
|
||||
private readonly _contextIdToContext: Map<number, js.ExecutionContext>;
|
||||
private _isolatedWorlds: Set<string>;
|
||||
private _sessionListeners: RegisteredListener[] = [];
|
||||
private _mainFrame: frames.Frame;
|
||||
private readonly _bootstrapScripts: string[] = [];
|
||||
|
||||
constructor(browserContext: BrowserContext) {
|
||||
super();
|
||||
this.rawKeyboard = new RawKeyboardImpl();
|
||||
this.rawMouse = new RawMouseImpl();
|
||||
this._networkManager = new NetworkManager(this);
|
||||
this._frames = new Map();
|
||||
this._contextIdToContext = new Map();
|
||||
this._isolatedWorlds = new Set();
|
||||
this._page = new Page(this, browserContext);
|
||||
this._networkManager = new NetworkManager(this._page);
|
||||
this._networkManager.on(NetworkManagerEvents.Request, event => this._page.emit(Events.Page.Request, event));
|
||||
this._networkManager.on(NetworkManagerEvents.Response, event => this._page.emit(Events.Page.Response, event));
|
||||
this._networkManager.on(NetworkManagerEvents.RequestFailed, event => this._page.emit(Events.Page.RequestFailed, event));
|
||||
@ -142,30 +139,11 @@ export class FrameManager extends EventEmitter implements PageDelegate {
|
||||
}
|
||||
|
||||
_onFrameStoppedLoading(frameId: string) {
|
||||
const frame = this._frames.get(frameId);
|
||||
if (!frame)
|
||||
return;
|
||||
const hasDOMContentLoaded = frame._firedLifecycleEvents.has('domcontentloaded');
|
||||
const hasLoad = frame._firedLifecycleEvents.has('load');
|
||||
frame._lifecycleEvent('domcontentloaded');
|
||||
frame._lifecycleEvent('load');
|
||||
if (frame === this.mainFrame() && !hasDOMContentLoaded)
|
||||
this._page.emit(Events.Page.DOMContentLoaded);
|
||||
if (frame === this.mainFrame() && !hasLoad)
|
||||
this._page.emit(Events.Page.Load);
|
||||
this._page._frameManager.frameStoppedLoading(frameId);
|
||||
}
|
||||
|
||||
_onLifecycleEvent(frameId: string, event: frames.LifecycleEvent) {
|
||||
const frame = this._frames.get(frameId);
|
||||
if (!frame)
|
||||
return;
|
||||
frame._lifecycleEvent(event);
|
||||
if (frame === this.mainFrame()) {
|
||||
if (event === 'load')
|
||||
this._page.emit(Events.Page.Load);
|
||||
if (event === 'domcontentloaded')
|
||||
this._page.emit(Events.Page.DOMContentLoaded);
|
||||
}
|
||||
this._page._frameManager.frameLifecycleEvent(frameId, event);
|
||||
}
|
||||
|
||||
_handleFrameTree(frameTree: Protocol.Page.FrameResourceTree) {
|
||||
@ -178,47 +156,12 @@ export class FrameManager extends EventEmitter implements PageDelegate {
|
||||
this._handleFrameTree(child);
|
||||
}
|
||||
|
||||
page(): Page {
|
||||
return this._page;
|
||||
}
|
||||
|
||||
mainFrame(): frames.Frame {
|
||||
return this._mainFrame;
|
||||
}
|
||||
|
||||
frames(): Array<frames.Frame> {
|
||||
return Array.from(this._frames.values());
|
||||
}
|
||||
|
||||
frame(frameId: string): frames.Frame | null {
|
||||
return this._frames.get(frameId) || null;
|
||||
}
|
||||
|
||||
_onFrameAttached(frameId: string, parentFrameId: string | null) {
|
||||
assert(!this._frames.has(frameId));
|
||||
const parentFrame = parentFrameId ? this._frames.get(parentFrameId) : null;
|
||||
const frame = new frames.Frame(this._page, frameId, parentFrame);
|
||||
this._frames.set(frameId, frame);
|
||||
if (!parentFrame)
|
||||
this._mainFrame = frame;
|
||||
this._page.emit(Events.Page.FrameAttached, frame);
|
||||
return frame;
|
||||
this._page._frameManager.frameAttached(frameId, parentFrameId);
|
||||
}
|
||||
|
||||
_onFrameNavigated(framePayload: Protocol.Page.Frame, initial: boolean) {
|
||||
const isMainFrame = !framePayload.parentId;
|
||||
const frame = isMainFrame ? this._mainFrame : this._frames.get(framePayload.id);
|
||||
|
||||
// Detach all child frames first.
|
||||
for (const child of frame.childFrames())
|
||||
this._removeFramesRecursively(child);
|
||||
if (isMainFrame) {
|
||||
// Update frame id to retain frame identity on cross-process navigation.
|
||||
this._frames.delete(frame._id);
|
||||
frame._id = framePayload.id;
|
||||
this._frames.set(framePayload.id, frame);
|
||||
}
|
||||
|
||||
const frame = this._page._frameManager.frame(framePayload.id);
|
||||
for (const context of this._contextIdToContext.values()) {
|
||||
if (context.frame() === frame) {
|
||||
const delegate = context._delegate as ExecutionContextDelegate;
|
||||
@ -227,26 +170,17 @@ export class FrameManager extends EventEmitter implements PageDelegate {
|
||||
frame._contextDestroyed(context as dom.FrameExecutionContext);
|
||||
}
|
||||
}
|
||||
|
||||
// Append session id to avoid cross-process loaderId clash.
|
||||
const documentId = this._session._sessionId + '::' + framePayload.loaderId;
|
||||
frame._onCommittedNewDocumentNavigation(framePayload.url, framePayload.name, documentId, initial);
|
||||
|
||||
this._page.emit(Events.Page.FrameNavigated, frame);
|
||||
this._page._frameManager.frameCommittedNewDocumentNavigation(framePayload.id, framePayload.url, framePayload.name || '', documentId, initial);
|
||||
}
|
||||
|
||||
_onFrameNavigatedWithinDocument(frameId: string, url: string) {
|
||||
const frame = this._frames.get(frameId);
|
||||
if (!frame)
|
||||
return;
|
||||
frame._onCommittedSameDocumentNavigation(url);
|
||||
this._page.emit(Events.Page.FrameNavigated, frame);
|
||||
this._page._frameManager.frameCommittedSameDocumentNavigation(frameId, url);
|
||||
}
|
||||
|
||||
_onFrameDetached(frameId: string) {
|
||||
const frame = this._frames.get(frameId);
|
||||
if (frame)
|
||||
this._removeFramesRecursively(frame);
|
||||
this._page._frameManager.frameDetached(frameId);
|
||||
}
|
||||
|
||||
_onExecutionContextCreated(contextPayload : Protocol.Runtime.ExecutionContextDescription) {
|
||||
@ -255,7 +189,7 @@ export class FrameManager extends EventEmitter implements PageDelegate {
|
||||
const frameId = contextPayload.frameId;
|
||||
// If the frame was attached manually there is no navigation event.
|
||||
// FIXME: support frameAttached event in WebKit protocol.
|
||||
const frame = this._frames.get(frameId) || null;
|
||||
const frame = this._page._frameManager.frame(frameId);
|
||||
if (!frame)
|
||||
return;
|
||||
const delegate = new ExecutionContextDelegate(this._session, contextPayload);
|
||||
@ -277,14 +211,6 @@ export class FrameManager extends EventEmitter implements PageDelegate {
|
||||
return context;
|
||||
}
|
||||
|
||||
_removeFramesRecursively(frame: frames.Frame) {
|
||||
for (const child of frame.childFrames())
|
||||
this._removeFramesRecursively(child);
|
||||
frame._onDetached();
|
||||
this._frames.delete(frame._id);
|
||||
this._page.emit(Events.Page.FrameDetached, frame);
|
||||
}
|
||||
|
||||
async navigateFrame(frame: frames.Frame, url: string, options: frames.GotoOptions = {}): Promise<network.Response | null> {
|
||||
const {
|
||||
timeout = this._page._timeoutSettings.navigationTimeout(),
|
||||
@ -355,7 +281,7 @@ export class FrameManager extends EventEmitter implements PageDelegate {
|
||||
else if (type === 'timing')
|
||||
derivedType = 'timeEnd';
|
||||
|
||||
const mainFrameContext = await this.mainFrame().executionContext();
|
||||
const mainFrameContext = await this._page.mainFrame().executionContext();
|
||||
const handles = (parameters || []).map(p => {
|
||||
let context: js.ExecutionContext | null = null;
|
||||
if (p.objectId) {
|
||||
@ -380,7 +306,7 @@ export class FrameManager extends EventEmitter implements PageDelegate {
|
||||
}
|
||||
|
||||
async _onFileChooserOpened(event: {frameId: Protocol.Network.FrameId, element: Protocol.Runtime.RemoteObject}) {
|
||||
const context = await this.frame(event.frameId)._mainContext();
|
||||
const context = await this._page._frameManager.frame(event.frameId)._mainContext();
|
||||
const handle = context._createHandle(event.element).asElement()!;
|
||||
this._page._onFileChooserOpened(handle);
|
||||
}
|
||||
@ -486,7 +412,7 @@ export class FrameManager extends EventEmitter implements PageDelegate {
|
||||
this._bootstrapScripts.unshift(script);
|
||||
const source = this._bootstrapScripts.join(';');
|
||||
await this._session.send('Page.setBootstrapScript', { source });
|
||||
await Promise.all(this.frames().map(frame => frame.evaluate(script).catch(debugError)));
|
||||
await Promise.all(this._page.frames().map(frame => frame.evaluate(script).catch(debugError)));
|
||||
}
|
||||
|
||||
async evaluateOnNewDocument(script: string): Promise<void> {
|
||||
|
@ -17,7 +17,7 @@
|
||||
|
||||
import { EventEmitter } from 'events';
|
||||
import { TargetSession } from './Connection';
|
||||
import { FrameManager } from './FrameManager';
|
||||
import { Page } from '../page';
|
||||
import { assert, helper, RegisteredListener } from '../helper';
|
||||
import { Protocol } from './protocol';
|
||||
import * as network from '../network';
|
||||
@ -32,16 +32,16 @@ export const NetworkManagerEvents = {
|
||||
|
||||
export class NetworkManager extends EventEmitter {
|
||||
private _session: TargetSession;
|
||||
private _frameManager: FrameManager;
|
||||
private _page: Page;
|
||||
private _requestIdToRequest = new Map<string, InterceptableRequest>();
|
||||
private _extraHTTPHeaders: network.Headers = {};
|
||||
private _attemptedAuthentications = new Set<string>();
|
||||
private _userCacheDisabled = false;
|
||||
private _sessionListeners: RegisteredListener[] = [];
|
||||
|
||||
constructor(frameManager: FrameManager) {
|
||||
constructor(page: Page) {
|
||||
super();
|
||||
this._frameManager = frameManager;
|
||||
this._page = page;
|
||||
}
|
||||
|
||||
setSession(session: TargetSession) {
|
||||
@ -97,7 +97,7 @@ export class NetworkManager extends EventEmitter {
|
||||
redirectChain = request.request._redirectChain;
|
||||
}
|
||||
}
|
||||
const frame = this._frameManager.frame(event.frameId);
|
||||
const frame = this._page._frameManager.frame(event.frameId);
|
||||
// TODO(einbinder) this will fail if we are an XHR document request
|
||||
const isNavigationRequest = event.type === 'Document';
|
||||
const documentId = isNavigationRequest ? this._session._sessionId + '::' + event.loaderId : undefined;
|
||||
|
Loading…
Reference in New Issue
Block a user