From 68c4485229db544cecae0678d4f34861bc2b97a4 Mon Sep 17 00:00:00 2001 From: Hawa Abdi Date: Tue, 3 Jan 2017 08:28:15 -0800 Subject: [PATCH 1/6] Tests passing --- lab-hawa/.env | 3 + lab-hawa/.eslintrc | 21 +++++ lab-hawa/.gitignore | 117 ++++++++++++++++++++++++++ lab-hawa/README.md | 0 lab-hawa/gulpfile.js | 25 ++++++ lab-hawa/lib/basic-auth-middleware.js | 36 ++++++++ lab-hawa/lib/error-middleware.js | 28 ++++++ lab-hawa/model/user.js | 75 +++++++++++++++++ lab-hawa/package.json | 42 +++++++++ lab-hawa/route/auth-router.js | 35 ++++++++ lab-hawa/server.js | 29 +++++++ lab-hawa/test/user-route-test.js | 74 ++++++++++++++++ 12 files changed, 485 insertions(+) create mode 100644 lab-hawa/.env create mode 100644 lab-hawa/.eslintrc create mode 100644 lab-hawa/.gitignore create mode 100644 lab-hawa/README.md create mode 100644 lab-hawa/gulpfile.js create mode 100644 lab-hawa/lib/basic-auth-middleware.js create mode 100644 lab-hawa/lib/error-middleware.js create mode 100644 lab-hawa/model/user.js create mode 100644 lab-hawa/package.json create mode 100644 lab-hawa/route/auth-router.js create mode 100644 lab-hawa/server.js create mode 100644 lab-hawa/test/user-route-test.js diff --git a/lab-hawa/.env b/lab-hawa/.env new file mode 100644 index 0000000..cff2e78 --- /dev/null +++ b/lab-hawa/.env @@ -0,0 +1,3 @@ +PORT='3000' +MONGODB_URI='mongodb://localhost/cfgram' +APP_SECRET='ninjaCoder' diff --git a/lab-hawa/.eslintrc b/lab-hawa/.eslintrc new file mode 100644 index 0000000..8dc6807 --- /dev/null +++ b/lab-hawa/.eslintrc @@ -0,0 +1,21 @@ +{ + "rules": { + "no-console": "off", + "indent": [ "error", 2 ], + "quotes": [ "error", "single" ], + "semi": ["error", "always"], + "linebreak-style": [ "error", "unix" ] + }, + "env": { + "es6": true, + "node": true, + "mocha": true, + "jasmine": true + }, + "ecmaFeatures": { + "modules": true, + "experimentalObjectRestSpread": true, + "impliedStrict": true + }, + "extends": "eslint:recommended" +} diff --git a/lab-hawa/.gitignore b/lab-hawa/.gitignore new file mode 100644 index 0000000..43bce2d --- /dev/null +++ b/lab-hawa/.gitignore @@ -0,0 +1,117 @@ +# Created by https://www.gitignore.io/api/ma,node,macos,windows,linux + +#!! ERROR: ma is undefined. Use list command to see defined gitignore types !!# + +node_modules/ + +### Node ### +# Logs +logs +*.log +npm-debug.log* + +# Runtime data +pids +*.pid +*.seed +*.pid.lock + +# Directory for instrumented libs generated by jscoverage/JSCover +lib-cov + +# Coverage directory used by tools like istanbul +coverage + +# nyc test coverage +.nyc_output + +# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) +.grunt + +# node-waf configuration +.lock-wscript + +# Compiled binary addons (http://nodejs.org/api/addons.html) +build/Release + +# Dependency directories +node_modules +jspm_packages + +# Optional npm cache directory +.npm + +# Optional eslint cache +.eslintcache + +# Optional REPL history +.node_repl_history + +# Output of 'npm pack' +*.tgz + +# Yarn Integrity file +.yarn-integrity + + + +### macOS ### +*.DS_Store +.AppleDouble +.LSOverride + +# Icon must end with two \r +Icon +# Thumbnails +._* +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns +.com.apple.timemachine.donotpresent +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk + + +### Windows ### +# Windows image file caches +Thumbs.db +ehthumbs.db + +# Folder config file +Desktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Windows Installer files +*.cab +*.msi +*.msm +*.msp + +# Windows shortcuts +*.lnk + + +### Linux ### +*~ + +# temporary files which can be created if a process still has a handle open of a deleted file +.fuse_hidden* + +# KDE directory preferences +.directory + +# Linux trash folder which might appear on any partition or disk +.Trash-* + +# .nfs files are created when an open file is removed but is still being accessed +.nfs* diff --git a/lab-hawa/README.md b/lab-hawa/README.md new file mode 100644 index 0000000..e69de29 diff --git a/lab-hawa/gulpfile.js b/lab-hawa/gulpfile.js new file mode 100644 index 0000000..00fd57d --- /dev/null +++ b/lab-hawa/gulpfile.js @@ -0,0 +1,25 @@ +'use strict'; + +const gulp = require('gulp'); +const eslint = require('gulp-eslint'); +const mocha = require('gulp-mocha'); + +//TODO:watch each individual file?? + +gulp.task('test', function(){ + gulp.src('./test/*-test.js', {read: false}) + .pipe(mocha({reporter: 'spec'})); +}); + +gulp.task('lint', function(){ + return gulp.src(['**/*.js','!node_modules/**']) + .pipe(eslint()) + .pipe(eslint.format()) + .pipe(eslint.failAfterError()); +}); + +gulp.task('dev', function(){ + gulp.watch(['**/*.js','!node_modules/**'], ['test', 'lint']); +}); + +gulp.task('default', ['dev']); diff --git a/lab-hawa/lib/basic-auth-middleware.js b/lab-hawa/lib/basic-auth-middleware.js new file mode 100644 index 0000000..123f4cd --- /dev/null +++ b/lab-hawa/lib/basic-auth-middleware.js @@ -0,0 +1,36 @@ +'use strict'; + +const createError = require('http-errors'); +const debug = require('debug')('cfgram:basic-auth-middleware'); + +module.exports = function(req, res, next) { + debug('basic-auth-middleware'); + + var authHeader = req.headers.authorization; + if (!authHeader) { + return next(createError(401, 'authorization header required')); + } + + var base64str = authHeader.split('Basic ')[1]; + if (!base64str) { + return next(createError(401, 'username and password required')); + } + + var utf8str = new Buffer(base64str, 'base64').toString(); + var authArr = utf8str.split(':'); + + req.auth = { + username: authArr[0], + password: authArr[1] + }; + + if (!req.auth.username) { + return next(createError(401, 'requires username')); + } + + if (!req.auth.password) { + return next(createError(401, 'requires password')); + } + + next(); +}; diff --git a/lab-hawa/lib/error-middleware.js b/lab-hawa/lib/error-middleware.js new file mode 100644 index 0000000..a554abd --- /dev/null +++ b/lab-hawa/lib/error-middleware.js @@ -0,0 +1,28 @@ +'use strict'; + +const createError = require('http-errors'); +const debug = require('debug')('cfgram:error-middleware'); + +module.exports = function(err, req, res, next) { + debug('error-middleware'); + + console.error('msg:', err.message); + console.error('name:', err.name); + + if (err.status) { + res.status(err.status).send(err.name); + next(); + return; + } + + if (err.name === 'ValidationError') { + err = createError(400, err.message); + res.status(err.status).send(err.name); + next(); + return; + } + + err = createError(500, err.message); + res.status(err.status).send(err.name); + next(); +}; diff --git a/lab-hawa/model/user.js b/lab-hawa/model/user.js new file mode 100644 index 0000000..a3fb4ec --- /dev/null +++ b/lab-hawa/model/user.js @@ -0,0 +1,75 @@ +'use strict'; + +const crypto = require('crypto'); +const bcrypt = require('bcrypt'); +const jwt = require('jsonwebtoken'); +const mongoose = require('mongoose'); +const createError = require('http-errors'); +const Promise = require('bluebird'); +const debug = require('debug')('cfgram:user'); + +const Schema = mongoose.Schema; + +const userSchema = Schema({ + username: { type: String, required: true, unique: true }, + email: { type: String, required: true, unique: true }, + password: { type: String, require: true }, + findHash: { type: String, unique: true } +}); + +userSchema.methods.generatePasswordHash = function(password) { + debug('generatePasswordHash'); + + return new Promise((resolve, reject) => { + bcrypt.hash(password, 10, (err, hash) => { + if (err) return reject(err); + this.password = hash; + resolve(this); + }); + }); +}; + +userSchema.methods.comparePasswordHash = function(password) { + debug('comparePasswordHash'); + + return new Promise((resolve, reject) => { + bcrypt.compare(password, this.password, (err, valid) => { + if (err) return reject(err); + if (!valid) return reject(createError(401, 'wrong password')); + resolve(this); + }); + }); +}; + +userSchema.methods.generateFindHash = function() { + debug('generateFindHash'); + + return new Promise((resolve, reject) => { + let tries = 0; + + _generateFindHash.call(this); + + function _generateFindHash() { + this.findHash = crypto.randomBytes(32).toString('hex'); + this.save() + .then( () => resolve(this.findHash)) + .catch( err => { + if (tries > 3) return reject(err); + tries++; + _generateFindHash.call(this); + }); + } + }); +}; + +userSchema.methods.generateToken = function() { + debug('generateToken'); + + return new Promise((resolve, reject) => { + this.generateFindHash() + .then( findHash => resolve(jwt.sign({ token: findHash }, process.env.APP_SECRET))) + .catch( err => reject(err)); + }); +}; + +module.exports = mongoose.model('user', userSchema); diff --git a/lab-hawa/package.json b/lab-hawa/package.json new file mode 100644 index 0000000..35a844d --- /dev/null +++ b/lab-hawa/package.json @@ -0,0 +1,42 @@ +{ + "name": "15-basic_auth", + "version": "1.0.0", + "description": "", + "main": "gulpfile.js", + "directories": { + "test": "test" + }, + "scripts": { + "test": "DEBUG='cfgram*' mocha", + "start": "DEBUG='cfgram*' node server.js" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/abdih17/15-basic_auth.git" + }, + "keywords": [], + "author": "", + "license": "ISC", + "bugs": { + "url": "https://github.com/abdih17/15-basic_auth/issues" + }, + "homepage": "https://github.com/abdih17/15-basic_auth#readme", + "dependencies": { + "bcrypt": "^1.0.2", + "bluebird": "^3.4.7", + "body-parser": "^1.15.2", + "cors": "^2.8.1", + "debug": "^2.6.0", + "dotenv": "^2.0.0", + "express": "^4.14.0", + "http-errors": "^1.5.1", + "jsonwebtoken": "^7.2.1", + "mongoose": "^4.7.6", + "morgan": "^1.7.0" + }, + "devDependencies": { + "chai": "^3.5.0", + "mocha": "^3.2.0", + "superagent": "^3.3.1" + } +} diff --git a/lab-hawa/route/auth-router.js b/lab-hawa/route/auth-router.js new file mode 100644 index 0000000..e8a19bb --- /dev/null +++ b/lab-hawa/route/auth-router.js @@ -0,0 +1,35 @@ +'use strict'; + +const jsonParser = require('body-parser').json(); +const debug = require('debug')('cfgram:auth-router'); +const Router = require('express').Router; +const basicAuth = require('../lib/basic-auth-middleware.js'); + +const User = require('../model/user.js'); + +const authRouter = module.exports = Router(); + +authRouter.post('/api/signup', jsonParser, function(req, res, next) { + debug('POST: /api/signup'); + + let password = req.body.password; + delete req.body.password; + + let user = new User(req.body); + + user.generatePasswordHash(password) + .then( user => user.save()) + .then( user => user.generateToken()) + .then( token => res.send(token)) + .catch(next); +}); + +authRouter.get('/api/signin', basicAuth, function(req, res, next) { + debug('GET:/api/signin'); + + User.findOne({ username: req.auth.username }) + .then( user => user.comparePasswordHash(req.auth.password)) + .then( user => user.generateToken()) + .then( token => res.send(token)) + .catch(next); +}); diff --git a/lab-hawa/server.js b/lab-hawa/server.js new file mode 100644 index 0000000..e8a99b9 --- /dev/null +++ b/lab-hawa/server.js @@ -0,0 +1,29 @@ +'use strict'; + +const express = require('express'); +const cors = require('cors'); +const dotenv = require('dotenv'); +const morgan = require('morgan'); +const mongoose = require('mongoose'); +// const Promise = require('bluebird'); +const debug = require('debug')('cfgram:server'); + +const authRouter = require('./route/auth-router.js'); +const errors = require('./lib/error-middleware.js'); + +dotenv.load(); + +const PORT = process.env.PORT; +const app = express(); + +mongoose.connect(process.env.MONGODB_URI); + +app.use(cors()); +app.use(morgan('dev')); + +app.use(authRouter); +app.use(errors); + +app.listen(PORT, () => { + debug('server up:', PORT); +}); diff --git a/lab-hawa/test/user-route-test.js b/lab-hawa/test/user-route-test.js new file mode 100644 index 0000000..47b2927 --- /dev/null +++ b/lab-hawa/test/user-route-test.js @@ -0,0 +1,74 @@ +'use strict'; + +const expect = require('chai').expect; +const request = require('superagent'); +const mongoose = require('mongoose'); +const Promise = require('bluebird'); +const User = require('../model/user.js'); + +mongoose.Promise = Promise; + +require('../server.js'); + +const url = `http://localhost:${process.env.PORT}`; + +const exampleuser ={ + username: 'exampleuser', + password: '1234', + email: 'exampleuser@test.com' +}; + +describe('Auth Routes', function() { + describe('POST: /api/signup', function() { + describe('with a valid body', function() { + after( done => { + User.remove({}) + .then( () => done()) + .catch(done); + }); + + it('should return a token', done => { + request.post(`${url}/api/signup`) + .send(exampleuser) + .end((err, res) => { + if(err) return done(err); + expect(res.status).to.equal(200); + expect(res.text).to.be.a('string'); + done(); + }); + }); + }); + }); + + describe('GET: /api/signin', function() { + describe('with a vaild body', function() { + before( done => { + let user = new User(exampleuser); + user.generatePasswordHash(exampleuser.password) + .then( user => user.save()) + .then( user => { + this.tempUser = user; + done(); + }) + .catch(done); + }); + + after( done => { + User.remove({}) + .then( () => done()) + .catch(done); + }); + + it('should return a token', done => { + request.get(`${url}/api/signin`) + .auth('exampleuser', '1234') + .end((err, res) => { + if (err) return done(err); + console.log('token:', res.text); + expect(res.status).to.equal(200); + done(); + }); + }); + }); + }); +}); From fa4af9e17614755a4366bf354b65849dcab623a9 Mon Sep 17 00:00:00 2001 From: Hawa Abdi Date: Wed, 4 Jan 2017 10:42:07 -0800 Subject: [PATCH 2/6] Included additional tests to cover errors. --- lab-hawa/test/user-route-test.js | 87 ++++++++++++++++++++++++-------- 1 file changed, 67 insertions(+), 20 deletions(-) diff --git a/lab-hawa/test/user-route-test.js b/lab-hawa/test/user-route-test.js index 47b2927..89ffece 100644 --- a/lab-hawa/test/user-route-test.js +++ b/lab-hawa/test/user-route-test.js @@ -12,10 +12,10 @@ require('../server.js'); const url = `http://localhost:${process.env.PORT}`; -const exampleuser ={ - username: 'exampleuser', +const exampleUser ={ + username: 'exampleUser', password: '1234', - email: 'exampleuser@test.com' + email: 'exampleUser@test.com' }; describe('Auth Routes', function() { @@ -29,7 +29,7 @@ describe('Auth Routes', function() { it('should return a token', done => { request.post(`${url}/api/signup`) - .send(exampleuser) + .send(exampleUser) .end((err, res) => { if(err) return done(err); expect(res.status).to.equal(200); @@ -38,30 +38,54 @@ describe('Auth Routes', function() { }); }); }); - }); - describe('GET: /api/signin', function() { - describe('with a vaild body', function() { - before( done => { - let user = new User(exampleuser); - user.generatePasswordHash(exampleuser.password) - .then( user => user.save()) - .then( user => { - this.tempUser = user; + describe('invalid POST route', function() { + it('should return a 404 code', done => { + request.post(`${url}/api/invalid`) + .send(exampleUser) + .end((err, res) => { + expect(err).to.be.an('error'); + expect(res.status).to.equal(404); done(); - }) - .catch(done); + }); }); + }); - after( done => { - User.remove({}) - .then( () => done()) - .catch(done); + describe('bad request', function() { + it('should return a 400 code', done => { + request.post(`${url}/api/signup`) + .send({username: 'test name', password: '1234'}) + .end((err, res) => { + expect(err).to.be.an('error'); + expect(res.status).to.equal(400); + done(); + }); }); + }); + }); + + describe('GET: /api/signin', function() { + before( done => { + let user = new User(exampleUser); + user.generatePasswordHash(exampleUser.password) + .then( user => user.save()) + .then( user => { + this.tempUser = user; + done(); + }) + .catch(done); + }); + after( done => { + User.remove({}) + .then( () => done()) + .catch(done); + }); + + describe('with a valid body', function () { it('should return a token', done => { request.get(`${url}/api/signin`) - .auth('exampleuser', '1234') + .auth('exampleUser', '1234') .end((err, res) => { if (err) return done(err); console.log('token:', res.text); @@ -70,5 +94,28 @@ describe('Auth Routes', function() { }); }); }); + + describe('with an invalid body', function() { + it('should return a 401', done => { + request.get(`${url}/api/signin`) + .auth('exampleUser', '9876') + .end((err, res) => { + expect(err).to.be.an('error'); + expect(res.status).to.equal(401); + done(); + }); + }); + }); + + describe('invalid GET route', function() { + it('should return a 404', done => { + request.get(`${url}/api/invalid`) + .end((err, res) => { + expect(err).to.be.an('error'); + expect(res.status).to.equal(404); + done(); + }); + }); + }); }); }); From 272651b878a36cf6e527bfa1a149788ef2e96f3b Mon Sep 17 00:00:00 2001 From: Hawa Abdi Date: Wed, 4 Jan 2017 11:56:23 -0800 Subject: [PATCH 3/6] Lab 16 - added additional tests, and gallery route. --- lab-hawa/lib/bearer-auth-middleware.js | 34 +++ lab-hawa/model/gallery.js | 13 + lab-hawa/route/gallery-router.js | 57 ++++ .../route/{auth-router.js => user-router.js} | 8 +- lab-hawa/server.js | 4 +- lab-hawa/test/gallery-route-test.js | 69 +++++ lab-hawa/test/user-route-test.js | 243 +++++++++--------- 7 files changed, 302 insertions(+), 126 deletions(-) create mode 100644 lab-hawa/lib/bearer-auth-middleware.js create mode 100644 lab-hawa/model/gallery.js create mode 100644 lab-hawa/route/gallery-router.js rename lab-hawa/route/{auth-router.js => user-router.js} (74%) create mode 100644 lab-hawa/test/gallery-route-test.js diff --git a/lab-hawa/lib/bearer-auth-middleware.js b/lab-hawa/lib/bearer-auth-middleware.js new file mode 100644 index 0000000..eb15495 --- /dev/null +++ b/lab-hawa/lib/bearer-auth-middleware.js @@ -0,0 +1,34 @@ +'use strict'; + +const jwt = require('jsonwebtoken'); +const createError = require('http-errors'); +const debug = require('debug')('cfgram:bearer-auth-middleware'); + +const User = require('../model/user.js'); + +module.exports = function(req, res, next) { + debug('bearer auth middleware'); + + var authHeader = req.headers.authorization; + if (!authHeader) { + return next(createError(401, 'authorization header required')); + } + + var token = authHeader.split('Bearer ')[1]; + if (!token) { + return next(createError(401, 'token required')); + } + + jwt.verify(token, process.env.APP_SECRET, (err, decoded) => { + if (err) return next(err); + + User.findOne({ findHash: decoded.token }) + .then( user => { + req.user = user; + next(); + }) + .catch( err => { + next(createError(401, err.message)); + }); + }); +}; diff --git a/lab-hawa/model/gallery.js b/lab-hawa/model/gallery.js new file mode 100644 index 0000000..d3438dc --- /dev/null +++ b/lab-hawa/model/gallery.js @@ -0,0 +1,13 @@ +'use strict'; + +const mongoose = require('mongoose'); +const Schema = mongoose. Schema; + +const gallerySchema = Schema ({ + name: { type: String, required: true }, + desc: { type: String, required: true }, + created: { type: Date, required: true, default: Date.now }, + userID: { type: Schema.Types.ObjectId, required: true } +}); + +module.exports = mongoose.model('gallery', gallerySchema); diff --git a/lab-hawa/route/gallery-router.js b/lab-hawa/route/gallery-router.js new file mode 100644 index 0000000..028ba23 --- /dev/null +++ b/lab-hawa/route/gallery-router.js @@ -0,0 +1,57 @@ +'use strict'; + +const Router = require('express').Router; +const jsonParser = require('body-parser').json(); +const createError = require('http-errors'); +const debug = require('debug')('cfgram:gallery-router'); + +const Gallery = require('../model/gallery.js'); +const bearerAuth = require('../lib/bearer-auth-middleware.js'); + +const galleryRouter = module.exports = Router(); + +galleryRouter.post('/api/gallery', bearerAuth, jsonParser, function(req, res, next) { + debug('POST: /api/gallery'); + + req.body.userID = req.user._id; + new Gallery(req.body).save() + .then( gallery => res.json(gallery)) + .catch(next); +}); + +galleryRouter.get('/api/gallery/:id', bearerAuth, function(req, res, next) { + debug('GET: /api/gallery/:id'); + + Gallery.findById(req.params.id) + .then( gallery => { + if (gallery.userID.toString() !== req.user._id.toString()){ + return next(createError(401, 'invalid user')); + } + res.json(gallery); + }) + .catch(next); +}); + +galleryRouter.put('/api/gallery/:id', bearerAuth, function(req, res, next) { + debug('GET: /api/gallery/:id'); + + Gallery.findByIdAndUpdate(req.params.id, req.body, {new: true}) + .then(gallery => { + if (gallery.userID.toString() !== req.user._id.toString()){ + return next(createError(401, 'invalid user')); + } + res.json(gallery); + }) + .catch(err => next(createError(404, err.message))); +}); + +galleryRouter.delete('/api/student/:id', bearerAuth, function(req, res, next) { + debug('DELETE: /api/gallery/:id'); + + Gallery.findByIdAndRemove(req.params.id) + .then( () => { + res.status(204) + .send('Removed user.'); + }) + .catch(err => next(createError(404, err.message))); +}); diff --git a/lab-hawa/route/auth-router.js b/lab-hawa/route/user-router.js similarity index 74% rename from lab-hawa/route/auth-router.js rename to lab-hawa/route/user-router.js index e8a19bb..ebcb402 100644 --- a/lab-hawa/route/auth-router.js +++ b/lab-hawa/route/user-router.js @@ -2,14 +2,16 @@ const jsonParser = require('body-parser').json(); const debug = require('debug')('cfgram:auth-router'); +const createError = require('http-errors'); const Router = require('express').Router; const basicAuth = require('../lib/basic-auth-middleware.js'); +const bearerAuth = require('../lib/bearer-auth-middleware.js'); const User = require('../model/user.js'); -const authRouter = module.exports = Router(); +const userRouter = module.exports = Router(); -authRouter.post('/api/signup', jsonParser, function(req, res, next) { +userRouter.post('/api/signup', jsonParser, function(req, res, next) { debug('POST: /api/signup'); let password = req.body.password; @@ -24,7 +26,7 @@ authRouter.post('/api/signup', jsonParser, function(req, res, next) { .catch(next); }); -authRouter.get('/api/signin', basicAuth, function(req, res, next) { +userRouter.get('/api/signin', basicAuth, function(req, res, next) { debug('GET:/api/signin'); User.findOne({ username: req.auth.username }) diff --git a/lab-hawa/server.js b/lab-hawa/server.js index e8a99b9..974641a 100644 --- a/lab-hawa/server.js +++ b/lab-hawa/server.js @@ -8,7 +8,7 @@ const mongoose = require('mongoose'); // const Promise = require('bluebird'); const debug = require('debug')('cfgram:server'); -const authRouter = require('./route/auth-router.js'); +const userRouter = require('./route/user-router.js'); const errors = require('./lib/error-middleware.js'); dotenv.load(); @@ -21,7 +21,7 @@ mongoose.connect(process.env.MONGODB_URI); app.use(cors()); app.use(morgan('dev')); -app.use(authRouter); +app.use(userRouter); app.use(errors); app.listen(PORT, () => { diff --git a/lab-hawa/test/gallery-route-test.js b/lab-hawa/test/gallery-route-test.js new file mode 100644 index 0000000..7eae731 --- /dev/null +++ b/lab-hawa/test/gallery-route-test.js @@ -0,0 +1,69 @@ +'use strict'; + +const expect = require('chai').expect; +const request = require('superagent'); +const mongoose = require('mongoose'); +const Promise = require('bluebird'); +const User = require('../model/user.js'); +const Gallery = require('../model/gallery.js'); +const url = `http://localhost:${process.env.PORT}`; + +mongoose.Promise = Promise; + +require('../server.js'); + +const exampleUser = { + username: 'exampleUser', + password: '1234', + email: 'exampleUser@test.com' +}; + +const exampleGallery = { + name: 'Example Gallery', + desc: 'test gallery description', +}; + +describe('Gallery Routes', function() { + afterEach( done => { + Promise.all([ + User.remove({}), + Gallery.remove({}) + ]) + .then( () => done()) + .catch(done); + }); + + describe('POST: /api/gallery', () => { + before( done => { + new User(exampleUser) + .generatePasswordHash(exampleUser.password) + .then( user => user.save()) + .then( user => { + this.tempUser = user; + return user.generateToken(); + }) + .then(token => { + this.tempToken = token; + done(); + }) + .catch(done); + }); + + it('should return a gallery', done => { + request.post(`${url}/api/gallery`) + .send(exampleGallery) + .set({ + Authorization: `Bearer ${this.tempToken}` + }) + .end((err, res) => { + if (err) return done(err); + let date = new Date(res.body.created).toString(); + expect(res.body.name).to.equal(exampleGallery.name); + expect(res.body.desc).to.equal(exampleGallery.desc); + expect(res.body.userID).to.equal(this.tempUser._id.toString()); + expect(date).to.not.equal('Invalid Date'); + done(); + }); + }); + }); +}); diff --git a/lab-hawa/test/user-route-test.js b/lab-hawa/test/user-route-test.js index 89ffece..ca3e761 100644 --- a/lab-hawa/test/user-route-test.js +++ b/lab-hawa/test/user-route-test.js @@ -1,121 +1,122 @@ -'use strict'; - -const expect = require('chai').expect; -const request = require('superagent'); -const mongoose = require('mongoose'); -const Promise = require('bluebird'); -const User = require('../model/user.js'); - -mongoose.Promise = Promise; - -require('../server.js'); - -const url = `http://localhost:${process.env.PORT}`; - -const exampleUser ={ - username: 'exampleUser', - password: '1234', - email: 'exampleUser@test.com' -}; - -describe('Auth Routes', function() { - describe('POST: /api/signup', function() { - describe('with a valid body', function() { - after( done => { - User.remove({}) - .then( () => done()) - .catch(done); - }); - - it('should return a token', done => { - request.post(`${url}/api/signup`) - .send(exampleUser) - .end((err, res) => { - if(err) return done(err); - expect(res.status).to.equal(200); - expect(res.text).to.be.a('string'); - done(); - }); - }); - }); - - describe('invalid POST route', function() { - it('should return a 404 code', done => { - request.post(`${url}/api/invalid`) - .send(exampleUser) - .end((err, res) => { - expect(err).to.be.an('error'); - expect(res.status).to.equal(404); - done(); - }); - }); - }); - - describe('bad request', function() { - it('should return a 400 code', done => { - request.post(`${url}/api/signup`) - .send({username: 'test name', password: '1234'}) - .end((err, res) => { - expect(err).to.be.an('error'); - expect(res.status).to.equal(400); - done(); - }); - }); - }); - }); - - describe('GET: /api/signin', function() { - before( done => { - let user = new User(exampleUser); - user.generatePasswordHash(exampleUser.password) - .then( user => user.save()) - .then( user => { - this.tempUser = user; - done(); - }) - .catch(done); - }); - - after( done => { - User.remove({}) - .then( () => done()) - .catch(done); - }); - - describe('with a valid body', function () { - it('should return a token', done => { - request.get(`${url}/api/signin`) - .auth('exampleUser', '1234') - .end((err, res) => { - if (err) return done(err); - console.log('token:', res.text); - expect(res.status).to.equal(200); - done(); - }); - }); - }); - - describe('with an invalid body', function() { - it('should return a 401', done => { - request.get(`${url}/api/signin`) - .auth('exampleUser', '9876') - .end((err, res) => { - expect(err).to.be.an('error'); - expect(res.status).to.equal(401); - done(); - }); - }); - }); - - describe('invalid GET route', function() { - it('should return a 404', done => { - request.get(`${url}/api/invalid`) - .end((err, res) => { - expect(err).to.be.an('error'); - expect(res.status).to.equal(404); - done(); - }); - }); - }); - }); -}); +// 'use strict'; +// +// const expect = require('chai').expect; +// const request = require('superagent'); +// const mongoose = require('mongoose'); +// const Promise = require('bluebird'); +// const User = require('../model/user.js'); +// +// mongoose.Promise = Promise; +// +// require('../server.js'); +// +// const url = `http://localhost:${process.env.PORT}`; +// +// const exampleUser ={ +// username: 'exampleUser', +// password: '1234', +// email: 'exampleUser@test.com' +// }; +// +// describe('Auth Routes', function() { +// describe('POST: /api/signup', function() { +// describe('with a valid username and password', function() { +// after( done => { +// User.remove({}) +// .then( () => done()) +// .catch(done); +// }); +// +// it('should return a token', done => { +// request.post(`${url}/api/signup`) +// .send(exampleUser) +// .end((err, res) => { +// if(err) return done(err); +// expect(res.status).to.equal(200); +// expect(res.text).to.be.a('string'); +// done(); +// }); +// }); +// }); +// +// describe('invalid POST route', function() { +// it('should return a 404 code', done => { +// request.post(`${url}/api/invalid`) +// .send(exampleUser) +// .end((err, res) => { +// expect(err).to.be.an('error'); +// expect(res.status).to.equal(404); +// done(); +// }); +// }); +// }); +// +// describe('with an invalid username and password', function() { +// it('should return a 400 error', done => { +// request.post(`${url}/api/signup`) +// .send({username: 'hello', password: '1234'}) +// .end((err, res) => { +// expect(err).to.be.an('error'); +// expect(res.status).to.equal(400); +// done(); +// }); +// }); +// }); +// }); +// +// describe('GET: /api/signin', function() { +// before( done => { +// let user = new User(exampleUser); +// user.generatePasswordHash(exampleUser.password) +// .then( user => user.save()) +// .then( user => { +// this.tempUser = user; +// done(); +// }) +// .catch(done); +// }); +// +// after( done => { +// User.remove({}) +// .then( () => done()) +// .catch(done); +// }); +// +// describe('with a valid username and password', function () { +// it('should return a token', done => { +// request.get(`${url}/api/signin`) +// .auth('exampleUser', '1234') +// .end((err, res) => { +// if (err) return done(err); +// console.log('token:', res.text); +// expect(res.status).to.equal(200); +// expect(res.text).to.be.a('string'); +// done(); +// }); +// }); +// }); +// +// describe('with an invalid password', function() { +// it('should return a 401', done => { +// request.get(`${url}/api/signin`) +// .auth('exampleUser', '9876') +// .end((err, res) => { +// expect(err).to.be.an('error'); +// expect(res.status).to.equal(401); +// done(); +// }); +// }); +// }); +// +// describe('invalid GET route', function() { +// it('should return a 404', done => { +// request.get(`${url}/api/invalid`) +// .end((err, res) => { +// expect(err).to.be.an('error'); +// expect(res.status).to.equal(404); +// done(); +// }); +// }); +// }); +// }); +// }); From 0f42118a9246f8e52dfeb07d6fa502dfc3d32793 Mon Sep 17 00:00:00 2001 From: Hawa Abdi Date: Wed, 4 Jan 2017 12:01:28 -0800 Subject: [PATCH 4/6] uncommented user tests --- lab-hawa/test/user-route-test.js | 244 +++++++++++++++---------------- 1 file changed, 122 insertions(+), 122 deletions(-) diff --git a/lab-hawa/test/user-route-test.js b/lab-hawa/test/user-route-test.js index ca3e761..b24d80f 100644 --- a/lab-hawa/test/user-route-test.js +++ b/lab-hawa/test/user-route-test.js @@ -1,122 +1,122 @@ -// 'use strict'; -// -// const expect = require('chai').expect; -// const request = require('superagent'); -// const mongoose = require('mongoose'); -// const Promise = require('bluebird'); -// const User = require('../model/user.js'); -// -// mongoose.Promise = Promise; -// -// require('../server.js'); -// -// const url = `http://localhost:${process.env.PORT}`; -// -// const exampleUser ={ -// username: 'exampleUser', -// password: '1234', -// email: 'exampleUser@test.com' -// }; -// -// describe('Auth Routes', function() { -// describe('POST: /api/signup', function() { -// describe('with a valid username and password', function() { -// after( done => { -// User.remove({}) -// .then( () => done()) -// .catch(done); -// }); -// -// it('should return a token', done => { -// request.post(`${url}/api/signup`) -// .send(exampleUser) -// .end((err, res) => { -// if(err) return done(err); -// expect(res.status).to.equal(200); -// expect(res.text).to.be.a('string'); -// done(); -// }); -// }); -// }); -// -// describe('invalid POST route', function() { -// it('should return a 404 code', done => { -// request.post(`${url}/api/invalid`) -// .send(exampleUser) -// .end((err, res) => { -// expect(err).to.be.an('error'); -// expect(res.status).to.equal(404); -// done(); -// }); -// }); -// }); -// -// describe('with an invalid username and password', function() { -// it('should return a 400 error', done => { -// request.post(`${url}/api/signup`) -// .send({username: 'hello', password: '1234'}) -// .end((err, res) => { -// expect(err).to.be.an('error'); -// expect(res.status).to.equal(400); -// done(); -// }); -// }); -// }); -// }); -// -// describe('GET: /api/signin', function() { -// before( done => { -// let user = new User(exampleUser); -// user.generatePasswordHash(exampleUser.password) -// .then( user => user.save()) -// .then( user => { -// this.tempUser = user; -// done(); -// }) -// .catch(done); -// }); -// -// after( done => { -// User.remove({}) -// .then( () => done()) -// .catch(done); -// }); -// -// describe('with a valid username and password', function () { -// it('should return a token', done => { -// request.get(`${url}/api/signin`) -// .auth('exampleUser', '1234') -// .end((err, res) => { -// if (err) return done(err); -// console.log('token:', res.text); -// expect(res.status).to.equal(200); -// expect(res.text).to.be.a('string'); -// done(); -// }); -// }); -// }); -// -// describe('with an invalid password', function() { -// it('should return a 401', done => { -// request.get(`${url}/api/signin`) -// .auth('exampleUser', '9876') -// .end((err, res) => { -// expect(err).to.be.an('error'); -// expect(res.status).to.equal(401); -// done(); -// }); -// }); -// }); -// -// describe('invalid GET route', function() { -// it('should return a 404', done => { -// request.get(`${url}/api/invalid`) -// .end((err, res) => { -// expect(err).to.be.an('error'); -// expect(res.status).to.equal(404); -// done(); -// }); -// }); -// }); -// }); -// }); +'use strict'; + +const expect = require('chai').expect; +const request = require('superagent'); +const mongoose = require('mongoose'); +const Promise = require('bluebird'); +const User = require('../model/user.js'); + +mongoose.Promise = Promise; + +require('../server.js'); + +const url = `http://localhost:${process.env.PORT}`; + +const exampleUser ={ + username: 'exampleUser', + password: '1234', + email: 'exampleUser@test.com' +}; + +describe('Auth Routes', function() { + describe('POST: /api/signup', function() { + describe('with a valid username and password', function() { + after( done => { + User.remove({}) + .then( () => done()) + .catch(done); + }); + + it('should return a token', done => { + request.post(`${url}/api/signup`) + .send(exampleUser) + .end((err, res) => { + if(err) return done(err); + expect(res.status).to.equal(200); + expect(res.text).to.be.a('string'); + done(); + }); + }); + }); + + describe('invalid POST route', function() { + it('should return a 404 code', done => { + request.post(`${url}/api/invalid`) + .send(exampleUser) + .end((err, res) => { + expect(err).to.be.an('error'); + expect(res.status).to.equal(404); + done(); + }); + }); + }); + + describe('with an invalid username and password', function() { + it('should return a 400 error', done => { + request.post(`${url}/api/signup`) + .send({username: 'hello', password: '1234'}) + .end((err, res) => { + expect(err).to.be.an('error'); + expect(res.status).to.equal(400); + done(); + }); + }); + }); + }); + + describe('GET: /api/signin', function() { + before( done => { + let user = new User(exampleUser); + user.generatePasswordHash(exampleUser.password) + .then( user => user.save()) + .then( user => { + this.tempUser = user; + done(); + }) + .catch(done); + }); + + after( done => { + User.remove({}) + .then( () => done()) + .catch(done); + }); + + describe('with a valid username and password', function () { + it('should return a token', done => { + request.get(`${url}/api/signin`) + .auth('exampleUser', '1234') + .end((err, res) => { + if (err) return done(err); + console.log('token:', res.text); + expect(res.status).to.equal(200); + expect(res.text).to.be.a('string'); + done(); + }); + }); + }); + + describe('with an invalid password', function() { + it('should return a 401', done => { + request.get(`${url}/api/signin`) + .auth('exampleUser', '9876') + .end((err, res) => { + expect(err).to.be.an('error'); + expect(res.status).to.equal(401); + done(); + }); + }); + }); + + describe('invalid GET route', function() { + it('should return a 404', done => { + request.get(`${url}/api/invalid`) + .end((err, res) => { + expect(err).to.be.an('error'); + expect(res.status).to.equal(404); + done(); + }); + }); + }); + }); +}); From 9903f3ee339cc08eee8d79434e8d4d99632d1ec6 Mon Sep 17 00:00:00 2001 From: Hawa Abdi Date: Thu, 5 Jan 2017 12:53:43 -0800 Subject: [PATCH 5/6] Failing tests, push for submission. --- lab-hawa/test/gallery-route-test.js | 232 ++++++++++++++++++++++++++++ lab-hawa/test/user-route-test.js | 6 +- 2 files changed, 235 insertions(+), 3 deletions(-) diff --git a/lab-hawa/test/gallery-route-test.js b/lab-hawa/test/gallery-route-test.js index 7eae731..5d0cb87 100644 --- a/lab-hawa/test/gallery-route-test.js +++ b/lab-hawa/test/gallery-route-test.js @@ -66,4 +66,236 @@ describe('Gallery Routes', function() { }); }); }); + + describe('invalid POST route', function() { + it('should return a 404 code', done => { + request.post(`${url}/api/invalid`) + .send(exampleGallery) + .end((err, res) => { + expect(err).to.be.an('error'); + expect(res.status).to.equal(404); + done(); + }); + }); + }); + + describe('GET: /api/gallery/:id', () => { + beforeEach(done => { + let user = new User(exampleUser) + .generatePasswordHash(exampleUser.password) + .then(user => { + this.tempUser = user; + return user.generateToken(); + }) + .then(token => { + this.tempToken = token; + exampleGallery.userID = this.tempUser._id; + return new Gallery(exampleGallery).save(); + }) + .then(gallery => { + this.tempGallery = gallery; + done(); + }) + .catch(done); + }); + + describe('with no ID', () => { + it('should return an array of all gallery IDs', done => { + request + .get(`${url}/api/gallery`) + .set({authorization: `Bearer ${this.tempToken}`}) + .end((err, response) => { + if (err) return done(err); + expect(response.status).to.equal(200); + expect(response.body).to.be.an('array'); + expect(response.body.length).to.be.at.least(1); + done(); + }); + }); + }); + + describe('with a valid ID', () => { + it('should return a gallery', done => { + request + .get(`${url}/api/gallery/${this.tempGallery._id}`) + .set({authorization: `Bearer ${this.tempToken}`}) + .end((err, response) => { + if (err) return done(err); + expect(response.status).to.equal(200); + expect(response.body.name).to.equal(exampleGallery.name); + expect(response.body.desc).to.equal(exampleGallery.desc); + expect(response.body.userID).to.equal(this.tempUser._id.toString()); + done(); + }); + }); + }); + + describe('with no token', () => { + it('should return a 401 unauthorized error', done => { + request + .get(`${url}/api/gallery/${this.tempGallery._id}`) + .end((err, response) => { + expect(err).to.be.an('error'); + expect(response.status).to.equal(401); + // expect(response.body.name).to.equal(undefined); + done(); + }); + }); + }); + + describe('with an invalid id', () => { + it('should return a 404 not found error', done => { + request + .get(`${url}/api/gallery/69`) + .set({authorization: `Bearer ${this.tempToken}`}) + .end((err, response) => { + expect(err).to.be.an('error'); + expect(response.status).to.equal(404); + expect(response.body.name).to.equal(undefined); + done(); + }); + }); + }); + }); + + describe('PUT: /api/gallery/:id', () => { + beforeEach(done => { + new User(exampleUser) + .generatePasswordHash(exampleUser.password) + .then(user => { + this.tempUser = user; + return user.generateToken(); + }) + .then(token => { + this.tempToken = token; + exampleGallery.userID = this.tempUser._id; + return new Gallery(exampleGallery).save(); + }) + .then(gallery => { + this.tempGallery = gallery; + done(); + }) + .catch(done); + }); + + describe('with a valid body and token', () => { + it('should return a gallery', done => { + request + .put(`${url}/api/gallery/${this.tempGallery._id}`) + .set({authorization: `Bearer ${this.tempToken}`}) + .send({name: 'New name', desc: 10}) + .end((err, response) => { + if (err) return done(err); + expect(response.status).to.equal(200); + expect(response.body.name).to.equal('New name'); + expect(response.body.desc).to.equal(10); + expect(response.body.userID).to.equal(this.tempUser._id.toString()); + done(); + }); + }); + }); + + describe('with no token provided', () => { + it('should return a 401 error', done => { + request + .put(`${url}/api/gallery/${this.tempGallery._id}`) + .send({name: 'New name', desc: 10}) + .end((err, response) => { + expect(err).to.be.an('error'); + expect(response.status).to.equal(401); + expect(response.body.name).to.equal(undefined); + done(); + }); + }); + }); + + describe('with no body provided', () => { + it('should return a 400 error', done => { + request + .put(`${url}/api/gallery/${this.tempGallery._id}`) + .set({authorization: `Bearer ${this.tempToken}`}) + .end((err, response) => { + expect(err).to.be.an('error'); + expect(response.status).to.equal(400); + expect(response.body.name).to.equal(undefined); + done(); + }); + }); + }); + + describe('with the wrong ID', () => { + it('should return a 404 not found error', done => { + request + .put(`${url}/api/gallery/69`) + .set({authorization: `Bearer ${this.tempToken}`}) + .send({name: 'New name', desc: 10}) + .end((err, response) => { + expect(err).to.be.an('error'); + expect(response.status).to.equal(404); + expect(response.body.name).to.equal(undefined); + done(); + }); + }); + }); + }); + + describe('DELETE: /api/gallery/:id', () => { + beforeEach(done => { + new User(exampleUser) + .generatePasswordHash(exampleUser.password) + .then(user => { + this.tempUser = user; + return user.generateToken(); + }) + .then(token => { + this.tempToken = token; + exampleGallery.userID = this.tempUser._id; + return new Gallery(exampleGallery).save(); + }) + .then(gallery => { + this.tempGallery = gallery; + done(); + }) + .catch(done); + }); + + describe('with a valid ID and token', () => { + it('should return a 204 status', done => { + request + .delete(`${url}/api/gallery/${this.tempGallery._id}`) + .set({authorization: `Bearer ${this.tempToken}`}) + .end((err, response) => { + if (err) return done(err); + expect(response.status).to.equal(204); + expect(response.body.name).to.equal(undefined); + done(); + }); + }); + }); + + describe('with an invalid ID', () => { + it('should return a 404 not found error', done => { + request + .delete(`${url}/api/gallery/invalid`) + .set({authorization: `Bearer ${this.tempToken}`}) + .end((err, response) => { + expect(err).to.be.an('error'); + expect(response.status).to.equal(404); + done(); + }); + }); + }); + + describe('without a token', () => { + it('should return a 401 unauthorized error', done => { + request + .delete(`${url}/api/gallery/${this.tempGallery._id}`) + .end((err, response) => { + expect(err).to.be.an('error'); + expect(response.status).to.equal(401); + done(); + }); + }); + }); + }); }); diff --git a/lab-hawa/test/user-route-test.js b/lab-hawa/test/user-route-test.js index b24d80f..aa8f857 100644 --- a/lab-hawa/test/user-route-test.js +++ b/lab-hawa/test/user-route-test.js @@ -40,7 +40,7 @@ describe('Auth Routes', function() { }); describe('invalid POST route', function() { - it('should return a 404 code', done => { + it('should return a 404 not found error', done => { request.post(`${url}/api/invalid`) .send(exampleUser) .end((err, res) => { @@ -97,7 +97,7 @@ describe('Auth Routes', function() { }); describe('with an invalid password', function() { - it('should return a 401', done => { + it('should return a 401 unauthorized error', done => { request.get(`${url}/api/signin`) .auth('exampleUser', '9876') .end((err, res) => { @@ -109,7 +109,7 @@ describe('Auth Routes', function() { }); describe('invalid GET route', function() { - it('should return a 404', done => { + it('should return a 404 not found error', done => { request.get(`${url}/api/invalid`) .end((err, res) => { expect(err).to.be.an('error'); From cfa9d1b656d6acc0fba9c1c219fc18888e29f043 Mon Sep 17 00:00:00 2001 From: Hawa Abdi Date: Sun, 5 Mar 2017 15:01:56 -0800 Subject: [PATCH 6/6] All invalid and valid tests are written --- lab-hawa/.env | 3 + lab-hawa/.gitignore | 1 + lab-hawa/model/picture.js | 16 ++ lab-hawa/package.json | 5 +- lab-hawa/route/picture-router.js | 96 ++++++++ lab-hawa/route/user-router.js | 2 - lab-hawa/server.js | 10 +- lab-hawa/test/gallery-route-test.js | 332 +++++++++++++--------------- lab-hawa/test/lib/server-toggle.js | 30 +++ lab-hawa/test/picture-route-test.js | 179 +++++++++++++++ lab-hawa/test/user-route-test.js | 52 +++-- 11 files changed, 518 insertions(+), 208 deletions(-) create mode 100644 lab-hawa/model/picture.js create mode 100644 lab-hawa/route/picture-router.js create mode 100644 lab-hawa/test/lib/server-toggle.js create mode 100644 lab-hawa/test/picture-route-test.js diff --git a/lab-hawa/.env b/lab-hawa/.env index cff2e78..236cc82 100644 --- a/lab-hawa/.env +++ b/lab-hawa/.env @@ -1,3 +1,6 @@ PORT='3000' MONGODB_URI='mongodb://localhost/cfgram' APP_SECRET='ninjaCoder' +AWS_BUCKET='codegram' +AWS_ACCESS_KEY_ID='AKIAIOH6ZWVXMF2HJNSA' +AWS_SECRET_ACCESS_KEY='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' diff --git a/lab-hawa/.gitignore b/lab-hawa/.gitignore index 43bce2d..dc7cf16 100644 --- a/lab-hawa/.gitignore +++ b/lab-hawa/.gitignore @@ -3,6 +3,7 @@ #!! ERROR: ma is undefined. Use list command to see defined gitignore types !!# node_modules/ +.env ### Node ### # Logs diff --git a/lab-hawa/model/picture.js b/lab-hawa/model/picture.js new file mode 100644 index 0000000..04eea00 --- /dev/null +++ b/lab-hawa/model/picture.js @@ -0,0 +1,16 @@ +'use strict'; + +const mongoose = require('mongoose'); +const Schema = mongoose.Schema; + +const pictureSchema = Schema({ + name: {type: String, required: true}, + desc: {type: String, required: true}, + created: {type: Date, default: Date.now}, + userID: {type: Schema.Types.ObjectId, required: true}, + galleryID: {type: Schema.Types.ObjectId, required: true}, + imageURI: {type: String, required: true, unique: true}, + objectKey: {type: String, required: true, unique: true}, +}); + +module.exports = mongoose.model('picture', pictureSchema); diff --git a/lab-hawa/package.json b/lab-hawa/package.json index 35a844d..17ba29a 100644 --- a/lab-hawa/package.json +++ b/lab-hawa/package.json @@ -22,17 +22,20 @@ }, "homepage": "https://github.com/abdih17/15-basic_auth#readme", "dependencies": { + "aws-sdk": "^2.22.0", "bcrypt": "^1.0.2", "bluebird": "^3.4.7", "body-parser": "^1.15.2", "cors": "^2.8.1", "debug": "^2.6.0", + "del": "^2.2.2", "dotenv": "^2.0.0", "express": "^4.14.0", "http-errors": "^1.5.1", "jsonwebtoken": "^7.2.1", "mongoose": "^4.7.6", - "morgan": "^1.7.0" + "morgan": "^1.7.0", + "multer": "^1.3.0" }, "devDependencies": { "chai": "^3.5.0", diff --git a/lab-hawa/route/picture-router.js b/lab-hawa/route/picture-router.js new file mode 100644 index 0000000..f77e368 --- /dev/null +++ b/lab-hawa/route/picture-router.js @@ -0,0 +1,96 @@ +'use strict'; + +const fs = require('fs'); +const path = require('path'); +const del = require('del'); +const multer = require('multer'); +const AWS = require('aws-sdk'); +const Router = require('express').Router; +const createError = require('http-errors'); +const Picture = require('../model/picture.js'); +const Gallery = require('../model/gallery.js'); +const bearerAuth = require('../lib/bearer-auth-middleware.js'); +const debug = require('debug')('cfgram:picture-router'); + +AWS.config.setPromisesDependency(require('bluebird')); + +const s3 = new AWS.S3(); +const dataDir = `${__dirname}/../data`; +const upload = multer({ dest: dataDir }); + +const pictureRouter = module.exports = Router(); + +function s3uploadProm(params) { + return new Promise((resolve, reject) => { + s3.upload(params, (err, s3data) => { + if(err) return reject(err); + resolve(s3data); + }); + }); +} + +function s3deleteProm(params) { + return new Promise((resolve, reject) => { + s3.deleteObject(params, (err, s3data) => { + if(err) return reject(err); + resolve(s3data); + }); + }); +} + +pictureRouter.post('/api/gallery/:galleryID/picture', bearerAuth, upload.single('image'), function(req, res, next) { + debug('POST: /api/gallery/:galleryID/picture'); + + if(!req.file) { + return next(createError(400, 'file not found')); + } + + if(!req.file.path) { + return next (createError(500, 'file not saved')); + } + + let ext = path.extname(req.file.originalname); + + let params = { + ACL: 'public-read', + Bucket: process.env.AWS_BUCKET, + Key: `${req.file.filename}${ext}`, + Body: fs.createReadStream(req.file.path) + }; + + Gallery.findById(req.params.galleryID) + .then( () => s3uploadProm(params)) + .then( s3data => { + del([`${dataDir}/*`]); + let pictureData = { + name: req.body.name, + desc: req.body.desc, + objectKey: s3data.Key, + imageURI: s3data.Location, + userID: req.user._id, + galleryID: req.params.galleryID + }; + return new Picture(pictureData).save(); + }) + .then( picture => res.json(picture)) + .catch( err => next(err)); +}); + +pictureRouter.delete('/api/gallery/:galleryID/picture/:pictureID', bearerAuth, function(req, res, next) { + debug('DELETE: /api/gallery/:galleryID/picture/:pictureID'); + + let ext = path.extname(req.file.originalname); + + let params = { + Bucket: process.env.AWS_BUCKET, + Key: `${req.file.filename}${ext}` + }; + + Picture.findByIdAndRemove(req.params.id) + .then( () => s3deleteProm(params)) + .then( () => { + del([`${dataDir}/*`]); + }) + .then( () => res.status(204).send()) + .catch( err => next(err)); +}); diff --git a/lab-hawa/route/user-router.js b/lab-hawa/route/user-router.js index ebcb402..a8c7e3d 100644 --- a/lab-hawa/route/user-router.js +++ b/lab-hawa/route/user-router.js @@ -2,10 +2,8 @@ const jsonParser = require('body-parser').json(); const debug = require('debug')('cfgram:auth-router'); -const createError = require('http-errors'); const Router = require('express').Router; const basicAuth = require('../lib/basic-auth-middleware.js'); -const bearerAuth = require('../lib/bearer-auth-middleware.js'); const User = require('../model/user.js'); diff --git a/lab-hawa/server.js b/lab-hawa/server.js index 974641a..5f7fab0 100644 --- a/lab-hawa/server.js +++ b/lab-hawa/server.js @@ -6,8 +6,10 @@ const dotenv = require('dotenv'); const morgan = require('morgan'); const mongoose = require('mongoose'); // const Promise = require('bluebird'); -const debug = require('debug')('cfgram:server'); +const debug = require('debug')('cfgram:server.js'); +const pictureRouter = require('./route/picture-router.js'); +const galleryRouter = require('./route/gallery-router.js'); const userRouter = require('./route/user-router.js'); const errors = require('./lib/error-middleware.js'); @@ -21,9 +23,13 @@ mongoose.connect(process.env.MONGODB_URI); app.use(cors()); app.use(morgan('dev')); +app.use(pictureRouter); +app.use(galleryRouter); app.use(userRouter); app.use(errors); -app.listen(PORT, () => { +const server = module.exports = app.listen(PORT, () => { debug('server up:', PORT); }); + +server.isRunning = true; diff --git a/lab-hawa/test/gallery-route-test.js b/lab-hawa/test/gallery-route-test.js index 5d0cb87..21a3d6f 100644 --- a/lab-hawa/test/gallery-route-test.js +++ b/lab-hawa/test/gallery-route-test.js @@ -7,23 +7,31 @@ const Promise = require('bluebird'); const User = require('../model/user.js'); const Gallery = require('../model/gallery.js'); const url = `http://localhost:${process.env.PORT}`; +const serverToggle = require('./lib/server-toggle.js'); mongoose.Promise = Promise; -require('../server.js'); +const server = require('../server.js'); const exampleUser = { - username: 'exampleUser', + username: 'tester', password: '1234', - email: 'exampleUser@test.com' + email: 'test@test.com' }; const exampleGallery = { - name: 'Example Gallery', - desc: 'test gallery description', + name: 'test gallery', + desc: 'test gallery description' }; describe('Gallery Routes', function() { + before( done => { + serverToggle.serverOn(server, done); + }); + after( done => { + serverToggle.serverOff(server,done); + }); + afterEach( done => { Promise.all([ User.remove({}), @@ -32,9 +40,8 @@ describe('Gallery Routes', function() { .then( () => done()) .catch(done); }); - describe('POST: /api/gallery', () => { - before( done => { + beforeEach( done => { new User(exampleUser) .generatePasswordHash(exampleUser.password) .then( user => user.save()) @@ -42,13 +49,12 @@ describe('Gallery Routes', function() { this.tempUser = user; return user.generateToken(); }) - .then(token => { + .then( token => { this.tempToken = token; done(); }) .catch(done); }); - it('should return a gallery', done => { request.post(`${url}/api/gallery`) .send(exampleGallery) @@ -58,6 +64,7 @@ describe('Gallery Routes', function() { .end((err, res) => { if (err) return done(err); let date = new Date(res.body.created).toString(); + expect(res.status).to.equal(200); expect(res.body.name).to.equal(exampleGallery.name); expect(res.body.desc).to.equal(exampleGallery.desc); expect(res.body.userID).to.equal(this.tempUser._id.toString()); @@ -65,236 +72,209 @@ describe('Gallery Routes', function() { done(); }); }); - }); - - describe('invalid POST route', function() { - it('should return a 404 code', done => { - request.post(`${url}/api/invalid`) + it('should return a 401 unauthorized', done => { + request.post(`${url}/api/gallery`) .send(exampleGallery) .end((err, res) => { + let date = new Date(res.body.created).toString(); expect(err).to.be.an('error'); - expect(res.status).to.equal(404); + expect(res.status).to.equal(401); + expect(date).to.equal('Invalid Date'); + done(); + }); + }); + it('should return a 400 bad request', done => { + request.post(`${url}/api/gallery`) + .send({name: 10}) + .set({ + Authorization: `Bearer ${this.tempToken}` + }) + .end((err, res) => { + let date = new Date(res.body.created).toString(); + expect(err).to.be.an('error'); + expect(res.status).to.equal(400); + expect(date).to.equal('Invalid Date'); done(); }); }); }); - describe('GET: /api/gallery/:id', () => { - beforeEach(done => { - let user = new User(exampleUser) + beforeEach( done => { + new User(exampleUser) .generatePasswordHash(exampleUser.password) - .then(user => { + .then( user => user.save()) + .then( user => { this.tempUser = user; return user.generateToken(); }) - .then(token => { + .then( token => { this.tempToken = token; - exampleGallery.userID = this.tempUser._id; - return new Gallery(exampleGallery).save(); + done(); }) - .then(gallery => { + .catch(done); + }); + beforeEach( done => { + exampleGallery.userID = this.tempUser._id.toString(); + new Gallery(exampleGallery).save() + .then( gallery => { this.tempGallery = gallery; done(); }) .catch(done); }); - - describe('with no ID', () => { - it('should return an array of all gallery IDs', done => { - request - .get(`${url}/api/gallery`) - .set({authorization: `Bearer ${this.tempToken}`}) - .end((err, response) => { - if (err) return done(err); - expect(response.status).to.equal(200); - expect(response.body).to.be.an('array'); - expect(response.body.length).to.be.at.least(1); - done(); - }); - }); + after( () => { + delete exampleGallery.userID; }); - - describe('with a valid ID', () => { - it('should return a gallery', done => { - request - .get(`${url}/api/gallery/${this.tempGallery._id}`) - .set({authorization: `Bearer ${this.tempToken}`}) - .end((err, response) => { - if (err) return done(err); - expect(response.status).to.equal(200); - expect(response.body.name).to.equal(exampleGallery.name); - expect(response.body.desc).to.equal(exampleGallery.desc); - expect(response.body.userID).to.equal(this.tempUser._id.toString()); - done(); - }); + it('should return a gallery', done => { + request.get(`${url}/api/gallery/${this.tempGallery._id}`) + .set({ + Authorization: `Bearer ${this.tempToken}` + }) + .end((err, res) => { + if(err) return done(err); + let date = new Date(res.body.created).toString(); + expect(res.status).to.equal(200); + expect(res.body.name).to.equal(exampleGallery.name); + expect(res.body.desc).to.equal(exampleGallery.desc); + expect(res.body.userID).to.equal(this.tempUser._id.toString()); + expect(date).to.not.equal('Invalid Date'); + done(); }); }); - - describe('with no token', () => { - it('should return a 401 unauthorized error', done => { - request - .get(`${url}/api/gallery/${this.tempGallery._id}`) - .end((err, response) => { - expect(err).to.be.an('error'); - expect(response.status).to.equal(401); - // expect(response.body.name).to.equal(undefined); - done(); - }); + it('should return a 401', done => { + request.get(`${url}/api/gallery/${this.tempGallery._id}`) + .end((err, res) => { + expect(err).to.be.an('error'); + expect(res.status).to.equal(401); + done(); }); }); - - describe('with an invalid id', () => { - it('should return a 404 not found error', done => { - request - .get(`${url}/api/gallery/69`) - .set({authorization: `Bearer ${this.tempToken}`}) - .end((err, response) => { - expect(err).to.be.an('error'); - expect(response.status).to.equal(404); - expect(response.body.name).to.equal(undefined); - done(); - }); + it('should return a 404', done => { + request.get(`${url}/api/gallery/586d2d44e61cdb0a8bdd1c69`) + .set({ + Authorization: `Bearer ${this.tempToken}` + }) + .end((err, res) => { + expect(err).to.be.an('error'); + expect(res.status).to.equal(404); + done(); }); }); }); - describe('PUT: /api/gallery/:id', () => { - beforeEach(done => { + beforeEach( done => { new User(exampleUser) .generatePasswordHash(exampleUser.password) - .then(user => { + .then( user => user.save()) + .then( user => { this.tempUser = user; return user.generateToken(); }) - .then(token => { + .then( token => { this.tempToken = token; - exampleGallery.userID = this.tempUser._id; - return new Gallery(exampleGallery).save(); + done(); }) - .then(gallery => { + .catch(done); + }); + beforeEach( done => { + exampleGallery.userID = this.tempUser._id.toString(); + new Gallery(exampleGallery).save() + .then( gallery => { this.tempGallery = gallery; done(); }) .catch(done); }); - - describe('with a valid body and token', () => { - it('should return a gallery', done => { - request - .put(`${url}/api/gallery/${this.tempGallery._id}`) - .set({authorization: `Bearer ${this.tempToken}`}) - .send({name: 'New name', desc: 10}) - .end((err, response) => { - if (err) return done(err); - expect(response.status).to.equal(200); - expect(response.body.name).to.equal('New name'); - expect(response.body.desc).to.equal(10); - expect(response.body.userID).to.equal(this.tempUser._id.toString()); - done(); - }); + after( () => { + delete exampleGallery.userID; + }); + it('should update gallery', done => { + request.put(`${url}/api/gallery/${this.tempGallery._id}`) + .send({name: 'update name', desc: 'update desc'}) + .set({ + Authorization: `Bearer ${this.tempToken}` + }) + .end((err, res) => { + if(err) return done(err); + let date = new Date(res.body.created).toString(); + expect(res.body.name).to.equal('update name'); + expect(res.body.desc).to.equal('update desc'); + expect(res.body.userID).to.equal(this.tempUser._id.toString()); + expect(date).to.not.equal('Invalid Date'); + done(); }); }); - - describe('with no token provided', () => { - it('should return a 401 error', done => { - request - .put(`${url}/api/gallery/${this.tempGallery._id}`) - .send({name: 'New name', desc: 10}) - .end((err, response) => { - expect(err).to.be.an('error'); - expect(response.status).to.equal(401); - expect(response.body.name).to.equal(undefined); - done(); - }); + it('should return 401', done => { + request.put(`${url}/api/gallery/${this.tempGallery._id}`) + .send({name: 'update name', desc: 'update desc'}) + .end((err, res) => { + expect(err).to.be.an('error'); + expect(res.status).to.equal(401); + done(); }); }); - - describe('with no body provided', () => { - it('should return a 400 error', done => { - request - .put(`${url}/api/gallery/${this.tempGallery._id}`) - .set({authorization: `Bearer ${this.tempToken}`}) - .end((err, response) => { - expect(err).to.be.an('error'); - expect(response.status).to.equal(400); - expect(response.body.name).to.equal(undefined); - done(); - }); + it('should return 400', done => { + request.put(`${url}/api/gallery/${this.tempGallery._id}`) + .send({blah: 'blah'}) + .set({ + Authorization: `Bearer ${this.tempToken}` + }) + .end((err, res) => { + expect(err).to.be.an('error'); + expect(res.status).to.equal(400); + done(); }); }); - - describe('with the wrong ID', () => { - it('should return a 404 not found error', done => { - request - .put(`${url}/api/gallery/69`) - .set({authorization: `Bearer ${this.tempToken}`}) - .send({name: 'New name', desc: 10}) - .end((err, response) => { - expect(err).to.be.an('error'); - expect(response.status).to.equal(404); - expect(response.body.name).to.equal(undefined); - done(); - }); + it('should return 404', done => { + request.put(`${url}/api/gallery/586d2d44e61cdb0a8bdd1c69`) + .send(exampleGallery) + .set({ + Authorization: `Bearer ${this.tempToken}` + }) + .end((err, res) => { + expect(err).to.be.an('error'); + expect(res.status).to.equal(404); + done(); }); }); }); - describe('DELETE: /api/gallery/:id', () => { - beforeEach(done => { + before( done => { new User(exampleUser) .generatePasswordHash(exampleUser.password) - .then(user => { + .then( user => user.save()) + .then( user => { this.tempUser = user; return user.generateToken(); }) - .then(token => { + .then( token => { this.tempToken = token; - exampleGallery.userID = this.tempUser._id; - return new Gallery(exampleGallery).save(); + done(); }) - .then(gallery => { + .catch(done); + }); + before( done => { + exampleGallery.userID = this.tempUser._id.toString(); + new Gallery(exampleGallery).save() + .then( gallery => { this.tempGallery = gallery; done(); }) .catch(done); }); - - describe('with a valid ID and token', () => { - it('should return a 204 status', done => { - request - .delete(`${url}/api/gallery/${this.tempGallery._id}`) - .set({authorization: `Bearer ${this.tempToken}`}) - .end((err, response) => { - if (err) return done(err); - expect(response.status).to.equal(204); - expect(response.body.name).to.equal(undefined); - done(); - }); - }); - }); - - describe('with an invalid ID', () => { - it('should return a 404 not found error', done => { - request - .delete(`${url}/api/gallery/invalid`) - .set({authorization: `Bearer ${this.tempToken}`}) - .end((err, response) => { - expect(err).to.be.an('error'); - expect(response.status).to.equal(404); - done(); - }); - }); + after( () => { + delete exampleGallery.userID; }); - - describe('without a token', () => { - it('should return a 401 unauthorized error', done => { - request - .delete(`${url}/api/gallery/${this.tempGallery._id}`) - .end((err, response) => { - expect(err).to.be.an('error'); - expect(response.status).to.equal(401); - done(); - }); + it('should delete a gallery', done => { + request.delete(`${url}/api/gallery/${this.tempGallery._id}`) + .set({ + Authorization: `Bearer ${this.tempToken}` + }) + .end((err, res) => { + if(err) return done(err); + expect(res.status).to.equal(204); + expect(res.body).to.be.empty; + done(); }); }); }); diff --git a/lab-hawa/test/lib/server-toggle.js b/lab-hawa/test/lib/server-toggle.js new file mode 100644 index 0000000..977b496 --- /dev/null +++ b/lab-hawa/test/lib/server-toggle.js @@ -0,0 +1,30 @@ +'use strict'; + +const debug = require('debug')('cfgram:server-toggle'); + +module.exports = exports = {}; + +exports.serverOn = function(server, done) { + if(!server.isRunning) { + server.listen(process.env.PORT, () => { + server.isRunning = true; + debug('Server up.'); + done(); + }); + return; + } + done(); +}; + +exports.serverOff = function(server, done) { + if(server.isRunning) { + server.close( err => { + if (err) return done(err); + server.isRunning = false; + debug('Server down.'); + done(); + }); + return; + } + done(); +}; diff --git a/lab-hawa/test/picture-route-test.js b/lab-hawa/test/picture-route-test.js new file mode 100644 index 0000000..3a95b02 --- /dev/null +++ b/lab-hawa/test/picture-route-test.js @@ -0,0 +1,179 @@ +'use strict'; + +const expect = require('chai').expect; +const request = require('superagent'); +const debug = require('debug')('cfgram:picture-route-test'); + +const Picture = require('../model/picture.js'); +const User = require('../model/user.js'); +const Gallery = require('../model/gallery.js'); + +const serverToggle = require('./lib/server-toggle.js'); +const server = require('../server.js'); + +const url = `http://localhost:${process.env.PORT}`; + +const exampleUser = { + username: 'exampleName', + password: '1234', + email: 'exampleuser@test.com' +}; + +const exampleGallery = { + name: 'test gallery', + desc: 'test gallery description' +}; + +const examplePicture = { + name: 'example picture', + desc: 'example picture description', + image: `${__dirname}/data/tester.png` +}; + +describe('Picture Routes', function() { + before( done => { + serverToggle.serverOn(server, done); + }); + after( done => { + serverToggle.serverOff(server, done); + }); + + afterEach( done => { + Promise.all([ + Picture.remove({}), + User.remove({}), + Gallery.remove({}) + ]) + .then( () => { + console.log('afterEach'); + done(); + }) + .catch(done); + }); + + describe('POST: /api/gallery/:galleryID/picture', function() { + describe('with a valid token and valid data', function() { + before( done => { + new User ({ + username: 'blah', + password: '1234', + email: 'exampleuser@test.com' + }) + .generatePasswordHash(exampleUser.password) + .then( user => user.save()) + .then( user => { + this.tempUser = user; + return user.generateToken(); + }) + .then( token => { + this.tempToken = token; + done(); + }) + .catch(done); + }); + before( done => { + exampleGallery.userID = this.tempUser._id.toString(); + new Gallery(exampleGallery).save() + .then( gallery => { + this.tempGallery = gallery; + done(); + }) + .catch(done); + }); + + after( done => { + Promise.all([ + Picture.remove({}), + User.remove({}), + Gallery.remove({}) + ]) + .then( () => { + console.log('afterEach'); + done(); + }) + .catch(done); + }); + + it('should return a picture', done => { + request.post(`${url}/api/gallery/${this.tempGallery._id}/picture`) + .set({ + Authorization: `Bearer ${this.tempToken}` + }) + .field('name', examplePicture.name) + .field('desc', examplePicture.desc) + .attach('image', examplePicture.image) + .end((err, res) =>{ + if(err) return done(err); + expect(res.body.name).to.equal(examplePicture.name); + expect(res.body.desc).to.equal(examplePicture.desc); + expect(res.body.galleryID).to.equal(this.tempGallery._id.toString()); + done(); + }); + }); + }); + }); + describe('DELETE: /api/gallery/:galleryID/picture/:pictureID', function() { + describe('with a valid id', function() { + before( done => { + new User ({ + username: 'blerg', + password: '1234', + email: 'exampleuser@test.com' + }) + .generatePasswordHash(exampleUser.password) + .then( user => user.save()) + .then( user => { + this.tempUser = user; + return user.generateToken(); + }) + .then( token => { + this.tempToken = token; + done(); + }) + .catch(done); + }); + before( done => { + exampleGallery.userID = this.tempUser._id.toString(); + new Gallery(exampleGallery).save() + .then( gallery => { + this.tempGallery = gallery; + done(); + }) + .catch(done); + }); + before( done => { + examplePicture.userID = this.tempUser._id.toString(); + new Picture(examplePicture).save() + .then( picture => { + this.tempPicture = picture; + done(); + }) + .catch(done); + }); + + after( done => { + Promise.all([ + Picture.remove({}), + User.remove({}), + Gallery.remove({}) + ]) + .then( () => { + done(); + }) + .catch(done); + }); + it('should delete a picture', done => { + request.delete(`${url}/api/gallery/${this.tempGallery._id}/picture/${this.tempPicture._id}`) + .set({ + Authorization: `Bearer ${this.tempToken}` + }) + .send({Bucket: process.env.AWS_BUCKET, Key: this.tempPictureture.objectkey}) + .end((err, res) => { + if(err) return done(err); + expect(res.status).to.equal(204); + done(); + }); + }); + }); + }); +}); diff --git a/lab-hawa/test/user-route-test.js b/lab-hawa/test/user-route-test.js index aa8f857..53114e4 100644 --- a/lab-hawa/test/user-route-test.js +++ b/lab-hawa/test/user-route-test.js @@ -5,28 +5,35 @@ const request = require('superagent'); const mongoose = require('mongoose'); const Promise = require('bluebird'); const User = require('../model/user.js'); +const serverToggle = require('./lib/server-toggle.js'); mongoose.Promise = Promise; -require('../server.js'); +const server = require('../server.js'); const url = `http://localhost:${process.env.PORT}`; -const exampleUser ={ - username: 'exampleUser', +const exampleUser = { + username: 'exampleuser', password: '1234', - email: 'exampleUser@test.com' + email: 'exampleuser@test.com' }; describe('Auth Routes', function() { + before( done => { + serverToggle.serverOn(server, done); + }); + after( done => { + serverToggle.serverOff(server, done); + }); + describe('POST: /api/signup', function() { - describe('with a valid username and password', function() { + describe('with a valid body', function() { after( done => { User.remove({}) .then( () => done()) .catch(done); }); - it('should return a token', done => { request.post(`${url}/api/signup`) .send(exampleUser) @@ -38,9 +45,8 @@ describe('Auth Routes', function() { }); }); }); - describe('invalid POST route', function() { - it('should return a 404 not found error', done => { + it('should return a 404 code', done => { request.post(`${url}/api/invalid`) .send(exampleUser) .end((err, res) => { @@ -50,11 +56,10 @@ describe('Auth Routes', function() { }); }); }); - - describe('with an invalid username and password', function() { - it('should return a 400 error', done => { + describe('bad request', function() { + it('should return a 400 code', done => { request.post(`${url}/api/signup`) - .send({username: 'hello', password: '1234'}) + .send({username: 'test name', password: '1234'}) .end((err, res) => { expect(err).to.be.an('error'); expect(res.status).to.equal(400); @@ -63,7 +68,6 @@ describe('Auth Routes', function() { }); }); }); - describe('GET: /api/signin', function() { before( done => { let user = new User(exampleUser); @@ -75,31 +79,26 @@ describe('Auth Routes', function() { }) .catch(done); }); - after( done => { User.remove({}) .then( () => done()) .catch(done); }); - - describe('with a valid username and password', function () { + describe('with a valid body', function() { it('should return a token', done => { request.get(`${url}/api/signin`) - .auth('exampleUser', '1234') + .auth('exampleuser', '1234') .end((err, res) => { - if (err) return done(err); - console.log('token:', res.text); + if(err) return done(err); expect(res.status).to.equal(200); - expect(res.text).to.be.a('string'); done(); }); }); }); - - describe('with an invalid password', function() { - it('should return a 401 unauthorized error', done => { + describe('with an invalid body', function() { + it('should return a 401', done => { request.get(`${url}/api/signin`) - .auth('exampleUser', '9876') + .auth('exampleuser', '9876') .end((err, res) => { expect(err).to.be.an('error'); expect(res.status).to.equal(401); @@ -107,10 +106,9 @@ describe('Auth Routes', function() { }); }); }); - describe('invalid GET route', function() { - it('should return a 404 not found error', done => { - request.get(`${url}/api/invalid`) + it('should return a 404', done => { + request.get(`${url}/api/biscuit`) .end((err, res) => { expect(err).to.be.an('error'); expect(res.status).to.equal(404);