Handle errors in http test requests - javascript

I am using jest to test my code:
export const getReq = async () => {
let data = '';
await fetch(
'https://api.github.com/repos/javascript-tutorial/en.javascript.info/commits',
)
.then((response) => {
let status = null;
if (response.status === 200) {
status = response.status;
} else {
status = 'error';
}
if (status === 200) {
alert('success');
} else {
data = '';
alert('Error');
}
return response.json();
})
.then((commits) => {
data = commits.map(({ sha }: any) => sha)[0];
});
return data;
};
And now i want to test the situation when in my alert should appear: alert('Error'); and data = '';. So, for this i created this test:
test('Asynchronous return values error', async() => {
global.alert = jest.fn();
global.fetch = jest.fn().mockResolvedValueOnce({
json: () =>
Promise.reject(new Error('my error')),
status: 401,
});
const result = await getReq();
expect(global.alert).toHaveBeenCalledWith('Error');
expect(global.fetch).toHaveBeenCalledWith(
'https://api.github.com/repos/javascript-tutorial/en.javascript.info/commits',
);
expect(result).toEqual('');
});
But when i run the test i get: Error: my error and my test does not work
What could be the issue and how to test the things that i described above?

Related

error boundary when using hooks to display data

I try to get user data when load page using hooks(in case useEffect), but i got error said "Consider adding an error boundary to your tree" and my app getting blank.
my code looks similar like below
still configure out how to fix it, but i dont know how. coz i new using react
const [ProfileData, setProfileData] = useState({});
const [ownerId, setOwnerId] = useState('')
let ProfileID = 12
const getId = async () => {
const responseData = await getUserData();
setOwnerId(responseData.ID);
};
this is my function to get data from API
const getProfileData = () => {
setLoading(true);
getId();
const jsonData = {
ID: ProfileID,
OwnerId: ownerId
};
const headers = {
'Access-Control-Allow-Headers': '*'
};
try {
axios
.post(
config.API_SERVER + 'SearchProfile',
{
Data: jsonData ,
},
headers
)
.then(function (response) {
if (response.data.status == 'Success') {
setProfileData(response.data.Data);
setLoading(false);
} else {
setProfileData({});
alert(response.data.status);
}
})
} catch (error) {
console.log(error);
}
};
this is my hooks
useEffect(() => {
const load = async () => {
try {
await getProfileData();
} catch (err) {
throw err
}
}
load()
}, []);
and this is my return to display data
return (
<p>{ProfileData.Name}</p>
)
Since you throw an error (throw err) but you don't catch it, you can omit that part, pass the error message to state, or use react-error-boundary.
useEffect(() => {
getProfileData();
}, []);

How to improve the efficiency of an algorithm that does multiple fetch calls in terms of security and complexity?

