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.11.0
  • Source
  • npm
  • Socket score

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

@corez/mock

A powerful, flexible, and type-safe mocking library for TypeScript testing.

npm version License: Apache-2.0 Node Version pnpm

目录

Features

  • 🎯 Type Safety - Full TypeScript support with precise type inference
  • 🔄 Deep Mocking - Automatic mocking of nested objects and methods
  • 🕵️ Spy Tracking - Comprehensive call tracking and verification
  • 🎭 Multiple Mocking Styles - Support for functions, objects, and classes
  • 🔗 Inheritance Support - Proper handling of class inheritance and prototype chains
  • 🎮 Intuitive API - Clean and chainable API design
  • 🛡 Debug Support - Detailed logging for troubleshooting
  • 🔄 In-Place Mocking - Option to modify original classes with restore capability

Installation

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

# Using yarn
yarn add -D @corez/mock

# Using pnpm
pnpm add -D @corez/mock

Quick Start

import {mock} from '@corez/mock';

// Mock a function
const greet = mock.fn<(name: string) => string>();
greet.mockImplementation(name => `Hello, ${name}!`);

// Mock an object
interface UserService {
  getUser(id: number): Promise<User>;
  updateUser(user: User): Promise<void>;
}

const userService = mock.obj<UserService>(
  {
    getUser: async id => ({id, name: 'John'}),
    updateUser: async user => {},
  },
  {
    shouldClone: true, // Create a new instance instead of modifying the original
    shouldIgnorePrototype: false, // Mock prototype chain methods
  },
);

// Mock a class
class Database {
  async connect() {
    /* ... */
  }
  async query(sql: string) {
    /* ... */
  }
}

const MockDatabase = mock.cls(Database, {
  shouldIgnoreStatic: false, // Mock static members
  shouldMockConstructor: false, // Keep original constructor behavior
  shouldIgnoreInheritance: false, // Mock inherited methods
});

const db = new MockDatabase();
db.query.mockResolvedValue({rows: []});

Core APIs

mock.fn() - Function Mocking

Create standalone mock functions with full tracking capabilities:

const mockFn = mock.fn<(x: number) => number>();

// Set implementation
mockFn.mockImplementation(x => x * 2);

// Set return value
mockFn.mockReturnValue(42);

// Handle async scenarios
mockFn.mockResolvedValue('result');
mockFn.mockRejectedValue(new Error('failed'));

// Verify calls
expect(mockFn.calls.count()).toBe(1);
expect(mockFn.calls.all()[0].args).toEqual([1]);

mock.obj() - Object Mocking

Create mock objects with automatic method tracking:

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

const userService = mock.obj<UserService>({
  getUser: async id => ({id, name: 'John'}),
  updateUser: async user => {},
});

// Track method calls
userService.getUser(1);
expect((userService.getUser as any).mock.calls.length).toBe(1);

// Override return values
(userService.getUser as any).mockResolvedValue({id: 1, name: 'Mock'});

mock.cls() - Class Mocking

Create mock classes with advanced method tracking and inheritance support:

class Database {
  static getInstance() {
    return new Database();
  }
  async connect() {
    /* ... */
  }
  async query(sql: string) {
    /* ... */
  }
}

// Basic mocking with default options
const MockDatabase = mock.cls(Database);
const db = new MockDatabase();
db.query.mockResolvedValue({rows: []});

// Advanced mocking with patterns and inheritance
const AdvancedMockDatabase = mock.cls(Database, {
  patterns: ['getInstance'], // Only mock specific methods
  shouldIgnoreInheritance: false, // Mock inherited methods
  shouldReplacePrototype: false, // Keep original prototype chain
  shouldIgnoreStatic: false, // Mock static members
});

// Static method mocking
AdvancedMockDatabase.getInstance.mockReturnValue(new AdvancedMockDatabase());

// Pattern-based method mocking
const dbWithPatterns = mock.cls(Database, {
  patterns: ['get*', '!getPrivate*'], // Mock all get* methods except getPrivate*
  shouldIgnoreStatic: false, // Enable static method mocking
});

// Verify mocking
console.log(MockDatabase.__is_mocked__); // true
console.log(db.query.calls.count()); // Track call count
console.log(db.query.calls.all()); // Get all call details

// Example with all options
const FullOptionsMock = mock.cls(Database, {
  shouldClone: true, // Create new class instead of modifying original
  shouldReplacePrototype: false, // Keep original prototype chain
  shouldMockConstructor: false, // Keep original constructor
  shouldIgnoreStatic: false, // Mock static members
  shouldIgnoreInheritance: false, // Mock inherited methods
  patterns: ['get*', 'set*', '!private*'], // Mock getters and setters, exclude private methods
  overrides: {
    // Custom implementations
    connect: async () => {
      /* custom connect logic */
    },
    query: async (sql: string) => ({rows: []}),
  },
});

mock.factory() - Factory Mocking

Create factory-based mock classes that automatically mock instances:

const MockDatabase = mock.factory(Database, {
  shouldIgnorePrototype: false, // Mock prototype chain methods
  shouldReplacePrototype: false, // Keep original prototype chain
  shouldMockConstructor: false, // Keep original constructor behavior
  patterns: ['query', 'connect'], // Only mock specific methods
});

