@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,89 @@
1
+ import * as path from "path";
2
+
3
+ interface WebdriverConfig {
4
+ command: string;
5
+ url: URL;
6
+ title: string;
7
+ timeoutMs: number;
8
+ capabilities?: unknown;
9
+ }
10
+
11
+ export interface WebdriverParams extends WebdriverConfig {
12
+ jrId: string;
13
+ }
14
+
15
+ export interface ConfigInterface {
16
+ hostAndPort: URL;
17
+ runAsynchronously?: boolean;
18
+ webdrivers: WebdriverParams[];
19
+ }
20
+
21
+ export async function createConfig(
22
+ args: string[],
23
+ ): Promise<ConfigInterface | Error> {
24
+ let configFilepath = args[0];
25
+ let relPath = path.resolve(process.cwd(), configFilepath);
26
+
27
+ try {
28
+ // windows might need a "file://<relPath>" situation
29
+ let { default: json } = await import(`file://${relPath}`, {
30
+ with: { type: "json" },
31
+ });
32
+
33
+ let hostAndPort: URL | null = URL.parse(json.host_and_port);
34
+ if (!hostAndPort)
35
+ throw new Error(`Config: invalid host_and_port json property`);
36
+
37
+ let { run_asynchronously: runAsynchronously } = json;
38
+ if (
39
+ typeof runAsynchronously !== "boolean" &&
40
+ undefined !== runAsynchronously
41
+ )
42
+ throw new Error(
43
+ "Config: the property runAsynchronously is not a boolean or undefined",
44
+ );
45
+
46
+ let webdrivers: WebdriverParams[] = [];
47
+ if (Array.isArray(json.webdrivers))
48
+ for (const [index, webdriverParams] of json.webdrivers.entries()) {
49
+ let params = createWebdriverParams(webdriverParams);
50
+ if (params instanceof Error) return params;
51
+
52
+ let session = Math.floor(Math.random() * Number.MAX_SAFE_INTEGER);
53
+ let jrId = `${index}:${session.toString(32)}`;
54
+
55
+ webdrivers.push({ ...params, jrId });
56
+ }
57
+ return {
58
+ hostAndPort,
59
+ runAsynchronously,
60
+ webdrivers,
61
+ };
62
+ } catch (e) {
63
+ if (e instanceof Error) return e;
64
+ return new Error("Config: failed to parse config params from string");
65
+ }
66
+ }
67
+
68
+ export function createWebdriverParams(json: any): WebdriverConfig | Error {
69
+ let { command, url, title, timeout_ms, capabilities } = json;
70
+
71
+ if (typeof command !== "string")
72
+ return new Error("WebdriverParams: command is not a string");
73
+
74
+ let parsedUrl: URL | null = URL.parse(url);
75
+ if (null === parsedUrl)
76
+ return new Error("WebdriverParams: url is not a valid URL");
77
+ if (typeof title !== "string")
78
+ return new Error("WebdriverParams: title is not a string");
79
+ if (typeof timeout_ms !== "number")
80
+ return new Error("WebdriverParams: timeout_ms is not a number");
81
+
82
+ return {
83
+ command,
84
+ url: parsedUrl,
85
+ title,
86
+ timeoutMs: timeout_ms,
87
+ capabilities,
88
+ };
89
+ }
@@ -0,0 +1,104 @@
1
+ import type { LoggerAction } from "../../core/dist/jackrabbit_types.js";
2
+
3
+ export interface WebdriverSessionAction {
4
+ id: string;
5
+ }
6
+
7
+ export interface WebdriverSessionStartAction extends WebdriverSessionAction {
8
+ type: "session_start";
9
+ }
10
+
11
+ export interface WebdriverSessionErrorAction extends WebdriverSessionAction {
12
+ type: "session_error";
13
+ error: string;
14
+ }
15
+
16
+ export interface WebdriverSessionClosedAction extends WebdriverSessionAction {
17
+ type: "session_closed";
18
+ }
19
+
20
+ export interface WebdriverRunCompleteAction extends WebdriverSessionAction {
21
+ type: "run_complete";
22
+ }
23
+
24
+ export interface WebdriverLogAction extends WebdriverSessionAction {
25
+ type: "log";
26
+ loggerAction: LoggerAction;
27
+ }
28
+
29
+ export interface WebdriverCliOutpuAction extends WebdriverSessionAction {
30
+ type: "stdout";
31
+ output: string;
32
+ }
33
+
34
+ export interface WebdriverCliErrorOutpuAction extends WebdriverSessionAction {
35
+ type: "stderr";
36
+ output: string;
37
+ }
38
+
39
+ export interface WebdriverEndAction {
40
+ type: "end";
41
+ }
42
+
43
+ export interface WebdriverActionMap {
44
+ end: WebdriverEndAction;
45
+ log: WebdriverLogAction;
46
+ run_complete: WebdriverRunCompleteAction;
47
+ session_closed: WebdriverSessionClosedAction;
48
+ session_error: WebdriverSessionErrorAction;
49
+ session_start: WebdriverSessionStartAction;
50
+ stderr: WebdriverCliErrorOutpuAction;
51
+ stdout: WebdriverCliOutpuAction;
52
+ }
53
+
54
+ export type WebdriverActions =
55
+ | WebdriverCliErrorOutpuAction
56
+ | WebdriverCliOutpuAction
57
+ | WebdriverEndAction
58
+ | WebdriverLogAction
59
+ | WebdriverRunCompleteAction
60
+ | WebdriverSessionClosedAction
61
+ | WebdriverSessionErrorAction
62
+ | WebdriverSessionStartAction;
63
+
64
+ interface TypedEventBusListener<
65
+ K extends keyof WebdriverActionMap = keyof WebdriverActionMap,
66
+ > {
67
+ (action: WebdriverActionMap[K]): void;
68
+ }
69
+
70
+ interface EventBusListener extends TypedEventBusListener {
71
+ (action: WebdriverActions): void;
72
+ }
73
+
74
+ export interface EventBusInterface {
75
+ addListener<K extends keyof WebdriverActionMap>(
76
+ type: K,
77
+ listener: TypedEventBusListener<K>,
78
+ ): void;
79
+ dispatchAction(action: WebdriverActions): void;
80
+ }
81
+
82
+ export class EventBus implements EventBusInterface {
83
+ #eventMap: Map<string, EventBusListener[]> = new Map();
84
+
85
+ addListener<K extends keyof WebdriverActionMap>(
86
+ type: K,
87
+ cb: TypedEventBusListener<K>,
88
+ ) {
89
+ let listeners = this.#eventMap.get(type);
90
+ if (!listeners) {
91
+ listeners = [];
92
+ this.#eventMap.set(type, listeners);
93
+ }
94
+ listeners.push(cb as EventBusListener);
95
+ }
96
+
97
+ dispatchAction(action: WebdriverActions) {
98
+ let listeners = this.#eventMap.get(action.type);
99
+ if (listeners)
100
+ for (const listener of listeners) {
101
+ listener(action);
102
+ }
103
+ }
104
+ }
@@ -0,0 +1,247 @@
1
+ import type { EndTest } from "../../core/dist/jackrabbit_types.js";
2
+ import type { ConfigInterface } from "./config.js";
3
+ import type {
4
+ EventBus,
5
+ WebdriverLogAction,
6
+ WebdriverSessionErrorAction,
7
+ } from "./eventbus.js";
8
+ import type { SessionResults, RunResults } from "./results.js";
9
+
10
+ import { getResultsAsString, isComplete } from "./results.js";
11
+
12
+ export class Logger {
13
+ #eventbus: EventBus;
14
+
15
+ #sessionResults: SessionResults = {
16
+ fails: 0,
17
+ errors: 0,
18
+ runs: new Map(),
19
+ };
20
+
21
+ constructor(config: ConfigInterface, eventbus: EventBus) {
22
+ this.#eventbus = eventbus;
23
+ this.#eventbus.addListener("log", this.#boundLog);
24
+ this.#eventbus.addListener("session_error", this.#boundError);
25
+
26
+ for (let webdriverParams of config.webdrivers) {
27
+ this.#sessionResults.runs.set(webdriverParams.jrId, {
28
+ startTime: 0,
29
+ fails: 0,
30
+ errors: 0,
31
+ expectedTests: 0,
32
+ expectedModules: 0,
33
+ endTime: 0,
34
+ testTime: 0,
35
+ errorLogs: [],
36
+ completedTests: 0,
37
+ completedModules: 0,
38
+ expectedCollections: 0,
39
+ completedCollections: 0,
40
+ webdriverParams,
41
+ collections: [],
42
+ });
43
+ }
44
+ }
45
+
46
+ get failed() {
47
+ return this.#sessionResults.fails !== 0;
48
+ }
49
+
50
+ get errored() {
51
+ return this.#sessionResults.errors !== 0;
52
+ }
53
+
54
+ get completed() {
55
+ return isComplete(this.#sessionResults);
56
+ }
57
+
58
+ get results(): string {
59
+ return getResultsAsString(this.#sessionResults);
60
+ }
61
+
62
+ // get output
63
+ // output being a array of a string
64
+ #boundError = this.#onError.bind(this);
65
+ #onError(action: WebdriverSessionErrorAction) {
66
+ let runResults = this.#sessionResults.runs.get(action.id);
67
+ if (runResults) {
68
+ this.#sessionResults.errors += 1;
69
+ runResults.errors += 1;
70
+ runResults.errorLogs.push(action);
71
+ }
72
+ }
73
+
74
+ #boundLog = this.#onLog.bind(this);
75
+ #onLog(action: WebdriverLogAction) {
76
+ let { loggerAction, id } = action;
77
+
78
+ let runResults = this.#sessionResults.runs.get(id);
79
+ if (!runResults) return;
80
+
81
+ if ("start_run" === loggerAction.type) {
82
+ runResults.startTime = loggerAction.time;
83
+ runResults.expectedCollections = loggerAction.expected_collection_count;
84
+ }
85
+
86
+ if ("end_run" === loggerAction.type) {
87
+ runResults.endTime = loggerAction.time;
88
+ this.#eventbus.dispatchAction({
89
+ type: "run_complete",
90
+ id,
91
+ });
92
+ }
93
+
94
+ if ("run_error" === loggerAction.type) {
95
+ this.#sessionResults.errors += 1;
96
+ runResults.errors += 1;
97
+ runResults.errorLogs.push(action);
98
+ }
99
+
100
+ if ("start_collection" === loggerAction.type) {
101
+ runResults.collections[loggerAction.collection_id] = {
102
+ completedModules: 0,
103
+ completedTests: 0,
104
+ errorLogs: [],
105
+ errors: 0,
106
+ expectedModules: loggerAction.expected_module_count,
107
+ expectedTests: 0,
108
+ fails: 0,
109
+ loggerAction,
110
+ modules: [],
111
+ };
112
+
113
+ runResults.expectedModules += loggerAction.expected_module_count;
114
+ }
115
+
116
+ if ("end_collection" === loggerAction.type) {
117
+ let collection = runResults.collections[loggerAction.collection_id];
118
+ if (!collection) return;
119
+
120
+ runResults.completedCollections += 1;
121
+ }
122
+
123
+ if ("collection_error" === loggerAction.type) {
124
+ let collection = runResults.collections[loggerAction.collection_id];
125
+ if (!collection) return;
126
+
127
+ this.#sessionResults.errors += 1;
128
+ runResults.errors += 1;
129
+ collection.errors += 1;
130
+
131
+ collection.errorLogs.push(loggerAction);
132
+ }
133
+
134
+ if ("start_module" === loggerAction.type) {
135
+ let collection = runResults.collections[loggerAction.collection_id];
136
+ if (!collection) return;
137
+
138
+ collection.modules[loggerAction.module_id] = {
139
+ completedTests: 0,
140
+ errorLogs: [],
141
+ errors: 0,
142
+ expectedTests: loggerAction.expected_test_count,
143
+ fails: 0,
144
+ loggerAction,
145
+ testResults: [],
146
+ };
147
+
148
+ collection.expectedTests += loggerAction.expected_test_count;
149
+ runResults.expectedTests += loggerAction.expected_test_count;
150
+ }
151
+
152
+ if ("end_module" === loggerAction.type) {
153
+ let collection = runResults.collections[loggerAction.collection_id];
154
+ if (!collection) return;
155
+
156
+ let module = collection.modules[loggerAction.module_id];
157
+ if (!module) return;
158
+
159
+ runResults.completedModules += 1;
160
+ collection.completedModules += 1;
161
+ }
162
+
163
+ if ("module_error" === loggerAction.type) {
164
+ let collection = runResults.collections[loggerAction.collection_id];
165
+ if (!collection) return;
166
+
167
+ let module = collection.modules[loggerAction.module_id];
168
+ if (!module) return;
169
+
170
+ this.#sessionResults.errors += 1;
171
+ runResults.errors += 1;
172
+ collection.errors += 1;
173
+ module.errors += 1;
174
+ module.errorLogs.push(loggerAction);
175
+ }
176
+
177
+ if ("start_test" === loggerAction.type) {
178
+ let collection = runResults.collections[loggerAction.collection_id];
179
+ if (!collection) return;
180
+
181
+ let module = collection.modules[loggerAction.module_id];
182
+ if (!module) return;
183
+
184
+ module.testResults[loggerAction.test_id] = {
185
+ loggerStartAction: loggerAction,
186
+ loggerEndAction: undefined,
187
+ };
188
+ }
189
+
190
+ if ("end_test" === loggerAction.type) {
191
+ endTest(this.#sessionResults, runResults, loggerAction);
192
+ }
193
+
194
+ if ("test_error" === loggerAction.type) {
195
+ let collection = runResults.collections[loggerAction.collection_id];
196
+ if (!collection) return;
197
+
198
+ let module = collection.modules[loggerAction.module_id];
199
+ if (!module) return;
200
+
201
+ let testResult = module.testResults[loggerAction.test_id];
202
+ if (!testResult) return;
203
+
204
+ testResult.loggerEndAction = loggerAction;
205
+ this.#sessionResults.errors += 1;
206
+ runResults.errors += 1;
207
+ collection.errors += 1;
208
+ module.errors += 1;
209
+ }
210
+ }
211
+ }
212
+
213
+ function endTest(
214
+ sessionResults: SessionResults,
215
+ runResults: RunResults,
216
+ loggerAction: EndTest,
217
+ ) {
218
+ let collection = runResults.collections[loggerAction.collection_id];
219
+ if (!collection) return;
220
+
221
+ let module = collection.modules[loggerAction.module_id];
222
+ if (!module) return;
223
+
224
+ let testResult = module.testResults[loggerAction.test_id];
225
+ if (!testResult) return;
226
+
227
+ testResult.loggerEndAction = loggerAction;
228
+ runResults.completedTests += 1;
229
+ collection.completedTests += 1;
230
+ module.completedTests += 1;
231
+
232
+ let { assertions } = loggerAction;
233
+ const isAssertionArray = Array.isArray(assertions) && assertions.length;
234
+ // might be worth just sticking with language standard "none" like "" or 0 or false
235
+ const isAssertion = !Array.isArray(assertions) && undefined !== assertions;
236
+ if (isAssertion || isAssertionArray) {
237
+ sessionResults.fails += 1;
238
+ runResults.fails += 1;
239
+ collection.fails += 1;
240
+ module.fails += 1;
241
+ }
242
+
243
+ runResults.testTime += Math.max(
244
+ 0,
245
+ loggerAction.end_time - loggerAction.start_time,
246
+ );
247
+ }
@@ -0,0 +1,45 @@
1
+ #!/usr/bin/env node
2
+
3
+ import * as http from "http";
4
+ import { createConfig } from "./config.js";
5
+ import { Logger } from "./logger.js";
6
+ import { Router } from "./routes.js";
7
+ import { WebDrivers } from "./webdriver.js";
8
+ import { EventBus } from "./eventbus.js";
9
+
10
+ let args = process.argv.slice(2);
11
+
12
+ const config = await createConfig(args);
13
+ if (config instanceof Error) {
14
+ console.log(config);
15
+ process.exit(1);
16
+ }
17
+
18
+ let eventbus = new EventBus();
19
+ let logger = new Logger(config, eventbus);
20
+ let router = new Router(config, eventbus);
21
+ let webdrivers = new WebDrivers(config, eventbus);
22
+
23
+ // setup server
24
+ let server = http.createServer();
25
+ server.addListener("request", router.route);
26
+ server.addListener("close", function () {
27
+ console.log(logger.results);
28
+ logger.errored || logger.failed || !logger.completed
29
+ ? process.exit(1)
30
+ : process.exit(0);
31
+ });
32
+ eventbus.addListener("end", function () {
33
+ server.closeAllConnections();
34
+ server.close();
35
+ });
36
+
37
+ // run server
38
+ let { port, hostname } = config.hostAndPort;
39
+ server.listen({
40
+ port,
41
+ hostname,
42
+ });
43
+
44
+ // start test run
45
+ config.runAsynchronously ? webdrivers.runAll() : webdrivers.run();