How to do unit test in dependent modules (node.js)? - javascript

I have an application with two modules (Book and User). The book model looks like this:
var mongoose = require('mongoose'),
Schema = mongoose.Schema;
var BookModel = new Schema({
name: String,
author: String,
description: String,
_user: {type: Schema.Types.ObjectId, ref: 'User'}
});
module.exports = mongoose.model('Book', bookModel);
And the user model:
var mongoose = require('mongoose'),
bcrypt = require('bcryptjs'),
Schema = mongoose.Schema;
var userModel = new Schema({
name: String,
username: String,
password: String,
});
module.exports = mongoose.model('User', userModel);
I want to do a unit test in the POST method (inserting a book in the DB) with the condition of not allowing empty name. This is what I have in the POST method:
var post = function (req, res) {
var bookNew = new book(req.body);
// get paylod from the user's token
var payload = tokenManager.getPayload(req.headers);
if (req.body._user)
delete req.body._user;
if (!req.body.name) {
res.status(400);
res.send("Name is required");
} else if (payload == null || payload == undefined) {
res.status(400);
res.send("Token error");
} else {
// store the user id
bookNew.set('_user', payload.id);
bookNew.save();
res.status(201);
res.send("Book saved");
}
};
As you can see, I get the payload from the token (created when the user is logged in). I do this because the payload contains the user id and, then, I insert it in _user (property in book model).
The problem is that if I do a unit test in order to verify if the book’s property (name) is filled, I don’t have a user to retrieve the payload. Therefore, the payload will be undefined and the book unit test will not be successful in any case. Do you have any suggestion on what I should do? It looks like I have to create a user in order to test all book modules… but I am not sure if that is the most suitable solution.

Related

