systemview 1.6.2 → 1.7.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 +1 -1
- package/api/Connections.js +3 -4
- package/api/connections.txt +1 -1
- package/api/index.js +32 -10
- package/build/asset-manifest.json +3 -3
- package/build/index.html +1 -1
- package/build/static/js/{main.a47760bc.chunk.js → main.6f3c8138.chunk.js} +2 -2
- package/build/static/js/main.6f3c8138.chunk.js.map +1 -0
- package/cli/appIsRunning.js +1 -2
- package/cli/index.js +51 -6
- package/cli/launchApp.js +12 -38
- package/cli/runTests.js +86 -33
- package/cli/startLineReader.js +12 -7
- package/package.json +2 -1
- package/testing-utilities/Argument.class.js +90 -0
- package/testing-utilities/FullTestController.js +78 -0
- package/testing-utilities/Test.class.js +162 -0
- package/testing-utilities/TestController.class.js +134 -0
- package/testing-utilities/test-helpers.js +149 -0
- package/testing-utilities/transformTests.js +56 -0
- package/testing-utilities/validators.js +228 -0
- package/testing-utilities/validtionMessages.js +45 -0
- package/build/static/js/main.a47760bc.chunk.js.map +0 -1
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
const moment = require("moment");
|
|
2
|
+
const {
|
|
3
|
+
arr,
|
|
4
|
+
obj,
|
|
5
|
+
parseIndex,
|
|
6
|
+
replaceLastIndex,
|
|
7
|
+
switchArrayIndices,
|
|
8
|
+
getType,
|
|
9
|
+
} = require("./test-helpers");
|
|
10
|
+
|
|
11
|
+
function evaluate(value, namespace, savedEval = {}, shouldSave) {
|
|
12
|
+
const type = getType(value);
|
|
13
|
+
const validations = savedEval.validations || [];
|
|
14
|
+
const expected_type = savedEval.expected_type || type;
|
|
15
|
+
const save = shouldSave || !!savedEval.save;
|
|
16
|
+
const indexed = savedEval.indexed;
|
|
17
|
+
const errors = getErrors({ type, value, validations, expected_type });
|
|
18
|
+
return {
|
|
19
|
+
namespace,
|
|
20
|
+
expected_type,
|
|
21
|
+
validations,
|
|
22
|
+
save,
|
|
23
|
+
indexed,
|
|
24
|
+
type,
|
|
25
|
+
value,
|
|
26
|
+
errors,
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function validateResults() {
|
|
31
|
+
const { results, response_type, savedEvaluations, editMode } = this;
|
|
32
|
+
const savedEvalClone = [...savedEvaluations];
|
|
33
|
+
const shouldSave = !savedEvaluations.length;
|
|
34
|
+
const evaluations = [];
|
|
35
|
+
const errors = [];
|
|
36
|
+
|
|
37
|
+
function getSavedIndices(data, nsp) {
|
|
38
|
+
const randomIndex = () => {
|
|
39
|
+
// get all matching indices and rename them
|
|
40
|
+
// so they can be found later during getSavedEval
|
|
41
|
+
const index = arr(data).randomIndex();
|
|
42
|
+
const new_nsp = replaceLastIndex(nsp, index);
|
|
43
|
+
savedEvalClone.forEach((e) => {
|
|
44
|
+
if (!e.indexed) e.namespace = switchArrayIndices(e.namespace, new_nsp);
|
|
45
|
+
});
|
|
46
|
+
return index;
|
|
47
|
+
};
|
|
48
|
+
const savedIndices = savedEvalClone
|
|
49
|
+
.filter(({ namespace }) => {
|
|
50
|
+
return replaceLastIndex(namespace) === nsp;
|
|
51
|
+
})
|
|
52
|
+
.map((e) => {
|
|
53
|
+
if (e.indexed) {
|
|
54
|
+
return parseIndex(e.namespace);
|
|
55
|
+
} else {
|
|
56
|
+
return randomIndex();
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
return savedIndices.length ? savedIndices : [randomIndex()];
|
|
60
|
+
}
|
|
61
|
+
const getSavedEval = (nsp) => {
|
|
62
|
+
const i = savedEvalClone.findIndex(({ namespace }) => {
|
|
63
|
+
return replaceLastIndex(namespace) === replaceLastIndex(nsp);
|
|
64
|
+
});
|
|
65
|
+
return i > -1 ? savedEvalClone.splice(i, 1)[0] : {};
|
|
66
|
+
};
|
|
67
|
+
const addEvaluation = (evaluation) => {
|
|
68
|
+
evaluation.errors.forEach(
|
|
69
|
+
(e) => evaluation.save && errors.push({ ...e, namespace: evaluation.namespace })
|
|
70
|
+
);
|
|
71
|
+
evaluations.push(evaluation);
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
//evaluate based on the result only in edit mode
|
|
75
|
+
if (editMode)
|
|
76
|
+
(function recursiveEval(data, namespace) {
|
|
77
|
+
const evaluation = evaluate(data, namespace, getSavedEval(namespace), shouldSave);
|
|
78
|
+
addEvaluation(evaluation);
|
|
79
|
+
if (evaluation.type === "object") {
|
|
80
|
+
Object.getOwnPropertyNames(data).forEach((prop) => {
|
|
81
|
+
recursiveEval(data[prop], `${namespace}.${prop}`);
|
|
82
|
+
});
|
|
83
|
+
} else if (evaluation.type === "array") {
|
|
84
|
+
const indices = getSavedIndices(data, `${namespace}[0]`);
|
|
85
|
+
indices.forEach((index) => recursiveEval(data[index], `${namespace}[${index}]`));
|
|
86
|
+
}
|
|
87
|
+
})(results, response_type);
|
|
88
|
+
|
|
89
|
+
//evaluate based on the saved evaluations
|
|
90
|
+
const objParser = new obj({ [response_type]: results });
|
|
91
|
+
savedEvalClone.forEach(({ namespace, ...e }) => {
|
|
92
|
+
const value = objParser.valueAtNsp(namespace);
|
|
93
|
+
if (e.save) addEvaluation(evaluate(value, namespace, e));
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
Object.assign(this, {
|
|
97
|
+
evaluations: evaluations.sort((e1, e2) => e1.namespace.localeCompare(e2.namespace)),
|
|
98
|
+
errors,
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
function getErrors({ type, value, validations, expected_type }) {
|
|
103
|
+
if (type !== expected_type && expected_type !== "mixed")
|
|
104
|
+
return [{ name: "typeError", expected: expected_type, received: type }];
|
|
105
|
+
|
|
106
|
+
switch (type) {
|
|
107
|
+
case "number":
|
|
108
|
+
return validateNumber(value, validations);
|
|
109
|
+
case "date":
|
|
110
|
+
return validateDate(value, validations);
|
|
111
|
+
case "string":
|
|
112
|
+
return validateString(value, validations);
|
|
113
|
+
case "array":
|
|
114
|
+
return validateArray(value, validations);
|
|
115
|
+
case "boolean":
|
|
116
|
+
return validateBoolean(value, validations);
|
|
117
|
+
case "null":
|
|
118
|
+
case "undefined":
|
|
119
|
+
default:
|
|
120
|
+
return [];
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
const defaultValue = (data_type) => {
|
|
125
|
+
switch (data_type) {
|
|
126
|
+
case "string":
|
|
127
|
+
return "";
|
|
128
|
+
case "number":
|
|
129
|
+
return 0;
|
|
130
|
+
case "date":
|
|
131
|
+
return moment().toJSON();
|
|
132
|
+
case "boolean":
|
|
133
|
+
return false;
|
|
134
|
+
case "array":
|
|
135
|
+
return [];
|
|
136
|
+
case "object":
|
|
137
|
+
return {};
|
|
138
|
+
case "null":
|
|
139
|
+
return null;
|
|
140
|
+
case "target":
|
|
141
|
+
return "";
|
|
142
|
+
case "undefined":
|
|
143
|
+
default:
|
|
144
|
+
return undefined;
|
|
145
|
+
}
|
|
146
|
+
};
|
|
147
|
+
|
|
148
|
+
const validateLength = (item, validations) =>
|
|
149
|
+
validations.reduce((errors, { name, value }) => {
|
|
150
|
+
if (name === "lengthEquals" && item.length !== value)
|
|
151
|
+
return errors.concat({ name, expected: value, received: item.length });
|
|
152
|
+
if (name === "maxLength" && item.length > value)
|
|
153
|
+
return errors.concat({ name, expected: value, received: item.length });
|
|
154
|
+
if (name === "minLength" && item.length < value)
|
|
155
|
+
return errors.concat({ name, expected: value, received: item.length });
|
|
156
|
+
return errors;
|
|
157
|
+
}, []);
|
|
158
|
+
|
|
159
|
+
const validateArray = (arr, validations) =>
|
|
160
|
+
validations.reduce((errors, { name, value }) => {
|
|
161
|
+
if (name === "includes" && !arr.includes(value))
|
|
162
|
+
return errors.concat({ name, expected: value, received: arr });
|
|
163
|
+
return errors;
|
|
164
|
+
}, validateLength(arr, validations));
|
|
165
|
+
|
|
166
|
+
const validateString = (str, validations) =>
|
|
167
|
+
validations.reduce((errors, { name, value }) => {
|
|
168
|
+
if (name === "strEquals" && str !== value)
|
|
169
|
+
return errors.concat({ name, expected: value, received: str });
|
|
170
|
+
//str.match() returns null when there is no match
|
|
171
|
+
if ((name === "isLike") & !str.match(new RegExp(value, "gi")))
|
|
172
|
+
return errors.concat({ name, expected: value, received: str });
|
|
173
|
+
if (
|
|
174
|
+
name === "isOneOf" &&
|
|
175
|
+
typeof value === "string" &&
|
|
176
|
+
!value
|
|
177
|
+
.split(",")
|
|
178
|
+
.map((v) => v.trim())
|
|
179
|
+
.includes(str)
|
|
180
|
+
)
|
|
181
|
+
return errors.concat({ name, expected: value, received: str });
|
|
182
|
+
return errors;
|
|
183
|
+
}, validateLength(str, validations));
|
|
184
|
+
|
|
185
|
+
const validateNumber = (num, validations) =>
|
|
186
|
+
validations.reduce((errors, { name, value }) => {
|
|
187
|
+
if (name === "numEquals" && num !== value)
|
|
188
|
+
return errors.concat({ name, expected: value, received: num });
|
|
189
|
+
if (name === "max" && num > value)
|
|
190
|
+
return errors.concat({ name, expected: value, received: num });
|
|
191
|
+
if (name === "min" && num < value)
|
|
192
|
+
return errors.concat({ name, expected: value, received: num });
|
|
193
|
+
if (
|
|
194
|
+
name === "isOneOf" &&
|
|
195
|
+
typeof value === "string" &&
|
|
196
|
+
!value
|
|
197
|
+
.split(",")
|
|
198
|
+
.map((v) => parseInt(v))
|
|
199
|
+
.includes(num)
|
|
200
|
+
)
|
|
201
|
+
return errors.concat({ name, expected: value, received: num });
|
|
202
|
+
return errors;
|
|
203
|
+
}, []);
|
|
204
|
+
|
|
205
|
+
const validateBoolean = (bool, validations) =>
|
|
206
|
+
validations.reduce((errors, { name, value }) => {
|
|
207
|
+
if (name === "boolEquals" && bool !== value)
|
|
208
|
+
return errors.concat({ name, expected: value, received: bool });
|
|
209
|
+
return errors;
|
|
210
|
+
}, []);
|
|
211
|
+
|
|
212
|
+
const validateDate = (datetime, validations) =>
|
|
213
|
+
validations.reduce((errors, { name, value }) => {
|
|
214
|
+
if (name === "dateEquals" && !moment(datetime).isSame(value))
|
|
215
|
+
return errors.concat({ name, expected: value, received: datetime });
|
|
216
|
+
if (name === "maxDate" && moment(datetime).isAfter(value))
|
|
217
|
+
return errors.concat({ name, expected: value, received: datetime });
|
|
218
|
+
if (name === "minDate" && moment(datetime).isBefore(value))
|
|
219
|
+
return errors.concat({ name, expected: value, received: datetime });
|
|
220
|
+
return errors;
|
|
221
|
+
}, []);
|
|
222
|
+
|
|
223
|
+
module.exports = {
|
|
224
|
+
evaluate,
|
|
225
|
+
validateResults,
|
|
226
|
+
getErrors,
|
|
227
|
+
defaultValue,
|
|
228
|
+
};
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
const moment = require("moment/moment");
|
|
2
|
+
|
|
3
|
+
const vowels = ["a", "e", "i", "o", "u"];
|
|
4
|
+
const isVowel = (str) => vowels.includes((str + "").toLowerCase());
|
|
5
|
+
const an = (word) =>
|
|
6
|
+
word + "" === "undefined" ? "" : isVowel((word + "")[0]) ? "an" : "a";
|
|
7
|
+
|
|
8
|
+
module.exports = function validationMessage({ name, namespace, expected, received }) {
|
|
9
|
+
return errorMessages[name](namespace, expected, received);
|
|
10
|
+
};
|
|
11
|
+
const errorMessages = {
|
|
12
|
+
typeError: (namespace, expected, received) => {
|
|
13
|
+
const a = isVowel(expected) ? "an" : "a";
|
|
14
|
+
return `Expected ${namespace}to be ${a} ${expected}, received ${received}`;
|
|
15
|
+
},
|
|
16
|
+
|
|
17
|
+
lengthEquals: (namespace, expected, received) =>
|
|
18
|
+
`Expected ${namespace} to have a length of ${expected}, received ${received}`,
|
|
19
|
+
maxLength: (namespace, expected, received) =>
|
|
20
|
+
`Expected ${namespace} to have a maximum length of ${expected}, received ${received}`,
|
|
21
|
+
minLength: (namespace, expected, received) =>
|
|
22
|
+
`Expected ${namespace} to have a minimum length of ${expected}, received ${received}`,
|
|
23
|
+
includes: (namespace, expected, received) =>
|
|
24
|
+
`Expected ${namespace} to include the following value: ${expected}, received ${received}`,
|
|
25
|
+
isLike: (namespace, expected, received) =>
|
|
26
|
+
`Expected ${namespace} to be like the following expression: ${expected}, received ${received}`,
|
|
27
|
+
isOneOf: (namespace, expected, received) =>
|
|
28
|
+
`Expected ${namespace} to be one of the following values: ${expected}, received ${received}`,
|
|
29
|
+
strEquals: (namespace, expected, received) =>
|
|
30
|
+
`Expected ${namespace} to equal "${expected}"`,
|
|
31
|
+
numEquals: (namespace, expected, received) =>
|
|
32
|
+
`Expected ${namespace} to equal ${expected}, received ${received}`,
|
|
33
|
+
max: (namespace, expected, received) =>
|
|
34
|
+
`Expected ${namespace} to be less than ${expected}, received ${received}`,
|
|
35
|
+
min: (namespace, expected, received) =>
|
|
36
|
+
`Expected ${namespace} to be greater than ${expected}, received ${received}`,
|
|
37
|
+
boolEquals: (namespace, expected, received) =>
|
|
38
|
+
`Expected ${namespace} to be ${expected.toString()}`,
|
|
39
|
+
dateEquals: (namespace, expected, received) =>
|
|
40
|
+
`Expected ${namespace} to be ${moment(expected).format()}`,
|
|
41
|
+
minDate: (namespace, expected, received) =>
|
|
42
|
+
`Expected ${namespace} to be a date/time later than ${expected}, received ${received}`,
|
|
43
|
+
maxDate: (namespace, expected, received) =>
|
|
44
|
+
`Expected ${namespace} to be a date/time earlier than ${expected}, received ${received}`,
|
|
45
|
+
};
|