Playwright Masters

Playwright Assertions: Complete Guide to expect(), Matchers, Auto-Waiting & Examples

Playwright Assertions are checks that verify whether your application behaved as expected during an automated test.

For example, suppose a user clicks the Login button. Your test should not only click the button. It should also check whether the login was successful.

await page.getByRole(‘button’, { name: ‘Login’ }).click();

await expect(page.getByRole(‘heading’, { name: ‘Dashboard’ })).toBeVisible();

Table of Contents

The first line performs an action.

The second line verifies the result.

That second step is an assertion.

In Playwright, assertions are mainly created with the expect() function. Playwright’s web-first assertions can automatically wait and retry until the expected condition becomes true or the assertion timeout is reached. The default assertion timeout is currently 5 seconds.

This makes Playwright Assertions especially useful for modern applications where content may appear or change after an API call, animation, navigation, or other asynchronous operation.

In simple words:

Action tells Playwright what to do. Assertion tells Playwright what must be true afterward.

Playwright Assertions

What Are Playwright Assertions?

Playwright Assertions are built-in validation methods used to check the actual state of a web application against an expected result.

The most common syntax is:

await expect(locator).toBeVisible();

 

Here:

  • expect() starts the assertion.
  • locator identifies the element.
  • toBeVisible() is the matcher.
  • await waits for the asynchronous assertion.

Playwright provides different assertion families for:

  • Web elements
  • Pages
  • URLs
  • Titles
  • API responses
  • Values
  • Text
  • Attributes
  • Screenshots
  • Generic JavaScript values

Playwright also supports advanced capabilities such as soft assertions, negative matchers, polling, retrying blocks of code, custom assertion messages and custom matchers.

Why Are Assertions Important in Playwright?

Imagine your automation test does this:

Open website

Enter username

Enter password

Click Login

Test finished

 

Did the user actually log in?

You don’t know.

Now add an assertion:

Open website

Enter username

Enter password

Click Login

Verify Dashboard is visible

Test passed

 

Now the test has proved something useful.

Assertions help your automation answer questions such as:

  • Did the correct page open?
  • Is the Login button visible?
  • Is the button enabled?
  • Was the correct message displayed?
  • Did the URL change?
  • Did the API return a successful response?
  • Is the checkbox selected?
  • Does the input contain the expected value?
  • Did the product get added to the cart?
  • Did the error message appear?
  • Did an unwanted element disappear?

Without meaningful assertions, a test can perform many actions but still fail to prove that the application worked correctly.

How Does expect() Work in Playwright?

The basic structure is:

expect(actual).matcher(expected);

 

For asynchronous web assertions, you normally use:

await expect(actual).matcher(expected);

 

For example:

await expect(page).toHaveTitle(/Playwright/);

 

Or:

await expect(page.getByRole(‘button’, { name: ‘Login’ })).toBeVisible();

 

Playwright’s test runner provides the expect function:

import { test, expect } from ‘@playwright/test’;

 

The official Playwright documentation recommends using Playwright’s own expect rather than treating it as a separate generic assertion library because Playwright integrates its web-specific assertions with its test runner.

How Playwright Auto-Retrying Assertions Work

This is one of the most important things to understand about Playwright Assertions.

Suppose a success message does not appear immediately after clicking Submit.

A weak test might check the element only once.

A Playwright web-first assertion can keep checking the condition until it passes or the assertion timeout is reached.

Example:

await page.getByRole(‘button’, { name: ‘Submit’ }).click();

 

await expect(page.getByText(‘Order submitted successfully’))

  .toBeVisible();

 

If the message takes a short time to appear, Playwright does not immediately give up.

It retries the assertion.

Conceptually:

Check

Not ready

Wait

Check again

Not ready

Wait

Check again

Condition satisfied

PASS

 

If the expected condition never becomes true before the assertion timeout, the test fails.

Playwright’s documentation describes these as web-first assertions, designed for conditions that may become true after some asynchronous application activity.

Playwright Assertions vs Manual Checks

This is a very important difference.

Less reliable approach

const visible = await page.getByText(‘Welcome’).isVisible();

 

