Skip to main content

Mock Data Generator

Generic mock data generation utility with support for nested data structures and hierarchical relationships for the WorkPayCore frontend application.

Core Function

generateData<TData>(options)

Generates an array of mock data objects with optional nested structure support.

Parameters:

  • count (number): Number of data objects to generate
  • generatorFunc (function): Function that generates a single data object
  • depth? (number, optional): Maximum depth for nested data (default: 0)
  • subRowKey? (keyof TData, optional): Key under which nested data will be stored

Returns:

  • TData[]: Array of generated data objects

Example:

import { generateData } from '@/utils/generateMockData';

// Simple user generator function
const generateUser = () => ({
id: Math.floor(Math.random() * 1000),
name: `User ${Math.floor(Math.random() * 100)}`,
email: `user${Math.floor(Math.random() * 100)}@example.com`,
active: Math.random() > 0.5,
});

// Generate 5 users
const users = generateData({
count: 5,
generatorFunc: generateUser,
});

console.log(users);
// Returns: [
// { id: 123, name: 'User 45', email: 'user45@example.com', active: true },
// { id: 456, name: 'User 78', email: 'user78@example.com', active: false },
// // ... 3 more users
// ]

Use Cases:

  • Creating test data for components
  • Generating table mock data
  • Building demo datasets
  • Development and testing scenarios

Nested Data Generation

Hierarchical Data Structure

Create nested data structures with parent-child relationships.

Example:

import { generateData } from '@/utils/generateMockData';

interface Department {
id: number;
name: string;
employees?: Employee[];
}

interface Employee {
id: number;
name: string;
role: string;
}

const generateEmployee = (): Employee => ({
id: Math.floor(Math.random() * 1000),
name: `Employee ${Math.floor(Math.random() * 100)}`,
role: ['Developer', 'Designer', 'Manager'][Math.floor(Math.random() * 3)],
});

const generateDepartment = (): Department => ({
id: Math.floor(Math.random() * 100),
name: ['Engineering', 'Design', 'Marketing', 'Sales'][
Math.floor(Math.random() * 4)
],
});

// Generate departments with nested employees
const departmentsWithEmployees = generateData&lt;Department&gt;({
count: 3,
generatorFunc: generateDepartment,
depth: 2, // Generate 2 levels deep
subRowKey: 'employees',
});

console.log(departmentsWithEmployees);
// Returns departments with nested employee arrays

Use Cases:

  • Organizational charts
  • File system structures
  • Category hierarchies
  • Complex table data with expandable rows

Advanced Usage Examples

Table Data Generation

import { generateData } from '@/utils/generateMockData';

interface TableRow {
id: string;
firstName: string;
lastName: string;
email: string;
department: string;
salary: number;
startDate: string;
status: 'Active' | 'Inactive';
}

const generateTableRow = (): TableRow => {
const firstNames = ['John', 'Jane', 'Mike', 'Sarah', 'David', 'Emma'];
const lastNames = ['Smith', 'Johnson', 'Brown', 'Davis', 'Wilson', 'Taylor'];
const departments = ['Engineering', 'Marketing', 'Sales', 'HR', 'Finance'];

return {
id: `EMP${Math.floor(Math.random() * 10000)
.toString()
.padStart(4, '0')}`,
firstName: firstNames[Math.floor(Math.random() * firstNames.length)],
lastName: lastNames[Math.floor(Math.random() * lastNames.length)],
email: `user${Math.floor(Math.random() * 1000)}@company.com`,
department: departments[Math.floor(Math.random() * departments.length)],
salary: Math.floor(Math.random() * 100000) + 30000,
startDate: new Date(
2020 + Math.floor(Math.random() * 4),
Math.floor(Math.random() * 12),
Math.floor(Math.random() * 28) + 1,
)
.toISOString()
.split('T')[0],
status: Math.random() > 0.1 ? 'Active' : 'Inactive',
};
};

// Generate employee table data
const employeeTableData = generateData({
count: 50,
generatorFunc: generateTableRow,
});

