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

Version published
Maintainers
0
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 => {},
  },
  {
    overrides: {
      getUser: async id => ({id, name: 'Mock User'}),
    },
  },
);

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

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

// Or modify the original class
mock.cls(Database, {
  mockInPlace: true,
  overrides: {
    query: async () => [{id: 1}],
  },
});

Core Concepts

Mock Functions

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 Objects

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 => {},
  },
  {
    overrides: {
      getUser: async id => ({id, name: 'Mock User'}),
    },
  },
);

// Access call information
const getUserMock = userService.getUser as MockFunction;
console.log(getUserMock.calls.count());
console.log(getUserMock.calls.all());

Mock Classes

Create mock classes with automatic method tracking:

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

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

const db = new MockDatabase();
// Access call information
const queryMock = db.query as MockFunction;
console.log(queryMock.calls.count());

// Or modify the original class
mock.cls(Database, {
  mockInPlace: true,
  overrides: {
    query: async () => [{id: 1}],
  },
});

// Store original methods for restoration
const originalQuery = Database.prototype.query;
const originalConnect = Database.prototype.connect;

// Later, restore original methods
Database.prototype.query = originalQuery;
Database.prototype.connect = originalConnect;

API Reference

Core APIs

mock.fn<T extends Fn = Fn>(): MockFunction<T>

Creates a mock function with 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<T extends object>(target: T | undefined, options?: ObjMockOptions<T>): MockObject<T>

Creates a mock object 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 => {},
  },
  {
    overrides: {
      getUser: async id => ({id, name: 'Mock User'}),
    },
  },
);

// Access call information
const getUserMock = userService.getUser as MockFunction;
console.log(getUserMock.calls.count());
console.log(getUserMock.calls.all());

// Verify specific calls
expect(getUserMock.calls.count()).toBe(1);
expect(getUserMock.calls.all()[0].args).toEqual([1]);
mock.cls<T extends Constructor<any>>(target: T, options?: ClsMockOptions<T>): ClsMock<T>

Creates a mock class with automatic method tracking:

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

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

const db = new MockDatabase();
// Access call information
const queryMock = db.query as MockFunction;
console.log(queryMock.calls.count());

// Or modify the original class
mock.cls(Database, {
  mockInPlace: true,
  overrides: {
    query: async () => [{id: 1}],
  },
});

// Store original methods for restoration
const originalQuery = Database.prototype.query;
const originalConnect = Database.prototype.connect;

// Later, restore original methods
Database.prototype.query = originalQuery;
Database.prototype.connect = originalConnect;
mock.compose<T extends Fn>(): MockFunction<T>;
mock.compose<T extends new (...args: any[]) => any>(target: T, options?: {overrides?: DeepPartial<InstanceType<T>>} & Partial<Config>): ClsMock<T>;
mock.compose<T extends object>(target: T, options?: {overrides?: DeepPartial<T>; replace?: {[K in keyof T]?: T[K] extends Fn ? Fn : never}} & Partial<Config>): T;
mock.compose<T extends object>(partialImpl: DeepPartial<T>, options?: Partial<Config>): T;

Creates a mock from a class constructor, object, or function:

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

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

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

// Mock an object
interface Api {
  fetch(url: string): Promise<any>;
}

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

// Mock with partial implementation
interface ComplexApi {
  getUsers(): Promise<User[]>;
  getUser(id: number): Promise<User>;
  createUser(user: User): Promise<void>;
}

const partialApi = mock.compose<ComplexApi>({
  getUsers: async () => [{id: 1, name: 'John'}],
  getUser: async id => ({id, name: 'John'}),
});
mock.cast<T extends object>(partial: DeepPartial<T>, options?: Partial<Config>): T

Casts a partial implementation to a complete mock:

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 the methods we need
const api = mock.cast<CompleteApi>({
  getUsers: async () => [{id: 1, name: 'John'}],
  getUser: async id => ({id, name: 'John'}),
});

// All other methods will be automatically mocked
await api.createUser({id: 1, name: 'Test'}); // Works, returns undefined
await api.updateUser({id: 1, name: 'Test'}); // Works, returns undefined
await api.deleteUser(1); // Works, returns undefined

