npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@przeslijmi/real-fake-data-playwright

v1.18.0

Published

Playwright fixtures for Real Fake Data — 327 seeded, realistic test-data generators plus a compose() method that seeds a whole nested dataset in one call: person & company names across 27 EU countries, the United States and Canada, one-call whole people a

Readme

@przeslijmi/real-fake-data-playwright

Playwright fixtures for Real Fake Data — 327 generators of realistic, synthetic test data, one typed method per record:

  • Person & company names and email addresses across 29 countries (the 27 EU member states plus the US and Canada) — dePersonName, itCompanyName, usPersonName, caCompanyName, plEmail, … in the local script and inflection (names romanised to ASCII for emails, with free, regional, and company-derived domains), plus multi-country personName/companyName/email that draw from any mix of countries.
  • National identifiers and VAT / company numbers for every EU member state — French frNir/frSiren, Italian itCodiceFiscale, Spanish esDni/esNie, Danish dkCpr, Swedish sePersonnummer, Dutch nlBsn, German deSteuerId/deUstIdnr, and 60+ more — each with correct checksums and the same invalid/edge/extreme triggers.
  • One-call whole people and companies for every EU country — dkPerson, frPerson, … return a consistent name + national number; dkCompany, deCompany, nlCompany, … return a consistent trading name, legal form, and the country's register / tax / VAT numbers, all from one seed.
  • Vehicle registration plates for all 29 countries — deVehicleRegistration, frVehicleRegistration, itVehicleRegistration, plus usVehicleRegistration (all 51 US jurisdictions) and caVehicleRegistration (all 13 provinces and territories) — produce realistic plates with each country's own plate kinds (standard, custom/vanity, motorcycle, diplomatic, military, historic, electric, …), region/district codes, era formats, and the shared edge/extreme triggers. Plus multi-country vehicleRegistration, whose type speaks a shared category vocabulary rather than any one country's names — { type: 'historic' } reaches Hungary's oldtimer, Ireland's vintage and Finland's museum alike.
  • IBANs for all 27 EU countries — deIban, frIban, itIban, … return a valid IBAN with correct mod-97 check digits (and, where the national account number has its own internal check digit, that too — Italy's CIN, Spain's DC, France's clé RIB, and the rest), embedding a real bank code you can pin by bankCode or bankName. The shared invalid / edge / extreme triggers apply.
  • Product & service offerings for all 29 countries — deOffering, frOffering, usOffering, caOffering, … return a localized product/service with a plausible price, unit, and its NACE industry; plus multi-country offering that draws from any mix. Prices are EUR for the EU members, USD for the US and CAD for Canada (not rate-converted), so an unpinned multi-country batch mixes currencies — each record reports its own currency. Filter by industry, type, or full-text offeringName/industryName, with the shared edge/extreme/invalid triggers.
  • United States — usSsn, usEin, usRoutingNumber, usBankAccount, usVehicleRegistration, usPerson, usCompany, plus usPersonName/usCompanyName/usEmail/usOffering. Three differ from their EU counterparts by nature: usSsn takes no sex/age options (an SSN encodes neither), usPerson accepts them but draws the birth date rather than decoding it, and usBankAccount pairs a checksum-valid ABA routing number with a synthetic account number — the US has no national account-number standard to validate against. usRoutingNumber({ realBank: true }) returns a genuine published routing number. usVehicleRegistration covers all 51 jurisdictions in each state's own format and reports state (a US plate doesn't encode it), with Wyoming also reporting its county.
  • Canada — caSin, caBusinessNumber, caTransitNumber, caBankAccount, caVehicleRegistration, caPerson, caCompany, plus caPersonName/caCompanyName/caEmail/caOffering. Where the US identifiers lack checksums, Canada's have them: the SIN and Business Number are both Luhn-checked, so invalid breaks real arithmetic. caTransitNumber returns both renderings — XXXXX-YYY on a cheque and 0YYYXXXXX for EFT, whose field order reverses — and caBankAccount follows CPA Standard 006 (7 or 12 digits), making it better standardised than its US counterpart. Names and company forms are bilingual (Tremblay, Ltée), and jurisdictions resolve in either language: QC, Quebec, Québec.
  • The full Polish national set — valid PESELs (correct checksums), NIPs, REGONs, IBANs, KRS and land-register numbers, ID cards, passports, driving licences, and addresses drawn from real cities and streets.
  • Synthetic IDs — uuid (v4/v7), ulid, nanoId, objectId, and auto-increment sequence: the technical primary keys every record needs, deterministic from the seed (so a seeded UUID is reproducible).
  • Locale-agnostic — lorem ipsum, customRegex (a random string matching any regex you supply; needs a free account), and the weighted enum / object pickers (draw a member or object from a distribution you supply).

Output looks real but is fake — safe for staging, demos, and seed data.

  • Random by default. It's a random-data generator: every call returns fresh data on each run. Pin a seed only when you want a fixed, reproducible dataset — e.g. to replay exactly what a failing run used.
  • Three ways in, no lock-in. A zero-config fakeData singleton (import and go), a createFakeData builder for full control (custom URL, auth headers, seed), or the Playwright fakeData fixture — pick per test, mix freely.
  • Typed end to end. Two methods per generator (one record, or a batch), fully typed inputs and results.

Install

npm install -D @przeslijmi/real-fake-data-playwright
# or: pnpm add -D @przeslijmi/real-fake-data-playwright

Requires @playwright/test (peer dependency) and Node 18+ (for global fetch).

Quick start

There are three ways to pull data in — pick whichever fits, they all return the same typed records. None is privileged; the fixture is not required.

1. Singleton — import and go

Zero config. The fakeData singleton is pre-wired to the public hosted API and returns fresh random data on every run. Best when you just want data in one (or many) tests without touching your Playwright config.