The exercise is Write a JavaScript package that is able to:
fetch an array of URLs which contain JSON data
return their contents in a promise
I have already made a solution to this exercise, but I would like some input on how to improve this solution in terms of efficiency, security and complexity. I have also included unit tests for this solution.
index.js
const { InvalidParameterError, EmptyArrayError, InvalidURLError, FetchError, APIError } = require("./errors");
const fetch = require('node-fetch');
const validUrl = require('valid-url');
const links = [
'https://ft-tech-test-example.s3-eu-west-1.amazonaws.com/ftse-fsi.json',
'https://ft-tech-test-example.s3-eu-west-1.amazonaws.com/gbp-hkd.json',
'https://ft-tech-test-example.s3-eu-west-1.amazonaws.com/gbp-usd.json'
]
/**
* iterates through the array and fetches data from each url, includes edge cases
* #params {urls} array of URLs
* #return {Promise} promise which is an array of the data fetched from the URL in JSON format
*/
function requestMultipleUrls (urls) {
if (!Array.isArray(urls)){
console.log('Parameter passed is not in array format', urls)
return new InvalidParameterError('urls should be inside in an array')
}
if (urls.length === 0) {
console.log('Array cannot be empty', urls)
return new EmptyArrayError('Array of urls cannot be empty')
}
const promises = urls.map(async (url) => {
if ((!validUrl.isUri(url))) {
console.log('URL is in incorrect format', url)
return new InvalidURLError('Input URL is not in the correct format')
}
try {
const data = await fetch(url);
const { status } = data
if (status !== 200) {
console.log(`Your fetch call returned a status code of ${status}, check if the URL you entered is correct`)
return new APIError('Something went wrong with the URL you are trying to fetch', status)
} else {
return mapData(data)
}
} catch(error) {
console.log(error)
return new FetchError('Something went wrong during the fetch call')
}
})
return Promise.all(promises)
}
/**
* Deconstructs the data being passed to form an object that is eventually returned
* #params {data} response that is recieved from the fetch call in requestMultipleUrls
* #return {final} object that is formatted
*/
const mapData = async (data) => {
const {url, status} = data
const final = {
url,
status,
body: await data.json()
}
return final
}
requestMultipleUrls(links).then((data) => console.log(data))
module.exports = {
requestMultipleUrls
}
errors.js
class InvalidParameterError {
constructor (message) {
this.status = 400;
this.message = message;
}
}
class EmptyArrayError {
constructor(message) {
this.status = 400;
this.message = message;
}
}
class InvalidURLError {
constructor(message) {
this.status = 400;
this.message = message
}
}
class APIError {
constructor(message, status){
this.status = status,
this.message = message
}
}
class FetchError {
constructor(message) {
this.status = 502;
ths.message = message
}
}
module.exports = {
InvalidParameterError,
EmptyArrayError,
InvalidURLError,
FetchError,
APIError
}
index.spec.js
const { expect } = require('chai');
const { requestMultipleUrls } = require('../index');
const gbpUsd = require('./gbp-usd.json');
const gbpHkd = require('./gbp-hkd.json')
describe('requestMultipleUrl intended functionality', () => {
it('function should return an accumulated API response', async () => {
const dummyUrls = [
'https://ft-tech-test-example.s3-eu-west-1.amazonaws.com/gbp-usd.json',
'https://ft-tech-test-example.s3-eu-west-1.amazonaws.com/gbp-hkd.json'
]
const promise = await requestMultipleUrls(dummyUrls);
expect(promise).to.deep.equal([gbpUsd, gbpHkd]);
})
})
describe('requestMultipleUrl edge cases', () => {
it('should throw an error if the urls in the array do not match URI standards', async () => {
const dummyUrls = [
'lfkjklwfklm',
'ekefjkf;lfl;'
]
try {
await requestMultipleUrls(dummyUrls)
} catch (error) {
expect(error.message).to.eql('Input URL is not in the correct format')
}
})
it('should throw an error if URL array is empty', async () => {
const dummyUrls = []
try {
await requestMultipleUrls(dummyUrls)
} catch (error) {
expect(error.message).to.eql('Array of urls cannot be empty')
}
})
it('should throw an error if the parameter being passed is not an array', async () => {
const dummyUrls = 'https://ft-tech-test-example.s3-eu-west-1.amazonaws.com/gbp-hkd.json'
try {
await requestMultipleUrls(dummyUrls)
} catch (error) {
expect(error.message).to.eql('urls should be inside in an array')
}
})
it('should throw an error if status code is not 200', async () => {
const dummyUrls = ['https://ft-tech-test-example.s3-eu-west-1.amazonaws.com/gbp-jpy.json']
try {
await requestMultipleUrls(dummyUrls)
} catch(error){
expect(error.message).to.eql('Something went wrong with the URL you are trying to fetch')
}
})
})

Test get request in javascript

I have the next get request:
const getReq = () => {
fetch(
'https://api.github.com/repos/javascript-tutorial/en.javascript.info/commits',
)
.then((response) => {
let status = null;
if (response.status === 200) {
status = response.status;
} else {
status = 'error';
}
if (status === 200) {
alert('success')
} else {
alert('Error')
}
return response.json();
})
.then((commits) =>{
return commits.map(i=> i.sha[0])
});
};
getReq()
I want to make 3 tests for this request:
if I get the first sha from commits: i=> i.sha[0]
check for the 200 response
check for the response that is not 200.
I wrote my first test:
import { getReq } from './getReq';
global.fetch = jest.fn(() => {
return Promise.resolve(123);
});
describe('success', () => {
test('get first sha http', async () => {
const sha = await getReq();
expect(sha).toBe(123);
});
});
But I get TypeError: Cannot read property 'then' of undefined.
How to solve the issue with the test above?
Your promise is not getting mock.
You can try to adding this on the top of the file.
jest.mock(path_of_getReq_file, () => ({
getReq: jest.fn()
}));

Axios returns promise pending

