fix(mocking): Added mock for koa context object

This commit is contained in:
Chris Troutner
2020-11-12 07:44:14 -08:00
parent cfcfdd1d50
commit ba44070650
4 changed files with 208 additions and 9 deletions
+119
View File
@@ -781,6 +781,51 @@
"resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.14.0.tgz",
"integrity": "sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ=="
},
"@sinonjs/commons": {
"version": "1.8.1",
"resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.1.tgz",
"integrity": "sha512-892K+kWUUi3cl+LlqEWIDrhvLgdL79tECi8JZUyq6IviKy/DNhuzCRlbHUjxK89f4ypPMMaFnFuR9Ie6DoIMsw==",
"dev": true,
"requires": {
"type-detect": "4.0.8"
}
},
"@sinonjs/fake-timers": {
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-6.0.1.tgz",
"integrity": "sha512-MZPUxrmFubI36XS1DI3qmI0YdN1gks62JtFZvxR67ljjSNCeK6U08Zx4msEWOXuofgqUt6zPHSi1H9fbjR/NRA==",
"dev": true,
"requires": {
"@sinonjs/commons": "^1.7.0"
}
},
"@sinonjs/formatio": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/@sinonjs/formatio/-/formatio-5.0.1.tgz",
"integrity": "sha512-KaiQ5pBf1MpS09MuA0kp6KBQt2JUOQycqVG1NZXvzeaXe5LGFqAKueIS0bw4w0P9r7KuBSVdUk5QjXsUdu2CxQ==",
"dev": true,
"requires": {
"@sinonjs/commons": "^1",
"@sinonjs/samsam": "^5.0.2"
}
},
"@sinonjs/samsam": {
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-5.2.0.tgz",
"integrity": "sha512-CaIcyX5cDsjcW/ab7HposFWzV1kC++4HNsfnEdFJa7cP1QIuILAKV+BgfeqRXhcnSAc76r/Rh/O5C+300BwUIw==",
"dev": true,
"requires": {
"@sinonjs/commons": "^1.6.0",
"lodash.get": "^4.4.2",
"type-detect": "^4.0.8"
}
},
"@sinonjs/text-encoding": {
"version": "0.7.1",
"resolved": "https://registry.npmjs.org/@sinonjs/text-encoding/-/text-encoding-0.7.1.tgz",
"integrity": "sha512-+iTbntw2IZPb/anVDbypzfQa+ay64MW0Zo8aJ8gZPWMMK6/OubMVb6lUPMagqjOPnmtauXnFCACVl3O7ogjeqQ==",
"dev": true
},
"@szmarczak/http-timer": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-1.1.2.tgz",
@@ -5199,6 +5244,12 @@
"object.assign": "^4.1.0"
}
},
"just-extend": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/just-extend/-/just-extend-4.1.1.tgz",
"integrity": "sha512-aWgeGFW67BP3e5181Ep1Fv2v8z//iBJfrvyTnq8wG86vEESwmonn1zPBJ0VfmT9CJq2FIT0VsETtrNFm2a+SHA==",
"dev": true
},
"jwa": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz",
@@ -6298,6 +6349,36 @@
"integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==",
"dev": true
},
"nise": {
"version": "4.0.4",
"resolved": "https://registry.npmjs.org/nise/-/nise-4.0.4.tgz",
"integrity": "sha512-bTTRUNlemx6deJa+ZyoCUTRvH3liK5+N6VQZ4NIw90AgDXY6iPnsqplNFf6STcj+ePk0H/xqxnP75Lr0J0Fq3A==",
"dev": true,
"requires": {
"@sinonjs/commons": "^1.7.0",
"@sinonjs/fake-timers": "^6.0.0",
"@sinonjs/text-encoding": "^0.7.1",
"just-extend": "^4.0.2",
"path-to-regexp": "^1.7.0"
},
"dependencies": {
"isarray": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz",
"integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=",
"dev": true
},
"path-to-regexp": {
"version": "1.8.0",
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.8.0.tgz",
"integrity": "sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA==",
"dev": true,
"requires": {
"isarray": "0.0.1"
}
}
}
},
"node-emoji": {
"version": "1.10.0",
"resolved": "https://registry.npmjs.org/node-emoji/-/node-emoji-1.10.0.tgz",
@@ -11671,6 +11752,44 @@
"is-arrayish": "^0.3.1"
}
},
"sinon": {
"version": "9.2.1",
"resolved": "https://registry.npmjs.org/sinon/-/sinon-9.2.1.tgz",
"integrity": "sha512-naPfsamB5KEE1aiioaoqJ6MEhdUs/2vtI5w1hPAXX/UwvoPjXcwh1m5HiKx0HGgKR8lQSoFIgY5jM6KK8VrS9w==",
"dev": true,
"requires": {
"@sinonjs/commons": "^1.8.1",
"@sinonjs/fake-timers": "^6.0.1",
"@sinonjs/formatio": "^5.0.1",
"@sinonjs/samsam": "^5.2.0",
"diff": "^4.0.2",
"nise": "^4.0.4",
"supports-color": "^7.1.0"
},
"dependencies": {
"diff": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz",
"integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==",
"dev": true
},
"has-flag": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
"integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
"dev": true
},
"supports-color": {
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
"integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
"dev": true,
"requires": {
"has-flag": "^4.0.0"
}
}
}
},
"slash": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz",
+1
View File
@@ -66,6 +66,7 @@
"mocha": "^7.0.1",
"nyc": "^15.0.0",
"semantic-release": "^17.0.0",
"sinon": "^9.2.1",
"standard": "^14.3.1"
},
"release": {
+38 -9
View File
@@ -2,6 +2,7 @@ const testUtils = require('./utils')
const assert = require('chai').assert
const config = require('../config')
const axios = require('axios').default
const sinon = require('sinon')
const util = require('util')
util.inspect.defaultOptions = { depth: 1 }
@@ -10,6 +11,12 @@ const LOCALHOST = `http://localhost:${config.port}`
const context = {}
const UserController = require('../src/modules/users/controller')
let uut
let sandbox
const mockContext = require('./mocks/ctx-mock').context
describe('Users', () => {
before(async () => {
// console.log(`config: ${JSON.stringify(config, null, 2)}`)
@@ -38,6 +45,14 @@ describe('Users', () => {
// console.log(`admin: ${JSON.stringify(admin, null, 2)}`)
})
beforeEach(() => {
uut = new UserController()
sandbox = sinon.createSandbox()
})
afterEach(() => sandbox.restore())
describe('POST /users', () => {
it('should reject signup when data is incomplete', async () => {
try {
@@ -127,6 +142,7 @@ describe('Users', () => {
)
}
})
it('should reject if name property property is not string', async () => {
try {
const options = {
@@ -145,10 +161,7 @@ describe('Users', () => {
assert(false, 'Unexpected result')
} catch (err) {
assert.equal(err.response.status, 422)
assert.include(
err.response.data,
"Property 'name' must be a string"
)
assert.include(err.response.data, "Property 'name' must be a string")
}
})
@@ -275,6 +288,22 @@ describe('Users', () => {
assert.hasAnyKeys(users[0], ['type', '_id', 'email'])
assert.isNumber(users.length)
})
it('should catch and handle errors', async () => {
try {
// Force an error
sandbox.stub(uut.User, 'find').rejects(new Error('test error'))
// Mock the context object.
const ctx = mockContext()
await uut.getUsers(ctx)
assert.fail('Unexpected result')
} catch (err) {
assert.include(err.message, 'Not Found')
}
})
})
describe('GET /users/:id', () => {
@@ -544,10 +573,7 @@ describe('Users', () => {
assert.equal(true, false, 'Unexpected behavior')
} catch (err) {
assert.equal(err.response.status, 422)
assert.include(
err.response.data,
"Property 'email' must be a string!"
)
assert.include(err.response.data, "Property 'email' must be a string!")
}
})
it('should not be able to update if email is wrong format', async () => {
@@ -571,7 +597,10 @@ describe('Users', () => {
await axios(options)
} catch (err) {
assert.equal(err.response.status, 422)
assert.include(err.response.data, "Property 'email' must be email format!")
assert.include(
err.response.data,
"Property 'email' must be email format!"
)
}
})
it('should not be able to update type property if is not string', async () => {
+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
}