import { test, expect } from '@playwright/test';
import { fakeData } from '@przeslijmi/real-fake-data-playwright';

test('registers a new customer', async ({ page }) => {
  const person = await fakeData.plPerson({ sex: 'f' });

  await page.goto('/signup');
  await page.getByLabel('First name').fill(person.name);
  await page.getByLabel('Surname').fill(person.surname);
  await page.getByLabel('PESEL').fill(person.pesel);
  await page.getByRole('button', { name: 'Create account' }).click();

  await expect(page.getByText(person.surname)).toBeVisible();
});

The singleton targets the public endpoint only and sends no auth headers. Need a custom URL, headers, or a pinned seed? Use one of the next two.

2. createFakeData — full control

Build your own instance over any base URL, with auth headers and an optional seed. Best when you self-host the API, need authentication, or want to pin a fixed dataset.

import { test, expect } from '@playwright/test';
import { createFakeData, CloudFakeDataProvider } from '@przeslijmi/real-fake-data-playwright';

const fakeData = createFakeData(
  new CloudFakeDataProvider({
    baseUrl: 'https://api.real-fake-data.com',
    headers: { 'x-api-key': process.env.RFD_API_KEY ?? '' },
  }),
  { seed: 42 }, // optional — omit for random
);

test('uses pinned data', async ({ page }) => {
  const person = await fakeData.plPerson({ sex: 'f' });
  // …
});

3. Fixture — Playwright-native

Configure once with test.use(...) and the fakeData fixture is injected into every test in scope. Best when you want the data wired into Playwright's lifecycle and configured per file / project.

import { test, expect } from '@przeslijmi/real-fake-data-playwright';

test.use({ realFakeData: { baseUrl: 'https://api.real-fake-data.com' } });

test('registers a new customer', async ({ page, fakeData }) => {
  const person = await fakeData.plPerson({ sex: 'f' });
  // …
  await expect(page.getByText(person.surname)).toBeVisible();
});

Here test and expect are the standard Playwright exports, extended with the fakeData fixture — use them exactly as you would @playwright/test. baseUrl is optional: omit it to use the public hosted API, set it for a self-hosted instance. Like the other two, it's random by default; add seed to pin it (see Configuration).

Configuration

Set options with test.use({ realFakeData: { … } }), at any scope (file, describe, or project, via your Playwright config).

