The default formatter
for mountebank allows you to use EJS (version 2.x) templates
to split the test data into multiple files. This is particularly useful for separating out JavaScript injection
functions and XML or JSON HTTP response bodies because you store them as multi-line files and rely on
templating to turn them into JSON-friendly single line strings. It remains the default for backwards
compatibility, even though EJS 3.x has made breaking changes.
mountebank will pass a stringify
function into your templates that allows you to put
multi-line strings in separate files. The example below is loosely based on the
response injection example described on
the Injection page, and shows the use of the stringify
function. The path passed in
to stringify
is relative to the root file referenced in the configfile
command line parameter. You can also pass a custom object, referenced as data
in child
templates, as the second parameter of stringify
. This is useful if you want to reuse
the same template but add some dynamic data. For an example, look at the stringify
call in
templates/originServer.ejs below, and using the custom field in templates/originXMLResponse.ejs.
Assuming the files below are in a relative directory called templates
, you can
initialize mb
with the following command:
mb --configfile templates/imposters.ejs --allowInjection --localOnly
templates/imposters.ejs
{
"imposters": [
<% include originServer.ejs %>,
<% include proxyServer.ejs %>
]
}
templates/originServer.ejs
{
"port": 5555,
"protocol": "http",
"name": "origin",
"stubs": [
{
"predicates": [{ "contains": { "headers": { "Content-Type": "xml" } } }],
"responses": [{ "is": { "body": "<%- stringify('originXMLResponse.ejs', { value: 'first }) %>" }}]
},
{
"responses": [{ "inject": "<%- stringify('originServerResponse.ejs') %>" }]
}
]
}
templates/originXMLResponse.ejs
<rootNode>
<childNode><%= '<' + '%= data.value %' + '>' %></childNode>
</rootNode>
templates/originServerResponse.ejs
(request, state, logger) => {
logger.info('origin called');
state.requests = state.requests || 0;
state.requests += 1;
return {
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ count: state.requests })
};
}
templates/proxyServer.ejs
{
"port": 4546,
"protocol": "http",
"name": "proxy",
"stubs": [
{
"responses": [{ "inject": "<%- stringify('counter.ejs') %>" }],
"predicates": [{
"equals": {
"method": "GET",
"path": "/counter"
}
}]
},
{
"responses": [{ "inject": "<%- stringify('proxy.ejs') %>" }]
}
]
}
templates/counter.ejs
function (request, state) {
var count = state.requests ? Object.keys(state.requests).length : 0;
return {
body: `There have been ${count} proxied calls`
};
}
templates/proxy.ejs
function (request, state, logger, callback) {
var cacheKey = request.method + ' ' + request.path;
if (typeof state.requests === 'undefined') {
state.requests = {};
}
if (state.requests[cacheKey]) {
logger.info('Using previous response');
callback(state.requests[cacheKey]);
}
var http = require('http'),
options = {
method: request.method,
hostname: 'localhost',
port: 5555,
path: request.path,
headers: request.headers
},
httpRequest = http.request(options, response => {
var body = '';
response.setEncoding('utf8');
response.on('data', chunk => {
body += chunk;
});
response.on('end', () => {
var stubResponse = {
statusCode: response.statusCode,
headers: response.headers,
body
};
logger.info('Successfully proxied: ' + JSON.stringify(stubResponse));
state.requests[cacheKey] = stubResponse;
callback(stubResponse);
});
});
httpRequest.end();
}