How to use Jasmine.js spy on a required function - javascript

I have this code (Node.js):
File: utils.js
// utils.js
const foo = () => {
// ....
}
const bar = () => {
// ....
}
module.exports = { foo, bar }
File: myModule.js
// myModule.js
const {
foo,
bar
} = require('./utils');
const bizz = () => {
let fooResult = foo()
return bar(fooResult)
}
module.exports = { bizz }
File: myModule.spec.js
// myModule.spec.js
const { bizz } = require('./myModule');
describe('myModule', () => {
it('bizz should return bla bla bla', () => {
let foo = jasmine.createSpy('foo').and.returnValue(true)
let bar = jasmine.createSpy('bar').and.callFake((data) => {
expect(date).toBeTrue();
return 'fake-data'
})
expect(bizz()).toBe('fake-data')
})
})
I'm trying to test bizz using spies on foo and bar functions but it's not working well.
Can anyone explain to me how to create spies on these functions with the purpose to test bizz??

Yes, it is possible.
You just need to require utils to spyOn first, then require myModule. The following test will pass.
const utils = require('./utils');
// myModule.spec.js
describe('myModule', () => {
it('bizz should return bla bla bla', () => {
const fooSpy = spyOn(utils, 'foo').and.returnValue(true);
const barSpy = spyOn(utils, 'bar').and.callFake(data => {
expect(data).toBeTrue();
return 'fake-data';
});
const { bizz } = require('./myModule'); // Import myModule after you added the spyOn
expect(bizz()).toBe('fake-data');
expect(fooSpy).toHaveBeenCalled();
expect(barSpy).toHaveBeenCalled();
});
});
Hope it helps

Seems like it's not possible. https://github.com/mjackson/expect/issues/169

Related

clear encapsulated value in imported module - Jest js

Let's say I'm importing to Jest module like:
let var;
export const getVar = () => {
if(var == null) {
var = Date.now()
}
return var;
}
I am trying to make unit tests for this module, however, on every unit test I have to reset the "var" value. I've tried to redefine the module using require on "beforeEach" method but it does not work. Does anyone know how to reset encapsulated values like this?
Using old require syntax and resetModules
foo.js
let foo;
const getFoo = () => {
if (!foo) {
foo = "foo";
} else {
foo = "bar";
}
return foo;
};
module.exports = { getFoo };
foo.test.js
beforeEach(() => jest.resetModules());
test("first", () => {
const { getFoo } = require("./foo");
expect(getFoo()).toBe("foo");
});
test("second", () => {
const { getFoo } = require("./foo");
expect(getFoo()).toBe("foo");
});
Using dynamic import and resetModules
foo.js
let foo;
export const getFoo = () => {
if (!foo) {
foo = "foo";
} else {
foo = "bar";
}
return foo;
};
foo.test.js
import { jest } from "#jest/globals";
beforeEach(async () => {
jest.resetModules();
});
test("first", async () => {
const { getFoo } = await import("./foo.js");
expect(getFoo()).toBe("foo");
});
test("second", async () => {
const { getFoo } = await import("./foo.js");
expect(getFoo()).toBe("foo");
});

How to mock functions called within the test function

I have module that contains several functions (foo, bar, etc).
// moduleA.js
const someModule = require('someModule')
const moduleA = () => {
const bar = (param1, param2) => {
// some implementation
}
const foo = (params) => {
// some implementation
bar(1, 2)
}
return Object.assign({}, someModule, {
foo,
bar
})
}
module.exports = moduleA
What I want to do is to mock other module functions (bar) being called within my current test (foo) function.
// jest test file
describe('Testing foo, mocking bar', () => {
const checker = moduleA()
it.only('When this, then that', async () => {
// THIS IS NOT WORKING
const spy = jest.spyOn(checker, "bar").mockReturnValue("XXXX")
const response = await checker.foo({ 1, 2, 3})
expect(response).toBeDefined()
})
})
What is the correct way to spy or stub the bar function so that I can mock the results and only focus testing the foo functionality?

Jest mocking module that exports a class and functions