i want this function to return either true or false, instead I get
/**
* Sends request to the backend to check if jwt is valid
* #returns {boolean}
*/
const isAuthenticated = () => {
const token = localStorage.getItem('jwt');
if(!token) return false;
const config = {headers : {'x-auth-token' : token}};
const response = axios.get('http://localhost:8000/user' , config)
.then(res => res.status === 200 ? true : false)
.catch(err => false);
return response;
}
export default isAuthenticated;
I tried separating them and using async/await :
const isAuthenticated = async () => {
const response = await makeRequest();
return response;
}
const makeRequest = async () => {
const token = localStorage.getItem('jwt');
const config = {headers : {'x-auth-token' : token}};
const response = await axios.get('http://localhost:8000/user' , config)
.then(res => res.status === 200 ? true : false)
.catch(err => false);
return response;
}
And still the same..
After some suggestions :
const isAuthenticated = () => {
const response = makeRequest();
return response;
}
const makeRequest = async () => {
try {
const token = localStorage.getItem('jwt');
const config = {headers : {'x-auth-token' : token}};
const response = await axios.get('http://localhost:8000/user', config);
if (response.status === 200) { // response - object, eg { status: 200, message: 'OK' }
console.log('success stuff');
return true;
}
return false;
} catch (err) {
console.error(err)
return false;
}
}
export default isAuthenticated;
First of all if.
If you are using the default promise then & catch, then the success action should be handled within the 'then' function.
axios.get('http://localhost:8000/user', config)
.then(res => console.log('succesfull stuff to be done here')
.catch(err => console.error(err)); // promise
if you want to use the async/await syntactic sugar, which I personally like it's
const makeRequest = async () => {
try {
const token = localStorage.getItem('jwt');
const config = {headers : {'x-auth-token' : token}};
const response = await axios.get('http://localhost:8000/user', config);
if (response.status === 200) { // response - object, eg { status: 200, message: 'OK' }
console.log('success stuff');
return true;
}
return false;
} catch (err) {
console.error(err)
return false;
}
}
You have to employ the use of async/await,like this:
const isAuthenticated =async () => {
const token = localStorage.getItem('jwt');
if(!token) return false;
const config = {headers : {'x-auth-token' : token}};
const response =await axios.get('http://localhost:8000/user' , config)
.then(res => res.status === 200 ? true : false)
.catch(err => false);
return response;
}

response.text is not a function while building react-native app

I'm trying to build a react-native app with expo and while trying to sign up I get the following error message stemming from my api.js file:
response.text is not a function. (In 'response.text()', 'response.text' is undefined).
Here is my code:
const BASE_URL = "my local IP:5000";
export const api = async (url, method, body = null, headers = {}) => {
try {
const endPoint = BASE_URL.concat(url);
const reqBody = body ? JSON.stringify(body) : null;
const fetchParams = {method, headers};
if((method === "POST" || method === "PUT") && !reqBody) {
throw new Error("Request body required");
}
if(reqBody) {
fetchParams.headers["Content-type"] = "application/json";
fetchParams.body = reqBody;
}
const fetchPromise = fetch(endPoint, fetchParams);
const timeOutPromise = new Promise((resolve, reject) => {
setTimeout(() => {
reject("Request Timeout");
}, 3000);
});
const response = await Promise.race([fetchPromise, timeOutPromise]);
return response;
} catch (e) {
return e;
}
}
export const fetchApi = async (url, method, body, statusCode, token = null, loader = false)
=> {
try {
const headers = {}
const result = {
token: null,
success: false,
responseBody: null
};
if(token) {
headers["x-auth"] = token;
}
const response = await api(url, method, body, headers);
console.log(response);
if(response.status === statusCode) {
result.success = true;
if(response.headers.get("x-auth")) {
result.token = response.headers.get("x-auth");
}
Here is response.text()
let responseBody;
const responseText = await response.text();
//const responseText = await response.json();
try {
responseBody = JSON.parse(responseText);
} catch (e) {
responseBody = responseText;
}
result.responseBody = responseBody;
return result;
}
Here is response.text()
let errorBody;
const errorText = await response.text();
//const errorText = await response.json();
try {
errorBody = JSON.parse(errorText);
} catch (e) {
errorBody = errorText;
}
result.responseBody = errorBody;
console.log(result);
throw result;
} catch (error) {
return error;
}
}
Any help would be immensely appreciated.

Categories

Resources