mock-data

Mock Data Generation Skill

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "mock-data" with this command: npx skills add sgcarstrends/sgcarstrends/sgcarstrends-sgcarstrends-mock-data

Mock Data Generation Skill

This skill helps you generate realistic mock data for testing, development, and seeding purposes.

When to Use This Skill

  • Creating test fixtures for unit/integration tests

  • Seeding test databases

  • Mocking API responses

  • Generating sample data for development

  • Creating realistic data for E2E tests

  • Populating staging environments

  • Testing edge cases with specific data patterns

Tools & Libraries

Faker.js

Primary library for generating realistic fake data:

Install Faker

pnpm add -D @faker-js/faker

Features:

  • Person data (names, emails, phone numbers)

  • Addresses and locations

  • Dates and times

  • Commerce data (products, prices)

  • Vehicle data

  • Lorem ipsum text

  • Custom locales (including Singapore)

Basic Mock Data Patterns

Simple Factories

// apps/api/tests/factories/car.factory.ts import { faker } from "@faker-js/faker";

export const createMockCar = (overrides = {}) => ({ id: faker.string.uuid(), make: faker.vehicle.manufacturer(), model: faker.vehicle.model(), vehicleType: faker.helpers.arrayElement(["Passenger Car", "Goods Vehicle"]), fuelType: faker.helpers.arrayElement(["Petrol", "Diesel", "Electric", "Hybrid"]), month: faker.date.recent({ days: 365 }).toISOString().slice(0, 7), number: faker.number.int({ min: 1, max: 1000 }), ...overrides, });

// Usage const car = createMockCar({ make: "Toyota", model: "Corolla" });

Factory Functions

// apps/api/tests/factories/index.ts import { faker } from "@faker-js/faker";

export const CarFactory = { build: (overrides = {}) => ({ id: faker.string.uuid(), make: faker.vehicle.manufacturer(), model: faker.vehicle.model(), month: faker.date.recent({ days: 365 }).toISOString().slice(0, 7), number: faker.number.int({ min: 1, max: 1000 }), ...overrides, }),

buildMany: (count: number, overrides = {}) => { return Array.from({ length: count }, () => CarFactory.build(overrides)); },

buildToyota: () => CarFactory.build({ make: "Toyota" }),

buildElectric: () => CarFactory.build({ fuelType: "Electric" }), };

export const COEFactory = { build: (overrides = {}) => ({ id: faker.string.uuid(), month: faker.date.recent({ days: 365 }).toISOString().slice(0, 7), biddingNo: faker.number.int({ min: 1, max: 24 }), vehicleClass: faker.helpers.arrayElement(["A", "B", "C", "D", "E"]), quota: faker.number.int({ min: 100, max: 5000 }), bidsReceived: faker.number.int({ min: 1000, max: 10000 }), premiumAmount: faker.number.int({ min: 50000, max: 150000 }), ...overrides, }),

buildMany: (count: number, overrides = {}) => { return Array.from({ length: count }, () => COEFactory.build(overrides)); },

buildCategoryA: () => COEFactory.build({ vehicleClass: "A" }), };

export const BlogPostFactory = { build: (overrides = {}) => ({ id: faker.string.uuid(), title: faker.lorem.sentence(), slug: faker.helpers.slugify(faker.lorem.sentence()), content: faker.lorem.paragraphs(3), excerpt: faker.lorem.paragraph(), publishedAt: faker.date.recent({ days: 30 }), authorId: faker.string.uuid(), ...overrides, }),

buildMany: (count: number, overrides = {}) => { return Array.from({ length: count }, () => BlogPostFactory.build(overrides)); },

buildPublished: () => BlogPostFactory.build({ publishedAt: faker.date.past(), }),

buildDraft: () => BlogPostFactory.build({ publishedAt: null, }), };

Advanced Factories

Class-Based Factories

// apps/api/tests/factories/base.factory.ts import { faker } from "@faker-js/faker";

export abstract class BaseFactory<T> { abstract build(overrides?: Partial<T>): T;

buildMany(count: number, overrides?: Partial<T>): T[] { return Array.from({ length: count }, () => this.build(overrides)); }

buildList(items: Partial<T>[]): T[] { return items.map((item) => this.build(item)); } }

// Specific factory export class CarFactory extends BaseFactory<Car> { build(overrides: Partial<Car> = {}): Car { return { id: faker.string.uuid(), make: faker.vehicle.manufacturer(), model: faker.vehicle.model(), month: faker.date.recent({ days: 365 }).toISOString().slice(0, 7), number: faker.number.int({ min: 1, max: 1000 }), ...overrides, }; }