// Access call information
const createUserMock = api.createUser as MockFunction;
expect(createUserMock.calls.count()).toBe(1);
mock.replace<T extends object, K extends keyof T>(obj: T, key: K, impl: Fn, options?: Partial<Config>): void

Replaces 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 the method was replaced
expect(await service.getData()).toEqual(['mocked']);

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

// Access call information
const getDataMock = service.getData as unknown as MockFunction;
expect(getDataMock.calls.count()).toBe(1);

// Restore original implementation
mock.restore(service);

Mock Control

All mocks provide these control methods:

// Clear call 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

Advanced Usage

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 for method replacement
mock.replace(service, 'getUser', async id => ({
  id,
  name: 'Mock User',
}));

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

Best Practices

  1. Reset Between Tests

    beforeEach(() => {
      mockFn.mockReset();
      // or
      mockObj.mockReset();
    });
    
  2. Type Safety

    // Prefer interfaces for better type inference
    interface Service {
      method(): string;
    }
    const mock = mock.obj<Service>();
    
  3. Error Handling

    // Always test error cases
    api.fetch.mockRejectedValue(new Error('Network error'));
    await expect(api.fetch()).rejects.toThrow('Network error');
    
  4. Verification

    // Verify call count and arguments
    expect(mockFn.calls.count()).toBe(1);
    expect(mockFn.calls.all()[0].args).toEqual(['expected arg']);
    

Troubleshooting

Common Issues

  1. Mock Not Tracking Calls

    • Enable trackCalls in config
    • Ensure mock is properly created
  2. Type Inference Issues

    • Use explicit type parameters
    • Define interfaces for complex types
  3. Prototype Chain Issues

    • Enable preservePrototype
    • Use mock.cls() for classes

Contributing

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

License

Apache-2.0 - see LICENSE for details.

Mock Options

Base Options

All mock types support these basic options:

  • debug: Enables detailed logging of mock operations (default: false)

Function Mock Options

Options for mocking functions:

  • trackCalls: Records arguments, return values, and call count (default: false)
  • autoSpy: Automatically creates spies for all function properties (default: false)

Object Mock Options

Options for mocking objects:

  • handleCircular: Handles circular references in complex objects (default: true)
  • mockPrototype: Controls whether to mock methods from the prototype chain (default: false)
  • overrides: Allows overriding specific properties or methods with custom implementations

Class Mock Options

Options for mocking classes (extends Object Mock Options):

  • mockInPlace: Modifies the original class instead of creating a new one (default: false)
  • preservePrototype: Maintains the original prototype chain (default: true)
  • preserveConstructor: Preserves original constructor behavior (default: true)
  • mockStaticMembers: Controls mocking of static class members (default: false)

Cast Mock Options

Options for type casting and partial implementations:

  • handleCircular: Handles circular references (default: true)
  • keepPrototype: Maintains the prototype chain when casting (default: true)
  • asyncTimeout: Maximum time to wait for async operations in ms (default: 5000)

Usage Examples

Basic Function Mocking

import {mock} from 'hexxspark';

// Create a mock function
const mockFn = mock.fn<() => string>();
mockFn.mockReturnValue('hello');

// Track calls
expect(mockFn()).toBe('hello');
expect(mockFn.mock.calls.length).toBe(1);

Object Mocking

import {mock} from 'hexxspark';

interface User {
  name: string;
  getId(): number;
}

// Create a mock object
const mockUser = mock.obj<User>({
  name: 'Test User',
  getId: () => 1,
});

// Override methods
mockUser.getId.mockReturnValue(2);

Class Mocking

import {mock} from 'hexxspark';

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

// Create a mock class
const MockDatabase = mock.cls(Database, {
  mockStaticMembers: true,
  preserveConstructor: true,
});

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

Type Casting

import {mock} from 'hexxspark';

interface ComplexType {
  data: string;
  process(): Promise<void>;
}

// Cast partial implementation to full mock
const partial = {data: 'test'};
const mockObj = mock.cast<ComplexType>(partial, {
  asyncTimeout: 1000,
});

Keywords

FAQs

Package last updated on 11 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