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: introduce types for all evaluation functions #65

Closed
wants to merge 1 commit into from
Closed
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
22 changes: 11 additions & 11 deletions src/chromium/DOMWorld.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,10 @@ import { ElementHandle, JSHandle } from './JSHandle';
import { LifecycleWatcher } from './LifecycleWatcher';
import { TimeoutSettings } from '../TimeoutSettings';
import { ClickOptions, MultiClickOptions, PointerActionOptions, SelectOption } from '../input';
import * as types from '../types';
const readFileAsync = helper.promisify(fs.readFile);

export class DOMWorld {
export class DOMWorld implements types.DOMEvaluationContext<JSHandle> {
private _frameManager: FrameManager;
private _frame: Frame;
private _timeoutSettings: TimeoutSettings;
Expand Down Expand Up @@ -79,14 +80,14 @@ export class DOMWorld {
return this._contextPromise;
}

async evaluateHandle(pageFunction: Function | string, ...args: any[]): Promise<JSHandle> {
async evaluateHandle<Args extends any[]>(pageFunction: types.Func<Args>, ...args: types.Boxed<Args, JSHandle>): Promise<JSHandle> {
const context = await this.executionContext();
return context.evaluateHandle(pageFunction, ...args);
return context.evaluateHandle(pageFunction, ...args as any);
}

async evaluate(pageFunction: Function | string, ...args: any[]): Promise<any> {
async evaluate<Args extends any[], R>(pageFunction: types.Func<Args, R>, ...args: types.Boxed<Args, JSHandle>): Promise<R> {
const context = await this.executionContext();
return context.evaluate(pageFunction, ...args);
return context.evaluate(pageFunction, ...args as any);
}

async $(selector: string): Promise<ElementHandle | null> {
Expand All @@ -111,15 +112,14 @@ export class DOMWorld {
return value;
}

async $eval(selector: string, pageFunction: Function | string, ...args: any[]): Promise<any> {
async $eval<Args extends any[], R>(selector: string, pageFunction: types.FuncOn<Element, Args, R>, ...args: types.Boxed<Args, JSHandle>): Promise<R> {
const document = await this._document();
return document.$eval(selector, pageFunction, ...args);
return document.$eval(selector, pageFunction, ...args as any);
}

async $$eval(selector: string, pageFunction: Function | string, ...args: any[]): Promise<any> {
async $$eval<Args extends any[], R>(selector: string, pageFunction: types.FuncOn<Element[], Args, R>, ...args: types.Boxed<Args, JSHandle>): Promise<R> {
const document = await this._document();
const value = await document.$$eval(selector, pageFunction, ...args);
return value;
return document.$$eval(selector, pageFunction, ...args as any);
}

async $$(selector: string): Promise<ElementHandle[]> {
Expand Down Expand Up @@ -439,7 +439,7 @@ class WaitTask {
}
}

async function waitForPredicatePageFunction(predicateBody: string, polling: string, timeout: number, ...args): Promise<any> {
async function waitForPredicatePageFunction(predicateBody: string, polling: string | number, timeout: number, ...args): Promise<any> {
const predicate = new Function('...args', predicateBody);
let timedOut = false;
if (timeout)
Expand Down
9 changes: 5 additions & 4 deletions src/chromium/ExecutionContext.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,12 @@ import { Protocol } from './protocol';
import * as injectedSource from '../generated/injectedSource';
import * as cssSelectorEngineSource from '../generated/cssSelectorEngineSource';
import * as xpathSelectorEngineSource from '../generated/xpathSelectorEngineSource';
import * as types from '../types';

export const EVALUATION_SCRIPT_URL = '__playwright_evaluation_script__';
const SOURCE_URL_REGEX = /^[\040\t]*\/\/[@#] sourceURL=\s*(\S*?)\s*$/m;

export class ExecutionContext {
export class ExecutionContext implements types.EvaluationContext<JSHandle> {
_client: CDPSession;
_world: DOMWorld;
private _injectedPromise: Promise<JSHandle> | null = null;
Expand All @@ -45,11 +46,11 @@ export class ExecutionContext {
return this._world ? this._world.frame() : null;
}

async evaluate(pageFunction: Function | string, ...args: any[]): Promise<any> {
return await this._evaluateInternal(true /* returnByValue */, pageFunction, ...args);
evaluate<Args extends any[], R>(pageFunction: types.Func<Args, R>, ...args: types.Boxed<Args, JSHandle>): Promise<R> {
return this._evaluateInternal(true /* returnByValue */, pageFunction, ...args);
}

async evaluateHandle(pageFunction: Function | string, ...args: any[]): Promise<JSHandle> {
evaluateHandle<Args extends any[]>(pageFunction: types.Func<Args>, ...args: types.Boxed<Args, JSHandle>): Promise<JSHandle> {
return this._evaluateInternal(false /* returnByValue */, pageFunction, ...args);
}

Expand Down
19 changes: 10 additions & 9 deletions src/chromium/Frame.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,9 @@ import { FrameManager } from './FrameManager';
import { ElementHandle, JSHandle } from './JSHandle';
import { Response } from './NetworkManager';
import { Protocol } from './protocol';
import * as types from '../types';

export class Frame {
export class Frame implements types.DOMEvaluationContext<JSHandle> {
_id: string;
_frameManager: FrameManager;
private _client: CDPSession;
Expand Down Expand Up @@ -68,12 +69,12 @@ export class Frame {
return this._mainWorld.executionContext();
}

async evaluateHandle(pageFunction: Function | string, ...args: any[]): Promise<JSHandle> {
return this._mainWorld.evaluateHandle(pageFunction, ...args);
evaluateHandle<Args extends any[]>(pageFunction: types.Func<Args>, ...args: types.Boxed<Args, JSHandle>): Promise<JSHandle> {
return this._mainWorld.evaluateHandle(pageFunction, ...args as any);
}

async evaluate(pageFunction: Function | string, ...args: any[]): Promise<any> {
return this._mainWorld.evaluate(pageFunction, ...args);
evaluate<Args extends any[], R>(pageFunction: types.Func<Args, R>, ...args: types.Boxed<Args, JSHandle>): Promise<R> {
return this._mainWorld.evaluate(pageFunction, ...args as any);
}

async $(selector: string): Promise<ElementHandle | null> {
Expand All @@ -84,12 +85,12 @@ export class Frame {
return this._mainWorld.$x(expression);
}

async $eval(selector: string, pageFunction: Function | string, ...args: any[]): Promise<(object | undefined)> {
return this._mainWorld.$eval(selector, pageFunction, ...args);
$eval<Args extends any[], R>(selector: string, pageFunction: types.FuncOn<Element, Args, R>, ...args: types.Boxed<Args, JSHandle>): Promise<R> {
return this._mainWorld.$eval(selector, pageFunction, ...args as any);
}

async $$eval(selector: string, pageFunction: Function | string, ...args: any[]): Promise<(object | undefined)> {
return this._mainWorld.$$eval(selector, pageFunction, ...args);
$$eval<Args extends any[], R>(selector: string, pageFunction: types.FuncOn<Element[], Args, R>, ...args: types.Boxed<Args, JSHandle>): Promise<R> {
return this._mainWorld.$$eval(selector, pageFunction, ...args as any);
}

async $$(selector: string): Promise<ElementHandle[]> {
Expand Down
19 changes: 10 additions & 9 deletions src/chromium/JSHandle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import { Page } from './Page';
import { Protocol } from './protocol';
import { releaseObject, valueFromRemoteObject } from './protocolHelper';
import Injected from '../injected/injected';
import * as types from '../types';

type SelectorRoot = Element | ShadowRoot | Document;

Expand All @@ -43,7 +44,7 @@ export function createJSHandle(context: ExecutionContext, remoteObject: Protocol
return new JSHandle(context, context._client, remoteObject);
}

export class JSHandle {
export class JSHandle implements types.HandleEvaluationContext<JSHandle> {
_context: ExecutionContext;
protected _client: CDPSession;
_remoteObject: Protocol.Runtime.RemoteObject;
Expand All @@ -59,12 +60,12 @@ export class JSHandle {
return this._context;
}

async evaluate(pageFunction: Function | string, ...args: any[]): Promise<any> {
return await this.executionContext().evaluate(pageFunction, this, ...args);
evaluate<Args extends any[], R>(pageFunction: types.FuncOn<any, Args, R>, ...args: types.Boxed<Args, JSHandle>): Promise<R> {
return this.executionContext().evaluate(pageFunction, this, ...args);
}

async evaluateHandle(pageFunction: Function | string, ...args: any[]): Promise<JSHandle> {
return await this.executionContext().evaluateHandle(pageFunction, this, ...args);
evaluateHandle<Args extends any[]>(pageFunction: types.FuncOn<any, Args>, ...args: types.Boxed<Args, JSHandle>): Promise<JSHandle> {
return this.executionContext().evaluateHandle(pageFunction, this, ...args);
}

async getProperty(propertyName: string): Promise<JSHandle | null> {
Expand Down Expand Up @@ -432,22 +433,22 @@ export class ElementHandle extends JSHandle {
return result;
}

async $eval(selector: string, pageFunction: Function | string, ...args: any[]): Promise<object | undefined> {
async $eval<Args extends any[], R>(selector: string, pageFunction: types.FuncOn<Element, Args, R>, ...args: types.Boxed<Args, JSHandle>): Promise<R> {
const elementHandle = await this.$(selector);
if (!elementHandle)
throw new Error(`Error: failed to find element matching selector "${selector}"`);
const result = await elementHandle.evaluate(pageFunction, ...args);
const result = await elementHandle.evaluate(pageFunction, ...args as any);
await elementHandle.dispose();
return result;
}

async $$eval(selector: string, pageFunction: Function | string, ...args: any[]): Promise<object | undefined> {
async $$eval<Args extends any[], R>(selector: string, pageFunction: types.FuncOn<Element[], Args, R>, ...args: types.Boxed<Args, JSHandle>): Promise<R> {
const arrayHandle = await this.evaluateHandle(
(root: SelectorRoot, selector: string, injected: Injected) => injected.querySelectorAll('css=' + selector, root),
selector, await this._context._injected()
);

const result = await arrayHandle.evaluate(pageFunction, ...args);
const result = await arrayHandle.evaluate(pageFunction, ...args as any);
await arrayHandle.dispose();
return result;
}
Expand Down
20 changes: 10 additions & 10 deletions src/chromium/Page.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ import { Protocol } from './protocol';
import { getExceptionMessage, releaseObject, valueFromRemoteObject } from './protocolHelper';
import { Target } from './Target';
import { TaskQueue } from './TaskQueue';
import * as types from '../types';

const writeFileAsync = helper.promisify(fs.writeFile);

Expand All @@ -55,7 +56,7 @@ export type Viewport = {
hasTouch?: boolean;
}

export class Page extends EventEmitter {
export class Page extends EventEmitter implements types.DOMEvaluationContext<JSHandle> {
private _closed = false;
_client: CDPSession;
private _target: Target;
Expand Down Expand Up @@ -230,17 +231,16 @@ export class Page extends EventEmitter {
return this.mainFrame().$(selector);
}

async evaluateHandle(pageFunction: Function | string, ...args: any[]): Promise<JSHandle> {
const context = await this.mainFrame().executionContext();
return context.evaluateHandle(pageFunction, ...args);
evaluateHandle<Args extends any[]>(pageFunction: types.Func<Args>, ...args: types.Boxed<Args, JSHandle>): Promise<JSHandle> {
return this.mainFrame().evaluateHandle(pageFunction, ...args as any);
}

async $eval(selector: string, pageFunction: Function | string, ...args: any[]): Promise<(object | undefined)> {
return this.mainFrame().$eval(selector, pageFunction, ...args);
$eval<Args extends any[], R>(selector: string, pageFunction: types.FuncOn<Element, Args, R>, ...args: types.Boxed<Args, JSHandle>): Promise<R> {
return this.mainFrame().$eval(selector, pageFunction, ...args as any);
}

async $$eval(selector: string, pageFunction: Function | string, ...args: any[]): Promise<(object | undefined)> {
return this.mainFrame().$$eval(selector, pageFunction, ...args);
$$eval<Args extends any[], R>(selector: string, pageFunction: types.FuncOn<Element[], Args, R>, ...args: types.Boxed<Args, JSHandle>): Promise<R> {
return this.mainFrame().$$eval(selector, pageFunction, ...args as any);
}

async $$(selector: string): Promise<ElementHandle[]> {
Expand Down Expand Up @@ -565,8 +565,8 @@ export class Page extends EventEmitter {
return this._viewport;
}

async evaluate(pageFunction: Function | string, ...args: any[]): Promise<any> {
return this._frameManager.mainFrame().evaluate(pageFunction, ...args);
evaluate<Args extends any[], R>(pageFunction: types.Func<Args, R>, ...args: types.Boxed<Args, JSHandle>): Promise<R> {
return this._frameManager.mainFrame().evaluate(pageFunction, ...args as any);
}

async evaluateOnNewDocument(pageFunction: Function | string, ...args: any[]) {
Expand Down
11 changes: 6 additions & 5 deletions src/chromium/features/workers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import { debugError } from '../../helper';
import { JSHandle } from '../JSHandle';
import { Protocol } from '../protocol';
import { Events } from '../events';
import * as types from '../../types';

type AddToConsoleCallback = (type: string, args: JSHandle[], stackTrace: Protocol.Runtime.StackTrace | undefined) => void;
type HandleExceptionCallback = (exceptionDetails: Protocol.Runtime.ExceptionDetails) => void;
Expand Down Expand Up @@ -53,7 +54,7 @@ export class Workers extends EventEmitter {
}
}

export class Worker extends EventEmitter {
export class Worker extends EventEmitter implements types.EvaluationContext<JSHandle> {
private _client: CDPSession;
private _url: string;
private _executionContextPromise: Promise<ExecutionContext>;
Expand Down Expand Up @@ -85,11 +86,11 @@ export class Worker extends EventEmitter {
return this._executionContextPromise;
}

async evaluate(pageFunction: Function | string, ...args: any[]): Promise<any> {
return (await this._executionContextPromise).evaluate(pageFunction, ...args);
async evaluate<Args extends any[], R>(pageFunction: string | ((...args: Args) => R | Promise<R>), ...args: types.Boxed<Args, JSHandle>): Promise<R> {
return (await this._executionContextPromise).evaluate(pageFunction, ...args as any);
}

async evaluateHandle(pageFunction: Function | string, ...args: any[]): Promise<JSHandle> {
return (await this._executionContextPromise).evaluateHandle(pageFunction, ...args);
async evaluateHandle<Args extends any[]>(pageFunction: string | ((...args: Args) => any), ...args: types.Boxed<Args, JSHandle>): Promise<JSHandle> {
return (await this._executionContextPromise).evaluateHandle(pageFunction, ...args as any);
}
}
19 changes: 10 additions & 9 deletions src/firefox/DOMWorld.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,11 @@ import * as fs from 'fs';
import * as util from 'util';
import {ElementHandle, JSHandle} from './JSHandle';
import { ExecutionContext } from './ExecutionContext';
import * as types from '../types';

const readFileAsync = util.promisify(fs.readFile);

export class DOMWorld {
export class DOMWorld implements types.DOMEvaluationContext<JSHandle> {
_frame: any;
_timeoutSettings: any;
_documentPromise: any;
Expand Down Expand Up @@ -61,14 +62,14 @@ export class DOMWorld {
throw new Error('Method not implemented.');
}

async evaluateHandle(pageFunction, ...args): Promise<JSHandle> {
async evaluateHandle<Args extends any[]>(pageFunction: types.Func<Args>, ...args: types.Boxed<Args, JSHandle>): Promise<JSHandle> {
const context = await this.executionContext();
return context.evaluateHandle(pageFunction, ...args);
return context.evaluateHandle(pageFunction, ...args as any);
}

async evaluate(pageFunction, ...args): Promise<any> {
async evaluate<Args extends any[], R>(pageFunction: types.Func<Args, R>, ...args: types.Boxed<Args, JSHandle>): Promise<R> {
const context = await this.executionContext();
return context.evaluate(pageFunction, ...args);
return context.evaluate(pageFunction, ...args as any);
}

async $(selector: string): Promise<ElementHandle | null> {
Expand All @@ -87,14 +88,14 @@ export class DOMWorld {
return document.$x(expression);
}

async $eval(selector: string, pageFunction: Function | string, ...args: Array<any>): Promise<(object | undefined)> {
async $eval<Args extends any[], R>(selector: string, pageFunction: types.FuncOn<Element, Args, R>, ...args: types.Boxed<Args, JSHandle>): Promise<R> {
const document = await this._document();
return document.$eval(selector, pageFunction, ...args);
return document.$eval(selector, pageFunction, ...args as any);
}

async $$eval(selector: string, pageFunction: Function | string, ...args: Array<any>): Promise<(object | undefined)> {
async $$eval<Args extends any[], R>(selector: string, pageFunction: types.FuncOn<Element[], Args, R>, ...args: types.Boxed<Args, JSHandle>): Promise<R> {
const document = await this._document();
return document.$$eval(selector, pageFunction, ...args);
return document.$$eval(selector, pageFunction, ...args as any);
}

async $$(selector: string): Promise<Array<ElementHandle>> {
Expand Down
13 changes: 7 additions & 6 deletions src/firefox/ExecutionContext.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,9 @@ import { Frame } from './FrameManager';
import * as injectedSource from '../generated/injectedSource';
import * as cssSelectorEngineSource from '../generated/cssSelectorEngineSource';
import * as xpathSelectorEngineSource from '../generated/xpathSelectorEngineSource';
import * as types from '../types';

export class ExecutionContext {
export class ExecutionContext implements types.EvaluationContext<JSHandle> {
_session: any;
_frame: Frame;
_executionContextId: string;
Expand All @@ -34,7 +35,7 @@ export class ExecutionContext {
this._executionContextId = executionContextId;
}

async evaluateHandle(pageFunction, ...args): Promise<JSHandle> {
async evaluateHandle<Args extends any[]>(pageFunction: types.Func<Args>, ...args: types.Boxed<Args, JSHandle>): Promise<JSHandle> {
if (helper.isString(pageFunction)) {
const payload = await this._session.send('Runtime.evaluate', {
expression: pageFunction.trim(),
Expand Down Expand Up @@ -62,7 +63,7 @@ export class ExecutionContext {
throw new Error('Passed function is not well-serializable!');
}
}
args = args.map(arg => {
const protocolArgs = args.map(arg => {
if (arg instanceof JSHandle) {
if (arg._context !== this)
throw new Error('JSHandles can be evaluated only in the context they were created!');
Expand All @@ -84,7 +85,7 @@ export class ExecutionContext {
try {
callFunctionPromise = this._session.send('Runtime.callFunction', {
functionDeclaration: functionText,
args,
args: protocolArgs,
executionContextId: this._executionContextId
});
} catch (err) {
Expand All @@ -106,9 +107,9 @@ export class ExecutionContext {
return this._frame;
}

async evaluate(pageFunction, ...args): Promise<any> {
async evaluate<Args extends any[], R>(pageFunction: types.Func<Args, R>, ...args: types.Boxed<Args, JSHandle>): Promise<R> {
try {
const handle = await this.evaluateHandle(pageFunction, ...args);
const handle = await this.evaluateHandle(pageFunction, ...args as any);
const result = await handle.jsonValue();
await handle.dispose();
return result;
Expand Down
Loading