Jest:模拟NPM模块方法



我需要测试一个函数,其中我调用了NPM包中的另一个名为'heartbeats'的函数:

index.ts

export async function checkUp(app: App, heart, beats: number, iterations: number): Promise<void> {
// const heart = heartbeats.createHeart(1000, 'checkUp');
heart.createEvent(beats, { countTo: iterations }, async (count, last) => {
const secondCheck = await secondCheckStatus();
if (!secondCheck) {
app.quit();
}
});
}

index.test.ts

import * as Heartbeats from 'heartbeats';
import { secondCheckStatus } from './utils';
...
jest.mock('./utils', () => ({
...jest.requireActual('./utils'),
secondCheckStatus: jest.fn(),
}));
const mockSecondCheckStatus = secondCheckStatus as jest.MockedFunction< typeof secondCheckStatus >;
...
beforeEach(() => {
jest.clearAllMocks();
});
...
it('should auto kill app after checks', async () => {
const mockApp = new MockApp() as unknown as jest.Mocked<App>;
const mockHeart = Heartbeats.heart as unknown as jest.Mock;
const mockCreateEvent = Heartbeats.heart.createEvent as unknown as jest.MockedFunction<
typeof Heartbeats.heart.createEvent
>;
mockCreateEvent.mockImplementation((beats, iter, cb) => {
cb(null, null);
});
mockSecondCheckStatus.mockResolvedValueOnce(false);
mockApp.requestSingleInstanceLock.mockReturnValue(true);
const isRunning = await checkUp(mockApp, mockHeart, 1, 1);
await main(mockApp);
expect(mockApp.quit).toHaveBeenCalledTimes(1);
expect(isRunning).toBe(false);
});

但是我总是得到:

TypeError: Cannot read property 'mockImplementation' of undefined

83 |     typeof Heartbeats.heart.createEvent
84 |   >;
> 85 |   mockCreateEvent.mockImplementation((beats, iter, cb) => {

你知道我做错了什么吗?

非常感谢(对我来说还有很长的路要走)

由于checkUp函数接受appheart作为其参数,因此您可以创建与这些参数类型或接口匹配的模拟对象。

只有secondCheckStatus函数是通过import关键字导入的,您必须使用jest.mock()方法来模拟它。

要处理模拟对象/函数的TS类型问题,可以使用ts-jest的mock (item: T, deep = false)辅助函数。

index.ts:

import { secondCheckStatus } from './utils';
export async function checkUp(app, heart, beats: number, iterations: number): Promise<void> {
heart.createEvent(beats, { countTo: iterations }, async (count, last) => {
const secondCheck = await secondCheckStatus();
if (!secondCheck) {
app.quit();
}
});
}

util.ts:

export async function secondCheckStatus() {
return true;
}

index.test.ts:

import { checkUp } from './';
import { secondCheckStatus } from './utils';
import { mocked } from 'ts-jest/utils';
jest.mock('./utils', () => ({
...(jest.requireActual('./utils') as object),
secondCheckStatus: jest.fn(),
}));
const mockSecondCheckStatus = mocked(secondCheckStatus);
describe('69720608', () => {
beforeEach(() => {
jest.clearAllMocks();
});
test('should pass', async () => {
const mockApp = {
quit: jest.fn(),
};
const mockHeart = {
createEvent: jest.fn().mockImplementation(async (beats, options, callback) => {
await callback();
}),
};
await checkUp(mockApp, mockHeart, 1, 1);
expect(mockSecondCheckStatus).toBeCalledTimes(1);
expect(mockApp.quit).toBeCalledTimes(1);
});
});

测试结果:

PASS  examples/69720608/index.test.ts (13.424 s)
69720608
✓ should pass (4 ms)
----------|---------|----------|---------|---------|-------------------
File      | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s 
----------|---------|----------|---------|---------|-------------------
All files |   88.89 |       50 |      75 |    87.5 |                   
index.ts |     100 |       50 |     100 |     100 | 6                 
utils.ts |      50 |      100 |       0 |      50 | 2                 
----------|---------|----------|---------|---------|-------------------
Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        15.478 s