mock-web-server
Advanced tools
+6
-0
@@ -6,4 +6,10 @@ language: node_js | ||
| - "8" | ||
| - "10" | ||
| - "12" | ||
| - "14" | ||
| - "16" | ||
| - "18" | ||
| - "20" | ||
| after_success: | ||
| npm run coveralls |
+4
-0
| mock-web-server | ||
| ================ | ||
| ## 0.9.2 | ||
| - support preResponse hook | ||
| - change lisence to ISC | ||
| ## 0.9.1 | ||
@@ -5,0 +9,0 @@ - fix issue #1 - after .reset(response) - server still responds with old response |
+14
-8
@@ -10,14 +10,20 @@ const bodyParser = require('body-parser'); | ||
| const parsers = mockSvrFactory.mapParsers(bodyParsers); | ||
| //a REPL-friendly request view | ||
| const collectAccepted = ({ httpVersion, method, url, headers, rawHeaders, upgrade, body, trailers, rawTrailers }, parseError) => { | ||
| const mapped = {httpVersion, method, url, headers, rawHeaders, upgrade, parseError, body, trailers, rawTrailers}; | ||
| accepted.push(mapped); | ||
| return mapped; | ||
| }; | ||
| const svr = require('http').createServer((q,r) => { | ||
| parseBody(parsers, q,r, (parseError) => { | ||
| {//keep a REPL-friendly request view | ||
| const {httpVersion, method, url, headers, rawHeaders, upgrade, body, trailers, rawTrailers} = q; | ||
| accepted.push({httpVersion, method, url, headers, rawHeaders, upgrade, parseError, body, trailers, rawTrailers}); | ||
| } | ||
| {//emit headers | ||
| const {headers = {}} = response; | ||
| const acc = collectAccepted(q, parseError); | ||
| {//emit response | ||
| const { status, body, headers = {} } = | ||
| 'function' == typeof response.preResponse | ||
| ? Object.assign({}, response, response.preResponse(acc, response) || response) | ||
| : response; | ||
| Object.keys(headers).forEach(h => r.setHeader(h, headers[h])) | ||
| r.statusCode = status || 200; | ||
| r.end( JSON.stringify(body) ) | ||
| } | ||
| r.statusCode = response.status || 200; | ||
| r.end( JSON.stringify(response.body) ) | ||
| }) | ||
@@ -24,0 +30,0 @@ }); |
+3
-3
| { | ||
| "name": "mock-web-server", | ||
| "version": "0.9.1", | ||
| "version": "0.9.2", | ||
| "description": "", | ||
@@ -18,3 +18,3 @@ "main": "lib", | ||
| }, | ||
| "license": "MIT", | ||
| "license": "ISC", | ||
| "repository": { | ||
@@ -25,3 +25,3 @@ "type": "git", | ||
| "publishConfig": { | ||
| "registry": "http://registry.npmjs.org/" | ||
| "registry": "https://registry.npmjs.org/" | ||
| }, | ||
@@ -28,0 +28,0 @@ "scripts": { |
+121
-37
@@ -26,5 +26,12 @@ # mock-web-server [](http://travis-ci.org/osher/mock-web-server) [](https://coveralls.io/github/osher/mock-web-server) | ||
| ## Example | ||
| This example uses mocha, however - it can be used with every test runner for node. | ||
| ## Example - the common simple case: | ||
| This example uses a simple static response descriptor. | ||
| Every time the server receives a request - it will: | ||
| 1. capture a REPL-friendly detailed view of the request. | ||
| 2. respond with the same respopnse, no matter what are the characteristics of the request. | ||
| You can replace the response descriptor using `svr.reset(newResponseDescriptor)`. | ||
| This example uses mocha, however - it can be used with every any test runner. | ||
| ```javascript | ||
@@ -126,6 +133,73 @@ const mockSvrFactory = require('mock-web-server'); | ||
| ``` | ||
| ## Example - logic for dynamic responses | ||
| (since: `0.9.2`) | ||
| In most cases, a static response to a single API is enough. | ||
| However, sometimes you need your mock server to support few endpoints, and/or control for a non-idempotent API that accumulates state between responses. | ||
| For this, you can provide an `preResponse` hook. The hook can map an accepted request to a response, or mutate the response object behind the server. | ||
| * The hook should be synchronous. | ||
| * The hook is passed the accepted request view as a 1st argument. | ||
| * The hook is passed the response descriptor the server holds as a 2nd parameter. | ||
| * The hook is also called on the context of the response descriptor. | ||
| The server will keep collecting REPL-friendly views of the accepted requests as usual, so you can ask it what it heard from your tested client. | ||
| ### mapper preResponse hook | ||
| If you return a value from your preResponse hook - its props cascades their equivalents on the response descriptor the server holds. | ||
| In this example, the response descriptor the sever is initiated with defaults to a reply of *Not-found*. However, when the uri represents a supported entry - the returned object cascades the `status: 200` and the `body` for that entry. | ||
| ```js | ||
| const routes = { | ||
| '/api/user/1': { name: 'John Snow '}, | ||
| '/api/user/2': { name: 'John Doe '}, | ||
| }; | ||
| const svr = mockSvrFactory({ | ||
| status: 404, | ||
| headers: { | ||
| 'Content-Type': 'application/json; charset: utf-8', | ||
| }, | ||
| body: { err: 'not-found' }, | ||
| preResponse: ({ uri }) => routes[uri] && ({ status: 200, body: this.routes[uri] }), | ||
| }); | ||
| ``` | ||
| ### mutator preResponse hook | ||
| Using the hook as a mutator lets you manage a simple in-memory state on the response descriptor. | ||
| If you don't want to manage it in a closure - you can use this object as a context object. | ||
| The response descriptor is both passed to the hook as a 2nd argument, and used as the context on which the hook is called, so you can use `this`, or an arrow-function according to your preferences. | ||
| This example uses a queue of bodies on the response descriptor, and accesses it via the `this` keyword. | ||
| ```js | ||
| const faker = require('faker'); | ||
| const svr = mockSvrFactory({ | ||
| queue: [{ one: 1 }, { two: 2 }, { three: 3 }], | ||
| preResponse: ({ method }, response) => { | ||
| const body = this.queue.unshift(); | ||
| if (!body) return { status: 404, body: { status: 'empty' } }; | ||
| return { status: 200, body }; | ||
| }, | ||
| }); | ||
| ``` | ||
| This example uses a `sum` counter on the response desriptor, and accesses it via the 2nd argument: | ||
| ```js | ||
| const svr = mockSvrFactory({ | ||
| sum: 0, | ||
| preResponse: ({ body: { sum = 0 } }, response) => { | ||
| this.sum += sum; | ||
| return { status: 200, body: { requests: svr.accepted.length, sum: this.sum } }; | ||
| }, | ||
| }); | ||
| ``` | ||
| ## Specs | ||
@@ -135,58 +209,68 @@ | ||
| mock-web-server | ||
| √ should be a factory function that names 1 arguments - response (it has an optional 2nd param for options) | ||
| ✓ should be a factory function that names 1 arguments - response (it has an optional 2nd param for options) | ||
| when provided only a response object | ||
| √ should not fail and return an server instance | ||
| ✓ should not fail and return an server instance | ||
| when provided a response object and the optional config object | ||
| √ should not fail and return an server instance | ||
| ✓ should not fail and return an server instance | ||
| a server instance obtained by the factory | ||
| supported API: | ||
| √ method .listen(port, done) to start the server | ||
| √ method .close(done) to close it | ||
| √ attribute .response as the provided response | ||
| √ attribute .accepted as array of accepted requests | ||
| √ method .reset() to clear the accepted requests and optionally - reset the response | ||
| ✓ method .listen(port, done) to start the server | ||
| ✓ method .close(done) to close it | ||
| ✓ attribute .response as the provided response | ||
| ✓ attribute .accepted as array of accepted requests | ||
| ✓ method .reset() to clear the accepted requests and optionally - reset the response | ||
| starting and closing the server should work | ||
| and the server should serve requests with | ||
| √ the provided status code | ||
| √ the provided headers | ||
| √ the provided body | ||
| ✓ the provided status code | ||
| ✓ the provided headers | ||
| ✓ the provided body | ||
| and server keeps a REPL-friendly view of the accepted requests that is cleared with .reset() | ||
| √ found 3 requests | ||
| √ views are serializable | ||
| √ .reset() returns the interface and clears the accepted array | ||
| √ .reset(response) returns the interface and sets the response | ||
| ✓ found 3 requests | ||
| ✓ views are serializable | ||
| ✓ .reset() returns the interface and clears the accepted array | ||
| ✓ .reset(response) returns the interface and sets the response | ||
| structure of a request view should contain | ||
| √ httpVersion | ||
| √ method | ||
| √ url | ||
| √ headers | ||
| √ rawHeaders | ||
| √ upgrade | ||
| √ body | ||
| √ trailers | ||
| √ rawTrailers | ||
| ✓ httpVersion | ||
| ✓ method | ||
| ✓ url | ||
| ✓ headers | ||
| ✓ rawHeaders | ||
| ✓ upgrade | ||
| ✓ body | ||
| ✓ trailers | ||
| ✓ rawTrailers | ||
| when response object has a preResponse hook | ||
| and the response hook returns an object | ||
| the server should serve request with response returned by the hook | ||
| ✓ the provided status code | ||
| ✓ the provided headers | ||
| ✓ the provided body | ||
| and the response hook mutates current response using `this` | ||
| the server should serve request with response mutated by the hook | ||
| ✓ the provided status code | ||
| ✓ the provided headers | ||
| ✓ the provided body | ||
| closing the server with a callback | ||
| √ should call the callback as well as closing the server | ||
| ✓ should call the callback as well as closing the server | ||
| an error passed by body-parser | ||
| √ should be collected to the request view as .parseError | ||
| ✓ should be collected to the request view as .parseError | ||
| ~internals | ||
| .mapParsers(parsers) | ||
| √ should be a function that names 1 argument - parsers | ||
| ✓ should be a function that names 1 argument - parsers | ||
| when called with an object element | ||
| √ should not fail | ||
| ✓ should not fail | ||
| when called with a function element | ||
| √ should not fail | ||
| ✓ should not fail | ||
| when called with a string element that is not a body-parser built-in | ||
| √ should not fail and map it to an instance produced by the required module | ||
| ✓ should not fail and map it to an instance produced by the required module | ||
| when called with an object element who's first key is not a body-parser built-in | ||
| √ should not fail | ||
| √ should map it to an instance produced by the required module | ||
| √ should pass it the arguments | ||
| ✓ should not fail | ||
| ✓ should map it to an instance produced by the required module | ||
| ✓ should pass it the arguments | ||
| 33 passing (94ms) | ||
| 39 passing (53ms) | ||
| ``` |
Network access
Supply chain riskThis module accesses the network.
Found 1 instance in 1 package
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
Found 1 instance in 1 package
Network access
Supply chain riskThis module accesses the network.
Found 1 instance in 1 package
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
Found 1 instance in 1 package
14502
37.23%62
10.71%274
44.21%