Jest test does not find provided route - express

Started working on a new application and decided to write tests from very early stage to avoid any future mistakes. However, little bit struggling I guess with setting up the Jest correctly. I made a follow on few tutorials and documentation, but the result is not the one I'm expecting. What I am trying to do is to make a basic test for creating a user, however I receive and error:
error: Error: cannot POST /register (404)
I get the point that the test can't find the endpoint /register, but I thought that is the point to keep server.js and app.js for supertest, because he will be smart enough to understand the path to this endpoint, which actually is: "/api/v1/auth/register". I want to mark that the registration process works fine trough postman.
Here is the app.js:
require("dotenv").config();
require("express-async-errors");
const express = require("express");
const app = express();
// routers
const authRouter = require("./src/routes/auth/auth.router");
// packages
const morgan = require("morgan");
const fs = require("fs");
const cookieParser = require("cookie-parser");
// middlewares
const errorMiddleware = require("./src/middlewares/errorMiddleware");
app.use(express.json());
app.use(cookieParser(process.env.ACCESS_TOKEN));
app.use(morgan("common", {
stream: fs.createWriteStream("./src/utils/logs/logs.log", {
flags: "a"
})
}));
// endpoints
app.use("/api/v1/auth", authRouter);
app.use(errorMiddleware);
module.exports = app;
Here is the server.js:
const app = require("./app");
const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
console.log(`Server is running on port ${PORT}...`);
});
Here is the auth.test.js:
const request = require("supertest");
const app = require("../../../app");
describe("POST /register", () => {
it("Should create a new user", async () => {
const response = await request(app).post("/register").send({
email: "superemail#gmail.com",
username: "superusername",
password: "superpassword"
});
console.log(response); // I see here the 404 error.
});
});
Not sure if it helps, but here is the router file:
const express = require("express");
const router = express.Router();
const {check} = require("express-validator");
const {registerUserController, loginUserController} = require("../../controllers/auth/auth.controller");
router.post("/register", [
check("email").trim().not().isEmpty().isEmail(),
check("username").trim().not().isEmpty().isString(),
check("password").trim().not().isEmpty().isString().isLength({
min: 6
}).withMessage("Password has to be at least 6 characters long"),
check("firstName").optional().trim().not().isEmpty().isString(),
check("lastName").optional().trim().not().isEmpty().isString(),
check("age").optional().trim().not().isEmpty().isNumeric().isInt({
min: 0
}).withMessage("Age can't be less than 0"),
], registerUserController);
module.exports = router;

Related

Can't seem to get req.body in Express when embedded in Zoho Catalyst framework

