One data pool. Two front doors.
Your manual testers lock and consume test data through the browser extension. Your automated tests do the exact same thing through the API or npm client—against the same pool, the same templates, the same lock rules. Neither side can grab data the other is using.
Manual testing and automation run on two different data setups.
A manual tester grabs a row from a spreadsheet. Automation runs its own seed script. Nobody notices when they drift apart—until two test runs collide over the same “test user”, or a manual tester ends up testing with data automation already used up.
Spreadsheet, row 47.
Still labelled “the test user” three sprints later. Nobody remembers who is using it right now.
Seed script, hardcoded.
Written once, drifted from the spreadsheet months ago, and nobody updates it until a test fails.
One entity pool.
Same lock, release, and consume rules for everyone. Both sides see the same data, in the same state, at the same time.
Parallel runs, one shared user
Manual exploratory testing and a CI run both reach for the same account at the same time. One of them loses.
Edge cases live in one head at a time
A client under 18, an overdue invoice—hand-typed by a tester or hardcoded in a script, never reused between the two.
Drift nobody notices
The spreadsheet and the seed script started in sync. Three sprints later, neither matches what the other expects.
Onboarding, twice
A new manual tester and a new SDET both get the “where does test data come from” explanation—separately, from scratch.
Same entity, same lock state, no matter who's asking.
The browser extension popup calls GET /business-objects and locks or consumes a record. Your Playwright test or npm client calls the identical lifecycle—lock(), release(), consume()—on the identical record. Whoever gets there first, gets it.
Call getTestData(). Done.
Four lines cover most of it.
const testUser = await getTestData( 'test-user', 'support' );
Typed, ready to use, no setup boilerplate. Nothing for a manual tester to know about, nothing for automation to maintain.
for (const item of await pool('client-profile')) {
test(`onboarding · ${item.id}`, async ({ page }) => {
await page.goto('/onboarding');
});
}Playwright generates one test per pooled item automatically—no maintained list of usernames to keep in sync with what manual testers already used up.
await orderTestData('invoice', {
status: 'overdue'
});If the exact variant isn't in the pool yet, both the extension's Order button and this call place the same order and wait on the same generation pipeline.
await testUser.lock(); await testUser.consume(); await testUser.release();
Lock it, use it, release it—or let consume() retire it for good. Automation and manual testers play by the same three verbs.
No new test framework to learn.
Safe for the QA lead, too. Synthetic data, redacted logs, and safe email domains are enforced once at the template level—and inherited by every consumer, manual or automated. Nobody has to remember to scrub anything.
Stop maintaining two test-data setups.
One pool, one set of rules, two ways in.