api: add isVisible, isHidden, isEnabled, isDisabled and isEditable (#4915)
These methods are useful for verification in tests, e.g.
```js
expect(await page.isEnabled(':text("Remove All")')).toBe(false);
await page.click(':text("Add Item")');
expect(await page.isVisible('.item:text("new item")')).toBe(true);
expect(await page.isEnabled(':text("Remove All")')).toBe(true);
```
This commit is contained in:
parent
498f9a52c6
commit
3f904056ee
|
|
@ -44,11 +44,11 @@ Element is considered stable when it has maintained the same bounding box for at
|
||||||
|
|
||||||
### Enabled
|
### Enabled
|
||||||
|
|
||||||
Element is considered enabled when it is not a `<button>`, `<select>` or `<input>` with a `disabled` property set.
|
Element is considered enabled when it is not a `<button>`, `<select>`, `<input>` or `<textarea>` with a `disabled` property set.
|
||||||
|
|
||||||
### Editable
|
### Editable
|
||||||
|
|
||||||
Element is considered editable when it does not have `readonly` property set.
|
Element is considered editable when it is [enabled] and does not have `readonly` property set.
|
||||||
|
|
||||||
### Receiving events
|
### Receiving events
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -317,6 +317,31 @@ Returns the `element.innerHTML`.
|
||||||
|
|
||||||
Returns the `element.innerText`.
|
Returns the `element.innerText`.
|
||||||
|
|
||||||
|
## async method: ElementHandle.isDisabled
|
||||||
|
- returns: <[boolean]>
|
||||||
|
|
||||||
|
Returns whether the element is disabled, the opposite of [enabled](./actionability.md#enabled).
|
||||||
|
|
||||||
|
## async method: ElementHandle.isEditable
|
||||||
|
- returns: <[boolean]>
|
||||||
|
|
||||||
|
Returns whether the element is [editable](./actionability.md#editable).
|
||||||
|
|
||||||
|
## async method: ElementHandle.isEnabled
|
||||||
|
- returns: <[boolean]>
|
||||||
|
|
||||||
|
Returns whether the element is [enabled](./actionability.md#enabled).
|
||||||
|
|
||||||
|
## async method: ElementHandle.isHidden
|
||||||
|
- returns: <[boolean]>
|
||||||
|
|
||||||
|
Returns whether the element is hidden, the opposite of [visible](./actionability.md#visible).
|
||||||
|
|
||||||
|
## async method: ElementHandle.isVisible
|
||||||
|
- returns: <[boolean]>
|
||||||
|
|
||||||
|
Returns whether the element is [visible](./actionability.md#visible).
|
||||||
|
|
||||||
## async method: ElementHandle.ownerFrame
|
## async method: ElementHandle.ownerFrame
|
||||||
- returns: <[null]|[Frame]>
|
- returns: <[null]|[Frame]>
|
||||||
|
|
||||||
|
|
@ -544,11 +569,12 @@ checks to pass. This method throws when the element is detached while waiting, u
|
||||||
* `"stable"` Wait until the element is both [visible](./actionability.md#visible) and [stable](./actionability.md#stable).
|
* `"stable"` Wait until the element is both [visible](./actionability.md#visible) and [stable](./actionability.md#stable).
|
||||||
* `"enabled"` Wait until the element is [enabled](./actionability.md#enabled).
|
* `"enabled"` Wait until the element is [enabled](./actionability.md#enabled).
|
||||||
* `"disabled"` Wait until the element is [not enabled](./actionability.md#enabled).
|
* `"disabled"` Wait until the element is [not enabled](./actionability.md#enabled).
|
||||||
|
* `"editable"` Wait until the element is [editable](./actionability.md#editable).
|
||||||
|
|
||||||
If the element does not satisfy the condition for the [`option: timeout`] milliseconds, this method will throw.
|
If the element does not satisfy the condition for the [`option: timeout`] milliseconds, this method will throw.
|
||||||
|
|
||||||
### param: ElementHandle.waitForElementState.state
|
### param: ElementHandle.waitForElementState.state
|
||||||
- `state` <"visible"|"hidden"|"stable"|"enabled"|"disabled">
|
- `state` <"visible"|"hidden"|"stable"|"enabled"|"disabled"|"editable">
|
||||||
|
|
||||||
A state to wait for, see below for more details.
|
A state to wait for, see below for more details.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -507,6 +507,51 @@ Returns `element.innerText`.
|
||||||
|
|
||||||
Returns `true` if the frame has been detached, or `false` otherwise.
|
Returns `true` if the frame has been detached, or `false` otherwise.
|
||||||
|
|
||||||
|
## async method: Frame.isDisabled
|
||||||
|
- returns: <[boolean]>
|
||||||
|
|
||||||
|
Returns whether the element is disabled, the opposite of [enabled](./actionability.md#enabled).
|
||||||
|
|
||||||
|
### param: Frame.isDisabled.selector = %%-input-selector-%%
|
||||||
|
|
||||||
|
### option: Frame.isDisabled.timeout = %%-input-timeout-%%
|
||||||
|
|
||||||
|
## async method: Frame.isEditable
|
||||||
|
- returns: <[boolean]>
|
||||||
|
|
||||||
|
Returns whether the element is [editable](./actionability.md#editable).
|
||||||
|
|
||||||
|
### param: Frame.isEditable.selector = %%-input-selector-%%
|
||||||
|
|
||||||
|
### option: Frame.isEditable.timeout = %%-input-timeout-%%
|
||||||
|
|
||||||
|
## async method: Frame.isEnabled
|
||||||
|
- returns: <[boolean]>
|
||||||
|
|
||||||
|
Returns whether the element is [enabled](./actionability.md#enabled).
|
||||||
|
|
||||||
|
### param: Frame.isEnabled.selector = %%-input-selector-%%
|
||||||
|
|
||||||
|
### option: Frame.isEnabled.timeout = %%-input-timeout-%%
|
||||||
|
|
||||||
|
## async method: Frame.isHidden
|
||||||
|
- returns: <[boolean]>
|
||||||
|
|
||||||
|
Returns whether the element is hidden, the opposite of [visible](./actionability.md#visible).
|
||||||
|
|
||||||
|
### param: Frame.isHidden.selector = %%-input-selector-%%
|
||||||
|
|
||||||
|
### option: Frame.isHidden.timeout = %%-input-timeout-%%
|
||||||
|
|
||||||
|
## async method: Frame.isVisible
|
||||||
|
- returns: <[boolean]>
|
||||||
|
|
||||||
|
Returns whether the element is [visible](./actionability.md#visible).
|
||||||
|
|
||||||
|
### param: Frame.isVisible.selector = %%-input-selector-%%
|
||||||
|
|
||||||
|
### option: Frame.isVisible.timeout = %%-input-timeout-%%
|
||||||
|
|
||||||
## method: Frame.name
|
## method: Frame.name
|
||||||
- returns: <[string]>
|
- returns: <[string]>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -972,6 +972,51 @@ Returns `element.innerText`.
|
||||||
|
|
||||||
Indicates that the page has been closed.
|
Indicates that the page has been closed.
|
||||||
|
|
||||||
|
## async method: Page.isDisabled
|
||||||
|
- returns: <[boolean]>
|
||||||
|
|
||||||
|
Returns whether the element is disabled, the opposite of [enabled](./actionability.md#enabled).
|
||||||
|
|
||||||
|
### param: Page.isDisabled.selector = %%-input-selector-%%
|
||||||
|
|
||||||
|
### option: Page.isDisabled.timeout = %%-input-timeout-%%
|
||||||
|
|
||||||
|
## async method: Page.isEditable
|
||||||
|
- returns: <[boolean]>
|
||||||
|
|
||||||
|
Returns whether the element is [editable](./actionability.md#editable).
|
||||||
|
|
||||||
|
### param: Page.isEditable.selector = %%-input-selector-%%
|
||||||
|
|
||||||
|
### option: Page.isEditable.timeout = %%-input-timeout-%%
|
||||||
|
|
||||||
|
## async method: Page.isEnabled
|
||||||
|
- returns: <[boolean]>
|
||||||
|
|
||||||
|
Returns whether the element is [enabled](./actionability.md#enabled).
|
||||||
|
|
||||||
|
### param: Page.isEnabled.selector = %%-input-selector-%%
|
||||||
|
|
||||||
|
### option: Page.isEnabled.timeout = %%-input-timeout-%%
|
||||||
|
|
||||||
|
## async method: Page.isHidden
|
||||||
|
- returns: <[boolean]>
|
||||||
|
|
||||||
|
Returns whether the element is hidden, the opposite of [visible](./actionability.md#visible).
|
||||||
|
|
||||||
|
### param: Page.isHidden.selector = %%-input-selector-%%
|
||||||
|
|
||||||
|
### option: Page.isHidden.timeout = %%-input-timeout-%%
|
||||||
|
|
||||||
|
## async method: Page.isVisible
|
||||||
|
- returns: <[boolean]>
|
||||||
|
|
||||||
|
Returns whether the element is [visible](./actionability.md#visible).
|
||||||
|
|
||||||
|
### param: Page.isVisible.selector = %%-input-selector-%%
|
||||||
|
|
||||||
|
### option: Page.isVisible.timeout = %%-input-timeout-%%
|
||||||
|
|
||||||
## property: Page.keyboard
|
## property: Page.keyboard
|
||||||
- type: <[Keyboard]>
|
- type: <[Keyboard]>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -87,6 +87,36 @@ export class ElementHandle<T extends Node = Node> extends JSHandle<T> implements
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async isDisabled(): Promise<boolean> {
|
||||||
|
return this._wrapApiCall('elementHandle.isDisabled', async () => {
|
||||||
|
return (await this._elementChannel.isDisabled()).value;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async isEditable(): Promise<boolean> {
|
||||||
|
return this._wrapApiCall('elementHandle.isEditable', async () => {
|
||||||
|
return (await this._elementChannel.isEditable()).value;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async isEnabled(): Promise<boolean> {
|
||||||
|
return this._wrapApiCall('elementHandle.isEnabled', async () => {
|
||||||
|
return (await this._elementChannel.isEnabled()).value;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async isHidden(): Promise<boolean> {
|
||||||
|
return this._wrapApiCall('elementHandle.isHidden', async () => {
|
||||||
|
return (await this._elementChannel.isHidden()).value;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async isVisible(): Promise<boolean> {
|
||||||
|
return this._wrapApiCall('elementHandle.isVisible', async () => {
|
||||||
|
return (await this._elementChannel.isVisible()).value;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
async dispatchEvent(type: string, eventInit: Object = {}) {
|
async dispatchEvent(type: string, eventInit: Object = {}) {
|
||||||
return this._wrapApiCall('elementHandle.dispatchEvent', async () => {
|
return this._wrapApiCall('elementHandle.dispatchEvent', async () => {
|
||||||
await this._elementChannel.dispatchEvent({ type, eventInit: serializeArgument(eventInit) });
|
await this._elementChannel.dispatchEvent({ type, eventInit: serializeArgument(eventInit) });
|
||||||
|
|
|
||||||
|
|
@ -362,6 +362,36 @@ export class Frame extends ChannelOwner<channels.FrameChannel, channels.FrameIni
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async isDisabled(selector: string, options: channels.FrameIsDisabledOptions = {}): Promise<boolean> {
|
||||||
|
return this._wrapApiCall(this._apiName('isDisabled'), async () => {
|
||||||
|
return (await this._channel.isDisabled({ selector, ...options })).value;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async isEditable(selector: string, options: channels.FrameIsEditableOptions = {}): Promise<boolean> {
|
||||||
|
return this._wrapApiCall(this._apiName('isEditable'), async () => {
|
||||||
|
return (await this._channel.isEditable({ selector, ...options })).value;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async isEnabled(selector: string, options: channels.FrameIsEnabledOptions = {}): Promise<boolean> {
|
||||||
|
return this._wrapApiCall(this._apiName('isEnabled'), async () => {
|
||||||
|
return (await this._channel.isEnabled({ selector, ...options })).value;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async isHidden(selector: string, options: channels.FrameIsHiddenOptions = {}): Promise<boolean> {
|
||||||
|
return this._wrapApiCall(this._apiName('isHidden'), async () => {
|
||||||
|
return (await this._channel.isHidden({ selector, ...options })).value;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async isVisible(selector: string, options: channels.FrameIsVisibleOptions = {}): Promise<boolean> {
|
||||||
|
return this._wrapApiCall(this._apiName('isVisible'), async () => {
|
||||||
|
return (await this._channel.isVisible({ selector, ...options })).value;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
async hover(selector: string, options: channels.FrameHoverOptions = {}) {
|
async hover(selector: string, options: channels.FrameHoverOptions = {}) {
|
||||||
return this._wrapApiCall(this._apiName('hover'), async () => {
|
return this._wrapApiCall(this._apiName('hover'), async () => {
|
||||||
await this._channel.hover({ selector, ...options });
|
await this._channel.hover({ selector, ...options });
|
||||||
|
|
|
||||||
|
|
@ -530,6 +530,26 @@ export class Page extends ChannelOwner<channels.PageChannel, channels.PageInitia
|
||||||
return this._attributeToPage(() => this._mainFrame.getAttribute(selector, name, options));
|
return this._attributeToPage(() => this._mainFrame.getAttribute(selector, name, options));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async isDisabled(selector: string, options?: channels.FrameIsDisabledOptions): Promise<boolean> {
|
||||||
|
return this._attributeToPage(() => this._mainFrame.isDisabled(selector, options));
|
||||||
|
}
|
||||||
|
|
||||||
|
async isEditable(selector: string, options?: channels.FrameIsEditableOptions): Promise<boolean> {
|
||||||
|
return this._attributeToPage(() => this._mainFrame.isEditable(selector, options));
|
||||||
|
}
|
||||||
|
|
||||||
|
async isEnabled(selector: string, options?: channels.FrameIsEnabledOptions): Promise<boolean> {
|
||||||
|
return this._attributeToPage(() => this._mainFrame.isEnabled(selector, options));
|
||||||
|
}
|
||||||
|
|
||||||
|
async isHidden(selector: string, options?: channels.FrameIsHiddenOptions): Promise<boolean> {
|
||||||
|
return this._attributeToPage(() => this._mainFrame.isHidden(selector, options));
|
||||||
|
}
|
||||||
|
|
||||||
|
async isVisible(selector: string, options?: channels.FrameIsVisibleOptions): Promise<boolean> {
|
||||||
|
return this._attributeToPage(() => this._mainFrame.isVisible(selector, options));
|
||||||
|
}
|
||||||
|
|
||||||
async hover(selector: string, options?: channels.FrameHoverOptions) {
|
async hover(selector: string, options?: channels.FrameHoverOptions) {
|
||||||
return this._attributeToPage(() => this._mainFrame.hover(selector, options));
|
return this._attributeToPage(() => this._mainFrame.hover(selector, options));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -66,6 +66,26 @@ export class ElementHandleDispatcher extends JSHandleDispatcher implements chann
|
||||||
return { value: await this._elementHandle.innerHTML() };
|
return { value: await this._elementHandle.innerHTML() };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async isDisabled(): Promise<channels.ElementHandleIsDisabledResult> {
|
||||||
|
return { value: await this._elementHandle.isDisabled() };
|
||||||
|
}
|
||||||
|
|
||||||
|
async isEditable(): Promise<channels.ElementHandleIsEditableResult> {
|
||||||
|
return { value: await this._elementHandle.isEditable() };
|
||||||
|
}
|
||||||
|
|
||||||
|
async isEnabled(): Promise<channels.ElementHandleIsEnabledResult> {
|
||||||
|
return { value: await this._elementHandle.isEnabled() };
|
||||||
|
}
|
||||||
|
|
||||||
|
async isHidden(): Promise<channels.ElementHandleIsHiddenResult> {
|
||||||
|
return { value: await this._elementHandle.isHidden() };
|
||||||
|
}
|
||||||
|
|
||||||
|
async isVisible(): Promise<channels.ElementHandleIsVisibleResult> {
|
||||||
|
return { value: await this._elementHandle.isVisible() };
|
||||||
|
}
|
||||||
|
|
||||||
async dispatchEvent(params: channels.ElementHandleDispatchEventParams): Promise<void> {
|
async dispatchEvent(params: channels.ElementHandleDispatchEventParams): Promise<void> {
|
||||||
await this._elementHandle.dispatchEvent(params.type, parseArgument(params.eventInit));
|
await this._elementHandle.dispatchEvent(params.type, parseArgument(params.eventInit));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -159,6 +159,26 @@ export class FrameDispatcher extends Dispatcher<Frame, channels.FrameInitializer
|
||||||
return { value: value === null ? undefined : value };
|
return { value: value === null ? undefined : value };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async isDisabled(params: channels.FrameIsDisabledParams): Promise<channels.FrameIsDisabledResult> {
|
||||||
|
return { value: await this._frame.isDisabled(params.selector, params) };
|
||||||
|
}
|
||||||
|
|
||||||
|
async isEditable(params: channels.FrameIsEditableParams): Promise<channels.FrameIsEditableResult> {
|
||||||
|
return { value: await this._frame.isEditable(params.selector, params) };
|
||||||
|
}
|
||||||
|
|
||||||
|
async isEnabled(params: channels.FrameIsEnabledParams): Promise<channels.FrameIsEnabledResult> {
|
||||||
|
return { value: await this._frame.isEnabled(params.selector, params) };
|
||||||
|
}
|
||||||
|
|
||||||
|
async isHidden(params: channels.FrameIsHiddenParams): Promise<channels.FrameIsHiddenResult> {
|
||||||
|
return { value: await this._frame.isHidden(params.selector, params) };
|
||||||
|
}
|
||||||
|
|
||||||
|
async isVisible(params: channels.FrameIsVisibleParams): Promise<channels.FrameIsVisibleResult> {
|
||||||
|
return { value: await this._frame.isVisible(params.selector, params) };
|
||||||
|
}
|
||||||
|
|
||||||
async hover(params: channels.FrameHoverParams, metadata?: channels.Metadata): Promise<void> {
|
async hover(params: channels.FrameHoverParams, metadata?: channels.Metadata): Promise<void> {
|
||||||
return runAction(async controller => {
|
return runAction(async controller => {
|
||||||
return await this._frame.hover(controller, params.selector, params);
|
return await this._frame.hover(controller, params.selector, params);
|
||||||
|
|
|
||||||
|
|
@ -1190,6 +1190,11 @@ export interface FrameChannel extends Channel {
|
||||||
hover(params: FrameHoverParams, metadata?: Metadata): Promise<FrameHoverResult>;
|
hover(params: FrameHoverParams, metadata?: Metadata): Promise<FrameHoverResult>;
|
||||||
innerHTML(params: FrameInnerHTMLParams, metadata?: Metadata): Promise<FrameInnerHTMLResult>;
|
innerHTML(params: FrameInnerHTMLParams, metadata?: Metadata): Promise<FrameInnerHTMLResult>;
|
||||||
innerText(params: FrameInnerTextParams, metadata?: Metadata): Promise<FrameInnerTextResult>;
|
innerText(params: FrameInnerTextParams, metadata?: Metadata): Promise<FrameInnerTextResult>;
|
||||||
|
isDisabled(params: FrameIsDisabledParams, metadata?: Metadata): Promise<FrameIsDisabledResult>;
|
||||||
|
isEnabled(params: FrameIsEnabledParams, metadata?: Metadata): Promise<FrameIsEnabledResult>;
|
||||||
|
isHidden(params: FrameIsHiddenParams, metadata?: Metadata): Promise<FrameIsHiddenResult>;
|
||||||
|
isVisible(params: FrameIsVisibleParams, metadata?: Metadata): Promise<FrameIsVisibleResult>;
|
||||||
|
isEditable(params: FrameIsEditableParams, metadata?: Metadata): Promise<FrameIsEditableResult>;
|
||||||
press(params: FramePressParams, metadata?: Metadata): Promise<FramePressResult>;
|
press(params: FramePressParams, metadata?: Metadata): Promise<FramePressResult>;
|
||||||
querySelector(params: FrameQuerySelectorParams, metadata?: Metadata): Promise<FrameQuerySelectorResult>;
|
querySelector(params: FrameQuerySelectorParams, metadata?: Metadata): Promise<FrameQuerySelectorResult>;
|
||||||
querySelectorAll(params: FrameQuerySelectorAllParams, metadata?: Metadata): Promise<FrameQuerySelectorAllResult>;
|
querySelectorAll(params: FrameQuerySelectorAllParams, metadata?: Metadata): Promise<FrameQuerySelectorAllResult>;
|
||||||
|
|
@ -1441,6 +1446,56 @@ export type FrameInnerTextOptions = {
|
||||||
export type FrameInnerTextResult = {
|
export type FrameInnerTextResult = {
|
||||||
value: string,
|
value: string,
|
||||||
};
|
};
|
||||||
|
export type FrameIsDisabledParams = {
|
||||||
|
selector: string,
|
||||||
|
timeout?: number,
|
||||||
|
};
|
||||||
|
export type FrameIsDisabledOptions = {
|
||||||
|
timeout?: number,
|
||||||
|
};
|
||||||
|
export type FrameIsDisabledResult = {
|
||||||
|
value: boolean,
|
||||||
|
};
|
||||||
|
export type FrameIsEnabledParams = {
|
||||||
|
selector: string,
|
||||||
|
timeout?: number,
|
||||||
|
};
|
||||||
|
export type FrameIsEnabledOptions = {
|
||||||
|
timeout?: number,
|
||||||
|
};
|
||||||
|
export type FrameIsEnabledResult = {
|
||||||
|
value: boolean,
|
||||||
|
};
|
||||||
|
export type FrameIsHiddenParams = {
|
||||||
|
selector: string,
|
||||||
|
timeout?: number,
|
||||||
|
};
|
||||||
|
export type FrameIsHiddenOptions = {
|
||||||
|
timeout?: number,
|
||||||
|
};
|
||||||
|
export type FrameIsHiddenResult = {
|
||||||
|
value: boolean,
|
||||||
|
};
|
||||||
|
export type FrameIsVisibleParams = {
|
||||||
|
selector: string,
|
||||||
|
timeout?: number,
|
||||||
|
};
|
||||||
|
export type FrameIsVisibleOptions = {
|
||||||
|
timeout?: number,
|
||||||
|
};
|
||||||
|
export type FrameIsVisibleResult = {
|
||||||
|
value: boolean,
|
||||||
|
};
|
||||||
|
export type FrameIsEditableParams = {
|
||||||
|
selector: string,
|
||||||
|
timeout?: number,
|
||||||
|
};
|
||||||
|
export type FrameIsEditableOptions = {
|
||||||
|
timeout?: number,
|
||||||
|
};
|
||||||
|
export type FrameIsEditableResult = {
|
||||||
|
value: boolean,
|
||||||
|
};
|
||||||
export type FramePressParams = {
|
export type FramePressParams = {
|
||||||
selector: string,
|
selector: string,
|
||||||
key: string,
|
key: string,
|
||||||
|
|
@ -1728,6 +1783,11 @@ export interface ElementHandleChannel extends JSHandleChannel {
|
||||||
hover(params: ElementHandleHoverParams, metadata?: Metadata): Promise<ElementHandleHoverResult>;
|
hover(params: ElementHandleHoverParams, metadata?: Metadata): Promise<ElementHandleHoverResult>;
|
||||||
innerHTML(params?: ElementHandleInnerHTMLParams, metadata?: Metadata): Promise<ElementHandleInnerHTMLResult>;
|
innerHTML(params?: ElementHandleInnerHTMLParams, metadata?: Metadata): Promise<ElementHandleInnerHTMLResult>;
|
||||||
innerText(params?: ElementHandleInnerTextParams, metadata?: Metadata): Promise<ElementHandleInnerTextResult>;
|
innerText(params?: ElementHandleInnerTextParams, metadata?: Metadata): Promise<ElementHandleInnerTextResult>;
|
||||||
|
isDisabled(params?: ElementHandleIsDisabledParams, metadata?: Metadata): Promise<ElementHandleIsDisabledResult>;
|
||||||
|
isEditable(params?: ElementHandleIsEditableParams, metadata?: Metadata): Promise<ElementHandleIsEditableResult>;
|
||||||
|
isEnabled(params?: ElementHandleIsEnabledParams, metadata?: Metadata): Promise<ElementHandleIsEnabledResult>;
|
||||||
|
isHidden(params?: ElementHandleIsHiddenParams, metadata?: Metadata): Promise<ElementHandleIsHiddenResult>;
|
||||||
|
isVisible(params?: ElementHandleIsVisibleParams, metadata?: Metadata): Promise<ElementHandleIsVisibleResult>;
|
||||||
ownerFrame(params?: ElementHandleOwnerFrameParams, metadata?: Metadata): Promise<ElementHandleOwnerFrameResult>;
|
ownerFrame(params?: ElementHandleOwnerFrameParams, metadata?: Metadata): Promise<ElementHandleOwnerFrameResult>;
|
||||||
press(params: ElementHandlePressParams, metadata?: Metadata): Promise<ElementHandlePressResult>;
|
press(params: ElementHandlePressParams, metadata?: Metadata): Promise<ElementHandlePressResult>;
|
||||||
querySelector(params: ElementHandleQuerySelectorParams, metadata?: Metadata): Promise<ElementHandleQuerySelectorResult>;
|
querySelector(params: ElementHandleQuerySelectorParams, metadata?: Metadata): Promise<ElementHandleQuerySelectorResult>;
|
||||||
|
|
@ -1882,6 +1942,31 @@ export type ElementHandleInnerTextOptions = {};
|
||||||
export type ElementHandleInnerTextResult = {
|
export type ElementHandleInnerTextResult = {
|
||||||
value: string,
|
value: string,
|
||||||
};
|
};
|
||||||
|
export type ElementHandleIsDisabledParams = {};
|
||||||
|
export type ElementHandleIsDisabledOptions = {};
|
||||||
|
export type ElementHandleIsDisabledResult = {
|
||||||
|
value: boolean,
|
||||||
|
};
|
||||||
|
export type ElementHandleIsEditableParams = {};
|
||||||
|
export type ElementHandleIsEditableOptions = {};
|
||||||
|
export type ElementHandleIsEditableResult = {
|
||||||
|
value: boolean,
|
||||||
|
};
|
||||||
|
export type ElementHandleIsEnabledParams = {};
|
||||||
|
export type ElementHandleIsEnabledOptions = {};
|
||||||
|
export type ElementHandleIsEnabledResult = {
|
||||||
|
value: boolean,
|
||||||
|
};
|
||||||
|
export type ElementHandleIsHiddenParams = {};
|
||||||
|
export type ElementHandleIsHiddenOptions = {};
|
||||||
|
export type ElementHandleIsHiddenResult = {
|
||||||
|
value: boolean,
|
||||||
|
};
|
||||||
|
export type ElementHandleIsVisibleParams = {};
|
||||||
|
export type ElementHandleIsVisibleOptions = {};
|
||||||
|
export type ElementHandleIsVisibleResult = {
|
||||||
|
value: boolean,
|
||||||
|
};
|
||||||
export type ElementHandleOwnerFrameParams = {};
|
export type ElementHandleOwnerFrameParams = {};
|
||||||
export type ElementHandleOwnerFrameOptions = {};
|
export type ElementHandleOwnerFrameOptions = {};
|
||||||
export type ElementHandleOwnerFrameResult = {
|
export type ElementHandleOwnerFrameResult = {
|
||||||
|
|
@ -2027,7 +2112,7 @@ export type ElementHandleUncheckOptions = {
|
||||||
};
|
};
|
||||||
export type ElementHandleUncheckResult = void;
|
export type ElementHandleUncheckResult = void;
|
||||||
export type ElementHandleWaitForElementStateParams = {
|
export type ElementHandleWaitForElementStateParams = {
|
||||||
state: 'visible' | 'hidden' | 'stable' | 'enabled' | 'disabled',
|
state: 'visible' | 'hidden' | 'stable' | 'enabled' | 'disabled' | 'editable',
|
||||||
timeout?: number,
|
timeout?: number,
|
||||||
};
|
};
|
||||||
export type ElementHandleWaitForElementStateOptions = {
|
export type ElementHandleWaitForElementStateOptions = {
|
||||||
|
|
|
||||||
|
|
@ -1218,6 +1218,41 @@ Frame:
|
||||||
returns:
|
returns:
|
||||||
value: string
|
value: string
|
||||||
|
|
||||||
|
isDisabled:
|
||||||
|
parameters:
|
||||||
|
selector: string
|
||||||
|
timeout: number?
|
||||||
|
returns:
|
||||||
|
value: boolean
|
||||||
|
|
||||||
|
isEnabled:
|
||||||
|
parameters:
|
||||||
|
selector: string
|
||||||
|
timeout: number?
|
||||||
|
returns:
|
||||||
|
value: boolean
|
||||||
|
|
||||||
|
isHidden:
|
||||||
|
parameters:
|
||||||
|
selector: string
|
||||||
|
timeout: number?
|
||||||
|
returns:
|
||||||
|
value: boolean
|
||||||
|
|
||||||
|
isVisible:
|
||||||
|
parameters:
|
||||||
|
selector: string
|
||||||
|
timeout: number?
|
||||||
|
returns:
|
||||||
|
value: boolean
|
||||||
|
|
||||||
|
isEditable:
|
||||||
|
parameters:
|
||||||
|
selector: string
|
||||||
|
timeout: number?
|
||||||
|
returns:
|
||||||
|
value: boolean
|
||||||
|
|
||||||
press:
|
press:
|
||||||
parameters:
|
parameters:
|
||||||
selector: string
|
selector: string
|
||||||
|
|
@ -1602,6 +1637,26 @@ ElementHandle:
|
||||||
returns:
|
returns:
|
||||||
value: string
|
value: string
|
||||||
|
|
||||||
|
isDisabled:
|
||||||
|
returns:
|
||||||
|
value: boolean
|
||||||
|
|
||||||
|
isEditable:
|
||||||
|
returns:
|
||||||
|
value: boolean
|
||||||
|
|
||||||
|
isEnabled:
|
||||||
|
returns:
|
||||||
|
value: boolean
|
||||||
|
|
||||||
|
isHidden:
|
||||||
|
returns:
|
||||||
|
value: boolean
|
||||||
|
|
||||||
|
isVisible:
|
||||||
|
returns:
|
||||||
|
value: boolean
|
||||||
|
|
||||||
ownerFrame:
|
ownerFrame:
|
||||||
returns:
|
returns:
|
||||||
frame: Frame?
|
frame: Frame?
|
||||||
|
|
@ -1724,6 +1779,7 @@ ElementHandle:
|
||||||
- stable
|
- stable
|
||||||
- enabled
|
- enabled
|
||||||
- disabled
|
- disabled
|
||||||
|
- editable
|
||||||
timeout: number?
|
timeout: number?
|
||||||
|
|
||||||
waitForSelector:
|
waitForSelector:
|
||||||
|
|
|
||||||
|
|
@ -578,6 +578,26 @@ export function createScheme(tChannel: (name: string) => Validator): Scheme {
|
||||||
selector: tString,
|
selector: tString,
|
||||||
timeout: tOptional(tNumber),
|
timeout: tOptional(tNumber),
|
||||||
});
|
});
|
||||||
|
scheme.FrameIsDisabledParams = tObject({
|
||||||
|
selector: tString,
|
||||||
|
timeout: tOptional(tNumber),
|
||||||
|
});
|
||||||
|
scheme.FrameIsEnabledParams = tObject({
|
||||||
|
selector: tString,
|
||||||
|
timeout: tOptional(tNumber),
|
||||||
|
});
|
||||||
|
scheme.FrameIsHiddenParams = tObject({
|
||||||
|
selector: tString,
|
||||||
|
timeout: tOptional(tNumber),
|
||||||
|
});
|
||||||
|
scheme.FrameIsVisibleParams = tObject({
|
||||||
|
selector: tString,
|
||||||
|
timeout: tOptional(tNumber),
|
||||||
|
});
|
||||||
|
scheme.FrameIsEditableParams = tObject({
|
||||||
|
selector: tString,
|
||||||
|
timeout: tOptional(tNumber),
|
||||||
|
});
|
||||||
scheme.FramePressParams = tObject({
|
scheme.FramePressParams = tObject({
|
||||||
selector: tString,
|
selector: tString,
|
||||||
key: tString,
|
key: tString,
|
||||||
|
|
@ -750,6 +770,11 @@ export function createScheme(tChannel: (name: string) => Validator): Scheme {
|
||||||
});
|
});
|
||||||
scheme.ElementHandleInnerHTMLParams = tOptional(tObject({}));
|
scheme.ElementHandleInnerHTMLParams = tOptional(tObject({}));
|
||||||
scheme.ElementHandleInnerTextParams = tOptional(tObject({}));
|
scheme.ElementHandleInnerTextParams = tOptional(tObject({}));
|
||||||
|
scheme.ElementHandleIsDisabledParams = tOptional(tObject({}));
|
||||||
|
scheme.ElementHandleIsEditableParams = tOptional(tObject({}));
|
||||||
|
scheme.ElementHandleIsEnabledParams = tOptional(tObject({}));
|
||||||
|
scheme.ElementHandleIsHiddenParams = tOptional(tObject({}));
|
||||||
|
scheme.ElementHandleIsVisibleParams = tOptional(tObject({}));
|
||||||
scheme.ElementHandleOwnerFrameParams = tOptional(tObject({}));
|
scheme.ElementHandleOwnerFrameParams = tOptional(tObject({}));
|
||||||
scheme.ElementHandlePressParams = tObject({
|
scheme.ElementHandlePressParams = tObject({
|
||||||
key: tString,
|
key: tString,
|
||||||
|
|
@ -814,7 +839,7 @@ export function createScheme(tChannel: (name: string) => Validator): Scheme {
|
||||||
timeout: tOptional(tNumber),
|
timeout: tOptional(tNumber),
|
||||||
});
|
});
|
||||||
scheme.ElementHandleWaitForElementStateParams = tObject({
|
scheme.ElementHandleWaitForElementStateParams = tObject({
|
||||||
state: tEnum(['visible', 'hidden', 'stable', 'enabled', 'disabled']),
|
state: tEnum(['visible', 'hidden', 'stable', 'enabled', 'disabled', 'editable']),
|
||||||
timeout: tOptional(tNumber),
|
timeout: tOptional(tNumber),
|
||||||
});
|
});
|
||||||
scheme.ElementHandleWaitForSelectorParams = tObject({
|
scheme.ElementHandleWaitForSelectorParams = tObject({
|
||||||
|
|
|
||||||
|
|
@ -632,7 +632,36 @@ export class ElementHandle<T extends Node = Node> extends js.JSHandle<T> {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
async waitForElementState(state: 'visible' | 'hidden' | 'stable' | 'enabled' | 'disabled', options: types.TimeoutOptions = {}): Promise<void> {
|
async isVisible(): Promise<boolean> {
|
||||||
|
return this._evaluateInUtility(([injected, node]) => {
|
||||||
|
const element = node.nodeType === Node.ELEMENT_NODE ? node as Node as Element : node.parentElement;
|
||||||
|
return element ? injected.isVisible(element) : false;
|
||||||
|
}, {});
|
||||||
|
}
|
||||||
|
|
||||||
|
async isHidden(): Promise<boolean> {
|
||||||
|
return !(await this.isVisible());
|
||||||
|
}
|
||||||
|
|
||||||
|
async isEnabled(): Promise<boolean> {
|
||||||
|
return !(await this.isDisabled());
|
||||||
|
}
|
||||||
|
|
||||||
|
async isDisabled(): Promise<boolean> {
|
||||||
|
return this._evaluateInUtility(([injected, node]) => {
|
||||||
|
const element = node.nodeType === Node.ELEMENT_NODE ? node as Node as Element : node.parentElement;
|
||||||
|
return element ? injected.isElementDisabled(element) : false;
|
||||||
|
}, {});
|
||||||
|
}
|
||||||
|
|
||||||
|
async isEditable(): Promise<boolean> {
|
||||||
|
return this._evaluateInUtility(([injected, node]) => {
|
||||||
|
const element = node.nodeType === Node.ELEMENT_NODE ? node as Node as Element : node.parentElement;
|
||||||
|
return element ? !injected.isElementDisabled(element) && !injected.isElementReadOnly(element) : false;
|
||||||
|
}, {});
|
||||||
|
}
|
||||||
|
|
||||||
|
async waitForElementState(state: 'visible' | 'hidden' | 'stable' | 'enabled' | 'disabled' | 'editable', options: types.TimeoutOptions = {}): Promise<void> {
|
||||||
return runAbortableTask(async progress => {
|
return runAbortableTask(async progress => {
|
||||||
progress.log(` waiting for element to be ${state}`);
|
progress.log(` waiting for element to be ${state}`);
|
||||||
if (state === 'visible') {
|
if (state === 'visible') {
|
||||||
|
|
@ -667,6 +696,14 @@ export class ElementHandle<T extends Node = Node> extends js.JSHandle<T> {
|
||||||
assertDone(throwRetargetableDOMError(await pollHandler.finish()));
|
assertDone(throwRetargetableDOMError(await pollHandler.finish()));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (state === 'editable') {
|
||||||
|
const poll = await this._evaluateHandleInUtility(([injected, node]) => {
|
||||||
|
return injected.waitForNodeEnabled(node, true /* waitForEnabled */);
|
||||||
|
}, {});
|
||||||
|
const pollHandler = new InjectedScriptPollHandler(progress, poll);
|
||||||
|
assertDone(throwRetargetableDOMError(await pollHandler.finish()));
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (state === 'stable') {
|
if (state === 'stable') {
|
||||||
const rafCount = this._page._delegate.rafCountForStablePosition();
|
const rafCount = this._page._delegate.rafCountForStablePosition();
|
||||||
const poll = await this._evaluateHandleInUtility(([injected, node, rafOptions]) => {
|
const poll = await this._evaluateHandleInUtility(([injected, node, rafOptions]) => {
|
||||||
|
|
@ -676,7 +713,7 @@ export class ElementHandle<T extends Node = Node> extends js.JSHandle<T> {
|
||||||
assertDone(throwRetargetableDOMError(await pollHandler.finish()));
|
assertDone(throwRetargetableDOMError(await pollHandler.finish()));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
throw new Error(`state: expected one of (visible|hidden|stable|enabled)`);
|
throw new Error(`state: expected one of (visible|hidden|stable|enabled|disabled|editable)`);
|
||||||
}, this._page._timeoutSettings.timeout(options));
|
}, this._page._timeoutSettings.timeout(options));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -958,3 +995,39 @@ export function getAttributeTask(selector: SelectorInfo, name: string): Schedula
|
||||||
});
|
});
|
||||||
}, { parsed: selector.parsed, name });
|
}, { parsed: selector.parsed, name });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function visibleTask(selector: SelectorInfo): SchedulableTask<boolean> {
|
||||||
|
return injectedScript => injectedScript.evaluateHandle((injected, parsed) => {
|
||||||
|
return injected.pollRaf((progress, continuePolling) => {
|
||||||
|
const element = injected.querySelector(parsed, document);
|
||||||
|
if (!element)
|
||||||
|
return continuePolling;
|
||||||
|
progress.log(` selector resolved to ${injected.previewNode(element)}`);
|
||||||
|
return injected.isVisible(element);
|
||||||
|
});
|
||||||
|
}, selector.parsed);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function disabledTask(selector: SelectorInfo): SchedulableTask<boolean> {
|
||||||
|
return injectedScript => injectedScript.evaluateHandle((injected, parsed) => {
|
||||||
|
return injected.pollRaf((progress, continuePolling) => {
|
||||||
|
const element = injected.querySelector(parsed, document);
|
||||||
|
if (!element)
|
||||||
|
return continuePolling;
|
||||||
|
progress.log(` selector resolved to ${injected.previewNode(element)}`);
|
||||||
|
return injected.isElementDisabled(element);
|
||||||
|
});
|
||||||
|
}, selector.parsed);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function editableTask(selector: SelectorInfo): SchedulableTask<boolean> {
|
||||||
|
return injectedScript => injectedScript.evaluateHandle((injected, parsed) => {
|
||||||
|
return injected.pollRaf((progress, continuePolling) => {
|
||||||
|
const element = injected.querySelector(parsed, document);
|
||||||
|
if (!element)
|
||||||
|
return continuePolling;
|
||||||
|
progress.log(` selector resolved to ${injected.previewNode(element)}`);
|
||||||
|
return !injected.isElementDisabled(element) && !injected.isElementReadOnly(element);
|
||||||
|
});
|
||||||
|
}, selector.parsed);
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -928,6 +928,41 @@ export class Frame extends EventEmitter {
|
||||||
}, this._page._timeoutSettings.timeout(options));
|
}, this._page._timeoutSettings.timeout(options));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async isVisible(selector: string, options: types.TimeoutOptions = {}): Promise<boolean> {
|
||||||
|
const info = this._page.selectors._parseSelector(selector);
|
||||||
|
const task = dom.visibleTask(info);
|
||||||
|
return runAbortableTask(async progress => {
|
||||||
|
progress.log(` checking visibility of "${selector}"`);
|
||||||
|
return this._scheduleRerunnableTask(progress, info.world, task);
|
||||||
|
}, this._page._timeoutSettings.timeout(options));
|
||||||
|
}
|
||||||
|
|
||||||
|
async isHidden(selector: string, options: types.TimeoutOptions = {}): Promise<boolean> {
|
||||||
|
return !(await this.isVisible(selector, options));
|
||||||
|
}
|
||||||
|
|
||||||
|
async isDisabled(selector: string, options: types.TimeoutOptions = {}): Promise<boolean> {
|
||||||
|
const info = this._page.selectors._parseSelector(selector);
|
||||||
|
const task = dom.disabledTask(info);
|
||||||
|
return runAbortableTask(async progress => {
|
||||||
|
progress.log(` checking disabled state of "${selector}"`);
|
||||||
|
return this._scheduleRerunnableTask(progress, info.world, task);
|
||||||
|
}, this._page._timeoutSettings.timeout(options));
|
||||||
|
}
|
||||||
|
|
||||||
|
async isEnabled(selector: string, options: types.TimeoutOptions = {}): Promise<boolean> {
|
||||||
|
return !(await this.isDisabled(selector, options));
|
||||||
|
}
|
||||||
|
|
||||||
|
async isEditable(selector: string, options: types.TimeoutOptions = {}): Promise<boolean> {
|
||||||
|
const info = this._page.selectors._parseSelector(selector);
|
||||||
|
const task = dom.editableTask(info);
|
||||||
|
return runAbortableTask(async progress => {
|
||||||
|
progress.log(` checking editable state of "${selector}"`);
|
||||||
|
return this._scheduleRerunnableTask(progress, info.world, task);
|
||||||
|
}, this._page._timeoutSettings.timeout(options));
|
||||||
|
}
|
||||||
|
|
||||||
async hover(controller: ProgressController, selector: string, options: types.PointerActionOptions & types.PointerActionWaitOptions = {}) {
|
async hover(controller: ProgressController, selector: string, options: types.PointerActionOptions & types.PointerActionWaitOptions = {}) {
|
||||||
return controller.run(async progress => {
|
return controller.run(async progress => {
|
||||||
return dom.assertDone(await this._retryWithProgressIfNotConnected(progress, selector, handle => handle._hover(progress, options)));
|
return dom.assertDone(await this._retryWithProgressIfNotConnected(progress, selector, handle => handle._hover(progress, options)));
|
||||||
|
|
|
||||||
|
|
@ -418,15 +418,19 @@ export class InjectedScript {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
waitForNodeEnabled(node: Node): InjectedScriptPoll<'error:notconnected' | 'done'> {
|
waitForNodeEnabled(node: Node, waitForEditable?: boolean): InjectedScriptPoll<'error:notconnected' | 'done'> {
|
||||||
return this.pollRaf((progress, continuePolling) => {
|
return this.pollRaf((progress, continuePolling) => {
|
||||||
const element = node.nodeType === Node.ELEMENT_NODE ? node as Element : node.parentElement;
|
const element = node.nodeType === Node.ELEMENT_NODE ? node as Element : node.parentElement;
|
||||||
if (!node.isConnected || !element)
|
if (!node.isConnected || !element)
|
||||||
return 'error:notconnected';
|
return 'error:notconnected';
|
||||||
if (this._isElementDisabled(element)) {
|
if (this.isElementDisabled(element)) {
|
||||||
progress.logRepeating(' element is not enabled - waiting...');
|
progress.logRepeating(' element is not enabled - waiting...');
|
||||||
return continuePolling;
|
return continuePolling;
|
||||||
}
|
}
|
||||||
|
if (waitForEditable && this.isElementReadOnly(element)) {
|
||||||
|
progress.logRepeating(' element is readonly - waiting...');
|
||||||
|
return continuePolling;
|
||||||
|
}
|
||||||
return 'done';
|
return 'done';
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
@ -436,7 +440,7 @@ export class InjectedScript {
|
||||||
const element = node.nodeType === Node.ELEMENT_NODE ? node as Element : node.parentElement;
|
const element = node.nodeType === Node.ELEMENT_NODE ? node as Element : node.parentElement;
|
||||||
if (!node.isConnected || !element)
|
if (!node.isConnected || !element)
|
||||||
return 'error:notconnected';
|
return 'error:notconnected';
|
||||||
if (!this._isElementDisabled(element)) {
|
if (!this.isElementDisabled(element)) {
|
||||||
progress.logRepeating(' element is enabled - waiting...');
|
progress.logRepeating(' element is enabled - waiting...');
|
||||||
return continuePolling;
|
return continuePolling;
|
||||||
}
|
}
|
||||||
|
|
@ -545,7 +549,7 @@ export class InjectedScript {
|
||||||
const style = element.ownerDocument && element.ownerDocument.defaultView ? element.ownerDocument.defaultView.getComputedStyle(element) : undefined;
|
const style = element.ownerDocument && element.ownerDocument.defaultView ? element.ownerDocument.defaultView.getComputedStyle(element) : undefined;
|
||||||
const isVisible = !!style && style.visibility !== 'hidden';
|
const isVisible = !!style && style.visibility !== 'hidden';
|
||||||
|
|
||||||
const isDisabled = waitForEnabled && this._isElementDisabled(element);
|
const isDisabled = waitForEnabled && this.isElementDisabled(element);
|
||||||
|
|
||||||
if (isDisplayed && isStable && isVisible && !isDisabled)
|
if (isDisplayed && isStable && isVisible && !isDisabled)
|
||||||
return 'done';
|
return 'done';
|
||||||
|
|
@ -611,9 +615,14 @@ export class InjectedScript {
|
||||||
node.dispatchEvent(event);
|
node.dispatchEvent(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
private _isElementDisabled(element: Element): boolean {
|
isElementDisabled(element: Element): boolean {
|
||||||
const elementOrButton = element.closest('button, [role=button]') || element;
|
const elementOrButton = element.closest('button, [role=button]') || element;
|
||||||
return ['BUTTON', 'INPUT', 'SELECT'].includes(elementOrButton.nodeName) && elementOrButton.hasAttribute('disabled');
|
return ['BUTTON', 'INPUT', 'SELECT', 'TEXTAREA'].includes(elementOrButton.nodeName) && elementOrButton.hasAttribute('disabled');
|
||||||
|
}
|
||||||
|
|
||||||
|
isElementReadOnly(element: Element): boolean {
|
||||||
|
const target = this.findLabelTarget(element);
|
||||||
|
return !!target && ['INPUT', 'TEXTAREA'].includes(target.nodeName) && target.hasAttribute('readonly');
|
||||||
}
|
}
|
||||||
|
|
||||||
deepElementFromPoint(document: Document, x: number, y: number): Element | undefined {
|
deepElementFromPoint(document: Document, x: number, y: number): Element | undefined {
|
||||||
|
|
|
||||||
|
|
@ -156,3 +156,54 @@ it('getAttribute should be atomic', async ({ playwright, page }) => {
|
||||||
expect(tc).toBe('hello');
|
expect(tc).toBe('hello');
|
||||||
expect(await page.evaluate(() => document.querySelector('div').getAttribute('foo'))).toBe('modified');
|
expect(await page.evaluate(() => document.querySelector('div').getAttribute('foo'))).toBe('modified');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('isVisible and isHidden should work', async ({ page }) => {
|
||||||
|
await page.setContent(`<div>Hi</div><span></span>`);
|
||||||
|
const div = await page.$('div');
|
||||||
|
expect(await div.isVisible()).toBe(true);
|
||||||
|
expect(await div.isHidden()).toBe(false);
|
||||||
|
expect(await page.isVisible('div')).toBe(true);
|
||||||
|
expect(await page.isHidden('div')).toBe(false);
|
||||||
|
const span = await page.$('span');
|
||||||
|
expect(await span.isVisible()).toBe(false);
|
||||||
|
expect(await span.isHidden()).toBe(true);
|
||||||
|
expect(await page.isVisible('span')).toBe(false);
|
||||||
|
expect(await page.isHidden('span')).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('isEnabled and isDisabled should work', async ({ page }) => {
|
||||||
|
await page.setContent(`
|
||||||
|
<button disabled>button1</button>
|
||||||
|
<button>button2</button>
|
||||||
|
<div>div</div>
|
||||||
|
`);
|
||||||
|
const div = await page.$('div');
|
||||||
|
expect(await div.isEnabled()).toBe(true);
|
||||||
|
expect(await div.isDisabled()).toBe(false);
|
||||||
|
expect(await page.isEnabled('div')).toBe(true);
|
||||||
|
expect(await page.isDisabled('div')).toBe(false);
|
||||||
|
const button1 = await page.$(':text("button1")');
|
||||||
|
expect(await button1.isEnabled()).toBe(false);
|
||||||
|
expect(await button1.isDisabled()).toBe(true);
|
||||||
|
expect(await page.isEnabled(':text("button1")')).toBe(false);
|
||||||
|
expect(await page.isDisabled(':text("button1")')).toBe(true);
|
||||||
|
const button2 = await page.$(':text("button2")');
|
||||||
|
expect(await button2.isEnabled()).toBe(true);
|
||||||
|
expect(await button2.isDisabled()).toBe(false);
|
||||||
|
expect(await page.isEnabled(':text("button2")')).toBe(true);
|
||||||
|
expect(await page.isDisabled(':text("button2")')).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('isEditable should work', async ({ page }) => {
|
||||||
|
await page.setContent(`<input id=input1 disabled><textarea></textarea><input id=input2>`);
|
||||||
|
await page.$eval('textarea', t => t.readOnly = true);
|
||||||
|
const input1 = await page.$('#input1');
|
||||||
|
expect(await input1.isEditable()).toBe(false);
|
||||||
|
expect(await page.isEditable('#input1')).toBe(false);
|
||||||
|
const input2 = await page.$('#input2');
|
||||||
|
expect(await input2.isEditable()).toBe(true);
|
||||||
|
expect(await page.isEditable('#input2')).toBe(true);
|
||||||
|
const textarea = await page.$('textarea');
|
||||||
|
expect(await textarea.isEditable()).toBe(false);
|
||||||
|
expect(await page.isEditable('textarea')).toBe(false);
|
||||||
|
});
|
||||||
|
|
|
||||||
|
|
@ -130,3 +130,14 @@ it('should wait for stable position', (test, { browserName, platform }) => {
|
||||||
await button.evaluate(button => button.style.transition = '');
|
await button.evaluate(button => button.style.transition = '');
|
||||||
await promise;
|
await promise;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should wait for editable input', async ({page, server}) => {
|
||||||
|
await page.setContent('<input readonly>');
|
||||||
|
const input = await page.$('input');
|
||||||
|
let done = false;
|
||||||
|
const promise = input.waitForElementState('editable').then(() => done = true);
|
||||||
|
await giveItAChanceToResolve(page);
|
||||||
|
expect(done).toBe(false);
|
||||||
|
await input.evaluate(input => input.readOnly = false);
|
||||||
|
await promise;
|
||||||
|
});
|
||||||
|
|
|
||||||
188
types/types.d.ts
vendored
188
types/types.d.ts
vendored
|
|
@ -2038,6 +2038,86 @@ export interface Page {
|
||||||
*/
|
*/
|
||||||
isClosed(): boolean;
|
isClosed(): boolean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether the element is disabled, the opposite of [enabled](https://github.com/microsoft/playwright/blob/master/docs/actionability.md#enabled).
|
||||||
|
* @param selector A selector to search for element. If there are multiple elements satisfying the selector, the first will be used. See [working with selectors](https://github.com/microsoft/playwright/blob/master/docs/selectors.md#working-with-selectors) for more details.
|
||||||
|
* @param options
|
||||||
|
*/
|
||||||
|
isDisabled(selector: string, options?: {
|
||||||
|
/**
|
||||||
|
* Maximum time in milliseconds, defaults to 30 seconds, pass `0` to disable timeout. The default value can be changed by
|
||||||
|
* using the
|
||||||
|
* [browserContext.setDefaultTimeout(…)](https://github.com/microsoft/playwright/blob/master/docs/api.md#browsercontextsetdefaulttimeout)
|
||||||
|
* or [page.setDefaultTimeout(…)](https://github.com/microsoft/playwright/blob/master/docs/api.md#pagesetdefaulttimeout)
|
||||||
|
* methods.
|
||||||
|
*/
|
||||||
|
timeout?: number;
|
||||||
|
}): Promise<boolean>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether the element is [editable](https://github.com/microsoft/playwright/blob/master/docs/actionability.md#editable).
|
||||||
|
* @param selector A selector to search for element. If there are multiple elements satisfying the selector, the first will be used. See [working with selectors](https://github.com/microsoft/playwright/blob/master/docs/selectors.md#working-with-selectors) for more details.
|
||||||
|
* @param options
|
||||||
|
*/
|
||||||
|
isEditable(selector: string, options?: {
|
||||||
|
/**
|
||||||
|
* Maximum time in milliseconds, defaults to 30 seconds, pass `0` to disable timeout. The default value can be changed by
|
||||||
|
* using the
|
||||||
|
* [browserContext.setDefaultTimeout(…)](https://github.com/microsoft/playwright/blob/master/docs/api.md#browsercontextsetdefaulttimeout)
|
||||||
|
* or [page.setDefaultTimeout(…)](https://github.com/microsoft/playwright/blob/master/docs/api.md#pagesetdefaulttimeout)
|
||||||
|
* methods.
|
||||||
|
*/
|
||||||
|
timeout?: number;
|
||||||
|
}): Promise<boolean>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether the element is [enabled](https://github.com/microsoft/playwright/blob/master/docs/actionability.md#enabled).
|
||||||
|
* @param selector A selector to search for element. If there are multiple elements satisfying the selector, the first will be used. See [working with selectors](https://github.com/microsoft/playwright/blob/master/docs/selectors.md#working-with-selectors) for more details.
|
||||||
|
* @param options
|
||||||
|
*/
|
||||||
|
isEnabled(selector: string, options?: {
|
||||||
|
/**
|
||||||
|
* Maximum time in milliseconds, defaults to 30 seconds, pass `0` to disable timeout. The default value can be changed by
|
||||||
|
* using the
|
||||||
|
* [browserContext.setDefaultTimeout(…)](https://github.com/microsoft/playwright/blob/master/docs/api.md#browsercontextsetdefaulttimeout)
|
||||||
|
* or [page.setDefaultTimeout(…)](https://github.com/microsoft/playwright/blob/master/docs/api.md#pagesetdefaulttimeout)
|
||||||
|
* methods.
|
||||||
|
*/
|
||||||
|
timeout?: number;
|
||||||
|
}): Promise<boolean>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether the element is hidden, the opposite of [visible](https://github.com/microsoft/playwright/blob/master/docs/actionability.md#visible).
|
||||||
|
* @param selector A selector to search for element. If there are multiple elements satisfying the selector, the first will be used. See [working with selectors](https://github.com/microsoft/playwright/blob/master/docs/selectors.md#working-with-selectors) for more details.
|
||||||
|
* @param options
|
||||||
|
*/
|
||||||
|
isHidden(selector: string, options?: {
|
||||||
|
/**
|
||||||
|
* Maximum time in milliseconds, defaults to 30 seconds, pass `0` to disable timeout. The default value can be changed by
|
||||||
|
* using the
|
||||||
|
* [browserContext.setDefaultTimeout(…)](https://github.com/microsoft/playwright/blob/master/docs/api.md#browsercontextsetdefaulttimeout)
|
||||||
|
* or [page.setDefaultTimeout(…)](https://github.com/microsoft/playwright/blob/master/docs/api.md#pagesetdefaulttimeout)
|
||||||
|
* methods.
|
||||||
|
*/
|
||||||
|
timeout?: number;
|
||||||
|
}): Promise<boolean>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether the element is [visible](https://github.com/microsoft/playwright/blob/master/docs/actionability.md#visible).
|
||||||
|
* @param selector A selector to search for element. If there are multiple elements satisfying the selector, the first will be used. See [working with selectors](https://github.com/microsoft/playwright/blob/master/docs/selectors.md#working-with-selectors) for more details.
|
||||||
|
* @param options
|
||||||
|
*/
|
||||||
|
isVisible(selector: string, options?: {
|
||||||
|
/**
|
||||||
|
* Maximum time in milliseconds, defaults to 30 seconds, pass `0` to disable timeout. The default value can be changed by
|
||||||
|
* using the
|
||||||
|
* [browserContext.setDefaultTimeout(…)](https://github.com/microsoft/playwright/blob/master/docs/api.md#browsercontextsetdefaulttimeout)
|
||||||
|
* or [page.setDefaultTimeout(…)](https://github.com/microsoft/playwright/blob/master/docs/api.md#pagesetdefaulttimeout)
|
||||||
|
* methods.
|
||||||
|
*/
|
||||||
|
timeout?: number;
|
||||||
|
}): Promise<boolean>;
|
||||||
|
|
||||||
keyboard: Keyboard;
|
keyboard: Keyboard;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -3916,6 +3996,86 @@ export interface Frame {
|
||||||
*/
|
*/
|
||||||
isDetached(): boolean;
|
isDetached(): boolean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether the element is disabled, the opposite of [enabled](https://github.com/microsoft/playwright/blob/master/docs/actionability.md#enabled).
|
||||||
|
* @param selector A selector to search for element. If there are multiple elements satisfying the selector, the first will be used. See [working with selectors](https://github.com/microsoft/playwright/blob/master/docs/selectors.md#working-with-selectors) for more details.
|
||||||
|
* @param options
|
||||||
|
*/
|
||||||
|
isDisabled(selector: string, options?: {
|
||||||
|
/**
|
||||||
|
* Maximum time in milliseconds, defaults to 30 seconds, pass `0` to disable timeout. The default value can be changed by
|
||||||
|
* using the
|
||||||
|
* [browserContext.setDefaultTimeout(…)](https://github.com/microsoft/playwright/blob/master/docs/api.md#browsercontextsetdefaulttimeout)
|
||||||
|
* or [page.setDefaultTimeout(…)](https://github.com/microsoft/playwright/blob/master/docs/api.md#pagesetdefaulttimeout)
|
||||||
|
* methods.
|
||||||
|
*/
|
||||||
|
timeout?: number;
|
||||||
|
}): Promise<boolean>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether the element is [editable](https://github.com/microsoft/playwright/blob/master/docs/actionability.md#editable).
|
||||||
|
* @param selector A selector to search for element. If there are multiple elements satisfying the selector, the first will be used. See [working with selectors](https://github.com/microsoft/playwright/blob/master/docs/selectors.md#working-with-selectors) for more details.
|
||||||
|
* @param options
|
||||||
|
*/
|
||||||
|
isEditable(selector: string, options?: {
|
||||||
|
/**
|
||||||
|
* Maximum time in milliseconds, defaults to 30 seconds, pass `0` to disable timeout. The default value can be changed by
|
||||||
|
* using the
|
||||||
|
* [browserContext.setDefaultTimeout(…)](https://github.com/microsoft/playwright/blob/master/docs/api.md#browsercontextsetdefaulttimeout)
|
||||||
|
* or [page.setDefaultTimeout(…)](https://github.com/microsoft/playwright/blob/master/docs/api.md#pagesetdefaulttimeout)
|
||||||
|
* methods.
|
||||||
|
*/
|
||||||
|
timeout?: number;
|
||||||
|
}): Promise<boolean>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether the element is [enabled](https://github.com/microsoft/playwright/blob/master/docs/actionability.md#enabled).
|
||||||
|
* @param selector A selector to search for element. If there are multiple elements satisfying the selector, the first will be used. See [working with selectors](https://github.com/microsoft/playwright/blob/master/docs/selectors.md#working-with-selectors) for more details.
|
||||||
|
* @param options
|
||||||
|
*/
|
||||||
|
isEnabled(selector: string, options?: {
|
||||||
|
/**
|
||||||
|
* Maximum time in milliseconds, defaults to 30 seconds, pass `0` to disable timeout. The default value can be changed by
|
||||||
|
* using the
|
||||||
|
* [browserContext.setDefaultTimeout(…)](https://github.com/microsoft/playwright/blob/master/docs/api.md#browsercontextsetdefaulttimeout)
|
||||||
|
* or [page.setDefaultTimeout(…)](https://github.com/microsoft/playwright/blob/master/docs/api.md#pagesetdefaulttimeout)
|
||||||
|
* methods.
|
||||||
|
*/
|
||||||
|
timeout?: number;
|
||||||
|
}): Promise<boolean>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether the element is hidden, the opposite of [visible](https://github.com/microsoft/playwright/blob/master/docs/actionability.md#visible).
|
||||||
|
* @param selector A selector to search for element. If there are multiple elements satisfying the selector, the first will be used. See [working with selectors](https://github.com/microsoft/playwright/blob/master/docs/selectors.md#working-with-selectors) for more details.
|
||||||
|
* @param options
|
||||||
|
*/
|
||||||
|
isHidden(selector: string, options?: {
|
||||||
|
/**
|
||||||
|
* Maximum time in milliseconds, defaults to 30 seconds, pass `0` to disable timeout. The default value can be changed by
|
||||||
|
* using the
|
||||||
|
* [browserContext.setDefaultTimeout(…)](https://github.com/microsoft/playwright/blob/master/docs/api.md#browsercontextsetdefaulttimeout)
|
||||||
|
* or [page.setDefaultTimeout(…)](https://github.com/microsoft/playwright/blob/master/docs/api.md#pagesetdefaulttimeout)
|
||||||
|
* methods.
|
||||||
|
*/
|
||||||
|
timeout?: number;
|
||||||
|
}): Promise<boolean>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether the element is [visible](https://github.com/microsoft/playwright/blob/master/docs/actionability.md#visible).
|
||||||
|
* @param selector A selector to search for element. If there are multiple elements satisfying the selector, the first will be used. See [working with selectors](https://github.com/microsoft/playwright/blob/master/docs/selectors.md#working-with-selectors) for more details.
|
||||||
|
* @param options
|
||||||
|
*/
|
||||||
|
isVisible(selector: string, options?: {
|
||||||
|
/**
|
||||||
|
* Maximum time in milliseconds, defaults to 30 seconds, pass `0` to disable timeout. The default value can be changed by
|
||||||
|
* using the
|
||||||
|
* [browserContext.setDefaultTimeout(…)](https://github.com/microsoft/playwright/blob/master/docs/api.md#browsercontextsetdefaulttimeout)
|
||||||
|
* or [page.setDefaultTimeout(…)](https://github.com/microsoft/playwright/blob/master/docs/api.md#pagesetdefaulttimeout)
|
||||||
|
* methods.
|
||||||
|
*/
|
||||||
|
timeout?: number;
|
||||||
|
}): Promise<boolean>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns frame's name attribute as specified in the tag.
|
* Returns frame's name attribute as specified in the tag.
|
||||||
*
|
*
|
||||||
|
|
@ -5697,6 +5857,31 @@ export interface ElementHandle<T=Node> extends JSHandle<T> {
|
||||||
*/
|
*/
|
||||||
innerText(): Promise<string>;
|
innerText(): Promise<string>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether the element is disabled, the opposite of [enabled](https://github.com/microsoft/playwright/blob/master/docs/actionability.md#enabled).
|
||||||
|
*/
|
||||||
|
isDisabled(): Promise<boolean>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether the element is [editable](https://github.com/microsoft/playwright/blob/master/docs/actionability.md#editable).
|
||||||
|
*/
|
||||||
|
isEditable(): Promise<boolean>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether the element is [enabled](https://github.com/microsoft/playwright/blob/master/docs/actionability.md#enabled).
|
||||||
|
*/
|
||||||
|
isEnabled(): Promise<boolean>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether the element is hidden, the opposite of [visible](https://github.com/microsoft/playwright/blob/master/docs/actionability.md#visible).
|
||||||
|
*/
|
||||||
|
isHidden(): Promise<boolean>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether the element is [visible](https://github.com/microsoft/playwright/blob/master/docs/actionability.md#visible).
|
||||||
|
*/
|
||||||
|
isVisible(): Promise<boolean>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the frame containing the given element.
|
* Returns the frame containing the given element.
|
||||||
*/
|
*/
|
||||||
|
|
@ -6112,12 +6297,13 @@ export interface ElementHandle<T=Node> extends JSHandle<T> {
|
||||||
* [stable](https://github.com/microsoft/playwright/blob/master/docs/actionability.md#stable).
|
* [stable](https://github.com/microsoft/playwright/blob/master/docs/actionability.md#stable).
|
||||||
* - `"enabled"` Wait until the element is [enabled](https://github.com/microsoft/playwright/blob/master/docs/actionability.md#enabled).
|
* - `"enabled"` Wait until the element is [enabled](https://github.com/microsoft/playwright/blob/master/docs/actionability.md#enabled).
|
||||||
* - `"disabled"` Wait until the element is [not enabled](https://github.com/microsoft/playwright/blob/master/docs/actionability.md#enabled).
|
* - `"disabled"` Wait until the element is [not enabled](https://github.com/microsoft/playwright/blob/master/docs/actionability.md#enabled).
|
||||||
|
* - `"editable"` Wait until the element is [editable](https://github.com/microsoft/playwright/blob/master/docs/actionability.md#editable).
|
||||||
*
|
*
|
||||||
* If the element does not satisfy the condition for the `timeout` milliseconds, this method will throw.
|
* If the element does not satisfy the condition for the `timeout` milliseconds, this method will throw.
|
||||||
* @param state A state to wait for, see below for more details.
|
* @param state A state to wait for, see below for more details.
|
||||||
* @param options
|
* @param options
|
||||||
*/
|
*/
|
||||||
waitForElementState(state: "visible"|"hidden"|"stable"|"enabled"|"disabled", options?: {
|
waitForElementState(state: "visible"|"hidden"|"stable"|"enabled"|"disabled"|"editable", options?: {
|
||||||
/**
|
/**
|
||||||
* 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 a new issue