dynamock
v2.1.1
Published
Dynamic mock server which serves fixtures based on property matching
Downloads
3,382
Maintainers
Readme
dynamock
dynamock
is a dynamic mock/fixture HTTP server designed for functional testing.
Installation
yarn add dynamock -D
# or NPM
npm install dynamock --save-dev
Usage
⚠️ Security
Be aware of running your dynamock server in a CLOSED network, there is no authentication required to configure it. It is highly recommended using dynamock for dev/testing purpose ONLY.
Run the server (NodeJS required)
# dynamock PORT [HOST]
dynamock 3001
Inject fixtures
fetch('http://localhost:3001/___fixtures', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
request: {
method: 'GET',
path: '/products/1'
},
response: {
body: {
id: 1
}
}
})
})
Consume fixtures
fetch('http://localhost:3001/products/1', { method: 'GET' })
.then(response => response.json())
.then(response => assert.equal(response, { id: 1 }))
Dynamock is designed to remove the fixture once consumed, see options.lifetime to adapt this behavior.
fetch('http://localhost:3001/products/1', { method: 'GET' }).then(response => assert.equal(response.status, 404))
Property response matching
By default, dynamock uses partial matching for headers
, query
and cookies
.
Configuration api
Using the configuration is optional. However, it gives the ability of reusing redundant data across requests and simplifying fixtures setup.
/___config - Retrieve configuration
Responses
- Status 200 - OK
{
"cors": "{null|'*'} - '*' allows all requests via cors headers, this creates a global route OPTIONS",
"headers": "{object} - Dictionary of headers (object) by name (string)",
"query": "{object} - Dictionary of query (object) by name (string)",
"cookies": "{object} - Dictionary of cookies (object) by name (string)"
}
Example:
{
"cors": null,
"headers": {},
"query": {},
"cookies": {}
}
/___config - Update configuration
Request
- Body
{
"cors": "{null|'*'} [default=null] - '*' allows all requests via cors headers, this creates a global route OPTIONS",
"headers": "{object} [default={}] - Dictionary of headers (object) by name (string)",
"query": "{object} [default={}] - Dictionary of query (object) by name (string)",
"cookies": "{object} [default={}] - Dictionary of cookies (object) by name (string)"
}
Example:
{
"cors": "*",
"headers": {
"apiBearer": {
"Authorization": "Bearer xyz"
}
}
}
Responses
- Status 200 - OK
{
"cors": "{null|'*'}",
"headers": "{object}",
"query": "{object}",
"cookies": "{object}"
}
Example:
{
"cors": null,
"headers": {
"captcha": {
"X-CAPTCHA-TOKEN": "fake"
},
"cors": {
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Methods": "*",
"Access-Control-Allow-Headers": "*"
}
},
"query": {
"campaign": {
"utm_source": "x",
"utm_campaign": "y"
}
},
"cookies": {
"anonymousUser": {
"PHPSESSID": "x"
},
"loggedInUser": {
"PHPSESSID": "y"
}
}
}
- Status 400 - BAD REQUEST
Wrong configuration format
/___config - Reset configuration
Responses
- Status 204 - NO CONTENT
Fixtures api
A fixture is composed of:
- request data to match the incoming requests
- response data to define the result(s) of the requests
/___fixtures - Add fixture
Request
- Body
{
"request": {
"method": "{string} - Http method to match requests, case insensitive, use wildcard '*' to match all",
"path": "{string} - Http path to match requests, use wildcard '*' to match all",
"headers": "{object|array} [default={}] - Headers to match requests",
"query": "{object|array} [default={}] - Query to match requests",
"cookies": "{object|array} [default={}] - Cookies to match requests",
"body": "{object} [default=``] - Body to match requests",
"options": {
"path": {
"allowRegex": "{boolean} [default=false] - Allow matching RegExp",
"disableEncodeURI": "{boolean} [default=false] - Disable encode URI, always on when allowRegex is true"
},
"method": {
"allowRegex": "{boolean} [default=false] - Allow matching RegExp"
},
"headers": {
"strict": "{boolean} [default=false] - Strictly match headers",
"allowRegex": "{boolean} [default=false] - Allow matching RegExp"
},
"cookies": {
"strict": "{boolean} [default=false] - Strictly match cookies",
"allowRegex": "{boolean} [default=false] - Allow matching RegExp"
},
"query": {
"strict": "{boolean} [default=false] - Strictly match query",
"allowRegex": "{boolean} [default=false] - Allow matching RegExp"
},
"body": {
"strict": "{boolean} [default=false] - Strictly match body",
"allowRegex": "{boolean} [default=false] - Allow matching RegExp"
}
}
},
"response": {
"status": "{number} [default=200] - Response status code",
"headers": "{object|array} [default={}] - Response headers",
"cookies": "{object|array} [default={}] - Response cookies",
"body": "{string|object|array} [default=``] - Body to response",
"filepath": "{string} [default=``] - Absolute filepath to serve with auto mime-types",
"options": {
"delay": "{number} [default=0] - Delay the response with a number of milliseconds",
"lifetime": "{number} [default=1] - Number of times the fixture can be consumed before getting removed, use 0 for unlimited consumption"
}
},
"responses": "{array} [default=[]] - Array of responses"
}
Examples:
{
"request": {
"method": "GET",
"path": "/pandas"
},
"response": {
"body": [{ "id": "1" }, { "id": "2" }]
}
}
{
"request": {
"method": "GET",
"path": "/cdn/images/fennec.jpg"
},
"response": {
"filepath": "/absolute/path/tofennec.jpg",
"options": {
"delay": 1000
}
}
}
{
"request": {
"method": "POST",
"path": "/heros",
"body": {
"name": "po",
"type": "panda"
},
"options": {
"body": {
"strict": true
}
}
},
"response": {
"body": {
"id": "1",
"name": "po",
"type": "panda"
}
}
}
{
"request": {
"method": "OPTIONS",
"path": "*"
},
"response": {
"headers": {
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Methods": "*",
"Access-Control-Allow-Headers": "*"
},
"body": ""
}
}
{
"request": {
"method": "get",
"path": "/"
},
"responses": [
{
"body": "first return"
},
{
"body": "second return"
}
]
}
{
"request": {
"method": "GET",
"path": "/",
"headers": {
"user-agent": "/firefox/70$/i"
},
"options": {
"headers": {
"allowRegex": true
}
}
},
"response": {
"body": "Only for Firefox 70 users !"
}
}
{
"request": {
"method": "GET",
"path": "/%20a",
"options": {
"path": {
"disableEncodeURI": true
}
}
},
"response": {
"body": "This will match '/ a' or '/%20a' calls"
}
}
Responses
- Status 200 - OK
{
"id": "{string}"
}
Example:
{
"id": "38ed32e9fb0a1e5c7cb1b6f0ff43f6060d8b4508"
}
- Status 400 - BAD REQUEST
The configuration is not valid
- Status 409 - CONFLICT
Route {METHOD} ${PATH} is already registered.
/___fixtures/bulk - Bulk add fixtures
It is meant to setup multiple fixtures at once.
Request
- Body
[
{
"request": {
"method": "{string} - Http method to match requests, case insensitive, use wildcard '*' to match all",
"path": "{string} - Http path to match requests, use wildcard '*' to match all",
"headers": "{object|array} [default={}] - Headers to match requests",
"query": "{object|array} [default={}] - Query to match requests",
"cookies": "{object|array} [default={}] - Cookies to match requests",
"body": "{object} [default=``] - Body to match requests",
"options": {
"path": {
"allowRegex": "{boolean} [default=false] - Allow matching RegExp"
},
"method": {
"allowRegex": "{boolean} [default=false] - Allow matching RegExp"
},
"headers": {
"strict": "{boolean} [default=false] - Strictly match headers",
"allowRegex": "{boolean} [default=false] - Allow matching RegExp"
},
"cookies": {
"strict": "{boolean} [default=false] - Strictly match cookies",
"allowRegex": "{boolean} [default=false] - Allow matching RegExp"
},
"query": {
"strict": "{boolean} [default=false] - Strictly match query",
"allowRegex": "{boolean} [default=false] - Allow matching RegExp"
},
"body": {
"strict": "{boolean} [default=false] - Strictly match body",
"allowRegex": "{boolean} [default=false] - Allow matching RegExp"
}
}
},
"response": {
"status": "{number} [default=200] - Response status code",
"headers": "{object|array} [default={}] - Response headers",
"cookies": "{object|array} [default={}] - Response cookies",
"body": "{string|object|array} [default=``] - Body response",
"filepath": "{string} [default=``] - Absolute filepath to serve with auto mime-types",
"options": {
"delay": "{number} [default=0] - Delay the response with a number of milliseconds",
"lifetime": "{number} [default=1] - Number of times the fixture can be consumed before getting removed, use 0 for unlimited consumption"
}
},
"responses": "{array} [default=[]] - Array of responses"
}
]
Examples:
[
{
"request": {
"method": "GET",
"path": "/pandas"
},
"response": {
"body": [{ "id": "1" }, { "id": "2" }]
}
},
{
"request": {
"method": "GET",
"path": "/cdn/images/fennec.jpg"
},
"response": {
"filepath": "/absolute/path/tofennec.jpg"
}
}
]
Responses
- Status 200 - OK
[
{
"id": "{string}"
}
]
Example:
[
{
"id": "38ed32e9fb0a1e5c7cb1b6f0ff43f6060d8b4508"
},
{
"id": "086c67ef89fd832deeae33b209e6e8ecc6b32003"
}
]
- Status 400 - BAD REQUEST
The fixture is not valid
- Status 409 - CONFLICT
Another fixture with the same request is already registered
/___fixtures/:id - Delete a fixture
Request
- Params
{
"id": "{string}"
}
Example:
DELETE /___fixtures/38ed32e9fb0a1e5c7cb1b6f0ff43f6060d8b4508
Responses
- Status 204 - NO CONTENT
/___fixtures - Delete all fixtures
Responses
- Status 204 - NO CONTENT
Next features
- Handle other web protocols like https or websocket
- Security tokens for public environments