ts-mockery
ts-mockery is a TypeScript mocking library designed for creating type-safe and intuitive mocks for unit testing. Currently at version 2.0.0, it provides a comprehensive suite of features including full IntelliSense support, deep nested object mocking, and automatic spy setup for functions. The library integrates seamlessly with popular testing frameworks such as Jest and Jasmine, offering a consistent API across different test runners. Its key differentiators include a strong emphasis on compile-time type safety through partial object mocking with `RecursivePartial<T>`, robust Promise handling, and advanced capabilities for mocking static methods and imported modules. While a specific release cadence isn't explicitly documented, its major versioning indicates active development and a commitment to modern TypeScript practices, requiring TypeScript 4.5 or newer.
Common errors
-
TS2345: Argument of type '{ ... }' is not assignable to parameter of type 'RecursivePartial<T>'.cause The mock object provided to `Mock.of<T>` does not fully satisfy the `T` interface or contains properties with incompatible types. This often happens with required properties that are omitted or incorrectly typed.fixReview the interface `T` and ensure that all required properties are present in the mock object with correct types. For nested objects, ensure their types also align. The error message usually points to the specific incompatible property. -
TypeError: (0, ts_mockery_1.Mock) is not a function
cause This error typically occurs when `ts-mockery` is imported using CommonJS `require()` syntax in a project configured for ESM, or if the bundler/runtime doesn't correctly resolve the module's exports. It indicates `Mock` is not correctly recognized as a callable constructor or object.fixUse ESM `import { Mock } from 'ts-mockery';` syntax. Ensure your `tsconfig.json` and build tools (like Webpack, Rollup, Jest) are configured for ESM (`"module": "ESNext"` or `"module": "Node16"`). If using Jest, ensure it runs in an ESM context or transpiles `node_modules`. -
TypeError: Cannot read properties of undefined (reading 'toHaveBeenCalled')
cause This error usually occurs when attempting to assert `toHaveBeenCalled` on a mocked function that was not correctly set up as a spy. `ts-mockery` auto-spies functions when `Mock.noop` is used, or when a function stub is provided, but plain `undefined` or non-function values won't have the spy properties.fixEnsure the mocked function is explicitly assigned `Mock.noop` or a stub function (e.g., `() => { /* ... */ }`) within your `Mock.of` definition. For example: `myMethod: Mock.noop` or `myMethod: () => { console.log('Mocked method called'); }`.
Warnings
- breaking ts-mockery version 2.0.0 requires TypeScript 4.5 or higher. Attempting to use it with older TypeScript versions will result in compilation errors due to incompatible type definitions and language features.
- gotcha When mocking imported modules or static methods, `ts-mockery` recommends specific import syntax to ensure type safety and proper mocking behavior. Using default exports or different import patterns might lead to issues.
- gotcha When creating partial mocks, properties not explicitly defined in the `Mock.of` object will be `undefined` by default (if optional) or may result in type errors if they are required properties of the mocked interface. TypeScript's strictness can flag these.
Install
-
npm install ts-mockery -
yarn add ts-mockery -
pnpm add ts-mockery
Imports
- Mock
const Mock = require('ts-mockery');import { Mock } from 'ts-mockery'; - Mock.of
import Mock from 'ts-mockery'; const myMock = Mock.of<MyInterface>({});import { Mock } from 'ts-mockery'; const myMock = Mock.of<MyInterface>({}); - Mock.noop
import { noop } from 'ts-mockery';import { Mock } from 'ts-mockery'; const func = Mock.noop;
Quickstart
import { Mock } from 'ts-mockery';
interface UserService {
getUser(id: number): Promise<{ id: number; name: string; email?: string }>;
updateUser(user: { id: number; name: string }): void;
deleteUser(id: number): boolean;
}
// Create a type-safe partial mock for UserService
const userServiceMock = Mock.of<UserService>({
getUser: (id: number) => Promise.resolve({ id: id, name: 'Mocked User' }), // Only specify necessary properties
updateUser: Mock.noop, // Function is auto-spied and does nothing
deleteUser: () => true // Provide a simple return value
});
async function runTest() {
// Use the mocked service in a test context
const userId = 123;
const userResult = await userServiceMock.getUser(userId);
console.log(`Retrieved user: ${userResult.name} (ID: ${userResult.id})`);
userServiceMock.updateUser({ id: userId, name: 'Updated User' });
const deleteSuccess = userServiceMock.deleteUser(userId);
// Assertions (using Jest-like syntax for demonstration)
console.assert(userResult.id === userId, 'User ID should match');
console.assert(userServiceMock.updateUser.toHaveBeenCalled, 'updateUser should have been called');
console.assert(deleteSuccess === true, 'deleteUser should return true');
console.assert(userServiceMock.deleteUser.mock.calls[0][0] === userId, 'deleteUser should be called with correct ID');
}
runTest();