New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

@corez/mock

Package Overview
Dependencies
Maintainers
0
Versions
24
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@corez/mock

A powerful and flexible TypeScript mocking library for testing

  • 0.2.2
  • Source
  • npm
  • Socket score

Version published
Weekly downloads
12
increased by33.33%
Maintainers
0
Weekly downloads
 
Created
Source

@corez/mock

A powerful and flexible TypeScript mocking library for testing.

npm version License: Apache-2.0 Node Version pnpm

Table of Contents

Core Concepts

What is Mocking?

Mocking is a technique used in unit testing to isolate the code being tested by replacing dependencies with controlled test doubles. This library provides three main types of test doubles:

  1. Mocks: Complete replacements for dependencies

    • Full control over behavior
    • Verification capabilities
    • Type-safe implementations
  2. Spies: Wrappers around existing functions

    • Track method calls
    • Preserve original behavior
    • Add verification capabilities
  3. Stubs: Simple implementations

    • Return predefined values
    • No verification needed
    • Minimal implementation

Type Safety

The library is built with TypeScript first in mind:

interface UserService {
  getUser(id: number): Promise<User>;
  updateUser(id: number, data: Partial<User>): Promise<void>;
}

const mockService = mock<UserService>();

// ✅ Valid - matches interface
mockService.getUser.mockResolvedValue({id: 1, name: 'User'});

// ❌ Type Error - wrong parameter type
mockService.getUser.mockImplementation((id: string) => Promise.resolve({id: 1}));

// ❌ Type Error - missing required property
mockService.getUser.mockResolvedValue({id: 1});

Key type safety features:

  • Full interface compliance
  • Parameter type checking
  • Return type validation
  • Generic type support
  • Strict null checks
  • Method signature matching

Framework Integration

Works seamlessly with popular testing frameworks:

// Jest
describe('UserService', () => {
  let mockService: jest.Mocked<UserService>;

  beforeEach(() => {
    mockService = mock<UserService>();
  });

  it('should mock async methods', async () => {
    mockService.getUser.mockResolvedValue({id: 1, name: 'Test'});
    const result = await mockService.getUser(1);
    expect(result.name).toBe('Test');
  });
});

// Jasmine
describe('UserService', () => {
  let mockService: jasmine.SpyObj<UserService>;

  beforeEach(() => {
    mockService = mock<UserService>();
  });

  it('should track calls', () => {
    mockService.getUser(1);
    expect(mockService.getUser).toHaveBeenCalledWith(1);
  });
});

Installation

# Using npm
npm install @corez/mock --save-dev

# Using yarn
yarn add -D @corez/mock

# Using pnpm (recommended)
pnpm add -D @corez/mock

API Reference

Core Functions

mock()

The primary function that intelligently determines how to create mocks based on the input type:

// Function signatures
function mock<T>(): T; // Create from interface
function mock<T>(target: Class<T>): T; // Create from class
function mock<T>(target: T): T; // Create from object
function mock<T>(target?: T, options?: MockOptions<T>): T; // Create with options

interface MockOptions<T> {
  selective?: boolean; // Only mock specified methods
  preserveThis?: boolean; // Maintain original 'this' context
  handleCircular?: boolean; // Handle circular references
  implementation?: DeepPartial<T>; // Default implementations
  debug?: boolean; // Enable debug logging
  trackCalls?: boolean; // Track method calls
  preservePrototype?: boolean; // Preserve prototype chain
}

// Examples:
// 1. Mock from interface
interface UserService {
  getUser(id: number): Promise<User>;
  updateUser(user: User): Promise<void>;
}

const mockService = mock<UserService>();
mockService.getUser.mockResolvedValue({id: 1, name: 'Mock'});
mockService.updateUser.mockResolvedValue();

// 2. Mock from class
class DataService {
  private data = new Map<string, any>();

  async getData(id: string) {
    return this.data.get(id);
  }
}

const mockDataService = mock(DataService);
mockDataService.getData.mockResolvedValue({id: '1', data: 'mock'});

// 3. Mock from object
const realService = {
  calculate: (x: number, y: number) => x + y,
  config: {timeout: 1000},
};

const mockService = mock(realService);
mockService.calculate.mockReturnValue(42);
mockService.config.timeout = 2000;

