Skip to content

Commit

Permalink
chore: prepare library types for rpc
Browse files Browse the repository at this point in the history
  • Loading branch information
pavelfeldman committed Jun 25, 2020
1 parent f111974 commit 1af2f4c
Show file tree
Hide file tree
Showing 21 changed files with 268 additions and 192 deletions.
8 changes: 6 additions & 2 deletions src/browser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,25 +14,29 @@
* limitations under the License.
*/

import { BrowserContext, BrowserContextOptions, BrowserContextBase, PersistentContextOptions } from './browserContext';
import * as types from './types';
import { BrowserContext, BrowserContextBase } from './browserContext';
import { Page } from './page';
import { EventEmitter } from 'events';
import { Download } from './download';
import type { BrowserServer } from './server/browserServer';
import { Events } from './events';
import { Loggers } from './logger';
import { ProxySettings } from './types';
import { LoggerSink } from './loggerSink';

export type BrowserOptions = {
loggers: Loggers,
downloadsPath?: string,
headful?: boolean,
persistent?: PersistentContextOptions, // Undefined means no persistent context.
persistent?: types.BrowserContextOptions, // Undefined means no persistent context.
slowMo?: number,
ownedServer?: BrowserServer,
proxy?: ProxySettings,
};

export type BrowserContextOptions = types.BrowserContextOptions & { logger?: LoggerSink };

