Jest : mock constructor function - javascript

I'm having trouble trying to mock a constructor Function.
Here is the main class that I want to test
// main.js
import { Handler } from './handler/handler.js';
var lh = new Handler(windowAlias, documentAlias);
// rest of code
Here is how my Handler function looks. Im trying to mock this
//handler.js
export function Handler(windowAlias, documentAlias) {
this.windowAlias = windowAlias;
this.documentAlias = documentAlias;
this.attachEventListners = function(globalSet) {
// do something
};
}
And the test code:
// main.test.js
import { Handler } from 'handlers/handler'
describe('main script', () => {
it('test handler', () => {
jest.mock('handlers/handler', () => jest.fn())
const mockEventListner = jest.fn()
Handler.mockImplementation(() => ({mockEventListner}))
//call main.js
expect(mockEventListner).toBeCalledTimes(1);
})
I referred this stack overflow and tried but now Im getting error like _handler.Handler is not a constructor on the line that does new Handler(). How can I mock the new Handler call when its a constructor function

You could use jest.mock(moduleName, factory, options) to mock ./handler/handler.js module and Handler class manually.
E.g.
main.js:
import { Handler } from './handler/handler.js';
const windowAlias = 'windowAlias';
const documentAlias = 'documentAlias';
var lh = new Handler(windowAlias, documentAlias);
handler/handler.js:
export function Handler(windowAlias, documentAlias) {
this.windowAlias = windowAlias;
this.documentAlias = documentAlias;
this.attachEventListners = function(globalSet) {
// do something
};
}
main.test.js:
import './main';
import { Handler } from './handler/handler.js';
jest.mock('./handler/handler.js', () => {
return { Handler: jest.fn() };
});
describe('64382021', () => {
it('should pass', async () => {
expect(Handler).toBeCalledWith('windowAlias', 'documentAlias');
});
});
unit test result:
PASS src/stackoverflow/64382021/main.test.js
64382021
✓ should pass (6ms)
Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: 4.093s, estimated 10s

Related

How to check if one function triggers another function with `Mocha`, `Chai`, `Sinon`

How to create test with Mocha, Chai, Sinon to check if one function triggers another function.
I would like to check if funcToTrigger triggers funcToSpy
import { expect } from 'chai';
import sinon from 'sinon';
it('one function should trigger other function', () => {
const funcToSpy = () => {
console.log('I should be called');
};
const funcToTrigger = () => {
funcToSpy();
};
const spyFunc = sinon.spy(funcToSpy);
funcToTrigger();
expect(spyFunc.called).to.be.true;
});
When I test only one function it works fine:
it('function should be called', () => {
const funcToSpy = () => {
console.log('I should be called');
};
const spyFunc = sinon.spy(funcToSpy);
spyFunc();
expect(spyFunc.called).to.be.true;
});
Based on documentation:
var spy = sinon.spy(myFunc);
Wraps the function in a spy. You can pass this spy where the original
function would otherwise be passed when you need to verify how the
function is being used.
Usage examples:
import { expect } from 'chai';
import sinon from 'sinon';
it('use Object', () => {
const Test = {
funcToSpy: () => {
console.log('I should be called');
},
};
const funcToTrigger = () => {
Test.funcToSpy();
};
const spyFunc = sinon.spy(Test, 'funcToSpy');
funcToTrigger();
expect(spyFunc.called).to.be.true;
});
it('use Function', () => {
const funcToSpy = () => {
console.log('I should be called');
};
const spyFunc = sinon.spy(funcToSpy);
const funcToTrigger = () => {
spyFunc();
};
funcToTrigger();
expect(spyFunc.called).to.be.true;
});
it('use Function Argument', () => {
const funcToSpy = () => {
console.log('I should be called');
};
const funcToTrigger = (funcToSpy) => {
funcToSpy();
};
const spyFunc = sinon.spy(funcToSpy);
funcToTrigger(spyFunc);
expect(spyFunc.called).to.be.true;
});
Result:
$ npx mocha index.spec.js
I should be called
✓ use Object
I should be called
✓ use Function
I should be called
✓ use Function Argument
3 passing (3ms)
$
Your test fail because: funcToTrigger has defined and always calls the original funcToSpy.
In the 'use Object' case, funcToTrigger calls method inside object Test, which has been replaced by spy, which is wrapping funcToSpy.
In the 'use Function' case, funcToTrigger calls spy directly, and the spy is wrapping funcToSpy.
In the 'use Function Argument' case, funcToTrigger calls first argument which is a spy, which is wrapping funcToSpy.

Mocking a method on "this" object in jest

I have the following implementation:
export const actions = {
async submitPhoneNumber(context) {
let data = await this.$axios.
$get('https://jsonplaceholder.typicode.com/todos/1')
// do something with data
return data
}
}
When I run my test I get
TypeError: Cannot read property '$get' of undefined
How do I mock this.$axios.$get?
I looked at mocking global in jest but mocking global is just mocking window.whatever.
I need to mock this object.
This is my test:
import { actions } from '#/store/channel-add'
import flushPromises from 'flush-promises'
describe('channel-add', () => {
it('submits phone number and returns phone code hash', async () => {
let data = await actions.submitPhoneNumber()
await flushPromises()
expect(data).toBeTruthy()
})
})
Here is the solution:
index.ts:
export const actions = {
// I don't know where you get $axios from this, you didn't give the completed code. so I made a fake one for the demo.
$axios: {
$get: url => ''
},
async submitPhoneNumber(context) {
let data = await this.$axios.$get('https://jsonplaceholder.typicode.com/todos/1');
// do something with data
data = this.processData(data);
return data;
},
// for demo
processData(data) {
return data;
}
};
index.spec.ts:
import { actions } from './';
actions.$axios = {
$get: jest.fn()
};
describe('actions', () => {
it('should mock action.$axios.$get method', () => {
expect(jest.isMockFunction(actions.$axios.$get)).toBeTruthy();
});
it('should get data correctly', async () => {
(actions.$axios.$get as jest.Mock<any, any>).mockResolvedValueOnce({ userId: 1 });
const actualValue = await actions.submitPhoneNumber({});
expect(actualValue).toEqual({ userId: 1 });
expect(actions.$axios.$get).toBeCalledWith('https://jsonplaceholder.typicode.com/todos/1');
});
});
Unit tests result:
PASS src/mock-module/axios/index.spec.ts
actions
✓ should mock action.$axios.$get method (4ms)
✓ should get data correctly (4ms)
Test Suites: 1 passed, 1 total
Tests: 2 passed, 2 total
Snapshots: 0 total
Time: 2.181s, estimated 3s

mock a specific function in a module

I have two functions in one file
file1.ts:
const function1 = () => {
return 123;
};
const function2 = () => {
return function1() + 2;
};
export { function1, function2 };
I'm writing unit tests using jest for function 2. but I'm unable to mock function1
I just tried to use jest.spyOn to mock function1
import * as helperFunctions from 'file1';
describe('test function2 ', () => {
let functionSpy: any;
beforeAll(() => {
functionSpy = jest.spyOn(helperFunctions, 'function1 ');
});
afterAll(() => {
functionSpy.mockReset();
});
test('test', () => {
functionSpy.mockReturnValue(1);
expect(helperFunctions.function2()).toEqual(3);
});
});
in my test, function1 is not mocked, it still calls the actual implementation.
Any help is appreciated.
Here is the solution:
index.ts:
const function1 = () => {
return 123;
};
const function2 = () => {
return exports.function1() + 2;
};
exports.function1 = function1;
exports.function2 = function2;
Unit test:
describe('test function2 ', () => {
const helperFunctions = require('./');
helperFunctions.function1 = jest.fn();
test('test', () => {
helperFunctions.function1.mockReturnValueOnce(1);
expect(helperFunctions.function2()).toEqual(3);
});
});
Unit test result:
PASS src/stackoverflow/56354252/index.spec.ts
test function2
✓ test (8ms)
Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: 2.696s, estimated 3s
You can find this issue for more detail: https://github.com/facebook/jest/issues/936#issuecomment-214939935

How to properly mock a node module for jest unit testing

I'm new to jest and just want to implement a unit test for a simple function that uses a third party node module.
function to test (say it lives in utilFolder.js):
import moduleName from 'third_party_module'
const util = {
simple_function() {
const name = moduleName.func1();
}
}
export default util;
test file:
import util from "utilFolder";
import moduleName from 'third_party_module';
jest.mock("third_party_module", () => ({
func1: jest.fn()
}));
describe("was mocked functions called", () {
test("was mocked functions called??", () => {
util.simple_function();
expect(moduleName.func1).toHaveBeenCalled();
});
});
Error:
Expected mock function to have been called, but it was not called.
Any help please?
Use jest.mock mock the module. Here is the working example:
util.js:
import moduleName from './third_party_module';
const util = {
simple_function() {
const name = moduleName.func1();
}
};
export default util;
third_party_module.js:
export default {
func1() {}
};
util.spec.js:
import util from './util';
import moduleName from './third_party_module';
jest.mock('./third_party_module', () => ({
func1: jest.fn()
}));
describe('was mocked functions called', () => {
test('was mocked functions called??', () => {
util.simple_function();
expect(moduleName.func1).toHaveBeenCalled();
});
});
Unit test result:
PASS src/stackoverflow/54729837/util.spec.js (8.414s)
was mocked functions called
✓ was mocked functions called?? (4ms)
Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: 9.742s
Source code: https://github.com/mrdulin/jest-codelab/tree/master/src/stackoverflow/54729837

How to restore a mock implementation between tests in jest?

I'm trying to create two tests for distinct functions in the same file.
I have func1 that calls func2 inside it, so I'm spying on func2 and mocking its implementation to test func1, and by the end of the first test I'm restoring the mock.
The problem is that the second test fails because func2 implementation is still mocked.
Why didn't the mock restore?
describe('myClass.func1', () => {
it('returns true', async () => {
const func2spy = jest.spyOn(myClass, 'func2').mockImplementation(() => true);
await expect(func1()).toBe(true);
func2spy.mockRestore();
})
});
describe('myClass.func2', () => {
it('returns false if argument is 0', () => {
expect(func2(0)).toBe(false);
})
});
Here is a demo works for me:
index.ts:
export class MyClass {
constructor() {}
public async func1() {
return this.func2();
}
public func2(int?: number) {
return false;
}
}
index.spec.ts:
import { MyClass } from './';
const myClass = new MyClass();
describe('MyClass.func1', () => {
it('returns true', async () => {
const func2Spy = jest.spyOn(myClass, 'func2').mockImplementation(() => true);
const actualValue = await myClass.func1();
expect(actualValue).toBeTruthy();
func2Spy.mockRestore();
});
});
describe('myClass.func2', () => {
it('returns false if argument is 0', () => {
expect(myClass.func2(0)).toBe(false);
});
});
Unit test result:
PASS src/stackoverflow/50912106/index.spec.ts
MyClass.func1
✓ returns true (7ms)
myClass.func2
✓ returns false if argument is 0 (1ms)
Test Suites: 1 passed, 1 total
Tests: 2 passed, 2 total
Snapshots: 0 total
Time: 4.939s, estimated 5s

Categories