// 4. Mock with options
const mockWithOptions = mock<UserService>({
  selective: true,
  preserveThis: true,
  implementation: {
    getUser: async id => ({id, name: 'Mock'}),
  },
});

Key features:

  • Intelligent type inference
  • Full TypeScript support
  • Automatic spy creation
  • Property tracking
  • Method call monitoring
  • Framework compatibility (Jest/Jasmine)
  • Chainable API support
mock.object()

Creates a fully mocked object where all properties and methods are spies:

// Function signature
function object<T extends object>(): T;

// Examples:
interface Service {
  getData(): Promise<string>;
  processValue(value: string): string;
  config: {
    timeout: number;
    retries: number;
  };
}

const mockService = mock.object<Service>();

// Mock methods
mockService.getData.mockResolvedValue('test data');
mockService.processValue.mockImplementation(value => `processed-${value}`);

// Set properties
mockService.config = {
  timeout: 1000,
  retries: 3,
};

// Use the mock
await mockService.getData(); // Returns 'test data'
mockService.processValue('input'); // Returns 'processed-input'
expect(mockService.getData).toHaveBeenCalled();
expect(mockService.processValue).toHaveBeenCalledWith('input');

Key features:

  • Creates spies for all methods automatically
  • Supports property tracking
  • Handles nested objects
  • Preserves type information
  • Supports getters and setters
  • Handles circular references
  • Maintains property descriptors
mock.of()

Creates a mock from stubs, supporting both object and array types:

// Function signatures
function of<T extends Array<any>>(stubs?: Array<DeepPartial<T[number]>>): MockOf<T>;
function of<T extends ReadonlyArray<any>>(stubs?: ReadonlyArray<DeepPartial<T[number]>>): MockOf<T>;
function of<T extends object>(stubs?: DeepPartial<T>): MockOf<T>;

// Examples:
// 1. Object mocking
interface User {
  id: number;
  name: string;
  getData(): Promise<string>;
  getDetails(): {age: number; email: string};
}

// With initial values
const mockUser = mock.of<User>({
  id: 1,
  name: 'John',
});
// id and name are preserved
// getData and getDetails are automatically mocked
mockUser.getData.mockResolvedValue('test data');
mockUser.getDetails.mockReturnValue({age: 30, email: 'john@example.com'});

// With method implementation
const mockWithMethod = mock.of<User>({
  id: 1,
  getData: async () => 'real data',
  getDetails: () => ({age: 25, email: 'test@example.com'}),
});
// Method implementations are preserved but monitored
expect(mockWithMethod.getData).toHaveBeenCalled();

// 2. Array mocking
interface Task {
  id: number;
  title: string;
  complete(): Promise<void>;
}

const mockTasks = mock.of<Task[]>([
  {id: 1, title: 'Task 1'},
  {id: 2, title: 'Task 2'},
]);
// Array items are mocked
mockTasks[0].complete.mockResolvedValue();
mockTasks[1].complete.mockRejectedValue(new Error('Failed'));

// 3. Nested objects
interface ComplexObject {
  data: {
    id: number;
    nested: {
      value: string;
    };
  };
  getNestedValue(): string;
}

const mockComplex = mock.of<ComplexObject>({
  data: {
    id: 1,
    nested: {
      value: 'test',
    },
  },
  getNestedValue: function () {
    return this.data.nested.value;
  },
});

Key features:

  • Preserves provided values
  • Automatically mocks undefined methods
  • Supports array mocking
  • Handles nested objects
  • Maintains type safety
  • Monitors method calls
  • Supports method chaining
mock.cls()

Creates mock classes with full type safety and spy capabilities:

// Function signature
function cls<T extends new (...args: any[]) => any>(classConstructor: T, options?: ClsMockOptions<T>): ClsMock<T>;

interface ClsMockOptions<T extends new (...args: any[]) => any> {
  selective?: boolean; // Only mock specified methods
  implementation?: DeepPartial<InstanceType<T>>; // Default implementations
}

// Examples:
// 1. Basic class mocking
class UserService {
  private value: string;

  constructor(initialValue: string = '') {
    this.value = initialValue;
  }

  getValue(): string {
    return this.value;
  }

  setValue(newValue: string): void {
    this.value = newValue;
  }

  static staticMethod(): string {
    return 'static';
  }
}

