Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: prepare library types for rpc #2706

Merged
merged 1 commit into from
Jun 25, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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