@w-lfpup/jackrabbit 0.2.0 → 0.3.1

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.
Files changed (98) hide show
  1. package/.github/workflows/browsers.json +55 -0
  2. package/.github/workflows/browsers.macos.json +51 -0
  3. package/.github/workflows/browsers.windows.json +19 -0
  4. package/.github/workflows/tests.yml +13 -0
  5. package/README.md +41 -1
  6. package/browser/dist/logger.js +43 -0
  7. package/browser/dist/mod.js +25 -0
  8. package/browser/dist/queue.js +27 -0
  9. package/browser/dist/runner.js +20 -0
  10. package/{cli → browser}/package.json +1 -1
  11. package/browser/src/logger.ts +57 -0
  12. package/browser/src/mod.ts +30 -0
  13. package/browser/src/runner.ts +22 -0
  14. package/browser/tsconfig.json +11 -0
  15. package/browser/tsconfig.tsbuildinfo +1 -0
  16. package/browsers.json +38 -0
  17. package/core/dist/jackrabbit_types.d.ts +61 -27
  18. package/core/dist/mod.d.ts +2 -2
  19. package/core/dist/mod.js +1 -1
  20. package/core/dist/run_steps.d.ts +2 -2
  21. package/core/dist/run_steps.js +83 -67
  22. package/core/src/jackrabbit_types.ts +72 -28
  23. package/core/src/mod.ts +2 -8
  24. package/core/src/run_steps.ts +111 -80
  25. package/examples/hello_world/goodbye_world.ts +1 -1
  26. package/examples/hello_world/hello_world.ts +1 -1
  27. package/nodejs/dist/logger.js +164 -0
  28. package/nodejs/dist/mod.js +33 -0
  29. package/nodejs/dist/results.js +145 -0
  30. package/nodejs/dist/results_str.js +147 -0
  31. package/nodejs/dist/runner.js +17 -0
  32. package/nodejs/src/logger.ts +200 -0
  33. package/nodejs/src/mod.ts +39 -0
  34. package/nodejs/src/results.ts +239 -0
  35. package/{nodejs_cli → nodejs}/tsconfig.json +2 -1
  36. package/nodejs/tsconfig.tsbuildinfo +1 -0
  37. package/package.json +6 -4
  38. package/tests/dist/mod.d.ts +14 -3
  39. package/tests/dist/mod.js +33 -15
  40. package/tests/dist/test_error.test.d.ts +9 -0
  41. package/tests/dist/test_error.test.js +25 -0
  42. package/tests/dist/test_errors.test.d.ts +9 -0
  43. package/tests/dist/test_errors.test.js +27 -0
  44. package/tests/dist/test_fail.test.js +0 -2
  45. package/tests/dist/test_logger.d.ts +3 -2
  46. package/tests/dist/test_logger.js +5 -1
  47. package/tests/dist/test_pass.test.js +0 -2
  48. package/tests/src/mod.ts +31 -15
  49. package/tests/src/test_error.test.ts +32 -0
  50. package/tests/src/test_logger.ts +6 -1
  51. package/tests/tsconfig.tsbuildinfo +1 -1
  52. package/tsconfig.json +3 -2
  53. package/webdriver/dist/config.js +56 -0
  54. package/webdriver/dist/eventbus.js +18 -0
  55. package/webdriver/dist/listeners.js +21 -0
  56. package/webdriver/dist/logger.js +200 -0
  57. package/webdriver/dist/mod.js +35 -0
  58. package/webdriver/dist/results.js +190 -0
  59. package/webdriver/dist/results_str.js +167 -0
  60. package/webdriver/dist/routes.js +162 -0
  61. package/webdriver/dist/routes2.js +163 -0
  62. package/webdriver/dist/test_hangar.js +20 -0
  63. package/webdriver/dist/webdriver.js +272 -0
  64. package/webdriver/package.json +8 -0
  65. package/webdriver/src/config.ts +89 -0
  66. package/webdriver/src/eventbus.ts +104 -0
  67. package/webdriver/src/logger.ts +247 -0
  68. package/webdriver/src/mod.ts +45 -0
  69. package/webdriver/src/results.ts +311 -0
  70. package/webdriver/src/routes.ts +198 -0
  71. package/webdriver/src/test_hangar.ts +25 -0
  72. package/webdriver/src/webdriver.ts +373 -0
  73. package/{cli → webdriver}/tsconfig.json +1 -0
  74. package/webdriver/tsconfig.tsbuildinfo +1 -0
  75. package/cli/dist/cli.d.ts +0 -3
  76. package/cli/dist/cli.js +0 -8
  77. package/cli/dist/cli_types.d.ts +0 -7
  78. package/cli/dist/cli_types.js +0 -1
  79. package/cli/dist/config.d.ts +0 -5
  80. package/cli/dist/config.js +0 -6
  81. package/cli/dist/importer.d.ts +0 -7
  82. package/cli/dist/importer.js +0 -16
  83. package/cli/dist/logger.d.ts +0 -7
  84. package/cli/dist/logger.js +0 -88
  85. package/cli/dist/mod.d.ts +0 -6
  86. package/cli/dist/mod.js +0 -4
  87. package/cli/src/cli.ts +0 -17
  88. package/cli/src/cli_types.ts +0 -9
  89. package/cli/src/config.ts +0 -9
  90. package/cli/src/importer.ts +0 -25
  91. package/cli/src/logger.ts +0 -126
  92. package/cli/src/mod.ts +0 -7
  93. package/cli/tsconfig.tsbuildinfo +0 -1
  94. package/nodejs_cli/dist/mod.d.ts +0 -2
  95. package/nodejs_cli/dist/mod.js +0 -20
  96. package/nodejs_cli/src/mod.ts +0 -25
  97. package/nodejs_cli/tsconfig.tsbuildinfo +0 -1
  98. /package/{nodejs_cli → nodejs}/package.json +0 -0
