forked from ipfs-service-provider

This commit is contained in:
Chris Troutner
2021-11-23 08:38:01 -08:00
commit 8f7f3896a3
115 changed files with 58101 additions and 0 deletions
+8
View File
@@ -0,0 +1,8 @@
# Unit Tests
Unit tests are defined as testing the smallest possible unit of a function. They also do not make any live network calls.
Unit tests are broken up by directory:
- [biz-logic](./biz-logic) tests the business logic libraries.
- [rest-api](./rest-api) tests the REST API specific handling of the router.
- json-rpc (coming soon) tests the JSON-RPC routing using ipfs-coord library.
+129
View File
@@ -0,0 +1,129 @@
const assert = require('chai').assert
const sinon = require('sinon')
const ContactLib = require('../../../src/adapters/contact')
let uut
let sandbox
describe('Contact', () => {
beforeEach(() => {
uut = new ContactLib()
sandbox = sinon.createSandbox()
})
afterEach(() => sandbox.restore())
describe('sendEmail()', () => {
it('should throw error if email property is not provided', async () => {
try {
const data = {
formMessage: 'test msg'
}
await uut.sendEmail(data)
assert(false, 'Unexpected result')
} catch (err) {
assert.include(err.message, "Property 'email' must be a string!")
}
})
it('should throw error if formMessage property is not provided', async () => {
try {
const data = {
email: 'test@email.com'
}
await uut.sendEmail(data)
assert(false, 'Unexpected result')
} catch (err) {
assert.include(err.message, "Property 'formMessage' must be a string!")
}
})
it('should throw error if email list provided is not a array', async () => {
try {
sandbox.stub(uut.nodemailer, 'sendEmail').resolves(true)
const data = {
formMessage: 'test msg',
email: 'test@email.com',
emailList: 'test@email.com'
}
await uut.sendEmail(data)
assert(false, 'Unexpected result')
} catch (err) {
assert.include(
err.message,
"Property 'emailList' must be a array of emails!"
)
}
})
it('should throw error if email list provided is a empty array', async () => {
try {
sandbox.stub(uut.nodemailer, 'sendEmail').resolves(true)
const data = {
formMessage: 'test msg',
email: 'test@email.com',
emailList: []
}
await uut.sendEmail(data)
assert(false, 'Unexpected result')
} catch (err) {
assert.include(
err.message,
"Property 'emailList' must be a array of emails!"
)
}
})
it('should send email to default server email', async () => {
try {
sandbox.stub(uut.nodemailer, 'sendEmail').resolves(true)
const data = {
formMessage: 'test msg',
email: 'test@email.com'
}
const result = await uut.sendEmail(data)
assert.isTrue(result)
} catch (err) {
assert(false, 'Unexpected result')
}
})
it('should catch and throw nodemailer lib error', async () => {
try {
// Force an error with the database.
sandbox
.stub(uut.nodemailer, 'sendEmail')
.throws(new Error('test error'))
const data = {
formMessage: 'test msg',
email: 'test@email.com'
}
await uut.sendEmail(data)
assert(false, 'Unexpected result')
} catch (err) {
assert.include(err.message, 'test error')
}
})
it('should send email to specifics email list', async () => {
try {
sandbox.stub(uut.nodemailer, 'sendEmail').resolves(true)
const data = {
formMessage: 'test msg',
email: 'test@email.com',
emailList: ['testcontact@email.com']
}
const result = await uut.sendEmail(data)
assert.isTrue(result)
} catch (err) {
assert(false, 'Unexpected result')
}
})
})
})
@@ -0,0 +1,162 @@
/*
Unit tests for the jwt-bch-lib and fullstack-jwt.js adapter library.
*/
const assert = require('chai').assert
const sinon = require('sinon')
const FullStackJWT = require('../../../src/adapters/fullstack-jwt')
describe('#FullStackJWT', () => {
let sandbox
let uut
beforeEach(() => {
sandbox = sinon.createSandbox()
const localConfig = {
authServer: 'someserver',
apiServer: 'someserver',
fullstackLogin: 'somelogin',
fullstackPassword: 'somepassword'
}
uut = new FullStackJWT(localConfig)
})
afterEach(() => sandbox.restore())
describe('#constructor', () => {
it('should throw an error if auth server is not specified', () => {
try {
uut = new FullStackJWT()
assert.fail('Unexpected code path')
console.log(uut) // For linting.
} catch (err) {
assert.include(
err.message,
'Must pass a url for the AUTH server when instantiating FullStackJWT class.'
)
}
})
it('should throw an error if api server is not specified', () => {
try {
const localConfig = {
authServer: 'someserver'
}
uut = new FullStackJWT(localConfig)
assert.fail('Unexpected code path')
console.log(uut) // For linting.
} catch (err) {
assert.include(
err.message,
'Must pass a url for the API server when instantiating FullStackJWT class.'
)
}
})
it('should throw an error if login is not specified', () => {
try {
const localConfig = {
authServer: 'someserver',
apiServer: 'someserver'
}
uut = new FullStackJWT(localConfig)
assert.fail('Unexpected code path')
console.log(uut) // For linting.
} catch (err) {
assert.include(
err.message,
'Must pass a FullStack.cash login (email) instantiating FullStackJWT class.'
)
}
})
it('should throw an error if login is not specified', () => {
try {
const localConfig = {
authServer: 'someserver',
apiServer: 'someserver',
fullstackLogin: 'somelogin'
}
uut = new FullStackJWT(localConfig)
assert.fail('Unexpected code path')
console.log(uut) // For linting.
} catch (err) {
assert.include(
err.message,
'Must pass a FullStack.cash account password when instantiating FullStackJWT class.'
)
}
})
})
describe('#getJWT', () => {
it('should return the JWT token', async () => {
// Mock dependencies to force a code path.
sandbox.stub(uut.jwtLib, 'register').resolves({})
uut.jwtLib.userData.apiToken = 'abc123'
sandbox.stub(uut.jwtLib, 'validateApiToken').resolves({ isValid: true })
const result = await uut.getJWT()
// console.log('result: ', result)
assert.equal(result, 'abc123')
})
it('should catch and throw an error', async () => {
try {
// Force an error
sandbox.stub(uut.jwtLib, 'register').rejects(new Error('test error'))
await uut.getJWT()
assert.fail('Unexpected code path')
} catch (err) {
assert.include(err.message, 'test error')
}
})
it('should throw an error if user does not have a JWT', async () => {
try {
// Mock dependencies to force a code path.
sandbox.stub(uut.jwtLib, 'register').resolves({})
await uut.getJWT()
assert.fail('Unexpected code path')
} catch (err) {
// console.log('err.message: ', err.message)
assert.include(err.message, 'This account does not have a JWT')
}
})
it('should retrieve a new JWT token if the old one invalid', async () => {
// Mock dependencies to force a code path.
sandbox.stub(uut.jwtLib, 'register').resolves({})
uut.jwtLib.userData.apiToken = 'abc123'
uut.jwtLib.userData.apiLevel = 30
sandbox.stub(uut.jwtLib, 'validateApiToken').resolves({ isValid: false })
sandbox.stub(uut.jwtLib, 'getApiToken').resolves('xyz789')
const result = await uut.getJWT()
// console.log('result: ', result)
assert.equal(result, 'xyz789')
})
})
describe('#instanceBchjs', () => {
it('should return an instance of bch-js', () => {
const result = uut.instanceBchjs()
// console.log('result: ', result)
assert.property(result, 'restURL')
})
})
})
@@ -0,0 +1,103 @@
/*
Unit tests for the IPFS Adapter.
*/
const assert = require('chai').assert
const sinon = require('sinon')
const IPFSCoordAdapter = require('../../../src/adapters/ipfs/ipfs-coord')
const IPFSMock = require('../mocks/ipfs-mock')
const IPFSCoordMock = require('../mocks/ipfs-coord-mock')
describe('#IPFS', () => {
let uut
let sandbox
beforeEach(() => {
const ipfs = IPFSMock.create()
uut = new IPFSCoordAdapter({ ipfs })
sandbox = sinon.createSandbox()
})
afterEach(() => sandbox.restore())
describe('#constructor', () => {
it('should throw an error if ipfs instance is not included', () => {
try {
uut = new IPFSCoordAdapter()
assert.fail('Unexpected code path')
} catch (err) {
assert.include(
err.message,
'Instance of IPFS must be passed when instantiating ipfs-coord.'
)
}
})
})
describe('#start', () => {
it('should return a promise that resolves into an instance of IPFS.', async () => {
// Mock dependencies.
uut.IpfsCoord = IPFSCoordMock
const result = await uut.start()
// console.log('result: ', result)
assert.equal(result, true)
})
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')
// Force Circuit Relay
uut.config.isCircuitRelay = true
const result = await uut.start()
// console.log('result: ', result)
assert.equal(result, true)
})
})
describe('#attachRPCRouter', () => {
it('should attached a router output', async () => {
// Mock dependencies
uut.ipfsCoord = {
privateLog: {},
ipfs: {
orbitdb: {
privateLog: {}
}
},
adapters: {
orbit: {
privateLog: () => {}
}
}
}
const router = console.log
uut.attachRPCRouter(router)
})
it('should catch and throw an error', () => {
try {
// Force an error
delete uut.ipfsCoord.adapters
const router = console.log
uut.attachRPCRouter(router)
assert.fail('Unexpected code path')
} catch (err) {
assert.include(err.message, 'Cannot read property')
}
})
})
})
@@ -0,0 +1,67 @@
/*
Unit tests for the index.js file for the IPFS and ipfs-coord libraries.
*/
const assert = require('chai').assert
const sinon = require('sinon')
const IPFSLib = require('../../../src/adapters/ipfs')
const IPFSMock = require('../mocks/ipfs-mock')
const IPFSCoordMock = require('../mocks/ipfs-coord-mock')
describe('#IPFS-adapter-index', () => {
let uut
let sandbox
beforeEach(() => {
uut = new IPFSLib()
sandbox = sinon.createSandbox()
})
afterEach(() => sandbox.restore())
describe('#start', () => {
it('should return a promise that resolves into an instance of IPFS.', async () => {
// Mock dependencies.
uut.ipfsAdapter = new IPFSMock()
uut.IpfsCoordAdapter = IPFSCoordMock
const result = await uut.start()
assert.equal(result, true)
})
it('should catch and throw an error', async () => {
try {
// Force an error
sandbox.stub(uut.ipfsAdapter, 'start').rejects(new Error('test error'))
await uut.start()
assert.fail('Unexpected code path.')
} catch (err) {
// console.log(err)
assert.include(err.message, 'test error')
}
})
it('should handle lock-file errors', async () => {
try {
// Force an error
sandbox
.stub(uut.ipfsAdapter, 'start')
.rejects(new Error('Lock already being held'))
// Prevent process from exiting
sandbox.stub(uut.process, 'exit').returns()
await uut.start()
assert.fail('Unexpected code path.')
} catch (err) {
assert.include(err.message, 'Lock already being held')
}
})
})
})
+63
View File
@@ -0,0 +1,63 @@
/*
Unit tests for the IPFS Adapter.
*/
const assert = require('chai').assert
const sinon = require('sinon')
const IPFSLib = require('../../../src/adapters/ipfs/ipfs')
const IPFSMock = require('../mocks/ipfs-mock')
describe('#IPFS-adapter', () => {
let uut
let sandbox
beforeEach(() => {
uut = new IPFSLib()
sandbox = sinon.createSandbox()
})
afterEach(() => sandbox.restore())
describe('#start', () => {
it('should return a promise that resolves into an instance of IPFS.', async () => {
// Mock dependencies.
uut.IPFS = IPFSMock
const result = await uut.start()
// console.log('result: ', result)
assert.equal(uut.isReady, true)
assert.property(result, 'config')
})
it('should catch and throw an error', async () => {
try {
// Force an error
sandbox.stub(uut.IPFS, 'create').rejects(new Error('test error'))
await uut.start()
assert.fail('Unexpected code path.')
} catch (err) {
// console.log(err)
assert.include(err.message, 'test error')
}
})
})
describe('#stop', () => {
it('should stop the IPFS node', async () => {
// Mock dependencies
uut.ipfs = {
stop: () => {}
}
const result = await uut.stop()
assert.equal(result, true)
})
})
})
@@ -0,0 +1,139 @@
const assert = require('chai').assert
const fs = require('fs')
const sinon = require('sinon')
const util = require('util')
util.inspect.defaultOptions = { depth: 1 }
const JsonFiles = require('../../../src/adapters/json-files')
const JSON_FILE = 'test-json-file.json'
const JSON_PATH = `${__dirname.toString()}/${JSON_FILE}`
const deleteFile = filepath => {
try {
// Delete state if exist
fs.unlinkSync(filepath)
} catch (error) {}
}
let sandbox
let uut
describe('JsonFiles', () => {
const obj = {
json: 'file'
}
beforeEach(() => {
uut = new JsonFiles()
sandbox = sinon.createSandbox()
})
afterEach(() => sandbox.restore())
after(() => {
deleteFile(JSON_PATH)
})
describe('writeJSON()', () => {
it('should throw error if inputs is not provided', async () => {
try {
await uut.writeJSON()
assert(false, 'Unexpected result')
} catch (err) {
assert.include(err.message, 'obj property is required')
}
})
it('should throw error if filename property is not provided', async () => {
try {
await uut.writeJSON(obj)
assert(false, 'Unexpected result')
} catch (err) {
assert.include(err.message, 'fileName property must be a string')
}
})
it('should throw error if filename property is not string', async () => {
try {
await uut.writeJSON(obj, 1)
assert(false, 'Unexpected result')
} catch (err) {
assert.include(err.message, 'fileName property must be a string')
}
})
it('should throw error if fs library return an error', async () => {
try {
// https://sinonjs.org/releases/latest/stubs/
// About yields
sandbox.stub(uut.fs, 'writeFile').yields(new Error('test error'))
await uut.writeJSON(obj, JSON_PATH)
assert(false, 'Unexpected result')
} catch (err) {
assert.include(err.message, 'test error')
}
})
it('should write a json file', async () => {
try {
await uut.writeJSON(obj, JSON_PATH)
assert.isTrue(fs.existsSync(JSON_PATH))
} catch (err) {
assert(false, 'Unexpected result')
}
})
})
describe('readJSON()', () => {
it('should throw error if filename property is not provided', async () => {
try {
await uut.readJSON(obj)
assert(false, 'Unexpected result')
} catch (err) {
assert.include(err.message, 'fileName property must be a string')
}
})
it('should throw error if filename property is not string', async () => {
try {
await uut.readJSON(obj, 1)
assert(false, 'Unexpected result')
} catch (err) {
assert.include(err.message, 'fileName property must be a string')
}
})
it('should throw error if fs library return an error', async () => {
try {
// https://sinonjs.org/releases/latest/stubs/
// About yields
sandbox.stub(uut.fs, 'readFile').yields(new Error('test error'))
await uut.readJSON(JSON_PATH)
assert(false, 'Unexpected result')
} catch (err) {
assert.include(err.message, 'test error')
}
})
it('should throw error if file not found', async () => {
try {
const testError = new Error('test error')
testError.code = 'ENOENT'
sandbox.stub(uut.fs, 'readFile').yields(testError)
await uut.readJSON(JSON_PATH)
assert(false, 'Unexpected result')
} catch (err) {
assert.include(err.message, 'test error')
}
})
it('should read a json file', async () => {
try {
const result = await uut.readJSON(JSON_PATH)
const objKeys = Object.keys(obj)
const resultKeys = Object.keys(result)
assert.isObject(result)
assert.equal(objKeys.length, resultKeys.length)
} catch (err) {
assert(false, 'Unexpected result')
}
})
})
})
+231
View File
@@ -0,0 +1,231 @@
const assert = require('chai').assert
const sinon = require('sinon')
const util = require('util')
util.inspect.defaultOptions = { depth: 1 }
const LogsApiLib = require('../../../src/adapters/logapi')
const mockData = require('../mocks/log-api-mock')
const context = {}
let sandbox
let uut
describe('#LogsApiLib', () => {
beforeEach(() => {
uut = new LogsApiLib()
sandbox = sinon.createSandbox()
})
afterEach(() => sandbox.restore())
describe('#getLogs()', () => {
it('should return false if password is not provided', async () => {
try {
const result = await uut.getLogs()
assert.property(result, 'success')
assert.isFalse(result.success)
} catch (err) {
assert(false, 'Unexpected result')
}
})
it('should return log', async () => {
try {
const pass = 'test'
const result = await uut.getLogs(pass)
// console.log('result', result)
assert.isTrue(result.success)
assert.isArray(result.data)
assert.property(result.data[0], 'message')
assert.property(result.data[0], 'level')
assert.property(result.data[0], 'timestamp')
} catch (err) {
assert(false, 'Unexpected result')
}
})
it('should return false if files are not found!', async () => {
try {
sandbox.stub(uut, 'generateFileName').resolves('bad router')
const password = 'test'
const result = await uut.getLogs(password)
// console.log(result)
assert.isFalse(result.success)
assert.include(result.data, 'file does not exist')
} catch (err) {
console.log('ERRROR', err)
assert.fail('Unexpected result')
}
})
it('should catch and handle errors', async () => {
try {
// Force an error
sandbox.stub(uut.fs, 'existsSync').throws(new Error('test error'))
const password = 'test'
await uut.getLogs(password)
assert.fail('Unexpected result')
} catch (err) {
assert.include(err.message, 'test error')
}
})
it('should throw unhandled error', async () => {
try {
// Force an error
sandbox.stub(uut.fs, 'existsSync').throws(new Error('Unhandled error'))
const password = 'test'
await uut.getLogs(password)
assert.fail('Unexpected result')
} catch (err) {
assert.include(err.message, 'Unhandled error')
}
})
})
describe('#filterLogs()', () => {
it('should throw error if data is not provided', async () => {
try {
await uut.filterLogs()
assert.fail('Unexpected result')
} catch (err) {
assert.include(err.message, 'Data must be array')
}
})
it('should throw error if data provided is not an array', async () => {
try {
const data = 'data'
await uut.filterLogs(data)
assert.fail('Unexpected result')
} catch (err) {
assert.include(err.message, 'Data must be array')
}
})
it('should sort the log data', async () => {
try {
const data = mockData.data
const result = await uut.filterLogs(data)
assert.isArray(result)
assert.property(result[1], 'message')
assert.property(result[1], 'level')
assert.property(result[1], 'timestamp')
} catch (err) {
assert.fail('Unexpected result')
}
})
it('should sort the log data with a limit', async () => {
try {
const data = mockData.data
const limit = 1
const result = await uut.filterLogs(data, limit)
assert.isArray(result)
assert.equal(result.length, limit)
assert.property(result[0], 'message')
assert.property(result[0], 'level')
assert.property(result[0], 'timestamp')
} catch (err) {
assert.fail('Unexpected result')
}
})
})
describe('#generateFileName()', () => {
it('should return file name', async () => {
try {
const fileName = await uut.generateFileName()
assert.isString(fileName)
context.fileName = fileName
} catch (err) {
assert.fail('Unexpected result')
}
})
it('should throw error if something fails', async () => {
try {
uut.config = null
await uut.generateFileName()
assert.fail('Unexpected result')
} catch (err) {
assert.exists(err)
assert.isString(err.message)
}
})
})
describe('#readLines()', () => {
it('should throw error if fileName is not provided', async () => {
try {
await uut.readLines()
assert.fail('Unexpected result')
} catch (err) {
assert.include(err.message, 'filename must be a string')
}
})
it('should throw error if fileName provided is not string', async () => {
try {
const fileName = true
await uut.readLines(fileName)
assert.fail('Unexpected result')
} catch (err) {
assert.include(err.message, 'filename must be a string')
}
})
it('should throw error if the file does not exist', async () => {
try {
const fileName = 'test/logs/'
await uut.readLines(fileName)
assert.fail('Unexpected result')
} catch (err) {
assert.include(err.message, 'file does not exist')
}
})
it('should ignore fileReader callback errors', async () => {
try {
// https://sinonjs.org/releases/latest/stubs/
// About yields
sandbox.stub(uut.lineReader, 'eachLine').yieldsRight({}, true)
const fileName = context.fileName
const result = await uut.readLines(fileName)
assert.isArray(result)
} catch (err) {
assert.fail('Unexpected result')
}
})
it('should return data', async () => {
try {
const fileName = context.fileName
const result = await uut.readLines(fileName)
assert.isArray(result)
assert.property(result[1], 'message')
assert.property(result[1], 'level')
assert.property(result[1], 'timestamp')
} catch (err) {
assert.fail('Unexpected result')
}
})
})
})
@@ -0,0 +1,230 @@
/*
Unit tests for the nodemailer.js library.
*/
// Public npm libraries
const assert = require('chai').assert
const sinon = require('sinon')
const NodeMailer = require('../../../src/adapters/nodemailer')
let sandbox
let uut
describe('NodeMailer', () => {
beforeEach(() => {
uut = new NodeMailer()
sandbox = sinon.createSandbox()
})
afterEach(() => sandbox.restore())
describe('sendEmail()', () => {
it('should throw error if email property is not provided', async () => {
try {
const data = {
formMessage: 'test msg',
name: 'test name',
subject: 'test subject',
to: ['test2@email.com']
}
await uut.sendEmail(data)
assert(false, 'Unexpected result')
} catch (err) {
assert.include(err.message, "Property 'email' must be a string!")
}
})
it('should throw error if formMessage property is not provided', async () => {
try {
const data = {
email: 'test@email.com',
name: 'test name',
subject: 'test subject',
to: ['test2@email.com']
}
await uut.sendEmail(data)
assert(false, 'Unexpected result')
} catch (err) {
assert.include(err.message, "Property 'formMessage' must be a string!")
}
})
it('should throw error if <to> property is not provided', async () => {
try {
const data = {
email: 'test@email.com',
name: 'test name',
subject: 'test subject'
}
await uut.sendEmail(data)
assert(false, 'Unexpected result')
} catch (err) {
assert.include(err.message, "Property 'to' must be a array!")
}
})
it('should throw error if <to> is wrong type', async () => {
try {
const data = {
email: 'test@email.com',
formMessage: 'test msg',
name: 'test name',
subject: 'test subject',
to: 'test'
}
await uut.sendEmail(data)
assert(false, 'Unexpected result')
} catch (err) {
assert.include(err.message, "Property 'to' must be a array!")
}
})
it('should throw error if subject Property is not provided', async () => {
try {
const data = {
email: 'test@email.com',
formMessage: 'test msg',
name: 'test name',
to: ['test2@email.com']
}
await uut.sendEmail(data)
assert(false, 'Unexpected result')
} catch (err) {
assert.include(err.message, "Property 'subject' must be a string!")
}
})
it('should send email with default html data', async () => {
try {
sandbox
.stub(uut.transporter, 'sendMail')
.resolves({ messageId: 'messageId' })
const data = {
email: 'test@email.com',
formMessage: 'test msg',
to: ['test2@email.com'],
subject: 'test subject'
}
const info = await uut.sendEmail(data)
assert.isObject(info)
assert.isString(info.messageId)
} catch (err) {
assert(false, 'Unexpected result')
}
})
it('should send email if htmlData is provided', async () => {
try {
sandbox
.stub(uut.transporter, 'sendMail')
.resolves({ messageId: 'messageId' })
const data = {
email: 'test@email.com',
formMessage: 'test msg',
name: 'test name',
to: ['test2@email.com'],
subject: 'test subject',
htmlData: '<p> Unit test </p>'
}
const info = await uut.sendEmail(data)
assert.isObject(info)
assert.isString(info.messageId)
} catch (err) {
assert(false, 'Unexpected result')
}
})
})
describe('validateEmailArray()', () => {
it('should throw error if email list is not provided ', async () => {
try {
await uut.validateEmailArray()
assert(false, 'Unexpected result')
} catch (err) {
assert.include(err.message, "Property 'emailList' must be a array!")
}
})
it('should throw error if email list is empty', async () => {
try {
const emailList = []
await uut.validateEmailArray(emailList)
assert(false, 'Unexpected result')
} catch (err) {
assert.include(err.message, "Property 'emailList' cant be empty!")
}
})
it('should return true ', async () => {
try {
const emailList = ['test@email.com', 'simple@email.com']
const result = await uut.validateEmailArray(emailList)
assert.isTrue(result)
} catch (err) {
assert(false, 'Unexpected result')
}
})
})
describe('getHtmlFromObject()', () => {
it('should throw error if the input is not provided ', async () => {
try {
await uut.getHtmlFromObject()
assert(false, 'Unexpected result')
} catch (err) {
assert.include(err.message, "Property 'objectData' must be a object!")
}
})
it('should throw error if the object is empty', async () => {
try {
await uut.getHtmlFromObject({})
assert(false, 'Unexpected result')
} catch (err) {
assert.include(err.message, "Property 'subject' must be a string!")
}
})
it('should throw error if "formMessage" property is not provided', async () => {
try {
const obj = {
subject: 'unit'
}
await uut.getHtmlFromObject(obj)
assert(false, 'Unexpected result')
} catch (err) {
assert.include(err.message, "Property 'formMessage' must be a string!")
}
})
it('should return the html', async () => {
try {
const obj = {
subject: 'unit ',
formMessage: 'test',
value1: 'value1',
value2: 'value2',
value3: 'value3'
}
const result = await uut.getHtmlFromObject(obj)
assert.isString(result)
assert.include(result, '<p>', 'expect html tag')
assert.include(result, '</p>', 'expect html tag')
assert.include(
result,
'value1',
'Expect value 1 is included in the html'
)
assert.include(result, 'value2', 'expect is included in the html')
assert.include(result, 'value3', 'expect is included in the html')
} catch (err) {
assert(false, 'Unexpected result')
}
})
})
})
@@ -0,0 +1,46 @@
const assert = require('chai').assert
const PassportLib = require('../../../src/adapters/passport')
const sinon = require('sinon')
let uut
let sandbox
describe('#passport.js', () => {
beforeEach(() => {
uut = new PassportLib()
sandbox = sinon.createSandbox()
})
afterEach(() => sandbox.restore())
describe('authUser()', () => {
it('should throw error if ctx is not provided', async () => {
try {
await uut.authUser()
assert(false, 'Unexpected result')
} catch (err) {
assert.include(err.message, 'ctx is required')
}
})
it('Should throw error if the passport library fails', async () => {
try {
const error = new Error('cant auth user')
const user = null
// Mock calls
// https://sinonjs.org/releases/latest/stubs/
// About yields
sandbox.stub(uut.passport, 'authenticate').yields(error, user)
const ctx = {}
await uut.authUser(ctx)
assert(false, 'Unexpected result')
} catch (err) {
assert.include(err.message, 'cant auth user')
}
})
})
})
+82
View File
@@ -0,0 +1,82 @@
/*
Unit tests for the users Mongoose model.
*/
const assert = require('chai').assert
const sinon = require('sinon')
const mongoose = require('mongoose')
// Set the environment variable to signal this is a test.
process.env.SVC_ENV = 'test'
const User = require('../../../src/adapters/localdb/models/users')
const config = require('../../../config')
describe('#User-Adapter', () => {
// let uut
let sandbox
let testuser
before(async () => {
// Connect to the Mongo Database.
console.log(`Connecting to database: ${config.database}`)
mongoose.Promise = global.Promise
mongoose.set('useCreateIndex', true) // Stop deprecation warning.
await mongoose.connect(config.database, {
useUnifiedTopology: true,
useNewUrlParser: true
})
testuser = new User({
email: 'test983@test.com',
name: 'test983',
password: 'password'
})
})
beforeEach(async () => {
sandbox = sinon.createSandbox()
})
afterEach(() => sandbox.restore())
after(async () => {
await testuser.remove()
mongoose.connection.close()
})
describe('#save', () => {
it('should replace the password with a salt', async () => {
await testuser.save()
// console.log('testuser: ', testuser)
assert.notEqual(testuser.password, 'password')
})
})
describe('#validatePassword', () => {
it('should return true when password matches', async () => {
const result = await testuser.validatePassword('password')
// console.log('result: ', result)
assert.equal(result, true)
})
it('should return false when password does not match', async () => {
const result = await testuser.validatePassword('wrongpassword')
// console.log('result: ', result)
assert.equal(result, false)
})
})
describe('#generateToken', () => {
it('should generate a JWT token', () => {
const token = testuser.generateToken()
// console.log('token: ', token)
assert.include(token, 'eyJ')
})
})
})
@@ -0,0 +1,40 @@
const assert = require('chai').assert
const { Wlogger } = require('../../../src/adapters/wlogger')
const sinon = require('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()
})
})
})
+38
View File
@@ -0,0 +1,38 @@
/*
Unit tests for controllers index.js file.
*/
// Public npm libraries
// const assert = require('chai').assert
const sinon = require('sinon')
const Controllers = require('../../../src/controllers')
describe('#Controllers', () => {
let uut
let sandbox
beforeEach(() => {
sandbox = sinon.createSandbox()
uut = new Controllers()
})
afterEach(() => sandbox.restore())
describe('#attachControllers', () => {
it('should attach the controllers', async () => {
// mock IPFS
sandbox.stub(uut.adapters, 'start').resolves({})
uut.adapters.ipfs.ipfsCoordAdapter = {
attachRPCRouter: () => {}
}
const app = {
use: () => {}
}
await uut.attachControllers(app)
})
})
})
@@ -0,0 +1,298 @@
/*
Unit tests for the rpc/index.js library.
*/
// Public npm libraries
const assert = require('chai').assert
const jsonrpc = require('jsonrpc-lite')
const sinon = require('sinon')
const { v4: uid } = require('uuid')
// Set the environment variable to signal this is a test.
process.env.SVC_ENV = 'test'
// Local libraries.
const JSONRPC = require('../../../../src/controllers/json-rpc')
const adapters = require('../../mocks/adapters')
const UseCasesMock = require('../../mocks/use-cases')
describe('#JSON RPC', () => {
let uut
let sandbox
beforeEach(() => {
sandbox = sinon.createSandbox()
const useCases = new UseCasesMock()
uut = new JSONRPC({ adapters, useCases })
})
afterEach(() => sandbox.restore())
describe('#constructor', () => {
it('should throw an error if adapters are not passed in', () => {
try {
uut = new JSONRPC()
assert.fail('Unexpected code path')
} catch (err) {
assert.include(
err.message,
'Instance of Adapters library required when instantiating JSON RPC Controllers.'
)
}
})
it('should throw an error if useCases are not passed in', () => {
try {
uut = new JSONRPC({ adapters })
assert.fail('Unexpected code path')
} catch (err) {
assert.include(
err.message,
'Instance of Use Cases library required when instantiating JSON RPC Controllers.'
)
}
})
})
describe('#router', () => {
it('should exit quietly if given a random string', async () => {
const str = 'random string message'
await uut.router(str)
assert.isOk('Not throwing an error is a pass.')
})
it('should exit quietly if invalid JSON RPC message received', async () => {
const malformedRpc = '{"jsonrpc":"2.0"}'
await uut.router(malformedRpc, 'peerA')
assert.isOk('Not throwing an error is a pass.')
})
it('should return default response if routing is not possible', async () => {
const id = uid()
const json = jsonrpc.request(id, 'unknownMethod', {})
const str = JSON.stringify(json)
const result = await uut.router(str, 'peerA')
// console.log('result: ', result)
const jsonObj = jsonrpc.parse(result.retStr)
// console.log(`jsonObj: ${JSON.stringify(jsonObj, null, 2)}`)
// Assert the expected properties exist on the returned object.
assert.property(jsonObj, 'payload')
assert.property(jsonObj, 'type')
assert.property(jsonObj.payload, 'jsonrpc')
assert.property(jsonObj.payload, 'id')
assert.property(jsonObj.payload, 'result')
assert.property(jsonObj.payload.result, 'reciever')
assert.property(jsonObj.payload.result.value, 'success')
assert.property(jsonObj.payload.result.value, 'message')
// Assert the expected values exist.
assert.equal(jsonObj.payload.id, id)
assert.equal(jsonObj.payload.result.value.success, false)
assert.equal(jsonObj.payload.result.value.status, 422)
assert.equal(
jsonObj.payload.result.value.message,
'Input does not match routing rules.'
)
})
it('should catch and handle errors', async () => {
// Force an error
sandbox.stub(uut.jsonrpc, 'parse').throws(new Error('test error'))
const malformedRpc = '{"jsonrpc":"2.0"}'
await uut.router(malformedRpc, 'peerA')
assert.isOk('Not throwing an error is a pass.')
})
it('should route to users handler', async () => {
const id = uid()
const userCall = jsonrpc.request(id, 'users', { endpoint: 'getAll' })
const jsonStr = JSON.stringify(userCall, null, 2)
// Mock the users controller.
sandbox.stub(uut.userController, 'userRouter').resolves('true')
const result = await uut.router(jsonStr, 'peerA')
// console.log(result)
const obj = JSON.parse(result.retStr)
// console.log('obj: ', obj)
assert.equal(obj.result.value, 'true')
assert.equal(obj.result.method, 'users')
assert.equal(obj.id, id)
})
it('should route to auth handler', async () => {
const id = uid()
const userCall = jsonrpc.request(id, 'auth', { endpoint: 'getAll' })
const jsonStr = JSON.stringify(userCall, null, 2)
// Mock the controller.
sandbox.stub(uut.authController, 'authRouter').resolves('true')
const result = await uut.router(jsonStr, 'peerA')
// console.log(result)
const obj = JSON.parse(result.retStr)
// console.log('obj: ', obj)
assert.equal(obj.result.value, 'true')
assert.equal(obj.result.method, 'auth')
assert.equal(obj.id, id)
})
it('should route to about handler', async () => {
const id = uid()
const userCall = jsonrpc.request(id, 'about', { endpoint: 'getAll' })
const jsonStr = JSON.stringify(userCall, null, 2)
// Mock the controller.
sandbox.stub(uut.aboutController, 'aboutRouter').resolves('true')
// Force ipfs-coord communication.
uut.ipfsCoord.ipfs = {
orbitdb: {
sendToDb: () => {}
}
}
const result = await uut.router(jsonStr, 'peerA')
// console.log(result)
const obj = JSON.parse(result.retStr)
// console.log('obj: ', obj)
assert.equal(obj.result.value, 'true')
assert.equal(obj.result.method, 'about')
assert.equal(obj.id, id)
})
it('should exit quietly for duplicate RPC message', async () => {
const id = uid()
const json = jsonrpc.request(id, 'unknownMethod', {})
const str = JSON.stringify(json)
// Call router once.
await uut.router(str, 'peerA')
// Call the router again with the same input.
const result = await uut.router(str, 'peerA')
assert.equal(result, false)
})
it('should ignore metric queries from ipfs-coord', async () => {
const id = uid()
const json = jsonrpc.request(id, 'unknownMethod', {})
const str = JSON.stringify(json)
// Force the RPC type to be 'success', to indicate an RPC that was
// processed internal to ipfs-coord.
sandbox.stub(uut.jsonrpc, 'parse').returns({
payload: {},
type: 'success'
})
// Call the router again with the same input.
const result = await uut.router(str, 'peerA')
assert.equal(result, false)
})
it('should report errors when trying to send messages to peers', async () => {
const id = uid()
const json = jsonrpc.request(id, 'unknownMethod', {})
const str = JSON.stringify(json)
// Force issue with sendPrivateMessage()
sandbox
.stub(uut.ipfsCoord.useCases.peer, 'sendPrivateMessage')
.rejects('test error')
// Call the router again with the same input.
const result = await uut.router(str, 'peerA')
// console.log('result: ', result)
assert.property(result, 'from')
assert.property(result, 'retStr')
})
})
describe('#_checkIfAlreadyProcessed', () => {
it('should return false the first time an RPC command is seen', () => {
const data = {
payload: {
jsonrpc: '2.0',
id: '6c515f3c-cf8a-42ec-870e-e416edd4923f',
method: 'unknownMethod',
params: {}
},
type: 'request'
}
const result = uut._checkIfAlreadyProcessed(data)
assert.equal(result, false)
})
it('should return true the second time an RPC command is seen', () => {
const data = {
payload: {
jsonrpc: '2.0',
id: '6c515f3c-cf8a-42ec-870e-e416edd4923f',
method: 'unknownMethod',
params: {}
},
type: 'request'
}
// First call.
uut._checkIfAlreadyProcessed(data)
// Second call.
const result = uut._checkIfAlreadyProcessed(data)
assert.equal(result, true)
})
it('should push out old data from the cache for new data', () => {
const data = {
payload: {
jsonrpc: '2.0',
id: '6c515f3c-cf8a-42ec-870e-e416edd4923f',
method: 'unknownMethod',
params: {}
},
type: 'request'
}
uut.MSG_CACHE_SIZE = 0
const result = uut._checkIfAlreadyProcessed(data)
assert.equal(result, false)
})
it('should return true on error', () => {
const result = uut._checkIfAlreadyProcessed()
assert.equal(result, true)
})
})
})
@@ -0,0 +1,307 @@
/*
Unit tests for the JSON RPC validator middleware.
TODO: ensureTargetUserOrAdmin: it should exit quietly if user is an admin.
*/
// Public npm libraries
const jsonrpc = require('jsonrpc-lite')
const sinon = require('sinon')
const assert = require('chai').assert
const { v4: uid } = require('uuid')
// Set the environment variable to signal this is a test.
process.env.SVC_ENV = 'test'
// Local libraries
const Validators = require('../../../../src/controllers/json-rpc/validators')
const adapters = require('../../mocks/adapters')
describe('#validators', () => {
let uut
let sandbox
beforeEach(() => {
sandbox = sinon.createSandbox()
uut = new Validators({ adapters })
})
afterEach(() => sandbox.restore())
describe('#constructor', () => {
it('should throw an error if adapters is not passed in.', () => {
try {
uut = new Validators()
assert.fail('Unexpected code path')
} catch (err) {
assert.include(
err.message,
'Instance of Adapters library required when instantiating JSON RPC Validators library.'
)
}
})
})
describe('#ensureUser', () => {
it('should return user model for valid JWT token', async () => {
// Generate the parsed data that the main router would pass to this
// endpoint.
const id = uid()
const userCall = jsonrpc.request(id, 'users', {
endpoint: 'getAll',
apiToken: 'fakeJWTToken'
})
const jsonStr = JSON.stringify(userCall, null, 2)
const rpcData = jsonrpc.parse(jsonStr)
// Mock external dependencies.
sandbox.stub(uut.jwt, 'verify').returns(true)
sandbox.stub(uut.UserModel, 'findById').resolves(true)
const user = await uut.ensureUser(rpcData)
// console.log('user: ', user)
// For this test, we return a value of 'true' instead of actual user data.
assert.equal(user, true)
})
it('should throw an error if JWT token is not included', async () => {
try {
// Generate the parsed data that the main router would pass to this
// endpoint.
const id = uid()
const userCall = jsonrpc.request(id, 'users', {
endpoint: 'getAll'
})
const jsonStr = JSON.stringify(userCall, null, 2)
const rpcData = jsonrpc.parse(jsonStr)
await uut.ensureUser(rpcData)
assert.fail('Unexpected code path')
} catch (err) {
// console.log(err)
assert.include(err.message, 'apiToken JWT required as a parameter')
}
})
it('should throw an error if JWT token can not be decoded', async () => {
try {
const token =
'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjYwNmQxYTlkNTgxNTVjMjIzNWFmMTNhMSIsImlhdCI6MTYxNzc2Mjk3M30.6JkM1v0n71Mzsd3qzClzlMKtq6HlD0umoauG23N9FFF'
// Generate the parsed data that the main router would pass to this
// endpoint.
const id = uid()
const userCall = jsonrpc.request(id, 'users', {
endpoint: 'getAll',
apiToken: token
})
const jsonStr = JSON.stringify(userCall, null, 2)
const rpcData = jsonrpc.parse(jsonStr)
await uut.ensureUser(rpcData)
assert.fail('Unexpected code path')
} catch (err) {
// console.log(err)
assert.include(err.message, 'invalid signature')
}
})
it('should throw an error if the user can not be found', async () => {
try {
// Force 'error not found' error
sandbox.stub(uut.UserModel, 'findById').resolves(null)
sandbox.stub(uut.jwt, 'verify').returns(true)
// Generate the parsed data that the main router would pass to this
// endpoint.
const id = uid()
const userCall = jsonrpc.request(id, 'users', {
endpoint: 'getAll',
apiToken: 'fakeJWTToken'
})
const jsonStr = JSON.stringify(userCall, null, 2)
const rpcData = jsonrpc.parse(jsonStr)
await uut.ensureUser(rpcData)
assert.fail('Unexpected code path')
} catch (err) {
// console.log(err)
assert.include(err.message, 'User not found!')
}
})
})
describe('#ensureTargetUserOrAdmin', () => {
it('should return user model for valid JWT token', async () => {
// Generate the parsed data that the main router would pass to this
// endpoint.
const id = uid()
const userCall = jsonrpc.request(id, 'users', {
endpoint: 'deleteUser',
apiToken: 'fakeJWTToken',
userId: 'abc123'
})
const jsonStr = JSON.stringify(userCall, null, 2)
const rpcData = jsonrpc.parse(jsonStr)
// Mock external dependencies.
sandbox.stub(uut.jwt, 'verify').returns(true)
sandbox.stub(uut.UserModel, 'findById').resolves({ _id: 'abc123' })
const user = await uut.ensureTargetUserOrAdmin(rpcData)
// console.log('user: ', user)
// Assert that the mocked data expected is returned.
assert.equal(user._id, 'abc123')
})
it('should throw error if JWT token is not provided', async () => {
try {
// Generate the parsed data that the main router would pass to this
// endpoint.
const id = uid()
const userCall = jsonrpc.request(id, 'users', {
endpoint: 'deleteUser'
})
const jsonStr = JSON.stringify(userCall, null, 2)
const rpcData = jsonrpc.parse(jsonStr)
await uut.ensureTargetUserOrAdmin(rpcData)
assert.fail('Unexpected code path')
} catch (err) {
// console.log(err)
assert.include(err.message, 'apiToken JWT required as a parameter')
}
})
it('should throw error if user ID is not specified', async () => {
try {
// Generate the parsed data that the main router would pass to this
// endpoint.
const id = uid()
const userCall = jsonrpc.request(id, 'users', {
endpoint: 'deleteUser',
apiToken: 'fakeJWTToken'
})
const jsonStr = JSON.stringify(userCall, null, 2)
const rpcData = jsonrpc.parse(jsonStr)
await uut.ensureTargetUserOrAdmin(rpcData)
assert.fail('Unexpected code path')
} catch (err) {
// console.log(err)
assert.include(err.message, 'userId must be specified')
}
})
it('should throw error if JWT token can not be decoded', async () => {
try {
const token =
'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjYwNmU0YzkxYzdlYWNjN2Q4NWJjOGI0NCIsImlhdCI6MTYxNzg0MTI5N30.n1sas7YlqtmhBlNDBY_IXxQCrIQTiE8UITqy0PJAFFF'
// Generate the parsed data that the main router would pass to this
// endpoint.
const id = uid()
const userCall = jsonrpc.request(id, 'users', {
endpoint: 'deleteUser',
apiToken: token,
userId: 'abc123'
})
const jsonStr = JSON.stringify(userCall, null, 2)
const rpcData = jsonrpc.parse(jsonStr)
await uut.ensureTargetUserOrAdmin(rpcData)
assert.fail('Unexpected code path')
} catch (err) {
// console.log(err)
assert.include(err.message, 'invalid signature')
}
})
it('should throw an error if user can not be found', async () => {
try {
// Mock external dependencies.
sandbox.stub(uut.jwt, 'verify').returns(true)
sandbox.stub(uut.UserModel, 'findById').resolves(null)
// Generate the parsed data that the main router would pass to this
// endpoint.
const id = uid()
const userCall = jsonrpc.request(id, 'users', {
endpoint: 'deleteUser',
apiToken: 'fakeJWTToken',
userId: 'abc123'
})
const jsonStr = JSON.stringify(userCall, null, 2)
const rpcData = jsonrpc.parse(jsonStr)
await uut.ensureTargetUserOrAdmin(rpcData)
assert.fail('Unexpected code path')
} catch (err) {
// console.log(err)
assert.include(err.message, 'User not found!')
}
})
it('should throw an error if JWT is from a different user', async () => {
try {
// Mock external dependencies.
sandbox.stub(uut.jwt, 'verify').returns(true)
sandbox.stub(uut.UserModel, 'findById').resolves({ _id: 'badId' })
// Generate the parsed data that the main router would pass to this
// endpoint.
const id = uid()
const userCall = jsonrpc.request(id, 'users', {
endpoint: 'deleteUser',
apiToken: 'fakeJWTToken',
userId: 'abc123'
})
const jsonStr = JSON.stringify(userCall, null, 2)
const rpcData = jsonrpc.parse(jsonStr)
await uut.ensureTargetUserOrAdmin(rpcData)
assert.fail('Unexpected code path')
} catch (err) {
// console.log(err)
assert.include(err.message, 'User is neither admin nor target user.')
}
})
it('should return true if user is an admin', async () => {
// Generate the parsed data that the main router would pass to this
// endpoint.
const id = uid()
const userCall = jsonrpc.request(id, 'users', {
endpoint: 'deleteUser',
apiToken: 'fakeJWTToken',
userId: 'abc123'
})
const jsonStr = JSON.stringify(userCall, null, 2)
const rpcData = jsonrpc.parse(jsonStr)
// Mock external dependencies.
sandbox.stub(uut.jwt, 'verify').returns(true)
sandbox
.stub(uut.UserModel, 'findById')
.resolves({ _id: 'abc123', type: 'admin' })
const user = await uut.ensureTargetUserOrAdmin(rpcData)
// console.log('user: ', user)
// Assert that the mocked data expected is returned.
assert.equal(user, true)
})
})
})
@@ -0,0 +1,109 @@
/*
Unit tests for the JSON RPC validator middleware.
TODO: ensureTargetUserOrAdmin: it should exit quietly if user is an admin.
*/
// Public npm libraries
const sinon = require('sinon')
const assert = require('chai').assert
// Set the environment variable to signal this is a test.
process.env.SVC_ENV = 'test'
// Local libraries
const RateLimit = require('../../../../src/controllers/json-rpc/rate-limit')
describe('#rate-limit', () => {
let uut
let sandbox
beforeEach(() => {
sandbox = sinon.createSandbox()
uut = new RateLimit()
})
afterEach(() => sandbox.restore())
describe('#constructor', () => {
it('should use the options provided', async () => {
try {
const options = {
interval: { min: 10 },
delayAfter: 1,
timeWait: { sec: 5 },
max: 2,
onLimitReached: () => {
throw new Error('custom message error')
}
}
const _uut = new RateLimit(options)
// Assert options
assert.equal(_uut.rateLimitOptions.interval.min, options.interval.min)
assert.equal(_uut.rateLimitOptions.delayAfter, options.delayAfter)
assert.equal(_uut.rateLimitOptions.timeWait.sec, options.timeWait.sec)
const from = 'constructor test'
const firstRequest = await _uut.limiter(from)
assert.isTrue(firstRequest)
const secondRequest = await _uut.limiter(from)
assert.isTrue(secondRequest)
await _uut.limiter(from)
assert.fail('unexpected error')
} catch (error) {
assert.include(error.message, 'custom message error')
}
})
})
describe('#onLimitReached', () => {
it('should throw error', async () => {
try {
uut.onLimitReached()
assert.fail('unexpected error')
} catch (error) {
assert.equal(error.status, 429)
assert.include(
error.message,
'Too many requests, please try again later.'
)
}
})
})
describe('#limiter', () => {
it('should throw error if "from" input is not provider', async () => {
try {
await uut.limiter()
assert.fail('unexpected error')
} catch (error) {
assert.include(error.message, 'from must be a string')
}
})
it('should throw error 429', async () => {
try {
const _uut = new RateLimit({ max: 1 })
const from = 'Origin request'
const firstRequest = await _uut.limiter(from)
assert.isTrue(firstRequest)
const secondRequest = await _uut.limiter(from)
assert.isTrue(secondRequest)
await _uut.limiter(from)
assert.fail('unexpected error')
} catch (error) {
assert.include(
error.message,
'Too many requests, please try again later.'
)
}
})
})
})
@@ -0,0 +1,38 @@
/*
Unit tests for the json-rpc/about/index.js file.
*/
// Public npm libraries
const sinon = require('sinon')
const assert = require('chai').assert
// Local libraries
const AboutRPC = require('../../../../src/controllers/json-rpc/about')
describe('#AboutRPC', () => {
let uut
let sandbox
beforeEach(() => {
sandbox = sinon.createSandbox()
uut = new AboutRPC()
})
afterEach(() => sandbox.restore())
describe('#aboutRouter', () => {
it('should return information about the service', async () => {
const result = await uut.aboutRouter()
// console.log('result: ', result)
assert.property(result, 'success')
assert.equal(result.success, true)
assert.property(result, 'status')
assert.equal(result.status, 200)
assert.property(result, 'message')
assert.property(result, 'endpoint')
assert.equal(result.endpoint, 'about')
})
})
})
@@ -0,0 +1,194 @@
/*
Unit tests for the json-rpc/auth/index.js file.
*/
// Public npm libraries
const jsonrpc = require('jsonrpc-lite')
const sinon = require('sinon')
const assert = require('chai').assert
const { v4: uid } = require('uuid')
// Set the environment variable to signal this is a test.
process.env.SVC_ENV = 'test'
// Local libraries
const AuthRPC = require('../../../../src/controllers/json-rpc/auth')
const RateLimit = require('../../../../src/controllers/json-rpc/rate-limit')
const adapters = require('../../mocks/adapters')
const UseCasesMock = require('../../mocks/use-cases')
describe('#AuthRPC', () => {
let uut
let sandbox
beforeEach(() => {
sandbox = sinon.createSandbox()
const useCases = new UseCasesMock()
uut = new AuthRPC({ adapters, useCases })
uut.rateLimit = new RateLimit({ max: 100 })
})
afterEach(() => sandbox.restore())
describe('#constructor', () => {
it('should throw an error if adapters are not passed in', () => {
try {
uut = new AuthRPC()
assert.fail('Unexpected code path')
} catch (err) {
assert.include(
err.message,
'Instance of Adapters library required when instantiating Auth JSON RPC Controller.'
)
}
})
it('should throw an error if useCases are not passed in', () => {
try {
uut = new AuthRPC({ adapters })
assert.fail('Unexpected code path')
} catch (err) {
assert.include(
err.message,
'Instance of Use Cases library required when instantiating Auth JSON RPC Controller.'
)
}
})
})
describe('#authRouter', () => {
it('should route to the authUser method', async () => {
// Mock dependencies
sandbox.stub(uut, 'authUser').resolves(true)
// Generate the parsed data that the main router would pass to this
// endpoint.
const id = uid()
const authCall = jsonrpc.request(id, 'auth', { endpoint: 'authUser' })
const jsonStr = JSON.stringify(authCall, null, 2)
const rpcData = jsonrpc.parse(jsonStr)
rpcData.from = 'Origin request'
const result = await uut.authRouter(rpcData)
assert.equal(result, true)
})
it('should return 500 status on routing issue', async () => {
// Mock dependencies
sandbox.stub(uut, 'authUser').rejects(new Error('test error'))
// Generate the parsed data that the main router would pass to this
// endpoint.
const id = uid()
const authCall = jsonrpc.request(id, 'auth', { endpoint: 'authUser' })
const jsonStr = JSON.stringify(authCall, null, 2)
const rpcData = jsonrpc.parse(jsonStr)
rpcData.from = 'Origin request'
const result = await uut.authRouter(rpcData)
assert.equal(result.success, false)
assert.equal(result.status, 500)
assert.equal(result.message, 'test error')
assert.equal(result.endpoint, 'authUser')
})
})
describe('#authUser', () => {
it('should return a JWT token if user successfully authenticates', async () => {
// Generate the parsed data that the main router would pass to this
// endpoint.
const id = uid()
const authCall = jsonrpc.request(id, 'auth', {
endpoint: 'authUser',
login: 'test543@test.com',
password: 'password'
})
const jsonStr = JSON.stringify(authCall, null, 2)
const rpcData = jsonrpc.parse(jsonStr)
const response = await uut.authUser(rpcData)
// console.log('response: ', response)
assert.equal(response.endpoint, 'authUser')
assert.property(response, 'userId')
// assert.equal(response.userType, 'user')
assert.property(response, 'userName')
assert.property(response, 'userEmail')
assert.property(response, 'apiToken')
assert.equal(response.status, 200)
assert.equal(response.success, true)
assert.property(response, 'message')
})
it('should return an error for invalid credentials', async () => {
// Generate the parsed data that the main router would pass to this
// endpoint.
const id = uid()
const authCall = jsonrpc.request(id, 'auth', {
endpoint: 'authUser',
login: 'test543@test.com',
password: 'badpassword'
})
const jsonStr = JSON.stringify(authCall, null, 2)
const rpcData = jsonrpc.parse(jsonStr)
// Force an error.
sandbox
.stub(uut.userLib, 'authUser')
.rejects(new Error('Login credential do not match'))
const response = await uut.authUser(rpcData)
// console.log('response: ', response)
assert.equal(response.success, false)
assert.equal(response.status, 422)
assert.equal(response.message, 'Login credential do not match')
assert.equal(response.endpoint, 'authUser')
})
it('should throw an error if login is not provided', async () => {
// Generate the parsed data that the main router would pass to this
// endpoint.
const id = uid()
const authCall = jsonrpc.request(id, 'auth', {
endpoint: 'authUser'
})
const jsonStr = JSON.stringify(authCall, null, 2)
const rpcData = jsonrpc.parse(jsonStr)
const response = await uut.authUser(rpcData)
// console.log('response: ', response)
assert.equal(response.success, false)
assert.equal(response.status, 422)
assert.equal(response.message, 'login must be specified')
assert.equal(response.endpoint, 'authUser')
})
it('should throw an error if password is not provided', async () => {
// Generate the parsed data that the main router would pass to this
// endpoint.
const id = uid()
const authCall = jsonrpc.request(id, 'auth', {
endpoint: 'authUser',
login: 'test543@test.com'
})
const jsonStr = JSON.stringify(authCall, null, 2)
const rpcData = jsonrpc.parse(jsonStr)
const response = await uut.authUser(rpcData)
// console.log('response: ', response)
assert.equal(response.success, false)
assert.equal(response.status, 422)
assert.equal(response.message, 'password must be specified')
assert.equal(response.endpoint, 'authUser')
})
})
})
@@ -0,0 +1,412 @@
/*
Unit tests for the rpc/users/index.js file.
*/
// Public npm libraries
const jsonrpc = require('jsonrpc-lite')
const sinon = require('sinon')
const assert = require('chai').assert
const { v4: uid } = require('uuid')
// Set the environment variable to signal this is a test.
process.env.SVC_ENV = 'test'
// Local libraries
const UserRPC = require('../../../../src/controllers/json-rpc/users')
const adapters = require('../../mocks/adapters')
const UseCasesMock = require('../../mocks/use-cases')
describe('#UserRPC', () => {
let uut
let sandbox
let testUser
beforeEach(() => {
sandbox = sinon.createSandbox()
const useCases = new UseCasesMock()
uut = new UserRPC({ adapters, useCases })
})
afterEach(() => sandbox.restore())
describe('#constructor', () => {
it('should throw an error if adapters are not passed in', () => {
try {
uut = new UserRPC()
assert.fail('Unexpected code path')
} catch (err) {
assert.include(
err.message,
'Instance of Adapters library required when instantiating User JSON RPC Controller.'
)
}
})
it('should throw an error if useCases are not passed in', () => {
try {
uut = new UserRPC({ adapters })
assert.fail('Unexpected code path')
} catch (err) {
assert.include(
err.message,
'Instance of Use Cases library required when instantiating User JSON RPC Controller.'
)
}
})
})
describe('#createUser', () => {
it('should create a new user', async () => {
// Generate the parsed data that the main router would pass to this
// endpoint.
const id = uid()
const userCall = jsonrpc.request(id, 'users', {
endpoint: 'createUser',
email: 'test973@test.com',
name: 'test973',
password: 'password'
})
const jsonStr = JSON.stringify(userCall, null, 2)
const rpcData = jsonrpc.parse(jsonStr)
const result = await uut.createUser(rpcData)
// console.log('result: ', result)
// CreateUser() specific return values.
// assert.equal(result.userData.type, 'user')
// assert.equal(result.userData.email, 'test973@test.com')
// assert.equal(result.userData.name, 'test973')
// assert.property(result.userData, '_id')
// assert.property(result, 'token')
// Generic JSON RPC return values
assert.equal(result.endpoint, 'createUser')
assert.equal(result.success, true)
assert.equal(result.status, 200)
assert.equal(result.message, '')
// Save the user ID for future tests.
testUser = result
})
it('should return error data if biz logic throws an error', async () => {
// Force an error
sandbox.stub(uut.userLib, 'createUser').rejects(new Error('test error'))
// Generate the parsed data that the main router would pass to this
// endpoint.
const id = uid()
const userCall = jsonrpc.request(id, 'users', {
endpoint: 'createUser',
email: 'test973@test.com',
name: 'test973',
password: 'password'
})
const jsonStr = JSON.stringify(userCall, null, 2)
const rpcData = jsonrpc.parse(jsonStr)
const result = await uut.createUser(rpcData)
// console.log('result: ', result)
// Generic JSON RPC return values
assert.equal(result.endpoint, 'createUser')
assert.equal(result.success, false)
assert.equal(result.status, 422)
assert.equal(result.message, 'test error')
})
})
describe('#userRouter', () => {
it('should route to the createUser method', async () => {
// Mock dependencies
sandbox.stub(uut, 'createUser').resolves(true)
// Generate the parsed data that the main router would pass to this
// endpoint.
const id = uid()
const userCall = jsonrpc.request(id, 'users', { endpoint: 'createUser' })
const jsonStr = JSON.stringify(userCall, null, 2)
const rpcData = jsonrpc.parse(jsonStr)
rpcData.from = 'Origin request'
const result = await uut.userRouter(rpcData)
assert.equal(result, true)
})
it('should route to the getAllUsers method', async () => {
// Mock dependencies
sandbox.stub(uut, 'getAll').resolves(true)
// Generate the parsed data that the main router would pass to this
// endpoint.
const id = uid()
const userCall = jsonrpc.request(id, 'users', {
endpoint: 'getAllUsers',
apiToken: testUser.token
})
const jsonStr = JSON.stringify(userCall, null, 2)
const rpcData = jsonrpc.parse(jsonStr)
rpcData.from = 'Origin request'
// Force middleware to pass.
sandbox.stub(uut.validators, 'ensureUser').resolves(true)
const result = await uut.userRouter(rpcData)
// console.log('result', result)
assert.equal(result, true)
})
it('should route to the updateUser method', async () => {
// Mock dependencies
sandbox.stub(uut, 'updateUser').resolves(true)
// Generate the parsed data that the main router would pass to this
// endpoint.
const id = uid()
const userCall = jsonrpc.request(id, 'users', {
endpoint: 'updateUser',
apiToken: 'fakeJWTToken',
userId: 'abc123'
})
const jsonStr = JSON.stringify(userCall, null, 2)
const rpcData = jsonrpc.parse(jsonStr)
rpcData.from = 'Origin request'
// Force middleware to pass.
sandbox.stub(uut.validators, 'ensureTargetUserOrAdmin').resolves(true)
const result = await uut.userRouter(rpcData)
// console.log('result: ', result)
assert.equal(result, true)
})
it('should route to the getUser method', async () => {
// Mock dependencies
sandbox.stub(uut, 'getUser').resolves(true)
// Generate the parsed data that the main router would pass to this
// endpoint.
const id = uid()
const userCall = jsonrpc.request(id, 'users', {
endpoint: 'getUser',
apiToken: testUser.token
})
const jsonStr = JSON.stringify(userCall, null, 2)
const rpcData = jsonrpc.parse(jsonStr)
rpcData.from = 'Origin request'
// Force middleware to pass.
sandbox.stub(uut.validators, 'ensureUser').resolves(true)
const result = await uut.userRouter(rpcData)
// console.log('result: ', result)
assert.equal(result, true)
})
it('should route to the deleteUsers method', async () => {
// Mock dependencies
sandbox.stub(uut, 'deleteUser').resolves(true)
// Generate the parsed data that the main router would pass to this
// endpoint.
const id = uid()
const userCall = jsonrpc.request(id, 'users', {
endpoint: 'deleteUser',
apiToken: 'fakeJWTToken',
userId: 'abc123'
})
const jsonStr = JSON.stringify(userCall, null, 2)
const rpcData = jsonrpc.parse(jsonStr)
rpcData.from = 'Origin request'
// Force middleware to pass.
sandbox.stub(uut.validators, 'ensureTargetUserOrAdmin').resolves(true)
const result = await uut.userRouter(rpcData)
// console.log('result: ', result)
assert.equal(result, true)
})
it('should return 500 status on routing issue', async () => {
// Force an error
sandbox.stub(uut, 'createUser').rejects(new Error('test error'))
// Generate the parsed data that the main router would pass to this
// endpoint.
const id = uid()
const userCall = jsonrpc.request(id, 'users', { endpoint: 'createUser' })
const jsonStr = JSON.stringify(userCall, null, 2)
const rpcData = jsonrpc.parse(jsonStr)
rpcData.from = 'Origin request'
const result = await uut.userRouter(rpcData)
// console.log('result: ', result)
assert.equal(result.success, false)
assert.equal(result.status, 500)
assert.equal(result.message, 'test error')
assert.equal(result.endpoint, 'createUser')
})
})
describe('#getAllUsers', () => {
it('should return all users', async () => {
const result = await uut.getAll()
// console.log('getAll result: ', result)
// Endpoint specific properties
assert.property(result, 'users')
// Generic JSON RPC return values
assert.equal(result.endpoint, 'getAllUsers')
assert.equal(result.success, true)
assert.equal(result.status, 200)
assert.equal(result.message, '')
})
it('should return error data if biz logic throws an error', async () => {
// Force an error
sandbox.stub(uut.userLib, 'getAllUsers').rejects(new Error('test error'))
const result = await uut.getAll()
// console.log('result: ', result)
// Generic JSON RPC return values
assert.equal(result.endpoint, 'getAllUsers')
assert.equal(result.success, false)
assert.equal(result.status, 422)
assert.equal(result.message, 'test error')
})
})
describe('#updateUser', () => {
it('should update a user', async () => {
// Get the user model for the test user.
// const testUserModel = await UserModel.findById(
// testUser.userData._id,
// '-password'
// )
// Generate the parsed data that the main router would pass to this
// endpoint.
const id = uid()
const userCall = jsonrpc.request(id, 'users', {
endpoint: 'updateUser',
// userId: testUser.userData._id.toString(),
userId: 'abc123',
name: 'test777'
})
const jsonStr = JSON.stringify(userCall, null, 2)
const rpcData = jsonrpc.parse(jsonStr)
const result = await uut.updateUser(rpcData, {})
// console.log('updateUser result: ', result)
// Endpoint specific properties
assert.property(result, 'user')
// assert.property(result.user, 'type')
// assert.property(result.user, '_id')
// assert.property(result.user, 'email')
// assert.property(result.user, 'name')
// Generic JSON RPC return values
assert.equal(result.endpoint, 'updateUser')
assert.equal(result.success, true)
assert.equal(result.status, 200)
assert.equal(result.message, '')
})
it('should return error data if biz logic throws an error', async () => {
// Force an error by not specifying an user ID.
const result = await uut.updateUser()
// console.log('result: ', result)
// Generic JSON RPC return values
assert.equal(result.endpoint, 'updateUser')
assert.equal(result.success, false)
assert.equal(result.status, 422)
assert.include(result.message, 'Cannot read property')
})
})
describe('#getUser', () => {
it('should return a specific user', async () => {
// Generate the parsed data that the main router would pass to this
// endpoint.
const id = uid()
const userCall = jsonrpc.request(id, 'users', {
endpoint: 'getUser',
userId: 'abc123'
})
const jsonStr = JSON.stringify(userCall, null, 2)
const rpcData = jsonrpc.parse(jsonStr)
const result = await uut.getUser(rpcData)
// console.log('getUser result: ', result)
// Endpoint specific properties
assert.property(result, 'user')
// assert.property(result.user, 'type')
// assert.property(result.user, '_id')
// assert.property(result.user, 'email')
// assert.property(result.user, 'name')
// Generic JSON RPC return values
assert.equal(result.endpoint, 'getUser')
assert.equal(result.success, true)
assert.equal(result.status, 200)
assert.equal(result.message, '')
})
it('should return error data if biz logic throws an error', async () => {
// Force an error by not specifying an user ID.
const result = await uut.getUser()
// console.log('result: ', result)
// Generic JSON RPC return values
assert.equal(result.endpoint, 'getUser')
assert.equal(result.success, false)
assert.equal(result.status, 422)
assert.include(result.message, 'Cannot read property')
})
})
describe('#deleteUser', () => {
it('should delete a user', async () => {
// Get the user model for the test user.
// const testUserModel = await UserModel.findById(
// testUser.userData._id,
// '-password'
// )
await uut.deleteUser({}, {})
// console.log(result)
assert.isOk('Not throwing an error is a success')
})
it('should return error data if biz logic throws an error', async () => {
// Force an error:
sandbox
.stub(uut.userLib, 'deleteUser')
.rejects(new Error('Cannot read property'))
const result = await uut.deleteUser()
// console.log('result: ', result)
// Generic JSON RPC return values
assert.equal(result.endpoint, 'deleteUser')
assert.equal(result.success, false)
assert.equal(result.status, 422)
assert.include(result.message, 'Cannot read property')
})
})
})
+9
View File
@@ -0,0 +1,9 @@
# REST API Unit Tests
The tests in this directory are unit tests of REST API. These tests are not
concerned with the business logic behind the endpoints. They are only concerned
with the handling of the REST API endpoint. These tests answer questions like:
- Is the endpoint responding properly when the business logic throws an error?
- When returning an error, is it returning the proper HTTP response?
- When returning success, is it returning the correct payload?
@@ -0,0 +1,90 @@
/*
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 AuthRESTController = require('../../../../../src/controllers/rest-api/auth/controller')
let uut
let sandbox
let ctx
const mockContext = require('../../../../unit/mocks/ctx-mock').context
describe('#Auth-REST-Router', () => {
// const testUser = {}
beforeEach(() => {
const useCases = new UseCasesMock()
uut = new AuthRESTController({ 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 AuthRESTController()
assert.fail('Unexpected code path')
} catch (err) {
assert.include(
err.message,
'Instance of Adapters library required when instantiating Auth REST Controller.'
)
}
})
it('should throw an error if useCases are not passed in', () => {
try {
uut = new AuthRESTController({ adapters })
assert.fail('Unexpected code path')
} catch (err) {
assert.include(
err.message,
'Instance of Use Cases library required when instantiating Auth REST Controller.'
)
}
})
})
describe('#authUser', () => {
it('should authorize a user', async () => {
// Mock dependencies
const user = {
toJSON: () => {
return { password: 'password' }
},
generateToken: () => {}
}
sandbox.stub(uut.passport, 'authUser').resolves(user)
await uut.authUser(ctx)
})
it('should catch and throw an 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')
}
})
})
})
@@ -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 AuthRouter = require('../../../../../src/controllers/rest-api/auth')
let uut
let sandbox
// let ctx
// const mockContext = require('../../../../unit/mocks/ctx-mock').context
describe('#Auth-REST-Router', () => {
// const testUser = {}
beforeEach(() => {
const useCases = new UseCasesMock()
uut = new AuthRouter({ 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 AuthRouter()
assert.fail('Unexpected code path')
} catch (err) {
assert.include(
err.message,
'Instance of Adapters library required when instantiating PostEntry REST Controller.'
)
}
})
it('should throw an error if useCases are not passed in', () => {
try {
uut = new AuthRouter({ adapters })
assert.fail('Unexpected code path')
} catch (err) {
assert.include(
err.message,
'Instance of Use Cases library required when instantiating PostEntry 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 attached REST API controllers.'
)
}
})
})
})
@@ -0,0 +1,88 @@
/*
Unit tests for the REST API handler for the /users endpoints.
*/
// Public npm libraries
const assert = require('chai').assert
const sinon = require('sinon')
const ContactController = require('../../../../../src/controllers/rest-api/contact/controller')
let uut
let sandbox
let ctx
const mockContext = require('../../../../unit/mocks/ctx-mock').context
describe('Contact', () => {
before(async () => {})
beforeEach(() => {
uut = new ContactController()
sandbox = sinon.createSandbox()
// Mock the context object.
ctx = mockContext()
})
afterEach(() => sandbox.restore())
describe('#POST /contact', () => {
it('should return 422 status on biz logic error', async () => {
try {
await uut.email(ctx)
assert.fail('Unexpected result')
} catch (err) {
// console.log(err)
assert.equal(err.status, 422)
assert.include(err.message, 'Cannot read property')
}
})
it('should return 200 status on success', async () => {
sandbox.stub(uut.contactLib, 'sendEmail').resolves(true)
ctx.request.body = {
email: 'test02@test.com',
formMessage: 'test'
}
await uut.email(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)
})
})
describe('#handleError', () => {
it('should pass an error message', () => {
try {
const err = {
status: 422,
message: 'Unprocessable Entity'
}
uut.handleError(ctx, err)
} catch (err) {
assert.include(err.message, 'Unprocessable Entity')
}
})
it('should still throw error if there is no message', () => {
try {
const err = {
status: 404
}
uut.handleError(ctx, err)
} catch (err) {
assert.include(err.message, 'Not Found')
}
})
})
})
@@ -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 ContactRouter = require('../../../../../src/controllers/rest-api/contact')
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 ContactRouter({ 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 ContactRouter()
assert.fail('Unexpected code path')
} catch (err) {
assert.include(
err.message,
'Instance of Adapters library required when instantiating Contact REST Controller.'
)
}
})
it('should throw an error if useCases are not passed in', () => {
try {
uut = new ContactRouter({ adapters })
assert.fail('Unexpected code path')
} catch (err) {
assert.include(
err.message,
'Instance of Use Cases library required when instantiating Contact 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.'
)
}
})
})
})
@@ -0,0 +1,75 @@
/*
Unit tests for the REST API handler for the /users endpoints.
*/
// Public npm libraries
const assert = require('chai').assert
const sinon = require('sinon')
const LogsApiController = require('../../../../../src/controllers/rest-api/logs/controller')
let uut
let sandbox
let ctx
const mockContext = require('../../../../unit/mocks/ctx-mock').context
describe('Logapi', () => {
before(async () => {})
beforeEach(() => {
uut = new LogsApiController()
sandbox = sinon.createSandbox()
// Mock the context object.
ctx = mockContext()
})
afterEach(() => sandbox.restore())
describe('#POST /logapi', () => {
it('should return 422 status on biz logic error', async () => {
try {
await uut.getLogs(ctx)
assert.fail('Unexpected result')
} catch (err) {
assert.equal(err.status, 422)
assert.include(err.message, 'Cannot read property')
}
})
it('should return 500 status on biz logic Unhandled error', async () => {
try {
// eslint-disable
sandbox
.stub(uut.logsApiLib, 'getLogs')
.returns(Promise.reject(new Error()))
ctx.request.body = {
password: 'test'
}
await uut.getLogs(ctx)
assert.fail('Unexpected result')
} catch (err) {
assert.equal(err.status, 500)
assert.include(err.message, 'Unhandled error')
}
})
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.isOk(ctx.body)
})
})
})
@@ -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.'
)
}
})
})
})
@@ -0,0 +1,64 @@
/*
Unit tests for the REST API controllers/rest-api/index.js library.
*/
// Public npm libraries
const assert = require('chai').assert
const sinon = require('sinon')
// Local libraries
const RESTControllers = require('../../../../src/controllers/rest-api/')
// const mockContext = require('../../../unit/mocks/ctx-mock').context
const adapters = require('../../mocks/adapters')
const UseCasesMock = require('../../mocks/use-cases')
describe('#RESTControllers', () => {
let uut
let sandbox
// let ctx
before(async () => {})
beforeEach(() => {
const useCases = new UseCasesMock()
uut = new RESTControllers({ 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 RESTControllers()
assert.fail('Unexpected code path')
} catch (err) {
assert.include(
err.message,
'Instance of Adapters library required when instantiating REST Controller libraries.'
)
}
})
it('should throw an error if useCases are not passed in', () => {
try {
uut = new RESTControllers({ adapters })
assert.fail('Unexpected code path')
// use to prevent complaints from linter.
console.log('uut: ', uut)
} catch (err) {
assert.include(
err.message,
'Instance of Use Cases library required when instantiating REST Controller libraries.'
)
}
})
})
})
@@ -0,0 +1,258 @@
/*
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 UserController = require('../../../../../src/controllers/rest-api/users/controller')
let uut
let sandbox
let ctx
const mockContext = require('../../../../unit/mocks/ctx-mock').context
describe('#Users-REST-Controller', () => {
// const testUser = {}
beforeEach(() => {
const useCases = new UseCasesMock()
uut = new UserController({ 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 UserController()
assert.fail('Unexpected code path')
} catch (err) {
assert.include(
err.message,
'Instance of Adapters library required when instantiating /users REST Controller.'
)
}
})
it('should throw an error if useCases are not passed in', () => {
try {
uut = new UserController({ adapters })
assert.fail('Unexpected code path')
} catch (err) {
assert.include(
err.message,
'Instance of Use Cases library required when instantiating /users REST Controller.'
)
}
})
})
describe('#POST /users', () => {
it('should return 422 status on biz logic error', async () => {
try {
await uut.createUser(ctx)
assert.fail('Unexpected result')
} catch (err) {
// console.log(err)
assert.equal(err.status, 422)
assert.include(err.message, 'Cannot read property')
}
})
it('should return 200 status on success', async () => {
ctx.request.body = {
user: {
email: 'test02@test.com',
password: 'test',
name: 'test02'
}
}
await uut.createUser(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, 'user')
assert.property(ctx.response.body, 'token')
// Used by downstream tests.
// testUser = ctx.response.body.user
// console.log('testUser: ', testUser)
})
})
describe('GET /users', () => {
it('should return 422 status on arbitrary biz logic error', async () => {
try {
// Force an error
sandbox
.stub(uut.useCases.user, 'getAllUsers')
.rejects(new Error('test error'))
await uut.getUsers(ctx)
assert.fail('Unexpected result')
} catch (err) {
assert.equal(err.status, 422)
assert.include(err.message, 'test error')
}
})
it('should return 200 status on success', async () => {
await uut.getUsers(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, 'users')
})
})
describe('GET /users/:id', () => {
it('should return 422 status on arbitrary biz logic error', async () => {
try {
// Force an error
sandbox
.stub(uut.useCases.user, 'getUser')
.rejects(new Error('test error'))
await uut.getUser(ctx)
assert.fail('Unexpected result')
} catch (err) {
assert.equal(err.status, 422)
assert.include(err.message, 'test error')
}
})
it('should return 200 status on success', async () => {
// Mock dependencies
sandbox.stub(uut.useCases.user, 'getUser').resolves({ _id: '123' })
await uut.getUser(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, 'user')
})
it('should return other error status passed by biz logic', async () => {
try {
// Mock dependencies
const testErr = new Error('test error')
testErr.status = 404
sandbox.stub(uut.useCases.user, 'getUser').rejects(testErr)
await uut.getUser(ctx)
assert.fail('Unexpected result')
} catch (err) {
assert.equal(err.status, 404)
assert.include(err.message, 'test error')
}
})
})
describe('PUT /users/:id', () => {
it('should return 422 if no input data given', async () => {
try {
await uut.updateUser(ctx)
assert.fail('Unexpected result')
} catch (err) {
// console.log(err)
assert.equal(err.status, 422)
assert.include(err.message, 'Cannot read property')
}
})
it('should return 200 on success', async () => {
// Prep the testUser data.
// console.log('testUser: ', testUser)
// testUser.password = 'password'
// delete testUser.type
// Replace the testUser variable with an actual model from the DB.
// const existingUser = await User.findById(testUser._id)
ctx.body = {
user: {}
}
ctx.request.body = {
user: {}
}
// Mock dependencies
sandbox.stub(uut.useCases.user, 'updateUser').resolves({})
await uut.updateUser(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, 'user')
})
})
describe('DELETE /users/:id', () => {
it('should return 422 if no input data given', async () => {
try {
await uut.deleteUser(ctx)
assert.fail('Unexpected result')
} catch (err) {
// console.log(err)
assert.equal(err.status, 422)
assert.include(err.message, 'Cannot read property')
}
})
it('should return 200 status on success', async () => {
// Replace the testUser variable with an actual model from the DB.
const existingUser = {}
ctx.body = {
user: existingUser
}
await uut.deleteUser(ctx)
// Assert the expected HTTP response
assert.equal(ctx.status, 200)
})
})
describe('#handleError', () => {
it('should still throw error if there is no message', () => {
try {
const err = {
status: 404
}
uut.handleError(ctx, err)
} catch (err) {
assert.include(err.message, 'Not Found')
}
})
})
})
@@ -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 UserRouter = require('../../../../../src/controllers/rest-api/users')
let uut
let sandbox
// let ctx
// const mockContext = require('../../../../unit/mocks/ctx-mock').context
describe('#Users-REST-Router', () => {
// const testUser = {}
beforeEach(() => {
const useCases = new UseCasesMock()
uut = new UserRouter({ 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 UserRouter()
assert.fail('Unexpected code path')
} catch (err) {
assert.include(
err.message,
'Instance of Adapters library required when instantiating PostEntry REST Controller.'
)
}
})
it('should throw an error if useCases are not passed in', () => {
try {
uut = new UserRouter({ adapters })
assert.fail('Unexpected code path')
} catch (err) {
assert.include(
err.message,
'Instance of Use Cases library required when instantiating PostEntry 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.'
)
}
})
})
})
+69
View File
@@ -0,0 +1,69 @@
/*
Unit tests for the User entity library.
*/
const assert = require('chai').assert
const sinon = require('sinon')
const User = require('../../../src/entities/user')
let sandbox
let uut
describe('#User-Entity', () => {
before(async () => {})
beforeEach(() => {
uut = new User()
sandbox = sinon.createSandbox()
})
afterEach(() => sandbox.restore())
describe('#validate', () => {
it('should throw an error if email is not provided', () => {
try {
uut.validate()
} catch (err) {
assert.include(err.message, "Property 'email' must be a string!")
}
})
it('should throw an error if password is not provided', () => {
try {
uut.validate({ email: 'test@test.com' })
} catch (err) {
assert.include(err.message, "Property 'password' must be a string!")
}
})
it('should throw an error if name is not provided', () => {
try {
uut.validate({ email: 'test@test.com', password: 'test' })
} catch (err) {
assert.include(err.message, "Property 'name' must be a string!")
}
})
it('should return a User object', () => {
const inputData = {
email: 'test@test.com',
password: 'test',
name: 'test'
}
const entry = uut.validate(inputData)
// console.log('entry: ', entry)
assert.property(entry, 'email')
assert.equal(entry.email, inputData.email)
assert.property(entry, 'password')
assert.equal(entry.password, inputData.password)
assert.property(entry, 'name')
assert.equal(entry.name, inputData.name)
})
})
})
+77
View File
@@ -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)
})
})
})
+56
View File
@@ -0,0 +1,56 @@
/*
Mocks for the Adapter library.
*/
const ipfs = {
ipfsAdapter: {
ipfs: {}
},
ipfsCoordAdapter: {
ipfsCoord: {
useCases: {
peer: {
sendPrivateMessage: () => {}
}
}
}
}
}
const localdb = {
Users: class Users {
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
}
},
validatePassword: () => {
return true
}
}
module.exports = { ipfs, localdb }
+9
View File
@@ -0,0 +1,9 @@
/*
Mocks for Koa 'app' object.
*/
const app = {
use: () => {}
}
module.exports = app
+50
View File
@@ -0,0 +1,50 @@
// Ripped from https://github.com/koajs/koa/blob/master/test/helpers/context.js
// Solution courtesy of user @fl0w. See: https://github.com/koajs/koa/issues/999#issuecomment-309270599
// Take from this gist: https://gist.github.com/emmanuelnk/f1254eed8f947a81e8d715476d9cc92c
// if you want more comprehensive Koa Context object to test stuff like Cookies etc
// then use https://www.npmjs.com/package/@shopify/jest-koa-mocks (requires Jest)
// INSTRUCTIONS:
// Import in test file as below:
//
// const mockContext = require('./mocks/ctx-mock').context
// const ctx = mockContext()
// ...
const Stream = require('stream')
const Koa = require('koa')
const context = (req, res, app) => {
const socket = new Stream.Duplex()
req = Object.assign(
{ headers: {}, socket },
Stream.Readable.prototype,
req || {}
)
res = Object.assign(
{ _headers: {}, socket },
Stream.Writable.prototype,
res || {}
)
req.socket.remoteAddress = req.socket.remoteAddress || '127.0.0.1'
app = app || new Koa()
res.getHeader = k => res._headers[k.toLowerCase()]
res.setHeader = (k, v) => (res._headers[k.toLowerCase()] = v)
res.removeHeader = (k, v) => delete res._headers[k.toLowerCase()]
const retApp = app.createContext(req, res)
return retApp
}
const request = (req, res, app) => context(req, res, app).request
const response = (req, res, app) => context(req, res, app).response
module.exports = {
context,
request,
response
}
+13
View File
@@ -0,0 +1,13 @@
/*
Mocks for the ipfs-coord library
*/
class IPFSCoord {
async isReady () {
return true
}
async start () {}
}
module.exports = IPFSCoord
+31
View File
@@ -0,0 +1,31 @@
/*
Mocks for the js-ipfs
*/
class IPFS {
constructor () {
this.ipfs = {}
}
static create () {
const mockIpfs = new MockIpfsInstance()
return mockIpfs
}
async start () {}
}
class MockIpfsInstance {
constructor () {
this.config = {
profiles: {
apply: () => {}
}
}
}
stop () {}
}
module.exports = IPFS
+28
View File
@@ -0,0 +1,28 @@
// Mocks representing an array of logs for the
// Unit tests of logapi
const data = [
{
message: 'Error in lib/nodemailer.js/validateEmailArray()',
level: 'error',
timestamp: '2020-11-14T12:15:55.230Z'
},
{
message: 'Error in lib/nodemailer.js/validateEmailArray()',
level: 'error',
timestamp: '2020-11-14T12:15:55.231Z'
},
{
message: 'Error in lib/nodemailer.js/validateEmailArray()',
level: 'error',
timestamp: '2020-11-14T12:15:55.230Z'
},
{
message: 'Error in lib/nodemailer.js/validateEmailArray()',
level: 'error',
timestamp: '2020-11-14T12:15:55.231Z'
}
]
module.exports = {
data
}
+42
View File
@@ -0,0 +1,42 @@
/*
Mocks for the use cases.
*/
/* eslint-disable */
class UserUseCaseMock {
async createUser(userObj) {
return {}
}
async getAllUsers() {
return true
}
async getUser(params) {
return true
}
async updateUser(existingUser, newData) {
return true
}
async deleteUser(user) {
return true
}
async authUser(login, passwd) {
return {
generateToken: () => {}
}
}
}
class UseCasesMock {
constuctor(localConfig = {}) {
// this.user = new UserUseCaseMock(localConfig)
}
user = new UserUseCaseMock()
}
module.exports = UseCasesMock
@@ -0,0 +1,50 @@
/*
Unit tests for the index.js file that aggregates all use-cases.
*/
// Public npm libraries
const assert = require('chai').assert
const sinon = require('sinon')
// Local support libraries
// const testUtils = require('../../utils/test-utils')
// Unit under test (uut)
const UseCases = require('../../../src/use-cases')
const adapters = require('../mocks/adapters')
describe('#use-cases', () => {
let uut
let sandbox
before(async () => {
// Delete all previous users in the database.
// await testUtils.deleteAllUsers()
})
beforeEach(() => {
sandbox = sinon.createSandbox()
uut = new UseCases({ adapters })
})
afterEach(() => sandbox.restore())
describe('#constructor', () => {
it('should throw an error if adapters are not passed in', () => {
try {
uut = new UseCases()
assert.fail('Unexpected code path')
// This is here to prevent the linter from complaining.
assert.isOk(uut)
} catch (err) {
assert.include(
err.message,
'Instance of adapters must be passed in when instantiating Use Cases library.'
)
}
})
})
})
+414
View File
@@ -0,0 +1,414 @@
/*
Unit tests for the src/lib/users.js business logic library.
TODO: verify that an admin can change the type of a user
*/
// Public npm libraries
const assert = require('chai').assert
const sinon = require('sinon')
// Local support libraries
// const testUtils = require('../../utils/test-utils')
// Unit under test (uut)
const UserLib = require('../../../src/use-cases/user')
const adapters = require('../mocks/adapters')
describe('#users-use-case', () => {
let uut
let sandbox
let testUser = {}
before(async () => {
// Delete all previous users in the database.
// await testUtils.deleteAllUsers()
})
beforeEach(() => {
sandbox = sinon.createSandbox()
uut = new UserLib({ adapters })
})
afterEach(() => sandbox.restore())
describe('#constructor', () => {
it('should throw an error if adapters are not passed in', () => {
try {
uut = new UserLib()
assert.fail('Unexpected code path')
} catch (err) {
assert.include(
err.message,
'Instance of adapters must be passed in when instantiating User Use Cases library.'
)
}
})
})
describe('#createUser', () => {
it('should throw an error if no input is given', async () => {
try {
await uut.createUser()
assert.fail('Unexpected code path')
} catch (err) {
// console.log(err)
// assert.equal(err.status, 422)
assert.include(err.message, "Property 'email' must be a string!")
}
})
it('should throw an error if email is not provided', async () => {
try {
await uut.createUser({})
assert.fail('Unexpected code path')
} catch (err) {
assert.include(err.message, "Property 'email' must be a string!")
}
})
it('should throw an error if password is not provided', async () => {
try {
const usrObj = {
email: 'test@test.com'
}
await uut.createUser(usrObj)
assert.fail('Unexpected code path')
} catch (err) {
assert.include(err.message, "Property 'password' must be a string!")
}
})
it('should throw an error if name is not provided', async () => {
try {
const usrObj = {
email: 'test@test.com',
password: 'password'
}
await uut.createUser(usrObj)
assert.fail('Unexpected code path')
} catch (err) {
assert.include(err.message, "Property 'name' must be a string!")
}
})
it('should catch and throw DB errors', async () => {
try {
// Force an error with the database.
sandbox.stub(uut, 'UserModel').throws(new Error('test error'))
const usrObj = {
email: 'test@test.com',
password: 'password',
name: 'test'
}
await uut.createUser(usrObj)
assert.fail('Unexpected code path')
} catch (err) {
assert.include(err.message, 'test error')
}
})
it('should create a new user in the DB', async () => {
// Note: The user created in this test is used by the getUser, update,
// and delete tests.
const usrObj = {
email: 'test01@test.com',
password: 'test',
name: 'test01'
}
const { userData, token } = await uut.createUser(usrObj)
testUser = userData
// Commented out because there is some sophisticated mocking required that
// I didn't have time to figure out. -CT 6/11/21
// Assert that the user model has the expected properties with expected values.
// assert.property(userData, 'type')
// assert.equal(userData.type, 'user')
// assert.property(userData, '_id')
// assert.property(userData, 'email')
// assert.property(userData, 'name')
// Assert that the JWT token was generated for this user.
assert.isString(token)
assert.include(token, '123')
})
})
describe('#getAllUsers', () => {
it('should return all users from the database', async () => {
await uut.getAllUsers()
// console.log(`users: ${JSON.stringify(users, null, 2)}`)
// assert.isArray(users)
})
it('should catch and throw an error', async () => {
try {
// Force an error.
sandbox.stub(uut.UserModel, 'find').rejects(new Error('test error'))
await uut.getAllUsers()
assert.fail('Unexpected code path')
} catch (err) {
assert.include(err.message, 'test error')
}
})
})
describe('#getUser', () => {
it('should throw 422 if no id given.', async () => {
try {
await uut.getUser()
assert.fail('Unexpected code path.')
} catch (err) {
// console.log(err)
assert.equal(err.status, 422)
assert.include(err.message, 'Unprocessable Entity')
}
})
it('should throw 422 for malformed id', async () => {
try {
// Force an error.
sandbox
.stub(uut.UserModel, 'findById')
.rejects(new Error('Unprocessable Entity'))
const params = { id: 1 }
await uut.getUser(params)
assert.fail('Unexpected code path.')
} catch (err) {
// console.log(err)
assert.equal(err.status, 422)
assert.include(err.message, 'Unprocessable Entity')
}
})
it('should throw 404 if user is not found', async () => {
try {
const params = { id: '5fa4bd7ee1828f5f4d3ed004' }
await uut.getUser(params)
assert.fail('Unexpected code path.')
} catch (err) {
// console.log(err)
assert.equal(err.status, 404)
assert.include(err.message, 'User not found')
}
})
it('should return the user model', async () => {
sandbox.stub(uut.UserModel, 'findById').resolves({ _id: 'abc123' })
const params = { id: testUser._id }
const result = await uut.getUser(params)
// console.log('result: ', result)
// Replace the JSON model with an actual Mongoos model. Used by later
// test cases.
testUser = result
// Assert that the expected properties for the user model exist.
// assert.property(result, 'type')
assert.property(result, '_id')
// assert.property(result, 'email')
// assert.property(result, 'name')
})
})
describe('#updateUser', () => {
it('should throw an error if no input is given', async () => {
try {
await uut.updateUser()
assert.fail('Unexpected code path')
} catch (err) {
// console.log(err)
assert.include(err.message, 'Cannot read property')
}
})
it('should throw an error if email is not a string', async () => {
try {
await uut.updateUser(testUser, {
email: 1234
})
assert.fail('Unexpected code path')
} catch (err) {
// console.log(err)
assert.include(err.message, "Property 'email' must be a string!")
}
})
it('should throw an error if name is not a string', async () => {
try {
const newData = {
name: 1234
}
await uut.updateUser(testUser, newData)
assert.fail('Unexpected code path')
} catch (err) {
// console.log(err)
assert.include(err.message, "Property 'name' must be a string!")
}
})
it('should throw an error if non-string password given', async () => {
try {
const newData = {
email: 'test@test.com',
name: 'test',
password: 1234
}
await uut.updateUser(testUser, newData)
assert.fail('Unexpected code path')
} catch (err) {
// console.log(err)
assert.include(err.message, "Property 'password' must be a string!")
}
})
it('should throw an error for malformed type given', async () => {
try {
const newData = {
email: 'test@test.com',
password: 'password',
name: 'test',
type: 1234
}
await uut.updateUser(testUser, newData)
assert.fail('Unexpected code path')
} catch (err) {
// console.log(err)
assert.include(err.message, "Property 'type' must be a string!")
}
})
it('should throw an error if normal user tries to change themselves into an admin', async () => {
try {
const newData = {
email: 'test@test.com',
password: 'password',
name: 'test',
type: 'admin'
}
await uut.updateUser(testUser, newData)
assert.fail('Unexpected code path')
} catch (err) {
// console.log(err)
assert.include(
err.message,
"Property 'type' can only be changed by Admin user"
)
}
})
// 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')
// })
// TODO: verify that an admin can change the type of a user
})
describe('#authUser', () => {
it('should return a user db model after successful authentication', async () => {
// sandbox.stub(uut.UserModel, 'findOne').resolves(true)
await uut.authUser('test@test.com', 'password')
// console.log('user: ', user)
// assert.property(user, '_id')
// assert.property(user, 'email')
// assert.property(user, 'name')
})
it('should throw an error if no user matches the login', async () => {
try {
sandbox.stub(uut.UserModel, 'findOne').resolves(false)
await uut.authUser('noone@nowhere.com', 'password')
// console.log('user: ', user)
assert.fail('Unexpected code path')
} catch (err) {
assert.include(err.message, 'User not found')
}
})
it('should throw an error if password does not match', async () => {
try {
// Force authentication to fial.
adapters.localdb.validatePassword = () => {
return false
}
await uut.authUser('test@test.com', 'badpassword')
// console.log('user: ', user)
assert.fail('Unexpected code path')
} catch (err) {
assert.include(err.message, 'Login credential do not match')
}
})
})
describe('#deleteUser', () => {
it('should throw error if no user provided', async () => {
try {
await uut.deleteUser()
assert.fail('Unexpected code path.')
} catch (err) {
// console.log(err)
assert.include(err.message, 'Cannot read property')
}
})
it('should delete the user from the database', async () => {
testUser = new adapters.localdb.Users()
await uut.deleteUser(testUser)
assert.isOk('Not throwing an error is a pass!')
})
})
})