From 3d911d1062ae071dc4b3d500462b9c48fa2b47dd Mon Sep 17 00:00:00 2001 From: Daniel Gonzalez Date: Fri, 27 Jun 2025 20:11:27 -0400 Subject: [PATCH 1/2] feat(tests): Increased unit test coverage --- src/use-cases/usage-use-cases.js | 11 +++- test/unit/adapters/adapters-index-unit.js | 15 +++++ test/unit/adapters/admin.adapter.unit.js | 19 +++--- test/unit/adapters/passport.adapter.unit.js | 12 ++++ test/unit/adapters/users.adapter.unit.js | 7 +++ test/unit/controllers/controllers.unit.js | 21 +++++++ .../auth/auth.rest.controller.unit.js | 13 +++- .../rest-api/rest.controller.unit.js | 17 ++++- .../users/users.rest.controller.unit.js | 14 +++++ .../rest-api/users/users.rest.router.unit.js | 38 +++++++++++ test/unit/misc/passport.unit.js | 15 +++++ test/unit/misc/server-unit.js | 2 +- test/unit/mocks/adapters/index.js | 33 ++++++++++ test/unit/use-cases/usage.use-case.unit.js | 63 +++++++++++++++++++ 14 files changed, 265 insertions(+), 15 deletions(-) diff --git a/src/use-cases/usage-use-cases.js b/src/use-cases/usage-use-cases.js index c6886c2..77e952d 100644 --- a/src/use-cases/usage-use-cases.js +++ b/src/use-cases/usage-use-cases.js @@ -128,6 +128,7 @@ class UsageUseCases { // Delete this code after debugging const usage = await this.UsageModel.find({}) console.log('clearUsage() usage: ', usage) + return true } catch (err) { console.error('Error in usage-use-cases.js/clearUsage()') throw err @@ -141,9 +142,9 @@ class UsageUseCases { const thisRestCall = restCalls[i] // Debugging: delete this code after debugging - if (i === 5) { - console.log('saveUsage() thisRestCall: ', thisRestCall) - } + // if (i === 5) { + // console.log('saveUsage() thisRestCall: ', thisRestCall) + // } const usageData = { ip: thisRestCall.ip, @@ -155,6 +156,7 @@ class UsageUseCases { const usage = new this.UsageModel(usageData) await usage.save() } + return true } catch (err) { console.error('Error in usage-use-cases.js/saveUsage()') throw err @@ -167,13 +169,16 @@ class UsageUseCases { const usage = await this.UsageModel.find({}) // console.log('usage: ', usage) + // Debugging: delete this code after debugging if (usage[5]) { console.log('loadUsage() usage[5]: ', usage[5]) } restCalls = usage + return usage } catch (err) { console.error('Error in usage-use-cases.js/loadUsage(): ', err) + return false // throw err } } diff --git a/test/unit/adapters/adapters-index-unit.js b/test/unit/adapters/adapters-index-unit.js index ee382e4..328f2bb 100644 --- a/test/unit/adapters/adapters-index-unit.js +++ b/test/unit/adapters/adapters-index-unit.js @@ -37,6 +37,21 @@ describe('#adapters', () => { assert.equal(result, true) }) + it('should not start ipfs on test enviroment', async () => { + // Mock dependencies + uut.config.getJwtAtStartup = true + uut.config.useIpfs = true + uut.config.env = 'test' + + sandbox.stub(uut.fullStackJwt, 'getJWT').resolves() + sandbox.stub(uut.fullStackJwt, 'instanceBchjs').resolves() + const ipfsSpy = sandbox.stub(uut.ipfs, 'start').resolves(null) + + const result = await uut.start() + + assert.isTrue(ipfsSpy.notCalled) + assert.equal(result, true) + }) it('should catch and throw an error', async () => { try { diff --git a/test/unit/adapters/admin.adapter.unit.js b/test/unit/adapters/admin.adapter.unit.js index 796b2e3..6b59261 100644 --- a/test/unit/adapters/admin.adapter.unit.js +++ b/test/unit/adapters/admin.adapter.unit.js @@ -19,16 +19,17 @@ describe('Admin', () => { if (!config.noMongo) { describe('loginAdmin()', () => { - // it('should login admin', async () => { - // try { - // sandbox.stub(uut.axios, 'request').resolves(true) + it('should login admin', async () => { + try { + sandbox.stub(uut.jsonFiles, 'readJSON').resolves({ password: 'pass' }) + sandbox.stub(uut.axios, 'request').resolves(true) - // const result = await uut.loginAdmin() - // assert.isTrue(result) - // } catch (err) { - // assert(false, 'Unexpected result') - // } - // }) + const result = await uut.loginAdmin() + assert.isTrue(result) + } catch (err) { + assert(false, 'Unexpected result') + } + }) it('should handle axios error', async () => { try { diff --git a/test/unit/adapters/passport.adapter.unit.js b/test/unit/adapters/passport.adapter.unit.js index 536fe54..2372a19 100644 --- a/test/unit/adapters/passport.adapter.unit.js +++ b/test/unit/adapters/passport.adapter.unit.js @@ -41,5 +41,17 @@ describe('#passport.js', () => { assert.include(err.message, 'cant auth user') } }) + it('should authenticate user', async () => { + const ctx = {} + const errMock = null + const userMock = { + _id: '123', + email: 'test@test.com' + } + sandbox.stub(uut.passport, 'authenticate').yields(errMock, userMock) + const user = await uut.authUser(ctx) + assert.equal(user._id, userMock._id) + assert.equal(user.email, userMock.email) + }) }) }) diff --git a/test/unit/adapters/users.adapter.unit.js b/test/unit/adapters/users.adapter.unit.js index 286d1eb..0205d55 100644 --- a/test/unit/adapters/users.adapter.unit.js +++ b/test/unit/adapters/users.adapter.unit.js @@ -54,6 +54,13 @@ describe('#User-Adapter', () => { assert.notEqual(testuser.password, 'password') }) + it('should ignore password encrption if password property is not provided', async () => { + const lastPassword = testuser.password + await testuser.save() + // console.log('testuser: ', testuser) + + assert.equal(testuser.password, lastPassword) + }) }) describe('#validatePassword', () => { diff --git a/test/unit/controllers/controllers.unit.js b/test/unit/controllers/controllers.unit.js index 15742b7..0a8a74c 100644 --- a/test/unit/controllers/controllers.unit.js +++ b/test/unit/controllers/controllers.unit.js @@ -38,4 +38,25 @@ describe('#Controllers', () => { await uut.attachControllers(app) }) }) + describe('#attachRESTControllers', () => { + it('should attach the controllers', async () => { + const app = { + use: () => {} + } + + await uut.attachRESTControllers(app) + }) + }) + describe('#initAdapters', () => { + it('should attach the controllers', async () => { + sandbox.stub(uut.adapters, 'start').resolves({}) + await uut.initAdapters() + }) + }) + describe('#initUseCases', () => { + it('should attach the controllers', async () => { + sandbox.stub(uut.useCases, 'start').resolves({}) + await uut.initUseCases() + }) + }) }) diff --git a/test/unit/controllers/rest-api/auth/auth.rest.controller.unit.js b/test/unit/controllers/rest-api/auth/auth.rest.controller.unit.js index 9c53d05..90a7726 100644 --- a/test/unit/controllers/rest-api/auth/auth.rest.controller.unit.js +++ b/test/unit/controllers/rest-api/auth/auth.rest.controller.unit.js @@ -79,11 +79,22 @@ describe('#Auth-REST-Router', () => { await uut.authUser(ctx) }) - it('should catch and throw an error', async () => { + it('should catch and throw passport error', async () => { try { // Force an error sandbox.stub(uut.passport, 'authUser').rejects('test error') + await uut.authUser(ctx) + } catch (err) { + // console.log('err: ', err) + assert.include(err.message, 'Unauthorized') + } + }) + it('should handle error if user is not found!', async () => { + try { + // Force an error + sandbox.stub(uut.passport, 'authUser').resolves(null) + await uut.authUser(ctx) } catch (err) { // console.log('err: ', err) diff --git a/test/unit/controllers/rest-api/rest.controller.unit.js b/test/unit/controllers/rest-api/rest.controller.unit.js index 0e46689..ae70c6e 100644 --- a/test/unit/controllers/rest-api/rest.controller.unit.js +++ b/test/unit/controllers/rest-api/rest.controller.unit.js @@ -20,7 +20,7 @@ describe('#RESTControllers', () => { let sandbox // let ctx - before(async () => {}) + before(async () => { }) beforeEach(() => { const useCases = new UseCasesMock() @@ -64,4 +64,19 @@ describe('#RESTControllers', () => { } }) }) + + describe('#attachRESTControllers', () => { + it('should attach controllers without mongo service', () => { + uut.config.noMongo = true + + const app = { use: () => {} } + uut.attachRESTControllers(app) + }) + it('should attach controllers with mongo service', () => { + uut.config.noMongo = false + + const app = { use: () => {} } + uut.attachRESTControllers(app) + }) + }) }) diff --git a/test/unit/controllers/rest-api/users/users.rest.controller.unit.js b/test/unit/controllers/rest-api/users/users.rest.controller.unit.js index 45b1b81..47c0a82 100644 --- a/test/unit/controllers/rest-api/users/users.rest.controller.unit.js +++ b/test/unit/controllers/rest-api/users/users.rest.controller.unit.js @@ -153,6 +153,20 @@ describe('#Users-REST-Controller', () => { // Assert that expected properties exist in the returned data. assert.property(ctx.response.body, 'user') }) + it('should run next function if it exists', async () => { + // Mock dependencies + const nextSpy = sandbox.spy() + sandbox.stub(uut.useCases.user, 'getUser').resolves({ _id: '123' }) + + await uut.getUser(ctx, nextSpy) + + // Assert the expected HTTP response + assert.equal(ctx.status, 200) + + // Assert that expected properties exist in the returned data. + assert.property(ctx.response.body, 'user') + assert.isTrue(nextSpy.calledOnce) + }) it('should return other error status passed by biz logic', async () => { try { diff --git a/test/unit/controllers/rest-api/users/users.rest.router.unit.js b/test/unit/controllers/rest-api/users/users.rest.router.unit.js index ef5fcb3..126e5ae 100644 --- a/test/unit/controllers/rest-api/users/users.rest.router.unit.js +++ b/test/unit/controllers/rest-api/users/users.rest.router.unit.js @@ -107,4 +107,42 @@ describe('#Users-REST-Router', () => { assert.isTrue(validationSpy.calledOnce, 'Admin validator should be called') }) }) + describe('#getAll', () => { + it('should route to controller', async () => { + sandbox.stub(uut.validators, 'ensureUser').resolves(true) + const spy = sandbox.stub(uut.userRESTController, 'getUsers').resolves(true) + + await uut.getAll() + assert.isTrue(spy.calledOnce) + }) + }) + describe('#getById', () => { + it('should route to controller', async () => { + sandbox.stub(uut.validators, 'ensureUser').resolves(true) + const spy = sandbox.stub(uut.userRESTController, 'getUser').resolves(true) + + await uut.getById() + assert.isTrue(spy.calledOnce) + }) + }) + describe('#updateUser', () => { + it('should route to controller', async () => { + sandbox.stub(uut.validators, 'ensureTargetUserOrAdmin').resolves(true) + sandbox.stub(uut.userRESTController, 'getUser').resolves(true) + const spy = sandbox.stub(uut.userRESTController, 'updateUser').resolves(true) + + await uut.updateUser() + assert.isTrue(spy.calledOnce) + }) + }) + describe('#deleteUser', () => { + it('should route to controller', async () => { + sandbox.stub(uut.validators, 'ensureTargetUserOrAdmin').resolves(true) + sandbox.stub(uut.userRESTController, 'getUser').resolves(true) + const spy = sandbox.stub(uut.userRESTController, 'deleteUser').resolves(true) + + await uut.deleteUser() + assert.isTrue(spy.calledOnce) + }) + }) }) diff --git a/test/unit/misc/passport.unit.js b/test/unit/misc/passport.unit.js index 6cd1705..b646e45 100644 --- a/test/unit/misc/passport.unit.js +++ b/test/unit/misc/passport.unit.js @@ -34,6 +34,12 @@ describe('#passport', () => { passportCallback(id, 'password', done) }) + it('should handle not found user', () => { + // Mock Users model. + sandbox.stub(User, 'findOne').resolves(null) + + passportCallback(id, 'password', done) + }) it('should return if password is validated', () => { // Mock Users model. @@ -41,6 +47,15 @@ describe('#passport', () => { passportCallback(id, 'password', done) }) + it('should handle error on password validation', () => { + // Mock Users model. + const userMock = { + validatePassword: () => false + } + sandbox.stub(User, 'findOne').resolves(userMock) + + passportCallback(id, 'password', done) + }) it('should catch a high-level error', () => { // Force an error diff --git a/test/unit/misc/server-unit.js b/test/unit/misc/server-unit.js index da56b91..bffeac9 100644 --- a/test/unit/misc/server-unit.js +++ b/test/unit/misc/server-unit.js @@ -30,7 +30,7 @@ describe('#server', () => { sandbox.stub(uut.adminLib, 'createSystemUser').resolves(true) sandbox.stub(uut.controllers, 'attachControllers').resolves() uut.config.env = 'dev' - + uut.config.port = 5040 const result = await uut.startServer() // console.log('result: ', result) diff --git a/test/unit/mocks/adapters/index.js b/test/unit/mocks/adapters/index.js index 80cd290..0257955 100644 --- a/test/unit/mocks/adapters/index.js +++ b/test/unit/mocks/adapters/index.js @@ -70,6 +70,39 @@ const localdb = { } }, + Usage: class Usage { + static findById () {} + static find () {} + static findOne () { + return { + validatePassword: localdb.validatePassword + } + } + + async save () { + return {} + } + + generateToken () { + return '123' + } + + toJSON () { + return {} + } + + async remove () { + return true + } + + async validatePassword () { + return true + } + static async deleteMany(){ + return true + } + }, + validatePassword: () => { return true } diff --git a/test/unit/use-cases/usage.use-case.unit.js b/test/unit/use-cases/usage.use-case.unit.js index 790832a..b29900f 100644 --- a/test/unit/use-cases/usage.use-case.unit.js +++ b/test/unit/use-cases/usage.use-case.unit.js @@ -255,4 +255,67 @@ describe('#usage-use-case', () => { } }) }) + describe('#clearUsage', () => { + it('should clear the usage database data', async () => { + const res = await uut.clearUsage() + assert.isTrue(res) + }) + + it('should handle error', async () => { + try { + sandbox.stub(uut.UsageModel, 'deleteMany').throws(new Error('uut error')) + await uut.clearUsage() + assert.fail('Unexpected code path') + } catch (error) { + assert.equal(error.message, 'uut error') + } + }) + }) + + describe('#saveUsage', () => { + it('should save usage', async () => { + // Set mock data + restCalls.push({ + timestamp: new Date().getTime(), + ip: 'localhost', + url: 'fakeUrl', + method: 'unit test' + }) + const res = await uut.saveUsage() + assert.isTrue(res) + }) + + it('should handle error', async () => { + try { + restCalls.push(null) + await uut.saveUsage() + assert.fail('Unexpected code path') + } catch (error) { + console.log(error) + assert.include(error.message, 'Cannot read properties') + } + }) + }) + + describe('#loadUsage', () => { + it('should load usage', async () => { + // Set mock data + const mockObj = { + timestamp: new Date().getTime(), + ip: 'localhost', + url: 'fakeUrl', + method: 'unit test' + } + sandbox.stub(uut.UsageModel, 'find').returns(new Array(10).fill(null).map((_, i) => (mockObj))) + const res = await uut.loadUsage() + assert.equal(restCalls.length, 10) + assert.equal(res.length, 10) + }) + + it('should skip error', async () => { + sandbox.stub(uut.UsageModel, 'find').throws(new Error('uut error')) + const res = await uut.loadUsage() + assert.isFalse(res) + }) + }) }) From 883f9aca679687818fb8d0160117555bc0340ff4 Mon Sep 17 00:00:00 2001 From: Chris Troutner Date: Thu, 21 Aug 2025 08:45:28 -0700 Subject: [PATCH 2/2] linting --- src/use-cases/usage-use-cases.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/use-cases/usage-use-cases.js b/src/use-cases/usage-use-cases.js index 0e466df..dc1397d 100644 --- a/src/use-cases/usage-use-cases.js +++ b/src/use-cases/usage-use-cases.js @@ -51,7 +51,7 @@ class UsageUseCases { restCalls = restCalls.filter(x => x.timestamp > twentyFourHoursAgo) console.log('cleanUsage() restCalls.length after filtering: ', restCalls.length) - if(!restCalls) restCalls = [] + if (!restCalls) restCalls = [] return restCalls } catch (err) { @@ -167,7 +167,7 @@ class UsageUseCases { // console.log('usage: ', usage) restCalls = usage - if(!restCalls) restCalls = [] + if (!restCalls) restCalls = [] return usage } catch (err) {