supertest changing url at every test - javascript

I'm new to backend development and i face a problem that i don't understand.
I set up the 1st route of my API called "health" who just return a simple message to know if my server is up.
This route looks to works as expected.
However,
when I try to test this route with the method "toMatchSnapshot" from
jest API, the test is not passing because of the in the url is changing constantly.
My test file "index.test.ts":
const request = supertest.agent(app);
describe("app", () => {
it("should return a successful response for GET /health", async () => {
const res = await request.get("/health");
res.header = omit(res.header, ["date"]);
expect(res).toMatchSnapshot();
});
});
index of the server "index.ts":
const app = express();
expressService(app);
if (require.main === module) {
app.listen(PORT, () => {
console.log("server started at http://localhost:" + PORT);
});
}
export default app;
my function "expressService":
const expressService = (app: Application) => {
app.use(cors());
app.use(express.urlencoded({ extended: true }));
app.use(express.json());
app.use(api);
};
export default expressService;
My PORT variable: PORT = 3000;
- "url": "http://127.0.0.1:49694/health",
+ "url": "http://127.0.0.1:52568/health",
this is where the test is failing.
Thank you for your answers.

The doc of supertest says:
You may pass an http.Server, or a Function to request() - if the server is not already listening for connections then it is bound to an ephemeral port for you so there is no need to keep track of ports.
You need to pass a Node.js http.Server object to supertest.agent(), then you can use the specific PORT for testing.
Here is the solution:
index.ts:
import express from 'express';
import expressService from './expressService';
import http from 'http';
const app = express();
const PORT = process.env.PORT || 3000;
expressService(app);
function createHttpServer() {
const httpServer: http.Server = app.listen(PORT, () => {
console.log('server started at http://localhost:' + PORT);
});
return httpServer;
}
if (require.main === module) {
createHttpServer();
}
export default createHttpServer;
expressService.ts:
import { Application } from 'express-serve-static-core';
import express, { Router } from 'express';
import cors from 'cors';
const expressService = (app: Application) => {
app.use(cors());
app.use(express.urlencoded({ extended: true }));
app.use(express.json());
const api = Router();
api.get('/health', (req, res) => {
res.sendStatus(200);
});
app.use(api);
};
export default expressService;
index.spec.ts:
import createHttpServer from './';
import { agent } from 'supertest';
import { omit } from 'lodash';
const httpServer = createHttpServer();
const request = agent(httpServer);
afterAll(done => {
httpServer.close(done);
});
describe('app', () => {
it('should return a successful response for GET /health', async () => {
const res = await request.get('/health');
res.header = omit(res.header, ['date']);
expect(res).toMatchSnapshot();
});
});
Unit test result:
PASS src/stackoverflow/57409561/index.spec.ts (7.853s)
app
✓ should return a successful response for GET /health (61ms)
console.log src/stackoverflow/57409561/index.ts:12
server started at http://localhost:3000
Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 1 passed, 1 total
Time: 8.66s
Snapshot:
// Jest Snapshot v1
exports[`app should return a successful response for GET /health 1`] = `
Object {
"header": Object {
"access-control-allow-origin": "*",
"connection": "close",
"content-length": "2",
"content-type": "text/plain; charset=utf-8",
"etag": "W/\\"2-nOO9QiTIwXgNtWtBJezz8kv3SLc\\"",
"x-powered-by": "Express",
},
"req": Object {
"data": undefined,
"headers": Object {
"user-agent": "node-superagent/3.8.3",
},
"method": "GET",
"url": "http://127.0.0.1:3000/health",
},
"status": 200,
"text": "OK",
}
`;
Here is the completed demo: https://github.com/mrdulin/jest-codelab/tree/master/src/stackoverflow/57409561

Simple enough solution:
const request = require('supertest'); // npm i -ED supertest
const app = require('../app'); // your expressjs app
const { url } = request(app).get('/'); // next, just use url
console.debug(url); // prints: http://127.0.0.1:57516/

