@stuntman/client 0.1.1 → 0.1.3
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 +2 -0
- package/dist/apiClient.d.ts +1 -0
- package/dist/apiClient.js +8 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +3 -1
- package/dist/ruleBuilder.d.ts +6 -4
- package/dist/ruleBuilder.js +189 -50
- package/package.json +9 -5
- package/dist/clientTestExample.d.ts +0 -1
- package/dist/clientTestExample.js +0 -22
package/README.md
CHANGED
package/dist/apiClient.d.ts
CHANGED
package/dist/apiClient.js
CHANGED
|
@@ -107,7 +107,14 @@ class Client {
|
|
|
107
107
|
controller.abort();
|
|
108
108
|
}, this.options.timeout);
|
|
109
109
|
try {
|
|
110
|
-
const response = await fetch(url, {
|
|
110
|
+
const response = await fetch(url, {
|
|
111
|
+
...init,
|
|
112
|
+
headers: {
|
|
113
|
+
...(this.options.apiKey && { 'x-api-key': this.options.apiKey }),
|
|
114
|
+
...init === null || init === void 0 ? void 0 : init.headers,
|
|
115
|
+
},
|
|
116
|
+
signal: (_a = init === null || init === void 0 ? void 0 : init.signal) !== null && _a !== void 0 ? _a : controller.signal,
|
|
117
|
+
});
|
|
111
118
|
if (!response.ok) {
|
|
112
119
|
const text = await response.text();
|
|
113
120
|
let json;
|
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.StuntmanClient = void 0;
|
|
3
|
+
exports.ruleBuilder = exports.StuntmanClient = void 0;
|
|
4
4
|
var apiClient_1 = require("./apiClient");
|
|
5
5
|
Object.defineProperty(exports, "StuntmanClient", { enumerable: true, get: function () { return apiClient_1.Client; } });
|
|
6
|
+
var ruleBuilder_1 = require("./ruleBuilder");
|
|
7
|
+
Object.defineProperty(exports, "ruleBuilder", { enumerable: true, get: function () { return ruleBuilder_1.ruleBuilder; } });
|
package/dist/ruleBuilder.d.ts
CHANGED
|
@@ -45,6 +45,7 @@ declare class RuleBuilder extends RuleBuilderBase {
|
|
|
45
45
|
onRequestTo(filter: string | RegExp): RuleBuilderInitialized;
|
|
46
46
|
onRequestToHostname(hostname: string | RegExp): RuleBuilderInitialized;
|
|
47
47
|
onRequestToPathname(pathname: string | RegExp): RuleBuilderInitialized;
|
|
48
|
+
onRequestToPort(port: string | number | RegExp): RuleBuilderInitialized;
|
|
48
49
|
onAnyRequest(): RuleBuilderInitialized;
|
|
49
50
|
}
|
|
50
51
|
declare class RuleBuilderInitialized extends RuleBuilderBase {
|
|
@@ -56,7 +57,7 @@ declare class RuleBuilderInitialized extends RuleBuilderBase {
|
|
|
56
57
|
withSearchParams(params: KeyValueMatcher[]): RuleBuilderInitialized;
|
|
57
58
|
withHeader(key: string | RegExp): RuleBuilderInitialized;
|
|
58
59
|
withHeader(key: string, value?: string | RegExp): RuleBuilderInitialized;
|
|
59
|
-
withHeaders(headers: KeyValueMatcher[]): RuleBuilderInitialized;
|
|
60
|
+
withHeaders(...headers: KeyValueMatcher[]): RuleBuilderInitialized;
|
|
60
61
|
withBodyText(includes: string): RuleBuilderInitialized;
|
|
61
62
|
withBodyText(matches: RegExp): RuleBuilderInitialized;
|
|
62
63
|
withoutBody(): RuleBuilderInitialized;
|
|
@@ -67,11 +68,12 @@ declare class RuleBuilderInitialized extends RuleBuilderBase {
|
|
|
67
68
|
proxyPass(): Stuntman.SerializableRule;
|
|
68
69
|
mockResponse(staticResponse: Stuntman.Response): Stuntman.SerializableRule;
|
|
69
70
|
mockResponse(generationFunction: Stuntman.RemotableFunction<Stuntman.ResponseGenerationFn>): Stuntman.SerializableRule;
|
|
70
|
-
|
|
71
|
-
|
|
71
|
+
mockResponse(localFn: Stuntman.ResponseGenerationFn, localVariables?: Stuntman.LocalVariables): Stuntman.SerializableRule;
|
|
72
|
+
modifyRequest(modifyFunction: Stuntman.RequestManipulationFn | Stuntman.RemotableFunction<Stuntman.RequestManipulationFn>, localVariables?: Stuntman.LocalVariables): RuleBuilderRequestInitialized;
|
|
73
|
+
modifyResponse(modifyFunction: Stuntman.ResponseManipulationFn | Stuntman.RemotableFunction<Stuntman.ResponseManipulationFn>, localVariables?: Stuntman.LocalVariables): Stuntman.SerializableRule;
|
|
72
74
|
}
|
|
73
75
|
declare class RuleBuilderRequestInitialized extends RuleBuilderBase {
|
|
74
|
-
modifyResponse(modifyFunction: Stuntman.RemotableFunction<Stuntman.ResponseManipulationFn
|
|
76
|
+
modifyResponse(modifyFunction: Stuntman.ResponseManipulationFn | Stuntman.RemotableFunction<Stuntman.ResponseManipulationFn>, localVariables?: Stuntman.LocalVariables): Stuntman.SerializableRule;
|
|
75
77
|
}
|
|
76
78
|
export declare const ruleBuilder: () => RuleBuilder;
|
|
77
79
|
export {};
|
package/dist/ruleBuilder.js
CHANGED
|
@@ -13,43 +13,54 @@ class RuleBuilderBaseBase {
|
|
|
13
13
|
priority: shared_1.DEFAULT_RULE_PRIORITY,
|
|
14
14
|
matches: {
|
|
15
15
|
localFn: (req) => {
|
|
16
|
+
var _a, _b, _c, _d;
|
|
16
17
|
const ___url = new URL(req.url);
|
|
17
18
|
const ___headers = req.rawHeaders;
|
|
18
19
|
const arrayIndexerRegex = /\[(?<arrayIndex>[0-9]*)\]/i;
|
|
19
|
-
const matchObject = (obj, path, value) => {
|
|
20
|
-
var _a, _b;
|
|
20
|
+
const matchObject = (obj, path, value, parentPath) => {
|
|
21
|
+
var _a, _b, _c, _d;
|
|
21
22
|
if (!obj) {
|
|
22
|
-
return false;
|
|
23
|
+
return { result: false, description: `${parentPath} is falsey` };
|
|
23
24
|
}
|
|
24
25
|
const [rawKey, ...rest] = path.split('.');
|
|
25
26
|
const key = rawKey.replace(arrayIndexerRegex, '');
|
|
26
27
|
const shouldBeArray = arrayIndexerRegex.test(rawKey);
|
|
27
|
-
const arrayIndex =
|
|
28
|
+
const arrayIndex = (((_b = (_a = arrayIndexerRegex.exec(rawKey)) === null || _a === void 0 ? void 0 : _a.groups) === null || _b === void 0 ? void 0 : _b.arrayIndex) || '').length > 0
|
|
29
|
+
? Number((_d = (_c = arrayIndexerRegex.exec(rawKey)) === null || _c === void 0 ? void 0 : _c.groups) === null || _d === void 0 ? void 0 : _d.arrayIndex)
|
|
30
|
+
: Number.NaN;
|
|
28
31
|
const actualValue = key ? obj[key] : obj;
|
|
32
|
+
const currentPath = `${parentPath ? `${parentPath}.` : ''}${rawKey}`;
|
|
29
33
|
if (value === undefined && actualValue === undefined) {
|
|
30
|
-
return false;
|
|
34
|
+
return { result: false, description: `${currentPath}=undefined` };
|
|
31
35
|
}
|
|
32
36
|
if (rest.length === 0) {
|
|
33
37
|
if (shouldBeArray &&
|
|
34
38
|
(!Array.isArray(actualValue) ||
|
|
35
|
-
|
|
36
|
-
return false;
|
|
39
|
+
(Number.isInteger(arrayIndex) && actualValue.length <= Number(arrayIndex)))) {
|
|
40
|
+
return { result: false, description: `${currentPath} empty array` };
|
|
37
41
|
}
|
|
38
42
|
if (value === undefined) {
|
|
39
|
-
|
|
43
|
+
const result = shouldBeArray
|
|
40
44
|
? !Number.isInteger(arrayIndex) || actualValue.length >= Number(arrayIndex)
|
|
41
45
|
: actualValue !== undefined;
|
|
46
|
+
return { result, description: `${currentPath}` };
|
|
42
47
|
}
|
|
43
48
|
if (!shouldBeArray) {
|
|
44
|
-
|
|
49
|
+
const result = value instanceof RegExp ? value.test(actualValue) : value === actualValue;
|
|
50
|
+
return { result, description: `${currentPath}` };
|
|
45
51
|
}
|
|
46
52
|
}
|
|
47
53
|
if (shouldBeArray) {
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
54
|
+
if (Number.isInteger(arrayIndex)) {
|
|
55
|
+
return matchObject(actualValue[Number(arrayIndex)], rest.join('.'), value, currentPath);
|
|
56
|
+
}
|
|
57
|
+
const hasArrayMatch = actualValue.some((arrayValue) => matchObject(arrayValue, rest.join('.'), value, currentPath).result);
|
|
58
|
+
return { result: hasArrayMatch, description: `array match ${currentPath}` };
|
|
51
59
|
}
|
|
52
|
-
|
|
60
|
+
if (typeof actualValue !== 'object') {
|
|
61
|
+
return { result: false, description: `${currentPath} not an object` };
|
|
62
|
+
}
|
|
63
|
+
return matchObject(actualValue, rest.join('.'), value, currentPath);
|
|
53
64
|
};
|
|
54
65
|
const ___matchesValue = (matcher, value) => {
|
|
55
66
|
if (matcher === undefined) {
|
|
@@ -70,32 +81,60 @@ class RuleBuilderBaseBase {
|
|
|
70
81
|
return true;
|
|
71
82
|
};
|
|
72
83
|
if (!___matchesValue(matchBuilderVariables.filter, req.url)) {
|
|
73
|
-
return
|
|
84
|
+
return {
|
|
85
|
+
result: false,
|
|
86
|
+
description: `url ${req.url} doesn't match ${(_a = matchBuilderVariables.filter) === null || _a === void 0 ? void 0 : _a.toString()}`,
|
|
87
|
+
};
|
|
74
88
|
}
|
|
75
89
|
if (!___matchesValue(matchBuilderVariables.hostname, ___url.hostname)) {
|
|
76
|
-
return
|
|
90
|
+
return {
|
|
91
|
+
result: false,
|
|
92
|
+
description: `hostname ${___url.hostname} doesn't match ${(_b = matchBuilderVariables.hostname) === null || _b === void 0 ? void 0 : _b.toString()}`,
|
|
93
|
+
};
|
|
77
94
|
}
|
|
78
95
|
if (!___matchesValue(matchBuilderVariables.pathname, ___url.pathname)) {
|
|
79
|
-
return
|
|
96
|
+
return {
|
|
97
|
+
result: false,
|
|
98
|
+
description: `pathname ${___url.pathname} doesn't match ${(_c = matchBuilderVariables.pathname) === null || _c === void 0 ? void 0 : _c.toString()}`,
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
if (matchBuilderVariables.port) {
|
|
102
|
+
const port = ___url.port && ___url.port !== '' ? ___url.port : ___url.protocol === 'https:' ? '443' : '80';
|
|
103
|
+
if (!___matchesValue(matchBuilderVariables.port instanceof RegExp
|
|
104
|
+
? matchBuilderVariables.port
|
|
105
|
+
: `${matchBuilderVariables.port}`, port)) {
|
|
106
|
+
return {
|
|
107
|
+
result: false,
|
|
108
|
+
description: `port ${port} doesn't match ${(_d = matchBuilderVariables.port) === null || _d === void 0 ? void 0 : _d.toString()}`,
|
|
109
|
+
};
|
|
110
|
+
}
|
|
80
111
|
}
|
|
81
112
|
if (matchBuilderVariables.searchParams) {
|
|
82
113
|
for (const searchParamMatcher of matchBuilderVariables.searchParams) {
|
|
83
114
|
if (typeof searchParamMatcher === 'string') {
|
|
84
|
-
|
|
115
|
+
const result = ___url.searchParams.has(searchParamMatcher);
|
|
116
|
+
return { result, description: `searchParams.has("${searchParamMatcher}")` };
|
|
85
117
|
}
|
|
86
118
|
if (searchParamMatcher instanceof RegExp) {
|
|
87
|
-
|
|
119
|
+
const result = Array.from(___url.searchParams.keys()).some((key) => searchParamMatcher.test(key));
|
|
120
|
+
return { result, description: `searchParams.keys() matches ${searchParamMatcher.toString()}` };
|
|
88
121
|
}
|
|
89
122
|
if (!___url.searchParams.has(searchParamMatcher.key)) {
|
|
90
|
-
return false;
|
|
123
|
+
return { result: false, description: `searchParams.has("${searchParamMatcher.key}")` };
|
|
91
124
|
}
|
|
92
125
|
if (searchParamMatcher.value) {
|
|
93
126
|
const value = ___url.searchParams.get(searchParamMatcher.key);
|
|
94
127
|
if (value === null) {
|
|
95
|
-
return
|
|
128
|
+
return {
|
|
129
|
+
result: false,
|
|
130
|
+
description: `searchParams.get("${searchParamMatcher.key}") === null`,
|
|
131
|
+
};
|
|
96
132
|
}
|
|
97
133
|
if (!___matchesValue(searchParamMatcher.value, value)) {
|
|
98
|
-
return
|
|
134
|
+
return {
|
|
135
|
+
result: false,
|
|
136
|
+
description: `searchParams.get("${searchParamMatcher.key}") = "${searchParamMatcher.value}"`,
|
|
137
|
+
};
|
|
99
138
|
}
|
|
100
139
|
}
|
|
101
140
|
}
|
|
@@ -103,31 +142,56 @@ class RuleBuilderBaseBase {
|
|
|
103
142
|
if (matchBuilderVariables.headers) {
|
|
104
143
|
for (const headerMatcher of matchBuilderVariables.headers) {
|
|
105
144
|
if (typeof headerMatcher === 'string') {
|
|
106
|
-
|
|
145
|
+
const result = ___headers.has(headerMatcher);
|
|
146
|
+
if (result) {
|
|
147
|
+
continue;
|
|
148
|
+
}
|
|
149
|
+
return { result: false, description: `headers.has("${headerMatcher}")` };
|
|
107
150
|
}
|
|
108
151
|
if (headerMatcher instanceof RegExp) {
|
|
109
|
-
|
|
152
|
+
const result = ___headers.toHeaderPairs().some(([key]) => headerMatcher.test(key));
|
|
153
|
+
if (result) {
|
|
154
|
+
continue;
|
|
155
|
+
}
|
|
156
|
+
return { result: false, description: `headers.keys matches ${headerMatcher.toString()}` };
|
|
110
157
|
}
|
|
111
158
|
if (!___headers.has(headerMatcher.key)) {
|
|
112
|
-
return false;
|
|
159
|
+
return { result: false, description: `headers.has("${headerMatcher.key}")` };
|
|
113
160
|
}
|
|
114
161
|
if (headerMatcher.value) {
|
|
115
162
|
const value = ___headers.get(headerMatcher.key);
|
|
116
163
|
if (value === null) {
|
|
117
|
-
return false;
|
|
164
|
+
return { result: false, description: `headers.get("${headerMatcher.key}") === null` };
|
|
118
165
|
}
|
|
119
166
|
if (!___matchesValue(headerMatcher.value, value)) {
|
|
120
|
-
return
|
|
167
|
+
return {
|
|
168
|
+
result: false,
|
|
169
|
+
description: `headerMatcher.get("${headerMatcher.key}") = "${headerMatcher.value}"`,
|
|
170
|
+
};
|
|
121
171
|
}
|
|
122
172
|
}
|
|
123
173
|
}
|
|
124
174
|
}
|
|
125
175
|
if (matchBuilderVariables.bodyText === null && !!req.body) {
|
|
126
|
-
return false;
|
|
176
|
+
return { result: false, description: `empty body` };
|
|
127
177
|
}
|
|
128
178
|
if (matchBuilderVariables.bodyText) {
|
|
129
|
-
if (!
|
|
130
|
-
return false;
|
|
179
|
+
if (!req.body) {
|
|
180
|
+
return { result: false, description: `empty body` };
|
|
181
|
+
}
|
|
182
|
+
if (matchBuilderVariables.bodyText instanceof RegExp) {
|
|
183
|
+
if (!___matchesValue(matchBuilderVariables.bodyText, req.body)) {
|
|
184
|
+
return {
|
|
185
|
+
result: false,
|
|
186
|
+
description: `body text doesn't match ${matchBuilderVariables.bodyText.toString()}`,
|
|
187
|
+
};
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
else if (!req.body.includes(matchBuilderVariables.bodyText)) {
|
|
191
|
+
return {
|
|
192
|
+
result: false,
|
|
193
|
+
description: `body text doesn't include "${matchBuilderVariables.bodyText}"`,
|
|
194
|
+
};
|
|
131
195
|
}
|
|
132
196
|
}
|
|
133
197
|
if (matchBuilderVariables.bodyJson) {
|
|
@@ -136,47 +200,64 @@ class RuleBuilderBaseBase {
|
|
|
136
200
|
json = JSON.parse(req.body);
|
|
137
201
|
}
|
|
138
202
|
catch (kiss) {
|
|
139
|
-
return false;
|
|
203
|
+
return { result: false, description: `unparseable json` };
|
|
140
204
|
}
|
|
141
205
|
if (!json) {
|
|
142
|
-
return false;
|
|
206
|
+
return { result: false, description: `empty json object` };
|
|
143
207
|
}
|
|
144
208
|
for (const jsonMatcher of Array.isArray(matchBuilderVariables.bodyJson)
|
|
145
209
|
? matchBuilderVariables.bodyJson
|
|
146
210
|
: [matchBuilderVariables.bodyJson]) {
|
|
147
|
-
|
|
148
|
-
|
|
211
|
+
const matchObjectResult = matchObject(json, jsonMatcher.key, jsonMatcher.value);
|
|
212
|
+
if (!matchObjectResult.result) {
|
|
213
|
+
return { result: false, description: `$.${jsonMatcher.key} != "${jsonMatcher.value}"` };
|
|
149
214
|
}
|
|
150
215
|
}
|
|
151
216
|
}
|
|
152
217
|
if (matchBuilderVariables.bodyGql) {
|
|
153
218
|
if (!req.gqlBody) {
|
|
154
|
-
return false;
|
|
219
|
+
return { result: false, description: `not a gql body` };
|
|
155
220
|
}
|
|
156
221
|
if (!___matchesValue(matchBuilderVariables.bodyGql.methodName, req.gqlBody.methodName)) {
|
|
157
|
-
return
|
|
222
|
+
return {
|
|
223
|
+
result: false,
|
|
224
|
+
description: `methodName "${matchBuilderVariables.bodyGql.methodName}" !== "${req.gqlBody.methodName}"`,
|
|
225
|
+
};
|
|
158
226
|
}
|
|
159
227
|
if (!___matchesValue(matchBuilderVariables.bodyGql.operationName, req.gqlBody.operationName)) {
|
|
160
|
-
return
|
|
228
|
+
return {
|
|
229
|
+
result: false,
|
|
230
|
+
description: `operationName "${matchBuilderVariables.bodyGql.operationName}" !== "${req.gqlBody.operationName}"`,
|
|
231
|
+
};
|
|
161
232
|
}
|
|
162
233
|
if (!___matchesValue(matchBuilderVariables.bodyGql.query, req.gqlBody.query)) {
|
|
163
|
-
return
|
|
234
|
+
return {
|
|
235
|
+
result: false,
|
|
236
|
+
description: `query "${matchBuilderVariables.bodyGql.query}" !== "${req.gqlBody.query}"`,
|
|
237
|
+
};
|
|
164
238
|
}
|
|
165
239
|
if (!___matchesValue(matchBuilderVariables.bodyGql.type, req.gqlBody.type)) {
|
|
166
|
-
return
|
|
240
|
+
return {
|
|
241
|
+
result: false,
|
|
242
|
+
description: `type "${matchBuilderVariables.bodyGql.type}" !== "${req.gqlBody.type}"`,
|
|
243
|
+
};
|
|
167
244
|
}
|
|
168
245
|
if (!matchBuilderVariables.bodyGql.variables) {
|
|
169
|
-
return true;
|
|
246
|
+
return { result: true, description: `no variables to match` };
|
|
170
247
|
}
|
|
171
248
|
for (const jsonMatcher of Array.isArray(matchBuilderVariables.bodyGql.variables)
|
|
172
249
|
? matchBuilderVariables.bodyGql.variables
|
|
173
250
|
: [matchBuilderVariables.bodyGql.variables]) {
|
|
174
|
-
|
|
175
|
-
|
|
251
|
+
const matchObjectResult = matchObject(req.gqlBody.variables, jsonMatcher.key, jsonMatcher.value);
|
|
252
|
+
if (!matchObjectResult.result) {
|
|
253
|
+
return {
|
|
254
|
+
result: false,
|
|
255
|
+
description: `GQL variable ${jsonMatcher.key} != "${jsonMatcher.value}". Detail: ${matchObjectResult.description}`,
|
|
256
|
+
};
|
|
176
257
|
}
|
|
177
258
|
}
|
|
178
259
|
}
|
|
179
|
-
return true;
|
|
260
|
+
return { result: true, description: 'match' };
|
|
180
261
|
},
|
|
181
262
|
localVariables: { matchBuilderVariables: this._matchBuilderVariables },
|
|
182
263
|
},
|
|
@@ -185,6 +266,9 @@ class RuleBuilderBaseBase {
|
|
|
185
266
|
}
|
|
186
267
|
class RuleBuilderBase extends RuleBuilderBaseBase {
|
|
187
268
|
limitedUse(hitCount) {
|
|
269
|
+
if (this.rule.removeAfterUse) {
|
|
270
|
+
throw new Error(`limit already set at ${this.rule.removeAfterUse}`);
|
|
271
|
+
}
|
|
188
272
|
if (Number.isNaN(hitCount) || !Number.isFinite(hitCount) || !Number.isInteger(hitCount) || hitCount <= 0) {
|
|
189
273
|
throw new Error('Invalid hitCount');
|
|
190
274
|
}
|
|
@@ -204,6 +288,9 @@ class RuleBuilderBase extends RuleBuilderBaseBase {
|
|
|
204
288
|
}
|
|
205
289
|
class RuleBuilder extends RuleBuilderBase {
|
|
206
290
|
raisePriority(by) {
|
|
291
|
+
if (this.rule.priority !== shared_1.DEFAULT_RULE_PRIORITY) {
|
|
292
|
+
throw new Error('you should not alter rule priority more than once');
|
|
293
|
+
}
|
|
207
294
|
const subtract = by !== null && by !== void 0 ? by : 1;
|
|
208
295
|
if (subtract >= shared_1.DEFAULT_RULE_PRIORITY) {
|
|
209
296
|
throw new Error(`Unable to raise priority over the default ${shared_1.DEFAULT_RULE_PRIORITY}`);
|
|
@@ -212,6 +299,9 @@ class RuleBuilder extends RuleBuilderBase {
|
|
|
212
299
|
return this;
|
|
213
300
|
}
|
|
214
301
|
decreasePriority(by) {
|
|
302
|
+
if (this.rule.priority !== shared_1.DEFAULT_RULE_PRIORITY) {
|
|
303
|
+
throw new Error('you should not alter rule priority more than once');
|
|
304
|
+
}
|
|
215
305
|
const add = by !== null && by !== void 0 ? by : 1;
|
|
216
306
|
this.rule.priority = shared_1.DEFAULT_RULE_PRIORITY + add;
|
|
217
307
|
return this;
|
|
@@ -242,21 +332,33 @@ class RuleBuilder extends RuleBuilderBase {
|
|
|
242
332
|
this._matchBuilderVariables.pathname = pathname;
|
|
243
333
|
return new RuleBuilderInitialized(this.rule, this._matchBuilderVariables);
|
|
244
334
|
}
|
|
335
|
+
onRequestToPort(port) {
|
|
336
|
+
this._matchBuilderVariables.port = port;
|
|
337
|
+
return new RuleBuilderInitialized(this.rule, this._matchBuilderVariables);
|
|
338
|
+
}
|
|
245
339
|
onAnyRequest() {
|
|
246
|
-
this.rule.matches = { localFn: () => true };
|
|
247
340
|
return new RuleBuilderInitialized(this.rule, this._matchBuilderVariables);
|
|
248
341
|
}
|
|
249
342
|
}
|
|
250
343
|
class RuleBuilderInitialized extends RuleBuilderBase {
|
|
251
344
|
withHostname(hostname) {
|
|
345
|
+
if (this._matchBuilderVariables.hostname) {
|
|
346
|
+
throw new Error('hostname already set');
|
|
347
|
+
}
|
|
252
348
|
this._matchBuilderVariables.hostname = hostname;
|
|
253
349
|
return this;
|
|
254
350
|
}
|
|
255
351
|
withPathname(pathname) {
|
|
352
|
+
if (this._matchBuilderVariables.pathname) {
|
|
353
|
+
throw new Error('pathname already set');
|
|
354
|
+
}
|
|
256
355
|
this._matchBuilderVariables.pathname = pathname;
|
|
257
356
|
return this;
|
|
258
357
|
}
|
|
259
358
|
withPort(port) {
|
|
359
|
+
if (this._matchBuilderVariables.port) {
|
|
360
|
+
throw new Error('port already set');
|
|
361
|
+
}
|
|
260
362
|
this._matchBuilderVariables.port = port;
|
|
261
363
|
return this;
|
|
262
364
|
}
|
|
@@ -308,7 +410,7 @@ class RuleBuilderInitialized extends RuleBuilderBase {
|
|
|
308
410
|
this._matchBuilderVariables.headers.push({ key, value });
|
|
309
411
|
return this;
|
|
310
412
|
}
|
|
311
|
-
withHeaders(headers) {
|
|
413
|
+
withHeaders(...headers) {
|
|
312
414
|
if (!this._matchBuilderVariables.headers) {
|
|
313
415
|
this._matchBuilderVariables.headers = [];
|
|
314
416
|
}
|
|
@@ -323,10 +425,19 @@ class RuleBuilderInitialized extends RuleBuilderBase {
|
|
|
323
425
|
return this;
|
|
324
426
|
}
|
|
325
427
|
withBodyText(includesOrMatches) {
|
|
428
|
+
if (this._matchBuilderVariables.bodyText) {
|
|
429
|
+
throw new Error('bodyText already set');
|
|
430
|
+
}
|
|
431
|
+
if (this._matchBuilderVariables.bodyText === null) {
|
|
432
|
+
throw new Error('cannot use both withBodyText and withoutBody');
|
|
433
|
+
}
|
|
326
434
|
this._matchBuilderVariables.bodyText = includesOrMatches;
|
|
327
435
|
return this;
|
|
328
436
|
}
|
|
329
437
|
withoutBody() {
|
|
438
|
+
if (this._matchBuilderVariables.bodyText) {
|
|
439
|
+
throw new Error('cannot use both withBodyText and withoutBody');
|
|
440
|
+
}
|
|
330
441
|
this._matchBuilderVariables.bodyText = null;
|
|
331
442
|
return this;
|
|
332
443
|
}
|
|
@@ -337,7 +448,7 @@ class RuleBuilderInitialized extends RuleBuilderBase {
|
|
|
337
448
|
}
|
|
338
449
|
if (typeof keyOrMatcher === 'string') {
|
|
339
450
|
if (!keyRegex.test(keyOrMatcher)) {
|
|
340
|
-
throw new Error(
|
|
451
|
+
throw new Error(`invalid key "${keyOrMatcher}"`);
|
|
341
452
|
}
|
|
342
453
|
this._matchBuilderVariables.bodyJson.push({ key: keyOrMatcher, value: withValue });
|
|
343
454
|
return this;
|
|
@@ -346,7 +457,7 @@ class RuleBuilderInitialized extends RuleBuilderBase {
|
|
|
346
457
|
throw new Error('invalid usage');
|
|
347
458
|
}
|
|
348
459
|
if (!keyRegex.test(keyOrMatcher.key)) {
|
|
349
|
-
throw new Error(
|
|
460
|
+
throw new Error(`invalid key "${keyOrMatcher}"`);
|
|
350
461
|
}
|
|
351
462
|
this._matchBuilderVariables.bodyJson.push(keyOrMatcher);
|
|
352
463
|
return this;
|
|
@@ -358,24 +469,52 @@ class RuleBuilderInitialized extends RuleBuilderBase {
|
|
|
358
469
|
proxyPass() {
|
|
359
470
|
return this.rule;
|
|
360
471
|
}
|
|
361
|
-
mockResponse(response) {
|
|
472
|
+
mockResponse(response, localVariables) {
|
|
473
|
+
if (typeof response === 'function') {
|
|
474
|
+
this.rule.actions = { mockResponse: { localFn: response, localVariables: localVariables !== null && localVariables !== void 0 ? localVariables : {} } };
|
|
475
|
+
return this.rule;
|
|
476
|
+
}
|
|
477
|
+
if (localVariables) {
|
|
478
|
+
throw new Error('invalid call - localVariables cannot be used together with Response or RemotableFunction');
|
|
479
|
+
}
|
|
362
480
|
this.rule.actions = { mockResponse: response };
|
|
363
481
|
return this.rule;
|
|
364
482
|
}
|
|
365
|
-
modifyRequest(modifyFunction) {
|
|
483
|
+
modifyRequest(modifyFunction, localVariables) {
|
|
484
|
+
if (typeof modifyFunction === 'function') {
|
|
485
|
+
this.rule.actions = { modifyRequest: { localFn: modifyFunction, localVariables: localVariables !== null && localVariables !== void 0 ? localVariables : {} } };
|
|
486
|
+
return new RuleBuilderRequestInitialized(this.rule, this._matchBuilderVariables);
|
|
487
|
+
}
|
|
488
|
+
if (localVariables) {
|
|
489
|
+
throw new Error('invalid call - localVariables cannot be used together with Response or RemotableFunction');
|
|
490
|
+
}
|
|
366
491
|
this.rule.actions = { modifyRequest: modifyFunction };
|
|
367
492
|
return new RuleBuilderRequestInitialized(this.rule, this._matchBuilderVariables);
|
|
368
493
|
}
|
|
369
|
-
modifyResponse(modifyFunction) {
|
|
494
|
+
modifyResponse(modifyFunction, localVariables) {
|
|
495
|
+
if (typeof modifyFunction === 'function') {
|
|
496
|
+
this.rule.actions = { modifyResponse: { localFn: modifyFunction, localVariables: localVariables !== null && localVariables !== void 0 ? localVariables : {} } };
|
|
497
|
+
return this.rule;
|
|
498
|
+
}
|
|
499
|
+
if (localVariables) {
|
|
500
|
+
throw new Error('invalid call - localVariables cannot be used together with Response or RemotableFunction');
|
|
501
|
+
}
|
|
370
502
|
this.rule.actions = { modifyResponse: modifyFunction };
|
|
371
503
|
return this.rule;
|
|
372
504
|
}
|
|
373
505
|
}
|
|
374
506
|
class RuleBuilderRequestInitialized extends RuleBuilderBase {
|
|
375
|
-
modifyResponse(modifyFunction) {
|
|
507
|
+
modifyResponse(modifyFunction, localVariables) {
|
|
376
508
|
if (!this.rule.actions) {
|
|
377
509
|
throw new Error('rule.actions not defined - builder implementation error');
|
|
378
510
|
}
|
|
511
|
+
if (typeof modifyFunction === 'function') {
|
|
512
|
+
this.rule.actions = { modifyResponse: { localFn: modifyFunction, localVariables: localVariables !== null && localVariables !== void 0 ? localVariables : {} } };
|
|
513
|
+
return this.rule;
|
|
514
|
+
}
|
|
515
|
+
if (localVariables) {
|
|
516
|
+
throw new Error('invalid call - localVariables cannot be used together with Response or RemotableFunction');
|
|
517
|
+
}
|
|
379
518
|
this.rule.actions.modifyResponse = modifyFunction;
|
|
380
519
|
return this.rule;
|
|
381
520
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stuntman/client",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.3",
|
|
4
4
|
"description": "Stuntman - HTTP proxy / mock API client",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"repository": {
|
|
@@ -32,13 +32,17 @@
|
|
|
32
32
|
"author": "Andrzej Pasterczyk",
|
|
33
33
|
"license": "MIT",
|
|
34
34
|
"dependencies": {
|
|
35
|
-
"@stuntman/shared": "^0.1.
|
|
35
|
+
"@stuntman/shared": "^0.1.2",
|
|
36
36
|
"serialize-javascript": "6.0.1",
|
|
37
37
|
"uuid": "9.0.0"
|
|
38
38
|
},
|
|
39
39
|
"devDependencies": {
|
|
40
|
+
"@jest/globals": "29.4.3",
|
|
40
41
|
"@types/serialize-javascript": "5.0.2",
|
|
41
|
-
"@types/uuid": "9.0.0"
|
|
42
|
+
"@types/uuid": "9.0.0",
|
|
43
|
+
"jest": "29.4.3",
|
|
44
|
+
"ts-jest": "29.0.5",
|
|
45
|
+
"typescript": "4.9.5"
|
|
42
46
|
},
|
|
43
47
|
"files": [
|
|
44
48
|
"dist/",
|
|
@@ -47,10 +51,10 @@
|
|
|
47
51
|
"CHANGELOG.md"
|
|
48
52
|
],
|
|
49
53
|
"scripts": {
|
|
50
|
-
"test": "
|
|
54
|
+
"test": "SUPPRESS_NO_CONFIG_WARNING=1 jest",
|
|
51
55
|
"clean": "rm -fr dist",
|
|
52
56
|
"build": "tsc",
|
|
53
57
|
"lint": "prettier --check . && eslint . --ext ts",
|
|
54
|
-
"lint:fix": "prettier --write ./src && eslint ./src --ext ts --fix"
|
|
58
|
+
"lint:fix": "prettier --write ./{src,test} && eslint ./{src,test} --ext ts --fix"
|
|
55
59
|
}
|
|
56
60
|
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
const apiClient_1 = require("./apiClient");
|
|
4
|
-
const ruleBuilder_1 = require("./ruleBuilder");
|
|
5
|
-
const client = new apiClient_1.Client();
|
|
6
|
-
const uniqueQaUserEmail = 'unique_qa_email@example.com';
|
|
7
|
-
const rule = (0, ruleBuilder_1.ruleBuilder)()
|
|
8
|
-
.limitedUse(2)
|
|
9
|
-
.onAnyRequest()
|
|
10
|
-
.withBodyJson('test', 'value')
|
|
11
|
-
.mockResponse({
|
|
12
|
-
localFn: (req) => {
|
|
13
|
-
if (JSON.parse(req.body).email !== uniqueQaUserEmail) {
|
|
14
|
-
return {
|
|
15
|
-
status: 500,
|
|
16
|
-
};
|
|
17
|
-
}
|
|
18
|
-
return { status: 201 };
|
|
19
|
-
},
|
|
20
|
-
localVariables: { uniqueQaUserEmail },
|
|
21
|
-
});
|
|
22
|
-
client.addRule(rule).then((x) => console.log(x));
|