@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.
- package/.github/workflows/browsers.json +55 -0
- package/.github/workflows/browsers.macos.json +51 -0
- package/.github/workflows/browsers.windows.json +19 -0
- package/.github/workflows/tests.yml +13 -0
- package/README.md +41 -1
- package/browser/dist/logger.js +43 -0
- package/browser/dist/mod.js +25 -0
- package/browser/dist/queue.js +27 -0
- package/browser/dist/runner.js +20 -0
- package/{cli → browser}/package.json +1 -1
- package/browser/src/logger.ts +57 -0
- package/browser/src/mod.ts +30 -0
- package/browser/src/runner.ts +22 -0
- package/browser/tsconfig.json +11 -0
- package/browser/tsconfig.tsbuildinfo +1 -0
- package/browsers.json +38 -0
- package/core/dist/jackrabbit_types.d.ts +61 -27
- package/core/dist/mod.d.ts +2 -2
- package/core/dist/mod.js +1 -1
- package/core/dist/run_steps.d.ts +2 -2
- package/core/dist/run_steps.js +83 -67
- package/core/src/jackrabbit_types.ts +72 -28
- package/core/src/mod.ts +2 -8
- package/core/src/run_steps.ts +111 -80
- package/examples/hello_world/goodbye_world.ts +1 -1
- package/examples/hello_world/hello_world.ts +1 -1
- package/nodejs/dist/logger.js +164 -0
- package/nodejs/dist/mod.js +33 -0
- package/nodejs/dist/results.js +145 -0
- package/nodejs/dist/results_str.js +147 -0
- package/nodejs/dist/runner.js +17 -0
- package/nodejs/src/logger.ts +200 -0
- package/nodejs/src/mod.ts +39 -0
- package/nodejs/src/results.ts +239 -0
- package/{nodejs_cli → nodejs}/tsconfig.json +2 -1
- package/nodejs/tsconfig.tsbuildinfo +1 -0
- package/package.json +6 -4
- package/tests/dist/mod.d.ts +14 -3
- package/tests/dist/mod.js +33 -15
- package/tests/dist/test_error.test.d.ts +9 -0
- package/tests/dist/test_error.test.js +25 -0
- package/tests/dist/test_errors.test.d.ts +9 -0
- package/tests/dist/test_errors.test.js +27 -0
- package/tests/dist/test_fail.test.js +0 -2
- package/tests/dist/test_logger.d.ts +3 -2
- package/tests/dist/test_logger.js +5 -1
- package/tests/dist/test_pass.test.js +0 -2
- package/tests/src/mod.ts +31 -15
- package/tests/src/test_error.test.ts +32 -0
- package/tests/src/test_logger.ts +6 -1
- package/tests/tsconfig.tsbuildinfo +1 -1
- package/tsconfig.json +3 -2
- package/webdriver/dist/config.js +56 -0
- package/webdriver/dist/eventbus.js +18 -0
- package/webdriver/dist/listeners.js +21 -0
- package/webdriver/dist/logger.js +200 -0
- package/webdriver/dist/mod.js +35 -0
- package/webdriver/dist/results.js +190 -0
- package/webdriver/dist/results_str.js +167 -0
- package/webdriver/dist/routes.js +162 -0
- package/webdriver/dist/routes2.js +163 -0
- package/webdriver/dist/test_hangar.js +20 -0
- package/webdriver/dist/webdriver.js +272 -0
- package/webdriver/package.json +8 -0
- package/webdriver/src/config.ts +89 -0
- package/webdriver/src/eventbus.ts +104 -0
- package/webdriver/src/logger.ts +247 -0
- package/webdriver/src/mod.ts +45 -0
- package/webdriver/src/results.ts +311 -0
- package/webdriver/src/routes.ts +198 -0
- package/webdriver/src/test_hangar.ts +25 -0
- package/webdriver/src/webdriver.ts +373 -0
- package/{cli → webdriver}/tsconfig.json +1 -0
- package/webdriver/tsconfig.tsbuildinfo +1 -0
- package/cli/dist/cli.d.ts +0 -3
- package/cli/dist/cli.js +0 -8
- package/cli/dist/cli_types.d.ts +0 -7
- package/cli/dist/cli_types.js +0 -1
- package/cli/dist/config.d.ts +0 -5
- package/cli/dist/config.js +0 -6
- package/cli/dist/importer.d.ts +0 -7
- package/cli/dist/importer.js +0 -16
- package/cli/dist/logger.d.ts +0 -7
- package/cli/dist/logger.js +0 -88
- package/cli/dist/mod.d.ts +0 -6
- package/cli/dist/mod.js +0 -4
- package/cli/src/cli.ts +0 -17
- package/cli/src/cli_types.ts +0 -9
- package/cli/src/config.ts +0 -9
- package/cli/src/importer.ts +0 -25
- package/cli/src/logger.ts +0 -126
- package/cli/src/mod.ts +0 -7
- package/cli/tsconfig.tsbuildinfo +0 -1
- package/nodejs_cli/dist/mod.d.ts +0 -2
- package/nodejs_cli/dist/mod.js +0 -20
- package/nodejs_cli/src/mod.ts +0 -25
- package/nodejs_cli/tsconfig.tsbuildinfo +0 -1
- /package/{nodejs_cli → nodejs}/package.json +0 -0
|
@@ -0,0 +1,311 @@
|
|
|
1
|
+
import type { LoggerAction } from "../../core/dist/jackrabbit_types.js";
|
|
2
|
+
import type { WebdriverParams } from "./config.js";
|
|
3
|
+
import type { WebdriverActions } from "./eventbus.js";
|
|
4
|
+
|
|
5
|
+
export interface TestResults {
|
|
6
|
+
loggerStartAction: LoggerAction;
|
|
7
|
+
loggerEndAction: LoggerAction | undefined;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export interface ModuleResults {
|
|
11
|
+
loggerAction: LoggerAction;
|
|
12
|
+
fails: number;
|
|
13
|
+
errors: number;
|
|
14
|
+
expectedTests: number;
|
|
15
|
+
completedTests: number;
|
|
16
|
+
errorLogs: LoggerAction[];
|
|
17
|
+
testResults: (TestResults | undefined)[];
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export interface CollectionResults {
|
|
21
|
+
loggerAction: LoggerAction;
|
|
22
|
+
fails: number;
|
|
23
|
+
errors: number;
|
|
24
|
+
expectedTests: number;
|
|
25
|
+
completedTests: number;
|
|
26
|
+
expectedModules: number;
|
|
27
|
+
completedModules: number;
|
|
28
|
+
errorLogs: LoggerAction[];
|
|
29
|
+
modules: (ModuleResults | undefined)[];
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export interface RunResults {
|
|
33
|
+
fails: number;
|
|
34
|
+
errors: number;
|
|
35
|
+
startTime: number;
|
|
36
|
+
endTime: number;
|
|
37
|
+
testTime: number;
|
|
38
|
+
expectedTests: number;
|
|
39
|
+
completedTests: number;
|
|
40
|
+
expectedModules: number;
|
|
41
|
+
completedModules: number;
|
|
42
|
+
expectedCollections: number;
|
|
43
|
+
completedCollections: number;
|
|
44
|
+
errorLogs: WebdriverActions[];
|
|
45
|
+
webdriverParams: WebdriverParams;
|
|
46
|
+
collections: (CollectionResults | undefined)[];
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export interface SessionResults {
|
|
50
|
+
fails: number;
|
|
51
|
+
errors: number;
|
|
52
|
+
runs: Map<string, RunResults>;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const SPACE = " ";
|
|
56
|
+
|
|
57
|
+
/*
|
|
58
|
+
Lots of nested loops because results a nested structure.
|
|
59
|
+
I'd rather see composition nested in one function
|
|
60
|
+
than have for loops spread across each function.
|
|
61
|
+
*/
|
|
62
|
+
|
|
63
|
+
export function getResultsAsString(sessionResults: SessionResults): string {
|
|
64
|
+
const output: string[] = [];
|
|
65
|
+
|
|
66
|
+
logSessionErrors(output, sessionResults);
|
|
67
|
+
|
|
68
|
+
for (let [, result] of sessionResults.runs) {
|
|
69
|
+
if (logRunResults(output, result)) continue;
|
|
70
|
+
|
|
71
|
+
for (const collection of result.collections) {
|
|
72
|
+
if (logCollectionResult(output, collection)) continue;
|
|
73
|
+
|
|
74
|
+
if (collection)
|
|
75
|
+
for (const moduleResult of collection.modules) {
|
|
76
|
+
if (logModuleResult(output, moduleResult)) continue;
|
|
77
|
+
|
|
78
|
+
if (moduleResult)
|
|
79
|
+
for (const testResult of moduleResult.testResults) {
|
|
80
|
+
logTest(output, testResult);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
logSummary(output, sessionResults);
|
|
87
|
+
|
|
88
|
+
return output.join("\n");
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function logSessionErrors(output: string[], sessionResults: SessionResults) {
|
|
92
|
+
if (!sessionResults.runs.size) output.push("\nNo webdrivers were run.");
|
|
93
|
+
|
|
94
|
+
for (let [, result] of sessionResults.runs) {
|
|
95
|
+
if (result.errorLogs.length)
|
|
96
|
+
output.push(`\n${result.webdriverParams.title}`);
|
|
97
|
+
for (let errorAction of result.errorLogs) {
|
|
98
|
+
if ("session_error" === errorAction.type) {
|
|
99
|
+
output.push(`${SPACE}[session_error] ${errorAction.error}`);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
function logRunResults(output: string[], result: RunResults): boolean {
|
|
106
|
+
output.push(`\n${result.webdriverParams.title}`);
|
|
107
|
+
|
|
108
|
+
for (let errorAction of result.errorLogs) {
|
|
109
|
+
if ("log" !== errorAction.type) continue;
|
|
110
|
+
if ("run_error" !== errorAction.loggerAction.type) continue;
|
|
111
|
+
|
|
112
|
+
output.push(
|
|
113
|
+
`${SPACE.repeat(2)}[run_error] ${errorAction.loggerAction.error}`,
|
|
114
|
+
);
|
|
115
|
+
}
|
|
116
|
+
if (result.errorLogs.length) output.push("");
|
|
117
|
+
|
|
118
|
+
if (!result.collections && !result.expectedTests) {
|
|
119
|
+
output.push(`${SPACE}No tests were run.`);
|
|
120
|
+
return true;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// When everything goes right :3
|
|
124
|
+
if (
|
|
125
|
+
!result.fails &&
|
|
126
|
+
!result.errors &&
|
|
127
|
+
result.expectedTests === result.completedTests &&
|
|
128
|
+
result.expectedModules === result.completedModules &&
|
|
129
|
+
result.expectedCollections === result.completedCollections
|
|
130
|
+
) {
|
|
131
|
+
output.push(`${SPACE}${result.completedTests} tests
|
|
132
|
+
${SPACE}${result.completedModules} modules
|
|
133
|
+
${SPACE}${result.completedCollections} collections`);
|
|
134
|
+
return true;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
return false;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
function logCollectionResult(
|
|
141
|
+
output: string[],
|
|
142
|
+
collection: CollectionResults | undefined,
|
|
143
|
+
): boolean {
|
|
144
|
+
if (!collection) return true;
|
|
145
|
+
|
|
146
|
+
let { loggerAction } = collection;
|
|
147
|
+
if ("start_collection" !== loggerAction.type) return true;
|
|
148
|
+
|
|
149
|
+
output.push(`${SPACE}${loggerAction.collection_url}`);
|
|
150
|
+
|
|
151
|
+
// when everything in the collection goes right
|
|
152
|
+
if (
|
|
153
|
+
!collection.fails &&
|
|
154
|
+
!collection.errors &&
|
|
155
|
+
collection.expectedTests === collection.completedTests &&
|
|
156
|
+
collection.expectedModules === collection.completedModules
|
|
157
|
+
) {
|
|
158
|
+
output.push(
|
|
159
|
+
`${SPACE.repeat(2)}${collection.expectedTests} tests
|
|
160
|
+
${SPACE.repeat(2)}${loggerAction.expected_module_count} modules`,
|
|
161
|
+
);
|
|
162
|
+
|
|
163
|
+
return true;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
for (let errorAction of collection.errorLogs) {
|
|
167
|
+
if ("collection_error" !== errorAction.type) continue;
|
|
168
|
+
output.push(`${SPACE.repeat(2)}[collection_error] ${errorAction.error}`);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
if (collection.errorLogs.length) output.push("");
|
|
172
|
+
|
|
173
|
+
return false;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
function logModuleResult(
|
|
177
|
+
output: string[],
|
|
178
|
+
module: ModuleResults | undefined,
|
|
179
|
+
): boolean {
|
|
180
|
+
if (!module) return true;
|
|
181
|
+
|
|
182
|
+
let { loggerAction } = module;
|
|
183
|
+
if ("start_module" !== loggerAction.type) return true;
|
|
184
|
+
|
|
185
|
+
output.push(`${SPACE.repeat(2)}${loggerAction.module_name}`);
|
|
186
|
+
|
|
187
|
+
// when everything in the module goes right
|
|
188
|
+
if (
|
|
189
|
+
!module.fails &&
|
|
190
|
+
!module.errors &&
|
|
191
|
+
module.expectedTests === module.completedTests
|
|
192
|
+
) {
|
|
193
|
+
output.push(`${SPACE.repeat(3)}${module.expectedTests} tests`);
|
|
194
|
+
return true;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
output.push(
|
|
198
|
+
`${SPACE.repeat(3)}${module.completedTests - module.fails}/${module.expectedTests} tests`,
|
|
199
|
+
);
|
|
200
|
+
|
|
201
|
+
output.push("");
|
|
202
|
+
for (let errorAction of module.errorLogs) {
|
|
203
|
+
if ("module_error" !== errorAction.type) continue;
|
|
204
|
+
output.push(`${SPACE.repeat(3)}[module_error] ${errorAction.error}`);
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
if (module.errorLogs.length) output.push("");
|
|
208
|
+
|
|
209
|
+
return false;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
function logTest(output: string[], test: TestResults | undefined) {
|
|
213
|
+
if (!test) return;
|
|
214
|
+
|
|
215
|
+
let { loggerStartAction, loggerEndAction } = test;
|
|
216
|
+
if ("start_test" !== loggerStartAction.type) return;
|
|
217
|
+
|
|
218
|
+
if ("test_error" === loggerEndAction?.type) {
|
|
219
|
+
let { test_name } = loggerStartAction;
|
|
220
|
+
output.push(
|
|
221
|
+
`${SPACE.repeat(3)}${test_name}
|
|
222
|
+
${SPACE.repeat(4)}[error] ${loggerEndAction.error}`,
|
|
223
|
+
);
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
if ("end_test" === loggerEndAction?.type) {
|
|
227
|
+
let { assertions } = loggerEndAction;
|
|
228
|
+
const isAssertionArray = Array.isArray(assertions) && assertions.length;
|
|
229
|
+
const isAssertion =
|
|
230
|
+
!Array.isArray(assertions) &&
|
|
231
|
+
undefined !== assertions &&
|
|
232
|
+
null !== assertions;
|
|
233
|
+
|
|
234
|
+
if (isAssertion || isAssertionArray) {
|
|
235
|
+
let { test_name } = loggerStartAction;
|
|
236
|
+
output.push(`${SPACE.repeat(3)}${test_name}`);
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
if (isAssertion) {
|
|
240
|
+
output.push(`${SPACE.repeat(4)}- ${assertions}`);
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
if (isAssertionArray) {
|
|
244
|
+
for (const assertion of assertions) {
|
|
245
|
+
output.push(`${SPACE.repeat(4)}- ${assertion}`);
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
if (undefined === loggerEndAction) {
|
|
251
|
+
let { test_name } = loggerStartAction;
|
|
252
|
+
|
|
253
|
+
output.push(`${SPACE.repeat(3)}${test_name}
|
|
254
|
+
${SPACE.repeat(4)}[incomplete]`);
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
function logSummary(output: string[], sessionResults: SessionResults) {
|
|
259
|
+
let status_with_color = blue("\u{2714} passed");
|
|
260
|
+
|
|
261
|
+
if (!isComplete(sessionResults))
|
|
262
|
+
status_with_color = gray("\u{2717} incomplete");
|
|
263
|
+
if (sessionResults.fails) status_with_color = yellow("\u{2717} failed");
|
|
264
|
+
if (sessionResults.errors) status_with_color = gray("\u{2717} errored");
|
|
265
|
+
|
|
266
|
+
let totalTime = 0;
|
|
267
|
+
let testTime = 0;
|
|
268
|
+
for (let [, run] of sessionResults.runs) {
|
|
269
|
+
totalTime += run.endTime - run.startTime;
|
|
270
|
+
testTime += run.testTime;
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
output.push(`
|
|
274
|
+
${status_with_color}
|
|
275
|
+
duration: ${testTime.toFixed(4)} mS
|
|
276
|
+
total: ${totalTime.toFixed(4)} mS
|
|
277
|
+
`);
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
export function isComplete(sessionResults: SessionResults): boolean {
|
|
281
|
+
for (const [, result] of sessionResults.runs) {
|
|
282
|
+
if (
|
|
283
|
+
!result.expectedTests ||
|
|
284
|
+
!result.expectedModules ||
|
|
285
|
+
!result.expectedCollections
|
|
286
|
+
)
|
|
287
|
+
return false;
|
|
288
|
+
if (
|
|
289
|
+
result.expectedTests !== result.completedTests ||
|
|
290
|
+
result.expectedModules !== result.completedModules ||
|
|
291
|
+
result.expectedCollections !== result.completedCollections
|
|
292
|
+
)
|
|
293
|
+
return false;
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
return true;
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
// 39 - default foreground color
|
|
300
|
+
// 49 - default background color
|
|
301
|
+
function blue(text: string) {
|
|
302
|
+
return `\x1b[44m\x1b[97m${text}\x1b[0m`;
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
function yellow(text: string) {
|
|
306
|
+
return `\x1b[43m\x1b[97m${text}\x1b[0m`;
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
function gray(text: string) {
|
|
310
|
+
return `\x1b[100m\x1b[97m${text}\x1b[0m`;
|
|
311
|
+
}
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
import type { IncomingMessage, ServerResponse } from "http";
|
|
2
|
+
import type { EventBus } from "./eventbus.js";
|
|
3
|
+
import type { LoggerAction } from "../../core/dist/jackrabbit_types.js";
|
|
4
|
+
|
|
5
|
+
import * as fs from "fs";
|
|
6
|
+
import * as path from "path";
|
|
7
|
+
import { testHanger } from "./test_hangar.js";
|
|
8
|
+
import { ConfigInterface } from "./config.js";
|
|
9
|
+
|
|
10
|
+
let cwd = process.cwd();
|
|
11
|
+
const parentPath = path.join(import.meta.url.substring(5), "../../../");
|
|
12
|
+
|
|
13
|
+
const MIME_TYPES: Record<string, string> = {
|
|
14
|
+
octet: "application/octet-stream",
|
|
15
|
+
html: "text/html; charset=UTF-8",
|
|
16
|
+
js: "text/javascript",
|
|
17
|
+
json: "application/json",
|
|
18
|
+
css: "text/css",
|
|
19
|
+
png: "image/png",
|
|
20
|
+
jpg: "image/jpeg",
|
|
21
|
+
ico: "image/x-icon",
|
|
22
|
+
svg: "image/svg+xml",
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
export class Router {
|
|
26
|
+
#config: ConfigInterface;
|
|
27
|
+
#eventbus: EventBus;
|
|
28
|
+
|
|
29
|
+
constructor(config: ConfigInterface, eventbus: EventBus) {
|
|
30
|
+
this.#config = config;
|
|
31
|
+
this.#eventbus = eventbus;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
get route() {
|
|
35
|
+
return this.#boundRoute;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
#boundRoute = this.#route.bind(this);
|
|
39
|
+
async #route(req: IncomingMessage, res: ServerResponse) {
|
|
40
|
+
if (serveBadRequest(req, res)) return;
|
|
41
|
+
if (servePing(req, res)) return;
|
|
42
|
+
if (serveTestPage(req, res, this.#config)) return;
|
|
43
|
+
if (logAction(req, res, this.#eventbus)) return;
|
|
44
|
+
|
|
45
|
+
await serveFile(req, res);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function serveBadRequest(req: IncomingMessage, res: ServerResponse): boolean {
|
|
50
|
+
let { url } = req;
|
|
51
|
+
if (url) return false;
|
|
52
|
+
|
|
53
|
+
res.setHeader("Content-Type", "text/html");
|
|
54
|
+
res.writeHead(400);
|
|
55
|
+
res.end();
|
|
56
|
+
|
|
57
|
+
return true;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function servePing(req: IncomingMessage, res: ServerResponse): boolean {
|
|
61
|
+
let { url, method } = req;
|
|
62
|
+
if (url !== "/ping" || "GET" !== method) return false;
|
|
63
|
+
|
|
64
|
+
res.setHeader("Content-Type", "text/html");
|
|
65
|
+
res.writeHead(200);
|
|
66
|
+
res.end("The cookie train has arrived!");
|
|
67
|
+
|
|
68
|
+
return true;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function serveTestPage(
|
|
72
|
+
req: IncomingMessage,
|
|
73
|
+
res: ServerResponse,
|
|
74
|
+
config: ConfigInterface,
|
|
75
|
+
): boolean {
|
|
76
|
+
let { url, method } = req;
|
|
77
|
+
if (url !== "/" || "GET" !== method) return false;
|
|
78
|
+
|
|
79
|
+
let hangar = testHanger({
|
|
80
|
+
jackrabbit_url: config.hostAndPort,
|
|
81
|
+
test_collections: process.argv.slice(3),
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
res.setHeader("Content-Type", "text/html");
|
|
85
|
+
res.writeHead(200);
|
|
86
|
+
res.end(hangar);
|
|
87
|
+
|
|
88
|
+
return true;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function logAction(
|
|
92
|
+
req: IncomingMessage,
|
|
93
|
+
res: ServerResponse,
|
|
94
|
+
eventbus: EventBus,
|
|
95
|
+
): boolean {
|
|
96
|
+
let { url, method } = req;
|
|
97
|
+
if (!url?.startsWith("/log/") || "POST" !== method) return false;
|
|
98
|
+
|
|
99
|
+
let id: string | undefined;
|
|
100
|
+
let cookies = req.headers.cookie?.split(";") ?? [];
|
|
101
|
+
for (const cookieLine of cookies) {
|
|
102
|
+
if (cookieLine.startsWith("jackrabbit=")) {
|
|
103
|
+
let [_name, value] = cookieLine.split("=");
|
|
104
|
+
id = value;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
if (id) {
|
|
109
|
+
getLoggerActionFromRequestBody(req)
|
|
110
|
+
.then(function (loggerAction: LoggerAction) {
|
|
111
|
+
eventbus.dispatchAction({
|
|
112
|
+
type: "log",
|
|
113
|
+
loggerAction,
|
|
114
|
+
id,
|
|
115
|
+
});
|
|
116
|
+
res.writeHead(201);
|
|
117
|
+
})
|
|
118
|
+
.catch(function () {
|
|
119
|
+
res.writeHead(401);
|
|
120
|
+
})
|
|
121
|
+
.finally(function () {
|
|
122
|
+
res.end();
|
|
123
|
+
});
|
|
124
|
+
} else {
|
|
125
|
+
res.writeHead(401);
|
|
126
|
+
res.end();
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
return true;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
async function serveFile(req: IncomingMessage, res: ServerResponse) {
|
|
133
|
+
let { url, method } = req;
|
|
134
|
+
|
|
135
|
+
if (!url || "GET" !== method) {
|
|
136
|
+
res.setHeader("Content-Type", MIME_TYPES["html"]);
|
|
137
|
+
res.writeHead(400);
|
|
138
|
+
res.end();
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// assume http 1.1
|
|
143
|
+
let urlFilePath = path.join(url);
|
|
144
|
+
|
|
145
|
+
let extStr = "";
|
|
146
|
+
if (url.endsWith("/")) extStr = "index.html";
|
|
147
|
+
let urlNoPrefix = url;
|
|
148
|
+
|
|
149
|
+
if (urlFilePath.startsWith("/jackrabbit")) {
|
|
150
|
+
let strippedUrl = urlFilePath.substring("/jackrabbit".length);
|
|
151
|
+
urlFilePath = path.join(parentPath, strippedUrl, extStr);
|
|
152
|
+
} else {
|
|
153
|
+
urlFilePath = path.join(cwd, urlNoPrefix, extStr);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
let stream = await getFile(urlFilePath);
|
|
157
|
+
|
|
158
|
+
if (stream) {
|
|
159
|
+
// throws errors if not a string
|
|
160
|
+
// filepath is always a string
|
|
161
|
+
const ext = path.extname(urlFilePath).substring(1).toLowerCase();
|
|
162
|
+
let mimeType = MIME_TYPES[ext] ?? MIME_TYPES["octet"];
|
|
163
|
+
res.setHeader("Content-Type", mimeType);
|
|
164
|
+
res.writeHead(200);
|
|
165
|
+
stream.pipe(res);
|
|
166
|
+
} else {
|
|
167
|
+
res.setHeader("Content-Type", MIME_TYPES["html"]);
|
|
168
|
+
res.writeHead(404);
|
|
169
|
+
res.end();
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
function getLoggerActionFromRequestBody(
|
|
174
|
+
req: IncomingMessage,
|
|
175
|
+
): Promise<LoggerAction> {
|
|
176
|
+
return new Promise(function (resolve, reject) {
|
|
177
|
+
let data: Uint8Array[] = [];
|
|
178
|
+
req.addListener("data", function (chunk) {
|
|
179
|
+
data.push(chunk);
|
|
180
|
+
});
|
|
181
|
+
req.addListener("end", function () {
|
|
182
|
+
let actionStr = Buffer.concat(data).toString();
|
|
183
|
+
let action = JSON.parse(actionStr) as LoggerAction;
|
|
184
|
+
|
|
185
|
+
resolve(action);
|
|
186
|
+
});
|
|
187
|
+
req.addListener("error", function (err: Error) {
|
|
188
|
+
reject(err);
|
|
189
|
+
});
|
|
190
|
+
});
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
async function getFile(filePath: string): Promise<fs.ReadStream | undefined> {
|
|
194
|
+
try {
|
|
195
|
+
await fs.promises.access(filePath);
|
|
196
|
+
return fs.createReadStream(filePath);
|
|
197
|
+
} catch {}
|
|
198
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
interface TestHangerParams {
|
|
2
|
+
jackrabbit_url: URL;
|
|
3
|
+
test_collections: string[];
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
export function testHanger(params: TestHangerParams) {
|
|
7
|
+
return `<!DOCTYPE html>
|
|
8
|
+
<html>
|
|
9
|
+
<head>
|
|
10
|
+
<script type="jackrabbit_config">
|
|
11
|
+
${JSON.stringify(params)}
|
|
12
|
+
</script>
|
|
13
|
+
<script type="importmap">
|
|
14
|
+
{
|
|
15
|
+
"imports": {
|
|
16
|
+
"jackrabbit/core/": "/jackrabbit/core/"
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
</script>
|
|
20
|
+
<script type="module" src="/jackrabbit/browser/dist/mod.js"></script>
|
|
21
|
+
</head>
|
|
22
|
+
<body></body>
|
|
23
|
+
</html>
|
|
24
|
+
`;
|
|
25
|
+
}
|