diff --git a/src/chromium/ExecutionContext.ts b/src/chromium/ExecutionContext.ts index 446df6cdd2..b719a15b92 100644 --- a/src/chromium/ExecutionContext.ts +++ b/src/chromium/ExecutionContext.ts @@ -26,9 +26,6 @@ import * as dom from '../dom'; export const EVALUATION_SCRIPT_URL = '__playwright_evaluation_script__'; const SOURCE_URL_REGEX = /^[\040\t]*\/\/[@#] sourceURL=\s*(\S*?)\s*$/m; -export type ExecutionContext = js.ExecutionContext; -export type JSHandle = js.JSHandle; - export class ExecutionContextDelegate implements js.ExecutionContextDelegate { _client: CDPSession; _contextId: number; @@ -38,7 +35,7 @@ export class ExecutionContextDelegate implements js.ExecutionContextDelegate { this._contextId = contextPayload.id; } - async evaluate(context: ExecutionContext, returnByValue: boolean, pageFunction: Function | string, ...args: any[]): Promise { + async evaluate(context: js.ExecutionContext, returnByValue: boolean, pageFunction: Function | string, ...args: any[]): Promise { const suffix = `//# sourceURL=${EVALUATION_SCRIPT_URL}`; if (helper.isString(pageFunction)) { @@ -136,7 +133,7 @@ export class ExecutionContextDelegate implements js.ExecutionContextDelegate { } } - async adoptBackendNodeId(context: ExecutionContext, backendNodeId: Protocol.DOM.BackendNodeId) { + async adoptBackendNodeId(context: js.ExecutionContext, backendNodeId: Protocol.DOM.BackendNodeId) { const {object} = await this._client.send('DOM.resolveNode', { backendNodeId, executionContextId: this._contextId, @@ -144,7 +141,7 @@ export class ExecutionContextDelegate implements js.ExecutionContextDelegate { return createJSHandle(context, object) as dom.ElementHandle; } - async getProperties(handle: JSHandle): Promise> { + async getProperties(handle: js.JSHandle): Promise> { const response = await this._client.send('Runtime.getProperties', { objectId: toRemoteObject(handle).objectId, ownProperties: true @@ -158,11 +155,11 @@ export class ExecutionContextDelegate implements js.ExecutionContextDelegate { return result; } - async releaseHandle(handle: JSHandle): Promise { + async releaseHandle(handle: js.JSHandle): Promise { await releaseObject(this._client, toRemoteObject(handle)); } - async handleJSONValue(handle: JSHandle): Promise { + async handleJSONValue(handle: js.JSHandle): Promise { const remoteObject = toRemoteObject(handle); if (remoteObject.objectId) { const response = await this._client.send('Runtime.callFunctionOn', { @@ -176,7 +173,7 @@ export class ExecutionContextDelegate implements js.ExecutionContextDelegate { return valueFromRemoteObject(remoteObject); } - handleToString(handle: JSHandle): string { + handleToString(handle: js.JSHandle): string { const object = toRemoteObject(handle); if (object.objectId) { const type = object.subtype || object.type; @@ -188,10 +185,10 @@ export class ExecutionContextDelegate implements js.ExecutionContextDelegate { const remoteObjectSymbol = Symbol('RemoteObject'); -export function toRemoteObject(handle: JSHandle): Protocol.Runtime.RemoteObject { +export function toRemoteObject(handle: js.JSHandle): Protocol.Runtime.RemoteObject { return (handle as any)[remoteObjectSymbol]; } -export function markJSHandle(handle: JSHandle, remoteObject: Protocol.Runtime.RemoteObject) { +export function markJSHandle(handle: js.JSHandle, remoteObject: Protocol.Runtime.RemoteObject) { (handle as any)[remoteObjectSymbol] = remoteObject; } diff --git a/src/chromium/FrameManager.ts b/src/chromium/FrameManager.ts index 64f06f53fb..208f94de60 100644 --- a/src/chromium/FrameManager.ts +++ b/src/chromium/FrameManager.ts @@ -20,11 +20,12 @@ import * as frames from '../frames'; import { assert, debugError } from '../helper'; import * as js from '../javascript'; import * as dom from '../dom'; +import * as network from '../network'; import { TimeoutSettings } from '../TimeoutSettings'; import { CDPSession } from './Connection'; -import { EVALUATION_SCRIPT_URL, ExecutionContext, ExecutionContextDelegate, toRemoteObject } from './ExecutionContext'; +import { EVALUATION_SCRIPT_URL, ExecutionContextDelegate, toRemoteObject } from './ExecutionContext'; import { LifecycleWatcher } from './LifecycleWatcher'; -import { NetworkManager, Response } from './NetworkManager'; +import { NetworkManager } from './NetworkManager'; import { Page } from './Page'; import { Protocol } from './protocol'; @@ -45,17 +46,15 @@ type FrameData = { lifecycleEvents: Set, }; -export type Frame = frames.Frame; - export class FrameManager extends EventEmitter implements frames.FrameDelegate { _client: CDPSession; private _page: Page; private _networkManager: NetworkManager; _timeoutSettings: TimeoutSettings; - private _frames = new Map(); - private _contextIdToContext = new Map(); + private _frames = new Map(); + private _contextIdToContext = new Map(); private _isolatedWorlds = new Set(); - private _mainFrame: Frame; + private _mainFrame: frames.Frame; constructor(client: CDPSession, page: Page, ignoreHTTPSErrors: boolean, timeoutSettings: TimeoutSettings) { super(); @@ -92,14 +91,14 @@ export class FrameManager extends EventEmitter implements frames.FrameDelegate { return this._networkManager; } - _frameData(frame: Frame): FrameData { + _frameData(frame: frames.Frame): FrameData { return (frame as any)[frameDataSymbol]; } async navigateFrame( - frame: Frame, + frame: frames.Frame, url: string, - options: { referer?: string; timeout?: number; waitUntil?: string | string[]; } = {}): Promise { + options: { referer?: string; timeout?: number; waitUntil?: string | string[]; } = {}): Promise { assertNoLegacyNavigationOptions(options); const { referer = this._networkManager.extraHTTPHeaders()['referer'], @@ -136,9 +135,9 @@ export class FrameManager extends EventEmitter implements frames.FrameDelegate { } async waitForFrameNavigation( - frame: Frame, + frame: frames.Frame, options: { timeout?: number; waitUntil?: string | string[]; } = {} - ): Promise { + ): Promise { assertNoLegacyNavigationOptions(options); const { waitUntil = ['load'], @@ -156,7 +155,7 @@ export class FrameManager extends EventEmitter implements frames.FrameDelegate { return watcher.navigationResponse(); } - async setFrameContent(frame: Frame, html: string, options: frames.NavigateOptions = {}) { + async setFrameContent(frame: frames.Frame, html: string, options: frames.NavigateOptions = {}) { const { waitUntil = ['load'], timeout = this._timeoutSettings.navigationTimeout(), @@ -179,11 +178,7 @@ export class FrameManager extends EventEmitter implements frames.FrameDelegate { throw error; } - timeoutSettings(): TimeoutSettings { - return this._timeoutSettings; - } - - async adoptElementHandle(elementHandle: dom.ElementHandle, context: ExecutionContext): Promise { + async adoptElementHandle(elementHandle: dom.ElementHandle, context: js.ExecutionContext): Promise { const nodeInfo = await this._client.send('DOM.describeNode', { objectId: toRemoteObject(elementHandle).objectId, }); @@ -228,15 +223,15 @@ export class FrameManager extends EventEmitter implements frames.FrameDelegate { return this._page; } - mainFrame(): Frame { + mainFrame(): frames.Frame { return this._mainFrame; } - frames(): Frame[] { + frames(): frames.Frame[] { return Array.from(this._frames.values()); } - frame(frameId: string): Frame | null { + frame(frameId: string): frames.Frame | null { return this._frames.get(frameId) || null; } @@ -245,7 +240,7 @@ export class FrameManager extends EventEmitter implements frames.FrameDelegate { return; assert(parentFrameId); const parentFrame = this._frames.get(parentFrameId); - const frame = new frames.Frame(this, parentFrame); + const frame = new frames.Frame(this, this._timeoutSettings, parentFrame); const data: FrameData = { id: frameId, loaderId: '', @@ -276,7 +271,7 @@ export class FrameManager extends EventEmitter implements frames.FrameDelegate { data.id = framePayload.id; } else { // Initial main frame navigation. - frame = new frames.Frame(this, null); + frame = new frames.Frame(this, this._timeoutSettings, null); const data: FrameData = { id: framePayload.id, loaderId: '', @@ -329,7 +324,7 @@ export class FrameManager extends EventEmitter implements frames.FrameDelegate { const frame = this._frames.get(frameId) || null; if (contextPayload.auxData && contextPayload.auxData['type'] === 'isolated') this._isolatedWorlds.add(contextPayload.name); - const context: ExecutionContext = new js.ExecutionContext(new ExecutionContextDelegate(this._client, contextPayload), frame); + const context: js.ExecutionContext = new js.ExecutionContext(new ExecutionContextDelegate(this._client, contextPayload), frame); if (frame) { if (contextPayload.auxData && !!contextPayload.auxData['isDefault']) frame._contextCreated('main', context); @@ -353,13 +348,13 @@ export class FrameManager extends EventEmitter implements frames.FrameDelegate { this._onExecutionContextDestroyed(contextId); } - executionContextById(contextId: number): ExecutionContext { + executionContextById(contextId: number): js.ExecutionContext { const context = this._contextIdToContext.get(contextId); assert(context, 'INTERNAL ERROR: missing context with id = ' + contextId); return context; } - _removeFramesRecursively(frame: Frame) { + _removeFramesRecursively(frame: frames.Frame) { for (const child of frame.childFrames()) this._removeFramesRecursively(child); frame._detach(); diff --git a/src/chromium/JSHandle.ts b/src/chromium/JSHandle.ts index c5a8943e39..1c27dcb3de 100644 --- a/src/chromium/JSHandle.ts +++ b/src/chromium/JSHandle.ts @@ -19,13 +19,14 @@ import { assert, debugError } from '../helper'; import * as js from '../javascript'; import * as dom from '../dom'; import * as input from '../input'; +import * as types from '../types'; +import * as frames from '../frames'; import { CDPSession } from './Connection'; -import { Frame } from './FrameManager'; import { FrameManager } from './FrameManager'; import { Protocol } from './protocol'; -import { JSHandle, ExecutionContext, ExecutionContextDelegate, markJSHandle, toRemoteObject } from './ExecutionContext'; +import { ExecutionContextDelegate, markJSHandle, toRemoteObject } from './ExecutionContext'; -export function createJSHandle(context: ExecutionContext, remoteObject: Protocol.Runtime.RemoteObject): JSHandle { +export function createJSHandle(context: js.ExecutionContext, remoteObject: Protocol.Runtime.RemoteObject): js.JSHandle { const frame = context.frame(); if (remoteObject.subtype === 'node' && frame) { const frameManager = frame._delegate as FrameManager; @@ -49,7 +50,7 @@ class DOMWorldDelegate implements dom.DOMWorldDelegate { this._frameManager = frameManager; } - async contentFrame(handle: dom.ElementHandle): Promise { + async contentFrame(handle: dom.ElementHandle): Promise { const nodeInfo = await this._client.send('DOM.describeNode', { objectId: toRemoteObject(handle).objectId }); @@ -68,7 +69,7 @@ class DOMWorldDelegate implements dom.DOMWorldDelegate { }).catch(error => debugError(error)); } - async boundingBox(handle: dom.ElementHandle): Promise { + async boundingBox(handle: dom.ElementHandle): Promise { const result = await this._getBoxModel(handle); if (!result) return null; @@ -121,7 +122,7 @@ class DOMWorldDelegate implements dom.DOMWorldDelegate { return imageData; } - async ensurePointerActionPoint(handle: dom.ElementHandle, relativePoint?: dom.Point): Promise { + async ensurePointerActionPoint(handle: dom.ElementHandle, relativePoint?: types.Point): Promise { await handle._scrollIntoViewIfNeeded(); if (!relativePoint) return this._clickablePoint(handle); @@ -142,8 +143,8 @@ class DOMWorldDelegate implements dom.DOMWorldDelegate { return r.point; } - private async _clickablePoint(handle: dom.ElementHandle): Promise { - const fromProtocolQuad = (quad: number[]): dom.Point[] => { + private async _clickablePoint(handle: dom.ElementHandle): Promise { + const fromProtocolQuad = (quad: number[]): types.Point[] => { return [ {x: quad[0], y: quad[1]}, {x: quad[2], y: quad[3]}, @@ -152,14 +153,14 @@ class DOMWorldDelegate implements dom.DOMWorldDelegate { ]; }; - const intersectQuadWithViewport = (quad: dom.Point[], width: number, height: number): dom.Point[] => { + const intersectQuadWithViewport = (quad: types.Point[], width: number, height: number): types.Point[] => { return quad.map(point => ({ x: Math.min(Math.max(point.x, 0), width), y: Math.min(Math.max(point.y, 0), height), })); }; - const computeQuadArea = (quad: dom.Point[]) => { + const computeQuadArea = (quad: types.Point[]) => { // Compute sum of all directed areas of adjacent triangles // https://en.wikipedia.org/wiki/Polygon#Simple_polygons let area = 0; @@ -200,9 +201,9 @@ class DOMWorldDelegate implements dom.DOMWorldDelegate { }; } - async _viewportPointAndScroll(handle: dom.ElementHandle, relativePoint: dom.Point): Promise<{point: dom.Point, scrollX: number, scrollY: number}> { + async _viewportPointAndScroll(handle: dom.ElementHandle, relativePoint: types.Point): Promise<{point: types.Point, scrollX: number, scrollY: number}> { const model = await this._getBoxModel(handle); - let point: dom.Point; + let point: types.Point; if (!model) { point = relativePoint; } else { diff --git a/src/chromium/LifecycleWatcher.ts b/src/chromium/LifecycleWatcher.ts index 93303c324c..0b5cfec9a3 100644 --- a/src/chromium/LifecycleWatcher.ts +++ b/src/chromium/LifecycleWatcher.ts @@ -17,18 +17,19 @@ import { CDPSessionEvents } from './Connection'; import { TimeoutError } from '../Errors'; -import { Frame } from './FrameManager'; import { FrameManager, FrameManagerEvents } from './FrameManager'; import { assert, helper, RegisteredListener } from '../helper'; -import { NetworkManagerEvents, Request, Response } from './NetworkManager'; +import { NetworkManagerEvents } from './NetworkManager'; +import * as frames from '../frames'; +import * as network from '../network'; export class LifecycleWatcher { private _expectedLifecycle: string[]; private _frameManager: FrameManager; - private _frame: Frame; + private _frame: frames.Frame; private _initialLoaderId: string; private _timeout: number; - private _navigationRequest: Request | null = null; + private _navigationRequest: network.Request | null = null; private _eventListeners: RegisteredListener[]; private _sameDocumentNavigationPromise: Promise; private _sameDocumentNavigationCompleteCallback: () => void; @@ -42,7 +43,7 @@ export class LifecycleWatcher { private _maximumTimer: NodeJS.Timer; private _hasSameDocumentNavigation: boolean; - constructor(frameManager: FrameManager, frame: Frame, waitUntil: string | string[], timeout: number) { + constructor(frameManager: FrameManager, frame: frames.Frame, waitUntil: string | string[], timeout: number) { if (Array.isArray(waitUntil)) waitUntil = waitUntil.slice(); else if (typeof waitUntil === 'string') @@ -84,13 +85,13 @@ export class LifecycleWatcher { this._checkLifecycleComplete(); } - _onRequest(request: Request) { + _onRequest(request: network.Request) { if (request.frame() !== this._frame || !request.isNavigationRequest()) return; this._navigationRequest = request; } - _onFrameDetached(frame: Frame) { + _onFrameDetached(frame: frames.Frame) { if (this._frame === frame) { this._terminationCallback.call(null, new Error('Navigating frame was detached')); return; @@ -98,7 +99,7 @@ export class LifecycleWatcher { this._checkLifecycleComplete(); } - navigationResponse(): Response | null { + navigationResponse(): network.Response | null { return this._navigationRequest ? this._navigationRequest.response() : null; } @@ -130,7 +131,7 @@ export class LifecycleWatcher { .then(() => new TimeoutError(errorMessage)); } - _navigatedWithinDocument(frame: Frame) { + _navigatedWithinDocument(frame: frames.Frame) { if (frame !== this._frame) return; this._hasSameDocumentNavigation = true; @@ -138,7 +139,7 @@ export class LifecycleWatcher { } _checkLifecycleComplete() { - const checkLifecycle = (frame: Frame, expectedLifecycle: string[]): boolean => { + const checkLifecycle = (frame: frames.Frame, expectedLifecycle: string[]): boolean => { for (const event of expectedLifecycle) { if (!this._frameManager._frameData(frame).lifecycleEvents.has(event)) return false; diff --git a/src/chromium/NetworkManager.ts b/src/chromium/NetworkManager.ts index 83bbc25448..c5ef9c26e7 100644 --- a/src/chromium/NetworkManager.ts +++ b/src/chromium/NetworkManager.ts @@ -17,11 +17,11 @@ import { EventEmitter } from 'events'; import { CDPSession } from './Connection'; -import { Frame } from './FrameManager'; import { FrameManager } from './FrameManager'; import { assert, debugError, helper } from '../helper'; import { Protocol } from './protocol'; import * as network from '../network'; +import * as frames from '../frames'; export const NetworkManagerEvents = { Request: Symbol('Events.NetworkManager.Request'), @@ -30,9 +30,6 @@ export const NetworkManagerEvents = { RequestFinished: Symbol('Events.NetworkManager.RequestFinished'), }; -export type Request = network.Request; -export type Response = network.Response; - export class NetworkManager extends EventEmitter { private _client: CDPSession; private _ignoreHTTPSErrors: boolean; @@ -191,7 +188,7 @@ export class NetworkManager extends EventEmitter { } _onRequest(event: Protocol.Network.requestWillBeSentPayload, interceptionId: string | null) { - let redirectChain: Request[] = []; + let redirectChain: network.Request[] = []; if (event.redirectResponse) { const request = this._requestIdToRequest.get(event.requestId); // If we connect late to the target, we could have missed the requestWillBeSent event. @@ -206,7 +203,7 @@ export class NetworkManager extends EventEmitter { this.emit(NetworkManagerEvents.Request, request.request); } - _createResponse(request: InterceptableRequest, responsePayload: Protocol.Network.Response): Response { + _createResponse(request: InterceptableRequest, responsePayload: Protocol.Network.Response): network.Response { const remoteAddress: network.RemoteAddress = { ip: responsePayload.remoteIPAddress, port: responsePayload.remotePort }; const getResponseBody = async () => { const response = await this._client.send('Network.getResponseBody', { requestId: request._requestId }); @@ -273,14 +270,14 @@ export function toInterceptableRequest(request: network.Request): InterceptableR } class InterceptableRequest { - readonly request: Request; + readonly request: network.Request; _requestId: string; _interceptionId: string; private _client: CDPSession; private _allowInterception: boolean; private _interceptionHandled = false; - constructor(client: CDPSession, frame: Frame | null, interceptionId: string, allowInterception: boolean, event: Protocol.Network.requestWillBeSentPayload, redirectChain: Request[]) { + constructor(client: CDPSession, frame: frames.Frame | null, interceptionId: string, allowInterception: boolean, event: Protocol.Network.requestWillBeSentPayload, redirectChain: network.Request[]) { this._client = client; this._requestId = event.requestId; this._interceptionId = interceptionId; diff --git a/src/chromium/Page.ts b/src/chromium/Page.ts index 5e50be7ea2..7ce6e52e88 100644 --- a/src/chromium/Page.ts +++ b/src/chromium/Page.ts @@ -33,12 +33,11 @@ import { Overrides } from './features/overrides'; import { Interception } from './features/interception'; import { PDF } from './features/pdf'; import { Workers } from './features/workers'; -import { Frame } from './FrameManager'; import { FrameManager, FrameManagerEvents } from './FrameManager'; import { RawMouseImpl, RawKeyboardImpl } from './Input'; import { createJSHandle } from './JSHandle'; -import { JSHandle, toRemoteObject } from './ExecutionContext'; -import { NetworkManagerEvents, Response } from './NetworkManager'; +import { toRemoteObject } from './ExecutionContext'; +import { NetworkManagerEvents } from './NetworkManager'; import { Protocol } from './protocol'; import { getExceptionMessage, releaseObject, valueFromRemoteObject } from './protocolHelper'; import { Target } from './Target'; @@ -46,6 +45,9 @@ import { TaskQueue } from './TaskQueue'; import * as input from '../input'; import * as types from '../types'; import * as dom from '../dom'; +import * as frames from '../frames'; +import * as js from '../javascript'; +import * as network from '../network'; import { ExecutionContextDelegate } from './ExecutionContext'; const writeFileAsync = helper.promisify(fs.writeFile); @@ -205,7 +207,7 @@ export class Page extends EventEmitter { this.emit(Events.Page.Console, new ConsoleMessage(level, text, [], {url, lineNumber})); } - mainFrame(): Frame { + mainFrame(): frames.Frame { return this._frameManager.mainFrame(); } @@ -213,7 +215,7 @@ export class Page extends EventEmitter { return this._keyboard; } - frames(): Frame[] { + frames(): frames.Frame[] { return this._frameManager.frames(); } @@ -229,16 +231,16 @@ export class Page extends EventEmitter { return this.mainFrame().$(selector); } - evaluateHandle: types.EvaluateHandle = async (pageFunction, ...args) => { + evaluateHandle: types.EvaluateHandle = async (pageFunction, ...args) => { const context = await this.mainFrame().executionContext(); return context.evaluateHandle(pageFunction, ...args as any); } - $eval: types.$Eval = (selector, pageFunction, ...args) => { + $eval: types.$Eval = (selector, pageFunction, ...args) => { return this.mainFrame().$eval(selector, pageFunction, ...args as any); } - $$eval: types.$$Eval = (selector, pageFunction, ...args) => { + $$eval: types.$$Eval = (selector, pageFunction, ...args) => { return this.mainFrame().$$eval(selector, pageFunction, ...args as any); } @@ -355,7 +357,7 @@ export class Page extends EventEmitter { } } - _addConsoleMessage(type: string, args: JSHandle[], stackTrace: Protocol.Runtime.StackTrace | undefined) { + _addConsoleMessage(type: string, args: js.JSHandle[], stackTrace: Protocol.Runtime.StackTrace | undefined) { if (!this.listenerCount(Events.Page.Console)) { args.forEach(arg => arg.dispose()); return; @@ -404,11 +406,11 @@ export class Page extends EventEmitter { await this._frameManager.mainFrame().setContent(html, options); } - async goto(url: string, options: { referer?: string; timeout?: number; waitUntil?: string | string[]; } | undefined): Promise { + async goto(url: string, options: { referer?: string; timeout?: number; waitUntil?: string | string[]; } | undefined): Promise { return await this._frameManager.mainFrame().goto(url, options); } - async reload(options: { timeout?: number; waitUntil?: string | string[]; } = {}): Promise { + async reload(options: { timeout?: number; waitUntil?: string | string[]; } = {}): Promise { const [response] = await Promise.all([ this.waitForNavigation(options), this._client.send('Page.reload') @@ -416,7 +418,7 @@ export class Page extends EventEmitter { return response; } - async waitForNavigation(options: { timeout?: number; waitUntil?: string | string[]; } = {}): Promise { + async waitForNavigation(options: { timeout?: number; waitUntil?: string | string[]; } = {}): Promise { return await this._frameManager.mainFrame().waitForNavigation(options); } @@ -439,7 +441,7 @@ export class Page extends EventEmitter { }, timeout, this._sessionClosePromise()); } - async waitForResponse(urlOrPredicate: (string | Function), options: { timeout?: number; } = {}): Promise { + async waitForResponse(urlOrPredicate: (string | Function), options: { timeout?: number; } = {}): Promise { const { timeout = this._timeoutSettings.timeout(), } = options; @@ -452,15 +454,15 @@ export class Page extends EventEmitter { }, timeout, this._sessionClosePromise()); } - async goBack(options: { timeout?: number; waitUntil?: string | string[]; } | undefined): Promise { + async goBack(options: { timeout?: number; waitUntil?: string | string[]; } | undefined): Promise { return this._go(-1, options); } - async goForward(options: { timeout?: number; waitUntil?: string | string[]; } | undefined): Promise { + async goForward(options: { timeout?: number; waitUntil?: string | string[]; } | undefined): Promise { return this._go(+1, options); } - async _go(delta, options: { timeout?: number; waitUntil?: string | string[]; } | undefined): Promise { + async _go(delta, options: { timeout?: number; waitUntil?: string | string[]; } | undefined): Promise { const history = await this._client.send('Page.getNavigationHistory'); const entry = history.entries[history.currentIndex + delta]; if (!entry) @@ -512,7 +514,7 @@ export class Page extends EventEmitter { return this._viewport; } - evaluate: types.Evaluate = (pageFunction, ...args) => { + evaluate: types.Evaluate = (pageFunction, ...args) => { return this._frameManager.mainFrame().evaluate(pageFunction, ...args as any); } @@ -660,7 +662,7 @@ export class Page extends EventEmitter { return this.mainFrame().type(selector, text, options); } - waitFor(selectorOrFunctionOrTimeout: (string | number | Function), options: { visible?: boolean; hidden?: boolean; timeout?: number; polling?: string | number; } = {}, ...args: any[]): Promise { + waitFor(selectorOrFunctionOrTimeout: (string | number | Function), options: { visible?: boolean; hidden?: boolean; timeout?: number; polling?: string | number; } = {}, ...args: any[]): Promise { return this.mainFrame().waitFor(selectorOrFunctionOrTimeout, options, ...args); } @@ -675,7 +677,7 @@ export class Page extends EventEmitter { waitForFunction(pageFunction: Function, options: { polling?: string | number; timeout?: number; } = {}, - ...args: any[]): Promise { + ...args: any[]): Promise { return this.mainFrame().waitForFunction(pageFunction, options, ...args); } } @@ -704,10 +706,10 @@ type ConsoleMessageLocation = { export class ConsoleMessage { private _type: string; private _text: string; - private _args: JSHandle[]; + private _args: js.JSHandle[]; private _location: any; - constructor(type: string, text: string, args: JSHandle[], location: ConsoleMessageLocation = {}) { + constructor(type: string, text: string, args: js.JSHandle[], location: ConsoleMessageLocation = {}) { this._type = type; this._text = text; this._args = args; @@ -722,7 +724,7 @@ export class ConsoleMessage { return this._text; } - args(): JSHandle[] { + args(): js.JSHandle[] { return this._args; } diff --git a/src/chromium/features/interception.ts b/src/chromium/features/interception.ts index 0fc7e9426b..8a78dffdb9 100644 --- a/src/chromium/features/interception.ts +++ b/src/chromium/features/interception.ts @@ -1,7 +1,8 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT license. -import { NetworkManager, Request, toInterceptableRequest } from '../NetworkManager'; +import { NetworkManager, toInterceptableRequest } from '../NetworkManager'; +import * as network from '../../network'; export class Interception { private _networkManager: NetworkManager; @@ -18,15 +19,15 @@ export class Interception { await this._networkManager.setRequestInterception(false); } - async continue(request: Request, overrides: { url?: string; method?: string; postData?: string; headers?: {[key: string]: string}; } = {}) { + async continue(request: network.Request, overrides: { url?: string; method?: string; postData?: string; headers?: {[key: string]: string}; } = {}) { return toInterceptableRequest(request).continue(overrides); } - async fulfill(request: Request, response: { status: number; headers: {[key: string]: string}; contentType: string; body: (string | Buffer); }) { + async fulfill(request: network.Request, response: { status: number; headers: {[key: string]: string}; contentType: string; body: (string | Buffer); }) { return toInterceptableRequest(request).fulfill(response); } - async abort(request: Request, errorCode: string = 'failed') { + async abort(request: network.Request, errorCode: string = 'failed') { return toInterceptableRequest(request).abort(errorCode); } diff --git a/src/chromium/features/workers.ts b/src/chromium/features/workers.ts index 78a0006c1d..93409b3a78 100644 --- a/src/chromium/features/workers.ts +++ b/src/chromium/features/workers.ts @@ -21,10 +21,10 @@ import { Protocol } from '../protocol'; import { Events } from '../events'; import * as types from '../../types'; import * as js from '../../javascript'; -import { JSHandle, ExecutionContext, ExecutionContextDelegate } from '../ExecutionContext'; +import { ExecutionContextDelegate } from '../ExecutionContext'; import { createJSHandle } from '../JSHandle'; -type AddToConsoleCallback = (type: string, args: JSHandle[], stackTrace: Protocol.Runtime.StackTrace | undefined) => void; +type AddToConsoleCallback = (type: string, args: js.JSHandle[], stackTrace: Protocol.Runtime.StackTrace | undefined) => void; type HandleExceptionCallback = (exceptionDetails: Protocol.Runtime.ExceptionDetails) => void; export class Workers extends EventEmitter { @@ -58,15 +58,15 @@ export class Workers extends EventEmitter { export class Worker extends EventEmitter { private _client: CDPSession; private _url: string; - private _executionContextPromise: Promise; - private _executionContextCallback: (value?: ExecutionContext) => void; + private _executionContextPromise: Promise; + private _executionContextCallback: (value?: js.ExecutionContext) => void; constructor(client: CDPSession, url: string, addToConsole: AddToConsoleCallback, handleException: HandleExceptionCallback) { super(); this._client = client; this._url = url; this._executionContextPromise = new Promise(x => this._executionContextCallback = x); - let jsHandleFactory: (o: Protocol.Runtime.RemoteObject) => JSHandle; + let jsHandleFactory: (o: Protocol.Runtime.RemoteObject) => js.JSHandle; this._client.once('Runtime.executionContextCreated', async event => { jsHandleFactory = remoteObject => createJSHandle(executionContext, remoteObject); const executionContext = new js.ExecutionContext(new ExecutionContextDelegate(client, event.context), null); @@ -83,15 +83,15 @@ export class Worker extends EventEmitter { return this._url; } - async executionContext(): Promise { + async executionContext(): Promise { return this._executionContextPromise; } - evaluate: types.Evaluate = async (pageFunction, ...args) => { + evaluate: types.Evaluate = async (pageFunction, ...args) => { return (await this._executionContextPromise).evaluate(pageFunction, ...args as any); } - evaluateHandle: types.EvaluateHandle = async (pageFunction, ...args) => { + evaluateHandle: types.EvaluateHandle = async (pageFunction, ...args) => { return (await this._executionContextPromise).evaluateHandle(pageFunction, ...args as any); } } diff --git a/src/dom.ts b/src/dom.ts index 7b15b5392a..9a67ef218c 100644 --- a/src/dom.ts +++ b/src/dom.ts @@ -2,24 +2,21 @@ // Licensed under the MIT license. import * as frames from './frames'; -import * as types from './types'; -import * as js from './javascript'; -import * as input from './input'; import { assert, helper } from './helper'; import Injected from './injected/injected'; +import * as input from './input'; +import * as js from './javascript'; +import * as types from './types'; -export type Rect = { x: number, y: number, width: number, height: number }; -export type Point = { x: number, y: number }; type SelectorRoot = Element | ShadowRoot | Document; export interface DOMWorldDelegate { isJavascriptEnabled(): boolean; contentFrame(handle: ElementHandle): Promise; - boundingBox(handle: ElementHandle): Promise; + boundingBox(handle: ElementHandle): Promise; screenshot(handle: ElementHandle, options?: any): Promise; - ensurePointerActionPoint(handle: ElementHandle, relativePoint?: Point): Promise; + ensurePointerActionPoint(handle: ElementHandle, relativePoint?: types.Point): Promise; setInputFiles(handle: ElementHandle, files: input.FilePayload[]): Promise; -// await this.evaluate(input.setFileInputFunction, ); } export class ElementHandle extends js.JSHandle { @@ -71,7 +68,7 @@ export class ElementHandle extends js.JSHandle { throw new Error(error); } - async _performPointerAction(action: (point: Point) => Promise, options?: input.PointerActionOptions): Promise { + async _performPointerAction(action: (point: types.Point) => Promise, options?: input.PointerActionOptions): Promise { const point = await this._delegate.ensurePointerActionPoint(this, options ? options.relativePoint : undefined); let restoreModifiers: input.Modifier[] | undefined; if (options && options.modifiers) @@ -141,7 +138,7 @@ export class ElementHandle extends js.JSHandle { await this._keyboard.press(key, options); } - async boundingBox(): Promise { + async boundingBox(): Promise { return this._delegate.boundingBox(this); } @@ -177,7 +174,7 @@ export class ElementHandle extends js.JSHandle { return result; } - $eval: types.$Eval = async (selector, pageFunction, ...args) => { + $eval: types.$Eval = async (selector, pageFunction, ...args) => { const elementHandle = await this.$(selector); if (!elementHandle) throw new Error(`Error: failed to find element matching selector "${selector}"`); @@ -186,7 +183,7 @@ export class ElementHandle extends js.JSHandle { return result; } - $$eval: types.$$Eval = async (selector, pageFunction, ...args) => { + $$eval: types.$$Eval = async (selector, pageFunction, ...args) => { const arrayHandle = await this.evaluateHandle( (root: SelectorRoot, selector: string, injected: Injected) => injected.querySelectorAll('css=' + selector, root), selector, await this._context._injected() diff --git a/src/firefox/ExecutionContext.ts b/src/firefox/ExecutionContext.ts index f4f1a6880d..f67e6d32db 100644 --- a/src/firefox/ExecutionContext.ts +++ b/src/firefox/ExecutionContext.ts @@ -20,9 +20,6 @@ import { createHandle } from './JSHandle'; import * as js from '../javascript'; import { JugglerSession } from './Connection'; -export type ExecutionContext = js.ExecutionContext; -export type JSHandle = js.JSHandle; - export class ExecutionContextDelegate implements js.ExecutionContextDelegate { _session: JugglerSession; _executionContextId: string; @@ -32,7 +29,7 @@ export class ExecutionContextDelegate implements js.ExecutionContextDelegate { this._executionContextId = executionContextId; } - async evaluate(context: ExecutionContext, returnByValue: boolean, pageFunction: Function | string, ...args: any[]): Promise { + async evaluate(context: js.ExecutionContext, returnByValue: boolean, pageFunction: Function | string, ...args: any[]): Promise { if (returnByValue) { try { const handle = await this.evaluate(context, false /* returnByValue */, pageFunction, ...args as any); @@ -113,7 +110,7 @@ export class ExecutionContextDelegate implements js.ExecutionContextDelegate { } } - async getProperties(handle: JSHandle): Promise> { + async getProperties(handle: js.JSHandle): Promise> { const response = await this._session.send('Runtime.getObjectProperties', { executionContextId: this._executionContextId, objectId: toPayload(handle).objectId, @@ -124,7 +121,7 @@ export class ExecutionContextDelegate implements js.ExecutionContextDelegate { return result; } - async releaseHandle(handle: JSHandle): Promise { + async releaseHandle(handle: js.JSHandle): Promise { await this._session.send('Runtime.disposeObject', { executionContextId: this._executionContextId, objectId: toPayload(handle).objectId, @@ -135,7 +132,7 @@ export class ExecutionContextDelegate implements js.ExecutionContextDelegate { }); } - async handleJSONValue(handle: JSHandle): Promise { + async handleJSONValue(handle: js.JSHandle): Promise { const payload = toPayload(handle); if (!payload.objectId) return deserializeValue(payload); @@ -148,7 +145,7 @@ export class ExecutionContextDelegate implements js.ExecutionContextDelegate { return deserializeValue(simpleValue.result); } - handleToString(handle: JSHandle): string { + handleToString(handle: js.JSHandle): string { const payload = toPayload(handle); if (payload.objectId) return 'JSHandle@' + (payload.subtype || payload.type); @@ -162,11 +159,11 @@ export class ExecutionContextDelegate implements js.ExecutionContextDelegate { const payloadSymbol = Symbol('payload'); -export function toPayload(handle: JSHandle): any { +export function toPayload(handle: js.JSHandle): any { return (handle as any)[payloadSymbol]; } -export function markJSHandle(handle: JSHandle, payload: any) { +export function markJSHandle(handle: js.JSHandle, payload: any) { (handle as any)[payloadSymbol] = payload; } diff --git a/src/firefox/FrameManager.ts b/src/firefox/FrameManager.ts index 684cd56180..51ac44cfc3 100644 --- a/src/firefox/FrameManager.ts +++ b/src/firefox/FrameManager.ts @@ -23,9 +23,10 @@ import * as js from '../javascript'; import * as dom from '../dom'; import { TimeoutSettings } from '../TimeoutSettings'; import { JugglerSession } from './Connection'; -import { ExecutionContext, ExecutionContextDelegate } from './ExecutionContext'; +import { ExecutionContextDelegate } from './ExecutionContext'; import { NavigationWatchdog, NextNavigationWatchdog } from './NavigationWatchdog'; import { Page } from './Page'; +import { NetworkManager } from './NetworkManager'; export const FrameManagerEvents = { FrameNavigated: Symbol('FrameManagerEvents.FrameNavigated'), @@ -42,16 +43,14 @@ type FrameData = { firedEvents: Set, }; -export type Frame = frames.Frame; - export class FrameManager extends EventEmitter implements frames.FrameDelegate { _session: JugglerSession; _page: Page; - _networkManager: any; - _timeoutSettings: any; - _mainFrame: Frame; - _frames: Map; - _contextIdToContext: Map; + _networkManager: NetworkManager; + _timeoutSettings: TimeoutSettings; + _mainFrame: frames.Frame; + _frames: Map; + _contextIdToContext: Map; _eventListeners: RegisteredListener[]; constructor(session: JugglerSession, page: Page, networkManager, timeoutSettings) { @@ -98,24 +97,24 @@ export class FrameManager extends EventEmitter implements frames.FrameDelegate { context.frame()._contextDestroyed(context); } - _frameData(frame: Frame): FrameData { + _frameData(frame: frames.Frame): FrameData { return (frame as any)[frameDataSymbol]; } - frame(frameId: string): Frame { + frame(frameId: string): frames.Frame { return this._frames.get(frameId); } - mainFrame(): Frame { + mainFrame(): frames.Frame { return this._mainFrame; } frames() { - const frames: Array = []; + const frames: Array = []; collect(this._mainFrame); return frames; - function collect(frame: Frame) { + function collect(frame: frames.Frame) { frames.push(frame); for (const subframe of frame.childFrames()) collect(subframe); @@ -139,7 +138,7 @@ export class FrameManager extends EventEmitter implements frames.FrameDelegate { _onFrameAttached(params) { const parentFrame = this._frames.get(params.parentFrameId) || null; - const frame = new frames.Frame(this, parentFrame); + const frame = new frames.Frame(this, this._timeoutSettings, parentFrame); const data: FrameData = { frameId: params.frameId, lastCommittedNavigationId: '', @@ -176,16 +175,12 @@ export class FrameManager extends EventEmitter implements frames.FrameDelegate { helper.removeEventListeners(this._eventListeners); } - timeoutSettings(): TimeoutSettings { - return this._timeoutSettings; - } - - async adoptElementHandle(elementHandle: dom.ElementHandle, context: ExecutionContext): Promise { + async adoptElementHandle(elementHandle: dom.ElementHandle, context: js.ExecutionContext): Promise { assert(false, 'Multiple isolated worlds are not implemented'); return elementHandle; } - async waitForFrameNavigation(frame: Frame, options: { timeout?: number; waitUntil?: string | Array; } = {}) { + async waitForFrameNavigation(frame: frames.Frame, options: { timeout?: number; waitUntil?: string | Array; } = {}) { const { timeout = this._timeoutSettings.navigationTimeout(), waitUntil = ['load'], @@ -230,7 +225,7 @@ export class FrameManager extends EventEmitter implements frames.FrameDelegate { return watchDog.navigationResponse(); } - async navigateFrame(frame: Frame, url: string, options: { timeout?: number; waitUntil?: string | Array; referer?: string; } = {}) { + async navigateFrame(frame: frames.Frame, url: string, options: { timeout?: number; waitUntil?: string | Array; referer?: string; } = {}) { const { timeout = this._timeoutSettings.navigationTimeout(), waitUntil = ['load'], @@ -262,7 +257,7 @@ export class FrameManager extends EventEmitter implements frames.FrameDelegate { return watchDog.navigationResponse(); } - async setFrameContent(frame: Frame, html: string) { + async setFrameContent(frame: frames.Frame, html: string) { const context = await frame._utilityContext(); await context.evaluate(html => { document.open(); diff --git a/src/firefox/JSHandle.ts b/src/firefox/JSHandle.ts index 1dd88c7d9c..c0abb32fd4 100644 --- a/src/firefox/JSHandle.ts +++ b/src/firefox/JSHandle.ts @@ -19,9 +19,11 @@ import { assert, debugError } from '../helper'; import * as js from '../javascript'; import * as dom from '../dom'; import * as input from '../input'; +import * as types from '../types'; +import * as frames from '../frames'; import { JugglerSession } from './Connection'; -import { Frame, FrameManager } from './FrameManager'; -import { ExecutionContext, markJSHandle, ExecutionContextDelegate, toPayload } from './ExecutionContext'; +import { FrameManager } from './FrameManager'; +import { markJSHandle, ExecutionContextDelegate, toPayload } from './ExecutionContext'; class DOMWorldDelegate implements dom.DOMWorldDelegate { private _session: JugglerSession; @@ -34,7 +36,7 @@ class DOMWorldDelegate implements dom.DOMWorldDelegate { this._frameId = frameId; } - async contentFrame(handle: dom.ElementHandle): Promise { + async contentFrame(handle: dom.ElementHandle): Promise { const {frameId} = await this._session.send('Page.contentFrame', { frameId: this._frameId, objectId: toPayload(handle).objectId, @@ -49,7 +51,7 @@ class DOMWorldDelegate implements dom.DOMWorldDelegate { return this._frameManager._page._javascriptEnabled; } - async boundingBox(handle: dom.ElementHandle): Promise { + async boundingBox(handle: dom.ElementHandle): Promise { return await this._session.send('Page.getBoundingBox', { frameId: this._frameId, objectId: toPayload(handle).objectId, @@ -77,7 +79,7 @@ class DOMWorldDelegate implements dom.DOMWorldDelegate { })); } - async ensurePointerActionPoint(handle: dom.ElementHandle, relativePoint?: dom.Point): Promise { + async ensurePointerActionPoint(handle: dom.ElementHandle, relativePoint?: types.Point): Promise { await handle._scrollIntoViewIfNeeded(); if (!relativePoint) return this._clickablePoint(handle); @@ -85,8 +87,8 @@ class DOMWorldDelegate implements dom.DOMWorldDelegate { return { x: box.x + relativePoint.x, y: box.y + relativePoint.y }; } - private async _clickablePoint(handle: dom.ElementHandle): Promise { - type Quad = {p1: dom.Point, p2: dom.Point, p3: dom.Point, p4: dom.Point}; + private async _clickablePoint(handle: dom.ElementHandle): Promise { + type Quad = {p1: types.Point, p2: types.Point, p3: types.Point, p4: types.Point}; const computeQuadArea = (quad: Quad) => { // Compute sum of all directed areas of adjacent triangles @@ -129,7 +131,7 @@ class DOMWorldDelegate implements dom.DOMWorldDelegate { } } -export function createHandle(context: ExecutionContext, result: any, exceptionDetails?: any) { +export function createHandle(context: js.ExecutionContext, result: any, exceptionDetails?: any) { if (exceptionDetails) { if (exceptionDetails.value) throw new Error('Evaluation failed: ' + JSON.stringify(exceptionDetails.value)); diff --git a/src/firefox/NavigationWatchdog.ts b/src/firefox/NavigationWatchdog.ts index 7c11448da4..f2b40596b8 100644 --- a/src/firefox/NavigationWatchdog.ts +++ b/src/firefox/NavigationWatchdog.ts @@ -1,17 +1,35 @@ +/** + * Copyright 2019 Google Inc. All rights reserved. + * Modifications copyright (c) Microsoft Corporation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + import { helper, RegisteredListener } from '../helper'; import { JugglerSessionEvents } from './Connection'; -import { Frame, FrameManagerEvents, FrameManager } from './FrameManager'; +import { FrameManagerEvents, FrameManager } from './FrameManager'; import { NetworkManager, NetworkManagerEvents } from './NetworkManager'; +import * as frames from '../frames'; export class NextNavigationWatchdog { private _frameManager: FrameManager; - private _navigatedFrame: Frame; + private _navigatedFrame: frames.Frame; private _promise: Promise; private _resolveCallback: (value?: unknown) => void; private _navigation: {navigationId: number|null, url?: string} = null; private _eventListeners: RegisteredListener[]; - constructor(frameManager: FrameManager, navigatedFrame: Frame) { + constructor(frameManager: FrameManager, navigatedFrame: frames.Frame) { this._frameManager = frameManager; this._navigatedFrame = navigatedFrame; this._promise = new Promise(x => this._resolveCallback = x); @@ -55,7 +73,7 @@ export class NextNavigationWatchdog { export class NavigationWatchdog { private _frameManager: FrameManager; - private _navigatedFrame: Frame; + private _navigatedFrame: frames.Frame; private _targetNavigationId: any; private _firedEvents: any; private _targetURL: any; @@ -64,7 +82,7 @@ export class NavigationWatchdog { private _navigationRequest: any; private _eventListeners: RegisteredListener[]; - constructor(frameManager: FrameManager, navigatedFrame: Frame, networkManager: NetworkManager, targetNavigationId, targetURL, firedEvents) { + constructor(frameManager: FrameManager, navigatedFrame: frames.Frame, networkManager: NetworkManager, targetNavigationId, targetURL, firedEvents) { this._frameManager = frameManager; this._navigatedFrame = navigatedFrame; this._targetNavigationId = targetNavigationId; @@ -100,7 +118,7 @@ export class NavigationWatchdog { } _checkNavigationComplete() { - const checkFiredEvents = (frame: Frame, firedEvents) => { + const checkFiredEvents = (frame: frames.Frame, firedEvents) => { for (const subframe of frame.childFrames()) { if (!checkFiredEvents(subframe, firedEvents)) return false; diff --git a/src/firefox/NetworkManager.ts b/src/firefox/NetworkManager.ts index b57f476ed0..07c00480e6 100644 --- a/src/firefox/NetworkManager.ts +++ b/src/firefox/NetworkManager.ts @@ -18,11 +18,9 @@ import { EventEmitter } from 'events'; import { assert, debugError, helper, RegisteredListener } from '../helper'; import { JugglerSession } from './Connection'; -import { FrameManager, Frame } from './FrameManager'; +import { FrameManager } from './FrameManager'; import * as network from '../network'; - -export type Request = network.Request; -export type Response = network.Response; +import * as frames from '../frames'; export const NetworkManagerEvents = { RequestFailed: Symbol('NetworkManagerEvents.RequestFailed'), @@ -78,7 +76,7 @@ export class NetworkManager extends EventEmitter { const frame = redirected ? redirected.request.frame() : (this._frameManager && event.frameId ? this._frameManager.frame(event.frameId) : null); if (!frame) return; - let redirectChain: Request[] = []; + let redirectChain: network.Request[] = []; if (redirected) { redirectChain = redirected.request._redirectChain; redirectChain.push(redirected.request); @@ -170,13 +168,13 @@ export function toInterceptableRequest(request: network.Request): InterceptableR } class InterceptableRequest { - readonly request: Request; + readonly request: network.Request; _id: string; private _session: JugglerSession; private _suspended: boolean; private _interceptionHandled: boolean; - constructor(session: JugglerSession, frame: Frame, redirectChain: Request[], payload: any) { + constructor(session: JugglerSession, frame: frames.Frame, redirectChain: network.Request[], payload: any) { this._id = payload.requestId; this._session = session; this._suspended = payload.suspended; diff --git a/src/firefox/Page.ts b/src/firefox/Page.ts index 13d1d3ce28..2aa3de2720 100644 --- a/src/firefox/Page.ts +++ b/src/firefox/Page.ts @@ -1,3 +1,20 @@ +/** + * Copyright 2019 Google Inc. All rights reserved. + * Modifications copyright (c) Microsoft Corporation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + import { EventEmitter } from 'events'; import * as fs from 'fs'; import * as mime from 'mime'; @@ -10,15 +27,18 @@ import { Dialog } from './Dialog'; import { Events } from './events'; import { Accessibility } from './features/accessibility'; import { Interception } from './features/interception'; -import { FrameManager, FrameManagerEvents, normalizeWaitUntil, Frame } from './FrameManager'; +import { FrameManager, FrameManagerEvents, normalizeWaitUntil } from './FrameManager'; import { RawMouseImpl, RawKeyboardImpl } from './Input'; import { createHandle } from './JSHandle'; import { NavigationWatchdog } from './NavigationWatchdog'; -import { NetworkManager, NetworkManagerEvents, Request, Response } from './NetworkManager'; +import { NetworkManager, NetworkManagerEvents } from './NetworkManager'; import * as input from '../input'; import * as types from '../types'; import * as dom from '../dom'; -import { JSHandle, toPayload, deserializeValue } from './ExecutionContext'; +import * as js from '../javascript'; +import * as network from '../network'; +import * as frames from '../frames'; +import { toPayload, deserializeValue } from './ExecutionContext'; const writeFileAsync = helper.promisify(fs.writeFile); @@ -172,7 +192,7 @@ export class Page extends EventEmitter { return this._disconnectPromise; } - async waitForRequest(urlOrPredicate: (string | Function), options: { timeout?: number; } | undefined = {}): Promise { + async waitForRequest(urlOrPredicate: (string | Function), options: { timeout?: number; } | undefined = {}): Promise { const { timeout = this._timeoutSettings.timeout(), } = options; @@ -185,7 +205,7 @@ export class Page extends EventEmitter { }, timeout, this._sessionClosePromise()); } - async waitForResponse(urlOrPredicate: (string | Function), options: { timeout?: number; } | undefined = {}): Promise { + async waitForResponse(urlOrPredicate: (string | Function), options: { timeout?: number; } | undefined = {}): Promise { const { timeout = this._timeoutSettings.timeout(), } = options; @@ -288,7 +308,7 @@ export class Page extends EventEmitter { this.emit(Events.Page.Dialog, new Dialog(this._session, params)); } - mainFrame(): Frame { + mainFrame(): frames.Frame { return this._frameManager.mainFrame(); } @@ -420,7 +440,7 @@ export class Page extends EventEmitter { } } - evaluate: types.Evaluate = (pageFunction, ...args) => { + evaluate: types.Evaluate = (pageFunction, ...args) => { return this.mainFrame().evaluate(pageFunction, ...args as any); } @@ -464,11 +484,11 @@ export class Page extends EventEmitter { return this._frameManager.mainFrame().hover(selector); } - waitFor(selectorOrFunctionOrTimeout: (string | number | Function), options: { polling?: string | number; timeout?: number; visible?: boolean; hidden?: boolean; } | undefined = {}, ...args: Array): Promise { + waitFor(selectorOrFunctionOrTimeout: (string | number | Function), options: { polling?: string | number; timeout?: number; visible?: boolean; hidden?: boolean; } | undefined = {}, ...args: Array): Promise { return this._frameManager.mainFrame().waitFor(selectorOrFunctionOrTimeout, options, ...args); } - waitForFunction(pageFunction: Function | string, options: { polling?: string | number; timeout?: number; } | undefined = {}, ...args): Promise { + waitForFunction(pageFunction: Function | string, options: { polling?: string | number; timeout?: number; } | undefined = {}, ...args): Promise { return this._frameManager.mainFrame().waitForFunction(pageFunction, options, ...args); } @@ -492,11 +512,11 @@ export class Page extends EventEmitter { return this._frameManager.mainFrame().$$(selector); } - $eval: types.$Eval = (selector, pageFunction, ...args) => { + $eval: types.$Eval = (selector, pageFunction, ...args) => { return this._frameManager.mainFrame().$eval(selector, pageFunction, ...args as any); } - $$eval: types.$$Eval = (selector, pageFunction, ...args) => { + $$eval: types.$$Eval = (selector, pageFunction, ...args) => { return this._frameManager.mainFrame().$$eval(selector, pageFunction, ...args as any); } @@ -504,7 +524,7 @@ export class Page extends EventEmitter { return this._frameManager.mainFrame().$x(expression); } - evaluateHandle: types.EvaluateHandle = async (pageFunction, ...args) => { + evaluateHandle: types.EvaluateHandle = async (pageFunction, ...args) => { return this._frameManager.mainFrame().evaluateHandle(pageFunction, ...args as any); } @@ -564,10 +584,10 @@ export class Page extends EventEmitter { export class ConsoleMessage { private _type: string; - private _args: JSHandle[]; + private _args: js.JSHandle[]; private _location: any; - constructor(type: string, args: Array, location) { + constructor(type: string, args: Array, location) { this._type = type; this._args = args; this._location = location; @@ -581,7 +601,7 @@ export class ConsoleMessage { return this._type; } - args(): Array { + args(): Array { return this._args; } diff --git a/src/firefox/features/interception.ts b/src/firefox/features/interception.ts index f168ef05ba..0ececc9e20 100644 --- a/src/firefox/features/interception.ts +++ b/src/firefox/features/interception.ts @@ -1,7 +1,8 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT license. -import { NetworkManager, Request, toInterceptableRequest } from '../NetworkManager'; +import { NetworkManager, toInterceptableRequest } from '../NetworkManager'; +import * as network from '../../network'; export class Interception { private _networkManager: NetworkManager; @@ -18,15 +19,15 @@ export class Interception { await this._networkManager.setRequestInterception(false); } - async continue(request: Request, overrides: { url?: string; method?: string; postData?: string; headers?: {[key: string]: string}; } = {}) { + async continue(request: network.Request, overrides: { url?: string; method?: string; postData?: string; headers?: {[key: string]: string}; } = {}) { return toInterceptableRequest(request).continue(overrides); } - async fulfill(request: Request, response: { status: number; headers: {[key: string]: string}; contentType: string; body: (string | Buffer); }) { + async fulfill(request: network.Request, response: { status: number; headers: {[key: string]: string}; contentType: string; body: (string | Buffer); }) { throw new Error('Not implemented'); } - async abort(request: Request, errorCode: string = 'failed') { + async abort(request: network.Request, errorCode: string = 'failed') { return toInterceptableRequest(request).abort(); } } diff --git a/src/frames.ts b/src/frames.ts index 01ed530f61..fdeb4092fb 100644 --- a/src/frames.ts +++ b/src/frames.ts @@ -45,7 +45,6 @@ export type GotoOptions = NavigateOptions & { }; export interface FrameDelegate { - timeoutSettings(): TimeoutSettings; navigateFrame(frame: Frame, url: string, options?: GotoOptions): Promise; waitForFrameNavigation(frame: Frame, options?: NavigateOptions): Promise; setFrameContent(frame: Frame, html: string, options?: NavigateOptions): Promise; @@ -54,6 +53,7 @@ export interface FrameDelegate { export class Frame { _delegate: FrameDelegate; + private _timeoutSettings: TimeoutSettings; private _parentFrame: Frame; private _url = ''; private _detached = false; @@ -61,8 +61,9 @@ export class Frame { private _childFrames = new Set(); private _name: string; - constructor(delegate: FrameDelegate, parentFrame: Frame | null) { + constructor(delegate: FrameDelegate, timeoutSettings: TimeoutSettings, parentFrame: Frame | null) { this._delegate = delegate; + this._timeoutSettings = timeoutSettings; this._parentFrame = parentFrame; this._worlds.set('main', { contextPromise: new Promise(() => {}), contextResolveCallback: () => {}, context: null, waitTasks: new Set() }); @@ -98,12 +99,12 @@ export class Frame { return this._mainContext(); } - evaluateHandle: types.EvaluateHandle = async (pageFunction, ...args) => { + evaluateHandle: types.EvaluateHandle = async (pageFunction, ...args) => { const context = await this._mainContext(); return context.evaluateHandle(pageFunction, ...args as any); } - evaluate: types.Evaluate = async (pageFunction, ...args) => { + evaluate: types.Evaluate = async (pageFunction, ...args) => { const context = await this._mainContext(); return context.evaluate(pageFunction, ...args as any); } @@ -120,13 +121,13 @@ export class Frame { return document.$x(expression); } - $eval: types.$Eval = async (selector, pageFunction, ...args) => { + $eval: types.$Eval = async (selector, pageFunction, ...args) => { const context = await this._mainContext(); const document = await context._document(); return document.$eval(selector, pageFunction, ...args as any); } - $$eval: types.$$Eval = async (selector, pageFunction, ...args) => { + $$eval: types.$$Eval = async (selector, pageFunction, ...args) => { const context = await this._mainContext(); const document = await context._document(); return document.$$eval(selector, pageFunction, ...args as any); @@ -390,7 +391,7 @@ export class Frame { visible?: boolean; hidden?: boolean; timeout?: number; } | undefined): Promise { - const params = waitForSelectorOrXPath(selector, false /* isXPath */, { timeout: this._delegate.timeoutSettings().timeout(), ...options }); + const params = waitForSelectorOrXPath(selector, false /* isXPath */, { timeout: this._timeoutSettings.timeout(), ...options }); const handle = await this._scheduleWaitTask(params, this._worlds.get('utility')); if (!handle.asElement()) { await handle.dispose(); @@ -404,7 +405,7 @@ export class Frame { visible?: boolean; hidden?: boolean; timeout?: number; } | undefined): Promise { - const params = waitForSelectorOrXPath(xpath, true /* isXPath */, { timeout: this._delegate.timeoutSettings().timeout(), ...options }); + const params = waitForSelectorOrXPath(xpath, true /* isXPath */, { timeout: this._timeoutSettings.timeout(), ...options }); const handle = await this._scheduleWaitTask(params, this._worlds.get('utility')); if (!handle.asElement()) { await handle.dispose(); @@ -420,7 +421,7 @@ export class Frame { ...args): Promise { const { polling = 'raf', - timeout = this._delegate.timeoutSettings().timeout(), + timeout = this._timeoutSettings.timeout(), } = options; const params: WaitTaskParams = { predicateBody: pageFunction, diff --git a/src/input.ts b/src/input.ts index cae8290856..5e4e2885e3 100644 --- a/src/input.ts +++ b/src/input.ts @@ -4,20 +4,17 @@ import * as fs from 'fs'; import * as path from 'path'; import { assert, helper } from './helper'; +import * as types from './types'; import * as keyboardLayout from './USKeyboardLayout'; + const readFileAsync = helper.promisify(fs.readFile); export type Modifier = 'Alt' | 'Control' | 'Meta' | 'Shift'; export type Button = 'left' | 'right' | 'middle'; -type Point = { - x: number; - y: number; -}; - export type PointerActionOptions = { modifiers?: Modifier[]; - relativePoint?: Point; + relativePoint?: types.Point; }; export type ClickOptions = PointerActionOptions & { diff --git a/src/javascript.ts b/src/javascript.ts index bb2ea98349..777040f1fa 100644 --- a/src/javascript.ts +++ b/src/javascript.ts @@ -31,11 +31,11 @@ export class ExecutionContext { return this._frame; } - evaluate: types.Evaluate = (pageFunction, ...args) => { + evaluate: types.Evaluate = (pageFunction, ...args) => { return this._delegate.evaluate(this, true /* returnByValue */, pageFunction, ...args); } - evaluateHandle: types.EvaluateHandle = (pageFunction, ...args) => { + evaluateHandle: types.EvaluateHandle = (pageFunction, ...args) => { return this._delegate.evaluate(this, false /* returnByValue */, pageFunction, ...args); } @@ -71,11 +71,11 @@ export class JSHandle { return this._context; } - evaluate: types.EvaluateOn = (pageFunction, ...args) => { + evaluate: types.EvaluateOn = (pageFunction, ...args) => { return this._context.evaluate(pageFunction, this, ...args); } - evaluateHandle: types.EvaluateHandleOn = (pageFunction, ...args) => { + evaluateHandle: types.EvaluateHandleOn = (pageFunction, ...args) => { return this._context.evaluateHandle(pageFunction, this, ...args); } diff --git a/src/types.ts b/src/types.ts index e575e659d6..9587ee3619 100644 --- a/src/types.ts +++ b/src/types.ts @@ -1,13 +1,18 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT license. -type Boxed = { [Index in keyof Args]: Args[Index] | Handle }; +import * as js from './javascript'; + +type Boxed = { [Index in keyof Args]: Args[Index] | js.JSHandle }; type PageFunction = string | ((...args: Args) => R | Promise); type PageFunctionOn = string | ((on: On, ...args: Args) => R | Promise); -export type Evaluate = (pageFunction: PageFunction, ...args: Boxed) => Promise; -export type EvaluateHandle = (pageFunction: PageFunction, ...args: Boxed) => Promise; -export type $Eval = (selector: string, pageFunction: PageFunctionOn, ...args: Boxed) => Promise; -export type $$Eval = (selector: string, pageFunction: PageFunctionOn, ...args: Boxed) => Promise; -export type EvaluateOn = (pageFunction: PageFunctionOn, ...args: Boxed) => Promise; -export type EvaluateHandleOn = (pageFunction: PageFunctionOn, ...args: Boxed) => Promise; +export type Evaluate = (pageFunction: PageFunction, ...args: Boxed) => Promise; +export type EvaluateHandle = (pageFunction: PageFunction, ...args: Boxed) => Promise; +export type $Eval = (selector: string, pageFunction: PageFunctionOn, ...args: Boxed) => Promise; +export type $$Eval = (selector: string, pageFunction: PageFunctionOn, ...args: Boxed) => Promise; +export type EvaluateOn = (pageFunction: PageFunctionOn, ...args: Boxed) => Promise; +export type EvaluateHandleOn = (pageFunction: PageFunctionOn, ...args: Boxed) => Promise; + +export type Rect = { x: number, y: number, width: number, height: number }; +export type Point = { x: number, y: number }; diff --git a/src/webkit/ExecutionContext.ts b/src/webkit/ExecutionContext.ts index 6abb12a317..11ca2e0490 100644 --- a/src/webkit/ExecutionContext.ts +++ b/src/webkit/ExecutionContext.ts @@ -25,9 +25,6 @@ import * as js from '../javascript'; export const EVALUATION_SCRIPT_URL = '__playwright_evaluation_script__'; const SOURCE_URL_REGEX = /^[\040\t]*\/\/[@#] sourceURL=\s*(\S*?)\s*$/m; -export type ExecutionContext = js.ExecutionContext; -export type JSHandle = js.JSHandle; - export class ExecutionContextDelegate implements js.ExecutionContextDelegate { private _globalObjectId?: string; _session: TargetSession; @@ -48,7 +45,7 @@ export class ExecutionContextDelegate implements js.ExecutionContextDelegate { this._contextDestroyedCallback(); } - async evaluate(context: ExecutionContext, returnByValue: boolean, pageFunction: Function | string, ...args: any[]): Promise { + async evaluate(context: js.ExecutionContext, returnByValue: boolean, pageFunction: Function | string, ...args: any[]): Promise { const suffix = `//# sourceURL=${EVALUATION_SCRIPT_URL}`; if (helper.isString(pageFunction)) { @@ -275,7 +272,7 @@ export class ExecutionContextDelegate implements js.ExecutionContextDelegate { return this._globalObjectId; } - async getProperties(handle: JSHandle): Promise> { + async getProperties(handle: js.JSHandle): Promise> { const response = await this._session.send('Runtime.getProperties', { objectId: toRemoteObject(handle).objectId, ownProperties: true @@ -289,11 +286,11 @@ export class ExecutionContextDelegate implements js.ExecutionContextDelegate { return result; } - async releaseHandle(handle: JSHandle): Promise { + async releaseHandle(handle: js.JSHandle): Promise { await releaseObject(this._session, toRemoteObject(handle)); } - async handleJSONValue(handle: JSHandle): Promise { + async handleJSONValue(handle: js.JSHandle): Promise { const remoteObject = toRemoteObject(handle); if (remoteObject.objectId) { const response = await this._session.send('Runtime.callFunctionOn', { @@ -306,7 +303,7 @@ export class ExecutionContextDelegate implements js.ExecutionContextDelegate { return valueFromRemoteObject(remoteObject); } - handleToString(handle: JSHandle): string { + handleToString(handle: js.JSHandle): string { const object = toRemoteObject(handle); if (object.objectId) { let type: string = object.subtype || object.type; @@ -318,7 +315,7 @@ export class ExecutionContextDelegate implements js.ExecutionContextDelegate { return 'JSHandle:' + valueFromRemoteObject(object); } - private _convertArgument(arg: JSHandle | any) : Protocol.Runtime.CallArgument { + private _convertArgument(arg: js.JSHandle | any) : Protocol.Runtime.CallArgument { const objectHandle = arg && (arg instanceof js.JSHandle) ? arg : null; if (objectHandle) { if (objectHandle._context._delegate !== this) @@ -337,10 +334,10 @@ export class ExecutionContextDelegate implements js.ExecutionContextDelegate { const remoteObjectSymbol = Symbol('RemoteObject'); -export function toRemoteObject(handle: JSHandle): Protocol.Runtime.RemoteObject { +export function toRemoteObject(handle: js.JSHandle): Protocol.Runtime.RemoteObject { return (handle as any)[remoteObjectSymbol]; } -export function markJSHandle(handle: JSHandle, remoteObject: Protocol.Runtime.RemoteObject) { +export function markJSHandle(handle: js.JSHandle, remoteObject: Protocol.Runtime.RemoteObject) { (handle as any)[remoteObjectSymbol] = remoteObject; } diff --git a/src/webkit/FrameManager.ts b/src/webkit/FrameManager.ts index 1132ac6fa4..5e2f5aac2a 100644 --- a/src/webkit/FrameManager.ts +++ b/src/webkit/FrameManager.ts @@ -21,11 +21,12 @@ import * as frames from '../frames'; import { assert, debugError, helper, RegisteredListener } from '../helper'; import * as js from '../javascript'; import * as dom from '../dom'; +import * as network from '../network'; import { TimeoutSettings } from '../TimeoutSettings'; import { TargetSession } from './Connection'; import { Events } from './events'; -import { ExecutionContext, ExecutionContextDelegate } from './ExecutionContext'; -import { NetworkManager, NetworkManagerEvents, Request, Response } from './NetworkManager'; +import { ExecutionContextDelegate } from './ExecutionContext'; +import { NetworkManager, NetworkManagerEvents } from './NetworkManager'; import { Page } from './Page'; import { Protocol } from './protocol'; @@ -42,18 +43,16 @@ type FrameData = { id: string, }; -export type Frame = frames.Frame; - export class FrameManager extends EventEmitter implements frames.FrameDelegate { _session: TargetSession; _page: Page; _networkManager: NetworkManager; _timeoutSettings: TimeoutSettings; - _frames: Map; - _contextIdToContext: Map; + _frames: Map; + _contextIdToContext: Map; _isolatedWorlds: Set; _sessionListeners: RegisteredListener[]; - _mainFrame: Frame; + _mainFrame: frames.Frame; constructor(session: TargetSession, page: Page, timeoutSettings: TimeoutSettings) { super(); @@ -134,19 +133,19 @@ export class FrameManager extends EventEmitter implements frames.FrameDelegate { return this._page; } - mainFrame(): Frame { + mainFrame(): frames.Frame { return this._mainFrame; } - frames(): Array { + frames(): Array { return Array.from(this._frames.values()); } - frame(frameId: string): Frame | null { + frame(frameId: string): frames.Frame | null { return this._frames.get(frameId) || null; } - _frameData(frame: Frame): FrameData { + _frameData(frame: frames.Frame): FrameData { return (frame as any)[frameDataSymbol]; } @@ -155,7 +154,7 @@ export class FrameManager extends EventEmitter implements frames.FrameDelegate { return; assert(parentFrameId); const parentFrame = this._frames.get(parentFrameId); - const frame = new frames.Frame(this, parentFrame); + const frame = new frames.Frame(this, this._timeoutSettings, parentFrame); const data: FrameData = { id: frameId, }; @@ -182,7 +181,7 @@ export class FrameManager extends EventEmitter implements frames.FrameDelegate { } } else if (isMainFrame) { // Initial frame navigation. - frame = new frames.Frame(this, null); + frame = new frames.Frame(this, this._timeoutSettings, null); const data: FrameData = { id: framePayload.id, }; @@ -236,7 +235,7 @@ export class FrameManager extends EventEmitter implements frames.FrameDelegate { const frame = this._frames.get(frameId) || null; if (!frame) return; - const context: ExecutionContext = new js.ExecutionContext(new ExecutionContextDelegate(this._session, contextPayload), frame); + const context: js.ExecutionContext = new js.ExecutionContext(new ExecutionContextDelegate(this._session, contextPayload), frame); if (frame) { frame._contextCreated('main', context); frame._contextCreated('utility', context); @@ -244,13 +243,13 @@ export class FrameManager extends EventEmitter implements frames.FrameDelegate { this._contextIdToContext.set(contextPayload.id, context); } - executionContextById(contextId: number): ExecutionContext { + executionContextById(contextId: number): js.ExecutionContext { const context = this._contextIdToContext.get(contextId); assert(context, 'INTERNAL ERROR: missing context with id = ' + contextId); return context; } - _removeFramesRecursively(frame: Frame) { + _removeFramesRecursively(frame: frames.Frame) { for (const child of frame.childFrames()) this._removeFramesRecursively(child); frame._detach(); @@ -258,11 +257,7 @@ export class FrameManager extends EventEmitter implements frames.FrameDelegate { this.emit(FrameManagerEvents.FrameDetached, frame); } - timeoutSettings(): TimeoutSettings { - return this._timeoutSettings; - } - - async navigateFrame(frame: Frame, url: string, options: { referer?: string; timeout?: number; waitUntil?: string | Array; } | undefined = {}): Promise { + async navigateFrame(frame: frames.Frame, url: string, options: { referer?: string; timeout?: number; waitUntil?: string | Array; } | undefined = {}): Promise { const { timeout = this._timeoutSettings.navigationTimeout(), } = options; @@ -271,18 +266,18 @@ export class FrameManager extends EventEmitter implements frames.FrameDelegate { return watchDog.waitForNavigation(); } - async waitForFrameNavigation(frame: Frame, options?: frames.NavigateOptions): Promise { + async waitForFrameNavigation(frame: frames.Frame, options?: frames.NavigateOptions): Promise { // FIXME: this method only works for main frames. const watchDog = new NextNavigationWatchdog(this, frame, 10000); return watchDog.waitForNavigation(); } - async adoptElementHandle(elementHandle: dom.ElementHandle, context: ExecutionContext): Promise { + async adoptElementHandle(elementHandle: dom.ElementHandle, context: js.ExecutionContext): Promise { assert(false, 'Multiple isolated worlds are not implemented'); return elementHandle; } - async setFrameContent(frame: Frame, html: string, options: { timeout?: number; waitUntil?: string | Array; } | undefined = {}) { + async setFrameContent(frame: frames.Frame, html: string, options: { timeout?: number; waitUntil?: string | Array; } | undefined = {}) { // We rely upon the fact that document.open() will trigger Page.loadEventFired. const watchDog = new NextNavigationWatchdog(this, frame, 1000); await frame.evaluate(html => { @@ -299,7 +294,7 @@ export class FrameManager extends EventEmitter implements frames.FrameDelegate { */ class NextNavigationWatchdog { _frameManager: FrameManager; - _frame: Frame; + _frame: frames.Frame; _newDocumentNavigationPromise: Promise; _newDocumentNavigationCallback: (value?: unknown) => void; _sameDocumentNavigationPromise: Promise; @@ -309,7 +304,7 @@ class NextNavigationWatchdog { _timeoutPromise: Promise; _timeoutId: NodeJS.Timer; - constructor(frameManager: FrameManager, frame: Frame, timeout) { + constructor(frameManager: FrameManager, frame: frames.Frame, timeout) { this._frameManager = frameManager; this._frame = frame; this._newDocumentNavigationPromise = new Promise(fulfill => { @@ -368,13 +363,13 @@ class NextNavigationWatchdog { this._sameDocumentNavigationCallback(); } - _onRequest(request: Request) { + _onRequest(request: network.Request) { if (request.frame() !== this._frame || !request.isNavigationRequest()) return; this._navigationRequest = request; } - navigationResponse(): Response | null { + navigationResponse(): network.Response | null { return this._navigationRequest ? this._navigationRequest.response() : null; } diff --git a/src/webkit/JSHandle.ts b/src/webkit/JSHandle.ts index 05da5e0b4b..c732993dc0 100644 --- a/src/webkit/JSHandle.ts +++ b/src/webkit/JSHandle.ts @@ -20,15 +20,16 @@ import { debugError, helper } from '../helper'; import * as input from '../input'; import * as dom from '../dom'; import * as frames from '../frames'; +import * as types from '../types'; import { TargetSession } from './Connection'; -import { ExecutionContext, ExecutionContextDelegate, markJSHandle, toRemoteObject } from './ExecutionContext'; +import { ExecutionContextDelegate, markJSHandle, toRemoteObject } from './ExecutionContext'; import { FrameManager } from './FrameManager'; import { Protocol } from './protocol'; import * as js from '../javascript'; const writeFileAsync = helper.promisify(fs.writeFile); -export function createJSHandle(context: ExecutionContext, remoteObject: Protocol.Runtime.RemoteObject) { +export function createJSHandle(context: js.ExecutionContext, remoteObject: Protocol.Runtime.RemoteObject) { const frame = context.frame(); if (remoteObject.subtype === 'node' && frame) { const frameManager = frame._delegate as FrameManager; @@ -57,7 +58,7 @@ class DOMWorldDelegate implements dom.DOMWorldDelegate { return this._frameManager.page()._javascriptEnabled; } - async boundingBox(handle: dom.ElementHandle): Promise { + async boundingBox(handle: dom.ElementHandle): Promise { throw new Error('boundingBox() is not implemented'); } @@ -73,7 +74,7 @@ class DOMWorldDelegate implements dom.DOMWorldDelegate { return buffer; } - async ensurePointerActionPoint(handle: dom.ElementHandle, relativePoint?: dom.Point): Promise { + async ensurePointerActionPoint(handle: dom.ElementHandle, relativePoint?: types.Point): Promise { await handle._scrollIntoViewIfNeeded(); if (!relativePoint) return this._clickablePoint(handle); @@ -81,8 +82,8 @@ class DOMWorldDelegate implements dom.DOMWorldDelegate { return { x: box.x + relativePoint.x, y: box.y + relativePoint.y }; } - private async _clickablePoint(handle: dom.ElementHandle): Promise { - const fromProtocolQuad = (quad: number[]): dom.Point[] => { + private async _clickablePoint(handle: dom.ElementHandle): Promise { + const fromProtocolQuad = (quad: number[]): types.Point[] => { return [ {x: quad[0], y: quad[1]}, {x: quad[2], y: quad[3]}, @@ -91,14 +92,14 @@ class DOMWorldDelegate implements dom.DOMWorldDelegate { ]; }; - const intersectQuadWithViewport = (quad: dom.Point[], width: number, height: number): dom.Point[] => { + const intersectQuadWithViewport = (quad: types.Point[], width: number, height: number): types.Point[] => { return quad.map(point => ({ x: Math.min(Math.max(point.x, 0), width), y: Math.min(Math.max(point.y, 0), height), })); }; - const computeQuadArea = (quad: dom.Point[]) => { + const computeQuadArea = (quad: types.Point[]) => { // Compute sum of all directed areas of adjacent triangles // https://en.wikipedia.org/wiki/Polygon#Simple_polygons let area = 0; diff --git a/src/webkit/NetworkManager.ts b/src/webkit/NetworkManager.ts index dc2689131a..6143c31f65 100644 --- a/src/webkit/NetworkManager.ts +++ b/src/webkit/NetworkManager.ts @@ -17,10 +17,11 @@ import { EventEmitter } from 'events'; import { TargetSession } from './Connection'; -import { Frame, FrameManager } from './FrameManager'; +import { FrameManager } from './FrameManager'; import { assert, helper, RegisteredListener } from '../helper'; import { Protocol } from './protocol'; import * as network from '../network'; +import * as frames from '../frames'; export const NetworkManagerEvents = { Request: Symbol('Events.NetworkManager.Request'), @@ -29,9 +30,6 @@ export const NetworkManagerEvents = { RequestFinished: Symbol('Events.NetworkManager.RequestFinished'), }; -export type Request = network.Request; -export type Response = network.Response; - export class NetworkManager extends EventEmitter { private _sesssion: TargetSession; private _frameManager: FrameManager; @@ -93,7 +91,7 @@ export class NetworkManager extends EventEmitter { } _onRequestWillBeSent(event: Protocol.Network.requestWillBeSentPayload, interceptionId: string | null) { - let redirectChain: Request[] = []; + let redirectChain: network.Request[] = []; if (event.redirectResponse) { const request = this._requestIdToRequest.get(event.requestId); // If we connect late to the target, we could have missed the requestWillBeSent event. @@ -108,7 +106,7 @@ export class NetworkManager extends EventEmitter { this.emit(NetworkManagerEvents.Request, request.request); } - _createResponse(request: InterceptableRequest, responsePayload: Protocol.Network.Response): Response { + _createResponse(request: InterceptableRequest, responsePayload: Protocol.Network.Response): network.Response { const remoteAddress: network.RemoteAddress = { ip: '', port: 0 }; const getResponseBody = async () => { const response = await this._sesssion.send('Network.getResponseBody', { requestId: request._requestId }); @@ -175,11 +173,11 @@ export function toInterceptableRequest(request: network.Request): InterceptableR } class InterceptableRequest { - readonly request: Request; + readonly request: network.Request; _requestId: string; _interceptionId: string; - constructor(frame: Frame | null, interceptionId: string, event: Protocol.Network.requestWillBeSentPayload, redirectChain: Request[]) { + constructor(frame: frames.Frame | null, interceptionId: string, event: Protocol.Network.requestWillBeSentPayload, redirectChain: network.Request[]) { this._requestId = event.requestId; // TODO(einbinder) this will fail if we are an XHR document request const isNavigationRequest = event.type === 'Document'; diff --git a/src/webkit/Page.ts b/src/webkit/Page.ts index 1258ed87f2..407e3b3406 100644 --- a/src/webkit/Page.ts +++ b/src/webkit/Page.ts @@ -24,11 +24,11 @@ import { TimeoutSettings } from '../TimeoutSettings'; import { Browser, BrowserContext } from './Browser'; import { TargetSession, TargetSessionEvents } from './Connection'; import { Events } from './events'; -import { Frame, FrameManager, FrameManagerEvents } from './FrameManager'; +import { FrameManager, FrameManagerEvents } from './FrameManager'; import { RawKeyboardImpl, RawMouseImpl } from './Input'; import { createJSHandle } from './JSHandle'; -import { JSHandle, toRemoteObject } from './ExecutionContext'; -import { NetworkManagerEvents, Response } from './NetworkManager'; +import { toRemoteObject } from './ExecutionContext'; +import { NetworkManagerEvents } from './NetworkManager'; import { Protocol } from './protocol'; import { valueFromRemoteObject } from './protocolHelper'; import { Target } from './Target'; @@ -36,6 +36,9 @@ import { TaskQueue } from './TaskQueue'; import * as input from '../input'; import * as types from '../types'; import * as dom from '../dom'; +import * as frames from '../frames'; +import * as js from '../javascript'; +import * as network from '../network'; import { Dialog, DialogType } from './Dialog'; const writeFileAsync = helper.promisify(fs.writeFile); @@ -195,7 +198,7 @@ export class Page extends EventEmitter { this.emit(Events.Page.Console, new ConsoleMessage(derivedType, formattedText, handles, location)); } - mainFrame(): Frame { + mainFrame(): frames.Frame { return this._frameManager.mainFrame(); } @@ -203,7 +206,7 @@ export class Page extends EventEmitter { return this._keyboard; } - frames(): Frame[] { + frames(): frames.Frame[] { return this._frameManager.frames(); } @@ -224,16 +227,16 @@ export class Page extends EventEmitter { return this.mainFrame().$(selector); } - evaluateHandle: types.EvaluateHandle = async (pageFunction, ...args) => { + evaluateHandle: types.EvaluateHandle = async (pageFunction, ...args) => { const context = await this.mainFrame().executionContext(); return context.evaluateHandle(pageFunction, ...args as any); } - $eval: types.$Eval = (selector, pageFunction, ...args) => { + $eval: types.$Eval = (selector, pageFunction, ...args) => { return this.mainFrame().$eval(selector, pageFunction, ...args as any); } - $$eval: types.$$Eval = (selector, pageFunction, ...args) => { + $$eval: types.$$Eval = (selector, pageFunction, ...args) => { return this.mainFrame().$$eval(selector, pageFunction, ...args as any); } @@ -273,11 +276,11 @@ export class Page extends EventEmitter { await this._frameManager.mainFrame().setContent(html, options); } - async goto(url: string, options: { referer?: string; timeout?: number; waitUntil?: string | string[]; } | undefined): Promise { + async goto(url: string, options: { referer?: string; timeout?: number; waitUntil?: string | string[]; } | undefined): Promise { return await this._frameManager.mainFrame().goto(url, options); } - async reload(): Promise { + async reload(): Promise { const [response] = await Promise.all([ this.waitForNavigation(), this._session.send('Page.reload') @@ -285,7 +288,7 @@ export class Page extends EventEmitter { return response; } - async waitForNavigation(): Promise { + async waitForNavigation(): Promise { return await this._frameManager.mainFrame().waitForNavigation(); } @@ -350,7 +353,7 @@ export class Page extends EventEmitter { return this._viewport; } - evaluate: types.Evaluate = (pageFunction, ...args) => { + evaluate: types.Evaluate = (pageFunction, ...args) => { return this._frameManager.mainFrame().evaluate(pageFunction, ...args as any); } @@ -505,7 +508,7 @@ export class Page extends EventEmitter { return this.mainFrame().type(selector, text, options); } - waitFor(selectorOrFunctionOrTimeout: (string | number | Function), options: { visible?: boolean; hidden?: boolean; timeout?: number; polling?: string | number; } = {}, ...args: any[]): Promise { + waitFor(selectorOrFunctionOrTimeout: (string | number | Function), options: { visible?: boolean; hidden?: boolean; timeout?: number; polling?: string | number; } = {}, ...args: any[]): Promise { return this.mainFrame().waitFor(selectorOrFunctionOrTimeout, options, ...args); } @@ -520,7 +523,7 @@ export class Page extends EventEmitter { waitForFunction(pageFunction: Function, options: { polling?: string | number; timeout?: number; } = {}, - ...args: any[]): Promise { + ...args: any[]): Promise { return this.mainFrame().waitForFunction(pageFunction, options, ...args); } } @@ -561,10 +564,10 @@ type ConsoleMessageLocation = { export class ConsoleMessage { private _type: string; private _text: string; - private _args: JSHandle[]; + private _args: js.JSHandle[]; private _location: any; - constructor(type: string, text: string, args: JSHandle[], location: ConsoleMessageLocation = {}) { + constructor(type: string, text: string, args: js.JSHandle[], location: ConsoleMessageLocation = {}) { this._type = type; this._text = text; this._args = args; @@ -579,7 +582,7 @@ export class ConsoleMessage { return this._text; } - args(): JSHandle[] { + args(): js.JSHandle[] { return this._args; }