diff --git a/stefanie-hansen/.eslintignore b/stefanie-hansen/.eslintignore new file mode 100644 index 0000000..5b88cef --- /dev/null +++ b/stefanie-hansen/.eslintignore @@ -0,0 +1,5 @@ +**/node_modules/* +**/vendor/* +**/*.min.js +/*.md +/package.json diff --git a/stefanie-hansen/.eslintrc b/stefanie-hansen/.eslintrc new file mode 100644 index 0000000..60c9f49 --- /dev/null +++ b/stefanie-hansen/.eslintrc @@ -0,0 +1,41 @@ +{ +rules: { +no-console: 0, +indent: [ +2, +2 +], +quotes: [ +2, +"single" +], +linebreak-style: [ +2, +"unix" +], +semi: [ +2, +"always" +] +}, +env: { +es6: true, +node: true, +browser: true, +mocha: true +}, +globals: { +describe: false, +it: false, +beforeEach: false, +afterEach: false, +before: false, +after: false +}, +ecmaFeatures: { +modules: true, +experimentalObjectRestSpread: true, +impliedStrict: true +}, +extends: "eslint:recommended" +} diff --git a/stefanie-hansen/.gitignore b/stefanie-hansen/.gitignore new file mode 100644 index 0000000..800b29c --- /dev/null +++ b/stefanie-hansen/.gitignore @@ -0,0 +1,86 @@ + +# application specific +db/ + +# Created by https://www.gitignore.io/api/node,osx,vim + +### Node ### +# Logs +logs +*.log +npm-debug.log* + +# Runtime data +pids +*.pid +*.seed + +# 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 REPL history +.node_repl_history + + +### OSX ### +*.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 + + +### Vim ### +# swap +[._]*.s[a-w][a-z] +[._]s[a-w][a-z] +# session +Session.vim +# temporary +.netrwhist +*~ +# auto-generated tag files +tags diff --git a/stefanie-hansen/README.md b/stefanie-hansen/README.md new file mode 100644 index 0000000..bb8e157 --- /dev/null +++ b/stefanie-hansen/README.md @@ -0,0 +1 @@ +## Authenticated two-resource REST API diff --git a/stefanie-hansen/gulpfile.js b/stefanie-hansen/gulpfile.js new file mode 100644 index 0000000..8d1e7ed --- /dev/null +++ b/stefanie-hansen/gulpfile.js @@ -0,0 +1,62 @@ +const gulp = require('gulp'); +const mocha = require('gulp-mocha'); +const lint = require('gulp-eslint'); +const opts = { + 'extends': 'eslint:recommended', + 'ecmaFeatures': { + 'modules': true + }, + 'rules': { + 'no-alert': 0, + 'no-bitwise': 0, + 'camelcase': 1, + 'no-console': 1, + 'curly': 1, + 'eqeqeq': 0, + 'no-eq-null': 0, + 'guard-for-in': 1, + 'no-empty': 1, + 'no-use-before-define': 0, + 'no-obj-calls': 2, + 'no-unused-vars': 0, + 'new-cap': 1, + 'no-shadow': 0, + 'strict': 1, + 'no-invalid-regexp': 2, + 'comma-dangle': 2, + 'no-undef': 1, + 'no-new': 1, + 'no-extra-semi': 1, + 'no-debugger': 2, + 'no-caller': 1, + 'semi': 1, + 'quotes': 0, + 'no-unreachable': 2 + }, + 'globals': { + '$': false + }, + 'env': { + 'node': true, + 'es6': true + } +}; + + +gulp.task('linter', () => { + return gulp.src(['./*.js', './model/*.js', './route/*.js', './test/*.js', './lib/*.js']) + .pipe(lint(opts)) + .pipe(lint.format()); +}); + +gulp.task('tests', () => { + return gulp.src(['./test/*.js'], {read: false}) + .pipe(mocha({reporter: 'nyan'})); +}); + +gulp.task('watch', () => { + gulp.watch(['./*.js', './model/*.js', './route/*.js', './test/*.js', './lib/*.js'], ['linter', 'tests']); +}); + +gulp.task('default', ['linter', 'tests', 'watch'], () => { +}); diff --git a/stefanie-hansen/lib/basic-auth.js b/stefanie-hansen/lib/basic-auth.js new file mode 100644 index 0000000..8de30dc --- /dev/null +++ b/stefanie-hansen/lib/basic-auth.js @@ -0,0 +1,18 @@ +'use strict'; + +module.exports = function(req, res, next) { + let authString = req.headers.authorization.split(' ').pop(); + let userBuf = new Buffer(authString, 'base64'); + let userArr = userBuf.toString().split(':'); + userBuf.fill(0); + + req.auth = { + username: userArr[0], + password: userArr[1] + }; + + if (!req.auth.username || !req.auth.password) { + return next(new Error('Username or Password missing')); + } + next(); +}; diff --git a/stefanie-hansen/lib/jwt-auth.js b/stefanie-hansen/lib/jwt-auth.js new file mode 100644 index 0000000..57c6871 --- /dev/null +++ b/stefanie-hansen/lib/jwt-auth.js @@ -0,0 +1,22 @@ +'use strict'; + +const jwt = require('jsonwebtoken'); +const User = require('../model/user'); +const secret = process.env.SECRET || 'testPass'; + +module.exports = function(req, res, next) { + let token = req.headers.token || req.body.token; + if (!token) return next(new Error('No token provided')); + + try { + token = jwt.verify(token, secret); + } catch(err) { + return next(new Error('Invalid token')); + } + + User.findOne({_id: token}, (err, user) => { + if (err) return next(new Error('Cannot find user')); + req.user = user; + next(); + }); +}; diff --git a/stefanie-hansen/model/plant.js b/stefanie-hansen/model/plant.js new file mode 100644 index 0000000..8651144 --- /dev/null +++ b/stefanie-hansen/model/plant.js @@ -0,0 +1,14 @@ +'use strict'; + +const mongoose = require('mongoose'); +mongoose.Promise = require('bluebird'); + +const Plant = mongoose.Schema({ + commonName: {type: String, required: true}, + scientificName: {type: String, required: true}, + medicinalUses: {type: Array, required: true}, + nutritionalValue: {type: Array, required: true}, + zone: {type: Number, required: true} +}); + +module.exports = mongoose.model('plant', Plant); diff --git a/stefanie-hansen/model/supplement.js b/stefanie-hansen/model/supplement.js new file mode 100644 index 0000000..e88ce21 --- /dev/null +++ b/stefanie-hansen/model/supplement.js @@ -0,0 +1,12 @@ +'use strict'; + +const mongoose = require('mongoose'); +mongoose.Promise = require('bluebird'); + +const Supplement = mongoose.Schema({ + name: {type: String, required: true}, + medicinalEffects: {type: Array, required: true}, + sideEffects: {type: Array, required: false} +}); + +module.exports = mongoose.model('supplement', Supplement); diff --git a/stefanie-hansen/model/user.js b/stefanie-hansen/model/user.js new file mode 100644 index 0000000..4279916 --- /dev/null +++ b/stefanie-hansen/model/user.js @@ -0,0 +1,26 @@ +'use strict'; + +const mongoose = require('mongoose'); +mongoose.Promise = require('bluebird'); +const bcrypt = require('bcrypt'); +const jwt = require('jsonwebtoken'); +const secret = process.env.SECRET || 'testPass'; + +const User = new mongoose.Schema({ + username: {type: String, required: true}, + password: {type: String, required: true} +}); + +User.methods.hashPassword = function() { + return bcrypt.hashSync(this.password, 8); +}; + +User.methods.comparePassword = function(password) { + return bcrypt.compareSync(password, this.password); +}; + +User.methods.generateToken = function() { + return jwt.sign({_id: this._id}, secret); +}; + +module.exports = mongoose.model('user', User); diff --git a/stefanie-hansen/package.json b/stefanie-hansen/package.json new file mode 100644 index 0000000..c8d3abb --- /dev/null +++ b/stefanie-hansen/package.json @@ -0,0 +1,36 @@ +{ + "name": "stefanie-hansen", + "version": "1.0.0", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1", + "start": "node server.js" + }, + "keywords": [], + "author": "", + "license": "ISC", + "dependencies": { + "bcrypt": "^0.8.6", + "express": "^4.13.4", + "jsonwebtoken": "^7.0.0", + "mongoose": "^4.4.19" + }, + "devDependencies": { + "body-parser": "^1.15.1", + "chai": "^3.5.0", + "chai-http": "^2.0.1", + "eslint": "^2.10.2", + "eslint-config-standard": "^5.3.1", + "eslint-plugin-promise": "^1.1.0", + "eslint-plugin-standard": "^1.3.2", + "gulp": "^3.9.1", + "gulp-eslint": "^2.0.0", + "gulp-mocha": "^2.2.0", + "mocha": "^2.5.2", + "morgan": "^1.7.0" + }, + "directories": { + "test": "test" + }, + "description": "" +} diff --git a/stefanie-hansen/route/auth-routes.js b/stefanie-hansen/route/auth-routes.js new file mode 100644 index 0000000..0935b3c --- /dev/null +++ b/stefanie-hansen/route/auth-routes.js @@ -0,0 +1,31 @@ +'use strict'; + +const express = require('express'); +const bodyParser = require('body-parser').json(); +const basicAuth = require('../lib/basic-auth'); +const User = require('../model/user'); +const router = module.exports = express.Router(); + +router.get('/login', basicAuth, (req, res, next) => { + let username = req.auth.username; + User.findOne({username}, (err, user) => { + if (err || !user) return next(new Error('Cannot find user')); + if (!user.comparePassword(req.auth.password)) { + return next(new Error('Invalid password')); + } + return res.json({token: user.generateToken()}); + }); +}); + +router.post('/signup', bodyParser, (req, res, next) => { + let newUser = new User(req.body); + newUser.password = newUser.hashPassword(); + req.body.password = null; + User.findOne({username: req.body.username}, (err, user) => { + if (err || user) return next(new Error('Could not create user')); + newUser.save((err, user) => { + if (err) return next(new Error('Could not create user')); + res.json({token: user.generateToken()}); + }); + }); +}); diff --git a/stefanie-hansen/route/plant-routes.js b/stefanie-hansen/route/plant-routes.js new file mode 100644 index 0000000..7b9e16d --- /dev/null +++ b/stefanie-hansen/route/plant-routes.js @@ -0,0 +1,71 @@ +'use strict'; + +const express = require('express'); +const router = express.Router(); +const Plant = require('../model/plant'); +const jwtAuth = require('../lib/jwt-auth'); + +router.all('/zones', (req, res, next) => { + let minZone = 100; + let maxZone = 0; + Plant.find({}, (err, plants) => { + if (err) return next(err); + plants.forEach((plant) => { + if (plant.zone < minZone) minZone = plant.zone; + if (plant.zone > maxZone) maxZone = plant.zone; + }); + res.send(`The range of zones represented in the database includes ${minZone} - ${maxZone}`); + }); +}); + +router.get('/', (req, res, next) => { + Plant.find({}, (err, data) => { + if (err) return next(err); + else res.json(data); + }); +}); + +router.put('/', (req, res, next) => { + if (!req.body) return res.sendStatus(400); + let _id = req.body._id; + Plant.findOneAndUpdate({_id}, req.body, (err) => { + if (err) return next(err); + return res.json({Message:'Successfully updated'}); + }); +}); + +router.post('/', (req, res, next) => { + if (!req.body) return res.sendStatus(400); + else { + Plant.findOne( + { + commonName: req.body.commonName, + scientificName: req.body.scientificName + }, (err, plant) => { + if (err) return next(err); + else { + if (!plant) { + let newPlant = new Plant(req.body); + newPlant.save((err, data) => { + if (err) return next(err); + else return res.json(data); + }); + } else { + return res.sendStatus(400); + } + } + }); + } +}); + +router.delete('/:id', jwtAuth, (req, res, next) => { + let _id = req.params.id; + Plant.findOneAndRemove({_id}, null, (err) => { + if (err) return next(err); + else { + return res.send(`Deleted plant with ID of ${req.params.id}`); + } + }); +}); + +module.exports = router; diff --git a/stefanie-hansen/route/supplement-routes.js b/stefanie-hansen/route/supplement-routes.js new file mode 100644 index 0000000..57580dc --- /dev/null +++ b/stefanie-hansen/route/supplement-routes.js @@ -0,0 +1,59 @@ +'use strict'; + +const express = require('express'); +const router = express.Router(); +const Supplement = require('../model/supplement'); +const jwtAuth = require('../lib/jwt-auth'); + +router.get('/', (req, res, next) => { + Supplement.find({}, (err, data) => { + if (err) return next(err); + else res.json(data); + }); +}); + +router.put('/', (req, res, next) => { + if (!req.body) return res.sendStatus(400); + let _id = req.body._id; + Supplement.findOneAndUpdate({_id}, req.body, (err) => { + if (err) return next(err); + return res.json({Message:'Successfully updated'}); + }); +}); + +router.post('/', (req, res, next) => { + if (!req.body) return res.sendStatus(400); + else { + Supplement.findOne( + { + name: req.body.name, + medicinalEffects: req.body.medicinalEffects, + sideEffects: req.body.sideEffects + }, (err, supplement) => { + if (err) return next(err); + else { + if (!supplement) { + let newSupplement = new Supplement(req.body); + newSupplement.save((err, data) => { + if (err) return next(err); + else return res.json(data); + }); + } else { + return res.sendStatus(400); + } + } + }); + } +}); + +router.delete('/:id', jwtAuth, (req, res, next) => { + let _id = req.params.id; + Supplement.findOneAndRemove({_id}, null, (err) => { + if (err) return next(err); + else { + return res.send(`Deleted supplement with ID of ${req.params.id}`); + } + }); +}); + +module.exports = router; diff --git a/stefanie-hansen/server.js b/stefanie-hansen/server.js new file mode 100644 index 0000000..f40bd46 --- /dev/null +++ b/stefanie-hansen/server.js @@ -0,0 +1,35 @@ +'use strict'; + +const app = require('express')(); +const bodyParser = require('body-parser').json(); +const mongoose = require('mongoose'); +const morgan = require('morgan'); +const plantRouter = require('./route/plant-routes'); +const supplementRouter = require('./route/supplement-routes'); +const authRouter = require('./route/auth-routes'); + +const dbPort = process.env.MONGOLAB_URI || 'mongodb://localhost/dev_db'; +mongoose.connect(dbPort); + +app.use(morgan('dev')); + +app.use(bodyParser); + +app.use('/plants', plantRouter); + +app.use('/supplements', supplementRouter); + +app.use('/', authRouter); + +app.all('*', (req, res) => { + res.status(404).json({Message:'Not Found'}); +}); + +app.use((err, req, res, next) => { + res.send('Error: ', err.message); + next(err); +}); + +app.listen(3000, () => { + console.log('listening on 3000'); +}); diff --git a/stefanie-hansen/test/auth-test.js b/stefanie-hansen/test/auth-test.js new file mode 100644 index 0000000..5f355f8 --- /dev/null +++ b/stefanie-hansen/test/auth-test.js @@ -0,0 +1,125 @@ +'use strict'; + +const chai = require('chai'); +const chaiHttp = require('chai-http'); +chai.use(chaiHttp); +const expect = chai.expect; +const request = require('chai').request; +const mongoose = require('mongoose'); +const basicAuth = require('../lib/basic-auth'); +const jwtAuth = require('../lib/jwt-auth'); +const dbPort = process.env.MONGOLAB_URI; + +process.env.MONGOLAB_URI = 'mongodb://localhost/test_db'; +require('../server'); + +describe('unit tests', () => { + let authString; + let baseString; + let req; + let token; + + before((done) => { + request('localhost:3000') + .post('/signup') + .send({username:'test', password:'test'}) + .end((err, res) => { + token = res.body.token; + done(); + }); + }); + + it('should decode a basic auth string into username and password', () => { + + baseString = new Buffer('user:pass').toString('base64'); + authString = 'Basic ' + baseString; + req = { + headers: { + authorization: authString + } + }; + + basicAuth(req, {}, () => { + expect(req.auth).to.eql({username: 'user', password: 'pass'}); + }); + }); + + it('should find a user given a token for JWT authorization', (done) => { + + req = { + headers: { + token: token + } + }; + + jwtAuth(req, null, () => { + expect(req).to.have.property('user'); + expect(req.user.username).to.eql('test'); + done(); + }); + }); + + it('should error on invalid token', (done) => { + req = { + headers: { + token: 'invalid' + } + }; + + jwtAuth(req, null, (err) => { + expect(err.message).to.eql('Invalid token'); + done(); + }); + + }); + + + describe('auth route tests', () => { + + after((done)=> { + process.env.MONGOLAB_URI = dbPort; + mongoose.connection.db.dropDatabase(() => { + done(); + }); + }); + + it('should sign up a new user', (done) => { + request('localhost:3000') + .post('/signup') + .send({username:'test2', password:'test2'}) + .end((err, res) => { + token = res.body.token; + expect(err).to.eql(null); + expect(res).to.have.status(200); + expect(typeof token).to.eql('string'); + done(); + }); + }); + + it('should sign in a user with a token', (done) => { + request('localhost:3000') + .get('/login') + .auth('test2', 'test2') + .end((err, res) => { + expect(err).to.eql(null); + expect(res).to.have.status(200); + expect(res.body.token).to.eql(token); + done(); + }); + }); + }); +}); + +describe('catch all test', () => { + + it('should give an error for unsupported routes', (done) => { + request('localhost:3000') + .get('/test') + .end((err, res) => { + expect(err).to.not.eql(null); + expect(res).to.have.status(404); + expect(res.body).to.eql({Message: 'Not Found'}); + done(); + }); + }); +}); diff --git a/stefanie-hansen/test/plant-test.js b/stefanie-hansen/test/plant-test.js new file mode 100644 index 0000000..ef1e910 --- /dev/null +++ b/stefanie-hansen/test/plant-test.js @@ -0,0 +1,186 @@ +'use strict'; + +const chai = require('chai'); +const chaiHTTP = require('chai-http'); +chai.use(chaiHTTP); +const Plant = require('../model/plant'); +const mongoose = require('mongoose'); + +const expect = chai.expect; +const request = chai.request; + +const dbPort = process.env.MONGLAB_URI; +require('../server'); + +describe('Plant router tests', () => { + + after((done) => { + process.env.MONGOLAB_URI = dbPort; + mongoose.connection.db.dropDatabase(() => { + done(); + }); + }); + + describe('Catch all test', () => { + + it('should respond to a request to a random route with an error', (done) => { + request('localhost:3000') + .get('/test') + .end((err, res) => { + expect(err).to.not.eql(null); + expect(res).to.have.status(404); + done(); + }); + }); + }); + + describe('tests that don\'t need data', () => { + it('should get a list of Plants', (done) => { + request('localhost:3000') + .get('/plants') + .end((err, res) => { + expect(err).to.eql(null); + expect(res).to.have.status(200); + expect(Array.isArray(res.body)).to.eql(true); + done(); + }); + }); + + it('should post a plant', (done) => { + request('localhost:3000') + .post('/plants') + .send( + { + commonName:'test', + scientificName:'testus maximus', + medicinalUses: ['test', 'test'], + nutritionalValue: ['test'], + zone: 2 + }) + .end((err, res) => { + expect(err).to.eql(null); + expect(res).to.have.status(200); + expect(res.body.commonName).to.eql('test'); + expect(res.body.scientificName).to.eql('testus maximus'); + expect(res.body.medicinalUses).to.eql(['test', 'test']); + expect(res.body.nutritionalValue).to.eql(['test']); + expect(res.body.zone).to.eql(2); + done(); + }); + }); + + it('should respond with an error if an attempt is made to post a duplicate Plant', (done) => { + request('localhost:3000') + .post('/plants') + .send( + { + commonName:'test', + scientificName:'testus maximus', + medicinalUses: ['test', 'test'], + nutritionalValue: ['test'], + zone: 2 + }) + .end((err, res) => { + expect(err).to.not.eql(null); + expect(res).to.have.status(400); + done(); + }); + }); + }); + + describe('tests that need data', () => { + let testPlant; + let testPlant2; + let testPlant3; + let token; + + before((done) => { + request('localhost:3000') + .post('/signup') + .send({username:'test', password:'test'}) + .end((err, res) => { + token = res.body.token; + done(); + }); + }); + + beforeEach((done) => { + testPlant = new Plant({ + commonName:'test', + scientificName:'testus maximus', + medicinalUses: ['test', 'test'], + nutritionalValue: ['test'], + zone: 2 + }); + + testPlant.save((err) => { + if (err) return console.log('Error: ', err); + done(); + }); + }); + + it('should update a plant with a PUT request', (done) => { + testPlant.commonName = 'updatedByTest'; + request('localhost:3000') + .put('/plants/') + .send(testPlant) + .end((err, res) => { + expect(err).to.eql(null); + expect(res).to.have.status(200); + expect(res.body).to.eql({Message:'Successfully updated'}); + done(); + }); + }); + + it('should delete a plant', (done) => { + console.log(testPlant); + request('localhost:3000') + .delete(`/plants/${testPlant._id}`) + .set('token', token) + .end((err, res) => { + expect(err).to.eql(null); + expect(res).to.have.status(200); + expect(res.text).to.eql(`Deleted plant with ID of ${testPlant._id}`); + done(); + }); + }); + + before((done) => { + + testPlant2 = new Plant({ + commonName:'test2', + scientificName:'testus maximus', + medicinalUses: ['test', 'test'], + nutritionalValue: ['test'], + zone: 100 + }); + + testPlant3 = new Plant({ + commonName:'test3', + scientificName:'testus maximus', + medicinalUses: ['test', 'test'], + nutritionalValue: ['test'], + zone: 40 + }); + + testPlant2.save((err) => { + if (err) return console.log('Error: ', err); + }); + testPlant3.save((err) => { + if (err) return console.log('Error: ', err); + done(); + }); + }); + + it('should get a range of zones included in the database upon any kind of request to the /plants/zones route', (done) => { + request('localhost:3000') + .get('/plants/zones') + .end((err, res) => { + expect(err).to.eql(null); + expect(res).to.have.status(200); + expect(res.text).to.eql('The range of zones represented in the database includes 2 - 100'); + done(); + }); + }); + }); +}); diff --git a/stefanie-hansen/test/supplement-test.js b/stefanie-hansen/test/supplement-test.js new file mode 100644 index 0000000..7362ca5 --- /dev/null +++ b/stefanie-hansen/test/supplement-test.js @@ -0,0 +1,125 @@ +'use strict'; + +const chai = require('chai'); +const chaiHTTP = require('chai-http'); +chai.use(chaiHTTP); +const Supplement = require('../model/supplement'); +const mongoose = require('mongoose'); + +const expect = chai.expect; +const request = chai.request; + +const dbPort = process.env.MONGLAB_URI; +require('../server'); + +describe('Supplement router tests', () => { + + after((done) => { + process.env.MONGOLAB_URI = dbPort; + mongoose.connection.db.dropDatabase(() => { + done(); + }); + }); + + describe('tests that don\'t need data', () => { + it('should get a list of Supplements', (done) => { + request('localhost:3000') + .get('/supplements') + .end((err, res) => { + expect(err).to.eql(null); + expect(res).to.have.status(200); + expect(Array.isArray(res.body)).to.eql(true); + done(); + }); + }); + + it('should post a supplement', (done) => { + request('localhost:3000') + .post('/supplements') + .send( + { + name:'test', + medicinalEffects: ['test'], + sideEffects: ['test', 'test'] + }) + .end((err, res) => { + expect(err).to.eql(null); + expect(res).to.have.status(200); + expect(res.body.name).to.eql('test'); + expect(res.body.medicinalEffects).to.eql(['test']); + expect(res.body.sideEffects).to.eql(['test', 'test']); + done(); + }); + }); + + it('should respond with an error if an attempt is made to post a duplicate Supplement', (done) => { + request('localhost:3000') + .post('/supplements') + .send( + { + name:'test', + medicinalEffects: ['test'], + sideEffects: ['test', 'test'] + }) + .end((err, res) => { + expect(err).to.not.eql(null); + expect(res).to.have.status(400); + done(); + }); + }); + }); + + describe('tests that need data', () => { + let testSupplement; + let token; + + before((done) => { + request('localhost:3000') + .post('/signup') + .send({username:'test', password:'test'}) + .end((err, res) => { + token = res.body.token; + done(); + }); + }); + + beforeEach((done) => { + testSupplement = new Supplement({ + name:'test', + medicinalEffects: ['test'], + sideEffects: ['test', 'test'] + }); + + testSupplement.save((err) => { + if (err) return console.log('Error: ', err); + done(); + }); + }); + + it('should update a supplement with a PUT request', (done) => { + testSupplement.name = 'updatedByTest'; + request('localhost:3000') + .put('/supplements/') + .send(testSupplement) + .end((err, res) => { + expect(err).to.eql(null); + expect(res).to.have.status(200); + expect(res.body).to.eql({Message:'Successfully updated'}); + done(); + }); + }); + + it('should delete a supplement', (done) => { + console.log(testSupplement); + request('localhost:3000') + .delete(`/supplements/${testSupplement._id}`) + .set('token', token) + .end((err, res) => { + expect(err).to.eql(null); + expect(res).to.have.status(200); + expect(res.text).to.eql(`Deleted supplement with ID of ${testSupplement._id}`); + done(); + }); + }); + }); +});