diff --git a/docs/src/actionability.md b/docs/src/actionability.md index 7902d9abbf..f0f3ca721d 100644 --- a/docs/src/actionability.md +++ b/docs/src/actionability.md @@ -20,6 +20,7 @@ Here is the complete list of actionability checks performed for each action: | check | Yes | Yes | Yes | Yes | Yes | - | | click | Yes | Yes | Yes | Yes | Yes | - | | dblclick | Yes | Yes | Yes | Yes | Yes | - | +| setChecked | Yes | Yes | Yes | Yes | Yes | - | | tap | Yes | Yes | Yes | Yes | Yes | - | | uncheck | Yes | Yes | Yes | Yes | Yes | - | | hover | Yes | Yes | Yes | Yes | - | - | diff --git a/docs/src/api/class-elementhandle.md b/docs/src/api/class-elementhandle.md index 3e2ed1e586..af7edb3815 100644 --- a/docs/src/api/class-elementhandle.md +++ b/docs/src/api/class-elementhandle.md @@ -743,6 +743,29 @@ content. ### option: ElementHandle.selectText.force = %%-input-force-%% ### option: ElementHandle.selectText.timeout = %%-input-timeout-%% +## async method: ElementHandle.setChecked + +This method checks or unchecks an element by performing the following steps: +1. Ensure that element is a checkbox or a radio input. If not, this method throws. +1. If the element already has the right checked state, this method returns immediately. +1. Wait for [actionability](./actionability.md) checks on the matched element, unless [`option: force`] option is + set. If the element is detached during the checks, the whole action is retried. +1. Scroll the element into view if needed. +1. Use [`property: Page.mouse`] to click in the center of the element. +1. Wait for initiated navigations to either succeed or fail, unless [`option: noWaitAfter`] option is set. +1. Ensure that the element is now checked or unchecked. If not, this method throws. + +When all steps combined have not finished during the specified [`option: timeout`], this method throws a +[TimeoutError]. Passing zero timeout disables this. + +### param: ElementHandle.setChecked.checked = %%-input-checked-%% +### option: ElementHandle.setChecked.force = %%-input-force-%% +### option: ElementHandle.setChecked.noWaitAfter = %%-input-no-wait-after-%% +### option: ElementHandle.setChecked.position = %%-input-position-%% +### option: ElementHandle.setChecked.strict = %%-input-strict-%% +### option: ElementHandle.setChecked.timeout = %%-input-timeout-%% +### option: ElementHandle.setChecked.trial = %%-input-trial-%% + ## async method: ElementHandle.setInputFiles This method expects `elementHandle` to point to an diff --git a/docs/src/api/class-frame.md b/docs/src/api/class-frame.md index 597a259a5e..929d1453cc 100644 --- a/docs/src/api/class-frame.md +++ b/docs/src/api/class-frame.md @@ -1097,6 +1097,34 @@ await frame.SelectOptionAsync("select#colors", new[] { "red", "green", "blue" }) ### option: Frame.selectOption.strict = %%-input-strict-%% ### option: Frame.selectOption.timeout = %%-input-timeout-%% + +## async method: Frame.setChecked + +This method checks or unchecks an element matching [`param: selector`] by performing the following steps: +1. Find an element matching [`param: selector`]. If there is none, wait until a matching element is attached to + the DOM. +1. Ensure that matched element is a checkbox or a radio input. If not, this method throws. +1. If the element already has the right checked state, this method returns immediately. +1. Wait for [actionability](./actionability.md) checks on the matched element, unless [`option: force`] option is + set. If the element is detached during the checks, the whole action is retried. +1. Scroll the element into view if needed. +1. Use [`property: Page.mouse`] to click in the center of the element. +1. Wait for initiated navigations to either succeed or fail, unless [`option: noWaitAfter`] option is set. +1. Ensure that the element is now checked or unchecked. If not, this method throws. + +When all steps combined have not finished during the specified [`option: timeout`], this method throws a +[TimeoutError]. Passing zero timeout disables this. + +### param: Frame.setChecked.selector = %%-input-selector-%% +### param: Frame.setChecked.checked = %%-input-checked-%% +### option: Frame.setChecked.force = %%-input-force-%% +### option: Frame.setChecked.noWaitAfter = %%-input-no-wait-after-%% +### option: Frame.setChecked.position = %%-input-position-%% +### option: Frame.setChecked.strict = %%-input-strict-%% +### option: Frame.setChecked.timeout = %%-input-timeout-%% +### option: Frame.setChecked.trial = %%-input-trial-%% + + ## async method: Frame.setContent ### param: Frame.setContent.html diff --git a/docs/src/api/class-locator.md b/docs/src/api/class-locator.md index 245f999e7e..e6c94970fa 100644 --- a/docs/src/api/class-locator.md +++ b/docs/src/api/class-locator.md @@ -799,6 +799,29 @@ content. ### option: Locator.selectText.force = %%-input-force-%% ### option: Locator.selectText.timeout = %%-input-timeout-%% +## async method: Locator.setChecked + +This method checks or unchecks an element by performing the following steps: +1. Ensure that matched element is a checkbox or a radio input. If not, this method throws. +1. If the element already has the right checked state, this method returns immediately. +1. Wait for [actionability](./actionability.md) checks on the matched element, unless [`option: force`] option is + set. If the element is detached during the checks, the whole action is retried. +1. Scroll the element into view if needed. +1. Use [`property: Page.mouse`] to click in the center of the element. +1. Wait for initiated navigations to either succeed or fail, unless [`option: noWaitAfter`] option is set. +1. Ensure that the element is now checked or unchecked. If not, this method throws. + +When all steps combined have not finished during the specified [`option: timeout`], this method throws a +[TimeoutError]. Passing zero timeout disables this. + +### param: Locator.setChecked.checked = %%-input-checked-%% +### option: Locator.setChecked.force = %%-input-force-%% +### option: Locator.setChecked.noWaitAfter = %%-input-no-wait-after-%% +### option: Locator.setChecked.position = %%-input-position-%% +### option: Locator.setChecked.strict = %%-input-strict-%% +### option: Locator.setChecked.timeout = %%-input-timeout-%% +### option: Locator.setChecked.trial = %%-input-trial-%% + ## async method: Locator.setInputFiles This method expects `element` to point to an diff --git a/docs/src/api/class-page.md b/docs/src/api/class-page.md index e625f98ff0..cce865be20 100644 --- a/docs/src/api/class-page.md +++ b/docs/src/api/class-page.md @@ -2676,6 +2676,34 @@ Shortcut for main frame's [`method: Frame.selectOption`]. ### option: Page.selectOption.strict = %%-input-strict-%% ### option: Page.selectOption.timeout = %%-input-timeout-%% +## async method: Page.setChecked + +This method checks or unchecks an element matching [`param: selector`] by performing the following steps: +1. Find an element matching [`param: selector`]. If there is none, wait until a matching element is attached to + the DOM. +1. Ensure that matched element is a checkbox or a radio input. If not, this method throws. +1. If the element already has the right checked state, this method returns immediately. +1. Wait for [actionability](./actionability.md) checks on the matched element, unless [`option: force`] option is + set. If the element is detached during the checks, the whole action is retried. +1. Scroll the element into view if needed. +1. Use [`property: Page.mouse`] to click in the center of the element. +1. Wait for initiated navigations to either succeed or fail, unless [`option: noWaitAfter`] option is set. +1. Ensure that the element is now checked or unchecked. If not, this method throws. + +When all steps combined have not finished during the specified [`option: timeout`], this method throws a +[TimeoutError]. Passing zero timeout disables this. + +Shortcut for main frame's [`method: Frame.setChecked`]. + +### param: Page.setChecked.selector = %%-input-selector-%% +### param: Page.setChecked.checked = %%-input-checked-%% +### option: Page.setChecked.force = %%-input-force-%% +### option: Page.setChecked.noWaitAfter = %%-input-no-wait-after-%% +### option: Page.setChecked.position = %%-input-position-%% +### option: Page.setChecked.strict = %%-input-strict-%% +### option: Page.setChecked.timeout = %%-input-timeout-%% +### option: Page.setChecked.trial = %%-input-trial-%% + ## async method: Page.setContent ### param: Page.setContent.html diff --git a/docs/src/api/params.md b/docs/src/api/params.md index 21ef65b379..18b20aeee1 100644 --- a/docs/src/api/params.md +++ b/docs/src/api/params.md @@ -117,6 +117,11 @@ Clicks on the source element at this point relative to the top-left corner of th Drops on the target element at this point relative to the top-left corner of the element's padding box. If not specified, some visible point of the element is used. +## input-checked +- `checked` <[boolean]> + +Whether to check or uncheck the checkbox. + ## query-selector - `selector` <[string]> diff --git a/src/client/elementHandle.ts b/src/client/elementHandle.ts index 15ad3cb75c..c92b4f081f 100644 --- a/src/client/elementHandle.ts +++ b/src/client/elementHandle.ts @@ -217,6 +217,13 @@ export class ElementHandle extends JSHandle implements }); } + async setChecked(checked: boolean, options?: channels.ElementHandleCheckOptions) { + if (checked) + await this.check(options); + else + await this.uncheck(options); + } + async boundingBox(): Promise { return this._wrapApiCall(async (channel: channels.ElementHandleChannel) => { const value = (await channel.boundingBox()).value; diff --git a/src/client/frame.ts b/src/client/frame.ts index 60a3895d9f..e03ceb8d18 100644 --- a/src/client/frame.ts +++ b/src/client/frame.ts @@ -437,6 +437,13 @@ export class Frame extends ChannelOwner { await new Promise(fulfill => setTimeout(fulfill, timeout)); diff --git a/src/client/locator.ts b/src/client/locator.ts index 5bb7db78af..fade145f1a 100644 --- a/src/client/locator.ts +++ b/src/client/locator.ts @@ -177,6 +177,13 @@ export class Locator implements api.Locator { return this._withElement((h, timeout) => h.selectText({ ...options, timeout }), options.timeout); } + async setChecked(checked: boolean, options?: channels.ElementHandleCheckOptions) { + if (checked) + await this.check(options); + else + await this.uncheck(options); + } + async setInputFiles(files: string | FilePayload | string[] | FilePayload[], options: channels.ElementHandleSetInputFilesOptions = {}) { return this._frame.setInputFiles(this._selector, files, { strict: true, ...options }); } diff --git a/src/client/page.ts b/src/client/page.ts index c3f48d3cc7..2c05e90bd9 100644 --- a/src/client/page.ts +++ b/src/client/page.ts @@ -603,6 +603,10 @@ export class Page extends ChannelOwner { expect(await page.evaluate('checkbox.checked')).toBe(true); }); +it('should check the box using setChecked', async ({ page }) => { + await page.setContent(``); + const input = await page.$('input'); + await input.setChecked(true); + expect(await page.evaluate('checkbox.checked')).toBe(true); + await input.setChecked(false); + expect(await page.evaluate('checkbox.checked')).toBe(false); +}); + it('should uncheck the box', async ({ page }) => { await page.setContent(``); const input = await page.$('input'); diff --git a/tests/page/locator-misc-1.spec.ts b/tests/page/locator-misc-1.spec.ts index 98d3919cea..cac3fb4333 100644 --- a/tests/page/locator-misc-1.spec.ts +++ b/tests/page/locator-misc-1.spec.ts @@ -55,6 +55,15 @@ it('should check the box', async ({ page }) => { expect(await page.evaluate('checkbox.checked')).toBe(true); }); +it('should check the box using setChecked', async ({ page }) => { + await page.setContent(``); + const input = page.locator('input'); + await input.setChecked(true); + expect(await page.evaluate('checkbox.checked')).toBe(true); + await input.setChecked(false); + expect(await page.evaluate('checkbox.checked')).toBe(false); +}); + it('should uncheck the box', async ({ page }) => { await page.setContent(``); const input = page.locator('input'); diff --git a/tests/page/page-check.spec.ts b/tests/page/page-check.spec.ts index 7b9bf1f412..6b94e3e865 100644 --- a/tests/page/page-check.spec.ts +++ b/tests/page/page-check.spec.ts @@ -131,3 +131,11 @@ it('trial run should not uncheck', async ({page}) => { await page.uncheck('input', { trial: true }); expect(await page.evaluate(() => window['checkbox'].checked)).toBe(true); }); + +it('should check the box using setChecked', async ({page}) => { + await page.setContent(``); + await page.setChecked('input', true); + expect(await page.evaluate(() => window['checkbox'].checked)).toBe(true); + await page.setChecked('input', false); + expect(await page.evaluate(() => window['checkbox'].checked)).toBe(false); +}); diff --git a/types/types.d.ts b/types/types.d.ts index a3a955dc70..3164934478 100644 --- a/types/types.d.ts +++ b/types/types.d.ts @@ -2897,6 +2897,71 @@ export interface Page { timeout?: number; }): Promise>; + /** + * This method checks or unchecks an element matching `selector` by performing the following steps: + * 1. Find an element matching `selector`. If there is none, wait until a matching element is attached to the DOM. + * 1. Ensure that matched element is a checkbox or a radio input. If not, this method throws. + * 1. If the element already has the right checked state, this method returns immediately. + * 1. Wait for [actionability](https://playwright.dev/docs/actionability) checks on the matched element, unless `force` option is set. If the + * element is detached during the checks, the whole action is retried. + * 1. Scroll the element into view if needed. + * 1. Use [page.mouse](https://playwright.dev/docs/api/class-page#page-mouse) to click in the center of the element. + * 1. Wait for initiated navigations to either succeed or fail, unless `noWaitAfter` option is set. + * 1. Ensure that the element is now checked or unchecked. If not, this method throws. + * + * When all steps combined have not finished during the specified `timeout`, this method throws a [TimeoutError]. Passing + * zero timeout disables this. + * + * Shortcut for main frame's + * [frame.setChecked(selector, checked[, options])](https://playwright.dev/docs/api/class-frame#frame-set-checked). + * @param selector A selector to search for an element. If there are multiple elements satisfying the selector, the first will be used. See [working with selectors](https://playwright.dev/docs/selectors) for more details. + * @param checked Whether to check or uncheck the checkbox. + * @param options + */ + setChecked(selector: string, checked: boolean, 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 + * opt out of waiting via setting this flag. You would only need this option in the exceptional cases such as navigating to + * inaccessible pages. Defaults to `false`. + */ + noWaitAfter?: boolean; + + /** + * A point to use relative to the top-left corner of element padding box. If not specified, uses some visible point of the + * element. + */ + position?: { + x: number; + + y: number; + }; + + /** + * When true, the call requires selector to resolve to a single element. If given selector resolves to more then one + * element, the call throws an exception. + */ + strict?: boolean; + + /** + * Maximum time in milliseconds, defaults to 30 seconds, pass `0` to disable timeout. The default value can be changed by + * using the + * [browserContext.setDefaultTimeout(timeout)](https://playwright.dev/docs/api/class-browsercontext#browser-context-set-default-timeout) + * or [page.setDefaultTimeout(timeout)](https://playwright.dev/docs/api/class-page#page-set-default-timeout) methods. + */ + timeout?: number; + + /** + * When set, this method only performs the [actionability](https://playwright.dev/docs/actionability) checks and skips the action. Defaults to + * `false`. Useful to wait until the element is ready for the action without performing it. + */ + trial?: boolean; + }): Promise; + /** * @param html HTML markup to assign to the page. * @param options @@ -5254,6 +5319,68 @@ export interface Frame { timeout?: number; }): Promise>; + /** + * This method checks or unchecks an element matching `selector` by performing the following steps: + * 1. Find an element matching `selector`. If there is none, wait until a matching element is attached to the DOM. + * 1. Ensure that matched element is a checkbox or a radio input. If not, this method throws. + * 1. If the element already has the right checked state, this method returns immediately. + * 1. Wait for [actionability](https://playwright.dev/docs/actionability) checks on the matched element, unless `force` option is set. If the + * element is detached during the checks, the whole action is retried. + * 1. Scroll the element into view if needed. + * 1. Use [page.mouse](https://playwright.dev/docs/api/class-page#page-mouse) to click in the center of the element. + * 1. Wait for initiated navigations to either succeed or fail, unless `noWaitAfter` option is set. + * 1. Ensure that the element is now checked or unchecked. If not, this method throws. + * + * When all steps combined have not finished during the specified `timeout`, this method throws a [TimeoutError]. Passing + * zero timeout disables this. + * @param selector A selector to search for an element. If there are multiple elements satisfying the selector, the first will be used. See [working with selectors](https://playwright.dev/docs/selectors) for more details. + * @param checked Whether to check or uncheck the checkbox. + * @param options + */ + setChecked(selector: string, checked: boolean, 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 + * opt out of waiting via setting this flag. You would only need this option in the exceptional cases such as navigating to + * inaccessible pages. Defaults to `false`. + */ + noWaitAfter?: boolean; + + /** + * A point to use relative to the top-left corner of element padding box. If not specified, uses some visible point of the + * element. + */ + position?: { + x: number; + + y: number; + }; + + /** + * When true, the call requires selector to resolve to a single element. If given selector resolves to more then one + * element, the call throws an exception. + */ + strict?: boolean; + + /** + * Maximum time in milliseconds, defaults to 30 seconds, pass `0` to disable timeout. The default value can be changed by + * using the + * [browserContext.setDefaultTimeout(timeout)](https://playwright.dev/docs/api/class-browsercontext#browser-context-set-default-timeout) + * or [page.setDefaultTimeout(timeout)](https://playwright.dev/docs/api/class-page#page-set-default-timeout) methods. + */ + timeout?: number; + + /** + * When set, this method only performs the [actionability](https://playwright.dev/docs/actionability) checks and skips the action. Defaults to + * `false`. Useful to wait until the element is ready for the action without performing it. + */ + trial?: boolean; + }): Promise; + /** * @param html HTML markup to assign to the page. * @param options @@ -7866,6 +7993,66 @@ export interface ElementHandle extends JSHandle { timeout?: number; }): Promise; + /** + * This method checks or unchecks an element by performing the following steps: + * 1. Ensure that element is a checkbox or a radio input. If not, this method throws. + * 1. If the element already has the right checked state, this method returns immediately. + * 1. Wait for [actionability](https://playwright.dev/docs/actionability) checks on the matched element, unless `force` option is set. If the + * element is detached during the checks, the whole action is retried. + * 1. Scroll the element into view if needed. + * 1. Use [page.mouse](https://playwright.dev/docs/api/class-page#page-mouse) to click in the center of the element. + * 1. Wait for initiated navigations to either succeed or fail, unless `noWaitAfter` option is set. + * 1. Ensure that the element is now checked or unchecked. If not, this method throws. + * + * When all steps combined have not finished during the specified `timeout`, this method throws a [TimeoutError]. Passing + * zero timeout disables this. + * @param checked Whether to check or uncheck the checkbox. + * @param options + */ + setChecked(checked: boolean, 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 + * opt out of waiting via setting this flag. You would only need this option in the exceptional cases such as navigating to + * inaccessible pages. Defaults to `false`. + */ + noWaitAfter?: boolean; + + /** + * A point to use relative to the top-left corner of element padding box. If not specified, uses some visible point of the + * element. + */ + position?: { + x: number; + + y: number; + }; + + /** + * When true, the call requires selector to resolve to a single element. If given selector resolves to more then one + * element, the call throws an exception. + */ + strict?: boolean; + + /** + * Maximum time in milliseconds, defaults to 30 seconds, pass `0` to disable timeout. The default value can be changed by + * using the + * [browserContext.setDefaultTimeout(timeout)](https://playwright.dev/docs/api/class-browsercontext#browser-context-set-default-timeout) + * or [page.setDefaultTimeout(timeout)](https://playwright.dev/docs/api/class-page#page-set-default-timeout) methods. + */ + timeout?: number; + + /** + * When set, this method only performs the [actionability](https://playwright.dev/docs/actionability) checks and skips the action. Defaults to + * `false`. Useful to wait until the element is ready for the action without performing it. + */ + trial?: boolean; + }): Promise; + /** * This method expects `elementHandle` to point to an * [input element](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input). @@ -9063,6 +9250,66 @@ export interface Locator { timeout?: number; }): Promise; + /** + * This method checks or unchecks an element by performing the following steps: + * 1. Ensure that matched element is a checkbox or a radio input. If not, this method throws. + * 1. If the element already has the right checked state, this method returns immediately. + * 1. Wait for [actionability](https://playwright.dev/docs/actionability) checks on the matched element, unless `force` option is set. If the + * element is detached during the checks, the whole action is retried. + * 1. Scroll the element into view if needed. + * 1. Use [page.mouse](https://playwright.dev/docs/api/class-page#page-mouse) to click in the center of the element. + * 1. Wait for initiated navigations to either succeed or fail, unless `noWaitAfter` option is set. + * 1. Ensure that the element is now checked or unchecked. If not, this method throws. + * + * When all steps combined have not finished during the specified `timeout`, this method throws a [TimeoutError]. Passing + * zero timeout disables this. + * @param checked Whether to check or uncheck the checkbox. + * @param options + */ + setChecked(checked: boolean, 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 + * opt out of waiting via setting this flag. You would only need this option in the exceptional cases such as navigating to + * inaccessible pages. Defaults to `false`. + */ + noWaitAfter?: boolean; + + /** + * A point to use relative to the top-left corner of element padding box. If not specified, uses some visible point of the + * element. + */ + position?: { + x: number; + + y: number; + }; + + /** + * When true, the call requires selector to resolve to a single element. If given selector resolves to more then one + * element, the call throws an exception. + */ + strict?: boolean; + + /** + * Maximum time in milliseconds, defaults to 30 seconds, pass `0` to disable timeout. The default value can be changed by + * using the + * [browserContext.setDefaultTimeout(timeout)](https://playwright.dev/docs/api/class-browsercontext#browser-context-set-default-timeout) + * or [page.setDefaultTimeout(timeout)](https://playwright.dev/docs/api/class-page#page-set-default-timeout) methods. + */ + timeout?: number; + + /** + * When set, this method only performs the [actionability](https://playwright.dev/docs/actionability) checks and skips the action. Defaults to + * `false`. Useful to wait until the element is ready for the action without performing it. + */ + trial?: boolean; + }): Promise; + /** * This method expects `element` to point to an * [input element](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input).