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

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

Related

Jest says TypeError: (0 , ClassName.functionName) is not a function

I have a js file as follows
import axios from "axios";
export default class SomeService {
static getSomething(id) {
return axios
.get(API_BASE_URL + API_URL_Something, {
params: { id: id},
})
.then((result) => {
return result.data;
})
.catch((error) => {
throw error;
});
}
}
And I have a test.js using jest as follows
import axios from "axios";
import { getSomething } from "../SomeService.js";
jest.mock("axios");
describe("getSomething", () => {
describe("when API call is successful", () => {
it("should return some details", () => {
// given
const someDetails = [
{ id: 1, name: "Something 1" },
{ id: 2, name: "Something 2" },
];
axios.get.mockResolvedValueOnce(someDetails);
// when
const result = getSomething(123); // ERROR THROWN HERE
// then
let url = API_BASE_URL + Constants.API_URL_Something;
expect(axios.get).toHaveBeenCalledWith(`${url}`);
expect(result).toEqual(someDetails);
});
});
describe("when API call fails", () => {
it("should return empty entity details", () => {
// ...
});
});
});
But when I run npm test I get this error
TypeError: (0 , _SomeService.getSomething) is not a function
I have tried making the function non static (I shouldn't have to), tried exporting it (couldn't get the syntax right perhaps), but can't get it to quite work. Other similar posts do not solve my issue either. What am I doing wrong?
From what I can see in your code you are exporting the class SomeService, not its internal getSomething method. So surely you need to change your test code to something like the following:
import axios from "axios";
import { getSomething } from "../SomeService.js";
jest.mock("axios");
describe("getSomething", () => {
describe("when API call is successful", () => {
it("should return some details", () => {
//...
// when
const service = new SomeService();
const result = service.getSomething(123);
// ...

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);
})

Jest Enzyme unit test axios api services with coverage

I'm new to jest, enzyme unit tests. I have the following code and it is working as expected
Component
import productService from './../../../productService';
constructor(props) {
super(props);
this.productService = new productService();
}
componentDidMount() {
this.productService.getProductList().then(res => {
if (res.status === "Success") {
/// Some actions
} else {
/// Some actions
}
});
}
productService.js
import axios from 'axios';
class productService {
constructor() {
this.state = {
apiUrl: process.env.REACT_APP_API_URL
}
}
getProductList() {
return axios.get(this.state.apiUrl + "products/listProducts")
.then(res => {
return res.data;
}).catch(err => {
return err;
});
}
}
export default productService;
and I have tried axios-mock-adapter for mocking the API and its response.
import axios from 'axios';
import MockAdapter from 'axios-mock-adapter';
describe('User List Component Unit Tests', () => {
var mock = new MockAdapter(axios);
mock.onGet("/products/listProducts").reply(200, {
"status": "Success",
"data": [...]
});
it('Should trigger the product list api', () => {
wrapper.find('myComponent').instance().componentDidMount();
axios.get("/products/listProducts").then(function (response) {
console.log(response);
});
});
});
So the test will run successfully but I can't see the coverage in the coverage report.
Any help would be appreciated.
That's because in your getProductList() you return res.data on successful fetch, and then in componentDidMount() you check if the getProductList()'s response status equals 'Success', so essentially what you're doing is this:
axios.get("/products/listProducts").then(res => {
if (res.data.status==='Success') {...}
});
No wonder this path is never taken.

How do I mock a axios post request with Jest?

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);
});
});

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.

Resources