Testing with JEST and nock causing 'Cross origin null forbidden' - jestjs

I'm trying to test my service with JEST and mocking endpoint with nock. Service looks like this
export async function get(id) {
const params = {
mode: 'cors',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
}
};
let response = await fetch(`{$API}/projects/${id}`, params);
return response.json();
}
Test:
import {
get
} from './project';
import nock from 'nock';
const fetchNockProject = nock($API)
.get('/projects/1')
.reply('200', {});
const data = await get(1);
expect(data).resolves.toEqual(project);
When I run the test I get error:
console.error node_modules/jsdom/lib/jsdom/virtual-console.js:29
Error: Cross origin null forbidden
TypeError: Network request failed
Any idea why virtual-console is throwing this as this is only service.

I found a solution for my problem which was connected with CORS. Nock mock should be:
fetchNockProject = nock($API)
.defaultReplyHeaders({
'access-control-allow-origin': '*',
'access-control-allow-credentials': 'true'
})
.get('/projects/1')
.reply('200', project);

Well, the posted answer didn't work for me and while I'm not saying it's wrong I thought I should share what did work for me.
In my case, my server is ASP.NET Core. I wasn't using the Cors middleware module that is provided. I added that in and configured it and that fixed my issue with no change to my javascript files.

Related

unexpected end of data at line 1 column 1 of the JSON data in express with React

I am working on a node API with React and Express. Node retrieves the data from Postgress like this:
router.get('/getRestaurants', async(req, res) => {
console.log('Restaurants');
try {
const { rows } = await db.getAllRestaurants();
console.log(rows);
res.json(rows);
} catch(error) {
console.error(`Error ${error}`);
res.status(500).send({message: `API internal error`});
}});
The console.log it shows the data without problem and if I use Postman or Curl it seems to work fine. But when I try to retrieve the data from my frontend React I get this error:
Uncaught (in promise) SyntaxError: JSON.parse: unexpected end of data at line 1 column 1 of the JSON data
React makes the POST request like this:
useEffect(() => {
async function fetchData() {
const response = await fetch('http://172.20.0.4:3000/getRestaurants', {
method: 'GET', // *GET, POST, PUT, DELETE, etc.
mode: 'no-cors', // no-cors, *cors, same-origin
cache: 'no-cache', // *default, no-cache, reload, force-cache, only-if-cached
credentials: 'same-origin', // include, *same-origin, omit
headers: {
'Content-Type': 'application/json'
// 'Content-Type': 'application/x-www-form-urlencoded',
},
redirect: 'follow', // manual, *follow, error
referrerPolicy: 'no-referrer', // no-referrer, *no-referrer-when-downgrade, origin, origin-when-cross-origin, same-origin, strict-origin, strict-origin-when-cross-origin, unsafe-url
});
const data = await response.json();
console.log(data);
return data;
}
fetchData();
});
It's probably not hard to see but there's something I'm missing. Thank you in advance!
I think you have a problem with CORS, since you are fetching data from another origin, you need to set mode: 'cors', which means that you will fetch data across origins. when you set it to mode: 'no-cors' that mean that you don't allow cross origins and that is the cause of the problem. cos as you said. your express app has a different origin than your react app. but it will still not work until you allow your express api, the origin you are fetching from. by setting headers to: ACCESS-CONTROLLE-ALLOW-ORIGIN * and the star * means allow all kind of origins. but if you want to allow a specific origin, replace the
* with url of your react app. you can also use a node.js package that will help you at this in a clean and easy way, example using cors package https://github.com/expressjs/cors:
const cors = require("cors");
let whitelist = ["http://localhost:3000"];
// Middleware
app.use(
cors({
origin: function (origin, callback) {
if (!origin) return callback(null, true);
if (whitelist.indexOf(origin) === -1) {
var message =
"The CORS policy for this origin doesnt " +
"allow access from the particular origin.";
return callback(new Error(message), false);
}
return callback(null, true);
},
})
);

MERN simple app CORS error issue - POST request

I am getting,
Access to fetch at 'http://localhost:9000/api/v1/content' from origin 'http://localhost:3000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.
and
for my FE(react)
and getting syntax err for BE(node),
SyntaxError: Unexpected token " in JSON at position 0
I have no issue with GET request but I can't POST.
Here is my FE
addContent = async (e) => {
e.preventDefault();
try {
const response = await fetch('http://localhost:9000/api/v1/content', {
method: 'POST',
body: JSON.stringify(this.state.title),
// mode:'cors', --> tried after researching but it didn't solve my issue
headers: {
'Content-Type': 'application/json'
}
});
if(!response.ok) {
throw Error(response.statusText)
}
} catch (err) {
console.log('addContent failed -', err)
}
}
Here is my BE
origin: ['http://localhost:3000', 'https://localhost:3000'],
credentials: true,
optionsSuccessStatus:200
}
app.use(cors(corsOptions));
Also, when I POST with postman, I was able to POST(got 200) however, it only returns _id. there is no body(content title that I want to post)
I read many articles that explained about cors issue but I couldn't find right answer to solve my issue. Please assume me as beginner of programing.. Thank you ahead!!
Try This
addContent = async (e) => {
e.preventDefault();
try {
const response = await fetch('http://localhost:9000/api/v1/content', {
method: 'POST',
body: JSON.stringify(this.state.title),
// mode:'cors', --> tried after researching but it didn't solve my issue
headers: {
'Access-Control-Allow-Origin': '*',
'Content-Type': 'application/json'
}
});
if(!response.ok) {
throw Error(response.statusText)
}
} catch (err) {
console.log('addContent failed -', err)
}
}
And also you can refer https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch
And I suggest try once without using cors at express.
origin: ['http://localhost:3000', 'https://localhost:3000'],
credentials: true,
optionsSuccessStatus:200
}
//app.use(cors(corsOptions));
Your error here, means that you are not allowed to access localhost:9000 from any other URL.
I recommend you take a look at this (https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS)
If you want your API to be accessed by anyone, you can set your "Access-Control-Allow-Origin" header to "*".
Here is a full explanation of this header purpose (https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin).
I hope it will be useful.

