chore: migrate src/Page.js to TypeScript (#5809)

* chore: migrate src/Page.js to TypeScript

The final one! This is a huge file and needs to be split up and tidied,
but for now I've left all the definitions in place and converted types
accordingly.

There's some additional tidying we can do now every `src` file is TS,
but I'll leave that for another PR to avoid this one getting any bigger.

Co-authored-by: Mathias Bynens <mathias@qiwi.be>
This commit is contained in:
Jack Franklin 2020-05-05 13:53:22 +01:00 committed by GitHub
parent eed7d94a2b
commit de4f08dc52
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 353 additions and 688 deletions

View File

@ -20,6 +20,7 @@ import * as EventEmitter from 'events';
import {TaskQueue} from './TaskQueue'; import {TaskQueue} from './TaskQueue';
import {Events} from './Events'; import {Events} from './Events';
import {Connection} from './Connection'; import {Connection} from './Connection';
import {Page} from './Page';
import {ChildProcess} from 'child_process'; import {ChildProcess} from 'child_process';
type BrowserCloseCallback = () => Promise<void> | void; type BrowserCloseCallback = () => Promise<void> | void;
@ -137,11 +138,11 @@ export class Browser extends EventEmitter {
return this._connection.url(); return this._connection.url();
} }
async newPage(): Promise<Puppeteer.Page> { async newPage(): Promise<Page> {
return this._defaultContext.newPage(); return this._defaultContext.newPage();
} }
async _createPageInContext(contextId?: string): Promise<Puppeteer.Page> { async _createPageInContext(contextId?: string): Promise<Page> {
const {targetId} = await this._connection.send('Target.createTarget', {url: 'about:blank', browserContextId: contextId || undefined}); const {targetId} = await this._connection.send('Target.createTarget', {url: 'about:blank', browserContextId: contextId || undefined});
const target = await this._targets.get(targetId); const target = await this._targets.get(targetId);
assert(await target._initializedPromise, 'Failed to create target for page'); assert(await target._initializedPromise, 'Failed to create target for page');
@ -188,10 +189,7 @@ export class Browser extends EventEmitter {
} }
} }
/** async pages(): Promise<Page[]> {
* @return {!Promise<!Array<!Puppeteer.Page>>}
*/
async pages(): Promise<Puppeteer.Page[]> {
const contextPages = await Promise.all(this.browserContexts().map(context => context.pages())); const contextPages = await Promise.all(this.browserContexts().map(context => context.pages()));
// Flatten array. // Flatten array.
return contextPages.reduce((acc, x) => acc.concat(x), []); return contextPages.reduce((acc, x) => acc.concat(x), []);
@ -245,7 +243,7 @@ export class BrowserContext extends EventEmitter {
return this._browser.waitForTarget(target => target.browserContext() === this && predicate(target), options); return this._browser.waitForTarget(target => target.browserContext() === this && predicate(target), options);
} }
async pages(): Promise<Puppeteer.Page[]> { async pages(): Promise<Page[]> {
const pages = await Promise.all( const pages = await Promise.all(
this.targets() this.targets()
.filter(target => target.type() === 'page') .filter(target => target.type() === 'page')
@ -292,7 +290,7 @@ export class BrowserContext extends EventEmitter {
await this._connection.send('Browser.resetPermissions', {browserContextId: this._id || undefined}); await this._connection.send('Browser.resetPermissions', {browserContextId: this._id || undefined});
} }
newPage(): Promise<Puppeteer.Page> { newPage(): Promise<Page> {
return this._browser._createPageInContext(this._id); return this._browser._createPageInContext(this._id);
} }

View File

@ -17,14 +17,17 @@
import {assert} from './helper'; import {assert} from './helper';
import {CDPSession} from './Connection'; import {CDPSession} from './Connection';
enum DialogType { /* TODO(jacktfranklin): protocol.d.ts defines this
* so let's ditch this and avoid the duplication
*/
export enum DialogType {
Alert = 'alert', Alert = 'alert',
BeforeUnload = 'beforeunload', BeforeUnload = 'beforeunload',
Confirm = 'confirm', Confirm = 'confirm',
Prompt = 'prompt' Prompt = 'prompt'
} }
class Dialog { export class Dialog {
static Type = DialogType; static Type = DialogType;
private _client: CDPSession; private _client: CDPSession;
@ -69,5 +72,3 @@ class Dialog {
}); });
} }
} }
export = {Dialog};

View File

