Testing a class that calls a utilities class, with typescript. The goal is to mock the utilities class and test the data passed to the calls.
A class to test
import {Utils} from "~/src/play/utils";
export class Actions {
constructor() {
}
async readFile(): Promise<void> {
const utils = new Utils();
await utils.action(5)
}
}
const actions = new Actions();
actions.readFile()
Utilities class
export class Utils {
constructor() {}
async action(count: number): Promise<boolean> {
console.log(count);
return Promise.resolve(true);
}
}
Test script
// @ts-ignore
import {Utils} from "./utils";
import {Actions} from "~/src/play/actions";
const mockUtils = jest.fn();
jest.mock('../utils', () => {
return {
Utils: jest.fn().mockImplementation(() => {
return {
default: () => {return {utils: mockUtils}},
action: () => {
return 5;
}
}
})
}
})
describe('actions', () => {
beforeEach(() => {
// Utils.mockClear();
mockUtils.mockClear();
})
test('success', async () => {
const actions = new Actions()
await actions.readFile()
expect(mockUtils).toHaveBeenCalledWith(2)
})
})
It doesn't appear to be picking up the mock. The result is
Error: expect(jest.fn()).toHaveBeenCalledWith(...expected)
Expected: 2
Number of calls: 0
at Object.<anonymous> (/Users/jrobens/NetBeansProjects/azuron/winpay-uploader/src/play/__test__/actions.spec.ts:28:27)
at processTicksAndRejections (internal/process/task_queues.js:95:5)
Taking @Stanislav Šolc advice add the return and argument value, including async
// @ts-ignore
import {Utils} from "../utils";
import {Actions} from "../actions";
const mockUtils = jest.fn();
jest.mock('../utils', () => {
return {
Utils: jest.fn().mockImplementation(() => {
return {
default: () => {return {utils: mockUtils}},
action: (count: number): Promise<boolean> => {
console.log(count);
return Promise.resolve(true);
}
}
})
}
})
The result doesn't change
You can use jest.spyOn(object, methodName) to mock Utils.prototype.action()
method. Use jest.restoreAllMocks() restores all mocks back to their original value in afterEach
hook. Prevent the value of mock from affecting other test cases.
E.g.
actions.ts
:
import { Utils } from './utils';
export class Actions {
constructor() {}
async readFile(): Promise<void> {
const utils = new Utils();
await utils.action(5);
}
}
utils.ts
:
export class Utils {
constructor() {}
async action(count: number): Promise<boolean> {
console.log(count);
return Promise.resolve(true);
}
}
actions.test.ts
:
import { Utils } from './utils';
import { Actions } from './actions';
describe('actions', () => {
afterEach(() => {
jest.restoreAllMocks();
});
test('success', async () => {
const actionSpy = jest.spyOn(Utils.prototype, 'action').mockResolvedValueOnce(false);
const actions = new Actions();
await actions.readFile();
expect(actionSpy).toHaveBeenCalledWith(5);
});
});
test result:
PASS examples/68879782/actions.test.ts (10.186 s)
actions
✓ success (3 ms)
------------|---------|----------|---------|---------|-------------------
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
------------|---------|----------|---------|---------|-------------------
All files | 71.43 | 100 | 75 | 71.43 |
actions.ts | 100 | 100 | 100 | 100 |
utils.ts | 33.33 | 100 | 50 | 33.33 | 5-6
------------|---------|----------|---------|---------|-------------------
Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: 10.827 s, estimated 11 s