Post an object with fetch using react js and express API server - node.js

I am getting troubles with the post method in fetch because my server is receiving an empty object from the client. I've checked in the client side and can't send the value that I want to send.
This is my server:
const express = require('express');
const app = express();
const bodyParser = require('body-parser');
const mysql = require('mysql');
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({
extended: true
}));
// connection configurations
const mc = mysql.createConnection({
host: 'localhost',
user: 'root',
password: '12345',
database: 'node_task_demo',
//socketPath: '/Applications/MAMP/tmp/mysql/mysql.sock'
});
// connect to database
mc.connect();
// default route
app.get('/', function (req, res) {
return res.send({ error: true, message: 'hello' })
});
// Here where I'm calling in the client side
app.get('/todos', function (req, res) {
mc.query('SELECT * FROM tasks', function (error, results, fields) {
if (error) throw error;
return res.send({ error: false, data: results, message: 'Todo list' });
});
});
// Search for todos with ‘bug’ in their name
app.get('/todos/search/:keyword', function (req, res) {
var mensaje = 'Todos search list.';
let keyword = req.params.keyword;
mc.query("SELECT * FROM tasks WHERE task LIKE ? ", ['%' + keyword + '%'], function (error, results, fields) {
if (error) throw error;
return res.send({ error: false, data: results, message: mensaje});
});
});
// Retrieve todo with id
app.get('/todo/:id', function (req, res) {
let task_id = req.params.id;
if (!task_id) {
return res.status(400).send({ error: true, message: 'Please provide task_id' });
}
mc.query('SELECT * FROM tasks where id=?', task_id, function (error, results, fields) {
if (error) throw error;
return res.send({ error: false, data: results[0], message: 'Todos list.' });
});
});
// Add a new todo
app.post('/todo/meterla', function (req, res) {
let task = req.body.task;
if (!task) {
return res.status(400).send({ error:true, message: 'Please provide task' });
}
//var task = req.body.task;
var query = mc.query("INSERT INTO tasks SET ? ", { task: task}, function (error, results, fields) {
if (error) throw error;
console.log(task);
return res.send({ error: false, data: results, message: 'New task has been created successfully.' });
});
});
// Update todo with id
app.put('/todo', function (req, res) {
let task_id = req.body.task_id;
let task = req.body.task;
if (!task_id || !task) {
return res.status(400).send({ error: task, message: 'Please provide task and task_id' });
}
mc.query("UPDATE tasks SET task = ? WHERE id = ?", [task, task_id], function (error, results, fields) {
if (error) throw error;
return res.send({ error: false, data: results, message: 'Task has been updated successfully.' });
});
});
// Delete todo
app.delete('/todo', function (req, res) {
let task_id = req.body.task_id;
if (!task_id) {
return res.status(400).send({ error: true, message: 'Please provide task_id' });
}
mc.query('DELETE FROM tasks WHERE id = ?', [task_id], function (error, results, fields) {
if (error) throw error;
return res.send({ error: false, data: results, message: 'Task has been updated successfully.' });
});
});
// all other requests redirect to 404
app.all("*", function (req, res, next) {
return res.send('page not found');
next();
});
// port must be set to 8080 because incoming http requests are routed from port 80 to port 8080
app.listen(8081, function () {
console.log('Escuchando por el puerto 8081');
});
// allows "grunt dev" to create a development server with livereload
module.exports = app;
This is my client:
import React, { Component } from 'react';
import logo from './logo.svg';
import './App.css';
class App extends Component {
constructor(props) {
super(props);
this.state = {data: ""};
this.state_2 = {message: []};
this.onSubmit = this.handleSubmit.bind(this);
}
componentDidMount() {
fetch('/todo/1')
.then((response) => response.json())
.then((responseJson) =>{
this.setState({
message: responseJson.data
});
})
}
handleSubmit(e){
e.preventDefault();
var self = this;
// On submit of the form, send a POST request with the data to the server.
fetch('/todo/meterla',{
method: 'POST',
body:{
task: self.refs.task.value
}
})
.then(function(response){
return response.json()
}).then(function(body){
console.log(body);
alert(self.refs.task.value)
});
}
render() {
return (
<div className="App">
<div className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<h2>Welcome to React</h2>
</div>
<form onSubmit={this.onSubmit}>
<input type="text" placeholder="task" ref="task"/>
<input type="submit"/>
</form>
<p className="App-intro">
Este es el resultado de la consulta = <b>{JSON.stringify(this.state.message)}</b>
</p>
</div>
);
}
}
export default App;

