Debugging guides
StatePort vs Playwright and HAR: saving a bug setup for changed code
Read the guide ↓
A frontend bug report says the invitation form loses its input after the server rejects an email address. The developer has the HTTP response. They can even replay it. But opening the members page still shows an empty form, under a different role, with no invitation in progress.
The HAR contains the rejection. It does not contain the steps that filled the form. You still need to execute those steps on the code you are testing.
Playwright can supply those steps as a test. StatePort offers another workflow: capture the supported setup while it is available, then reopen it during the investigation.
Start with what Playwright already provides
Playwright can record HTTP traffic and serve responses from a HAR with routeFromHAR(). It also supports explicit request handlers, saved authentication and assertions. These are working alternatives to a separate debugging tool, not missing features that StatePort invented. 1, 2
If your existing test reliably reaches the failing form, keep it. Change the application, run the test, and inspect the result. Adding another capture step would not necessarily help.
The harder case arrives outside the test suite: a selected role, a half-filled form and a rejection that staging may stop returning before you finish the fix.
A HAR replay example, with its assumptions visible
The following test is an illustrative template for an invitation form. It assumes the app is running at http://127.0.0.1:3000, the HAR was captured with the same API URLs, and the test already has the required local authentication. Adapt the labels and paths to your application.
import { expect, test } from '@playwright/test';
test.use({ serviceWorkers: 'block' });
test('keeps the invitation after a rejected email', async ({ page }) => {
await page.routeFromHAR('./fixtures/rejected-invite.har', {
url: '**/api/**',
notFound: 'abort',
update: false,
});
await page.goto('http://127.0.0.1:3000/settings/members');
await page.getByLabel('Role').selectOption('viewer');
await page.getByLabel('Email').fill('already-invited@example.test');
await page.getByRole('button', { name: 'Invite', exact: true }).click();
await expect(page.getByRole('alert')).toContainText('Already invited');
await expect(page.getByLabel('Email')).toHaveValue(
'already-invited@example.test',
);
});
Run this check on the failing code first. It should reach the rejection and fail on the lost input. If it fails before submission, fix the fixture or setup before using it to judge a patch. On the candidate code, both assertions should pass.
Service workers are blocked in this example because requests they intercept bypass HAR routing. The URL filter only covers matching /api/ requests; other traffic is outside this rule. HAR matching uses the URL and method, plus the POST payload. A staging URL does not become a localhost URL when you load the HAR. update: true records fresh traffic, so leave it off when checking a preserved case. 1
A trace is for inspecting a run
A Playwright trace is useful when you need to inspect actions, DOM snapshots, console output and network activity from a recorded execution. Open it with the Trace Viewer instead of guessing from the final screenshot. 3
npx playwright show-trace ./test-results/invite/trace.zip
To check a patch, run the test again with the intended inputs and dependencies. The trace remains a record of its original execution.
Saved authentication can also restore application choices kept in cookies or local storage. It does not guarantee the complete setup: check the selected organisation, pending server workflow and transient UI inputs in the new context. Review authentication files before storing or sharing them; Playwright warns that they can enable account impersonation. 2
Which artifact answers which question?
| Artifact | Useful question | What still needs a fresh check |
|---|---|---|
| Screen recording | What did the person see and do? | Whether changed code behaves differently |
| Playwright trace | What happened during this test execution? | The next execution on the candidate build |
| Saved authentication | How can this test begin signed in? | Application data and the remaining setup |
| HAR plus a Playwright test | Can the code handle these responses along these steps? | Whether the fixture still represents the intended case |
| StatePort State Card | Can I reopen this captured setup on my local app? | Compatibility, the observed symptom and the fix criterion |
Reopen the rejected invitation on local code
In StatePort, reproduce the case in the managed browser, stop Capture, review the retained material and save a State Card. The supported capture can retain actions, checkpoints, browser/form state and responses needed by the case. It is not a JavaScript heap snapshot or a copy of the backend. 4
Start the application you are editing, open the Card and select Local app. Current pages and assets come from the local target while matching retained API responses come from the Card. Missing required responses remain visible failures instead of silently switching to a live backend. 5
Before changing the code, check that the Card reproduces the invitation failure. After the patch, use the same intended setup and inspect the role, rejection and email field. A failed or incomplete restoration is not a successful fix check.
If the fixture already reaches this state reliably, keep using it. The Card is an alternative to repeated preparation, not a required layer around a working test.
A changed request is a different experiment
Suppose the fix changes the invitation payload. Serving the previous response to that new payload can help investigate frontend behaviour, but it cannot establish that the real server accepts the request.
Keep these checks separate. With retained responses, test the form’s error handling. With an authorised test backend, check that the new request has the intended effect. StatePort exposes routing and replay prerequisites; it does not turn a saved response into proof of a backend fix. 5
A permission label is not an authorisation grant either. Another developer may need their own sign-in, and ordinary Card sharing does not transfer the original person’s browser profile or raw session credentials. 4, 5
Keep the regression test; choose how to prepare it
StatePort is not a replacement for a regression suite. Keep Playwright for durable tests, fixtures and assertions. Use a Card when a useful case exists now and you need to return to it while investigating, including when a colleague prepared the setup.
A coding agent needs the same baseline and criterion. Do not let its final message substitute for the email-field assertion.
Capture is free. Current-code reproduction requires Developer access; the trial lasts 14 days and starts after email verification. Check current platform availability and supported scope before selecting a case. 5, 6, 7
Explore Free Capture · Capture a first Card
Sources and scope
This article is written by StatePort, not as an independent benchmark. The examples are illustrative, not reported customer results. Playwright sources rechecked on 3 November 2026; the code above is an app-specific template, not a reported product acceptance run.