Seeded Test Fixtures for Vitest
Problem
Test suites need realistic mock data that stays stable across runs so snapshots and assertions do not flake in CI. Hand-written fixtures drift from real shapes; unseeded random generators produce different output every run.
APIs involved: createIllusion, person, internet, location, system.
Solution
Create a seeded illusionist instance inside each test. The same seed reproduces the same data in every run.
ts
import { createIllusion } from '@vielzeug/illusionist';
import { en } from '@vielzeug/illusionist/locales';
import { describe, expect, test } from 'vitest';
function makeUser(seed: number) {
const illusion = createIllusion({ seed, locale: en });
const user = {
name: illusion.person.fullName(),
email: illusion.internet.email(),
address: illusion.location.streetAddress(),
city: illusion.location.city(),
zip: illusion.location.zipCode(),
};
illusion.dispose();
return user;
}
describe('user profile', () => {
test('generates a valid user', () => {
const user = makeUser(12345);
expect(user.name).toContain(' ');
expect(user.email).toContain('@');
});
test('is deterministic for the same seed', () => {
const a = makeUser(12345);
const b = makeUser(12345);
expect(a).toEqual(b);
});
test('snapshot stays stable', () => {
const user = makeUser(12345);
expect(user).toMatchInlineSnapshot();
});
});With per-test isolation
Give each test a distinct seed so failures point to a specific case. Use using to release the instance automatically.
ts
import { createIllusion } from '@vielzeug/illusionist';
import { en } from '@vielzeug/illusionist/locales';
import { describe, expect, test } from 'vitest';
describe('orders', () => {
test.each([1, 2, 3])('order #%s', (seed) => {
using illusion = createIllusion({ seed, locale: en });
const order = {
customer: illusion.person.fullName(),
product: illusion.commerce.productName(),
price: illusion.commerce.price({ min: 10, max: 100 }),
};
expect(order.price.amount).toBeGreaterThan(0n);
});
});Pitfalls
- Do not share a single instance across tests that run concurrently — each call advances the shared random source and causes cross-test drift.
- Do not reuse an instance after
dispose(); create a fresh one per test instead. - String seeds are hashed, so two different strings never collide, but the same string always produces the same sequence.
system.uuid()usescrypto.randomUUID(), not the seeded source. Do not use it in deterministic fixtures or snapshot tests.