DEV Community

Cover image for Realistic Mock Data for Cypress, Playwright & Postman
yobox
yobox

Posted on • Originally published at yobox.dev

Realistic Mock Data for Cypress, Playwright & Postman

The cheapest test failure to debug is the one that says exactly what's wrong. The most expensive one is the test that passes against "test@test.com" and "John Doe" and then explodes the moment a real user with an apostrophe in their name signs up. Realistic mock data is the difference.

This guide covers a complete mock-data toolkit for Cypress, Playwright, and Postman — emails from YoBox, passwords from the Password Generator, filler text from Lorem Ipsum, and a few patterns for the long tail of edge cases.

Why "test@test.com" is a problem

"test@test.com" has been registered as a real account on most major SaaS apps at least once a day for the last decade. Your CI is competing with everyone else's. Worse, your tests probably pass because the response matches expectations — even when the database update silently failed because a unique constraint fired.

The fix is one HTTP call:

const inbox = await fetch("https://yobox.dev/api/mail/new", { method: "POST" }).then(r => r.json());
Now every test gets an address no one else owns, ever.

The four categories of mock data
Category Source Edge cases to cover
Emails YoBox Temp Mail Plus addressing, long local part
Passwords Password Generator Unicode, length 64+
Names Faker / custom Apostrophes, CJK, RTL
Long text Lorem Ipsum Newlines, emoji, HTML entities
The first two are completely solved by YoBox. The other two need a faker library plus deliberate edge cases.

A reusable factory module

// tests/factories.ts
import { faker } from "@faker-js/faker";

const YOBOX = process.env.YOBOX ?? "https://yobox.dev/api";

export async function makeUser() {
const inbox = await fetch(${YOBOX}/mail/new, { method: "POST" }).then(r => r.json());
return {
email: inbox.address,
inboxId: inbox.id,
firstName: faker.person.firstName(),
lastName: faker.person.lastName(),
password: faker.internet.password({ length: 20, memorable: false, prefix: "T!" }),
};
}

export const edgeCaseUsers = [
{ firstName: "O'Brien", lastName: "Müller" },
{ firstName: "", lastName: "" },
{ firstName: "Ñoño", lastName: "García" },
{ firstName: "Anne-Marie", lastName: "de la Vega" },
];
Enter fullscreen mode Exit fullscreen mode

That one file covers 95% of the variety you need.

Cypress

import { makeUser, edgeCaseUsers } from "../factories";

describe("Signup variety", () => {
it("happy path", () => {
cy.wrap(makeUser()).then((u) => {
cy.visit("/signup");
cy.get("[data-test=email]").type(u.email);
// ...
});
});

edgeCaseUsers.forEach((u) => {
it(handles "${u.firstName} ${u.lastName}", () => {
cy.wrap(makeUser()).then((base) => {
cy.visit("/signup");
cy.get("[data-test=first]").type(u.firstName);
cy.get("[data-test=last]").type(u.lastName);
cy.get("[data-test=email]").type(base.email);
});
});
});
});
Enter fullscreen mode Exit fullscreen mode

Playwright

import { test, expect } from "./fixtures";
import { makeUser } from "./factories";

test("variety", async ({ page }) => {
const u = await makeUser();
await page.goto("/signup");
await page.getByLabel("Email").fill(u.email);
await page.getByLabel("First name").fill(u.firstName);
});
Enter fullscreen mode Exit fullscreen mode

Postman

In a pre-request script:

const first = pm.variables.replaceIn("{{$randomFirstName}}");
const last = pm.variables.replaceIn("{{$randomLastName}}");
pm.collectionVariables.set("firstName", first);
pm.collectionVariables.set("lastName", last);
Pair with the YoBox inbox bootstrap from the Postman + YoBox guide.

Long-form text
For description fields, comment bodies, blog posts:

const longText = await fetch("/* lorem source */").then(r => r.text());
Or simply paste blocks from YoBox Lorem Ipsum into a fixtures file. Include at least one block with emoji, one with newlines, and one with HTML entities — they catch the most regressions.

Payload fixtures

Free tool
Open Cypress Guide
End-to-end recipes for Cypress + YoBox.