// Create mock class
const MockService = mock.cls(UserService);
const instance = new MockService('test');

// Instance methods are spied on
expect(instance.getValue()).toBe('test'); // Original behavior preserved
expect(instance.getValue).toHaveBeenCalled(); // Call tracked

// Static methods are spied on
expect(MockService.staticMethod()).toBe('static'); // Original behavior preserved
expect(MockService.staticMethod).toHaveBeenCalled(); // Call tracked

// 2. Selective mocking
const SelectiveMock = mock.cls(UserService, {
  selective: true,
  implementation: {
    getValue: () => 'mocked',
  },
});

const selectiveInstance = new SelectiveMock();
expect(selectiveInstance.getValue()).toBe('mocked'); // Mocked method
expect(selectiveInstance.getValue).toHaveBeenCalled(); // Call tracked
expect(SelectiveMock.staticMethod()).toBe('static'); // Original not mocked

// 3. Inheritance support
class BaseClass {
  static baseStatic() {
    return 'base';
  }
  baseMethod() {
    return 'base method';
  }
}

class DerivedClass extends BaseClass {
  static derivedStatic() {
    return 'derived';
  }
  derivedMethod() {
    return 'derived method';
  }
}

const MockDerived = mock.cls(DerivedClass);
const derivedInstance = new MockDerived();

// Both base and derived methods are mocked
expect(MockDerived.baseStatic()).toBe('base');
expect(MockDerived.derivedStatic()).toBe('derived');
expect(derivedInstance.baseMethod()).toBe('base method');
expect(derivedInstance.derivedMethod()).toBe('derived method');

Key features:

  • Mocks both instance and static methods
  • Preserves original behavior by default
  • Supports selective mocking
  • Handles inheritance chain
  • Maintains prototype chain
  • Tracks all method calls
  • Supports constructor arguments
  • Type-safe implementation
mock.fn()

Creates mock functions with full spy capabilities:

// Function signature
function fn<T extends Fn = Fn>(): MockFunction<T>;

interface MockFunction<T extends Fn = Fn> extends Function {
  (...args: Parameters<T>): ReturnType<T>;
  mockReturnValue(value: ReturnType<T>): this;
  mockResolvedValue<U>(value: U): MockFunction<AsyncFn & {(...args: Parameters<T>): Promise<U>}>;
  mockImplementation(fn: T): this;
  mockReset(): void;
  mockClear(): void;
  calls: {
    all(): Array<{args: Parameters<T>}>;
    count(): number;
  };
  toHaveBeenCalled(): boolean;
  toHaveBeenCalledTimes(n: number): boolean;
  toHaveBeenCalledWith(...args: Parameters<T>): boolean;
}

// Examples:
// 1. Basic mock function
const mockFn = mock.fn();
mockFn.mockReturnValue('result');
mockFn('arg1');
expect(mockFn).toHaveBeenCalledWith('arg1');
expect(mockFn.calls.count()).toBe(1);

// 2. Typed mock function
interface User {
  id: number;
  name: string;
}
const getUser = mock.fn<(id: number) => Promise<User>>();
getUser.mockResolvedValue({id: 1, name: 'Test User'});
await getUser(1);
expect(getUser).toHaveBeenCalledWith(1);

// 3. With implementation
const calculate = mock.fn((x: number, y: number) => x * y);
expect(calculate(2, 3)).toBe(6);
expect(calculate).toHaveBeenCalledWith(2, 3);

// 4. Multiple return values
const multiValue = mock.fn();
multiValue.mockReturnValueOnce(1).mockReturnValueOnce(2).mockReturnValue(3);
expect(multiValue()).toBe(1);
expect(multiValue()).toBe(2);
expect(multiValue()).toBe(3);

// 5. Async function mocking
const fetchData = mock.fn<(query: string) => Promise<any>>();
fetchData.mockResolvedValueOnce({data: 'test'}).mockRejectedValueOnce(new Error('Network error'));

await fetchData('query1'); // Returns { data: 'test' }
await expect(fetchData('query2')).rejects.toThrow('Network error');

// 6. Call tracking
const trackedFn = mock.fn();
trackedFn('a', 1);
trackedFn('b', 2);