// Each instance is automatically mocked
const db = new MockDatabase();
expect(db.query).toHaveProperty('mock');

// Mock implementation
db.query.mockResolvedValue({rows: []});

// Track calls
db.query('SELECT * FROM users');
expect(db.query).toHaveBeenCalled();

// Example with all options
const FullOptionsMockFactory = mock.factory(Database, {
  shouldClone: true, // Create new instances
  shouldIgnorePrototype: false, // Mock prototype methods
  shouldReplacePrototype: false, // Keep prototype chain
  shouldMockConstructor: false, // Keep constructor
  shouldIgnoreStatic: false, // Mock static members
  shouldIgnoreInheritance: false, // Mock inherited methods
  patterns: ['get*', 'set*', '!private*'], // Mock patterns
  overrides: {
    connect: async () => {
      /* custom connect */
    },
    query: async () => ({rows: []}),
  },
});

mock.compose() - Composition Mocking

Create mocks from classes, objects, or functions:

// Mock a function
const mockFn = mock.compose<(x: number) => string>();
mockFn.mockImplementation(x => x.toString());

// Mock a class
const MockDatabase = mock.compose(Database, {
  overrides: {
    query: async () => [{id: 1}],
  },
});

// Mock an object
const api = mock.compose<Api>(
  {
    fetch: async url => ({data: []}),
  },
  {
    overrides: {
      fetch: async url => ({data: [{id: 1}]}),
    },
  },
);

mock.cast() - Type Casting

Cast partial implementations to complete mocks:

interface CompleteApi {
  getUsers(): Promise<User[]>;
  getUser(id: number): Promise<User>;
  createUser(user: User): Promise<void>;
  updateUser(user: User): Promise<void>;
  deleteUser(id: number): Promise<void>;
}

// Only implement needed methods
const api = mock.cast<CompleteApi>({
  getUsers: async () => [{id: 1, name: 'John'}],
  getUser: async id => ({id, name: 'John'}),
});

// All other methods automatically mocked
await api.createUser({id: 1, name: 'Test'});

mock.replace() - Method Replacement

Replace methods while preserving original implementation:

class Service {
  async getData() {
    /* ... */
  }
  async processData(data: any) {
    /* ... */
  }
}

const service = new Service();

// Replace single method
mock.replace(service, 'getData', async () => ['mocked']);

// Verify replacement
expect(await service.getData()).toEqual(['mocked']);

// Original processData remains unchanged
expect(service.processData).toBeDefined();

// Restore original
mock.restore(service);

Mock Options

Common Options

Base options shared by all mock types:

interface BaseMockOptions {
  debug?: boolean; // Enable detailed logging
  asyncTimeout?: number; // Timeout for async operations (ms)
  name?: string; // Name of mock instance for debugging
}

Function Mock Options

Options specific to function mocking:

interface FunctionMockOptions extends BaseMockOptions {
  trackCalls?: boolean; // Track function calls
  autoSpy?: boolean; // Auto-create spies for function properties
}

Object Mock Options

Options specific to object mocking:

interface ObjectMockOptions<T> extends BaseMockOptions {
  shouldClone?: boolean; // Create new instance instead of modifying original
  shouldIgnorePrototype?: boolean; // Ignore prototype chain methods
  overrides?: DeepPartial<T>; // Partial implementation to override properties
  patterns?: string[]; // Glob patterns for methods/properties to mock
}

Class Mock Options

Options specific to class mocking:

interface ClassMockOptions<T> extends BaseMockOptions {
  shouldClone?: boolean; // Create new class instead of modifying original
  shouldReplacePrototype?: boolean; // Replace prototype chain
  shouldMockConstructor?: boolean; // Mock constructor behavior
  shouldIgnoreStatic?: boolean; // Ignore static members
  shouldIgnoreInheritance?: boolean; // Ignore inherited methods
  overrides?: DeepPartial<T>; // Partial implementation to override methods
  patterns?: string[]; // Glob patterns for methods to mock
}

Migration Guide

Starting from v0.11.0, we've introduced new option names that are more intuitive and consistent. Old options are still supported but marked as deprecated:

Old OptionNew OptionDescription
inplace: trueshouldClone: falseControl object/class modification
prototypeChain: trueshouldIgnorePrototype: falseControl prototype chain handling
preservePrototype: trueshouldReplacePrototype: falseControl prototype replacement
preserveConstructor: trueshouldMockConstructor: falseControl constructor mocking
static: trueshouldIgnoreStatic: falseControl static member handling
inheritance: trueshouldIgnoreInheritance: falseControl inherited method handling

Example:

// Old way
const mockObj = mock.obj(target, {
  inplace: true,
  prototypeChain: true,
});

// New way (recommended)
const mockObj = mock.obj(target, {
  shouldClone: false,
  shouldIgnorePrototype: false,
});

