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 generategeneratorFunc(function): Function that generates a single data objectdepth?(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<Department>({
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<TreeNode>({
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<T> {
count: number;
generatorFunc: () => T;
depth?: number;
subRowKey?: keyof T;
refreshInterval?: number;
}
const useMockData = <T>({
count,
generatorFunc,
depth = 0,
subRowKey,
refreshInterval,
}: UseMockDataOptions<T>) => {
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 = <T,>(options: UseMockDataOptions<T>) => {
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 = <T,>(
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<T>(
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
- Keep generators simple: Focus on single responsibility
- Use realistic data: Make mock data representative of real data
- Consider performance: Use chunking for large datasets
- Type safety: Always use TypeScript interfaces
- Deterministic seeds: Use fixed seeds for reproducible tests
- Memory management: Be cautious with very large datasets
Related Utilities
- Object & Array Utilities - For data manipulation
- String Utilities - For generating text content
- Number Utilities - For generating numeric data
TypeScript Definitions
interface TGenerateData<TData> {
count: number;
generatorFunc: () => TData;
depth?: number;
subRowKey?: keyof TData;
}
export function generateData<
TData extends Record<string, unknown> = Record<string, unknown>,
>(options: TGenerateData<TData>): TData[];
Dependencies
- TypeScript: For type safety and generics
- Array methods: For data generation and manipulation