expect(visible).toBe(true);

 

The visibility check happens first.

Then the result is passed to expect().

The assertion itself cannot retry the locator until it becomes visible.

Better Playwright approach

await expect(page.getByText(‘Welcome’)).toBeVisible();

 

Now Playwright owns the waiting and assertion process.

The official Playwright best-practices documentation specifically recommends web-first assertions instead of immediately resolving methods such as isVisible() and then asserting on the returned boolean.

Easy rule to remember

Don’t ask the page for a value too early if Playwright already has an assertion that can wait for it.

Main Types of Playwright Assertions

Playwright Assertions can be grouped into several useful categories.

1. Locator Assertions

Locator assertions validate elements on the page.

Example:

await expect(page.getByRole(‘button’, { name: ‘Login’ }))

  .toBeVisible();

 

Common locator assertions include:

Assertion

What it checks

toBeVisible()

Element is visible

toBeHidden()

Element is hidden

toBeAttached()

Element is attached to the document

toBeEnabled()

Element is enabled

toBeDisabled()

Element is disabled

toBeEditable()

Element can be edited

toBeChecked()

Checkbox/radio is checked

toBeFocused()

Element has focus

toBeEmpty()

Container is empty

toBeInViewport()

Element intersects the viewport

toHaveText()

Element has expected text

toContainText()

Element contains expected text

toHaveValue()

Input has expected value

toHaveValues()

Select has expected values

toHaveAttribute()

Element has an attribute

toHaveClass()

Element has expected class

toHaveCount()

Locator matches expected number

toHaveCSS()

Element has expected CSS

toHaveId()

Element has expected ID

toHaveJSProperty()

Element has expected JavaScript property

toHaveScreenshot()

Element matches screenshot expectation

The current Playwright API includes newer locator assertions such as toBeAttached(), while the broader locator assertion API supports checks for state, content, attributes, count, CSS and screenshots.

2. toBeVisible()

Use toBeVisible() when you want to verify that an element is visible to the user.

await expect(page.getByRole(‘heading’, {

  name: ‘Dashboard’

})).toBeVisible();

This is useful after:

  • Login
  • Navigation
  • Form submission
  • Opening a menu
  • Opening a modal
  • Searching for a product
  • Completing checkout

Example

await page.getByRole(‘button’, { name: ‘Login’ }).click();

await expect(

  page.getByRole(‘heading’, { name: ‘Dashboard’ })

).toBeVisible();

3. toBeHidden()

Use toBeHidden() when something should disappear.

For example, after submitting a form, a loading spinner may disappear.

await expect(page.getByTestId(‘loading-spinner’))

  .toBeHidden();

 

This is much better than blindly waiting:

await page.waitForTimeout(3000);

 

The test should wait for the condition, not an arbitrary number of seconds.

4. toHaveText() vs toContainText()

  • These two assertions are commonly confused.

    toHaveText()

    Use it when you want to verify the expected text.

    await expect(page.getByTestId(‘status’))

      .toHaveText(‘Order confirmed’);

     

    toContainText()

    Use it when the element contains the expected text but may also contain other text.

    await expect(page.getByTestId(‘message’))

      .toContainText(‘confirmed’);

     

    Think of it like this:

    toHaveText()

    = Match the expected text

     

    toContainText()

    = Expected text appears somewhere inside

5. toHaveValue()

Use toHaveValue() to check the current value of an input.

await page.getByLabel(‘Email’).fill(‘user@example.com’);

 

await expect(page.getByLabel(‘Email’))

  .toHaveValue(‘user@example.com’);

 

This is useful for forms, search boxes and profile pages.

6. toBeChecked()

Use this for checkboxes and radio buttons.

await page.getByLabel(‘Accept Terms’).check();

 

await expect(page.getByLabel(‘Accept Terms’))

  .toBeChecked();

 

You can also check the opposite state:

await expect(page.getByLabel(‘Accept Terms’))

  .not.toBeChecked();

7. toBeEnabled() and toBeDisabled()

These assertions verify whether a control can be interacted with.

