Check whether an element exists in Playwright

Use retrying assertions for DOM presence and visibility, and understand when count() or isVisible() only gives a snapshot.

Best practices
Illustration of software development and testing

Use await expect(locator).toBeVisible() when a test requires a visible element. Use toBeAttached() when DOM presence is sufficient. For a conditional branch, isVisible() or count() can inspect the current state, but they do not wait for a future render.

Presence, visibility, and the number of matches are different requirements. None alone guarantees that an element can receive a click.

Prefer retrying assertions

These fragments assume a configured Playwright Test project with expect imported and a test page already loaded:

// Visible: attached, with a nonempty bounding box and visible style.
await expect(page.getByRole('button', { name: 'Submit' })).toBeVisible();

// Attached to the DOM, even if hidden with display: none.
await expect(page.locator('#modal')).toBeAttached();

// Hidden or absent, versus specifically absent from the DOM.
await expect(page.locator('.error')).toBeHidden();
await expect(page.locator('.error')).not.toBeAttached();

// Exactly five matching elements.
await expect(page.locator('ul > li')).toHaveCount(5);

Playwright's asynchronous assertions retry until they pass or reach the assertion timeout, which defaults to five seconds. A one-time if check does not provide that behavior.

Use snapshots for conditional logic

For example, close an optional dialog if it is currently present and visible:

const dialog = page.locator('.dialog').first();
if (await dialog.count() > 0 && await dialog.isVisible()) {
  await dialog.getByRole('button', { name: 'Close' }).click();
}

isVisible() returns immediately. This branch can miss a dialog that appears asynchronously afterward. Wait for an application-specific readiness signal first, or use a bounded wait if that matches the flow. For a required element, use an assertion instead of silently skipping the interaction.

Choose the right condition

Method What it checks Appropriate use
toBeAttached() The element is attached to the DOM Presence regardless of visibility
toBeVisible() A nonempty bounding box and visibility other than hidden Visibility, not viewport position or clickability; opacity: 0 can still count as visible
toHaveCount(n) The number of matches Lists and duplicate-element checks

Frequently asked questions

Should I use isVisible() or toBeVisible()?

Use the assertion to express a required test outcome. Use the immediate query for a deliberate branch based on current state. The assertion is usually the better default for verifying a page.

Why does my if miss an element that appears later?

count() can run before rendering finishes. Use locator.waitFor() for an explicit wait, or let a retrying assertion wait for the required condition. For optional elements, define when the application is ready before deciding that absence is meaningful.

How do I wait for an element to disappear?

Use toBeHidden() if hiding is sufficient, or not.toBeAttached() if it must leave the DOM. Both retry and are useful when waiting for a loading indicator to go away.

References

Related reading

Get a tailored plan

Contact us

Join the community

Scan with WeChat
to join the community

Try Guance

Start online and pay only for what you use.

Get started

Choose a Guance plan

Code hosting