Skip to content
Snippets Groups Projects
Commit 807a7009 authored by Lucendio's avatar Lucendio
Browse files

[app/server] Introduce a test for creating a user document in the database

* introduce a test on the server to see if user creation works (backend process <-> db only;
  still needs a test that involves the router, too)
* main server process is no connection-aware and wont start if database is not reachable
* some renaming, cause it's more descriptive
* unify quote usage
parent 08b36521
No related branches found
No related tags found
No related merge requests found
PORT=3000
MONGODB_URL=mongodb://localhost:27017/todo-app
JWT_SECRET=myjwtsecret
module.exports = {
testEnvironment: 'node'
};
Source diff could not be displayed: it is too large. Options to address this: view the blob.
...@@ -5,10 +5,13 @@ ...@@ -5,10 +5,13 @@
"license": "MIT", "license": "MIT",
"scripts": { "scripts": {
"start": "node src/index", "start": "node src/index",
"dev": "env-cmd -f ./dev.env nodemon src/index" "dev": "env-cmd -f ./dev.env nodemon src/index",
"test": "env-cmd -f ./dev.env jest --ci"
}, },
"devDependencies": { "devDependencies": {
"@shelf/jest-mongodb": "^1.1.5",
"env-cmd": "^10.1.0", "env-cmd": "^10.1.0",
"jest": "^25.1.0",
"nodemon": "^2.0.2" "nodemon": "^2.0.2"
}, },
"dependencies": { "dependencies": {
......
const mongoose = require('mongoose');
const mongooseInstance_ = mongoose.connect(process.env.MONGODB_URL, {
useNewUrlParser: true,
useCreateIndex: true,
useFindAndModify: false,
useUnifiedTopology: true,
// NOTE: as of the docs `connectTimeoutMS` should be used when `useUnifiedTopology: true`,
// but apparently it has no impact what so ever. Instead, the following works ¯\_(ツ)_/¯
serverSelectionTimeoutMS: 7000 // 7 sec
});
module.exports = mongooseInstance_;
const mongoose = require('mongoose')
mongoose.connect(process.env.MONGODB_URL, {
useNewUrlParser: true,
useCreateIndex: true,
useFindAndModify: false,
useUnifiedTopology: true
})
const path = require( 'path' ); const path = require( 'path' );
const express = require('express') const express = require('express');
const cors = require('cors') const cors = require('cors');
const helmet = require('helmet') const helmet = require('helmet');
require('./db/mongoose') const dbClientInstance_ = require('./db/mongo.js');
const todoRoutes = require('./routes/todo-routes') const todoRoutes = require('./routes/todo');
const userRoutes = require('./routes/user-routes') const userRoutes = require('./routes/user');
const errorRoutes = require('./routes/error-routes') const errorRoutes = require('./routes/error');
let cookieParser = require('cookie-parser') let cookieParser = require('cookie-parser');
const app = express() const app = express();
const port = process.env.PORT || 5000 const port = process.env.PORT || 5000;
const corsOptions = { const corsOptions = {
origin: `http://localhost:${ port }`, origin: `http://localhost:${ port }`,
credentials: true credentials: true
} };
app.use(express.json()) app.use(express.json());
app.use(cors(corsOptions)) app.use(cors(corsOptions));
app.use(cookieParser()) app.use(cookieParser());
app.use(helmet()) app.use(helmet());
app.use(helmet.contentSecurityPolicy({ app.use(helmet.contentSecurityPolicy({
directives: { directives: {
defaultSrc: ["'self'"], defaultSrc: ["'self'"],
styleSrc: ["'self' 'unsafe-inline'"], styleSrc: ["'self' 'unsafe-inline'"],
scriptSrc: ["'self' 'unsafe-inline' 'unsafe-eval'"] scriptSrc: ["'self' 'unsafe-inline' 'unsafe-eval'"]
} }
})) }));
app.use(todoRoutes) app.use(todoRoutes);
app.use(userRoutes) app.use(userRoutes);
app.use('/', express.static(path.join(__dirname,`./../../client/build`))); app.use('/', express.static(path.join(__dirname,`./../../client/build`)));
app.use(errorRoutes) app.use(errorRoutes);
app.listen(port, () => {
console.log('ToDo server is up on port ' + port) (async function main(){
}) try{
const dbClient = await dbClientInstance_;
process.on( 'exit', ()=>{
dbClient.disconnect();
});
await new Promise( (__ful, rej__ )=>{
app.listen(port, function(){
console.log( `ToDo server is up on port ${ port }`);
__ful();
}).on( 'error', rej__);
});
}catch(e){
console.error( new Error( `Cannot connect to database ${ process.env.MONGODB_URL }` ) );
process.exit( 1 );
}
})();
const jwt = require('jsonwebtoken') const jwt = require('jsonwebtoken')
const Users = require('../models/Users-model') const { model: Users } = require('../models/Users')
const auth = async (req, res, next) => { const auth = async (req, res, next) => {
try { try {
......
const mongoose = require("mongoose") const mongoose = require('mongoose');
const ToDosSchema = new mongoose.Schema({
const schema = new mongoose.Schema({
title: { title: {
type: String, type: String,
required: true, required: true,
...@@ -23,9 +24,9 @@ const ToDosSchema = new mongoose.Schema({ ...@@ -23,9 +24,9 @@ const ToDosSchema = new mongoose.Schema({
} }
}, { }, {
timestamps: true timestamps: true
}) });
const ToDos = mongoose.model('ToDos', ToDosSchema) const model = mongoose.model( 'ToDos', schema );
module.exports = ToDos
module.exports = { schema, model };
const dbClientInstance_ = require( './../db/mongo.js' );
const { model: Users } = require( './Users.js' );
describe( 'Model: Users', ()=>{
beforeAll( async ()=>{
await dbClientInstance_;
});
const userData = {
name: 'myname',
email: 'myname@example.com',
password: 'mypassword'
};
test( 'creating a user', async ()=>{
const userData = {
name: 'myname',
email: 'myname@example.com',
password: 'mypassword'
};
const userDoc = await Users( userData );
await userDoc.save();
const userRecord = await Users.findOne({ email: userData.email });
const { password, ...userInfo } = userData;
expect( userRecord ).toEqual( expect.objectContaining( userInfo ) );
});
afterAll( async ()=>{
const dbClient = await dbClientInstance_;
const { connection } = dbClient;
await connection.dropDatabase();
await dbClient.disconnect();
});
});
const mongoose = require("mongoose") const mongoose = require('mongoose');
const validator = require('validator') const validator = require('validator');
const bcrypt = require('bcryptjs') const bcrypt = require('bcryptjs');
const jwt = require('jsonwebtoken') const jwt = require('jsonwebtoken');
const usersSchema = new mongoose.Schema({
const schema = new mongoose.Schema({
name: { name: {
type: String, type: String,
required: true, required: true,
...@@ -16,7 +17,7 @@ const usersSchema = new mongoose.Schema({ ...@@ -16,7 +17,7 @@ const usersSchema = new mongoose.Schema({
required: true, required: true,
validate(value) { validate(value) {
if (!validator.isEmail(value)) { if (!validator.isEmail(value)) {
throw new Error("Invalid email format") throw new Error('Invalid email format');
} }
} }
}, },
...@@ -34,59 +35,58 @@ const usersSchema = new mongoose.Schema({ ...@@ -34,59 +35,58 @@ const usersSchema = new mongoose.Schema({
}] }]
}, { }, {
timestamps: true timestamps: true
}) });
usersSchema.pre('save', async function (next) { schema.pre('save', async function (next) {
const user = this const user = this;
if (user.isModified('password')) { if (user.isModified('password')) {
user.password = await bcrypt.hash(user.password, 8) user.password = await bcrypt.hash(user.password, 8);
} }
next() next();
}) });
usersSchema.statics.findByCredentials = async (email, password) => { schema.statics.findByCredentials = async (email, password) => {
const user = await Users.findOne({ email }) const user = await Users.findOne({ email });
if (!user) { if (!user) {
throw new Error('Unable to login') throw new Error('Unable to login');
} }
const isMatch = await bcrypt.compare(password, user.password) const isMatch = await bcrypt.compare(password, user.password);
if (!isMatch) { if (!isMatch) {
throw new Error('Unable to login') throw new Error('Unable to login');
} }
return user return user;
} };
usersSchema.methods.generateAuthToken = async function () { schema.methods.generateAuthToken = async function () {
const user = this const user = this;
const token = jwt.sign({ _id: user._id.toString() }, process.env.JWT_SECRET) const token = jwt.sign({ _id: user._id.toString() }, process.env.JWT_SECRET);
user.tokens = user.tokens.concat({ token }) user.tokens = user.tokens.concat({ token });
await user.save() await user.save();
return token return token;
} };
usersSchema.methods.toJSON = function () { schema.methods.toJSON = function () {
const user = this const user = this;
const publicUserData = user.toObject() const publicUserData = user.toObject();
delete publicUserData.password delete publicUserData.password;
delete publicUserData.tokens delete publicUserData.tokens;
return publicUserData return publicUserData
} }
const Users = mongoose.model('Users', usersSchema) const model = mongoose.model( 'Users', schema );
module.exports = Users
module.exports = { schema, model };
...@@ -6,7 +6,7 @@ routes.get('*', async (req, res) => { ...@@ -6,7 +6,7 @@ routes.get('*', async (req, res) => {
try { try {
res.status(404).send({ res.status(404).send({
error: "Invalid endpoint." error: 'Not Found'
}) })
} }
catch (e) { catch (e) {
...@@ -15,4 +15,4 @@ routes.get('*', async (req, res) => { ...@@ -15,4 +15,4 @@ routes.get('*', async (req, res) => {
}) })
module.exports = routes module.exports = routes
\ No newline at end of file
const express = require('express') const express = require('express')
const ToDos = require('../models/Todos-model') const { model: ToDos } = require('../models/Todos')
const auth = require('../middlewares/auth') const auth = require('../middlewares/auth')
const routes = express.Router() const routes = express.Router()
...@@ -53,11 +53,11 @@ routes.patch('/todo/update', auth, async (req, res) => { ...@@ -53,11 +53,11 @@ routes.patch('/todo/update', auth, async (req, res) => {
return res.status(400).send({ error: 'Invalid fields to update!' }) return res.status(400).send({ error: 'Invalid fields to update!' })
} }
const updateObj = {} const updateObj = {}
if (changedTodo.hasOwnProperty("important")) { if (changedTodo.hasOwnProperty('important')) {
updateObj.important = changedTodo.important updateObj.important = changedTodo.important
} }
if (changedTodo.hasOwnProperty("done")) { if (changedTodo.hasOwnProperty('done')) {
updateObj.done = changedTodo.done updateObj.done = changedTodo.done
} }
......
const express = require('express') const express = require('express')
const Users = require('../models/Users-model') const { model: Users } = require('../models/Users')
const auth = require('../middlewares/auth') const auth = require('../middlewares/auth')
const routes = express.Router() const routes = express.Router()
...@@ -77,4 +77,4 @@ routes.post('/logout', auth, async (req, res) => { ...@@ -77,4 +77,4 @@ routes.post('/logout', auth, async (req, res) => {
} }
}) })
module.exports = routes module.exports = routes
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment