I need to test a function where I call another function from an NPM package called '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);
});
But I always get:
TypeError: Cannot read property 'mockImplementation' of undefined
83 | typeof Heartbeats.heart.createEvent
84 | >;
> 85 | mockCreateEvent.mockImplementation((beats, iter, cb) => {
Any idea what I am doing wrong?
Thanks a lot (still long way for me to work smoothly with Jest)
CodePudding user response:
Since the checkUp
function accepts app
and heart
as its parameters, you can create mock objects that match these parameter types or interfaces.
Only the secondCheckStatus
function is imported by the import
keyword, you have to use jest.mock()
method to mock it.
For handling the TS type issue for mocked object/function, you can use mocked(item: T, deep = false) helper function of ts-jest
.
E.g.
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);
});
});
test result:
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