body must be stringified + don't forget the content-type
fetch('/todo/meterla',{
method: 'POST',
body: JSON.stringify({
task: self.refs.task.value
}),
headers: {"Content-Type": "application/json"}
})
.then(function(response){
return response.json()
}).then(function(body){
console.log(body);
alert(self.refs.task.value)
});

try using axios instead of fetch
I rewrote ur code like this and it works perfectly
server
const express = require('express');
const { Client } = require('pg');
const bodyParser = require('body-parser');
const app = express();
const cors = require("cors");
app.use(cors());
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
app.post('/api/insertUsers', function(req, res) {
// console.log(req);
console.log(req.body);
res.send(req.body);
});
app.listen(3001, () => {
console.log('listening on port 3001');
});
react (ensure you have axios installed)
handleSubmit(e){
e.preventDefault();
var data = {
name: "zadiki",
contact: "0705578809",
email: "zadiki",
message: "test",
}
console.log("wow");
var url = ' http://localhost:3001/api/insertUsers';
axios.post(url,data)
.then(response=>console.log(response))
.catch(e=>console.log(e))
}

Looks like this is where the issue is.
constructor(props) {
super(props);
this.state = {data: ""};
this.state_2 = {message: []};
this.onSubmit = this.handleSubmit.bind(this);
}
componentDidMount() {
fetch('/todo/1')
.then((response) => response.json())
.then((responseJson) =>{
this.setState({
message: responseJson.data
});
})
}
In componentDidMount() you are setting the state for 'message'. But that is in this.state_2.
I would recommend not having this.state_2 and instead constructing your state like this:
this.state = {
data: '',
message: []
}

try using fetch like this
fetch(url, {
method: "POST",
mode: "cors",
cache: "no-cache",
credentials: "same-origin",
headers: {
"Content-Type": "application/json; charset=utf-8",
},
redirect: "follow",
referrer: "no-referrer",
body: JSON.stringify(data)
}).then(function (response) {
return response.json();
})
.then(function (myJson) {
console.log(myJson);
});

$(document).ready(()=>{
$("#formSignUp").submit(()=>{
fetch("/auth/sign/up",{
method:'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
body:$("#formSignUp").serialize(),
})
.then((response)=>response.json())
.then(response=>{
}).catch(response=>{
});
return false;
});
});

Related

how to retrieve jwt stored in cookies