// Class mock example
const MockClass = mock.cls(TargetClass, {
  shouldClone: false, // Modify original class
  shouldReplacePrototype: false, // Keep prototype chain
  shouldMockConstructor: false, // Keep constructor
  shouldIgnoreStatic: false, // Mock static members
  shouldIgnoreInheritance: false, // Mock inherited methods
  patterns: ['get*', '!private*'], // Only mock get* methods, exclude private*
});

Best Practices

  1. Use New Option Names

    • New option names better express their purpose
    • Default false values are more intuitive
    • IDE provides suggestions for new options
  2. Choose Appropriate Defaults

    • Use shouldClone: true when original object needs protection
    • Use shouldIgnorePrototype: true when only own properties matter
    • Use shouldMockConstructor: true for full instance control
  3. Pattern Matching

    const mock = mock.cls(MyClass, {
      patterns: [
        'get*', // Mock all getters
        '!private*', // Exclude private methods
        'handle*', // Mock all handler methods
      ],
    });
    

Pattern-based Method Mocking

You can use glob patterns to control which methods get mocked:

const MockDatabase = mock.cls(Database, {
  static: ['query*', '!queryPrivate*'], // Mock all query* methods except queryPrivate*
  inheritance: true, // Mock inherited methods
  preservePrototype: true, // Keep original implementations
});

const db = new MockDatabase();
// query and queryAll will be mocked
// queryPrivate and queryPrivateData will not be mocked

Base Options

All mock types support these basic options:

  • debug: Enable detailed logging (default: false)
  • asyncTimeout: Maximum time for async operations (default: 5000ms)

Function Mock Options

  • trackCalls: Record arguments and return values (default: false)
  • autoSpy: Create spies for function properties (default: false)

Object Mock Options

  • inplace: Modify original object or create new one (default: false)
  • prototypeChain: Deep clone and mock prototype chain (default: true)
  • overrides: Override specific properties or methods

Class Mock Options

  • inplace: Modify original class or create new one (default: false)
  • preservePrototype: Preserve prototype chain (default: true)
  • preserveConstructor: Preserve constructor behavior (default: true)
  • mockStatic: Mock static members (default: false)
  • overrides: Override specific methods

Advanced Usage

Pattern Matching

Control which methods to mock using glob patterns:

const service = mock.obj<Service>(
  {
    getData: () => Promise.resolve({data: 'test'}),
    getDataAsync: () => Promise.resolve({data: 'test'}),
    setData: data => {},
    setDataAsync: async data => {},
  },
  {
    patterns: [
      'get*', // Mock all getter methods
      '!setData', // Exclude setData method
    ],
  },
);

Async Mocking

Handle async operations:

const api = mock.obj<Api>(
  {},
  {
    overrides: {
      fetch: async url => {
        if (url === '/users') {
          return [{id: 1}];
        }
        throw new Error('Not found');
      },
    },
  },
);

Partial Mocking

Selectively mock methods:

class UserService {
  async getUser(id: number) {
    /* ... */
  }
  async validate(user: User) {
    /* ... */
  }
}

const service = new UserService();

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

// Using overrides
const partialService = mock.obj<UserService>(
  {},
  {
    overrides: {
      getUser: async id => ({id, name: 'Mock User'}),
    },
  },
);

Debugging

Debug Logging

Enable detailed logging for troubleshooting:

import {debug} from '@corez/mock';

// Enable debug logging
debug.enable();

// Set log level
debug.setLevel('error'); // 'error' | 'warn' | 'info' | 'debug'

// Custom handler
debug.setHandler((level, message) => {
  console.log(`[MOCK] ${level}: ${message}`);
});

Call Tracking

Track and verify method calls:

// Clear history
mock.mockClear(); // Clears calls but keeps implementation

// Reset completely
mock.mockReset(); // Clears everything

// Restore original
mock.mockRestore(); // Restores original implementation

// Access state
mock.calls.all(); // Call arguments with context
mock.calls.count(); // Number of calls

Best Practices

  1. Type Safety

    • Always provide type parameters
    • Use interfaces for mock shapes
    • Let TypeScript infer return types
  2. Pattern Matching

    • Use specific patterns for needed methods
    • Combine positive and negative patterns
    • Group related methods with patterns
  3. Performance

    • Disable prototype chain mocking when not needed
    • Use shallow cloning for simple objects
    • Clean up mocks after use
  4. Error Handling

    • Test error cases
    • Verify error messages
    • Handle async errors properly

Troubleshooting

Common Issues

  1. Mock Not Tracking Calls

    • Enable trackCalls for functions
    • Method calls tracked automatically for objects/classes
    • Check mock property access
  2. Type Inference Issues

    • Use explicit type parameters
    • Define complete interfaces
    • Use as MockFunction<T> for better typing
  3. Prototype Chain Issues

    • Use preservePrototype: true for classes
    • Use prototypeChain: true for objects
    • Use keepPrototype: true for casting
  4. Circular References

    • Use WeakSet to track processed objects
    • Enable debug logging
    • Consider shallow cloning

Contributing

We welcome contributions! Please see our Contributing Guide for details.

License

Apache-2.0 - see LICENSE for details.

Keywords

FAQs

Package last updated on 14 Jan 2025

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