expect(trackedFn.calls.count()).toBe(2);
expect(trackedFn.calls.all()).toEqual([{args: ['a', 1]}, {args: ['b', 2]}]);

Key features:

  • Type-safe mock functions
  • Flexible return values
  • Async support
  • Call tracking
  • Chainable API
  • Multiple return values
  • Error simulation
  • Framework compatibility
mock.partial()

Creates partial mocks from existing objects or class instances:

// Function signature
function partial<T extends object>(base: T, stubs?: DeepPartial<T>, options?: PartialOptions<T>): T | PartialBuilder<T>;

interface PartialOptions<T> {
  selective?: boolean; // Only mock specified methods
  preserveThis?: boolean; // Maintain original 'this' context
  handleCircular?: boolean; // Handle circular references
}

// Examples:
// 1. Basic partial mocking
class UserService {
  private value: string = 'original';

  getValue(): string {
    return this.value;
  }

  setValue(newValue: string): void {
    this.value = newValue;
  }

  process(data: string): string {
    return data.toUpperCase();
  }
}

const service = new UserService();
const mockService = mock.partial(service, {
  getValue: () => 'mocked',
});

expect(mockService.getValue()).toBe('mocked'); // Mocked method
expect(mockService.getValue).toHaveBeenCalled(); // Call tracked
expect(mockService.process('test')).toBe('TEST'); // Original method

// 2. Selective mocking with preserved context
class DataService {
  private data = new Map<string, any>();

  constructor(initialData: Record<string, any> = {}) {
    Object.entries(initialData).forEach(([key, value]) => {
      this.data.set(key, value);
    });
  }

  getData(key: string): any {
    return this.data.get(key);
  }

  setData(key: string, value: any): void {
    this.data.set(key, value);
  }
}

const dataService = new DataService({key: 'value'});
const mockDataService = mock.partial(
  dataService,
  {
    getData: function (this: DataService, key: string) {
      return this.data.get(key)?.toUpperCase();
    },
  },
  {
    preserveThis: true,
  },
);

mockDataService.setData('key', 'test');
expect(mockDataService.getData('key')).toBe('TEST'); // Uses this context
expect(mockDataService.getData).toHaveBeenCalledWith('key');

// 3. Handling circular references
interface Node {
  value: string;
  next?: Node;
}

const node: Node = {
  value: 'root',
};
node.next = node; // Circular reference

const mockNode = mock.partial(
  node,
  {
    value: 'mocked',
  },
  {
    handleCircular: true,
  },
);

expect(mockNode.value).toBe('mocked');
expect(mockNode.next?.value).toBe('mocked'); // Circular reference handled

// 4. Chainable API
class Service {
  getValue() {
    return 'original';
  }
  transform(value: string) {
    return value.toUpperCase();
  }
}

const chainableMock = mock
  .partial(new Service())
  .spy('getValue')
  .preserve('transform')
  .with({
    getValue: () => 'mocked',
  });

expect(chainableMock.getValue()).toBe('mocked');
expect(chainableMock.getValue).toHaveBeenCalled();
expect(chainableMock.transform('test')).toBe('TEST');

Key features:

  • Selective method mocking
  • Original behavior preservation
  • Context preservation
  • Circular reference handling
  • Property tracking
  • Method call monitoring
  • Chainable API support
  • Type-safe implementation
mock.cast()

Casts an existing mock to a different type while preserving its behavior:

// Function signature
function cast<T, U>(mock: T): U;

// Examples:
// 1. Basic type casting
interface BaseService {
  getData(): string;
}

interface ExtendedService extends BaseService {
  getExtendedData(): number;
}

const baseMock = mock.object<BaseService>();
const extendedMock = mock.cast<BaseService, ExtendedService>(baseMock);

// Original behavior is preserved
baseMock.getData.mockReturnValue('data');
expect(extendedMock.getData()).toBe('data');

// New methods are available
extendedMock.getExtendedData.mockReturnValue(42);
expect(extendedMock.getExtendedData()).toBe(42);

// 2. Complex object casting
interface ComplexType {
  nested: {
    deep: {
      value: number;
    };
  };
  method(): string;
}

const partial = {
  nested: {
    deep: {
      value: 42,
    },
  },
  method: () => 'test',
};

const typed = mock.cast<ComplexType>(partial);
expect(typed.nested.deep.value).toBe(42);
expect(typed.method()).toBe('test');