I am exercising authentication for MERN stack and I decided to store JWT inside cookies, where during login new token will be sent to the cookies and during logout the function checks for the token from the request and clears the cookie and removes the token from database. I can send the cookie inside node with res.cookie on http://localhost:3000/ without errors and see the content from chrome application, but when I console.log the cookie with req.cookies from http://localhost:3000/main, it is undefined
backend
server.js
const express = require("express");
const app = express();
require("dotenv").config();
const cors = require("cors");
const cookieParser = require("cookie-parser");
const dbConnect = require("./dbConnect");
const authRoutes = require("./routes/auth");
const refreshTokenRoutes = require("./routes/refreshToken");
const port = process.env.PORT;
dbConnect(); //connect to mongoDb database
app.use(
cors({
// origin: "http://localhost:3000/main",
origin: ["http://localhost:3000", "http://localhost:3000/main"],
methods: "GET, POST, UPDATE, DELETE",
credentials: true,
})
);
app.use(express.json());
app.use(cookieParser());
app.use("/api", authRoutes);
app.use("/api/refreshToken", refreshTokenRoutes);
app.get("/", (req, res) => {
res.send("hello");
});
app.listen(port, () => {
console.log(`listening on http://localhost:${port}`);
});
auth.js
router.post("/login", async (req, res) => {
try {
//check if the input is in a valid format
const { error } = logInBodyValidation(req.body);
if (error) {
res.status(400).json({ error: true, message: error.details[0].message });
}
//check if the user is registered in the database
const user = await users.findOne({
email: req.body.email,
});
const passwordCheck = await bcrypt.compare(
req.body.password,
user.password
);
if (!user || !passwordCheck) {
res
.status(401)
.json({ error: true, message: "invalid email or password" });
}
const { accessToken, refreshToken } = await generateToken(user);
res
.cookie("jwtoken", refreshToken, {
maxAge: 1296000000,
path: "/",
domain: "localhost:3000",
httpOnly: true,
})
.status(200)
.json({
error: false,
accessToken,
refreshToken,
message: "Logged in sucessfully!",
});
} catch (error) {
// res.status(500).json({ error: true, message: "Internal Server Error" });
}
});
req.cookies returns the cookies
refreshToken.js
// logout
router.get("/", async (req, res) => {
try {
const { error } = refreshTokenBodyValidation(req.user);
if (error)
return res
.status(400)
.json({ error: true, message: error.details[0].message });
const userToken = await UserToken.findOne({
token: req.user.refreshToken,
});
if (!userToken)
return res
.status(200)
.json({ error: false, message: "Logged Out Sucessfully!" });
await userToken.remove();
res
.clearCookie("jwtoken")
.status(200)
.json({ error: false, message: "Logged Out Sucessfully!" });
} catch (error) {
console.log(error)
}
});
req.cookies returns [Object: null prototype] {}
Frontend
Login.js
import React from "react";
const Login = ({ email, password, setEmail, setPassword }) => {
const loginUser = async (e) => {
e.preventDefault();
try {
const response = await fetch("http://localhost:5000/api/login", {
headers: {
"Content-type": "application/json",
},
method: "POST",
credentials: "include",
body: JSON.stringify({
email,
password,
}),
});
const data = await response.json();
localStorage.setItem("token", data);
console.log(data);
// window.location.href = "/main";
} catch (error) {
console.log(error);
}
};
return (
<div className="container">
<h1>Login</h1>
<form onSubmit={loginUser}>
<input
title="Email"
// value={email}
placeholder="Enter E-mail"
type="email"
className="email"
onChange={(e) => {
setEmail(e.target.value);
}}
/>
<input
title="Password"
// value={password}
placeholder="Enter Password"
type="password"
className="pass"
onChange={(e) => {
setPassword(e.target.value);
}}
/>
<button>Log in</button>
</form>
</div>
);
};
export default Login;
Logout.js
import React from "react";
const Logout = () => {
const logoutUser = async () => {
const response = await fetch("http://localhost:5000/api/refeshToken/", {
headers: {
"Content-type": "application/json",
},
method: "GET",
});
const data = await response.json();
if (data.user) {
alert("Logged out successfuly");
window.location.href = "/";
}
};
return (
<div className="logout">
<button
className="logout_button"
title="Logout"
onClick={(e) => logoutUser(e)}
>
Log out
</button>
</div>
);
};
export default Logout;
the problem was a CORS error, must include credentials: "include" in the logout fetch request header

Express API working locally but not in amplify

