Jest - how to mock a class in jest - reactjs

I've been trying to mock a test in jest through the methods that they have on their documentation. By mocking the whole class but I can't seem to get it to work properly.
https://jestjs.io/docs/en/es6-class-mocks
jest.mock('../../../../../src/SubscriptionOrder');
SubscriptionOrder.prototype.createChargebeeSubscription = jest.fn(() => 'response');
const test = new SubscriptionOrder(
'subscription',
[{}],
'errorMethods',
'customerMethods',
);
test.createChargebeeSubscription();
I'd expect this to mock the createChargebeeSubscription method and return the string response but it seems to be returning undeifined
Then this is the piece of code I'm trying to run a test for as well.
const subscriptionOrder = new SubscriptionOrder(
'subscription',
subscriptionRequest,
errorMethods,
customerMethods,
);
const response = await subscriptionOrder.createChargebeeSubscription(token);
this.setState({ successfulSubmit: response });
I want to update the state to the string response but getting undefined instead. so it appears I'm kinda mocking something but just not properly.

You can use spyOn as follows to do the mocking for you. I also recommend that you set up and tear down this spy once you are finished.
So here's a sample piece of code which will do what you want:
describe('createChargebeeSubscription() method behaviour', () => {
let createChargebeeSubscriptionSpy;
let testResponse;
beforeAll(() => {
// Lets create an instance of your class first
const subscriptionOrder = new SubscriptionOrder(
'subscription',
subscriptionRequest,
errorMethods,
customerMethods
);
// Now use a spy to mock the return value from your function
createChargebeeSubscriptionSpy = jest.spyOn(subscriptionOrder, 'createChargebeeSubscription').mockImplementation(() => {
return 'response';
});
// Finally invoke the method being tested
testResponse = subscriptionOrder.createChargebeeSubscription();
});
afterAll(() => {
// Restore the functionality (ie. disable the spy) of your method
createChargebeeSubscriptionSpy.mockRestore();
});
it('verifies that the expected response was returned', () => {
expect(testResponse).toBe('response');
});
});

Related

Jest to test a class method which has inner function

I'm writing unit test for once of my .ts file. Where I'm facing a problem and unable to find the solution. Hopefully someone can help me to resolve it.
Problem
While writing unit test. I'm unable to test the value for profile. After calling a method called getProfile().
File setup
Profile.ts
import { getProfileAPI} from "./api";
class ProfileDetails implements IProfileDetails {
public profile: string = ''
constructor() {}
getProfile = async () => {
const { data } = await getProfileAPI();
if (data) {
this.profile = data
}
};
}
const profileDetail = new ProfileDetails();
export default profileDetail;
Profile.spec.ts
import Profile from './Profile';
describe('Profile', () => {
it('getProfile', async () => {
Profile.getProfile = jest.fn();
await Profile.getProfile();
expect(Profile.getProfile).toHaveBeenCalled();
});
});
So the challenge I'm facing here is, I can able to mock the getProfile method. But I'm not able to mock the getProfileAPI function which is called inside the getProfile method.
How can I mock a function which is called inside a mocked method (or) is there any other way to resolve this. Kindly help.
Thanks in advance.
Before answering your questions, I may have some comments :
your test is wrong, all it does is calling the method then checking if it is called, of course it will always pass !
you are not really mocking, in fact you're erasing the old method and it may have some impacts on other tests.
your method "getProfile" should be called "getAndSetProfile", or "syncProfile", or something like that, getProfile is confusing for a developer, he will think it only get the profile and returns it.
I don't recommend creating & exporting an instance of ProfileDetails like this, you should take a look on DI (Dependency Injection) with typedi for example.
Do not forget :
A unit test means that any dependency inside your "unit" should be mock, you must only test the logic inside your "unit" (in your case, the getProfile function, or the class itself).
Here, you are invoking a method called "getProfileAPI" from another service that is not mocked, so you are currently testing its logic too.
This test should work :
Profile.spec.ts
jest.mock('./api', () => ({
getProfileAPI: jest.fn(),
}));
import { getProfileAPI } from "./api";
import Profile from './Profile';
describe('Profile', () => {
it('getProfile', async () => {
await Profile.getProfile();
expect(getProfileAPI).toHaveBeenCalled();
});
});
In our example, Profile.profile will be empty, because even if we mocked to getProfileAPI method, we didn't make it return something. You could test both cases :
jest.mock('./api', () => ({
getProfileAPI: jest.fn(),
}));
import { getProfileAPI } from "./api";
import Profile from './Profile';
const mockGetProfileAPI = getProfileAPI as jest.Mock; // Typescript fix for mocks, else mockResolvedValue method will show an error
describe('Profile', () => {
describe('getProfile', () => {
describe('with data', () => {
const profile = 'TEST_PROFILE';
beforeEach(() => {
mockGetProfileAPI.mockResolvedValue({
data: profile,
});
});
it('should call getProfileAPI method', async () => {
await Profile.getProfile();
expect(mockGetProfileAPI).toHaveBeenCalled(); // Please note that "expect(getProfileAPI).toHaveBeenCalled();" would work
});
it('should set profile', async () => {
await Profile.getProfile();
expect(Profile.profile).toBe(profile);
});
});
describe.skip('with no data', () => {
it('should not set profile', async () => {
await Profile.getProfile();
expect(Profile.profile).toStrictEqual(''); // the default value
});
});
});
});
NB : I skipped the last test because it won't work in your case. Profile isn't recreated between tests, and as it is an object, it keeps the value of Profile.profile (btw, this is a bit weird) between each tests. This is one of the reasons why you should not export a new instance of the class.

