Sinon spy return "undefined" - node.js

I'm on node.js using Mongoose model and testing with Mocha with Sinon.
The function I'm testing:
exports.findAllUsers = (req, res) => {
UserCollection.find()
.then(users => {
res.status(500)
.send(users)
})
.catch(err => {
res.status(500)
.send({message: err.message || "error occurred retriving users informations"})
})
Here my test code:
describe("findAllUsers", () => {
const sandbox = sinon.createSandbox();
afterEach(function () {
sinon.restore();
sandbox.restore();
});
const req = {
params: {
id: new mongoose.Types.ObjectId(),
},
};
const statusJsonSpy = sinon.spy();
const res = {
send: sinon.spy(),
status: sinon.stub().returns({ json: statusJsonSpy }),
};
it("should return all users data if found", async () => {
mongoose.Model.find = sandbox
.stub()
.returns(Promise.resolve("users data"));
await findAllUsers(req, res);
console.log(res.send.callCount);
expect(res.send).to.have.been.calledWith("users data");
});
res.send.callCount return 0, res.send is never been called thus the test fail!

If I edit my function as in the following, the test work:
exports.findAllUsers = (req, res) => {
UserCollection.find()
.then(users => {
res.status(500)
res.send(users) // added res, not using concatenation
})
.catch(err => {
res.status(500)
.send({message: err.message || "error occurred retriving users informations"})
})
}

Related

Jest error MongoServerError: E11000 duplicate key error collection

I'm trying to learn testing with jest and supertest. I have this simple API:
app.get("/", (req, res) => {
res.json({ name: "bob" });
});
app.delete("/delete", async (req, res) => {
const result = await Todos.deleteOne({ _id: req.body.id });
res.send(result);
});
app.post("/add", (req, res) => {
const { item, status } = req.body;
const todo = new Todos({
item,
});
todo.save();
res.send(todo);
});
They all work. I also have these tests **which when individually run they all pass, but when I run them together the delete fails.
My logic is, when adding a post, I'm passing the id of the created post to the test so that the delete test can use
const request = require("supertest");
const app = require("../server");
describe("testing Todos API", () => {
let payload = { id: "6156c95c9ecf28237844489b" };
let item = { item: "test" };
it("get", (done) => {
request(app)
.get("/")
.expect(200)
.end((err, res) => {
expect(res.body).toEqual({ name: "bob" });
expect(res.body.name).toEqual("bob");
done();
});
});
it("post", (done) => {
request(app)
.post("/add")
.send(item)
.expect(200)
.end((err, res) => {
payload.id = res.body._id;
expect(res.body.item).toEqual(item.item);
done();
});
});
it("delete", (done) => {
request(app)
.delete("/delete")
.send(payload)
.end((err, res) => {
console.log(res.body);
expect(res.body.deletedCount).toEqual(1);
done();
});
});
});
But I get the error of error MongoServerError: E11000 duplicate key error collection and deletedCount is 0

Stubbing function with jest to test Internal error

I'm trying to test a controller function using jest, and i want to test all three status return
const messagesSender = async (req, res) => {
try {
const { message } = req.body;
if (!message) {
return res.status(400).send({ message: 'Message cannot be null' });
}
return res.status(200).send(message);
} catch (error) {
return res.status(500).json({ error: 'Internal Error' });
}
};
module.exports = { messagesSender };
Test file:
const messages = require('../controller/messagesController');
describe('Testing Messages Controller', () => {
it('should return internal error', async () => {
const req = {
body: {
message: 'testing',
},
};
const res = {
send: jest.fn(),
status: jest.fn(() => res),
};
const messageResponse = await messages.messagesSender(req, res);
messageResponse.mockImplementation(() => {
throw new Error('User not found');
});
expect(res.status).toBeCalledWith(500);
});
});
But i'm receiving the error:
TypeError: Cannot read property 'mockImplementation' of undefined
How can i fix this and test the 500 result?
it('should return internal error', async () => {
const req = {
body: {
message: 'testing',
},
};
const res = {
send: jest.fn().mockImplementation(() => {
throw new Error('User not found');
}),
status: jest.fn(() => res),
};
await messages.messagesSender(req, res);
expect(res.status.mock.calls[1][0]).toBe(500);
});
In your case send function returning nothing and causing this problem. In this case status method have been called twice, so you need to check the second call.

How to return a custom message instead of an empty array from a Mongoose Find query when no results are found

I'm trying to return a custom message when I do a mongoose.find query and it doesn't find anything on the system.
At the moment I have the following and it works, but I was wondering if there is a better way of accomplishing what I'm doing .
// <status> => one of ["valid", "expired", "attributed"]
const getByStatus = (status) => {
return new Promise((resolve, reject) => {
PhotoCodes.find({ status: status })
.then((response) => {
resolve(response)
})
.catch((error) => {
reject(error)
})
})
}
router.post('/byStatus', (req, res, next) => {
const { status } = req.body
photoCodesModel
.getByStatus(status)
.then((response) => {
if (response.length == 0 ) {
res.status(404).send('Not Found') // [ASK]: If response is an empty "[]" treat it as nothing was found. Is there a better way of doing this?
} else {
res.status(200).json({ result: 'ok', data: response })
}
})
.catch((error) => {
res.status(400).json({ result: 'ok', error: error })
})
})
You can use async/await to do, like this
const getByStatus = async (status) => {
const photo = await PhotoCodes.find({ status: status })
return photo .
}
router.post('/byStatus',async (req, res, next) => {
const status = req.body.status;
try {
const photo = await getByStatus(status)
if(photo.length!==0) {
return res.status(200).json({ result: 'ok', data: photo })
}
return res.status(404).json({message : "treat it as nothing was found"})
}
catch(error) {
return res.status(400).json({ result: 'ok', error: error })
}
});

Subscribe method does not work in angular

product-operations.component.ts
deleteProduct() {
this.productsService.delete_product(this.deleteID).subscribe((res: any) => {
console.log("helloooooo");
});
};
product.service.ts
delete_product(id) {
return this.http.delete("http://localhost:3000/delete_product/" + id);
}
backend
exports.deleteProduct = (req, res, next) => {
const id = req.param("id");
Product.deleteOne({ _id: id })
.then(() => {
console.log("deleted");
})
.catch(err => {
console.log(err);
});
};
Problem:
In the above codes, the deleteProduct function in product-operations.component.ts doesn't work properly. More precisely, it does the removal. But after doing the uninstall, subscribe doesn't run its contents. This prevents my instant update after deletion. How can I solve this?
Try to send a response back from the server.
exports.deleteProduct = (req, res, next) => {
const id = req.param("id");
Product.deleteOne({ _id: id })
.then(() => {
res.send({}) // or res.send({id: id})
console.log("deleted");
})
.catch(err => {
res.status(500)
res.send({error: err})
console.log(err);
});
};

How to create a Mongo database to Node.js?

I have created the backend operations using Node.js / MongoDB and created services for them, but when I run the server it indicates that I've connected successfully, but I can't see a database in Robo 3T.
Here is what I coded:
DBConfig.js
var mongoose = require ('mongoose');
var Schema = mongoose.Schema;
var UserSchema = new Schema({
name : {
type : String,
require : true
},
address : {
type : String,
require : true
}
});
mongoose.model("User", UserSchema);
module.exports = mongoose;
mongoose.connect('mongodb://127.0.0.1:27017/TestDB4', function(err){
if(err)
{
console.log(err);
process.exit(-1);
}
console.log("Connected to the db")
});
I can't see an error. Why isn't the DB created?
check your User.Controller.js as this below,
var mongoose = require('../DBSchema/SchemaMapper');
var UserSchema = mongoose.model('User');
var UserController = function(){
this.insert = (data) => {
return new Promise((resolve, reject) => {
var user = new UserSchema({
userName: data.userName,
password: data.password
});
user.save().then(() => {
resolve({status: 200, message: "Added new user"});
}).catch(err => {
reject({status: 500, message: "Error:- "+err});
})
})
}
this.update = (id, data) => {
return new Promise((resolve, reject) => {
UserSchema.update({_id: id}, data).then(() => {
resolve({status: 200, message: "update user"});
}).catch(err => {
reject({status: 500, message: "Error:- " + err});
})
})
}
this.searchAll = () => {
return new Promise((resolve, reject) => {
UserSchema.find().exec().then((data) => {
resolve({status: 200, data: data});
}).catch(err => {
reject({status: 500, message: "Error:- " + err});
})
})
}
this.search = (id) => {
return new Promise((resolve, reject) => {
UserSchema.find({_id:id}).exec().then(user => {
resolve({status: 200, data: user});
}).catch(err => {
reject({status: 500, message: "Error:- " + err});
})
})
}
this.delete = (id) => {
return new Promise((resolve, reject) => {
UserSchema.remove({_id:id}).then(() => {
resolve({status: 200, message: "remove user"});
}).catch(err => {
reject({status: 500, message:"Error:- " + err});
})
})
}
}
module.exports = new UserController();
And User.Route.js as below,
var express = require('express');
var router = express.Router();
var Controller = require('./User.Controller');
router.post('/', (req, res) => {
Controller.insert(req.body).then(data => {
res.status(data.status).send({message: data.message});
}).catch(err => {
res.status(err.status).send({message: err.message});
})
});
router.put('/:id', (req, res) => {
Controller.update(req.params.id, req.body).then(data => {
res.status(data.status).send({message: data.message});
}).catch(err => {
res.status(err.status).send({message: err.message});
})
});
router.get('/', (req, res) => {
Controller.searchAll().then(data => {
res.status(data.status).send({data: data.data});
}).catch(err => {
res.status(err.status).send({message: err.message});
});
});
router.get('/:id', (req, res) => {
Controller.search(req.params.id).then(data => {
res.status(data.status).send({data: data.data});
}).catch(err => {
res.status(err.status).send({message: err.message});
});
});
router.delete('/:id', (req, res) => {
Controller.delete(req.params.id).then(data => {
res.status(data.status).send({message: data.message});
}).catch(err => {
res.status(err.status).send({message: err.message});
})
})
module.exports = router;
check your app.js as follows
const Express = require("express");
const BodyParser = require("body-parser");
const Routes = require("./Routes");
const Cors = require("cors");
const app = Express();
app.use(Cors());
app.use(BodyParser.urlencoded({ extended: false }));
app.use(BodyParser.json());
app.use('/', Routes);
app.listen(8083, 'localhost', (err) => {
if(err) {
console.log(err);
process.exit(-1);
}
console.log("Server listen port 8083");
});
and Routes.js as follows,
var Express = require("express");
var Routes = Express.Router();
var UserRoute = require('./src/User/User.Route');
var CommentRoute = require('./src/Comment/Comment.Route');
Routes.use('/user/', UserRoute);
Routes.use('/comment/', CommentRoute);
module.exports = Routes;

Resources