Open
Don't write JSON by hand:

export const invoicePayload = (overrides = {}) => ({
id: crypto.randomUUID(),
customer_email: "",
amount_cents: 4200,
currency: "USD",
created_at: new Date().toISOString(),
...overrides,
});
Override the fields a test actually cares about; leave the rest as realistic defaults.

Edge cases worth always testing

Email with +tag addressing.
Name with a single apostrophe.
Name with a hyphen.
256-character display name.
Empty middle name vs missing middle name ("" vs undefined).
Currency with thousands separator.
Timestamps in non-UTC zones.

Pairs with

YoBox Temp Mail for unique inboxes.
Password Generator for credentials.
Lorem Ipsum for body copy.
Regex Patterns cheat sheet for validation assertions.

Common pitfalls

Hard-coded "test@test.com" — every issue traceable to this string is your fault.
No CJK or RTL coverage — your i18n layer is untested.
Predictable timestamps — new Date(0) everywhere will hide timezone bugs.
Reusing the same fake user — defeats the purpose of fixtures.

FAQ

Should I commit fixtures to git?
Static fixtures yes; generated user data no.

Is Faker deterministic?
It can be, via faker.seed(123). Use seeded data for snapshot tests, random for everything else.

How big should a fixture file be?
Small. If it's over 200 lines, you're testing the fixture, not the app.

What about PII?
Never use real customer data, even anonymized. Faker + YoBox covers every legitimate need.

Conclusion

Realistic mock data is the cheapest quality investment your team can make. YoBox gives you the inboxes and the passwords; Faker plus a small edge-case list covers names and payloads; Lorem Ipsum covers prose. Wire it all into a single factories module and every test in Cypress, Playwright, and Postman gets variety for free.

See also: Stop Using Fake Data in Production Demos, Cypress + YoBox, Secure Test Credentials.

Locales and i18n

Faker supports locale-specific data. Set \faker.locale = "ja"\ for Japanese names and addresses, then run your suite in that locale to catch text-direction and character-width bugs.

Payment data

Use Stripe's published test card numbers (\4242 4242 4242 4242\ for success, \4000 0000 0000 0002\ for decline) — never generate fake card numbers, even for tests. Real card-number formats can trigger fraud rules in scanners.

Date and timezone variety

Generate timestamps across at least three timezones in every fixture set. The bugs around DST, leap seconds, and ISO formatting are not edge cases — they are weekly cases in any global app.

Migration from fixed fixtures
Replace \fixture("user.json")\ calls with factory calls one folder at a time. Each PR is small, reviewable, and instantly increases coverage of the messy edges that fixed fixtures never exercise.

A data generation strategy that survives contact with reality

Mock data should be realistic, deterministic, and disposable. Realistic so you catch shape bugs; deterministic so failures reproduce; disposable so a leak is a non-event.

The standard stack:

Faker for shapes (names, addresses, lorem ipsum).
A seeded RNG so two runs of the same test produce the same data.
YoBox primitives for things Faker can't produce — real inboxes, real webhook URLs, real cryptographic strings.

import { faker } from "@faker-js/faker";
faker.seed(42);

export function buildUser(runId: string) {
return {
name: faker.person.fullName(),
email: qa+${runId}@yobox.dev,
company: faker.company.name(),
bio: faker.lorem.sentences(2),
};
}
Enter fullscreen mode Exit fullscreen mode

Cypress fixtures vs. factories

Fixtures (cypress/fixtures/user.json) are great for static reference data. The moment a value must differ per run — an email, a username, a timestamp — switch to a factory function called from your test.

// cypress/support/factories.ts
export const newUser = () => ({
email: qa+${Date.now()}@yobox.dev,
password: crypto.randomUUID(),
});

Playwright + storage state

Playwright's storageState lets you log in once and reuse the session across tests. Pair this with a factory that registers a fresh user during globalSetup so every CI run gets a clean account.

// playwright/global-setup.ts
import { chromium } from "@playwright/test";
export default async function () {
const browser = await chromium.launch();
const page = await browser.newPage();
// sign up using YoBox temp mail for the OTP
await page.goto("/signup");
// ...
await page.context().storageState({ path: "state.json" });
await browser.close();
}