// 3. Array type casting
interface Item {
  id: number;
  name: string;
}

const items = [
  {id: 1, name: 'Item 1'},
  {id: 2, name: 'Item 2'},
];

const typedItems = mock.cast<Item[]>(items);
expect(typedItems[0].id).toBe(1);
expect(typedItems[1].name).toBe('Item 2');

Key features:

  • Type-safe casting
  • Behavior preservation
  • Property access
  • Method call tracking
  • Nested object support
  • Array support
  • Framework compatibility
mock.replace()

Temporarily replaces a method or property on an object:

// Function signature
function replace<T extends object, K extends keyof T>(obj: T, key: K, impl: T[K] & Function): void;

// Examples:
// 1. Basic method replacement
class UserService {
  async getUser(id: number) {
    // Real implementation
    return {id, name: 'Real User'};
  }

  getValue() {
    return 'original';
  }
}

const service = new UserService();

// Replace async method
mock.replace(service, 'getUser', async id => {
  return {id, name: 'Mock User'};
});

// Method is replaced and monitored
const user = await service.getUser(1);
expect(user.name).toBe('Mock User');
expect(service.getUser).toHaveBeenCalledWith(1);

// 2. Function property handling
const original = function () {
  return 'original';
};
(original as any).customProp = 'test';

const obj = {method: original};
mock.replace(obj, 'method', () => 'mocked');

// Original properties are preserved
expect((obj.method as any).customProp).toBe('test');
expect(obj.method()).toBe('mocked');

// 3. Multiple replacements
class Service {
  method1() {
    return 'original1';
  }
  method2() {
    return 'original2';
  }
}

const svc = new Service();
mock.replace(svc, 'method1', () => 'mocked1');
mock.replace(svc, 'method2', () => 'mocked2');

expect(svc.method1()).toBe('mocked1');
expect(svc.method2()).toBe('mocked2');
expect(svc.method1).toHaveBeenCalled();
expect(svc.method2).toHaveBeenCalled();

// 4. Restore original methods
mock.restore(svc, 'method1'); // Restore single method
expect(svc.method1()).toBe('original1');

mock.restore(svc); // Restore all methods
expect(svc.method2()).toBe('original2');

Key features:

  • Temporary method replacement
  • Original property preservation
  • Method call tracking
  • Multiple replacements
  • Selective restoration
  • Type safety
  • Framework compatibility
mock.restore()

Restores replaced methods to their original implementations:

// Function signatures
function restore<T extends object>(obj: T): boolean; // Restore all methods
function restore<T extends object, K extends keyof T>(obj: T, key: K): boolean; // Restore specific method

// Examples:
// 1. Basic method restoration
class UserService {
  async getUser(id: number) {
    return {id, name: 'Real User'};
  }
}

const service = new UserService();
mock.replace(service, 'getUser', async id => ({id, name: 'Mock User'}));

// Verify mock works
const mockResult = await service.getUser(1);
expect(mockResult.name).toBe('Mock User');

// Restore original method
const restored = mock.restore(service, 'getUser');
expect(restored).toBe(true); // Method was restored

// Original behavior is restored
const realResult = await service.getUser(1);
expect(realResult.name).toBe('Real User');

// 2. Batch restoration
class Service {
  method1() {
    return 'original1';
  }
  method2() {
    return 'original2';
  }
}

const svc = new Service();
mock.replace(svc, 'method1', () => 'mocked1');
mock.replace(svc, 'method2', () => 'mocked2');

// Get list of replaced methods
const replaced = mock.getReplacedMethods(svc);
expect(replaced).toEqual(['method1', 'method2']);

// Restore all methods
const batchRestored = mock.restore(svc);
expect(batchRestored).toBe(true); // Methods were restored

// 3. Restoration verification
class VerifyService {
  getValue() {
    return 'original';
  }
}

const verifySvc = new VerifyService();
mock.replace(verifySvc, 'getValue', () => 'mocked');

// Check if method is replaced
expect(mock.isReplaced(verifySvc, 'getValue')).toBe(true);

// Restore and verify
mock.restore(verifySvc, 'getValue');
expect(mock.verifyRestored(verifySvc, 'getValue')).toBe(true);

