Mystery meat test data is a recipe for confusion. When your test fails six months from now, you should understand the test data instantly, not need archaeology skills.
// 😱 BAD: Shared, mutable test data
// fixtures/users.json
{
"testUser": {
"id": 1,
"email": "test@example.com",
"balance": 100
}
}
// test1.js
test('user can make purchase', () => {
const user = loadFixture('users.json').testUser;
makePurchase(user, 50);
expect(user.balance).toBe(50); // Mutates shared data!
});
// test2.js
test('user can receive refund', () => {
const user = loadFixture('users.json').testUser;
// Fails because test1 mutated the balance!
expect(user.balance).toBe(100);
refund(user, 25);
expect(user.balance).toBe(125);
});// 😱 BAD: What do these values mean?
test('calculates shipping cost', () => {
const order = createOrder(
3, // What is 3?
'US', // Shipping to or from US?
true, // What is true?
false, // What is false?
2 // What is 2?
);
expect(calculateShipping(order)).toBe(15.99); // Why 15.99?
});// 😱 BAD: Hidden data relationships
test('applies bulk discount', () => {
// Depends on products.json having items with specific IDs
const cart = new Cart();
cart.addItem(101, 5); // Assumes product 101 exists
cart.addItem(102, 3); // Assumes product 102 exists
// Assumes prices in fixture: 101 = $10, 102 = $20
expect(cart.total()).toBe(110); // How did we get 110?
});// ✅ GOOD: Centralized test data creation
class UserMother {
static simple() {
return {
id: generateId(),
email: 'user@example.com',
name: 'Test User',
balance: 0
};
}
static withBalance(amount) {
return {
...this.simple(),
balance: amount
};
}
static premium() {
return {
...this.simple(),
email: 'premium@example.com',
name: 'Premium User',
subscription: 'premium',
balance: 1000
};
}
static suspended() {
return {
...this.simple(),
status: 'suspended',
suspendedAt: new Date()
};
}
}
// Usage
test('premium users get free shipping', () => {
const user = UserMother.premium();
const shipping = calculateShipping(user, standardOrder);
expect(shipping).toBe(0);
});// ✅ GOOD: Flexible, explicit test data
class OrderBuilder {
constructor() {
this.order = {
id: generateId(),
items: [],
shipping: 'standard',
country: 'US',
express: false,
giftWrap: false,
discount: null
};
}
withItems(...items) {
this.order.items = items;
return this;
}
withExpressShipping() {
this.order.shipping = 'express';
this.order.express = true;
return this;
}
toCountry(country) {
this.order.country = country;
return this;
}
withDiscount(code, percentage) {
this.order.discount = { code, percentage };
return this;
}
build() {
return { ...this.order };
}
}
// Usage - Explicit and readable!
test('calculates international express shipping', () => {
const order = new OrderBuilder()
.withItems(
{ name: 'Widget', price: 29.99, quantity: 2 },
{ name: 'Gadget', price: 49.99, quantity: 1 }
)
.toCountry('UK')
.withExpressShipping()
.build();
const shipping = calculateShipping(order);
expect(shipping).toBe(35.00); // Clear what we're testing
});// ✅ GOOD: Simple factories with defaults
function createUser(overrides = {}) {
return {
id: uniqueId(),
email: `test-${Date.now()}@example.com`,
name: 'Test User',
createdAt: new Date(),
verified: true,
...overrides // Explicit overrides last
};
}
function createProduct(overrides = {}) {
return {
id: uniqueId(),
name: 'Test Product',
price: 10.00,
stock: 100,
category: 'general',
...overrides
};
}
// Usage - minimal and clear
test('out of stock products cannot be purchased', () => {
const product = createProduct({ stock: 0 });
const result = purchaseProduct(product, 1);
expect(result.success).toBe(false);
expect(result.error).toBe('Product out of stock');
});// ❌ BAD: Hidden important details
const user = getTestUser();
expect(canPurchaseAlcohol(user)).toBe(true);
// ✅ GOOD: Relevant data is visible
const user = createUser({ age: 21 });
expect(canPurchaseAlcohol(user)).toBe(true);// ❌ BAD: Shared array modified by tests
const sharedItems = [item1, item2, item3];
// ✅ GOOD: Fresh array for each test
function getTestItems() {
return [
createItem({ name: 'Item 1' }),
createItem({ name: 'Item 2' }),
createItem({ name: 'Item 3' })
];
}// ❌ BAD: Same email in every test
email: 'test@example.com'
// ✅ GOOD: Unique but recognizable
email: `test-${testName}-${Date.now()}@example.com`
email: `user-${uuid()}@test.local`// ❌ BAD: Everything including kitchen sink
const user = {
id: 1, email: '...', name: '...',
address: {...}, preferences: {...},
history: [...], social: {...}
// 20 more fields...
};
// ✅ GOOD: Just what we need
const user = {
email: 'test@example.com',
subscriptionStatus: 'active'
};Use random data when:
Use deterministic data when: