Test a POST Http request from a local node server in REACT - javascript

I need to make unit tests for some post requests but i dont understand how.I tried with mswjs but the test passes because i'm missing something and i dont know what.I tried to test the requests in an usual way but i wasnt able to put my conditions there and it was sending only 200 status code..
To start with,this is my folder structure:
+main folder
++nodeServer
+++public
+++routes
++public
++src
+++tests
This is my try for testing the post request to /subscribe endpoint,where i should send an email as a payload and get the response that the payload was received succesefully.
subscribeFetch.test.js:
import {setupServer} from 'msw/node'
import {rest} from 'msw'
const handlers = [
rest.post("/api/subscribe",(req,res,context)=>{
if (!req.body || !req.body.email) {
return res(context.status(400).json({ error: "Wrong payload" }));
}
if (req.body.email === 'forbidden#email.com') {
return res(context.status(422).json({ error: "Email is already in use" }));
}
return res(
context.status(200),
context.json({email:'gigi#gmail.com'})
)
})
]
const server = setupServer(...handlers)
beforeAll(()=>server.listen())
afterAll(()=>server.close())
afterEach(()=>server.resetHandlers())
test('should send post request to the server',async()=>{
server.use(
rest.post('/api/subscribe',(req,res,ctx)=>{
return res(
expect (ctx.status()).toBe(200)
)
}
)
)
})
//export {handlers,rest}
This is the subscribe post request function that i need to test:
import { validateEmail } from './email-validator.js'
export const sendSubscribe = (emailInput) => {
const isValidEmail = validateEmail(emailInput)
if (isValidEmail === true) {
sendData(emailInput)
}
}
export const sendHttpRequest = (method, url, data) => {
return fetch(url, {
method: method,
body: JSON.stringify(data),
headers: data
? {
'Content-Type': 'application/json'
}
: {}
}).then(response => {
if (response.status >= 400) {
return response.json().then(errResData => {
const error = new Error('Something went wrong!')
error.data = errResData
throw error
})
}
return response.json()
})
}
const sendData = (emailInput) => {
sendHttpRequest('POST', '/api/subscribe', {
email: emailInput
}).then(responseData => {
return responseData
}).catch(err => {
console.log(err, err.data)
window.alert(err.data.error)
})
}
Files from the server:
app.js:
const express = require('express');
const path = require('path');
const cookieParser = require('cookie-parser');
const logger = require('morgan');
const indexRouter = require('./routes/index');
const communityRouter = require('./routes/community');
const analyticsRouter = require('./routes/analytics');
const app = express();
global.appRoot = path.resolve(__dirname);
app.use(logger('dev'));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
app.use('/', indexRouter);
app.use('/community', communityRouter);
app.use('/analytics', analyticsRouter);
module.exports = app;
index.js from routes folder in the server folder:
const express = require('express');
const router = express.Router();
const FileStorage = require('../services/FileStorage');
/* POST /subscribe */
router.post('/subscribe', async function (req, res) {
try {
if (!req.body || !req.body.email) {
return res.status(400).json({ error: "Wrong payload" });
}
if (req.body.email === 'forbidden#email.com') {
return res.status(422).json({ error: "Email is already in use" });
}
const data = {email: req.body.email};
await FileStorage.writeFile('user.json', data);
await res.json({success: true})
} catch (e) {
console.log(e);
res.status(500).send('Internal error');
}
});
/* GET /unsubscribe */
router.post('/unsubscribe', async function (req, res) {
try {
await FileStorage.deleteFile('user.json');
await FileStorage.writeFile('user-analytics.json', []);
await FileStorage.writeFile('performance-analytics.json', []);
await res.json({success: true})
} catch (e) {
console.log(e);
res.status(500).send('Internal error');
}
});
module.exports = router;
Please guys,help me write unit test for subscribe endpoint to match the conditions from index.js file from routes folder in the server folder,thank you in advance!

