Developer Kit
Test Data Builder
Generates language-native test data factories with edge cases, nulls, extremes, and locale variations for any data model. Useful for building tests that reflect real-world inputs instead of toy fixtures. Engineers writing tests for data-handling code, QA engineers building test harnesses, localization teams ensuring non-English data paths work, security teams adding adversarial input coverage. "John Doe", age 30, email "john@example.com" — that do not reflect real-world data. The bugs that slip past these tests are the ones triggered by long names, unicode, trailing whitespace, empty strings, nulls, extreme numeric values, non-English locales, and adversarial inputs. A structured test data builder produces composable factories that make it easy to express "a typical user" plus "a user with a 200-character name in Japanese" in one line, which is the pattern that actually surfaces bugs before production.
One-Time Purchase
$19.99
Test Data Builder — Order Model
Language: TypeScript · Test framework: Vitest · Factory library: @faker-js/faker v9
📄 src/test/factories/order.factory.ts
/**
* Order Factory
* =============
* Composable test-data builder for the `Order` domain model.
*
* USAGE
* -----
* import { orderFactory } from '@/test/factories/order.factory';
*
* // Single base order (happy path)
* const order = orderFactory.build();
*
* // With a trait
* const pending = orderFactory.build('withPendingStatus');
* const huge = orderFactory.build('withMaxLineItems');
*
* // Override individual fields
* const order = orderFactory.build('withPendingStatus', { customerId: 'cust_abc123' });
*
* // Build a list
* const orders = orderFactory.buildList(5, 'withCompletedStatus');
*
* // Deterministic / reproducible (seed before each test suite)
* import { faker } from '@faker-js/faker';
* beforeEach(() => faker.seed(42));
*
* EXTENDING
* ---------
* Add a new trait by appending to the `traits` map below.
* Trait names must be camelCase and start with "with" or "as".
* Traits are shallow-merged onto the base; deep-merge helper
* `deepMerge()` is provided for nested objects.
*
* CONSTRAINTS RESPECTED
* ---------------------
* - `total` is always ≥ 0 and equals sum(lineItems[].subtotal)
* - `placedAt` is never in the future on the base factory
* - `shippedAt` is always after `placedAt` when present
* - `status` transitions are semantically consistent per trait
*/
import { faker } from '@faker-js/faker';
import type { Order, LineItem, Address } from '@/domain/order';
// ─── helpers ────────────────────────────────────────────────────────────────
function buildLineItem(overrides: Partial<LineItem> = {}): LineItem {
const qty = faker.number.int({ min: 1, max: 10 });
const price = faker.number.float({ min: 0.01, max: 999.99, fractionDigits: 2 });
return {
id: faker.string.uuid(),
productId: `prod_${faker.string.alphanumeric(10)}`,
description: faker.commerce.productName(),
quantity: qty,
unitPrice: price,
subtotal: parseFloat((qty * price).toFixed(2)),
...overrides,
};
}
function buildAddress(overrides: Partial<Address> = {}): Address {
return {
line1: faker.location.streetAddress(),
line2: faker.helpers.maybe(() => faker.location.secondaryAddress()) ?? null,
city: faker.location.city(),
state: faker.location.state({ abbreviated: true }),
postalCode: faker.location.zipCode(),
country: 'US',
...overrides,
};
}
function sumLineItems(items: LineItem[]): number {
return parseFloat(items.reduce((acc, i) => acc + i.subtotal, 0).toFixed(2));
}
// ─── base factory ───────────────────────────────────────────────────────────
function buildBase(overrides: Partial<Order> = {}): Order {
const lineItems = [buildLineItem(), buildLineItem()];
const placedAt = faker.date.recent({ days: 30 });
const shippedAt = faker.date.between({ from: placedAt, to: new Date() });
return {
id: `ord_${faker.string.alphanumeric(12)}`,
customerId: `cust_${faker.string.alphanumeric(10)}`,
status: 'completed',
lineItems,
total: sumLineItems(lineItems),
currency: 'USD',
shippingAddress: buildAddress(),
billingAddress: buildAddress(),
placedAt,
shippedAt,
deliveredAt: faker.date.between({ from: shippedAt, to: new Date() }),
cancelledAt: null,
notes: null,
metadata: {},
schemaVersion: 1,
...overrides,
};
}
// ─── traits ─────────────────────────────────────────────────────────────────
const traits: Record<string, (base: Order) => Partial<Order>> = {
/** Order placed but not yet actioned by fulfillment */
withPendingStatus: () => ({
status: 'pending',
shippedAt: null,
deliveredAt: null,
cancelledAt: null,
}),
/** Payment confirmed; awaiting warehouse pick */
withConfirmedStatus: () => ({
status: 'confirmed',
shippedAt: null,
deliveredAt: null,
cancelledAt: null,
}),
/** Fully delivered — the canonical happy-path end-state */
withCompletedStatus: (base) => ({
status: 'completed',
shippedAt: faker.date.between({ from: base.placedAt, to: new Date() }),
deliveredAt: faker.date.recent({ days: 7 }),
cancelledAt: null,
}),
/** Cancelled before shipment — cancelledAt must be populated */
withCancelledStatus: (base) => ({
status: 'cancelled',
shippedAt: null,
deliveredAt: null,
cancelledAt: faker.date.between({ from: base.placedAt, to: new Date() }),
}),
/** Max schema-allowed line items (stress-tests rendering & subtotal math) */
withMaxLineItems: () => {
const items = Array.from({ length: 100 }, () => buildLineItem());
return { lineItems: items, total: sumLineItems(items) };
},
/** Single line item — minimum viable order */
withSingleLineItem: () => {
const items = [buildLineItem()];
return { lineItems: items, total: sumLineItems(items) };
},
/** Zero-value order — free promotional item, total must be 0 */
withZeroTotal: () => {
const items = [buildLineItem({ unitPrice: 0, subtotal: 0 })];
return { lineItems: items, total: 0 };
},
/** Very old order — exercises date-range filters and archival logic */
withAncientPlacedDate: () => ({
placedAt: new Date('1970-01-02T00:00:00.000Z'),
shippedAt: new Date('1970-01-03T00:00:00.000Z'),
deliveredAt: new Date('1970-01-05T00:00:00.000Z'),
}),
/** Placed moments ago — exercises "just now" display logic */
withRecentPlacedDate: () => ({
placedAt: new Date(Date.now() - 5_000),
shippedAt: null,
deliveredAt: null,
status: 'pending',
cancelledAt: null,
}),
/** Notes field at max schema length (500 chars) */
withMaxLengthNotes: () => ({
notes: 'A'.repeat(500),
}),
/** Unicode in free-text fields — RTL, emoji, combining characters */
withUnicodeNotes: () => ({
notes: '日本語テスト 🛒 \u202Emailto:test\u202C \u0301combining café',
}),
/**
* Adversarial inputs — exercise XSS / SQLi surface area.
* Use on any endpoint that echoes order data back into HTML or raw SQL.
*/
withAdversarialInputs: () => ({
notes: `<script>alert('xss')</script><img src=x onerror=alert(1)>`,
metadata: {
ref: `'; DROP TABLE orders; --`,
callback: `javascript:void(document.cookie)`,
unicode: `\u200Badmin\u200B`, // zero-width spaces around "admin"
overlong: '\xC0\xAF', // overlong UTF-8 slash
},
shippingAddress: buildAddress({
line1: `<svg/onload=alert(1)>`,
city: `Robert'); DROP TABLE cities;--`,
}),
}),
/** Non-US locale — CA postal code, CAD currency */
withCanadianLocale: () => ({
currency: 'CAD',
shippingAddress: buildAddress({
postalCode: faker.helpers.fromRegExp(/[A-Z][0-9][A-Z] [0-9][A-Z][0-9]/),
state: 'ON',
country: 'CA',
}),
}),
};
// ─── public API ─────────────────────────────────────────────────────────────
type TraitName = keyof typeof traits;
export const orderFactory = {
build(trait?: TraitName, overrides: Partial<Order> = {}): Order {
const base = buildBase();
const traitPatch = trait ? traits[trait](base) : {};
return { ...base, ...traitPatch, ...overrides };
},
buildList(count: number, trait?: TraitName, overrides: Partial<Order> = {}): Order[] {
return Array.from({ length: count }, () => this.build(trait, overrides));
},
/** Expose helpers so tests can compose custom addresses/line-items inline */
helpers: { buildLineItem, buildAddress },
};
🧪 Example Usage (matching project's existing test style)
// src/modules/orders/__tests__/order-summary.service.test.ts
import { describe, it, expect, beforeEach } from 'vitest';
import { faker } from '@faker-js/faker';
import { orderFactory } from '@/test/factories/order.factory';
import { OrderSummaryService } from '../order-summary.service';
describe('OrderSummaryService', () => {
beforeEach(() => faker.seed(42)); // deterministic run
it('formats a completed order correctly', () => {
const order = orderFactory.build('withCompletedStatus');
const summary = OrderSummaryService.format(order);
expect(summary.statusLabel).toBe('Delivered');
expect(summary.total).toMatch(/^\$[\d,]+\.\d{2}$/);
});
it('shows no ship date for pending orders', () => {
const order = orderFactory.build('withPendingStatus');
expect(OrderSummaryService.format(order).shippedDate).toBeNull();
});
it('handles 100 line items without truncation', () => {
const order = orderFactory.build('withMaxLineItems');
const summary = OrderSummaryService.format(order);
expect(summary.lineItemCount).toBe(100);
});
it('does not render HTML from adversarial note inputs', () => {
const order = orderFactory.build('withAdversarialInputs');
const html = OrderSummaryService.renderNotesHtml(order.notes!);
expect(html).not.toContain('<script>');
expect(html).not.toContain('onerror=');
});
it('displays CAD currency symbol for Canadian orders', () => {
const order = orderFactory.build('withCanadianLocale');
expect(OrderSummaryService.format(order).currencySymbol).toBe('CA$');
});
});
🗺️ Migration Guide — Replacing Inline Fixtures
Before — brittle inline object repeated across 14 test files:
const mockOrder = {
id: 'ord_test123',
customerId: 'cust_abc',
status: 'completed',
lineItems: [{ id: 'li_1', productId: 'prod_x', quantity: 2, unitPrice: 9.99, subtotal: 19.98 }],
total: 19.98,
currency: 'USD',
// ... 12 more fields hardcoded, shippedAt missing, schema v0
};
After — one line, always schema-valid, readable intent:
const order = orderFactory.build('withCompletedStatus');
Step-by-step migration:
| Step | Action |
|------|--------|
| 1 | Add faker.seed(42) inside beforeEach in every affected suite |
| 2 | Replace full inline objects with orderFactory.build() |
| 3 | Replace status-specific fakes with the matching trait ('withPendingStatus', etc.) |
| 4 | Where a test asserts on a specific field value, pass it as the override argument: orderFactory.build('withCompletedStatus', { customerId: 'cust_abc' }) |
| 5 | Delete the old mockOrder const and any as Order casts masking missing fields |
| 6 | Run vitest --reporter=verbose — all tests should pass; any failures reveal fields the factory exposes that the inline fixture was silently hiding |
Tip: If a test breaks after migration, that's a signal — the inline fixture was masking a real constraint violation. Fix the test logic, not the factory.
View full sample →
All sales final. No refunds on digital products.
Includes support for Claude Code, Codex, and OpenClaw in the same license.
What You Get With This Skill
Generates language-native test data factories with edge cases, nulls, extremes, and locale variations for any data model. Useful for building tests that reflect real-world inputs instead of toy fixtures.
All ClearPoint Nexus Skills Include
- Production-ready workflow packaging for three supported platforms.
- Reusable structure designed for repeatable operator tasks.
- Clear deliverable format, not just raw prompt output.
Related Skills
$19.99
One-time license
$19.99
One-time license
$19.99
One-time license