buildToyota(): Car { return this.build({ make: "Toyota" }); }

buildWithHighRegistrations(): Car { return this.build({ number: faker.number.int({ min: 500, max: 1000 }) }); } }

// Usage const carFactory = new CarFactory(); const cars = carFactory.buildMany(10); const toyota = carFactory.buildToyota();

Sequence Factories

// apps/api/tests/factories/sequence.ts import { faker } from "@faker-js/faker";

let sequenceCounters: Record<string, number> = {};

export const sequence = (name: string, fn: (n: number) => any) => { if (!sequenceCounters[name]) { sequenceCounters[name] = 0; } sequenceCounters[name]++; return fn(sequenceCounters[name]); };

export const resetSequences = () => { sequenceCounters = {}; };

// Usage export const UserFactory = { build: (overrides = {}) => ({ id: sequence("user", (n) => user-${n}), email: sequence("email", (n) => user${n}@example.com), name: faker.person.fullName(), ...overrides, }), };

// In tests beforeEach(() => { resetSequences(); });

const user1 = UserFactory.build(); // { id: "user-1", email: "user1@example.com" } const user2 = UserFactory.build(); // { id: "user-2", email: "user2@example.com" }

Fixtures

Static Fixtures

// apps/api/tests/fixtures/cars.ts export const toyotaCorollaFixture = { make: "Toyota", model: "Corolla", month: "2024-01", number: 150, };

export const hondaCivicFixture = { make: "Honda", model: "Civic", month: "2024-01", number: 120, };

export const popularCarsFixture = [ toyotaCorollaFixture, hondaCivicFixture, { make: "BMW", model: "3 Series", month: "2024-01", number: 80, }, ];

// Usage in tests import { toyotaCorollaFixture } from "./fixtures/cars";

it("should process Toyota Corolla data", () => { const result = processCarData(toyotaCorollaFixture); expect(result.make).toBe("Toyota"); });

JSON Fixtures

// apps/api/tests/fixtures/cars.json [ { "make": "Toyota", "model": "Corolla", "month": "2024-01", "number": 150 }, { "make": "Honda", "model": "Civic", "month": "2024-01", "number": 120 } ]

// Load in tests import carsFixture from "./fixtures/cars.json";

it("should load fixture data", () => { expect(carsFixture).toHaveLength(2); expect(carsFixture[0].make).toBe("Toyota"); });

Dynamic Fixtures

// apps/api/tests/fixtures/dynamic.ts import { faker } from "@faker-js/faker";

export const generateCarFixtures = (count: number, month: string) => { return Array.from({ length: count }, () => ({ make: faker.vehicle.manufacturer(), model: faker.vehicle.model(), month, number: faker.number.int({ min: 1, max: 500 }), })); };

// Usage const januaryCars = generateCarFixtures(100, "2024-01"); const februaryCars = generateCarFixtures(100, "2024-02");

Singapore-Specific Mock Data

Singapore Locales

// apps/api/tests/factories/singapore.ts import { faker } from "@faker-js/faker"; import { fakerEN_SG } from "@faker-js/faker";

// Use Singapore locale faker.setDefaultLocale("en_SG");

