0
# Core Mocking
1
2
Core mocking functionality for replacing object properties and function behavior with custom implementations. All mocked functions automatically include spy functionality for tracking calls.
3
4
## Capabilities
5
6
### Primary Mock Function
7
8
The main mocking function that replaces any property on any object with a custom value. When mocking functions, automatic spy instrumentation is added.
9
10
```typescript { .api }
11
/**
12
* Replace a property with a custom value and add spy functionality for functions
13
* @param target - Object to mock property on
14
* @param property - Property name to mock (string, symbol, or number)
15
* @param value - Replacement value or function
16
*/
17
function mock(target: any, property: PropertyKey, value?: any): void;
18
```
19
20
**Usage Examples:**
21
22
```typescript
23
import fs from "node:fs";
24
import mm from "mm";
25
26
// Mock with custom function
27
mm(fs, "readFileSync", () => "custom content");
28
29
// Mock with direct value
30
mm(process, "env", { NODE_ENV: "test" });
31
32
// Mock method with automatic spy tracking
33
const obj = { getData: async () => "real data" };
34
mm(obj, "getData", async () => "mock data");
35
console.log(await obj.getData()); // => "mock data"
36
console.log(obj.getData.called); // => 1
37
```
38
39
### Alternative Call Patterns
40
41
The mock function can be accessed through multiple patterns. All patterns are equivalent and provide the same functionality:
42
43
```typescript { .api }
44
// Via default export (proxy function)
45
function mm(target: any, property: PropertyKey, value?: any): void;
46
47
// Via named export
48
function mock(target: any, property: PropertyKey, value?: any): void;
49
50
// Via named export alias
51
const mm: typeof mock; // Named export with same name as default
52
53
// Via property on default export
54
mm.mock(target: any, property: PropertyKey, value?: any): void;
55
mm.mm(target: any, property: PropertyKey, value?: any): void;
56
```
57
58
**Usage Examples:**
59
60
```typescript
61
import mm, { mock, mm as mmNamed } from "mm";
62
63
// All these calls are equivalent:
64
mm(fs, "readFileSync", mockFn); // Default export as function
65
mock(fs, "readFileSync", mockFn); // Named export
66
mmNamed(fs, "readFileSync", mockFn); // Named export alias
67
mm.mock(fs, "readFileSync", mockFn); // Property access
68
mm.mm(fs, "readFileSync", mockFn); // Alternative property access
69
70
// Import flexibility examples
71
import mm from "mm"; // Default only
72
import { mock } from "mm"; // Named only
73
import { mm as mockFn } from "mm"; // Named with alias
74
import mm, { mock } from "mm"; // Mixed import
75
```
76
77
### Mock Status Checking
78
79
Check whether a property is currently mocked.
80
81
```typescript { .api }
82
/**
83
* Check if a property is currently mocked
84
* @param target - Object to check
85
* @param property - Property name to check
86
* @returns True if property is mocked, false otherwise
87
*/
88
function isMocked(target: any, property: PropertyKey): boolean;
89
```
90
91
**Usage Examples:**
92
93
```typescript
94
import fs from "node:fs";
95
import { isMocked } from "mm";
96
97
console.log(isMocked(fs, "readFileSync")); // => false
98
99
mm(fs, "readFileSync", () => "mock");
100
console.log(isMocked(fs, "readFileSync")); // => true
101
```
102
103
### Mock Restoration
104
105
Restore all mocked properties to their original values and clean up spy instrumentation.
106
107
```typescript { .api }
108
/**
109
* Restore all mocked properties to their original state
110
* Removes all spy instrumentation and resets call tracking
111
*/
112
function restore(): void;
113
```
114
115
**Usage Examples:**
116
117
```typescript
118
import fs from "node:fs";
119
import mm from "mm";
120
121
mm(fs, "readFileSync", () => "mock content");
122
console.log(fs.readFileSync("file.txt")); // => "mock content"
123
124
mm.restore();
125
console.log(fs.readFileSync("file.txt")); // Throws real file system error
126
```
127
128
### Automatic Spy Instrumentation
129
130
When mocking functions, mm automatically adds spy properties to track function calls:
131
132
```typescript { .api }
133
interface SpyProperties {
134
/** Number of times the function has been called */
135
called: number;
136
/** Array containing the arguments from each function call */
137
calledArguments: any[][];
138
/** Arguments from the most recent function call */
139
lastCalledArguments: any[];
140
}
141
```
142
143
**Usage Examples:**
144
145
```typescript
146
import mm from "mm";
147
148
const api = {
149
fetchUser: async (id: string) => ({ id, name: "Real User" })
150
};
151
152
mm(api, "fetchUser", async (id: string) => ({ id, name: "Mock User" }));
153
154
await api.fetchUser("123");
155
await api.fetchUser("456");
156
157
console.log(api.fetchUser.called); // => 2
158
console.log(api.fetchUser.calledArguments); // => [["123"], ["456"]]
159
console.log(api.fetchUser.lastCalledArguments); // => ["456"]
160
```
161
162
### Jest Mock Function Compatibility
163
164
mm recognizes and preserves Jest mock functions without adding duplicate spy instrumentation. When a Jest mock function is detected (via `_isMockFunction` property and `mock` object), mm skips adding its own spy wrapper.
165
166
```typescript
167
import mm from "mm";
168
import { jest } from "@jest/globals";
169
170
const mockFn = jest.fn(() => "jest mock");
171
mm(someObject, "method", mockFn);
172
173
// Jest's native mock properties are preserved and work normally
174
console.log(mockFn.mock.calls.length);
175
console.log(mockFn.mock.results);
176
console.log(mockFn.mock.instances);
177
178
// mm does not add conflicting spy properties when Jest mocks are used
179
// The function retains Jest's original behavior and tracking
180
```
181
182
**Usage Examples:**
183
184
```typescript
185
import { jest } from "@jest/globals";
186
import mm from "mm";
187
188
const api = {
189
fetchData: async () => "real data"
190
};
191
192
// Using Jest mock with mm
193
const jestMock = jest.fn().mockResolvedValue("jest mock data");
194
mm(api, "fetchData", jestMock);
195
196
await api.fetchData();
197
198
// Use Jest's assertions and properties
199
expect(jestMock).toHaveBeenCalledTimes(1);
200
expect(jestMock.mock.calls).toEqual([[]]);
201
202
// Mixed usage - some functions with Jest mocks, others with mm
203
const logMock = jest.fn();
204
mm(console, "log", logMock);
205
mm(api, "getData", () => "mm mock"); // Regular mm mock with spy properties
206
207
console.log("test");
208
api.getData();
209
210
expect(logMock).toHaveBeenCalledWith("test");
211
console.log(api.getData.called); // => 1 (mm spy properties)
212
```
213
214
### Async Function Type Safety
215
216
mm enforces type safety between async and sync function mocking to prevent runtime errors:
217
218
```typescript
219
const obj = {
220
asyncMethod: async () => "async result"
221
};
222
223
// This will work
224
mm(obj, "asyncMethod", async () => "mock result");
225
226
// This will throw an error at runtime
227
mm(obj, "asyncMethod", () => "sync result"); // Error: Can't mock async function to normal function
228
```
229
230
## Types
231
232
```typescript { .api }
233
// Property key types for mocking
234
type PropertyKey = string | number | symbol;
235
236
// Spy properties automatically added to mocked functions
237
interface SpyProperties {
238
called: number;
239
calledArguments: any[][];
240
lastCalledArguments: any[];
241
}
242
```