ReactJS testing causing a typeError: network request failed - reactjs

I have been trying to simulate file-upload as a test for my react-app but that was generating the following error :
TypeError: Network request failed
at node_modules/whatwg-fetch/dist/fetch.umd.js:535:18
at Timeout.task [as _onTimeout] (node_modules/jsdom/lib/jsdom/browser/Window.js:516:19)
This is my test: trying to upload a file and check if an alert is raised.
test("triggers alert when receiving a file with inadequate content", async () => {
renderComponent();
global.alert = jest.fn();
const fileContent = raw("./file.kml");
const fakeFile = new File(
[fileContent],
"file.kml",
{ type: "text/xml" }
);
const selectType = screen.getByTestId("select-type");
await fireEvent.change(selectType, { target: { value: "type" } });
const fileUploader = screen.getByTestId("file-uploader");
await fireEvent.change(fileUploader, {
target: { files: [fakeFile] },
});
await waitFor(() => {
expect(global.alert).toHaveBeenCalledWith(
"alert"
);
});
});
});
I am kind of confused, because file is received and parsed by the component and it raise the alert I need to check but still fails because of the network error.
PS: I tried to mock a fetch but still have the same problem.
Any help would be appreciated.

I have been getting the same
Network request failed: Connection refused
error while testing.
I have explored many threads but no luck.
Out of the blue starting the back end server worked for me. (Even though I used mock service worker that intercepts network calls, starting the back end server worked.)
I don't know why.
Also, I have used import fetch from 'isomorphic-fetch'; in setup-test.js instead of whatwg-fetch.
In the end try adding a timeout:3000 option to your waitFor.

Related

Can't get the Generic Sensor API to work in a React app

I'm trying to implement the Generic Sensor API in a React app.
https://www.w3.org/TR/generic-sensor/#the-sensor-interface
I keep getting an error when I try to implement any of the sensors in my code.
For example:
var sensor1 = new AmbientLightSensor();
I get the error: Cannot find name: 'AmbientLightSensor'.
I assume that I need an import statement in my code. All of the examples I've found only include LitElement. I've even tried that but still get the unknown error.
What import statements do I need in my typescript code?
What npm packages do I need?
Below is the typescript code I'm using.
I'm getting a typescript error:
/Users/scoleman/dev/current/bigbrother/src/utility/testAccel.ts(14,24):
Cannot find name 'AmbientLightSensor'. TS2304
export const testAccel = async (
databaseName: string,
) => {
const {state} = await navigator.permissions.query({
name: "ambient-light-sensor"
});
if (state !== "granted") {
console.warn("You haven't granted permission to use the light sensor");
return;
}
const sensor = new AmbientLightSensor();
sensor.addEventListener("reading", () => {
console.log(sensor.illuminance);
});
sensor.addEventListener("error", (err: any) => {
console.error(err);
});
sensor.start();
};
I was able to get these api's running using the polyfill at:
https://github.com/kenchris/sensor-polyfills
This would depend entirely on the browser you are using. I don't think FireFox supports it at the moment so I will focus on Chrome.
Firstly, you might need to be serving your site over HTTPS. It seems like this almost varies from permission to permission and also some are available on a localhost URL no matter what.
Secondly, for Chrome, you have to enable the "Generic Sensor Extra Classes" flag in Chrome at the chrome://flags/#enable-generic-sensor-extra-classes page.
Next, you need to make sure that have permission from the user to use the sensor, then you could actually use it. A snippet that would check that is as follows:
(async function(){
const {state} = await navigator.permissions.query({
name: "ambient-light-sensor"
});
if (state !== "granted") {
console.warn("You haven't granted permission to use the light sensor");
return;
}
const sensor = new AmbientLightSensor();
sensor.addEventListener("reading", () => {
console.log(sensor.illuminance);
});
sensor.addEventListener("error", err => {
console.error(err);
});
sensor.start();
}());

Getting “TypeError: failed to fetch” when sending an email with SendGrid on ReactJS project

