like in selenium, do we have option in Playwright to wait for an element to be clickable ?
-
Please provide more details. What do you mean by clickable? What element is this? Please show the site and the code you're using so far. Providing this info will improve the quality of your answers and enable folks to write a specific, guaranteed correct answer that actually solves your problem, rather than hand-wavey guesses that probably won't help you much. Thanks.ggorlen– ggorlen2022-07-23 23:23:38 +00:00Commented Jul 23, 2022 at 23:23
-
Yes , you can. See this - stackoverflow.com/a/78322389Vishal Aggarwal– Vishal Aggarwal2024-04-14 00:48:31 +00:00Commented Apr 14, 2024 at 0:48
-
Use Locator assertions- playwright.dev/docs/api/class-locatorassertionsVishal Aggarwal– Vishal Aggarwal2024-04-14 01:00:16 +00:00Commented Apr 14, 2024 at 1:00
6 Answers
For page.click(selector[, options]), Playwright will ensure that:
- element is Attached to the DOM
- element is Visible
- element is Stable, as in not animating or completed animation
- element Receives Events, as in not obscured by other elements
- element is Enabled
So, you can use this:
await page.click('button');
If you want to add a timeout, basically to allow playwright to complete the above checks and then click, you can do like this:
await page.click('button', {timeout: 9000});
To first check that the element is visible and then click another element based on the result, you can use an if-else like this:
if (await page.locator('modal-selector').isEnabled()) {
await page.click('button1')
} else {
//do something
}
4 Comments
await expect(page.locator(selector)).toBeEnabled()Playwright is "auto-waiting" for this.
Checkout the documentation: https://playwright.dev/docs/actionability
You can check the button state with the method isDisabled()
Checkout the docs: https://playwright.dev/docs/api/class-elementhandle#element-handle-is-disabled
2 Comments
Yes - you can wait for an element to reach a certain state
Use locator assertions
The LocatorAssertions class provides assertion methods that can be used to make assertions about the Locator state in the tests.This will wait for an locator to reach an certain state until timeout.
Ensures the Locator points to an enabled element.
const locator = page.locator('button.submit');
await expect(locator).toBeEnabled();
Ensures the Locator points to an editable element.
const locator = page.getByRole('textbox');
await expect(locator).toBeEditable();
Comments
This is not exactly about clickable-state, but for visible one. Java implementation
page.locator("button[aria-label=Search]")
.waitFor(new Locator.WaitForOptions()
.setState(WaitForSelectorState.VISIBLE)
.setTimeout(10000));
I have found only 4 possible states to wait for:
package com.microsoft.playwright.options;
public enum WaitForSelectorState {
ATTACHED,
DETACHED,
VISIBLE,
HIDDEN
}
Comments
I haven't found the solution offered by playwright directly. For performance testing, you should not wait for load event. This way you can verify latency of e.g. button doing what it's expected to do and click it. Even if page browser hasn't emitted load event yet.
Waiting for load event, which is a default Page.NavigateOptions, disturbs the measurements. Depending on what page you're testing you might have even 50%+ worse latencies which do not reflect the reality - that user can already interact with an element before regardless of browser events
Side effect is a visible element might not have event listeners yet and be clickable.
What I wish was working
page.navigate("https://some-tested-page.com", Page.NavigateOptions().setWaitUntil(WaitUntilState.COMMIT))
val button = page.getByText("Yes").first()
button.waitFor()
// nope, not working. button is clicked before it has event listeners
button.click(Locator. ClickOptions().setTimeout(2000.0))
// timeout
page.getByText("This field is required").first().waitFor()
And what actually works. It's using a piece of code out of playwright that does the polling and checks if button started working
page.navigate("https://some-tested-page.com")
val success = conditionPolling.await(
retryWait = ofMillis(10),
timeout = ofMillis(2000)
) {
val button = page.getByText("Yes").first()
button.waitFor()
button.click(Locator.ClickOptions().setNoWaitAfter(true))
page.getByText("This field is required").count() >= 1
}
if (!success) {
throw TimeoutError("Waiting for working button timed out")
}
It would be great if if playwright checked if element is not only clickable, but handling events. Or offer a method for waiting until element has event listeners attached.
EDIT: I've found out there is Page.waitForCondition. I don't know what polling interval there is under the hood, but it doesn't give the same performance results as 'manual' polling every 10ms. Using Page.waitForCondition gives ~4% bigger latencies in measurements. So the additional complexity by using custom code has value.
page.navigate("https://some-tested-page.com")
page.waitForCondition {
val button = page.getByText("Yes").first()
button.waitFor()
button.click(Locator.ClickOptions().setNoWaitAfter(true))
page.getByText("This field is required").count() >= 1
}
1 Comment
The Click method has an overload that lets you pass an instance of LocatorClickOptions. Use that with the Trial property set to true.
In the following C# code, the execution will wait until the page has a button labelled "Sign In" that is clickable.
await Page.GetByRole(AriaRole.Button, new() { Name = "Sign In" }).ClickAsync(new LocatorClickOptions() { Trial = true });
Clickable means:
- element is Attached to the DOM
- element is Visible
- element is Stable, as in not animating or completed animation
- element Receives Events, as in not obscured by other elements
- element is Enabled