DevOps & Security
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
What this is
A composable factory for the Order domain model with 12 traits that exercise the cases inline fixtures usually miss: empty states, max line items, unicode, RTL characters, adversarial XSS/SQLi inputs, ancient dates, "just now" dates, and non-US locales. Seeded for reproducibility (faker.seed(42)) so failing tests give the same output across machines.
Trait families
📄 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.
Adversarial trait — handle with care
The withAdversarialInputs trait deliberately injects XSS, SQLi, and unicode bidi attacks into the fixture. Use it only on tests that exercise output sanitization or input validation; using it on a happy-path test will produce false failures. Never feed an adversarial fixture into a fixture-comparing snapshot test — the snapshot itself becomes a payload carrier.
Determinism gotcha
faker.seed(42) makes runs reproducible, but only if every call to the factory in a test is in the same order. If you call orderFactory.build() inside a describe.each loop and the framework runs them in parallel, the seed is shared and outputs interleave. Either move the seed call inside the loop or pin the test runner to serial mode for that suite.
Generated by the ClearPoint Nexus Test Data Builder skill. Extend with project-specific traits as you find bug classes the existing traits miss.
This sample illustrates the skill's output format. Names, metrics, and operational details are illustrative unless the artifact explicitly analyzes public information.
View full sample →
All sales final. No refunds on digital products.
Includes support for Claude Code, Codex, OpenClaw, and Google Antigravity in the same license.
Also in Testing & QA
Bundle price: $55. Compare this skill with the full workflow bundle or Pro access.
Best for
Engineering teams writing or refreshing test fixtures (unit, integration, end-to-end) who want language-native factory builders with edge cases (nulls, extremes, locales, special characters) rather than a flat block of test data, platform teams standardizing test-data patterns across services, and QA leads catching test-fragility issues that come from inconsistent fixtures across the suite. Most valuable on data models with non-trivial structure (nested objects, optional fields, locale-sensitive fields) where hand-built fixtures consistently miss the edge cases.
Not ideal for
Trivial data models where hand-built fixtures take minutes. Also a poor fit as a substitute for production-like test data; factories produce structurally diverse fixtures but synthetic data still differs from the messiness of real production data.
Included in this purchase
- Claude Code, Codex, OpenClaw, and Google Antigravity skill files.
- Setup guidance for the right adapter in your workspace.
- One-time license for the purchased skill version.
Setup
Plan for a short setup in the repository or workspace where the skill will run. Some coding familiarity helps for implementation-heavy outputs.
Related Skills
$19.99
One-time license
$19.99
One-time license
$19.99
One-time license
Future Updates
This purchase includes the current version of the skill. If you want future adapter updates — meaning compatibility and packaging updates as supported platforms evolve — plus new catalog additions included automatically, upgrade to Pro.