Any Restful service API can be mocked such as:
Yes - It is same as for any other backend service. For AJAX call, point it to the mocked server instance instead of the actual back end service and add a mocked route in the file containing mocked routes for mock server.
"dependencies": {
"testarmada-midway": "1.0.1" // add the latest version
}
Add the following code in your routes file, typically endpoints.js
midway.route({
id: 'helloWorld', // required
label: 'Hello World', // Used for Mock Server UI
path: '/helloWorld', // the path you want to mock
method: 'GET', // The Rest Method you want to mock for this API
handler: function (req, reply) { // Add Logic to massage data before returning back to the request.
reply('Hello World');
}
});
By adding the URL part in curly brackets that you would liek to by dynamic such as /get/customerInfo/{customerid}/{zipcode}
For example:
midway.route({
id: 'customerInfo',
label: 'Customer Info',
path: '/get/customerInfo/{customerid}/{zipcode}', // both customerid and zipcode will be dynamic
method: 'GET',
variantLabel: 'Get Customer Info',
handler: function (req, reply) {
reply('How to read the customer id :(');
}
});
var midway = require('testarmada-midway');
midway.route({
path: '/get/customerInfo/{customerid}/{zipcode}'
handler: function(request, reply) {
var params = request.params;
var customerid = params.customerid; // customerid is 123 if request is "/get/customerInfo/123/92127"
var zipcode = params.zipcode; // zipcode is 92127 if request is "/get/customerInfo/123/92127"
}
});
var midway = require('testarmada-midway');
midway.route({
path: '/api/getCart'
handler: function(request, reply) {
var headers = request.raw.req.headers;
var authorization = headers.authorization;
}
});
var midway = require('testarmada-midway');
midway.route({
path: '/api/getCart'
handler: function(request, reply) {
var payload = request.payload;
// foo would be "bar" if the posted body content (as JSON) is {"foo": "bar"}
var foo = payload.foo;
}
});
var midway = require('testarmada-midway');
midway.route({
path: '/api/getCart'
handler: function(request, reply) {
var queryParams = request.query;
// foo would be "bar" if incoming request is "/api/getCart?foo=bar"
var foo = queryParams.foo;
}
});
midway.route({
id: 'header',
label: 'Test Headers',
path: '/api/testHeaders',
handler: function (req, reply) {
var myHeaders = {
header1: 'test1',
header2: 'test2',
header3: true
};
midway.util.respondWithFile(this, reply, {headers: myHeaders});
}
});
midway.route({
id: 'Get Collection',
label: 'Get Collections',
path: '/product/grouping/api/collection/{collectionId}',
handler: function(req, reply) {
reply({message: 'test'})
.header('X-Res-Header', 'I\'m a custom response header')
}
});
midway.route({
id: 'cookie',
label: 'Test Cookies',
path: '/api/testCookies',
handler: function (req, reply) {
var cookies = [
{name: 'com.wm.customer', value: 'vz7.0b5c56'},
{name: 'CID', value: 'SmockedCID', options: {domain: 'domain', path: '/'}},
{name: 'anotherCookie', value: 'cookieValue'}
];
midway.util.respondWithFile(this, reply, {cookies: cookies});
}
});
midway.route({
id: 'Get Collection',
label: 'Get Collections',
path: '/product/grouping/api/collection/{collectionId}',
handler: function(req, reply) {
reply({message: 'test'})
.state('test-cookie', 'I\'m a custom response cookie')
}
});
var corsHeaders = {
origin: ['*'],
headers: ["Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept"],
credentials: true,
}
// Items
midway.route({
id: 'tempo',
label: 'Tempo',
path: '/tempo1',
config: {
cors: corsHeaders
},
handler: function(req, reply) {
midway.util.respondWithFile(this, reply);
}
});
respondWithFile
Utility?This feature allows you to respond with a data stored in a file instead of hard coding the response data in the routes definition. This way user does not have to hard-code/change the response in handler and rather can just swap the file with different data without even bringing the server down.
midway.route({
id: 'ResponseFromFile',
label: 'Response From File',
path: '/get/fromFile',
handler: function(req, reply) {
midway.util.respondWithFile(this, reply);
}
});
In the above example, mock server will automatically look for a file default.{some_extension}
at ./mocked-data/get/fromFile/GET/default.{some_extension}
respondWithFile
Utility?The path to the mocked data file is auto-calculated based on the route path. For example if the route path is /get/cart than for the default variant, mock server will look for the default.{some_extension}
file at ./mocked-data/get/fromFile/GET/default.{some_extension}
. For variants, the name of the file should be changed from default to the variant name as shown below:
midway.route({
id: 'ResponseFromFile',
label: 'Response From File',
path: '/get/fromFile',
handler: function(req, reply) {
midway.util.respondWithFile(this, reply);
}
})
.variant({
id: 'textData',
label: 'Text Data',
handler: function (req, reply) {
midway.util.respondWithFile(this, reply);
}
});
In above example mock server will look for ./resources/mocked-data/get/fromFile/GET/textData.{some_extension} file for the variant textData
respondWithFile
Utility?Yes. By adding filePath
parameter as shown in below example:
midway.route({
id: 'CustomResponseFile',
label: 'Response From Custom Path',
path: '/get/customFile',
handler: function(req, reply) {
midway.util.respondWithFile(this, reply, {filePath: './custom.json'});
}
});
In above example mock server will look for the file under MockedDirectory only but at ./mocked-data/custom.json
midway.route({
id: 'message',
label: 'hello message',
path: '/message',
handler: function(req, reply) {
reply().code(400);
}
});
respondWithFile
Utility?Yes - by adding code
parameter as shown in below example:
midway.route({
id: 'message',
label: 'hello message',
path: '/message',
handler: function(req, reply) {
midway.util.respondWithFile(this, reply, {code: 400});
}
});
Mocked directory path is the location to the base directory where all your mocked response file will be stored. This parameter is defined in run-mock-server-console.js file. It is defined at the start of mock server as shown in the code below:
require('./endpoints');
require('testarmada-midway').start({
host: "localhost",
mockedDirectory: "./resources/mocked-data",
port: 8000,
project: 'HelloMidway'
});
If you have set your default folder to be mocked-data
, then based on your URL path:
For default variant, mock server will look for ./mocked-data/product/grouping/api/collection/GET/default.json
and for mixItem
variant mock server will look for ./mocked-data/product/grouping/api/collection/GET/mixItem.json
Variants allows to return a different data set for a given mocked route. Variants can be selected either in the admin UI or through automation APIs to determine what type of response a route should have. Routes are defined using the variant method on the Route object (returned by calling the route method). An object parameter is provided with the following attributes
Variants are useful because they allow you to test multiple scenarios that can happen with your route. Say, for example, you have a route exposing the ability to update a password. You might have several exceptional scenarios that you would want to test out (each could be a variant that you simply select to tell the route handler to use the appropriate response)
To add a one or more variants do the following:
midway.route({
id: 'message',
label: 'Message',
path: '/get/message',
method: 'GET',
variantLabel: 'Hello',
handler: function (req, reply) {
reply('Hello');
}
})
.variant({
id: 'hello',
label: 'Hello World',
handler: function (req, reply) {
reply('Hello World');
}
})
.variant({
id: 'hello',
label: 'Hello Universe',
handler: function (req, reply) {
reply('Hello Universe');
}
});
browser.setMockVariant({ fixture: "fixture id", variant: "variant id" });
You can also switch the variants via HTTP call (Recommended only when not using Midway as a library). As an example, if you want to set variant to helloUniverse
for the route below:
midway.route({
id: 'helloWorld',
label: 'Hello World',
path: '/helloWorld',
method: 'GET',
handler: function (req, reply) {
reply('Hello World');
}
})
.variant({
id: 'helloUniverse',
label: 'Hello Universe',
handler: function (req, reply) {
reply('Hello Universe');
}
});
curl -H "Content-type: application/json" -X POST -d '{"variant":"<variant>"}' <host>:<port>/midway/api/route/<routeId>
So for the above route, you can switch the variant to helloUniverse
like this:
curl -H "Content-type: application/json" -X POST -d '{"variant":"helloUniverse"}' http://localhost:8000/midway/api/route/helloWorld
When using parallel sessions, if you want to switch a variant for a route for a particular session, register the session with mock server like this:
curl <host>:<port>/midway/api/registerSession
// e.g
curl http://localhost:8000/midway/api/registerSession
If sessions are available, mock server will return a response like:
{"session":"33b08d"}
Extract the session id from response and append it to the route id you want to switch variant for e.g:
curl -H "Content-type: application/json" -X POST -d "variant":"helloUniverse"}' http://localhost:8000/midway/api/route/helloWorld-33b08d
UI can be used to view and test mocked routes as well as for manual switching of variants when running tests manually.
Parallel sessions allows you to run multiple instance of server virtually while running only one server. This is helpful when you are running multiple test cases which access the same routes but different variants as parallel sessions allow you to set different variants on same routes without conflicting. This saves CPU and RAM both as only one server is running instead of multiple. Please see the call flow explaination without and with Parallel Sessions Below:
Add sessions
parameter with number of virtual services you want as shown in below example while startung mock Server.
require('./endpoints');
var midway = require('testarmada-midway');
midway.start({
host: "localhost",
mockedDirectory: "./resources/mocked-data",
port: 8000,
sessions: 2,
project: 'HelloMidway'
});
var sessionId = midway.registerSession();
var closeSession = midway.closeSession(sessionId);
Yes - Mock Server exposes transpose
option that cna be passed in respondWithFile
method to modify the JSON files dynamically.
transposeData
Work To Modify JSON Data Stored In Files?If you have many variants for a Rest end point and the mocked data for all variants can use the same JSON response with few changes to the values, than this feature is what you need. This feature allows you to dynamically change a JSON file before sending the response back from the mock server for the request. It removes the need of having one to one mapping of static JSON files with each variants.
// Static Response JSON File
{
id: "1234",
name: "toothpaste"
details: [
{
flavor: "Mint 1",
Size: "10",
Size_Type: ounce
},
{
flavor: "Mint",
Size: "10",
Size_Type: ounce
}
]
}
// Sample code for substituting id from 1234 to 7777 and flavor from Mint to Mint 2 for second array element in routes
midway.route({
id: 'Get Collection',
label: 'Get Collections',
path: '/product/grouping/api/collection/{collectionId}',
handler: function(req, reply) {
var dataToChange = {
'id': '7777',
'details[1].flavor': 'Mint 2'
}
midway.util.respondWithFile(this, reply, {transpose: dataToChange});
}
});
// Dynamic Response JSON File returned from Mock service
{
id: "7777",
name: "toothpaste"
details: [
{
flavor: "Mint 1",
Size: "10",
Size_Type: ounce
},
{
flavor: "Mint 2",
Size: "10",
Size_Type: ounce
}
]
}
transposeData
Functionality Outside Of respondWithFile
?Yes - You can use it by Midway Utils.
var fileLocation = require("path").join(__dirname, './resources/test-data/data-transposition-test.json');
var dataSet = utils.readJsonFile(fileLocation);
var dataToChange = {
'items.item[0].id': 1234, // substitue id 0001 to 1234
'items.item[0].val': "value", // Add 'val' to first array element of items.item
'items.item[1].id': 4567, // Add 'id' to second array element of items.item
'items.item[0].batters.batter[0].id': 5678 // substitue id 1001 to 5678
}
substitutedData = midway.util.transposeData(dataSet, dataToChange);
// Base JSON file - data-transposition-test.json
{
"items":
{
"item":
[
{
"id": "0001",
"type": "donut",
"name": "Cake",
"ppu": 0.55,
"batters":
{
"type" : 1,
"batter":
[
{ "id": "1001", "type": "Regular" },
]
},
"topping":
[
{ "id": "5001", "type": "None" }
]
}
]
}
};
// Resulted JSON
{
"items": {
"item": [
{
"id": 1234,
"type": "donut",
"name": "Cake",
"ppu": 0.55,
"val": "value"
"batters": {
"type": 1,
"batter": [
{"id": 5678, "type": "Regular"}
]
},
"topping": [
{"id": "5001", "type": "None"}
]
},
{
"id": 4567
}
]
}
};
If you’re using content type like application/graphql
, follow this example
midway.route({
id: 'id',
label: 'id',
path: '/graphql',
method: ['POST', 'PUT'],
config : {
payload: {
parse: false,
allow: 'application/graphql'
}
},
handler: function (req, reply) {
midway.util.respondWithFile(this, reply, {code: 200});
}
});
For more details, read this