diff --git a/api/controllers/book.js b/api/controllers/book.js index 8414706..c9f2217 100644 --- a/api/controllers/book.js +++ b/api/controllers/book.js @@ -1,25 +1,23 @@ -const { Book } = require('../../shared/models'); - -module.exports = { +module.exports = Book => ({ books: { // GET /api/books get(req, res, next) { - Book.find() + return Book.find() .then(books => res.status(200).json(books)) .catch(next); }, // POST /api/books post(req, res, next) { - Book.create(req.body) + return Book.create(req.body) .then(book => res.status(201).json(book)) .catch(next); } }, book: { - find(req, res, next, id) { - Book.findById(id) + find(req, res, next, slug) { + Book.findOne({ slug }) .then(book => { if (!book) return res.sendStatus(404); req.book = book; @@ -59,4 +57,4 @@ module.exports = { } } } -}; \ No newline at end of file +}); \ No newline at end of file diff --git a/api/controllers/book.xtest.js b/api/controllers/book.xtest.js new file mode 100644 index 0000000..d4c9161 --- /dev/null +++ b/api/controllers/book.xtest.js @@ -0,0 +1,56 @@ +const { expect } = require('chai'); +const sinon = require('sinon'); + +const configureBookController = require('./book'); + +describe('bookController', () => { + const BOOKS = [{ id: 1 }, { id: 2 }, { id: 3 }]; + const BOOK = { id: 1 }; + + class Book { + static find() {} + static create() {} + } + + sinon.stub(Book, 'find').resolves(BOOKS); + sinon.stub(Book, 'create').resolves(BOOK); + + const bookController = configureBookController(Book); + + describe('books', () => { + describe('get', () => { + it('should send an array with status 200', () => { + let req = {}; + let res = { + status: sinon.stub().returnsThis(), + json: sinon.spy() + }; + + return bookController.books.get(req, res) + .then(() => { + expect(res.status.calledOnce).to.equal(true, '`res.status` is not called at least once'); + expect(res.status.calledWith(200)).to.equal(true); + expect(res.json.calledWith(BOOKS)).to.equal(true); + }); + }); + }); + }); + + describe('post', () => { + it('should send and object with status 201', () => { + const req = { + body: { slug: '', title: '' } + }; + const res = { + status: sinon.stub().returnsThis(), + json: sinon.spy() + }; + + return bookController.books.post(req, res) + .then(() => { + expect(res.status.calledWith(201)).to.equal(true); + expect(res.json.calledWith(BOOK)).to.equal(true); + }); + }); + }); +}); \ No newline at end of file diff --git a/api/routers/auth.js b/api/routers/auth.js index 782830c..9dbff41 100644 --- a/api/routers/auth.js +++ b/api/routers/auth.js @@ -1,13 +1,14 @@ +const mongoose = require('mongoose'); const router = require('express').Router(); const jwt = require('jwt-simple'); const { jwtSecret } = require('../../shared/config'); -const { User } = require('../../shared/models'); +const User = mongoose.model('User'); router.post('/token', (req, res, next) => { if (!req.body.email || !req.body.password) return res.sendStatus(401); - User.findOne({ email: req.body.email }) + User.findOne({ email: req.body.email, blocked: false }) .then(user => { if (!user) return res.sendStatus(401); if (!user.isCorrectPassword(req.body.password)) return res.sendStatus(201); diff --git a/api/routers/auth.test.js b/api/routers/auth.test.js new file mode 100644 index 0000000..a6f73dc --- /dev/null +++ b/api/routers/auth.test.js @@ -0,0 +1,70 @@ +const express = require('express'); +const mongoose = require('mongoose'); +const supertest = require('supertest'); +const { expect } = require('chai'); + +const { User } = require('../../shared/models'); +const authRouter = require('./auth'); +const bookRouter = require('./book'); + +const app = express(); + +app.use(express.json()); +app.use(authRouter); +app.use('/books', bookRouter); + +const agent = supertest.agent(app); + +describe('/api', () => { + let token; + + before('Connect to db', () => { + return mongoose.connect('mongodb://localhost:27017/codelibrary-test'); + }); + + before('Create a new user', function() { + this.timeout(10000); + + return User.create({ email: 'olegpolyakov@outlook.com', password: '12345' }); + }); + + after('Delete the user', () => { + return User.deleteMany({}); + }); + + after('Disconnect from db', () => { + return mongoose.disconnect(); + }); + + beforeEach(() => { + return agent.post('/token') + .send({ email: 'olegpolyakov@outlook.com', password: '12345' }) + .expect(200) + .then(res => { + console.log(res.body.token); + }); + }); + + describe('/token', () => { + describe('POST', () => { + it('return a token', () => { + expect(token).to.exist; + }); + }); + }); + + describe('/books', () => { + describe('GET', () => { + it('returns a 401 status for an unauthenticated user', () => { + return agent.get('/books') + .expect(200); + }); + + it('returns a 200 status for an authenticated user', () => { + return agent.get('/books') + .set('Authorization', 'Bearer ' + token) + .expect(200); + }); + }); + }); +}); \ No newline at end of file diff --git a/api/routers/book.js b/api/routers/book.js index 11f59d8..60e318c 100644 --- a/api/routers/book.js +++ b/api/routers/book.js @@ -1,6 +1,8 @@ +const mongoose = require('mongoose'); const router = require('express').Router(); -const { book: bookController } = require('../controllers'); +const Book = mongoose.model('Book'); +const bookController = require('../controllers').book(Book); router.param('id', bookController.book.find); diff --git a/api/routers/book.test.js b/api/routers/book.test.js new file mode 100644 index 0000000..4382a20 --- /dev/null +++ b/api/routers/book.test.js @@ -0,0 +1,103 @@ +const express = require('express'); +const mongoose = require('mongoose'); +const supertest = require('supertest'); +const { expect } = require('chai'); + +const { Book } = require('../../shared/models'); +const bookRuter = require('./book'); + +const app = express(); + +app.use(express.json()); +app.use('/books', bookRuter); + +const request = supertest(app); + +describe('/api', () => { + let book1 = new Book({ slug: 'js', title: 'JavaScript' }); + let book2 = new Book({ slug: 'node', title: 'Node.js' }); + let book3 = new Book({ slug: 'mongo', title: 'MongoDB' }); + + before('Connect to db', () => { + return mongoose.connect('mongodb://localhost:27017/codelibrary-test'); + }); + + before('Initialize db', () => { + return Book.insertMany([book1, book2, book3]); + }); + + after('Clean db', () => { + return Book.deleteMany({}); + }); + + after('Disconnect from db', () => { + return mongoose.disconnect(); + }); + + describe('/books', () => { + describe('GET', () => { + it('should return a list of books', () => { + return request.get('/books') + .expect(200) + .then(res => { + expect(res.body).to.have.length(3); + }); + }); + }); + + describe('POST', () => { + it('should create a new book', () => { + return request.post('/books') + .set('Content-Type', 'application/json') + .send({ slug: 'react', title: 'React' }) + .expect(201) + .then(res => { + expect(res.body.title).to.equal('React'); + }); + }); + }); + }); + + describe('/books/:id', () => { + describe('GET', () => { + it('should return a book by id', () => { + return request.get('/books/node') + .expect(200) + .then(res => { + expect(res.body.slug).to.equal('node'); + }); + }); + }); + + describe('PUT', () => { + it('should update the book', () => { + return request.put('/books/node') + .set('Content-Type', 'application/json') + .send({ slug: 'nodejs' }) + .expect(201) + .then(res => { + expect(res.body.slug).to.equal('nodejs'); + }); + }); + }); + + describe('DELETE', () => { + it('should delete the book', () => { + return request.delete('/books/nodejs') + .expect(204); + }); + }); + }); + + describe('/books/:id/likes', () => { + describe('PUT', () => { + it('should update the likes of the book', () => { + return request.put('/books/react/likes') + .expect(201) + .then(res => { + expect(typeof res.body).to.equal('number'); + }); + }); + }); + }); +}); \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 9bbd8e7..7d69f98 100644 --- a/package-lock.json +++ b/package-lock.json @@ -291,6 +291,11 @@ "integrity": "sha1-104bh+ev/A24qttwIfP+SBAasjQ=", "dev": true }, + "assertion-error": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", + "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==" + }, "assign-symbols": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", @@ -550,6 +555,11 @@ "repeat-element": "1.1.2" } }, + "browser-stdout": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.0.tgz", + "integrity": "sha1-81HTKWnTL6XXpVZxVCY9korjvR8=" + }, "browserslist": { "version": "2.10.0", "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-2.10.0.tgz", @@ -677,6 +687,19 @@ "lazy-cache": "1.0.4" } }, + "chai": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chai/-/chai-4.1.2.tgz", + "integrity": "sha1-D2RYS6ZC8PKs4oBiefTwbKI61zw=", + "requires": { + "assertion-error": "1.1.0", + "check-error": "1.0.2", + "deep-eql": "3.0.1", + "get-func-name": "2.0.0", + "pathval": "1.1.0", + "type-detect": "4.0.8" + } + }, "chalk": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.3.0.tgz", @@ -722,6 +745,11 @@ "integrity": "sha1-tUc7M9yXxCTl2Y3IfVXU2KKci/I=", "dev": true }, + "check-error": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz", + "integrity": "sha1-V00xLt2Iu13YkS6Sht1sCu1KrII=" + }, "chokidar": { "version": "1.7.0", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-1.7.0.tgz", @@ -924,8 +952,7 @@ "component-emitter": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz", - "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=", - "dev": true + "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=" }, "concat-map": { "version": "0.0.1", @@ -1041,6 +1068,11 @@ "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" }, + "cookiejar": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/cookiejar/-/cookiejar-2.1.1.tgz", + "integrity": "sha1-Qa1XsbVVlR7BcUEqgZQrHoIA00o=" + }, "copy-descriptor": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", @@ -1141,7 +1173,6 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", - "dev": true, "requires": { "ms": "2.0.0" } @@ -1157,6 +1188,14 @@ "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=", "dev": true }, + "deep-eql": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-3.0.1.tgz", + "integrity": "sha512-+QeIQyN5ZuO+3Uk5DYh6/1eKO0m0YmJFGNmFHGACpf1ClL1nmlV/p4gNgbl2pJGxgXb4faqo6UE+M5ACEMyVcw==", + "requires": { + "type-detect": "4.0.8" + } + }, "deep-extend": { "version": "0.4.2", "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.4.2.tgz", @@ -1232,6 +1271,11 @@ "integrity": "sha1-8NZtA2cqglyxtzvbP+YjEMjlUrc=", "dev": true }, + "diff": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/diff/-/diff-3.3.1.tgz", + "integrity": "sha512-MKPHZDMB0o6yHyDryUOScqZibp914ksXwAMYMTHj6KO8UeKsRYNJD3oNCKjTqZon+V488P7N/HzXF8t7ZR95ww==" + }, "doctrine": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.0.2.tgz", @@ -1412,8 +1456,7 @@ "escape-string-regexp": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", - "dev": true + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" }, "eslint": { "version": "4.13.1", @@ -2081,6 +2124,19 @@ "mime-types": "2.1.17" } }, + "formatio": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/formatio/-/formatio-1.2.0.tgz", + "integrity": "sha1-87IWfZBoxGmKjVH092CjmlTYGOs=", + "requires": { + "samsam": "1.3.0" + } + }, + "formidable": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/formidable/-/formidable-1.1.1.tgz", + "integrity": "sha1-lriIb3w8NQi5Mta9cMTTqI818ak=" + }, "forwarded": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz", @@ -2216,6 +2272,11 @@ "integrity": "sha1-9wLmMSfn4jHBYKgMFVSstw1QR+U=", "dev": true }, + "get-func-name": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz", + "integrity": "sha1-6td0q+5y4gQJQzoGY2YCPdaIekE=" + }, "get-stdin": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz", @@ -2519,6 +2580,11 @@ "resolved": "https://registry.npmjs.org/graceful-readlink/-/graceful-readlink-1.0.1.tgz", "integrity": "sha1-TK+tdrxi8C+gObL5Tpo906ORpyU=" }, + "growl": { + "version": "1.10.3", + "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.3.tgz", + "integrity": "sha512-hKlsbA5Vu3xsh1Cg3J7jSmX/WaW6A5oBeqzM88oNbCRQFz+zUaXm6yxS4RVytp1scBoJzSYl4YAEOQIt6O8V1Q==" + }, "gulp": { "version": "3.9.1", "resolved": "https://registry.npmjs.org/gulp/-/gulp-3.9.1.tgz", @@ -2746,8 +2812,7 @@ "has-flag": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz", - "integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE=", - "dev": true + "integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE=" }, "has-gulplog": { "version": "0.1.0", @@ -2838,8 +2903,7 @@ "he": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/he/-/he-1.1.1.tgz", - "integrity": "sha1-k0EP0hsAlzUVH4howvJx80J+I/0=", - "dev": true + "integrity": "sha1-k0EP0hsAlzUVH4howvJx80J+I/0=" }, "hoek": { "version": "2.16.3", @@ -3495,6 +3559,11 @@ "promise": "7.3.1" } }, + "just-extend": { + "version": "1.1.27", + "resolved": "https://registry.npmjs.org/just-extend/-/just-extend-1.1.27.tgz", + "integrity": "sha512-mJVp13Ix6gFo3SBAy9U/kL+oeZqzlYYYLQBwXVBlVzIsZwBqGREnOro24oC/8s8aox+rJhtZ2DiQof++IrkA+g==" + }, "jwa": { "version": "1.1.5", "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.1.5.tgz", @@ -3759,6 +3828,11 @@ "lodash.escape": "3.2.0" } }, + "lolex": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/lolex/-/lolex-2.3.2.tgz", + "integrity": "sha512-A5pN2tkFj7H0dGIAM6MFvHKMJcPnjZsOMvR7ujCjfgW5TbV6H9vb1PgxLtHvjqNZTHsUolz+6/WEO0N1xNx2ng==" + }, "longest": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz", @@ -4299,6 +4373,38 @@ "minimist": "0.0.8" } }, + "mocha": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-5.0.0.tgz", + "integrity": "sha512-ukB2dF+u4aeJjc6IGtPNnJXfeby5d4ZqySlIBT0OEyva/DrMjVm5HkQxKnHDLKEfEQBsEnwTg9HHhtPHJdTd8w==", + "requires": { + "browser-stdout": "1.3.0", + "commander": "2.11.0", + "debug": "3.1.0", + "diff": "3.3.1", + "escape-string-regexp": "1.0.5", + "glob": "7.1.2", + "growl": "1.10.3", + "he": "1.1.1", + "mkdirp": "0.5.1", + "supports-color": "4.4.0" + }, + "dependencies": { + "commander": { + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.11.0.tgz", + "integrity": "sha512-b0553uYA5YAEGgyYIGYROzKQ7X5RAqedkfjiZxwi0kL1g3bOaBNNZfYkzt/CL0umgD5wc9Jec2FbB98CjkMRvQ==" + }, + "supports-color": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.4.0.tgz", + "integrity": "sha512-rKC3+DyXWgK0ZLKwmRsrkyHVZAjNkfzeehuFWdGGcqGDTZFH73+RH6S/RDAAxl9GusSjZSUWYLmT9N5pzXFOXQ==", + "requires": { + "has-flag": "2.0.0" + } + } + } + }, "moment": { "version": "2.20.1", "resolved": "https://registry.npmjs.org/moment/-/moment-2.20.1.tgz", @@ -4479,6 +4585,33 @@ "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.1.tgz", "integrity": "sha1-KzJxhOiZIQEXeyhWP7XnECrNDKk=" }, + "nise": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/nise/-/nise-1.2.3.tgz", + "integrity": "sha512-qJRxyKdGuaCS/SMgp2S7lR8CBY29jyrz3Z6OdB4oZorkv81nkSspLhbxMJq3/MGzZWgqUHjTMjBI/G6RTgvqJQ==", + "requires": { + "formatio": "1.2.0", + "just-extend": "1.1.27", + "lolex": "2.3.2", + "path-to-regexp": "1.7.0", + "text-encoding": "0.6.4" + }, + "dependencies": { + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" + }, + "path-to-regexp": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.7.0.tgz", + "integrity": "sha1-Wf3g9DW62suhA6hOnTvGTpa5k30=", + "requires": { + "isarray": "0.0.1" + } + } + } + }, "node-gyp": { "version": "3.6.2", "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-3.6.2.tgz", @@ -5297,6 +5430,11 @@ "pinkie-promise": "2.0.1" } }, + "pathval": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.0.tgz", + "integrity": "sha1-uULm1L3mUwBe9rcTYd74cn0GReA=" + }, "pause": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/pause/-/pause-0.0.1.tgz", @@ -6012,6 +6150,11 @@ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==" }, + "samsam": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/samsam/-/samsam-1.3.0.tgz", + "integrity": "sha512-1HwIYD/8UlOtFS3QO3w7ey+SdSDFE4HRNLZoZRYVQefrOY3l17epswImeB1ijgJFQJodIaHcwkp3r/myBjFVbg==" + }, "sass-graph": { "version": "2.2.4", "resolved": "https://registry.npmjs.org/sass-graph/-/sass-graph-2.2.4.tgz", @@ -6239,6 +6382,30 @@ "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=" }, + "sinon": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/sinon/-/sinon-4.2.2.tgz", + "integrity": "sha512-BEa593xl+IkIc94nKo0O0LauQC/gQy8Gyv4DkzPwF/9DweC5phr1y+42zibCpn9abfkdHxt9r8AhD0R6u9DE/Q==", + "requires": { + "diff": "3.3.1", + "formatio": "1.2.0", + "lodash.get": "4.4.2", + "lolex": "2.3.2", + "nise": "1.2.3", + "supports-color": "5.1.0", + "type-detect": "4.0.8" + }, + "dependencies": { + "supports-color": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.1.0.tgz", + "integrity": "sha512-Ry0AwkoKjDpVKK4sV4h6o3UJmNRbjYm2uXhwfj3J56lMVdvnUNqzQVRztOOMGQ++w1K/TjNDFvpJk0F/LoeBCQ==", + "requires": { + "has-flag": "2.0.0" + } + } + } + }, "slice-ansi": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-1.0.0.tgz", @@ -6607,6 +6774,44 @@ "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=" }, + "superagent": { + "version": "3.8.2", + "resolved": "https://registry.npmjs.org/superagent/-/superagent-3.8.2.tgz", + "integrity": "sha512-gVH4QfYHcY3P0f/BZzavLreHW3T1v7hG9B+hpMQotGQqurOvhv87GcMCd6LWySmBuf+BDR44TQd0aISjVHLeNQ==", + "requires": { + "component-emitter": "1.2.1", + "cookiejar": "2.1.1", + "debug": "3.1.0", + "extend": "3.0.1", + "form-data": "2.3.1", + "formidable": "1.1.1", + "methods": "1.1.2", + "mime": "1.4.1", + "qs": "6.5.1", + "readable-stream": "2.3.3" + }, + "dependencies": { + "form-data": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.1.tgz", + "integrity": "sha1-b7lPvXGIUwbXPRXMSX/kzE7NRL8=", + "requires": { + "asynckit": "0.4.0", + "combined-stream": "1.0.5", + "mime-types": "2.1.17" + } + } + } + }, + "supertest": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/supertest/-/supertest-3.0.0.tgz", + "integrity": "sha1-jUu2j9GDDuBwM7HFpamkAhyWUpY=", + "requires": { + "methods": "1.1.2", + "superagent": "3.8.2" + } + }, "supports-color": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", @@ -6676,6 +6881,11 @@ "execa": "0.7.0" } }, + "text-encoding": { + "version": "0.6.4", + "resolved": "https://registry.npmjs.org/text-encoding/-/text-encoding-0.6.4.tgz", + "integrity": "sha1-45mpgiV6J22uQou5KEXLcb3CbRk=" + }, "text-table": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", @@ -6878,6 +7088,11 @@ "prelude-ls": "1.1.2" } }, + "type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==" + }, "type-is": { "version": "1.6.15", "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.15.tgz", diff --git a/package.json b/package.json index 9361c20..c402170 100644 --- a/package.json +++ b/package.json @@ -21,6 +21,7 @@ "dependencies": { "apicache": "^1.2.0", "bcrypt": "^1.0.3", + "chai": "^4.1.2", "connect-mongo": "^2.0.1", "cors": "^2.8.4", "dotenv": "^4.0.0", @@ -29,6 +30,7 @@ "express-session": "^1.15.6", "jwt-simple": "^0.5.1", "material-components-web": "^0.28.0", + "mocha": "^5.0.0", "moment": "^2.20.1", "mongoose": "^5.0.1", "morgan": "^1.9.0", @@ -38,6 +40,8 @@ "passport-jwt": "^3.0.1", "passport-local": "^1.0.0", "pug": "^2.0.0-rc.4", - "serve-favicon": "^2.4.5" + "serve-favicon": "^2.4.5", + "sinon": "^4.2.2", + "supertest": "^3.0.0" } }