chore: use progress.continuePolling instead of passing it around (#9929)

This commit is contained in:
Dmitry Gozman 2021-11-01 13:57:13 -07:00 committed by GitHub
parent b924b7e076
commit 50f7477906
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 29 additions and 28 deletions

View file

@ -952,7 +952,7 @@ export function waitForSelectorTask(selector: SelectorInfo, state: 'attached' |
return injectedScript => injectedScript.evaluateHandle((injected, { parsed, strict, state, omitReturnValue, root }) => { return injectedScript => injectedScript.evaluateHandle((injected, { parsed, strict, state, omitReturnValue, root }) => {
let lastElement: Element | undefined; let lastElement: Element | undefined;
return injected.pollRaf((progress, continuePolling) => { return injected.pollRaf(progress => {
const elements = injected.querySelectorAll(parsed, root || document); const elements = injected.querySelectorAll(parsed, root || document);
let element: Element | undefined = elements[0]; let element: Element | undefined = elements[0];
const visible = element ? injected.isVisible(element) : false; const visible = element ? injected.isVisible(element) : false;
@ -977,13 +977,13 @@ export function waitForSelectorTask(selector: SelectorInfo, state: 'attached' |
switch (state) { switch (state) {
case 'attached': case 'attached':
return hasElement ? element : continuePolling; return hasElement ? element : progress.continuePolling;
case 'detached': case 'detached':
return !hasElement ? undefined : continuePolling; return !hasElement ? undefined : progress.continuePolling;
case 'visible': case 'visible':
return visible ? element : continuePolling; return visible ? element : progress.continuePolling;
case 'hidden': case 'hidden':
return !visible ? undefined : continuePolling; return !visible ? undefined : progress.continuePolling;
} }
}); });
}, { parsed: selector.parsed, strict: selector.strict, state, omitReturnValue, root }); }, { parsed: selector.parsed, strict: selector.strict, state, omitReturnValue, root });

View file

@ -70,7 +70,7 @@ export type NavigationEvent = {
}; };
export type SchedulableTask<T> = (injectedScript: js.JSHandle<InjectedScript>) => Promise<js.JSHandle<InjectedScriptPoll<T>>>; export type SchedulableTask<T> = (injectedScript: js.JSHandle<InjectedScript>) => Promise<js.JSHandle<InjectedScriptPoll<T>>>;
export type DomTaskBody<T, R, E> = (progress: InjectedScriptProgress, element: E, data: T, elements: Element[], continuePolling: symbol) => R | symbol; export type DomTaskBody<T, R, E> = (progress: InjectedScriptProgress, element: E, data: T, elements: Element[]) => R | symbol;
export class FrameManager { export class FrameManager {
private _page: Page; private _page: Page;
@ -1158,7 +1158,7 @@ export class Frame extends SdkObject {
const controller = new ProgressController(metadata, this); const controller = new ProgressController(metadata, this);
const querySelectorAll = options.expression === 'to.have.count' || options.expression.endsWith('.array'); const querySelectorAll = options.expression === 'to.have.count' || options.expression.endsWith('.array');
const mainWorld = options.expression === 'to.have.property'; const mainWorld = options.expression === 'to.have.property';
return await this._scheduleRerunnableTaskWithController(controller, selector, (progress, element, options, elements, continuePolling) => { return await this._scheduleRerunnableTaskWithController(controller, selector, (progress, element, options, elements) => {
if (!element) { if (!element) {
// expect(locator).toBeHidden() passes when there is no element. // expect(locator).toBeHidden() passes when there is no element.
if (!options.isNot && options.expression === 'to.be.hidden') if (!options.isNot && options.expression === 'to.be.hidden')
@ -1181,7 +1181,7 @@ export class Frame extends SdkObject {
return { matches: expectsEmptyCount, received: 0 }; return { matches: expectsEmptyCount, received: 0 };
// When none of the above applies, keep waiting for the element. // When none of the above applies, keep waiting for the element.
return continuePolling; return progress.continuePolling;
} }
const { matches, received } = progress.injectedScript.expect(progress, element, options, elements); const { matches, received } = progress.injectedScript.expect(progress, element, options, elements);
@ -1192,7 +1192,7 @@ export class Frame extends SdkObject {
progress.setIntermediateResult(received); progress.setIntermediateResult(received);
if (!Array.isArray(received)) if (!Array.isArray(received))
progress.log(` unexpected value "${received}"`); progress.log(` unexpected value "${received}"`);
return continuePolling; return progress.continuePolling;
} }
// Reached the expected state! // Reached the expected state!
@ -1226,8 +1226,8 @@ export class Frame extends SdkObject {
return result; return result;
}; };
if (typeof polling !== 'number') if (typeof polling !== 'number')
return injectedScript.pollRaf((progress, continuePolling) => predicate(arg) || continuePolling); return injectedScript.pollRaf(progress => predicate(arg) || progress.continuePolling);
return injectedScript.pollInterval(polling, (progress, continuePolling) => predicate(arg) || continuePolling); return injectedScript.pollInterval(polling, progress => predicate(arg) || progress.continuePolling);
}, { expression, isFunction, polling: options.pollingInterval, arg }); }, { expression, isFunction, polling: options.pollingInterval, arg });
return controller.run( return controller.run(
progress => this._scheduleRerunnableHandleTask(progress, world, task), progress => this._scheduleRerunnableHandleTask(progress, world, task),
@ -1286,7 +1286,7 @@ export class Frame extends SdkObject {
const callback = injected.eval(callbackText) as DomTaskBody<T, R, Element | undefined>; const callback = injected.eval(callbackText) as DomTaskBody<T, R, Element | undefined>;
const poller = logScale ? injected.pollLogScale.bind(injected) : injected.pollRaf.bind(injected); const poller = logScale ? injected.pollLogScale.bind(injected) : injected.pollRaf.bind(injected);
let markedElements = new Set<Element>(); let markedElements = new Set<Element>();
return poller((progress, continuePolling) => { return poller(progress => {
let element: Element | undefined; let element: Element | undefined;
let elements: Element[] = []; let elements: Element[] = [];
if (querySelectorAll) { if (querySelectorAll) {
@ -1301,7 +1301,7 @@ export class Frame extends SdkObject {
} }
if (!element && !omitAttached) if (!element && !omitAttached)
return continuePolling; return progress.continuePolling;
if (snapshotName) { if (snapshotName) {
const previouslyMarkedElements = markedElements; const previouslyMarkedElements = markedElements;
@ -1316,7 +1316,7 @@ export class Frame extends SdkObject {
} }
} }
return callback(progress, element, taskData as T, elements, continuePolling); return callback(progress, element, taskData as T, elements);
}); });
}, { info, taskData, callbackText, querySelectorAll: options.querySelectorAll, logScale: options.logScale, omitAttached: options.omitAttached, snapshotName: progress.metadata.afterSnapshot }); }, { info, taskData, callbackText, querySelectorAll: options.querySelectorAll, logScale: options.logScale, omitAttached: options.omitAttached, snapshotName: progress.metadata.afterSnapshot });
}, true); }, true);

