From 85686e67b5fd6a5bd2d855334c0f48749383f5b7 Mon Sep 17 00:00:00 2001 From: Lloyd Brookes Date: Thu, 19 Nov 2015 16:03:01 +0000 Subject: [PATCH] mock responses --- example/mock/.local-web-server.json | 5 ++-- example/mock/mocks/search.mock.js | 20 +++++++++++++++ example/mock/mocks/tree.mock.js | 17 +++++++++++++ example/mock/mocks/trees.mock.js | 41 +++++++++++++++++++++---------- lib/local-web-server.js | 49 ++++++++++++++++++++++++++++--------- package.json | 4 ++- 6 files changed, 108 insertions(+), 28 deletions(-) create mode 100644 example/mock/mocks/search.mock.js diff --git a/example/mock/.local-web-server.json b/example/mock/.local-web-server.json index a16f358..4259315 100644 --- a/example/mock/.local-web-server.json +++ b/example/mock/.local-web-server.json @@ -1,6 +1,7 @@ { "rewrite": [ - { "from": "/tree", "to": "/mocks/trees.mock.js" }, - { "from": "/tree/:id", "to": "/mocks/tree.mock.js" } + { "from": "/trees", "to": "/mocks/trees.mock.js" }, + { "from": "/trees/:id", "to": "/mocks/tree.mock.js" }, + { "from": "/search", "to": "/mocks/search.mock.js" } ] } diff --git a/example/mock/mocks/search.mock.js b/example/mock/mocks/search.mock.js new file mode 100644 index 0000000..2fc9a72 --- /dev/null +++ b/example/mock/mocks/search.mock.js @@ -0,0 +1,20 @@ +module.exports = [ + { + request: { + accepts: 'json' + }, + response: { + status: 200, + body: { id: 2, name: 'eucalyptus', maxHeight: 210 } + } + }, + { + request: { + accepts: 'xml' + }, + response: { + status: 200, + body: '' + } + } +] diff --git a/example/mock/mocks/tree.mock.js b/example/mock/mocks/tree.mock.js index 753f707..f8ac1e2 100644 --- a/example/mock/mocks/tree.mock.js +++ b/example/mock/mocks/tree.mock.js @@ -1,8 +1,25 @@ module.exports = [ + /* CREATE (409 CONFLICT - should be called on the collection) */ { + request: { method: 'POST' }, + response: { status: 409 } + }, + /* READ */ + { + request: { method: 'GET' }, response: { status: 200, body: { id: 2, name: 'eucalyptus', maxHeight: 210 } } + }, + /* UPDATE */ + { + request: { method: 'PUT' }, + response: { status: 204 } + }, + /* DELETE */ + { + request: { method: 'DELETE' }, + response: { status: 204 } } ] diff --git a/example/mock/mocks/trees.mock.js b/example/mock/mocks/trees.mock.js index 2d3e30e..588259f 100644 --- a/example/mock/mocks/trees.mock.js +++ b/example/mock/mocks/trees.mock.js @@ -1,23 +1,38 @@ +const data = [ + { id: 1, name: 'Conifer', maxHeight: 115 }, + { id: 2, name: 'Eucalyptus', maxHeight: 210 }, + { id: 3, name: 'Ash', maxHeight: 40 }, + { id: 4, name: 'Elder', maxHeight: 5 }, + { id: 5, name: 'Holly', maxHeight: 10 } +] + module.exports = [ + /* CREATE */ { - request: { - method: 'GET' - }, + request: { method: 'POST' }, response: { - status: 200, - body: [ - { id: 1, name: 'conifer', maxHeight: 115 }, - { id: 2, name: 'eucalyptus', maxHeight: 210 } - ] + status: 201, + location: '/tree/1' } }, + /* READ */ { - request: { - method: 'POST' - }, + request: { method: 'GET' }, response: { - status: 201, - location: '/tree/1' + status: 200, + body: function (ctx) { + return data.filter(tree => tree.maxHeight > Number(ctx.query.tallerThan)) + } } + }, + /* UPDATE (forbidden on collection)*/ + { + request: { method: 'PUT' }, + response: { status: 404 } + }, + /* DELETE (forbidden on collection) */ + { + request: { method: 'DELETE' }, + response: { status: 404 } } ] diff --git a/lib/local-web-server.js b/lib/local-web-server.js index d7e9409..d040512 100644 --- a/lib/local-web-server.js +++ b/lib/local-web-server.js @@ -3,7 +3,7 @@ const path = require('path') const http = require('http') const url = require('url') const arrayify = require('array-back') -let debug +let debug, pathToRegexp /** * @module local-web-server @@ -57,7 +57,7 @@ function localWebServer (options) { const convert = require('koa-convert') const cors = require('kcors') const _ = require('koa-route') - const pathToRegexp = require('path-to-regexp') + pathToRegexp = require('path-to-regexp') debug = require('debug')('local-web-server') const log = options.log @@ -70,9 +70,6 @@ function localWebServer (options) { function verbose (category, message) { if (options.verbose) { debug(category, message) - // process.nextTick(() => { - // app.emit('verbose', category, message) - // }) } } app._verbose = verbose @@ -93,8 +90,9 @@ function localWebServer (options) { app.use(_.all(route.from, proxyRequest(route, app))) } else { const rewrite = require('koa-rewrite') - verbose('local rewrite', `${route.from} -> ${route.to}`) - app.use(rewrite(route.from, route.to)) + const mw = rewrite(route.from, route.to) + mw._name = 'rewrite' + app.use(mw) } } }) @@ -110,7 +108,6 @@ function localWebServer (options) { if (!options['no-cache']) { const conditional = require('koa-conditional-get') const etag = require('koa-etag') - // verbose('etag caching', 'enabled') app.use(conditional()) app.use(etag()) } @@ -239,11 +236,39 @@ function mockResponses (options) { return function mockResponses (ctx, next) { if (/\.mock.js$/.test(ctx.path)) { const mocks = arrayify(require(path.join(options.root, ctx.path))) - const mock = mocks.find(mock => { - return !mock.request || mock.request.method === ctx.method + const testValue = require('test-value') + const t = require('typical') + + /* find a mock with compatible method and accepts */ + let mock = mocks.find(mock => { + return testValue(mock, { + request: { + method: [ ctx.method, undefined ], + accepts: type => ctx.accepts(type) + } + }) }) - Object.assign(ctx.response, mock.response) - options.verbose('mock response', JSON.stringify(mock.response), JSON.stringify(ctx.response)) + + /* else take the first mock without a request (no request means 'all requests') */ + if (!mock) { + mock = mocks.find(mock => !mock.request) + } + + const mockedReponse = {} + /* resolve any functions on the mock */ + Object.keys(mock.response).forEach(key => { + if (t.isFunction(mock.response[key])) { + mockedReponse[key] = mock.response[key](ctx) + } else { + mockedReponse[key] = mock.response[key] + } + }) + + if (mock) { + Object.assign(ctx.response, mockedReponse) + options.verbose('mocked response', JSON.stringify(mockedReponse)) + options.verbose('actual response', JSON.stringify(ctx.response)) + } } else { return next() } diff --git a/package.json b/package.json index a891801..23d9b72 100644 --- a/package.json +++ b/package.json @@ -48,7 +48,9 @@ "koa-static": "^1.5.2", "path-to-regexp": "^1.2.1", "stream-log-stats": "^v1.1.0-0", - "string-tools": "^1.0.0" + "string-tools": "^1.0.0", + "test-value": "^1.0.1", + "typical": "^2.4.0" }, "devDependencies": { "req-then": "^0.2.2",