// 4. Property preservation
class PropService {
  method() {
    return 'original';
  }
}

const propSvc = new PropService();
const original = propSvc.method;
(original as any).customProp = 'test';

// Replace and verify custom property is preserved
mock.replace(propSvc, 'method', () => 'mocked');
expect((propSvc.method as any).customProp).toBe('test');

// Restore and verify custom property is still preserved
mock.restore(propSvc, 'method');
expect((propSvc.method as any).customProp).toBe('test');
expect(propSvc.method()).toBe('original');

// 5. Error handling
class InvalidService {
  method() {}
}

const invalidSvc = new InvalidService();

// Attempting to restore a method that wasn't replaced
const notRestored = mock.restore(invalidSvc, 'method');
expect(notRestored).toBe(false); // No methods were restored

// Attempting to restore an invalid property
const invalidRestored = mock.restore(invalidSvc, 'nonexistent' as any);
expect(invalidRestored).toBe(false); // No methods were restored

Key features:

  • Batch restoration support
  • Restoration status tracking
  • Property preservation
  • Restoration verification
  • Method replacement checking
  • Graceful error handling
  • Type-safe implementation
  • Framework compatibility
Configuration Methods

The library provides several methods to configure mocking behavior:

// Configuration interface
interface Config {
  debug: boolean; // Enable debug logging (default: false in production)
  trackCalls: boolean; // Track method calls (default: true)
  allowUndefined: boolean; // Allow undefined properties (default: true)
  strict: boolean; // Throw on undefined properties (default: false)
  preservePrototype: boolean; // Preserve prototype chain (default: true)
  handleCircular: boolean; // Handle circular references (default: false)
  preserveThis: boolean; // Preserve this context (default: false)
  selective: boolean; // Only mock specified methods (default: false)
}

// Get current configuration
const config = mock.getConfig();

// Update configuration
mock.setConfig({
  debug: true, // Enable detailed logging
  trackCalls: true, // Track all method calls
  allowUndefined: false, // Throw on undefined properties
  strict: true, // Strict mode enabled
  preservePrototype: true, // Keep prototype chain
  handleCircular: true, // Handle circular references
  preserveThis: true, // Keep original context
  selective: false, // Mock all methods
});

// Reset to defaults
mock.resetConfig();

// Scoped configuration
mock.withConfig(
  {
    debug: true,
    trackCalls: true,
  },
  () => {
    // Configuration only applies within this function scope
    const mockObj = mock.object<Service>();
    mockObj.method(); // Will be logged and tracked
  },
);

// Configuration scope example with async functions
await mock.withConfig(
  {
    preserveThis: true,
    handleCircular: true,
  },
  async () => {
    const mockService = mock.partial(realService);
    await mockService.asyncMethod();
  },
);

// Nested configuration scopes
mock.withConfig({debug: true}, () => {
  mock.withConfig({strict: true}, () => {
    // Both debug and strict are true here
  });
  // Only debug is true here
});

// Get configuration statistics
interface ConfigStats {
  configChanges: number; // Number of times config was changed
  activeScopes: number; // Number of active scoped configs
  defaultResets: number; // Number of times config was reset
}
const stats = mock.getConfigStats();

Configuration options:

  • debug: Enable debug logging (default: false in production)
  • trackCalls: Track method calls (default: true)
  • allowUndefined: Allow undefined properties (default: true)
  • strict: Throw on undefined properties (default: false)
  • preservePrototype: Preserve prototype chain (default: true)
  • handleCircular: Handle circular references (default: false)
  • preserveThis: Preserve original context (default: false)
  • selective: Only mock specified methods (default: false)

Best Practices

Testing Patterns

  1. Clean State

    • Reset mocks between tests
    • Use beforeEach/afterEach hooks
    • Avoid state leakage
  2. Type Safety

    • Always provide proper types
    • Use interface mocking when possible
    • Leverage TypeScript's type inference
  3. Selective Mocking

    • Mock only what you need
    • Preserve original behavior when possible
    • Use partial mocks for large classes

