diff --git a/README.md b/README.md
index ce07e19..c389359 100644
--- a/README.md
+++ b/README.md
@@ -47,16 +47,6 @@ By default, typical SPA urls (e.g. `/user/1`, `/login`) would return `404 Not Fo
[Example](https://github.com/75lb/local-web-server/tree/master/example/spa).
-### Access Control
-
-By default, access to all files is allowed (including dot files). Use `--forbid` to establish a blacklist:
-```sh
-$ ws --forbid '*.json' '*.yml'
-serving at http://localhost:8000
-```
-
-[Example](https://github.com/75lb/local-web-server/tree/master/example/forbid).
-
### URL rewriting
Your application requested `/css/style.css` but it's stored at `/build/css/style.css`. To avoid a 404 you need a rewrite rule:
@@ -79,7 +69,6 @@ $ ws --rewrite '/css/* -> /build/css/$1'
this rewrites `/css/a` as `/build/css/a`, `/css/a/b/c` as `/build/css/a/b/c` etc.
-
#### Proxied requests
If the `to` URL contains a remote host, local-web-server will act as a proxy - fetching and responding with the remote resource.
@@ -96,6 +85,91 @@ $ ws --rewrite '/:user/repos/:name -> https://api.github.com/repos/:user/:name'
[Example](https://github.com/75lb/local-web-server/tree/master/example/rewrite).
+### Mock Responses
+
+Mock a data service, serve any custom/dynamic content.
+
+A mock definition maps a route to a response. Mock a home page.
+```json
+{
+ "mocks": [
+ {
+ "route": "/",
+ "response": {
+ "body": "
Welcome to the Mock Responses example "
+ }
+ }
+ ]
+}
+```
+
+Conditional response, depending on the request.
+```json
+{
+ "mocks": [
+ {
+ "route": "/two",
+ "request": { "accepts": "xml" },
+ "response": {
+ "body": " "
+ }
+ }
+ ]
+}
+```
+
+Multiple potential responses. First request to match.
+```json
+{
+ "mocks": [
+ {
+ "route": "/three",
+ "responses": [
+ {
+ "request": { "method": "GET" },
+ "response": {
+ "body": "Mock response for 'GET' request on /three "
+ }
+ },
+ {
+ "request": { "method": "POST" },
+ "response": {
+ "status": 400,
+ "body": { "message": "That method is not allowed." }
+ }
+ }
+ ]
+ }
+ ]
+}
+```
+
+More dynamic response.
+```json
+{
+ "mocks": [
+ {
+ "route": "/four",
+ "module": "/mocks/four.js"
+ }
+ ]
+}
+```
+
+Tokens in the route are passed to the response.
+```json
+{
+ "mocks": [
+ {
+ "route": "/five/:id\\?name=:name",
+ "module": "/mocks/five.js"
+ }
+ ]
+}
+```
+
+[Example](https://github.com/75lb/local-web-server/tree/master/example/mock).
+
### Stored config
Use the same port and blacklist every time? Persist it to `package.json`:
@@ -136,6 +210,16 @@ serving at http://localhost:8000
The format value supplied is passed directly to [morgan](https://github.com/expressjs/morgan). The exception is `--log-format none` which disables all output.
+### Access Control
+
+By default, access to all files is allowed (including dot files). Use `--forbid` to establish a blacklist:
+```sh
+$ ws --forbid '*.json' '*.yml'
+serving at http://localhost:8000
+```
+
+[Example](https://github.com/75lb/local-web-server/tree/master/example/forbid).
+
### Other usage
#### Debugging
diff --git a/example/mock/.local-web-server.json b/example/mock/.local-web-server.json
index 5b49c4f..ffa1c2b 100644
--- a/example/mock/.local-web-server.json
+++ b/example/mock/.local-web-server.json
@@ -1,9 +1,9 @@
{
"mocks": [
{
- "route": "/one",
+ "route": "/",
"response": {
- "body": { "id": 1, "name": "whatever" }
+ "body": "Welcome to the Mock Responses example "
}
},
{
@@ -15,11 +15,11 @@
},
{
"route": "/three",
- "targets": [
+ "responses": [
{
"request": { "method": "GET" },
"response": {
- "body": { "id": 1, "name": "whatever" }
+ "body": "Mock response for 'GET' request on /three "
}
},
{
diff --git a/example/mock/css/style.css b/example/mock/css/style.css
deleted file mode 100644
index 7fb71e5..0000000
--- a/example/mock/css/style.css
+++ /dev/null
@@ -1,7 +0,0 @@
-body {
- background-color: #AA3939;
- color: #FFE2E2
-}
-svg {
- fill: #000
-}
diff --git a/example/mock/index.html b/example/mock/index.html
deleted file mode 100644
index eec74b2..0000000
--- a/example/mock/index.html
+++ /dev/null
@@ -1,8 +0,0 @@
-
-
-
-Mock responses
-
-
diff --git a/example/mock/index.js b/example/mock/index.js
deleted file mode 100644
index ce602ed..0000000
--- a/example/mock/index.js
+++ /dev/null
@@ -1,9 +0,0 @@
-'use strict'
-const request = require('req-then')
-const $ = document.querySelector.bind(document)
-
-request('http://localhost:8000/tree').then(response => {
- $('ul').innerHTML = JSON.parse(response.data).map(tree => {
- return `${tree.name} `
- }).join('')
-})
diff --git a/example/mock/mocks/data.json b/example/mock/mocks/data.json
new file mode 100644
index 0000000..fe13696
--- /dev/null
+++ b/example/mock/mocks/data.json
@@ -0,0 +1,3 @@
+{
+ "one": "static data"
+}
diff --git a/example/mock/mocks/five.js b/example/mock/mocks/five.js
index 168708d..9138cc0 100644
--- a/example/mock/mocks/five.js
+++ b/example/mock/mocks/five.js
@@ -1,8 +1,5 @@
module.exports = {
response: function (ctx, id, name) {
- this.body = {
- id: id,
- name: name
- }
+ ctx.body = `id: ${id}, name: ${name} `
}
}
diff --git a/example/mock/mocks/four.js b/example/mock/mocks/four.js
index 4beeb30..981fe26 100644
--- a/example/mock/mocks/four.js
+++ b/example/mock/mocks/four.js
@@ -1,5 +1,7 @@
+const fs = require('fs')
+
module.exports = {
response: {
- body: { id: 2, name: 'eucalyptus', maxHeight: 210 }
+ body: fs.createReadStream(__filename)
}
}
diff --git a/jsdoc2md/README.hbs b/jsdoc2md/README.hbs
index 1c66e8d..e5a7c1c 100644
--- a/jsdoc2md/README.hbs
+++ b/jsdoc2md/README.hbs
@@ -47,16 +47,6 @@ By default, typical SPA urls (e.g. `/user/1`, `/login`) would return `404 Not Fo
[Example](https://github.com/75lb/local-web-server/tree/master/example/spa).
-### Access Control
-
-By default, access to all files is allowed (including dot files). Use `--forbid` to establish a blacklist:
-```sh
-$ ws --forbid '*.json' '*.yml'
-serving at http://localhost:8000
-```
-
-[Example](https://github.com/75lb/local-web-server/tree/master/example/forbid).
-
### URL rewriting
Your application requested `/css/style.css` but it's stored at `/build/css/style.css`. To avoid a 404 you need a rewrite rule:
@@ -79,7 +69,6 @@ $ ws --rewrite '/css/* -> /build/css/$1'
this rewrites `/css/a` as `/build/css/a`, `/css/a/b/c` as `/build/css/a/b/c` etc.
-
#### Proxied requests
If the `to` URL contains a remote host, local-web-server will act as a proxy - fetching and responding with the remote resource.
@@ -96,6 +85,91 @@ $ ws --rewrite '/:user/repos/:name -> https://api.github.com/repos/:user/:name'
[Example](https://github.com/75lb/local-web-server/tree/master/example/rewrite).
+### Mock Responses
+
+Mock a data service, serve any custom/dynamic content.
+
+A mock definition maps a route to a response. Mock a home page.
+```json
+{
+ "mocks": [
+ {
+ "route": "/",
+ "response": {
+ "body": "Welcome to the Mock Responses example "
+ }
+ }
+ ]
+}
+```
+
+Conditional response, depending on the request.
+```json
+{
+ "mocks": [
+ {
+ "route": "/two",
+ "request": { "accepts": "xml" },
+ "response": {
+ "body": " "
+ }
+ }
+ ]
+}
+```
+
+Multiple potential responses. First request to match.
+```json
+{
+ "mocks": [
+ {
+ "route": "/three",
+ "responses": [
+ {
+ "request": { "method": "GET" },
+ "response": {
+ "body": "Mock response for 'GET' request on /three "
+ }
+ },
+ {
+ "request": { "method": "POST" },
+ "response": {
+ "status": 400,
+ "body": { "message": "That method is not allowed." }
+ }
+ }
+ ]
+ }
+ ]
+}
+```
+
+More dynamic response.
+```json
+{
+ "mocks": [
+ {
+ "route": "/four",
+ "module": "/mocks/four.js"
+ }
+ ]
+}
+```
+
+Tokens in the route are passed to the response.
+```json
+{
+ "mocks": [
+ {
+ "route": "/five/:id\\?name=:name",
+ "module": "/mocks/five.js"
+ }
+ ]
+}
+```
+
+[Example](https://github.com/75lb/local-web-server/tree/master/example/mock).
+
### Stored config
Use the same port and blacklist every time? Persist it to `package.json`:
@@ -136,6 +210,16 @@ serving at http://localhost:8000
The format value supplied is passed directly to [morgan](https://github.com/expressjs/morgan). The exception is `--log-format none` which disables all output.
+### Access Control
+
+By default, access to all files is allowed (including dot files). Use `--forbid` to establish a blacklist:
+```sh
+$ ws --forbid '*.json' '*.yml'
+serving at http://localhost:8000
+```
+
+[Example](https://github.com/75lb/local-web-server/tree/master/example/forbid).
+
### Other usage
#### Debugging
diff --git a/lib/local-web-server.js b/lib/local-web-server.js
index 0621a4e..7972c1f 100644
--- a/lib/local-web-server.js
+++ b/lib/local-web-server.js
@@ -148,11 +148,11 @@ function localWebServer (options) {
/* Mock Responses */
options.mocks.forEach(mock => {
if (mock.module) {
- mock.targets = require(path.join(options.static.root, mock.module))
+ mock.responses = require(path.join(options.static.root, mock.module))
}
- if (mock.targets) {
- app.use(mw.mockResponses(mock.route, mock.targets))
+ if (mock.responses) {
+ app.use(mw.mockResponses(mock.route, mock.responses))
} else if (mock.response) {
mock.target = {
request: mock.request,
diff --git a/test/test.js b/test/test.js
index a917551..ca73da0 100644
--- a/test/test.js
+++ b/test/test.js
@@ -17,6 +17,13 @@ function launchServer (app, options) {
})
}
+function checkResponse (t, status, body) {
+ return function (response) {
+ if (status) t.strictEqual(response.res.statusCode, status)
+ if (body) t.ok(body.test(response.data))
+ }
+}
+
test('static', function (t) {
t.plan(1)
const app = localWebServer({
@@ -201,3 +208,130 @@ test('rewrite: proxy with port', function (t) {
})
})
})
+
+test('mock: simple response', function (t) {
+ t.plan(2)
+ const app = localWebServer({
+ log: { format: 'none' },
+ mocks: [
+ { route: '/test', response: { body: 'test' } }
+ ]
+ })
+ launchServer(app, { path: '/test', onSuccess: response => {
+ t.strictEqual(response.res.statusCode, 200)
+ t.ok(/test/.test(response.data))
+ }})
+})
+
+test('mock: method request filter', function (t) {
+ t.plan(3)
+ const app = localWebServer({
+ log: { format: 'none' },
+ mocks: [
+ {
+ route: '/test',
+ request: { method: 'POST' },
+ response: { body: 'test' }
+ }
+ ]
+ })
+ const server = http.createServer(app.callback())
+ server.listen(8100, () => {
+ request('http://localhost:8100/test')
+ .then(checkResponse(t, 404))
+ .then(() => request('http://localhost:8100/test', { data: 'something' }))
+ .then(checkResponse(t, 200, /test/))
+ .then(server.close.bind(server))
+ })
+})
+
+test('mock: accepts request filter', function (t) {
+ t.plan(3)
+ const app = localWebServer({
+ log: { format: 'none' },
+ mocks: [
+ {
+ route: '/test',
+ request: { accepts: 'text' },
+ response: { body: 'test' }
+ }
+ ]
+ })
+ const server = http.createServer(app.callback())
+ server.listen(8100, () => {
+ request('http://localhost:8100/test', { headers: { Accept: '*/json' }})
+ .then(checkResponse(t, 404))
+ .then(() => request('http://localhost:8100/test', { headers: { Accept: 'text/plain' }}))
+ .then(checkResponse(t, 200, /test/))
+ .then(server.close.bind(server))
+ })
+})
+
+test('mock: responses array', function (t) {
+ t.plan(4)
+ const app = localWebServer({
+ log: { format: 'none' },
+ mocks: [
+ {
+ route: '/test',
+ responses: [
+ { request: { method: 'GET' }, response: { body: 'get' } },
+ { request: { method: 'POST' }, response: { body: 'post' } }
+ ]
+ }
+ ]
+ })
+ const server = http.createServer(app.callback())
+ server.listen(8100, () => {
+ request('http://localhost:8100/test')
+ .then(checkResponse(t, 200, /get/))
+ .then(() => request('http://localhost:8100/test', { method: 'POST' }))
+ .then(checkResponse(t, 200, /post/))
+ .then(server.close.bind(server))
+ })
+})
+
+test('mock: response function', function (t) {
+ t.plan(4)
+ const app = localWebServer({
+ log: { format: 'none' },
+ mocks: [
+ {
+ route: '/test',
+ responses: [
+ { request: { method: 'GET' }, response: ctx => ctx.body = 'get' },
+ { request: { method: 'POST' }, response: ctx => ctx.body = 'post' }
+ ]
+ }
+ ]
+ })
+ const server = http.createServer(app.callback())
+ server.listen(8100, () => {
+ request('http://localhost:8100/test')
+ .then(checkResponse(t, 200, /get/))
+ .then(() => request('http://localhost:8100/test', { method: 'POST' }))
+ .then(checkResponse(t, 200, /post/))
+ .then(server.close.bind(server))
+ })
+})
+
+test('mock: response function args', function (t) {
+ t.plan(2)
+ const app = localWebServer({
+ log: { format: 'none' },
+ mocks: [
+ {
+ route: '/test/:one',
+ responses: [
+ { request: { method: 'GET' }, response: (ctx, one) => ctx.body = one }
+ ]
+ }
+ ]
+ })
+ const server = http.createServer(app.callback())
+ server.listen(8100, () => {
+ request('http://localhost:8100/test/yeah')
+ .then(checkResponse(t, 200, /yeah/))
+ .then(server.close.bind(server))
+ })
+})