100% test coverage of JSON RPC users handler

This commit is contained in:
Chris Troutner
2021-04-08 14:30:49 -07:00
parent 313e054f55
commit cd0aff2057
4 changed files with 184 additions and 8 deletions
+1 -1
View File
@@ -14,7 +14,7 @@
"lint": "standard --env mocha --fix",
"docs": "./node_modules/.bin/apidoc -i src/ -o docs",
"coverage": "nyc report --reporter=text-lcov | coveralls",
"coverage:report": "export SVC_ENV=test && nyc --reporter=html mocha --exit --timeout 15000 test/unit/biz-logic/ test/unit/rest-api/ test/e2e/automated/"
"coverage:report": "export SVC_ENV=test && nyc --reporter=html mocha --exit --timeout 15000 test/unit/biz-logic/ test/unit/json-rpc/ test/unit/rest-api/ test/e2e/automated/"
},
"keywords": [
"koa-api-boilerplate",
+3
View File
@@ -95,6 +95,9 @@ class UserLib {
async updateUser (existingUser, newData) {
try {
// console.log('existingUser: ', existingUser)
// console.log('newData: ', newData)
// Input Validation
// Optional inputs, but they must be strings if included.
if (newData.email && typeof newData.email !== 'string') {
+56 -5
View File
@@ -21,10 +21,11 @@ class UserRPC {
// a specific endpoint. This method routes incoming calls to one of those
// methods.
async userRouter (rpcData) {
let endpoint = 'unknown'
try {
// console.log('userRouter rpcData: ', rpcData)
const endpoint = rpcData.payload.params.endpoint
endpoint = rpcData.payload.params.endpoint
let user
// Route the call based on the value of the method property.
@@ -40,13 +41,24 @@ class UserRPC {
user = await this.validators.ensureUser(rpcData)
return await this.getUser(rpcData, user)
case 'updateUser':
user = await this.validators.ensureTargetUserOrAdmin(rpcData)
return await this.updateUser(rpcData, user)
case 'deleteUser':
user = await this.validators.ensureTargetUserOrAdmin(rpcData)
return await this.deleteUser(rpcData, user)
}
} catch (err) {
console.error('Error in UsersRPC/rpcRouter()')
throw err
// throw err
return {
success: false,
status: 500,
message: err.message,
endpoint
}
}
}
@@ -135,6 +147,34 @@ class UserRPC {
}
}
async updateUser (rpcData, userModel) {
try {
// console.log('updateUser rpcData: ', rpcData)
const newData = rpcData.payload.params
const user = await this.userLib.updateUser(userModel, newData)
return {
user,
endpoint: 'updateUser',
success: true,
status: 200,
message: ''
}
} catch (err) {
// console.log('updateUser err: ', err)
// Return an error response
return {
success: false,
status: 422,
message: err.message,
endpoint: 'updateUser'
}
}
}
async deleteUser (rpcData, userModel) {
try {
// console.log('deleteUser rpcData: ', rpcData)
@@ -142,13 +182,24 @@ class UserRPC {
await this.userLib.deleteUser(userModel)
const retObj = {
endpoint: 'deleteUser'
endpoint: 'deleteUser',
success: true,
status: 200,
message: ''
}
return retObj
} catch (err) {
console.error('Error in deleteUser()')
throw err
// console.error('Error in deleteUser()')
// throw err
// Return an error response
return {
success: false,
status: 422,
message: err.message,
endpoint: 'deleteUser'
}
}
}
+124 -2
View File
@@ -145,6 +145,46 @@ describe('#UserRPC', () => {
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: testUser.token,
userId: testUser.userData._id
})
const jsonStr = JSON.stringify(userCall, null, 2)
const rpcData = jsonrpc.parse(jsonStr)
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)
const result = await uut.userRouter(rpcData)
assert.equal(result, true)
})
it('should route to the deleteUsers method', async () => {
// Mock dependencies
sandbox.stub(uut, 'deleteUser').resolves(true)
@@ -165,12 +205,33 @@ describe('#UserRPC', () => {
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)
const result = await uut.userRouter(rpcData)
// console.log('result: ', result)
// assert.equal(result, true)
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('result: ', result)
// console.log('getAll result: ', result)
// Endpoint specific properties
assert.property(result, 'users')
@@ -198,6 +259,55 @@ describe('#UserRPC', () => {
})
})
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(),
name: 'test777'
})
const jsonStr = JSON.stringify(userCall, null, 2)
const rpcData = jsonrpc.parse(jsonStr)
const result = await uut.updateUser(rpcData, testUserModel)
// 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
@@ -211,7 +321,7 @@ describe('#UserRPC', () => {
const rpcData = jsonrpc.parse(jsonStr)
const result = await uut.getUser(rpcData)
// console.log('result: ', result)
// console.log('getUser result: ', result)
// Endpoint specific properties
assert.property(result, 'user')
@@ -253,5 +363,17 @@ describe('#UserRPC', () => {
assert.isOk('Not throwing an error is a success')
})
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.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')
})
})
})