I am new to amplify and I have a simple project where I send email from my backend with nodemailer and that email to a mailchimp list and everything was working fine locally but when I hosted it with aws amplify CLI. it showed it was successful but nothing actually happened
here is my code:
const express = require("express")
const EmailSender = require("./emailSender.js")
const client = require("mailchimp-marketing")
const bodyParser = require("body-parser")
const awsServerlessExpressMiddleware = require('aws-serverless-express/middleware')
// declare a new express app
const app = express()
app.use(bodyParser.json())
app.use(awsServerlessExpressMiddleware.eventContext())
// Enable CORS for all methods
app.use(function(req, res, next) {
res.header("Access-Control-Allow-Origin", "*")
res.header("Access-Control-Allow-Headers", "*")
next()
});
/**********************
* Example get method *
**********************/
app.get('/add', function(req, res) {
// Add your code here
console.log(req.body)
});
app.get('/add/*', function(req, res) {
// Add your code here
res.json({success: 'get call succeed!', url: req.url});
});
/****************************
* Example post method *
****************************/
app.post('/add', function(req, res) {
// Add your code here
try {
const { firstName, lastName,email,budget, message,company,country} = req.body
EmailSender({firstName, lastName,email,budget, message,company,country})
res.json({ msg: `Your message sent successfully` });
}
catch (error) {
res.status(404).json({ msg: "Error ❌" });
}
const client = require("mailchimp-marketing");
client.setConfig({
apiKey: "xxxx" ,
server: "xxx",
});
const run = async () => {
const response = await client.lists.addListMember("xxxxxx", {
email_address: req.body.email ,
merge_fields: {
FNAME: req.body.firstName,
LNAME: req.body.lastName
} ,
status: "subscribed",
});
console.log(response);
};
run().catch(errors => console.log(errors.response.text));
// catch(err) {
// console.log("erorr")
// }
console.log(req.body)
});
app.post('/add/*', function(req, res) {
// Add your code here
res.json({success: 'post call succeed!', url: req.url, body: req.body})
});
/****************************
* Example put method *
****************************/
app.put('/add', function(req, res) {
// Add your code here
res.json({success: 'put call succeed!', url: req.url, body: req.body})
});
app.put('/add/*', function(req, res) {
// Add your code here
res.json({success: 'put call succeed!', url: req.url, body: req.body})
});
/****************************
* Example delete method *
****************************/
app.delete('/add', function(req, res) {
// Add your code here
res.json({success: 'delete call succeed!', url: req.url});
});
app.delete('/add/*', function(req, res) {
// Add your code here
res.json({success: 'delete call succeed!', url: req.url});
});
app.listen(3000, function() {
console.log("App started")
});
// Export the app object. When executing the application local this does nothing. However,
// to port it to AWS Lambda we will create a wrapper around that will load the app from
// this file
module.exports = app
Please help
here is my cloudwatch console
enter image description here
Emailsender.js
const EmailSender = ({ firstName, lastName,email,budget, message,company,country }) => {
const sgMail = require('#sendgrid/mail')
sgMail.setApiKey("API_KEY")
const msg = {
to: 'email#gmail.com',
from: 'info#example.io',
subject: 'Sending with SendGrid is Fun',
text: 'and easy to do anywhere, even with Node.js',
html: `
<div>${firstName}<div/>
<div>${lastName}<div/>
<div>${email}<div/>
<div>${budget}<div/>
<div>${message}<div/>
<div>${company}<div/>
<div>${country}<div/>
` ,
}
sgMail
.send(msg)
.then((response) => {
console.log(response[0].statusCode)
console.log(response[0].headers)
})
.catch((error) => {
console.error(error)
})

Client doesnt get cookie from my node.js api

I have made an authentication with jwt api in node.js/express and i run it on heroku.
When a user logged in, server create a cookie via cookie-parser and send it to the client.
Below is the code from server.js
const express = require('express');
const jwt = require('jsonwebtoken');
const cookieParser = require('cookie-parser');
const cors = require('cors');
const path = require('path');
const bcrypt = require('bcrypt');
const PORT = process.env.PORT || 3000;
const serveStatic = require('serve-static');
require('dotenv').config();
const mongoose = require('mongoose');
const { User, Posts } = require(path.join(__dirname, './model.js'));
const mongoString = process.env.DATABASE_URL;
const JWT_SECRET = process.env.JWT_SECRET;
const { verifyToken, checkUser } = require(path.join(__dirname, './auth.js'));
const app = express();
//Middlewares
app.use(
cors({
credentials: true,
origin: true,
})
);
app.use(express.json());
app.use(cookieParser());
//Connect to Database
mongoose.connect(mongoString);
const db = mongoose.connection;
db.on('error', (err) => {
console.log(err);
});
db.once('connected', () => {
console.log('----Database Connected----\n');
});
//functions
const maxAge = 3 * 24 * 60 * 60;
const createToken = (id) => {
return jwt.sign({ id }, JWT_SECRET, {
expiresIn: maxAge,
});
};
// AUTH ROUTES
app.get('*', checkUser);
app.get('/', checkUser, (req, res) => {
res.json({ status: 'success' });
});
app.post('/api/register', async (req, res) => {
const salt = await bcrypt.genSalt();
try {
const user = await User.create(
new User({
username: req.body.username,
email: req.body.email,
city: req.body.city,
password: await bcrypt.hash(req.body.password, salt),
})
);
const token = createToken(user._id);
res.cookie('jwt', token, {
maxAge: maxAge * 1000,
secure: true,
});
res.status(201).json(user);
console.log(user);
} catch (err) {
console.log(err);
res.json(err);
}
});
app.post('/api/login', async (req, res) => {
try {
const { email, password } = req.body;
const user = await User.findOne({ email }).lean();
if (!user) {
return res.send({
status: 'error',
error: 'Invalid email',
});
}
if (await bcrypt.compare(password, user.password)) {
const token = createToken(user._id);
res.cookie('jwt', token, { secure: true, maxAge: maxAge * 1000 });
res.status(200).send({ status: 'ok', token: token });
console.log(user._id + ' logged in successfully');
return;
}
return res.send({ status: 'error', error: 'Invalid password' });
} catch (err) {
console.log(err);
}
});
app.get('/api/home', verifyToken, (req, res) => {
res.send(res.locals.user);
});
app.get('/api/logout', (req, res) => {
try {
res.cookie('jwt', '', { maxAge: 1 });
res.status(200).send({ status: 'ok' });
} catch (err) {
res.send(err);
}
});
//POSTS ROUTES
app.post('/api/posts', verifyToken, checkUser, async (req, res) => {
try {
const post = await Posts.create(
new Posts({
postBody: req.body.postBody,
city: req.body.city,
author: res.locals.user.id,
})
);
res.status(200).json(post);
console.log('====New Post=====');
} catch (err) {
res.status(400).send({ message: err.message });
}
});
app.get('/api/posts', verifyToken, async (req, res) => {
try {
const data = await Posts.find();
res.send({ user: res.locals.user, data: data });
} catch (err) {
res.json({ message: err.message });
}
});
app.get('/api/posts/:city', verifyToken, async (req, res) => {
try {
const data = await Posts.find({ city: req.params.city });
res.json(data);
res.send(res.locals.user);
} catch (err) {
res.json({ message: err.message });
}
});
//run server
app.listen(PORT, () => {
console.log(`Server running on ${PORT}...\n`);
});
Now, for front-end i use Vue.js that its running on Firebase.
Here is the script part of Login.Vue
<script>
/* eslint-disable */
import axios from 'axios';
export default {
name: 'Login',
data() {
return {
email: '',
password: '',
error: '',
};
},
methods: {
async onSubmit() {
if (!this.email || this.password.length < 6) {
this.error = 'vale kati';
return;
}
await axios
.post(
'https://thelostpet.herokuapp.com/api/login',
{
email: this.email,
password: this.password,
},
{ withCredentials: true }
)
.then((res) => {
console.log(res.data.token);
if (res.data.status == 'error') {
this.error = res.data.error;
}
if (res.data.status == 'ok') {
this.$router.push('/home');
}
})
.catch((err) => {
console.log(err);
});
},
},
};
</script>
When I try to login from Login.vue, that its ruuning on Firebase, the browser doesn't save the cookie that it created from the api.
BUT when I make a post request on https://thelostpet.herokuapp.com/api/login from postman, the cookie is saved on postman.
Thank you!

I am getting 404 error and 204 error when consuming backend (node,vuejs)?

When signing in with postman everything works fine. But when i am doing an axios request i get 404 error and directly after 204 error. When i render my vue.js page i get "cannot get api/auth/signin. Also I get a message somewhere that says user not found.
What i have tried:
Frontend: I tried with adding headers to my axios request. I console logged the data and it seems perfectly fine.
Backend: Changed deprecated body parsers.
Frontend Code:
Auth store
import axios from "axios";
const state = {
token: "",
users: [],
};
const getters = {};
const actions = {
async signIn(_, payload) {
const response = await axios.post(
"http://localhost:3000/api/auth/signin",
{ payload },
{
headers: {
"Content-Type": "application/json",
},
}
);
console.log(response.data);
console.log(response.headers);
console.log(response.status);
},
};
const mutations = {};
export default {
state,
getters,
actions,
mutations,
};
This is my backend:
Controller
//signin
exports.signin = (req, res) => {
User.findOne({
username: req.body.username,
})
.populate("roles", "-__v")
.exec((err, user) => {
if (err) {
res.status(500).send({ message: err });
return;
}
if (!user) {
return res.status(404).send({ message: "User Not found." });
}
var passwordIsValid = bcrypt.compareSync(
req.body.password,
user.password
);
if (!passwordIsValid) {
return res.status(401).send({
accessToken: null,
message: "Invalid Password!",
});
}
var token = jwt.sign({ id: user.id }, config.secret, {
expiresIn: 86400, // 24 hours
});
var authorities = [];
for (let i = 0; i < user.roles.length; i++) {
authorities.push("ROLE_" + user.roles[i].name.toUpperCase());
}
res.status(200).send({
id: user._id,
username: user.username,
email: user.email,
roles: authorities,
accessToken: token,
});
});
};
Route
module.exports = function (app) {
app.use(function (req, res, next) {
res.header(
"Access-Control-Allow-Headers",
"x-access-token, Origin, Content-Type, Accept"
);
next();
});
app.post(
"/api/auth/signup",
[
verifySignUp.checkDuplicateUsernameOrEmail,
verifySignUp.checkRolesExisted,
],
controller.signup
);
app.post("/api/auth/signin", controller.signin);
And my server
const express = require("express");
const bodyParser = require("body-parser");
const cors = require("cors");
const jwt = require("jsonwebtoken");
const mongoose = require("mongoose");
const Quote = require("./models/Quote");
const quoteRoute = require("./routes/quoteRoute");
const quoteController = require("../Maxico/controllers/quoteController");
const config = require("./config/config");
const verifySignup = require("./middlewares/verifySignUp");
const Role = require("./models/Role");
const app = express();
//Import routes
//const authRoute = require("./routes/auth");
var corsOptions = {
origin: "http://localhost:8080/?#/",
};
app.use(cors(corsOptions));
app.use(express.urlencoded({ extended: true }));
app.use(express.json()); //
const db = require("./models/Quote");
mongoose
.connect(
"url",
{
useNewUrlParser: true,
useUnifiedTopology: true,
useFindAndModify: false,
}
)
.then(() => {
console.log("Connected to the database!");
})
.catch((err) => {
console.log("Cannot connect to the database!", err);
process.exit();
});
app.use(express.json());
app.get("/", (req, res) => {
res.send("Welcome to homepage");
});
app.use("/quote", quoteRoute);
require("./routes/authRoute")(app);
//require("./routes/userRoute")(app);
// initial roles
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: "moderator",
}).save((err) => {
if (err) {
console.log("error", err);
}
console.log("added 'moderator' to roles collection");
});
new Role({
name: "admin",
}).save((err) => {
if (err) {
console.log("error", err);
}
console.log("added 'admin' to roles collection");
});
new Role({
name: "superadmin",
}).save((err) => {
if (err) {
console.log("error", err);
}
console.log("added 'superadmin' to roles collection");
});
}
});
// set port, listen for requests
const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
console.log(`Server is running on port ${PORT}.`);
});
In my network tab the request pay load got sent like this:
{payload: {username: "jon", password: "password"}}
payload: {username: "jon", password: "password"}
But my postman only accepts this:
{username: "jon", password: "password"}
So in my action i sent like this:
const actions = {
async signIn(_, payload) {
console.log(payload);
const response = await axios.post(
"http://localhost:3000/api/auth/signin",
payload,
{
headers: {
"Content-Type": "application/json",
},
}
);
console.log(payload);
console.log(response.data);
console.log(response.headers);
console.log(response.status);
},
};