@ -25,12 +25,13 @@ import {TimeoutSettings} from './TimeoutSettings';
import {CDPSession} from './Connection'; import {CDPSession} from './Connection';
import {JSHandle, ElementHandle} from './JSHandle'; import {JSHandle, ElementHandle} from './JSHandle';
import {MouseButtonInput} from './Input'; import {MouseButtonInput} from './Input';
import {Page} from './Page';
const UTILITY_WORLD_NAME = '__puppeteer_utility_world__'; const UTILITY_WORLD_NAME = '__puppeteer_utility_world__';
export class FrameManager extends EventEmitter { export class FrameManager extends EventEmitter {
_client: CDPSession; _client: CDPSession;
_page: Puppeteer.Page; _page: Page;
_networkManager: NetworkManager; _networkManager: NetworkManager;
_timeoutSettings: TimeoutSettings; _timeoutSettings: TimeoutSettings;
_frames = new Map<string, Frame>(); _frames = new Map<string, Frame>();
@ -38,7 +39,7 @@ export class FrameManager extends EventEmitter {
_isolatedWorlds = new Set<string>(); _isolatedWorlds = new Set<string>();
_mainFrame: Frame; _mainFrame: Frame;
constructor(client: CDPSession, page: Puppeteer.Page, ignoreHTTPSErrors: boolean, timeoutSettings: TimeoutSettings) { constructor(client: CDPSession, page: Page, ignoreHTTPSErrors: boolean, timeoutSettings: TimeoutSettings) {
super(); super();
this._client = client; this._client = client;
this._page = page; this._page = page;
@ -155,7 +156,7 @@ export class FrameManager extends EventEmitter {
this._handleFrameTree(child); this._handleFrameTree(child);
} }
page(): Puppeteer.Page { page(): Page {
return this._page; return this._page;
} }

View File

@ -16,6 +16,7 @@
import {helper, assert, debugError} from './helper'; import {helper, assert, debugError} from './helper';
import {ExecutionContext} from './ExecutionContext'; import {ExecutionContext} from './ExecutionContext';
import {Page} from './Page';
import {CDPSession} from './Connection'; import {CDPSession} from './Connection';
import {KeyInput} from './USKeyboardLayout'; import {KeyInput} from './USKeyboardLayout';
import {FrameManager, Frame} from './FrameManager'; import {FrameManager, Frame} from './FrameManager';
@ -124,16 +125,9 @@ export class JSHandle {
} }
export class ElementHandle extends JSHandle { export class ElementHandle extends JSHandle {
_page: Puppeteer.Page; _page: Page;
_frameManager: FrameManager; _frameManager: FrameManager;
/** constructor(context: ExecutionContext, client: CDPSession, remoteObject: Protocol.Runtime.RemoteObject, page: Page, frameManager: FrameManager) {
* @param {!ExecutionContext} context
* @param {!CDPSession} client
* @param {!Protocol.Runtime.RemoteObject} remoteObject
* @param {!Puppeteer.Page} page
* @param {!FrameManager} frameManager
*/
constructor(context: ExecutionContext, client: CDPSession, remoteObject: Protocol.Runtime.RemoteObject, page: Puppeteer.Page, frameManager: FrameManager) {
super(context, client, remoteObject); super(context, client, remoteObject);
this._client = client; this._client = client;
this._remoteObject = remoteObject; this._remoteObject = remoteObject;
@ -231,12 +225,6 @@ export class ElementHandle extends JSHandle {
]; ];
} }
/**
* @param {!Array<{x: number, y: number}>} quad
* @param {number} width
* @param {number} height
* @return {!Array<{x: number, y: number}>}
*/
_intersectQuadWithViewport(quad: Array<{x: number; y: number}>, width: number, height: number): Array<{x: number; y: number}> { _intersectQuadWithViewport(quad: Array<{x: number; y: number}>, width: number, height: number): Array<{x: number; y: number}> {
return quad.map(point => ({ return quad.map(point => ({
x: Math.min(Math.max(point.x, 0), width), x: Math.min(Math.max(point.x, 0), width),
@ -256,10 +244,6 @@ export class ElementHandle extends JSHandle {
await this._page.mouse.click(x, y, options); await this._page.mouse.click(x, y, options);
} }
/**
* @param {!Array<string>} values
* @return {!Promise<!Array<string>>}
*/
async select(...values: string[]): Promise<string[]> { async select(...values: string[]): Promise<string[]> {
for (const value of values) for (const value of values)
assert(helper.isString(value), 'Values must be strings. Found value "' + value + '" of type "' + (typeof value) + '"'); assert(helper.isString(value), 'Values must be strings. Found value "' + value + '" of type "' + (typeof value) + '"');
@ -439,10 +423,6 @@ export class ElementHandle extends JSHandle {
return null; return null;
} }
/**
* @param {string} selector
* @return {!Promise<!Array<!ElementHandle>>}
*/
async $$(selector: string): Promise<ElementHandle[]> { async $$(selector: string): Promise<ElementHandle[]> {
const defaultHandler = (element: Element, selector: string) => element.querySelectorAll(selector); const defaultHandler = (element: Element, selector: string) => element.querySelectorAll(selector);
const {updatedSelector, queryHandler} = getQueryHandlerAndSelector(selector, defaultHandler); const {updatedSelector, queryHandler} = getQueryHandlerAndSelector(selector, defaultHandler);

View File

@ -19,7 +19,7 @@ import {Events} from './Events';
import {CDPSession} from './Connection'; import {CDPSession} from './Connection';
import {FrameManager, Frame} from './FrameManager'; import {FrameManager, Frame} from './FrameManager';
interface Credentials { export interface Credentials {
username: string; username: string;
password: string; password: string;
} }

File diff suppressed because it is too large Load Diff

View File

@ -29,7 +29,7 @@ export class Target {
_ignoreHTTPSErrors: boolean; _ignoreHTTPSErrors: boolean;
_defaultViewport?: Puppeteer.Viewport; _defaultViewport?: Puppeteer.Viewport;
_screenshotTaskQueue: TaskQueue; _screenshotTaskQueue: TaskQueue;
_pagePromise?: Promise<Puppeteer.Page>; _pagePromise?: Promise<Page>;
_workerPromise?: Promise<PuppeteerWorker>; _workerPromise?: Promise<PuppeteerWorker>;
_initializedPromise: Promise<boolean>; _initializedPromise: Promise<boolean>;
_initializedCallback: (x: boolean) => void; _initializedCallback: (x: boolean) => void;
@ -72,7 +72,7 @@ export class Target {
return this._sessionFactory(); return this._sessionFactory();
} }
async page(): Promise<Puppeteer.Page | null> { async page(): Promise<Page | null> {
if ((this._targetInfo.type === 'page' || this._targetInfo.type === 'background_page') && !this._pagePromise) { if ((this._targetInfo.type === 'page' || this._targetInfo.type === 'background_page') && !this._pagePromise) {
this._pagePromise = this._sessionFactory() this._pagePromise = this._sessionFactory()
.then(client => Page.create(client, this, this._ignoreHTTPSErrors, this._defaultViewport, this._screenshotTaskQueue)); .then(client => Page.create(client, this, this._ignoreHTTPSErrors, this._defaultViewport, this._screenshotTaskQueue));

7
src/externs.d.ts vendored
View File

@ -1,14 +1,7 @@
import {Page as RealPage} from './Page.js';
import * as child_process from 'child_process'; import * as child_process from 'child_process';
declare global { declare global {
module Puppeteer { module Puppeteer {
export class Page extends RealPage { }
/* TODO(jacktfranklin@): once DOMWorld, Page, and FrameManager are in TS
* we can remove this and instead use the type defined in LifeCycleWatcher
*/
export type PuppeteerLifeCycleEvent = 'load' | 'domcontentloaded' | 'networkidle0' | 'networkidle2';
export interface ConnectionTransport { export interface ConnectionTransport {
send(string); send(string);
close(); close();

View File

@ -359,6 +359,46 @@ function compareDocumentations(actual, expected) {
actualName: 'Object', actualName: 'Object',
expectedName: 'BrowserFetcherOptions' expectedName: 'BrowserFetcherOptions'
}], }],
['Method Page.authenticate() credentials', {
actualName: 'Object',
expectedName: 'Credentials'
}],
['Method Page.emulateMediaFeatures() features', {
actualName: 'Array<Object>',
expectedName: 'Array<MediaFeature>'
}],
['Method Page.goBack() options', {
actualName: 'Object',
expectedName: 'WaitForOptions'
}],
['Method Page.goForward() options', {
actualName: 'Object',
expectedName: 'WaitForOptions'
}],
['Method Page.reload() options', {
actualName: 'Object',
expectedName: 'WaitForOptions'
}],
['Method Page.waitForNavigation() options', {
actualName: 'Object',
expectedName: 'WaitForOptions'
}],
['Method Page.pdf() options', {
actualName: 'Object',
expectedName: 'PDFOptions'
}],
['Method Page.screenshot() options', {
actualName: 'Object',
expectedName: 'ScreenshotOptions'
}],
['Method Page.setContent() options', {
actualName: 'Object',
expectedName: 'WaitForOptions'
}],
['Method Page.setCookie() ...cookies', {
actualName: '...Object',
expectedName: '...CookieParam'
}],
]); ]);
const expectedForSource = expectedNamingMismatches.get(source); const expectedForSource = expectedNamingMismatches.get(source);