CastError: Cast to ObjectId failed for value ...` at path "questions"

I'm currently building a Node backend with MongoDB / Mongoose and I seem to be having some problem with tying my data together. Specifically, I wish for all users to be able to submit a form (question form) which will then be added to the "questions" collection. In addition to being added to the questions collection, I also need to store a reference to all of the questions a user has answer directly inside of the user object.
Below you can check out my code. Whenever I make a POST requestion to /questions, it spits out this error. I should note that it successfully adds documents into the questions collection, and each question contains the ID of the user who created it, but the main problem is the user's questions array is not getting updated to include an ID value of submitted questions.
Models/User.js
const mongoose = require('mongoose'),
Schema = mongoose.Schema,
bcrypt = require('bcrypt-nodejs');
const UserSchema = new Schema({
email: {
type: String,
lowercase: true,
unique: true,
required: true
},
password: {
type: String,
required: true
},
profile: {
firstName: { type: String },
lastName: { type: String }
},
questions: [
{
type: Schema.Types.ObjectId,
ref: 'Question'
}
],
role: {
type: String,
enum: ['Member', 'Client', 'Owner', 'Admin'],
default: 'Member'
},
resetPasswordToken: { type: String },
resetPasswordExpires: { type: Date }
},
{
timestamps: true
});
/** Pre-save of user to database,
hash password if password is modified or new
*/
module.exports = mongoose.model('User', UserSchema);
Models/Question.js
const mongoose = require('mongoose'),
Schema = mongoose.Schema;
// Schema defines how questions will be stored in MongoDB
const QuestionSchema = new Schema({
questionString: String,
answer: Boolean,
_createdBy : [
{
type: mongoose.Schema.Types.ObjectId,
ref: 'User'
}
],
},{
//user timestamps to save date created as .createdAt
timestamps: true
});
module.exports = mongoose.model('Question', QuestionSchema);
Controller/QuestionController.js
const jwt = require('jsonwebtoken'),
crypto = require('crypto'),
Question = require('../models/question'),
User = require('../models/user'),
config = require('../config/main');
function setQuestionInfo(request) {
return {
_id: request._id,
questionString: request.questionString,
answer: request.answer,
user: request.user
}
}
exports.addQuestion = function(req, res, next) {
User.findById(req.user.id, (err, user) => {
if (err) throw new Error(err);
// We create an object containing the data from our post request
const newQuestion = {
questionString: req.body.questionString,
answer: req.body.answer,
// in the author field we add our current user id as a reference
_createdBy: req.user._id
};
// we create our new post in our database
Question.create(newQuestion, (err, question) => {
if (err) {
res.redirect('/');
throw new Error(err);
}
// we insert our newQuestion in our posts field corresponding to the user we found in our database call
user.questions.push(newQuestion);
// we save our user with our new data (our new post).
user.save((err) => {
return res.send('sucess!');
});
})
});
}
Router.js
module.exports = function(app) {
// Initializing route groups
const apiRoutes = express.Router(),
userRoutes = express.Router(),
authRoutes = express.Router(),
questionRoutes = express.Router();
//=========================
// Auth Routes
//=========================
/** ROUTES BELOW WORK FINE -- ONLY DEALS WITH POST TO /questions
*
app.use middle ware sets /auth as auth route (everything goes through /api/auth)
apiRoutes.use('/auth', authRoutes);
apiRoutes.get('/dashboard', requireAuth, function(req, res) {
res.send('It worked! User id is: ' + req.user._id + '.');
});
// Set user routes as a subgroup/middleware to apiRoutes
apiRoutes.use('/user', userRoutes);
// View user profile route
userRoutes.get('/:userId', requireAuth, UserController.viewProfile);
// Test protected route
apiRoutes.get('/protected', requireAuth, (req, res) => {
res.send({ content: 'The protected test route is functional!' });
});
// Registration route
authRoutes.post('/register', AuthenticationController.register);
// Login route
authRoutes.post('/login', requireLogin, AuthenticationController.login);
*/
// Problem Area --> Making POST req to /questions
apiRoutes.post('/questions', requireAuth, QuestionController.addQuestion);
// Set url for API group routes
app.use('/api', apiRoutes);
};
You've your schema defined to accept question ids for a user.
questions: [
{
type: Schema.Types.ObjectId,
ref: 'Question'
}
After you save with Question.create(newQuestion, (err, question)... the callback attribute question has the updated data, one with the ObjectId.
Now you add this ObjectId value to your existing questions array that you got from findById on User model.
user.questions.push(question._id);
Mongoose will use the questionId to fill your question object when you use populate on questions array, but thats part for retrieving information.

Mongoose Populate returning undefined when requiring schema from another File

I'm making a node application. Users can have favorite Listings of rooms ( just like wish list). I'm trying to add listings ids to user favorite listings but that always gives undefined. if i do "console.log(users.favoriteListings);" the output comes to be undefined. Any help please.
listingModel.js
var mongoose = require("mongoose");
var Schema = mongoose.Schema;//creating schema
var ListingSchema = new Schema({
location: {//ROOM LOCATION
type: [Number], // [<longitude>, <latitude>]
index: '2d' // create the geospatial index
},
}
);
var Listing = mongoose.model('Listing', ListingSchema);
module.exports = Listing;
userModel.js
var mongoose = require("mongoose");
var Schema = mongoose.Schema;//creating schema
var Listing=require('../listing/listingModel');
var UserSchema = new Schema({
favoriteListings : [{ type: Schema.Types.ObjectId, ref: 'Listing' }],
}
);
var User = mongoose.model('User', UserSchema);
module.exports = User;
userController.js
addFavListing:function(req,res){
//READ TOKEN AND FIND USER ID, IF USER HAS REACHED THIS POINT, THIS MEANS THAT TOKEN ALREADY
//HAS BEEN VERIFIED
var token = req.body.token || req.query.token || req.headers['x-access-token'];
var decoded=jwt.verify(token, app.get('superSecret'));
var id=decoded._doc._id;console.log(id);
User.find({_id:id}).populate('favoriteListings').exec(function(err,users) {
if (err){ return handleError(err);}
console.log(users.favoriteListings);
});
You got an array of users from mongoose.
This array has no favoriteListings property.
But each user in the array must have his favoriteListings.
In your userController, try to replace the console.log by this one:
console.log(users.forEach(function(user) {
console.log(user.favoriteListings);
}));

Multiple connection error when using node js and mongodb

I'm using the following schema located in my /routes/schema.js file...
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var userSchema = new Schema({
username: String,
password: String,
name: String,
last: String,
year: Number,
degree: String
});
var User = mongoose.model('User', userSchema);
module.exports = {
User: User
}
In my /routes/register.js file I am storing some information using POST data...
var User = require('../routes/schema').User;
exports.postRegister = function (req, res) {
var u = new User({
username: req.body.reg_username,
password: req.body.reg_password,
name: req.body.reg_name,
last: req.body.reg_lastname,
year: req.body.reg_year,
degree: req.body.reg_degree
});
u.save(function (err) {
if (err) {
throw err;
}
else {
console.log("saved");
res.render('index', { title: 'Express' });
}
});
}
Everything gets saved fine in my Database. But now, this register.js file redirects the user back to /routes/index.js where the user must then sign in using some credentials stored in the database.
So in my index.js file I need to check if username and password exist together in a collection in my database, I tried the following...
var User = require('../routes/schema').User;
exports.signin = function (req, res) {
User.findOne({
username: req.body.log_username,
password: req.body.log_password
}, function (err, docs) {
if (docs.length) {
console.log("name exists");
}
else {
console.log("no exist");
}
});
};
I used the findOne function with the same Schema to check if username and password exist in a collection in the database, but it doesn't work properly. I seem to get a multiple connection error and I do not know how to avoid it.
When I try to login using some credentials already in the database, the console prints out no exist meaning the else statement in exports.signin is reached.
The value of the docs will be null if the object is not found in the collection.
If the user enters wrong credentials, you will be calling docs.length on null object, which will cause an error. Use docs != null instead, to avoid calling length on null object.
try it docs.length !== 0 this is check docs field is existed or empty.

Express/Mongoose REST trouble

Im running Express on my application with a delete route below:
router.route('/lists/:id')
.delete(function(req, res){
Entry.remove({
_id: req.params.id
}, function(err, list){
if(err)
res.send(err)
list.title = req.body.title;
res.json({message: 'successfully deleted'});
console.log('DELETE on /lists/'+ req.params.id);
});
});
Here is my Mongoose schema:
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var ListSchema = new Schema({
title: String
});
module.exports = mongoose.model('List', ListSchema);
When my application hits the delete route, my terminal logs the appropriate statement, but the model is not deleted from the database. When I call fetch on the collection, all of there records are still there.
I am using a very similar approach on a different collection of data on my website, and it works fine, so Im really at a loss for why this is happening.
Mongoose assigns each of your schemas an _id field by default if one is not passed into the Schema constructor. The type assiged is an ObjectId to coincide with MongoDBs default behavior
Try passing the _id as ObjectId:
var ObjectId = require('mongoose').Types.ObjectId;
var query = { _id: new ObjectId(req.params.id) };

Mongoose Database Connection and Schema

Hi There: I'm having a difficult time online finding out how to perform a simple database connection, schema creation, and basic CRUD using mongoose with node.js. Right now I have the following code but am getting the error:
"TypeError: object is not a function
at Schema.CALL_NON_FUNCTION_AS_CONSTRUCTOR (native).."
// Launch express and server
var express = require('express');
var app = express.createServer();
//connect to DB
var mongoose = require('mongoose');
var db = mongoose.connect('mongodb://localhost/napkin_0.1');
// Define Model
var Schema = mongoose.Schema,
ObjectId = Schema.ObjectId;
User = new Schema({
'title': { type: String, index: true },
'data': String,
'tags': [String],
'user_id': ObjectId
});
//Define Collection
mongoose.model('Document', User);
var user = new User();
user.title = "TEST TITLE";
user.save();
//Launch Server
app.listen(3002);
You are trying to instantiate an instance of the Schema. I would change
User = new Schema({
To
UserSchema = new Schema({
and later on call
var User = mongoose.model('user', UserSchema);
and finally
var user = new User();
After your schema definition.
//Define Collection
mongoose.model('Document', User);
The above code is not for defining collection, it is to initialize the model object.
Change it as follows:
//Create Model Object
var UserModel = mongoose.model('user_model_name', User); // 2nd param -> User is a schema object
Then create the Document object out of model object.
As follows:
var user_doc = new UserModel();
Then you can use getters/setters and methods.
user_doc.title = 'your text for title';
user_doc.save();

Categories