Related

i try to upload file in my mocha nodejs test but i got [Object null prototype] { file: { ... }}

i find evrywhere solution white :
app.use(bodyParser.urlencoded({extended: true}));
i can use
JSON.stringify(req.files)
but im sur having a way to fix my problem
my mocha test :
it('a file', async function () {
const body = { pseudo: 'user', password: 'test#123', mail: 'supermail' };
const response = await fetch(hostName + '/authentication/register', {
method: 'post',
body: JSON.stringify(body),
headers: { 'Content-Type': 'application/json' }
})
const usr = await response.json();
request.post('/usrAction1/doc')
.field('token', usr.token)
.attach('file', 'test/test.pdf')
.end(function (err, res) {
if (err) {
console.log(err)
}
console.log(res.status) // 'success' status
});
});
and my rout handler :
router.post('/doc', async (req, res) => {
console.log('req.files');
console.log(req.files)
})
also my server.js:
import express from 'express'
import authentication from './src/login.js'
import './global/host.js'
import bodyParser from 'body-parser'
import cors from "cors"
import verifyToken from './middleware/auth.js'
import { userAction1, userAction2 } from './src/userAction.js'
import verifyLevel from './middleware/level.js'
import fileUpload from 'express-fileupload';
export default function myApp() {
const whitelist = [/http:\/\/localhost:*/, /http:\/\/127.0.0.1:*/]
const corsConfig = { origin: whitelist }
const app = express();
const port = hostPort;
//json encoded
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json())
app.use(cors(corsConfig))
// enable files upload
app.use(fileUpload({
createParentPath: true
}));
app.use('/usrAction1', userAction1())
app.listen(port, () => {
console.log(`Example app listening at http://localhost:${port}`);
});
return app;
}
myApp();
but don't to work for me .
i also test white external client server who juste runing a form and send it to my tested adress and
do the same [Object null prototype]
thank u for evry litel help
i waiting of some help i using this magique code i found somwhere on stackoverflow:
req.files && Object.keys(req.files)?.map((obj, idx) => { console.log(req.files['file'].data) })
if somone have a better idea i waiting .
thank to all

Socket.io on Heroku does not run as expected

I have a MERN application. I want to run this on Heroku. That also works so far. But I can't get socket.io to run on Heroku. My server listens on port 5555. Below I have listed all possible scenarios that I have already tried without success. What else can I do ?
I specify "ws://localhost:5555" or "http://localhost:5555" whatever it is, it works with a local address.
Thank you very much!
index.js Server
import express from "express";
import http from "http";
import { Server } from "socket.io";
const app = express();
const server = http.createServer(app);
const socketio = new Server(server, { cors: { origin: "*" } });
socketio.on("connect", (socket) => {
socket.on("addUser", (userId) => {
addUser(userId, socket.id);
console.log(users);
});
...
});
app.listen(process.env.PORT || 5050, () => {
verbindugZuMongoDb();
});
server.listen(5555);
App.js
import { io } from "socket.io-client";
useEffect(() => {
setSocket(io("wss://example.herokuapp.com:5555/")); // Also not working
setSocket(io("https://example.herokuapp.com:5555/")); // Also not working
setSocket(io()); // Also not working
setSocket(io(":5555")); // Also not working
setSocket(io("https://example.herokuapp.com/")); // Also not working
}, []);

Send data between GraphQL Node.js server and React in Nx