My Zoho Catalyst framework isn't passing the request.body. Here is the code.
module.exports = (req, res1) => {
const debug = require('debug');
const https = require('https');
const tools = require('./tools.js');
const crypto = require('crypto');
const express = require('express');
const app = express();
app.use(express.json())
app.use(express.urlencoded({ extended: true }));
app.use(express.text());
function getHash(){
var hmac = crypto.createHmac('sha256', apisecretkey);
hmac.update(dataToSign);
return hmac.digest('base64');
};
var url = req.url;
switch (url) {
case '/scanName':
//var s = JSON.stringify(req.body)
console.log(req.body)
console.log(req.get('Accept'))
console.log(req.accepts('application/json'));
res1.write('xx')
res1.end()
break;
case '/':
Here is the output:
undefined
*/*
application/json
I've tried every form of POST from Postman that I can think of, and still nothing.
You have bound the express app variable to recognize the incoming data of the following types JSON, urlencoded and text. But you haven’t used that app variable to get the incoming request so technically it is like you have declared it but never used it. So, your function code couldn’t be able to identify the type of incoming data in the request body. You can modify your code like below:
'use strict';
const debug = require('debug');
const https = require('https');
const tools = require('./tools.js');
const crypto = require('crypto');
const express = require('express');
const app = express();
app.use(express.json());
app.use(express.text());
app.use(express.urlencoded({ extended: true }));
app.post('/scanName',async(req, res) => {
try {
let body = req.body;
console.log(body);
res.status(200).send(body);
} catch (error) {
console.log(error);
res.status(500).send(error);
}
});
module.exports = app;
You have to export the express app variable to make the endpoints accessible. You can check out this tutorial where we have shown an example of how to get and send data in the Catalyst Advanced IO function using Express.js.

Nuxt/Express API is returning in console but not browser

I'm quite new to this whole backend business and I'm wondering if anyone can see where I'm going wrong. I've got an express server in my Nuxt app which is serving out an API. When I run the localhost:3000/api/salesforce/:id route - my vscode terminal generates a response - but it doesn't show up on the browser. Which in turn makes it inaccessible to Nuxt.
In my nuxt.config.js:
serverMiddleware: {
'/api': '~/api'
},
/api/index.js:
const express = require('express')
// Create express instance
const app = express()
// Require API routes
const users = require('./routes/users')
const test = require('./routes/test')
const salesforce = require('./routes/salesforce')
// Import API Routes
app.use(users)
app.use(test)
app.use(salesforce)
// Export express app
module.exports = app
// Start standalone server if directly running
if (require.main === module) {
const port = process.env.PORT || 3001
app.listen(port, () => {
// eslint-disable-next-line no-console
console.log(`API server listening on port ${port}`)
})
}
Then in /api/routes/salesforce.js:
const e = require('express')
const { Router } = require('express')
const router = Router()
const jsforce = require('jsforce');
// require the .env file for login
require('dotenv').config();
const { SF_USERNAME, SF_PASSWORD, SF_TOKEN, SF_LOGIN_URL } = process.env;
if (!(SF_USERNAME && SF_PASSWORD && SF_TOKEN && SF_LOGIN_URL)) {
console.error(
'Cannot start app: missing mandatory configuration. Check your .env file.'
);
process.exit(-1);
}
const conn = new jsforce.Connection({
loginUrl: SF_LOGIN_URL
});
conn.login(SF_USERNAME, SF_PASSWORD + SF_TOKEN, err => {
if (err) {
console.error(err);
process.exit(-1);
}
});
// get OPPORTUNITY specific
router.get('/salesforce/:id', function (req, res, next) {
const id = req.params.id
console.log(req.params.id)
const sfData = conn.query(`SELECT Id, Name, StageName FROM Opportunity WHERE Name = '` + id + `'`, (err, res)=>{
if(err){
console.log(err)
return "error";
} else {
console.log(res.records[0])
let sanitisedData = res.records[0]
return sanitisedData;
}
})
res.json(sfData.json)
})
If anyone can tell me where I'm going wrong that would be greatly appreciated, I'm kind of stuck here.

keep getting a 404 on routing with params

Im doing a mern tutorial on freecodecamp and I have run into an issue that is driving me nuts.
I have a route which is localhost:5000/exercises/1234
however I keep getting a 404 on that route.
If someone could point out the error if would be appreciated.
I have a server file:
const express = require("express");
const cors = require("cors");
const mongoose = require("mongoose");
const exerciseRouter = require("./routes/exercises");
const usersRouter = require("./routes/users");
require("dotenv").config();
const app = express();
const port = process.env.PORT || 5000;
const uri = process.env.ATLAS_URI;
mongoose.connect(uri, {
useNewUrlParser: true,
useCreateIndex: true,
useUnifiedTopology: true,
});
const connection = mongoose.connection;
connection.once("open", () => {
console.log("Mongo DB database connection established successfully 👾👾👾");
});
app.use(cors());
app.use(express.json());
app.use("/exercises", exerciseRouter);
app.use("/users", usersRouter);
app.listen(port, () => {
console.log(`server is running on port ${port} 😻`);
});
and the route is defined here in an exercise.js file:
const router = require("express").Router();
const Exercise = require("../models/exercise.model");
router.route("/:id").get((req, res) => {
console.log(req.params);
Exercise.findById(req.params.id)
.then((exercise) => res.json(exercise))
.catch((err) => res.status(400).json(`Error ${req.params}`));
});
When i run this in the browser I get a 404 and not even the console log is run. Im really not sure why it isnt working.
Ah disregard this issue, i did an idiotic mistake. I had the method get inside another method (which isnt apparent in the above question).
Note to myself and others make sure your route aren't nested by accident in another route! lol

Keep getting this error: Error: Route.post() requires callback functions but got a [object Undefined]

I am trying to set up a react express application with mongo db as the database. I am in the preliminary stages and keep coming across this error:
Error: Route.post() requires callback functions but got a [object Undefined]
here is my app.js
const express = require('express');
// const http = require('http');
const bodyParser = require('body-parser');
const morgan = require('morgan');
const app = express();
const mongoose = require('mongoose');
mongoose.Promise = global.Promise;
//db and name is auth
mongoose.connect('mongodb://localhost/auth', {
useMongoClient: true,
/* other options */
});
// app setup
//server setup
const port = process.env.Port || 4000
// const server = http.createServer(app);
app.listen(port);
console.log(`Sever listening on ${port}`)
const authRoutes = require('./routes/auth_routes');
app.use('/',authRoutes);
my routes are right here. I am just testing to see if there is a correct connection.
const authController = '../controllers/auth_controller';
const express = require('express');
const authRoutes = express.Router();
authRoutes.post('/',authController.signup)
module.exports = authRoutes;
my controller is listed below:
const authController = {};
authController.signup = function(req,res,next) {
console.log('here');
res.json({
user: "doesnt matter",
data: 'Put a user profile on this route'
});
}
module.exports = authController;
not sure if mongo is the problem since it is my first time using it, but my connection to the database works robo 3t to check whats in the database and the user schema is there. if i comment out that one route in the routes page, the errors go away.
I believe the problem is here:
const authController = '../controllers/auth_controller';
authRoutes.post('/',authController.signup)
Note that authController is just a string. I'm guessing you intended:
const authController = require('../controllers/auth_controller');

express.js 4 and sockets with express router

