I am working with rest js using typescript and I am trying to mock multiple API calls using jest for unit testing.
My api calls are in the following format:
await axios.request({
method: 'POST',
url: //api url,
data: {},
headers: {}
})
.then()
.catch()
I am mocking the axios as follows:
jest.mock('axios', () => {
return {
request: jest.fn().mockResolvedValue({
data: ['responseData', 'responseData1']
headers: //response header
})
}
});
The test case for api call is created as follows:
expect(axios.request).toHaveBeenCalled(); expect(axios.request).toHaveBeenCalledWith({
method: 'POST',
url: //api url,
data: {},
headers: {}
});
For multiple API calls, I am mocking it multiple times with different response data but it is taking the last mocked value as the response of all the API calls in the test cases.
for example: for multiple data mocks like:
jest.mock('axios', () => {
return {
request: jest.fn().mockResolvedValue({
data: ['responseData', 'responseData1']
headers: //response header
})
}
});
jest.mock('axios', () => {
return {
request: jest.fn().mockResolvedValue({
data: ['secondResponseData', 'secondResponseData1']
headers: //response header
})
}
});
when I am running the test cases I am getting the response for all my apis as:
data: ['secondResponseData', 'secondResponseData1']
headers: //response header
data: ['secondResponseData', 'secondResponseData1']
headers: //response header
instead of:
data: ['responseData', 'responseData1']
headers: //response header
data: ['secondResponseData', 'secondResponseData1']
headers: //response header
I don't know how to mock the correct response with the correct api call in the test cases. Is there any way that I can mock the correct response with the API calls?
Basic usage.
import * as axios from "axios";
// Mock out all top level functions, such as get, put, delete and post:
jest.mock("axios");
// ...
test("good response", () => {
axios.get.mockImplementation(() => Promise.resolve({ data: {...} }));
// ...
});
test("bad response", () => {
axios.get.mockImplementation(() => Promise.reject({ ... }));
// ...
});
With response code.
axios.get.mockImplementation(() => Promise.resolve({ status: 200, data: {...} }));
Based on parameters.
axios.get.mockImplementation((url) => {
if (url === 'www.example.com') {
return Promise.resolve({ data: {...} });
} else {
//...
}
});
Try something like this:
axiosPostSpy = jest.spyOn(axios, 'post').mockImplementation((url) => {
if( url === 'www.test.com?key=serverKey') {
return {
data: {
success: false,
},
};
} else {
return {
data: {
success: true,
},
};
}
});
Related
In React query every responses are considered as success.
Axios is used to call api request. Here is a axios component.
export const callAxios = async ({
url,
method,
data,
headers,
params,
responseType,
}: CallAxiosAPI) => {
const config: AxiosRequestConfig = {
method: method || 'GET',
url: `${baseUrl}${url}`,
headers: {
'Content-Type': 'application/json',
'Access-Control-Allow-Origin': '*',
Authorization: accessToken !== null ? `Bearer ${accessToken}` : '',
...headers,
},
data,
params,
responseType,
}
return axios(config)
.then((res: AxiosResponse<any, any>) => {
return res
})
.catch(err => {
return err
})
}
Here is sample of using useMutation
const adjustProfit = useMutation(
['adjustProfit'],
(params: { configurationId: string; configurationPriceId: number; data: IAdjustType }) => {
return PricingQueries.adjustProfit(
parseFloat(String(params.configurationId)),
params.configurationPriceId,
params.data,
)
},
{
onSuccess: () => {
refetch()
},
onError: () => {
toast.error(t(`message.adjust_price_failed`))
},
},
)
Even there is error onSuccess is called.
The problem is the .catch. By catching an error because you want to log and then not re-throwing the error, you are transforming the error into a resolved Promise. So you're actually never returning the error to useQuery.
The fix is to remove the catch and use the onError callback for logging, or re-throw the error after logging.
This gotcha is so common that I have added it to my FAQ post:
https://tkdodo.eu/blog/react-query-fa-qs#why-do-i-not-get-errors-
I have created a config file to create an Axios.
export const http = axios.create({
baseURL: process.env.REACT_APP_API_URI,
responseType: "json",
timeout: 30000,
timeoutErrorMessage: "Request Time out",
headers: {
withCredentials:true
}
})
In the other file, I have created helper functions to post, update, and get. Now I am trying to pass data from the body through the get function so far I have following code to get data without passing the body.
export const getRequest = (url, is_strict = false) => {
return new Promise((resolve, reject) => {
http.get(url, {
headers: getHeaders(is_strict)
}).then((response) => {
if(response.status === StatusCodes.OK || response.status === StatusCodes.CREATED){
resolve(response.data);
} else {
reject(response);
}
})
.catch((error) => {
reject(error);
})
})
}
How can I achieve that?
You cannot have a request body in GET method. You can use request params instead. Or you can use POST method.
Form the MDN docs for GET,
property
avaiability
Request has body
No
Request has body
Yes
I tried make a call to a web service with axios and AJAX. None of them worked. In axios I get an error request aborted and in AJAX I get an error too.
I specified headers for CORS, I specified the type of content which is xml.
let configAxios: object = {
responseType: 'document',
headers: {
"Access-Control-Allow-Origin": "*",
'Content-Type': 'text/xml'
}
}
export function getFornecedores(){
console.log("Dentro do getFornecedores");
axios.get(config.web_service_url + "/TM_GetEnt?pEntTp=F", configAxios)
.then( (response) => {
console.log(response);
return response;
})
.catch((err) => console.log("Axios falhou" + err))
}
export function getFornecedores2(){
$.ajax({
type: 'GET',
url: config.web_service_url + "/TM_GetEnt?pEntTp=F",
// async: false,
success: function (data) {
var xml_node = $('DocumentElement',data);
var entnm: any = [];
var entcd: any = [];
xml_node.find('Tabela>ENTNM').each(function(){
entnm.push($(this).text());
});
xml_node.find('Tabela>ENTCD').each(function(index){
// $(".fornecedor-select").append($("<option>").text(entnm[index]).val($(this).text()));
entcd.push($(this).text());
});
return {entnm, entcd};
},
error: function(){
console.log( "ERROR", arguments );
alert("Erro");
}
});
}
These functions are called in a useEffect in the component when the DOM is first loaded. How can I make the calls return a valid response?
I've tried
axios.get(url, {headers:{},data:{}})
But it doesn't work with this.
You should refer to https://github.com/axios/axios#request-config
Check the section for data and header.
As far as I know you can't send body data with GET request. With get you can have only Headers. Just simply change to POST and then you can do something like this :
const bodyParameters = {
key: "value",
};
const config = {
headers: { Authorization: `Bearer ${userToken}` },
};
axios.post("http://localhost:5000/user", bodyParameters, config)
.then((res)=> {
console.log(res)
})
.catch((err) => console.log(err));
};
or if you want to send headers with GET request
axios.get('/user', {
params: {
ID: 12345
}
})
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
})
.then(function () {
// always executed
});
// data is the data to be sent as the request body
// Only applicable for request methods 'PUT', 'POST', 'DELETE , and 'PATCH'
https://stackoverflow.com/a/54008789
yeah, it's true it doesn't work to send body in Axios get even if it works in the postman or the backend.
You can try this:
const getData = async () => {
try {
const response = await axios.post(`https://jsonplaceholder.typicode.com/posts`, {
method: 'POST',
body: JSON.stringify({
id: id,
title: 'title is here',
body: 'body is here',
userId: 1
}),
headers: {
"Content-type": "application/json; charset=UTF-8"
}
})
.then(response => response.json())
.then(json => console.log(json));
console.warn(response.data);
} catch (error) {
console.warn(error);
}
}
You can send data in a get request by using the config object and the params option of the config object. This is a workaround and it works, but on the server the data sent is available as request.query not as request.body. Based on the example below you would access your params data on your server using request.query.user_id. It should be noted that using this method will also append the params to your request url which could have unintended consequences based on your specific situation. For example, the url for the request below would be sent as example.com?user_id=1234. You can read more about the axios request config here.
axios.get(
'example.com/',
{
params: { user_id: 1234 },
headers: {
Authorization: `Bearer ${token}`,
'Content-Type': 'application/json',
},
},
);
I am trying to make common function which will handle all of my API calls from anywhere
I am using react": "^16.8.6" and fetch for making api call
So far what i have figure out to do
is
Helper.js
export function ApiHelper(url, data = {}, method = 'POST') {
let bearer = 'Bearer ' + localStorage.getItem('user_token');
var promise = fetch(url, {
method: method,
withCredentials: true,
// credentials: 'include',
headers: {
'Authorization': bearer,
'X-FP-API-KEY': 'chaptoken',
'Content-Type': 'application/json'
}
})
.then(res => res.json())
.then(
(result) => {
console.log(result);
},
(error) => {
error = error;
}
)
}
export function AnyOtherHelper() {
return 'i am from helper function';
}
And here is from where i am calling this function
componentDidMount() {
let url = `http://localhost/project/api/getdata`;
let op = ApiHelper(url);
}
when I console result in then i am getting appropriate result but what i want to return that response how can i do this part is troubling me
Even i have try to store the result in global variable and it is not working.
Also i have to return the response only when promise is resolved.
You are making an async call from your helper function which means, you will have to return promise from your helper function like this -
export function ApiHelper(url, data = {}, method = 'POST') {
let bearer = 'Bearer ' + localStorage.getItem('user_token');
return fetch(url, { // Return promise
method: method,
withCredentials: true,
// credentials: 'include',
headers: {
'Authorization': bearer,
'X-FP-API-KEY': 'chaptoken',
'Content-Type': 'application/json'
}
})
.then(res => res.json())
.then((result) => {
console.log(result);
return result;
}, (error) => {
error = error;
})
}
USAGE
componentDidMount() {
let url = `http://localhost/project/api/getdata`;
ApiHelper(url)
.then(resposnse => {
console.log(resposnse);
});
}