export const SingaporeAddressFactory = { build: () => ({ street: faker.location.street(), postalCode: faker.location.zipCode("######"), // 6-digit postal code country: "Singapore", }), };

export const SingaporePhoneFactory = { build: () => ({ mobile: +65 ${faker.helpers.arrayElement(["8", "9"])}${faker.string.numeric(7)}, home: +65 6${faker.string.numeric(7)}, }), };

// Singapore car makes (popular in Singapore) export const SingaporeCarMakes = [ "Toyota", "Honda", "Mercedes-Benz", "BMW", "Mazda", "Hyundai", "Kia", "Nissan", "Volkswagen", "Audi", ];

export const SingaporeCarFactory = { build: (overrides = {}) => ({ make: faker.helpers.arrayElement(SingaporeCarMakes), model: faker.vehicle.model(), month: faker.date.recent({ days: 365 }).toISOString().slice(0, 7), number: faker.number.int({ min: 1, max: 500 }), ...overrides, }), };

COE Categories

// apps/api/tests/factories/coe.ts export const COECategories = { A: "Cars up to 1600cc & 97kW", B: "Cars above 1600cc or 97kW", C: "Goods Vehicles & Buses", D: "Motorcycles", E: "Open Category", };

export const COEFactory = { build: (overrides = {}) => { const category = faker.helpers.arrayElement(["A", "B", "C", "D", "E"]);

return {
  month: faker.date.recent({ days: 365 }).toISOString().slice(0, 7),
  biddingNo: faker.number.int({ min: 1, max: 24 }),
  vehicleClass: category,
  quota: faker.number.int({ min: 100, max: 5000 }),
  bidsReceived: faker.number.int({ min: 1000, max: 10000 }),
  premiumAmount: faker.number.int({ min: 30000, max: 150000 }),
  ...overrides,
};

},

buildRealistic: () => { const category = faker.helpers.arrayElement(["A", "B"]) as "A" | "B"; const basePrice = category === "A" ? 60000 : 90000;

return COEFactory.build({
  vehicleClass: category,
  premiumAmount: basePrice + faker.number.int({ min: -10000, max: 30000 }),
});

}, };

Database Seeding

Seed Scripts

// apps/api/scripts/seed.ts import { db } from "../src/config/database"; import { cars, coe, posts } from "@sgcarstrends/database/schema"; import { CarFactory, COEFactory, BlogPostFactory } from "../tests/factories";

async function seed() { console.log("Seeding database...");

// Clear existing data await db.delete(cars); await db.delete(coe); await db.delete(posts);

// Seed cars const carData = CarFactory.buildMany(1000); await db.insert(cars).values(carData); console.log("✓ Seeded 1000 cars");

// Seed COE const coeData = COEFactory.buildMany(240); // 24 bidding rounds * 10 months await db.insert(coe).values(coeData); console.log("✓ Seeded 240 COE records");

// Seed blog posts const postData = BlogPostFactory.buildMany(50); await db.insert(posts).values(postData); console.log("✓ Seeded 50 blog posts");

console.log("Seeding complete!"); }

seed().catch(console.error);

Environment-Specific Seeding

// apps/api/scripts/seed-env.ts import { db } from "../src/config/database"; import { CarFactory, COEFactory } from "../tests/factories";

async function seedForEnvironment(env: string) { const counts = { development: { cars: 1000, coe: 240 }, test: { cars: 100, coe: 24 }, staging: { cars: 10000, coe: 1000 }, };

const config = counts[env as keyof typeof counts] || counts.development;

console.log(Seeding ${env} environment...);

await db.insert(cars).values(CarFactory.buildMany(config.cars)); await db.insert(coe).values(COEFactory.buildMany(config.coe));

console.log(✓ Seeded ${config.cars} cars and ${config.coe} COE records); }

const env = process.env.NODE_ENV || "development"; seedForEnvironment(env).catch(console.error);

API Response Mocking

Mock API Responses

// apps/api/tests/mocks/api-responses.ts export const mockLTACarResponse = { records: [ { month: "2024-01", make: "TOYOTA", fuel_type: "Petrol", vehicle_type: "Passenger Car", number: 150, }, { month: "2024-01", make: "HONDA", fuel_type: "Petrol", vehicle_type: "Passenger Car", number: 120, }, ], };

export const mockLTACOEResponse = { records: [ { month: "2024-01", bidding_no: "1", vehicle_class: "A", quota: 1000, bids_received: 5000, premium: 65000, }, ], };

export const mockErrorResponse = { error: { code: "INTERNAL_ERROR", message: "An error occurred", }, };

// Usage in tests import { mockLTACarResponse } from "./mocks/api-responses";

vi.spyOn(global, "fetch").mockResolvedValue({ ok: true, json: async () => mockLTACarResponse, } as Response);

Dynamic Mock Generators

// apps/api/tests/mocks/generators.ts import { faker } from "@faker-js/faker";

export const generateMockLTAResponse = (recordCount: number) => ({ records: Array.from({ length: recordCount }, () => ({ month: faker.date.recent({ days: 365 }).toISOString().slice(0, 7), make: faker.vehicle.manufacturer().toUpperCase(), fuel_type: faker.helpers.arrayElement(["Petrol", "Diesel", "Electric"]), vehicle_type: "Passenger Car", number: faker.number.int({ min: 1, max: 500 }), })), });

// Usage const response = generateMockLTAResponse(100);

Testing with Mock Data

Using Factories in Tests

// apps/api/tests/routes/cars.test.ts import { describe, it, expect, beforeEach } from "vitest"; import { db } from "../../src/config/database"; import { CarFactory } from "../factories"; import app from "../../src/index";

describe("GET /api/v1/cars/makes", () => { beforeEach(async () => { // Seed with factory data const cars = CarFactory.buildMany(100); await db.insert(cars).values(cars); });

it("should return list of makes", async () => { const res = await app.request("/api/v1/cars/makes");

expect(res.status).toBe(200);
expect(await res.json()).toHaveLength(expect.any(Number));

}); });

Using Fixtures in Tests

// apps/api/tests/services/coe.test.ts import { describe, it, expect } from "vitest"; import { calculateCOEPremium } from "../../src/services/coe"; import { mockCOEData } from "../fixtures/coe";

describe("calculateCOEPremium", () => { it("should calculate premium correctly", () => { const result = calculateCOEPremium(mockCOEData);

expect(result).toBeGreaterThan(0);

}); });

Best Practices

  1. Keep Factories Simple

// ❌ Too complex export const ComplexCarFactory = { build: async (overrides = {}) => { const make = await fetchMakeFromDatabase(); // Don't do async operations const model = complexCalculation(make); // Don't do complex logic return { make, model, ...overrides }; }, };

// ✅ Simple and synchronous export const SimpleCarFactory = { build: (overrides = {}) => ({ make: faker.vehicle.manufacturer(), model: faker.vehicle.model(), ...overrides, }), };

  1. Use Realistic Data

// ❌ Unrealistic test data const car = { make: "test", model: "test", number: 99999999 };

// ✅ Realistic test data const car = CarFactory.build({ make: "Toyota", model: "Corolla", number: 150, });

  1. Don't Over-Mock

// ❌ Mocking everything vi.spyOn(db, "insert").mockResolvedValue([]); vi.spyOn(redis, "get").mockResolvedValue(null); vi.spyOn(fetch, "fetch").mockResolvedValue({});

// ✅ Only mock external dependencies vi.spyOn(fetch, "fetch").mockResolvedValue(mockResponse); // Let db and redis work normally in integration tests

  1. Isolate Test Data

// ❌ Shared mutable state const sharedCar = CarFactory.build();

it("test 1", () => { sharedCar.number = 100; // Mutates shared state });

it("test 2", () => { expect(sharedCar.number).toBe(100); // Depends on test 1 });

// ✅ Independent test data it("test 1", () => { const car = CarFactory.build(); car.number = 100; });

it("test 2", () => { const car = CarFactory.build(); expect(car.number).toBeGreaterThan(0); });

Troubleshooting

Faker Generating Same Data

// Issue: Faker generates same data in tests // Solution: Use unique identifiers or sequences

import { sequence } from "./sequence";

const user1 = UserFactory.build(); // Same email const user2 = UserFactory.build(); // Same email

// Fix with sequence export const UserFactory = { build: (overrides = {}) => ({ email: sequence("email", (n) => user${n}@example.com), ...overrides, }), };

Factory Data Not Matching Schema

// Issue: Factory generates invalid data // Solution: Use Zod schema validation in factory

import { z } from "zod";

const carSchema = z.object({ make: z.string().min(1), model: z.string().min(1), month: z.string().regex(/^\d{4}-\d{2}$/), number: z.number().int().min(0), });

export const CarFactory = { build: (overrides = {}) => { const data = { make: faker.vehicle.manufacturer(), model: faker.vehicle.model(), month: faker.date.recent({ days: 365 }).toISOString().slice(0, 7), number: faker.number.int({ min: 1, max: 1000 }), ...overrides, };

return carSchema.parse(data); // Validates before returning

}, };

References

Best Practices Summary

  • Use Factories: Create reusable factory functions for common entities

  • Realistic Data: Generate data that resembles production

  • Fixtures for Static: Use fixtures for known test cases

  • Factories for Dynamic: Use factories for varied test scenarios

  • Isolate Test Data: Each test should have independent data

  • Seed Databases: Use factories to seed dev/test databases

  • Singapore-Specific: Use appropriate locales and realistic values

  • Keep Simple: Factories should be synchronous and straightforward

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

General

framer-motion-animations

No summary provided by upstream source.

Repository SourceNeeds Review
General

shadcn-components

No summary provided by upstream source.

Repository SourceNeeds Review
General

api-testing

No summary provided by upstream source.

Repository SourceNeeds Review
General

design-language-system

No summary provided by upstream source.

Repository SourceNeeds Review