I setup two projects, Node.js and React in Nx monorepo. I would like to use GraphQL for communication. Projects I'm running with command nx serve api(Node.js) and nx serve totodile (React). Problem is that React cannot access data from /graphql endpoint.
React is running on http://localhost:4200/.
Node.js is running on http://localhost:3333/.
Node.js part
According to GraphQL instructions for Node.js I run Node.js server. I have created two endpoints /api and /graphql.
import * as express from 'express';
import { graphqlHTTP } from 'express-graphql';
import { Message } from '#totodile/api-interfaces';
import { buildSchema } from 'graphql';
const app = express();
const greeting: Message = { message: 'Welcome to api!' };
app.get('/api', (req, res) => {
res.send(greeting);
});
app.use('/graphql', graphqlHTTP({
schema: buildSchema(`
type Query {
hello : String
}
`),
rootValue: {
hello: () => 'Hello world'
},
graphiql: true,
}));
const port = process.env.port || 3333;
const server = app.listen(port, () => {
console.log('Listening at http://localhost:' + port + '/api');
});
server.on('error', console.error);
In a result I am able to connect to http://localhost:3333/graphql and receive response. So graphql server is working well.
// graphql response
{
"data": {
"hello": "Hello world"
}
}
React part
Inside functional component I fetch with /api and /graphql. First one return valid data, but /graphql is returning 404, Cannot POST /graphql.
useEffect(() => {
fetch('/api') // successfully return data
.then((r) => r.json())
.then(setMessage);
fetch('/graphql', { // 404, no data
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
},
body: JSON.stringify({query: "{ hello }"})
})
.then(r => r.json())
.then(data => console.log('data returned:', data));
}, []);
I investigate that:
http://localhost:4200/api return valid data ("message": "Welcome to api!")
http://localhost:3333/api return valid data ("message": "Welcome to api!")
http://localhost:4200/graphql 404 no data
http://localhost:3333/graphql return valid data ("hello": "Hello world")
It must be something with ports.
I don't understand how /api is able to return any data. Why on both ports?
What should I do to share data from /graphql to react?
To fix issue there was 2 steps to do:
In React I should fetch from endpoint with port fetch('http://localhost:3333/graphql',(...))
In Node.js there is need to use cors library
import express from "express";
import cors from 'cors';
const app = express();
app.use(cors());
app.use('/graphql', graphqlHTTP({
schema: schema,
rootValue: root,
graphiql: true,
}));
...

React JS & Axios Render after getting response data from POST request

