@gjsify/unit 0.1.15 → 0.3.0
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/lib/esm/index.js +29 -6
- package/lib/types/index.d.ts +2 -2
- package/package.json +9 -9
- package/src/index.ts +45 -6
package/lib/esm/index.js
CHANGED
|
@@ -8,6 +8,8 @@ let countTestsFailed = 0;
|
|
|
8
8
|
let countTestsIgnored = 0;
|
|
9
9
|
let runtime = "";
|
|
10
10
|
let runStartTime = 0;
|
|
11
|
+
let currentSuite = "";
|
|
12
|
+
let testErrors = [];
|
|
11
13
|
const DEFAULT_TIMEOUT_CONFIG = {
|
|
12
14
|
testTimeout: 5e3,
|
|
13
15
|
suiteTimeout: 3e4,
|
|
@@ -62,7 +64,8 @@ const formatDuration = (ms) => {
|
|
|
62
64
|
if (ms >= 100) return `${Math.round(ms)}ms`;
|
|
63
65
|
return `${ms.toFixed(1)}ms`;
|
|
64
66
|
};
|
|
65
|
-
const
|
|
67
|
+
const _isGjsProcess = typeof globalThis.process?.versions?.gjs === "string";
|
|
68
|
+
const print = !_isGjsProcess && typeof globalThis.document !== "undefined" ? console.log : globalThis.print || console.log;
|
|
66
69
|
class MatcherFactory {
|
|
67
70
|
constructor(actualValue, positive, negated) {
|
|
68
71
|
this.actualValue = actualValue;
|
|
@@ -330,6 +333,8 @@ class MatcherFactory {
|
|
|
330
333
|
const describe = async function(moduleName, callback, options) {
|
|
331
334
|
const suiteTimeoutMs = typeof options === "number" ? options : options?.timeout ?? timeoutConfig.suiteTimeout;
|
|
332
335
|
print("\n" + moduleName);
|
|
336
|
+
const prevSuite = currentSuite;
|
|
337
|
+
currentSuite = moduleName;
|
|
333
338
|
const t0 = now();
|
|
334
339
|
try {
|
|
335
340
|
await withTimeout(callback, suiteTimeoutMs, `describe: ${moduleName}`);
|
|
@@ -341,6 +346,7 @@ const describe = async function(moduleName, callback, options) {
|
|
|
341
346
|
throw e;
|
|
342
347
|
}
|
|
343
348
|
}
|
|
349
|
+
currentSuite = prevSuite;
|
|
344
350
|
const duration = now() - t0;
|
|
345
351
|
print(` ${GRAY}\u21B3 ${formatDuration(duration)}${RESET}`);
|
|
346
352
|
beforeEachCb = null;
|
|
@@ -432,6 +438,7 @@ const it = async function(expectation, callback, options) {
|
|
|
432
438
|
if (!e.__testFailureCounted) {
|
|
433
439
|
++countTestsFailed;
|
|
434
440
|
}
|
|
441
|
+
testErrors.push({ suite: currentSuite, test: expectation, message: e.message ?? String(e) });
|
|
435
442
|
const icon = e instanceof TimeoutError ? "\u23F1" : "\u274C";
|
|
436
443
|
print(` ${RED}${icon}${RESET} ${GRAY}${expectation} (${formatDuration(duration)})${RESET}`);
|
|
437
444
|
print(`${RED}${e.message}${RESET}`);
|
|
@@ -502,6 +509,17 @@ const runTests = async function(namespaces) {
|
|
|
502
509
|
}
|
|
503
510
|
}
|
|
504
511
|
};
|
|
512
|
+
const browserSignalDone = () => {
|
|
513
|
+
const doc = globalThis.document;
|
|
514
|
+
if (!doc) return;
|
|
515
|
+
globalThis.__gjsify_test_results = {
|
|
516
|
+
passed: countTestsOverall - countTestsFailed,
|
|
517
|
+
failed: countTestsFailed,
|
|
518
|
+
total: countTestsOverall,
|
|
519
|
+
errors: testErrors
|
|
520
|
+
};
|
|
521
|
+
doc.documentElement.dataset.testsDone = "true";
|
|
522
|
+
};
|
|
505
523
|
const printResult = () => {
|
|
506
524
|
const totalMs = runStartTime > 0 ? now() - runStartTime : 0;
|
|
507
525
|
const durationStr = totalMs > 0 ? ` ${GRAY}(${formatDuration(totalMs)})` : "";
|
|
@@ -523,23 +541,27 @@ const getRuntime = async () => {
|
|
|
523
541
|
}
|
|
524
542
|
if (globalThis.Deno?.version?.deno) {
|
|
525
543
|
return "Deno " + globalThis.Deno?.version?.deno;
|
|
526
|
-
}
|
|
544
|
+
}
|
|
545
|
+
{
|
|
527
546
|
let process = globalThis.process;
|
|
528
547
|
if (!process) {
|
|
529
548
|
try {
|
|
530
549
|
process = await import("process");
|
|
531
|
-
} catch (
|
|
532
|
-
console.error(error);
|
|
533
|
-
console.warn(error.message);
|
|
534
|
-
runtime = "Unknown";
|
|
550
|
+
} catch (_e) {
|
|
535
551
|
}
|
|
536
552
|
}
|
|
537
553
|
if (process?.versions?.gjs) {
|
|
538
554
|
runtime = "Gjs " + process.versions.gjs;
|
|
555
|
+
return runtime;
|
|
539
556
|
} else if (process?.versions?.node) {
|
|
540
557
|
runtime = "Node.js " + process.versions.node;
|
|
558
|
+
return runtime;
|
|
541
559
|
}
|
|
542
560
|
}
|
|
561
|
+
if (typeof globalThis.document !== "undefined") {
|
|
562
|
+
runtime = "Browser";
|
|
563
|
+
return runtime;
|
|
564
|
+
}
|
|
543
565
|
return runtime || "Unknown";
|
|
544
566
|
};
|
|
545
567
|
const printRuntime = async () => {
|
|
@@ -573,6 +595,7 @@ ${RED}\u23F1 ${e.message}${RESET}`);
|
|
|
573
595
|
}
|
|
574
596
|
}).then(async () => {
|
|
575
597
|
printResult();
|
|
598
|
+
browserSignalDone();
|
|
576
599
|
print();
|
|
577
600
|
quitMainLoop();
|
|
578
601
|
mainloop?.quit();
|
package/lib/types/index.d.ts
CHANGED
|
@@ -14,7 +14,7 @@ export interface Namespaces {
|
|
|
14
14
|
}
|
|
15
15
|
export type Callback = () => Promise<void>;
|
|
16
16
|
export type Runtime = 'Gjs' | 'Deno' | 'Node.js' | 'Unknown' | 'Browser' | 'Display';
|
|
17
|
-
export declare const print:
|
|
17
|
+
export declare const print: (...data: any[]) => void;
|
|
18
18
|
declare class MatcherFactory {
|
|
19
19
|
protected readonly actualValue: any;
|
|
20
20
|
protected readonly positive: boolean;
|
|
@@ -101,6 +101,6 @@ declare const _default: {
|
|
|
101
101
|
skip(moduleName: string, _callback?: Callback): Promise<void>;
|
|
102
102
|
};
|
|
103
103
|
configure: (overrides: Partial<TimeoutConfig>) => void;
|
|
104
|
-
print:
|
|
104
|
+
print: (...data: any[]) => void;
|
|
105
105
|
};
|
|
106
106
|
export default _default;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gjsify/unit",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "A BDD-style testing framework for Gjs",
|
|
5
5
|
"module": "lib/esm/index.js",
|
|
6
6
|
"types": "lib/types/index.d.ts",
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
"build:test:gjs": "gjsify build src/test.mts --app gjs --outfile test.gjs.mjs",
|
|
22
22
|
"build:test:node": "gjsify build src/test.mts --app node --outfile test.node.mjs",
|
|
23
23
|
"test": "yarn build:gjsify && yarn build:test && yarn test:node && yarn test:gjs",
|
|
24
|
-
"test:gjs": "
|
|
24
|
+
"test:gjs": "gjsify run test.gjs.mjs",
|
|
25
25
|
"test:node": "node test.node.mjs"
|
|
26
26
|
},
|
|
27
27
|
"repository": {
|
|
@@ -41,15 +41,15 @@
|
|
|
41
41
|
},
|
|
42
42
|
"homepage": "https://github.com/gjsify/unit#readme",
|
|
43
43
|
"devDependencies": {
|
|
44
|
-
"@girs/gjs": "^4.0.0-rc.
|
|
45
|
-
"@girs/glib-2.0": "^2.88.0-4.0.0-rc.
|
|
46
|
-
"@gjsify/cli": "^0.
|
|
44
|
+
"@girs/gjs": "^4.0.0-rc.9",
|
|
45
|
+
"@girs/glib-2.0": "^2.88.0-4.0.0-rc.9",
|
|
46
|
+
"@gjsify/cli": "^0.3.0",
|
|
47
47
|
"@types/node": "^25.6.0",
|
|
48
|
-
"typescript": "^6.0.
|
|
48
|
+
"typescript": "^6.0.3"
|
|
49
49
|
},
|
|
50
50
|
"dependencies": {
|
|
51
|
-
"@gjsify/assert": "^0.
|
|
52
|
-
"@gjsify/process": "^0.
|
|
53
|
-
"@gjsify/utils": "^0.
|
|
51
|
+
"@gjsify/assert": "^0.3.0",
|
|
52
|
+
"@gjsify/process": "^0.3.0",
|
|
53
|
+
"@gjsify/utils": "^0.3.0"
|
|
54
54
|
}
|
|
55
55
|
}
|
package/src/index.ts
CHANGED
|
@@ -14,6 +14,8 @@ let countTestsFailed = 0;
|
|
|
14
14
|
let countTestsIgnored = 0;
|
|
15
15
|
let runtime = '';
|
|
16
16
|
let runStartTime = 0;
|
|
17
|
+
let currentSuite = '';
|
|
18
|
+
let testErrors: Array<{ suite: string; test: string; message: string }> = [];
|
|
17
19
|
|
|
18
20
|
export interface TimeoutConfig {
|
|
19
21
|
/** Per-it() timeout in ms. Default: 5000. 0 = disabled. */
|
|
@@ -102,7 +104,14 @@ export type Callback = () => Promise<void>;
|
|
|
102
104
|
export type Runtime = 'Gjs' | 'Deno' | 'Node.js' | 'Unknown' | 'Browser' | 'Display';
|
|
103
105
|
|
|
104
106
|
// Makes this work on Gjs and Node.js
|
|
105
|
-
|
|
107
|
+
// In browsers, globalThis.print is window.print() (the print dialog), not text output.
|
|
108
|
+
// Use console.log in browser contexts to avoid triggering print dialogs.
|
|
109
|
+
// GJS check takes priority: @gjsify/dom-elements can set globalThis.document on GJS,
|
|
110
|
+
// which would otherwise cause a false-positive browser detection.
|
|
111
|
+
const _isGjsProcess = typeof (globalThis as any).process?.versions?.gjs === 'string';
|
|
112
|
+
export const print = (!_isGjsProcess && typeof (globalThis as any).document !== 'undefined')
|
|
113
|
+
? console.log
|
|
114
|
+
: (globalThis.print || console.log);
|
|
106
115
|
|
|
107
116
|
class MatcherFactory {
|
|
108
117
|
|
|
@@ -373,6 +382,8 @@ export const describe = async function(moduleName: string, callback: Callback, o
|
|
|
373
382
|
|
|
374
383
|
print('\n' + moduleName);
|
|
375
384
|
|
|
385
|
+
const prevSuite = currentSuite;
|
|
386
|
+
currentSuite = moduleName;
|
|
376
387
|
const t0 = now();
|
|
377
388
|
try {
|
|
378
389
|
await withTimeout(callback, suiteTimeoutMs, `describe: ${moduleName}`);
|
|
@@ -384,6 +395,7 @@ export const describe = async function(moduleName: string, callback: Callback, o
|
|
|
384
395
|
throw e;
|
|
385
396
|
}
|
|
386
397
|
}
|
|
398
|
+
currentSuite = prevSuite;
|
|
387
399
|
const duration = now() - t0;
|
|
388
400
|
print(` ${GRAY}↳ ${formatDuration(duration)}${RESET}`);
|
|
389
401
|
|
|
@@ -508,6 +520,7 @@ export const it = async function(expectation: string, callback: () => void | Pro
|
|
|
508
520
|
if (!e.__testFailureCounted) {
|
|
509
521
|
++countTestsFailed;
|
|
510
522
|
}
|
|
523
|
+
testErrors.push({ suite: currentSuite, test: expectation, message: e.message ?? String(e) });
|
|
511
524
|
const icon = e instanceof TimeoutError ? '⏱' : '❌';
|
|
512
525
|
print(` ${RED}${icon}${RESET} ${GRAY}${expectation} (${formatDuration(duration)})${RESET}`);
|
|
513
526
|
print(`${RED}${e.message}${RESET}`);
|
|
@@ -596,6 +609,18 @@ const runTests = async function(namespaces: Namespaces) {
|
|
|
596
609
|
}
|
|
597
610
|
}
|
|
598
611
|
|
|
612
|
+
const browserSignalDone = () => {
|
|
613
|
+
const doc = (globalThis as any).document;
|
|
614
|
+
if (!doc) return;
|
|
615
|
+
(globalThis as any).__gjsify_test_results = {
|
|
616
|
+
passed: countTestsOverall - countTestsFailed,
|
|
617
|
+
failed: countTestsFailed,
|
|
618
|
+
total: countTestsOverall,
|
|
619
|
+
errors: testErrors,
|
|
620
|
+
};
|
|
621
|
+
doc.documentElement.dataset.testsDone = 'true';
|
|
622
|
+
};
|
|
623
|
+
|
|
599
624
|
const printResult = () => {
|
|
600
625
|
const totalMs = runStartTime > 0 ? now() - runStartTime : 0;
|
|
601
626
|
const durationStr = totalMs > 0 ? ` ${GRAY}(${formatDuration(totalMs)})` : '';
|
|
@@ -622,25 +647,38 @@ const getRuntime = async () => {
|
|
|
622
647
|
|
|
623
648
|
if(globalThis.Deno?.version?.deno) {
|
|
624
649
|
return 'Deno ' + globalThis.Deno?.version?.deno;
|
|
625
|
-
}
|
|
650
|
+
}
|
|
651
|
+
|
|
652
|
+
// Check process (GJS / Node) BEFORE document: @gjsify/dom-elements can set
|
|
653
|
+
// globalThis.document on GJS, which would otherwise cause a false browser-positive.
|
|
654
|
+
// dynamic import('process') throws in the browser so this stays safe there.
|
|
655
|
+
{
|
|
626
656
|
let process = globalThis.process;
|
|
627
657
|
|
|
628
658
|
if(!process) {
|
|
629
659
|
try {
|
|
630
660
|
process = await import('process');
|
|
631
|
-
} catch (
|
|
632
|
-
|
|
633
|
-
console.warn(error.message);
|
|
634
|
-
runtime = 'Unknown'
|
|
661
|
+
} catch (_e) {
|
|
662
|
+
// browser or runtime without process — fall through to document check
|
|
635
663
|
}
|
|
636
664
|
}
|
|
637
665
|
|
|
638
666
|
if(process?.versions?.gjs) {
|
|
639
667
|
runtime = 'Gjs ' + process.versions.gjs;
|
|
668
|
+
return runtime;
|
|
640
669
|
} else if (process?.versions?.node) {
|
|
641
670
|
runtime = 'Node.js ' + process.versions.node;
|
|
671
|
+
return runtime;
|
|
642
672
|
}
|
|
643
673
|
}
|
|
674
|
+
|
|
675
|
+
// Only treat as Browser after confirming no Node/GJS process is present.
|
|
676
|
+
// dynamic imports throw in browsers, so we are safely past that path here.
|
|
677
|
+
if (typeof (globalThis as any).document !== 'undefined') {
|
|
678
|
+
runtime = 'Browser';
|
|
679
|
+
return runtime;
|
|
680
|
+
}
|
|
681
|
+
|
|
644
682
|
return runtime || 'Unknown';
|
|
645
683
|
}
|
|
646
684
|
|
|
@@ -679,6 +717,7 @@ export const run = async (namespaces: Namespaces, options?: { timeout?: number;
|
|
|
679
717
|
})
|
|
680
718
|
.then(async () => {
|
|
681
719
|
printResult();
|
|
720
|
+
browserSignalDone();
|
|
682
721
|
print();
|
|
683
722
|
|
|
684
723
|
quitMainLoop(); // Pre-quit ensureMainLoop's loop so it exits immediately when the hook fires
|