// Use in React component
const EmployeeTable = () => {
const [data, setData] = useState(() => employeeTableData);

return (
<table>
<thead>
<tr>
<th>ID</th>
<th>Name</th>
<th>Email</th>
<th>Department</th>
<th>Salary</th>
<th>Start Date</th>
<th>Status</th>
</tr>
</thead>
<tbody>
{data.map(row => (
<tr key={row.id}>
<td>{row.id}</td>
<td>
{row.firstName} {row.lastName}
</td>
<td>{row.email}</td>
<td>{row.department}</td>
<td>${row.salary.toLocaleString()}</td>
<td>{row.startDate}</td>
<td>{row.status}</td>
</tr>
))}
</tbody>
</table>
);
};

Financial Data Generation

interface Transaction {
id: string;
amount: number;
type: 'credit' | 'debit';
description: string;
date: string;
category: string;
}

const generateTransaction = (): Transaction => {
const types: Array<'credit' | 'debit'> = ['credit', 'debit'];
const categories = ['Salary', 'Expense', 'Bonus', 'Refund', 'Purchase'];
const descriptions = [
'Monthly salary payment',
'Office supplies',
'Performance bonus',
'Vendor refund',
'Equipment purchase',
];

return {
id: `TXN${Date.now()}${Math.floor(Math.random() * 1000)}`,
amount: Math.floor(Math.random() * 5000) + 100,
type: types[Math.floor(Math.random() * types.length)],
description: descriptions[Math.floor(Math.random() * descriptions.length)],
date: new Date(
Date.now() - Math.floor(Math.random() * 90 * 24 * 60 * 60 * 1000),
)
.toISOString()
.split('T')[0],
category: categories[Math.floor(Math.random() * categories.length)],
};
};

// Generate transaction history
const transactionHistory = generateData({
count: 25,
generatorFunc: generateTransaction,
});

Tree Structure Generation

interface TreeNode {
id: string;
label: string;
type: 'folder' | 'file';
children?: TreeNode[];
}

const generateFileSystemNode = (): TreeNode => {
const folders = ['Documents', 'Images', 'Downloads', 'Projects', 'Archive'];
const files = [
'report.pdf',
'image.jpg',
'data.xlsx',
'code.js',
'readme.txt',
];

const isFolder = Math.random() > 0.6;

return {
id: `node_${Math.random().toString(36).substr(2, 9)}`,
label: isFolder
? folders[Math.floor(Math.random() * folders.length)]
: files[Math.floor(Math.random() * files.length)],
type: isFolder ? 'folder' : 'file',
};
};

// Generate file system tree
const fileSystemTree = generateData&lt;TreeNode&gt;({
count: 5,
generatorFunc: generateFileSystemNode,
depth: 3,
subRowKey: 'children',
});

Time Series Data

interface DataPoint {
timestamp: string;
value: number;
category: string;
}

const generateTimeSeriesData = (days: number = 30) => {
const categories = ['Revenue', 'Expenses', 'Profit'];
const data: DataPoint[] = [];

for (let i = 0; i < days; i++) {
categories.forEach(category => {
const date = new Date();
date.setDate(date.getDate() - i);

data.push({
timestamp: date.toISOString().split('T')[0],
value: Math.floor(Math.random() * 10000) + 1000,
category,
});
});
}

return data;
};

// Generate 30 days of financial data
const chartData = generateTimeSeriesData(30);

Component Integration

React Hook for Mock Data

import { useState, useEffect } from 'react';
import { generateData } from '@/utils/generateMockData';

interface UseMockDataOptions&lt;T&gt; {
count: number;
generatorFunc: () => T;
depth?: number;
subRowKey?: keyof T;
refreshInterval?: number;
}

const useMockData = &lt;T&gt;({
count,
generatorFunc,
depth = 0,
subRowKey,
refreshInterval,
}: UseMockDataOptions&lt;T&gt;) => {
const [data, setData] = useState<T[]>(() =>
generateData({ count, generatorFunc, depth, subRowKey })
);

const refreshData = () => {
setData(generateData({ count, generatorFunc, depth, subRowKey }));
};

useEffect(() => {
if (refreshInterval) {
const interval = setInterval(refreshData, refreshInterval);
return () => clearInterval(interval);
}
}, [refreshInterval]);

return { data, refreshData };
};

