use jest mock functions to test code that calls another server - unit-testing

Roughly, my JavaScript function that I want to unit-test looks like this:
const request = require('request-promise-native');
async function callServer() {
// Prepare parameters
// Call `request` with parameters
// Parse response JSON and return
}
Is there any way to unit-test this function without making an actual call to the real server? Can I use a jest mock function to somehow override request()? To do that, will I need to modify every function to take the request function as a parameter or there is another way?

You can mock imported module via jest.mock. https://jestjs.io/docs/en/api#requirerequiremockmodulename
describe('main description', () => {
it('description of test case', () => {
jest.mock('request-promise-native', () => {
return {}; // Return what the request-promise-native supposed to return
});
const result = callServer();
expect(result).toBe({});
});
});

Related

jest.fn() v/s jest.mock()?

For mocking uuidv4, I am using this :
import { v4 as uuidv4 } from "uuid";
jest.mock("uuid");
uuidv4.mockReturnValue("uuid123");
And for mocking window.confirm, I am using this:
window.confirm = jest.fn().mockImplementation(() => true);
These both are working all right.
But when i try doing this i.e
const uuidv4 = jest.fn.mockImplementation(() => "uuid123");
I get this error
TypeError: jest.fn.mockImplementation is not a function
I am confused between jest.fn() and jest.mock().
Can someone please elaborate on which one to use and when to use, with suitable example?
Just a quick explanation for you:
jest.mock is to mock a certain module. Once you write jest.mock('uuid') then it means all exported things would be turned to a jest.Mock type, that's why you can mock v4 method: v4.mockReturnValue('yourV4Id');
jest.mock('aModule');
import {aMember} from "aModule";
// is now a jest mock type <=> jest.fn()
aMember.mockReturnValue('a value');
jest.fn is a function which returns a jest.Mock type which can be considered as an function to create whatever you want:
const aMock = jest.fn().mockReturnValue(1) // <=> const aMock = () => 1;
// The difference is jest mock type can be used to assert then. Most of cases is to check
// whether it gets called or not

Jest: Spy on other function in module being tested

I'm trying to test a module using jest. In the module, I have a function which works as a kind of front to two other functions, and delegates to them based on its parameter. I'm trying to figure out if these functions have indeed been called.
I have tried using a spy function, but it is never called. Instead, the actual function is called, bypassing my spy.
All examples I have found with mocking and spies involve mocking and spying on another module than the one being tested, but in this case I am trying to spy on a function from the module being tested. Is this even possible? Is there a better way to do this?
Example code:
// funcs.js
const decide = obj => {
if (obj.a !== undefined) {
return funcA(obj);
} else {
return funcB(obj);
}
};
const funcA = obj => obj.a;
const funcB = obj => obj.b;
export { decide, funcA, funcB };
// funcs.test.js
import * as fns from "./funcs";
describe("decide", () => {
it("should delegate to 'funcA' when the parameter has an 'a' property", () => {
const spy = jest.spyOn(fns, "funcA");
fns.decide({ a: "Cake" });
expect(spy).toHaveBeenCalled(); // Error! Number of calls: 0
});
});
There's no way to spy or mock a function that is called in the same ES module it is defined.
This is possible for CommonJS modules but only if functions are consistently referred as methods:
exports.decide = obj => {
...
exports.funcA(obj);
...
};
exports.funcA = obj => obj.a;
It's possible to adopt this recipe to ES modules but this discards their benefits:
const exports = {};
export default exports;
// same as CommonJS
funcA and funcB should be either moved to separate module for testability purposes and be spied or mocked with jest.mock, or all of them should be tested as a single unit.

Jest how to test if a mocked function is called

In my jest test I mock a service that i have made like this:
jest.mock("../../services/testService");
this works fine. Now I want to test if a mocked function was called how can is do this?
It tried to put the mock in a variable like this:
const fn = jest.mock("../../services/testService");
But when i do this i get errors because the test now refer to the real testservice and not the mocked one.
Can someone tell me how to test if a mocked function was called?
You could do something like
//this is the key to know if a function has been called
const yourFunction = jest.fn()
jest.doMock('../../services/testService', () => ({
testService: {
yourFunction
},
}))
And then use the assertion on yourFunction to have been called.
EDIT:
I think this should work if you are trying to mock react-native-push-notification:
const localNotification = jest.fn()
jest.doMock('react-native-push-notification', () => ({
PushNotification: {
configure: () => {},
default: () => {},
localNotification
},
}))

Jasmine spying on method that calls external method (Angular 2)

In my angular 2 app, How do I test if my external method (dependency) inside my main method is being called accordingly.
For instance,
Class ServiceA
{
constructor(
private serviceB : ServiceB
){}
//How do I test this method to make sure it does what it should ?
mainMethod()
{
//External method
this.serviceB.otherMethod();
this.sideMethod();
}
sideMethod()
{
//Do something
}
}
Class ServiceB
{
constructor(){}
otherMethod()
{
//Do something
}
}
Here's what I've tried so far
it('On otherMethod returns false, do something',
inject([ServiceA, ServiceB], (serviceA: ServiceA, serviceB: ServiceB) => {
spyOn(serviceB, 'otherMethod').and.returnValue(false);
spyOn(serviceA, 'sideMethod');
spyOn(serviceA, 'mainMethod').and.callThrough();
expect(serviceB.otherMethod()).toHaveBeenCalled();
expect(serviceA.sideMethod()).toHaveBeenCalled();
expect(serviceA.mainMethod()).toHaveBeenCalled();
}));
From above code, I got an error stating
could not find an object to spy upon for otherMethod()
What is wrong here ?
You have to pass the function reference of your spy serviceB.otherMethod. You are currently invoking the spy by calling serviceB.otherMethod() which will return the return value of otherMethod instead of the spy.
it('On otherMethod returns false, do something',
inject([ServiceA, ServiceB], (serviceA: ServiceA, serviceB: ServiceB) => {
spyOn(serviceB, 'otherMethod').and.returnValue(false);
spyOn(serviceA, 'sideMethod');
spyOn(serviceA, 'mainMethod').and.callThrough();
// Notice spy reference here instead of calling it.
expect(serviceB.otherMethod).toHaveBeenCalled();
expect(serviceA.sideMethod).toHaveBeenCalled();
expect(serviceA.mainMethod).toHaveBeenCalled();
}));
Jasmine documentation: https://jasmine.github.io/2.0/introduction.html#section-Spies

Jasmine: Testing a function that uses a browser object

I am trying to test this function with Jasmine:
myFunc: function () {
var name = document.getElementById("bob");
display.innerHTML = name;
return 100;
}
The test fails with ReferenceError: document is not defined. I understand that I'm not running the test in a browser so document isn't defined. But how come mocking it out isn't working? Is there a way to write this test with standalone Jasmine only?
How would one generally go about testing these kinds of functions (JavaScript mixed with DOM)? I'd prefer not to use another library/framework.
// Mock, stub dom object.
var document;
beforeEach(function () {
document = jasmine.createSpyObj('document', ['getElementById', 'createElement']);
});
describe("myFunc", function () {
it("return 100", function () {
console.log(document); // My mock document object successfully logs.
expect(myFunc()).toEqual(100); // but document isn't defined in here.
});
});