Skip to content

Feature/match body payload as object #68

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 7 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
69 changes: 68 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ There are a couple of rules to follow.
{
"expression": "your expression here (ie a regex without the leading and trailing '/' or a string)",
"method": "the http method (ie GET, POST, PUT or DELETE)", // supports JSONP as well
"body": "request body matcher (ie a regex without the leading and trailing '/' or a string)" // optional
"body": "request body matcher (ie an object, a regex without the leading and trailing '/' or a string)" // optional
"name": "identifiable name for this service call" // if non is provided, expression$$method will be used
"isArray": "indicates if the response data is an array or object",
"responses": {
Expand All @@ -81,6 +81,73 @@ There are a couple of rules to follow.

```

## About the body matcher

### As a string
The string provided as the body matcher will be used as a RegExp to match against the request payload.

### As an object
You can provide a full or partial object to be matched against the request payload.

The request body will match the payload if:
- the fields names match;
- the field values and types match;
- the fields are at the same level in the object hierarchy;

For example, consider the following request payload:
```json
{
"company": "YouTube, LLC",
"address": {
"street": "901 Cherry Ave",
"city": "San Bruno",
"state": "CA",
"zip": 94066
}
}
```

**Example #1:**
```json
{
"body": {
"company": "YouTube, LLC"
}
}
```
| Match | Reason |
| ----- | ------ |
| True | Partial object with same field matching name, type, value and level |

**Example #2:**
```json
{
"body": {
"address": {
"state": "CA"
}
}
}
```
| Match | Reason |
| ----- | ------ |
| True | Partial object with sub-node with same field matching name, type, value and level |

**Example #3:**
```json
{
"body": {
"address": {
"state": "CA",
"country": "USA" // <-- not present on request payload
}
}
}
```
| Match | Reason |
| ----- | ------ |
| False | It expects a field that is not present on payload |

## Howto use global variables
If for instance, you have date sensitive information in you mocks, mock data is not flexible enough.
You can use global variables for this. By surrounding a value in the response.data with %%theVariableName%%,
Expand Down
19 changes: 18 additions & 1 deletion lib/ngApimockHandler.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import * as http from 'http';
import * as fs from 'fs-extra';
import * as url from 'url';
import { clone, isEqual, merge } from 'lodash';
import Mock from '../tasks/mock';
import {httpHeaders} from './http';
import Registry from './registry';
Expand Down Expand Up @@ -158,14 +159,30 @@ abstract class NgApimockHandler implements Handler {
const allMatches: Mock[] = mocks.filter(_mock => {
const expressionMatches: boolean = !!(new RegExp(_mock.expression).exec(decodeURI(requestUrl)));
const methodMatches: boolean = _mock.method === method;
const bodyMatches: boolean = _mock.body ? !!(new RegExp(_mock.body).exec(payload)) : true;
const bodyMatches: boolean = _mock.body ? this.bodyMatches(_mock.body, payload) : true;

return expressionMatches && methodMatches && bodyMatches;
});

return allMatches.filter(_mock => _mock.body)[0] || allMatches[0]
}

/**
* Indicates if the payload matches the mock body either as a string or as an object.
* @param mockBody {string|object} the mock body
* @param payload {string} the request payload
*/
bodyMatches(mockBody: any, payload: string): boolean {
// mock body as string
if (typeof mockBody === 'string') {
return !!(new RegExp(mockBody).exec(payload));
}
// mock body as object
const requestBody = JSON.parse(payload);
const expectedBody = merge(clone(requestBody), mockBody);
return isEqual(requestBody, expectedBody);
}

/**
* Indicates if the given response is a binary response.
* @param response The response
Expand Down
Loading