Nock not catch post requests using chai-http and mocha

I'm creating a web app that connects with an API in order to do a login and some stuff, currently I'm trying to test a /authenticate route on my app using chai, chai-http and nock.
var chai = require('chai');
var expect = chai.expect;
var chaiHttp = require('chai-http');
var nock = require('nock');
chai.use(chaiHttp);
describe('/authenticate', function() {
var agent = chai.request.agent('http://localhost:3000');
afterEach(function() {
agent.close();
nock.cleanAll();
});
describe('User authorized', function() {
it('redirects to /dashboard', function() {
// I'm trying to mock the response here but is not working.
nock('http://the.api.com:8080')
.post('/v1/authenticate')
.reply(201, {
'authorized': true,
'jwt': 'thejwtasdf'
});
agent
.post('/authenticate')
.send({ email: 'test#gmail.com', password: 'TheAmazingPass' })
.then(function(res) {
expect(res).to.redirectTo('http://localhost:3000/dashboard');
expect(res.text).to.match(/Dashboard/);
})
.catch(function(e) { console.log(e); });
});
});
});
The test pass but I got this caught error, according to this, the page is not redirected because the call is not caught by nock and it is directly sent to the API:
{ AssertionError: expected redirect with 30X status code but got 200
at Proxy.<anonymous>
... rest of the error omitted.
But when I use a real and valid email and password this test pass with no caught error:
var chai = require('chai');
var expect = chai.expect;
var chaiHttp = require('chai-http');
var nock = require('nock');
chai.use(chaiHttp);
describe('/authenticate', function() {
var agent = chai.request.agent('http://localhost:3000')
afterEach(function() {
agent.close();
nock.cleanAll();
});
describe('User authorized', function() {
it('redirects to /dashboard', function() {
agent
.post('/authenticate')
.send({ email: 'realemail#gmail.com', password: 'RealPass' })
.then(function(res) {
expect(res).to.redirectTo('http://localhost:3000/dashboard');
expect(res.text).to.match(/Dashboard/);
})
.catch(function(e) { console.log(e); });
});
});
});
With this code the test passes, Am I missing something with nock?
=== EDIT ===
This is the code that I'm trying to test:
This is my login router (flashMessages is a custom middleware that helps with flash messages).
var loginService = require('../services/login');
var flashMessages = require('../utils/flash_messages').flashMessages;
var router = require('express').Router();
// check if user is logged in
var sessionChecker = function(req, res, next) {
if (req.session.auth && req.cookies.user_sid) {
res.redirect('/dashboard');
} else {
next();
}
};
router.get('/', sessionChecker, flashMessages, function(req, res, next){
res.render('login', {
title: 'Welcome',
errors: res.locals.flash.errors,
typeError: res.locals.flash.errorType,
});
});
router.post('/authenticate', function(req, res, next){
req.checkBody('email', 'Email is required').notEmpty();
req.checkBody('email', 'Invalid email format').isEmail();
req.checkBody('password', 'Password is required').notEmpty();
req.getValidationResult().then(function(result){
if (result.isEmpty()) {
loginService.authenticate(req.body).then(function(result){
if (result.authorized){
// success
req.session.auth = result;
req.session.auth.user = loginService.currentUser(result.jwt)
res.redirect('/dashboard');
} else {
// user not found error
req.session.flash = {
errors: [{msg: result.msg}],
errorType: 'anotherError'
};
res.redirect('/');
}
}).catch(function(e){
// server errors
req.session.flash = {
errors: [e],
errorType: 'anotherError'
};
res.redirect('/');
});
} else {
//validation errors
req.session.flash = {
errors: result.array(),
errorType: 'validationError'
};
res.redirect('/');
}
});
});
module.exports = router;
The login router uses a loginService, this is the part that works with the login:
var httpReq = require('../utils/http_requests');
module.exports.authenticate = function(params){
return new Promise(function(resolve, reject) {
httpReq.callToAPI(params, {
path: '/v1/authenticate',
method: 'POST'
})
.then(function(authorization) {
resolve(JSON.parse(authorization));
})
.catch(function(err) {
reject(err);
});
});
};
module.exports.currentUser = function(shaCode){
return JSON.parse(Buffer.from(shaCode.split('.')[1], 'base64').toString());
};
And finally I have a utils for http requests:
var http = require('http');
function createOptions(options) {
headers = {
'Content-Type': 'application/json',
'Accept': 'application/json',
'Connection': 'close'
};
if (options.jwt) { headers['Authorization'] = 'Bearer ' + options.jwt; }
return {
hostname: 'the.api.com',
port: 8080,
path: options.path,
method: options.method,
headers: headers
};
};
module.exports.callToAPI = function(params, options) {
reqObj = createOptions(options);
return new Promise(function(resolve, reject) {
body = [];
req = http.request(reqObj, function(res) {
res.on('data', function(chunk) {
body.push(chunk);
});
res.on('end', function() {
console.log(body.join(''));
resolve(body.join(''));
});
});
req.on('error', function(err) {
reject({ msg: "We're sorry, but something went wrong" });
});
if (params) { req.write(JSON.stringify(params)); }
req.end();
});
};
Any help will be appreciated.
Regards.

Resources