@type_sync/testing
v0.1.2
Published
Testing utilities for TypeSync - mock generation and type-safe test client
Maintainers
Readme
@typesync/testing
Testing utilities for TypeSync - mock data generation and type-safe test client.
Features
- 🎭 Mock Generation - Generate realistic mock data from Zod schemas
- 🧪 Test Client - Type-safe HTTP client for testing APIs
- ✅ Assertions - Custom assertions for API testing
- 🔄 Reproducible - Seeded random generation for consistent tests
Installation
pnpm add -D @typesync/testingMock Generation
Generate realistic test data from your Zod schemas:
import { generateMock, generateMocks } from '@typesync/testing';
import { z } from 'zod';
const UserSchema = z.object({
id: z.string().uuid(),
name: z.string(),
email: z.string().email(),
age: z.number().min(18).max(100),
});
// Generate a single mock
const mockUser = generateMock(UserSchema);
// { id: '123e4567-...', name: 'John Doe', email: '[email protected]', age: 25 }
// Generate multiple mocks
const mockUsers = generateMocks(UserSchema, 10);Custom Values
Override specific fields:
const mockUser = generateMock(UserSchema, {
overrides: {
name: 'Alice Smith',
email: '[email protected]',
},
});Custom Generators
Provide custom generators for specific fields:
const mockUser = generateMock(UserSchema, {
generators: {
id: () => 'custom-id-123',
age: () => Math.floor(Math.random() * 50) + 18,
},
});Reproducible Mocks
Use a seed for reproducible test data:
const mockUser1 = generateMock(UserSchema, { seed: 12345 });
const mockUser2 = generateMock(UserSchema, { seed: 12345 });
// mockUser1 and mockUser2 are identicalTest Client
Type-safe HTTP client for testing your APIs:
import { createTestClient } from '@typesync/testing';
const client = createTestClient({
baseURL: 'http://localhost:3000',
});
// Make requests
const response = await client.get('/users');
const user = await client.post('/users', {
name: 'John Doe',
email: '[email protected]',
});
// With params and query
const user = await client.get('/users/:id', {
params: { id: '123' },
query: { include: 'posts' },
});
// With headers
const response = await client.get('/protected', {
headers: { Authorization: 'Bearer token' },
});
// Or use setAuth helper
client.setAuth('your-token');
const response = await client.get('/protected');Test Response
Every response includes:
interface TestResponse<T> {
status: number; // HTTP status code
statusText: string; // Status text
headers: Headers; // Response headers
data: T; // Parsed response data
raw: Response; // Raw fetch Response
}Assertions
Custom assertions for API testing:
import { expect, assertStatus, assertSchema } from '@typesync/testing';
// Assert status code
assertStatus(response, 200);
// Assert successful response (2xx)
assertSuccess(response);
// Assert error response (4xx or 5xx)
assertError(response);
// Assert response matches schema
assertSchema(response, UserSchema);
// Assert response has property
assertHasProperty(response, 'id');
// Assert response header
assertHeader(response, 'Content-Type', 'application/json');
// Assert cached response
assertCached(response);
// Assert validation errors
assertValidationError(response, {
email: 'Invalid email',
age: 'must be greater than or equal to 18',
});Using with Test Frameworks
With Vitest:
import { describe, it, expect as vitestExpect } from 'vitest';
import { createTestClient, assertStatus, assertSchema } from '@typesync/testing';
describe('User API', () => {
const client = createTestClient();
it('should create a user', async () => {
const response = await client.post('/users', {
name: 'John Doe',
email: '[email protected]',
});
assertStatus(response, 201);
assertSchema(response, UserSchema);
vitestExpect(response.data.name).toBe('John Doe');
});
});With Jest:
import { createTestClient, assertStatus } from '@typesync/testing';
describe('User API', () => {
const client = createTestClient();
test('should get users', async () => {
const response = await client.get('/users');
assertStatus(response, 200);
expect(Array.isArray(response.data)).toBe(true);
});
});Complete Example
import { describe, it, expect } from 'vitest';
import {
createTestClient,
generateMock,
assertStatus,
assertSchema,
assertValidationError,
} from '@typesync/testing';
import { z } from 'zod';
const UserSchema = z.object({
id: z.string(),
name: z.string().min(2),
email: z.string().email(),
age: z.number().min(18),
});
describe('User API', () => {
const client = createTestClient({
baseURL: 'http://localhost:3000',
});
it('should create a user with valid data', async () => {
const mockUser = generateMock(UserSchema, {
overrides: { id: undefined }, // Don't send ID
});
const response = await client.post('/users', mockUser);
assertStatus(response, 201);
assertSchema(response, UserSchema);
expect(response.data.name).toBe(mockUser.name);
});
it('should reject invalid email', async () => {
const response = await client.post('/users', {
name: 'John',
email: 'invalid-email',
age: 25,
});
assertValidationError(response, {
email: 'Invalid email',
});
});
it('should reject age under 18', async () => {
const response = await client.post('/users', {
name: 'John',
email: '[email protected]',
age: 15,
});
assertValidationError(response, {
age: 'greater than or equal to 18',
});
});
it('should get user by ID', async () => {
// Create user first
const mockUser = generateMock(UserSchema);
const createResponse = await client.post('/users', mockUser);
// Get user
const response = await client.get('/users/:id', {
params: { id: createResponse.data.id },
});
assertStatus(response, 200);
assertSchema(response, UserSchema);
expect(response.data.id).toBe(createResponse.data.id);
});
it('should cache GET requests', async () => {
const response1 = await client.get('/users');
assertStatus(response1, 200);
const response2 = await client.get('/users');
assertCached(response2);
});
});API Reference
Mock Generation
generateMock<T>(schema, options?)- Generate a single mockgenerateMocks<T>(schema, count, options?)- Generate multiple mockscreateMockGenerator(options)- Create a mock generator with preset options
Test Client
createTestClient(options)- Create a test clientclient.get(path, options)- GET requestclient.post(path, body, options)- POST requestclient.put(path, body, options)- PUT requestclient.patch(path, body, options)- PATCH requestclient.delete(path, options)- DELETE requestclient.setAuth(token, type?)- Set authorization headerclient.setHeader(key, value)- Set header
Assertions
assertStatus(response, expected)- Assert status codeassertSuccess(response)- Assert 2xx statusassertError(response)- Assert 4xx/5xx statusassertSchema(response, schema)- Assert data matches schemaassertHasProperty(response, property)- Assert property existsassertHeader(response, header, value?)- Assert headerassertCached(response)- Assert X-Cache: HITassertNotCached(response)- Assert X-Cache: MISSassertEqual(actual, expected)- Deep equalityassertValidationError(response, fields)- Assert validation errors
License
MIT