Common Pitfalls

  1. Context Loss

    • Use preserveThis option
    • Be careful with arrow functions
    • Maintain proper binding
  2. Memory Leaks

    • Reset mocks after use
    • Clean up spies
    • Handle circular references
  3. Circular References

    • Enable handleCircular option for objects with self-references
    • Use mock.partial with handleCircular for complex objects
    • Consider restructuring deeply nested objects
    • Monitor memory usage in tests with circular structures
  4. Type Safety

    • Enable TypeScript strict mode (strict: true in tsconfig.json)
    • Use explicit type parameters with mock functions
    • Avoid type assertions unless necessary
    • Leverage interface mocking for better type inference

Troubleshooting

Common Issues

  1. Type Inference Issues

Problem:

const mock = mock<Service>(); // Type 'any' inferred

Solution:

// Provide explicit type or interface
interface Service {
  method(): void;
}
const mockService = mock<Service>();
  1. This Context Lost

Problem:

class Service {
  private value = 'test';
  method() {
    return this.value;
  }
}
const mockService = mock.partial(new Service());
mockService.method(); // this is undefined

Solution:

const mockService = mock.partial(
  new Service(),
  {},
  {
    preserveThis: true,
  },
);
  1. Circular References

Problem:

interface Node {
  next: Node;
}
const node = {next: null};
node.next = node;

Solution:

const mockNode = mock.partial(
  node,
  {},
  {
    handleCircular: true,
  },
);

Error Messages

Common error messages and their solutions:

  1. "Cannot spy on property which has no getter"

    • Ensure the property exists on the target object
    • Check if the property is accessible
    • Use proper access modifiers
  2. "Cannot mock non-function value"

    • Verify the target is actually a function
    • Check if the property is a getter/setter
    • Ensure proper type definitions
  3. "Maximum call stack size exceeded"

    • Check for circular references
    • Enable handleCircular option
    • Review recursive mock implementations
    • Consider using mock.partial with handleCircular option
  4. "Property has a circular reference"

    • Enable handleCircular in mock options
    • Use mock.partial with handleCircular: true
    • Consider restructuring the object graph
    • Use WeakMap for circular reference tracking
  5. "Accessing undefined property"

    • Check if strict mode is enabled
    • Verify property exists on mock object
    • Consider using allowUndefined option
    • Add explicit property definitions
  6. "Invalid spy implementation"

    • Ensure mock implementation matches original signature
    • Check for proper this context binding
    • Verify async/sync function compatibility
    • Review method parameter types

Development

# Install dependencies
pnpm install

# Run tests
pnpm test

# Build
pnpm build

# Lint
pnpm lint

# Format
pnpm format

# Run tests with coverage
pnpm test:coverage

For development, make sure to:

  1. Write tests for new features
  2. Update documentation for API changes
  3. Follow the TypeScript coding style
  4. Run the full test suite before submitting PR

TypeScript Configuration

The library is built with strict TypeScript settings:

{
  "compilerOptions": {
    "strict": true,
    "noImplicitAny": true,
    "strictNullChecks": true,
    "strictFunctionTypes": true,
    "strictBindCallApply": true,
    "strictPropertyInitialization": true,
    "noImplicitThis": true,
    "useUnknownInCatchVariables": true,
    "alwaysStrict": true,
    "noUncheckedIndexedAccess": true,
    "noImplicitReturns": true,
    "noFallthroughCasesInSwitch": true,
    "exactOptionalPropertyTypes": true
  }
}

These strict settings ensure:

  • No implicit any types
  • Null and undefined checks
  • Strict function type checking
  • Proper this context handling
  • Strict property initialization
  • Index signature checking
  • Exhaustive switch/case handling

Contributing

  1. Fork the repository
  2. Create your feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'Add some amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Open a Pull Request at https://github.com/corezlab/mock

Please ensure your PR:

  • Includes tests for new features
  • Updates documentation as needed
  • Follows the existing code style
  • Includes a clear description of changes

Development Guidelines

  1. Code Style

    • Follow TypeScript best practices
    • Use ESLint and Prettier
    • Write clear comments
    • Use meaningful variable names
  2. Testing

    • Write unit tests for new features
    • Maintain test coverage
    • Test edge cases
    • Use meaningful test descriptions
  3. Documentation

    • Update README.md as needed
    • Document new features
    • Include examples
    • Keep API documentation up to date

License

This project is licensed under the Apache License 2.0 - see the LICENSE file for details.

Keywords

FAQs

Package last updated on 29 Dec 2024

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc