Dev.to WebDev 🛠 Dev 👁 0 📖 5 min read

Two Playwright tests, one account. Keep their data separate.

Originally published on anton.qa. One test expects Email alerts On. After reloading, it sees Off. In this Playwright demo, one test checks the Email alerts setting. Another test changes it. Run either test alone, and i

Originally published on anton.qa.

One test expects Email alerts On. After reloading, it sees Off.

In this Playwright demo, one test checks the Email alerts setting. Another test changes it. Run either test alone, and it passes. Run them together against one account, and the reader fails.

Both tests still have their own browser storage. The writer saved Off to the account they share.

These are real test results from a local app with made-up accounts. The demo deliberately places the save before the reader's reload. It shows how interference happens, without measuring how often it happens naturally.

Follow the setting

Both tests begin with Email alerts set to On. The reader loads the setting, then waits while the writer changes it.

The writer selects Off, clicks Save, and reloads. It sees Off, so its check passes. The reader then reloads the same account and receives that saved value.

The shared run reports this mismatch:

Expected: "On"
Received: "Off"

That excerpt comes from the reader's value assertion in the checked shared run. The writer passed. The reader failed because its account no longer had the expected setting.

Give the writer and reader different accounts, and both tests pass. The writer reloads Off. The reader reloads On. The test steps and save order stay the same.

Try the four runs

Get the public example and open its posts/parallel-playwright-account-data directory in a terminal. The verified setup used Node 26.13.0, npm 11.20.0, and Playwright 1.64.1.

Install the dependencies and Chromium browser, then check the demo runner:

npm ci
npx playwright install chromium
npm run test:guards

These checks verify how the runner recognizes results and cleans up afterward. All 45 passed in the verified run.

On Linux, use this browser-install command instead:

npx playwright install --with-deps chromium

Installation needs network access and may need permission to install system libraries. The demonstration itself stays on your machine and uses made-up accounts. It sends no emails.

Run each command separately, checking its result before starting the next:

npm run demo -- writer-alone
npm run demo -- reader-alone
npm run demo -- shared
npm run demo -- separate

Each command starts a fresh server with the setting back at On. You don't need to start the app separately.

Run Observed result Exit code
Writer alone Saves Off and reads Off after reload 0
Reader alone Reads On after reload 0
Together, shared account Writer passes. Reader expects On and receives Off 1
Together, separate accounts Writer reads Off. Reader reads On. Both pass 0

The shared command intentionally exits with code 1. Keep that failure visible when trying the example. A setup problem or an unrecognized result exits with code 2.

For the combined verification, run:

npm run verify

This runs the guards and six fresh scenarios, including a repeated shared/separate pair. The six scenarios produce eight passes and two reader failures. The command exits 0 only after confirming those exact expected results.

Each scenario prints an artifacts/ directory containing its report, observations and server events. Those files let you inspect the values and save order.

What separate browsers protect

A browser context keeps a test's browser state separate. Cookies and localStorage belong to that context. The Playwright isolation guide explains this boundary.

The example checks localStorage, a store inside the browser. Both tests use the key context-probe. The writer stores writer, and the reader stores reader. Each still reads its own value after the account change.

The reader's two checks appear together in tests/accounts.spec.js:

  expect(observation.probe, 'Reader context keeps its own storage').toBe('reader');
  expect(observation.value, 'Reader account remains On after reload').toBe('On');

The storage check passes in the shared run. The account-value check fails.

Email alerts lives on the server, outside those browser contexts. Both requests select the same account, so both see its saved setting. Opening a fresh context doesn't create a new server account.

Here, a cookie holds a made-up account name for the server to select. It demonstrates account selection without implementing production sign-in or using real credentials.

Separate the data each test changes

The two paired modes use these entries from verify.mjs:

  shared: { writer: 'demo-shared', reader: 'demo-shared' },
  separate: { writer: 'demo-writer', reader: 'demo-reader' },

Only the account assignment changes. Both modes use two workers, meaning two processes running the tests. Both keep separate browser contexts and zero retries.

For an account-wide setting such as Email alerts, separate accounts fit the change. Playwright's authentication guide describes one account per parallel worker. Tests reusing that account still need a known starting state.

For tests editing different records, give each test records it alone owns. The parallelism guide describes this approach. Separate accounts won't help if both tests still edit the same shared record.

I'd also keep account pools separate between simultaneous suite runs. Otherwise, two runs could assign the same account to different writers. Reset changed data before another test needs its starting value.

A shared account can still make sense

Sharing an account can suit tests that read data without interfering with one another. Their setup must also leave the other tests' data unchanged. Playwright's authentication guide explicitly supports that choice.

I'd choose the account arrangement around what each test can change. A page-reading test and an account-settings test need different protection when they share an account.

Keep the demonstration's limits

The example uses explicit waiting points to arrange the save and reload. Those waiting points belong to the demonstration setup. They make the sequence repeatable without measuring random failures.

The server holds its settings in memory for one scenario. Values survive page reloads, but a new scenario starts fresh. This example doesn't implement a production account pool or persistent database.

Use the four-run example to see the boundary before choosing accounts for your tests. The reader can keep On while the writer saves Off, with both tests running together.

I'm Anton. I build AI tools and measure how fast they really run. Former Apple engineer. I make ollamatps.com and write about building and measuring AI at anton.qa.

📰 Read the original article on Dev.to WebDev

Originally published by Dev.to WebDev. Aggregated on AIWithGhost for educational purposes — full credit and traffic to the original publisher.