systemview 1.6.2 → 1.6.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/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 +148 -0
- package/testing-utilities/transformTests.js +56 -0
- package/testing-utilities/validators.js +228 -0
- package/testing-utilities/validtionMessages.js +45 -0
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "systemview",
|
|
3
3
|
"description": "A documentation and testing suite for SystemLynx",
|
|
4
|
-
"version": "1.6.
|
|
4
|
+
"version": "1.6.3",
|
|
5
5
|
"license": "UNLICENSED",
|
|
6
6
|
"bin": {
|
|
7
7
|
"systemview": "cli/index.js"
|
|
@@ -83,6 +83,7 @@
|
|
|
83
83
|
"cli/",
|
|
84
84
|
"api/",
|
|
85
85
|
"build/",
|
|
86
|
+
"testing-utilities",
|
|
86
87
|
"server.js"
|
|
87
88
|
]
|
|
88
89
|
}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
const {
|
|
2
|
+
isTargetValueFn,
|
|
3
|
+
isTargetNamespace,
|
|
4
|
+
targetValueFnRegex,
|
|
5
|
+
obj,
|
|
6
|
+
isEqualArrays,
|
|
7
|
+
isFunction,
|
|
8
|
+
strFn,
|
|
9
|
+
} = require("./test-helpers");
|
|
10
|
+
|
|
11
|
+
function TargetValue(target_namespace, source_map = [], source_index = 0) {
|
|
12
|
+
this.target_namespace = target_namespace;
|
|
13
|
+
this.source_map = source_map;
|
|
14
|
+
this.source_index = source_index;
|
|
15
|
+
}
|
|
16
|
+
function Argument(name, FullTest, input_type = "undefined", input, targetValues = []) {
|
|
17
|
+
this.name = name;
|
|
18
|
+
this.input = input;
|
|
19
|
+
this.input_type = input_type;
|
|
20
|
+
this.data_type = "";
|
|
21
|
+
this.targetValues = targetValues;
|
|
22
|
+
|
|
23
|
+
this.value = () => {
|
|
24
|
+
return this.targetValues.reduce((arg, { source_map, target_namespace: nsp }) => {
|
|
25
|
+
const [value, placeholder, key] = obj(arg).parse(source_map);
|
|
26
|
+
|
|
27
|
+
if (isTargetValueFn(nsp)) {
|
|
28
|
+
placeholder[key] = value
|
|
29
|
+
.trim()
|
|
30
|
+
.replace(nsp, getTargetValue(nsp.substring(3, nsp.length - 1)));
|
|
31
|
+
} else if (isTargetNamespace(nsp)) {
|
|
32
|
+
placeholder[key] = getTargetValue(nsp);
|
|
33
|
+
} else {
|
|
34
|
+
placeholder[key] = strFn(nsp);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
return arg;
|
|
38
|
+
//creating a deep copy in order to lose refs to original
|
|
39
|
+
}, obj(this).clone()).input;
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
this.parseTargetValues = (input, source_map) => {
|
|
43
|
+
//extract one or more target replacer text from string (i.e. "tv(beforeTest.Action1.error)")
|
|
44
|
+
Array.from(input.matchAll(targetValueFnRegex)).forEach((match) => {
|
|
45
|
+
this.addTargetValue(match[0], source_map, match.index);
|
|
46
|
+
});
|
|
47
|
+
if (isTargetNamespace(input) || isFunction(input))
|
|
48
|
+
this.addTargetValue(input, source_map, 0);
|
|
49
|
+
|
|
50
|
+
return this;
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
this.checkTargetNamespaces = () => {
|
|
54
|
+
// check target namespaces against current input for deletion
|
|
55
|
+
//keep if the target value string still exist on this.input...
|
|
56
|
+
this.targetValues = this.targetValues.filter(
|
|
57
|
+
({ target_namespace, source_map, source_index }) => {
|
|
58
|
+
const value = obj(this).valueAt(source_map);
|
|
59
|
+
return (
|
|
60
|
+
typeof value === "string" &&
|
|
61
|
+
value.indexOf(target_namespace, source_index) === source_index
|
|
62
|
+
);
|
|
63
|
+
}
|
|
64
|
+
);
|
|
65
|
+
return this;
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
this.addTargetValue = (target_namespace, source_map = [], source_index) => {
|
|
69
|
+
//check to see if target value already exists first
|
|
70
|
+
this.targetValues.findIndex(
|
|
71
|
+
(tv) =>
|
|
72
|
+
tv.target_namespace === target_namespace &&
|
|
73
|
+
isEqualArrays(tv.source_map, source_map) &&
|
|
74
|
+
tv.source_index === source_index
|
|
75
|
+
) === -1 &&
|
|
76
|
+
this.targetValues.push(new TargetValue(target_namespace, source_map, source_index));
|
|
77
|
+
return this;
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
const getTargetValue = (input) => {
|
|
81
|
+
const [test, action] = input.split(".");
|
|
82
|
+
const nsp = input
|
|
83
|
+
.replace(test, { beforeTest: 0, mainTest: 1, Events: 2, afterTest: 3 }[test])
|
|
84
|
+
.replace(action, parseInt(action.replace("Action", "")) - 1)
|
|
85
|
+
.replace("error", "results");
|
|
86
|
+
return obj(FullTest).valueAtNsp(nsp);
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
module.exports = { Argument, TargetValue, default: Argument };
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
const Test = require("./Test.class");
|
|
2
|
+
|
|
3
|
+
const sections = ["Before", "Main", "Events", "After"];
|
|
4
|
+
|
|
5
|
+
module.exports = function FullTestController({ FullTest, connectedServices } = {}) {
|
|
6
|
+
this.runFullTest = async ([Before, Main, Events, After] = FullTest || [], Logger) => {
|
|
7
|
+
Events.forEach((test) => test.runTest());
|
|
8
|
+
|
|
9
|
+
await new Promise((resolve) => {
|
|
10
|
+
function recursiveRunTest(tests, i = 0) {
|
|
11
|
+
if (i === tests.length) resolve();
|
|
12
|
+
else tests[i].runTest(Logger).then(() => recursiveRunTest(tests, i + 1));
|
|
13
|
+
}
|
|
14
|
+
recursiveRunTest([...Before, ...Main, ...After]);
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
return [Before, Main, Events, After];
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
function validateTest({ title, evaluations, shouldValidate }, section, index) {
|
|
21
|
+
if (!title)
|
|
22
|
+
return {
|
|
23
|
+
message: `${sections[section]}: Action ${index + 1} description is required`,
|
|
24
|
+
error: true,
|
|
25
|
+
};
|
|
26
|
+
if (shouldValidate && !evaluations.filter((e) => e.save).length)
|
|
27
|
+
return {
|
|
28
|
+
message: `${sections[section]}: Action ${index + 1} validations required`,
|
|
29
|
+
error: true,
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
return { error: false };
|
|
33
|
+
}
|
|
34
|
+
this.saveTests = async (Tests = FullTest) => {
|
|
35
|
+
const { title, getConnection, namespace, index } = Tests[1][0];
|
|
36
|
+
|
|
37
|
+
for (let i = 0; i < Tests.length; i++) {
|
|
38
|
+
for (let x = 0; x < Tests.length; x++) {
|
|
39
|
+
const res = Tests[i][x] ? validateTest(Tests[i][x], i, x) : {};
|
|
40
|
+
if (res.error) return res;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const { connection } = getConnection(connectedServices);
|
|
45
|
+
|
|
46
|
+
const { Plugin } = connection[namespace.serviceId];
|
|
47
|
+
|
|
48
|
+
if (Plugin) {
|
|
49
|
+
const [Before, Main, Events, After] = Tests.map((testSection) =>
|
|
50
|
+
testSection.map((test) => {
|
|
51
|
+
const { args, evaluations, namespace, title } = test;
|
|
52
|
+
//resetting scope of test
|
|
53
|
+
Object.assign(test, new Test(test));
|
|
54
|
+
return {
|
|
55
|
+
args,
|
|
56
|
+
namespace,
|
|
57
|
+
title,
|
|
58
|
+
savedEvaluations: evaluations
|
|
59
|
+
.filter((e) => e.save)
|
|
60
|
+
.map(({ namespace, expected_type, validations, save, indexed }) => ({
|
|
61
|
+
namespace,
|
|
62
|
+
expected_type,
|
|
63
|
+
validations,
|
|
64
|
+
save,
|
|
65
|
+
indexed,
|
|
66
|
+
})),
|
|
67
|
+
};
|
|
68
|
+
})
|
|
69
|
+
);
|
|
70
|
+
|
|
71
|
+
const testIndex = await Plugin.saveTest(
|
|
72
|
+
{ Before, Main, Events, After, title, namespace },
|
|
73
|
+
index
|
|
74
|
+
);
|
|
75
|
+
return { message: "Test Saved!", error: false, testIndex };
|
|
76
|
+
} else return { message: "Plugin Plugin not connected!", error: true };
|
|
77
|
+
};
|
|
78
|
+
};
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
const { validateResults } = require("./validators");
|
|
2
|
+
const { Client } = require("systemlynx");
|
|
3
|
+
const moment = require("moment");
|
|
4
|
+
const { getArrayNamespaces, getLastArrayNamespace, obj } = require("./test-helpers");
|
|
5
|
+
|
|
6
|
+
module.exports = function Test({
|
|
7
|
+
namespace,
|
|
8
|
+
args,
|
|
9
|
+
title,
|
|
10
|
+
shouldValidate = false,
|
|
11
|
+
savedEvaluations = [],
|
|
12
|
+
index,
|
|
13
|
+
editMode = true,
|
|
14
|
+
}) {
|
|
15
|
+
this.index = index;
|
|
16
|
+
this.connection = {};
|
|
17
|
+
this.title = title;
|
|
18
|
+
this.args = args || [];
|
|
19
|
+
this.editMode = editMode;
|
|
20
|
+
this.shouldValidate = shouldValidate || !!savedEvaluations.length;
|
|
21
|
+
this.namespace = namespace || {
|
|
22
|
+
serviceId: "",
|
|
23
|
+
moduleName: "",
|
|
24
|
+
methodName: "",
|
|
25
|
+
};
|
|
26
|
+
this.clearResults = () => {
|
|
27
|
+
this.results = null;
|
|
28
|
+
this.response_type = "";
|
|
29
|
+
this.test_start = null;
|
|
30
|
+
this.test_end = null;
|
|
31
|
+
this.evaluations = [];
|
|
32
|
+
this.savedEvaluations = obj(savedEvaluations).clone();
|
|
33
|
+
this.errors = [];
|
|
34
|
+
return this;
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
this.clearResults();
|
|
38
|
+
|
|
39
|
+
this.getErrors = () => {
|
|
40
|
+
this.errors = this.evaluations
|
|
41
|
+
.filter(({ save }) => save)
|
|
42
|
+
.reduce(
|
|
43
|
+
(sum, { errors, namespace }) =>
|
|
44
|
+
sum.concat(errors.map((e) => ({ ...e, namespace }))),
|
|
45
|
+
[]
|
|
46
|
+
);
|
|
47
|
+
return this.errors;
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
this.validate = validateResults.bind(this);
|
|
51
|
+
|
|
52
|
+
this.runTest = async (_logger) => {
|
|
53
|
+
const logger = _logger || new TestLogger(this);
|
|
54
|
+
const { serviceId, moduleName, methodName } = this.namespace;
|
|
55
|
+
const args = this.args.map((arg) => arg.value());
|
|
56
|
+
|
|
57
|
+
this.test_start = moment().toJSON();
|
|
58
|
+
const Module = this.connection[serviceId][moduleName];
|
|
59
|
+
if (methodName === "on") {
|
|
60
|
+
const eventTest = (e) => {
|
|
61
|
+
this.results = e;
|
|
62
|
+
this.test_end = moment().toJSON();
|
|
63
|
+
this.response_type = "event";
|
|
64
|
+
this.shouldValidate && this.validate();
|
|
65
|
+
logger.end(this);
|
|
66
|
+
Module.$clearEvent(args[0], "eventTest");
|
|
67
|
+
};
|
|
68
|
+
logger.start(args);
|
|
69
|
+
Module.on(args[0], eventTest);
|
|
70
|
+
} else {
|
|
71
|
+
try {
|
|
72
|
+
logger.start(args);
|
|
73
|
+
this.results = await Module[methodName](...args);
|
|
74
|
+
this.test_end = moment().toJSON();
|
|
75
|
+
this.response_type = "results";
|
|
76
|
+
this.shouldValidate && this.validate();
|
|
77
|
+
logger.end(this);
|
|
78
|
+
} catch (error) {
|
|
79
|
+
this.test_end = moment().toJSON();
|
|
80
|
+
this.results = error;
|
|
81
|
+
this.response_type = "error";
|
|
82
|
+
this.shouldValidate && this.validate();
|
|
83
|
+
logger.end(this);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
return this;
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
this.getConnection = (connectedServices) => {
|
|
90
|
+
const { serviceId } = this.namespace;
|
|
91
|
+
|
|
92
|
+
if (connectedServices.length > 0) {
|
|
93
|
+
const service = connectedServices.find(
|
|
94
|
+
(service) => service.serviceId === serviceId
|
|
95
|
+
);
|
|
96
|
+
if (!service) {
|
|
97
|
+
console.warn("connection data not found");
|
|
98
|
+
return this;
|
|
99
|
+
}
|
|
100
|
+
const { connectionData } = service.system;
|
|
101
|
+
|
|
102
|
+
this.connection[serviceId] = Client.createService(connectionData);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
return this;
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
this.addEvaluation = (evaluation) => {
|
|
109
|
+
const savedEval = this.savedEvaluations.find(
|
|
110
|
+
({ namespace }) => namespace === evaluation.namespace
|
|
111
|
+
);
|
|
112
|
+
if (savedEval) Object.assign(savedEval, evaluation);
|
|
113
|
+
else this.savedEvaluations.push(evaluation);
|
|
114
|
+
};
|
|
115
|
+
this.removeEvaluation = (namespace) => {
|
|
116
|
+
const index = this.savedEvaluations.findIndex((e) => e.namespace === namespace);
|
|
117
|
+
if (index > -1) return this.savedEvaluations.splice(index, 1)[0];
|
|
118
|
+
else return {};
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
this.addSavedIndices = (arrayNamespace, newArrayNamespace) => {
|
|
122
|
+
//break namespace into multiple array namespaces
|
|
123
|
+
const nspList = getArrayNamespaces(arrayNamespace);
|
|
124
|
+
this.evaluations.forEach((e) => {
|
|
125
|
+
if (nspList.includes(getLastArrayNamespace(e.namespace))) {
|
|
126
|
+
e.namespace = e.namespace.replace(arrayNamespace, newArrayNamespace);
|
|
127
|
+
e.indexed = true;
|
|
128
|
+
e.expected_type = undefined;
|
|
129
|
+
this.addEvaluation(e);
|
|
130
|
+
}
|
|
131
|
+
});
|
|
132
|
+
};
|
|
133
|
+
this.removeSavedIndices = (namespace) => {
|
|
134
|
+
this.savedEvaluations = this.savedEvaluations.filter(
|
|
135
|
+
(e) => !e.namespace.includes(namespace) //|| !e.indexed
|
|
136
|
+
);
|
|
137
|
+
};
|
|
138
|
+
};
|
|
139
|
+
|
|
140
|
+
function TestLogger(test) {
|
|
141
|
+
this.start = (args) => {
|
|
142
|
+
const { serviceId, moduleName, methodName } = test.namespace;
|
|
143
|
+
|
|
144
|
+
console.log(
|
|
145
|
+
`[${moment(this.test_start).format(
|
|
146
|
+
"L LTS"
|
|
147
|
+
)}]> [invoking]:${serviceId}.${moduleName}.${methodName}()`
|
|
148
|
+
);
|
|
149
|
+
console.log.apply({}, ["args:"].concat(args));
|
|
150
|
+
};
|
|
151
|
+
this.end = () => {
|
|
152
|
+
const { serviceId, moduleName, methodName } = test.namespace;
|
|
153
|
+
const { results, response_type } = test;
|
|
154
|
+
console.log(
|
|
155
|
+
`[${moment(this.test_end).format(
|
|
156
|
+
"L LTS"
|
|
157
|
+
)}]> [${response_type}]:${serviceId}.${moduleName}.${methodName}()`,
|
|
158
|
+
`${response_type}:`,
|
|
159
|
+
results
|
|
160
|
+
);
|
|
161
|
+
};
|
|
162
|
+
}
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
const Test = require("./Test.class");
|
|
2
|
+
const { Argument, TargetValue } = require("./Argument.class");
|
|
3
|
+
const { getType } = require("./test-helpers");
|
|
4
|
+
|
|
5
|
+
module.exports = function TestController({
|
|
6
|
+
TestSection,
|
|
7
|
+
setState,
|
|
8
|
+
section,
|
|
9
|
+
FullTest,
|
|
10
|
+
connectedServices,
|
|
11
|
+
}) {
|
|
12
|
+
this.runTest = async (testIndex) => {
|
|
13
|
+
const test = TestSection[testIndex];
|
|
14
|
+
//run only one test
|
|
15
|
+
await test.runTest();
|
|
16
|
+
setState([...TestSection]);
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
this.updateNamespace = (index, namespace) => {
|
|
20
|
+
TestSection[index].namespace = namespace;
|
|
21
|
+
TestSection[index].getConnection(connectedServices);
|
|
22
|
+
setState([...TestSection]);
|
|
23
|
+
};
|
|
24
|
+
this.addTest = (namespace, args, title) => {
|
|
25
|
+
TestSection.push(new Test({ namespace, args, title, editMode: true }));
|
|
26
|
+
setState([...TestSection]);
|
|
27
|
+
if (namespace) this.updateNamespace(TestSection.length - 1, namespace);
|
|
28
|
+
};
|
|
29
|
+
this.deleteTest = (index) => {
|
|
30
|
+
TestSection.splice(index, 1);
|
|
31
|
+
setState([...TestSection]);
|
|
32
|
+
};
|
|
33
|
+
this.addArg = (index) => {
|
|
34
|
+
const name = "arg" + (TestSection[0].args.length + 1);
|
|
35
|
+
TestSection[index].args.push(new Argument(name, FullTest));
|
|
36
|
+
setState([...TestSection]);
|
|
37
|
+
};
|
|
38
|
+
this.deleteArg = (index, arg_index) => {
|
|
39
|
+
TestSection[index].args.splice(arg_index, 1);
|
|
40
|
+
setState([...TestSection]);
|
|
41
|
+
};
|
|
42
|
+
this.editArg = (index, arg_index, arg) => {
|
|
43
|
+
arg.data_type = getType(arg.input);
|
|
44
|
+
TestSection[index].args[arg_index] = arg;
|
|
45
|
+
setState([...TestSection]);
|
|
46
|
+
};
|
|
47
|
+
this.resetResults = (index) => {
|
|
48
|
+
TestSection[index].clearResults();
|
|
49
|
+
setState([...TestSection]);
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
this.addTargetValue = (
|
|
53
|
+
testIndex,
|
|
54
|
+
arg_index,
|
|
55
|
+
target_namespace,
|
|
56
|
+
source_map,
|
|
57
|
+
source_index
|
|
58
|
+
) => {
|
|
59
|
+
//check to see if target value already exists first
|
|
60
|
+
const arg = TestSection[testIndex].args[arg_index];
|
|
61
|
+
arg.addTargetValue(target_namespace, source_map, source_index);
|
|
62
|
+
setState([...TestSection]);
|
|
63
|
+
};
|
|
64
|
+
this.setTargetValue = (
|
|
65
|
+
testIndex,
|
|
66
|
+
arg_index,
|
|
67
|
+
target_index,
|
|
68
|
+
target_namespace,
|
|
69
|
+
source_map,
|
|
70
|
+
source_index
|
|
71
|
+
) => {
|
|
72
|
+
const arg = TestSection[testIndex].args[arg_index];
|
|
73
|
+
|
|
74
|
+
arg.targetValues[target_index] = new TargetValue(
|
|
75
|
+
target_namespace.trim(),
|
|
76
|
+
source_map,
|
|
77
|
+
source_index
|
|
78
|
+
);
|
|
79
|
+
setState([...TestSection]);
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
this.parseTargetValues = (testIndex, arg_index, input, source_map) => {
|
|
83
|
+
const arg = TestSection[testIndex].args[arg_index];
|
|
84
|
+
arg.parseTargetValues(input, source_map).checkTargetNamespaces();
|
|
85
|
+
setState([...TestSection]);
|
|
86
|
+
};
|
|
87
|
+
this.checkTargetValues = (testIndex, arg_index) => {
|
|
88
|
+
const arg = TestSection[testIndex].args[arg_index];
|
|
89
|
+
arg.checkTargetNamespaces();
|
|
90
|
+
setState([...TestSection]);
|
|
91
|
+
};
|
|
92
|
+
this.updateTitle = (testIndex, title) => {
|
|
93
|
+
TestSection[testIndex].title = title;
|
|
94
|
+
setState([...TestSection]);
|
|
95
|
+
};
|
|
96
|
+
this.updateEvaluations = (testIndex, evaluations) => {
|
|
97
|
+
TestSection[testIndex].evaluations = evaluations;
|
|
98
|
+
setState([...TestSection]);
|
|
99
|
+
};
|
|
100
|
+
this.updateTests = () => {
|
|
101
|
+
setState([...TestSection]);
|
|
102
|
+
};
|
|
103
|
+
this.updateValidationStatus = (testIndex) => {
|
|
104
|
+
if (section !== 1) {
|
|
105
|
+
TestSection[testIndex].shouldValidate = !TestSection[testIndex].shouldValidate;
|
|
106
|
+
if (TestSection[testIndex].shouldValidate) TestSection[testIndex].validate();
|
|
107
|
+
else TestSection[testIndex].evaluations = [];
|
|
108
|
+
setState([...TestSection]);
|
|
109
|
+
}
|
|
110
|
+
};
|
|
111
|
+
this.getTargetSuggestions = (testIndex) => {
|
|
112
|
+
//get target value suggestion (namespaces) for previous test including sub test
|
|
113
|
+
const suggestions = [];
|
|
114
|
+
const test_names = ["beforeTest", "mainTest", "afterTest"];
|
|
115
|
+
//exclude all test sections following current section
|
|
116
|
+
const targetTests = FullTest.slice(0, section + 1);
|
|
117
|
+
|
|
118
|
+
targetTests.forEach((test_section, sIndex) => {
|
|
119
|
+
//also exclude current test and the tests that follow by the suggestions
|
|
120
|
+
const count = sIndex === section ? testIndex : test_section.length;
|
|
121
|
+
for (let i = 0; i < count; i++) {
|
|
122
|
+
suggestions.push(
|
|
123
|
+
`${test_names[sIndex]}.${"Action" + (i + 1) + "."}${
|
|
124
|
+
test_section[i].response_type || "results"
|
|
125
|
+
}`
|
|
126
|
+
);
|
|
127
|
+
}
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
return suggestions;
|
|
131
|
+
};
|
|
132
|
+
|
|
133
|
+
return this;
|
|
134
|
+
};
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
const moment = require("moment");
|
|
2
|
+
const rnb = (min, max) => Math.floor(Math.random() * (max - min + 1) + min);
|
|
3
|
+
|
|
4
|
+
const isTargetNamespace = (str) =>
|
|
5
|
+
/^(?:before|main|after)Test\.Action\d+\.(?:error|results)(?:\.(?![0-9])[a-zA-Z0-9$_]+(?:\[\d\])*)*$/.test(
|
|
6
|
+
str
|
|
7
|
+
);
|
|
8
|
+
const targetValueFnRegex =
|
|
9
|
+
/tv\((?:before|main|after)Test\.Action\d+\.(?:error|results)(?:\.(?![0-9])[a-zA-Z0-9$_]+(?:\[\d\])*)*\)/g;
|
|
10
|
+
const isTargetValueFn = (str) =>
|
|
11
|
+
/^tv\((?:before|main|after)Test\.Action\d+\.(?:error|results)(?:\.(?![0-9])[a-zA-Z0-9$_]+(?:\[\d\])*)*\)$/.test(
|
|
12
|
+
str
|
|
13
|
+
);
|
|
14
|
+
const isEqualArrays = (a, b) => a.join(".") === b.join("."); //specifically for arrays of strings
|
|
15
|
+
const isValidNamespace = (str) => /^(?![0-9])[a-zA-Z0-9$_]+$/.test(str); //_id
|
|
16
|
+
const startsWithNameAndArray = (str) => /^\w+(\[\d+\])+/.test(str); //users[0]
|
|
17
|
+
const isNameAndArray = (str) => /^\w+(\[\d+\])+$/.test(str); //users[0]
|
|
18
|
+
const endsWithArrayIndex = (str) => /\w+(\[\d+\])+$/.test(str); //users[0].docs[3]...
|
|
19
|
+
const getLastArrayNamespace = (str) => (str.match(/(\w+(\[\d+\])+)$/) || [str])[0];
|
|
20
|
+
|
|
21
|
+
const parseIndex = (nsp) => parseInt((nsp.match(/\[(\d+)\]$/) || [null, "0"])[1]);
|
|
22
|
+
const replaceFirstIndex = (nsp, insert = "0") => nsp.replace(/(\[\d+\])/, `[${insert}]`);
|
|
23
|
+
const replaceLastIndex = (nsp, insert = "0") => nsp.replace(/(\[\d+\])$/, `[${insert}]`);
|
|
24
|
+
|
|
25
|
+
const replaceAllIndices = (nsp, insert = "0") => nsp.replace(/(\[\d+\])/g, `[${insert}]`);
|
|
26
|
+
|
|
27
|
+
const getArrayNamespaces = (str) =>
|
|
28
|
+
str
|
|
29
|
+
.split(/(\w+(\[\d+\])+)/)
|
|
30
|
+
.filter(isNameAndArray)
|
|
31
|
+
.reduce((sum, nsp) => {
|
|
32
|
+
//split by indexes in case of nested arrays
|
|
33
|
+
const indices = nsp.split(/(\[\d+\])/).filter((n) => n);
|
|
34
|
+
const [name] = indices.splice(0, 1);
|
|
35
|
+
return sum.concat(
|
|
36
|
+
indices.map((index, i) => {
|
|
37
|
+
return name + indices.slice(0, i + 1).join("");
|
|
38
|
+
}, [])
|
|
39
|
+
);
|
|
40
|
+
}, []);
|
|
41
|
+
const switchArrayIndices = (nsp, replace) => {
|
|
42
|
+
// normalize nsp and replace nsp
|
|
43
|
+
const n = replaceAllIndices(nsp);
|
|
44
|
+
const r = replaceAllIndices(replace);
|
|
45
|
+
// match the normalized namespaces
|
|
46
|
+
if (n.substr(0, r.length) === r) {
|
|
47
|
+
// create new namespace by concatenating
|
|
48
|
+
const n = nsp.split(".");
|
|
49
|
+
const r = replace.split(".");
|
|
50
|
+
n.splice(...[0, r.length, ...r]);
|
|
51
|
+
return n.join(".");
|
|
52
|
+
} else return nsp;
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
//separate prop names from other prop names and indices (ie. 'test.results[0][0]'...);
|
|
56
|
+
const mapNamespace = (nsp) =>
|
|
57
|
+
nsp
|
|
58
|
+
.replace(/(?:\.|\[|\])/g, " ")
|
|
59
|
+
.split(" ")
|
|
60
|
+
.reduce((sum, str) => sum.concat(str.trim() || []), []);
|
|
61
|
+
|
|
62
|
+
const obj = function ObjectParser(obj) {
|
|
63
|
+
const parser = this || {};
|
|
64
|
+
parser.parse = (map) =>
|
|
65
|
+
map.reduce(([placeholder], key) => [placeholder?.[key], placeholder, key], [obj]);
|
|
66
|
+
|
|
67
|
+
parser.valueAt = (map) => parser.parse(map)[0];
|
|
68
|
+
|
|
69
|
+
parser.valueAtNsp = (nsp) => parser.valueAt(mapNamespace(nsp));
|
|
70
|
+
|
|
71
|
+
parser.parseNsp = (nsp) => parser.parse(mapNamespace(nsp));
|
|
72
|
+
//using JSON to create a deep copy in order to lose refs to original
|
|
73
|
+
parser.clone = () => JSON.parse(JSON.stringify(obj));
|
|
74
|
+
|
|
75
|
+
parser.isEmpty = () => Object.getOwnPropertyNames(obj).length === 0;
|
|
76
|
+
|
|
77
|
+
return parser;
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
const arr = function ArrayParser(arr) {
|
|
81
|
+
const parser = this || {};
|
|
82
|
+
|
|
83
|
+
parser.randomIndex = () => rnb(0, arr.length - 1);
|
|
84
|
+
|
|
85
|
+
parser.randomItem = () => arr[parser.randomIndex()];
|
|
86
|
+
return parser;
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
const isFn = /^\w+\(([^,)]*(,[^,)]*)*)\)$/;
|
|
90
|
+
const parseArgs = (str) => str.split(",").map((value) => value.trim());
|
|
91
|
+
const isFunction = (str) => isFn.test(str);
|
|
92
|
+
const isDateFunction = (str) => /^[dD]ate\(([^,)]*(,[^,)]*)*)\)$/.test(str);
|
|
93
|
+
|
|
94
|
+
const strFn = (str) => {
|
|
95
|
+
if (isDateFunction(str)) {
|
|
96
|
+
const [fullStr, args] = str.match(isFn);
|
|
97
|
+
return moment(args).toJSON();
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
return str;
|
|
101
|
+
};
|
|
102
|
+
function getType(value) {
|
|
103
|
+
switch (true) {
|
|
104
|
+
case typeof value === "object":
|
|
105
|
+
if (!value) return "null";
|
|
106
|
+
else if (Array.isArray(value)) return "array";
|
|
107
|
+
else return "object";
|
|
108
|
+
case typeof value === "string":
|
|
109
|
+
if (moment(value).isValid()) return "date";
|
|
110
|
+
else return "string";
|
|
111
|
+
case typeof value === "number":
|
|
112
|
+
return "number";
|
|
113
|
+
case typeof value === "boolean":
|
|
114
|
+
return "boolean";
|
|
115
|
+
case typeof value === "undefined":
|
|
116
|
+
return "undefined";
|
|
117
|
+
default:
|
|
118
|
+
return "?";
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
const isObjectLike = (value) =>
|
|
122
|
+
["object", "array", "string"].indexOf(getType(value)) > -1;
|
|
123
|
+
module.exports = {
|
|
124
|
+
rnb,
|
|
125
|
+
isObjectLike,
|
|
126
|
+
isTargetNamespace,
|
|
127
|
+
targetValueFnRegex,
|
|
128
|
+
isTargetValueFn,
|
|
129
|
+
isEqualArrays,
|
|
130
|
+
isValidNamespace,
|
|
131
|
+
startsWithNameAndArray,
|
|
132
|
+
isNameAndArray,
|
|
133
|
+
endsWithArrayIndex,
|
|
134
|
+
getLastArrayNamespace,
|
|
135
|
+
parseIndex,
|
|
136
|
+
replaceFirstIndex,
|
|
137
|
+
replaceLastIndex,
|
|
138
|
+
replaceAllIndices,
|
|
139
|
+
getArrayNamespaces,
|
|
140
|
+
switchArrayIndices,
|
|
141
|
+
mapNamespace,
|
|
142
|
+
obj,
|
|
143
|
+
arr,
|
|
144
|
+
isFunction,
|
|
145
|
+
isDateFunction,
|
|
146
|
+
strFn,
|
|
147
|
+
getType,
|
|
148
|
+
};
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
const { Argument } = require("./Argument.class");
|
|
2
|
+
const Test = require("./Test.class");
|
|
3
|
+
|
|
4
|
+
function initializeSavedTests(savedTests, connectedServices) {
|
|
5
|
+
return savedTests.map((ft) => {
|
|
6
|
+
// context matters
|
|
7
|
+
const newTests = [];
|
|
8
|
+
const { title, namespace } = ft;
|
|
9
|
+
|
|
10
|
+
const Before = ft.Before.map((test) =>
|
|
11
|
+
resetTestClass(test, newTests, connectedServices, false)
|
|
12
|
+
);
|
|
13
|
+
const Main = ft.Main.map((test) =>
|
|
14
|
+
resetTestClass(test, newTests, connectedServices, false)
|
|
15
|
+
);
|
|
16
|
+
const Events = ft.Events.map((test) =>
|
|
17
|
+
resetTestClass(test, newTests, connectedServices, false)
|
|
18
|
+
);
|
|
19
|
+
const After = ft.After.map((test) =>
|
|
20
|
+
resetTestClass(test, newTests, connectedServices, false)
|
|
21
|
+
);
|
|
22
|
+
newTests.push(Before);
|
|
23
|
+
newTests.push(Main);
|
|
24
|
+
newTests.push(Events);
|
|
25
|
+
newTests.push(After);
|
|
26
|
+
return { Before, Main, Events, After, title, namespace };
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const resetTestClass = (test, FullTest, connectedServices, editMode) => {
|
|
31
|
+
return new Test({
|
|
32
|
+
...test,
|
|
33
|
+
args: test.args.map(
|
|
34
|
+
(arg) =>
|
|
35
|
+
new Argument(arg.name, FullTest, arg.input_type, arg.input, arg.targetValues)
|
|
36
|
+
),
|
|
37
|
+
editMode,
|
|
38
|
+
}).getConnection(connectedServices);
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
const resetFullTest = (FullTest, connectedServices, editMode) => {
|
|
42
|
+
//context matters
|
|
43
|
+
const newTests = [[], [], [], []];
|
|
44
|
+
return FullTest.map((section, i) => {
|
|
45
|
+
return section.map((test) => {
|
|
46
|
+
const newTest = resetTestClass(test, newTests, connectedServices, editMode);
|
|
47
|
+
newTests[i].push(newTest);
|
|
48
|
+
return newTest;
|
|
49
|
+
});
|
|
50
|
+
});
|
|
51
|
+
};
|
|
52
|
+
module.exports = {
|
|
53
|
+
initializeSavedTests,
|
|
54
|
+
resetTestClass,
|
|
55
|
+
resetFullTest,
|
|
56
|
+
};
|
|
@@ -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
|
+
};
|