@loadmill/core 0.3.50 → 0.3.53
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/dist/conf/extrema.d.ts +1 -1
- package/dist/conf/extrema.js +2 -2
- package/dist/conf/extrema.js.map +1 -1
- package/dist/conf/types.d.ts +12 -0
- package/dist/conf/validate.d.ts +2 -1
- package/dist/conf/validate.js +6 -1
- package/dist/conf/validate.js.map +1 -1
- package/dist/multipart-form-data/form-data-utils.js +2 -2
- package/dist/multipart-form-data/form-data-utils.js.map +1 -1
- package/dist/multipart-form-data/is-binary-file.d.ts +2 -0
- package/dist/multipart-form-data/is-binary-file.js +215 -0
- package/dist/multipart-form-data/is-binary-file.js.map +1 -0
- package/dist/multipart-form-data/multipart-text-to-post-form-data.d.ts +5 -1
- package/dist/multipart-form-data/multipart-text-to-post-form-data.js +96 -35
- package/dist/multipart-form-data/multipart-text-to-post-form-data.js.map +1 -1
- package/dist/parameters/extractions.d.ts +2 -1
- package/dist/parameters/extractions.js.map +1 -1
- package/dist/parameters/index.d.ts +1 -1
- package/dist/parameters/index.js +4 -0
- package/dist/parameters/index.js.map +1 -1
- package/dist/request/index.d.ts +1 -0
- package/dist/request/index.js.map +1 -1
- package/package.json +7 -2
- package/src/conf/defaults.ts +0 -25
- package/src/conf/extrema.ts +0 -35
- package/src/conf/index.ts +0 -95
- package/src/conf/notifications.ts +0 -17
- package/src/conf/types.ts +0 -86
- package/src/conf/validate.ts +0 -548
- package/src/distributed-logger-reporter.ts +0 -19
- package/src/echo/firehose.ts +0 -64
- package/src/echo/index.ts +0 -4
- package/src/echo/stats.ts +0 -84
- package/src/har/index.ts +0 -81
- package/src/multipart-form-data/form-data-utils.ts +0 -81
- package/src/multipart-form-data/multipart-text-to-post-form-data.ts +0 -89
- package/src/parameters/extractions.ts +0 -51
- package/src/parameters/extractors/cheerio-extractor.ts +0 -57
- package/src/parameters/extractors/expression-extractor.ts +0 -13
- package/src/parameters/extractors/extractor.ts +0 -3
- package/src/parameters/extractors/header-extractor.ts +0 -24
- package/src/parameters/extractors/index.ts +0 -10
- package/src/parameters/extractors/json-path-extractor.ts +0 -63
- package/src/parameters/extractors/parametrized-extractor.ts +0 -27
- package/src/parameters/extractors/regex-extractor.ts +0 -18
- package/src/parameters/extractors/regex-matcher.ts +0 -17
- package/src/parameters/extractors/ws-extractor.ts +0 -91
- package/src/parameters/generate-random.ts +0 -114
- package/src/parameters/index.ts +0 -621
- package/src/parameters/json-path-utils.ts +0 -20
- package/src/parameters/operators/binary-operator.ts +0 -23
- package/src/parameters/operators/index.ts +0 -39
- package/src/parameters/parameter-functions/boolean-parameter-functions.ts +0 -24
- package/src/parameters/parameter-functions/crypto.ts +0 -55
- package/src/parameters/parameter-functions/json-schema.ts +0 -29
- package/src/parameters/parameter-functions/numeric-input-parameter-functions.ts +0 -22
- package/src/parameters/parameter-functions/numeric-parameter-functions.ts +0 -37
- package/src/parameters/parameter-functions/parameter-function-utils.ts +0 -55
- package/src/parameters/parameter-functions/parameter-function.ts +0 -7
- package/src/parameters/parameter-functions/parameter-functions.ts +0 -54
- package/src/parameters/parameter-functions/random-parameter-functions.ts +0 -22
- package/src/parameters/parameter-functions/textual-parameter-functions.ts +0 -464
- package/src/parameters/parameter-regex-providers.ts +0 -78
- package/src/parameters/resolvers/random-parameters-resolver.ts +0 -8
- package/src/parameters/type.ts +0 -7
- package/src/parameters/value-utils.ts +0 -47
- package/src/request/index.ts +0 -525
- package/src/schema/json-schema-generator.ts +0 -76
- package/test/conf/validate.spec.js +0 -141
- package/test/har/is-har.spec.js +0 -33
- package/test/multipart-form-data/form-data-utils.spec.ts +0 -121
- package/test/multipart-form-data/resources/multipart-form-data-file-text-content.json +0 -5
- package/test/parameters/builtin-functions.spec.js +0 -85
- package/test/parameters/json-path-utils.spec.ts +0 -50
- package/test/parameters/parameter-functions.spec.js +0 -48
- package/test/parameters/parameter-utils.spec.js +0 -185
- package/test/parameters/regex-functions.spec.ts +0 -57
- package/test/parameters/value-utils.spec.js +0 -73
- package/test/schema/json-schema-generator.spec.js +0 -227
- package/tsconfig.json +0 -9
package/src/parameters/index.ts
DELETED
|
@@ -1,621 +0,0 @@
|
|
|
1
|
-
import isEmpty = require('lodash/isEmpty');
|
|
2
|
-
import isEqual = require('lodash/isEqual');
|
|
3
|
-
import uniqWith = require('lodash/uniqWith');
|
|
4
|
-
import { Parameters, ParametersScope, SequenceExecutorParameters } from './type';
|
|
5
|
-
import { pickRandom } from './value-utils';
|
|
6
|
-
import * as valueUtils from './value-utils';
|
|
7
|
-
import { operators, operatorsAsStrings } from './operators';
|
|
8
|
-
import { resolveRandomParameter } from './resolvers/random-parameters-resolver';
|
|
9
|
-
import {
|
|
10
|
-
canHaveNullParameterValue,
|
|
11
|
-
getParameterFunction,
|
|
12
|
-
parameterFunctionOperations,
|
|
13
|
-
} from './parameter-functions/parameter-functions';
|
|
14
|
-
import {
|
|
15
|
-
globalUsageRegExpProvider,
|
|
16
|
-
spacesRegExpProvider,
|
|
17
|
-
getParameterUsageRegexp,
|
|
18
|
-
getParameterfunctionGroupingRegexp,
|
|
19
|
-
getParameterOperatorsGroupingRegexp,
|
|
20
|
-
usageRegExpProvider,
|
|
21
|
-
PARAMETER_USAGE_PATTERN,
|
|
22
|
-
LEGAL_PARAM_CHARS,
|
|
23
|
-
CAPTURE_REGEX,
|
|
24
|
-
PARAM_USAGE_REGEXP,
|
|
25
|
-
CSRF_REGEXP,
|
|
26
|
-
getCsrfTokenByRegexp
|
|
27
|
-
} from './parameter-regex-providers';
|
|
28
|
-
import * as arrayUtils from '@loadmill/universal/dist/array-utils';
|
|
29
|
-
import { PresentableError } from '@loadmill/universal/dist/errors';
|
|
30
|
-
import { applyJSONSchema } from './parameter-functions/json-schema';
|
|
31
|
-
import { Assertions, Extractions, RequestLike } from '../request';
|
|
32
|
-
import { TestConfLike, validate } from '../conf';
|
|
33
|
-
import { getLongestJsonPathToken } from './json-path-utils';
|
|
34
|
-
|
|
35
|
-
class ParameterFunctionError extends PresentableError {
|
|
36
|
-
constructor(
|
|
37
|
-
public readonly functionName: string,
|
|
38
|
-
public readonly prettyError: string
|
|
39
|
-
) {
|
|
40
|
-
super(`Error in function '${functionName}': ${prettyError}`);
|
|
41
|
-
|
|
42
|
-
// Workaround suggested in: https://github.com/Microsoft/TypeScript-wiki/blob/master/Breaking-Changes.md#extending-built-ins-like-error-array-and-map-may-no-longer-work
|
|
43
|
-
Object.setPrototypeOf(this, ParameterFunctionError.prototype);
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
export const BUILT_IN_VOLATILE_PARAMS = {
|
|
48
|
-
requestBody: '__requestBody',
|
|
49
|
-
};
|
|
50
|
-
|
|
51
|
-
export const MAX_PARAM_ARRAY_SIZE = 100;
|
|
52
|
-
export {
|
|
53
|
-
CAPTURE_REGEX,
|
|
54
|
-
getLongestJsonPathToken,
|
|
55
|
-
LEGAL_PARAM_CHARS,
|
|
56
|
-
parameterFunctionOperations,
|
|
57
|
-
Parameters,
|
|
58
|
-
ParametersScope,
|
|
59
|
-
PresentableError,
|
|
60
|
-
SequenceExecutorParameters,
|
|
61
|
-
usageRegExpProvider,
|
|
62
|
-
valueUtils,
|
|
63
|
-
CSRF_REGEXP,
|
|
64
|
-
getCsrfTokenByRegexp
|
|
65
|
-
};
|
|
66
|
-
export class ParameterError extends PresentableError {
|
|
67
|
-
constructor(
|
|
68
|
-
public readonly prettyError: string,
|
|
69
|
-
public readonly parameter: Parameters
|
|
70
|
-
) {
|
|
71
|
-
super(`Error in parameter ${parameterUtils.getParameterName(parameter)}: ${prettyError}`);
|
|
72
|
-
|
|
73
|
-
// Workaround suggested in: https://github.com/Microsoft/TypeScript-wiki/blob/master/Breaking-Changes.md#extending-built-ins-like-error-array-and-map-may-no-longer-work
|
|
74
|
-
Object.setPrototypeOf(this, ParameterError.prototype);
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
// Order of resolving!
|
|
79
|
-
const parameterResolvers = [
|
|
80
|
-
resolveNoArgFunctionParameter,
|
|
81
|
-
// This one is legacy for e.g. __random_boolean_75:
|
|
82
|
-
resolveRandomParameter,
|
|
83
|
-
resolvePlainParameter,
|
|
84
|
-
];
|
|
85
|
-
|
|
86
|
-
export const parameterUtils = {
|
|
87
|
-
isParametrized(expression: string) {
|
|
88
|
-
return globalUsageRegExpProvider.use((regExp) => regExp.test(expression));
|
|
89
|
-
},
|
|
90
|
-
|
|
91
|
-
resolveAllExpressions(parameters: Parameters[]): Parameters {
|
|
92
|
-
const context: Parameters = {};
|
|
93
|
-
|
|
94
|
-
parameters.forEach((currentParameters: Parameters, index) => {
|
|
95
|
-
const temp: Parameters = {};
|
|
96
|
-
|
|
97
|
-
Object.keys(currentParameters).forEach(name => {
|
|
98
|
-
try {
|
|
99
|
-
const value = currentParameters[name];
|
|
100
|
-
temp[name] = parameterUtils.resolveExpression(
|
|
101
|
-
pickValue(value),
|
|
102
|
-
context
|
|
103
|
-
);
|
|
104
|
-
} catch (e) {
|
|
105
|
-
e['parameterName'] = name;
|
|
106
|
-
e['parameterIndex'] = index;
|
|
107
|
-
throw e;
|
|
108
|
-
}
|
|
109
|
-
});
|
|
110
|
-
|
|
111
|
-
Object.assign(context, temp);
|
|
112
|
-
});
|
|
113
|
-
|
|
114
|
-
return context;
|
|
115
|
-
},
|
|
116
|
-
|
|
117
|
-
resolveParameter(parameterName: string, parameters: Parameters, onError?) {
|
|
118
|
-
try {
|
|
119
|
-
for (const resolver of parameterResolvers) {
|
|
120
|
-
const value = resolver(parameterName, parameters);
|
|
121
|
-
|
|
122
|
-
if (value != null) {
|
|
123
|
-
return value;
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
} catch (e) {
|
|
127
|
-
if (onError) {
|
|
128
|
-
onError(e);
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
throw e;
|
|
132
|
-
}
|
|
133
|
-
},
|
|
134
|
-
|
|
135
|
-
resolveExpression(
|
|
136
|
-
parametrized: string,
|
|
137
|
-
parameters: Parameters | Parameters[],
|
|
138
|
-
onError?
|
|
139
|
-
): string {
|
|
140
|
-
try {
|
|
141
|
-
if (Array.isArray(parameters)) {
|
|
142
|
-
parameters = parameterUtils.resolveAllExpressions(parameters);
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
return globalUsageRegExpProvider.use((usageRegExp) => typeof parametrized !== 'string' ? parametrized :
|
|
146
|
-
parametrized.replace(usageRegExp, (usage: string) => {
|
|
147
|
-
// No ${}:
|
|
148
|
-
const strippedExpression = usage.slice(2, -1).trim();
|
|
149
|
-
|
|
150
|
-
// [expression, ...[operator, expression, ...]]
|
|
151
|
-
const tokens = spacesRegExpProvider.use((spacesRegExp) =>
|
|
152
|
-
strippedExpression.split(spacesRegExp)
|
|
153
|
-
);
|
|
154
|
-
|
|
155
|
-
// null if undefined or invalid parameters:
|
|
156
|
-
const value = resolveTokens(tokens, parameters as Parameters);
|
|
157
|
-
|
|
158
|
-
/* log.trace(`Parameter found in [${parametrized}]:`, {
|
|
159
|
-
usage,
|
|
160
|
-
tokens,
|
|
161
|
-
value,
|
|
162
|
-
}); */
|
|
163
|
-
return value != null ? value : usage;
|
|
164
|
-
})
|
|
165
|
-
);
|
|
166
|
-
} catch (e) {
|
|
167
|
-
if (onError) {
|
|
168
|
-
onError(e);
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
throw e;
|
|
172
|
-
}
|
|
173
|
-
},
|
|
174
|
-
|
|
175
|
-
addParamToArray(key, value, arr) {
|
|
176
|
-
arr.push({ [key]: value });
|
|
177
|
-
},
|
|
178
|
-
|
|
179
|
-
findIndex(key, arr) {
|
|
180
|
-
return arr.findIndex((obj) => {
|
|
181
|
-
return Object.keys(obj)[0] === key;
|
|
182
|
-
});
|
|
183
|
-
},
|
|
184
|
-
|
|
185
|
-
getParametersRegexGroups(src: string) {
|
|
186
|
-
return {
|
|
187
|
-
functionGroupingRegexp: getParameterfunctionGroupingRegexp(
|
|
188
|
-
src
|
|
189
|
-
),
|
|
190
|
-
operatorsGroupingRegexp: getParameterOperatorsGroupingRegexp(
|
|
191
|
-
src
|
|
192
|
-
)
|
|
193
|
-
};
|
|
194
|
-
},
|
|
195
|
-
|
|
196
|
-
suggestNewParamName(paramKey, flowConfParameters) {
|
|
197
|
-
let flowIndex;
|
|
198
|
-
do {
|
|
199
|
-
let suffix = parseInt(
|
|
200
|
-
paramKey.substr(paramKey.length - 1, paramKey.length),
|
|
201
|
-
10
|
|
202
|
-
);
|
|
203
|
-
if (Number.isInteger(suffix)) {
|
|
204
|
-
suffix += 1;
|
|
205
|
-
paramKey = paramKey.substr(0, paramKey.length - 1) + suffix;
|
|
206
|
-
} else {
|
|
207
|
-
paramKey = paramKey + '_1';
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
flowIndex = this.findIndex(paramKey, flowConfParameters); // new name might exist in flow conf
|
|
211
|
-
} while (flowIndex > -1);
|
|
212
|
-
|
|
213
|
-
return paramKey;
|
|
214
|
-
},
|
|
215
|
-
|
|
216
|
-
/** Search any parameters with the following patterns:
|
|
217
|
-
* ${param1}
|
|
218
|
-
* ${__encode_url(param1)}
|
|
219
|
-
* ${__if_then_else(param12,'good','bad')}
|
|
220
|
-
*/
|
|
221
|
-
searchParameterizedExpressionOccurrences(
|
|
222
|
-
parameterName: string,
|
|
223
|
-
data: string
|
|
224
|
-
): Array<string> {
|
|
225
|
-
return data.match(getParameterUsageRegexp(parameterName)) || [];
|
|
226
|
-
},
|
|
227
|
-
|
|
228
|
-
getUsedConfParams(conf: TestConfLike, parameters: Parameters[]): Parameters[] {
|
|
229
|
-
let usedParameters: Parameters[] = [];
|
|
230
|
-
if (parameters) {
|
|
231
|
-
const stringifyConf = JSON.stringify(conf);
|
|
232
|
-
parameters.forEach((p) => {
|
|
233
|
-
const paramName = this.getParameterName(p);
|
|
234
|
-
if (isParamUsedInConf(paramName, conf, stringifyConf)) {
|
|
235
|
-
const currentUsedParams = this.findUsedParameters(parameters ,p, []);
|
|
236
|
-
usedParameters = usedParameters.concat(currentUsedParams);
|
|
237
|
-
}
|
|
238
|
-
});
|
|
239
|
-
}
|
|
240
|
-
return uniqWith(usedParameters, isEqual);
|
|
241
|
-
},
|
|
242
|
-
|
|
243
|
-
getUsedRequestParams(request, parameters: Parameters[]): Parameters[] {
|
|
244
|
-
return this.getUsedConfParams({ requests: [request] }, parameters);
|
|
245
|
-
},
|
|
246
|
-
|
|
247
|
-
getValueByKeyFromArr(key: string, parameters: Parameters[], returnArray: boolean = false) {
|
|
248
|
-
let res;
|
|
249
|
-
const param = getParameterByKey(key, parameters);
|
|
250
|
-
if (param) {
|
|
251
|
-
res = this.getParameterValue(param);
|
|
252
|
-
if (Array.isArray(res)) {
|
|
253
|
-
if (returnArray && res.length > 1) {
|
|
254
|
-
return res;
|
|
255
|
-
}
|
|
256
|
-
return res[0];
|
|
257
|
-
}
|
|
258
|
-
}
|
|
259
|
-
return res;
|
|
260
|
-
},
|
|
261
|
-
|
|
262
|
-
pickFirstValue(p: Parameters): Parameters {
|
|
263
|
-
const name = parameterUtils.getParameterName(p);
|
|
264
|
-
const value = parameterUtils.getParameterValue(p);
|
|
265
|
-
if (Array.isArray(value) && value.length > 0) {
|
|
266
|
-
return { [name]: value[0] };
|
|
267
|
-
}
|
|
268
|
-
return { [name]: value };
|
|
269
|
-
},
|
|
270
|
-
getParameterValue(parameter: Parameters) {
|
|
271
|
-
const [value] = Object.values(parameter);
|
|
272
|
-
return value;
|
|
273
|
-
},
|
|
274
|
-
getParameterName(parameter: Parameters | Extractions): string {
|
|
275
|
-
const [name] = Object.keys(parameter);
|
|
276
|
-
return name;
|
|
277
|
-
},
|
|
278
|
-
getParametersNames(parameters: Parameters[]) {
|
|
279
|
-
return parameters.map((p) => {
|
|
280
|
-
const [pName] = Object.keys(p);
|
|
281
|
-
return pName;
|
|
282
|
-
});
|
|
283
|
-
},
|
|
284
|
-
setParameterValue(name: string, value: string| string[], parameters: Parameters[]) {
|
|
285
|
-
const index = this.findIndex(name, parameters);
|
|
286
|
-
parameters[index][name] = value;
|
|
287
|
-
},
|
|
288
|
-
getUsedRequestParamNames(stringifiedRequest: string): string[] {
|
|
289
|
-
const usedParams: string[] = [];
|
|
290
|
-
|
|
291
|
-
const allParametersOccurrences = searchExpressionOccurrences(
|
|
292
|
-
stringifiedRequest
|
|
293
|
-
);
|
|
294
|
-
|
|
295
|
-
allParametersOccurrences.map((paramOccurrence) => {
|
|
296
|
-
const tokensWithoutOperators = getTokensWithoutOperators(paramOccurrence);
|
|
297
|
-
for (const token of tokensWithoutOperators) {
|
|
298
|
-
if (isBuiltInFunction(token)) {
|
|
299
|
-
if (hasLeftParenthesis(token)) {
|
|
300
|
-
const [ , ...args] = stripToFunctionAndArgs(token);
|
|
301
|
-
for (const arg of args) {
|
|
302
|
-
if (!isSingleQuoted(arg)) {
|
|
303
|
-
usedParams.push(arg);
|
|
304
|
-
}
|
|
305
|
-
}
|
|
306
|
-
}
|
|
307
|
-
} else {
|
|
308
|
-
if (!isSingleQuoted(token)) {
|
|
309
|
-
usedParams.push(token);
|
|
310
|
-
}
|
|
311
|
-
}
|
|
312
|
-
}
|
|
313
|
-
});
|
|
314
|
-
|
|
315
|
-
return usedParams;
|
|
316
|
-
},
|
|
317
|
-
deleteAllSrcElementsFromParamArr(paramArr, src) {
|
|
318
|
-
let isSrcInParamArr = this.isParamKeyInArr(src, paramArr);
|
|
319
|
-
while (isSrcInParamArr) {
|
|
320
|
-
this.removeParameterFromArrayByKey(src, paramArr);
|
|
321
|
-
isSrcInParamArr = this.isParamKeyInArr(src, paramArr);
|
|
322
|
-
}
|
|
323
|
-
},
|
|
324
|
-
removeParameterFromArrayByKey(src, paramArr) {
|
|
325
|
-
const index = this.findIndex(src, paramArr);
|
|
326
|
-
paramArr.splice(index, 1);
|
|
327
|
-
},
|
|
328
|
-
isParamKeyInArr(key, arr) {
|
|
329
|
-
return this.findIndex(key, arr) >= 0;
|
|
330
|
-
},
|
|
331
|
-
/**
|
|
332
|
-
* Returns a Parameter ({name:value}) obj with the given value to search for.
|
|
333
|
-
* if non found, returns undefined
|
|
334
|
-
* @param value string | string[]
|
|
335
|
-
* @param arr Parameters[]
|
|
336
|
-
*/
|
|
337
|
-
findParamValueInArr(value, arr) {
|
|
338
|
-
return arr.find(p => isEqual(this.getParameterValue(p), value));
|
|
339
|
-
},
|
|
340
|
-
findUsedParameters(
|
|
341
|
-
suiteParameters: Parameters[], param: Parameters, usedParameters: Parameters[]
|
|
342
|
-
) {
|
|
343
|
-
try {
|
|
344
|
-
return findUsedParametersRecursively(suiteParameters, param, usedParameters).reverse();
|
|
345
|
-
}
|
|
346
|
-
catch (error) {
|
|
347
|
-
if (error instanceof RangeError) {
|
|
348
|
-
throw new ParameterError(
|
|
349
|
-
'circular dependency value' , param
|
|
350
|
-
);
|
|
351
|
-
} else {
|
|
352
|
-
throw new Error(error);
|
|
353
|
-
}
|
|
354
|
-
}
|
|
355
|
-
},
|
|
356
|
-
applyJSONSchema(instance, schema) {
|
|
357
|
-
return applyJSONSchema(instance, schema);
|
|
358
|
-
},
|
|
359
|
-
isUsingParameterizedValue(value: string) {
|
|
360
|
-
return PARAM_USAGE_REGEXP.test(value);
|
|
361
|
-
},
|
|
362
|
-
};
|
|
363
|
-
|
|
364
|
-
function resolvePlainParameter(parameterName: string, parameters) {
|
|
365
|
-
if (parameters.hasOwnProperty(parameterName)) {
|
|
366
|
-
return pickValue(parameters[parameterName]);
|
|
367
|
-
}
|
|
368
|
-
}
|
|
369
|
-
|
|
370
|
-
function resolveNoArgFunctionParameter(parameterName: string, parameters) {
|
|
371
|
-
return applyParameterFunction(
|
|
372
|
-
parameterName,
|
|
373
|
-
getParameterFunction(parameterName),
|
|
374
|
-
[],
|
|
375
|
-
parameters
|
|
376
|
-
);
|
|
377
|
-
}
|
|
378
|
-
|
|
379
|
-
function pickValue(parameterValue: string | string[]) {
|
|
380
|
-
return Array.isArray(parameterValue)
|
|
381
|
-
? pickRandom(parameterValue)
|
|
382
|
-
: parameterValue;
|
|
383
|
-
}
|
|
384
|
-
|
|
385
|
-
function resolveTokens(tokens: string[], parameters: Parameters) {
|
|
386
|
-
const [leftSide, operator, ...rest] = tokens;
|
|
387
|
-
|
|
388
|
-
const leftSideValue = resolveArgument(leftSide, parameters);
|
|
389
|
-
|
|
390
|
-
if (!operator) {
|
|
391
|
-
return leftSideValue;
|
|
392
|
-
}
|
|
393
|
-
|
|
394
|
-
if (leftSideValue == null) {
|
|
395
|
-
throw new ParameterFunctionError(
|
|
396
|
-
operator,
|
|
397
|
-
`No value for left side operand '${leftSide}'`
|
|
398
|
-
);
|
|
399
|
-
}
|
|
400
|
-
|
|
401
|
-
const rightSideValue = resolveTokens(rest, parameters);
|
|
402
|
-
|
|
403
|
-
if (rightSideValue == null) {
|
|
404
|
-
throw new ParameterFunctionError(
|
|
405
|
-
operator,
|
|
406
|
-
`No value for right side operand '${rest[0]}'`
|
|
407
|
-
);
|
|
408
|
-
}
|
|
409
|
-
|
|
410
|
-
return applyParameterFunction(operator, resolveOperator(operator), [
|
|
411
|
-
leftSideValue,
|
|
412
|
-
rightSideValue,
|
|
413
|
-
]);
|
|
414
|
-
}
|
|
415
|
-
|
|
416
|
-
function resolveArgument(arg: string, parameters: Parameters) {
|
|
417
|
-
if (arg.startsWith('\'')) {
|
|
418
|
-
return resolveLiteral(arg);
|
|
419
|
-
} else if (arg.includes('(')) {
|
|
420
|
-
return resolveParameterFunction(arg, parameters);
|
|
421
|
-
} else {
|
|
422
|
-
return parameterUtils.resolveParameter(arg, parameters);
|
|
423
|
-
}
|
|
424
|
-
}
|
|
425
|
-
|
|
426
|
-
function resolveLiteral(literal: string) {
|
|
427
|
-
return literal.slice(1, -1);
|
|
428
|
-
}
|
|
429
|
-
|
|
430
|
-
function resolveParameterFunction(
|
|
431
|
-
functionUsage: string,
|
|
432
|
-
parameters: Parameters
|
|
433
|
-
) {
|
|
434
|
-
let [functionName, ...args] = functionUsage
|
|
435
|
-
.replace(/\(/, ',')
|
|
436
|
-
.slice(0, -1)
|
|
437
|
-
.split(',');
|
|
438
|
-
|
|
439
|
-
if (args.length === 1 && args[0] === '') {
|
|
440
|
-
/// No args case, e.g. ${func()}
|
|
441
|
-
args = [];
|
|
442
|
-
}
|
|
443
|
-
|
|
444
|
-
return applyParameterFunction(
|
|
445
|
-
functionName,
|
|
446
|
-
getParameterFunction(functionName),
|
|
447
|
-
args,
|
|
448
|
-
parameters
|
|
449
|
-
);
|
|
450
|
-
}
|
|
451
|
-
|
|
452
|
-
function applyParameterFunction(
|
|
453
|
-
functionName: string,
|
|
454
|
-
parameterFunction,
|
|
455
|
-
args,
|
|
456
|
-
parameters?
|
|
457
|
-
) {
|
|
458
|
-
if (parameterFunction) {
|
|
459
|
-
const { minArgs, maxArgs, operate } = parameterFunction;
|
|
460
|
-
|
|
461
|
-
if (minArgs != null && args.length < minArgs) {
|
|
462
|
-
throw new ParameterFunctionError(
|
|
463
|
-
functionName,
|
|
464
|
-
`Must have at least ${minArgs} arguments`
|
|
465
|
-
);
|
|
466
|
-
} else if (maxArgs != null && args.length > maxArgs) {
|
|
467
|
-
throw new ParameterFunctionError(
|
|
468
|
-
functionName,
|
|
469
|
-
`Cannot have more than ${maxArgs} arguments`
|
|
470
|
-
);
|
|
471
|
-
}
|
|
472
|
-
|
|
473
|
-
if (parameters) {
|
|
474
|
-
args = args.map((arg, index) => {
|
|
475
|
-
const value = resolveArgument(arg, parameters);
|
|
476
|
-
|
|
477
|
-
if (value == null) {
|
|
478
|
-
if (canHaveNullParameterValue(functionName)) {
|
|
479
|
-
return '';
|
|
480
|
-
}
|
|
481
|
-
throw new ParameterFunctionError(
|
|
482
|
-
functionName,
|
|
483
|
-
`No value for '${arg}' at index ${index}`
|
|
484
|
-
);
|
|
485
|
-
}
|
|
486
|
-
|
|
487
|
-
return value;
|
|
488
|
-
});
|
|
489
|
-
}
|
|
490
|
-
try {
|
|
491
|
-
return operate(...args);
|
|
492
|
-
} catch (e) {
|
|
493
|
-
// log.debug('Parameter function error caught:', { functionName }, e);
|
|
494
|
-
throw new ParameterFunctionError(
|
|
495
|
-
functionName,
|
|
496
|
-
e.prettyMessage || 'Unexpected error'
|
|
497
|
-
);
|
|
498
|
-
}
|
|
499
|
-
}
|
|
500
|
-
}
|
|
501
|
-
|
|
502
|
-
function resolveOperator(opSymbol: string) {
|
|
503
|
-
return operators[opSymbol].parameterFunction;
|
|
504
|
-
}
|
|
505
|
-
|
|
506
|
-
function findUsedParametersRecursively(
|
|
507
|
-
suiteParameters: Parameters[], param: Parameters, usedParameters: Parameters[]
|
|
508
|
-
) : Parameters[] {
|
|
509
|
-
const paramValueStringified = JSON.stringify(parameterUtils.getParameterValue(param));
|
|
510
|
-
const currentUsedParameterNames = parameterUtils.getUsedRequestParamNames(paramValueStringified);
|
|
511
|
-
|
|
512
|
-
if (!usedParameters.some(p => isEqual(p, param))) {
|
|
513
|
-
const smallestIndex = getSmallestIndexInParamArr(currentUsedParameterNames, usedParameters);
|
|
514
|
-
usedParameters.splice(smallestIndex, 0, param);
|
|
515
|
-
}
|
|
516
|
-
if (isEmpty(currentUsedParameterNames)) {
|
|
517
|
-
return usedParameters;
|
|
518
|
-
}
|
|
519
|
-
for (const paramName of currentUsedParameterNames) {
|
|
520
|
-
const newParam = getParameterByKey(paramName, suiteParameters);
|
|
521
|
-
if (newParam) {
|
|
522
|
-
findUsedParametersRecursively(suiteParameters, newParam, usedParameters);
|
|
523
|
-
}
|
|
524
|
-
}
|
|
525
|
-
return usedParameters;
|
|
526
|
-
}
|
|
527
|
-
|
|
528
|
-
const getSmallestIndexInParamArr = (paramNames: string[], parameters: Parameters[]): number => {
|
|
529
|
-
let smallestIndex = 0;
|
|
530
|
-
if (arrayUtils.isNonEmptyArray(parameters)) {
|
|
531
|
-
smallestIndex = parameters.length;
|
|
532
|
-
for (const name of paramNames) {
|
|
533
|
-
const candidateIndex = parameterUtils.findIndex(name, parameters);
|
|
534
|
-
if (candidateIndex > -1 && candidateIndex < smallestIndex) {
|
|
535
|
-
smallestIndex = candidateIndex;
|
|
536
|
-
}
|
|
537
|
-
}
|
|
538
|
-
}
|
|
539
|
-
return smallestIndex;
|
|
540
|
-
};
|
|
541
|
-
|
|
542
|
-
const getParameterByKey = (key: string, parameters: Parameters[]): Parameters | null => {
|
|
543
|
-
const index = parameterUtils.findIndex(key, parameters);
|
|
544
|
-
return index > -1 ? parameters[index] : null;
|
|
545
|
-
};
|
|
546
|
-
|
|
547
|
-
/**
|
|
548
|
-
* a single quoted string starts and ends with a ' (single quote) char
|
|
549
|
-
* for example str = "'arnon'"
|
|
550
|
-
*/
|
|
551
|
-
const isSingleQuoted = (s: string): boolean => s.startsWith('\'') && s.endsWith('\'');
|
|
552
|
-
|
|
553
|
-
const hasLeftParenthesis = (s: string): boolean => s.includes('(');
|
|
554
|
-
|
|
555
|
-
export const stripToFunctionAndArgs = (s: string): string[] =>
|
|
556
|
-
s.replace(/\(/, ',').slice(0, -1).split(',');
|
|
557
|
-
|
|
558
|
-
export const stripParam = (s: string): string => s.replace(/\$|{|}/g, '');
|
|
559
|
-
|
|
560
|
-
const getTokens = (strippedExpression: string): string[] =>
|
|
561
|
-
spacesRegExpProvider.use((spacesRegExp) =>
|
|
562
|
-
strippedExpression.split(spacesRegExp)
|
|
563
|
-
);
|
|
564
|
-
|
|
565
|
-
const stripOperators = (tokens: string[]): string[] =>
|
|
566
|
-
tokens.filter((t) => !operatorsAsStrings.includes(t));
|
|
567
|
-
|
|
568
|
-
const getSubstringUntilChar = (s: string, c: string) => typeof s === 'string' ? s.split(c)[0] : '';
|
|
569
|
-
|
|
570
|
-
const isBuiltInFunction = (s: string) => getParameterFunction(getSubstringUntilChar(s, '('));
|
|
571
|
-
|
|
572
|
-
/* gets a string and returns all occurrences of ${...something/nothing..} */
|
|
573
|
-
export const searchExpressionOccurrences = (s: string): string[] =>
|
|
574
|
-
s.match(new RegExp(PARAMETER_USAGE_PATTERN, 'g')) || [];
|
|
575
|
-
|
|
576
|
-
export const getTokensWithoutOperators = (paramOccurrence: string): string[] => {
|
|
577
|
-
const strippedParam = stripParam(paramOccurrence);
|
|
578
|
-
const tokens = getTokens(strippedParam);
|
|
579
|
-
return stripOperators(tokens);
|
|
580
|
-
};
|
|
581
|
-
|
|
582
|
-
function isParamUsedInConf(paramName: string, conf: TestConfLike, stringifyConf: string): boolean {
|
|
583
|
-
return !isEmpty(parameterUtils.searchParameterizedExpressionOccurrences(paramName, stringifyConf)) ||
|
|
584
|
-
isParamNameUsedInConf(paramName, conf);
|
|
585
|
-
}
|
|
586
|
-
|
|
587
|
-
function isParamNameUsedInField(paramName: string, fieldValue?: string): boolean {
|
|
588
|
-
return !!fieldValue && fieldValue === paramName;
|
|
589
|
-
}
|
|
590
|
-
|
|
591
|
-
function isParamNameUsedInAssertions(paramName: string, assertions: Assertions = []): boolean {
|
|
592
|
-
return assertions.some(assertion => assertion.check === paramName);
|
|
593
|
-
}
|
|
594
|
-
|
|
595
|
-
function isParamNameUsedInRequest(paramName: string, request: RequestLike): boolean {
|
|
596
|
-
return isParamNameUsedInAssertions(paramName, request.assert) ||
|
|
597
|
-
isParamNameUsedInField(paramName, request.loop?.assert?.check) ||
|
|
598
|
-
isParamNameUsedInField(paramName, request.skipBefore?.condition) ||
|
|
599
|
-
isParamNameUsedInField(paramName, request.stopBefore);
|
|
600
|
-
}
|
|
601
|
-
|
|
602
|
-
function isParamNameUsedInConf(paramName: string, conf: TestConfLike): boolean {
|
|
603
|
-
if (!isEmpty(conf.requests)) {
|
|
604
|
-
return conf.requests.some(req => isParamNameUsedInRequest(paramName, req));
|
|
605
|
-
}
|
|
606
|
-
return false;
|
|
607
|
-
}
|
|
608
|
-
|
|
609
|
-
export function removeNonStringParameters(conf) {
|
|
610
|
-
const parameters = conf.parameters as Parameters[];
|
|
611
|
-
if (parameters) {
|
|
612
|
-
conf.parameters = parameters.filter(p =>
|
|
613
|
-
isEmpty(
|
|
614
|
-
validate.parameter(
|
|
615
|
-
parameterUtils.getParameterName(p),
|
|
616
|
-
parameterUtils.getParameterValue(p)
|
|
617
|
-
)
|
|
618
|
-
)
|
|
619
|
-
);
|
|
620
|
-
}
|
|
621
|
-
}
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
import jsonpath from 'jsonpath';
|
|
2
|
-
|
|
3
|
-
type jsonPathComponent = {
|
|
4
|
-
expression: {
|
|
5
|
-
type: string,
|
|
6
|
-
value: string
|
|
7
|
-
};
|
|
8
|
-
scope: string;
|
|
9
|
-
operation: string;
|
|
10
|
-
};
|
|
11
|
-
|
|
12
|
-
export const getLongestJsonPathToken = (jsonPath: string) => {
|
|
13
|
-
const pathExpressionsValues = (jsonpath.parse(jsonPath) as jsonPathComponent[])
|
|
14
|
-
.map(p => p.expression.value);
|
|
15
|
-
|
|
16
|
-
const longestToken = pathExpressionsValues.reduce(longestStringReducer);
|
|
17
|
-
return longestToken;
|
|
18
|
-
};
|
|
19
|
-
|
|
20
|
-
const longestStringReducer = (prev: string, curr: string) => curr.length > prev.length ? curr : prev;
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import { ParameterFunction } from '../parameter-functions/parameter-function';
|
|
2
|
-
|
|
3
|
-
export class BinaryOperator {
|
|
4
|
-
readonly regexSymbol;
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
*
|
|
8
|
-
* @param {string[]} symbols
|
|
9
|
-
* @param {ParameterFunction} parameterFunction
|
|
10
|
-
* @param {string} regexSymbol Must NOT contain any capture groups! I.e. use non-capturing (?:) instead.
|
|
11
|
-
*/
|
|
12
|
-
constructor(
|
|
13
|
-
readonly symbols: string[],
|
|
14
|
-
readonly parameterFunction: ParameterFunction,
|
|
15
|
-
regexSymbol?: string
|
|
16
|
-
) {
|
|
17
|
-
this.regexSymbol =
|
|
18
|
-
regexSymbol ||
|
|
19
|
-
symbols
|
|
20
|
-
.map((symbol) => (symbol.length > 1 ? `(?:${symbol})` : symbol))
|
|
21
|
-
.join('|');
|
|
22
|
-
}
|
|
23
|
-
}
|
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
import { BinaryOperator } from './binary-operator';
|
|
2
|
-
import { textualParameterFunctions } from '../parameter-functions/textual-parameter-functions';
|
|
3
|
-
import { booleanParameterFunctions } from '../parameter-functions/boolean-parameter-functions';
|
|
4
|
-
import { numericInputParameterFunctions } from '../parameter-functions/numeric-input-parameter-functions';
|
|
5
|
-
import { numericParameterFunctions } from '../parameter-functions/numeric-parameter-functions';
|
|
6
|
-
|
|
7
|
-
export const operators = mapOperators(
|
|
8
|
-
new BinaryOperator(['=', '==', '==='], textualParameterFunctions.__eq),
|
|
9
|
-
new BinaryOperator(['!=', '!=='], textualParameterFunctions.__neq),
|
|
10
|
-
|
|
11
|
-
new BinaryOperator(['&', '&&'], booleanParameterFunctions.__and),
|
|
12
|
-
new BinaryOperator(
|
|
13
|
-
['|', '||'],
|
|
14
|
-
booleanParameterFunctions.__or,
|
|
15
|
-
'\\||(?:\\|\\|)'
|
|
16
|
-
),
|
|
17
|
-
|
|
18
|
-
new BinaryOperator(['<'], numericInputParameterFunctions.__lt),
|
|
19
|
-
|
|
20
|
-
new BinaryOperator(['>'], numericInputParameterFunctions.__gt),
|
|
21
|
-
|
|
22
|
-
new BinaryOperator(['<='], numericInputParameterFunctions.__lte),
|
|
23
|
-
|
|
24
|
-
new BinaryOperator(['>='], numericInputParameterFunctions.__gte),
|
|
25
|
-
|
|
26
|
-
new BinaryOperator(['+'], numericParameterFunctions.__add, '\\+'),
|
|
27
|
-
new BinaryOperator(['-'], numericParameterFunctions.__sub),
|
|
28
|
-
new BinaryOperator(['*'], numericParameterFunctions.__mult, '\\*'),
|
|
29
|
-
new BinaryOperator(['/'], numericParameterFunctions.__div)
|
|
30
|
-
);
|
|
31
|
-
|
|
32
|
-
function mapOperators(...operators: BinaryOperator[]) {
|
|
33
|
-
return operators.reduce((obj, op) => {
|
|
34
|
-
op.symbols.forEach((symbol) => (obj[symbol] = op));
|
|
35
|
-
return obj;
|
|
36
|
-
}, {} as { [symbol: string]: BinaryOperator });
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
export const operatorsAsStrings = Object.keys(operators);
|