seed-skills/test-data-generation/SKILL.md
Test data generation and management skill covering Faker.js, factory patterns, builders, database seeding, and test data strategies for reliable test suites.
npx skillsauth add PramodDutta/qaskills Test Data GenerationInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
You are an expert QA engineer specializing in test data generation and management. When the user asks you to create, review, or improve test data strategies, follow these detailed instructions.
tests/
data/
factories/
user.factory.ts
product.factory.ts
order.factory.ts
builders/
user.builder.ts
order.builder.ts
fixtures/
static-data.json
seeders/
db-seeder.ts
api-seeder.ts
generators/
fake-data.ts
credit-card.ts
utils/
data-cleanup.ts
npm install --save-dev @faker-js/faker
import { faker } from '@faker-js/faker';
// Generate consistent data with a seed
faker.seed(12345);
// User data
const user = {
id: faker.string.uuid(),
firstName: faker.person.firstName(),
lastName: faker.person.lastName(),
email: faker.internet.email(),
phone: faker.phone.number(),
avatar: faker.image.avatar(),
address: {
street: faker.location.streetAddress(),
city: faker.location.city(),
state: faker.location.state(),
zip: faker.location.zipCode(),
country: faker.location.country(),
},
company: faker.company.name(),
jobTitle: faker.person.jobTitle(),
bio: faker.lorem.paragraph(),
createdAt: faker.date.past().toISOString(),
};
// Product data
const product = {
id: faker.string.uuid(),
name: faker.commerce.productName(),
description: faker.commerce.productDescription(),
price: parseFloat(faker.commerce.price({ min: 1, max: 1000 })),
category: faker.commerce.department(),
sku: faker.string.alphanumeric(10).toUpperCase(),
inStock: faker.datatype.boolean(),
rating: faker.number.float({ min: 1, max: 5, fractionDigits: 1 }),
imageUrl: faker.image.url(),
};
// Financial data
const transaction = {
id: faker.string.uuid(),
amount: parseFloat(faker.finance.amount({ min: 10, max: 5000 })),
currency: faker.finance.currencyCode(),
accountNumber: faker.finance.accountNumber(),
routingNumber: faker.finance.routingNumber(),
transactionType: faker.helpers.arrayElement(['credit', 'debit', 'transfer']),
date: faker.date.recent({ days: 30 }).toISOString(),
status: faker.helpers.arrayElement(['pending', 'completed', 'failed', 'reversed']),
};
import { faker } from '@faker-js/faker';
import { fakerDE } from '@faker-js/faker';
import { fakerJA } from '@faker-js/faker';
// German locale
const germanUser = {
name: fakerDE.person.fullName(),
address: fakerDE.location.streetAddress(),
phone: fakerDE.phone.number(),
};
// Japanese locale
const japaneseUser = {
name: fakerJA.person.fullName(),
address: fakerJA.location.streetAddress(),
};
// factories/user.factory.ts
import { faker } from '@faker-js/faker';
export interface User {
id: string;
email: string;
firstName: string;
lastName: string;
role: 'admin' | 'user' | 'viewer';
isActive: boolean;
createdAt: string;
}
export interface CreateUserInput {
email: string;
firstName: string;
lastName: string;
password: string;
role?: 'admin' | 'user' | 'viewer';
}
export class UserFactory {
static create(overrides: Partial<User> = {}): User {
return {
id: faker.string.uuid(),
email: faker.internet.email(),
firstName: faker.person.firstName(),
lastName: faker.person.lastName(),
role: 'user',
isActive: true,
createdAt: faker.date.past().toISOString(),
...overrides,
};
}
static createMany(count: number, overrides: Partial<User> = {}): User[] {
return Array.from({ length: count }, () => this.create(overrides));
}
static createInput(overrides: Partial<CreateUserInput> = {}): CreateUserInput {
return {
email: faker.internet.email(),
firstName: faker.person.firstName(),
lastName: faker.person.lastName(),
password: faker.internet.password({ length: 12, memorable: false }),
role: 'user',
...overrides,
};
}
static createAdmin(overrides: Partial<User> = {}): User {
return this.create({ role: 'admin', ...overrides });
}
static createInactive(overrides: Partial<User> = {}): User {
return this.create({ isActive: false, ...overrides });
}
}
import { test, expect } from '@playwright/test';
import { UserFactory } from '../data/factories/user.factory';
test('should create a new user', async ({ request }) => {
const userData = UserFactory.createInput();
const response = await request.post('/api/users', { data: userData });
expect(response.status()).toBe(201);
const body = await response.json();
expect(body.email).toBe(userData.email);
expect(body.firstName).toBe(userData.firstName);
});
test('should list users with pagination', async ({ request }) => {
// Create multiple users
const users = UserFactory.createMany(15);
for (const user of users) {
await request.post('/api/users', {
data: UserFactory.createInput({
email: user.email,
firstName: user.firstName,
}),
});
}
const response = await request.get('/api/users?page=1&pageSize=10');
const body = await response.json();
expect(body.data.length).toBe(10);
expect(body.total).toBeGreaterThanOrEqual(15);
});
// builders/order.builder.ts
import { faker } from '@faker-js/faker';
export interface OrderItem {
productId: string;
name: string;
quantity: number;
price: number;
}
export interface Order {
id: string;
customerId: string;
items: OrderItem[];
status: 'pending' | 'confirmed' | 'shipped' | 'delivered' | 'cancelled';
shippingAddress: {
street: string;
city: string;
state: string;
zip: string;
country: string;
};
totalAmount: number;
createdAt: string;
}
export class OrderBuilder {
private order: Order;
constructor() {
this.order = {
id: faker.string.uuid(),
customerId: faker.string.uuid(),
items: [],
status: 'pending',
shippingAddress: {
street: faker.location.streetAddress(),
city: faker.location.city(),
state: faker.location.state(),
zip: faker.location.zipCode(),
country: 'US',
},
totalAmount: 0,
createdAt: new Date().toISOString(),
};
}
withCustomer(customerId: string): this {
this.order.customerId = customerId;
return this;
}
withItem(item?: Partial<OrderItem>): this {
const newItem: OrderItem = {
productId: item?.productId ?? faker.string.uuid(),
name: item?.name ?? faker.commerce.productName(),
quantity: item?.quantity ?? faker.number.int({ min: 1, max: 5 }),
price: item?.price ?? parseFloat(faker.commerce.price({ min: 5, max: 200 })),
};
this.order.items.push(newItem);
this.order.totalAmount = this.order.items.reduce(
(sum, i) => sum + i.price * i.quantity, 0
);
return this;
}
withItems(count: number): this {
for (let i = 0; i < count; i++) {
this.withItem();
}
return this;
}
withStatus(status: Order['status']): this {
this.order.status = status;
return this;
}
withShippingTo(country: string): this {
this.order.shippingAddress.country = country;
return this;
}
cancelled(): this {
return this.withStatus('cancelled');
}
delivered(): this {
return this.withStatus('delivered');
}
build(): Order {
if (this.order.items.length === 0) {
this.withItem(); // Add at least one item
}
return { ...this.order };
}
}
// Usage in tests
const order = new OrderBuilder()
.withCustomer('customer-123')
.withItem({ name: 'Widget', price: 29.99, quantity: 2 })
.withItem({ name: 'Gadget', price: 49.99, quantity: 1 })
.withShippingTo('US')
.build();
from faker import Faker
fake = Faker()
Faker.seed(42) # For reproducibility
user = {
"id": fake.uuid4(),
"email": fake.email(),
"first_name": fake.first_name(),
"last_name": fake.last_name(),
"phone": fake.phone_number(),
"address": fake.address(),
"company": fake.company(),
"created_at": fake.date_time_this_year().isoformat(),
}
import factory
from faker import Faker
from myapp.models import User, Order
fake = Faker()
class UserFactory(factory.Factory):
class Meta:
model = User
id = factory.LazyFunction(fake.uuid4)
email = factory.LazyFunction(fake.email)
first_name = factory.LazyFunction(fake.first_name)
last_name = factory.LazyFunction(fake.last_name)
role = "user"
is_active = True
class Params:
admin = factory.Trait(role="admin")
inactive = factory.Trait(is_active=False)
# Usage
user = UserFactory()
admin = UserFactory(admin=True)
inactive_users = UserFactory.create_batch(5, inactive=True)
import com.github.javafaker.Faker;
import java.util.Locale;
public class TestDataGenerator {
private static final Faker faker = new Faker(new Locale("en-US"));
public static Map<String, Object> generateUser() {
Map<String, Object> user = new HashMap<>();
user.put("email", faker.internet().emailAddress());
user.put("firstName", faker.name().firstName());
user.put("lastName", faker.name().lastName());
user.put("phone", faker.phoneNumber().cellPhone());
user.put("address", faker.address().fullAddress());
return user;
}
public static Map<String, Object> generateProduct() {
Map<String, Object> product = new HashMap<>();
product.put("name", faker.commerce().productName());
product.put("price", Double.parseDouble(faker.commerce().price()));
product.put("category", faker.commerce().department());
product.put("description", faker.lorem().paragraph());
return product;
}
}
// seeders/db-seeder.ts
import { UserFactory } from '../factories/user.factory';
import { ProductFactory } from '../factories/product.factory';
import { OrderBuilder } from '../builders/order.builder';
import { db } from '../../src/database';
export class DatabaseSeeder {
async seedUsers(count: number = 50): Promise<string[]> {
const users = UserFactory.createMany(count);
const ids: string[] = [];
for (const user of users) {
const result = await db.users.create({ data: user });
ids.push(result.id);
}
return ids;
}
async seedProducts(count: number = 100): Promise<string[]> {
const products = ProductFactory.createMany(count);
const ids: string[] = [];
for (const product of products) {
const result = await db.products.create({ data: product });
ids.push(result.id);
}
return ids;
}
async seedOrders(userIds: string[], productIds: string[], count: number = 200): Promise<void> {
for (let i = 0; i < count; i++) {
const customerId = userIds[Math.floor(Math.random() * userIds.length)];
const order = new OrderBuilder()
.withCustomer(customerId)
.withItems(Math.floor(Math.random() * 5) + 1)
.withStatus(['pending', 'confirmed', 'shipped', 'delivered'][Math.floor(Math.random() * 4)] as any)
.build();
await db.orders.create({ data: order });
}
}
async seedAll(): Promise<void> {
const userIds = await this.seedUsers();
const productIds = await this.seedProducts();
await this.seedOrders(userIds, productIds);
console.log('Database seeded successfully');
}
async cleanup(): Promise<void> {
await db.orders.deleteMany({});
await db.products.deleteMany({});
await db.users.deleteMany({});
console.log('Database cleaned up');
}
}
Generate data within each test. Best for unit and integration tests.
test('should validate email format', () => {
const validEmail = faker.internet.email();
const result = validateEmail(validEmail);
expect(result).toBe(true);
});
Static data loaded from JSON files. Best for snapshot testing and deterministic scenarios.
{
"validUser": {
"email": "[email protected]",
"password": "ValidPass123!",
"name": "Test User"
},
"invalidEmails": ["not-email", "@missing.com", "spaces [email protected]"]
}
Deterministic random data using a fixed seed. Best for reproducible randomized tests.
beforeEach(() => {
faker.seed(Date.now()); // Different seed each run
// OR
faker.seed(42); // Same data every run
});
Create test data via API calls before tests run. Best for E2E tests.
test.beforeAll(async ({ request }) => {
const user = UserFactory.createInput();
await request.post('/api/users', { data: user });
});
"[email protected]" causes conflicts in parallel tests.beforeAll with shared data leads to coupled tests.development
Generate test data from the schemas you already have. Read OpenAPI, JSON Schema, SQL DDL, or TypeScript models and produce deterministic factories, boundary and negative cases, relational datasets with valid foreign keys, cleanup scripts, and PII-safe synthetic data. Production records never leave the machine.
development
Diagnose flaky test failures from Playwright reports, traces, and rerun history. Classify each failure as product, test, environment, data, or unknown with cited evidence and a proposed fix. Never auto-modifies code without opt-in.
tools
Test LLM, RAG, MCP, and agentic systems end to end. Build golden datasets, run deterministic checks and LLM judges, score retrieval, probe prompt injection, verify tool use, and gate CI on thresholds. Orchestrates DeepEval, Ragas, promptfoo, and Langfuse.
development
Analyze a git diff, map affected risks, select the tests that matter, detect coverage gaps on changed lines, run configurable quality gates, and produce a go/no-go release report with cited evidence. Recommends only; never merges or deploys.