Skip to content

Commit dbb45d4

Browse files
authored
Revert "feat(click): waitForInteractable option, defaults to true (#934)" (#1013)
Reason: new tests are flaky on all bots.
1 parent 9413351 commit dbb45d4

File tree

8 files changed

+63
-236
lines changed

8 files changed

+63
-236
lines changed

docs/api.md

+7-33
Large diffs are not rendered by default.

src/dom.ts

+38-85
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,6 @@ import { Page } from './page';
2525
import * as platform from './platform';
2626
import { Selectors } from './selectors';
2727

28-
export type WaitForInteractableOptions = types.TimeoutOptions & { waitForInteractable?: boolean };
29-
3028
export class FrameExecutionContext extends js.ExecutionContext {
3129
readonly frame: frames.Frame;
3230

@@ -232,15 +230,10 @@ export class ElementHandle<T extends Node = Node> extends js.JSHandle<T> {
232230
return point;
233231
}
234232

235-
async _performPointerAction(action: (point: types.Point) => Promise<void>, options?: input.PointerActionOptions & WaitForInteractableOptions): Promise<void> {
236-
const { waitForInteractable = true } = (options || {});
237-
if (waitForInteractable)
238-
await this._waitForStablePosition(options);
233+
async _performPointerAction(action: (point: types.Point) => Promise<void>, options?: input.PointerActionOptions): Promise<void> {
239234
const relativePoint = options ? options.relativePoint : undefined;
240235
await this._scrollRectIntoViewIfNeeded(relativePoint ? { x: relativePoint.x, y: relativePoint.y, width: 0, height: 0 } : undefined);
241236
const point = relativePoint ? await this._relativePoint(relativePoint) : await this._clickablePoint();
242-
if (waitForInteractable)
243-
await this._waitForHitTargetAt(point, options);
244237
let restoreModifiers: input.Modifier[] | undefined;
245238
if (options && options.modifiers)
246239
restoreModifiers = await this._page.keyboard._ensureModifiers(options.modifiers);
@@ -249,19 +242,19 @@ export class ElementHandle<T extends Node = Node> extends js.JSHandle<T> {
249242
await this._page.keyboard._ensureModifiers(restoreModifiers);
250243
}
251244

252-
hover(options?: input.PointerActionOptions & WaitForInteractableOptions): Promise<void> {
245+
hover(options?: input.PointerActionOptions): Promise<void> {
253246
return this._performPointerAction(point => this._page.mouse.move(point.x, point.y), options);
254247
}
255248

256-
click(options?: input.ClickOptions & WaitForInteractableOptions): Promise<void> {
249+
click(options?: input.ClickOptions): Promise<void> {
257250
return this._performPointerAction(point => this._page.mouse.click(point.x, point.y, options), options);
258251
}
259252

260-
dblclick(options?: input.MultiClickOptions & WaitForInteractableOptions): Promise<void> {
253+
dblclick(options?: input.MultiClickOptions): Promise<void> {
261254
return this._performPointerAction(point => this._page.mouse.dblclick(point.x, point.y, options), options);
262255
}
263256

264-
tripleclick(options?: input.MultiClickOptions & WaitForInteractableOptions): Promise<void> {
257+
tripleclick(options?: input.MultiClickOptions): Promise<void> {
265258
return this._performPointerAction(point => this._page.mouse.tripleclick(point.x, point.y, options), options);
266259
}
267260

@@ -409,20 +402,19 @@ export class ElementHandle<T extends Node = Node> extends js.JSHandle<T> {
409402
await this._page.keyboard.type(text, options);
410403
}
411404

412-
async press(key: string, options?: { delay?: number, text?: string }) {
405+
async press(key: string, options: { delay?: number; text?: string; } | undefined) {
413406
await this.focus();
414407
await this._page.keyboard.press(key, options);
415408
}
416-
417-
async check(options?: WaitForInteractableOptions) {
418-
await this._setChecked(true, options);
409+
async check() {
410+
await this._setChecked(true);
419411
}
420412

421-
async uncheck(options?: WaitForInteractableOptions) {
422-
await this._setChecked(false, options);
413+
async uncheck() {
414+
await this._setChecked(false);
423415
}
424416

425-
private async _setChecked(state: boolean, options: WaitForInteractableOptions = {}) {
417+
private async _setChecked(state: boolean) {
426418
const isCheckboxChecked = async (): Promise<boolean> => {
427419
return this._evaluateInUtility((node: Node) => {
428420
if (node.nodeType !== Node.ELEMENT_NODE)
@@ -450,7 +442,7 @@ export class ElementHandle<T extends Node = Node> extends js.JSHandle<T> {
450442

451443
if (await isCheckboxChecked() === state)
452444
return;
453-
await this.click(options);
445+
await this.click();
454446
if (await isCheckboxChecked() !== state)
455447
throw new Error('Unable to click checkbox');
456448
}
@@ -505,52 +497,6 @@ export class ElementHandle<T extends Node = Node> extends js.JSHandle<T> {
505497
return visibleRatio;
506498
});
507499
}
508-
509-
async _waitForStablePosition(options: types.TimeoutOptions = {}): Promise<void> {
510-
const context = await this._context.frame._utilityContext();
511-
const stablePromise = context.evaluate((injected: Injected, node: Node, timeout: number) => {
512-
if (!node.isConnected)
513-
throw new Error('Element is not attached to the DOM');
514-
const element = node.nodeType === Node.ELEMENT_NODE ? (node as Element) : node.parentElement;
515-
if (!element)
516-
throw new Error('Element is not attached to the DOM');
517-
518-
let lastRect: types.Rect | undefined;
519-
return injected.poll('raf', undefined, timeout, () => {
520-
const clientRect = element.getBoundingClientRect();
521-
const rect = { x: clientRect.top, y: clientRect.left, width: clientRect.width, height: clientRect.height };
522-
const isStable = lastRect && rect.x === lastRect.x && rect.y === lastRect.y && rect.width === lastRect.width && rect.height === lastRect.height;
523-
lastRect = rect;
524-
return isStable;
525-
});
526-
}, await context._injected(), this, options.timeout || 0);
527-
await helper.waitWithTimeout(stablePromise, 'element to stop moving', options.timeout || 0);
528-
}
529-
530-
async _waitForHitTargetAt(point: types.Point, options: types.TimeoutOptions = {}): Promise<void> {
531-
const frame = await this.ownerFrame();
532-
if (frame && frame.parentFrame()) {
533-
const element = await frame.frameElement();
534-
const box = await element.boundingBox();
535-
if (!box)
536-
throw new Error('Element is not attached to the DOM');
537-
// Translate from viewport coordinates to frame coordinates.
538-
point = { x: point.x - box.x, y: point.y - box.y };
539-
}
540-
const context = await this._context.frame._utilityContext();
541-
const hitTargetPromise = context.evaluate((injected: Injected, node: Node, timeout: number, point: types.Point) => {
542-
const element = node.nodeType === Node.ELEMENT_NODE ? (node as Element) : node.parentElement;
543-
if (!element)
544-
throw new Error('Element is not attached to the DOM');
545-
return injected.poll('raf', undefined, timeout, () => {
546-
let hitElement = injected.utils.deepElementFromPoint(document, point.x, point.y);
547-
while (hitElement && hitElement !== element)
548-
hitElement = injected.utils.parentElementOrShadowHost(hitElement);
549-
return hitElement === element;
550-
});
551-
}, await context._injected(), this, options.timeout || 0, point);
552-
await helper.waitWithTimeout(hitTargetPromise, 'element to receive mouse events', options.timeout || 0);
553-
}
554500
}
555501

556502
function normalizeSelector(selector: string): string {
@@ -568,44 +514,51 @@ function normalizeSelector(selector: string): string {
568514

569515
export type Task = (context: FrameExecutionContext) => Promise<js.JSHandle>;
570516

571-
function assertPolling(polling: types.Polling) {
517+
export function waitForFunctionTask(selector: string | undefined, pageFunction: Function | string, options: types.WaitForFunctionOptions, ...args: any[]) {
518+
const { polling = 'raf' } = options;
572519
if (helper.isString(polling))
573520
assert(polling === 'raf' || polling === 'mutation', 'Unknown polling option: ' + polling);
574521
else if (helper.isNumber(polling))
575522
assert(polling > 0, 'Cannot poll with non-positive interval: ' + polling);
576523
else
577524
throw new Error('Unknown polling options: ' + polling);
578-
}
579-
580-
export function waitForFunctionTask(selector: string | undefined, pageFunction: Function | string, options: types.WaitForFunctionOptions, ...args: any[]): Task {
581-
const { polling = 'raf' } = options;
582-
assertPolling(polling);
583525
const predicateBody = helper.isString(pageFunction) ? 'return (' + pageFunction + ')' : 'return (' + pageFunction + ')(...args)';
584526
if (selector !== undefined)
585527
selector = normalizeSelector(selector);
586528

587529
return async (context: FrameExecutionContext) => context.evaluateHandle((injected: Injected, selector: string | undefined, predicateBody: string, polling: types.Polling, timeout: number, ...args) => {
588530
const innerPredicate = new Function('...args', predicateBody);
589-
return injected.poll(polling, selector, timeout, (element: Element | undefined): any => {
531+
if (polling === 'raf')
532+
return injected.pollRaf(selector, predicate, timeout);
533+
if (polling === 'mutation')
534+
return injected.pollMutation(selector, predicate, timeout);
535+
return injected.pollInterval(selector, polling, predicate, timeout);
536+
537+
function predicate(element: Element | undefined): any {
590538
if (selector === undefined)
591539
return innerPredicate(...args);
592540
return innerPredicate(element, ...args);
593-
});
541+
}
594542
}, await context._injected(), selector, predicateBody, polling, options.timeout || 0, ...args);
595543
}
596544

597545
export function waitForSelectorTask(selector: string, visibility: types.Visibility, timeout: number): Task {
598-
selector = normalizeSelector(selector);
599-
return async (context: FrameExecutionContext) => context.evaluateHandle((injected: Injected, selector: string, visibility: types.Visibility, timeout: number) => {
600-
const polling = visibility === 'any' ? 'mutation' : 'raf';
601-
return injected.poll(polling, selector, timeout, (element: Element | undefined): Element | boolean => {
602-
if (!element)
603-
return visibility === 'hidden';
604-
if (visibility === 'any')
605-
return element;
606-
return injected.isVisible(element) === (visibility === 'visible') ? element : false;
607-
});
608-
}, await context._injected(), selector, visibility, timeout);
546+
return async (context: FrameExecutionContext) => {
547+
selector = normalizeSelector(selector);
548+
return context.evaluateHandle((injected: Injected, selector: string, visibility: types.Visibility, timeout: number) => {
549+
if (visibility !== 'any')
550+
return injected.pollRaf(selector, predicate, timeout);
551+
return injected.pollMutation(selector, predicate, timeout);
552+
553+
function predicate(element: Element | undefined): Element | boolean {
554+
if (!element)
555+
return visibility === 'hidden';
556+
if (visibility === 'any')
557+
return element;
558+
return injected.isVisible(element) === (visibility === 'visible') ? element : false;
559+
}
560+
}, await context._injected(), selector, visibility, timeout);
561+
};
609562
}
610563

611564
export const setFileInputFunction = async (element: HTMLInputElement, payloads: types.FilePayload[]) => {

src/frames.ts

+8-8
Original file line numberDiff line numberDiff line change
@@ -780,19 +780,19 @@ export class Frame {
780780
return result!;
781781
}
782782

783-
async click(selector: string, options?: WaitForOptions & ClickOptions & dom.WaitForInteractableOptions) {
783+
async click(selector: string, options?: WaitForOptions & ClickOptions) {
784784
const handle = await this._optionallyWaitForSelectorInUtilityContext(selector, options);
785785
await handle.click(options);
786786
await handle.dispose();
787787
}
788788

789-
async dblclick(selector: string, options?: WaitForOptions & MultiClickOptions & dom.WaitForInteractableOptions) {
789+
async dblclick(selector: string, options?: WaitForOptions & MultiClickOptions) {
790790
const handle = await this._optionallyWaitForSelectorInUtilityContext(selector, options);
791791
await handle.dblclick(options);
792792
await handle.dispose();
793793
}
794794

795-
async tripleclick(selector: string, options?: WaitForOptions & MultiClickOptions & dom.WaitForInteractableOptions) {
795+
async tripleclick(selector: string, options?: WaitForOptions & MultiClickOptions) {
796796
const handle = await this._optionallyWaitForSelectorInUtilityContext(selector, options);
797797
await handle.tripleclick(options);
798798
await handle.dispose();
@@ -810,7 +810,7 @@ export class Frame {
810810
await handle.dispose();
811811
}
812812

813-
async hover(selector: string, options?: WaitForOptions & PointerActionOptions & dom.WaitForInteractableOptions) {
813+
async hover(selector: string, options?: WaitForOptions & PointerActionOptions) {
814814
const handle = await this._optionallyWaitForSelectorInUtilityContext(selector, options);
815815
await handle.hover(options);
816816
await handle.dispose();
@@ -830,15 +830,15 @@ export class Frame {
830830
await handle.dispose();
831831
}
832832

833-
async check(selector: string, options?: WaitForOptions & dom.WaitForInteractableOptions) {
833+
async check(selector: string, options?: WaitForOptions) {
834834
const handle = await this._optionallyWaitForSelectorInUtilityContext(selector, options);
835-
await handle.check(options);
835+
await handle.check();
836836
await handle.dispose();
837837
}
838838

839-
async uncheck(selector: string, options?: WaitForOptions & dom.WaitForInteractableOptions) {
839+
async uncheck(selector: string, options?: WaitForOptions) {
840840
const handle = await this._optionallyWaitForSelectorInUtilityContext(selector, options);
841-
await handle.uncheck(options);
841+
await handle.uncheck();
842842
await handle.dispose();
843843
}
844844

src/injected/injected.ts

+3-11
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,7 @@ class Injected {
145145
return !!(rect.top || rect.bottom || rect.width || rect.height);
146146
}
147147

148-
private _pollMutation(selector: string | undefined, predicate: Predicate, timeout: number): Promise<any> {
148+
pollMutation(selector: string | undefined, predicate: Predicate, timeout: number): Promise<any> {
149149
let timedOut = false;
150150
if (timeout)
151151
setTimeout(() => timedOut = true, timeout);
@@ -178,7 +178,7 @@ class Injected {
178178
return result;
179179
}
180180

181-
private _pollRaf(selector: string | undefined, predicate: Predicate, timeout: number): Promise<any> {
181+
pollRaf(selector: string | undefined, predicate: Predicate, timeout: number): Promise<any> {
182182
let timedOut = false;
183183
if (timeout)
184184
setTimeout(() => timedOut = true, timeout);
@@ -203,7 +203,7 @@ class Injected {
203203
return result;
204204
}
205205

206-
private _pollInterval(selector: string | undefined, pollInterval: number, predicate: Predicate, timeout: number): Promise<any> {
206+
pollInterval(selector: string | undefined, pollInterval: number, predicate: Predicate, timeout: number): Promise<any> {
207207
let timedOut = false;
208208
if (timeout)
209209
setTimeout(() => timedOut = true, timeout);
@@ -226,14 +226,6 @@ class Injected {
226226
onTimeout();
227227
return result;
228228
}
229-
230-
poll(polling: 'raf' | 'mutation' | number, selector: string | undefined, timeout: number, predicate: Predicate): Promise<any> {
231-
if (polling === 'raf')
232-
return this._pollRaf(selector, predicate, timeout);
233-
if (polling === 'mutation')
234-
return this._pollMutation(selector, predicate, timeout);
235-
return this._pollInterval(selector, polling, predicate, timeout);
236-
}
237229
}
238230

239231
export default Injected;

src/page.ts

+6-6
Original file line numberDiff line numberDiff line change
@@ -485,15 +485,15 @@ export class Page extends platform.EventEmitter {
485485
return this._closed;
486486
}
487487

488-
async click(selector: string, options?: frames.WaitForOptions & input.ClickOptions & dom.WaitForInteractableOptions) {
488+
async click(selector: string, options?: frames.WaitForOptions & input.ClickOptions) {
489489
return this.mainFrame().click(selector, options);
490490
}
491491

492-
async dblclick(selector: string, options?: frames.WaitForOptions & input.MultiClickOptions & dom.WaitForInteractableOptions) {
492+
async dblclick(selector: string, options?: frames.WaitForOptions & input.MultiClickOptions) {
493493
return this.mainFrame().dblclick(selector, options);
494494
}
495495

496-
async tripleclick(selector: string, options?: frames.WaitForOptions & input.MultiClickOptions & dom.WaitForInteractableOptions) {
496+
async tripleclick(selector: string, options?: frames.WaitForOptions & input.MultiClickOptions) {
497497
return this.mainFrame().tripleclick(selector, options);
498498
}
499499

@@ -505,7 +505,7 @@ export class Page extends platform.EventEmitter {
505505
return this.mainFrame().focus(selector, options);
506506
}
507507

508-
async hover(selector: string, options?: frames.WaitForOptions & input.PointerActionOptions & dom.WaitForInteractableOptions) {
508+
async hover(selector: string, options?: frames.WaitForOptions & input.PointerActionOptions) {
509509
return this.mainFrame().hover(selector, options);
510510
}
511511

@@ -517,11 +517,11 @@ export class Page extends platform.EventEmitter {
517517
return this.mainFrame().type(selector, text, options);
518518
}
519519

520-
async check(selector: string, options?: frames.WaitForOptions & dom.WaitForInteractableOptions) {
520+
async check(selector: string, options?: frames.WaitForOptions) {
521521
return this.mainFrame().check(selector, options);
522522
}
523523

524-
async uncheck(selector: string, options?: frames.WaitForOptions & dom.WaitForInteractableOptions) {
524+
async uncheck(selector: string, options?: frames.WaitForOptions) {
525525
return this.mainFrame().uncheck(selector, options);
526526
}
527527

test/assets/input/button.html

-2
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,6 @@
1313
window.pageX = undefined;
1414
window.pageY = undefined;
1515
window.shiftKey = undefined;
16-
window.pageX = undefined;
17-
window.pageY = undefined;
1816
document.querySelector('button').addEventListener('click', e => {
1917
result = 'Clicked';
2018
offsetX = e.offsetX;

0 commit comments

Comments
 (0)