Assertions are one of the most important concepts in Playwright test automation. They verify whether the application behaves as expected after performing an action. Without assertions, your automation script simply performs actions without validating the results.
Playwright provides a powerful assertion library built on top of expect(), which automatically waits for conditions to become true before failing the test. This feature makes Playwright tests much more reliable compared to traditional automation frameworks.
In this article, you’ll learn everything about Playwright assertions, including different assertion types, best practices, and practical examples using TypeScript.
What are Assertions?
Assertions verify the expected state of your application.
For example, after clicking the Login button, you may want to verify:
- User is redirected to Dashboard
- Welcome message is displayed
- Logout button is visible
- Shopping cart contains 3 products
If the expected condition is not met, the test fails.
Example:
expect(await page.title()).toBe("Dashboard");
Why Playwright Assertions are Powerful
Unlike traditional assertions, Playwright assertions:
- Auto-wait until the condition becomes true
- Retry assertions automatically
- Produce detailed error messages
- Capture screenshots on failures
- Generate trace files
- Work with UI elements directly
Traditional Selenium example:
Thread.sleep(5000);
Assert.assertEquals(driver.getTitle(), "Dashboard");
Playwright:
await expect(page).toHaveTitle("Dashboard");
No manual waits required.
Importing Assertions
Playwright Test automatically provides expect.
import { test, expect } from '@playwright/test';
Assertion Categories
Playwright provides several assertion types.
- Value Assertions
- Locator Assertions
- Page Assertions
- API Assertions
- Screenshot Assertions
- Soft Assertions
- Polling Assertions
- Custom Assertions
Let’s explore each one.
1. Value Assertions
Used for JavaScript values.
Example:
test('Number Assertion', async () => {
const count = 10;
expect(count).toBe(10);
});
toBe()
Checks exact equality.
expect(5).toBe(5);
Example
const user = "Deepesh";
expect(user).toBe("Deepesh");
not.toBe()
expect(5).not.toBe(10);
toEqual()
Used for arrays and objects.
const user = {
name: "John",
age: 30
};
expect(user).toEqual({
name: "John",
age: 30
});
toContain()
expect(["Apple","Orange"]).toContain("Apple");
String example
expect("Playwright Automation").toContain("Automation");
toHaveLength()
expect([1,2,3]).toHaveLength(3);
String
expect("Playwright").toHaveLength(10);
toBeTruthy()
expect(true).toBeTruthy();
Example
const isLoggedIn = true;
expect(isLoggedIn).toBeTruthy();
toBeFalsy()
expect(false).toBeFalsy();
toBeNull()
expect(null).toBeNull();
toBeDefined()
const username = "Admin";
expect(username).toBeDefined();
toBeUndefined()
let city;
expect(city).toBeUndefined();
toBeGreaterThan()
expect(20).toBeGreaterThan(10);
toBeLessThan()
expect(5).toBeLessThan(10);
toBeCloseTo()
Useful for decimal values.
expect(0.1 + 0.2).toBeCloseTo(0.3);
2. Locator Assertions
Locator assertions are the most commonly used assertions in Playwright.
Example locator
const loginButton = page.locator("#login");
toBeVisible()
Checks whether an element is visible.
await expect(loginButton).toBeVisible();
toBeHidden()
await expect(page.locator(".loader")).toBeHidden();
toBeEnabled()
await expect(loginButton).toBeEnabled();
toBeDisabled()
await expect(page.locator("#submit")).toBeDisabled();
toBeChecked()
Checkbox example
await page.locator("#remember").check();
await expect(page.locator("#remember")).toBeChecked();
toHaveText()
await expect(page.locator("h1"))
.toHaveText("Dashboard");
toContainText()
await expect(page.locator(".message"))
.toContainText("Success");
toHaveValue()
Textbox example
await page.fill("#username","Admin");
await expect(page.locator("#username"))
.toHaveValue("Admin");
toHaveAttribute()
await expect(page.locator("#email"))
.toHaveAttribute("type","email");
toHaveClass()
await expect(page.locator(".active"))
.toHaveClass("active");
Multiple classes
await expect(page.locator(".btn"))
.toHaveClass(/btn primary/);
toHaveCount()
Useful for lists.
await expect(page.locator(".product"))
.toHaveCount(8);
toBeEditable()
await expect(page.locator("#username"))
.toBeEditable();
toHaveCSS()
await expect(page.locator("#title"))
.toHaveCSS("color","rgb(255, 0, 0)");
toHaveJSProperty()
await expect(page.locator("#checkbox"))
.toHaveJSProperty("checked", true);
toHaveId()
await expect(page.locator("#login"))
.toHaveId("login");
3. Page Assertions
toHaveTitle()
await expect(page)
.toHaveTitle("Dashboard");
toHaveURL()
await expect(page)
.toHaveURL("https://example.com/dashboard");
Using Regex
await expect(page)
.toHaveURL(/dashboard/);
4. Screenshot Assertions
Playwright can compare screenshots automatically.
await expect(page)
.toHaveScreenshot();
Specific filename
await expect(page)
.toHaveScreenshot("homepage.png");
Element screenshot
await expect(page.locator(".logo"))
.toHaveScreenshot();
This is useful for visual regression testing.
5. API Assertions
Example
const response = await page.request.get(
"https://reqres.in/api/users/2"
);
expect(response.status()).toBe(200);
expect(response.ok()).toBeTruthy();
Verify JSON
const body = await response.json();
expect(body.data.first_name)
.toBe("Janet");
6. Soft Assertions
Normally,
expect(value).toBe(expected);
stops execution when it fails.
Soft assertions allow the test to continue.
expect.soft(title).toBe("Dashboard");
expect.soft(username).toBe("Admin");
Example
test('Soft Assertions', async ({ page }) => {
await page.goto("https://example.com");
await expect.soft(page).toHaveTitle("Home");
await expect.soft(page.locator("h1"))
.toContainText("Example");
await expect.soft(page.locator("#login"))
.toBeVisible();
});
7. Polling Assertions
Sometimes values are updated after several seconds.
Playwright provides polling.
await expect.poll(async () => {
return await page.locator(".counter").textContent();
}).toBe("10");
Playwright retries until timeout.
8. Custom Message
Provide a helpful failure message.
expect(
totalPrice,
"Total price should be greater than zero"
).toBeGreaterThan(0);
9. Array Assertions
const fruits = [
"Apple",
"Orange",
"Mango"
];
expect(fruits).toContain("Orange");
expect(fruits).toHaveLength(3);
10. Object Assertions
const employee = {
id:1,
name:"John"
};
expect(employee).toEqual({
id:1,
name:"John"
});
Real Login Example
import { test, expect } from '@playwright/test';
test('Verify Login', async ({ page }) => {
await page.goto("https://example.com");
await page.fill("#username","Admin");
await page.fill("#password","admin123");
await page.click("#login");
await expect(page)
.toHaveURL(/dashboard/);
await expect(page.locator("h1"))
.toContainText("Dashboard");
await expect(page.locator("#logout"))
.toBeVisible();
});
Assertion Timeouts
By default, Playwright retries assertions until the configured timeout.
Example:
await expect(locator).toBeVisible({
timeout: 10000
});
This waits up to 10 seconds before failing.
Combining Assertions
await expect(page).toHaveTitle("Dashboard");
await expect(page).toHaveURL(/dashboard/);
await expect(page.locator("#welcome"))
.toContainText("Welcome");
await expect(page.locator("#logout"))
.toBeVisible();
await expect(page.locator(".product"))
.toHaveCount(6);
Best Practices
- Prefer Playwright locator assertions (
toBeVisible,toHaveText, etc.) over manual value checks because they automatically wait for the expected condition. - Avoid using
waitForTimeout()before assertions. Let Playwright’s built-in retry mechanism handle synchronization. - Use descriptive locators (
getByRole,getByLabel,getByTestId) instead of fragile CSS or XPath selectors whenever possible. - Use
expect.soft()when you want to collect multiple verification failures in a single test execution. - Keep assertions focused on one expected behavior to make failures easier to understand.
- Add meaningful custom messages for business-critical validations.
- Use regular expressions with
toHaveURL()andtoHaveText()when parts of the value are dynamic. - For visual testing, use screenshot assertions only for stable UI components to reduce flaky results.
- Set assertion-specific timeouts only when an element legitimately requires more time to appear.
Common Mistakes
Using Manual Waits
❌
await page.waitForTimeout(5000);
expect(await page.title()).toBe("Dashboard");
✅
await expect(page).toHaveTitle("Dashboard");
Using textContent() Instead of Locator Assertions
❌
const text = await page.locator("h1").textContent();
expect(text).toBe("Dashboard");
✅
await expect(page.locator("h1"))
.toHaveText("Dashboard");
Hard-Coding Dynamic URLs
❌
await expect(page).toHaveURL(
"https://example.com/dashboard?id=123"
);
✅
await expect(page).toHaveURL(/dashboard/);
Summary
Playwright assertions are a core part of building stable and maintainable automated tests. Their automatic waiting, intelligent retries, and rich set of locator-specific assertions eliminate much of the flakiness found in traditional UI automation frameworks.
By mastering value assertions, locator assertions, page assertions, API assertions, soft assertions, polling, and visual assertions, you can create robust end-to-end tests that are easier to read, debug, and maintain. Adopting Playwright’s built-in assertion methods instead of manual waits or custom validation logic will result in faster, more reliable, and more professional automation suites.