Hone logo
Hone
Problems

Jest Test Data Generation Utility

Creating robust and maintainable tests is crucial for any software project. A common challenge is managing the generation of diverse and realistic test data. This challenge focuses on building a reusable utility in TypeScript for generating various types of test data using Jest.

Problem Description

Your task is to create a TypeScript module that provides functions to generate different kinds of test data. This utility should be designed to be easily integrated into Jest test suites, making it simpler to create mock objects, arrays of objects, and other data structures for testing purposes. The goal is to reduce boilerplate code in tests and improve their readability and maintainability.

Key Requirements

  1. Object Generation: A function to generate a single object with specified properties, allowing for primitive types, arrays, and nested objects.
  2. Array Generation: A function to generate an array of objects, where each object conforms to a given structure.
  3. Randomization: The generators should have options for introducing randomness in values where applicable (e.g., random numbers, randomly chosen strings from a list).
  4. Customization: The generators should be highly customizable, allowing users to define specific values, ranges for numbers, or selection pools for strings.
  5. Type Safety: Leverage TypeScript to ensure type safety for the generated data and the generator configurations.

Expected Behavior

The utility should export functions that can be imported and used directly within Jest test files. For example, you might have a generateObject function and a generateArray function.

Edge Cases to Consider

  • Generating empty arrays.
  • Generating objects with optional properties.
  • Handling circular references (though for this challenge, we can assume no circular references in the input structure).
  • Generating data with specific seeding for reproducibility (optional, but good to consider for advanced scenarios).

Examples

Example 1: Generating a Single User Object

Let's say we want to generate a user object with a name, age, and a list of hobbies.

// Assume `dataGenerators` is your module
import { generateObject } from './dataGenerators';

const userSchema = {
  id: 'uuid', // Placeholder for a UUID generation logic
  name: 'string',
  age: { type: 'number', min: 18, max: 99 },
  isActive: 'boolean',
  hobbies: ['string'], // Represents an array of strings
  address: {
    street: 'string',
    city: 'string',
    zipCode: 'string',
  },
};

const generatedUser = generateObject(userSchema);

// Example `generatedUser` output:
/*
{
  id: 'some-generated-uuid',
  name: 'Alice Smith',
  age: 35,
  isActive: true,
  hobbies: ['reading', 'hiking'],
  address: {
    street: '123 Main St',
    city: 'Anytown',
    zipCode: '12345',
  }
}
*/

Example 2: Generating an Array of Products

We need to generate a list of 5 products, each with a name, price, and category.

import { generateArray } from './dataGenerators';

const productSchema = {
  id: 'number', // Simple number sequence for ID
  name: { type: 'string', choices: ['Laptop', 'Keyboard', 'Mouse', 'Monitor'] },
  price: { type: 'number', min: 50, max: 1500, decimals: 2 },
  category: { type: 'string', choices: ['Electronics', 'Accessories'] },
};

const generatedProducts = generateArray(productSchema, 5);

// Example `generatedProducts` output (an array of 5 product objects):
/*
[
  { id: 1, name: 'Laptop', price: 1200.50, category: 'Electronics' },
  { id: 2, name: 'Keyboard', price: 75.00, category: 'Accessories' },
  { id: 3, name: 'Monitor', price: 300.99, category: 'Electronics' },
  { id: 4, name: 'Mouse', price: 25.99, category: 'Accessories' },
  { id: 5, name: 'Laptop', price: 999.00, category: 'Electronics' },
]
*/

Example 3: Generating Data with Specific Constraints

Generating a list of 3 orders, where each order has a unique ID and a status that can only be 'Pending' or 'Shipped'.

import { generateArray } from './dataGenerators';

const orderSchema = {
  orderId: 'string', // You'd implement string generation, perhaps UUIDs
  status: { type: 'string', choices: ['Pending', 'Shipped'] },
  quantity: { type: 'number', min: 1, max: 10 },
};

const generatedOrders = generateArray(orderSchema, 3);

// Example `generatedOrders` output:
/*
[
  { orderId: 'abc-123', status: 'Pending', quantity: 5 },
  { orderId: 'def-456', status: 'Shipped', quantity: 2 },
  { orderId: 'ghi-789', status: 'Pending', quantity: 8 },
]
*/

Constraints

  • The generateObject function should accept a schema object.
  • The generateArray function should accept a schema object and a count (number of items to generate).
  • The schema definition language should be flexible enough to define:
    • Primitive types: string, number, boolean.
    • Arrays of primitives: ['string'], ['number'], etc.
    • Nested objects: An object within the schema definition.
    • Specific values or choices: Using { type: 'string', choices: [...] }.
    • Numeric ranges: Using { type: 'number', min: ..., max: ... }.
    • Number of decimal places for floats: { type: 'number', decimals: ... }.
  • The generators should handle basic type coercion where sensible (e.g., if id: 'number' is specified, ensure it's a number type).
  • The implementation should be in TypeScript.

Notes

  • Think about how to represent different data types and their configurations within the schema object.
  • Consider using existing libraries for specific types of generation if allowed (e.g., faker-js for more advanced string/number generation), or implement simpler versions yourself. For this challenge, focus on the utility's structure and integration with Jest.
  • The "uuid" in Example 1 is a placeholder. You can choose to implement a basic string generator or simply use a placeholder string for id if full UUID generation is out of scope for your chosen implementation.
  • Your solution should export functions that are testable with Jest. Aim for clear, concise functions that take a schema and return generated data.
Loading editor...
typescript