node-tdd 3.0.6 → 3.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md
CHANGED
|
@@ -80,12 +80,13 @@ Can be used in the following ways:
|
|
|
80
80
|
|
|
81
81
|
- `--nock-heal`: Will try to heal ordering of nock cassette recordings
|
|
82
82
|
- `--nock-heal prune`: Will remove unmatched recordings from nock cassette
|
|
83
|
+
- `--nock-heal headers`: Will try to heal request headers of nock cassette recordings
|
|
83
84
|
- `--nock-heal body`: Will try to heal bodies of nock cassette recordings
|
|
84
85
|
- `--nock-heal path`: Will try to heal paths of nock cassette recordings
|
|
85
86
|
- `--nock-heal response`: Will try to heal responses
|
|
86
87
|
- `--nock-heal record`: Will record the next unmatched request
|
|
87
88
|
- `--nock-heal stub`: Will stub the next unmatched request
|
|
88
|
-
- `--nock-heal magic`: Shorthand for `
|
|
89
|
+
- `--nock-heal magic`: Shorthand for `headers,body,path,response`
|
|
89
90
|
|
|
90
91
|
Notes:
|
|
91
92
|
- Different flags can be combined as e.g. `--nock-heal body,path`
|
|
@@ -131,6 +132,13 @@ Default: `false`
|
|
|
131
132
|
|
|
132
133
|
When set to true, all headers are stripped when requests are recorded.
|
|
133
134
|
|
|
135
|
+
### nockReqHeaderOverwrite
|
|
136
|
+
|
|
137
|
+
Type: `object`<br>
|
|
138
|
+
Default: `{}`
|
|
139
|
+
|
|
140
|
+
Can be used to overwrite `reqheaders` in recordings. Cassette files are only updated when changed.
|
|
141
|
+
|
|
134
142
|
#### fixtureFolder
|
|
135
143
|
|
|
136
144
|
Type: `string`<br>
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
const nockCommon = require('nock/lib/common');
|
|
4
4
|
|
|
5
|
-
const fns = ['setInterval', 'setTimeout'];
|
|
5
|
+
const fns = ['setInterval', 'setTimeout', 'deleteHeadersField'];
|
|
6
6
|
const originals = fns.reduce((p, c) => Object.assign(p, {
|
|
7
7
|
[c]: nockCommon[c]
|
|
8
8
|
}), {});
|
|
@@ -10,6 +10,10 @@ module.exports = {
|
|
|
10
10
|
patch: () => {
|
|
11
11
|
fns.forEach(fn => {
|
|
12
12
|
nockCommon[fn] = (...args) => {
|
|
13
|
+
if (fn === 'deleteHeadersField') {
|
|
14
|
+
return undefined;
|
|
15
|
+
}
|
|
16
|
+
|
|
13
17
|
if (args[1] === 0) {
|
|
14
18
|
return args[0](...args.slice(2));
|
|
15
19
|
}
|
|
@@ -6,7 +6,7 @@ const http = require('http');
|
|
|
6
6
|
|
|
7
7
|
const https = require('https');
|
|
8
8
|
|
|
9
|
-
const
|
|
9
|
+
const nockCommon = require('nock/lib/common');
|
|
10
10
|
|
|
11
11
|
let lastProtocol = null;
|
|
12
12
|
let lastOptions = null;
|
|
@@ -21,7 +21,7 @@ const wrapper = proto => {
|
|
|
21
21
|
|
|
22
22
|
const requestWrapper = (...args) => {
|
|
23
23
|
lastProtocol = proto;
|
|
24
|
-
lastOptions =
|
|
24
|
+
lastOptions = nockCommon.normalizeClientRequestArgs(...args).options;
|
|
25
25
|
lastBody.length = 0;
|
|
26
26
|
const result = requestOriginal.call(protocol, ...args);
|
|
27
27
|
const writeOriginal = result.write;
|
|
@@ -24,4 +24,12 @@ module.exports.convertHeaders = array => {
|
|
|
24
24
|
}
|
|
25
25
|
|
|
26
26
|
return obj;
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
module.exports.rewriteHeaders = (headers, fn = (k, v) => v) => {
|
|
30
|
+
if (headers === undefined) {
|
|
31
|
+
return {};
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
return Object.fromEntries(Object.entries(headers).sort(([a], [b]) => a > b ? 1 : -1).map(([k, v]) => [k.toLowerCase(), fn(k, v)]));
|
|
27
35
|
};
|
|
@@ -18,6 +18,8 @@ const cloneDeep = require('lodash.clonedeep');
|
|
|
18
18
|
|
|
19
19
|
const compareUrls = require('compare-urls');
|
|
20
20
|
|
|
21
|
+
const nockCommon = require('nock/lib/common');
|
|
22
|
+
|
|
21
23
|
const nockListener = require('./request-recorder/nock-listener');
|
|
22
24
|
|
|
23
25
|
const nockMock = require('./request-recorder/nock-mock');
|
|
@@ -30,7 +32,8 @@ const {
|
|
|
30
32
|
buildKey,
|
|
31
33
|
tryParseJson,
|
|
32
34
|
nullAsString,
|
|
33
|
-
convertHeaders
|
|
35
|
+
convertHeaders,
|
|
36
|
+
rewriteHeaders
|
|
34
37
|
} = require('./request-recorder/util');
|
|
35
38
|
|
|
36
39
|
const requestInjector = require('./request-recorder/request-injector');
|
|
@@ -42,6 +45,7 @@ module.exports = opts => {
|
|
|
42
45
|
Joi.assert(opts, Joi.object().keys({
|
|
43
46
|
cassetteFolder: Joi.string(),
|
|
44
47
|
stripHeaders: Joi.boolean(),
|
|
48
|
+
reqHeaderOverwrite: Joi.object().pattern(Joi.string().case('lower'), Joi.string()),
|
|
45
49
|
strict: Joi.boolean(),
|
|
46
50
|
heal: Joi.alternatives(Joi.boolean(), Joi.string()),
|
|
47
51
|
modifiers: Joi.object().pattern(Joi.string(), Joi.alternatives(Joi.function(), Joi.link('#modifiers')))
|
|
@@ -65,6 +69,14 @@ module.exports = opts => {
|
|
|
65
69
|
return flags.some(flag => needleFlags.includes(flag));
|
|
66
70
|
};
|
|
67
71
|
|
|
72
|
+
const overwriteHeaders = (k, v) => {
|
|
73
|
+
if (k in opts.reqHeaderOverwrite) {
|
|
74
|
+
return opts.reqHeaderOverwrite[k];
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
return v;
|
|
78
|
+
};
|
|
79
|
+
|
|
68
80
|
return {
|
|
69
81
|
inject: async cassetteFile => {
|
|
70
82
|
assert(nockDone === null);
|
|
@@ -101,7 +113,7 @@ module.exports = opts => {
|
|
|
101
113
|
nockRecorder.rec({
|
|
102
114
|
output_objects: true,
|
|
103
115
|
dont_print: true,
|
|
104
|
-
enable_reqheaders_recording:
|
|
116
|
+
enable_reqheaders_recording: true
|
|
105
117
|
});
|
|
106
118
|
await new Promise(resolve => {
|
|
107
119
|
options.protocol = `${protocol}:`;
|
|
@@ -123,7 +135,8 @@ module.exports = opts => {
|
|
|
123
135
|
nockRecorder.clear();
|
|
124
136
|
return recorded.map(record => Object.assign(record, {
|
|
125
137
|
headers: opts.stripHeaders === true ? undefined : convertHeaders(record.rawHeaders),
|
|
126
|
-
rawHeaders: undefined
|
|
138
|
+
rawHeaders: undefined,
|
|
139
|
+
reqheaders: rewriteHeaders(record.reqheaders, overwriteHeaders)
|
|
127
140
|
}));
|
|
128
141
|
});
|
|
129
142
|
} else if (anyFlagPresent(['stub'])) {
|
|
@@ -133,6 +146,7 @@ module.exports = opts => {
|
|
|
133
146
|
path: options.path,
|
|
134
147
|
body: tryParseJson(body),
|
|
135
148
|
status: 200,
|
|
149
|
+
reqheaders: rewriteHeaders(options.headers, overwriteHeaders),
|
|
136
150
|
response: {},
|
|
137
151
|
responseIsBinary: false
|
|
138
152
|
});
|
|
@@ -143,6 +157,19 @@ module.exports = opts => {
|
|
|
143
157
|
records.push(cloneDeep(scope));
|
|
144
158
|
applyModifiers(scope, opts.modifiers); // eslint-disable-next-line no-param-reassign
|
|
145
159
|
|
|
160
|
+
scope.reqheaders = rewriteHeaders(scope.reqheaders, (k, valueRecording) => valueRequest => {
|
|
161
|
+
const match = nockCommon.matchStringOrRegexp(valueRequest, /^\^.*\$$/.test(valueRecording) ? new RegExp(valueRecording) : valueRecording);
|
|
162
|
+
|
|
163
|
+
if (!match && anyFlagPresent(['magic', 'headers'])) {
|
|
164
|
+
const idx = pendingMocks.findIndex(m => m.idx === scopeIdx); // overwrite existing headers
|
|
165
|
+
|
|
166
|
+
pendingMocks[idx].record.reqheaders[k] = valueRequest;
|
|
167
|
+
return true;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
return match;
|
|
171
|
+
}); // eslint-disable-next-line no-param-reassign
|
|
172
|
+
|
|
146
173
|
scope.filteringRequestBody = body => {
|
|
147
174
|
if (anyFlagPresent(['magic', 'body'])) {
|
|
148
175
|
const idx = pendingMocks.findIndex(m => m.idx === scopeIdx);
|
|
@@ -175,6 +202,14 @@ module.exports = opts => {
|
|
|
175
202
|
scope.on('request', (req, interceptor, requestBodyString) => {
|
|
176
203
|
const idx = pendingMocks.findIndex(e => e.idx === scopeIdx);
|
|
177
204
|
|
|
205
|
+
if (anyFlagPresent(['magic', 'headers'])) {
|
|
206
|
+
// add new headers
|
|
207
|
+
const reqheaders = { ...rewriteHeaders(req.headers),
|
|
208
|
+
...rewriteHeaders(pendingMocks[idx].record.reqheaders)
|
|
209
|
+
};
|
|
210
|
+
pendingMocks[idx].record.reqheaders = rewriteHeaders(reqheaders, overwriteHeaders);
|
|
211
|
+
}
|
|
212
|
+
|
|
178
213
|
if (anyFlagPresent(['magic', 'response'])) {
|
|
179
214
|
const responseBody = tryParseJson([healSqsSendMessageBatch].reduce((respBody, fn) => fn(requestBodyString, respBody, scope), interceptor.body)); // eslint-disable-next-line no-param-reassign
|
|
180
215
|
|
|
@@ -193,7 +228,8 @@ module.exports = opts => {
|
|
|
193
228
|
},
|
|
194
229
|
afterRecord: recordings => JSON.stringify(recordings.map(r => ({ ...r,
|
|
195
230
|
body: tryParseJson(r.body),
|
|
196
|
-
rawHeaders: opts.stripHeaders === true ? undefined : r.rawHeaders
|
|
231
|
+
rawHeaders: opts.stripHeaders === true ? undefined : r.rawHeaders,
|
|
232
|
+
reqheaders: rewriteHeaders(r.reqheaders, overwriteHeaders)
|
|
197
233
|
})), null, 2)
|
|
198
234
|
}, resolve));
|
|
199
235
|
requestInjector.inject();
|
|
@@ -201,10 +237,6 @@ module.exports = opts => {
|
|
|
201
237
|
release: async () => {
|
|
202
238
|
assert(nockDone !== null);
|
|
203
239
|
requestInjector.release();
|
|
204
|
-
nockDone();
|
|
205
|
-
nockDone = null;
|
|
206
|
-
nockListener.unsubscribeAll('no match');
|
|
207
|
-
nockMock.unpatch();
|
|
208
240
|
|
|
209
241
|
for (let idx = 0; idx < expectedCassette.length; idx += 1) {
|
|
210
242
|
if (typeof expectedCassette[idx] === 'function') {
|
|
@@ -214,8 +246,13 @@ module.exports = opts => {
|
|
|
214
246
|
}
|
|
215
247
|
}
|
|
216
248
|
|
|
249
|
+
nockDone();
|
|
250
|
+
nockDone = null;
|
|
251
|
+
nockListener.unsubscribeAll('no match');
|
|
252
|
+
nockMock.unpatch();
|
|
253
|
+
|
|
217
254
|
if (opts.heal !== false) {
|
|
218
|
-
fs.smartWrite(cassetteFilePath, anyFlagPresent(['
|
|
255
|
+
fs.smartWrite(cassetteFilePath, anyFlagPresent(['prune']) ? expectedCassette : [...expectedCassette, ...pendingMocks.map(({
|
|
219
256
|
record
|
|
220
257
|
}) => record)], {
|
|
221
258
|
keepOrder: outOfOrderErrors.length === 0 && pendingMocks.length === 0
|
package/lib/util/desc.js
CHANGED
|
@@ -73,6 +73,7 @@ const desc = (suiteName, optsOrTests, testsOrNull = null) => {
|
|
|
73
73
|
const nockFolder = resolve(get(opts, 'nockFolder', '$FILENAME__cassettes'));
|
|
74
74
|
const nockModifiers = get(opts, 'nockModifiers', {});
|
|
75
75
|
const nockStripHeaders = get(opts, 'nockStripHeaders', false);
|
|
76
|
+
const nockReqHeaderOverwrite = get(opts, 'nockReqHeaderOverwrite', {});
|
|
76
77
|
const fixtureFolder = resolve(get(opts, 'fixtureFolder', '$FILENAME__fixtures'));
|
|
77
78
|
const envVarsFile = resolve(get(opts, 'envVarsFile', '$FILENAME.env.yml'));
|
|
78
79
|
const envVars = get(opts, 'envVars', null);
|
|
@@ -178,6 +179,7 @@ const desc = (suiteName, optsOrTests, testsOrNull = null) => {
|
|
|
178
179
|
requestRecorder = RequestRecorder({
|
|
179
180
|
cassetteFolder: `${nockFolder}/`,
|
|
180
181
|
stripHeaders: nockStripHeaders,
|
|
182
|
+
reqHeaderOverwrite: nockReqHeaderOverwrite,
|
|
181
183
|
strict: true,
|
|
182
184
|
heal: nockHeal,
|
|
183
185
|
modifiers: nockModifiers
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "node-tdd",
|
|
3
|
-
"version": "3.0
|
|
3
|
+
"version": "3.2.0",
|
|
4
4
|
"description": "Drop in extension for mocha to abstract commonly used test setups",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -48,7 +48,7 @@
|
|
|
48
48
|
"@blackflux/robo-config-plugin": "5.3.0",
|
|
49
49
|
"aws-sdk": "2.981.0",
|
|
50
50
|
"aws-sdk-wrap": "9.6.0",
|
|
51
|
-
"axios": "0.
|
|
51
|
+
"axios": "0.24.0",
|
|
52
52
|
"babel-eslint": "10.1.0",
|
|
53
53
|
"babel-preset-latest-node": "5.5.1",
|
|
54
54
|
"chai": "4.3.4",
|