await expect(

  page.getByRole(‘button’, { name: ‘Submit’ })

).toBeEnabled();

 

Or:

await expect(

  page.getByRole(‘button’, { name: ‘Submit’ })

).toBeDisabled();

 

This is particularly useful for forms where a Submit button becomes enabled only after required fields are completed.

8. Page Assertions

Playwright can also assert properties of the entire page.

Check title

await expect(page).toHaveTitle(‘Playwright’);

Or use a regular expression:

await expect(page).toHaveTitle(/Playwright/);

Check URL

await expect(page).toHaveURL(/dashboard/);

For example:

await page.getByRole(‘link’, { name: ‘Dashboard’ }).click();

await expect(page).toHaveURL(/dashboard/);

Page assertions include URL, title and screenshot-related checks.

9. API Response Assertions

Playwright is not limited to browser UI testing.

You can also assert API responses.

Example:

const response = await page.request.get(

  ‘https://api.example.com/users’

);

 

await expect(response).toBeOK();

 

toBeOK() verifies that the HTTP response status is in the successful 200–299 range.

This makes assertions useful in API testing as well as UI testing.

For example:

const response = await request.post(‘/api/login’, {

  data: {

    username: ‘testuser’,

    password: ‘password123’

  }

});

 

await expect(response).toBeOK();

 

You can then validate the response body separately.

10. Generic Assertions

Not every assertion is about a web page.

You can also validate normal JavaScript values.

const total = 100;

 

expect(total).toBe(100);

 

Other examples include:

expect(value).toBeTruthy();

 

expect(value).toBeFalsy();

 

expect(value).toBeDefined();

 

expect(value).toBeGreaterThan(10);

 

expect(value).toBeLessThan(100);

 

expect(value).toEqual(expectedObject);

 

expect(value).toContain(‘Playwright’);

 

Unlike web-first locator assertions, these generic assertions normally operate on values that have already been resolved and do not automatically wait for a web condition.

11. Negative Assertions Using .not

Sometimes you don’t want to prove that something exists.

You want to prove that it does not exist.

Use .not.

Example:

await expect(

  page.getByText(‘Invalid username’)

).not.toBeVisible();

 

Another example:

expect(status).not.toBe(‘Failed’);

 

Negative assertions are useful for validating:

  • Error messages are absent
  • Deleted items are no longer displayed
  • Loading indicators disappear
  • Buttons are not disabled
  • Unwanted content is not present

The basic pattern is:

expect(value).not.matcher();

 

Playwright supports .not across its assertion APIs.

12. Soft Assertions in Playwright

Normally, when an assertion fails, the test stops at that point.

Example:

await expect(page.getByTestId(‘name’))

  .toHaveText(‘Rakesh’);

await expect(page.getByTestId(’email’))

  .toHaveText(‘user@example.com’);

If the first assertion fails, the second assertion is not reached.

Sometimes you want to continue checking the page.

That’s where soft assertions are useful.

await expect.soft(page.getByTestId(‘name’))

  .toHaveText(‘Rakesh’);

await expect.soft(page.getByTestId(’email’))

  .toHaveText(‘user@example.com’);

await expect.soft(page.getByTestId(‘phone’))

  .toHaveText(‘9999999999’);

The test records failures but continues executing.

This is useful when validating multiple fields on a page and you want to see several failures from one test run.

Playwright also allows you to check whether soft assertion failures were recorded through test.info().errors.

When should you use soft assertions?

Use them when:

  • Checking several independent UI fields
  • Validating a dashboard
  • Checking multiple labels
  • Performing a page-content audit

Do not use soft assertions everywhere.

If a failure makes the next step unsafe, a normal assertion is usually better.

13. Custom Assertion Messages

A useful feature for large test suites is a custom assertion message.

Example:

await expect(

  page.getByText(‘Welcome’),

  ‘User should be logged in’

).toBeVisible();

 

If this assertion fails, the custom message gives additional context in the test output.

This becomes valuable when a framework contains hundreds or thousands of assertions because the failure message can explain the business expectation instead of forcing someone to interpret the code.

Playwright supports custom messages as an argument to expect().

