Skip to content

Commit

Permalink
chore: remove injected -> types dependency (#3606)
Browse files Browse the repository at this point in the history
This way, injected is self-contained and we can ensure it does not
depend on anything node-specific.
  • Loading branch information
dgozman authored Aug 24, 2020
1 parent 3bdf0e8 commit bdbcae1
Show file tree
Hide file tree
Showing 4 changed files with 40 additions and 42 deletions.
8 changes: 4 additions & 4 deletions src/server/dom.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@

import * as frames from './frames';
import { assert } from '../utils/utils';
import type InjectedScript from './injected/injectedScript';
import type { InjectedScript, InjectedScriptPoll } from './injected/injectedScript';
import * as injectedScriptSource from '../generated/injectedScriptSource';
import * as debugScriptSource from '../generated/debugScriptSource';
import * as js from './javascript';
Expand Down Expand Up @@ -718,9 +718,9 @@ export class ElementHandle<T extends Node = Node> extends js.JSHandle<T> {
// - cancels the poll when progress cancels.
export class InjectedScriptPollHandler<T> {
private _progress: Progress;
private _poll: js.JSHandle<types.InjectedScriptPoll<T>> | null;
private _poll: js.JSHandle<InjectedScriptPoll<T>> | null;

constructor(progress: Progress, poll: js.JSHandle<types.InjectedScriptPoll<T>>) {
constructor(progress: Progress, poll: js.JSHandle<InjectedScriptPoll<T>>) {
this._progress = progress;
this._poll = poll;
// Ensure we cancel the poll before progress aborts and returns:
Expand Down Expand Up @@ -836,7 +836,7 @@ function compensateHalfIntegerRoundingError(point: types.Point) {
point.y -= 0.02;
}

export type SchedulableTask<T> = (injectedScript: js.JSHandle<InjectedScript>) => Promise<js.JSHandle<types.InjectedScriptPoll<T>>>;
export type SchedulableTask<T> = (injectedScript: js.JSHandle<InjectedScript>) => Promise<js.JSHandle<InjectedScriptPoll<T>>>;

export function waitForSelectorTask(selector: SelectorInfo, state: 'attached' | 'detached' | 'visible' | 'hidden', root?: ElementHandle): SchedulableTask<Element | undefined> {
return injectedScript => injectedScript.evaluateHandle((injected, { parsed, state, root }) => {
Expand Down
52 changes: 34 additions & 18 deletions src/server/injected/injectedScript.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
* limitations under the License.
*/

import type * as types from '../types';
import { createAttributeEngine } from './attributeSelectorEngine';
import { createCSSEngine } from './cssSelectorEngine';
import { SelectorEngine, SelectorRoot } from './selectorEngine';
Expand All @@ -23,9 +22,24 @@ import { XPathEngine } from './xpathSelectorEngine';
import { ParsedSelector } from '../common/selectorParser';
import { FatalDOMError } from '../common/domErrors';

type Predicate<T> = (progress: types.InjectedScriptProgress, continuePolling: symbol) => T | symbol;
type Predicate<T> = (progress: InjectedScriptProgress, continuePolling: symbol) => T | symbol;

export default class InjectedScript {
export type InjectedScriptProgress = {
aborted: boolean,
log: (message: string) => void,
logRepeating: (message: string) => void,
};

export type InjectedScriptPoll<T> = {
result: Promise<T>,
// Takes more logs, waiting until at least one message is available.
takeNextLogs: () => Promise<string[]>,
// Takes all current logs without waiting.
takeLastLogs: () => string[],
cancel: () => void,
};

export class InjectedScript {
readonly engines: Map<string, SelectorEngine>;

constructor(customEngines: { name: string, engine: SelectorEngine}[]) {
Expand Down Expand Up @@ -105,7 +119,7 @@ export default class InjectedScript {
return rect.width > 0 && rect.height > 0;
}

pollRaf<T>(predicate: Predicate<T>): types.InjectedScriptPoll<T> {
pollRaf<T>(predicate: Predicate<T>): InjectedScriptPoll<T> {
return this._runAbortableTask(progress => {
let fulfill: (result: T) => void;
let reject: (error: Error) => void;
Expand All @@ -131,7 +145,7 @@ export default class InjectedScript {
});
}

pollInterval<T>(pollInterval: number, predicate: Predicate<T>): types.InjectedScriptPoll<T> {
pollInterval<T>(pollInterval: number, predicate: Predicate<T>): InjectedScriptPoll<T> {
return this._runAbortableTask(progress => {
let fulfill: (result: T) => void;
let reject: (error: Error) => void;
Expand All @@ -157,7 +171,7 @@ export default class InjectedScript {
});
}

private _runAbortableTask<T>(task: (progess: types.InjectedScriptProgress) => Promise<T>): types.InjectedScriptPoll<T> {
private _runAbortableTask<T>(task: (progess: InjectedScriptProgress) => Promise<T>): InjectedScriptPoll<T> {
let unsentLogs: string[] = [];
let takeNextLogsCallback: ((logs: string[]) => void) | undefined;
const logReady = () => {
Expand All @@ -175,7 +189,7 @@ export default class InjectedScript {
});

let lastLog = '';
const progress: types.InjectedScriptProgress = {
const progress: InjectedScriptProgress = {
aborted: false,
log: (message: string) => {
lastLog = message;
Expand Down Expand Up @@ -203,7 +217,7 @@ export default class InjectedScript {
return { left: parseInt(style.borderLeftWidth || '', 10), top: parseInt(style.borderTopWidth || '', 10) };
}

selectOptions(node: Node, optionsToSelect: (Node | types.SelectOption)[]): string[] | 'error:notconnected' | FatalDOMError {
selectOptions(node: Node, optionsToSelect: (Node | { value?: string, label?: string, index?: number })[]): string[] | 'error:notconnected' | FatalDOMError {
if (node.nodeName.toLowerCase() !== 'select')
return 'error:notselect';
if (!node.isConnected)
Expand Down Expand Up @@ -234,7 +248,7 @@ export default class InjectedScript {
return options.filter(option => option.selected).map(option => option.value);
}

waitForEnabledAndFill(node: Node, value: string): types.InjectedScriptPoll<FatalDOMError | 'error:notconnected' | 'needsinput' | 'done'> {
waitForEnabledAndFill(node: Node, value: string): InjectedScriptPoll<FatalDOMError | 'error:notconnected' | 'needsinput' | 'done'> {
return this.pollRaf((progress, continuePolling) => {
if (node.nodeType !== Node.ELEMENT_NODE)
return 'error:notelement';
Expand Down Expand Up @@ -299,7 +313,7 @@ export default class InjectedScript {
});
}

waitForVisibleAndSelectText(node: Node): types.InjectedScriptPoll<FatalDOMError | 'error:notconnected' | 'done'> {
waitForVisibleAndSelectText(node: Node): InjectedScriptPoll<FatalDOMError | 'error:notconnected' | 'done'> {
return this.pollRaf((progress, continuePolling) => {
if (node.nodeType !== Node.ELEMENT_NODE)
return 'error:notelement';
Expand Down Expand Up @@ -344,7 +358,7 @@ export default class InjectedScript {
return 'done';
}

waitForNodeVisible(node: Node): types.InjectedScriptPoll<'error:notconnected' | 'done'> {
waitForNodeVisible(node: Node): InjectedScriptPoll<'error:notconnected' | 'done'> {
return this.pollRaf((progress, continuePolling) => {
const element = node.nodeType === Node.ELEMENT_NODE ? node as Element : node.parentElement;
if (!node.isConnected || !element)
Expand All @@ -357,7 +371,7 @@ export default class InjectedScript {
});
}

waitForNodeHidden(node: Node): types.InjectedScriptPoll<'done'> {
waitForNodeHidden(node: Node): InjectedScriptPoll<'done'> {
return this.pollRaf((progress, continuePolling) => {
const element = node.nodeType === Node.ELEMENT_NODE ? node as Element : node.parentElement;
if (!node.isConnected || !element)
Expand All @@ -370,7 +384,7 @@ export default class InjectedScript {
});
}

waitForNodeEnabled(node: Node): types.InjectedScriptPoll<'error:notconnected' | 'done'> {
waitForNodeEnabled(node: Node): InjectedScriptPoll<'error:notconnected' | 'done'> {
return this.pollRaf((progress, continuePolling) => {
const element = node.nodeType === Node.ELEMENT_NODE ? node as Element : node.parentElement;
if (!node.isConnected || !element)
Expand All @@ -383,7 +397,7 @@ export default class InjectedScript {
});
}

waitForNodeDisabled(node: Node): types.InjectedScriptPoll<'error:notconnected' | 'done'> {
waitForNodeDisabled(node: Node): InjectedScriptPoll<'error:notconnected' | 'done'> {
return this.pollRaf((progress, continuePolling) => {
const element = node.nodeType === Node.ELEMENT_NODE ? node as Element : node.parentElement;
if (!node.isConnected || !element)
Expand Down Expand Up @@ -438,7 +452,7 @@ export default class InjectedScript {
throw new Error('Not a checkbox');
}

async setInputFiles(node: Node, payloads: types.FilePayload[]) {
async setInputFiles(node: Node, payloads: { name: string, mimeType: string, buffer: string }[]) {
if (node.nodeType !== Node.ELEMENT_NODE)
return 'Node is not of type HTMLElement';
const element: Element | undefined = node as Element;
Expand All @@ -461,8 +475,8 @@ export default class InjectedScript {
input.dispatchEvent(new Event('change', { 'bubbles': true }));
}

waitForDisplayedAtStablePosition(node: Node, rafCount: number, waitForEnabled: boolean): types.InjectedScriptPoll<'error:notconnected' | 'done'> {
let lastRect: types.Rect | undefined;
waitForDisplayedAtStablePosition(node: Node, rafCount: number, waitForEnabled: boolean): InjectedScriptPoll<'error:notconnected' | 'done'> {
let lastRect: { x: number, y: number, width: number, height: number } | undefined;
let counter = 0;
let samePositionCounter = 0;
let lastTime = 0;
Expand Down Expand Up @@ -517,7 +531,7 @@ export default class InjectedScript {
});
}

checkHitTargetAt(node: Node, point: types.Point): 'error:notconnected' | 'done' | { hitTargetDescription: string } {
checkHitTargetAt(node: Node, point: { x: number, y: number }): 'error:notconnected' | 'done' | { hitTargetDescription: string } {
let element: Element | null | undefined = node.nodeType === Node.ELEMENT_NODE ? (node as Element) : node.parentElement;
if (!element || !element.isConnected)
return 'error:notconnected';
Expand Down Expand Up @@ -683,3 +697,5 @@ const eventType = new Map<string, 'mouse'|'keyboard'|'touch'|'pointer'|'focus'|'
['dragexit', 'drag'],
['drop', 'drag'],
]);

export default InjectedScript;
17 changes: 0 additions & 17 deletions src/server/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,6 @@
* limitations under the License.
*/

// NOTE: No imports allowed - only primitive, self-contained types are allowed here.

export type Size = { width: number, height: number };
export type Point = { x: number, y: number };
export type Rect = Size & Point;
Expand Down Expand Up @@ -158,21 +156,6 @@ export type JSCoverageEntry = {
}[]
};

export type InjectedScriptProgress = {
aborted: boolean,
log: (message: string) => void,
logRepeating: (message: string) => void,
};

export type InjectedScriptPoll<T> = {
result: Promise<T>,
// Takes more logs, waiting until at least one message is available.
takeNextLogs: () => Promise<string[]>,
// Takes all current logs without waiting.
takeLastLogs: () => string[],
cancel: () => void,
};

export type ProxySettings = {
server: string,
bypass?: string,
Expand Down
5 changes: 2 additions & 3 deletions utils/check_deps.js
Original file line number Diff line number Diff line change
Expand Up @@ -108,11 +108,10 @@ DEPS['src/server/'] = [

// No dependencies for code shared between node and page.
DEPS['src/server/common/'] = [];

// Strict dependencies for injected code.
// TODO: remove the injected->types dependency.
DEPS['src/server/injected/'] = ['src/server/common/', 'src/server/types.ts'];
DEPS['src/server/injected/'] = ['src/server/common/'];

// Electron uses chromium internally.
DEPS['src/server/electron/'] = [...DEPS['src/server/'], 'src/server/chromium/'];

DEPS['src/server/playwright.ts'] = [...DEPS['src/server/'], 'src/server/chromium/', 'src/server/webkit/', 'src/server/firefox/'];
Expand Down

0 comments on commit bdbcae1

Please sign in to comment.