So,i got the expected result without any library,but i dont know if its a good aproach,but at least it works :
const app = require('../../../personal-website-server/app')
const request = require('supertest')
describe('POST /subscribe', () => {
it('should give 400 status code when email is empty', async () => {
const email = { email: '' }
const response = await request(app).post('/subscribe').send(email)
if (!request.body || !request.body.email) {
expect(response.status).toBe(400)
}
})
it('should give 422 status code when email is forbidden', async () => {
const email = { email: 'forbidden#gmail.com' }
const response = await request(app).post('/subscribe').send(email)
if (request.body === 'forbidden#gmail.com') {
expect(response.status).toBe(422)
}
})
it('should give 200 status code when email is valid', async () => {
const email = { email: 'gigi#gmail.com' }
const response = await request(app).post('/subscribe').send(email)
expect(response.error).toBe(false)
expect(response.status).toBe(200)
expect(response.body.body).not.toBeNull()
})
})

Related

How to properly give next() in the middleware in node app

I am trying to verify the bearer token which has been generated after the login request. I have segregated the codes for controllers, middlewares and routes.
The login is working fine and is able to generate the token but when I try to verify it I get the following error:
Error: Route.post() requires a callback function but got a [object Undefined]
at Route.<computed> [as post] (C:\Users\Desktop\loginapi\node_modules\express\lib\router\route.js:211:15)
at Function.proto.<computed> [as post] (C:\UsersDesktop\loginapi\ at Module.require (node:internal/modules/cjs/loader:1028:19)
at require (node:internal/modules/cjs/helpers:102:18) at Object.<anonymous> (C:\Users\Desktop\loginapi\index.js:15:20)
[nodemon] app crashed - waiting for file changes before starting...
Below is the complete Code:
Server.js //Main file
const express = require('express')
const app = express()
require('dotenv').config();
const port = process.env.PORT;
console.log(port)
//initialize middleware
app.use(express.json())
//import routes
const authRoutes = require('./src/routes')
// initialize routes
app.use('/abc', authRoutes)
// console.log();
//app start
const appStart = () => {
try {
app.listen(port, ()=> {
console.log(`The app is listening at http://localhost:${port}`)
})
} catch (error) {
console.log(`${error.message}`)
}
}
appStart()
routes/index/js
const { Router} = require('express')
const userController = require('../controllers/index')
const { verifyToken } = require('../middlewares/verifyTokens')
const router = Router()
router.post('/login', userController.login)
router.post('/profile',verifyToken ,userController.profile)
module.exports = router
middlewares/verifyTokens.js
// Function to verify whether the bearer token is correct or not
function verifyToken(req, resp, next) {
const bearerHeader = req.headers['authorization'];
if (typeof bearerHeader !== 'undefined') {
const bearer = bearerHeader.split(" ");
const token = bearer[1];
req.token = token;
next();
} else {
resp.send({
result: 'Invalid Token'
})
}
}
module.exports = verifyToken
contollers/index.js
const { sign } = require('jsonwebtoken')
const secret = process.env.SECRET;
//login function
const login = async (req, res) => {
payload = {
"email": "abc#gmail.com",
"password": "user123"
}
console.log(payload)
try {
sign(payload, secret, (err, token) => {
try {
res.json({
token
})
// console.log(typeof resp.json)
} catch (err) {
res.send(err.message);
}
})
} catch (error) {
console.log(error.message)
return res.status(500).json({
error: error.message
})
}
}
const profile = async (req,res) => {
try {
return res.status(200).json({
success: true,
message: 'In Profile',
})
} catch (error) {
console.log(error.message)
return res.status(500).json({
error: error.message
})
}
}
const userControllers = {
login,
profile
}
module.exports = userControllers
There is some problem with the middleware verifyTokens ,I have gone through other answers but I am not getting it. Can someone please point it out as to where I am going wrong. It will be very helpful. Thank you
Import verifyTokens without { } it will solve the problem.
In routes/index/js :
const verifyTokens = require('../middlewares/verifyTokens')
Instead of this
router.post('/login', userController.login)
router.post('/profile',verifyToken ,userController.profile)
try this one
router.post('/login',(req, res) => {
userController.login
});
router.post('/profile',
(req, res, next) => {
verifyToken
},
(req,res,next) => {
userController.profile
}
);

Cannot POST /api/sentiment

I'm testing the endpoint for /api/sentiment in postman and I'm not sure why I am getting the cannot POST error. I believe I'm passing the correct routes and the server is listening on port 8080. All the other endpoints run with no issue so I'm unsure what is causing the error here.
server.js file
const express = require("express");
const cors = require("cors");
const dbConfig = require("./app/config/db.config");
const app = express();
var corsOptions = {
origin: "http://localhost:8081"
};
app.use(cors(corsOptions));
// parse requests of content-type - application/json
app.use(express.json());
// parse requests of content-type - application/x-www-form-urlencoded
app.use(express.urlencoded({ extended: true }));
const db = require("./app/models");
const Role = db.role;
db.mongoose
.connect(`mongodb+srv://tami00:MEUxClWqUNbLz359#cluster0.gmvao.mongodb.net/test?retryWrites=true&w=majority`, {
useNewUrlParser: true,
useUnifiedTopology: true
})
.then(() => {
console.log("Successfully connect to MongoDB.");
initial();
})
.catch(err => {
console.error("Connection error", err);
process.exit();
});
// simple route
app.use('/api/favourite', require('./app/routes/favourite.routes'));
app.use('/api/review', require('./app/routes/review.routes'));
app.use('/api/sentiment', require('./app/routes/sentiment-analysis.routes'));
// routes
// require(".app/routes/favourite.routes")(app);
require("./app/routes/auth.routes")(app);
require("./app/routes/user.routes")(app);
// set port, listen for requests
const PORT = process.env.PORT || 8080;
app.listen(PORT, () => {
console.log(`Server is running on port ${PORT}.`);
});
function initial() {
Role.estimatedDocumentCount((err, count) => {
if (!err && count === 0) {
new Role({
name: "user"
}).save(err => {
if (err) {
console.log("error", err);
}
console.log("added 'user' to roles collection");
});
new Role({
name: "creator"
}).save(err => {
if (err) {
console.log("error", err);
}
console.log("added 'creator' to roles collection");
});
new Role({
name: "watcher"
}).save(err => {
if (err) {
console.log("error", err);
}
console.log("added 'watcher' to roles collection");
});
}
});
}
sentiment-analysis routes file
const express = require('express');
const router = express.Router();
const getSentiment = require('../sentiment-analysis/sentimentAnalysis')
router.post('/api/sentiment', (req, res) => {
const data = req.body.data
const sentiment = getSentiment(data)
return res.send({sentiment})
})
module.exports = router;
sentimentAnalysis.js file
const aposToLexForm = require("apos-to-lex-form");
const {WordTokenizer, SentimentAnalyzer, PorterStemmer} = require("natural");
const SpellCorrector = require("spelling-corrector");
const stopword = require("stopword");
const tokenizer = new WordTokenizer();
const spellCorrector = new SpellCorrector();
spellCorrector.loadDictionary();
const analyzer = new SentimentAnalyzer('English', PorterStemmer, 'afinn')
function getSentiment(text){
if(!text.trim()) {
return 0;
}
const lexed = aposToLexForm(text).toLowerCase().replace(/[^a-zA-Z\s]+/g, "");
const tokenized = tokenizer.tokenize(lexed)
const correctSpelling = tokenized.map((word) => spellCorrector.correct(word))
const stopWordsRemoved = stopword.removeStopwords(correctSpelling)
console.log(stopWordsRemoved)
const analyzed = analyzer.getSentiment(stopWordsRemoved);
console.log(analyzed)
}
module.exports = getSentiment;
console.log(getSentiment("Wow this is fantaztic!"))
console.log(getSentiment("let's go together?"))
console.log(getSentiment("this is so bad, I hate it, it sucks!"))
I see that you use your routes like: app.use('/api/sentiment', require('./app/routes/sentiment-analysis.routes'));. But then in your sentiment-analysis you again use /api/sentiment so your request URL should be /api/sentiment/api/sentiment
Shouldn't it be:
const data = req.body.data

My data not reaching to the backend node server from react server

my Signup.js file from where the request is initiating,
import React,{ useState } from 'react';
import isEmail from 'validator/lib/isEmail';
import isEmpty from 'validator/lib/isEmpty';
import equals from 'validator/lib/equals';
import { Link } from 'react-router-dom';
import { showErrMsg,showSuccessMsg } from '../Helpers/messages.js';
import { showLoading } from '../Helpers/loading';
import { signup } from '../../api/auth';
import './SignUp.css';
const SignUp = () => {
// filled this for testing purpose
const[formData,setFormData] = useState({
username: 'shivshankar',
email:'shivshankarkumar.pusa#gmail.com',
password:'1234',
password2:'1234',
successMsg:false,
errorMsg:false,
loading:false,
});
const {
username,
email,
password,
password2,
successMsg,
errorMsg,
loading,
} = formData;
const handleSubmit = (e) => {
e.preventDefault();
if(isEmpty(username) || isEmpty(email) || isEmpty(password) || isEmpty(password2)){
setFormData({
...formData,errorMsg : "All fields are Required"
})
}else if(!isEmail(email)){
setFormData({
...formData , errorMsg : "Invalid Email"
})
}else if(!equals(password,password2)){
setFormData({
...formData , errorMsg: "Passwords do not Match"
})
}else{
const { username , email , password} = formData;
const data = { username , email , password};
setFormData({
...formData,
loading : true,
})
signup(data)
.then(response => {
console.log("Axios signup success",response);
setFormData({
username:"",
email:"",
password:"",
password2:"",
loading:false,
successMsg:response.data.successMessage
})
})
.catch(err => {
console.log("Axios post error : " , err);
setFormData({...formData, loading : false});
});
}
}
my auth.jjs file from the axios post request is generating
import axios from 'axios';
export const signup = async (data) => {
const config = {
headers : {
'Content-Type' : 'applicaion/json',
},
};
console.log(data);
const response = await axios.post('/api/auth/signup', data, config);
return response;
};
now in server side server.js
const express = require('express');
const app = express();
const cors = require('cors');
const morgan = require('morgan');
const connectDB = require('./database/db');
const authRoutes = require('./routes/auth');
const bodyParser = require('body-parser');
app.use(bodyParser.urlencoded({ extended : true }));
app.use(bodyParser.json());
app.use(cors());
app.use(morgan('dev'));
app.use(express.json());
app.use('/api/auth',authRoutes);
// app.post('/api/auth/signup',(req,res) => {
// console.log("inside signup");
// // res.send("api/auth/signup");
// });
connectDB();
const port = process.env.PORT || 5000;
app.listen(port, () => console.log(`listening to port ${port}`));
auth.js file for authRoutes`
const express = require('express');
const router = express.Router();
const { signupValidator, validatorResult } = require('../middleware/validator');
router.post('/signup', signupValidator, validatorResult);
module.exports = router;
my validator.js file
const { check, validationResult } = require('express-validator');
exports.signupValidator = [
check('username').not().isEmpty().trim().withMessage('All fields are required'),
check('email').isEmail().normalizeEmail().withMessage('Invalid Email'),
check('password').isLength({ min : 6 }).withMessage('Password must be 6 character long'),
];
exports.validatorResult = (req, res, next) => {
// console.log("request body" ,req.body);
const result = validationResult(req);
const hasErrors = !result.isEmpty();
// console.log(result);
if(hasErrors){
const firstError = result.array()[0].msg;
console.log("has errors",hasErrors);
console.log("result",result);
return res.status(400).json({
message : firstError,
});
}
next();
};
the data is being sent from front-end axios, but the data is not reaching to the back-end node server,
when i console.log(req.body) or console.log(data) it says undefined.
i am stuck here, can anyone please help me??
get this output in the console.
[0] result Result {
[0] formatter: [Function: formatter],
[0] errors:
[0] [ { value: undefined,
[0] msg: 'All fields are required',
[0] param: 'username',
[0] location: 'body' },
[0] { value: undefined,
[0] msg: 'Invalid Email',
[0] param: 'email',
[0] location: 'body' },
[0] { value: undefined,
[0] msg: 'Password must be 6 character long',
[0] param: 'password',
[0] location: 'body' } ] }
[0] POST /api/auth/signup 400 34.535 ms - 37
You have a typo in your auth.js file, you have set the Content-Type headers incorrectly it should be application/json & not applicaion/json
import axios from 'axios';
export const signup = async (data) => {
const config = {
headers : {
'Content-Type' : 'application/json', //this should be application/json
},
};
console.log(data);
const response = await axios.post('/api/auth/signup', data, config);
return response;
};
You need to require the routes after your app.use(bodyParser.json()); statement
So move const authRoutes = require('./routes/auth'); to after app.use(bodyParser.json());

"Sending request" loading on Get request on Postman

My /chat route works well through Post method with validation with Joi schema but when I send request through Get method, it show Sending Request and continue loading...
My index.js file:
const express = require('express');
const cors = require('cors');
const bodyParser = require('body-parser');
const morgan = require('morgan');
const chat = require('./db/ChatModel');
const app = express();
app.use(bodyParser.json());
app.get('/chat', (req, res) => {
chat.getAllMessages().then( (messages) => {
res.json(messages);
});
});
app.post('/chat', (req, res) => {
console.log(req.dody);
chat.createMessages(req.body).then((message) => {
res.json(message);
}).catch( (error) => {
res.status(500);
res.json(error);
});
});
const port = process.env.PORT || 8888;
app.listen(port, () => {
console.log(`Listening on port ${port}...`);
});
In connection.js I coded this
const monk = require('monk');
const connectionString = 'localhost/chatboard';
const db = monk(connectionString);
module.exports = db;
And ChatModal.js has the following code
const Joi = require('joi');
const db = require('./connection');
const schema = Joi.object().keys({
username: Joi.string().alphanum().min(4).max(16).required(),
subject: Joi.string().required(),
message:Joi.string().max(300).required(),
imgUrl: Joi.string().uri({
scheme: [ // https://github.com/hapijs/joi/blob/v14.3.1/API.md#stringurioptions
/https?/
]
})
});
const chat = db.get('chat');
function getAllMessages() {
return chat.find();
};
function createMessages(message) {
const result = Joi.validate(message, schema);
if (result.error == null) {
message.created = new Date();
return chat.insert(message);
} else {
return Promise.reject(result.error);
}
}
module.exports = {
createMessages,
getAllMessages
};
I can't understand why getAllMessages() doesn't work and postman continue loading when Get request applied like this http://prntscr.com/s0d9c5
ChatModal.js
function getAllMessages() {
try {
return chat.find();
} catch (err) {
return next(err);
}
index.js
app.get('/chat', (req, res, next) => {
try{
data = chat.getAllMessages()
} catch (err) {
return next(error);
}
res.json(data);
});
User try-catch in the ChatModal.js and also index.js then you can understand what is actual error, like bellow:
ChatModal.js
function getAllMessages() {
try {
chat.find();
} catch (err) {
return next(err);
}
I think, may be your data, i mean message list data so weight, in this case you get all message,res.json(messages); json method have long time to parse messages data

Why is the Query from getInitialProps empty?

I want to fetch some data using query parameters on the server for a page.
However, my query is empty inside getInitialProps when rendered through server. Why could this be happening?
Moreover, I have noticed this only happens in production server and not in the dev or prod env on my local.
Here's some code
import React from 'react';
import Config from 'component/Config';
import { withAuthSync } from 'util/auth';
import apiUrl from 'util/apiUrl';
function ResourceConfigPage({ data }) {
return <Config data={data} />;
}
ResourceConfigPage.getInitialProps = async ctx => {
const { resourceId } = ctx.query;
try {
const response = await fetch(`${apiUrl}/resource/config?resourceId=${resourceId}`, {
method: 'GET',
headers: {
'Content-Type': 'application/json',
}
});
if (response.ok) {
const data = await response.json();
return { data };
}
}
return {};
};
export default withAuthSync(ResourceConfigPage);
My next app uses a custom express server and here's how it looks.
const express = require('express');
const next = require('next');
const compression = require('compression');
const dev = process.env.NODE_ENV !== 'production';
const app = next({ dev });
const handle = app.getRequestHandler();
app
.prepare()
.then(() => {
const server = express();
app.setAssetPrefix(dev ? '' : 'https://example.com');
server.use(compression());
server.get('/healthcheck', (req, res) => {
res.status(200).json({});
});
server.get('/', (req, res) => {
if (req.cookies.sessionId) {
res.redirect('/dashboard');
}
res.redirect('/login');
});
server.get('*', (req, res) => {
return handle(req, res);
});
server.listen(3000, err => {
if (err) throw err;
console.log('> Ready on http://localhost:3000');
});
})
.catch(ex => {
console.error(ex.stack);
process.exit(1);
});

Categories