// Usage in component
const DashboardMetrics = () => {
const { data, refreshData } = useMockData({
count: 10,
generatorFunc: generateMetric,
refreshInterval: 5000, // Refresh every 5 seconds
});

return (
<div>
<button onClick={refreshData}>Refresh Data</button>
{data.map(metric => (
<MetricCard key={metric.id} metric={metric} />
))}
</div>
);
};

Loading States with Mock Data

const useAsyncMockData = &lt;T,&gt;(options: UseMockDataOptions&lt;T&gt;) => {
const [data, setData] = useState<T[]>([]);
const [loading, setLoading] = useState(true);

useEffect(() => {
const loadData = async () => {
setLoading(true);

// Simulate API delay
await new Promise(resolve => setTimeout(resolve, 1000));

const mockData = generateData(options);
setData(mockData);
setLoading(false);
};

loadData();
}, []);

return { data, loading };
};

Testing Utilities

Test Data Factories

import { generateData } from '@/utils/generateMockData';

export const createMockUsers = (count: number = 5) =>
generateData({
count,
generatorFunc: () => ({
id: Math.random().toString(36),
name: 'Test User',
email: 'test@example.com',
role: 'user',
}),
});

export const createMockDepartments = (count: number = 3) =>
generateData({
count,
generatorFunc: () => ({
id: Math.random().toString(36),
name: 'Test Department',
description: 'Test department description',
}),
depth: 1,
subRowKey: 'employees',
});

// Use in tests
describe('UserTable', () => {
it('should render users correctly', () => {
const mockUsers = createMockUsers(10);
render(<UserTable users={mockUsers} />);

expect(screen.getAllByRole('row')).toHaveLength(11); // 10 + header
});
});

Performance Considerations

Large Dataset Generation

// For large datasets, consider chunked generation
const generateLargeDataset = &lt;T,&gt;(
totalCount: number,
chunkSize: number,
generatorFunc: () => T,
): T[] => {
const result: T[] = [];

for (let i = 0; i < totalCount; i += chunkSize) {
const currentChunkSize = Math.min(chunkSize, totalCount - i);
const chunk = generateData({
count: currentChunkSize,
generatorFunc,
});
result.push(...chunk);
}

return result;
};

// Generate 10,000 records in chunks of 1,000
const largeDataset = generateLargeDataset(10000, 1000, generateUser);

Memory Management

// Use generators for memory-efficient large datasets
function* generateDataStream&lt;T&gt;(
count: number,
generatorFunc: () => T,
): Generator<T, void, unknown> {
for (let i = 0; i < count; i++) {
yield generatorFunc();
}
}

// Usage with streaming
const dataStream = generateDataStream(1000000, generateUser);

// Process in chunks
for (const user of dataStream) {
// Process one user at a time
processUser(user);
}

Error Handling

The generateData function includes validation:

// Throws error for invalid count
generateData({
count: -1, // Error: `count` must be a positive integer
generatorFunc: generateUser,
});

// Throws error for invalid depth
generateData({
count: 5,
generatorFunc: generateUser,
depth: -1, // Error: `depth` must be a non-negative integer
});

Best Practices

  1. Keep generators simple: Focus on single responsibility
  2. Use realistic data: Make mock data representative of real data
  3. Consider performance: Use chunking for large datasets
  4. Type safety: Always use TypeScript interfaces
  5. Deterministic seeds: Use fixed seeds for reproducible tests
  6. Memory management: Be cautious with very large datasets


TypeScript Definitions

interface TGenerateData&lt;TData&gt; {
count: number;
generatorFunc: () => TData;
depth?: number;
subRowKey?: keyof TData;
}

export function generateData<
TData extends Record<string, unknown> = Record<string, unknown>,
>(options: TGenerateData&lt;TData&gt;): TData[];

Dependencies

  • TypeScript: For type safety and generics
  • Array methods: For data generation and manipulation