-
Notifications
You must be signed in to change notification settings - Fork 0
/
index.js
157 lines (133 loc) · 4.79 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
'use strict';
/* eslint-disable consistent-this */
/* eslint-disable complexity */
/* eslint-disable no-unexpected-multiline */
const nock = require('nock');
const deepEqual = require('deep-equal');
const _ = require('lodash');
/**
* Create a nock inspector.
* @param {Object} options - The request.
* @param {string} options.method - The method (GET, PUT, etc.).
* @param {string} options.basePath - Base path of the URL.
* @param {string} options.endpoint - The endpoint.
* @param {Object} [options.response] - The default response.
*/
module.exports = function makeNockInspector(options) {
return new NockInspector(options);
};
module.exports.cleanAll = () => nock.cleanAll();
module.exports.activeMocks = () => nock.activeMocks();
function NockInspector({ method, basePath, endpoint, response }) {
if (response && !response.status) {
response.status = 200;
}
if (!method) {
throw new Error('method is required');
}
const headersMatch = (request, specRequest) =>
!specRequest.headers
? true
: deepEqual(
specRequest.headers,
_.pick(request.headers, _.keys(specRequest.headers))
);
const bodiesMatch = (request, specRequest) =>
deepEqual(request.body, specRequest.body);
const inspectorProps = this;
//the default response
inspectorProps.response = response;
//an array of all requests made to the thing
inspectorProps.requests = [];
//specific responses and headers that correlate to one another
inspectorProps.specifics = [];
//this is the nock itself
inspectorProps.scope = createScope({ method, basePath, endpoint });
//things to respond with when scope has been called a specific number of times
inspectorProps.numberedResponses = {};
/**
* Tailor a response for a specific request
* @param {Object} request - The request.
* @param {Object} [request.body] - The request body.
* @param {Object} [request.headers] - The request headers.
* @param {Object} response - The response.
* @param {number} [response.status] - The response status.
* @param {Object} [response.body] - The response body.
* @param {Object} [response.headers] - The response headers.
*/
inspectorProps.respondToRequest = function requestResponse(
request,
response
) {
if (!request || !response) {
throw new Error('both a request and a response are required');
}
if (!request.body && !request.headers) {
throw new Error('request must have a body or headers');
}
if (!response.status) {
response.status = 200;
}
const existingSpec = _.findIndex(inspectorProps.specifics, (specific) =>
deepEqual(specific.request, request)
);
if (existingSpec >= 0) {
inspectorProps.specifics[existingSpec] = { request, response };
return;
}
inspectorProps.specifics.push({ request, response });
};
/**
* @param {number} callNumber
* @param {Object} response - The response.
* @param {number} [response.status] - The response status.
* @param {Object} [response.body] - The response body.
* @param {Object} [response.headers] - The response headers.
*/
inspectorProps.respondOnCall = function respondOnCall(callNumber, response) {
inspectorProps.numberedResponses[callNumber] = response;
};
function createScope({ method, basePath, endpoint }) {
return nock(basePath)
[method.toLowerCase()](endpoint)
.query((query) => {
inspectorProps.request = { query };
return true;
})
.reply(function reply(uri, requestBody) {
const requestInfo = { headers: this.req.headers, body: requestBody };
inspectorProps.request = { ...inspectorProps.request, ...requestInfo };
inspectorProps.requests.push(inspectorProps.request);
const specific = _.find(
inspectorProps.specifics,
(specific) =>
headersMatch(requestInfo, specific.request)
&& bodiesMatch(requestInfo, specific.request)
);
const numberedResponse = inspectorProps.numberedResponses[inspectorProps.requests.length];
//todo if body is undefined should it be {}? right now it just comes back with no body.
if (numberedResponse) {
return [
numberedResponse.status,
numberedResponse.body,
numberedResponse.headers
];
} else if (specific) {
return [
specific.response.status,
specific.response.body,
specific.response.headers
];
} else if (inspectorProps.response) {
return [
inspectorProps.response.status,
inspectorProps.response.body,
inspectorProps.response.headers
];
} else {
throw new Error('There is no matching or default response');
}
})
.persist(true);
}
}