diff --git a/src/server/dom.ts b/src/server/dom.ts index 85f4e87453eee..b9d1b5e799a52 100644 --- a/src/server/dom.ts +++ b/src/server/dom.ts @@ -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'; @@ -718,9 +718,9 @@ export class ElementHandle extends js.JSHandle { // - cancels the poll when progress cancels. export class InjectedScriptPollHandler { private _progress: Progress; - private _poll: js.JSHandle> | null; + private _poll: js.JSHandle> | null; - constructor(progress: Progress, poll: js.JSHandle>) { + constructor(progress: Progress, poll: js.JSHandle>) { this._progress = progress; this._poll = poll; // Ensure we cancel the poll before progress aborts and returns: @@ -836,7 +836,7 @@ function compensateHalfIntegerRoundingError(point: types.Point) { point.y -= 0.02; } -export type SchedulableTask = (injectedScript: js.JSHandle) => Promise>>; +export type SchedulableTask = (injectedScript: js.JSHandle) => Promise>>; export function waitForSelectorTask(selector: SelectorInfo, state: 'attached' | 'detached' | 'visible' | 'hidden', root?: ElementHandle): SchedulableTask { return injectedScript => injectedScript.evaluateHandle((injected, { parsed, state, root }) => { diff --git a/src/server/injected/injectedScript.ts b/src/server/injected/injectedScript.ts index f930a975a2cb2..3a92e9467ea9e 100644 --- a/src/server/injected/injectedScript.ts +++ b/src/server/injected/injectedScript.ts @@ -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'; @@ -23,9 +22,24 @@ import { XPathEngine } from './xpathSelectorEngine'; import { ParsedSelector } from '../common/selectorParser'; import { FatalDOMError } from '../common/domErrors'; -type Predicate = (progress: types.InjectedScriptProgress, continuePolling: symbol) => T | symbol; +type Predicate = (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 = { + result: Promise, + // Takes more logs, waiting until at least one message is available. + takeNextLogs: () => Promise, + // Takes all current logs without waiting. + takeLastLogs: () => string[], + cancel: () => void, +}; + +export class InjectedScript { readonly engines: Map; constructor(customEngines: { name: string, engine: SelectorEngine}[]) { @@ -105,7 +119,7 @@ export default class InjectedScript { return rect.width > 0 && rect.height > 0; } - pollRaf(predicate: Predicate): types.InjectedScriptPoll { + pollRaf(predicate: Predicate): InjectedScriptPoll { return this._runAbortableTask(progress => { let fulfill: (result: T) => void; let reject: (error: Error) => void; @@ -131,7 +145,7 @@ export default class InjectedScript { }); } - pollInterval(pollInterval: number, predicate: Predicate): types.InjectedScriptPoll { + pollInterval(pollInterval: number, predicate: Predicate): InjectedScriptPoll { return this._runAbortableTask(progress => { let fulfill: (result: T) => void; let reject: (error: Error) => void; @@ -157,7 +171,7 @@ export default class InjectedScript { }); } - private _runAbortableTask(task: (progess: types.InjectedScriptProgress) => Promise): types.InjectedScriptPoll { + private _runAbortableTask(task: (progess: InjectedScriptProgress) => Promise): InjectedScriptPoll { let unsentLogs: string[] = []; let takeNextLogsCallback: ((logs: string[]) => void) | undefined; const logReady = () => { @@ -175,7 +189,7 @@ export default class InjectedScript { }); let lastLog = ''; - const progress: types.InjectedScriptProgress = { + const progress: InjectedScriptProgress = { aborted: false, log: (message: string) => { lastLog = message; @@ -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) @@ -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 { + waitForEnabledAndFill(node: Node, value: string): InjectedScriptPoll { return this.pollRaf((progress, continuePolling) => { if (node.nodeType !== Node.ELEMENT_NODE) return 'error:notelement'; @@ -299,7 +313,7 @@ export default class InjectedScript { }); } - waitForVisibleAndSelectText(node: Node): types.InjectedScriptPoll { + waitForVisibleAndSelectText(node: Node): InjectedScriptPoll { return this.pollRaf((progress, continuePolling) => { if (node.nodeType !== Node.ELEMENT_NODE) return 'error:notelement'; @@ -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) @@ -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) @@ -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) @@ -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) @@ -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; @@ -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; @@ -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'; @@ -683,3 +697,5 @@ const eventType = new Map void, - logRepeating: (message: string) => void, -}; - -export type InjectedScriptPoll = { - result: Promise, - // Takes more logs, waiting until at least one message is available. - takeNextLogs: () => Promise, - // Takes all current logs without waiting. - takeLastLogs: () => string[], - cancel: () => void, -}; - export type ProxySettings = { server: string, bypass?: string, diff --git a/utils/check_deps.js b/utils/check_deps.js index b36b4be2dbebc..101ea765f6ec0 100644 --- a/utils/check_deps.js +++ b/utils/check_deps.js @@ -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/'];