How would I go about rendering a component after an axios POST request? I want to load a new component after the success response has been received from Stripe. I am trying to update the state of my component by adding a setState after receiving the response and load a simple div if the state has any values. The issue I am having is that component is not re-rendering when I use the setState.
Below is how I have a stripe component setup and the express server:
import StripeCheckout from 'react-stripe-checkout';
import axios from 'axios';
import './stripe-button.styles.scss';
import { createStructuredSelector } from 'reselect';
import { selectCurrentUser } from '../../redux/user/user.selectors';
import { setCurrentUser } from '../../redux/user/user.actions';
class StripeCheckoutButton extends React.Component {
constructor(props) {
super(props);
this.state = {
cardListBacklog: []
};
}
onToken = token => {
console.log(token);
const { cartItems, price } = this.props;
const priceForStripe = price * 100;
const orderSummary = cartItems.reduce(
(cartItemAll, cartItem) =>
(cartItemAll += cartItem.name + cartItem.quantity),
''
);
axios({
url: 'payment',
method: 'post',
data: {
amount: priceForStripe,
order: orderSummary,
token
}
})
.then(response => {
alert(
`Payment successful, ${response.data.success.billing_details.name}; please check your email for your receipt.`
);
this.setState({cardListBacklog: response.data});
})
.catch(error => {
console.log('Payment error: ', JSON.parse(error));
alert('There was an issue with your payment. Please try again!');
});
};
render() {
const publishableKey = 'pk_test_gxxxxxxxxxxxxxxxxxxxxxxxxxxx';
const { price } = this.props;
const priceForStripe = price * 100;
return (
this.state.cardListBacklog.length
?
<div>Payment Successful</div>
:
<StripeCheckout
label="Pay Now"
name="Ltd."
billingAddress
shippingAddress
image="https://i.imgur.com/vWgUzv.png"
description={`Your total is $${price} USD`}
amount={priceForStripe}
panelLabel="Pay Now"
token={this.onToken}
stripeKey={publishableKey}
label="Pay with 💳"
/>
);
}
}
export default StripeCheckoutButton;
Here is my Server.js:
const express = require('express');
const cors = require('cors');
const bodyParser = require('body-parser');
const path = require('path');
if (process.env.NODE_ENV !== 'production') require('dotenv').config();
const stripe = require('stripe')(process.env.STRIPE_SECRET_KEY);
const app = express();
const port = process.env.PORT || 5000;
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
app.use(cors());
if (process.env.NODE_ENV === 'production') {
app.use(express.static(path.join(__dirname, 'client/build')));
app.get('*', function(req, res) {
res.sendFile(path.join(__dirname, 'client/build', 'index.html'));
});
}
app.listen(port, error => {
if (error) throw error;
console.log('Server running on port: ' + port);
});
app.post('/payment', (req, res) => {
const body = {
source: req.body.token.id,
amount: req.body.amount,
receipt_email: req.body.token.email,
description: req.body.order,
currency: 'usd'
};
stripe.charges.create(body, (stripeErr, stripeRes) => {
if (stripeErr) {
res.status(500).send({ error: stripeErr });
} else {
res.status(200).send({ success: stripeRes });
}
});
});
this.state.cardListBacklog.length
This is the issue. Its giving 0 before update, and undefined after its updated. Console log and check if its true.
this.state = {
cardListBacklog: false
};
and
this.setState({cardListBacklog: true});
should do the trick.
I guess, you expects stripeRes in the state, but you are receiving an object
{success: stripeRes} instead.
You response with an object from the server here
res.status(200).send({ success: stripeRes });
But on the client side in the state you expect the array, not an object.
this.state.cardListBacklog.length
Object doesn't have length property by default.
You should check something else on the client. Maybe you should update state
on success response like
this.setState({cardListBacklog: response.data.success });
This is not super cool, but should give you an idea that client side and server side expect different things.
You should rethink your API.
The idea to use flag of successful response here (https://stackoverflow.com/a/59011695/10559239) makes sense to you, if you doesn't want to use response data in near future. Good as a first step.
But the main problem, as I can see is inconsistency between server and client.

Travis tests returning undefined

I'm testing with jasmine and it's working fine locally. However Travis CI is returning undefined for all the API tests. Example
4) Server GET /api/v1/orders Status 200
Message:
Expected undefined to be 200.
Stack:
Error: Expected undefined to be 200.
at
Snippet from the tests
describe('GET /api/v1/orders', function () {
var data = {};
beforeAll(function (done) {
Request.get('http://localhost:3001/api/v1/orders', function (error, response, body) {
data.status = response.statusCode;
data.body = JSON.parse(body);
data.number = data.body.length;
done();
});
});
it('Status 200', function () {
expect(data.status).toBe(200);
});
it('It should return three Items', function () {
expect(data.number).toBe(3);
});
});
Could the problem be from the 'http://localhost:3001/api/v1/orders' URL?
You don't seem to be starting your server anywhere so localhost:3001 isn't available.
A good solution would be to use something like supertest. It would allow you to do something like so:
app.js
const express = require('express');
const bodyParser = require('body-parser');
const app = express();
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
const routes = require('./api/routes/routes.js')(app);
// We listen only if the file was called directly
if (require.main === module) {
const server = app.listen(3001, () => {
console.log('Listening on port %s...', server.address().port);
});
} else {
// If the file was required, we export our app
module.exports = app;
}
spec.routes.js
'use strict';
var request = require('supertest');
var app = require('../../app.js');
describe("Test the server", () => {
// We manually listen here
const server = app.listen();
// When all tests are done, we close the server
afterAll(() => {
server.close();
});
it("should return orders properly", async () => {
// If async/await isn't supported, use a callback
await request(server)
.get('/api/v1/orders')
.expect(res => {
expect(res.body.length).toBe(3);
expect(res.status).toBe(200);
});
});
});
Supertest allows you to make requests without relying on a specific port/url/other.

Categories