Do I need to mock the required module in Jest testing - jasmine

I had a mixin/Utils.js to test, where underscore is required and used in the module. Something like:
var _ = require('underscore');
var Utils = {
foo: function(arrayOfArray) {
return _.sortBy(arrayOfArray, function(array) {
return -1 * array[1].length;
}) || {};
}
};
module.exports = Utils;
When I tried to use Jest to test it, I made something like below. But the test failed. I had a feeling that was because I didn't mock the underscore. But how should I mock that? And in general if the module has dependencies like underscore, how should I set the mock correctly and test the module?
var __path__ = "PATH_TO/mixins/Utils.js";
jest.dontMock(__path__);
describe("Test for mixins/Utils.js", function() {
var Utils;
beforeEach(function() {
Utils = require(__path__);
});
describe("countInversion", function() {
it('Passing in [[0, [1,2]], [1, [1,2,3]]] and should get [[1, [1,2,3]]],[0, [1,2]] ', function() {
var testInput = [[0, [1,2]], [1, [1,2,3]]];
var expectedOutput = [[1, [1,2,3]]],[0, [1,2]];
expect(Utils.FOO(testInput)).toEqual(expectedOutput);
});
});
});

Jest mocks everything by default so you you actually do not want to mock underscore if your unit test depends on functionality in underscore. You should either add jest.dontMock('underscore') to your test, or include it in the unmockedModulePathPatterns property of your jest config to get the output you expect.
Edit
As #pgericson has noted in the comments, Jest no longer automocks as of jest 15. Jasmine spies can be used in lieu of automocks.

Related

Testing an Async function using Jest / Enzyme

Trying run a test case for the following:
async getParents() {
const { user, services, FirmId } = this.props;
let types = await Models.getAccounts({ user, services, firmId: FirmId });
let temp = types.map((type) => {
if(this.state.Parent_UID && this.state.Parent_UID.value === type.Account_UID) {
this.setState({Parent_UID: {label: type.AccountName, value: type.Account_UID}})
}
return {
label: type.AccountName,
value: type.Account_UID,
}
})
this.setState({ParentOptions: temp});
}
here is what i have so far for my test:
beforeEach(() => wrapper = mount(<MemoryRouter keyLength={0}><AccountForm {...baseProps} /></MemoryRouter>));
it('Test getParents function ',async() => {
wrapper.setProps({
user:{},
services:[],
FirmId:{},
})
wrapper.find('AccountForm').setState({
SourceOptions:[[]],
Parent_UID: [{
label:[],
value:[],
}],
});
wrapper.update();
await
expect(wrapper.find('AccountForm').instance().getParents()).toBeDefined()
});
If i try to make this ToEqual() it expects a promise and not anobject, what else could I add into this test to work properly.
Goal: Make sure the functions gets called correctly. The test is passing at the moment and has a slight increase on test coverage.
Using Jest and Enzyme for React Js
you can put the await before the async method, like:
await wrapper.find('AccountForm').instance().getParents()
and compare if the state was changed.
In another way, if can mock your API request, because this is a test, then you do not need the correct API, but know if the function calls the API correctly and if the return handling is correct.
And, you cand spy the function like:
const spy = jest.spyOn(wrapper.find('AccountForm').instance(), 'getParents');
and campare if the function was called if they are triggered by some action:
expect(spy).toBeCalled()

Using Jasmine spyOn to mock function in Browserify module

I'm trying to run a unit test on a function (testFunc). testFunc calls another function (secondFunc) which I would like to mock. Can I mock secondFunc so that when it is called in the context of testFunc, the spiedOn version of secondFunc is called? If not, how should I reformat my browserify module to make it testable?
Currently the setup looks something like this:
app.js (Browserify Module)
module.exports = (function () {
function testFunc() {
secondFunc();
}
function secondFunc(){
console.log('not mocked!');
}
return {
testFunc, secondFunc
};
})();
test.js (Jasmine Test)
describe("testFunc", () => {
let app = require('./app');
beforeEach(() => {
spyOn(app, 'secondFunc');
});
it("should call secondFunc spy", () => {
app.testFunc();
expect(app.secondFunc).toHaveBeenCalled();
});
});
The way you have it now, the spyOn is replacing the secondFunc property on your returned object with a proxy, but your code calls the secondFunc function that is inside the closure of the anonymous function. There are several ways to restructure your code to better expose the functions.
You could structure your module this way:
exports.testFunc = function() {
exports.secondFunc();
}
exports.secondFunc = function(){
console.log('not mocked!');
}
which is a lot smaller, easier to read, and let you mock the secondFunc function.
The reason this is happening is because you are setting up a mock on the returned object, but the code is calling the internal function. What I've done in the past is something like this:
module.exports = (function () {
function testFunc() {
api.secondFunc(); // Call the API function, which is what is mocked
}
function secondFunc(){
console.log('not mocked!');
}
var api = {
testFunc, secondFunc
};
return api;
})();

