Skip to content

Commit

Permalink
cherry-pick(#29770): docs: improve addLocatorHandler docs
Browse files Browse the repository at this point in the history
  • Loading branch information
dgozman committed Mar 1, 2024
1 parent a702595 commit d4ac444
Show file tree
Hide file tree
Showing 2 changed files with 36 additions and 31 deletions.
18 changes: 10 additions & 8 deletions docs/src/api/class-page.md
Original file line number Diff line number Diff line change
Expand Up @@ -3146,27 +3146,29 @@ return value resolves to `[]`.
## async method: Page.addLocatorHandler
* since: v1.42

Sometimes, the web page can show an overlay that obstructs elements behind it and prevents certain actions, like click, from completing. When such an overlay is shown predictably, we recommend dismissing it as a part of your test flow. However, sometimes such an overlay may appear non-deterministically, for example certain cookies consent dialogs behave this way. In this case, [`method: Page.addLocatorHandler`] allows handling an overlay during an action that it would block.
When testing a web page, sometimes unexpected overlays like a coookie consent dialog appear and block actions you want to automate, e.g. clicking a button. These overlays don't always show up in the same way or at the same time, making them tricky to handle in automated tests.
This method registers a handler for an overlay that is executed once the locator is visible on the page. The handler should get rid of the overlay so that actions blocked by it can proceed. This is useful for nondeterministic interstitial pages or dialogs, like a cookie consent dialog.
This method lets you set up a special function, called a handler, that activates when it detects that overlay is visible. The handler's job is to remove the overlay, allowing your test to continue as if the overlay wasn't there.
Note that execution time of the handler counts towards the timeout of the action/assertion that executed the handler.

You can register multiple handlers. However, only a single handler will be running at a time. Any actions inside a handler must not require another handler to run.
Things to keep in mind:
* When an overlay is shown predictably, we recommend explicitly waiting for it in your test and dismissing it as a part of your normal test flow, instead of using [`method: Page.addLocatorHandler`].
* Playwright checks for the overlay every time before executing or retrying an action that requires an [actionability check](../actionability.md), or before performing an auto-waiting assertion check. When overlay is visible, Playwright calls the handler first, and then proceeds with the action/assertion.
* The execution time of the handler counts towards the timeout of the action/assertion that executed the handler. If your handler takes too long, it might cause timeouts.
* You can register multiple handlers. However, only a single handler will be running at a time. Make sure the actions within a handler don't depend on another handler.

:::warning
Running the interceptor will alter your page state mid-test. For example it will change the currently focused element and move the mouse. Make sure that the actions that run after the interceptor are self-contained and do not rely on the focus and mouse state.
Running the handler will alter your page state mid-test. For example it will change the currently focused element and move the mouse. Make sure that actions that run after the handler are self-contained and do not rely on the focus and mouse state being unchanged.
<br />
<br />
For example, consider a test that calls [`method: Locator.focus`] followed by [`method: Keyboard.press`]. If your handler clicks a button between these two actions, the focused element most likely will be wrong, and key press will happen on the unexpected element. Use [`method: Locator.press`] instead to avoid this problem.
<br />
<br />
Another example is a series of mouse actions, where [`method: Mouse.move`] is followed by [`method: Mouse.down`]. Again, when the handler runs between these two actions, the mouse position will be wrong during the mouse down. Prefer methods like [`method: Locator.click`] that are self-contained.
Another example is a series of mouse actions, where [`method: Mouse.move`] is followed by [`method: Mouse.down`]. Again, when the handler runs between these two actions, the mouse position will be wrong during the mouse down. Prefer self-contained actions like [`method: Locator.click`] that do not rely on the state being unchanged by a handler.
:::

**Usage**

An example that closes a cookie dialog when it appears:
An example that closes a cookie consent dialog when it appears:

```js
// Setup the handler.
Expand Down
49 changes: 26 additions & 23 deletions packages/playwright-core/types/types.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1781,26 +1781,28 @@ export interface Page {
prependListener(event: 'worker', listener: (worker: Worker) => void): this;

/**
* Sometimes, the web page can show an overlay that obstructs elements behind it and prevents certain actions, like
* click, from completing. When such an overlay is shown predictably, we recommend dismissing it as a part of your
* test flow. However, sometimes such an overlay may appear non-deterministically, for example certain cookies consent
* dialogs behave this way. In this case,
* [page.addLocatorHandler(locator, handler)](https://playwright.dev/docs/api/class-page#page-add-locator-handler)
* allows handling an overlay during an action that it would block.
*
* This method registers a handler for an overlay that is executed once the locator is visible on the page. The
* handler should get rid of the overlay so that actions blocked by it can proceed. This is useful for
* nondeterministic interstitial pages or dialogs, like a cookie consent dialog.
*
* Note that execution time of the handler counts towards the timeout of the action/assertion that executed the
* handler.
*
* You can register multiple handlers. However, only a single handler will be running at a time. Any actions inside a
* handler must not require another handler to run.
*
* **NOTE** Running the interceptor will alter your page state mid-test. For example it will change the currently
* focused element and move the mouse. Make sure that the actions that run after the interceptor are self-contained
* and do not rely on the focus and mouse state. <br /> <br /> For example, consider a test that calls
* When testing a web page, sometimes unexpected overlays like a coookie consent dialog appear and block actions you
* want to automate, e.g. clicking a button. These overlays don't always show up in the same way or at the same time,
* making them tricky to handle in automated tests.
*
* This method lets you set up a special function, called a handler, that activates when it detects that overlay is
* visible. The handler's job is to remove the overlay, allowing your test to continue as if the overlay wasn't there.
*
* Things to keep in mind:
* - When an overlay is shown predictably, we recommend explicitly waiting for it in your test and dismissing it as
* a part of your normal test flow, instead of using
* [page.addLocatorHandler(locator, handler)](https://playwright.dev/docs/api/class-page#page-add-locator-handler).
* - Playwright checks for the overlay every time before executing or retrying an action that requires an
* [actionability check](https://playwright.dev/docs/actionability), or before performing an auto-waiting assertion check. When overlay
* is visible, Playwright calls the handler first, and then proceeds with the action/assertion.
* - The execution time of the handler counts towards the timeout of the action/assertion that executed the handler.
* If your handler takes too long, it might cause timeouts.
* - You can register multiple handlers. However, only a single handler will be running at a time. Make sure the
* actions within a handler don't depend on another handler.
*
* **NOTE** Running the handler will alter your page state mid-test. For example it will change the currently focused
* element and move the mouse. Make sure that actions that run after the handler are self-contained and do not rely on
* the focus and mouse state being unchanged. <br /> <br /> For example, consider a test that calls
* [locator.focus([options])](https://playwright.dev/docs/api/class-locator#locator-focus) followed by
* [keyboard.press(key[, options])](https://playwright.dev/docs/api/class-keyboard#keyboard-press). If your handler
* clicks a button between these two actions, the focused element most likely will be wrong, and key press will happen
Expand All @@ -1809,12 +1811,13 @@ export interface Page {
* problem. <br /> <br /> Another example is a series of mouse actions, where
* [mouse.move(x, y[, options])](https://playwright.dev/docs/api/class-mouse#mouse-move) is followed by
* [mouse.down([options])](https://playwright.dev/docs/api/class-mouse#mouse-down). Again, when the handler runs
* between these two actions, the mouse position will be wrong during the mouse down. Prefer methods like
* [locator.click([options])](https://playwright.dev/docs/api/class-locator#locator-click) that are self-contained.
* between these two actions, the mouse position will be wrong during the mouse down. Prefer self-contained actions
* like [locator.click([options])](https://playwright.dev/docs/api/class-locator#locator-click) that do not rely on
* the state being unchanged by a handler.
*
* **Usage**
*
* An example that closes a cookie dialog when it appears:
* An example that closes a cookie consent dialog when it appears:
*
* ```js
* // Setup the handler.
Expand Down

0 comments on commit d4ac444

Please sign in to comment.