Trying to spyOn a mocked function

I am trying to perform a spyOn on a function that exists in a mocked class:
test.ts -
import Service from '../base_classes/Service';
jest.mock('../base_classes/Service');
const o: Component = new Component();
it('should load model specific information', async () => {
const getSpy = jest.spyOn(Service.prototype, 'get');
let t = await o.load(1);
expect(t.name).toEqual('test_name');
expect(getSpy).toHaveBeenCalledTimes(1);
});
__mocks__/Service.ts -
export const mockGet = jest.fn(async () => Promise.resolve({name:
'test_name'}));
const mock = jest.fn().mockImplementation(() => {
return {
get: mockGet
}
});
export default mock;
The resulting error is: Cannot spy the get property because it is not a function
I tried changing the mocked arrow function to a function(), but that didn't help.
How can I set this up so I can spy on my mocked function?
When using jest.mock it automatically creates a mock for each property of the module, replacing it's functions with jest.fn() (without implementation). And from then on you can write assertions. There should be no reason you'd want to spy on a mock function as it's already a mock function.
You should either spy on the actual implementation or write assertions for the methods on the mocked module.
e.g.
it('should load model specific information', async () => {
let t = await o.load(1);
expect(t.name).toEqual('test_name');
expect(Service.mock.instances[0].get).toHaveBeenCalledTimes(1);
});
working example

integration tests - redux/react + nock.js

I have no clue how to find a way to write this integration test.
I am using enzyme for mocking react components, jest for testing and nock for mocking axios api calls.
So far I created test which simulate clicking on button and I would like to mock the api call.
In the internet there is no much help.
My test:
it('Should invoke clear action and clear the group', (done) => {
// GIVEN
const clearButtonComponent = wrapper.find('[id="123"]');
nock('http://localhost:8080')
.intercept('/path/api/brum/123/group', 'DELETE')
.reply(200, {
status: 200,
message: 'cleared',
});
const service = new myService();
// WHEN
clearButtonComponent.first().simulate('click');
const result = Promise.resolve(service.clearGroup(123));
// THEN
expect(result).toEqual({ x: 'x' }); // I know it's not what I expect
wrapper.update();
done();
});
async action redux:
export const clearGroup = id=> (dispatch, getState) => {
myService.clearGroup(id)
.then(() => {
return dispatch(getGroup(id))
});
};
method in myService:
clearGroup(id) {
return this._delete(`/${id}/group`);
}
of course path is more complex but my service extends base service which has this base url.
Can anybody tell me how to mock it to let code goes further?
It still complain that id is undefined - look like nock does not mock it.
I would drop nock (I try to only use it for testing clients these days) and mock myService with jest.
I don't use axios, so haven't used this, but it might do the trick.. https://github.com/knee-cola/jest-mock-axios.
Otherwise you could look at writing your own mock.. https://jestjs.io/docs/en/es6-class-mocks

Test multiple fetches in componentDidMount with Jest/Enzyme

I am starting to learn more about testing for React using Jest/Enzyme and I am trying to learn how to test api calls that use fetch.
I have a fetch call in a componentDidMount() method and I am able to test that correctly. In the beforeEach() method, I have a window.fetch method that creates the mock fetch. Here is an example:
beforeEach(() => {
mockData = /* mock data */
// mock fetch call
window.fetch = jest.fn().mockImplementation(() => Promise.resolve({
json: () => Promise.resolve({
data: mockData,
})
}));
component = shallow(<Component />);
});
However, I have another component that has two fetch calls in the componentDidMount() method, and I'm wondering how I can mock each fetch call individually. Is it possible to have two window.fetch calls or somehow pass in a url for the fetch?
I am still new to this, so any help would be appreciated!
Thanks!
You can use fetch-mock library to mock each request separately. Suppose you're requesting 2 URLs and you want to return mockData in the request to the first URL, and just 404 status in the second one. Your example code mocked with fetch-mock may look like this:
import fetchMock from "fetch-mock";
beforeEach(() => {
mockData = { /* mock data */ };
fetchMock.mock("/first/url", mockData);
fetchMock.mock("/second/url", 404);
component = shallow(<Component />);
});
/* You should also restore the original fetch in afterEach */
afterEach(() => {
fetchMock.restore();
}

How can we test the return type of method by using sinon.spy?

We are using the sinon to test our api call in reactjs application Like this:-
import * as Actions from 'routes/actions/Actions';
const requestAction = {
RequestShell() { Actions.request(); },
};
describe('testing for Actions', () => {
it('check whether request() method call is happening properly or not', () => {
const requestData = sinon.spy(requestAction, 'RequestShell');
requestAction.RequestShell();
sinon.assert.calledOnce(requestData);
requestData.restore();
});
Now I need to compare if Actions.request() return type is Json object or not. How can I test the return type of the action by using sinon? Please assist me.
Try with this
JS
it('check whether request() method call is happening properly or not', () => {
const requestData = sinon.spy(requestAction, 'RequestShell');
requestAction.RequestShell();
assert(requestData.calledOnce);
requestAction.RequestShell.restore();
});
refer this linksinon spies

Resources