| Option | Type | Description | | --------- | ------------------------ | ------------------------------------------------------------------------------------------------------- | | baseUrl | string | Base URL of the Real Fake Data API. Omit to use the public hosted API (https://api.real-fake-data.com); set it for a self-hosted or staging instance. | | seed | number | Base seed for the test. Omit (the default) for fresh random data on every run; set it to pin the test to a fixed, reproducible dataset. | | headers | Record<string, string> | Extra headers sent with every request (e.g. an API key, to draw on your account's tokens instead of the shared anonymous lane). |

Random by default, reproducible on demand

By default no seed is set, so every call draws fresh random data on each run — this is a random-data generator, and that's the point. When a test fails on a particular record, log the data (or have your CI capture it) and pin a seed to replay the exact same dataset:

test.use({ realFakeData: { baseUrl, seed: 42 } }); // pin this file to a fixed dataset

With a base seed in play, the Nth call within a test uses seed + N — so the calls stay distinct from one another, yet the whole sequence reproduces identically on the next run. So three back-to-back plPerson() calls still return three different people; re-running with the same seed returns those same three. The same holds for the singleton and createFakeData instances. Pass seed on any individual call to override just that one draw.

Seed a whole dataset — compose()

The generator methods return one record each. compose() fills a whole nested dataset in a single call — users with their orders, orders with their line items, foreign keys that line up. You send a shape skeleton whose slots are marked with $-sources; everything else is a literal.

const order = await fakeData.compose<{
  id: string;
  customer: string;
  items: { sku: string }[];
}>({
  shape: {
    id: '$generator.any.uuid.value',
    customer: '$generator.pl.person.name',
    items: {
      $count: [1, 3],
      sku: '$generator.any.nanoid.value',
    },
  },
});

compose() returns the filled document (the data, unwrapped). The result type is caller-defined — pass a type argument to type it, or leave it unknown. It respects the instance's seed the same way generator calls do: an unseeded fixture returns fresh data each run, a seeded one is reproducible, and a per-call seed in the request pins that draw.

compose() is available on every tier, including without an API key. The full request grammar — $count, $generators/shared for consistency, $date/$anchor for related dates — is documented at real-fake-data.com/seed-a-database.

Generators

Each generator exposes a singular method returning one record and a plural taking count as its first argument and returning an array of that many. Method names are locale-prefixed (plPesel, dePersonName, plEmail, …) so generators for different countries never collide; the locale-agnostic lorem and the multi-country aggregates (personName, companyName, email) carry no prefix.

Every method accepts optional constraints. Pass seed on any call to pin just that draw (overriding the instance's seed sequence when one is set).

Triggers. Beyond each generator's own knobs, three cross-cutting flags shape what kind of data you get. Every generator accepts all three, whether or not its row below lists them; what each does for a given generator is in its description at real-fake-data.com/docs:

  • edge: true — restrict output to rarely-exercised but still-valid corners (leap-day PESELs, punctuation-heavy company names, boundary serials).
  • invalid: true — return a value that fails validation: a deliberately wrong check digit where the value has a checksum, a deliberately malformed value elsewhere; the rest of the record stays correct.
  • extreme: true — return correct data in a deliberately hostile encoding: untrimmed whitespace (incl. non-breaking spaces), invisible/zero-width characters and a leading BOM, homoglyph lookalikes, or a bidi override / stacked combining marks — one class per value, so a plural call rotates across them. Only the human-facing string is mangled and it stays recoverable after normalisation: identifiers keep their digits ASCII (homoglyphs excluded) and still checksum; names/companies/people mangle the name only, leaving initials, legalForm, birth dates, and national identifiers clean. For lorem and customRegex homoglyphs are excluded, so the value stays machine-parseable. Use it to test that your pipeline trims, normalises, and compares values safely.
const messy = await fakeData.plPesel({ extreme: true });   // e.g. "  53022100027\n" — trims back to a valid PESEL
const spoof = await fakeData.dePersonName({ extreme: true }); // Cyrillic-lookalike letters; initials stay clean

Names across 29 countries

Every country listed below exposes <cc>PersonName/<cc>PersonNames, <cc>CompanyName/<cc>CompanyNames, <cc>Company/<cc>Companies, <cc>Email/<cc>Emails, and <cc>Offering/<cc>Offerings, where <cc> is its ISO 3166 code: at, be, bg, cy, cz, de, dk, ee, es, fi, fr, gr, hr, hu, ie, it, lt, lu, lv, mt, nl, pl, pt, ro, se, si, sk.

| Singular | Plural | Returns (singular) | Options | | ----------------------- | ------------------------------- | ------------------------------------------- | -------------------------------------- | | <cc>PersonName(opts?) | <cc>PersonNames(count, opts?) | { name, surname, initials, sex } | sex, edge, caseStrict | | <cc>CompanyName(opts?)| <cc>CompanyNames(count, opts?)| { value, legalForm, strategy } | strategy, legalForm, edge | | <cc>Company(opts?) | <cc>Companies(count, opts?) | { name, legalForm, …national ids } | strategy, legalForm, invalid, edge | | <cc>Email(opts?) | <cc>Emails(count, opts?) | { value, localPart, domain, pattern, domainCategory, company, plusTag } | domain, domainCategory, pattern, plusTag, exotic, edge | | <cc>Offering(opts?) | <cc>Offerings(count, opts?) | { value, offeringName, kind, unit, price, currency, industryCode, industryName, language } | industry, type, industryName, offeringName, language, edge, extreme, invalid | | personName(opts?) | personNames(count, opts?) | { name, surname, initials, sex, country } | sex, edge, caseStrict, countries | | companyName(opts?) | companyNames(count, opts?) | { value, legalForm, strategy, country } | strategy, edge, countries | | email(opts?) | emails(count, opts?) | { value, localPart, domain, pattern, domainCategory, company, plusTag, country } | domain, domainCategory, pattern, plusTag, exotic, edge, countries | | offering(opts?) | offerings(count, opts?) | { value, offeringName, kind, unit, price, currency, industryCode, industryName, language, country } | industry, type, industryName, offeringName, language, edge, extreme, invalid, countries | | vehicleRegistration(opts?) | vehicleRegistrations(count, opts?) | { country, value, type, category, region? } | type (a shared category), edge, extreme, invalid, countries |

const ceo = await fakeData.dePersonName({ sex: 'f' });        // German given name + surname
const vendor = await fakeData.itCompanyName({ edge: true });  // edge-case Italian company name
const eu = await fakeData.personName({ countries: ['pl', 'sk', 'it'] }); // drawn from one of the three
const inbox = await fakeData.plEmail({ domainCategory: 'corporate' }); // [email protected]
const item = await fakeData.deOffering({ type: 'service' });  // localized German service + price
const cart = await fakeData.offering({ countries: ['pl', 'it'], industry: '56.11' }); // restaurant items

An offering is a product or service a business sells: a localized value/offeringName, a kind (product/service), a unit (pc, month, kg, …), a price in EUR minor units (cents) with currency, and the industryCode + localized industryName it belongs to. Pin an industry by NACE code, restrict to type, or full-text filter with offeringName/industryName; language pins the name language (multilingual countries otherwise blend theirs). edge/extreme/invalid apply as elsewhere (invalid cannot combine with edge/extreme).

countries (on the prefix-less personName/companyName/email/offering/vehicleRegistration only) is an array of ISO codes; each record is generated by one country picked from the list. Omit it to draw from all 29 — the 27 EU member states plus the US and Canada. The per-country legalForm values differ by country (e.g. GmbH, S.r.l., S.A.), so they are typed as string; pass 'any' for a weighted-random one or 'none' to omit it. For email, domainCategory: 'corporate' builds the address on a company-derived domain and reports the brand in company; non-Latin names (Cyrillic, Greek) are romanised to ASCII.

Polish national generators

| Singular | Plural | Returns (singular) | Common options | | ------------------------------ | -------------------------------------- | ---------------------------------------------------------- | --------------------------------------------------------------------- | | plPesel(opts?) | plPesels(count, opts?) | { value, birthDate, sex } | sex, atAge, olderThan, youngerThan, bornOn/Before/After, edge, extreme, invalid | | plPerson(opts?) | plPeople(count, opts?) | { name, surname, initials, birthDate, pesel } | same as plPesel, plus caseStrict | | plAddress(opts?) | plAddresses(count, opts?) | { buildingNumber, postalCode, cityName, …, terytCodes } | teryt (1–7 digit prefix), live (full current register; default draws the frozen catalogue, so a seed reproduces) | | plNip(opts?) | plNips(count, opts?) | { value, digits } | format, invalid | | plIban(opts?) | plIbans(count, opts?) | { value, electronicFormat, bankCode, bankName } | format, bankCode, bankName, invalid | | plRegon(opts?) | plRegons(count, opts?) | { value, variant } | variant (short/long/any), invalid | | plCompany(opts?) | plCompanies(count, opts?) | { name, legalForm, nip, regon, krs } | strategy, legalForm, activityPrefix, format, edge, invalid | | plCompanyName(opts?) | plCompanyNames(count, opts?) | { value, legalForm, strategy } | strategy, legalForm, activityPrefix, edge | | plIdCard(opts?) | plIdCards(count, opts?) | { value, series, number, expirationDate } | format, expired, invalid | | plPassport(opts?) | plPassports(count, opts?) | { value, series, number } | format, invalid | | plKrs(opts?) | plKrsNumbers(count, opts?) | { value, number } | format | | plLandRegister(opts?) | plLandRegisters(count, opts?) | { value, courtCode, number, checkDigit, court? } | format, court, invalid | | plDrivingLicense(opts?) | plDrivingLicenses(count, opts?) | { value, serial, year, suffix } | format, year | | plVehicleRegistration(opts?) | plVehicleRegistrations(count, opts?) | { value, prefix, individualPart, type, … } | type, voivodeship, county, format, edge, extreme |

The Polish plate is also part of the all-29-country vehicle-registration family below.

A Polish person name on its own (no PESEL/birth date) is plPersonName — part of the 29-country table above.

EU national identifiers

Every EU member state exposes its core national-person identifier and its business / VAT numbers. Numbers that encode a birth date and/or sex accept the same person constraints as plPesel (sex, atAge, olderThan, youngerThan, bornOn/bornBefore/bornAfter); the rest expose only their own knobs. Every checksum-bearing number takes invalid (deliberately wrong check digit) and edge (rare-corner values); generators with a VAT/intra-EU rendering take format: 'national' | 'vat' (some use a generator-specific enum — see each row).

France (fr)

| Singular | Plural | Returns (singular) | Options | | -------- | ------ | ------------------ | ------- | | frSiren(opts?) | frSirens(count, opts?) | { value, digits } | format, invalid, edge | | frNir(opts?) | frNirs(count, opts?) | { value, digits, sex, birthYear, birthMonth } | sex, age/birth filters, invalid, edge | | frPerson(opts?) | frPeople(count, opts?) | { name, surname, initials, birthDate, nir } | sex, age/birth filters, invalid, edge, caseStrict |

Austria (at)

| Singular | Plural | Returns (singular) | Options | | -------- | ------ | ------------------ | ------- | | atSvnr(opts?) | atSvnrs(count, opts?) | { value, digits, birthDate } | age/birth filters, invalid, edge | | atPerson(opts?) | atPeople(count, opts?) | { name, surname, initials, birthDate, svnr } | sex, age/birth filters, invalid, edge, caseStrict | | atUid(opts?) | atUids(count, opts?) | { value, digits } | format, invalid, edge | | atFirmenbuchnummer(opts?) | atFirmenbuchnummers(count, opts?) | { value, number, letter } | invalid, edge | | atSteuernummer(opts?) | atSteuernummers(count, opts?) | { value, digits } | edge |

Belgium (be)

| Singular | Plural | Returns (singular) | Options | | -------- | ------ | ------------------ | ------- | | beRijksregisternummer(opts?) | beRijksregisternummers(count, opts?) | { value, digits, birthDate, sex } | sex, age/birth filters, kind, invalid, edge | | bePerson(opts?) | bePeople(count, opts?) | { name, surname, initials, birthDate, rijksregisternummer } | sex, age/birth filters, invalid, edge, caseStrict | | beOndernemingsnummer(opts?) | beOndernemingsnummers(count, opts?) | { value, digits } | format, invalid, edge |

Bulgaria (bg)

| Singular | Plural | Returns (singular) | Options | | -------- | ------ | ------------------ | ------- | | bgEgn(opts?) | bgEgns(count, opts?) | { value, digits, birthDate, sex } | sex, age/birth filters, invalid, edge | | bgPerson(opts?) | bgPeople(count, opts?) | { name, surname, initials, birthDate, egn } | sex, age/birth filters, invalid, edge, caseStrict | | bgEik(opts?) | bgEiks(count, opts?) | { value, digits } | format, invalid, edge |

Croatia (hr)

| Singular | Plural | Returns (singular) | Options | | -------- | ------ | ------------------ | ------- | | hrOib(opts?) | hrOibs(count, opts?) | { value, digits } | format, invalid, edge | | hrJmbg(opts?) | hrJmbgs(count, opts?) | { value, digits, birthDate, sex } | sex, age/birth filters, invalid, edge | | hrPerson(opts?) | hrPeople(count, opts?) | { name, surname, initials, birthDate, jmbg } | sex, age/birth filters, invalid, edge, caseStrict |

Cyprus (cy)

| Singular | Plural | Returns (singular) | Options | | -------- | ------ | ------------------ | ------- | | cyTic(opts?) | cyTics(count, opts?) | { value, digits, letter } | format, invalid, edge | | cyPerson(opts?) | cyPeople(count, opts?) | { name, surname, initials, birthDate, tic } | sex, age/birth filters, invalid, edge, caseStrict |

Czechia (cz)

| Singular | Plural | Returns (singular) | Options | | -------- | ------ | ------------------ | ------- | | czRodneCislo(opts?) | czRodneCislos(count, opts?) | { value, digits, birthDate, sex } | sex, age/birth filters, format, invalid, edge | | czPerson(opts?) | czPeople(count, opts?) | { name, surname, initials, birthDate, rodneCislo } | sex, age/birth filters, invalid, edge, caseStrict | | czIco(opts?) | czIcos(count, opts?) | { value, digits } | format, invalid, edge |

Denmark (dk)

| Singular | Plural | Returns (singular) | Options | | -------- | ------ | ------------------ | ------- | | dkCpr(opts?) | dkCprs(count, opts?) | { value, digits, birthDate, sex } | sex, age/birth filters, checksum, format, invalid, edge | | dkPerson(opts?) | dkPeople(count, opts?) | { name, surname, initials, birthDate, cpr } | same as dkCpr, plus caseStrict | | dkCvr(opts?) | dkCvrs(count, opts?) | { value, digits } | format, invalid, edge |

Estonia (ee)

| Singular | Plural | Returns (singular) | Options | | -------- | ------ | ------------------ | ------- | | eeIsikukood(opts?) | eeIsikukoods(count, opts?) | { value, digits, birthDate, sex } | sex, age/birth filters, invalid, edge | | eePerson(opts?) | eePeople(count, opts?) | { name, surname, initials, birthDate, isikukood } | sex, age/birth filters, invalid, edge, caseStrict | | eeRegistrikood(opts?) | eeRegistrikoods(count, opts?) | { value, digits } | invalid, edge | | eeKmkr(opts?) | eeKmkrs(count, opts?) | { value, digits } | format, invalid, edge |

Finland (fi)

| Singular | Plural | Returns (singular) | Options | | -------- | ------ | ------------------ | ------- | | fiHenkilotunnus(opts?) | fiHenkilotunnuss(count, opts?) | { value, digits, birthDate, sex } | sex, age/birth filters, invalid, edge | | fiPerson(opts?) | fiPeople(count, opts?) | { name, surname, initials, birthDate, henkilotunnus } | sex, age/birth filters, invalid, edge, caseStrict | | fiYTunnus(opts?) | fiYTunnuss(count, opts?) | { value, digits } | format, invalid, edge |

Germany (de)

| Singular | Plural | Returns (singular) | Options | | -------- | ------ | ------------------ | ------- | | deSteuerId(opts?) | deSteuerIds(count, opts?) | { value, digits } | invalid, edge | | dePerson(opts?) | dePeople(count, opts?) | { name, surname, initials, birthDate, steuerId } | sex, age/birth filters, invalid, edge, caseStrict | | deUstIdnr(opts?) | deUstIdnrs(count, opts?) | { value, digits } | format, invalid, edge | | deHandelsregisternummer(opts?) | deHandelsregisternummers(count, opts?) | { value, division, court, number } | division, edge | | deWirtschaftsIdnr(opts?) | deWirtschaftsIdnrs(count, opts?) | { value, digits, suffix } | suffix, invalid, edge | | dePersonalausweis(opts?) | dePersonalausweiss(count, opts?) | { value, serial, checkDigit } | invalid, edge |

Greece (gr)

| Singular | Plural | Returns (singular) | Options | | -------- | ------ | ------------------ | ------- | | grAmka(opts?) | grAmkas(count, opts?) | { value, digits, birthDate, sex } | sex, age/birth filters, invalid, edge | | grPerson(opts?) | grPeople(count, opts?) | { name, surname, initials, birthDate, amka } | sex, age/birth filters, invalid, edge, caseStrict | | grAfm(opts?) | grAfms(count, opts?) | { value, digits } | format, invalid, edge |

Hungary (hu)

| Singular | Plural | Returns (singular) | Options | | -------- | ------ | ------------------ | ------- | | huAdoazonositoJel(opts?) | huAdoazonositoJels(count, opts?) | { value, digits, birthDate } | age/birth filters, invalid, edge | | huTaj(opts?) | huTajs(count, opts?) | { value, digits } | invalid, edge | | huSzemelyiAzonosito(opts?) | huSzemelyiAzonositos(count, opts?) | { value, digits, birthDate, sex, standard } | sex, age/birth filters, standard, invalid, edge | | huPerson(opts?) | huPeople(count, opts?) | { name, surname, initials, birthDate, szemelyiAzonosito } | sex, age/birth filters, invalid, edge, caseStrict | | huAdoszam(opts?) | huAdoszams(count, opts?) | { value, digits } | format, invalid, edge | | huCegjegyzekszam(opts?) | huCegjegyzekszams(count, opts?) | { value, court, form, serial, digits } | edge |

Ireland (ie)

| Singular | Plural | Returns (singular) | Options | | -------- | ------ | ------------------ | ------- | | iePpsn(opts?) | iePpsns(count, opts?) | { value, digits, checkLetter, secondLetter? } | standard, invalid, edge | | iePerson(opts?) | iePeople(count, opts?) | { name, surname, initials, birthDate, ppsn } | sex, age/birth filters, invalid, edge, caseStrict | | ieVat(opts?) | ieVats(count, opts?) | { value, digits } | format, standard, invalid, edge | | ieCro(opts?) | ieCros(count, opts?) | { value, digits } | edge |

Italy (it)

| Singular | Plural | Returns (singular) | Options | | -------- | ------ | ------------------ | ------- | | itCodiceFiscale(opts?) | itCodiceFiscales(count, opts?) | { value, surnameCode, nameCode, birthDate, sex } | sex, age/birth filters, surname, name, invalid, edge | | itPerson(opts?) | itPeople(count, opts?) | { name, surname, initials, birthDate, codiceFiscale } | sex, age/birth filters, invalid, edge, caseStrict | | itPartitaIva(opts?) | itPartitaIvas(count, opts?) | { value, digits } | format, invalid, edge |

Latvia (lv)

| Singular | Plural | Returns (singular) | Options | | -------- | ------ | ------------------ | ------- | | lvPersonasKods(opts?) | lvPersonasKodss(count, opts?) | { value, digits, birthDate? } | age/birth filters, standard, format, invalid, edge | | lvPerson(opts?) | lvPeople(count, opts?) | { name, surname, initials, birthDate, personasKods } | sex, age/birth filters, invalid, edge, caseStrict | | lvRegistracijasNumurs(opts?) | lvRegistracijasNumurss(count, opts?) | { value, digits } | format, invalid, edge |

Lithuania (lt)

| Singular | Plural | Returns (singular) | Options | | -------- | ------ | ------------------ | ------- | | ltAsmensKodas(opts?) | ltAsmensKodass(count, opts?) | { value, digits, birthDate, sex } | sex, age/birth filters, invalid, edge | | ltPerson(opts?) | ltPeople(count, opts?) | { name, surname, initials, birthDate, asmensKodas } | sex, age/birth filters, invalid, edge, caseStrict | | ltImonesKodas(opts?) | ltImonesKodass(count, opts?) | { value, digits } | invalid, edge | | ltPvm(opts?) | ltPvms(count, opts?) | { value, digits } | format, invalid, edge |

Luxembourg (lu)

| Singular | Plural | Returns (singular) | Options | | -------- | ------ | ------------------ | ------- | | luMatricule(opts?) | luMatricules(count, opts?) | { value, digits, birthDate } | age/birth filters, invalid, edge | | luPerson(opts?) | luPeople(count, opts?) | { name, surname, initials, birthDate, matricule } | sex, age/birth filters, invalid, edge, caseStrict | | luTva(opts?) | luTvas(count, opts?) | { value, digits } | format, invalid, edge |

Malta (mt)

| Singular | Plural | Returns (singular) | Options | | -------- | ------ | ------------------ | ------- | | mtIdCard(opts?) | mtIdCards(count, opts?) | { value, digits, category } | category, edge | | mtPerson(opts?) | mtPeople(count, opts?) | { name, surname, initials, birthDate, idCard } | sex, age/birth filters, invalid, edge, caseStrict | | mtVat(opts?) | mtVats(count, opts?) | { value, digits } | format, invalid, edge |

Netherlands (nl)

| Singular | Plural | Returns (singular) | Options | | -------- | ------ | ------------------ | ------- | | nlBsn(opts?) | nlBsns(count, opts?) | { value, digits } | invalid, edge | | nlPerson(opts?) | nlPeople(count, opts?) | { name, surname, initials, birthDate, bsn } | sex, age/birth filters, invalid, edge, caseStrict | | nlRsin(opts?) | nlRsins(count, opts?) | { value, digits } | invalid, edge | | nlBtwId(opts?) | nlBtwIds(count, opts?) | { value, digits, standard } | standard, invalid, edge | | nlKvk(opts?) | nlKvks(count, opts?) | { value, digits } | edge |

Portugal (pt)

| Singular | Plural | Returns (singular) | Options | | -------- | ------ | ------------------ | ------- | | ptNif(opts?) | ptNifs(count, opts?) | { value, digits, entity } | entity, format, invalid, edge | | ptCartaoCidadao(opts?) | ptCartaoCidadaos(count, opts?) | { value, nic, version } | invalid, edge | | ptPerson(opts?) | ptPeople(count, opts?) | { name, surname, initials, birthDate, cartaoCidadao } | sex, age/birth filters, invalid, edge, caseStrict |

Romania (ro)

| Singular | Plural | Returns (singular) | Options | | -------- | ------ | ------------------ | ------- | | roCnp(opts?) | roCnps(count, opts?) | { value, digits, birthDate, sex, county } | sex, age/birth filters, invalid, edge | | roPerson(opts?) | roPeople(count, opts?) | { name, surname, initials, birthDate, cnp } | sex, age/birth filters, invalid, edge, caseStrict | | roCui(opts?) | roCuis(count, opts?) | { value, digits } | format, invalid, edge |

Slovakia (sk)

| Singular | Plural | Returns (singular) | Options | | -------- | ------ | ------------------ | ------- | | skRodneCislo(opts?) | skRodneCislos(count, opts?) | { value, digits, birthDate, sex } | sex, age/birth filters, format, invalid, edge | | skPerson(opts?) | skPeople(count, opts?) | { name, surname, initials, birthDate, rodneCislo } | sex, age/birth filters, invalid, edge, caseStrict | | skIco(opts?) | skIcos(count, opts?) | { value, digits } | invalid, edge | | skIcDph(opts?) | skIcDphs(count, opts?) | { value, digits } | format, invalid, edge |

Slovenia (si)

| Singular | Plural | Returns (singular) | Options | | -------- | ------ | ------------------ | ------- | | siEmso(opts?) | siEmsos(count, opts?) | { value, digits, birthDate, sex } | sex, age/birth filters, invalid, edge | | siPerson(opts?) | siPeople(count, opts?) | { name, surname, initials, birthDate, emso } | sex, age/birth filters, invalid, edge, caseStrict | | siDavcnaStevilka(opts?) | siDavcnaStevilkas(count, opts?) | { value, digits } | format, invalid, edge |

Spain (es)

| Singular | Plural | Returns (singular) | Options | | -------- | ------ | ------------------ | ------- | | esDni(opts?) | esDnis(count, opts?) | { value, digits, letter } | invalid, edge | | esPerson(opts?) | esPeople(count, opts?) | { name, surname, initials, birthDate, dni } | sex, age/birth filters, invalid, edge, caseStrict | | esNie(opts?) | esNies(count, opts?) | { value, prefix, digits, letter } | invalid, edge | | esCif(opts?) | esCifs(count, opts?) | { value, digits } | format, invalid, edge |

Sweden (se)

| Singular | Plural | Returns (singular) | Options | | -------- | ------ | ------------------ | ------- | | sePersonnummer(opts?) | sePersonnummers(count, opts?) | { value, digits, birthDate, sex } | sex, age/birth filters, format, kind, invalid, edge | | sePerson(opts?) | sePeople(count, opts?) | { name, surname, initials, birthDate, personnummer } | sex, age/birth filters, invalid, edge, caseStrict | | seOrganisationsnummer(opts?) | seOrganisationsnummers(count, opts?) | { value, digits } | format, invalid, edge |

Vehicle registration plates

Every EU member state exposes <cc>VehicleRegistration(opts?) / <cc>VehicleRegistrations(count, opts?), returning at least { value, type } (plus country-specific fields — region/district/province codes, era, expiryMonth, subregion, …). Each country owns its own type union — the plate kinds that country actually issues — so the returned type and the accepted type option are typed per country. Every method takes the shared edge and extreme triggers; other options (format, era, region filters) vary by country as listed below.

| Country | Method prefix | type values | Other options | | ------- | ------------- | ------------- | ------------- | | Poland (pl) | plVehicleRegistration | standard, custom, police, military, historic, motorcycle, short | voivodeship, county, format | | Austria (at) | atVehicleRegistration | standard, custom, motorcycle, military, police, diplomatic | district, state, format | | Belgium (be) | beVehicleRegistration | standard, custom, motorcycle, moped, diplomatic, dealer, export, oldtimer, taxi, trailer | format | | Bulgaria (bg) | bgVehicleRegistration | standard, custom, motorcycle, military, diplomatic, electric, temporary | script, province, format | | Cyprus (cy) | cyVehicleRegistration | standard, motorcycle, diplomatic, trailer, un, sba | format | | Czechia (cz) | czVehicleRegistration | standard, extended, custom, motorcycle, diplomatic, historic, electric, military | region, format | | Germany (de) | deVehicleRegistration | standard, custom, seasonal, historic, electric, motorcycle, military, diplomatic | district, era, format | | Denmark (dk) | dkVehicleRegistration | standard, custom, diplomatic, trailer, motorcycle, export | era, format | | Estonia (ee) | eeVehicleRegistration | standard, custom, diplomatic, dealer, racing, classic, motorcycle, moped, transit, military | era, format | | Spain (es) | esVehicleRegistration | standard, motorcycle, military, diplomatic, guardia-civil, national-police, temporary, dealer, historic, trailer | era, province, format | | Finland (fi) | fiVehicleRegistration | standard, custom, diplomatic, export, dealer, museum, trailer, military, motorcycle, aland | era, format | | France (fr) | frVehicleRegistration | standard, diplomatic, temporary, export, motorcycle | era, withDepartment, department, format | | Greece (gr) | grVehicleRegistration | standard, motorcycle, taxi, diplomatic, historic, trailer | script, era, region, format | | Croatia (hr) | hrVehicleRegistration | standard, custom, military, diplomatic, export, historic, motorcycle | city, format | | Hungary (hu) | huVehicleRegistration | standard, custom, military, diplomatic, police, oldtimer, taxi, electric, motorcycle, temporary | era, format | | Ireland (ie) | ieVehicleRegistration | standard, temporary-import, vintage, taxi, electric | era, county, format | | Italy (it) | itVehicleRegistration | standard, motorcycle, military, diplomatic, trailer | withProvince, province, format | | Lithuania (lt) | ltVehicleRegistration | standard, custom, military, diplomatic, motorcycle, moped, trailer, ev, taxi, historic, dealer | format | | Luxembourg (lu) | luVehicleRegistration | standard, custom, military, diplomatic, official, dealer, export, moped, deputies | era, format | | Latvia (lv) | lvVehicleRegistration | standard, custom, military, diplomatic, consular, historic, taxi, transit, motorcycle, moped | format | | Malta (mt) | mtVehicleRegistration | standard, motorcycle, military, government, diplomatic, taxi, bus, trailer, tax-free, custom | expiryMonth, format | | Netherlands (nl) | nlVehicleRegistration | standard, motorcycle, historic, diplomatic, military, dealer, export | sidecode, era, format | | Portugal (pt) | ptVehicleRegistration | standard, motorcycle, military, diplomatic, police, export | era, format | | Romania (ro) | roVehicleRegistration | standard, motorcycle, electric, temporary, military, police, diplomatic | county, format | | Sweden (se) | seVehicleRegistration | standard, custom, diplomatic, military, motorcycle | era, format | | Slovenia (si) | siVehicleRegistration | standard, custom, motorcycle, military, diplomatic, police, export | region, format | | Slovakia (sk) | skVehicleRegistration | standard, motorcycle, military, diplomatic, consular, trailer, historic, electric, dealer, custom | era, district, region, format |

All 29 at once — vehicleRegistration(opts?) / vehicleRegistrations(count, opts?) draw a country per record and return { country, value, type, category, region? }. Because the 29 type unions above share no vocabulary — standard in Italy is passenger in the US, oldtimer in Hungary is vintage in Ireland is museum in Finland — the cross-country type takes a shared category instead: standard, custom, motorcycle, moped, military, police, diplomatic, government, commercial, taxi, trailer, historic, electric, temporary, export, dealer, other. Each record reports both — category is what you asked for, type is what that country calls it.

A type narrows the pool to the countries that issue it ({ type: 'taxi' } draws from the seven that do), and combining it with a countries pool that issues nothing of the kind is a 400 rather than a silent substitution. format, era, script and the region filters stay on the per-country methods, where their vocabularies are exact.

const plates = await fakeData.vehicleRegistrations(3, { type: 'historic' });
// [{ country: 'ie', value: 'ZV 4861', type: 'vintage',  category: 'historic' },
//  { country: 'hr', value: 'GN-PV-842', type: 'historic', category: 'historic' },
//  { country: 'pl', value: 'SRB 5S', type: 'historic', category: 'historic', region: 'śląskie' }]

IBANs

Every EU member state exposes <cc>Iban(opts?) / <cc>Ibans(count, opts?), all returning the same shape { value, electronicFormat, bankCode, bankName }. The IBAN carries correct mod-97 check digits and, where the national account number has an internal check digit, that is reproduced too. Pin the issuing bank with bankCode (country-specific width) or bankName (case-insensitive fragment, mutually exclusive), or let it be chosen at random. Every method takes format (grouped/compact) and the shared invalid / edge / extreme triggers.

plIban, deIban, atIban, beIban, bgIban, cyIban, czIban, dkIban, eeIban, esIban, fiIban, frIban, grIban, hrIban, huIban, ieIban, itIban, ltIban, luIban, lvIban, mtIban, nlIban, ptIban, roIban, seIban, siIban, skIban — each hits GET /v1/<cc>/iban.

Locale-agnostic

| Singular | Plural | Returns (singular) | Common options | | ------------------------------ | -------------------------------------- | ---------------------------------------------------------- | --------------------------------------------------------------------- | | lorem(opts?) | lorems(count, opts?) | { value, words, chars, bytes, paragraphs, startedWithLorem } | bytes, chars, words, paragraphs, startWithLorem | | customRegex(opts) | customRegexes(count, opts) | { value, pattern } | pattern (required), maxRepetition — needs a free account | | enum(opts) | enums(count, opts) | { value, probability } | choices (weighted map {member:weight} or bare array […] for equal weights) or dictionary (name of an enum Dictionary defined in the Real-Fake-Data.com dashboard; needs the team's API key in headers) — exactly one; edge, extreme, invalid | | object(opts) | objects(count, opts) | { value, probability } | choices (weighted {object,weight}[] or bare array of objects for equal weights) or dictionary (name of an object Dictionary defined in the Real-Fake-Data.com dashboard; needs the team's API key in headers) — exactly one; edge, extreme, invalid |

Synthetic IDs

The technical identifiers a record needs but no national registry issues — primary keys. Locale-agnostic, no prefix. Deterministic from the seed, so a seeded UUID is reproducible; any embedded timestamp (UUID v7, ULID, ObjectId) is seed-derived, not wall-clock.

| Singular | Plural | Returns (singular) | Common options | | ------------------------------ | -------------------------------------- | --------------------------- | --------------------------------------- | | uuid(opts?) | uuids(count, opts?) | { value, version } | version: '4' \| '7' (default '4') | | ulid(opts?) | ulids(count, opts?) | { value } | — | | nanoId(opts?) | nanoIds(count, opts?) | { value } | size (default 21), alphabet | | objectId(opts?) | objectIds(count, opts?) | { value } | — | | sequence(opts?) | sequences(count, opts?) | { value } | start (default 1), step (default 1) |

For sequence, a plural call returns the run start, start + step, …; a singular call returns start.

Generating many records at once

Every plural takes count as its first argument and returns an array. The bound (10 by default, raised once you have credits) is enforced by the API — an out-of-range count throws a RealFakeDataError (HTTP 400), never a silent clamp. A plural is a single request, so — when a seed is in play — it consumes one slot of the seed sequence just like a singular call.

const team = await fakeData.plPeople(5, { sex: 'f' }); // PolishPersonData[] of length 5
const inboxes = await fakeData.emails(3); // EmailData[] of length 3

Special triggers

Three opt-in flags steer generators toward the cases real-world data throws at your code:

  • invalid: true — on every checksum generator (plPesel, plNip, plRegon, plIban, plCompany, plIdCard, plPassport, plLandRegister), produces a value with a deliberately wrong check digit while the rest stays well-formed. For asserting that your own validators reject bad input. When set, the response meta.invalid is true so a batch can tell the broken record apart.
  • edge: true — on the name generators (<cc>PersonName, <cc>CompanyName, personName, companyName, plCompany), biases toward edge-case shapes: second given names, double-barrelled surnames, very short names, punctuation-heavy or unusually long company names. The corners that break naïve form validation and layout.
  • caseStrict: false — on the person-name generators, deliberately mangles the casing of name and surname (all-lower, all-upper, or random); initials stay proper uppercase. Defaults to true (proper casing). For testing case-insensitive matching and normalisation.
const bad = await fakeData.plNip({ invalid: true });
await expect(submitNip(bad.value)).rejects.toThrow('invalid checksum');

const messy = await fakeData.dePersonName({ caseStrict: false }); // e.g. { name: 'hANS', surname: 'müller' }
const tricky = await fakeData.itCompanyName({ edge: true });      // punctuation-heavy / long-form name

Error handling

A non-2xx API response throws a RealFakeDataError carrying status (HTTP code), code (the API's machine error code), and details (per-field validation messages):

import { RealFakeDataError } from '@przeslijmi/real-fake-data-playwright';

try {
  await fakeData.plAddress({ teryt: 'not-digits' });
} catch (error) {
  if (error instanceof RealFakeDataError) {
    console.log(error.status, error.code, error.details);
    // 400 'VALIDATION_ERROR' [{ path: 'teryt', message: 'teryt must be 1–7 digits' }]
  }
}

Advanced: using the client without the fixture

The fixture is a thin wrapper over a provider and a facade you can use directly — handy in global setup, scripts, or non-Playwright code:

import { CloudFakeDataProvider, createFakeData } from '@przeslijmi/real-fake-data-playwright';

const provider = new CloudFakeDataProvider({ baseUrl: 'https://api.real-fake-data.com' });
const fakeData = createFakeData(provider, { seed: 42 });

const company = await fakeData.plCompanyName({ legalForm: 'S.A.' });

The FakeDataProvider interface is the swap point: the cloud provider talks HTTP to the hosted API, and the same facade can run against other backends.

License

MIT


This repository is auto-generated from a private upstream monorepo. Open issues here, but code changes are made upstream and re-synced — pull requests against this repo are applied upstream, not merged directly.