I am very new to jest testing. I have below implementation class
import { ExternalObject } from 'external-library';
export class MyClass {
public createInstance(settings : ISettings) : ExternalObject {
const setting1 = settings.getSetting("setting1");
const setting2 = settings.getSetting("setting2");
return new ExternalObject(setting1, setting2);
}
}
I am trying to test this class and I have been able to mock out settings correctly. However I am unable to mock the external object construction new ExternalObject(setting1, setting2);
and my test case is failing as it is trying to construct actual object (which fails as the parameters passed are not valid values in real).
describe("Create Instance", () => {
test("Allow creation of external instance", () => {
// not sure if I am using this correctly?
// Aim is to mock out external module and any objects it may need creating
jest.mock('external-library', () => {
return {
ExternalObject: jest.fn().mockImplementation()
}
});
let settings: ISetting = new Settings();
jest.spyOn(settings, "getSetting")
.mockImplementationOnce(() => 'abcd')
.mockImplementationOnce(() => 'xyz')
let myImpl = new MyClass();
let inst = myImpl.createInstance(settings);
// expecting that the instance is created successfully.
expect(inst).toBeTruthy();
});
});
However I was not sure what I am doing wrong here. I did go through the documentation and some of the other questions but was unable to understand what I am missing out on.
Using jest.mock()
in a function scope, the mocked module will not be hoisted to the top of the code block. This will result in the external-library
module not being mocked when importing the code being tested. Just move jest.mock()
to the module scope of the test file.
E.g.
MyClass.ts
:
//@ts-ignore
import { ExternalObject } from 'external-library';
import { ISettings } from './Settings';
export class MyClass {
public createInstance(settings: ISettings): ExternalObject {
const setting1 = settings.getSetting('setting1');
const setting2 = settings.getSetting('setting2');
return new ExternalObject(setting1, setting2);
}
}
Settings.ts
:
export interface ISettings {
getSetting(key: string): void;
}
export class Settings implements ISettings {
getSetting(key: string) {
return 'real implementation';
}
}
MyClass.test.ts
:
import { MyClass } from './MyClass';
import { ISettings, Settings } from './Settings';
//@ts-ignore
import { ExternalObject } from 'external-library';
jest.mock(
'external-library',
() => {
return { ExternalObject: jest.fn() };
},
{ virtual: true }
);
describe('68545423', () => {
afterEach(() => {
jest.restoreAllMocks();
});
afterAll(() => {
jest.resetAllMocks();
});
test('should pass', () => {
let myImpl = new MyClass();
let settings: ISettings = new Settings();
jest
.spyOn(settings, 'getSetting')
.mockImplementationOnce(() => 'abcd')
.mockImplementationOnce(() => 'xyz');
let inst = myImpl.createInstance(settings);
expect(inst).toBeTruthy();
expect(ExternalObject).toBeCalledWith('abcd', 'xyz');
});
});
test result:
PASS examples/68545423/MyClass.test.ts (7.233 s)
68545423
✓ should pass (4 ms)
-------------|---------|----------|---------|---------|-------------------
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
-------------|---------|----------|---------|---------|-------------------
All files | 85.71 | 100 | 50 | 85.71 |
MyClass.ts | 100 | 100 | 100 | 100 |
Settings.ts | 50 | 100 | 0 | 50 | 7
-------------|---------|----------|---------|---------|-------------------
Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: 8.032 s, estimated 9 s
Ran all test suites related to changed files.