Playwright rollback tests verify that a failed or deliberately reversed operation leaves both the user interface and the underlying API state consistent. Build them around a controlled starting state, perform the change through the UI, trigger rollback, then assert the restored state through the UI and an independent API check.
What rollback tests should prove
A rollback test is not simply a test that clicks an Undo button. It checks a state transition: an initial state changes, a failure or reversal occurs, and the system returns to the expected state without leaving partial effects behind. For a task-management app, for example, a test might archive a task, cause a later step to fail, and verify that the task is visible and unarchived again.
UI and API checks answer different questions. A UI assertion confirms what a person can see and interact with. An API assertion checks the persisted or service-level representation, where the application exposes a suitable endpoint. Seeing a restored row in the page alone does not prove that the database or service state was restored; seeing a correct API response alone does not prove the screen refreshed correctly.
Use a test environment and test data that the test owns. Do not run destructive rollback scenarios against shared production data. Keep the expected behavior specific: some products intentionally retain an audit event or a failed-operation record even when the main entity is restored.
Choose a reliable test boundary
Playwright supports browser automation and can also make HTTP requests with its API testing facilities. A practical design uses the browser for the user-facing action and an API request for setup, inspection, or cleanup. The API check should be independent of the UI mechanism under test; otherwise, a UI bug can be repeated by the same abstraction in the assertion.
Decide what “rollback” means before writing assertions. It may mean restoring a previous field value, cancelling an optimistic update after a server rejection, undoing a transaction, or compensating for a completed action. These behaviors are not interchangeable. A distributed workflow may use a compensating action rather than a database transaction that rewinds every service at once.
- UI boundary: the control, confirmation, error message, and visible final state.
- API boundary: the resource fields, status, or related records that define persistence.
- Side-effect boundary: any related object or event that the product promises to restore, cancel, or retain.
Structure the test as a state transition
Start by creating a uniquely identifiable record through a supported setup path. Record its initial state, then perform the action using the browser. Trigger a predictable failure or rollback condition, wait for the application’s defined response, and assert the final state. Finally, remove test data in a cleanup path that runs even when an assertion fails.
- Arrange: create a fresh record with a unique name or identifier and confirm its initial API state.
- Act: use locators and browser interactions to make the change as a user would.
- Trigger: cause a controlled rejection or invoke the documented undo action. Avoid relying on timing accidents.
- Assert: check the visible result and poll the relevant API state until it reaches the expected final value.
- Clean up: delete or reset only the record owned by this test.
For example, a test can create a draft, open it in the UI, change its status, and simulate a server rejection using a controlled test route or test service. It can then verify that the status shown in the page is back to “Draft” and that a GET request for that draft reports the same status. The exact route and response depend on the application; avoid hard-coding an assumed endpoint that the product does not provide.
Synchronize without hiding failures
Rollback often involves asynchronous work: a request fails, the application updates local state, and the interface rerenders. Fixed sleeps such as a long timeout are fragile. Prefer Playwright’s auto-waiting locators and assertions, and wait for an observable condition that represents completion, such as an error message disappearing or a status label returning to its expected value.
For API state that can take time to settle, use a bounded polling assertion rather than a single immediate request. The polling condition should be precise and the timeout finite. A timeout should fail with useful context, not silently accept an unexpected state. Do not wait only for the network to become idle: applications with background requests may never reach that condition, and network idleness does not necessarily mean the rollback has completed.
When intercepting requests to simulate failure, match the intended method and URL narrowly. A broad route that blocks every request can prevent the rollback request or page initialization from running, producing a misleading test. Decide whether the scenario is testing a failed initial write, a failed follow-up step, or an explicit undo; those require different failure points.
Keep API assertions meaningful
Inspect the smallest set of fields that defines correctness. If the contract is that an item’s status returns to its prior value, assert that field and any essential relationship, rather than comparing an entire response that may contain timestamps or generated metadata. If rollback should remove a newly created object, verify the documented absence or deleted state; do not assume every system physically deletes records.
Use the correct identity and authorization context. A test API request made with a different user or tenant can report a different view of state than the UI session. Where the application scopes records by account, keep both checks in the same intended account context and assert the resource identifier so a test cannot accidentally inspect another record.
API access is not a shortcut for testing the UI. If setup and verification happen only through API calls, the test does not establish that the browser interaction or rendering works. Conversely, avoid using UI setup for every record when it adds unrelated flakiness; API setup is often appropriate when the tested behavior begins after the record exists.
Common failures and design choices
- Checking too early: an immediate API read may observe the in-progress state. Poll for the expected final state with a bounded timeout.
- Shared test data: parallel tests can modify the same record. Use unique records or isolated tenants and avoid global cleanup.
- Testing implementation details: asserting internal framework state makes tests brittle. Prefer user-visible behavior and documented API contracts.
- Assuming all effects vanish: audit logs, notifications, or external messages may be intentionally retained. Assert the product’s actual contract.
- Overly broad failure simulation: blocking unrelated requests can prevent the rollback path from being exercised at all.
Choose between a real test backend and request interception based on the claim the test needs to make. Interception gives repeatable control over a response and is useful for UI behavior under a simulated failure. A real backend exercises actual persistence and rollback handling, but requires reliable test data and environment isolation. A layered suite can use fast intercepted UI tests for edge cases and a smaller number of integration tests against the real service.
Frequently Asked Questions
Can Playwright test API state as well as the UI?
Yes. Playwright can automate a browser and send API requests. Use the browser for the user interaction and a suitable API request to inspect or prepare state, while keeping each assertion tied to the behavior being tested.
Should rollback tests use API setup or UI setup?
Use API setup when creating data is not the behavior under test and the endpoint is part of a reliable test interface. Use UI setup when the creation flow itself matters. Either way, exercise the rollback action through the UI if that is the user-facing behavior being validated.
How do I test an optimistic UI update that gets rejected?
Make the UI action, have a narrowly matched test route return the expected failure, and assert both the displayed rollback and the final server state where a real server check is available. Keep the simulated rejection and any real persistence check clearly distinct.
Is checking the UI enough to prove rollback worked?
No. The screen may show stale or locally restored data while persisted state remains changed. Pair the UI assertion with an API or other authoritative state check when the system exposes one.
How can rollback tests remain stable in parallel runs?
Give each test its own uniquely identified records and limit cleanup to those records. Avoid shared mutable fixtures, broad deletes, and fixed waits; use bounded assertions for the state transition instead.
Related
Method: the standard formula for this calculation, rounded as each result states. See how the calculators work or report an error.
More cards in this drawer
- Wireless Controller Charging: Can You Play While Plugged In?
- Secure a Node.js API: Layered Checklist
- Zoom Desktop Client: Features, Setup, and Fixes
- Python Integer Identity: Why It Varies by Run
- Can Technology Solve Poverty? Facts & Limits
- Cannot Detect Device? Fixes for USB & Bluetooth