I read the following stack overflow messages:
Unit Test with Mongoose
Refusing / Erasing a Mongoose Model Save Method
I also looked at mockgoose, but I would prefer to use testdouble or sinon to drown / mock my calls in the database.
The information received here is probably the one closest to what I would like to do. But I can’t wrap it. The difference, I think, is that I'm trying to check the route in my api, and not on the Mongoose model. Here is my code:
server.ts
import * as express from 'express';
const app = express()
import { createServer } from 'http';
const server = createServer(app);
import * as ioModule from 'socket.io';
const io = ioModule(server);
import * as path from 'path';
import * as bodyParser from 'body-parser';
import * as helmet from 'helmet';
import * as compression from 'compression';
import * as morgan from 'morgan';
import './server/db';
import { api } from './server/routes/api'
import { socketHandler } from './server/socket/socket';
app.use(helmet());
app.use(compression());
app.use(morgan('common'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(express.static(path.join(__dirname, 'dist')));
app.use('/api', api);
app.get('*', (req: any, res: any) => {
res.sendFile(path.join(__dirname, 'dist/index.html'));
});
const port = process.env.PORT || '3000';
app.set('port', port);
server.listen(port, () => console.log(`API running on localhost:${port}`));
io.on('connection', socketHandler);
export { server };
/server/db.ts
import * as mongoose from 'mongoose';
// Enter database URL and delete this comment
const devDbUrl = 'mongodb://localhost:27017/book-trade';
const prodDbUrl = process.env.MONGOLAB_URI;
const dbUrl = devDbUrl || prodDbUrl;
mongoose.connect(dbUrl);
(<any>mongoose).Promise = global.Promise;
mongoose.connection.on('connected', () => {
console.log('Mongoose connected to ' + dbUrl);
});
mongoose.connection.on('disconnected', () => {
console.log('Mongoose disconnected');
});
mongoose.connection.on('error', (err: any) => {
console.log('Mongoose connection error' + err);
});
process.on('SIGINT', () => {
mongoose.connection.close(() => {
console.log('Mongoose disconnected through app termination (SIGINT)');
process.exit(0);
});
});
process.on('SIGTERM', () => {
mongoose.connection.close(() => {
console.log('Mongoose disconnected through app termination (SIGTERM)');
process.exit(0);
});
});
process.once('SIGUSR2', () => {
mongoose.connection.close(() => {
console.log('Mongoose disconnected through app termination (SIGUSR2)');
process.kill(process.pid, 'SIGUSR2');
});
});
/server/models/user.ts
import * as mongoose from 'mongoose';
const Schema = mongoose.Schema;
const mongooseUniqueValidator = require('mongoose-unique-validator');
export interface IUser extends mongoose.Document {
firstName: string,
lastName: string,
city: string,
state: string,
password: string,
email: string,
books: Array<{
book: any,
onLoan: boolean,
loanedTo: any
}>
}
const schema = new Schema({
firstName: { type: String, required: true },
lastName: { type: String, required: true },
city: { type: String, required: true },
state: { type: String, required: true },
password: { type: String, required: true },
email: { type: String, required: true, unique: true },
books: [{
book: { type: Schema.Types.ObjectId, ref: 'Book', required: true},
onLoan: { type: Boolean, required: true },
loanedTo: { type: Schema.Types.ObjectId, ref: 'User'}
}]
});
schema.plugin(mongooseUniqueValidator);
export const User = mongoose.model<IUser>('User', schema);
/server/routes/api.ts
import * as express from 'express';
const router = express.Router();
import { userRoutes } from './user';
router.use('/user', userRoutes);
export { router as api };
/server/routes/user.ts
import * as express from 'express';
const router = express.Router();
import * as bcrypt from 'bcryptjs';
import { User } from '../models/user';
router.post('/', function (req, res, next) {
bcrypt.hash(req.body.password, 10)
.then((hash) => {
const user = new User({
firstName: req.body.firstName,
lastName: req.body.lastName,
city: req.body.city,
state: req.body.state,
password: hash,
email: req.body.email
});
return user.save();
})
.then((user) => {
res.status(201).json({
message: 'User created',
obj: user
});
})
.catch((error) => {
res.status(500).json({
title: 'An error occured',
error: error
});
});
});
/server/routes/user.spec.ts
import * as request from 'supertest';
import * as td from 'testdouble';
import { server } from '../../server';
import { finishTest } from '../../spec/helpers/suptertest';
describe('user route', function () {
let app: any;
beforeEach(function () {
app = server;
});
afterEach(function (done) {
app.close(done);
});
it('creates a user /', (done) => {
request(app)
.post('/api/user')
.send({
firstName: 'Philippe',
lastName: 'Vaillancourt',
city: 'Laval',
state: 'Qc',
password: 'test',
email: 'test@test.com',
})
.expect(201, finishTest(done));
});
});
supertest Jasmine .
: spec , mocks?