Related to#1272
This PR adds support for soft assertions, allowing multiple assertion failures to be collected before raising them together. I implemented this using a context manager pattern since it feels more natural and Pythonic:
withexpect.soft()assoft_expect:awaitsoft_expect(page).to_have_title("wrong title")awaitsoft_expect(page.locator("#div1")).to_have_text("wrong")response=awaitpage.request.get("...")awaitsoft_expect(response).to_be_ok()
Example error report:
> with expect.soft() as soft_expect:E AssertionError: Soft assertion failuresE 1. Page title expected to be 'wrong title'E Actual value: Page TitleE Call log:E - PageAssertions.to_have_title with timeout 5000msE - - waiting for locator(":root")E - 9 × locator resolved to <html>…</html>E - - unexpected value "Page Title"EE 2. Locator expected to have text 'wrong'E Actual value: Text1E Call log:E - LocatorAssertions.to_have_text with timeout 5000msE - - waiting for locator("#div1")E - 9 × locator resolved to <div>Text1</div>E - - unexpected value "Text1"EE 3. Response status expected to be within [200..299] range, was '404'E Call log:E → GET http://localhost:2137/non-existentE - user-agent: (...)E - accept: */*E - accept-encoding: gzip,deflate,brE - ← 404 Not FoundE - content-type: text/plainE - transfer-encoding: chunked
Implementation Details
- The implementation maintains backward compatibility with all existing assertion methods
- Both sync and async APIs are fully supported with identical behavior
- Error messages preserve the order of failures and include clear numbering (1., 2., etc.)
- Custom error messages are properly handled and included in the final error report
- The implementation handles nested errors correctly (when other exceptions occur within the soft assertion block)
- Timeout settings are respected both at the global and individual assertion level
Initially, I usedcontextlib.contextmanager
forexpect.soft()
as it was a simpler implementation. However, this approach included some unrelevant information in the traceback when assertions failed. To address this, I created a customSoftAssertionContextManager
class that gives us more control over the error handling and traceback presentation.
This is just one way to add soft assertions in Python Playwright. I think the context manager pattern works well with Python, but I’m totally open to other ideas if they fit the project better.
Related to#1272
This PR adds support for soft assertions, allowing multiple assertion failures to be collected before raising them together. I implemented this using a context manager pattern since it feels more natural and Pythonic:
Example error report:
Implementation Details
Initially, I used
contextlib.contextmanager
forexpect.soft()
as it was a simpler implementation. However, this approach included some unrelevant information in the traceback when assertions failed. To address this, I created a customSoftAssertionContextManager
class that gives us more control over the error handling and traceback presentation.This is just one way to add soft assertions in Python Playwright. I think the context manager pattern works well with Python, but I’m totally open to other ideas if they fit the project better.