View file

@ -24,10 +24,11 @@ import { CSSComplexSelectorList } from '../common/cssParser';
import { generateSelector } from './selectorGenerator'; import { generateSelector } from './selectorGenerator';
import type * as channels from '../../protocol/channels'; import type * as channels from '../../protocol/channels';
type Predicate<T> = (progress: InjectedScriptProgress, continuePolling: symbol) => T | symbol; type Predicate<T> = (progress: InjectedScriptProgress) => T | symbol;
export type InjectedScriptProgress = { export type InjectedScriptProgress = {
injectedScript: InjectedScript; injectedScript: InjectedScript;
continuePolling: symbol;
aborted: boolean; aborted: boolean;
log: (message: string) => void; log: (message: string) => void;
logRepeating: (message: string) => void; logRepeating: (message: string) => void;
@ -293,9 +294,8 @@ export class InjectedScript {
if (progress.aborted) if (progress.aborted)
return; return;
try { try {
const continuePolling = Symbol('continuePolling'); const success = predicate(progress);
const success = predicate(progress, continuePolling); if (success !== progress.continuePolling)
if (success !== continuePolling)
fulfill(success as T); fulfill(success as T);
else else
scheduleNext(next); scheduleNext(next);
@ -333,6 +333,7 @@ export class InjectedScript {
const progress: InjectedScriptProgress = { const progress: InjectedScriptProgress = {
injectedScript: this, injectedScript: this,
aborted: false, aborted: false,
continuePolling: Symbol('continuePolling'),
log: (message: string) => { log: (message: string) => {
lastMessage = message; lastMessage = message;
unsentLog.push({ message }); unsentLog.push({ message });
@ -399,16 +400,16 @@ export class InjectedScript {
} }
waitForElementStatesAndPerformAction<T>(node: Node, states: ElementState[], force: boolean | undefined, waitForElementStatesAndPerformAction<T>(node: Node, states: ElementState[], force: boolean | undefined,
callback: (node: Node, progress: InjectedScriptProgress, continuePolling: symbol) => T | symbol): InjectedScriptPoll<T | 'error:notconnected'> { callback: (node: Node, progress: InjectedScriptProgress) => T | symbol): InjectedScriptPoll<T | 'error:notconnected'> {
let lastRect: { x: number, y: number, width: number, height: number } | undefined; let lastRect: { x: number, y: number, width: number, height: number } | undefined;
let counter = 0; let counter = 0;
let samePositionCounter = 0; let samePositionCounter = 0;
let lastTime = 0; let lastTime = 0;
return this.pollRaf((progress, continuePolling) => { return this.pollRaf(progress => {
if (force) { if (force) {
progress.log(` forcing action`); progress.log(` forcing action`);
return callback(node, progress, continuePolling); return callback(node, progress);
} }
for (const state of states) { for (const state of states) {
@ -418,7 +419,7 @@ export class InjectedScript {
return result; return result;
if (!result) { if (!result) {
progress.logRepeating(` element is not ${state} - waiting...`); progress.logRepeating(` element is not ${state} - waiting...`);
return continuePolling; return progress.continuePolling;
} }
continue; continue;
} }
@ -431,12 +432,12 @@ export class InjectedScript {
// any client rect difference compared to synchronous call. We skip the synchronous call // any client rect difference compared to synchronous call. We skip the synchronous call
// and only force layout during actual rafs as a small optimisation. // and only force layout during actual rafs as a small optimisation.
if (++counter === 1) if (++counter === 1)
return continuePolling; return progress.continuePolling;
// Drop frames that are shorter than 16ms - WebKit Win bug. // Drop frames that are shorter than 16ms - WebKit Win bug.
const time = performance.now(); const time = performance.now();
if (this._stableRafCount > 1 && time - lastTime < 15) if (this._stableRafCount > 1 && time - lastTime < 15)
return continuePolling; return progress.continuePolling;
lastTime = time; lastTime = time;
const clientRect = element.getBoundingClientRect(); const clientRect = element.getBoundingClientRect();
@ -452,10 +453,10 @@ export class InjectedScript {
if (!isStableForLogs) if (!isStableForLogs)
progress.logRepeating(` element is not stable - waiting...`); progress.logRepeating(` element is not stable - waiting...`);
if (!isStable) if (!isStable)
return continuePolling; return progress.continuePolling;
} }
return callback(node, progress, continuePolling); return callback(node, progress);
}); });
} }
@ -495,7 +496,7 @@ export class InjectedScript {
} }
selectOptions(optionsToSelect: (Node | { value?: string, label?: string, index?: number })[], selectOptions(optionsToSelect: (Node | { value?: string, label?: string, index?: number })[],
node: Node, progress: InjectedScriptProgress, continuePolling: symbol): string[] | 'error:notconnected' | symbol { node: Node, progress: InjectedScriptProgress): string[] | 'error:notconnected' | symbol {
const element = this.retarget(node, 'follow-label'); const element = this.retarget(node, 'follow-label');
if (!element) if (!element)
return 'error:notconnected'; return 'error:notconnected';
@ -531,7 +532,7 @@ export class InjectedScript {
} }
if (remainingOptionsToSelect.length) { if (remainingOptionsToSelect.length) {
progress.logRepeating(' did not find some options - waiting... '); progress.logRepeating(' did not find some options - waiting... ');
return continuePolling; return progress.continuePolling;
} }
select.value = undefined as any; select.value = undefined as any;
selectedOptions.forEach(option => option.selected = true); selectedOptions.forEach(option => option.selected = true);