'Jest manual mock of named class export
I'm trying to do a manual mock of a named ES6 class export, but I'm not if it's just not possible, or if I'm doing something wrong. I would like to do it this way so that the same mocks can be imported across several different test files rather than having to duplicate them in each test file. Here is a simplified example of what I want to do:
File structure:
.
└── test
├── __mocks__
└── test.service.ts
├── __tests__
└── test.consumer.spec.ts
├── test.service.ts
└── test.consumer.ts
test.service.ts
export default class TestService {
private readonly field: string;
constructor(field: any) {
this.field = field;
}
foo() {
console.log(this.field);
}
}
test.consumer.ts
import TestService from './test.service';
export default {
useService: () => {
const service = new TestService('Field value');
service.foo();
return true;
},
};
__ mocks __/test.service.ts
export const mockFoo = jest.fn();
const mock = jest.fn().mockImplementation(() => {
return { foo: mockFoo };
});
export default mock;
__ tests __/test.consumer.spec.ts
import TestConsumer from '../test.consumer';
import MockService, { mockFoo } from '../__mocks__/test.service';
jest.mock('../test.service');
describe('TestConsumer...', () => {
beforeEach(() => {
MockService.mockClear();
mockFoo.mockClear();
});
test('It works', () => {
const val = TestConsumer.useService();
expect(val).toEqual(true);
expect(mockFoo).toHaveBeenCalledTimes(1);
expect(MockService).toHaveBeenCalledTimes(1);
});
});
When running the test, I get this output:
FAIL src/test/__tests__/test.consumer.spec.ts
TestConsumer...
× It works (3 ms)
● TestConsumer... › It works
expect(jest.fn()).toHaveBeenCalledTimes(expected)
Expected number of calls: 1
Received number of calls: 0
12 | const val = TestConsumer.useService();
13 | expect(val).toEqual(true);
> 14 | expect(mockFoo).toHaveBeenCalledTimes(1);
| ^
15 | expect(MockService).toHaveBeenCalledTimes(1);
16 | });
17 | });
at Object.<anonymous> (src/test/__tests__/test.consumer.spec.ts:14:21)
Test Suites: 1 failed, 1 total
Tests: 1 failed, 1 total
Snapshots: 0 total
Time: 3.685 s, estimated 4 s
I can confirm that it is the real foo function that is being called. I've tried changing the way I import MockService and mockFoo to match the docs here by changing it to import MockService, { mockFoo } from '../test.service'; but then it complains that mockFoo is not exported.
Any help/suggestions are appreciated
Solution 1:[1]
Importing from __mocks__ doesn't seem to be a good idea. You should initialize a mock function from the test suite and manage the function from there.
import TestConsumer from '../test.consumer';
import MockService from '../test.service';
jest.mock('../test.service');
describe('TestConsumer...', () => {
const mockFoo = jest.fn();
beforeAll(() => {
MockService.mockImplementation(() => ({ foo: mockFoo }));
});
beforeEach(jest.clearAllMocks);
test('It works', () => {
const val = TestConsumer.useService();
expect(val).toEqual(true);
expect(mockFoo).toHaveBeenCalledTimes(1);
expect(MockService).toHaveBeenCalledTimes(1);
});
});
This way you won't need __mocks__/test.service.ts at all.
EDIT: Importing from the module to be mocked will work (rather than from __mocks__).
import TestConsumer from '../test.consumer';
import MockService, { mockFoo } from '../test.service';
jest.mock('../test.service');
describe('TestConsumer...', () => {
beforeEach(jest.clearAllMocks);
test('It works', () => {
const val = TestConsumer.useService();
expect(val).toEqual(true);
expect(mockFoo).toHaveBeenCalledTimes(1);
expect(MockService).toHaveBeenCalledTimes(1);
});
});
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 |
