Merge pull request #101 from Permissionless-Software-Foundation/ct-unstable

Increased test coverage to 100%
This commit is contained in:
Chris Troutner
2022-09-17 15:24:26 -07:00
committed by GitHub
22 changed files with 2359 additions and 3613 deletions
+8
View File
@@ -0,0 +1,8 @@
[
{
"srcDir": "",
"destDir": "",
"files": "**/*.js",
"command": "npm run lint"
}
]
+1 -1
View File
@@ -27,7 +27,7 @@ import AdminLib from '../src/adapters/admin.js'
import errorMiddleware from '../src/controllers/rest-api/middleware/error.js'
import wlogger from '../src/adapters/wlogger.js'
import Controllers from '../src/controllers/index.js'
import applyPassportMods from '../config/passport.js'
import { applyPassportMods } from '../config/passport.js'
class Server {
constructor () {
+7 -2
View File
@@ -5,9 +5,14 @@
/* eslint no-unneeded-ternary:0 */
// Hack to get __dirname back.
// https://blog.logrocket.com/alternatives-dirname-node-js-es-modules/
import * as url from 'url'
// Get the version from the package.json file.
import { readFileSync } from 'fs'
const pkgInfo = JSON.parse(readFileSync('package.json'))
const __dirname = url.fileURLToPath(new URL('.', import.meta.url))
const pkgInfo = JSON.parse(readFileSync(`${__dirname.toString()}/../../package.json`))
const version = pkgInfo.version
@@ -17,7 +22,7 @@ const ipfsCoordName = process.env.COORD_NAME
export default {
// Configure TCP port.
port: process.env.PORT || 5001,
port: process.env.PORT || 5020,
// Password for HTML UI that displays logs.
logPass: 'test',
+2 -1
View File
@@ -5,11 +5,12 @@ import production from './env/production.js'
import test from './env/test.js'
const env = process.env.SVC_ENV || 'development'
console.log(`Loading config for this environment: ${env}`)
let config = development
if (env === 'test') {
config = test
} else if (env === 'production') {
} else if (env === 'prod') {
config = production
}
+4 -1
View File
@@ -49,8 +49,11 @@ function applyPassportMods (passport) {
passportCallback
)
)
return true
}
// For testing
// export default { passport, passportCallback };
export default applyPassportMods
// export default applyPassportMods
export { applyPassportMods, passportCallback }
+1730 -3420
View File
File diff suppressed because it is too large Load Diff
+6 -6
View File
@@ -7,14 +7,14 @@
"scripts": {
"start": "node index.js",
"test": "npm run test:all",
"test:all": "export SVC_ENV=test && nyc --reporter=text mocha --exit --timeout 15000 --recursive test/unit test/e2e/automated/",
"test:all": "export SVC_ENV=test && c8 --reporter=text mocha --exit --timeout 15000 --recursive test/unit test/e2e/automated/",
"test:unit": "export SVC_ENV=test && mocha --exit --timeout 15000 --recursive test/unit/",
"test:e2e:auto": "export SVC_ENV=test && mocha --exit --timeout 15000 test/e2e/automated/",
"test:temp": "export SVC_ENV=test && mocha --exit --timeout 15000 -g '#rate-limit' test/unit/json-rpc/",
"lint": "standard --env mocha --fix",
"docs": "./node_modules/.bin/apidoc -i src/ -o docs",
"coverage": "nyc report --reporter=text-lcov | coveralls",
"coverage:report": "export SVC_ENV=test && nyc --reporter=html mocha --exit --timeout 15000 --recursive test/unit/ test/e2e/automated/"
"coverage": "c8 report --reporter=text-lcov | coveralls",
"coverage:report": "export SVC_ENV=test && c8 --reporter=html mocha --exit --timeout 15000 --recursive test/unit/ test/e2e/automated/"
},
"author": "Chris Troutner <chris.troutner@gmail.com>",
"license": "MIT",
@@ -27,7 +27,7 @@
"axios": "0.27.2",
"bcryptjs": "2.4.3",
"glob": "7.1.6",
"ipfs-coord-esm": "9.1.1",
"ipfs-coord-esm": "9.1.3",
"ipfs-http-client": "58.0.0",
"jsonrpc-lite": "2.2.0",
"jsonwebtoken": "8.5.1",
@@ -44,7 +44,7 @@
"koa-static": "5.0.0",
"koa2-ratelimit": "0.9.1",
"line-reader": "0.4.0",
"minimal-slp-wallet": "5.0.3",
"minimal-slp-wallet": "5.1.0",
"mongoose": "5.13.14",
"node-fetch": "npm:@achingbrain/node-fetch@2.6.7",
"nodemailer": "6.7.5",
@@ -55,11 +55,11 @@
},
"devDependencies": {
"apidoc": "0.51.1",
"c8": "7.12.0",
"chai": "4.3.0",
"coveralls": "3.1.0",
"husky": "4.3.8",
"mocha": "10.0.0",
"nyc": "15.1.0",
"semantic-release": "19.0.3",
"sinon": "9.2.4",
"standard": "17.0.0",
+5 -3
View File
@@ -25,12 +25,12 @@ import JsonFiles from '../adapters/json-files.js'
// Hack to get __dirname back.
// https://blog.logrocket.com/alternatives-dirname-node-js-es-modules/
import * as url from 'url'
const jsonFiles = new JsonFiles()
const __dirname = url.fileURLToPath(new URL('.', import.meta.url))
const jsonFiles = new JsonFiles()
const JSON_FILE = `system-user-${config.env}.json`
const JSON_PATH = `${__dirname.toString()}/../../config/${JSON_FILE}`
const JSON_PATH = `${__dirname.toString()}../../config/${JSON_FILE}`
const LOCALHOST = `http://localhost:${config.port}`
const context = {}
@@ -90,6 +90,8 @@ class Admin {
// applications like the Task Manager and the test scripts can access.
await jsonFiles.writeJSON(context, JSON_PATH)
// console.log('context: ', context)
// console.log('JSON_PATH: ', JSON_PATH)
return context
} catch (err) {
+3
View File
@@ -51,6 +51,9 @@ class Adapters {
// Do not start these adapters if this is an e2e test.
if (this.config.env !== 'test') {
await this.ipfs.start()
} else {
// These lines are here to ensure code coverage hits 100%.
console.log('Not starting IPFS node since this is an e2e test.')
}
console.log('Async Adapters have been started.')
+2 -2
View File
@@ -76,5 +76,5 @@ logger.outputToConsole()
const wlogger = logger.wlogger
// export default { wlogger, Wlogger };
export default wlogger
export { wlogger as default, Wlogger }
// export default wlogger
@@ -1,5 +1,17 @@
/*
REST API validator middleware.
These are a series of functions that ensure the user making a REST API
matches a user in the database (or not). In can do fine-grain user control
such as telling the difference between an admin, a normal user, and an
anonymous user.
This middleware is used to gatekeep access to different REST API resources.
CT 9/17/22:
This library was lightly refactored to make it work with the new unit tests.
This not and the commented code below can be deleted once it is verified that
this refactor did not result in any breaking changes.
*/
import User from '../../../adapters/localdb/models/users.js'
@@ -21,12 +33,10 @@ class Validators {
async ensureUser (ctx, next) {
try {
// console.log(`getToken: ${typeof (getToken)}`)
const token = _this.getToken(ctx)
if (!token) {
// console.log(`Err: Token not provided.`)
ctx.throw(401)
throw new Error('Token could not be retrieved from header')
}
let decoded = null
@@ -35,20 +45,23 @@ class Validators {
// console.log(`config: ${JSON.stringify(config, null, 2)}`)
decoded = _this.jwt.verify(token, config.token)
} catch (err) {
// console.log(`Err: Token could not be decoded: ${err}`)
ctx.throw(401)
throw new Error('Could not verify JWT')
}
ctx.state.user = await _this.User.findById(decoded.id, '-password')
if (!ctx.state.user) {
// console.log(`Err: Could not find user.`)
ctx.throw(401)
// console.log('Err: Could not find user.')
throw new Error('Could not find user')
}
// return next()
return true
} catch (error) {
ctx.throw(401)
// console.log('Ensure user error: ', error)
// console.log('ctx: ', ctx)
ctx.status = 401
ctx.throw(401, error.message)
}
}
@@ -61,7 +74,8 @@ class Validators {
if (!token) {
// console.log(`Err: Token not provided.`)
ctx.throw(401)
// ctx.throw(401)
throw new Error('Token could not be retrieved from header')
}
let decoded = null
@@ -71,22 +85,26 @@ class Validators {
decoded = _this.jwt.verify(token, config.token)
} catch (err) {
// console.log(`Err: Token could not be decoded: ${err}`)
ctx.throw(401)
// ctx.throw(401)
throw new Error('Could not verify JWT')
}
ctx.state.user = await _this.User.findById(decoded.id, '-password')
if (!ctx.state.user) {
// console.log(`Err: Could not find user.`)
ctx.throw(401)
// ctx.throw(401)
throw new Error('Could not find user')
}
if (ctx.state.user.type !== 'admin') {
ctx.throw(401, 'not admin')
// ctx.throw(401, 'not admin')
throw new Error('User is not an admin')
}
// return next()
return true
} catch (error) {
ctx.status = 401
ctx.throw(401, error.message)
}
}
@@ -102,7 +120,8 @@ class Validators {
if (!token) {
// console.log(`Err: Token not provided.`)
ctx.throw(401)
// ctx.throw(401)
throw new Error('Token could not be retrieved from header')
}
// The user ID targeted in this API call.
@@ -115,14 +134,16 @@ class Validators {
// console.log(`config: ${JSON.stringify(config, null, 2)}`)
decoded = _this.jwt.verify(token, config.token)
} catch (err) {
// console.log(`Err: Token could not be decoded: ${err}`)
ctx.throw(401)
console.log(`Err: Token could not be decoded: ${err}`)
// ctx.throw(401)
throw new Error('Could not verify JWT')
}
ctx.state.user = await _this.User.findById(decoded.id, '-password')
if (!ctx.state.user) {
// console.log(`Err: Could not find user.`)
ctx.throw(401)
// ctx.throw(401)
throw new Error('Could not find user')
}
// console.log('ctx.state.user: ', ctx.state.user)
@@ -136,7 +157,8 @@ class Validators {
// If they don't match, then the calling user better be an admin.
if (ctx.state.user.type !== 'admin') {
ctx.throw(401, 'not admin')
// ctx.throw(401, 'not admin')
throw new Error('User is not an admin')
} else {
wlogger.verbose("It's ok. The user is an admin.")
}
@@ -145,6 +167,8 @@ class Validators {
// return next()
return true
} catch (error) {
// console.log('Error in ensureTargetUserOrAdmin(): ', error)
ctx.status = 401
ctx.throw(401, error.message)
}
}
+2 -2
View File
@@ -36,7 +36,7 @@ class UserRESTControllerLib {
* @apiGroup REST Users
*
* @apiExample Example usage:
* curl -H "Content-Type: application/json" -X POST -d '{ "user": { "email": "email@format.com", "name": "my name", "password": "secretpasas" } }' localhost:5001/users
* curl -H "Content-Type: application/json" -X POST -d '{ "user": { "email": "email@format.com", "name": "my name", "password": "secretpasas" } }' localhost:5010/users
*
* @apiParam {Object} user User object (required)
* @apiParam {String} user.email Email
@@ -136,7 +136,7 @@ class UserRESTControllerLib {
* @apiGroup REST Users
*
* @apiExample Example usage:
* curl -H "Content-Type: application/json" -X GET localhost:5000/users/56bd1da600a526986cf65c80
* curl -H "Content-Type: application/json" -X GET localhost:5010/users/56bd1da600a526986cf65c80
*
* @apiSuccess {Object} users User object
* @apiSuccess {ObjectId} users._id User id
+11 -13
View File
@@ -1,20 +1,19 @@
/*
import testUtils from '../../utils/test-utils.js';
import { assert } from 'chai';
import config from '../../../config/index.js';
import axios from 'axios';
import sinon from 'sinon';
import util from 'util';
import testUtils from '../../utils/test-utils.js'
import { assert } from 'chai'
import config from '../../../config/index.js'
import axios from 'axios'
import sinon from 'sinon'
import util from 'util'
import UserController from '../../../src/controllers/rest-api/users/controller.js'
import Adapters from '../../../src/adapters/index.js'
import UseCases from '../../../src/use-cases/index.js'
util.inspect.defaultOptions = { depth: 1 }
const LOCALHOST = `http://localhost:${config.port}`
const context = {}
import UserController from '../../../src/controllers/rest-api/users/controller.js';
import Adapters from '../../../src/adapters/index.js';
const adapters = new Adapters()
import UseCases from '../../../src/use-cases/index.js';
let uut
let sandbox
@@ -39,7 +38,7 @@ describe('Users', () => {
// Get the JWT used to log in as the admin 'system' user.
const adminJWT = await testUtils.getAdminJWT()
// console.log(`adminJWT: ${admi nJWT}`)
console.log(`adminJWT: ${adminJWT}`)
context.adminJWT = adminJWT
// const admin = await testUtils.loginAdminUser()
@@ -786,4 +785,3 @@ describe('Users', () => {
})
})
})
*/
+16 -1
View File
@@ -52,7 +52,7 @@ describe('#IPFS', () => {
it('should get the public IP address if this node is a Circuit Relay', async () => {
// Mock dependencies.
uut.IpfsCoord = IPFSCoordMock
sandbox.stub(uut.publicIp, 'v4').returns('123')
sandbox.stub(uut.publicIp, 'v4').resolves('123')
// Force Circuit Relay
uut.config.isCircuitRelay = true
@@ -62,6 +62,21 @@ describe('#IPFS', () => {
assert.equal(result, true)
})
it('should exit quietly if this node is a Circuit Relay and there is an issue getting the IP address', async () => {
// Mock dependencies.
uut.IpfsCoord = IPFSCoordMock
sandbox.stub(uut.publicIp, 'v4').rejects(new Error('test error'))
// Force Circuit Relay
uut.config.isCircuitRelay = true
const result = await uut.start()
// console.log('result: ', result)
assert.equal(result, true)
})
it('should return a promise that resolves into an instance of IPFS in production mode', async () => {
uut.config.isProduction = true
// Mock dependencies.
+39 -39
View File
@@ -1,39 +1,39 @@
// import { assert } from 'chai';
// import { Wlogger } from '../../../src/adapters/wlogger.js';
// import sinon from 'sinon';
//
// let uut
// let sandbox
//
// describe('#wlogger', () => {
// beforeEach(() => {
// sandbox = sinon.createSandbox()
// })
//
// afterEach(() => {
// sandbox.restore()
//
// uut = new Wlogger()
// })
//
// describe('#constructor', () => {
// it('should create a new wlogger instance', () => {
// uut = new Wlogger()
// // console.log('uut: ', uut)
//
// assert.property(uut, 'transport')
// })
// })
//
// describe('#notifyRotation', () => {
// it('should notify of a log rotation', () => {
// uut.notifyRotation()
// })
// })
//
// describe('#envronment', () => {
// it('should write to console in non-test environment', () => {
// uut.outputToConsole()
// })
// })
// })
import { assert } from 'chai'
import { Wlogger } from '../../../src/adapters/wlogger.js'
import sinon from 'sinon'
let uut
let sandbox
describe('#wlogger', () => {
beforeEach(() => {
sandbox = sinon.createSandbox()
})
afterEach(() => {
sandbox.restore()
uut = new Wlogger()
})
describe('#constructor', () => {
it('should create a new wlogger instance', () => {
uut = new Wlogger()
// console.log('uut: ', uut)
assert.property(uut, 'transport')
})
})
describe('#notifyRotation', () => {
it('should notify of a log rotation', () => {
uut.notifyRotation()
})
})
describe('#envronment', () => {
it('should write to console in non-test environment', () => {
uut.outputToConsole()
})
})
})
@@ -0,0 +1,306 @@
/*
Unit tests for the REST API middleware that validates users.
*/
// Public npm libraries
import { assert } from 'chai'
import sinon from 'sinon'
// Local libraries
import Validators from '../../../../../src/controllers/rest-api/middleware/validators.js'
import { context as mockContext } from '../../../../unit/mocks/ctx-mock.js'
describe('#Validators', () => {
let uut
let ctx
let sandbox
beforeEach(() => {
uut = new Validators()
// Mock the context object.
ctx = mockContext()
sandbox = sinon.createSandbox()
})
afterEach(() => sandbox.restore())
describe('#getToken', () => {
it('should return null if no header is provided', () => {
const result = uut.getToken(ctx)
assert.equal(result, null)
})
it('should return null if header is not in two parts', () => {
ctx.request.header.authorization = 'Bearer'
const result = uut.getToken(ctx)
assert.equal(result, null)
})
it('should return null if first part of header does not container the word bearer', () => {
ctx.request.header.authorization = 'some thing'
const result = uut.getToken(ctx)
assert.equal(result, null)
})
it('should return the JWT token from the header', () => {
const jwt = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjYzMjNiNTUwNzgxYWYzNTc4YzI0ZmU5YiIsImlhdCI6MTY2MzQ0NDczNCwiZXhwIjoxNjYzNTMxMTM0fQ.BY5sOfXc4z5axS98CdTfyqnO9y2wijOlwnv52rcvxHA'
ctx.request.header.authorization = `Bearer ${jwt}`
const result = uut.getToken(ctx)
assert.equal(result, jwt)
})
})
describe('#ensureUser', () => {
it('should throw error if token is not provided', async () => {
try {
// Mock dependencies and force desired code path
sandbox.stub(uut, 'getToken').returns()
await uut.ensureUser(ctx)
assert.fail('Unexpected result')
} catch (err) {
assert.equal(ctx.status, 401)
}
})
it('should throw error if token can not be verified', async () => {
try {
// Mock dependencies and force desired code path
sandbox.stub(uut, 'getToken').returns('fake-jwt')
sandbox.stub(uut.jwt, 'verify').throws(new Error('test error'))
await uut.ensureUser(ctx)
assert.fail('Unexpected result')
} catch (err) {
assert.equal(ctx.status, 401)
}
})
it('should throw error if user can not be found in database', async () => {
try {
// Mock dependencies and force desired code path
sandbox.stub(uut, 'getToken').returns('fake-jwt')
sandbox.stub(uut.jwt, 'verify').returns({})
sandbox.stub(uut.User, 'findById').resolves(false)
await uut.ensureUser(ctx)
assert.fail('Unexpected result')
} catch (err) {
assert.equal(ctx.status, 401)
}
})
it('should return true if the user is verified', async () => {
// Mock dependencies and force desired code path
sandbox.stub(uut, 'getToken').returns('fake-jwt')
sandbox.stub(uut.jwt, 'verify').returns({})
sandbox.stub(uut.User, 'findById').resolves({ user: 'alice' })
const result = await uut.ensureUser(ctx)
assert.equal(result, true)
})
})
describe('#ensureUser', () => {
it('should throw error if token is not provided', async () => {
try {
// Mock dependencies and force desired code path
sandbox.stub(uut, 'getToken').returns()
await uut.ensureAdmin(ctx)
assert.fail('Unexpected result')
} catch (err) {
assert.equal(ctx.status, 401)
}
})
it('should throw error if token can not be verified', async () => {
try {
// Mock dependencies and force desired code path
sandbox.stub(uut, 'getToken').returns('fake-jwt')
sandbox.stub(uut.jwt, 'verify').throws(new Error('test error'))
await uut.ensureAdmin(ctx)
assert.fail('Unexpected result')
} catch (err) {
assert.equal(ctx.status, 401)
}
})
it('should throw error if user can not be found in database', async () => {
try {
// Mock dependencies and force desired code path
sandbox.stub(uut, 'getToken').returns('fake-jwt')
sandbox.stub(uut.jwt, 'verify').returns({})
sandbox.stub(uut.User, 'findById').resolves(false)
await uut.ensureAdmin(ctx)
assert.fail('Unexpected result')
} catch (err) {
assert.equal(ctx.status, 401)
}
})
it('should throw error if user is not an admin', async () => {
try {
// Mock dependencies and force desired code path
sandbox.stub(uut, 'getToken').returns('fake-jwt')
sandbox.stub(uut.jwt, 'verify').returns({})
sandbox.stub(uut.User, 'findById').resolves({ type: 'user' })
await uut.ensureAdmin(ctx)
assert.fail('Unexpected result')
} catch (err) {
assert.equal(ctx.status, 401)
}
})
it('should return true if the user is an admin', async () => {
// Mock dependencies and force desired code path
sandbox.stub(uut, 'getToken').returns('fake-jwt')
sandbox.stub(uut.jwt, 'verify').returns({})
sandbox.stub(uut.User, 'findById').resolves({ type: 'admin' })
const result = await uut.ensureAdmin(ctx)
assert.equal(result, true)
})
})
describe('#ensureTargetUserOrAdmin', () => {
it('should throw error if token is not provided', async () => {
try {
// Mock dependencies and force desired code path
sandbox.stub(uut, 'getToken').returns()
await uut.ensureTargetUserOrAdmin(ctx)
assert.fail('Unexpected result')
} catch (err) {
assert.equal(ctx.status, 401)
}
})
it('should throw error if token can not be verified', async () => {
try {
// Mock dependencies and force desired code path
sandbox.stub(uut, 'getToken').returns('fake-jwt')
sandbox.stub(uut.jwt, 'verify').throws(new Error('test error'))
ctx.params = {
id: '456'
}
await uut.ensureTargetUserOrAdmin(ctx)
assert.fail('Unexpected result')
} catch (err) {
assert.equal(ctx.status, 401)
}
})
it('should throw error if user can not be found in database', async () => {
try {
// Mock dependencies and force desired code path
sandbox.stub(uut, 'getToken').returns('fake-jwt')
sandbox.stub(uut.jwt, 'verify').returns({})
sandbox.stub(uut.User, 'findById').resolves(false)
ctx.params = {
id: '456'
}
await uut.ensureTargetUserOrAdmin(ctx)
assert.fail('Unexpected result')
} catch (err) {
assert.equal(ctx.status, 401)
}
})
it('should throw error if user is not an admin', async () => {
try {
// Mock dependencies and force desired code path
sandbox.stub(uut, 'getToken').returns('fake-jwt')
sandbox.stub(uut.jwt, 'verify').returns({})
sandbox.stub(uut.User, 'findById').resolves({ type: 'user' })
ctx.params = {
id: '456'
}
await uut.ensureTargetUserOrAdmin(ctx)
assert.fail('Unexpected result')
} catch (err) {
assert.equal(ctx.status, 401)
}
})
it('should throw error is user is not admin or target user', async () => {
try {
// Mock dependencies and force desired code path
sandbox.stub(uut, 'getToken').returns('fake-jwt')
sandbox.stub(uut.jwt, 'verify').returns({})
sandbox.stub(uut.User, 'findById').resolves({ type: 'user', _id: '123' })
ctx.params = {
id: '456'
}
await uut.ensureTargetUserOrAdmin(ctx)
assert.fail('Unexpected result')
} catch (err) {
assert.equal(ctx.status, 401)
}
})
it('should return true if the user is an admin', async () => {
// Mock dependencies and force desired code path
sandbox.stub(uut, 'getToken').returns('fake-jwt')
sandbox.stub(uut.jwt, 'verify').returns({})
sandbox.stub(uut.User, 'findById').resolves({ type: 'admin', _id: '123' })
ctx.params = {
id: '456'
}
const result = await uut.ensureTargetUserOrAdmin(ctx)
assert.equal(result, true)
})
it('should return true if the user is the target user', async () => {
// Mock dependencies and force desired code path
sandbox.stub(uut, 'getToken').returns('fake-jwt')
sandbox.stub(uut.jwt, 'verify').returns({})
sandbox.stub(uut.User, 'findById').resolves({ type: 'user', _id: '123' })
ctx.params = {
id: '123'
}
const result = await uut.ensureTargetUserOrAdmin(ctx)
assert.equal(result, true)
})
})
})
@@ -4,12 +4,10 @@
// Public npm libraries
import { assert } from 'chai'
import sinon from 'sinon'
// Local support libraries
import adapters from '../../../mocks/adapters/index.js'
import UseCasesMock from '../../../mocks/use-cases/index.js'
import UserController from '../../../../../src/controllers/rest-api/users/controller.js'
+50
View File
@@ -0,0 +1,50 @@
/*
Unit tests for the config directory
*/
import { assert } from 'chai'
let currentEnv
describe('#config', () => {
before(() => {
// Backup the current environment setting.
currentEnv = process.env.SVC_ENV
})
after(() => {
// Restore the environment setting before starting these tests.
process.env.SVC_ENV = currentEnv
})
it('Should return development environment config by default', async () => {
const importedConfig = await import('../../../config/index.js')
const config = importedConfig.default
// console.log('config: ', config)
assert.equal(config.env, 'dev')
})
it('Should return test environment config', async () => {
// Hack to dynamically import a library multiple times:
// https://github.com/denoland/deno/issues/6946
process.env.SVC_ENV = 'test'
const importedConfig2 = await import('../../../config/index.js?foo=bar1')
const config = importedConfig2.default
// console.log('config: ', config)
assert.equal(config.env, 'test')
})
it('Should return test environment config', async () => {
process.env.SVC_ENV = 'prod'
const importedConfig3 = await import('../../../config/index.js?foo=bar2')
const config = importedConfig3.default
// console.log('config: ', config)
assert.equal(config.env, 'prod')
})
})
+93 -78
View File
@@ -1,78 +1,93 @@
// /*
// Unit tests for the passport library.
// */
//
// // Public npm libraries
// // const assert = require('chai').assert
// import sinon from 'sinon';
//
// // Local libraries
// import User from '../../../src/adapters/localdb/models/users.js';
//
// import { passport, passportCallback } from '../../../config/passport.js';
// import adaptersMock from '../mocks/adapters/index.js';
//
// 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)
// })
// })
// })
/*
Unit tests for the passport library.
*/
// Public npm libraries
import { assert } from 'chai'
import sinon from 'sinon'
import passport from 'koa-passport'
// Local libraries
import User from '../../../src/adapters/localdb/models/users.js'
import { applyPassportMods, passportCallback } from '../../../config/passport.js'
import adaptersMock from '../mocks/adapters/index.js'
describe('#passport', () => {
let sandbox
let id
let done
beforeEach(() => {
sandbox = sinon.createSandbox()
id = 'abc123'
done = () => {}
})
afterEach(() => sandbox.restore())
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)
})
})
describe('#applyPassportMods', () => {
it('should apply modifications to default passport behavior', () => {
const result = applyPassportMods(passport)
assert.equal(result, true)
})
})
describe('#serializeUser', () => {
it('should serialize a user', () => {
const user = {
id: 'abc123'
}
const done = () => {}
applyPassportMods(passport)
passport.serializeUser(user, done)
})
})
describe('#deserializeUser', () => {
it('should deserialize a user', () => {
// Mock Users model.
sandbox.stub(User, 'findById').resolves({ id })
applyPassportMods(passport)
passport.deserializeUser(id, done)
})
it('should catch and handle errors', () => {
// Force an error
sandbox.stub(User, 'findById').rejects(new Error('test error'))
applyPassportMods(passport)
passport.deserializeUser(id, done)
})
})
})
-1
View File
@@ -4,7 +4,6 @@
// Public npm libraries
import { assert } from 'chai'
import sinon from 'sinon'
// Local libraries
+17 -17
View File
@@ -6,7 +6,6 @@
// Public npm libraries
import { assert } from 'chai'
import sinon from 'sinon'
// Local support libraries
@@ -331,22 +330,23 @@ describe('#users-use-case', () => {
}
})
// it('should update the user model', async () => {
// const newData = {
// email: 'test@test.com',
// password: 'password',
// name: 'testy tester'
// }
//
// const result = await uut.updateUser(testUser, newData)
//
// // Assert that expected properties and values exist.
// assert.property(result, '_id')
// assert.property(result, 'email')
// assert.equal(result.email, 'test@test.com')
// assert.property(result, 'name')
// assert.equal(result.name, 'testy tester')
// })
it('should update the user model', async () => {
const newData = {
email: 'test@test.com',
password: 'password',
name: 'testy tester'
}
testUser.save = async () => {}
const result = await uut.updateUser(testUser, newData)
// Assert that expected properties and values exist.
assert.property(result, '_id')
assert.property(result, 'email')
assert.equal(result.email, 'test@test.com')
assert.property(result, 'name')
assert.equal(result.name, 'testy tester')
})
// TODO: verify that an admin can change the type of a user
})
+16 -7
View File
@@ -4,15 +4,21 @@
// Public NPM libraries
import mongoose from 'mongoose'
import axios from 'axios'
// Local libraries
import config from '../../config/index.js'
import User from '../../src/adapters/localdb/models/users.js'
import JsonFiles from '../../src/adapters/json-files.js'
// Hack to get __dirname back.
// https://blog.logrocket.com/alternatives-dirname-node-js-es-modules/
import * as url from 'url'
const jsonFiles = new JsonFiles()
const LOCALHOST = `http://localhost:${config.port}`
const __dirname = url.fileURLToPath(new URL('.', import.meta.url))
// Remove all collections from the DB.
async function cleanDb () {
@@ -112,9 +118,11 @@ async function loginTestUser () {
async function loginAdminUser () {
try {
const FILENAME = `../../config/system-user-${config.env}.json`
const adminUserData = require(FILENAME)
console.log(`adminUserData: ${JSON.stringify(adminUserData, null, 2)}`)
const FILENAME = `${__dirname.toString()}../../config/system-user-${config.env}.json`
// console.log('FILENAME: ', FILENAME)
const adminUserData = await jsonFiles.readJSON(FILENAME)
// console.log(`adminUserData: ${JSON.stringify(adminUserData, null, 2)}`)
const options = {
method: 'POST',
@@ -151,8 +159,9 @@ async function getAdminJWT () {
// process.env.KOA_ENV = process.env.KOA_ENV || 'dev'
// console.log(`env: ${process.env.KOA_ENV}`)
const FILENAME = `../../config/system-user-${config.env}.json`
const adminUserData = require(FILENAME)
const FILENAME = `${__dirname.toString()}../../config/system-user-${config.env}.json`
// console.log('FILENAME: ', FILENAME)
const adminUserData = await jsonFiles.readJSON(FILENAME)
// console.log(`adminUserData: ${JSON.stringify(adminUserData, null, 2)}`)
return adminUserData.token