fix: noWaitAfter option for hover (#17856)

Fixes https://github.com/microsoft/playwright/issues/17833
This commit is contained in:
Yury Semikhatsky 2022-10-07 12:43:48 -07:00 committed by GitHub
parent 1b5c2f9aba
commit 639b28db3b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 67 additions and 2 deletions

View File

@ -555,6 +555,9 @@ When all steps combined have not finished during the specified [`option: timeout
### option: ElementHandle.hover.trial = %%-input-trial-%%
* since: v1.11
### option: ElementHandle.hover.noWaitAfter = %%-input-no-wait-after-%%
* since: v1.28
## async method: ElementHandle.innerHTML
* since: v1.8
- returns: <[string]>

View File

@ -1059,6 +1059,8 @@ When all steps combined have not finished during the specified [`option: timeout
* since: v1.8
### option: Frame.hover.trial = %%-input-trial-%%
* since: v1.11
### option: Frame.hover.noWaitAfter = %%-input-no-wait-after-%%
* since: v1.28
## async method: Frame.innerHTML
* since: v1.8

View File

@ -734,6 +734,8 @@ When all steps combined have not finished during the specified [`option: timeout
* since: v1.14
### option: Locator.hover.trial = %%-input-trial-%%
* since: v1.14
### option: Locator.hover.noWaitAfter = %%-input-no-wait-after-%%
* since: v1.28
## async method: Locator.innerHTML
* since: v1.14

View File

@ -2369,6 +2369,8 @@ Shortcut for main frame's [`method: Frame.hover`].
* since: v1.8
### option: Page.hover.trial = %%-input-trial-%%
* since: v1.11
### option: Page.hover.noWaitAfter = %%-input-no-wait-after-%%
* since: v1.28
## async method: Page.innerHTML
* since: v1.8

View File

@ -1331,6 +1331,7 @@ scheme.FrameHoverParams = tObject({
position: tOptional(tType('Point')),
timeout: tOptional(tNumber),
trial: tOptional(tBoolean),
noWaitAfter: tOptional(tBoolean),
});
scheme.FrameHoverResult = tOptional(tObject({}));
scheme.FrameInnerHTMLParams = tObject({
@ -1717,6 +1718,7 @@ scheme.ElementHandleHoverParams = tObject({
position: tOptional(tType('Point')),
timeout: tOptional(tNumber),
trial: tOptional(tBoolean),
noWaitAfter: tOptional(tBoolean),
});
scheme.ElementHandleHoverResult = tOptional(tObject({}));
scheme.ElementHandleInnerHTMLParams = tOptional(tObject({}));

View File

@ -499,7 +499,7 @@ export class ElementHandle<T extends Node = Node> extends js.JSHandle<T> {
}, this._page._timeoutSettings.timeout(options));
}
_hover(progress: Progress, options: types.PointerActionOptions & types.PointerActionWaitOptions): Promise<'error:notconnected' | 'done'> {
_hover(progress: Progress, options: types.PointerActionOptions & types.PointerActionWaitOptions & types.NavigatingActionWaitOptions): Promise<'error:notconnected' | 'done'> {
return this._retryPointerAction(progress, 'hover', false /* waitForEnabled */, point => this._page.mouse.move(point.x, point.y), options);
}

View File

@ -1287,7 +1287,7 @@ export class Frame extends SdkObject {
return this._elementState(metadata, selector, 'checked', options);
}
async hover(metadata: CallMetadata, selector: string, options: types.PointerActionOptions & types.PointerActionWaitOptions = {}) {
async hover(metadata: CallMetadata, selector: string, options: types.PointerActionOptions & types.PointerActionWaitOptions & types.NavigatingActionWaitOptions = {}) {
const controller = new ProgressController(metadata, this);
return controller.run(async progress => {
return dom.assertDone(await this._retryWithProgressIfNotConnected(progress, selector, options.strict, handle => handle._hover(progress, options)));

View File

@ -2753,6 +2753,13 @@ export interface Page {
*/
modifiers?: Array<"Alt"|"Control"|"Meta"|"Shift">;
/**
* Actions that initiate navigations are waiting for these navigations to happen and for pages to start loading. You can
* opt out of waiting via setting this flag. You would only need this option in the exceptional cases such as navigating to
* inaccessible pages. Defaults to `false`.
*/
noWaitAfter?: boolean;
/**
* A point to use relative to the top-left corner of element padding box. If not specified, uses some visible point of the
* element.
@ -5785,6 +5792,13 @@ export interface Frame {
*/
modifiers?: Array<"Alt"|"Control"|"Meta"|"Shift">;
/**
* Actions that initiate navigations are waiting for these navigations to happen and for pages to start loading. You can
* opt out of waiting via setting this flag. You would only need this option in the exceptional cases such as navigating to
* inaccessible pages. Defaults to `false`.
*/
noWaitAfter?: boolean;
/**
* A point to use relative to the top-left corner of element padding box. If not specified, uses some visible point of the
* element.
@ -8710,6 +8724,13 @@ export interface ElementHandle<T=Node> extends JSHandle<T> {
*/
modifiers?: Array<"Alt"|"Control"|"Meta"|"Shift">;
/**
* Actions that initiate navigations are waiting for these navigations to happen and for pages to start loading. You can
* opt out of waiting via setting this flag. You would only need this option in the exceptional cases such as navigating to
* inaccessible pages. Defaults to `false`.
*/
noWaitAfter?: boolean;
/**
* A point to use relative to the top-left corner of element padding box. If not specified, uses some visible point of the
* element.
@ -10171,6 +10192,13 @@ export interface Locator {
*/
modifiers?: Array<"Alt"|"Control"|"Meta"|"Shift">;
/**
* Actions that initiate navigations are waiting for these navigations to happen and for pages to start loading. You can
* opt out of waiting via setting this flag. You would only need this option in the exceptional cases such as navigating to
* inaccessible pages. Defaults to `false`.
*/
noWaitAfter?: boolean;
/**
* A point to use relative to the top-left corner of element padding box. If not specified, uses some visible point of the
* element.

View File

@ -2441,6 +2441,7 @@ export type FrameHoverParams = {
position?: Point,
timeout?: number,
trial?: boolean,
noWaitAfter?: boolean,
};
export type FrameHoverOptions = {
strict?: boolean,
@ -2449,6 +2450,7 @@ export type FrameHoverOptions = {
position?: Point,
timeout?: number,
trial?: boolean,
noWaitAfter?: boolean,
};
export type FrameHoverResult = void;
export type FrameInnerHTMLParams = {
@ -3095,6 +3097,7 @@ export type ElementHandleHoverParams = {
position?: Point,
timeout?: number,
trial?: boolean,
noWaitAfter?: boolean,
};
export type ElementHandleHoverOptions = {
force?: boolean,
@ -3102,6 +3105,7 @@ export type ElementHandleHoverOptions = {
position?: Point,
timeout?: number,
trial?: boolean,
noWaitAfter?: boolean,
};
export type ElementHandleHoverResult = void;
export type ElementHandleInnerHTMLParams = {};

View File

@ -1767,6 +1767,7 @@ Frame:
position: Point?
timeout: number?
trial: boolean?
noWaitAfter: boolean?
tracing:
snapshot: true
pausesBeforeInput: true
@ -2332,6 +2333,7 @@ ElementHandle:
position: Point?
timeout: number?
trial: boolean?
noWaitAfter: boolean?
tracing:
snapshot: true
pausesBeforeInput: true

View File

@ -33,6 +33,16 @@ it('should hover when Node is removed', async ({ page, server }) => {
expect(await page.evaluate(() => document.querySelector('button:hover').id)).toBe('button-6');
});
it('hover should support noWaitAfter', async ({ page, server }) => {
await page.goto(server.EMPTY_PAGE);
await page.setContent(`<button onmouseover='location.href="${server.PREFIX}/next"'>GO</button>`);
await Promise.all([
new Promise(fulfill => server.setRoute('/next', fulfill)),
page.locator('button').hover({ noWaitAfter: true })
]);
expect(page.url()).toBe(server.EMPTY_PAGE);
});
it('should fill input', async ({ page, server }) => {
await page.goto(server.PREFIX + '/input/textarea.html');
const handle = page.locator('input');

View File

@ -173,6 +173,16 @@ it('should trigger hover state', async ({ page, server }) => {
expect(await page.evaluate(() => document.querySelector('button:hover').id)).toBe('button-91');
});
it('hover should support noWaitAfter', async ({ page, server }) => {
await page.goto(server.EMPTY_PAGE);
await page.setContent(`<button onmouseover='location.href="${server.PREFIX}/next"'>GO</button>`);
await Promise.all([
new Promise(fulfill => server.setRoute('/next', fulfill)),
page.hover('button', { noWaitAfter: true })
]);
expect(page.url()).toBe(server.EMPTY_PAGE);
});
it('should trigger hover state on disabled button', async ({ page, server }) => {
await page.goto(server.PREFIX + '/input/scrollable.html');
await page.$eval('#button-6', (button: HTMLButtonElement) => button.disabled = true);