@loadmill/core 0.3.34 → 0.3.38
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 +2 -2
- package/dist/conf/extrema.js +2 -0
- package/dist/conf/extrema.js.map +1 -1
- package/dist/conf/types.d.ts +1 -1
- package/dist/conf/validate.js +4 -1
- package/dist/conf/validate.js.map +1 -1
- package/dist/har/index.d.ts +16 -4
- package/dist/har/index.js.map +1 -1
- package/dist/parameters/extractors/extractor.d.ts +1 -1
- package/dist/parameters/extractors/index.d.ts +2 -1
- package/dist/parameters/extractors/index.js +3 -1
- package/dist/parameters/extractors/index.js.map +1 -1
- package/dist/parameters/extractors/parametrized-extractor.d.ts +4 -2
- package/dist/parameters/extractors/regex-extractor.js +2 -13
- package/dist/parameters/extractors/regex-extractor.js.map +1 -1
- package/dist/parameters/extractors/regex-matcher.d.ts +1 -0
- package/dist/parameters/extractors/regex-matcher.js +20 -0
- package/dist/parameters/extractors/regex-matcher.js.map +1 -0
- package/dist/parameters/extractors/ws-extractor.d.ts +30 -0
- package/dist/parameters/extractors/ws-extractor.js +198 -0
- package/dist/parameters/extractors/ws-extractor.js.map +1 -0
- package/dist/parameters/index.d.ts +5 -2
- package/dist/parameters/index.js +33 -3
- package/dist/parameters/index.js.map +1 -1
- package/dist/parameters/parameter-regex-providers.d.ts +3 -0
- package/dist/parameters/parameter-regex-providers.js +7 -1
- package/dist/parameters/parameter-regex-providers.js.map +1 -1
- package/dist/request/index.d.ts +4 -1
- package/dist/request/index.js +17 -5
- package/dist/request/index.js.map +1 -1
- package/dist/schema/json-schema-generator.d.ts +1 -1
- package/dist/schema/json-schema-generator.js +14 -10
- package/dist/schema/json-schema-generator.js.map +1 -1
- package/package.json +4 -4
- package/src/conf/extrema.ts +1 -1
- package/src/conf/index.ts +6 -6
- package/src/conf/notifications.ts +3 -3
- package/src/conf/types.ts +2 -2
- package/src/conf/validate.ts +5 -2
- package/src/echo/firehose.ts +10 -10
- package/src/har/index.ts +15 -5
- package/src/parameters/extractors/extractor.ts +1 -1
- package/src/parameters/extractors/index.ts +2 -1
- package/src/parameters/extractors/json-path-extractor.ts +1 -1
- package/src/parameters/extractors/parametrized-extractor.ts +3 -1
- package/src/parameters/extractors/regex-extractor.ts +2 -14
- package/src/parameters/extractors/regex-matcher.ts +16 -0
- package/src/parameters/extractors/ws-extractor.ts +89 -0
- package/src/parameters/index.ts +45 -8
- package/src/parameters/parameter-functions/textual-parameter-functions.ts +1 -1
- package/src/parameters/parameter-regex-providers.ts +8 -0
- package/src/request/index.ts +15 -4
- package/src/schema/json-schema-generator.ts +14 -12
- package/test/parameters/value-utils.spec.js +2 -2
- package/test/schema/json-schema-generator.spec.js +70 -45
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { PresentableError } from '@loadmill/universal/dist/errors';
|
|
2
|
+
import log from '@loadmill/universal/dist/log';
|
|
3
|
+
import { delay } from '@loadmill/universal/dist/promise-utils';
|
|
4
|
+
import { CAPTURE_ALL_REGEX, isCaptureAllRegExp } from '../parameter-regex-providers';
|
|
5
|
+
import { Parameters } from '../type';
|
|
6
|
+
import { ParametrizedExtractor } from './parametrized-extractor';
|
|
7
|
+
import { matchRegex } from './regex-matcher';
|
|
8
|
+
|
|
9
|
+
export class WsExtractor extends ParametrizedExtractor {
|
|
10
|
+
private readonly _messages: string[];
|
|
11
|
+
private readonly _timeLimit: number;
|
|
12
|
+
constructor(
|
|
13
|
+
extractionData: WSExtractionData = { messages: [], timeLimit: 0 },
|
|
14
|
+
parameters: Parameters,
|
|
15
|
+
) {
|
|
16
|
+
super(parameters);
|
|
17
|
+
this._messages = extractionData.messages;
|
|
18
|
+
this._timeLimit = extractionData.timeLimit;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
extractResolved = async (resolvedRegex: string) => {
|
|
22
|
+
log.debug('Resolved WS extraction regex:', resolvedRegex);
|
|
23
|
+
const regexp = new RegExp(resolvedRegex || CAPTURE_ALL_REGEX);
|
|
24
|
+
const wsMessage = await this.queryMessage(regexp);
|
|
25
|
+
log.debug('WS message queried and found:', wsMessage);
|
|
26
|
+
|
|
27
|
+
return matchRegex(regexp, wsMessage);
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Querying all received incoming WS messages by regexp.
|
|
32
|
+
* @returns A WS message that satisfies the given regexp. If none found, returns an empty string.
|
|
33
|
+
* @throws RequestFailuresError if the procedure timeouts before any relevant message found.
|
|
34
|
+
*/
|
|
35
|
+
private async queryMessage(
|
|
36
|
+
regexp: RegExp,
|
|
37
|
+
): Promise<string> {
|
|
38
|
+
const res = await this.getWSMessageOrTimeout(regexp);
|
|
39
|
+
if (!res) {
|
|
40
|
+
throw new PresentableError('Websocket waiting timeout expired');
|
|
41
|
+
}
|
|
42
|
+
return res;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
private readonly GIVE_WS_MSG_TIME_MS = 250;
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Get an incoming ws message that satisfies the given regex, out of all already received incoming ws messages.
|
|
49
|
+
*
|
|
50
|
+
* If can't find that message, then actively waiting, until procedure timeouts.
|
|
51
|
+
* @param regex To test the messages with
|
|
52
|
+
* @param timeout Milliseconds for the procedure to find a message
|
|
53
|
+
* @returns ws message as string or undefined if timed out
|
|
54
|
+
*/
|
|
55
|
+
private async getWSMessageOrTimeout(
|
|
56
|
+
regexp: RegExp,
|
|
57
|
+
): Promise<string | undefined> {
|
|
58
|
+
const startTime = Date.now();
|
|
59
|
+
let message = '';
|
|
60
|
+
let elapsedTime = 0;
|
|
61
|
+
|
|
62
|
+
while (!message && elapsedTime < this._timeLimit) {
|
|
63
|
+
message = this.findMessageByRegex(regexp) || '';
|
|
64
|
+
if (message) {
|
|
65
|
+
break;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
await delay(this.GIVE_WS_MSG_TIME_MS);
|
|
69
|
+
elapsedTime = Date.now() - startTime;
|
|
70
|
+
}
|
|
71
|
+
return message;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
private findMessageByRegex(regexp: RegExp): string | undefined {
|
|
75
|
+
if (isCaptureAllRegExp(regexp)) {
|
|
76
|
+
return this.getLastMessage();
|
|
77
|
+
}
|
|
78
|
+
return this._messages.find(msg => regexp.test(msg));
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
private getLastMessage(): string {
|
|
82
|
+
return this._messages[this._messages.length - 1];
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export type WSExtractionData = {
|
|
87
|
+
messages: string[];
|
|
88
|
+
timeLimit: number;
|
|
89
|
+
}
|
package/src/parameters/index.ts
CHANGED
|
@@ -20,11 +20,14 @@ import {
|
|
|
20
20
|
usageRegExpProvider,
|
|
21
21
|
PARAMETER_USAGE_PATTERN,
|
|
22
22
|
LEGAL_PARAM_CHARS,
|
|
23
|
-
CAPTURE_REGEX
|
|
23
|
+
CAPTURE_REGEX,
|
|
24
|
+
PARAM_USAGE_REGEXP,
|
|
24
25
|
} from './parameter-regex-providers';
|
|
25
26
|
import * as arrayUtils from '@loadmill/universal/dist/array-utils';
|
|
26
27
|
import { PresentableError } from '@loadmill/universal/dist/errors';
|
|
27
28
|
import { applyJSONSchema } from './parameter-functions/json-schema';
|
|
29
|
+
import { Assertions, RequestLike } from '../request';
|
|
30
|
+
import { TestConfLike } from '../conf';
|
|
28
31
|
|
|
29
32
|
function isStackEmpty(s) {
|
|
30
33
|
return s.length === 0;
|
|
@@ -237,7 +240,7 @@ export const parameterUtils = {
|
|
|
237
240
|
* ${__encode_url(param1)}
|
|
238
241
|
* ${__if_then_else(param12,'good','bad')}
|
|
239
242
|
*/
|
|
240
|
-
|
|
243
|
+
searchParameterizedExpressionOccurrences(
|
|
241
244
|
parameterName: string,
|
|
242
245
|
data: string
|
|
243
246
|
): Array<string> {
|
|
@@ -259,13 +262,13 @@ export const parameterUtils = {
|
|
|
259
262
|
return extractionParamNames;
|
|
260
263
|
},
|
|
261
264
|
|
|
262
|
-
getUsedConfParams(conf, parameters: Parameters[]): Parameters[] {
|
|
265
|
+
getUsedConfParams(conf: TestConfLike, parameters: Parameters[]): Parameters[] {
|
|
263
266
|
let usedParameters: Parameters[] = [];
|
|
264
267
|
if (parameters) {
|
|
265
268
|
const stringifyConf = JSON.stringify(conf);
|
|
266
269
|
parameters.forEach((p) => {
|
|
267
270
|
const paramName = this.getParameterName(p);
|
|
268
|
-
if (
|
|
271
|
+
if (isParamUsedInConf(paramName, conf, stringifyConf)) {
|
|
269
272
|
const currentUsedParams = this.findUsedParameters(parameters ,p, []);
|
|
270
273
|
usedParameters = usedParameters.concat(currentUsedParams);
|
|
271
274
|
}
|
|
@@ -274,6 +277,10 @@ export const parameterUtils = {
|
|
|
274
277
|
return uniqWith(usedParameters, isEqual);
|
|
275
278
|
},
|
|
276
279
|
|
|
280
|
+
getUsedRequestParams(request, parameters: Parameters[]): Parameters[] {
|
|
281
|
+
return this.getUsedConfParams({ requests: [request] }, parameters);
|
|
282
|
+
},
|
|
283
|
+
|
|
277
284
|
getValueByKeyFromArr(key: string, parameters: Parameters[]) {
|
|
278
285
|
let res;
|
|
279
286
|
const param = getParameterByKey(key, parameters);
|
|
@@ -333,7 +340,7 @@ export const parameterUtils = {
|
|
|
333
340
|
}
|
|
334
341
|
}
|
|
335
342
|
} else {
|
|
336
|
-
if(!isSingleQuoted(token)) {
|
|
343
|
+
if (!isSingleQuoted(token)) {
|
|
337
344
|
usedParams.push(token);
|
|
338
345
|
}
|
|
339
346
|
}
|
|
@@ -344,7 +351,7 @@ export const parameterUtils = {
|
|
|
344
351
|
},
|
|
345
352
|
deleteAllSrcElementsFromParamArr(paramArr, src) {
|
|
346
353
|
let isSrcInParamArr = this.isParamKeyInArr(src, paramArr);
|
|
347
|
-
while(isSrcInParamArr) {
|
|
354
|
+
while (isSrcInParamArr) {
|
|
348
355
|
this.removeParameterFromArrayByKey(src, paramArr);
|
|
349
356
|
isSrcInParamArr = this.isParamKeyInArr(src, paramArr);
|
|
350
357
|
}
|
|
@@ -383,7 +390,10 @@ export const parameterUtils = {
|
|
|
383
390
|
},
|
|
384
391
|
applyJSONSchema(instance, schema) {
|
|
385
392
|
return applyJSONSchema(instance, schema);
|
|
386
|
-
}
|
|
393
|
+
},
|
|
394
|
+
isUsingParameterizedValue(value: string) {
|
|
395
|
+
return PARAM_USAGE_REGEXP.test(value);
|
|
396
|
+
},
|
|
387
397
|
};
|
|
388
398
|
|
|
389
399
|
function resolvePlainParameter(parameterName: string, parameters) {
|
|
@@ -530,7 +540,7 @@ function resolveOperator(opSymbol: string) {
|
|
|
530
540
|
|
|
531
541
|
function findUsedParametersRecursively(
|
|
532
542
|
suiteParameters: Parameters[], param: Parameters, usedParameters: Parameters[]
|
|
533
|
-
) : Parameters[]{
|
|
543
|
+
) : Parameters[] {
|
|
534
544
|
const paramValueStringified = JSON.stringify(parameterUtils.getParameterValue(param));
|
|
535
545
|
const currentUsedParameterNames = parameterUtils.getUsedRequestParamNames(paramValueStringified);
|
|
536
546
|
|
|
@@ -603,3 +613,30 @@ export const getTokensWithoutOperators = (paramOccurrence: string): string[] =>
|
|
|
603
613
|
const tokens = getTokens(strippedParam);
|
|
604
614
|
return stripOperators(tokens);
|
|
605
615
|
};
|
|
616
|
+
|
|
617
|
+
function isParamUsedInConf(paramName: string, conf: TestConfLike, stringifyConf: string): boolean {
|
|
618
|
+
return !isEmpty(parameterUtils.searchParameterizedExpressionOccurrences(paramName, stringifyConf)) ||
|
|
619
|
+
isParamNameUsedInConf(paramName, conf);
|
|
620
|
+
}
|
|
621
|
+
|
|
622
|
+
function isParamNameUsedInField(paramName: string, fieldValue?: string): boolean {
|
|
623
|
+
return !!fieldValue && fieldValue === paramName;
|
|
624
|
+
}
|
|
625
|
+
|
|
626
|
+
function isParamNameUsedInAssertions(paramName: string, assertions: Assertions = []): boolean {
|
|
627
|
+
return assertions.some(assertion => assertion.check === paramName);
|
|
628
|
+
}
|
|
629
|
+
|
|
630
|
+
function isParamNameUsedInRequest(paramName: string, request: RequestLike): boolean {
|
|
631
|
+
return isParamNameUsedInAssertions(paramName, request.assert) ||
|
|
632
|
+
isParamNameUsedInField(paramName, request.loop?.assert?.check) ||
|
|
633
|
+
isParamNameUsedInField(paramName, request.skipBefore?.condition) ||
|
|
634
|
+
isParamNameUsedInField(paramName, request.stopBefore);
|
|
635
|
+
}
|
|
636
|
+
|
|
637
|
+
function isParamNameUsedInConf(paramName: string, conf: TestConfLike): boolean {
|
|
638
|
+
if (!isEmpty(conf.requests)) {
|
|
639
|
+
return conf.requests.some(req => isParamNameUsedInRequest(paramName, req));
|
|
640
|
+
}
|
|
641
|
+
return false;
|
|
642
|
+
}
|
|
@@ -61,3 +61,11 @@ export const getParameterOperatorsGroupingRegexp = (parameterName) =>
|
|
|
61
61
|
);
|
|
62
62
|
|
|
63
63
|
export const CAPTURE_REGEX = /(([^\\]\(|^\().*[^\\]\))/;
|
|
64
|
+
|
|
65
|
+
export const PARAM_USAGE_REGEXP = /\$\{(.+)\}/;
|
|
66
|
+
|
|
67
|
+
export const CAPTURE_ALL_REGEX = /(.*)/;
|
|
68
|
+
|
|
69
|
+
export function isCaptureAllRegExp(regexp: RegExp): boolean {
|
|
70
|
+
return String(CAPTURE_ALL_REGEX) === String(regexp);
|
|
71
|
+
}
|
package/src/request/index.ts
CHANGED
|
@@ -2,7 +2,7 @@ import flatMap = require('lodash/flatMap');
|
|
|
2
2
|
import * as uriUtils from '@loadmill/universal/dist/uri-utils';
|
|
3
3
|
import { Parameters, parameterUtils } from '../parameters';
|
|
4
4
|
|
|
5
|
-
export const DEFAULT_REQUEST_TIMEOUT =
|
|
5
|
+
export const DEFAULT_REQUEST_TIMEOUT = 25000;
|
|
6
6
|
export const supportedMethods = {
|
|
7
7
|
GET: 'GET',
|
|
8
8
|
POST: 'POST',
|
|
@@ -46,6 +46,7 @@ export class LoadmillRequest implements RequestLike {
|
|
|
46
46
|
assert?: Assertions;
|
|
47
47
|
extract?: Extractions[];
|
|
48
48
|
postScript?: string;
|
|
49
|
+
disabled?: boolean;
|
|
49
50
|
timeout?: number;
|
|
50
51
|
expectedStatus?: HttpResponseStatus;
|
|
51
52
|
|
|
@@ -82,6 +83,7 @@ export function createRequest(from: RequestLike): LoadmillRequest {
|
|
|
82
83
|
description,
|
|
83
84
|
expectedStatus,
|
|
84
85
|
postScript,
|
|
86
|
+
disabled,
|
|
85
87
|
} = from;
|
|
86
88
|
|
|
87
89
|
const request = new LoadmillRequest(url);
|
|
@@ -104,11 +106,11 @@ export function createRequest(from: RequestLike): LoadmillRequest {
|
|
|
104
106
|
request.postData = { text, mimeType };
|
|
105
107
|
}
|
|
106
108
|
|
|
107
|
-
if (delay
|
|
109
|
+
if (delay !== null && delay !== undefined) {
|
|
108
110
|
request.delay = delay;
|
|
109
111
|
}
|
|
110
112
|
|
|
111
|
-
if (stopBefore) {
|
|
113
|
+
if (stopBefore !== undefined) {
|
|
112
114
|
request.stopBefore = stopBefore;
|
|
113
115
|
}
|
|
114
116
|
|
|
@@ -151,6 +153,9 @@ export function createRequest(from: RequestLike): LoadmillRequest {
|
|
|
151
153
|
if (postScript !== undefined) {
|
|
152
154
|
request.postScript = postScript;
|
|
153
155
|
}
|
|
156
|
+
if (disabled !== undefined) {
|
|
157
|
+
request.disabled = disabled;
|
|
158
|
+
}
|
|
154
159
|
|
|
155
160
|
return request;
|
|
156
161
|
}
|
|
@@ -192,7 +197,7 @@ function toSingleExtractions(extractions: Extractions): Extractions {
|
|
|
192
197
|
|
|
193
198
|
if (typeof extraction !== 'string') {
|
|
194
199
|
newExtraction = {};
|
|
195
|
-
const { header, jQuery, jsonPath, edn, regex } = extraction;
|
|
200
|
+
const { header, jQuery, jsonPath, edn, regex, ws } = extraction;
|
|
196
201
|
|
|
197
202
|
if (header != null) {
|
|
198
203
|
newExtraction.header = header;
|
|
@@ -216,6 +221,10 @@ function toSingleExtractions(extractions: Extractions): Extractions {
|
|
|
216
221
|
if (regex != null) {
|
|
217
222
|
newExtraction.regex = regex;
|
|
218
223
|
}
|
|
224
|
+
|
|
225
|
+
if (ws != null) {
|
|
226
|
+
newExtraction.ws = ws;
|
|
227
|
+
}
|
|
219
228
|
}
|
|
220
229
|
|
|
221
230
|
result[name] = newExtraction;
|
|
@@ -342,6 +351,7 @@ export interface RequestLike {
|
|
|
342
351
|
expectedStatus?: HttpResponseStatus;
|
|
343
352
|
parameters?;
|
|
344
353
|
postScript?: string;
|
|
354
|
+
disabled?: boolean;
|
|
345
355
|
}
|
|
346
356
|
|
|
347
357
|
export type SkipConf = {
|
|
@@ -396,6 +406,7 @@ export type ExtractionObj = {
|
|
|
396
406
|
query: string;
|
|
397
407
|
attr?: string;
|
|
398
408
|
};
|
|
409
|
+
ws?: string;
|
|
399
410
|
};
|
|
400
411
|
|
|
401
412
|
export type Assertions = Assertion[];
|
|
@@ -1,8 +1,10 @@
|
|
|
1
|
+
import find = require('lodash/find');
|
|
1
2
|
import log from '@loadmill/universal/dist/log';
|
|
3
|
+
import isEmpty = require('lodash/isEmpty');
|
|
2
4
|
|
|
3
|
-
export const generateJSONSchema = (jsObj: any, ignoreKeys: string[] = []): PrimitiveSchema | Schema => {
|
|
5
|
+
export const generateJSONSchema = (jsObj: any, ignoreKeys: string[] = [], shouldAddNullable: boolean = false): PrimitiveSchema | Schema => {
|
|
4
6
|
try {
|
|
5
|
-
const schema = _getSchema(jsObj, ignoreKeys);
|
|
7
|
+
const schema = _getSchema(jsObj, ignoreKeys, shouldAddNullable);
|
|
6
8
|
return schema;
|
|
7
9
|
} catch (err) {
|
|
8
10
|
_handleError('Error generating JSON Schema', err, jsObj);
|
|
@@ -11,27 +13,27 @@ export const generateJSONSchema = (jsObj: any, ignoreKeys: string[] = []): Primi
|
|
|
11
13
|
return {};
|
|
12
14
|
};
|
|
13
15
|
|
|
14
|
-
const _getSchema = (obj, ignoreKeys: string[] = []) => {
|
|
16
|
+
const _getSchema = (obj, ignoreKeys: string[] = [], shouldAddNullable: boolean = false) => {
|
|
15
17
|
if (obj == null) {
|
|
16
|
-
return {};
|
|
18
|
+
return shouldAddNullable ? { type: 'object', nullable: true } :{};
|
|
17
19
|
}
|
|
18
20
|
else if (_isPrimitive(obj)) {
|
|
19
21
|
return {
|
|
20
|
-
'type': typeof obj
|
|
21
|
-
'const': obj
|
|
22
|
+
'type': typeof obj
|
|
22
23
|
};
|
|
23
24
|
}
|
|
24
25
|
else if (Array.isArray(obj)) {
|
|
25
26
|
const items: any[] = [];
|
|
26
|
-
for (const [,value] of Object.entries(obj)) {
|
|
27
|
-
|
|
27
|
+
for (const [, value] of Object.entries(obj)) {
|
|
28
|
+
const elementSchema = _getSchema(value, ignoreKeys);
|
|
29
|
+
if (!find(items, elementSchema)) {
|
|
30
|
+
items.push(elementSchema);
|
|
31
|
+
}
|
|
28
32
|
}
|
|
29
33
|
// The use of 'oneOf' creates a schema that validates the existence of the items but not their order in the array
|
|
30
|
-
return {
|
|
34
|
+
return {
|
|
31
35
|
'type': 'array',
|
|
32
|
-
'items': {
|
|
33
|
-
'anyOf': items
|
|
34
|
-
}
|
|
36
|
+
'items': isEmpty(items) ? {} : { 'anyOf': items }
|
|
35
37
|
};
|
|
36
38
|
}
|
|
37
39
|
else {
|
|
@@ -36,7 +36,7 @@ suite('test valueUtils module', () => {
|
|
|
36
36
|
expect(valueUtils.isTruthyParameterValue('undefined')).equals(false);
|
|
37
37
|
});
|
|
38
38
|
it('"NaN" => false', () => {
|
|
39
|
-
expect(valueUtils.isTruthyParameterValue('NaN')).equals(false);
|
|
39
|
+
expect(valueUtils.isTruthyParameterValue('NaN')).equals(false);
|
|
40
40
|
});
|
|
41
41
|
it('"" => false', () => {
|
|
42
42
|
expect(valueUtils.isTruthyParameterValue('')).equals(false);
|
|
@@ -66,7 +66,7 @@ suite('test valueUtils module', () => {
|
|
|
66
66
|
expect(valueUtils.isTruthyParameterValue([])).equals(true);
|
|
67
67
|
});
|
|
68
68
|
it('Infinity => true', () => {
|
|
69
|
-
expect(valueUtils.isTruthyParameterValue(Infinity)).equals(true);
|
|
69
|
+
expect(valueUtils.isTruthyParameterValue(Infinity)).equals(true);
|
|
70
70
|
});
|
|
71
71
|
});
|
|
72
72
|
});
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const { suite } = require('mocha');
|
|
1
|
+
const { suite, describe, it } = require('mocha');
|
|
2
2
|
const { expect } = require('chai');
|
|
3
3
|
const { Validator } = require('jsonschema');
|
|
4
4
|
|
|
@@ -10,7 +10,7 @@ suite('JSON Schema generator', () => {
|
|
|
10
10
|
describe('Primitive cases', () => {
|
|
11
11
|
it('Just 1 string', () => {
|
|
12
12
|
const string = 'arnon';
|
|
13
|
-
const expected = { type: 'string'
|
|
13
|
+
const expected = { type: 'string' };
|
|
14
14
|
const res = generateJSONSchema(string);
|
|
15
15
|
expect(res).eql(expected);
|
|
16
16
|
|
|
@@ -19,7 +19,7 @@ suite('JSON Schema generator', () => {
|
|
|
19
19
|
});
|
|
20
20
|
it('Just 1 number', () => {
|
|
21
21
|
const number = 123;
|
|
22
|
-
const expected = { 'type': 'number'
|
|
22
|
+
const expected = { 'type': 'number' };
|
|
23
23
|
const res = generateJSONSchema(number);
|
|
24
24
|
expect(res).eql(expected);
|
|
25
25
|
|
|
@@ -28,7 +28,7 @@ suite('JSON Schema generator', () => {
|
|
|
28
28
|
});
|
|
29
29
|
it('Just 1 boolean', () => {
|
|
30
30
|
const boolie = false;
|
|
31
|
-
const expected = { 'type': 'boolean'
|
|
31
|
+
const expected = { 'type': 'boolean' };
|
|
32
32
|
const res = generateJSONSchema(boolie);
|
|
33
33
|
expect(res).eql(expected);
|
|
34
34
|
|
|
@@ -37,6 +37,18 @@ suite('JSON Schema generator', () => {
|
|
|
37
37
|
});
|
|
38
38
|
});
|
|
39
39
|
describe('Complex cases', () => {
|
|
40
|
+
it('Empty Array', () => {
|
|
41
|
+
const array = [];
|
|
42
|
+
const expected = {
|
|
43
|
+
'type': 'array',
|
|
44
|
+
'items': {}
|
|
45
|
+
};
|
|
46
|
+
const res = generateJSONSchema(array);
|
|
47
|
+
expect(res).eql(expected);
|
|
48
|
+
|
|
49
|
+
const schemaRes = v.validate(array, res);
|
|
50
|
+
expect(schemaRes.errors).eql([]);
|
|
51
|
+
});
|
|
40
52
|
it('Array of strings', () => {
|
|
41
53
|
const array = ['Arnon','Yochai'];
|
|
42
54
|
const expected = {
|
|
@@ -45,12 +57,7 @@ suite('JSON Schema generator', () => {
|
|
|
45
57
|
'anyOf':
|
|
46
58
|
[
|
|
47
59
|
{
|
|
48
|
-
'type': 'string'
|
|
49
|
-
'const': 'Arnon'
|
|
50
|
-
},
|
|
51
|
-
{
|
|
52
|
-
'type': 'string',
|
|
53
|
-
'const': 'Yochai'
|
|
60
|
+
'type': 'string'
|
|
54
61
|
}
|
|
55
62
|
]
|
|
56
63
|
}
|
|
@@ -60,6 +67,8 @@ suite('JSON Schema generator', () => {
|
|
|
60
67
|
|
|
61
68
|
const schemaRes = v.validate(array, res);
|
|
62
69
|
expect(schemaRes.errors).eql([]);
|
|
70
|
+
const schemaResRev = v.validate(array.reverse(), res);
|
|
71
|
+
expect(schemaResRev.errors).eql([]);
|
|
63
72
|
});
|
|
64
73
|
it('Object of primitives', () => {
|
|
65
74
|
const obj = { 'name':'arnon', 'age':48, 'isAntar':true };
|
|
@@ -67,16 +76,13 @@ suite('JSON Schema generator', () => {
|
|
|
67
76
|
'type': 'object',
|
|
68
77
|
'properties': {
|
|
69
78
|
'name': {
|
|
70
|
-
'type': 'string'
|
|
71
|
-
'const': 'arnon'
|
|
79
|
+
'type': 'string'
|
|
72
80
|
},
|
|
73
81
|
'age': {
|
|
74
|
-
'type': 'number'
|
|
75
|
-
'const': 48
|
|
82
|
+
'type': 'number'
|
|
76
83
|
},
|
|
77
84
|
'isAntar': {
|
|
78
|
-
'type': 'boolean'
|
|
79
|
-
'const': true
|
|
85
|
+
'type': 'boolean'
|
|
80
86
|
}
|
|
81
87
|
}
|
|
82
88
|
};
|
|
@@ -86,7 +92,7 @@ suite('JSON Schema generator', () => {
|
|
|
86
92
|
const schemaRes = v.validate(obj, res);
|
|
87
93
|
expect(schemaRes.errors).eql([]);
|
|
88
94
|
});
|
|
89
|
-
it('Array of objects', () => {
|
|
95
|
+
it('Array of similar objects', () => {
|
|
90
96
|
const array = [{ 'street': 'Arnon', 'building': 42 }, { 'street': 'Yochai', 'building': 77 }];
|
|
91
97
|
const expected = {
|
|
92
98
|
'type': 'array',
|
|
@@ -96,25 +102,52 @@ suite('JSON Schema generator', () => {
|
|
|
96
102
|
'type': 'object',
|
|
97
103
|
'properties': {
|
|
98
104
|
'street': {
|
|
99
|
-
'type': 'string'
|
|
100
|
-
'const': 'Arnon'
|
|
105
|
+
'type': 'string'
|
|
101
106
|
},
|
|
102
107
|
'building': {
|
|
103
|
-
'type': 'number'
|
|
104
|
-
|
|
108
|
+
'type': 'number'
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
]
|
|
113
|
+
}
|
|
114
|
+
};
|
|
115
|
+
const res = generateJSONSchema(array);
|
|
116
|
+
expect(res).eql(expected);
|
|
117
|
+
|
|
118
|
+
const schemaRes = v.validate(array, res);
|
|
119
|
+
expect(schemaRes.errors).eql([]);
|
|
120
|
+
const schemaResRev = v.validate(array.reverse(), res);
|
|
121
|
+
expect(schemaResRev.errors).eql([]);
|
|
122
|
+
});
|
|
123
|
+
it('Array of different types of objects', () => {
|
|
124
|
+
const array = [
|
|
125
|
+
{ a: 1 },
|
|
126
|
+
{ a: 2 },
|
|
127
|
+
{ a: 3 },
|
|
128
|
+
{ a: 4 },
|
|
129
|
+
{ b: 5 },
|
|
130
|
+
{ b: 6 },
|
|
131
|
+
{ b: 7 },
|
|
132
|
+
{ b: 8 },
|
|
133
|
+
];
|
|
134
|
+
const expected = {
|
|
135
|
+
'type': 'array',
|
|
136
|
+
'items': {
|
|
137
|
+
'anyOf': [
|
|
138
|
+
{
|
|
139
|
+
'type': 'object',
|
|
140
|
+
'properties': {
|
|
141
|
+
'a': {
|
|
142
|
+
'type': 'number'
|
|
105
143
|
}
|
|
106
144
|
}
|
|
107
145
|
},
|
|
108
146
|
{
|
|
109
147
|
'type': 'object',
|
|
110
148
|
'properties': {
|
|
111
|
-
'
|
|
112
|
-
'type': '
|
|
113
|
-
'const': 'Yochai'
|
|
114
|
-
},
|
|
115
|
-
'building': {
|
|
116
|
-
'type': 'number',
|
|
117
|
-
'const': 77
|
|
149
|
+
'b': {
|
|
150
|
+
'type': 'number'
|
|
118
151
|
}
|
|
119
152
|
}
|
|
120
153
|
}
|
|
@@ -126,6 +159,8 @@ suite('JSON Schema generator', () => {
|
|
|
126
159
|
|
|
127
160
|
const schemaRes = v.validate(array, res);
|
|
128
161
|
expect(schemaRes.errors).eql([]);
|
|
162
|
+
const schemaResRev = v.validate(array.reverse(), res);
|
|
163
|
+
expect(schemaResRev.errors).eql([]);
|
|
129
164
|
});
|
|
130
165
|
it('Mixed object', () => {
|
|
131
166
|
const obj = {
|
|
@@ -142,24 +177,20 @@ suite('JSON Schema generator', () => {
|
|
|
142
177
|
'type': 'object',
|
|
143
178
|
'properties': {
|
|
144
179
|
'foo': {
|
|
145
|
-
'type': 'number'
|
|
146
|
-
'const': 123
|
|
180
|
+
'type': 'number'
|
|
147
181
|
},
|
|
148
182
|
'bar': {
|
|
149
183
|
'type': 'object',
|
|
150
184
|
'properties': {
|
|
151
185
|
'x': {
|
|
152
|
-
'type': 'number'
|
|
153
|
-
'const': 1
|
|
186
|
+
'type': 'number'
|
|
154
187
|
},
|
|
155
188
|
'y': {
|
|
156
|
-
'type': 'string'
|
|
157
|
-
'const': 'one'
|
|
189
|
+
'type': 'string'
|
|
158
190
|
},
|
|
159
191
|
'null': {},
|
|
160
192
|
'yes': {
|
|
161
|
-
'type': 'boolean'
|
|
162
|
-
'const': true
|
|
193
|
+
'type': 'boolean'
|
|
163
194
|
}
|
|
164
195
|
}
|
|
165
196
|
},
|
|
@@ -168,21 +199,15 @@ suite('JSON Schema generator', () => {
|
|
|
168
199
|
'items': {
|
|
169
200
|
'anyOf': [
|
|
170
201
|
{
|
|
171
|
-
'type': 'number'
|
|
172
|
-
'const': 1
|
|
173
|
-
},
|
|
174
|
-
{
|
|
175
|
-
'type': 'number',
|
|
176
|
-
'const': 2
|
|
202
|
+
'type': 'number'
|
|
177
203
|
},
|
|
178
204
|
{
|
|
179
205
|
'type': 'array',
|
|
180
206
|
'items': {
|
|
181
|
-
'anyOf':
|
|
207
|
+
'anyOf':
|
|
182
208
|
[
|
|
183
209
|
{
|
|
184
|
-
'type': 'number'
|
|
185
|
-
'const': 3
|
|
210
|
+
'type': 'number'
|
|
186
211
|
}
|
|
187
212
|
]
|
|
188
213
|
}
|