I am trying to send email with SendGrid in ReactJS project.
This is my componnet:
//Email.js
import React from 'react'
const sgMail = require('#sendgrid/mail');
sgMail.setApiKey(process.env.SENDGRID_API_KEY);
const msg = {
to: 'aaaaa#gmail.com',
from: 'bbbb#gmail.com',
subject: 'This is a test mail',
text: 'and easy to do anywhere, even with Node.js',
html: '<strong>and easy to do anywhere, even with Node.js</strong>',
};
sgMail.send(msg).catch(error => {alert(error.toString()); });
export const Email= () => (
<h1>Email Sending Page</h1>
)
When I am trying to run the app with "npm start" on localhost, the email is not sent and I got the error message "TypeError: Failed to fetch".
But, if I am using this code:
//Email.js
const sgMail = require('#sendgrid/mail');
sgMail.setApiKey(process.env.SENDGRID_API_KEY);
const msg = {
to: 'aaaaa#gmail.com',
from: 'bbbb#gmail.com',
subject: 'This is a test mail',
text: 'and easy to do anywhere, even with Node.js',
html: '<strong>and easy to do anywhere, even with Node.js</strong>',
};
sgMail.send(msg)
and do this command: "node Email.js" the mail is sent. It works only this way and I cannot understand why.
I tried any solution that I could find but nothing works.
(I tried even to put the api_key hardcoded in the code just for the test and I got the same result).
EDIT
After looking around a bit I found out that you can't use Sendgrid to send email directly from the browser.
Sendgrid won't let you send an email directly using Javascript in the
browser.
You will need to have a server set-up and use the server to send the
email instead (using your favourite back-end framework/language,
Node.js, php, Java, etc.).
The steps for sending a mail will be similar to this:
Write email details in the React application
Send a POST request to
your server endpoint (for example, /sendemail) with the email data
(recipient, title, content, etc.) Receive Email data in the server and
send it to Sendgrid api Here is the official Sendgrid documentation
regarding their CORS policy:
https://sendgrid.com/docs/for-developers/sending-email/cors/
Source: React unable to send email with SendGrid
EDIT 2
If you want to implement Sendgrid without actually building and deploying a server, you can use a simple Firebase function which is free to host.
I know this may look intimidating but in reality its pretty easy. Also I just put this together real quick so if anything doesn't work out for you, shoot me a comment.
Follow steps 1-3 on the getting started page for firebase functions. It is pretty straightforward and you end up with the firebase tools CLI installed.
Navigate to the functions/ folder inside your project on the command line/terminal.
Install the Sendgrid and cors libraries in the functions folder
npm i #sendgrid/mail cors
Add your Sendgrid API key to your firebase environment with the following command in your project:
firebase functions:config:set sendgrid.key="THE API KEY"
Copy this into your functions/index.js file:
const functions = require("firebase-functions");
const cors = require("cors")({ origin: true });
const sgMail = require("#sendgrid/mail");
exports.sendEmail = functions.https.onRequest((req, res) => {
sgMail.setApiKey(functions.config().sendgrid.api);
return cors(req, res, () => {
const { msg } = req.body;
sgMail.send(msg).catch(error => {
alert(error.toString());
});
res.status(200).send(msg);
});
});
Save it and run firebase deploy --only functions on the command line. Your function should now be live at https://us-central1-<project-id>.cloudfunctions.net/sendEmail
Now change your React file to:
//Email.js
import React, { useEffect } from 'react'
export const Email= () => {
useEffect(() => {
const sendEmail = async() => {
const msg = {
to: 'aaaaa#gmail.com',
from: 'bbbb#gmail.com',
subject: 'This is a test mail',
text: 'and easy to do anywhere, even with Node.js',
html: '<strong>and easy to do anywhere, even with Node.js</strong>',
};
const response = await fetch(
'https://us-central1-FIREBASE-PROJECT-ID-HERE.cloudfunctions.net/sendEmail', {
method: 'POST',
body: JSON.stringify(msg),
headers: {
'Content-Type': 'application/json'
}
});
console.log("response", response);
}
sendEmail();
}, []);
return <h1>Email Sending Page</h1>
}
And thats it! You basically have a server side function without making a server and its free!
Feel free to ignore this if you don't feel like putting in the work but if you need any help, let me know.

How to get error body using React Apollo Link Rest

I am creating an React app using Apollo Graphql and I am having some trouble with the Apollo Link Rest. The problem is that in the middle of my app I have to make a REST request, however this request can be sucessful and return a status code = 200 or it can fail, returning a status code = 400.
It is important for my app to show the end user an error message that is returned in this request's body in case of a 400 error. However when an error happens the Apollo Link Rest just throws an exception, but it doesn't return response body back to me.
Is there a way for me to get the response body, when there is an error with the Apollo Link Rest? I thought that I could get it from the result variable, but since the Apollo throws an exception, this variable never changes.
Here is my code:
const result = await context.client.query<MyQuery>({
query: MyQuery,
variables: {
input: {
companyId: variables.companyId,
},
},
});
query MyQuery($input: MyQueryInput!) {
myQuery(input: $input) #rest(
type: "QueryResponse",
method: "POST"
path: "v1/my-query"
) {
id
minimumPreparationTime
maximumPreparationTime
extras {
id
optional
key
}
warning
error {
id
type
message
}
}
}
Extending Greg comment and apollo-link-error, you can retrieve the error body from networkError.result.message.
You can use apollo-link-error to catch and handle server errors, network errors, and GraphQL errors. You should be able to conditionally set response.errors if needed.
import { onError } from "apollo-link-error";
const link = onError(({ graphQLErrors, networkError, response, operation }) =>
{
if (graphQLErrors)
graphQLErrors.map(({ message, locations, path }) =>
console.log(
`[GraphQL error]: Message: ${message}, Location: ${locations}, Path:
${path}`,
),
);
if (networkError) console.log(`[Network error]: ${networkError}`);
response.error = // set error property here
});
It may also be worth noting Apollo exposes an errorPolicy option, for which the default is none. The policy can be modified to all which, according to the docs,
is the best way to notify your users of potential issues while still
showing as much data as possible from your server. It saves both data
and errors into the Apollo Cache so your UI can use them.