How to verify with Jasmine that a module called a sub-module method with correct arguments

The following test spec simulates calling a module that writes some content to the file system. Internally it uses fs to do that. I want to make sure fs.writeFile() was called with correct parameters. However, the toHaveBeenCalledWith() doesn't seem to work with a generic Function argument. Any ideas on how to make toHaveBeenCalledWith work as I expect?
Test Spec:
var fs = {
writeFile: function (arg1, arg2, cb){}
}
var writeContent = {
toFS: function (){
var path = "some/calculated/path";
var content = "some content";
fs.writeFile(path, content, function(){})
}
}
describe("writeContent", function() {
var writeFileSpy = null;
beforeEach(function() {
writeFileSpy = jasmine.createSpy('writeFileSpy');
spyOn(fs, 'writeFile').and.callFake(writeFileSpy);
});
it("can call spy with callback", function() {
writeContent.toFS();
expect(writeFileSpy).toHaveBeenCalledWith("some/calculated/path", "some content", Function);
});
});
Results:
Message:
Expected spy writeFileSpy to have been called with [ 'some/calculated/path', 'some content', Function ] but actual calls were [ 'some/calculated/path', 'some content', Function ].
Answering my own question :-) Just needed to enclose Function in jasmine.any() as in:
expect(writeFileSpy).toHaveBeenCalledWith("some/calculated/path", "some content", jasmine.any(Function));

Qunit test not recognizing defined object

I have a JS method I'm looking to test:
doMediation: function() {
var state,
that = this,
mediation_rule = "asdf";
Mediation.getRules(mediation_rule, function () {
[blah blah]
});
},
My Mediation object is defined above this method in my class. This is my qunit test:
test('doMediation: testing mediation', 1, function(){
var proto = $.extend({}, My.prototype, {
Mediation: {
getRules: function(rule, cb){}
}
proto.doMediation();
});
The problem is that I'm getting an error:
Died on test #1: Cannot call method 'getRules' of undefined - {}
Yet, it is defined right there in the test. Thanks.
Turns out that previously, Mediation was defined as such: var Mediation = AnotherClass.Mediation. In the qunit test, I had to actually define AnotherClass.Mediation = {} instead of Mediation{}

Skipping a test in Qunit

I just found qHint, a method to integrate jsHint testing into Qunit... but it doesn't work locally (I don't mean localhost) except in Firefox.
So I wanted to add a "warning" or "notice", NOT a test failure, showing that the test was skipped:
// do unit test if not local or local and running Firefox
t = QUnit.isLocal;
if (!t || (t && /Firefox/.test(navigator.userAgent))) {
jsHintTest('JSHint core check', 'js/myplugin.js');
} else {
test('JSHint core check (skipped)', function(){
ok( true, 'check not done locally' );
});
}
I would just like to make it more obvious that a test was skipped, is this possible?
Update: Thanks to Odi for the answer!, but I had to make a slight modification to make the code work in QUnit v1.11.0pre:
QUnit.testSkip = function( testName, callback ) {
QUnit.test(testName + ' (SKIPPED)', function() {
if (typeof callback === "function") {
callback();
}
var li = document.getElementById(QUnit.config.current.id);
QUnit.done(function() {
li.style.background = '#FFFF99';
});
});
};
testSkip = QUnit.testSkip;
I had the same requirement and I simply defined a new kind of test() that I called testSkip().
This test method simply replaces your test function and changes the name to <test name> (SKIPPED). After that the test is considered passed by QUnit.
To further indicate that this is a skipped test, I added a callback function to QUnit.done for each skipped test to change the color of the test in the HTML output to yellow. These callbacks are executed when the test suite is done. Setting the value directly does not work, because QUnit applies the styles for passed/failed tests at the end of the run.
QUnit.testSkip = function() {
QUnit.test(arguments[0] + ' (SKIPPED)', function() {
QUnit.expect(0);//dont expect any tests
var li = document.getElementById(QUnit.config.current.id);
QUnit.done(function() {
li.style.background = '#FFFF99';
});
});
};
testSkip = QUnit.testSkip;
Then you can use testSkip() instead of test() for skipped tests.
For my test suite the result looks like that:
For anyone who may have glazed over the comments, Mottie's comment on the question points out that Qunit now has a skip() function. Just replace any call to test() with skip() to skip that test.

Resources