Postman: dynamic variables done right

Postman ships dozens of {{$random...}} variables. The trap is that they regenerate on every reference, so chaining requests with the same value requires capturing once:

pm.collectionVariables.set("email", qa+${pm.variables.replaceIn("{{$timestamp}}")}@yobox.dev);

Realistic vs. random

Random data is not realistic data. asdf qwer will pass most validators and miss every visual bug. Faker's locale-aware generators (faker.location.streetAddress({ useFullAddress: true })) catch UI overflows that random strings will not.

Generator Realism Determinism Use when
Faker (seeded) High Yes Default for E2E suites
Random ASCII None Easy Property tests, fuzzing
Production-derived dumps Highest Yes Never (PII risk)
YoBox Temp Mail address Real Per-run Anything that sends real email

Troubleshooting

Tests pass with mock data, fail with real users.
Your mock data is too uniform. Inject edge cases: names with apostrophes, addresses without zip codes, emoji in bios.

Faker output changes between versions.
Pin Faker as an exact dependency in CI, or your snapshot tests will explode after a routine upgrade.

Postman variables behave unpredictably across requests.
Use pm.collectionVariables for per-run values and pm.variables only for true throwaways.

FAQ

Should I share fixtures across Cypress and Playwright?
If both suites cover the same flows, yes. Extract a fixtures/ package and consume from both. Otherwise you'll drift.

How do I avoid PII in test data?
Generate everything. Never copy from production. If you must mirror production shape, anonymize at the dump stage, not at the test stage.

What about contract tests?
Pact or Postman's schema tests cover contracts; mock data covers behavior. They're complementary, not competing.

Where does YoBox fit?
Temp Mail replaces hand-rolled inbox stubs. The Webhook Tester replaces requestbin-style listeners. The Password Generator replaces Password123!. Pull each in as you need it instead of building local equivalents.

Comparison: fixture files vs. factories vs. live faker

Approach Reproducibility Edge-case coverage Refactor cost Best for
Static JSON fixtures Perfect Low — only what you typed High — touch every file Snapshot tests, contract tests
Seeded factories Perfect (with a seed) High — randomized within rules Low — change the factory Most E2E and integration tests
Live faker (unseeded) None Maximum Low Exploratory and fuzz testing
Fixed fixtures lie to you. They pass on Monday because nothing changed since Friday, not because the code is correct. Factories with a seeded RNG give you reproducibility and breadth at the same time.

Real use cases

Cypress signup flows with Temp Mail
Combine a seeded factory with a fresh YoBox inbox per spec. The factory mints a realistic name, address, and locale; YoBox mints a real email address that actually receives the verification message. The Cypress + YoBox guide shows the full custom-command setup.

Playwright parallel-safe fixtures
When Playwright runs eight workers in parallel, every worker needs a unique user. A factory keyed off test.info().workerIndex guarantees uniqueness without coordination. See the Playwright + YoBox guide for the worker-scoped fixture pattern.

Postman collections shared across teams
A Postman collection that hardcodes { "email": "alice@example.com" } breaks the moment two engineers run it against the same environment. Replace the body with {{$randomEmail}} or, better, a pre-request script that calls into a factory function. The Postman + YoBox guide covers the YoBox-backed assertion side.

CI seed data for staging
The same factory that generates test data in Cypress can seed staging databases. One module, two callers — staging looks like production, and your QA team stops asking for "more realistic data."

Key takeaways

Treat test data as code: version it, review it, and refactor it.
Seed your RNG so failures are reproducible without sacrificing coverage.
Use real domains (example.com) or YoBox-issued inboxes for email fields — never test@test.com.
Generate one realistic value per attribute rather than copy/pasting the same string twelve times.
Ship a factory module on day one; retrofitting it after a hundred specs is painful.
The bugs your tests miss live in the data your tests never generate. Realistic mock data is the cheapest coverage you can buy.

YoBox Team

Builder behind YoBox — a privacy-first toolbox for developers and QA engineers covering disposable email, webhook capture, regex, secure passwords, Docker, and end-to-end testing.

Top comments (0)