Sending JSON via Postman causes an error in my Node.js service

I created schema in node.js. It worked before I included arrays.
This is my schema code:
const Item = new item_Schema({
info:{
title:{type:String, required:true},
bad_point:{type:Number, 'default':0},
Tag:{type:String, required:true}
},
review:{
Review_text:{type:Array, required:true},
Phone_list:{type:Array, required:true},
LatLng_list:{type:Array, required:true}
}
});
Item.statics.create = function(info, review){
const list = new this({
info:{
title,
bad_point,
Tag
},
review:{
Review_text,
Phone_list,
LatLng_list
}
});
return list.save();
};
This is my register code:
exports.register = (req, res) => {
const { info, review } = req.body
const create = (list) => {
return Item.create(info, review)
}
const respond = () => {
res.json({
message: 'place route registered successfully'
})
}
const onError = (error) => {
res.status(409).json({
message: error.message
})
}
RouteReviewItem.findOneBytitle(title)
.then(create)
.then(respond)
.catch(onError)
}
And this is the Postman JSON raw code:
{
"info":"{
"title":"test title",
"badPoint":"0"
"Tag":"tag1"
}",
"review":"{
"Review_text":["1번리뷰", "2번리뷰", "3번리뷰"],
"Phone_list":"["010-0000-0000", "010-1111-1111", "010-2222-2222"],
"LatLng_list":["111.1111,111.1111", "222.222,222.222","333.3333,333.3333"]
}"
}
This is the error I get in Postman:
SyntaxError: Unexpected token in JSON at position 17
at JSON.parse (<anonymous>)
at parse (C:\MainServer\node_modules\body-parser\lib\types\json.js:89:19)
at C:\MainServer\node_modules\body-parser\lib\read.js:121:18
at invokeCallback (C:\MainServer\node_modules\raw-body\index.js:224:16)
at done (C:\MainServer\node_modules\raw-body\index.js:213:7)
at IncomingMessage.onEnd (C:\MainServer\node_modules\raw-body\index.js:273:7)
at emitNone (events.js:105:13)
at IncomingMessage.emit (events.js:207:7)
at endReadableNT (_stream_readable.js:1045:12)
at _combinedTickCallback (internal/process/next_tick.js:138:11)
at process._tickCallback (internal/process/next_tick.js:180:9)
Is this a problem with postman? Or the node.js side?
I looked at the node.js book I was studying, but could not find any relevant information.
The code is fine, you have an issue with JSON you used for testing. For further testing and debugging, I suggest that you verify that the requests you send you the endpoint are correct by using a service like JSONLint (or any offlne tool that does the same). For the request you posted in the question, this service complains:
Error: Parse error on line 2:
{ "info": "{ "title": "test t
----------^
Expecting 'STRING', 'NUMBER', 'NULL', 'TRUE', 'FALSE', '{', '[', got 'undefined'
Next time, before sending a request, make sure it is correct syntactically. That way you'll know that there is a problem with your code, and won't spend time debugging a non-existent issue.

Incorporating Socket.IO in React Application

I am trying to incorporate socket.io in a React application. When the user clicks a button, I want the program to display a modal notifying all other users that the button has been clicked. In my current implementation, I set up the socket.io connection in my server.js file and use socket.io-client in one of the component files to send / listen for information from the server.
Server.js file:
io.on("connection", function(socket) {
console.log("Socket.io connection established");
socket.emit("saved article", function(article){
console.log("article saved");
io.emit("saved article", article);
});
});
Component file:
const socket = io();
class Search extends Component {
state = {
topic: "",
start: "",
end: "",
results: [],
savedModalTriggered: false,
articlesSaved: []
};
componentDidMount(){
socket.on("saved article", article => {
let articlesSavedCopy = this.state.articlesSaved;
articlesSavedCopy.push(article.title);
this.setState({savedModalTriggered: true, articlesSaved: articlesSavedCopy});
});
};
saveOrUnsave = (index) => {
API.saveArticle(this.state.results[index]).then(response => {
const article = {
title: response.data.title
};
socket.emit("saved article", article);
this.reverseSaved(index, response.data);
});
};
};
The following problems arise when I run my code:
1) When the Search component mounts, the program triggers socket.on("saved article"), causing the notification modal to pop up even though the saveOrUnsave function was not called.
2) After some period of time, I get the following error in my console: "WebSocket connection to localhost:3000... failed: Connection closed before receiving a handshake response"
3) I also get the following error in my console: "WebSocket connection to localhost:3000... failed: WebSocket opening handshake timed out"
The problem is that you are emitting a saved article event upon connection. When the client opens a new connection in the componentDidMount callback the server emits an event, thus triggering the callback you have registered.
If that is not what you want you should remove the emit logic from your connection callback in the server code.

Resources