export interface Browser extends EventEmitter {
newContext(options?: BrowserContextOptions): Promise<BrowserContext>;
contexts(): BrowserContext[];
Expand Down
52 changes: 20 additions & 32 deletions src/browserContext.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,43 +31,18 @@ import { ProgressController } from './progress';
import { DebugController } from './debug/debugController';
import { LoggerSink } from './loggerSink';

type CommonContextOptions = {
viewport?: types.Size | null,
ignoreHTTPSErrors?: boolean,
javaScriptEnabled?: boolean,
bypassCSP?: boolean,
userAgent?: string,
locale?: string,
timezoneId?: string,
geolocation?: types.Geolocation,
permissions?: string[],
extraHTTPHeaders?: network.Headers,
offline?: boolean,
httpCredentials?: types.Credentials,
deviceScaleFactor?: number,
isMobile?: boolean,
hasTouch?: boolean,
colorScheme?: types.ColorScheme,
acceptDownloads?: boolean,
};

export type PersistentContextOptions = CommonContextOptions;
export type BrowserContextOptions = CommonContextOptions & {
logger?: LoggerSink,
};

export interface BrowserContext {
setDefaultNavigationTimeout(timeout: number): void;
setDefaultTimeout(timeout: number): void;
pages(): Page[];
newPage(): Promise<Page>;
cookies(urls?: string | string[]): Promise<network.NetworkCookie[]>;
addCookies(cookies: network.SetNetworkCookieParam[]): Promise<void>;
cookies(urls?: string | string[]): Promise<types.NetworkCookie[]>;
addCookies(cookies: types.SetNetworkCookieParam[]): Promise<void>;
clearCookies(): Promise<void>;
grantPermissions(permissions: string[], options?: { origin?: string }): Promise<void>;
clearPermissions(): Promise<void>;
setGeolocation(geolocation: types.Geolocation | null): Promise<void>;
setExtraHTTPHeaders(headers: network.Headers): Promise<void>;
setExtraHTTPHeaders(headers: types.Headers): Promise<void>;
setOffline(offline: boolean): Promise<void>;
setHTTPCredentials(httpCredentials: types.Credentials | null): Promise<void>;
addInitScript(script: Function | string | { path?: string, content?: string }, arg?: any): Promise<void>;
Expand All @@ -79,6 +54,8 @@ export interface BrowserContext {
close(): Promise<void>;
}

type BrowserContextOptions = types.BrowserContextOptions & { logger?: LoggerSink };

export abstract class BrowserContextBase extends EventEmitter implements BrowserContext {
readonly _timeoutSettings = new TimeoutSettings();
readonly _pageBindings = new Map<string, PageBinding>();
Expand Down Expand Up @@ -141,21 +118,27 @@ export abstract class BrowserContextBase extends EventEmitter implements Browser
// BrowserContext methods.
abstract pages(): Page[];
abstract newPage(): Promise<Page>;
abstract cookies(...urls: string[]): Promise<network.NetworkCookie[]>;
abstract addCookies(cookies: network.SetNetworkCookieParam[]): Promise<void>;
abstract _doCookies(urls: string[]): Promise<types.NetworkCookie[]>;
abstract addCookies(cookies: types.SetNetworkCookieParam[]): Promise<void>;
abstract clearCookies(): Promise<void>;
abstract _doGrantPermissions(origin: string, permissions: string[]): Promise<void>;
abstract _doClearPermissions(): Promise<void>;
abstract setGeolocation(geolocation: types.Geolocation | null): Promise<void>;
abstract setHTTPCredentials(httpCredentials: types.Credentials | null): Promise<void>;
abstract setExtraHTTPHeaders(headers: network.Headers): Promise<void>;
abstract setExtraHTTPHeaders(headers: types.Headers): Promise<void>;
abstract setOffline(offline: boolean): Promise<void>;
abstract addInitScript(script: string | Function | { path?: string | undefined; content?: string | undefined; }, arg?: any): Promise<void>;
abstract _doAddInitScript(expression: string): Promise<void>;
abstract _doExposeBinding(binding: PageBinding): Promise<void>;
abstract route(url: types.URLMatch, handler: network.RouteHandler): Promise<void>;
abstract unroute(url: types.URLMatch, handler?: network.RouteHandler): Promise<void>;
abstract close(): Promise<void>;

async cookies(urls: string | string[] | undefined = []): Promise<types.NetworkCookie[]> {
if (urls && !Array.isArray(urls))
urls = [ urls ];
return await this._doCookies(urls as string[]);
}

async exposeFunction(name: string, playwrightFunction: Function): Promise<void> {
await this.exposeBinding(name, (options, ...args: any) => playwrightFunction(...args));
}
Expand All @@ -172,6 +155,11 @@ export abstract class BrowserContextBase extends EventEmitter implements Browser
this._doExposeBinding(binding);
}

async addInitScript(script: string | Function | { path?: string | undefined; content?: string | undefined; }, arg?: any): Promise<void> {
const source = await helper.evaluationScript(script, arg);
await this._doAddInitScript(source);
}

async grantPermissions(permissions: string[], options?: { origin?: string }) {
let origin = '*';
if (options && options.origin) {
Expand Down
19 changes: 9 additions & 10 deletions src/chromium/crBrowser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,10 @@
* limitations under the License.
*/

import { BrowserBase, BrowserOptions } from '../browser';
import { assertBrowserContextIsNotOwned, BrowserContext, BrowserContextBase, BrowserContextOptions, validateBrowserContextOptions, verifyGeolocation } from '../browserContext';
import { BrowserBase, BrowserOptions, BrowserContextOptions } from '../browser';
import { assertBrowserContextIsNotOwned, BrowserContext, BrowserContextBase, validateBrowserContextOptions, verifyGeolocation } from '../browserContext';
import { Events as CommonEvents } from '../events';
import { assert, helper } from '../helper';
import { assert } from '../helper';
import * as network from '../network';
import { Page, PageBinding, Worker } from '../page';
import { ConnectionTransport, SlowMoTransport } from '../transport';
Expand Down Expand Up @@ -280,7 +280,7 @@ export class CRBrowserContext extends BrowserContextBase {
readonly _browserContextId: string | null;
readonly _evaluateOnNewDocumentSources: string[];

constructor(browser: CRBrowser, browserContextId: string | null, options: BrowserContextOptions) {
constructor(browser: CRBrowser, browserContextId: string | null, options: types.BrowserContextOptions) {
super(browser, options);
this._browser = browser;
this._browserContextId = browserContextId;
Expand Down Expand Up @@ -325,18 +325,18 @@ export class CRBrowserContext extends BrowserContextBase {
throw result;
}

async cookies(urls?: string | string[]): Promise<network.NetworkCookie[]> {
async _doCookies(urls: string[]): Promise<types.NetworkCookie[]> {
const { cookies } = await this._browser._session.send('Storage.getCookies', { browserContextId: this._browserContextId || undefined });
return network.filterCookies(cookies.map(c => {
const copy: any = { sameSite: 'None', ...c };
delete copy.size;
delete copy.priority;
delete copy.session;
return copy as network.NetworkCookie;
return copy as types.NetworkCookie;
}), urls);
}

async addCookies(cookies: network.SetNetworkCookieParam[]) {
async addCookies(cookies: types.SetNetworkCookieParam[]) {
await this._browser._session.send('Storage.setCookies', { cookies: network.rewriteCookies(cookies), browserContextId: this._browserContextId || undefined });
}

Expand Down Expand Up @@ -384,7 +384,7 @@ export class CRBrowserContext extends BrowserContextBase {
await (page._delegate as CRPage).updateGeolocation();
}

async setExtraHTTPHeaders(headers: network.Headers): Promise<void> {
async setExtraHTTPHeaders(headers: types.Headers): Promise<void> {
this._options.extraHTTPHeaders = network.verifyHeaders(headers);
for (const page of this.pages())
await (page._delegate as CRPage).updateExtraHTTPHeaders();
Expand All @@ -402,8 +402,7 @@ export class CRBrowserContext extends BrowserContextBase {
await (page._delegate as CRPage).updateHttpCredentials();
}

async addInitScript(script: Function | string | { path?: string, content?: string }, arg?: any) {
const source = await helper.evaluationScript(script, arg);
async _doAddInitScript(source: string) {
this._evaluateOnNewDocumentSources.push(source);
for (const page of this.pages())
await (page._delegate as CRPage).evaluateOnNewDocument(source);
Expand Down
12 changes: 6 additions & 6 deletions src/chromium/crNetworkManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import { assert, helper, RegisteredListener } from '../helper';
import { Protocol } from './protocol';
import * as network from '../network';
import * as frames from '../frames';
import { Credentials } from '../types';
import * as types from '../types';
import { CRPage } from './crPage';

export class CRNetworkManager {
Expand Down Expand Up @@ -63,7 +63,7 @@ export class CRNetworkManager {
helper.removeEventListeners(this._eventListeners);
}

async authenticate(credentials: Credentials | null) {
async authenticate(credentials: types.Credentials | null) {
this._credentials = credentials;
await this._updateProtocolRequestInterception();
}
Expand Down Expand Up @@ -350,7 +350,7 @@ class InterceptableRequest implements network.RouteDelegate {
this.request = new network.Request(allowInterception ? this : null, frame, redirectedFrom, documentId, url, type, method, postData, headersObject(headers));
}

async continue(overrides: { method?: string; headers?: network.Headers; postData?: string } = {}) {
async continue(overrides: { method?: string; headers?: types.Headers; postData?: string } = {}) {
// In certain cases, protocol will return error if the request was already canceled
// or the page was closed. We should tolerate these errors.
await this._client._sendMayFail('Fetch.continueRequest', {
Expand All @@ -361,7 +361,7 @@ class InterceptableRequest implements network.RouteDelegate {
});
}

async fulfill(response: network.FulfillResponse) {
async fulfill(response: types.FulfillResponse) {
const responseBody = response.body && helper.isString(response.body) ? Buffer.from(response.body) : (response.body || null);

const responseHeaders: { [s: string]: string; } = {};
Expand Down Expand Up @@ -423,8 +423,8 @@ function headersArray(headers: { [s: string]: string; }): { name: string; value:
return result;
}

function headersObject(headers: Protocol.Network.Headers): network.Headers {
const result: network.Headers = {};
function headersObject(headers: Protocol.Network.Headers): types.Headers {
const result: types.Headers = {};
for (const key of Object.keys(headers))
result[key.toLowerCase()] = headers[key];
return result;
Expand Down
4 changes: 2 additions & 2 deletions src/cli/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,10 @@

import * as program from 'commander';
import { Playwright } from '../server/playwright';
import { BrowserType, LaunchOptions } from '../server/browserType';
import { BrowserType } from '../server/browserType';
import { DeviceDescriptors } from '../deviceDescriptors';
import { BrowserContextOptions } from '../browserContext';
import { helper } from '../helper';
import { LaunchOptions, BrowserContextOptions } from '../types';

const playwright = new Playwright(__dirname, require('../../browsers.json')['browsers']);

Expand Down
28 changes: 25 additions & 3 deletions src/dom.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import * as mime from 'mime';
import * as path from 'path';
import * as util from 'util';
import * as frames from './frames';
import { assert, helper } from './helper';
import { assert, helper, assertMaxArguments } from './helper';
import InjectedScript from './injected/injectedScript';
import * as injectedScriptSource from './generated/injectedScriptSource';
import * as debugScriptSource from './generated/debugScriptSource';
Expand Down Expand Up @@ -55,6 +55,12 @@ export class FrameExecutionContext extends js.ExecutionContext {
});
}

async evaluateExpressionInternal(expression: string, isFunction: boolean, ...args: any[]): Promise<any> {
return await this.frame._page._frameManager.waitForSignalsCreatedBy(null, false /* noWaitFor */, async () => {
return js.evaluateExpression(this, true /* returnByValue */, expression, isFunction, ...args);
});
}

async evaluateHandleInternal<R>(pageFunction: js.Func0<R>): Promise<js.SmartHandle<R>>;
async evaluateHandleInternal<Arg, R>(pageFunction: js.Func1<Arg, R>, arg: Arg): Promise<js.SmartHandle<R>>;
async evaluateHandleInternal(pageFunction: never, ...args: never[]): Promise<any> {
Expand All @@ -63,6 +69,12 @@ export class FrameExecutionContext extends js.ExecutionContext {
});
}

async evaluateExpressionHandleInternal(expression: string, isFunction: boolean, ...args: any[]): Promise<any> {
return await this.frame._page._frameManager.waitForSignalsCreatedBy(null, false /* noWaitFor */, async () => {
return js.evaluateExpression(this, false /* returnByValue */, expression, isFunction, ...args);
});
}

createHandle(remoteObject: js.RemoteObject): js.JSHandle {
if (this.frame._page._delegate.isElementHandle(remoteObject))
return new ElementHandle(this, remoteObject.objectId!);
Expand Down Expand Up @@ -618,19 +630,29 @@ export class ElementHandle<T extends Node = Node> extends js.JSHandle<T> {
async $eval<R, Arg>(selector: string, pageFunction: js.FuncOn<Element, Arg, R>, arg: Arg): Promise<R>;
async $eval<R>(selector: string, pageFunction: js.FuncOn<Element, void, R>, arg?: any): Promise<R>;
async $eval<R, Arg>(selector: string, pageFunction: js.FuncOn<Element, Arg, R>, arg: Arg): Promise<R> {
assertMaxArguments(arguments.length, 3);
return this._$evalExpression(selector, String(pageFunction), typeof pageFunction === 'function', arg);
}

async _$evalExpression(selector: string, expression: string, isFunction: boolean, arg: any): Promise<any> {
const handle = await selectors._query(this._context.frame, selector, this);
if (!handle)
throw new Error(`Error: failed to find element matching selector "${selector}"`);
const result = await handle.evaluate(pageFunction, arg);
const result = await handle._evaluateExpression(expression, isFunction, true, arg);
handle.dispose();
return result;
}

async $$eval<R, Arg>(selector: string, pageFunction: js.FuncOn<Element[], Arg, R>, arg: Arg): Promise<R>;
async $$eval<R>(selector: string, pageFunction: js.FuncOn<Element[], void, R>, arg?: any): Promise<R>;
async $$eval<R, Arg>(selector: string, pageFunction: js.FuncOn<Element[], Arg, R>, arg: Arg): Promise<R> {
assertMaxArguments(arguments.length, 3);
return this._$$evalExpression(selector, String(pageFunction), typeof pageFunction === 'function', arg);
}

async _$$evalExpression(selector: string, expression: string, isFunction: boolean, arg: any): Promise<any> {
const arrayHandle = await selectors._queryArray(this._context.frame, selector, this);
const result = await arrayHandle.evaluate(pageFunction, arg);
const result = await arrayHandle._evaluateExpression(expression, isFunction, true, arg);
arrayHandle.dispose();
return result;
}
Expand Down
17 changes: 8 additions & 9 deletions src/firefox/ffBrowser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@
* limitations under the License.
*/

import { BrowserBase, BrowserOptions } from '../browser';
import { assertBrowserContextIsNotOwned, BrowserContext, BrowserContextBase, BrowserContextOptions, validateBrowserContextOptions, verifyGeolocation } from '../browserContext';
import { BrowserBase, BrowserOptions, BrowserContextOptions } from '../browser';
import { assertBrowserContextIsNotOwned, BrowserContext, BrowserContextBase, validateBrowserContextOptions, verifyGeolocation } from '../browserContext';
import { Events } from '../events';
import { assert, helper, RegisteredListener } from '../helper';
import * as network from '../network';
Expand Down Expand Up @@ -146,7 +146,7 @@ export class FFBrowserContext extends BrowserContextBase {
readonly _browser: FFBrowser;
readonly _browserContextId: string | null;

constructor(browser: FFBrowser, browserContextId: string | null, options: BrowserContextOptions) {
constructor(browser: FFBrowser, browserContextId: string | null, options: types.BrowserContextOptions) {
super(browser, options);
this._browser = browser;
this._browserContextId = browserContextId;
Expand Down Expand Up @@ -237,17 +237,17 @@ export class FFBrowserContext extends BrowserContextBase {
throw pageOrError;
}

async cookies(urls?: string | string[]): Promise<network.NetworkCookie[]> {
async _doCookies(urls: string[]): Promise<types.NetworkCookie[]> {
const { cookies } = await this._browser._connection.send('Browser.getCookies', { browserContextId: this._browserContextId || undefined });
return network.filterCookies(cookies.map(c => {
const copy: any = { ... c };
delete copy.size;
delete copy.session;
return copy as network.NetworkCookie;
return copy as types.NetworkCookie;
}), urls);
}

async addCookies(cookies: network.SetNetworkCookieParam[]) {
async addCookies(cookies: types.SetNetworkCookieParam[]) {
await this._browser._connection.send('Browser.setCookies', { browserContextId: this._browserContextId || undefined, cookies: network.rewriteCookies(cookies) });
}

Expand Down Expand Up @@ -282,7 +282,7 @@ export class FFBrowserContext extends BrowserContextBase {
await this._browser._connection.send('Browser.setGeolocationOverride', { browserContextId: this._browserContextId || undefined, geolocation });
}

async setExtraHTTPHeaders(headers: network.Headers): Promise<void> {
async setExtraHTTPHeaders(headers: types.Headers): Promise<void> {
this._options.extraHTTPHeaders = network.verifyHeaders(headers);
const allHeaders = { ...this._options.extraHTTPHeaders };
if (this._options.locale)
Expand All @@ -300,8 +300,7 @@ export class FFBrowserContext extends BrowserContextBase {
await this._browser._connection.send('Browser.setHTTPCredentials', { browserContextId: this._browserContextId || undefined, credentials: httpCredentials });
}

async addInitScript(script: Function | string | { path?: string, content?: string }, arg?: any) {
const source = await helper.evaluationScript(script, arg);
async _doAddInitScript(source: string) {
await this._browser._connection.send('Browser.addScriptToEvaluateOnNewDocument', { browserContextId: this._browserContextId || undefined, script: source });
}

Expand Down
Loading

0 comments on commit 1af2f4c

Please sign in to comment.