14. expect.poll() for Dynamic Values

Sometimes the value you need to verify is not directly represented by a locator.

For example, an API might eventually return a successful status.

You can use expect.poll() to repeatedly evaluate a function until the result satisfies the assertion.

Example:

await expect.poll(async () => {

  const response = await page.request.get(‘/api/status’);

  return response.status();

}).toBe(200);

 

This is useful for:

  • Asynchronous API operations
  • Background processing
  • Eventually consistent systems
  • Status changes
  • Dynamic backend values

Playwright documents expect.poll() as a way to turn a synchronous-style expectation into an asynchronous polling assertion.

15. expect.toPass() for Retrying a Block

Sometimes one assertion is not enough.

You may need to retry a group of operations.

For example:

await expect(async () => {

  const response = await page.request.get(‘/api/order’);

 

  expect(response.status()).toBe(200);

}).toPass();

 

The block can be retried until it passes or its configured timeout is reached.

This can be useful when the entire operation is eventually consistent rather than a single locator state.

Playwright provides expect.toPass() for this kind of retryable block.

16. Playwright Assertion Timeout

Playwright Assertions have their own timeout.

The default assertion timeout is 5 seconds.

For example:

await expect(page.getByText(‘Success’))

  .toBeVisible({

    timeout: 10000

  });

This tells Playwright to retry the assertion for up to 10 seconds.

You can also configure assertion behavior globally in your Playwright configuration.

Example:

import { defineConfig } from ‘@playwright/test’;

export default defineConfig({

  expect: {

    timeout: 10000

  }

});

Important

Do not increase the timeout simply because a test is failing.

First ask:

  • Is the locator correct?
  • Is the application actually slow?
  • Is the expected state correct?
  • Is there a real application bug?
  • Is the test data valid?

A huge timeout can hide a genuine problem.

17. Assertions and Auto-Waiting Are Not the Same Thing

Beginners often mix these concepts.

Auto-waiting for actions

Playwright automatically performs actionability checks before actions such as clicking or filling.

Example:

await page.getByRole(‘button’, { name: ‘Submit’ }).click();

 

Assertion waiting

An assertion can wait for the expected result:

await expect(page.getByText(‘Submitted’))

  .toBeVisible();

 

So a typical Playwright test can look like:

Locate

Action

Application changes

Assertion waits for expected state

Pass or fail

 

This is one reason Playwright tests can be less dependent on arbitrary fixed waits.

18. A Real-World Login Assertion Example

Here is a complete example:

import { test, expect } from ‘@playwright/test’;

 