I'm trying to create a really simple node API using express.js 4 but I need a few 'realtime' events for which I added socket.io. I'm fairly new to both so I'm likely missing something basic but I can't find good docs/tuts on this.
In the express app (created with the express generator) I have something like this based on simple examples and project docs that I read. This works OK and from client apps, I can send/receive the socket events:
var express = require('express');
var path = require('path');
var logger = require('morgan');
var api = require('./routes/api');
var app = express();
var io = require('socket.io').listen(app.listen(3000));
app.use(logger('dev'));
app.use(express.static(path.join(__dirname, 'public')));
app.use('/api', api);
io.sockets.on('connection', function (socket) {
console.log('client connect');
socket.on('echo', function (data) {
io.sockets.emit('message', data);
});
});
// error handlers omitted
module.exports = app;
but I want to use the sockets from my API routes (in the ./routes/api.js file that I 'require' above). For example, someone might use the API to PUT/POST a resource and I want that broadcast to connected socket.io clients.
I cannot see how to use the 'io' variable or organise the code currently in the io.sockets.on('connection' ... function inside express routes. Here's the ./routes/api.js file:
var express = require('express');
var router = express.Router();
var io = ???;
router.put('/foo', function(req, res) {
/*
do stuff to update the foo resource
...
*/
// now broadcast the updated foo..
io.sockets.emit('update', foo); // how?
});
module.exports = router;
One option is to pass it in to req object.
app.js:
var express = require('express');
var path = require('path');
var logger = require('morgan');
var api = require('./routes/api');
var app = express();
var io = require('socket.io').listen(app.listen(3000));
app.use(logger('dev'));
app.use(express.static(path.join(__dirname, 'public')));
io.sockets.on('connection', function (socket) {
console.log('client connect');
socket.on('echo', function (data) {
io.sockets.emit('message', data);
});
});
// Make io accessible to our router
app.use(function(req,res,next){
req.io = io;
next();
});
app.use('/api', api);
// error handlers omitted
module.exports = app;
./routes/api.js:
var express = require('express');
var router = express.Router();
router.put('/foo', function(req, res) {
/*
do stuff to update the foo resource
...
*/
// now broadcast the updated foo..
req.io.sockets.emit('update', foo);
});
module.exports = router;
I've modified your files a little bit, may you check if it works?
You can pass the io you've defined to your routes like below;
require('./routes/api')(app,io);
I didn't test the Socket.IO parts but there is no syntax error and routes also working.
server.js file:
var express = require('express');
var app = express();
var path = require('path');
var logger = require('morgan');
var io = require('socket.io').listen(app.listen(3000));
app.use(logger('dev'));
app.use(express.static(path.join(__dirname, 'public')));
io.sockets.on('connection', function (socket) {
console.log('client connect');
socket.on('echo', function (data) {
io.sockets.emit('message', data);
});
});
require('./routes/api')(app,io);
console.log("Server listening at port 3000");
api.js:
module.exports = function(app,io) {
app.put('/foo', function(req, res) {
/*
do stuff to update the foo resource
...
*/
// now broadcast the updated foo..
console.log("PUT OK!");
io.sockets.emit('update'); // how?
res.json({result: "update sent over IO"});
});
}
Supposing you want to access the SocketIO from anywhere in your application, not just in the router, you could create a singleton for it. This is what works for me:
//socket-singletion.js
var socket = require('socket.io');
var SocketSingleton = (function() {
this.io = null;
this.configure = function(server) {
this.io = socket(server);
}
return this;
})();
module.exports = SocketSingleton;
Then, you need to configure it using your server:
//server config file
var SocketSingleton = require('./socket-singleton');
var http = require('http');
var server = http.createServer(app);
SocketSingleton.configure(server); // <--here
server.listen('3000');
Finally, use it wherever you want:
//router/index.js
var express = require('express');
var router = express.Router();
var SocketSingleton = require('../socket-singleton');
/* GET home page. */
router.get('/', function(req, res, next) {
setTimeout(function(){
SocketSingleton.io.emit('news', {msg: 'success!'});
}, 3000);
res.render('index', { title: 'Express' });
});
module.exports = router;
One more option is to use req.app.
app.js
const express = require('express');
const path = require('path');
const logger = require('morgan');
const api = require('./routes/api');
const app = express();
const io = require('socket.io').listen(app.listen(3000));
// Keep the io instance
app.io = io;
app.use(logger('dev'));
app.use(express.static(path.join(__dirname, 'public')));
// ...
app.use('/api', api);
module.exports = app;
routes/api.js
const express = require('express');
const router = express.Router();
router.put('/foo', function(req, res) {
/*
* API
*/
// Broadcast the updated foo..
req.app.io.sockets.emit('update', foo);
});
module.exports = router;
Refactored Edudjr's answer.
Change the singleton to create a new instance of socket.io server
const { Server } = require('socket.io');
const singleton = (() => {
this.configure = (server) => this.io = new Server(server)
return this
})();
module.exports = singleton
Initialise your express app, the server and the singleton.
// initialise app
const app = express();
const server = require('http').createServer(app);
// configure socket.io
socket.configure(server)
Then in your router
const socket = require('/utils/socket-singleton');
socket.io.emit('event', {message: 'your message here'})
I think best way is to set io as a property of req, like below:
app.use(function(req,res,next){
req.io = io;
next();
});
app.use('/your-sub-link', your-router);