mirror of
https://github.com/microsoft/playwright.git
synced 2024-12-15 06:02:57 +03:00
feat(force): add fill, selectOption, selectText ({force}) (#7286)
This commit is contained in:
parent
ba3f0ff6f5
commit
e6bf0a07fe
@ -448,8 +448,8 @@ To send fine-grained keyboard events, use [`method: ElementHandle.type`].
|
|||||||
|
|
||||||
Value to set for the `<input>`, `<textarea>` or `[contenteditable]` element.
|
Value to set for the `<input>`, `<textarea>` or `[contenteditable]` element.
|
||||||
|
|
||||||
|
### option: ElementHandle.fill.force = %%-input-force-%%
|
||||||
### option: ElementHandle.fill.noWaitAfter = %%-input-no-wait-after-%%
|
### option: ElementHandle.fill.noWaitAfter = %%-input-no-wait-after-%%
|
||||||
|
|
||||||
### option: ElementHandle.fill.timeout = %%-input-timeout-%%
|
### option: ElementHandle.fill.timeout = %%-input-timeout-%%
|
||||||
|
|
||||||
## async method: ElementHandle.focus
|
## async method: ElementHandle.focus
|
||||||
@ -717,9 +717,8 @@ await handle.SelectOptionAsync(new[] {
|
|||||||
```
|
```
|
||||||
|
|
||||||
### param: ElementHandle.selectOption.values = %%-select-options-values-%%
|
### param: ElementHandle.selectOption.values = %%-select-options-values-%%
|
||||||
|
### option: ElementHandle.selectOption.force = %%-input-force-%%
|
||||||
### option: ElementHandle.selectOption.noWaitAfter = %%-input-no-wait-after-%%
|
### option: ElementHandle.selectOption.noWaitAfter = %%-input-no-wait-after-%%
|
||||||
|
|
||||||
### option: ElementHandle.selectOption.timeout = %%-input-timeout-%%
|
### option: ElementHandle.selectOption.timeout = %%-input-timeout-%%
|
||||||
|
|
||||||
## async method: ElementHandle.selectText
|
## async method: ElementHandle.selectText
|
||||||
@ -727,6 +726,7 @@ await handle.SelectOptionAsync(new[] {
|
|||||||
This method waits for [actionability](./actionability.md) checks, then focuses the element and selects all its text
|
This method waits for [actionability](./actionability.md) checks, then focuses the element and selects all its text
|
||||||
content.
|
content.
|
||||||
|
|
||||||
|
### option: ElementHandle.selectText.force = %%-input-force-%%
|
||||||
### option: ElementHandle.selectText.timeout = %%-input-timeout-%%
|
### option: ElementHandle.selectText.timeout = %%-input-timeout-%%
|
||||||
|
|
||||||
## async method: ElementHandle.setInputFiles
|
## async method: ElementHandle.setInputFiles
|
||||||
|
@ -699,8 +699,8 @@ To send fine-grained keyboard events, use [`method: Frame.type`].
|
|||||||
|
|
||||||
Value to fill for the `<input>`, `<textarea>` or `[contenteditable]` element.
|
Value to fill for the `<input>`, `<textarea>` or `[contenteditable]` element.
|
||||||
|
|
||||||
|
### option: Frame.fill.force = %%-input-force-%%
|
||||||
### option: Frame.fill.noWaitAfter = %%-input-no-wait-after-%%
|
### option: Frame.fill.noWaitAfter = %%-input-no-wait-after-%%
|
||||||
|
|
||||||
### option: Frame.fill.timeout = %%-input-timeout-%%
|
### option: Frame.fill.timeout = %%-input-timeout-%%
|
||||||
|
|
||||||
## async method: Frame.focus
|
## async method: Frame.focus
|
||||||
@ -1065,11 +1065,9 @@ await frame.SelectOptionAsync("select#colors", new[] { "red", "green", "blue" })
|
|||||||
```
|
```
|
||||||
|
|
||||||
### param: Frame.selectOption.selector = %%-query-selector-%%
|
### param: Frame.selectOption.selector = %%-query-selector-%%
|
||||||
|
|
||||||
### param: Frame.selectOption.values = %%-select-options-values-%%
|
### param: Frame.selectOption.values = %%-select-options-values-%%
|
||||||
|
### option: Frame.selectOption.force = %%-input-force-%%
|
||||||
### option: Frame.selectOption.noWaitAfter = %%-input-no-wait-after-%%
|
### option: Frame.selectOption.noWaitAfter = %%-input-no-wait-after-%%
|
||||||
|
|
||||||
### option: Frame.selectOption.timeout = %%-input-timeout-%%
|
### option: Frame.selectOption.timeout = %%-input-timeout-%%
|
||||||
|
|
||||||
## async method: Frame.setContent
|
## async method: Frame.setContent
|
||||||
|
@ -1746,8 +1746,8 @@ Shortcut for main frame's [`method: Frame.fill`].
|
|||||||
|
|
||||||
Value to fill for the `<input>`, `<textarea>` or `[contenteditable]` element.
|
Value to fill for the `<input>`, `<textarea>` or `[contenteditable]` element.
|
||||||
|
|
||||||
|
### option: Page.fill.force = %%-input-force-%%
|
||||||
### option: Page.fill.noWaitAfter = %%-input-no-wait-after-%%
|
### option: Page.fill.noWaitAfter = %%-input-no-wait-after-%%
|
||||||
|
|
||||||
### option: Page.fill.timeout = %%-input-timeout-%%
|
### option: Page.fill.timeout = %%-input-timeout-%%
|
||||||
|
|
||||||
## async method: Page.focus
|
## async method: Page.focus
|
||||||
@ -2631,11 +2631,9 @@ await page.SelectOptionAsync("select#colors", new[] { "red", "green", "blue" });
|
|||||||
Shortcut for main frame's [`method: Frame.selectOption`].
|
Shortcut for main frame's [`method: Frame.selectOption`].
|
||||||
|
|
||||||
### param: Page.selectOption.selector = %%-input-selector-%%
|
### param: Page.selectOption.selector = %%-input-selector-%%
|
||||||
|
|
||||||
### param: Page.selectOption.values = %%-select-options-values-%%
|
### param: Page.selectOption.values = %%-select-options-values-%%
|
||||||
|
### option: Page.selectOption.force = %%-input-force-%%
|
||||||
### option: Page.selectOption.noWaitAfter = %%-input-no-wait-after-%%
|
### option: Page.selectOption.noWaitAfter = %%-input-no-wait-after-%%
|
||||||
|
|
||||||
### option: Page.selectOption.timeout = %%-input-timeout-%%
|
### option: Page.selectOption.timeout = %%-input-timeout-%%
|
||||||
|
|
||||||
## async method: Page.setContent
|
## async method: Page.setContent
|
||||||
|
@ -33,7 +33,7 @@ export type WaitForEventOptions = Function | { predicate?: Function, timeout?: n
|
|||||||
export type WaitForFunctionOptions = { timeout?: number, polling?: 'raf' | number };
|
export type WaitForFunctionOptions = { timeout?: number, polling?: 'raf' | number };
|
||||||
|
|
||||||
export type SelectOption = { value?: string, label?: string, index?: number };
|
export type SelectOption = { value?: string, label?: string, index?: number };
|
||||||
export type SelectOptionOptions = { timeout?: number, noWaitAfter?: boolean };
|
export type SelectOptionOptions = { force?: boolean, timeout?: number, noWaitAfter?: boolean };
|
||||||
export type FilePayload = { name: string, mimeType: string, buffer: Buffer };
|
export type FilePayload = { name: string, mimeType: string, buffer: Buffer };
|
||||||
export type StorageState = {
|
export type StorageState = {
|
||||||
cookies: channels.NetworkCookie[],
|
cookies: channels.NetworkCookie[],
|
||||||
|
@ -1490,10 +1490,12 @@ export type FrameEvaluateExpressionHandleResult = {
|
|||||||
export type FrameFillParams = {
|
export type FrameFillParams = {
|
||||||
selector: string,
|
selector: string,
|
||||||
value: string,
|
value: string,
|
||||||
|
force?: boolean,
|
||||||
timeout?: number,
|
timeout?: number,
|
||||||
noWaitAfter?: boolean,
|
noWaitAfter?: boolean,
|
||||||
};
|
};
|
||||||
export type FrameFillOptions = {
|
export type FrameFillOptions = {
|
||||||
|
force?: boolean,
|
||||||
timeout?: number,
|
timeout?: number,
|
||||||
noWaitAfter?: boolean,
|
noWaitAfter?: boolean,
|
||||||
};
|
};
|
||||||
@ -1681,6 +1683,7 @@ export type FrameSelectOptionParams = {
|
|||||||
label?: string,
|
label?: string,
|
||||||
index?: number,
|
index?: number,
|
||||||
}[],
|
}[],
|
||||||
|
force?: boolean,
|
||||||
timeout?: number,
|
timeout?: number,
|
||||||
noWaitAfter?: boolean,
|
noWaitAfter?: boolean,
|
||||||
};
|
};
|
||||||
@ -1691,6 +1694,7 @@ export type FrameSelectOptionOptions = {
|
|||||||
label?: string,
|
label?: string,
|
||||||
index?: number,
|
index?: number,
|
||||||
}[],
|
}[],
|
||||||
|
force?: boolean,
|
||||||
timeout?: number,
|
timeout?: number,
|
||||||
noWaitAfter?: boolean,
|
noWaitAfter?: boolean,
|
||||||
};
|
};
|
||||||
@ -2052,10 +2056,12 @@ export type ElementHandleDispatchEventOptions = {
|
|||||||
export type ElementHandleDispatchEventResult = void;
|
export type ElementHandleDispatchEventResult = void;
|
||||||
export type ElementHandleFillParams = {
|
export type ElementHandleFillParams = {
|
||||||
value: string,
|
value: string,
|
||||||
|
force?: boolean,
|
||||||
timeout?: number,
|
timeout?: number,
|
||||||
noWaitAfter?: boolean,
|
noWaitAfter?: boolean,
|
||||||
};
|
};
|
||||||
export type ElementHandleFillOptions = {
|
export type ElementHandleFillOptions = {
|
||||||
|
force?: boolean,
|
||||||
timeout?: number,
|
timeout?: number,
|
||||||
noWaitAfter?: boolean,
|
noWaitAfter?: boolean,
|
||||||
};
|
};
|
||||||
@ -2196,6 +2202,7 @@ export type ElementHandleSelectOptionParams = {
|
|||||||
label?: string,
|
label?: string,
|
||||||
index?: number,
|
index?: number,
|
||||||
}[],
|
}[],
|
||||||
|
force?: boolean,
|
||||||
timeout?: number,
|
timeout?: number,
|
||||||
noWaitAfter?: boolean,
|
noWaitAfter?: boolean,
|
||||||
};
|
};
|
||||||
@ -2206,6 +2213,7 @@ export type ElementHandleSelectOptionOptions = {
|
|||||||
label?: string,
|
label?: string,
|
||||||
index?: number,
|
index?: number,
|
||||||
}[],
|
}[],
|
||||||
|
force?: boolean,
|
||||||
timeout?: number,
|
timeout?: number,
|
||||||
noWaitAfter?: boolean,
|
noWaitAfter?: boolean,
|
||||||
};
|
};
|
||||||
@ -2213,9 +2221,11 @@ export type ElementHandleSelectOptionResult = {
|
|||||||
values: string[],
|
values: string[],
|
||||||
};
|
};
|
||||||
export type ElementHandleSelectTextParams = {
|
export type ElementHandleSelectTextParams = {
|
||||||
|
force?: boolean,
|
||||||
timeout?: number,
|
timeout?: number,
|
||||||
};
|
};
|
||||||
export type ElementHandleSelectTextOptions = {
|
export type ElementHandleSelectTextOptions = {
|
||||||
|
force?: boolean,
|
||||||
timeout?: number,
|
timeout?: number,
|
||||||
};
|
};
|
||||||
export type ElementHandleSelectTextResult = void;
|
export type ElementHandleSelectTextResult = void;
|
||||||
|
@ -1178,6 +1178,7 @@ Frame:
|
|||||||
parameters:
|
parameters:
|
||||||
selector: string
|
selector: string
|
||||||
value: string
|
value: string
|
||||||
|
force: boolean?
|
||||||
timeout: number?
|
timeout: number?
|
||||||
noWaitAfter: boolean?
|
noWaitAfter: boolean?
|
||||||
|
|
||||||
@ -1328,6 +1329,7 @@ Frame:
|
|||||||
value: string?
|
value: string?
|
||||||
label: string?
|
label: string?
|
||||||
index: number?
|
index: number?
|
||||||
|
force: boolean?
|
||||||
timeout: number?
|
timeout: number?
|
||||||
noWaitAfter: boolean?
|
noWaitAfter: boolean?
|
||||||
returns:
|
returns:
|
||||||
@ -1641,6 +1643,7 @@ ElementHandle:
|
|||||||
fill:
|
fill:
|
||||||
parameters:
|
parameters:
|
||||||
value: string
|
value: string
|
||||||
|
force: boolean?
|
||||||
timeout: number?
|
timeout: number?
|
||||||
noWaitAfter: boolean?
|
noWaitAfter: boolean?
|
||||||
|
|
||||||
@ -1759,6 +1762,7 @@ ElementHandle:
|
|||||||
value: string?
|
value: string?
|
||||||
label: string?
|
label: string?
|
||||||
index: number?
|
index: number?
|
||||||
|
force: boolean?
|
||||||
timeout: number?
|
timeout: number?
|
||||||
noWaitAfter: boolean?
|
noWaitAfter: boolean?
|
||||||
returns:
|
returns:
|
||||||
@ -1768,6 +1772,7 @@ ElementHandle:
|
|||||||
|
|
||||||
selectText:
|
selectText:
|
||||||
parameters:
|
parameters:
|
||||||
|
force: boolean?
|
||||||
timeout: number?
|
timeout: number?
|
||||||
|
|
||||||
setInputFiles:
|
setInputFiles:
|
||||||
|
@ -608,6 +608,7 @@ export function createScheme(tChannel: (name: string) => Validator): Scheme {
|
|||||||
scheme.FrameFillParams = tObject({
|
scheme.FrameFillParams = tObject({
|
||||||
selector: tString,
|
selector: tString,
|
||||||
value: tString,
|
value: tString,
|
||||||
|
force: tOptional(tBoolean),
|
||||||
timeout: tOptional(tNumber),
|
timeout: tOptional(tNumber),
|
||||||
noWaitAfter: tOptional(tBoolean),
|
noWaitAfter: tOptional(tBoolean),
|
||||||
});
|
});
|
||||||
@ -692,6 +693,7 @@ export function createScheme(tChannel: (name: string) => Validator): Scheme {
|
|||||||
label: tOptional(tString),
|
label: tOptional(tString),
|
||||||
index: tOptional(tNumber),
|
index: tOptional(tNumber),
|
||||||
}))),
|
}))),
|
||||||
|
force: tOptional(tBoolean),
|
||||||
timeout: tOptional(tNumber),
|
timeout: tOptional(tNumber),
|
||||||
noWaitAfter: tOptional(tBoolean),
|
noWaitAfter: tOptional(tBoolean),
|
||||||
});
|
});
|
||||||
@ -831,6 +833,7 @@ export function createScheme(tChannel: (name: string) => Validator): Scheme {
|
|||||||
});
|
});
|
||||||
scheme.ElementHandleFillParams = tObject({
|
scheme.ElementHandleFillParams = tObject({
|
||||||
value: tString,
|
value: tString,
|
||||||
|
force: tOptional(tBoolean),
|
||||||
timeout: tOptional(tNumber),
|
timeout: tOptional(tNumber),
|
||||||
noWaitAfter: tOptional(tBoolean),
|
noWaitAfter: tOptional(tBoolean),
|
||||||
});
|
});
|
||||||
@ -883,10 +886,12 @@ export function createScheme(tChannel: (name: string) => Validator): Scheme {
|
|||||||
label: tOptional(tString),
|
label: tOptional(tString),
|
||||||
index: tOptional(tNumber),
|
index: tOptional(tNumber),
|
||||||
}))),
|
}))),
|
||||||
|
force: tOptional(tBoolean),
|
||||||
timeout: tOptional(tNumber),
|
timeout: tOptional(tNumber),
|
||||||
noWaitAfter: tOptional(tBoolean),
|
noWaitAfter: tOptional(tBoolean),
|
||||||
});
|
});
|
||||||
scheme.ElementHandleSelectTextParams = tObject({
|
scheme.ElementHandleSelectTextParams = tObject({
|
||||||
|
force: tOptional(tBoolean),
|
||||||
timeout: tOptional(tNumber),
|
timeout: tOptional(tNumber),
|
||||||
});
|
});
|
||||||
scheme.ElementHandleSetInputFilesParams = tObject({
|
scheme.ElementHandleSetInputFilesParams = tObject({
|
||||||
|
@ -225,7 +225,7 @@ export class ElementHandle<T extends Node = Node> extends js.JSHandle<T> {
|
|||||||
|
|
||||||
async _waitAndScrollIntoViewIfNeeded(progress: Progress): Promise<void> {
|
async _waitAndScrollIntoViewIfNeeded(progress: Progress): Promise<void> {
|
||||||
while (progress.isRunning()) {
|
while (progress.isRunning()) {
|
||||||
assertDone(throwRetargetableDOMError(await this._waitForDisplayedAtStablePosition(progress, false /* waitForEnabled */)));
|
assertDone(throwRetargetableDOMError(await this._waitForDisplayedAtStablePosition(progress, false /* force */, false /* waitForEnabled */)));
|
||||||
|
|
||||||
progress.throwIfAborted(); // Avoid action that has side-effects.
|
progress.throwIfAborted(); // Avoid action that has side-effects.
|
||||||
const result = throwRetargetableDOMError(await this._scrollRectIntoViewIfNeeded());
|
const result = throwRetargetableDOMError(await this._scrollRectIntoViewIfNeeded());
|
||||||
@ -356,11 +356,9 @@ export class ElementHandle<T extends Node = Node> extends js.JSHandle<T> {
|
|||||||
const { force = false, position } = options;
|
const { force = false, position } = options;
|
||||||
if ((options as any).__testHookBeforeStable)
|
if ((options as any).__testHookBeforeStable)
|
||||||
await (options as any).__testHookBeforeStable();
|
await (options as any).__testHookBeforeStable();
|
||||||
if (!force) {
|
const result = await this._waitForDisplayedAtStablePosition(progress, force, waitForEnabled);
|
||||||
const result = await this._waitForDisplayedAtStablePosition(progress, waitForEnabled);
|
|
||||||
if (result !== 'done')
|
if (result !== 'done')
|
||||||
return result;
|
return result;
|
||||||
}
|
|
||||||
if ((options as any).__testHookAfterStable)
|
if ((options as any).__testHookAfterStable)
|
||||||
await (options as any).__testHookAfterStable();
|
await (options as any).__testHookAfterStable();
|
||||||
|
|
||||||
@ -469,7 +467,7 @@ export class ElementHandle<T extends Node = Node> extends js.JSHandle<T> {
|
|||||||
return this._retryPointerAction(progress, 'tap', true /* waitForEnabled */, point => this._page.touchscreen.tap(point.x, point.y), options);
|
return this._retryPointerAction(progress, 'tap', true /* waitForEnabled */, point => this._page.touchscreen.tap(point.x, point.y), options);
|
||||||
}
|
}
|
||||||
|
|
||||||
async selectOption(metadata: CallMetadata, elements: ElementHandle[], values: types.SelectOption[], options: types.NavigatingActionWaitOptions): Promise<string[]> {
|
async selectOption(metadata: CallMetadata, elements: ElementHandle[], values: types.SelectOption[], options: types.NavigatingActionWaitOptions & types.ForceOptions): Promise<string[]> {
|
||||||
const controller = new ProgressController(metadata, this);
|
const controller = new ProgressController(metadata, this);
|
||||||
return controller.run(async progress => {
|
return controller.run(async progress => {
|
||||||
const result = await this._selectOption(progress, elements, values, options);
|
const result = await this._selectOption(progress, elements, values, options);
|
||||||
@ -477,15 +475,15 @@ export class ElementHandle<T extends Node = Node> extends js.JSHandle<T> {
|
|||||||
}, this._page._timeoutSettings.timeout(options));
|
}, this._page._timeoutSettings.timeout(options));
|
||||||
}
|
}
|
||||||
|
|
||||||
async _selectOption(progress: Progress, elements: ElementHandle[], values: types.SelectOption[], options: types.NavigatingActionWaitOptions): Promise<string[] | 'error:notconnected'> {
|
async _selectOption(progress: Progress, elements: ElementHandle[], values: types.SelectOption[], options: types.NavigatingActionWaitOptions & types.ForceOptions): Promise<string[] | 'error:notconnected'> {
|
||||||
const optionsToSelect = [...elements, ...values];
|
const optionsToSelect = [...elements, ...values];
|
||||||
await progress.beforeInputAction(this);
|
await progress.beforeInputAction(this);
|
||||||
return this._page._frameManager.waitForSignalsCreatedBy(progress, options.noWaitAfter, async () => {
|
return this._page._frameManager.waitForSignalsCreatedBy(progress, options.noWaitAfter, async () => {
|
||||||
progress.throwIfAborted(); // Avoid action that has side-effects.
|
progress.throwIfAborted(); // Avoid action that has side-effects.
|
||||||
progress.log(' selecting specified option(s)');
|
progress.log(' selecting specified option(s)');
|
||||||
const poll = await this.evaluateHandleInUtility(([injected, node, optionsToSelect]) => {
|
const poll = await this.evaluateHandleInUtility(([injected, node, { optionsToSelect, force }]) => {
|
||||||
return injected.waitForElementStatesAndPerformAction(node, ['visible', 'enabled'], injected.selectOptions.bind(injected, optionsToSelect));
|
return injected.waitForElementStatesAndPerformAction(node, ['visible', 'enabled'], force, injected.selectOptions.bind(injected, optionsToSelect));
|
||||||
}, optionsToSelect);
|
}, { optionsToSelect, force: options.force });
|
||||||
const pollHandler = new InjectedScriptPollHandler(progress, poll);
|
const pollHandler = new InjectedScriptPollHandler(progress, poll);
|
||||||
const result = throwFatalDOMError(await pollHandler.finish());
|
const result = throwFatalDOMError(await pollHandler.finish());
|
||||||
await this._page._doSlowMo();
|
await this._page._doSlowMo();
|
||||||
@ -493,7 +491,7 @@ export class ElementHandle<T extends Node = Node> extends js.JSHandle<T> {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async fill(metadata: CallMetadata, value: string, options: types.NavigatingActionWaitOptions = {}): Promise<void> {
|
async fill(metadata: CallMetadata, value: string, options: types.NavigatingActionWaitOptions & types.ForceOptions = {}): Promise<void> {
|
||||||
const controller = new ProgressController(metadata, this);
|
const controller = new ProgressController(metadata, this);
|
||||||
return controller.run(async progress => {
|
return controller.run(async progress => {
|
||||||
const result = await this._fill(progress, value, options);
|
const result = await this._fill(progress, value, options);
|
||||||
@ -501,14 +499,14 @@ export class ElementHandle<T extends Node = Node> extends js.JSHandle<T> {
|
|||||||
}, this._page._timeoutSettings.timeout(options));
|
}, this._page._timeoutSettings.timeout(options));
|
||||||
}
|
}
|
||||||
|
|
||||||
async _fill(progress: Progress, value: string, options: types.NavigatingActionWaitOptions): Promise<'error:notconnected' | 'done'> {
|
async _fill(progress: Progress, value: string, options: types.NavigatingActionWaitOptions & types.ForceOptions): Promise<'error:notconnected' | 'done'> {
|
||||||
progress.log(`elementHandle.fill("${value}")`);
|
progress.log(`elementHandle.fill("${value}")`);
|
||||||
await progress.beforeInputAction(this);
|
await progress.beforeInputAction(this);
|
||||||
return this._page._frameManager.waitForSignalsCreatedBy(progress, options.noWaitAfter, async () => {
|
return this._page._frameManager.waitForSignalsCreatedBy(progress, options.noWaitAfter, async () => {
|
||||||
progress.log(' waiting for element to be visible, enabled and editable');
|
progress.log(' waiting for element to be visible, enabled and editable');
|
||||||
const poll = await this.evaluateHandleInUtility(([injected, node, value]) => {
|
const poll = await this.evaluateHandleInUtility(([injected, node, { value, force }]) => {
|
||||||
return injected.waitForElementStatesAndPerformAction(node, ['visible', 'enabled', 'editable'], injected.fill.bind(injected, value));
|
return injected.waitForElementStatesAndPerformAction(node, ['visible', 'enabled', 'editable'], force, injected.fill.bind(injected, value));
|
||||||
}, value);
|
}, { value, force: options.force });
|
||||||
const pollHandler = new InjectedScriptPollHandler(progress, poll);
|
const pollHandler = new InjectedScriptPollHandler(progress, poll);
|
||||||
const filled = throwFatalDOMError(await pollHandler.finish());
|
const filled = throwFatalDOMError(await pollHandler.finish());
|
||||||
progress.throwIfAborted(); // Avoid action that has side-effects.
|
progress.throwIfAborted(); // Avoid action that has side-effects.
|
||||||
@ -528,13 +526,13 @@ export class ElementHandle<T extends Node = Node> extends js.JSHandle<T> {
|
|||||||
}, 'input');
|
}, 'input');
|
||||||
}
|
}
|
||||||
|
|
||||||
async selectText(metadata: CallMetadata, options: types.TimeoutOptions = {}): Promise<void> {
|
async selectText(metadata: CallMetadata, options: types.TimeoutOptions & types.ForceOptions = {}): Promise<void> {
|
||||||
const controller = new ProgressController(metadata, this);
|
const controller = new ProgressController(metadata, this);
|
||||||
return controller.run(async progress => {
|
return controller.run(async progress => {
|
||||||
progress.throwIfAborted(); // Avoid action that has side-effects.
|
progress.throwIfAborted(); // Avoid action that has side-effects.
|
||||||
const poll = await this.evaluateHandleInUtility(([injected, node]) => {
|
const poll = await this.evaluateHandleInUtility(([injected, node, force]) => {
|
||||||
return injected.waitForElementStatesAndPerformAction(node, ['visible'], injected.selectText.bind(injected));
|
return injected.waitForElementStatesAndPerformAction(node, ['visible'], force, injected.selectText.bind(injected));
|
||||||
}, {});
|
}, options.force);
|
||||||
const pollHandler = new InjectedScriptPollHandler(progress, poll);
|
const pollHandler = new InjectedScriptPollHandler(progress, poll);
|
||||||
const result = throwFatalDOMError(await pollHandler.finish());
|
const result = throwFatalDOMError(await pollHandler.finish());
|
||||||
assertDone(throwRetargetableDOMError(result));
|
assertDone(throwRetargetableDOMError(result));
|
||||||
@ -732,7 +730,7 @@ export class ElementHandle<T extends Node = Node> extends js.JSHandle<T> {
|
|||||||
return controller.run(async progress => {
|
return controller.run(async progress => {
|
||||||
progress.log(` waiting for element to be ${state}`);
|
progress.log(` waiting for element to be ${state}`);
|
||||||
const poll = await this.evaluateHandleInUtility(([injected, node, state]) => {
|
const poll = await this.evaluateHandleInUtility(([injected, node, state]) => {
|
||||||
return injected.waitForElementStatesAndPerformAction(node, [state], () => 'done' as const);
|
return injected.waitForElementStatesAndPerformAction(node, [state], false, () => 'done' as const);
|
||||||
}, state);
|
}, state);
|
||||||
const pollHandler = new InjectedScriptPollHandler(progress, poll);
|
const pollHandler = new InjectedScriptPollHandler(progress, poll);
|
||||||
assertDone(throwRetargetableDOMError(throwFatalDOMError(await pollHandler.finish())));
|
assertDone(throwRetargetableDOMError(throwFatalDOMError(await pollHandler.finish())));
|
||||||
@ -770,15 +768,15 @@ export class ElementHandle<T extends Node = Node> extends js.JSHandle<T> {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
async _waitForDisplayedAtStablePosition(progress: Progress, waitForEnabled: boolean): Promise<'error:notconnected' | 'done'> {
|
async _waitForDisplayedAtStablePosition(progress: Progress, force: boolean, waitForEnabled: boolean): Promise<'error:notconnected' | 'done'> {
|
||||||
if (waitForEnabled)
|
if (waitForEnabled)
|
||||||
progress.log(` waiting for element to be visible, enabled and stable`);
|
progress.log(` waiting for element to be visible, enabled and stable`);
|
||||||
else
|
else
|
||||||
progress.log(` waiting for element to be visible and stable`);
|
progress.log(` waiting for element to be visible and stable`);
|
||||||
const poll = this.evaluateHandleInUtility(([injected, node, waitForEnabled]) => {
|
const poll = this.evaluateHandleInUtility(([injected, node, { waitForEnabled, force }]) => {
|
||||||
return injected.waitForElementStatesAndPerformAction(node,
|
return injected.waitForElementStatesAndPerformAction(node,
|
||||||
waitForEnabled ? ['visible', 'stable', 'enabled'] : ['visible', 'stable'], () => 'done' as const);
|
waitForEnabled ? ['visible', 'stable', 'enabled'] : ['visible', 'stable'], force, () => 'done' as const);
|
||||||
}, waitForEnabled);
|
}, { waitForEnabled, force });
|
||||||
const pollHandler = new InjectedScriptPollHandler(progress, await poll);
|
const pollHandler = new InjectedScriptPollHandler(progress, await poll);
|
||||||
const result = await pollHandler.finish();
|
const result = await pollHandler.finish();
|
||||||
if (waitForEnabled)
|
if (waitForEnabled)
|
||||||
|
@ -986,7 +986,7 @@ export class Frame extends SdkObject {
|
|||||||
}, this._page._timeoutSettings.timeout(options));
|
}, this._page._timeoutSettings.timeout(options));
|
||||||
}
|
}
|
||||||
|
|
||||||
async fill(metadata: CallMetadata, selector: string, value: string, options: types.NavigatingActionWaitOptions) {
|
async fill(metadata: CallMetadata, selector: string, value: string, options: types.NavigatingActionWaitOptions & { force?: boolean }) {
|
||||||
const controller = new ProgressController(metadata, this);
|
const controller = new ProgressController(metadata, this);
|
||||||
return controller.run(async progress => {
|
return controller.run(async progress => {
|
||||||
return dom.assertDone(await this._retryWithProgressIfNotConnected(progress, selector, handle => handle._fill(progress, value, options)));
|
return dom.assertDone(await this._retryWithProgressIfNotConnected(progress, selector, handle => handle._fill(progress, value, options)));
|
||||||
@ -1097,7 +1097,7 @@ export class Frame extends SdkObject {
|
|||||||
}, this._page._timeoutSettings.timeout(options));
|
}, this._page._timeoutSettings.timeout(options));
|
||||||
}
|
}
|
||||||
|
|
||||||
async selectOption(metadata: CallMetadata, selector: string, elements: dom.ElementHandle[], values: types.SelectOption[], options: types.NavigatingActionWaitOptions = {}): Promise<string[]> {
|
async selectOption(metadata: CallMetadata, selector: string, elements: dom.ElementHandle[], values: types.SelectOption[], options: types.NavigatingActionWaitOptions & types.ForceOptions = {}): Promise<string[]> {
|
||||||
const controller = new ProgressController(metadata, this);
|
const controller = new ProgressController(metadata, this);
|
||||||
return controller.run(async progress => {
|
return controller.run(async progress => {
|
||||||
return await this._retryWithProgressIfNotConnected(progress, selector, handle => handle._selectOption(progress, elements, values, options));
|
return await this._retryWithProgressIfNotConnected(progress, selector, handle => handle._selectOption(progress, elements, values, options));
|
||||||
|
@ -344,7 +344,7 @@ export class InjectedScript {
|
|||||||
return element;
|
return element;
|
||||||
}
|
}
|
||||||
|
|
||||||
waitForElementStatesAndPerformAction<T>(node: Node, states: ElementState[],
|
waitForElementStatesAndPerformAction<T>(node: Node, states: ElementState[], force: boolean | undefined,
|
||||||
callback: (node: Node, progress: InjectedScriptProgress, continuePolling: symbol) => T | symbol): InjectedScriptPoll<T | 'error:notconnected' | FatalDOMError> {
|
callback: (node: Node, progress: InjectedScriptProgress, continuePolling: symbol) => T | symbol): InjectedScriptPoll<T | 'error:notconnected' | FatalDOMError> {
|
||||||
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;
|
||||||
@ -352,6 +352,11 @@ export class InjectedScript {
|
|||||||
let lastTime = 0;
|
let lastTime = 0;
|
||||||
|
|
||||||
const predicate = (progress: InjectedScriptProgress, continuePolling: symbol) => {
|
const predicate = (progress: InjectedScriptProgress, continuePolling: symbol) => {
|
||||||
|
if (force) {
|
||||||
|
progress.log(` forcing action`);
|
||||||
|
return callback(node, progress, continuePolling);
|
||||||
|
}
|
||||||
|
|
||||||
for (const state of states) {
|
for (const state of states) {
|
||||||
if (state !== 'stable') {
|
if (state !== 'stable') {
|
||||||
const result = this.checkElementState(node, state);
|
const result = this.checkElementState(node, state);
|
||||||
|
@ -33,8 +33,11 @@ export type NavigatingActionWaitOptions = TimeoutOptions & {
|
|||||||
noWaitAfter?: boolean,
|
noWaitAfter?: boolean,
|
||||||
};
|
};
|
||||||
|
|
||||||
export type PointerActionWaitOptions = TimeoutOptions & {
|
export type ForceOptions = {
|
||||||
force?: boolean,
|
force?: boolean,
|
||||||
|
};
|
||||||
|
|
||||||
|
export type PointerActionWaitOptions = TimeoutOptions & ForceOptions & {
|
||||||
trial?: boolean;
|
trial?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
35
types/types.d.ts
vendored
35
types/types.d.ts
vendored
@ -1756,6 +1756,11 @@ export interface Page {
|
|||||||
* @param options
|
* @param options
|
||||||
*/
|
*/
|
||||||
fill(selector: string, value: string, options?: {
|
fill(selector: string, value: string, options?: {
|
||||||
|
/**
|
||||||
|
* Whether to bypass the [actionability](https://playwright.dev/docs/actionability) checks. Defaults to `false`.
|
||||||
|
*/
|
||||||
|
force?: boolean;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Actions that initiate navigations are waiting for these navigations to happen and for pages to start loading. You can
|
* 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
|
* opt out of waiting via setting this flag. You would only need this option in the exceptional cases such as navigating to
|
||||||
@ -2508,6 +2513,11 @@ export interface Page {
|
|||||||
*/
|
*/
|
||||||
index?: number;
|
index?: number;
|
||||||
}>, options?: {
|
}>, options?: {
|
||||||
|
/**
|
||||||
|
* Whether to bypass the [actionability](https://playwright.dev/docs/actionability) checks. Defaults to `false`.
|
||||||
|
*/
|
||||||
|
force?: boolean;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Actions that initiate navigations are waiting for these navigations to happen and for pages to start loading. You can
|
* 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
|
* opt out of waiting via setting this flag. You would only need this option in the exceptional cases such as navigating to
|
||||||
@ -3870,6 +3880,11 @@ export interface Frame {
|
|||||||
* @param options
|
* @param options
|
||||||
*/
|
*/
|
||||||
fill(selector: string, value: string, options?: {
|
fill(selector: string, value: string, options?: {
|
||||||
|
/**
|
||||||
|
* Whether to bypass the [actionability](https://playwright.dev/docs/actionability) checks. Defaults to `false`.
|
||||||
|
*/
|
||||||
|
force?: boolean;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Actions that initiate navigations are waiting for these navigations to happen and for pages to start loading. You can
|
* 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
|
* opt out of waiting via setting this flag. You would only need this option in the exceptional cases such as navigating to
|
||||||
@ -4299,6 +4314,11 @@ export interface Frame {
|
|||||||
*/
|
*/
|
||||||
index?: number;
|
index?: number;
|
||||||
}>, options?: {
|
}>, options?: {
|
||||||
|
/**
|
||||||
|
* Whether to bypass the [actionability](https://playwright.dev/docs/actionability) checks. Defaults to `false`.
|
||||||
|
*/
|
||||||
|
force?: boolean;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Actions that initiate navigations are waiting for these navigations to happen and for pages to start loading. You can
|
* 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
|
* opt out of waiting via setting this flag. You would only need this option in the exceptional cases such as navigating to
|
||||||
@ -6313,6 +6333,11 @@ export interface ElementHandle<T=Node> extends JSHandle<T> {
|
|||||||
* @param options
|
* @param options
|
||||||
*/
|
*/
|
||||||
fill(value: string, options?: {
|
fill(value: string, options?: {
|
||||||
|
/**
|
||||||
|
* Whether to bypass the [actionability](https://playwright.dev/docs/actionability) checks. Defaults to `false`.
|
||||||
|
*/
|
||||||
|
force?: boolean;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Actions that initiate navigations are waiting for these navigations to happen and for pages to start loading. You can
|
* 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
|
* opt out of waiting via setting this flag. You would only need this option in the exceptional cases such as navigating to
|
||||||
@ -6612,6 +6637,11 @@ export interface ElementHandle<T=Node> extends JSHandle<T> {
|
|||||||
*/
|
*/
|
||||||
index?: number;
|
index?: number;
|
||||||
}>, options?: {
|
}>, options?: {
|
||||||
|
/**
|
||||||
|
* Whether to bypass the [actionability](https://playwright.dev/docs/actionability) checks. Defaults to `false`.
|
||||||
|
*/
|
||||||
|
force?: boolean;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Actions that initiate navigations are waiting for these navigations to happen and for pages to start loading. You can
|
* 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
|
* opt out of waiting via setting this flag. You would only need this option in the exceptional cases such as navigating to
|
||||||
@ -6634,6 +6664,11 @@ export interface ElementHandle<T=Node> extends JSHandle<T> {
|
|||||||
* @param options
|
* @param options
|
||||||
*/
|
*/
|
||||||
selectText(options?: {
|
selectText(options?: {
|
||||||
|
/**
|
||||||
|
* Whether to bypass the [actionability](https://playwright.dev/docs/actionability) checks. Defaults to `false`.
|
||||||
|
*/
|
||||||
|
force?: boolean;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Maximum time in milliseconds, defaults to 30 seconds, pass `0` to disable timeout. The default value can be changed by
|
* Maximum time in milliseconds, defaults to 30 seconds, pass `0` to disable timeout. The default value can be changed by
|
||||||
* using the
|
* using the
|
||||||
|
Loading…
Reference in New Issue
Block a user