I have a module that exports a class and 2 functions and that module is imported into a file that is being tested.
someFile.js
const {theclass, thefunction} = require("theModule");
const getSomeFileData = () => {
let obj = new theclass();
//some logic
return obj.getData();
}
In the test file, I want to mock the module "theModule" and return a known value when the function obj.getData() is called. How would I go about mocking this module("theModule") when testing file "someFile.js"?
Edit:
.spec.ts
import { someFunction } from './index-test';
jest.mock('lodash', () => {
return {
uniqueId: () => 2,
};
});
describe('', () => {
it('', () => {
expect(someFunction()).toBe(2);
});
});
index-test.ts
import { uniqueId } from 'lodash';
export const someFunction = () => {
return uniqueId();
};

Unit testing an inner function?

I have a function that has inner functions, for my unit test, I only want to test the functionality of the inner function, but when I export the function and call the inner function, npm tests returns an error.
In my main.js:
mainFunction = () => {
functionToBeTested = () => {
// some code
}
}
module.exports = {mainFunction: mainFunction}
In my test.js
const chai = require("chai");
const assert = require("chai").assert;
const mainFunction = require("./main");
describe ("test", () => {
it("returns results", () => {
let result = mainfunction.functionToBeTested(args);
//equal code
});
})
But when I run npm test, it says:
mainfunction.functionToBeTested is not a function.
What am I doing wrong?
If you want to chain your functions you can try something like that.
main.js
const mainFunction = () => {
const functionToBeTested = () => {
return "I got it";
}
return { functionToBeTested };
}
module.exports = { mainFunction };
test.js
const chai = require("chai");
const assert = require("chai").assert;
const mainFunction = require("./main");
const mf = mainFunction();
describe ("test", () => {
it("returns results", () => {
let result = mf.functionToBeTested(args);
//equal code
});
});
Actually, you can't call a function declare inside another function that way. A solution would be to declare functionToBeTested outside mainFunction, then call it :
main.js
const functionToBeTested = () => {
// some code
};
const mainFunction = () => {
functionToBeTested();
};
module.exports = { mainFunction, functionToBeTested }
test.js
const chai = require("chai");
const assert = require("chai").assert;
const { mainFunction, functionToBeTested } = require("./main");
describe ("test", () => {
it("tests mainFunction", () => {
let main = mainfunction(args);
...
});
it("tests functionToBeTested"), () => {
let tested = functionToBeTested(args);
...
});
})
It is because only mainFunction() is exported and not the functionToBeTested(), outside this module JS doesn't knows about the existence of the functionToBeTested().
I will recommend you to move functionToBeTested separated and export that as well or have a helper method for calling it.

Mocking complex module using Jest.js

This is what the module I want to mock looks like:
class TheModule {
constructor() {
this.subClass = new SubClass();
}
}
class SubClass {
constructor() {
this.someMethod = () => 'Did Something great';
}
}
module.exports = TheModule;
This is TheModule usage I want to test:
const TheModule = require('./TheModule');
const method = () => {
const theModule = new TheModule();
return theModule.subClass.someMethod();
}
module.exports = method;
This is my test:
describe('method test', () => {
it('should return "Test pass"', () => {
jest.doMock('./TheModule');
const theModuleMock = require('./TheModule');
const method = require('./TheModuleUsage');
const mock = () => 'Test pass';
theModuleMock.subClass.someMethod.mockImplementation(() => mock);
expect(method()).toEqual('Test pass');
});
});
When I run this test I get TypeError: Cannot read property 'someMethod' of undefined
Is it possible to mock this module without changing TheModule implementation?
If you will export SubClass you can mock it without changing TheModule but in your case you should mock SubClass property in TheModule explicitly with factory for example:
describe('method test', () => {
it('should return "Test pass"', () => {
let mockedSomeMethod = jest.fn().mockImplementation(() => 'Test pass');
jest.doMock('./TheModule', () => {
// mock constructor
return jest.fn().mockImplementation(() => {
return { subClass: { someMethod: mockedSomeMethod } }
});
});
const method = require('./TheModuleUsage');
expect(method()).toEqual('Test pass');
});
});

Categories