How do I mock a axios post request with Jest? - reactjs

I can mock a get request with:
mockAxios.get.mockImplementationOnce(() => Promise.resolve({
data: { mockResponse },
}));
But how can I mock a Post request?

I use MockAdapter from axios-mock-adapter as follows:
import axios from 'axios';
import MockAdapter from 'axios-mock-adapter';
import requestGenerator, { API } from './httpClient';
// This sets the mock adapter on the default instance
const mock = new MockAdapter(API);
describe('Test for api calls', () => {
it('Should test for postReq method for Location not reachable by car', async () => {
const mockDirectionResponse = {
status: 'failure',
error: 'Location not accessible by car'
};
mock.onPost('/route/token').reply(200, mockDirectionResponse);
const response = await requestGenerator.postReq('/route/token');
expect(response.data).toEqual(mockDirectionResponse);
});
});

Related

How to mock axios in React with using axios.create function

I'm working on React project where I'm using axios for http requests. I have a separate file with axios configuration like below:
import axios from 'axios'
export default axios.create({
baseURL: " http://localhost:3001",
params: {
}
})
I'm using this in action thunk creators like below:
import streams from "../apis/streams";
export const fetchStreams = () => {
return async(dispatch: ThunkDispatch<void, State, Action>) => {
const response: AxiosResponse<Stream[]> = await streams.get<Stream[]>('/streams');
dispatch({type: ActionType.FETCH_STREAMS, payload: response.data});
}
}
First I created "src/__mocks__/axios.ts" file like:
const mockedAxios: any = jest.createMockFromModule('axios');
mockedAxios.create = jest.fn(() => mockedAxios);
export default mockedAxios;
then I wrote test like below:
import mockedAxios, {AxiosResponse} from "axios";
import streamsApi from '../apis/streams'
import expectedStreams from "../mocks/expectedStreams";
jest.mock('axios')
describe('fetchStreams action', () => {
it('Store is updated correctly', async () => {
const mockedResponse: AxiosResponse = {
data: expectedStreams,
status: 200,
statusText: 'OK',
headers: {},
config: {}
}
mockedAxios.get.mockImplementationOnce(() => {
Promise.resolve(mockedResponse);
})
const results = await streamsApi.get('/streams');
expect(results.data).toBe(mockedResponse.data);
});
});
Unfortunately I've received an error like this:
Why is that? How can I correctly create facke API response in this case?
I would be grateful for help.
Ok, I know what was wrong. I forget to add return before Promise like so:
mockedAxios.get.mockImplementationOnce(() => {
return Promise.resolve(mockedResponse);
})

How to mock Axios service wrapper using JEST

