I have this code that need to test
import Logger from './logger';
const logger = new Logger();
export function myFunction() {
// do something
logger.log('Hello');
}
How to test if function myFunction
has called logger.log? This is what I ve tried but failed
jest.mock('./logger');
const mockedLoggerClass = <jest.Mock>Logger;
describe('Test myFunction', () => {
it('should call logger log', () => {
const loggerInstance = {
log: jest.fn()
}
mockedLoggerClass.mockReturnValue(() => loggerInstance);
myFunction()
expect(loggerInstance.log).toBeCalled; // Nope no call
});
})
here is another try
const loggerInstance = {
log: jest.fn()
}
jest.mock('./logger', () => {
return function () {
return loggerInstance; // ReferenceError: Cannot access 'loggerInstance' before initialization
}
});
describe('Test myFunction', () => {
it('should call logger log', () => {
myFunction()
expect(loggerInstance.log).toBeCalled;
});
})
I know we should not init logger as global scope but this is not my code so I cannot touch it.
CodePudding user response:
Your loggerInstance
and the logger
in the production code are not the same references. logger
variable will be created right after you import myFunction
, then you have to get this Logger instance instead of trying to mock another instance.
To do it, you can get a mock instance by jest:
import { myFunction } from './index'; // a mocked logger already created
import Logger from './logger';
jest.mock('./logger'); // mock it
describe('myFunction', () => {
let logger: jest.Mocked<Logger>;
beforeEach(() => {
logger = (Logger as jest.Mock).mock.instances[0]; // get the mocked instance
});
it('should call Logger.log function with "Hello"', () => {
myFunction(); // action
expect(logger.log).toBeCalledWith('Hello'); // expectation
})
});
You create a dependency (logger) in a high component (myFunction
), this is an anti dependence injection pattern, which makes your code become hard to test. You can try module pattern, just export default new Logger()
instead of export default class Logger...