systemview 1.5.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/cli/appIsRunning.js +25 -0
- package/cli/index.js +8 -40
- package/cli/launchApp.js +48 -0
- package/cli/runTests.js +99 -0
- package/cli/startLineReader.js +27 -0
- package/cli/utils/log.js +2 -8
- package/package.json +3 -2
- 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/cli/runTest.js +0 -0
- package/plugin/SystemViewModule.js +0 -97
- package/plugin/getAllTest.js +0 -21
- package/plugin/index.js +0 -40
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
const http = require("http");
|
|
2
|
+
|
|
3
|
+
module.exports = async function appIsRunning(appUrls) {
|
|
4
|
+
let allAppsRunning = true;
|
|
5
|
+
const pingApps = appUrls.map(
|
|
6
|
+
(url) =>
|
|
7
|
+
new Promise((resolve, reject) => {
|
|
8
|
+
http.get(url, resolve).on("error", reject);
|
|
9
|
+
})
|
|
10
|
+
);
|
|
11
|
+
try {
|
|
12
|
+
const responses = await Promise.all(pingApps);
|
|
13
|
+
responses.forEach((res, index) => {
|
|
14
|
+
if (res.statusCode !== 200) {
|
|
15
|
+
allAppsRunning = false;
|
|
16
|
+
console.log(`App ${index + 1} is not running`);
|
|
17
|
+
}
|
|
18
|
+
});
|
|
19
|
+
} catch (err) {
|
|
20
|
+
console.error("Error pinging apps:", err.message);
|
|
21
|
+
allAppsRunning = false;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
return allAppsRunning;
|
|
25
|
+
};
|
package/cli/index.js
CHANGED
|
@@ -10,58 +10,26 @@
|
|
|
10
10
|
const init = require("./utils/init");
|
|
11
11
|
const cli = require("./utils/cli");
|
|
12
12
|
const log = require("./utils/log");
|
|
13
|
-
const { spawn } = require("child_process");
|
|
14
|
-
const path = require("path");
|
|
15
13
|
|
|
16
|
-
const
|
|
14
|
+
const launchApp = require("./launchApp");
|
|
15
|
+
const startLineReader = require("./startLineReader");
|
|
16
|
+
const runTests = require("./runTests");
|
|
17
17
|
|
|
18
18
|
const input = cli.input;
|
|
19
19
|
const flags = cli.flags;
|
|
20
20
|
const { clear, debug } = flags;
|
|
21
21
|
|
|
22
|
-
function startApp() {
|
|
23
|
-
// Start React app
|
|
24
|
-
const arg = parseInt();
|
|
25
|
-
const port = isNaN(arg) ? 3000 : arg;
|
|
26
|
-
const env = Object.create(process.env);
|
|
27
|
-
env.PORT = port;
|
|
28
|
-
log(`Launching SystemView UI @http://localhost:${port}/`);
|
|
29
|
-
const AppProcess = spawn("node", ["server"], {
|
|
30
|
-
stdio: ["inherit"],
|
|
31
|
-
shell: true,
|
|
32
|
-
env,
|
|
33
|
-
cwd: parentDirectory,
|
|
34
|
-
});
|
|
35
|
-
|
|
36
|
-
AppProcess.on("close", (code) => {
|
|
37
|
-
console.log(`React app exited with code ${code}`);
|
|
38
|
-
});
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
function startApi() {
|
|
42
|
-
log(`Launching SystemView API @http://localhost:${3300}/systemview/api`);
|
|
43
|
-
|
|
44
|
-
const AppProcess = spawn("node", ["api"], {
|
|
45
|
-
stdio: ["inherit"],
|
|
46
|
-
shell: true,
|
|
47
|
-
cwd: parentDirectory,
|
|
48
|
-
});
|
|
49
|
-
|
|
50
|
-
AppProcess.on("close", (code) => {
|
|
51
|
-
console.log(`React app exited with code ${code}`);
|
|
52
|
-
});
|
|
53
|
-
}
|
|
54
22
|
(async () => {
|
|
55
23
|
init({ clear });
|
|
56
24
|
if (input.includes(`help`)) {
|
|
57
25
|
cli.showHelp(0);
|
|
58
|
-
}
|
|
59
|
-
if (input[0] === "start") {
|
|
60
|
-
startApi();
|
|
61
|
-
startApp();
|
|
62
26
|
} else if (input.includes("test")) {
|
|
63
|
-
|
|
27
|
+
if (await launchApp()) await runTests(input[1]);
|
|
28
|
+
} else {
|
|
29
|
+
const shutdown = await launchApp();
|
|
30
|
+
if (typeof shutdown === "function") startLineReader(shutdown);
|
|
64
31
|
}
|
|
65
32
|
|
|
33
|
+
cli.input = [];
|
|
66
34
|
debug && log(flags);
|
|
67
35
|
})();
|
package/cli/launchApp.js
CHANGED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
const log = require("./utils/log");
|
|
2
|
+
const { spawn } = require("child_process");
|
|
3
|
+
const path = require("path");
|
|
4
|
+
const appIsRunning = require("./appIsRunning");
|
|
5
|
+
const parentDirectory = path.resolve(__dirname, "..");
|
|
6
|
+
const delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
7
|
+
|
|
8
|
+
function logConnection(api, app) {
|
|
9
|
+
log("connected!", "success");
|
|
10
|
+
console.log(`SystemView API running @${api}`);
|
|
11
|
+
console.log(`SystemView UI running @${app}`);
|
|
12
|
+
}
|
|
13
|
+
module.exports = async function launchApp(_port) {
|
|
14
|
+
const port = isNaN(_port) ? 3000 : _port;
|
|
15
|
+
const env = Object.create(process.env);
|
|
16
|
+
const api = `http://localhost:${3300}/systemview/api`;
|
|
17
|
+
const app = `http://localhost:${port}/`;
|
|
18
|
+
env.PORT = port;
|
|
19
|
+
|
|
20
|
+
if (await appIsRunning([api, app])) {
|
|
21
|
+
log("SystemView is running from another terminal", "info", "info");
|
|
22
|
+
logConnection(api, app);
|
|
23
|
+
return true;
|
|
24
|
+
} else {
|
|
25
|
+
log("Launching...");
|
|
26
|
+
|
|
27
|
+
const appProcess = spawn("node", ["api & node server"], {
|
|
28
|
+
stdio: ["inherit"],
|
|
29
|
+
shell: true,
|
|
30
|
+
env,
|
|
31
|
+
cwd: parentDirectory,
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
appProcess.on("close", (code) => {
|
|
35
|
+
console.log(`SystemView APP exited with code ${code}`);
|
|
36
|
+
});
|
|
37
|
+
const shutdown = () => {
|
|
38
|
+
if (appProcess) appProcess.kill();
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
await delay(2000);
|
|
42
|
+
const isRunning = await appIsRunning([api, app]);
|
|
43
|
+
if (isRunning) {
|
|
44
|
+
logConnection(api, app);
|
|
45
|
+
return shutdown;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
};
|
package/cli/runTests.js
ADDED
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
const { Client } = require("systemlynx");
|
|
2
|
+
const { initializeSavedTests } = require("../testing-utilities/transformTests");
|
|
3
|
+
const FullTestController = require("../testing-utilities/FullTestController");
|
|
4
|
+
const log = require("./utils/log");
|
|
5
|
+
const validationMessages = require("../testing-utilities/validtionMessages");
|
|
6
|
+
module.exports = async function runTests(project_code) {
|
|
7
|
+
if (!project_code) {
|
|
8
|
+
return log("project_code or service_url are required", "warning", "warning");
|
|
9
|
+
}
|
|
10
|
+
// get connected services from the systemview api
|
|
11
|
+
const connectedServices = await getConnectedServices(project_code);
|
|
12
|
+
//get all the test for each service or the targeted services
|
|
13
|
+
if (!connectedServices.length) {
|
|
14
|
+
return log("No connected services found!", "warning");
|
|
15
|
+
} else {
|
|
16
|
+
connectedServices.forEach(({ serviceId, system }) => {
|
|
17
|
+
log(`connected @${system.connectionData.serviceUrl}`, "success", serviceId);
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const Tests = await getTests(connectedServices);
|
|
22
|
+
//transform the test from the saved format to the testing format
|
|
23
|
+
|
|
24
|
+
const executeTest = async (savedTests) => {
|
|
25
|
+
const tests = initializeSavedTests(savedTests, connectedServices);
|
|
26
|
+
await runAllTests(tests);
|
|
27
|
+
};
|
|
28
|
+
(
|
|
29
|
+
await new Promise((resolve) => {
|
|
30
|
+
async function recursiveExecuteTest(i = 0) {
|
|
31
|
+
const { serviceId } = connectedServices[i];
|
|
32
|
+
log(`Initializing Tests...`, "info", serviceId);
|
|
33
|
+
if (i === Tests.length) resolve();
|
|
34
|
+
else executeTest(Tests[0]).then(() => recursiveExecuteTest(i + 1));
|
|
35
|
+
}
|
|
36
|
+
recursiveExecuteTest();
|
|
37
|
+
})
|
|
38
|
+
)();
|
|
39
|
+
};
|
|
40
|
+
const Logger = function (trackTime) {
|
|
41
|
+
this.start = (test) => {
|
|
42
|
+
if (trackTime) {
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
this.end = ({ errors }) => {
|
|
47
|
+
errors.forEach((err) => {
|
|
48
|
+
const msg = validationMessages(err);
|
|
49
|
+
log(msg, "error", err.namespace);
|
|
50
|
+
});
|
|
51
|
+
};
|
|
52
|
+
};
|
|
53
|
+
const { runFullTest } = new FullTestController();
|
|
54
|
+
const runAllTests = async (savedTest) => {
|
|
55
|
+
const runTest = async ({ Before, Main, Events, After }) => {
|
|
56
|
+
const fullTest = [Before, Main, Events, After];
|
|
57
|
+
const [B, M, E, A] = await runFullTest(fullTest, new Logger());
|
|
58
|
+
const { title, namespace } = Main[0];
|
|
59
|
+
return { Before: B, Main: M, Events: E, After: A, title, namespace };
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
await new Promise((resolve) => {
|
|
63
|
+
function recursiveRunTest(i = 0) {
|
|
64
|
+
if (i === savedTest.length) resolve();
|
|
65
|
+
else runTest(savedTest[i]).then(() => recursiveRunTest(i + 1));
|
|
66
|
+
}
|
|
67
|
+
recursiveRunTest();
|
|
68
|
+
});
|
|
69
|
+
};
|
|
70
|
+
async function getTests(connectedServices) {
|
|
71
|
+
return await new Promise(async (resolve) => {
|
|
72
|
+
const results = [];
|
|
73
|
+
|
|
74
|
+
return (async function recursiveGetTests(i = 0) {
|
|
75
|
+
if (i < connectedServices.length) {
|
|
76
|
+
const { connectionData } = connectedServices[1].system;
|
|
77
|
+
try {
|
|
78
|
+
results.push(await Client.createService(connectionData).Plugin.getTests());
|
|
79
|
+
} catch (error) {
|
|
80
|
+
console.log(`Failed to retrieve test from:${connectionData.serviceUrl}`);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
await recursiveGetTests(i + 1);
|
|
84
|
+
} else resolve(results);
|
|
85
|
+
})();
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
async function getConnectedServices(project_code) {
|
|
89
|
+
try {
|
|
90
|
+
const { SystemView } = await Client.loadService(
|
|
91
|
+
"http://localhost:3300/systemview/api"
|
|
92
|
+
);
|
|
93
|
+
try {
|
|
94
|
+
return SystemView.getServices(project_code);
|
|
95
|
+
} catch (error) {}
|
|
96
|
+
} catch (error) {
|
|
97
|
+
console.log("Failed to connect to systemview");
|
|
98
|
+
}
|
|
99
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
const runTests = require("./runTests");
|
|
2
|
+
const cli = require("./utils/cli");
|
|
3
|
+
|
|
4
|
+
const readline = require("readline");
|
|
5
|
+
|
|
6
|
+
module.exports = function startLineReader(shutdown) {
|
|
7
|
+
const lineReader = readline.createInterface({
|
|
8
|
+
input: process.stdin,
|
|
9
|
+
output: process.stdout,
|
|
10
|
+
});
|
|
11
|
+
const handleInput = (input = "") => {
|
|
12
|
+
const [command, argument] = input.split(" ").map((s) => s.trim());
|
|
13
|
+
if (["exit", "q"].includes(command)) {
|
|
14
|
+
shutdown();
|
|
15
|
+
lineReader.close();
|
|
16
|
+
} else if (command === "test") {
|
|
17
|
+
runTests(argument);
|
|
18
|
+
} else if (command === "help") {
|
|
19
|
+
cli.showHelp(0);
|
|
20
|
+
}
|
|
21
|
+
lineReader.prompt();
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
lineReader.prompt();
|
|
25
|
+
lineReader.on("line", handleInput);
|
|
26
|
+
lineReader.on("close", shutdown);
|
|
27
|
+
};
|
package/cli/utils/log.js
CHANGED
|
@@ -1,11 +1,5 @@
|
|
|
1
1
|
const alert = require("cli-alerts");
|
|
2
2
|
|
|
3
|
-
module.exports = (info) => {
|
|
4
|
-
alert({
|
|
5
|
-
type: `info`,
|
|
6
|
-
name: `SystemView`,
|
|
7
|
-
msg: ``,
|
|
8
|
-
});
|
|
9
|
-
|
|
10
|
-
console.log(info);
|
|
3
|
+
module.exports = (msg, type = "info", name = "SystemView") => {
|
|
4
|
+
alert({ type, name, msg });
|
|
11
5
|
};
|
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.
|
|
4
|
+
"version": "1.6.3",
|
|
5
5
|
"license": "UNLICENSED",
|
|
6
6
|
"bin": {
|
|
7
7
|
"systemview": "cli/index.js"
|
|
@@ -28,6 +28,7 @@
|
|
|
28
28
|
"react-router-dom": "^5.2.0",
|
|
29
29
|
"react-scripts": "^4.0.0",
|
|
30
30
|
"react-syntax-highlighter": "^15.5.0",
|
|
31
|
+
"readline": "^1.3.0",
|
|
31
32
|
"remark-gfm": "^3.0.1",
|
|
32
33
|
"systemlynx": "^1.8.3",
|
|
33
34
|
"web-vitals": "^0.2.4"
|
|
@@ -81,8 +82,8 @@
|
|
|
81
82
|
"files": [
|
|
82
83
|
"cli/",
|
|
83
84
|
"api/",
|
|
84
|
-
"plugin/",
|
|
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
|
+
}
|