I'm using JEST testing framework to write test cases for my React JS application. I'm using our internal axios wrapper to make service call. I would like to mock that wrapper service using JEST. Can someone help me on this ?
import Client from 'service-library/dist/client';
import urls from './urls';
import { NODE_ENV, API_VERSION } from '../screens/constants';
const versionHeader = 'X-API-VERSION';
class ViewServiceClass extends Client {
getFiltersList(params) {
const config = {
method: urls.View.getFilters.requestType,
url: urls.View.getFilters.path(),
params,
headers: { [versionHeader]: API_VERSION },
};
return this.client.request(config);
}
const options = { environment: NODE_ENV };
const ViewService = new ViewServiceClass(options);
export default ViewService;
Above is the Service Implementation to make API call. Which I'm leveraging that axios implementation from our internal library.
getFiltersData = () => {
const params = {
filters: 'x,y,z',
};
let {
abc,
def,
ghi
} = this.state;
trackPromise(
ViewService.getFiltersList(params)
.then((result) => {
if (result.status === 200 && result.data) {
const filtersJson = result.data;
.catch(() =>
this.setState({
alertMessage: 'No Filters Data Found. Please try after some time',
severity: 'error',
showAlert: true,
})
)
);
};
I'm using the ViewService to get the response, and I would like to mock this service. Can someone help me on this ?
You would need to spy your getFiltersList method from ViewServiceClass class.
Then mocking some response data (a Promise), something like:
import ViewService from '..';
const mockedData = {
status: 'ok',
data: ['some-data']
};
const mockedFn = jest.fn(() => Promise.resolve(mockedData));
let getFiltersListSpy;
// spy the method and set the mocked data before all tests execution
beforeAll(() => {
getFiltersListSpy = jest.spyOn(ViewService, 'getFiltersList');
getFiltersListSpy.mockReturnValue(mockedFn);
});
// clear the mock the method after all tests execution
afterAll(() => {
getFiltersListSpy.mockClear();
});
// call your method, should be returning same content as `mockedData` const
test('init', async () => {
const response = await ViewService.getFiltersList();
expect(response).toEqual(mockedData);
});
P.D: You can pass params to the method, but you will need to configure as well the mockedData as you wish.

React Jest TypeError: Cannot read property 'baseUrl' of undefined

I have a simple login api call where the base url is in config file, code below
api.js
export const login = (username, password) => {
Axios.post(`${config.loginApi.baseUrl}/login`, {
username,
password
})
.then(res => res)
.catch(e => e);
};
I wrote the test case(s) below,
api.test.js
import axios from 'axios';
import { login } from './api';
import MockAdapter from 'axios-mock-adapter';
import config from 'config';
describe('signin signup Api', () => {
afterEach(() => {
jest.restoreAllMocks();
});
it('logs in successfully', (done) => {
const mock = new MockAdapter(axios);
mock.onGet(`${config.loginApi.baseUrl}/login`).reply(200, { data: '1234abcd' });
login('dee#gmail.com', 'test').then((res)=>{
expect(res).toEqual('1234abcd');
done();
});
});
or the other test case I wrote earlier
import axios from 'axios';
import { login } from './api';
import config from 'config';
jest.mock('axios');
it('logs in successfully', async () => {
axios.post.mockImplementationOnce(() => Promise.resolve({ data: '1234abcd' }));
await expect(login('dee#gmail.com', 'test')).resolves.toEqual('1234abcd');
});
I researched and found this post close to my issue. But in all the cases I'm getting
TypeError: Cannot read property 'baseUrl' of undefined
Why is this not able to know the baseUrl?
I tried mocking the config,
jest.mock(config);
got TypeError: moduleName.split is not a function.
Please suggest a fix/workaround.
Adding more info on the config
in config folder, I have
require('dotenv').config();
module.exports = config;
in development environment, it will pick this config from dev.js, in prod - prod.js and so on
in public folder, dev.js file I have
loginApi: {
baseUrl: 'https://abcd.com',
mocks: true,
mockDelay: 2000
}
I found the fix for this issue,
in the setupTests.js, I added
global.config ={
loginApi: {
baseUrl: 'https://abcd.com',
mocks: true,
mockDelay: 2000
}
}
This fixed that TypeError: Cannot read property 'baseUrl' of undefined issue.

How can I do a jest test in this function in React axios?

I guys I created a service in React and I need to test this part of the service, I'm using axios and Jest to do this.
I have the next code in React :
import axios from 'axios';
import Endpoints from './endpoints';
const baseUrl = Endpoints.getBackendEndpoint();
export const validateName = (nameObject, callback) => {
axios.post(`${baseUrl}/validateName`, {...nameObject})
.then(response =>{
response.data
})
.then(data => callback(data));
};
I don't need return the promise because all the work is doing by the callback() function.
This is the code that I have in Jest:
mport moxios from 'moxios';
import * as service from '../service';
import mockResponses from './service.test.json';
import Endpoints from '../endpoints';
const validateObjName = {
Id: 1,
Name: 'Bob',
}
beforeEach(() => {
const baseUrl = Endpoints.getBackendEndpoint();
moxios.stubRequest(
`${baseUrl}/validateName`,
{ ...validateObjName },
{
status: 200,
response: mockResponses.validateForm,
}
);
});
afterEach(() => {
moxios.uninstall();
});
it('validateName()', () => {
service.validateName(validateObjName, jest.fn());
});
It works, but still need to increase the Branch coverage.
Thanks for you help guys :D
To get code coverage the code has to run while a test is running so you will want to return the Promise so you can await it in your test so the then callbacks run during your test.
Also, you can simplify validateName to this:
import axios from 'axios';
import Endpoints from './endpoints';
const baseUrl = Endpoints.getBackendEndpoint();
export const validateName = (nameObject, callback) => {
return axios.post(`${baseUrl}/validateName`, { ...nameObject })
.then(response => callback(response.data));
};
In your test you need to install moxios in your beforeEach and pass the mock response as the second parameter to moxios.stubRequest.
Then use an async test function and await the Promise returned by validateName:
import moxios from 'moxios';
import * as service from '../service';
import mockResponses from './service.test.json';
import Endpoints from '../endpoints';
const validateObjName = {
Id: 1,
Name: 'Bob',
}
beforeEach(() => {
moxios.install(); // install moxios
const baseUrl = Endpoints.getBackendEndpoint();
moxios.stubRequest(
`${baseUrl}/validateName`,
{
status: 200,
response: mockResponses.validateForm
}
); // response is the second argument
});
afterEach(() => {
moxios.uninstall();
});
it('validateName()', () => {
service.validateName(validateObjName, jest.fn());
});
it('validateName()', async () => { // use an async test function
const spy = jest.fn();
await service.validateName(validateObjName, spy); // await the Promise
expect(spy).toHaveBeenCalledWith(mockResponses.validateForm); // Success!
});
That should give you a working test and 100% code coverage.

How to test React function that has api request in it?

I have a function like so in a react component. How do I test a successful request and an unsuccessful request?
deleteQuestion(id) {
axios.delete('/api/questions/' + id)
.then(response => {
this.setState({message: "Deletion Successful!"});
}).catch(error => {
var errorMessage = 'Question not deleted: ' + error.response.data.message;
this.setState({error: errorMessage});
});
}
And I was thinking of doing something like this for the testing but this obviously does not work. Basically, the console.log and assertion in the final function do not run.
import React from 'react';
import { mount, shallow } from 'enzyme';
import axios from 'axios';
import axios from 'axios';
import QuestionList from './QuestionList';
import sinon from 'sinon';
beforeEach(function () {
// import and pass your custom axios instance to this method
moxios.install()
})
afterEach(function () {
// import and pass your custom axios instance to this method
moxios.uninstall()
})
it('should modals and <table>', () => {
const wrapper = shallow(<QuestionList/>);
wrapper.instance().deleteQuestion()
moxios.wait(function () {
let request = moxios.requests.mostRecent()
request.respondWith({
status: 200,
response: [
{ id: 1, question: 'Fred', answer: 'Flintstone' },
{ id: 2, question: 'Wilma', answer: 'Flintstone' }
]
}).then(function () {
console.log('hello')
expect(wrapper.state().message).to.equal('Deletion Successful');
done()
})
})
});
You can use some mock http server library. For example https://www.npmjs.com/package/mock-http-server

Resources