When writing automated tests, assertions are what verify that your application behaves as expected. In most testing frameworks, including Playwright, assertions are hard by default – meaning the test stops immediately when an assertion fails.

However there are situations where stopping at the first failure is not ideal. That’s where soft assertions come in.
In this article, we’ll explore what soft assertions are, how they work in Playwright, and when they are useful in real-world testing scenarios.
What Is a Soft Assertion?
A soft assertion is an assertion that records a failure but allows the test to continue executing. Instead of immediately stopping the test, Playwright collects the failure and reports it at the end of the test run.
This allows a single test to surface multiple failures at once, which can be very helpful when validating pages with many elements.
Playwright provides soft assertions by using the expect.soft() construct.
Hard Assertions vs Soft Assertions
By default, Playwright assertions are hard assertions.
Hard Assertion (Default)
await expect(page.locator('#title')).toHaveText('Dashboard');
await expect(page.locator('#username')).toHaveText('Alice');
If the first assertion fails, the test stops immediately and the second assertion will never run.
Soft Assertion
await expect.soft(page.locator('#title')).toHaveText('Dashboard');
await expect.soft(page.locator('#username')).toHaveText('Alice');
In this scenario, if the first assertion fails then Playwright records the error but continues running the test. At the end, all soft assertion failures are reported together.
Why Soft Assertions Are Useful
Soft assertions are useful when you want to validate multiple independent aspects of a page without stopping after the first failure.
Take for example the situation where a test has numerous assertions to verify multiple elements within a web page, and then the web page design or behaviour changes significantly. What can happen when using hard asserts is that the first error surfaces, and someone fixes it, only to find there is another error. That second error is fixed, only for a third one to become visible – all because using hard asserts prevents further assertions from being tested.
So instead of fixing issues one by one across multiple test runs, with soft asserts you can see everything that’s broken at once.
Real-World Example: Verifying Account Details
Imagine a test that validates that after retrieving a user’s account details, that they are all displayed correctly on a web page.
const user = db.getUser('joe1234@test.com');
await expect.soft(page.locator('#first-name')).toHaveText(user.firstName);
await expect.soft(page.locator('#last-name')).toHaveText(user.surname);
await expect.soft(page.locator('#email-address')).toHaveText(user.email);
await expect.soft(page.locator('#telephone')).toHaveText(user.telephone);
If all four elements are wrong, a hard assertion would reveal only the first issue. Soft assertions allow the test report to show all four failures in a single run, making debugging faster.
Real-World Example: Validating Multiple Error Messages
Soft assertions are also useful when multiple errors are displayed after the user submits the form.
await expect.soft(page.locator('#email-error')).toHaveText('Invalid email');
await expect.soft(page.locator('#password-error')).toHaveText('Password too short');
await expect.soft(page.locator('#terms-error')).toHaveText('You must accept terms');
This approach ensures every validation message is checked even if some fail.
Stopping the Test After Soft Assertions
Sometimes you may want to allow soft assertions to run, but still fail the test if any errors occurred.
Playwright provides access to collected errors through the test context:
test('profile page', async ({ page }) => {
await expect.soft(page.locator('#name')).toHaveText('Mary');
await expect.soft(page.locator('#role')).toHaveText('Admin');
expect(test.info().errors).toHaveLength(0); // fail NOW
// more testing ...
});
This pattern allows you to gather failures first and then stop the test if necessary.
When You Should Use Soft Assertions
Soft assertions work best when validating independent UI elements. Good use cases include:
- Checking multiple labels or UI texts on a page
- Verifying layout elements such as headers, menus, and footers
- Validating form error messages
- Performing large UI verification checks
These scenarios benefit from seeing all failures at once rather than fixing them incrementally.
When Not To Use Soft Assertions
Soft assertions should not be used for critical steps in a test flow.
For example:
- Login success
- Navigation steps
- Actions required for later steps to work
- Critical state checks
Using a soft assertion for these steps could cause the test to continue in a broken state, producing confusing failures later in the test.
In these cases, a hard assertion is the correct choice.
Best Practices
To use soft assertions effectively in Playwright:
- Use them for independent UI validations
- Avoid them in critical workflow steps
- Combine them with a final error check if the test should ultimately fail
- Use them to improve debugging efficiency and test feedback
Conclusion
Soft assertions in Playwright provide a powerful way to validate multiple aspects of a page without stopping at the first failure. They are particularly useful for UI-heavy tests where many elements need to be verified.
By using expect.soft() strategically, you can produce more informative test reports, reduce debugging cycles, and improve the overall efficiency of your test suite.
When used correctly, soft assertions help strike the right balance between test strictness and useful feedback.