test(‘successful login’, async ({ page }) => {

 

  await page.goto(‘https://example.com/login’);

 

  await page.getByLabel(‘Username’).fill(‘testuser’);

 

  await page.getByLabel(‘Password’).fill(‘password123’);

 

  await page.getByRole(‘button’, { name: ‘Login’ }).click();

 

  await expect(page).toHaveURL(/dashboard/);

 

  await expect(

    page.getByRole(‘heading’, { name: ‘Dashboard’ })

  ).toBeVisible();

});

 

Notice that the test does not merely click Login.

It proves two important outcomes:

  1. The URL changed to the dashboard.
  2. The Dashboard heading became visible.

That gives the test meaningful business validation.

19. Common Playwright Assertion Mistakes

Mistake 1: Using waitForTimeout()

 

Avoid:

await page.waitForTimeout(3000);

 

await expect(page.getByText(‘Success’)).toBeVisible();

 

Prefer:

await expect(page.getByText(‘Success’)).toBeVisible();

 

Wait for the condition rather than guessing how long the application needs.

Mistake 2: Checking isVisible() before expect()

 

Avoid:

expect(

  await page.getByText(‘Success’).isVisible()

).toBe(true);

 

Prefer:

await expect(

  page.getByText(‘Success’)

).toBeVisible();

 

The second version uses Playwright’s web-first assertion behavior.

Mistake 3: Using the wrong locator

 

An assertion cannot fix a bad locator.

For example:

await expect(page.locator(‘.button’)).toBeVisible();

 

If .button matches the wrong element, the assertion may fail even though the application is working.

Use strong, user-facing locators where appropriate:

page.getByRole(‘button’, { name: ‘Submit’ })

 

For a deeper explanation, see the Playwright Locators guide on Playwright Masters.

Mistake 4: Making every assertion too broad

 

Avoid assertions that validate large amounts of unstable text when a smaller, meaningful check is enough.

Instead of:

await expect(page.locator(‘body’))

  .toContainText(‘Everything on the page…’);

 

Prefer:

await expect(

  page.getByRole(‘heading’, { name: ‘Order Confirmed’ })

).toBeVisible();

 

Good assertions are specific and connected to the business requirement.

20. Best Practices for Playwright Assertions

Follow these rules when building professional Playwright tests.

1. Assert important outcomes

Don’t add assertions just to increase the number of checks.

Test meaningful behavior.

2. Prefer web-first assertions

Use:

await expect(locator).toBeVisible();

 

instead of manually resolving a value first.

3. Use strong locators

Combine good locators with good assertions.

4. Avoid fixed waits

Don’t use waitForTimeout() as your normal synchronization strategy.

5. Use the correct matcher

For example:

toBeVisible()

toHaveText()

toContainText()

toHaveValue()

toBeChecked()

toHaveURL()

toHaveTitle()

 

6. Use .not for negative conditions

await expect(locator).not.toBeVisible();

 

7. Use soft assertions selectively

Soft assertions are useful when multiple independent checks should be collected.

8. Use custom messages for important checks

This improves failure readability.

9. Use expect.poll() for eventually changing values

It is useful when you need to repeatedly evaluate a function.

10. Keep assertions close to the action they validate

Good:

await page.getByRole(‘button’, { name: ‘Save’ }).click();

 

await expect(page.getByText(‘Saved successfully’))

  .toBeVisible();

 

This is easier to understand than hiding the assertion far away from the action.

Playwright Assertions in a Professional Framework

Assertions become even more powerful when they are used correctly inside a structured automation framework.

A professional Playwright framework may contain:

tests/

pages/

fixtures/

utils/

api/

test-data/

config/

reports/

 

Tests describe the business scenario.

Page Objects organize page interactions.

Fixtures handle reusable setup.

API helpers handle backend operations.

Assertions verify the expected result.

For larger projects, Page Object Model can help separate page behavior from test scenarios.

Read the Playwright Framework guide to understand how assertions fit into a complete automation framework.

You can also follow the Playwright Roadmap to learn assertions as part of the progression from beginner concepts to framework development.

Playwright Assertions for API Testing

Assertions are not limited to UI.

A modern automation framework can validate both frontend and backend behavior.

For example:

const response = await request.get(‘/api/products’);

 

await expect(response).toBeOK();

 

Then you can validate returned data:

const data = await response.json();

 

expect(data.products.length).toBeGreaterThan(0);

 

This gives you two different validation layers:

API response

API assertion

 

Browser interaction

UI assertion

Playwright Assertions and Page Object Model

Assertions can be used directly inside tests or, depending on your framework design, inside reusable page-level verification methods.

For example:

async verifyDashboard() {

  await expect(

    this.page.getByRole(‘heading’, { name: ‘Dashboard’ })

  ).toBeVisible();

}

 

Then:

await dashboardPage.verifyDashboard();

 

However, don’t put every assertion inside Page Objects automatically.

A good framework should clearly separate:

  • User actions
  • Page behavior
  • Business scenarios
  • Test expectations

The right design depends on the size and needs of the project.

Playwright Assertions Cheat Sheet

Requirement

Recommended assertion

Check element is visible

toBeVisible()

Check element is hidden

toBeHidden()

Check element exists in DOM

toBeAttached()

Check button is enabled

toBeEnabled()

Check button is disabled

toBeDisabled()

Check checkbox

toBeChecked()

Check input value

toHaveValue()

Check exact text

toHaveText()

Check partial text

toContainText()

Check attribute

toHaveAttribute()

Check element count

toHaveCount()

Check CSS

toHaveCSS()

Check title

toHaveTitle()

Check URL

toHaveURL()

Check API success

toBeOK()

Check opposite condition

.not

Continue after assertion failure

expect.soft()

Poll a changing value

expect.poll()

Retry a block

expect.toPass()

Add failure explanation

Custom expect() message

The exact available matchers can evolve as Playwright releases new functionality, so for production projects always verify the current official API documentation.

Final Takeaway

Playwright Assertions are what turn browser automation into real testing.

Clicking a button only tells Playwright to perform an action.

An assertion tells Playwright to prove that the expected result happened.

The most important pattern to remember is:

await expect(locator).toBeVisible();

 

From there, learn the right matcher for each situation:

Visibility       → toBeVisible()

Text             → toHaveText()

Partial text     → toContainText()

Input value      → toHaveValue()

Checkbox         → toBeChecked()

Enabled state    → toBeEnabled()

Disabled state   → toBeDisabled()

URL              → toHaveURL()

Title            → toHaveTitle()

API success      → toBeOK()

Opposite result  → .not

Multiple checks  → expect.soft()

Dynamic value    → expect.poll()

Retry a block    → expect.toPass()

 

The biggest lesson is simple:

Don’t make your test guess when something will happen. Make your test describe the condition that must eventually be true.

That is the real strength of Playwright’s web-first assertion model.

If you combine strong locators + actions + auto-waiting + assertions + fixtures + Page Object Model + API testing, you can build Playwright automation that is easier to read, debug and maintain.

Frequently Asked Questions About Playwright Assertions

What are Playwright Assertions?

Playwright Assertions are validation checks used to verify that an application’s actual behavior matches the expected behavior. They are commonly written using the expect() function.

What is expect() in Playwright?

expect() is Playwright Test’s assertion function. It is used with matchers such as toBeVisible(), toHaveText(), toHaveURL() and toHaveTitle().

What is the most commonly used Playwright assertion?

Some of the most commonly used assertions include:

toBeVisible()

toHaveText()

toContainText()

toHaveValue()

toBeChecked()

toHaveURL()

toHaveTitle()

 

The best matcher depends on what you need to verify.

Do Playwright assertions automatically wait?

Many Playwright web-first assertions automatically retry until the expected condition is met or the assertion timeout is reached. The default assertion timeout is 5 seconds.

What is the difference between toHaveText() and toContainText()?

toHaveText() verifies the expected text, while toContainText() verifies that the expected text appears within the element’s text.

What is a soft assertion in Playwright?

A soft assertion records a failure but allows the test to continue running. It is created with:

await expect.soft(locator).toBeVisible();

 

How do you assert a URL in Playwright?

Use:

await expect(page).toHaveURL(/dashboard/);

 

How do you assert a page title?

Use:

await expect(page).toHaveTitle(/Playwright/);

 

How do you assert an API response in Playwright?

Use:

await expect(response).toBeOK();

 

This verifies that the HTTP response status is in the successful 200–299 range.

Should I use waitForTimeout() before an assertion?

Usually, no.

Prefer a condition-based Playwright assertion:

await expect(locator).toBeVisible();

 

instead of:

await page.waitForTimeout(3000);

await expect(locator).toBeVisible();

 

What is expect.poll() used for?

expect.poll() is useful when a function needs to be repeatedly evaluated until its returned value satisfies an assertion. It is especially useful for dynamic or eventually consistent values.

What is expect.toPass()?

expect.toPass() allows a block of code containing assertions to be retried until it succeeds or its configured timeout is reached.

Are Playwright Assertions only for UI testing?

No.

Playwright supports assertions for locators, pages, generic values and API responses. It also supports screenshot assertions and advanced assertion patterns.

Playwright Masters automation testing logo - White Back ground

Playwright Masters Team

Playwright Automation Testing Experts | Industry-Focused Training & Practical Learning

Playwright Masters is a dedicated automation testing training platform focused on helping learners build practical skills in Playwright automation testing. Our training covers real-world automation concepts, framework practices, coding, debugging, API testing, cross-browser testing, CI/CD, and interview preparation to help learners develop job-ready testing skills.

Scroll to Top