diff --git a/config/passport.js b/config/passport.js index 113ee03..1c07784 100644 --- a/config/passport.js +++ b/config/passport.js @@ -22,27 +22,32 @@ passport.use( usernameField: 'email', passwordField: 'password' }, - async (email, password, done) => { - try { - const user = await User.findOne({ email }) - if (!user) { - return done(null, false) - } - - try { - const isMatch = await user.validatePassword(password) - - if (!isMatch) { - return done(null, false) - } - - done(null, user) - } catch (err) { - done(err) - } - } catch (err) { - return done(err) - } - } + passportCallback ) ) + +async function passportCallback (email, password, done) { + try { + const user = await User.findOne({ email }) + if (!user) { + return done(null, false) + } + + try { + const isMatch = await user.validatePassword(password) + + if (!isMatch) { + return done(null, false) + } + + done(null, user) + } catch (err) { + done(err) + } + } catch (err) { + return done(err) + } +} + +// For testing +module.exports = { passport, passportCallback } diff --git a/src/controllers/rest-api/contact/index.js b/src/controllers/rest-api/contact/index.js index e4db57a..c36daae 100644 --- a/src/controllers/rest-api/contact/index.js +++ b/src/controllers/rest-api/contact/index.js @@ -7,7 +7,6 @@ const Router = require('koa-router') // Local libraries. const ContactRESTControllerLib = require('./controller') -const Validators = require('../middleware/validators') class ContactRouter { constructor (localConfig = {}) { @@ -32,7 +31,6 @@ class ContactRouter { // Encapsulate dependencies. this.contactRESTController = new ContactRESTControllerLib(dependencies) - this.validators = new Validators() // Instantiate the router and set the base route. const baseUrl = '/contact' diff --git a/src/controllers/rest-api/logs/index.js b/src/controllers/rest-api/logs/index.js index c8544c2..334ca67 100644 --- a/src/controllers/rest-api/logs/index.js +++ b/src/controllers/rest-api/logs/index.js @@ -2,16 +2,54 @@ REST API library for /logs route. */ -const LogsRESTRouter = require('./router') +// Public npm libraries. +const Router = require('koa-router') -class LogsRESTController { +// Local libraries. +const LogsRESTControllerLib = require('./controller') + +class LogsRouter { constructor (localConfig = {}) { - this.logsRESTRouter = new LogsRESTRouter() + // Dependency Injection. + this.adapters = localConfig.adapters + if (!this.adapters) { + throw new Error( + 'Instance of Adapters library required when instantiating Logs REST Controller.' + ) + } + this.useCases = localConfig.useCases + if (!this.useCases) { + throw new Error( + 'Instance of Use Cases library required when instantiating Logs REST Controller.' + ) + } + + const dependencies = { + adapters: this.adapters, + useCases: this.useCases + } + + this.logsRESTController = new LogsRESTControllerLib(dependencies) + + // Instantiate the router and set the base route. + const baseUrl = '/logs' + this.router = new Router({ prefix: baseUrl }) } attach (app) { - this.logsRESTRouter.attachControllers(app) + if (!app) { + throw new Error( + 'Must pass app object when attaching REST API controllers.' + ) + } + + // Define the routes and attach the controller. + this.router.post('/', this.logsRESTController.getLogs) + + // Attach the Controller routes to the Koa app. + app.use(this.router.routes()) + app.use(this.router.allowedMethods()) } } -module.exports = LogsRESTController +module.exports = LogsRouter diff --git a/src/controllers/rest-api/logs/router.js b/src/controllers/rest-api/logs/router.js deleted file mode 100644 index d4b1ccf..0000000 --- a/src/controllers/rest-api/logs/router.js +++ /dev/null @@ -1,43 +0,0 @@ -/* - REST Router for the /logs route. -*/ - -// Public npm libraries. -const Router = require('koa-router') - -// Local libraries. -const LogsRESTControllerLib = require('./controller') -const Validators = require('../middleware/validators') - -// let _this - -class LogsRESTRouter { - constructor (localConfig = {}) { - // Encapsulate dependencies. - this.logsRESTController = new LogsRESTControllerLib() - this.validators = new Validators() - - // Instantiate the router and set the base route. - const baseUrl = '/logs' - this.router = new Router({ prefix: baseUrl }) - - // _this = this - } - - attachControllers (app) { - if (!app) { - throw new Error( - 'Must pass app object when attaching REST API controllers.' - ) - } - - // Define the routes and attach the controller. - this.router.post('/', this.logsRESTController.getLogs) - - // Attach the Controller routes to the Koa app. - app.use(this.router.routes()) - app.use(this.router.allowedMethods()) - } -} - -module.exports = LogsRESTRouter diff --git a/test/unit/controllers/rest-api/a06-logapi.rest-unit.js b/test/unit/controllers/rest-api/logs/logs.rest.controller.unit.js similarity index 77% rename from test/unit/controllers/rest-api/a06-logapi.rest-unit.js rename to test/unit/controllers/rest-api/logs/logs.rest.controller.unit.js index f9ab138..ce181d1 100644 --- a/test/unit/controllers/rest-api/a06-logapi.rest-unit.js +++ b/test/unit/controllers/rest-api/logs/logs.rest.controller.unit.js @@ -6,12 +6,12 @@ const assert = require('chai').assert const sinon = require('sinon') -const LogsApiController = require('../../../../src/controllers/rest-api/logs/controller') +const LogsApiController = require('../../../../../src/controllers/rest-api/logs/controller') let uut let sandbox let ctx -const mockContext = require('../../../unit/mocks/ctx-mock').context +const mockContext = require('../../../../unit/mocks/ctx-mock').context describe('Logapi', () => { before(async () => {}) @@ -38,6 +38,7 @@ describe('Logapi', () => { assert.include(err.message, 'Cannot read property') } }) + it('should return 500 status on biz logic Unhandled error', async () => { try { // eslint-disable @@ -59,18 +60,16 @@ describe('Logapi', () => { }) it('should return 200 status on success', async () => { + // Mock dependencies + sandbox.stub(uut.logsApiLib, 'getLogs').resolves({}) + ctx.request.body = { password: 'test' } await uut.getLogs(ctx) - // Assert the expected HTTP response - assert.equal(ctx.status, 200) - - // Assert that expected properties exist in the returned data. - assert.property(ctx.response.body, 'success') - assert.isTrue(ctx.response.body.success) + assert.isOk(ctx.body) }) }) }) diff --git a/test/unit/controllers/rest-api/logs/logs.rest.router.unit.js b/test/unit/controllers/rest-api/logs/logs.rest.router.unit.js new file mode 100644 index 0000000..39f5a56 --- /dev/null +++ b/test/unit/controllers/rest-api/logs/logs.rest.router.unit.js @@ -0,0 +1,78 @@ +/* + Unit tests for the REST API handler for the /users endpoints. +*/ + +// Public npm libraries +const assert = require('chai').assert +const sinon = require('sinon') + +// Local support libraries +const adapters = require('../../../mocks/adapters') +const UseCasesMock = require('../../../mocks/use-cases') +// const app = require('../../../mocks/app-mock') + +const LogsRouter = require('../../../../../src/controllers/rest-api/logs') +let uut +let sandbox +// let ctx + +// const mockContext = require('../../../../unit/mocks/ctx-mock').context + +describe('#Contact-REST-Router', () => { + // const testUser = {} + + beforeEach(() => { + const useCases = new UseCasesMock() + uut = new LogsRouter({ adapters, useCases }) + + sandbox = sinon.createSandbox() + + // Mock the context object. + // ctx = mockContext() + }) + + afterEach(() => sandbox.restore()) + + describe('#constructor', () => { + it('should throw an error if adapters are not passed in', () => { + try { + uut = new LogsRouter() + + assert.fail('Unexpected code path') + } catch (err) { + assert.include( + err.message, + 'Instance of Adapters library required when instantiating Logs REST Controller.' + ) + } + }) + + it('should throw an error if useCases are not passed in', () => { + try { + uut = new LogsRouter({ adapters }) + + assert.fail('Unexpected code path') + } catch (err) { + assert.include( + err.message, + 'Instance of Use Cases library required when instantiating Logs REST Controller.' + ) + } + }) + }) + + describe('#attach', () => { + it('should throw an error if app is not passed in.', () => { + try { + uut.attach() + + assert.fail('Unexpected code path') + } catch (err) { + assert.include( + err.message, + 'Must pass app object when attaching REST API controllers.' + ) + } + }) + }) +}) diff --git a/test/unit/misc/passport.unit.js b/test/unit/misc/passport.unit.js new file mode 100644 index 0000000..71f273f --- /dev/null +++ b/test/unit/misc/passport.unit.js @@ -0,0 +1,77 @@ +/* + Unit tests for the passport library. +*/ + +// Public npm libraries +// const assert = require('chai').assert +const sinon = require('sinon') + +// Local libraries +const User = require('../../../src/adapters/localdb/models/users') +const { passport, passportCallback } = require('../../../config/passport') +const adaptersMock = require('../mocks/adapters') + +describe('#passport', () => { + let sandbox + let id + let done + + beforeEach(() => { + sandbox = sinon.createSandbox() + + id = 'abc123' + done = () => {} + }) + + afterEach(() => sandbox.restore()) + + describe('#serializeUser', () => { + it('should serialize a user', () => { + const user = { + id: 'abc123' + } + const done = () => {} + + passport.serializeUser(user, done) + }) + }) + + describe('#deserializeUser', () => { + it('should deserialize a user', () => { + // Mock Users model. + sandbox.stub(User, 'findById').resolves({ id }) + + passport.deserializeUser(id, done) + }) + + it('should catch and handle errors', () => { + // Force an error + sandbox.stub(User, 'findById').rejects(new Error('test error')) + + passport.deserializeUser(id, done) + }) + }) + + describe('#passportCallback', () => { + it('should return if user is found', () => { + // Mock Users model. + sandbox.stub(User, 'findOne').resolves({ id }) + + passportCallback(id, 'password', done) + }) + + it('should return if password is validated', () => { + // Mock Users model. + sandbox.stub(User, 'findOne').resolves(new adaptersMock.localdb.Users()) + + passportCallback(id, 'password', done) + }) + + it('should catch a high-level error', () => { + // Force an error + sandbox.stub(User, 'findOne').rejects(new Error('test error')) + + passportCallback(id, 'password', done) + }) + }) +}) diff --git a/test/unit/mocks/adapters/index.js b/test/unit/mocks/adapters/index.js index bdabe0b..aa84c05 100644 --- a/test/unit/mocks/adapters/index.js +++ b/test/unit/mocks/adapters/index.js @@ -36,6 +36,10 @@ const localdb = { async remove () { return true } + + async validatePassword () { + return true + } }, validatePassword: () => {