@@ -0,0 +1,56 @@
1
+ import * as path from "path";
2
+ export async function createConfig(args) {
3
+ let configFilepath = args[0];
4
+ let relPath = path.resolve(process.cwd(), configFilepath);
5
+ try {
6
+ let { default: json } = await import(`file://${relPath}`, {
7
+ with: { type: "json" },
8
+ });
9
+ let hostAndPort = URL.parse(json.host_and_port);
10
+ if (!hostAndPort)
11
+ throw new Error(`Config: invalid host_and_port json property`);
12
+ let { run_asynchronously: runAsynchronously } = json;
13
+ if (typeof runAsynchronously !== "boolean" &&
14
+ undefined !== runAsynchronously)
15
+ throw new Error("Config: the property runAsynchronously is not a boolean or undefined");
16
+ let webdrivers = [];
17
+ if (Array.isArray(json.webdrivers))
18
+ for (const [index, webdriverParams] of json.webdrivers.entries()) {
19
+ let params = createWebdriverParams(webdriverParams);
20
+ if (params instanceof Error)
21
+ return params;
22
+ let session = Math.floor(Math.random() * Number.MAX_SAFE_INTEGER);
23
+ let jrId = `${index}:${session.toString(32)}`;
24
+ webdrivers.push({ ...params, jrId });
25
+ }
26
+ return {
27
+ hostAndPort,
28
+ runAsynchronously,
29
+ webdrivers,
30
+ };
31
+ }
32
+ catch (e) {
33
+ if (e instanceof Error)
34
+ return e;
35
+ return new Error("Config: failed to parse config params from string");
36
+ }
37
+ }
38
+ export function createWebdriverParams(json) {
39
+ let { command, url, title, timeout_ms, capabilities } = json;
40
+ if (typeof command !== "string")
41
+ return new Error("WebdriverParams: command is not a string");
42
+ let parsedUrl = URL.parse(url);
43
+ if (null === parsedUrl)
44
+ return new Error("WebdriverParams: url is not a valid URL");
45
+ if (typeof title !== "string")
46
+ return new Error("WebdriverParams: title is not a string");
47
+ if (typeof timeout_ms !== "number")
48
+ return new Error("WebdriverParams: timeout_ms is not a number");
49
+ return {
50
+ command,
51
+ url: parsedUrl,
52
+ title,
53
+ timeoutMs: timeout_ms,
54
+ capabilities,
55
+ };
56
+ }
@@ -0,0 +1,18 @@
1
+ export class EventBus {
2
+ #eventMap = new Map();
3
+ addListener(type, cb) {
4
+ let listeners = this.#eventMap.get(type);
5
+ if (!listeners) {
6
+ listeners = [];
7
+ this.#eventMap.set(type, listeners);
8
+ }
9
+ listeners.push(cb);
10
+ }
11
+ dispatchAction(action) {
12
+ let listeners = this.#eventMap.get(action.type);
13
+ if (listeners)
14
+ for (const listener of listeners) {
15
+ listener(action);
16
+ }
17
+ }
18
+ }
@@ -0,0 +1,21 @@
1
+ export class Listeners {
2
+ #eventMap = new Map();
3
+ addEventListener(eventName, cb) {
4
+ let eventListeners = this.#eventMap.get(eventName);
5
+ if (!eventListeners) {
6
+ eventListeners = [];
7
+ this.#eventMap.set(eventName, eventListeners);
8
+ }
9
+ eventListeners.push(cb);
10
+ }
11
+ dispatchEvent(event) {
12
+ let eventListeners = this.#eventMap.get(event.type);
13
+ if (eventListeners)
14
+ for (const listener of eventListeners) {
15
+ listener instanceof Function
16
+ ? listener(event)
17
+ : listener.handleEvent(event);
18
+ }
19
+ return event.cancelable || event.defaultPrevented;
20
+ }
21
+ }
@@ -0,0 +1,200 @@
1
+ import { getResultsAsString, isComplete } from "./results.js";
2
+ export class Logger {
3
+ #eventbus;
4
+ #sessionResults = {
5
+ fails: 0,
6
+ errors: 0,
7
+ runs: new Map(),
8
+ };
9
+ constructor(config, eventbus) {
10
+ this.#eventbus = eventbus;
11
+ this.#eventbus.addListener("log", this.#boundLog);
12
+ this.#eventbus.addListener("session_error", this.#boundError);
13
+ for (let webdriverParams of config.webdrivers) {
14
+ this.#sessionResults.runs.set(webdriverParams.jrId, {
15
+ startTime: 0,
16
+ fails: 0,
17
+ errors: 0,
18
+ expectedTests: 0,
19
+ expectedModules: 0,
20
+ endTime: 0,
21
+ testTime: 0,
22
+ errorLogs: [],
23
+ completedTests: 0,
24
+ completedModules: 0,
25
+ expectedCollections: 0,
26
+ completedCollections: 0,
27
+ webdriverParams,
28
+ collections: [],
29
+ });
30
+ }
31
+ }
32
+ get failed() {
33
+ return this.#sessionResults.fails !== 0;
34
+ }
35
+ get errored() {
36
+ return this.#sessionResults.errors !== 0;
37
+ }
38
+ get completed() {
39
+ return isComplete(this.#sessionResults);
40
+ }
41
+ get results() {
42
+ return getResultsAsString(this.#sessionResults);
43
+ }
44
+ #boundError = this.#onError.bind(this);
45
+ #onError(action) {
46
+ let runResults = this.#sessionResults.runs.get(action.id);
47
+ if (runResults) {
48
+ this.#sessionResults.errors += 1;
49
+ runResults.errors += 1;
50
+ runResults.errorLogs.push(action);
51
+ }
52
+ }
53
+ #boundLog = this.#onLog.bind(this);
54
+ #onLog(action) {
55
+ let { loggerAction, id } = action;
56
+ let runResults = this.#sessionResults.runs.get(id);
57
+ if (!runResults)
58
+ return;
59
+ if ("start_run" === loggerAction.type) {
60
+ runResults.startTime = loggerAction.time;
61
+ runResults.expectedCollections = loggerAction.expected_collection_count;
62
+ }
63
+ if ("end_run" === loggerAction.type) {
64
+ runResults.endTime = loggerAction.time;
65
+ this.#eventbus.dispatchAction({
66
+ type: "run_complete",
67
+ id,
68
+ });
69
+ }
70
+ if ("run_error" === loggerAction.type) {
71
+ this.#sessionResults.errors += 1;
72
+ runResults.errors += 1;
73
+ runResults.errorLogs.push(action);
74
+ }
75
+ if ("start_collection" === loggerAction.type) {
76
+ runResults.collections[loggerAction.collection_id] = {
77
+ completedModules: 0,
78
+ completedTests: 0,
79
+ errorLogs: [],
80
+ errors: 0,
81
+ expectedModules: loggerAction.expected_module_count,
82
+ expectedTests: 0,
83
+ fails: 0,
84
+ loggerAction,
85
+ modules: [],
86
+ };
87
+ runResults.expectedModules += loggerAction.expected_module_count;
88
+ }
89
+ if ("end_collection" === loggerAction.type) {
90
+ let collection = runResults.collections[loggerAction.collection_id];
91
+ if (!collection)
92
+ return;
93
+ runResults.completedCollections += 1;
94
+ }
95
+ if ("collection_error" === loggerAction.type) {
96
+ let collection = runResults.collections[loggerAction.collection_id];
97
+ if (!collection)
98
+ return;
99
+ this.#sessionResults.errors += 1;
100
+ runResults.errors += 1;
101
+ collection.errors += 1;
102
+ collection.errorLogs.push(loggerAction);
103
+ }
104
+ if ("start_module" === loggerAction.type) {
105
+ let collection = runResults.collections[loggerAction.collection_id];
106
+ if (!collection)
107
+ return;
108
+ collection.modules[loggerAction.module_id] = {
109
+ completedTests: 0,
110
+ errorLogs: [],
111
+ errors: 0,
112
+ expectedTests: loggerAction.expected_test_count,
113
+ fails: 0,
114
+ loggerAction,
115
+ testResults: [],
116
+ };
117
+ collection.expectedTests += loggerAction.expected_test_count;
118
+ runResults.expectedTests += loggerAction.expected_test_count;
119
+ }
120
+ if ("end_module" === loggerAction.type) {
121
+ let collection = runResults.collections[loggerAction.collection_id];
122
+ if (!collection)
123
+ return;
124
+ let module = collection.modules[loggerAction.module_id];
125
+ if (!module)
126
+ return;
127
+ runResults.completedModules += 1;
128
+ collection.completedModules += 1;
129
+ }
130
+ if ("module_error" === loggerAction.type) {
131
+ let collection = runResults.collections[loggerAction.collection_id];
132
+ if (!collection)
133
+ return;
134
+ let module = collection.modules[loggerAction.module_id];
135
+ if (!module)
136
+ return;
137
+ this.#sessionResults.errors += 1;
138
+ runResults.errors += 1;
139
+ collection.errors += 1;
140
+ module.errors += 1;
141
+ module.errorLogs.push(loggerAction);
142
+ }
143
+ if ("start_test" === loggerAction.type) {
144
+ let collection = runResults.collections[loggerAction.collection_id];
145
+ if (!collection)
146
+ return;
147
+ let module = collection.modules[loggerAction.module_id];
148
+ if (!module)
149
+ return;
150
+ module.testResults[loggerAction.test_id] = {
151
+ loggerStartAction: loggerAction,
152
+ loggerEndAction: undefined,
153
+ };
154
+ }
155
+ if ("end_test" === loggerAction.type) {
156
+ endTest(this.#sessionResults, runResults, loggerAction);
157
+ }
158
+ if ("test_error" === loggerAction.type) {
159
+ let collection = runResults.collections[loggerAction.collection_id];
160
+ if (!collection)
161
+ return;
162
+ let module = collection.modules[loggerAction.module_id];
163
+ if (!module)
164
+ return;
165
+ let testResult = module.testResults[loggerAction.test_id];
166
+ if (!testResult)
167
+ return;
168
+ testResult.loggerEndAction = loggerAction;
169
+ this.#sessionResults.errors += 1;
170
+ runResults.errors += 1;
171
+ collection.errors += 1;
172
+ module.errors += 1;
173
+ }
174
+ }
175
+ }
176
+ function endTest(sessionResults, runResults, loggerAction) {
177
+ let collection = runResults.collections[loggerAction.collection_id];
178
+ if (!collection)
179
+ return;
180
+ let module = collection.modules[loggerAction.module_id];
181
+ if (!module)
182
+ return;
183
+ let testResult = module.testResults[loggerAction.test_id];
184
+ if (!testResult)
185
+ return;
186
+ testResult.loggerEndAction = loggerAction;
187
+ runResults.completedTests += 1;
188
+ collection.completedTests += 1;
189
+ module.completedTests += 1;
190
+ let { assertions } = loggerAction;
191
+ const isAssertionArray = Array.isArray(assertions) && assertions.length;
192
+ const isAssertion = !Array.isArray(assertions) && undefined !== assertions;
193
+ if (isAssertion || isAssertionArray) {
194
+ sessionResults.fails += 1;
195
+ runResults.fails += 1;
196
+ collection.fails += 1;
197
+ module.fails += 1;
198
+ }
199
+ runResults.testTime += Math.max(0, loggerAction.end_time - loggerAction.start_time);
200
+ }
@@ -0,0 +1,35 @@
1
+ #!/usr/bin/env node
2
+ import * as http from "http";
3
+ import { createConfig } from "./config.js";
4
+ import { Logger } from "./logger.js";
5
+ import { Router } from "./routes.js";
6
+ import { WebDrivers } from "./webdriver.js";
7
+ import { EventBus } from "./eventbus.js";
8
+ let args = process.argv.slice(2);
9
+ const config = await createConfig(args);
10
+ if (config instanceof Error) {
11
+ console.log(config);
12
+ process.exit(1);
13
+ }
14
+ let eventbus = new EventBus();
15
+ let logger = new Logger(config, eventbus);
16
+ let router = new Router(config, eventbus);
17
+ let webdrivers = new WebDrivers(config, eventbus);
18
+ let server = http.createServer();
19
+ server.addListener("request", router.route);
20
+ server.addListener("close", function () {
21
+ console.log(logger.results);
22
+ logger.errored || logger.failed || !logger.completed
23
+ ? process.exit(1)
24
+ : process.exit(0);
25
+ });
26
+ eventbus.addListener("end", function () {
27
+ server.closeAllConnections();
28
+ server.close();
29
+ });
30
+ let { port, hostname } = config.hostAndPort;
31
+ server.listen({
32
+ port,
33
+ hostname,
34
+ });
35
+ config.runAsynchronously ? webdrivers.runAll() : webdrivers.run();
@@ -0,0 +1,190 @@
1
+ const SPACE = " ";
2
+ export function getResultsAsString(sessionResults) {
3
+ const output = [];
4
+ logSessionErrors(output, sessionResults);
5
+ for (let [, result] of sessionResults.runs) {
6
+ if (logRunResults(output, result))
7
+ continue;
8
+ for (const collection of result.collections) {
9
+ if (logCollectionResult(output, collection))
10
+ continue;
11
+ if (collection)
12
+ for (const moduleResult of collection.modules) {
13
+ if (logModuleResult(output, moduleResult))
14
+ continue;
15
+ if (moduleResult)
16
+ for (const testResult of moduleResult.testResults) {
17
+ logTest(output, testResult);
18
+ }
19
+ }
20
+ }
21
+ }
22
+ logSummary(output, sessionResults);
23
+ return output.join("\n");
24
+ }
25
+ function logSessionErrors(output, sessionResults) {
26
+ if (!sessionResults.runs.size)
27
+ output.push("\nNo webdrivers were run.");
28
+ for (let [, result] of sessionResults.runs) {
29
+ if (result.errorLogs.length)
30
+ output.push(`\n${result.webdriverParams.title}`);
31
+ for (let errorAction of result.errorLogs) {
32
+ if ("session_error" === errorAction.type) {
33
+ output.push(`${SPACE}[session_error] ${errorAction.error}`);
34
+ }
35
+ }
36
+ }
37
+ }
38
+ function logRunResults(output, result) {
39
+ output.push(`\n${result.webdriverParams.title}`);
40
+ for (let errorAction of result.errorLogs) {
41
+ if ("log" !== errorAction.type)
42
+ continue;
43
+ if ("run_error" !== errorAction.loggerAction.type)
44
+ continue;
45
+ output.push(`${SPACE.repeat(2)}[run_error] ${errorAction.loggerAction.error}`);
46
+ }
47
+ if (result.errorLogs.length)
48
+ output.push("");
49
+ if (!result.collections && !result.expectedTests) {
50
+ output.push(`${SPACE}No tests were run.`);
51
+ return true;
52
+ }
53
+ if (!result.fails &&
54
+ !result.errors &&
55
+ result.expectedTests === result.completedTests &&
56
+ result.expectedModules === result.completedModules &&
57
+ result.expectedCollections === result.completedCollections) {
58
+ output.push(`${SPACE}${result.completedTests} tests
59
+ ${SPACE}${result.completedModules} modules
60
+ ${SPACE}${result.completedCollections} collections`);
61
+ return true;
62
+ }
63
+ return false;
64
+ }
65
+ function logCollectionResult(output, collection) {
66
+ if (!collection)
67
+ return true;
68
+ let { loggerAction } = collection;
69
+ if ("start_collection" !== loggerAction.type)
70
+ return true;
71
+ output.push(`${SPACE}${loggerAction.collection_url}`);
72
+ if (!collection.fails &&
73
+ !collection.errors &&
74
+ collection.expectedTests === collection.completedTests &&
75
+ collection.expectedModules === collection.completedModules) {
76
+ output.push(`${SPACE.repeat(2)}${collection.expectedTests} tests
77
+ ${SPACE.repeat(2)}${loggerAction.expected_module_count} modules`);
78
+ return true;
79
+ }
80
+ for (let errorAction of collection.errorLogs) {
81
+ if ("collection_error" !== errorAction.type)
82
+ continue;
83
+ output.push(`${SPACE.repeat(2)}[collection_error] ${errorAction.error}`);
84
+ }
85
+ if (collection.errorLogs.length)
86
+ output.push("");
87
+ return false;
88
+ }
89
+ function logModuleResult(output, module) {
90
+ if (!module)
91
+ return true;
92
+ let { loggerAction } = module;
93
+ if ("start_module" !== loggerAction.type)
94
+ return true;
95
+ output.push(`${SPACE.repeat(2)}${loggerAction.module_name}`);
96
+ if (!module.fails &&
97
+ !module.errors &&
98
+ module.expectedTests === module.completedTests) {
99
+ output.push(`${SPACE.repeat(3)}${module.expectedTests} tests`);
100
+ return true;
101
+ }
102
+ output.push(`${SPACE.repeat(3)}${module.completedTests - module.fails}/${module.expectedTests} tests`);
103
+ output.push("");
104
+ for (let errorAction of module.errorLogs) {
105
+ if ("module_error" !== errorAction.type)
106
+ continue;
107
+ output.push(`${SPACE.repeat(3)}[module_error] ${errorAction.error}`);
108
+ }
109
+ if (module.errorLogs.length)
110
+ output.push("");
111
+ return false;
112
+ }
113
+ function logTest(output, test) {
114
+ if (!test)
115
+ return;
116
+ let { loggerStartAction, loggerEndAction } = test;
117
+ if ("start_test" !== loggerStartAction.type)
118
+ return;
119
+ if ("test_error" === loggerEndAction?.type) {
120
+ let { test_name } = loggerStartAction;
121
+ output.push(`${SPACE.repeat(3)}${test_name}
122
+ ${SPACE.repeat(4)}[error] ${loggerEndAction.error}`);
123
+ }
124
+ if ("end_test" === loggerEndAction?.type) {
125
+ let { assertions } = loggerEndAction;
126
+ const isAssertionArray = Array.isArray(assertions) && assertions.length;
127
+ const isAssertion = !Array.isArray(assertions) &&
128
+ undefined !== assertions &&
129
+ null !== assertions;
130
+ if (isAssertion || isAssertionArray) {
131
+ let { test_name } = loggerStartAction;
132
+ output.push(`${SPACE.repeat(3)}${test_name}`);
133
+ }
134
+ if (isAssertion) {
135
+ output.push(`${SPACE.repeat(4)}- ${assertions}`);
136
+ }
137
+ if (isAssertionArray) {
138
+ for (const assertion of assertions) {
139
+ output.push(`${SPACE.repeat(4)}- ${assertion}`);
140
+ }
141
+ }
142
+ }
143
+ if (undefined === loggerEndAction) {
144
+ let { test_name } = loggerStartAction;
145
+ output.push(`${SPACE.repeat(3)}${test_name}
146
+ ${SPACE.repeat(4)}[incomplete]`);
147
+ }
148
+ }
149
+ function logSummary(output, sessionResults) {
150
+ let status_with_color = blue("\u{2714} passed");
151
+ if (!isComplete(sessionResults))
152
+ status_with_color = gray("\u{2717} incomplete");
153
+ if (sessionResults.fails)
154
+ status_with_color = yellow("\u{2717} failed");
155
+ if (sessionResults.errors)
156
+ status_with_color = gray("\u{2717} errored");
157
+ let totalTime = 0;
158
+ let testTime = 0;
159
+ for (let [, run] of sessionResults.runs) {
160
+ totalTime += run.endTime - run.startTime;
161
+ testTime += run.testTime;
162
+ }
163
+ output.push(`
164
+ ${status_with_color}
165
+ duration: ${testTime.toFixed(4)} mS
166
+ total: ${totalTime.toFixed(4)} mS
167
+ `);
168
+ }
169
+ export function isComplete(sessionResults) {
170
+ for (const [, result] of sessionResults.runs) {
171
+ if (!result.expectedTests ||
172
+ !result.expectedModules ||
173
+ !result.expectedCollections)
174
+ return false;
175
+ if (result.expectedTests !== result.completedTests ||
176
+ result.expectedModules !== result.completedModules ||
177
+ result.expectedCollections !== result.completedCollections)
178
+ return false;
179
+ }
180
+ return true;
181
+ }
182
+ function blue(text) {
183
+ return `\x1b[44m\x1b[97m${text}\x1b[0m`;
184
+ }
185
+ function yellow(text) {
186
+ return `\x1b[43m\x1b[97m${text}\x1b[0m`;
187
+ }
188
+ function gray(text) {
189
+ return `\x1b[100m\x1b[97m${text}\x1b[0m`;
190
+ }
@@ -0,0 +1,167 @@
1
+ const SPACE = " ";
2
+ export function getResultsAsString(sessionResults) {
3
+ const output = [];
4
+ // Lots of nested loops because results a nested structure.
5
+ // I'd rather see composition nested in one function
6
+ // than have for loops spread across each function.
7
+ logSessionErrors(output, sessionResults);
8
+ for (let [, result] of sessionResults.runs) {
9
+ if (logRunResults(output, result))
10
+ continue;
11
+ for (const collection of result.collections) {
12
+ if (logCollectionResult(output, collection))
13
+ continue;
14
+ if (collection)
15
+ for (const moduleResult of collection.modules) {
16
+ if (logModuleResult(output, moduleResult))
17
+ continue;
18
+ if (moduleResult)
19
+ for (const testResult of moduleResult.testResults) {
20
+ logTest(output, testResult);
21
+ }
22
+ }
23
+ }
24
+ }
25
+ logSummary(output, sessionResults);
26
+ return output.join("\n");
27
+ }
28
+ function logSessionErrors(output, sessionResults) {
29
+ for (let [, result] of sessionResults.runs) {
30
+ for (let errorAction of result.errorLogs) {
31
+ if ("session_error" === errorAction.type) {
32
+ output.push(`\n[${result.webdriverParams.title}:session_error] ${errorAction.error}`);
33
+ }
34
+ }
35
+ }
36
+ }
37
+ function logRunResults(output, result) {
38
+ output.push(`
39
+ ${result.webdriverParams.title}`);
40
+ for (let errorAction of result.errorLogs) {
41
+ if ("log" === errorAction.type) {
42
+ if ("run_error" === errorAction.loggerAction.type) {
43
+ output.push(`${SPACE}[run_error] ${errorAction.loggerAction.error}`);
44
+ }
45
+ }
46
+ }
47
+ if (!result.expectedTests) {
48
+ output.push(` No test runs occured.`);
49
+ }
50
+ // When everything goes right :3
51
+ if (!result.fails &&
52
+ !result.errors &&
53
+ result.expectedTests === result.completedTests &&
54
+ result.expectedModules === result.completedModules &&
55
+ result.expectedCollections === result.completedCollections) {
56
+ output.push(`${SPACE}${result.completedTests} tests
57
+ ${SPACE}${result.completedModules} modules
58
+ ${SPACE}${result.completedCollections} collections`);
59
+ return true;
60
+ }
61
+ return false;
62
+ }
63
+ function logCollectionResult(output, collection) {
64
+ if (!collection)
65
+ return true;
66
+ let { loggerAction } = collection;
67
+ if ("start_collection" !== loggerAction.type)
68
+ return true;
69
+ output.push(`${SPACE}${loggerAction.collection_url}`);
70
+ // when everything in the collection goes right
71
+ if (!collection.fails &&
72
+ !collection.errors &&
73
+ collection.expectedTests === collection.completedTests &&
74
+ collection.expectedModules === collection.completedModules) {
75
+ output.push(`${SPACE.repeat(2)}${collection.expectedTests} tests
76
+ ${SPACE.repeat(2)}${loggerAction.expected_module_count} modules`);
77
+ return true;
78
+ }
79
+ for (let errorAction of collection.errorLogs) {
80
+ if ("collection_error" !== errorAction.type)
81
+ continue;
82
+ output.push(`${SPACE.repeat(2)}[collection_error] ${errorAction.error}`);
83
+ }
84
+ return false;
85
+ }
86
+ function logModuleResult(output, module) {
87
+ if (!module)
88
+ return true;
89
+ let { loggerAction } = module;
90
+ if ("start_module" !== loggerAction.type)
91
+ return true;
92
+ output.push(`${SPACE.repeat(2)}${loggerAction.module_name}`);
93
+ // when everything in the module goes right
94
+ if (!module.fails &&
95
+ !module.errors &&
96
+ module.expectedTests === module.completedTests) {
97
+ output.push(`${SPACE.repeat(3)}${module.expectedTests} tests`);
98
+ return true;
99
+ }
100
+ for (let errorAction of module.errorLogs) {
101
+ if ("collection_error" !== errorAction.type)
102
+ continue;
103
+ output.push(`${SPACE.repeat(2)}[module_error] ${errorAction.error}`);
104
+ }
105
+ return false;
106
+ }
107
+ function logTest(output, test) {
108
+ if (!test)
109
+ return;
110
+ let { loggerStartAction, loggerEndAction } = test;
111
+ if ("start_test" !== loggerStartAction.type)
112
+ return;
113
+ if ("test_error" === loggerEndAction?.type) {
114
+ let { test_name } = loggerStartAction;
115
+ output.push(`${SPACE.repeat(3)}${test_name}
116
+ ${SPACE.repeat(4)}[error] ${loggerEndAction.error}`);
117
+ }
118
+ if ("end_test" === loggerEndAction?.type) {
119
+ let { assertions } = loggerEndAction;
120
+ const isAssertionArray = Array.isArray(assertions) && assertions.length;
121
+ const isAssertion = !Array.isArray(assertions) &&
122
+ undefined !== assertions &&
123
+ null !== assertions;
124
+ if (isAssertion || isAssertionArray) {
125
+ let { test_name } = loggerStartAction;
126
+ output.push(`${SPACE.repeat(3)}${test_name}`);
127
+ }
128
+ if (isAssertion) {
129
+ output.push(`${SPACE.repeat(4)}- ${assertions}`);
130
+ }
131
+ if (isAssertionArray) {
132
+ for (const assertion of assertions) {
133
+ output.push(`${SPACE.repeat(4)}- ${assertion}`);
134
+ }
135
+ }
136
+ }
137
+ }
138
+ function logSummary(output, sessionResults) {
139
+ let status_with_color = blue("\u{2714} passed");
140
+ if (sessionResults.fails)
141
+ status_with_color = yellow("\u{2717} failed");
142
+ if (sessionResults.errors)
143
+ status_with_color = gray("\u{2717} errored");
144
+ // expected tests
145
+ let totalTime = 0;
146
+ let testTime = 0;
147
+ for (let [, run] of sessionResults.runs) {
148
+ totalTime += run.endTime - run.startTime;
149
+ testTime += run.testTime;
150
+ }
151
+ output.push(`
152
+ ${status_with_color}
153
+ duration: ${testTime.toFixed(4)} mS
154
+ total: ${totalTime.toFixed(4)} mS
155
+ `);
156
+ }
157
+ // 39 - default foreground color
158
+ // 49 - default background color
159
+ function blue(text) {
160
+ return `\x1b[44m\x1b[97m${text}\x1b[0m`;
161
+ }
162
+ function yellow(text) {
163
+ return `\x1b[43m\x1b[97m${text}\x1b[0m`;
164
+ }
165
+ function gray(text) {
166
+ return `\x1b[100m\x1b[97m${text}\x1b[0m`;
167
+ }