@corez/mock v0.15.0
@corez/mock
A powerful TypeScript decorator-style mocking library with type-safe mock and spy capabilities.
Features
- 🔒 Fully type-safe API with TypeScript
- 🎭 Class and method decorators support
- 🎪 Multiple mocking patterns (function, class, method)
- 🎲 Built-in faker data generation
- 💾 Smart caching system with instance isolation
- 🔄 Jest-style API support
- 🎯 Getter/Setter mocking support
- 📦 Zero runtime dependencies
- 🔍 Comprehensive error handling
Installation
pnpm add @corez/mockRequirements
- Node.js 16.0.0 or later
- TypeScript 5.0.0 or later
Peer Dependencies
{
"@faker-js/faker": "^8.0.0"
}Imports
The library provides several ways to import its functionality:
// Default import for the main mock instance
import mock from '@corez/mock';
// Named imports for types and decorators
import {
// Decorator
Mock,
// Types
MockedFunction,
MockedObject,
MockedClass,
// Error handling
DecoratorError,
// Configuration
type MockConfig,
type FakerOptions,
} from '@corez/mock';
// Everything is exported from the package root
import * as MockLib from '@corez/mock';Exports Structure
The library exports are organized as follows:
Default Export
mock: The main mock instance with core functionality
Types and Interfaces (from
./types)- Core types:
Constructor,DeepPartial,PromiseOrValue - Mock function types:
MockedFunction,AsyncMockedFunction - Mock object types:
MockedObject,MockedClass - Configuration types:
MockConfig,MockConfigObject,MockOptions - Pattern types:
MockValue,MockMultipleConfig - Faker types:
Faker,FakerOptions - Jest adapter types:
JestMatcherExtensions,JestMockedFunction
- Core types:
Decorators and Errors (from
./decorators)Mock: The main decorator with all its variantsDecoratorError: Error class for decorator-related issues
All exports are available directly from the package root, making it easy to import any combination of functionality you need.
Basic Usage
Class Mocking
The @Mock() decorator can be used to mock an entire class:
interface User {
id: number;
name: string;
}
@Mock()
class UserService {
getUser(id: number): User {
// Original implementation...
return {id, name: 'John'};
}
get userCount(): number {
return this.users.length;
}
}
const service = new UserService();
// All methods and getters are now mocked functions
service.getUser(1);
service.userCount;
// Access mock data with type safety
const getUserMock = service.getUser as MockedFunction<[number], User>;
console.log(getUserMock.mock.calls); // [[1]]Method and Getter Mocking
Individual methods and getters can be mocked:
class UserService {
// Basic method mock
@Mock()
getUser(id: number): User {
return {id, name: 'John'};
}
// Mock with implementation
@Mock(() => ({id: 1, name: 'default'}))
createUser(): User {
return {id: 0, name: ''};
}
// Mock getter
@Mock()
get userCount(): number {
return this.users.length;
}
// Mock async methods
@Mock()
async fetchUsers(): Promise<User[]> {
return [];
}
}Mock Function Usage
import {mock} from '@corez/mock';
// Basic mock function
const simpleMock = mock.function();
// Typed mock function with parameters and return type
const typedMock = mock.function<[name: string, age: number], boolean>();
// Mock with implementation
const implMock = mock.function<[number], number>().mockImplementation(x => x * 2);
// Async mock function
const asyncMock = mock.function<[id: number], Promise<User>>().mockResolvedValue({id: 1, name: 'John'});
// Mock with conditional returns
const conditionalMock = mock.function<[number], string>().mockImplementation(x => (x > 0 ? 'positive' : 'negative'));Controlling Return Values
const fn = mock.function();
// Fixed return value
fn.mockReturnValue(42);
console.log(fn()); // 42
// Return values in sequence
fn.mockReturnValueOnce(1).mockReturnValueOnce(2).mockReturnValue(3);
console.log(fn()); // 1
console.log(fn()); // 2
console.log(fn()); // 3
// Implementation function
fn.mockImplementation((x: number) => x * 2);
console.log(fn(21)); // 42
// Clear mock
fn.mockClear(); // Clears usage data
fn.mockReset(); // Clears usage data and implementations
fn.mockRestore(); // Restores original implementation (if any)Advanced Features
Enhanced Mock Decorators
Mock.with
The Mock.with decorator provides advanced mocking patterns:
class UserService {
// Mock with multiple instances
@Mock.with({type: User, count: 3})
getUsers(): User[] {
return [];
}
// Mock with enum values
@Mock.with({enum: UserStatus})
getUserStatus(): UserStatus {
return UserStatus.Active;
}
// Mock with regex pattern
@Mock.with({pattern: /user_\d+/})
generateUserId(): string {
return '';
}
}Mock.withFaker
The Mock.withFaker decorator integrates with faker.js for realistic test data:
class UserService {
// Basic faker usage
@Mock.withFaker(faker => ({
id: faker.number.int(),
name: faker.person.fullName(),
email: faker.internet.email(),
}))
generateUser(): User {
return new User();
}
// Cached faker values with expiration
@Mock.withFaker(faker => faker.date.future(), {
cached: true,
maxAge: 3600000, // 1 hour cache
})
getNextSchedule(): Date {
return new Date();
}
}Instance Isolation
All mocked classes provide complete isolation between instances:
const service1 = new UserService();
const service2 = new UserService();
// Different mock implementations
(service1.getUser as MockedFunction).mockReturnValue(user1);
(service2.getUser as MockedFunction).mockReturnValue(user2);
// Separate call tracking
service1.getUser(1);
console.log((service1.getUser as MockedFunction).mock.calls.length); // 1
console.log((service2.getUser as MockedFunction).mock.calls.length); // 0
// Isolated cached values
@Mock.withFaker(faker => faker.number.int(), {cached: true})
getRandomNumber(): number {
return 0;
}
const num1 = service1.getRandomNumber(); // Cached for service1
const num2 = service2.getRandomNumber(); // Different value, cached for service2Smart Caching System
The library includes a smart caching system with instance isolation and automatic cleanup:
class UserService {
// Instance-level caching
@Mock.withFaker(faker => faker.number.int(), {cached: true})
getCachedNumber(): number {
return 0;
}
// Custom cache age with automatic cleanup
@Mock.withFaker(faker => faker.date.future(), {
cached: true,
maxAge: 3600000, // 1 hour cache
})
getExpiringDate(): Date {
return new Date();
}
}Mock Patterns
The library supports various advanced mocking patterns:
Regular Expression Pattern
Generate strings matching a regex pattern:
class DataService {
// Direct regex pattern
@Mock.with(/\d{3}-\d{2}-\d{4}/)
getSocialSecurity(): string {
return '';
} // Returns e.g. "123-45-6789"
// Object form with pattern
@Mock.with({pattern: /user_[a-z]{5}\d{3}/})
generateUserId(): string {
return '';
} // Returns e.g. "user_abcde123"
}Smart Caching System
The library includes an advanced caching system with instance isolation:
class UserService {
// Instance-level caching with default expiry (50ms)
@Mock.withFaker(faker => faker.number.int(), {
cached: true,
})
getCachedNumber(): number {
return 0;
}
// Custom cache expiry
@Mock.withFaker(faker => faker.date.future(), {
cached: true,
maxAge: 3600000, // 1 hour cache
})
get nextSchedule(): Date {
return new Date();
}
}
const service1 = new UserService();
const service2 = new UserService();
// Each instance maintains its own cache
service1.getCachedNumber() === service1.getCachedNumber(); // true (within maxAge)
service1.getCachedNumber() !== service2.getCachedNumber(); // true (instance isolation)
// Cache is automatically cleaned up when:
// 1. Cache size limit is reached (default: 100 entries per instance)
// 2. Cache entry expires based on maxAge (default: 50ms)
// 3. Instance is garbage collectedMock Function Behavior
The library provides detailed control over mock function behavior:
class UserService {
@Mock()
getUser(id: number): User {
return {id, name: 'original'};
}
}
const service = new UserService();
const mock = service.getUser as MockedFunction;
// Implementation is reset when changed
mock.mockImplementation(() => ({id: 1, name: 'first'}));
service.getUser(1); // Returns {id: 1, name: 'first'}
mock.mock.calls.length === 1; // true
mock.mockImplementation(() => ({id: 2, name: 'second'}));
mock.mock.calls.length === 0; // true (calls are reset)
// Manual reset
mock.mockReset(); // Clears calls, results, and implementationInstance Isolation
The library provides complete instance isolation for all mock types:
class UserService {
// Method mocks
@Mock()
getUser(): User {
return {id: 0, name: ''};
}
// Getter mocks
@Mock()
get userCount(): number {
return 0;
}
// Faker mocks with caching
@Mock.withFaker(faker => faker.number.int(), {cached: true})
getRandomNumber(): number {
return 0;
}
}
const service1 = new UserService();
const service2 = new UserService();
// Each instance has its own mock state
service1.getUser.mock !== service2.getUser.mock;
service1.userCount.mock !== service2.userCount.mock;
// Each instance has its own cache
service1.getRandomNumber() === service1.getRandomNumber(); // true (same instance)
service1.getRandomNumber() !== service2.getRandomNumber(); // true (different instances)
// Mock implementations are instance-specific
const mock1 = service1.getUser as MockedFunction;
const mock2 = service2.getUser as MockedFunction;
mock1.mockReturnValue({id: 1, name: 'one'});
mock2.mockReturnValue({id: 2, name: 'two'});
service1.getUser().name === 'one'; // true
service2.getUser().name === 'two'; // trueImportant Notes
Decorator Usage
- Decorators support both methods and accessors (getters/setters)
- Pattern-based mocks generate consistent values within instances
- Cached values are instance-specific
- Mock implementations are reset when changed
Caching Behavior
- Default cache size: 100 entries per instance
- Default cache expiry: 50ms
- Instance-specific caching
- Automatic cleanup of expired entries
- Cache keys include instance identity
Error Handling
- Detailed error messages with context
- Type-safe error handling
- Pattern validation for regex and enum patterns
- Implementation validation for class decorators
Type Safety
- Full TypeScript support
- Pattern-specific type checking
- Async function type safety
- Getter/setter type validation
- Instance-specific type checking
API Reference
For detailed API documentation, please visit our API Documentation.
License
MIT
Contributing
Contributions are welcome! Please read our Contributing Guidelines for details on how to submit pull requests, report issues, and contribute to the project.
11 months ago
11 months ago
11 months ago
11 months ago
11 months ago
11 months ago
11 months ago
12 months ago
12 months ago
12 months ago
12 months ago
12 months ago
12 months ago
12 months ago
12 months ago
12 months ago
12 months ago
12 months ago
12 months ago
12 months ago
12 months ago
1 year ago
1 year ago
1 year ago