Basic Auth is not working with Axios post Nodejs

I am trying to send a request using axios post with basic authorization. It is working fine with postman but not working when I try to send via code.
axios.post(`my-url`, {
headers: {
'Content-Type': 'application/json',
'Authorization': 'Basic **KEY_HERE**',
},
data: {
'id': 'event_order',
'date': '2021-09-09'
}
}).then(async (response) => {
console.log(response.data)
})
It is returning 401 Unauthorized. But, it works as excepted when I call it via Postman:
Postman Setup Image
Did you add your domain to whitelist in your cors module? If not:
app.use(cors({ origin: "PROTOCOL://DOMAIN:PORT", credentials: true }));
edit: Ok, sorry, I was confused and thought you were sending a frontend axios post request to your own NodeJS server. If possible, could you be more precise. But try passing in your headers/auth as the third argument-- since you're passing in everything in the second argument, the API is not parsing out your headers since its part of the data parameter.
const data = {
'id': 'event_order',
'date': '2021-09-09'
}
axios.post(`my-url`, data, {
headers: {'Content-Type': 'application/json'},
auth: {
username: "YOUR_USERNAME",
password: "YOUR_PASS"
}
})
.then(async (response) => {
console.log(response.data)
})
Also try and post the network errors, if you can.

Access-Control-Allow-Origin error when trying to invoke Firebase Functions (Even using firebase's example code!)

Please read, this is different!
I've used Firebase Functions previously and solved this issue by adding this code:
const cors = require('cors')({ origin: true });
return cors(req, res, () => {
let format = req.query.format;
if (!format) {
format = req.body.format;
}
const formattedDate = moment().format(format);
console.log('Sending Formatted date:', formattedDate);
res.status(200).send(formattedDate);
});
But now I'm working on a new project, and I'm getting this error no matter what I try to do.
I have read and tried the solutions in over 20 other questions here on stackoverflow and around the internet, and none of them work now.
So I went to firebase's GitHub, downloaded the date example (has the recommended cors fix implemented) and deployed it.
And I still get the same error!
Access to fetch at 'https://us-central1-generation-y-members.cloudfunctions.net/date' from origin
'http://localhost:3000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.
The function can be called from postman and does work. https://i.imgur.com/YTi1PpQ.png
I've upgraded my project to the blaze plan (didn't help).
I've tried changing to origin: "http://localhost:3000" instead of origin: true, didn't help at all.
I've tried uploading my react app to a server and calling from there, same result (http, not https) - even when setting origin: "http://my-site.com"
Any pointers would be highly appreciated.
The issue is that the query being made from the localhost is missing the CORS headers.
On your client side application you need to add the following headers to be able to perform the CORS calls.
'Access-Control-Allow-Origin', '*'
'Access-Control-Allow-Headers', 'Content-Type'
If you are using jav ascript on the client side application this can be done with the following code, according to the libraries you are using.
xhr.setRequestHeader('Access-Control-Allow-Origin', '*');
xhr.setRequestHeader('Access-Control-Allow-Headers', 'Content-Type');
I found the solution so I'll post it here for anyone that has the same error and doesn't know why it's happening:
This is the code I'm using now, the issue was not using JSON.stringify() when setting the body for the request.
let body: any = {};
body.name = currentUser.name;
body.email = currentUser.email;
body.password = generatedPassword;
body.message = '';
body.number = randomNumber;
const requestOptions: any = {
method: 'POST',
mode: 'cors',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(body), // ISSUE WAS HERE! I HAD 'body: body'
};
try {
let response = await (await fetch('https://us-central1-generation-y-members.cloudfunctions.net/register', requestOptions)).text();
// let response = await (await fetch('http://localhost:5001/generation-y-members/us-central1/register', requestOptions)).text();
console.log({ response: response });
sentEmails.push(currentUser.email);
} catch (e) {
console.log({ error: e });
}
Good luck!

403 access denied error with Node.js fetch on external API

I've deployed my Node.js Koa API app on Heroku. I'm making a call to a USAJOB.gov API and it works on my localhost. However, on Heroku I get this error:
You don't have permission to access "http://data.usajobs.gov/$(SERVE_403)/api/search?" on this server.
Here is my Koa router snippet:
router.get('/jobs', async (ctx) => {
const { keyword, location } = ctx.query;
const url = `https://data.usajobs.gov/api/search?
Keyword=${keyword}&LocationName=${location}`;
const host = 'data.usajobs.gov';
const userAgent = '<redacted>';
const authKey = '<redacted>';
const headers = {
Host: host,
'User-Agent': userAgent,
'Authorization-Key': authKey,
};
await fetch(url, {
headers,
method: 'GET',
});
}
So it turns out that whether or not cross-site Access-Control requests should be made using credentials was what was the issue. I wasn't able to figure out how to configure that with node-fetch but once I read the the solution (link below), switched to axios, configured withCredentials: true, and added headers: { 'X-Requested-With': 'XMLHttpRequest' }, then it all worked.
Source: axios delete method gives 403

Resources