@noego/wood 0.4.8 → 0.4.10
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/bin/axe.js +313 -98
- package/bin/wood.js +7 -1
- package/dist/automation/actions.cjs +17 -0
- package/dist/automation/actions.cjs.map +1 -0
- package/dist/automation/actions.d.cts +57 -0
- package/dist/automation/actions.d.ts +57 -0
- package/dist/automation/actions.js +1 -0
- package/dist/automation/actions.js.map +1 -0
- package/dist/automation/actions_executor.cjs +101 -0
- package/dist/automation/actions_executor.cjs.map +1 -0
- package/dist/automation/actions_executor.d.cts +16 -0
- package/dist/automation/actions_executor.d.ts +16 -0
- package/dist/automation/actions_executor.js +76 -0
- package/dist/automation/actions_executor.js.map +1 -0
- package/dist/automation/connection.cjs +86 -0
- package/dist/automation/connection.cjs.map +1 -0
- package/dist/automation/connection.d.cts +18 -0
- package/dist/automation/connection.d.ts +18 -0
- package/dist/automation/connection.js +51 -0
- package/dist/automation/connection.js.map +1 -0
- package/dist/automation/errors.cjs +50 -0
- package/dist/automation/errors.cjs.map +1 -0
- package/dist/automation/errors.d.cts +31 -0
- package/dist/automation/errors.d.ts +31 -0
- package/dist/automation/errors.js +24 -0
- package/dist/automation/errors.js.map +1 -0
- package/dist/automation/index.cjs +49 -0
- package/dist/automation/index.cjs.map +1 -0
- package/dist/automation/index.d.cts +16 -0
- package/dist/automation/index.d.ts +16 -0
- package/dist/automation/index.js +15 -0
- package/dist/automation/index.js.map +1 -0
- package/dist/automation/introspection_reader.cjs +75 -0
- package/dist/automation/introspection_reader.cjs.map +1 -0
- package/dist/automation/introspection_reader.d.cts +20 -0
- package/dist/automation/introspection_reader.d.ts +20 -0
- package/dist/automation/introspection_reader.js +48 -0
- package/dist/automation/introspection_reader.js.map +1 -0
- package/dist/automation/locator.cjs +102 -0
- package/dist/automation/locator.cjs.map +1 -0
- package/dist/automation/locator.d.cts +51 -0
- package/dist/automation/locator.d.ts +51 -0
- package/dist/automation/locator.js +75 -0
- package/dist/automation/locator.js.map +1 -0
- package/dist/automation/observation.cjs +17 -0
- package/dist/automation/observation.cjs.map +1 -0
- package/dist/automation/observation.d.cts +44 -0
- package/dist/automation/observation.d.ts +44 -0
- package/dist/automation/observation.js +1 -0
- package/dist/automation/observation.js.map +1 -0
- package/dist/automation/receipts.cjs +17 -0
- package/dist/automation/receipts.cjs.map +1 -0
- package/dist/automation/receipts.d.cts +27 -0
- package/dist/automation/receipts.d.ts +27 -0
- package/dist/automation/receipts.js +1 -0
- package/dist/automation/receipts.js.map +1 -0
- package/dist/automation/scenario.cjs +696 -0
- package/dist/automation/scenario.cjs.map +1 -0
- package/dist/automation/scenario.d.cts +89 -0
- package/dist/automation/scenario.d.ts +89 -0
- package/dist/automation/scenario.js +660 -0
- package/dist/automation/scenario.js.map +1 -0
- package/dist/automation/scrolling.cjs +17 -0
- package/dist/automation/scrolling.cjs.map +1 -0
- package/dist/automation/scrolling.d.cts +51 -0
- package/dist/automation/scrolling.d.ts +51 -0
- package/dist/automation/scrolling.js +1 -0
- package/dist/automation/scrolling.js.map +1 -0
- package/dist/automation/scrolling_executor.cjs +109 -0
- package/dist/automation/scrolling_executor.cjs.map +1 -0
- package/dist/automation/scrolling_executor.d.cts +13 -0
- package/dist/automation/scrolling_executor.d.ts +13 -0
- package/dist/automation/scrolling_executor.js +84 -0
- package/dist/automation/scrolling_executor.js.map +1 -0
- package/dist/automation/target_identity.cjs +17 -0
- package/dist/automation/target_identity.cjs.map +1 -0
- package/dist/automation/target_identity.d.cts +28 -0
- package/dist/automation/target_identity.d.ts +28 -0
- package/dist/automation/target_identity.js +1 -0
- package/dist/automation/target_identity.js.map +1 -0
- package/dist/automation/target_registry.cjs +148 -0
- package/dist/automation/target_registry.cjs.map +1 -0
- package/dist/automation/target_registry.d.cts +32 -0
- package/dist/automation/target_registry.d.ts +32 -0
- package/dist/automation/target_registry.js +122 -0
- package/dist/automation/target_registry.js.map +1 -0
- package/dist/automation/waits.cjs +17 -0
- package/dist/automation/waits.cjs.map +1 -0
- package/dist/automation/waits.d.cts +44 -0
- package/dist/automation/waits.d.ts +44 -0
- package/dist/automation/waits.js +1 -0
- package/dist/automation/waits.js.map +1 -0
- package/dist/automation/waits_executor.cjs +104 -0
- package/dist/automation/waits_executor.cjs.map +1 -0
- package/dist/automation/waits_executor.d.cts +14 -0
- package/dist/automation/waits_executor.d.ts +14 -0
- package/dist/automation/waits_executor.js +79 -0
- package/dist/automation/waits_executor.js.map +1 -0
- package/dist/client/index.d.cts +1 -0
- package/dist/client/index.d.ts +1 -0
- package/dist/codegen/renderer_app_generator.cjs +16 -1
- package/dist/codegen/renderer_app_generator.cjs.map +1 -1
- package/dist/codegen/renderer_app_generator.js +16 -1
- package/dist/codegen/renderer_app_generator.js.map +1 -1
- package/dist/index.d.cts +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/navigation/automation_introspection.cjs +110 -0
- package/dist/navigation/automation_introspection.cjs.map +1 -0
- package/dist/navigation/automation_introspection.d.cts +60 -0
- package/dist/navigation/automation_introspection.d.ts +60 -0
- package/dist/navigation/automation_introspection.js +85 -0
- package/dist/navigation/automation_introspection.js.map +1 -0
- package/dist/navigation/index.cjs +7 -2
- package/dist/navigation/index.cjs.map +1 -1
- package/dist/navigation/index.d.cts +2 -0
- package/dist/navigation/index.d.ts +2 -0
- package/dist/navigation/index.js +4 -1
- package/dist/navigation/index.js.map +1 -1
- package/dist/testing/automation_assertions.cjs +417 -0
- package/dist/testing/automation_assertions.cjs.map +1 -0
- package/dist/testing/automation_assertions.d.cts +44 -0
- package/dist/testing/automation_assertions.d.ts +44 -0
- package/dist/testing/automation_assertions.js +385 -0
- package/dist/testing/automation_assertions.js.map +1 -0
- package/dist/testing/browser.cjs +26 -34
- package/dist/testing/browser.cjs.map +1 -1
- package/dist/testing/browser.d.cts +2 -1
- package/dist/testing/browser.d.ts +2 -1
- package/dist/testing/browser.js +30 -31
- package/dist/testing/browser.js.map +1 -1
- package/dist/testing/create_controller_harness.d.cts +1 -0
- package/dist/testing/create_controller_harness.d.ts +1 -0
- package/dist/testing/geometry.cjs +109 -0
- package/dist/testing/geometry.cjs.map +1 -0
- package/dist/testing/geometry.d.cts +45 -0
- package/dist/testing/geometry.d.ts +45 -0
- package/dist/testing/geometry.js +79 -0
- package/dist/testing/geometry.js.map +1 -0
- package/dist/testing/index.cjs +31 -2
- package/dist/testing/index.cjs.map +1 -1
- package/dist/testing/index.d.cts +4 -0
- package/dist/testing/index.d.ts +4 -0
- package/dist/testing/index.js +31 -1
- package/dist/testing/index.js.map +1 -1
- package/dist/tracing/trace_hub.cjs +3 -0
- package/dist/tracing/trace_hub.cjs.map +1 -1
- package/dist/tracing/trace_hub.js +3 -0
- package/dist/tracing/trace_hub.js.map +1 -1
- package/package.json +7 -1
|
@@ -2,6 +2,7 @@ import { Navigation } from '../navigation/index.cjs';
|
|
|
2
2
|
import { TraceRecorder } from '../trace-testing/trace_recorder.cjs';
|
|
3
3
|
import { RouterBridgeResult } from './create_router_bridge.cjs';
|
|
4
4
|
import { createTestRouter } from './create_test_router.cjs';
|
|
5
|
+
import '../navigation/automation_introspection.cjs';
|
|
5
6
|
import '@noego/trace/testing';
|
|
6
7
|
import '../trace_hub-Cob54qRx.cjs';
|
|
7
8
|
import 'rxjs';
|
|
@@ -2,6 +2,7 @@ import { Navigation } from '../navigation/index.js';
|
|
|
2
2
|
import { TraceRecorder } from '../trace-testing/trace_recorder.js';
|
|
3
3
|
import { RouterBridgeResult } from './create_router_bridge.js';
|
|
4
4
|
import { createTestRouter } from './create_test_router.js';
|
|
5
|
+
import '../navigation/automation_introspection.js';
|
|
5
6
|
import '@noego/trace/testing';
|
|
6
7
|
import '../trace_hub-Cob54qRx.js';
|
|
7
8
|
import 'rxjs';
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
var geometry_exports = {};
|
|
20
|
+
__export(geometry_exports, {
|
|
21
|
+
axisEdges: () => axisEdges,
|
|
22
|
+
axisGap: () => axisGap,
|
|
23
|
+
evenSpacing: () => evenSpacing,
|
|
24
|
+
gaps: () => gaps,
|
|
25
|
+
rectsOverlap: () => rectsOverlap,
|
|
26
|
+
sharedEdges: () => sharedEdges,
|
|
27
|
+
snapshotRectsOverlap: () => snapshotRectsOverlap
|
|
28
|
+
});
|
|
29
|
+
module.exports = __toCommonJS(geometry_exports);
|
|
30
|
+
function axisEdges(rect, axis) {
|
|
31
|
+
return axis === "horizontal" ? { leading: rect.left, trailing: rect.right } : { leading: rect.top, trailing: rect.bottom };
|
|
32
|
+
}
|
|
33
|
+
function axisGap(first, second, axis) {
|
|
34
|
+
const a = axisEdges(first, axis);
|
|
35
|
+
const b = axisEdges(second, axis);
|
|
36
|
+
const [earlier, later] = a.leading <= b.leading ? [a, b] : [b, a];
|
|
37
|
+
return later.leading - earlier.trailing;
|
|
38
|
+
}
|
|
39
|
+
function rectsOverlap(a, b) {
|
|
40
|
+
return Boolean(
|
|
41
|
+
a && b && a.left < b.right && a.right > b.left && a.top < b.bottom && a.bottom > b.top
|
|
42
|
+
);
|
|
43
|
+
}
|
|
44
|
+
function snapshotRectsOverlap(a, b) {
|
|
45
|
+
return a.x < b.x + b.w && a.x + a.w > b.x && a.y < b.y + b.h && a.y + a.h > b.y;
|
|
46
|
+
}
|
|
47
|
+
function sharedEdges(rects, edge, options = {}) {
|
|
48
|
+
const tolerance = options.tolerance ?? 1;
|
|
49
|
+
if (rects.length < 2) {
|
|
50
|
+
return {
|
|
51
|
+
pass: false,
|
|
52
|
+
message: "sharedEdges requires at least two rects.",
|
|
53
|
+
details: { count: rects.length, edge, tolerance }
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
const expected = rects[0][edge];
|
|
57
|
+
const deltas = rects.slice(1).map((rect) => Math.abs(rect[edge] - expected));
|
|
58
|
+
const maximumDelta = Math.max(...deltas);
|
|
59
|
+
const pass = maximumDelta <= tolerance;
|
|
60
|
+
return {
|
|
61
|
+
pass,
|
|
62
|
+
message: pass ? `All rects share the ${edge} edge within ${tolerance}px.` : `Rects do not share the ${edge} edge within ${tolerance}px (maximum delta ${maximumDelta.toFixed(2)}px).`,
|
|
63
|
+
details: { edge, tolerance, expected, deltas, maximumDelta }
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
function gaps(rects, axis) {
|
|
67
|
+
const sorted = [...rects].sort(
|
|
68
|
+
(a, b) => axisEdges(a, axis).leading - axisEdges(b, axis).leading
|
|
69
|
+
);
|
|
70
|
+
return sorted.slice(1).map((rect, index) => axisGap(sorted[index], rect, axis));
|
|
71
|
+
}
|
|
72
|
+
function evenSpacing(rects, axis, options = {}) {
|
|
73
|
+
const tolerance = options.tolerance ?? 1;
|
|
74
|
+
if (rects.length < 3) {
|
|
75
|
+
return {
|
|
76
|
+
pass: false,
|
|
77
|
+
message: `evenSpacing requires at least three rects, got ${rects.length}.`,
|
|
78
|
+
details: { count: rects.length, axis, tolerance }
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
const measuredGaps = gaps(rects, axis);
|
|
82
|
+
const widest = Math.max(...measuredGaps);
|
|
83
|
+
const narrowest = Math.min(...measuredGaps);
|
|
84
|
+
const spread = widest - narrowest;
|
|
85
|
+
const pass = spread <= tolerance;
|
|
86
|
+
return {
|
|
87
|
+
pass,
|
|
88
|
+
message: pass ? `Rects are evenly spaced along ${axis} within ${tolerance}px.` : `Rects are not evenly spaced along ${axis}: gap spread ${spread.toFixed(2)}px exceeds ${tolerance}px.`,
|
|
89
|
+
details: {
|
|
90
|
+
axis,
|
|
91
|
+
tolerance,
|
|
92
|
+
gaps: measuredGaps,
|
|
93
|
+
widest,
|
|
94
|
+
narrowest,
|
|
95
|
+
spread
|
|
96
|
+
}
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
100
|
+
0 && (module.exports = {
|
|
101
|
+
axisEdges,
|
|
102
|
+
axisGap,
|
|
103
|
+
evenSpacing,
|
|
104
|
+
gaps,
|
|
105
|
+
rectsOverlap,
|
|
106
|
+
sharedEdges,
|
|
107
|
+
snapshotRectsOverlap
|
|
108
|
+
});
|
|
109
|
+
//# sourceMappingURL=geometry.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/testing/geometry.ts"],"sourcesContent":["export type RectAxis = 'horizontal' | 'vertical';\n\nexport interface RectBox {\n top: number;\n left: number;\n right: number;\n bottom: number;\n width: number;\n height: number;\n}\n\nexport interface SnapshotRect {\n x: number;\n y: number;\n w: number;\n h: number;\n}\n\nexport interface GeometryVerdict {\n pass: boolean;\n message: string;\n details?: Record<string, unknown>;\n}\n\nexport type RectEdge = 'left' | 'right' | 'top' | 'bottom';\n\nexport function axisEdges(\n rect: RectBox,\n axis: RectAxis,\n): { leading: number; trailing: number } {\n return axis === 'horizontal'\n ? { leading: rect.left, trailing: rect.right }\n : { leading: rect.top, trailing: rect.bottom };\n}\n\n/**\n * Edge-to-edge gap between two border boxes. The box with the smaller leading\n * edge is treated as the earlier box, so negative values mean overlap.\n */\nexport function axisGap(first: RectBox, second: RectBox, axis: RectAxis): number {\n const a = axisEdges(first, axis);\n const b = axisEdges(second, axis);\n const [earlier, later] = a.leading <= b.leading ? [a, b] : [b, a];\n return later.leading - earlier.trailing;\n}\n\nexport function rectsOverlap(\n a: RectBox | null | undefined,\n b: RectBox | null | undefined,\n): boolean {\n return Boolean(\n a && b\n && a.left < b.right && a.right > b.left\n && a.top < b.bottom && a.bottom > b.top,\n );\n}\n\n/** Two CDP snapshot `[x,y,w,h]` rects overlap on both axes. */\nexport function snapshotRectsOverlap(a: SnapshotRect, b: SnapshotRect): boolean {\n return a.x < b.x + b.w\n && a.x + a.w > b.x\n && a.y < b.y + b.h\n && a.y + a.h > b.y;\n}\n\n/** Assert that every rect shares one named edge with the first rect. */\nexport function sharedEdges(\n rects: readonly RectBox[],\n edge: RectEdge,\n options: { tolerance?: number } = {},\n): GeometryVerdict {\n const tolerance = options.tolerance ?? 1;\n if (rects.length < 2) {\n return {\n pass: false,\n message: 'sharedEdges requires at least two rects.',\n details: { count: rects.length, edge, tolerance },\n };\n }\n\n const expected = rects[0][edge];\n const deltas = rects.slice(1).map((rect) => Math.abs(rect[edge] - expected));\n const maximumDelta = Math.max(...deltas);\n const pass = maximumDelta <= tolerance;\n return {\n pass,\n message: pass\n ? `All rects share the ${edge} edge within ${tolerance}px.`\n : `Rects do not share the ${edge} edge within ${tolerance}px (maximum delta ${maximumDelta.toFixed(2)}px).`,\n details: { edge, tolerance, expected, deltas, maximumDelta },\n };\n}\n\n/** Consecutive edge-to-edge gaps, after sorting rects along the requested axis. */\nexport function gaps(rects: readonly RectBox[], axis: RectAxis): number[] {\n const sorted = [...rects].sort(\n (a, b) => axisEdges(a, axis).leading - axisEdges(b, axis).leading,\n );\n return sorted.slice(1).map((rect, index) => axisGap(sorted[index], rect, axis));\n}\n\n/** Assert that consecutive rect gaps have no more than the requested spread. */\nexport function evenSpacing(\n rects: readonly RectBox[],\n axis: RectAxis,\n options: { tolerance?: number } = {},\n): GeometryVerdict {\n const tolerance = options.tolerance ?? 1;\n if (rects.length < 3) {\n return {\n pass: false,\n message: `evenSpacing requires at least three rects, got ${rects.length}.`,\n details: { count: rects.length, axis, tolerance },\n };\n }\n\n const measuredGaps = gaps(rects, axis);\n const widest = Math.max(...measuredGaps);\n const narrowest = Math.min(...measuredGaps);\n const spread = widest - narrowest;\n const pass = spread <= tolerance;\n return {\n pass,\n message: pass\n ? `Rects are evenly spaced along ${axis} within ${tolerance}px.`\n : `Rects are not evenly spaced along ${axis}: gap spread ${spread.toFixed(2)}px exceeds ${tolerance}px.`,\n details: {\n axis,\n tolerance,\n gaps: measuredGaps,\n widest,\n narrowest,\n spread,\n },\n };\n}\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
type RectAxis = 'horizontal' | 'vertical';
|
|
2
|
+
interface RectBox {
|
|
3
|
+
top: number;
|
|
4
|
+
left: number;
|
|
5
|
+
right: number;
|
|
6
|
+
bottom: number;
|
|
7
|
+
width: number;
|
|
8
|
+
height: number;
|
|
9
|
+
}
|
|
10
|
+
interface SnapshotRect {
|
|
11
|
+
x: number;
|
|
12
|
+
y: number;
|
|
13
|
+
w: number;
|
|
14
|
+
h: number;
|
|
15
|
+
}
|
|
16
|
+
interface GeometryVerdict {
|
|
17
|
+
pass: boolean;
|
|
18
|
+
message: string;
|
|
19
|
+
details?: Record<string, unknown>;
|
|
20
|
+
}
|
|
21
|
+
type RectEdge = 'left' | 'right' | 'top' | 'bottom';
|
|
22
|
+
declare function axisEdges(rect: RectBox, axis: RectAxis): {
|
|
23
|
+
leading: number;
|
|
24
|
+
trailing: number;
|
|
25
|
+
};
|
|
26
|
+
/**
|
|
27
|
+
* Edge-to-edge gap between two border boxes. The box with the smaller leading
|
|
28
|
+
* edge is treated as the earlier box, so negative values mean overlap.
|
|
29
|
+
*/
|
|
30
|
+
declare function axisGap(first: RectBox, second: RectBox, axis: RectAxis): number;
|
|
31
|
+
declare function rectsOverlap(a: RectBox | null | undefined, b: RectBox | null | undefined): boolean;
|
|
32
|
+
/** Two CDP snapshot `[x,y,w,h]` rects overlap on both axes. */
|
|
33
|
+
declare function snapshotRectsOverlap(a: SnapshotRect, b: SnapshotRect): boolean;
|
|
34
|
+
/** Assert that every rect shares one named edge with the first rect. */
|
|
35
|
+
declare function sharedEdges(rects: readonly RectBox[], edge: RectEdge, options?: {
|
|
36
|
+
tolerance?: number;
|
|
37
|
+
}): GeometryVerdict;
|
|
38
|
+
/** Consecutive edge-to-edge gaps, after sorting rects along the requested axis. */
|
|
39
|
+
declare function gaps(rects: readonly RectBox[], axis: RectAxis): number[];
|
|
40
|
+
/** Assert that consecutive rect gaps have no more than the requested spread. */
|
|
41
|
+
declare function evenSpacing(rects: readonly RectBox[], axis: RectAxis, options?: {
|
|
42
|
+
tolerance?: number;
|
|
43
|
+
}): GeometryVerdict;
|
|
44
|
+
|
|
45
|
+
export { type GeometryVerdict, type RectAxis, type RectBox, type RectEdge, type SnapshotRect, axisEdges, axisGap, evenSpacing, gaps, rectsOverlap, sharedEdges, snapshotRectsOverlap };
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
type RectAxis = 'horizontal' | 'vertical';
|
|
2
|
+
interface RectBox {
|
|
3
|
+
top: number;
|
|
4
|
+
left: number;
|
|
5
|
+
right: number;
|
|
6
|
+
bottom: number;
|
|
7
|
+
width: number;
|
|
8
|
+
height: number;
|
|
9
|
+
}
|
|
10
|
+
interface SnapshotRect {
|
|
11
|
+
x: number;
|
|
12
|
+
y: number;
|
|
13
|
+
w: number;
|
|
14
|
+
h: number;
|
|
15
|
+
}
|
|
16
|
+
interface GeometryVerdict {
|
|
17
|
+
pass: boolean;
|
|
18
|
+
message: string;
|
|
19
|
+
details?: Record<string, unknown>;
|
|
20
|
+
}
|
|
21
|
+
type RectEdge = 'left' | 'right' | 'top' | 'bottom';
|
|
22
|
+
declare function axisEdges(rect: RectBox, axis: RectAxis): {
|
|
23
|
+
leading: number;
|
|
24
|
+
trailing: number;
|
|
25
|
+
};
|
|
26
|
+
/**
|
|
27
|
+
* Edge-to-edge gap between two border boxes. The box with the smaller leading
|
|
28
|
+
* edge is treated as the earlier box, so negative values mean overlap.
|
|
29
|
+
*/
|
|
30
|
+
declare function axisGap(first: RectBox, second: RectBox, axis: RectAxis): number;
|
|
31
|
+
declare function rectsOverlap(a: RectBox | null | undefined, b: RectBox | null | undefined): boolean;
|
|
32
|
+
/** Two CDP snapshot `[x,y,w,h]` rects overlap on both axes. */
|
|
33
|
+
declare function snapshotRectsOverlap(a: SnapshotRect, b: SnapshotRect): boolean;
|
|
34
|
+
/** Assert that every rect shares one named edge with the first rect. */
|
|
35
|
+
declare function sharedEdges(rects: readonly RectBox[], edge: RectEdge, options?: {
|
|
36
|
+
tolerance?: number;
|
|
37
|
+
}): GeometryVerdict;
|
|
38
|
+
/** Consecutive edge-to-edge gaps, after sorting rects along the requested axis. */
|
|
39
|
+
declare function gaps(rects: readonly RectBox[], axis: RectAxis): number[];
|
|
40
|
+
/** Assert that consecutive rect gaps have no more than the requested spread. */
|
|
41
|
+
declare function evenSpacing(rects: readonly RectBox[], axis: RectAxis, options?: {
|
|
42
|
+
tolerance?: number;
|
|
43
|
+
}): GeometryVerdict;
|
|
44
|
+
|
|
45
|
+
export { type GeometryVerdict, type RectAxis, type RectBox, type RectEdge, type SnapshotRect, axisEdges, axisGap, evenSpacing, gaps, rectsOverlap, sharedEdges, snapshotRectsOverlap };
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
function axisEdges(rect, axis) {
|
|
2
|
+
return axis === "horizontal" ? { leading: rect.left, trailing: rect.right } : { leading: rect.top, trailing: rect.bottom };
|
|
3
|
+
}
|
|
4
|
+
function axisGap(first, second, axis) {
|
|
5
|
+
const a = axisEdges(first, axis);
|
|
6
|
+
const b = axisEdges(second, axis);
|
|
7
|
+
const [earlier, later] = a.leading <= b.leading ? [a, b] : [b, a];
|
|
8
|
+
return later.leading - earlier.trailing;
|
|
9
|
+
}
|
|
10
|
+
function rectsOverlap(a, b) {
|
|
11
|
+
return Boolean(
|
|
12
|
+
a && b && a.left < b.right && a.right > b.left && a.top < b.bottom && a.bottom > b.top
|
|
13
|
+
);
|
|
14
|
+
}
|
|
15
|
+
function snapshotRectsOverlap(a, b) {
|
|
16
|
+
return a.x < b.x + b.w && a.x + a.w > b.x && a.y < b.y + b.h && a.y + a.h > b.y;
|
|
17
|
+
}
|
|
18
|
+
function sharedEdges(rects, edge, options = {}) {
|
|
19
|
+
const tolerance = options.tolerance ?? 1;
|
|
20
|
+
if (rects.length < 2) {
|
|
21
|
+
return {
|
|
22
|
+
pass: false,
|
|
23
|
+
message: "sharedEdges requires at least two rects.",
|
|
24
|
+
details: { count: rects.length, edge, tolerance }
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
const expected = rects[0][edge];
|
|
28
|
+
const deltas = rects.slice(1).map((rect) => Math.abs(rect[edge] - expected));
|
|
29
|
+
const maximumDelta = Math.max(...deltas);
|
|
30
|
+
const pass = maximumDelta <= tolerance;
|
|
31
|
+
return {
|
|
32
|
+
pass,
|
|
33
|
+
message: pass ? `All rects share the ${edge} edge within ${tolerance}px.` : `Rects do not share the ${edge} edge within ${tolerance}px (maximum delta ${maximumDelta.toFixed(2)}px).`,
|
|
34
|
+
details: { edge, tolerance, expected, deltas, maximumDelta }
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
function gaps(rects, axis) {
|
|
38
|
+
const sorted = [...rects].sort(
|
|
39
|
+
(a, b) => axisEdges(a, axis).leading - axisEdges(b, axis).leading
|
|
40
|
+
);
|
|
41
|
+
return sorted.slice(1).map((rect, index) => axisGap(sorted[index], rect, axis));
|
|
42
|
+
}
|
|
43
|
+
function evenSpacing(rects, axis, options = {}) {
|
|
44
|
+
const tolerance = options.tolerance ?? 1;
|
|
45
|
+
if (rects.length < 3) {
|
|
46
|
+
return {
|
|
47
|
+
pass: false,
|
|
48
|
+
message: `evenSpacing requires at least three rects, got ${rects.length}.`,
|
|
49
|
+
details: { count: rects.length, axis, tolerance }
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
const measuredGaps = gaps(rects, axis);
|
|
53
|
+
const widest = Math.max(...measuredGaps);
|
|
54
|
+
const narrowest = Math.min(...measuredGaps);
|
|
55
|
+
const spread = widest - narrowest;
|
|
56
|
+
const pass = spread <= tolerance;
|
|
57
|
+
return {
|
|
58
|
+
pass,
|
|
59
|
+
message: pass ? `Rects are evenly spaced along ${axis} within ${tolerance}px.` : `Rects are not evenly spaced along ${axis}: gap spread ${spread.toFixed(2)}px exceeds ${tolerance}px.`,
|
|
60
|
+
details: {
|
|
61
|
+
axis,
|
|
62
|
+
tolerance,
|
|
63
|
+
gaps: measuredGaps,
|
|
64
|
+
widest,
|
|
65
|
+
narrowest,
|
|
66
|
+
spread
|
|
67
|
+
}
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
export {
|
|
71
|
+
axisEdges,
|
|
72
|
+
axisGap,
|
|
73
|
+
evenSpacing,
|
|
74
|
+
gaps,
|
|
75
|
+
rectsOverlap,
|
|
76
|
+
sharedEdges,
|
|
77
|
+
snapshotRectsOverlap
|
|
78
|
+
};
|
|
79
|
+
//# sourceMappingURL=geometry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/testing/geometry.ts"],"sourcesContent":["export type RectAxis = 'horizontal' | 'vertical';\n\nexport interface RectBox {\n top: number;\n left: number;\n right: number;\n bottom: number;\n width: number;\n height: number;\n}\n\nexport interface SnapshotRect {\n x: number;\n y: number;\n w: number;\n h: number;\n}\n\nexport interface GeometryVerdict {\n pass: boolean;\n message: string;\n details?: Record<string, unknown>;\n}\n\nexport type RectEdge = 'left' | 'right' | 'top' | 'bottom';\n\nexport function axisEdges(\n rect: RectBox,\n axis: RectAxis,\n): { leading: number; trailing: number } {\n return axis === 'horizontal'\n ? { leading: rect.left, trailing: rect.right }\n : { leading: rect.top, trailing: rect.bottom };\n}\n\n/**\n * Edge-to-edge gap between two border boxes. The box with the smaller leading\n * edge is treated as the earlier box, so negative values mean overlap.\n */\nexport function axisGap(first: RectBox, second: RectBox, axis: RectAxis): number {\n const a = axisEdges(first, axis);\n const b = axisEdges(second, axis);\n const [earlier, later] = a.leading <= b.leading ? [a, b] : [b, a];\n return later.leading - earlier.trailing;\n}\n\nexport function rectsOverlap(\n a: RectBox | null | undefined,\n b: RectBox | null | undefined,\n): boolean {\n return Boolean(\n a && b\n && a.left < b.right && a.right > b.left\n && a.top < b.bottom && a.bottom > b.top,\n );\n}\n\n/** Two CDP snapshot `[x,y,w,h]` rects overlap on both axes. */\nexport function snapshotRectsOverlap(a: SnapshotRect, b: SnapshotRect): boolean {\n return a.x < b.x + b.w\n && a.x + a.w > b.x\n && a.y < b.y + b.h\n && a.y + a.h > b.y;\n}\n\n/** Assert that every rect shares one named edge with the first rect. */\nexport function sharedEdges(\n rects: readonly RectBox[],\n edge: RectEdge,\n options: { tolerance?: number } = {},\n): GeometryVerdict {\n const tolerance = options.tolerance ?? 1;\n if (rects.length < 2) {\n return {\n pass: false,\n message: 'sharedEdges requires at least two rects.',\n details: { count: rects.length, edge, tolerance },\n };\n }\n\n const expected = rects[0][edge];\n const deltas = rects.slice(1).map((rect) => Math.abs(rect[edge] - expected));\n const maximumDelta = Math.max(...deltas);\n const pass = maximumDelta <= tolerance;\n return {\n pass,\n message: pass\n ? `All rects share the ${edge} edge within ${tolerance}px.`\n : `Rects do not share the ${edge} edge within ${tolerance}px (maximum delta ${maximumDelta.toFixed(2)}px).`,\n details: { edge, tolerance, expected, deltas, maximumDelta },\n };\n}\n\n/** Consecutive edge-to-edge gaps, after sorting rects along the requested axis. */\nexport function gaps(rects: readonly RectBox[], axis: RectAxis): number[] {\n const sorted = [...rects].sort(\n (a, b) => axisEdges(a, axis).leading - axisEdges(b, axis).leading,\n );\n return sorted.slice(1).map((rect, index) => axisGap(sorted[index], rect, axis));\n}\n\n/** Assert that consecutive rect gaps have no more than the requested spread. */\nexport function evenSpacing(\n rects: readonly RectBox[],\n axis: RectAxis,\n options: { tolerance?: number } = {},\n): GeometryVerdict {\n const tolerance = options.tolerance ?? 1;\n if (rects.length < 3) {\n return {\n pass: false,\n message: `evenSpacing requires at least three rects, got ${rects.length}.`,\n details: { count: rects.length, axis, tolerance },\n };\n }\n\n const measuredGaps = gaps(rects, axis);\n const widest = Math.max(...measuredGaps);\n const narrowest = Math.min(...measuredGaps);\n const spread = widest - narrowest;\n const pass = spread <= tolerance;\n return {\n pass,\n message: pass\n ? `Rects are evenly spaced along ${axis} within ${tolerance}px.`\n : `Rects are not evenly spaced along ${axis}: gap spread ${spread.toFixed(2)}px exceeds ${tolerance}px.`,\n details: {\n axis,\n tolerance,\n gaps: measuredGaps,\n widest,\n narrowest,\n spread,\n },\n };\n}\n"],"mappings":"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","names":[]}
|
package/dist/testing/index.cjs
CHANGED
|
@@ -25,6 +25,7 @@ __export(testing_exports, {
|
|
|
25
25
|
RouterBridgeEvents: () => import_create_router_bridge.RouterBridgeEvents,
|
|
26
26
|
TraceRecorder: () => import_trace_testing.TraceRecorder,
|
|
27
27
|
assertLoopbackSerializable: () => import_transport.assertLoopbackSerializable,
|
|
28
|
+
automationAssertions: () => import_automation_assertions.automationAssertions,
|
|
28
29
|
browser: () => import_browser.browser,
|
|
29
30
|
buildTransportBridge: () => import_transport.buildTransportBridge,
|
|
30
31
|
createBrowserBridgeFixture: () => import_browser.createBrowserBridgeFixture,
|
|
@@ -32,8 +33,21 @@ __export(testing_exports, {
|
|
|
32
33
|
createRouterBridge: () => import_create_router_bridge.createRouterBridge,
|
|
33
34
|
createTestContainer: () => import_create_test_container.createTestContainer,
|
|
34
35
|
createTestRouter: () => import_create_test_router.createTestRouter,
|
|
36
|
+
evenSpacing: () => import_automation_assertions.evenSpacing,
|
|
37
|
+
evenSpacingRects: () => import_automation_assertions.evenSpacingRects,
|
|
38
|
+
gaps: () => import_automation_assertions.gaps,
|
|
35
39
|
getElectronMockFactory: () => import_mock_electron.getElectronMockFactory,
|
|
36
|
-
|
|
40
|
+
hidden: () => import_automation_assertions.hidden,
|
|
41
|
+
hitTestReachable: () => import_automation_assertions.hitTestReachable,
|
|
42
|
+
insideViewport: () => import_automation_assertions.insideViewport,
|
|
43
|
+
mockElectron: () => import_mock_electron.mockElectron,
|
|
44
|
+
notClipped: () => import_automation_assertions.notClipped,
|
|
45
|
+
notOverlapping: () => import_automation_assertions.notOverlapping,
|
|
46
|
+
rectsOverlap: () => import_automation_assertions.rectsOverlap,
|
|
47
|
+
sharedEdges: () => import_automation_assertions.sharedEdges,
|
|
48
|
+
sharedRectEdges: () => import_automation_assertions.sharedRectEdges,
|
|
49
|
+
stableAfterAnimation: () => import_automation_assertions.stableAfterAnimation,
|
|
50
|
+
visible: () => import_automation_assertions.visible
|
|
37
51
|
});
|
|
38
52
|
module.exports = __toCommonJS(testing_exports);
|
|
39
53
|
var import_create_test_container = require("./create_test_container.js");
|
|
@@ -42,6 +56,7 @@ var import_create_test_router = require("./create_test_router.js");
|
|
|
42
56
|
var import_mock_electron = require("./mock_electron.js");
|
|
43
57
|
var import_create_router_bridge = require("./create_router_bridge.js");
|
|
44
58
|
var import_browser = require("./browser.js");
|
|
59
|
+
var import_automation_assertions = require("./automation_assertions.js");
|
|
45
60
|
var import_transport = require("../transport/index.js");
|
|
46
61
|
var import_trace_testing = require("../trace-testing/index.js");
|
|
47
62
|
// Annotate the CommonJS export names for ESM import in node:
|
|
@@ -53,6 +68,7 @@ var import_trace_testing = require("../trace-testing/index.js");
|
|
|
53
68
|
RouterBridgeEvents,
|
|
54
69
|
TraceRecorder,
|
|
55
70
|
assertLoopbackSerializable,
|
|
71
|
+
automationAssertions,
|
|
56
72
|
browser,
|
|
57
73
|
buildTransportBridge,
|
|
58
74
|
createBrowserBridgeFixture,
|
|
@@ -60,7 +76,20 @@ var import_trace_testing = require("../trace-testing/index.js");
|
|
|
60
76
|
createRouterBridge,
|
|
61
77
|
createTestContainer,
|
|
62
78
|
createTestRouter,
|
|
79
|
+
evenSpacing,
|
|
80
|
+
evenSpacingRects,
|
|
81
|
+
gaps,
|
|
63
82
|
getElectronMockFactory,
|
|
64
|
-
|
|
83
|
+
hidden,
|
|
84
|
+
hitTestReachable,
|
|
85
|
+
insideViewport,
|
|
86
|
+
mockElectron,
|
|
87
|
+
notClipped,
|
|
88
|
+
notOverlapping,
|
|
89
|
+
rectsOverlap,
|
|
90
|
+
sharedEdges,
|
|
91
|
+
sharedRectEdges,
|
|
92
|
+
stableAfterAnimation,
|
|
93
|
+
visible
|
|
65
94
|
});
|
|
66
95
|
//# sourceMappingURL=index.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/testing/index.ts"],"sourcesContent":["export { createTestContainer } from './create_test_container.js';\nexport {\n createControllerHarness,\n type ControllerHarnessResult,\n type CreateControllerHarnessOptions,\n} from './create_controller_harness.js';\nexport { createTestRouter, type TestRouterResult } from './create_test_router.js';\nexport { mockElectron, getElectronMockFactory } from './mock_electron.js';\nexport {\n createRouterBridge,\n RouterBridgeEvents,\n type RouterBridgeResult,\n} from './create_router_bridge.js';\nexport {\n browser,\n createBrowserBridgeFixture,\n type MountedWoodBridge,\n type MountedWoodComponent,\n type MountedWoodNavigation,\n type MountedWoodRoute,\n type MountedWoodSurface,\n type MountedWoodTree,\n type MountComponentOptions,\n type MountRouteOptions,\n type MountTreeOptions,\n type WoodBridgeFixtureContext,\n type WoodBridgeFixtureInput,\n type WoodBridgeRecordedCall,\n type WoodBridgeRecordedEvent,\n type WoodRpcManifestEntryInput,\n type WoodBrowserExpect,\n type WoodHitTestResult,\n type WoodRectSnapshot,\n type WoodBrowserHarness,\n type WoodBrowserHarnessConfig,\n type WoodBrowserPageContext,\n type WoodBrowserTraceConfig,\n type WoodViewport,\n} from './browser.js';\nexport {\n InProcessRouterTransport,\n LoopbackRemoteTransport,\n LoopbackRemoteTransportServer,\n assertLoopbackSerializable,\n LoopbackSerializationError,\n buildTransportBridge,\n type WoodRpcTransport,\n type WoodChannelContract,\n type WoodChannelMapLike,\n type WoodChannelInput,\n type WoodChannelOutput,\n type TypedCall,\n type TransportBridgeResult,\n} from '../transport/index.js';\nexport { TraceRecorder } from '../trace-testing/index.js';\nexport type {\n TraceDispatchResult,\n TraceEvent,\n TraceInput,\n TraceWaitOptions,\n} from '../tracing/index.js';\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,mCAAoC;AACpC,uCAIO;AACP,gCAAwD;AACxD,2BAAqD;AACrD,kCAIO;AACP,qBAyBO;AACP,uBAcO;AACP,2BAA8B;","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/testing/index.ts"],"sourcesContent":["export { createTestContainer } from './create_test_container.js';\nexport {\n createControllerHarness,\n type ControllerHarnessResult,\n type CreateControllerHarnessOptions,\n} from './create_controller_harness.js';\nexport { createTestRouter, type TestRouterResult } from './create_test_router.js';\nexport { mockElectron, getElectronMockFactory } from './mock_electron.js';\nexport {\n createRouterBridge,\n RouterBridgeEvents,\n type RouterBridgeResult,\n} from './create_router_bridge.js';\nexport {\n browser,\n createBrowserBridgeFixture,\n type MountedWoodBridge,\n type MountedWoodComponent,\n type MountedWoodNavigation,\n type MountedWoodRoute,\n type MountedWoodSurface,\n type MountedWoodTree,\n type MountComponentOptions,\n type MountRouteOptions,\n type MountTreeOptions,\n type WoodBridgeFixtureContext,\n type WoodBridgeFixtureInput,\n type WoodBridgeRecordedCall,\n type WoodBridgeRecordedEvent,\n type WoodRpcManifestEntryInput,\n type WoodBrowserExpect,\n type WoodHitTestResult,\n type WoodRectSnapshot,\n type WoodBrowserHarness,\n type WoodBrowserHarnessConfig,\n type WoodBrowserPageContext,\n type WoodBrowserTraceConfig,\n type WoodViewport,\n} from './browser.js';\nexport {\n automationAssertions,\n visible,\n hidden,\n insideViewport,\n notClipped,\n notOverlapping,\n hitTestReachable,\n sharedEdges,\n evenSpacing,\n stableAfterAnimation,\n rectsOverlap,\n gaps,\n sharedRectEdges,\n evenSpacingRects,\n type AssertionVerdict,\n type AutomationTarget,\n type AutomationRectTarget,\n type GeometryVerdict,\n type RectAxis,\n type RectBox,\n type RectEdge,\n} from './automation_assertions.js';\nexport {\n InProcessRouterTransport,\n LoopbackRemoteTransport,\n LoopbackRemoteTransportServer,\n assertLoopbackSerializable,\n LoopbackSerializationError,\n buildTransportBridge,\n type WoodRpcTransport,\n type WoodChannelContract,\n type WoodChannelMapLike,\n type WoodChannelInput,\n type WoodChannelOutput,\n type TypedCall,\n type TransportBridgeResult,\n} from '../transport/index.js';\nexport { TraceRecorder } from '../trace-testing/index.js';\nexport type {\n TraceDispatchResult,\n TraceEvent,\n TraceInput,\n TraceWaitOptions,\n} from '../tracing/index.js';\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,mCAAoC;AACpC,uCAIO;AACP,gCAAwD;AACxD,2BAAqD;AACrD,kCAIO;AACP,qBAyBO;AACP,mCAsBO;AACP,uBAcO;AACP,2BAA8B;","names":[]}
|
package/dist/testing/index.d.cts
CHANGED
|
@@ -4,6 +4,7 @@ export { TestRouterResult, createTestRouter } from './create_test_router.cjs';
|
|
|
4
4
|
export { getElectronMockFactory, mockElectron } from './mock_electron.cjs';
|
|
5
5
|
export { RouterBridgeEvents, RouterBridgeResult, createRouterBridge } from './create_router_bridge.cjs';
|
|
6
6
|
export { MountComponentOptions, MountRouteOptions, MountTreeOptions, MountedWoodBridge, MountedWoodComponent, MountedWoodNavigation, MountedWoodRoute, MountedWoodSurface, MountedWoodTree, WoodBridgeFixtureContext, WoodBridgeFixtureInput, WoodBridgeRecordedCall, WoodBridgeRecordedEvent, WoodBrowserExpect, WoodBrowserHarness, WoodBrowserHarnessConfig, WoodBrowserPageContext, WoodBrowserTraceConfig, WoodHitTestResult, WoodRectSnapshot, WoodRpcManifestEntryInput, WoodViewport, browser, createBrowserBridgeFixture } from './browser.cjs';
|
|
7
|
+
export { AssertionVerdict, AutomationRectTarget, AutomationTarget, automationAssertions, evenSpacing, hidden, hitTestReachable, insideViewport, notClipped, notOverlapping, sharedEdges, stableAfterAnimation, visible } from './automation_assertions.cjs';
|
|
7
8
|
export { TypedCall, WoodChannelContract, WoodChannelInput, WoodChannelMapLike, WoodChannelOutput, WoodRpcTransport } from '../transport/wood_rpc_transport.cjs';
|
|
8
9
|
export { InProcessRouterTransport } from '../transport/in_process_router_transport.cjs';
|
|
9
10
|
export { LoopbackRemoteTransport, LoopbackRemoteTransportServer } from '../transport/loopback_remote_transport.cjs';
|
|
@@ -11,9 +12,12 @@ export { LoopbackSerializationError, assertLoopbackSerializable } from '../trans
|
|
|
11
12
|
export { TransportBridgeResult, buildTransportBridge } from '../transport/build_transport_bridge.cjs';
|
|
12
13
|
export { TraceRecorder } from '../trace-testing/trace_recorder.cjs';
|
|
13
14
|
export { T as TraceDispatchResult, a as TraceEvent, b as TraceInput, f as TraceWaitOptions } from '../trace_hub-Cob54qRx.cjs';
|
|
15
|
+
export { GeometryVerdict, RectAxis, RectBox, RectEdge, evenSpacing as evenSpacingRects, gaps, rectsOverlap, sharedEdges as sharedRectEdges } from './geometry.cjs';
|
|
14
16
|
import '../navigation/index.cjs';
|
|
17
|
+
import '../navigation/automation_introspection.cjs';
|
|
15
18
|
import '../router/wood_router.cjs';
|
|
16
19
|
import '../types/operations.cjs';
|
|
20
|
+
import 'playwright';
|
|
17
21
|
import '@noego/trace/testing';
|
|
18
22
|
import '../tracing/trace_provider.cjs';
|
|
19
23
|
import '@noego/ioc';
|
package/dist/testing/index.d.ts
CHANGED
|
@@ -4,6 +4,7 @@ export { TestRouterResult, createTestRouter } from './create_test_router.js';
|
|
|
4
4
|
export { getElectronMockFactory, mockElectron } from './mock_electron.js';
|
|
5
5
|
export { RouterBridgeEvents, RouterBridgeResult, createRouterBridge } from './create_router_bridge.js';
|
|
6
6
|
export { MountComponentOptions, MountRouteOptions, MountTreeOptions, MountedWoodBridge, MountedWoodComponent, MountedWoodNavigation, MountedWoodRoute, MountedWoodSurface, MountedWoodTree, WoodBridgeFixtureContext, WoodBridgeFixtureInput, WoodBridgeRecordedCall, WoodBridgeRecordedEvent, WoodBrowserExpect, WoodBrowserHarness, WoodBrowserHarnessConfig, WoodBrowserPageContext, WoodBrowserTraceConfig, WoodHitTestResult, WoodRectSnapshot, WoodRpcManifestEntryInput, WoodViewport, browser, createBrowserBridgeFixture } from './browser.js';
|
|
7
|
+
export { AssertionVerdict, AutomationRectTarget, AutomationTarget, automationAssertions, evenSpacing, hidden, hitTestReachable, insideViewport, notClipped, notOverlapping, sharedEdges, stableAfterAnimation, visible } from './automation_assertions.js';
|
|
7
8
|
export { TypedCall, WoodChannelContract, WoodChannelInput, WoodChannelMapLike, WoodChannelOutput, WoodRpcTransport } from '../transport/wood_rpc_transport.js';
|
|
8
9
|
export { InProcessRouterTransport } from '../transport/in_process_router_transport.js';
|
|
9
10
|
export { LoopbackRemoteTransport, LoopbackRemoteTransportServer } from '../transport/loopback_remote_transport.js';
|
|
@@ -11,9 +12,12 @@ export { LoopbackSerializationError, assertLoopbackSerializable } from '../trans
|
|
|
11
12
|
export { TransportBridgeResult, buildTransportBridge } from '../transport/build_transport_bridge.js';
|
|
12
13
|
export { TraceRecorder } from '../trace-testing/trace_recorder.js';
|
|
13
14
|
export { T as TraceDispatchResult, a as TraceEvent, b as TraceInput, f as TraceWaitOptions } from '../trace_hub-Cob54qRx.js';
|
|
15
|
+
export { GeometryVerdict, RectAxis, RectBox, RectEdge, evenSpacing as evenSpacingRects, gaps, rectsOverlap, sharedEdges as sharedRectEdges } from './geometry.js';
|
|
14
16
|
import '../navigation/index.js';
|
|
17
|
+
import '../navigation/automation_introspection.js';
|
|
15
18
|
import '../router/wood_router.js';
|
|
16
19
|
import '../types/operations.js';
|
|
20
|
+
import 'playwright';
|
|
17
21
|
import '@noego/trace/testing';
|
|
18
22
|
import '../tracing/trace_provider.js';
|
|
19
23
|
import '@noego/ioc';
|
package/dist/testing/index.js
CHANGED
|
@@ -12,6 +12,22 @@ import {
|
|
|
12
12
|
browser,
|
|
13
13
|
createBrowserBridgeFixture
|
|
14
14
|
} from "./browser.js";
|
|
15
|
+
import {
|
|
16
|
+
automationAssertions,
|
|
17
|
+
visible,
|
|
18
|
+
hidden,
|
|
19
|
+
insideViewport,
|
|
20
|
+
notClipped,
|
|
21
|
+
notOverlapping,
|
|
22
|
+
hitTestReachable,
|
|
23
|
+
sharedEdges,
|
|
24
|
+
evenSpacing,
|
|
25
|
+
stableAfterAnimation,
|
|
26
|
+
rectsOverlap,
|
|
27
|
+
gaps,
|
|
28
|
+
sharedRectEdges,
|
|
29
|
+
evenSpacingRects
|
|
30
|
+
} from "./automation_assertions.js";
|
|
15
31
|
import {
|
|
16
32
|
InProcessRouterTransport,
|
|
17
33
|
LoopbackRemoteTransport,
|
|
@@ -29,6 +45,7 @@ export {
|
|
|
29
45
|
RouterBridgeEvents,
|
|
30
46
|
TraceRecorder,
|
|
31
47
|
assertLoopbackSerializable,
|
|
48
|
+
automationAssertions,
|
|
32
49
|
browser,
|
|
33
50
|
buildTransportBridge,
|
|
34
51
|
createBrowserBridgeFixture,
|
|
@@ -36,7 +53,20 @@ export {
|
|
|
36
53
|
createRouterBridge,
|
|
37
54
|
createTestContainer,
|
|
38
55
|
createTestRouter,
|
|
56
|
+
evenSpacing,
|
|
57
|
+
evenSpacingRects,
|
|
58
|
+
gaps,
|
|
39
59
|
getElectronMockFactory,
|
|
40
|
-
|
|
60
|
+
hidden,
|
|
61
|
+
hitTestReachable,
|
|
62
|
+
insideViewport,
|
|
63
|
+
mockElectron,
|
|
64
|
+
notClipped,
|
|
65
|
+
notOverlapping,
|
|
66
|
+
rectsOverlap,
|
|
67
|
+
sharedEdges,
|
|
68
|
+
sharedRectEdges,
|
|
69
|
+
stableAfterAnimation,
|
|
70
|
+
visible
|
|
41
71
|
};
|
|
42
72
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/testing/index.ts"],"sourcesContent":["export { createTestContainer } from './create_test_container.js';\nexport {\n createControllerHarness,\n type ControllerHarnessResult,\n type CreateControllerHarnessOptions,\n} from './create_controller_harness.js';\nexport { createTestRouter, type TestRouterResult } from './create_test_router.js';\nexport { mockElectron, getElectronMockFactory } from './mock_electron.js';\nexport {\n createRouterBridge,\n RouterBridgeEvents,\n type RouterBridgeResult,\n} from './create_router_bridge.js';\nexport {\n browser,\n createBrowserBridgeFixture,\n type MountedWoodBridge,\n type MountedWoodComponent,\n type MountedWoodNavigation,\n type MountedWoodRoute,\n type MountedWoodSurface,\n type MountedWoodTree,\n type MountComponentOptions,\n type MountRouteOptions,\n type MountTreeOptions,\n type WoodBridgeFixtureContext,\n type WoodBridgeFixtureInput,\n type WoodBridgeRecordedCall,\n type WoodBridgeRecordedEvent,\n type WoodRpcManifestEntryInput,\n type WoodBrowserExpect,\n type WoodHitTestResult,\n type WoodRectSnapshot,\n type WoodBrowserHarness,\n type WoodBrowserHarnessConfig,\n type WoodBrowserPageContext,\n type WoodBrowserTraceConfig,\n type WoodViewport,\n} from './browser.js';\nexport {\n InProcessRouterTransport,\n LoopbackRemoteTransport,\n LoopbackRemoteTransportServer,\n assertLoopbackSerializable,\n LoopbackSerializationError,\n buildTransportBridge,\n type WoodRpcTransport,\n type WoodChannelContract,\n type WoodChannelMapLike,\n type WoodChannelInput,\n type WoodChannelOutput,\n type TypedCall,\n type TransportBridgeResult,\n} from '../transport/index.js';\nexport { TraceRecorder } from '../trace-testing/index.js';\nexport type {\n TraceDispatchResult,\n TraceEvent,\n TraceInput,\n TraceWaitOptions,\n} from '../tracing/index.js';\n"],"mappings":"AAAA,SAAS,2BAA2B;AACpC;AAAA,EACE;AAAA,OAGK;AACP,SAAS,wBAA+C;AACxD,SAAS,cAAc,8BAA8B;AACrD;AAAA,EACE;AAAA,EACA;AAAA,OAEK;AACP;AAAA,EACE;AAAA,EACA;AAAA,OAuBK;AACP;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OAQK;AACP,SAAS,qBAAqB;","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/testing/index.ts"],"sourcesContent":["export { createTestContainer } from './create_test_container.js';\nexport {\n createControllerHarness,\n type ControllerHarnessResult,\n type CreateControllerHarnessOptions,\n} from './create_controller_harness.js';\nexport { createTestRouter, type TestRouterResult } from './create_test_router.js';\nexport { mockElectron, getElectronMockFactory } from './mock_electron.js';\nexport {\n createRouterBridge,\n RouterBridgeEvents,\n type RouterBridgeResult,\n} from './create_router_bridge.js';\nexport {\n browser,\n createBrowserBridgeFixture,\n type MountedWoodBridge,\n type MountedWoodComponent,\n type MountedWoodNavigation,\n type MountedWoodRoute,\n type MountedWoodSurface,\n type MountedWoodTree,\n type MountComponentOptions,\n type MountRouteOptions,\n type MountTreeOptions,\n type WoodBridgeFixtureContext,\n type WoodBridgeFixtureInput,\n type WoodBridgeRecordedCall,\n type WoodBridgeRecordedEvent,\n type WoodRpcManifestEntryInput,\n type WoodBrowserExpect,\n type WoodHitTestResult,\n type WoodRectSnapshot,\n type WoodBrowserHarness,\n type WoodBrowserHarnessConfig,\n type WoodBrowserPageContext,\n type WoodBrowserTraceConfig,\n type WoodViewport,\n} from './browser.js';\nexport {\n automationAssertions,\n visible,\n hidden,\n insideViewport,\n notClipped,\n notOverlapping,\n hitTestReachable,\n sharedEdges,\n evenSpacing,\n stableAfterAnimation,\n rectsOverlap,\n gaps,\n sharedRectEdges,\n evenSpacingRects,\n type AssertionVerdict,\n type AutomationTarget,\n type AutomationRectTarget,\n type GeometryVerdict,\n type RectAxis,\n type RectBox,\n type RectEdge,\n} from './automation_assertions.js';\nexport {\n InProcessRouterTransport,\n LoopbackRemoteTransport,\n LoopbackRemoteTransportServer,\n assertLoopbackSerializable,\n LoopbackSerializationError,\n buildTransportBridge,\n type WoodRpcTransport,\n type WoodChannelContract,\n type WoodChannelMapLike,\n type WoodChannelInput,\n type WoodChannelOutput,\n type TypedCall,\n type TransportBridgeResult,\n} from '../transport/index.js';\nexport { TraceRecorder } from '../trace-testing/index.js';\nexport type {\n TraceDispatchResult,\n TraceEvent,\n TraceInput,\n TraceWaitOptions,\n} from '../tracing/index.js';\n"],"mappings":"AAAA,SAAS,2BAA2B;AACpC;AAAA,EACE;AAAA,OAGK;AACP,SAAS,wBAA+C;AACxD,SAAS,cAAc,8BAA8B;AACrD;AAAA,EACE;AAAA,EACA;AAAA,OAEK;AACP;AAAA,EACE;AAAA,EACA;AAAA,OAuBK;AACP;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OAQK;AACP;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OAQK;AACP,SAAS,qBAAqB;","names":[]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/tracing/trace_hub.ts"],"sourcesContent":["import { Observable, Subject } from 'rxjs';\nimport { share } from 'rxjs/operators';\nimport type {\n WoodTraceEventSink,\n WoodTraceEventSnapshot,\n WoodTraceSinkDisposer,\n} from './types/wood_trace_sink.types.js';\n\nexport type StandardTraceLevel = 'debug' | 'info' | 'warn' | 'error';\nexport type TraceLevel = StandardTraceLevel | (string & {});\nexport type TraceProcess = 'main' | 'renderer' | 'test';\n\nexport type TraceInput = {\n source: string;\n type: string;\n message?: string;\n conversationId?: number | string;\n payload?: Record<string, unknown>;\n windowId?: string;\n webContentsId?: number;\n routeKey?: string;\n harnessId?: string;\n};\n\nexport type TraceEvent = TraceInput & {\n level: TraceLevel;\n process: TraceProcess;\n timestamp: string;\n traceSeq: number;\n};\n\nexport type TraceDispatchResult = {\n ok: boolean;\n forwarded: boolean;\n};\n\nexport type TraceRuntimeContext = {\n windowId?: string;\n webContentsId?: number;\n routeKey?: string;\n harnessId?: string;\n};\n\nexport type TraceWaitOptions = {\n timeoutMs?: number;\n};\n\nconst TRACE_HUB_SYMBOL = Symbol.for('@noego/wood.trace.hub');\n\nconst LEVEL_ORDER: Record<StandardTraceLevel, number> = {\n debug: 0,\n info: 1,\n warn: 2,\n error: 3,\n};\nconst CUSTOM_LEVEL_ORDER = LEVEL_ORDER.info;\n\nexport function normalizeTraceLevel(level: unknown, fallback: TraceLevel = 'info'): TraceLevel {\n if (typeof level !== 'string') {\n return fallback;\n }\n\n const normalized = level.trim().toLowerCase();\n return normalized.length > 0 ? normalized : fallback;\n}\n\nfunction traceLevelOrder(level: TraceLevel): number {\n return LEVEL_ORDER[level as StandardTraceLevel] ?? CUSTOM_LEVEL_ORDER;\n}\n\nlet rendererMinLevel: TraceLevel = 'debug';\nlet rendererEnabled = false;\nlet customRendererTraceTransport: ((payload: unknown) => void) | null = null;\n\ntype GlobalWithTraceHub = typeof globalThis & {\n [TRACE_HUB_SYMBOL]?: TraceHub;\n};\n\ntype TraceBridgeLike = Record<string, unknown> & {\n __trace?: (payload: unknown) => void;\n};\n\ntype GlobalWithTraceBridge = typeof globalThis & {\n __NOEGO_WOOD_BRIDGE__?: unknown;\n wood?: unknown;\n window?: {\n __NOEGO_WOOD_BRIDGE__?: unknown;\n wood?: unknown;\n };\n};\n\nfunction normalizeTraceInput(raw: unknown): TraceInput {\n const input = (raw ?? {}) as Partial<TraceInput> & Record<string, unknown>;\n const source = typeof input.source === 'string' && input.source.trim().length > 0\n ? input.source\n : 'unknown';\n const type = typeof input.type === 'string' && input.type.trim().length > 0\n ? input.type\n : 'unknown';\n const message = typeof input.message === 'string' ? input.message : undefined;\n const conversationId = typeof input.conversationId === 'number' || typeof input.conversationId === 'string'\n ? input.conversationId\n : undefined;\n const windowId = typeof input.windowId === 'string' && input.windowId.trim().length > 0\n ? input.windowId\n : undefined;\n const webContentsId = typeof input.webContentsId === 'number' && Number.isFinite(input.webContentsId)\n ? input.webContentsId\n : undefined;\n const routeKey = typeof input.routeKey === 'string' && input.routeKey.trim().length > 0\n ? input.routeKey\n : undefined;\n const harnessId = typeof input.harnessId === 'string' && input.harnessId.trim().length > 0\n ? input.harnessId\n : undefined;\n const payload = isRecord(input.payload) ? { ...input.payload } : undefined;\n\n return {\n source,\n type,\n ...(message ? { message } : {}),\n ...(conversationId !== undefined ? { conversationId } : {}),\n ...(windowId !== undefined ? { windowId } : {}),\n ...(webContentsId !== undefined ? { webContentsId } : {}),\n ...(routeKey !== undefined ? { routeKey } : {}),\n ...(harnessId !== undefined ? { harnessId } : {}),\n ...(payload ? { payload } : {}),\n };\n}\n\nfunction mergeTraceRuntimeContext(input: unknown, context: TraceRuntimeContext | undefined): TraceInput {\n if (!context) {\n return normalizeTraceInput(input);\n }\n return normalizeTraceInput({\n ...(isRecord(input) ? input : {}),\n ...context,\n });\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction resolveTraceBridge(): TraceBridgeLike | null {\n const globalObj = globalThis as GlobalWithTraceBridge;\n const bridge = globalObj.__NOEGO_WOOD_BRIDGE__\n ?? globalObj.window?.__NOEGO_WOOD_BRIDGE__\n ?? globalObj.wood\n ?? globalObj.window?.wood;\n if (!bridge || typeof bridge !== 'object') {\n return null;\n }\n return bridge as TraceBridgeLike;\n}\n\nclass TraceHub {\n private readonly subject = new Subject<TraceEvent>();\n private readonly shared$ = this.subject.asObservable().pipe(share());\n private readonly sinks = new Set<WoodTraceEventSink>();\n private nextTraceSeq = 1;\n private minLevels: Record<TraceProcess, TraceLevel> = {\n main: 'debug',\n renderer: 'debug',\n test: 'debug',\n };\n\n get events$(): Observable<TraceEvent> {\n return this.shared$;\n }\n\n setMinLevel(process: TraceProcess, level: TraceLevel): void {\n this.minLevels[process] = level;\n }\n\n registerSink(sink: WoodTraceEventSink): WoodTraceSinkDisposer {\n this.sinks.add(sink);\n return () => {\n this.sinks.delete(sink);\n };\n }\n\n publish(process: TraceProcess, level: TraceLevel, input: unknown): TraceEvent {\n const normalized = normalizeTraceInput(input);\n const event: TraceEvent = {\n ...normalized,\n level,\n process,\n timestamp: new Date().toISOString(),\n traceSeq: this.nextTraceSeq++,\n };\n if (traceLevelOrder(level) >= traceLevelOrder(this.minLevels[process])) {\n this.publishToSinks(event);\n this.subject.next(event);\n }\n return event;\n }\n\n publishRendererToSinks(level: TraceLevel, input: TraceInput): void {\n if (this.sinks.size === 0) {\n return;\n }\n const event: TraceEvent = {\n ...input,\n level,\n process: 'renderer',\n timestamp: new Date().toISOString(),\n traceSeq: this.nextTraceSeq++,\n };\n this.publishToSinks(event);\n }\n\n private publishToSinks(event: TraceEvent): void {\n if (this.sinks.size === 0) {\n return;\n }\n const snapshot: WoodTraceEventSnapshot = Object.freeze({\n ...event,\n ...(event.payload ? { payload: Object.freeze({ ...event.payload }) } : {}),\n });\n for (const sink of this.sinks) {\n try {\n sink(snapshot);\n } catch {\n // Trace sinks are observational and cannot fail trace callers or peers.\n }\n }\n }\n}\n\nfunction getGlobalTraceHub(): TraceHub {\n const globalObj = globalThis as GlobalWithTraceHub;\n if (!globalObj[TRACE_HUB_SYMBOL]) {\n globalObj[TRACE_HUB_SYMBOL] = new TraceHub();\n }\n return globalObj[TRACE_HUB_SYMBOL] as TraceHub;\n}\n\nexport function getTraceEvents$(): Observable<TraceEvent> {\n return getGlobalTraceHub().events$;\n}\n\nexport function registerTraceSink(sink: WoodTraceEventSink): WoodTraceSinkDisposer {\n return getGlobalTraceHub().registerSink(sink);\n}\n\nexport function setMainTraceMinLevel(level: TraceLevel): void {\n getGlobalTraceHub().setMinLevel('main', level);\n}\n\nexport function setRendererTraceMinLevel(level: TraceLevel): void {\n rendererMinLevel = level;\n getGlobalTraceHub().setMinLevel('renderer', level);\n}\n\nexport function setRendererTraceEnabled(enabled: boolean): void {\n rendererEnabled = enabled;\n}\n\nexport function publishMainTrace(level: TraceLevel, input: unknown): TraceEvent {\n return getGlobalTraceHub().publish('main', level, input);\n}\n\nexport function publishTestTrace(process: TraceProcess, level: TraceLevel, input: unknown): TraceEvent {\n return getGlobalTraceHub().publish(process, level, input);\n}\n\nexport function dispatchRendererTracePayload(\n rawPayload: unknown,\n context?: TraceRuntimeContext,\n): TraceDispatchResult {\n const payload = (rawPayload ?? {}) as Partial<TraceInput> & { level?: unknown };\n const level = normalizeTraceLevel(payload.level);\n getGlobalTraceHub().publish('renderer', level, mergeTraceRuntimeContext(payload, context));\n return {\n ok: true,\n forwarded: true,\n };\n}\n\nexport function setRendererTraceTransport(fn: ((payload: unknown) => void) | null): void {\n customRendererTraceTransport = fn;\n}\n\nexport function emitRendererTrace(level: TraceLevel, input: TraceInput): void {\n if (!rendererEnabled) {\n return;\n }\n if (traceLevelOrder(level) < traceLevelOrder(rendererMinLevel)) {\n return;\n }\n const normalized = { ...normalizeTraceInput(input), level };\n getGlobalTraceHub().publishRendererToSinks(level, normalized);\n\n if (customRendererTraceTransport) {\n try {\n customRendererTraceTransport(normalized);\n return;\n } catch {\n // Fall through to bridge.__trace\n }\n }\n\n const bridge = resolveTraceBridge();\n if (!bridge || typeof bridge.__trace !== 'function') {\n return;\n }\n try {\n bridge.__trace(normalized);\n } catch {\n // Tracing is observational and must never break the caller.\n }\n}\n\nexport function clearTraceHubForTests(): void {\n const globalObj = globalThis as GlobalWithTraceHub;\n delete globalObj[TRACE_HUB_SYMBOL];\n rendererMinLevel = 'debug';\n rendererEnabled = false;\n customRendererTraceTransport = null;\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/tracing/trace_hub.ts"],"sourcesContent":["import { Observable, Subject } from 'rxjs';\nimport { share } from 'rxjs/operators';\nimport type {\n WoodTraceEventSink,\n WoodTraceEventSnapshot,\n WoodTraceSinkDisposer,\n} from './types/wood_trace_sink.types.js';\n\nexport type StandardTraceLevel = 'debug' | 'info' | 'warn' | 'error';\nexport type TraceLevel = StandardTraceLevel | (string & {});\nexport type TraceProcess = 'main' | 'renderer' | 'test';\n\nexport type TraceInput = {\n source: string;\n type: string;\n message?: string;\n conversationId?: number | string;\n payload?: Record<string, unknown>;\n windowId?: string;\n webContentsId?: number;\n routeKey?: string;\n harnessId?: string;\n};\n\nexport type TraceEvent = TraceInput & {\n level: TraceLevel;\n process: TraceProcess;\n timestamp: string;\n traceSeq: number;\n};\n\nexport type TraceDispatchResult = {\n ok: boolean;\n forwarded: boolean;\n};\n\nexport type TraceRuntimeContext = {\n windowId?: string;\n webContentsId?: number;\n routeKey?: string;\n harnessId?: string;\n};\n\nexport type TraceWaitOptions = {\n timeoutMs?: number;\n};\n\nconst TRACE_HUB_SYMBOL = Symbol.for('@noego/wood.trace.hub');\n\nconst LEVEL_ORDER: Record<StandardTraceLevel, number> = {\n debug: 0,\n info: 1,\n warn: 2,\n error: 3,\n};\nconst CUSTOM_LEVEL_ORDER = LEVEL_ORDER.info;\n\nexport function normalizeTraceLevel(level: unknown, fallback: TraceLevel = 'info'): TraceLevel {\n if (typeof level !== 'string') {\n return fallback;\n }\n\n const normalized = level.trim().toLowerCase();\n return normalized.length > 0 ? normalized : fallback;\n}\n\nfunction traceLevelOrder(level: TraceLevel): number {\n return LEVEL_ORDER[level as StandardTraceLevel] ?? CUSTOM_LEVEL_ORDER;\n}\n\nlet rendererMinLevel: TraceLevel = 'debug';\nlet rendererEnabled = false;\nlet customRendererTraceTransport: ((payload: unknown) => void) | null = null;\n\ntype GlobalWithTraceHub = typeof globalThis & {\n [TRACE_HUB_SYMBOL]?: TraceHub;\n};\n\ntype TraceBridgeLike = Record<string, unknown> & {\n __trace?: (payload: unknown) => void;\n};\n\ntype GlobalWithTraceBridge = typeof globalThis & {\n __NOEGO_WOOD_BRIDGE__?: unknown;\n wood?: unknown;\n window?: {\n __NOEGO_WOOD_BRIDGE__?: unknown;\n wood?: unknown;\n };\n};\n\nfunction normalizeTraceInput(raw: unknown): TraceInput {\n const input = (raw ?? {}) as Partial<TraceInput> & Record<string, unknown>;\n const source = typeof input.source === 'string' && input.source.trim().length > 0\n ? input.source\n : 'unknown';\n const type = typeof input.type === 'string' && input.type.trim().length > 0\n ? input.type\n : 'unknown';\n const message = typeof input.message === 'string' ? input.message : undefined;\n const conversationId = typeof input.conversationId === 'number' || typeof input.conversationId === 'string'\n ? input.conversationId\n : undefined;\n const windowId = typeof input.windowId === 'string' && input.windowId.trim().length > 0\n ? input.windowId\n : undefined;\n const webContentsId = typeof input.webContentsId === 'number' && Number.isFinite(input.webContentsId)\n ? input.webContentsId\n : undefined;\n const routeKey = typeof input.routeKey === 'string' && input.routeKey.trim().length > 0\n ? input.routeKey\n : undefined;\n const harnessId = typeof input.harnessId === 'string' && input.harnessId.trim().length > 0\n ? input.harnessId\n : undefined;\n const payload = isRecord(input.payload) ? { ...input.payload } : undefined;\n\n return {\n source,\n type,\n ...(message ? { message } : {}),\n ...(conversationId !== undefined ? { conversationId } : {}),\n ...(windowId !== undefined ? { windowId } : {}),\n ...(webContentsId !== undefined ? { webContentsId } : {}),\n ...(routeKey !== undefined ? { routeKey } : {}),\n ...(harnessId !== undefined ? { harnessId } : {}),\n ...(payload ? { payload } : {}),\n };\n}\n\nfunction mergeTraceRuntimeContext(input: unknown, context: TraceRuntimeContext | undefined): TraceInput {\n if (!context) {\n return normalizeTraceInput(input);\n }\n return normalizeTraceInput({\n ...(isRecord(input) ? input : {}),\n ...context,\n });\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction resolveTraceBridge(): TraceBridgeLike | null {\n const globalObj = globalThis as GlobalWithTraceBridge;\n const bridge = globalObj.__NOEGO_WOOD_BRIDGE__\n ?? globalObj.window?.__NOEGO_WOOD_BRIDGE__\n ?? globalObj.wood\n ?? globalObj.window?.wood;\n if (!bridge || typeof bridge !== 'object') {\n return null;\n }\n return bridge as TraceBridgeLike;\n}\n\nclass TraceHub {\n private readonly subject = new Subject<TraceEvent>();\n private readonly shared$ = this.subject.asObservable().pipe(share());\n private readonly sinks = new Set<WoodTraceEventSink>();\n private nextTraceSeq = 1;\n private minLevels: Record<TraceProcess, TraceLevel> = {\n main: 'debug',\n renderer: 'debug',\n test: 'debug',\n };\n\n get events$(): Observable<TraceEvent> {\n return this.shared$;\n }\n\n setMinLevel(process: TraceProcess, level: TraceLevel): void {\n this.minLevels[process] = level;\n }\n\n registerSink(sink: WoodTraceEventSink): WoodTraceSinkDisposer {\n this.sinks.add(sink);\n return () => {\n this.sinks.delete(sink);\n };\n }\n\n publish(process: TraceProcess, level: TraceLevel, input: unknown): TraceEvent {\n const normalized = normalizeTraceInput(input);\n const event: TraceEvent = {\n ...normalized,\n level,\n process,\n timestamp: new Date().toISOString(),\n traceSeq: this.nextTraceSeq++,\n };\n if (traceLevelOrder(level) >= traceLevelOrder(this.minLevels[process])) {\n this.publishToSinks(event);\n this.subject.next(event);\n }\n return event;\n }\n\n publishRendererToSinks(level: TraceLevel, input: TraceInput): void {\n if (this.sinks.size === 0) {\n return;\n }\n if (traceLevelOrder(level) < traceLevelOrder(this.minLevels.renderer)) {\n return;\n }\n const event: TraceEvent = {\n ...input,\n level,\n process: 'renderer',\n timestamp: new Date().toISOString(),\n traceSeq: this.nextTraceSeq++,\n };\n this.publishToSinks(event);\n }\n\n private publishToSinks(event: TraceEvent): void {\n if (this.sinks.size === 0) {\n return;\n }\n const snapshot: WoodTraceEventSnapshot = Object.freeze({\n ...event,\n ...(event.payload ? { payload: Object.freeze({ ...event.payload }) } : {}),\n });\n for (const sink of this.sinks) {\n try {\n sink(snapshot);\n } catch {\n // Trace sinks are observational and cannot fail trace callers or peers.\n }\n }\n }\n}\n\nfunction getGlobalTraceHub(): TraceHub {\n const globalObj = globalThis as GlobalWithTraceHub;\n if (!globalObj[TRACE_HUB_SYMBOL]) {\n globalObj[TRACE_HUB_SYMBOL] = new TraceHub();\n }\n return globalObj[TRACE_HUB_SYMBOL] as TraceHub;\n}\n\nexport function getTraceEvents$(): Observable<TraceEvent> {\n return getGlobalTraceHub().events$;\n}\n\nexport function registerTraceSink(sink: WoodTraceEventSink): WoodTraceSinkDisposer {\n return getGlobalTraceHub().registerSink(sink);\n}\n\nexport function setMainTraceMinLevel(level: TraceLevel): void {\n getGlobalTraceHub().setMinLevel('main', level);\n}\n\nexport function setRendererTraceMinLevel(level: TraceLevel): void {\n rendererMinLevel = level;\n getGlobalTraceHub().setMinLevel('renderer', level);\n}\n\nexport function setRendererTraceEnabled(enabled: boolean): void {\n rendererEnabled = enabled;\n}\n\nexport function publishMainTrace(level: TraceLevel, input: unknown): TraceEvent {\n return getGlobalTraceHub().publish('main', level, input);\n}\n\nexport function publishTestTrace(process: TraceProcess, level: TraceLevel, input: unknown): TraceEvent {\n return getGlobalTraceHub().publish(process, level, input);\n}\n\nexport function dispatchRendererTracePayload(\n rawPayload: unknown,\n context?: TraceRuntimeContext,\n): TraceDispatchResult {\n const payload = (rawPayload ?? {}) as Partial<TraceInput> & { level?: unknown };\n const level = normalizeTraceLevel(payload.level);\n getGlobalTraceHub().publish('renderer', level, mergeTraceRuntimeContext(payload, context));\n return {\n ok: true,\n forwarded: true,\n };\n}\n\nexport function setRendererTraceTransport(fn: ((payload: unknown) => void) | null): void {\n customRendererTraceTransport = fn;\n}\n\nexport function emitRendererTrace(level: TraceLevel, input: TraceInput): void {\n if (!rendererEnabled) {\n return;\n }\n if (traceLevelOrder(level) < traceLevelOrder(rendererMinLevel)) {\n return;\n }\n const normalized = { ...normalizeTraceInput(input), level };\n getGlobalTraceHub().publishRendererToSinks(level, normalized);\n\n if (customRendererTraceTransport) {\n try {\n customRendererTraceTransport(normalized);\n return;\n } catch {\n // Fall through to bridge.__trace\n }\n }\n\n const bridge = resolveTraceBridge();\n if (!bridge || typeof bridge.__trace !== 'function') {\n return;\n }\n try {\n bridge.__trace(normalized);\n } catch {\n // Tracing is observational and must never break the caller.\n }\n}\n\nexport function clearTraceHubForTests(): void {\n const globalObj = globalThis as GlobalWithTraceHub;\n delete globalObj[TRACE_HUB_SYMBOL];\n rendererMinLevel = 'debug';\n rendererEnabled = false;\n customRendererTraceTransport = null;\n}\n"],"mappings":"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","names":[]}
|