@noego/wood 0.4.6 → 0.4.7
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/wood.js +6 -1
- package/dist/client/app_env.cjs +39 -0
- package/dist/client/app_env.cjs.map +1 -0
- package/dist/client/app_env.d.cts +7 -0
- package/dist/client/app_env.d.ts +7 -0
- package/dist/client/app_env.js +14 -0
- package/dist/client/app_env.js.map +1 -0
- package/dist/client/index.cjs +33 -9
- package/dist/client/index.cjs.map +1 -1
- package/dist/client/index.d.cts +5 -1
- package/dist/client/index.d.ts +5 -1
- package/dist/client/index.js +32 -9
- package/dist/client/index.js.map +1 -1
- package/dist/codegen/channel_map_generator.cjs +102 -0
- package/dist/codegen/channel_map_generator.cjs.map +1 -0
- package/dist/codegen/channel_map_generator.d.cts +6 -0
- package/dist/codegen/channel_map_generator.d.ts +6 -0
- package/dist/codegen/channel_map_generator.js +78 -0
- package/dist/codegen/channel_map_generator.js.map +1 -0
- package/dist/codegen/controller_registration_generator.cjs +6 -1
- package/dist/codegen/controller_registration_generator.cjs.map +1 -1
- package/dist/codegen/controller_registration_generator.js +6 -1
- package/dist/codegen/controller_registration_generator.js.map +1 -1
- package/dist/codegen/generated_file_notice.cjs +40 -0
- package/dist/codegen/generated_file_notice.cjs.map +1 -0
- package/dist/codegen/generated_file_notice.d.cts +3 -0
- package/dist/codegen/generated_file_notice.d.ts +3 -0
- package/dist/codegen/generated_file_notice.js +16 -0
- package/dist/codegen/generated_file_notice.js.map +1 -0
- package/dist/codegen/index.cjs +3 -0
- package/dist/codegen/index.cjs.map +1 -1
- package/dist/codegen/index.d.cts +1 -0
- package/dist/codegen/index.d.ts +1 -0
- package/dist/codegen/index.js +2 -0
- package/dist/codegen/index.js.map +1 -1
- package/dist/codegen/preload_generator.cjs +97 -1
- package/dist/codegen/preload_generator.cjs.map +1 -1
- package/dist/codegen/preload_generator.js +97 -1
- package/dist/codegen/preload_generator.js.map +1 -1
- package/dist/codegen/renderer_app_generator.cjs +6 -1
- package/dist/codegen/renderer_app_generator.cjs.map +1 -1
- package/dist/codegen/renderer_app_generator.js +6 -1
- package/dist/codegen/renderer_app_generator.js.map +1 -1
- package/dist/codegen/renderer_controller_registration_generator.cjs +6 -1
- package/dist/codegen/renderer_controller_registration_generator.cjs.map +1 -1
- package/dist/codegen/renderer_controller_registration_generator.js +6 -1
- package/dist/codegen/renderer_controller_registration_generator.js.map +1 -1
- package/dist/codegen/renderer_view_manifest_generator.cjs +6 -1
- package/dist/codegen/renderer_view_manifest_generator.cjs.map +1 -1
- package/dist/codegen/renderer_view_manifest_generator.js +6 -1
- package/dist/codegen/renderer_view_manifest_generator.js.map +1 -1
- package/dist/codegen/runtime_generator.cjs +6 -1
- package/dist/codegen/runtime_generator.cjs.map +1 -1
- package/dist/codegen/runtime_generator.js +6 -1
- package/dist/codegen/runtime_generator.js.map +1 -1
- package/dist/codegen/test_mock_generator.cjs +5 -1
- package/dist/codegen/test_mock_generator.cjs.map +1 -1
- package/dist/codegen/test_mock_generator.js +5 -1
- package/dist/codegen/test_mock_generator.js.map +1 -1
- package/dist/codegen/type_generator.cjs +6 -1
- package/dist/codegen/type_generator.cjs.map +1 -1
- package/dist/codegen/type_generator.js +6 -1
- package/dist/codegen/type_generator.js.map +1 -1
- package/dist/index.cjs +19 -6
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +7 -1
- package/dist/index.d.ts +7 -1
- package/dist/index.js +13 -1
- package/dist/index.js.map +1 -1
- package/dist/main/index.cjs +133 -55
- package/dist/main/index.cjs.map +1 -1
- package/dist/main/index.d.cts +30 -2
- package/dist/main/index.d.ts +30 -2
- package/dist/main/index.js +134 -55
- package/dist/main/index.js.map +1 -1
- package/dist/main/renderer_trace_drain_coordinator.cjs +127 -0
- package/dist/main/renderer_trace_drain_coordinator.cjs.map +1 -0
- package/dist/main/renderer_trace_drain_coordinator.d.cts +46 -0
- package/dist/main/renderer_trace_drain_coordinator.d.ts +46 -0
- package/dist/main/renderer_trace_drain_coordinator.js +101 -0
- package/dist/main/renderer_trace_drain_coordinator.js.map +1 -0
- package/dist/router/wood_router.cjs +9 -1
- package/dist/router/wood_router.cjs.map +1 -1
- package/dist/router/wood_router.d.cts +1 -1
- package/dist/router/wood_router.d.ts +1 -1
- package/dist/router/wood_router.js +9 -1
- package/dist/router/wood_router.js.map +1 -1
- package/dist/runtime/app_env.cjs +52 -0
- package/dist/runtime/app_env.cjs.map +1 -0
- package/dist/runtime/app_env.d.cts +10 -0
- package/dist/runtime/app_env.d.ts +10 -0
- package/dist/runtime/app_env.js +18 -0
- package/dist/runtime/app_env.js.map +1 -0
- package/dist/runtime/index.cjs +9 -2
- package/dist/runtime/index.cjs.map +1 -1
- package/dist/runtime/index.d.cts +5 -1
- package/dist/runtime/index.d.ts +5 -1
- package/dist/runtime/index.js +9 -1
- package/dist/runtime/index.js.map +1 -1
- package/dist/runtime/renderer_log_dispatcher.cjs.map +1 -1
- package/dist/runtime/renderer_log_dispatcher.d.cts +1 -1
- package/dist/runtime/renderer_log_dispatcher.d.ts +1 -1
- package/dist/runtime/renderer_log_dispatcher.js.map +1 -1
- package/dist/runtime/renderer_trace_batch_receiver_registry.cjs +50 -0
- package/dist/runtime/renderer_trace_batch_receiver_registry.cjs.map +1 -0
- package/dist/runtime/renderer_trace_batch_receiver_registry.d.cts +10 -0
- package/dist/runtime/renderer_trace_batch_receiver_registry.d.ts +10 -0
- package/dist/runtime/renderer_trace_batch_receiver_registry.js +24 -0
- package/dist/runtime/renderer_trace_batch_receiver_registry.js.map +1 -0
- package/dist/runtime/runtime.cjs +75 -57
- package/dist/runtime/runtime.cjs.map +1 -1
- package/dist/runtime/runtime.d.cts +8 -1
- package/dist/runtime/runtime.d.ts +8 -1
- package/dist/runtime/runtime.js +80 -58
- package/dist/runtime/runtime.js.map +1 -1
- package/dist/testing/browser.cjs +540 -11
- package/dist/testing/browser.cjs.map +1 -1
- package/dist/testing/browser.d.cts +219 -3
- package/dist/testing/browser.d.ts +219 -3
- package/dist/testing/browser.js +540 -11
- package/dist/testing/browser.js.map +1 -1
- package/dist/testing/create_controller_harness.d.cts +1 -1
- package/dist/testing/create_controller_harness.d.ts +1 -1
- package/dist/testing/index.cjs +13 -0
- package/dist/testing/index.cjs.map +1 -1
- package/dist/testing/index.d.cts +7 -2
- package/dist/testing/index.d.ts +7 -2
- package/dist/testing/index.js +14 -0
- package/dist/testing/index.js.map +1 -1
- package/dist/trace-testing/index.d.cts +1 -1
- package/dist/trace-testing/index.d.ts +1 -1
- package/dist/trace-testing/trace_recorder.d.cts +1 -1
- package/dist/trace-testing/trace_recorder.d.ts +1 -1
- package/dist/trace-transport/index.cjs +32 -0
- package/dist/trace-transport/index.cjs.map +1 -0
- package/dist/trace-transport/index.d.cts +6 -0
- package/dist/trace-transport/index.d.ts +6 -0
- package/dist/trace-transport/index.js +7 -0
- package/dist/trace-transport/index.js.map +1 -0
- package/dist/trace_hub-Cob54qRx.d.cts +56 -0
- package/dist/trace_hub-Cob54qRx.d.ts +56 -0
- package/dist/tracing/index.cjs +14 -0
- package/dist/tracing/index.cjs.map +1 -1
- package/dist/tracing/index.d.cts +7 -1
- package/dist/tracing/index.d.ts +7 -1
- package/dist/tracing/index.js +12 -0
- package/dist/tracing/index.js.map +1 -1
- package/dist/tracing/renderer_trace_batch_host.cjs +80 -0
- package/dist/tracing/renderer_trace_batch_host.cjs.map +1 -0
- package/dist/tracing/renderer_trace_batch_host.d.cts +16 -0
- package/dist/tracing/renderer_trace_batch_host.d.ts +16 -0
- package/dist/tracing/renderer_trace_batch_host.js +56 -0
- package/dist/tracing/renderer_trace_batch_host.js.map +1 -0
- package/dist/tracing/renderer_trace_batch_transport.cjs +313 -0
- package/dist/tracing/renderer_trace_batch_transport.cjs.map +1 -0
- package/dist/tracing/renderer_trace_batch_transport.d.cts +53 -0
- package/dist/tracing/renderer_trace_batch_transport.d.ts +53 -0
- package/dist/tracing/renderer_trace_batch_transport.js +292 -0
- package/dist/tracing/renderer_trace_batch_transport.js.map +1 -0
- package/dist/tracing/trace_commit_writer.cjs +159 -0
- package/dist/tracing/trace_commit_writer.cjs.map +1 -0
- package/dist/tracing/trace_commit_writer.d.cts +97 -0
- package/dist/tracing/trace_commit_writer.d.ts +97 -0
- package/dist/tracing/trace_commit_writer.js +135 -0
- package/dist/tracing/trace_commit_writer.js.map +1 -0
- package/dist/tracing/trace_hub.cjs +58 -3
- package/dist/tracing/trace_hub.cjs.map +1 -1
- package/dist/tracing/trace_hub.d.cts +2 -46
- package/dist/tracing/trace_hub.d.ts +2 -46
- package/dist/tracing/trace_hub.js +56 -3
- package/dist/tracing/trace_hub.js.map +1 -1
- package/dist/tracing/trace_provider.cjs +42 -12
- package/dist/tracing/trace_provider.cjs.map +1 -1
- package/dist/tracing/trace_provider.d.cts +15 -1
- package/dist/tracing/trace_provider.d.ts +15 -1
- package/dist/tracing/trace_provider.js +43 -12
- package/dist/tracing/trace_provider.js.map +1 -1
- package/dist/tracing/types/wood_trace_batch.types.cjs +17 -0
- package/dist/tracing/types/wood_trace_batch.types.cjs.map +1 -0
- package/dist/tracing/types/wood_trace_batch.types.d.cts +124 -0
- package/dist/tracing/types/wood_trace_batch.types.d.ts +124 -0
- package/dist/tracing/types/wood_trace_batch.types.js +1 -0
- package/dist/tracing/types/wood_trace_batch.types.js.map +1 -0
- package/dist/tracing/types/wood_trace_sink.types.cjs +17 -0
- package/dist/tracing/types/wood_trace_sink.types.cjs.map +1 -0
- package/dist/tracing/types/wood_trace_sink.types.d.cts +2 -0
- package/dist/tracing/types/wood_trace_sink.types.d.ts +2 -0
- package/dist/tracing/types/wood_trace_sink.types.js +1 -0
- package/dist/tracing/types/wood_trace_sink.types.js.map +1 -0
- package/dist/tracing/wood_trace_batch_contract.cjs +229 -0
- package/dist/tracing/wood_trace_batch_contract.cjs.map +1 -0
- package/dist/tracing/wood_trace_batch_contract.d.cts +23 -0
- package/dist/tracing/wood_trace_batch_contract.d.ts +23 -0
- package/dist/tracing/wood_trace_batch_contract.js +205 -0
- package/dist/tracing/wood_trace_batch_contract.js.map +1 -0
- package/dist/transport/build_transport_bridge.cjs +62 -0
- package/dist/transport/build_transport_bridge.cjs.map +1 -0
- package/dist/transport/build_transport_bridge.d.cts +29 -0
- package/dist/transport/build_transport_bridge.d.ts +29 -0
- package/dist/transport/build_transport_bridge.js +38 -0
- package/dist/transport/build_transport_bridge.js.map +1 -0
- package/dist/transport/in_process_router_transport.cjs +41 -0
- package/dist/transport/in_process_router_transport.cjs.map +1 -0
- package/dist/transport/in_process_router_transport.d.cts +31 -0
- package/dist/transport/in_process_router_transport.d.ts +31 -0
- package/dist/transport/in_process_router_transport.js +17 -0
- package/dist/transport/in_process_router_transport.js.map +1 -0
- package/dist/transport/index.cjs +42 -0
- package/dist/transport/index.cjs.map +1 -0
- package/dist/transport/index.d.cts +8 -0
- package/dist/transport/index.d.ts +8 -0
- package/dist/transport/index.js +19 -0
- package/dist/transport/index.js.map +1 -0
- package/dist/transport/loopback_remote_transport.cjs +270 -0
- package/dist/transport/loopback_remote_transport.cjs.map +1 -0
- package/dist/transport/loopback_remote_transport.d.cts +49 -0
- package/dist/transport/loopback_remote_transport.d.ts +49 -0
- package/dist/transport/loopback_remote_transport.js +237 -0
- package/dist/transport/loopback_remote_transport.js.map +1 -0
- package/dist/transport/loopback_serialization.cjs +116 -0
- package/dist/transport/loopback_serialization.cjs.map +1 -0
- package/dist/transport/loopback_serialization.d.cts +28 -0
- package/dist/transport/loopback_serialization.d.ts +28 -0
- package/dist/transport/loopback_serialization.js +91 -0
- package/dist/transport/loopback_serialization.js.map +1 -0
- package/dist/transport/transport_contract_suite.cjs +110 -0
- package/dist/transport/transport_contract_suite.cjs.map +1 -0
- package/dist/transport/transport_contract_suite.d.cts +23 -0
- package/dist/transport/transport_contract_suite.d.ts +23 -0
- package/dist/transport/transport_contract_suite.js +85 -0
- package/dist/transport/transport_contract_suite.js.map +1 -0
- package/dist/transport/wood_rpc_transport.cjs +17 -0
- package/dist/transport/wood_rpc_transport.cjs.map +1 -0
- package/dist/transport/wood_rpc_transport.d.cts +44 -0
- package/dist/transport/wood_rpc_transport.d.ts +44 -0
- package/dist/transport/wood_rpc_transport.js +1 -0
- package/dist/transport/wood_rpc_transport.js.map +1 -0
- package/docs/browser-testing.md +139 -1
- package/package.json +22 -3
- package/src/components/NavigationShell.browser.test.ts +236 -0
- package/src/components/NavigationShell.svelte +162 -49
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { TraceLevel } from '../
|
|
1
|
+
import { c as TraceLevel } from '../trace_hub-Cob54qRx.cjs';
|
|
2
2
|
import { TraceRecorder } from '../trace-testing/trace_recorder.cjs';
|
|
3
|
+
import { WoodRpcTransport } from '../transport/wood_rpc_transport.cjs';
|
|
3
4
|
import 'rxjs';
|
|
4
5
|
import '@noego/trace/testing';
|
|
5
6
|
import '../tracing/trace_provider.cjs';
|
|
@@ -31,6 +32,30 @@ interface WoodBridgeFixtureInput {
|
|
|
31
32
|
operations?: Record<string, OperationHandler>;
|
|
32
33
|
events?: Record<string, unknown | unknown[]>;
|
|
33
34
|
record?: boolean;
|
|
35
|
+
/**
|
|
36
|
+
* Real-backend mode. When supplied, page `invoke` is routed through this
|
|
37
|
+
* `WoodRpcTransport` (dispatching through the REAL WoodRouter — full schema
|
|
38
|
+
* validation) instead of the fixture `operations` Map, and page `bridge.on(...)`
|
|
39
|
+
* subscriptions are relayed to `transport.subscribe(...)` so main-process push
|
|
40
|
+
* events reach page subscribers. Fixture `operations` still act as a fallback
|
|
41
|
+
* for any channel not registered on the transport, so hybrid fixtures work.
|
|
42
|
+
* Omit for the legacy fixture-only bridge (spec §4: labeled visual tests).
|
|
43
|
+
*/
|
|
44
|
+
transport?: WoodRpcTransport;
|
|
45
|
+
/**
|
|
46
|
+
* Full RPC manifest to build the page bridge tree from. Required in transport
|
|
47
|
+
* mode so every real channel is exposed on the bridge (in fixture mode the
|
|
48
|
+
* manifest is derived from `operations`). Supply the app's complete operations
|
|
49
|
+
* manifest (channel/controller/action/path/hasInput per operation).
|
|
50
|
+
*/
|
|
51
|
+
rpcManifest?: WoodRpcManifestEntryInput[];
|
|
52
|
+
}
|
|
53
|
+
interface WoodRpcManifestEntryInput {
|
|
54
|
+
channel: string;
|
|
55
|
+
controller: string;
|
|
56
|
+
action: string;
|
|
57
|
+
path: string[];
|
|
58
|
+
hasInput: boolean;
|
|
34
59
|
}
|
|
35
60
|
interface WoodBrowserPageContext {
|
|
36
61
|
page: any;
|
|
@@ -120,6 +145,43 @@ interface MountedWoodNavigation {
|
|
|
120
145
|
go(page: string, params?: Record<string, string>, query?: Record<string, string>): Promise<void>;
|
|
121
146
|
replace(page: string, params?: Record<string, string>, query?: Record<string, string>): Promise<void>;
|
|
122
147
|
}
|
|
148
|
+
/** Snapshot of one element's viewport-space box, tagged with its source selector. */
|
|
149
|
+
interface WoodRectSnapshot {
|
|
150
|
+
selector: string;
|
|
151
|
+
top: number;
|
|
152
|
+
left: number;
|
|
153
|
+
right: number;
|
|
154
|
+
bottom: number;
|
|
155
|
+
width: number;
|
|
156
|
+
height: number;
|
|
157
|
+
}
|
|
158
|
+
/** Axis along which edge-to-edge spacing is measured. */
|
|
159
|
+
type WoodSpacingAxis = 'horizontal' | 'vertical';
|
|
160
|
+
/**
|
|
161
|
+
* Description of the top-most element painted at a hit-test point, plus its
|
|
162
|
+
* relationship to the queried target. `document.elementFromPoint` honours
|
|
163
|
+
* `pointer-events`, so an element with `pointer-events: none` is transparent to
|
|
164
|
+
* the hit test even when it is painted on top (see `hitTest`/`unoccluded`).
|
|
165
|
+
*/
|
|
166
|
+
interface WoodHitTestResult {
|
|
167
|
+
/** False when no element is painted at the point (e.g. outside the document). */
|
|
168
|
+
found: boolean;
|
|
169
|
+
tag: string | null;
|
|
170
|
+
id: string | null;
|
|
171
|
+
classes: string[];
|
|
172
|
+
/** The hit element is exactly the target. */
|
|
173
|
+
isTarget: boolean;
|
|
174
|
+
/** The hit element is a descendant of the target (target paints through it). */
|
|
175
|
+
isDescendantOfTarget: boolean;
|
|
176
|
+
/** The hit element is an ancestor of the target. */
|
|
177
|
+
isAncestorOfTarget: boolean;
|
|
178
|
+
point: {
|
|
179
|
+
x: number;
|
|
180
|
+
y: number;
|
|
181
|
+
};
|
|
182
|
+
/** Human-readable one-line description of the hit element. */
|
|
183
|
+
description: string;
|
|
184
|
+
}
|
|
123
185
|
interface WoodBrowserExpect {
|
|
124
186
|
visible(selector: string): Promise<void>;
|
|
125
187
|
hidden(selector: string): Promise<void>;
|
|
@@ -128,6 +190,12 @@ interface WoodBrowserExpect {
|
|
|
128
190
|
}): Promise<void>;
|
|
129
191
|
notClipped(selector: string): Promise<void>;
|
|
130
192
|
notOverlapping(firstSelector: string, secondSelector: string): Promise<void>;
|
|
193
|
+
/**
|
|
194
|
+
* @deprecated Compares numeric computed `z-index` only, so it lies whenever
|
|
195
|
+
* stacking contexts, DOM paint order (auto/equal z-index), or
|
|
196
|
+
* transform/opacity contexts decide the real front-to-back order. Prefer
|
|
197
|
+
* `inFrontOf`, which hit-tests the actual painted pixel.
|
|
198
|
+
*/
|
|
131
199
|
zIndexAbove(topSelector: string, lowerSelector: string): Promise<void>;
|
|
132
200
|
stableAfterAnimation(selector?: string, options?: {
|
|
133
201
|
timeoutMs?: number;
|
|
@@ -138,6 +206,142 @@ interface WoodBrowserExpect {
|
|
|
138
206
|
mask?: string[];
|
|
139
207
|
threshold?: number;
|
|
140
208
|
}): Promise<void>;
|
|
209
|
+
/** Batch `getBoundingClientRect` reader — one snapshot per selector, in order. */
|
|
210
|
+
rects(selectors: string[]): Promise<WoodRectSnapshot[]>;
|
|
211
|
+
/**
|
|
212
|
+
* Hit-test at a point (default the target's center) and describe the top-most
|
|
213
|
+
* painted element and how it relates to the target.
|
|
214
|
+
*/
|
|
215
|
+
hitTest(selector: string, point?: {
|
|
216
|
+
x: number;
|
|
217
|
+
y: number;
|
|
218
|
+
} | 'center'): Promise<WoodHitTestResult>;
|
|
219
|
+
/** Assert two elements share the given edge coordinate within `tolerance` px. */
|
|
220
|
+
sharedEdge(a: string, b: string, edge: 'left' | 'right' | 'top' | 'bottom', options?: {
|
|
221
|
+
tolerance?: number;
|
|
222
|
+
}): Promise<void>;
|
|
223
|
+
/** Assert two elements share a center axis (centerX/centerY) within `tolerance` px. */
|
|
224
|
+
sharedAxis(a: string, b: string, axis: 'centerX' | 'centerY', options?: {
|
|
225
|
+
tolerance?: number;
|
|
226
|
+
}): Promise<void>;
|
|
227
|
+
/**
|
|
228
|
+
* Point-specific "does a click land here" check. Asserts the target receives
|
|
229
|
+
* the hit test at `point` (default center): the hit-test element is the target
|
|
230
|
+
* or a descendant of it. Ancestors are accepted only when the target is
|
|
231
|
+
* empty/zero-content at that point and the ancestor is what paints there — but a
|
|
232
|
+
* foreign overlay (not in the target's ancestry) fails. Honours
|
|
233
|
+
* `pointer-events: none`: an overlay so styled does not occlude, because it does
|
|
234
|
+
* not intercept the click.
|
|
235
|
+
*
|
|
236
|
+
* This is NOT the general visibility check — a `pointer-events: none` overlay
|
|
237
|
+
* that visually hides the element still passes here. For "is any foreign layer
|
|
238
|
+
* painted on top of the element", prefer `notCovered` (paint-order coverage).
|
|
239
|
+
*/
|
|
240
|
+
unoccluded(selector: string, options?: {
|
|
241
|
+
point?: {
|
|
242
|
+
x: number;
|
|
243
|
+
y: number;
|
|
244
|
+
} | 'center';
|
|
245
|
+
}): Promise<void>;
|
|
246
|
+
/**
|
|
247
|
+
* Honest front/behind primitive. DEFAULT (recommended): a whole-element
|
|
248
|
+
* paint-order comparison backed by Chromium's real paint tree (CDP
|
|
249
|
+
* `DOMSnapshot.captureSnapshot` with paint order). Passes when `topSelector`
|
|
250
|
+
* has a strictly greater global paint-order index than `lowerSelector` — i.e.
|
|
251
|
+
* it is painted later, so it is on top. This answers "which layer paints on
|
|
252
|
+
* top" for the whole element, independent of overlap or `pointer-events`, and
|
|
253
|
+
* is Chromium-only.
|
|
254
|
+
*
|
|
255
|
+
* Opt-in point form `inFrontOf(top, lower, { at })`: hit-tests a single painted
|
|
256
|
+
* pixel (`at` defaults to the center of the two rects' intersection) and passes
|
|
257
|
+
* when the painted element there is the top element (or its descendant) and is
|
|
258
|
+
* NOT the lower element. Use this only for the point-specific question ("is the
|
|
259
|
+
* top element the one painted AT THIS SPOT"); it honours `pointer-events` and
|
|
260
|
+
* requires the rects to intersect when no explicit `at` is given.
|
|
261
|
+
*
|
|
262
|
+
* If an element has multiple paint fragments, its maximum paint-order index is
|
|
263
|
+
* used. When the rects do not overlap the paint-order verdict is still valid
|
|
264
|
+
* (paint order is global), but the failure message notes there is no shared
|
|
265
|
+
* pixel where front/behind is visually observable.
|
|
266
|
+
*/
|
|
267
|
+
inFrontOf(topSelector: string, lowerSelector: string, options?: {
|
|
268
|
+
at?: {
|
|
269
|
+
x: number;
|
|
270
|
+
y: number;
|
|
271
|
+
};
|
|
272
|
+
}): Promise<void>;
|
|
273
|
+
/**
|
|
274
|
+
* Whole-element painted-coverage check: assert that NO foreign element paints
|
|
275
|
+
* on top of the target anywhere its rect overlaps. Backed by Chromium's real
|
|
276
|
+
* paint tree (CDP `DOMSnapshot.captureSnapshot` with paint order + computed
|
|
277
|
+
* styles + DOM rects), it is the honest, INSPECTABLE replacement for the old
|
|
278
|
+
* IntersectionObserver-v2 `fullyVisible` matcher, whose `isVisible` field is a
|
|
279
|
+
* black box that silently reports not-visible for any element painted on top —
|
|
280
|
+
* even a fully transparent one (see "why not IntersectionObserver v2" in the
|
|
281
|
+
* geometry docs).
|
|
282
|
+
*
|
|
283
|
+
* Algorithm (Chromium-only):
|
|
284
|
+
* 1. Find every laid-out element whose layout rect intersects the target's rect.
|
|
285
|
+
* 2. Exclude the target itself and its ancestors/descendants (they are not
|
|
286
|
+
* foreign coverage — the target paints through its own subtree).
|
|
287
|
+
* 3. Exclude candidates that paint nothing visible in the overlap, per an
|
|
288
|
+
* explicit transparent-wrapper heuristic: computed `opacity: 0` OR
|
|
289
|
+
* `visibility: hidden`, OR (no background-color alpha AND
|
|
290
|
+
* `background-image: none` AND all four border widths `0px` AND no own text
|
|
291
|
+
* or replaced/image content). This is the ONE rule that lets a transparent
|
|
292
|
+
* positioning wrapper spanning the target pass; it is intentionally
|
|
293
|
+
* documented and testable, unlike IOv2's opaque verdict. (`box-shadow`,
|
|
294
|
+
* `outline` and other purely decorative paints are NOT counted as coverage.)
|
|
295
|
+
* 4. Fail if any remaining foreign candidate has a strictly HIGHER max paint
|
|
296
|
+
* order than the target (painted later == on top). The failure names the
|
|
297
|
+
* covering element (tag/id/classes), its rect, and both paint indices.
|
|
298
|
+
*
|
|
299
|
+
* Note this tracks PAINTED coverage, so an opaque `pointer-events: none` overlay
|
|
300
|
+
* DOES fail `notCovered` (it paints pixels on top) while `unoccluded` still
|
|
301
|
+
* passes (it is transparent to hit testing) — the complementary pair of
|
|
302
|
+
* "painted coverage" vs "click reachability".
|
|
303
|
+
*/
|
|
304
|
+
notCovered(selector: string): Promise<void>;
|
|
305
|
+
/**
|
|
306
|
+
* Assert the edge-to-edge gap between two elements along `axis` satisfies a
|
|
307
|
+
* numeric constraint. The order is derived from the rects, not the argument
|
|
308
|
+
* order: the box with the smaller leading edge (left for `'horizontal'`, top
|
|
309
|
+
* for `'vertical'`) is treated as the earlier box and the gap is
|
|
310
|
+
* `later.leading - earlier.trailing` (horizontal: `later.left - earlier.right`;
|
|
311
|
+
* vertical: `later.top - earlier.bottom`).
|
|
312
|
+
*
|
|
313
|
+
* At least one of `equals` / `min` / `max` is required. `equals` passes when
|
|
314
|
+
* `|gap - equals| <= tolerance`; `min`/`max` are inclusive within `tolerance`.
|
|
315
|
+
* A negative gap means the border boxes OVERLAP along the axis; that fails
|
|
316
|
+
* clearly UNLESS the constraint explicitly allows negatives (a negative
|
|
317
|
+
* `equals` or `min`). The failure message states both rects, the computed gap,
|
|
318
|
+
* and the expected constraint.
|
|
319
|
+
*
|
|
320
|
+
* BORDER-BOX CAVEAT: rects are border boxes (`getBoundingClientRect`), so the
|
|
321
|
+
* gap is the distance between the elements' outer borders and EXCLUDES any
|
|
322
|
+
* padding inside either element. To assert visual whitespace between inner
|
|
323
|
+
* content, target the inner content elements instead of their padded wrappers.
|
|
324
|
+
*/
|
|
325
|
+
gapBetween(a: string, b: string, axis: WoodSpacingAxis, options: {
|
|
326
|
+
equals?: number;
|
|
327
|
+
min?: number;
|
|
328
|
+
max?: number;
|
|
329
|
+
tolerance?: number;
|
|
330
|
+
}): Promise<void>;
|
|
331
|
+
/**
|
|
332
|
+
* Assert three or more elements are evenly spaced along `axis`. Requires at
|
|
333
|
+
* least 3 selectors; the elements are sorted by their leading edge along the
|
|
334
|
+
* axis, adjacent edge-to-edge gaps are computed, and the assertion passes when
|
|
335
|
+
* `max gap - min gap <= tolerance`. The failure message lists every adjacent
|
|
336
|
+
* gap in sorted order and names the widest and narrowest (offending) pairs.
|
|
337
|
+
*
|
|
338
|
+
* BORDER-BOX CAVEAT: gaps are measured between border boxes
|
|
339
|
+
* (`getBoundingClientRect`), so they exclude padding inside the elements. Tests
|
|
340
|
+
* that care about visual whitespace should target inner content elements.
|
|
341
|
+
*/
|
|
342
|
+
evenlySpaced(selectors: string[], axis: WoodSpacingAxis, options?: {
|
|
343
|
+
tolerance?: number;
|
|
344
|
+
}): Promise<void>;
|
|
141
345
|
}
|
|
142
346
|
interface MountedWoodSurface {
|
|
143
347
|
page: any;
|
|
@@ -161,6 +365,12 @@ interface WoodBrowserHarness {
|
|
|
161
365
|
mountRoute(routeKey: string, options?: MountRouteOptions): Promise<MountedWoodRoute>;
|
|
162
366
|
mountComponent(component: string, options?: MountComponentOptions): Promise<MountedWoodComponent>;
|
|
163
367
|
mountTree(tree: MountTreeOptions): Promise<MountedWoodTree>;
|
|
368
|
+
/**
|
|
369
|
+
* Drain in-flight renderer `__trace` exposeBinding round-trips so the caller's
|
|
370
|
+
* trace-flush barrier (e.g. `TraceCommitWriter.requestRendererFlush`) has a
|
|
371
|
+
* definite quiescent point. Resolves immediately when no page is mounted.
|
|
372
|
+
*/
|
|
373
|
+
flushRendererTraces(): Promise<void>;
|
|
164
374
|
destroy(): Promise<void>;
|
|
165
375
|
}
|
|
166
376
|
type BridgeState = {
|
|
@@ -169,6 +379,8 @@ type BridgeState = {
|
|
|
169
379
|
calls: WoodBridgeRecordedCall[];
|
|
170
380
|
emittedEvents: WoodBridgeRecordedEvent[];
|
|
171
381
|
record: boolean;
|
|
382
|
+
transport?: WoodRpcTransport;
|
|
383
|
+
rpcManifest?: WoodRpcManifestEntryInput[];
|
|
172
384
|
};
|
|
173
385
|
type RuntimeBridgeManifestEntry = {
|
|
174
386
|
channel: string;
|
|
@@ -190,11 +402,15 @@ declare global {
|
|
|
190
402
|
interface Window {
|
|
191
403
|
__WOOD_BROWSER_APP__?: unknown;
|
|
192
404
|
__WOOD_BROWSER_DEFAULT_ROUTE__?: string;
|
|
405
|
+
__WOOD_BROWSER_NAV__?: unknown;
|
|
193
406
|
__WOOD_BROWSER_BRIDGE_MANIFEST__?: RuntimeBridgeManifestEntry[];
|
|
194
407
|
__woodBrowserInvoke?: (channel: string, input: unknown) => Promise<unknown>;
|
|
408
|
+
__woodBrowserSubscribe?: (channel: string) => void;
|
|
195
409
|
__woodBrowserEmit?: (channel: string, payload: unknown) => void;
|
|
196
|
-
__woodBrowserTrace?: (payload: unknown) => void;
|
|
410
|
+
__woodBrowserTrace?: (payload: unknown) => Promise<unknown> | void;
|
|
411
|
+
__woodBrowserTracePending?: Set<Promise<unknown>>;
|
|
412
|
+
__woodBrowserTraceFlush?: () => Promise<void>;
|
|
197
413
|
}
|
|
198
414
|
}
|
|
199
415
|
|
|
200
|
-
export { type MountComponentOptions, type MountRouteOptions, type MountTreeOptions, type MountedWoodBridge, type MountedWoodComponent, type MountedWoodNavigation, type MountedWoodRoute, type MountedWoodSurface, type MountedWoodTree, type WoodBridgeFixtureContext, type WoodBridgeFixtureInput, type WoodBridgeRecordedCall, type WoodBridgeRecordedEvent, type WoodBrowserExpect, type WoodBrowserHarness, type WoodBrowserHarnessConfig, type WoodBrowserPageContext, type WoodBrowserTraceConfig, type WoodViewport, browser, createBrowserBridgeFixture };
|
|
416
|
+
export { type MountComponentOptions, type MountRouteOptions, type MountTreeOptions, type MountedWoodBridge, type MountedWoodComponent, type MountedWoodNavigation, type MountedWoodRoute, type MountedWoodSurface, type MountedWoodTree, type WoodBridgeFixtureContext, type WoodBridgeFixtureInput, type WoodBridgeRecordedCall, type WoodBridgeRecordedEvent, type WoodBrowserExpect, type WoodBrowserHarness, type WoodBrowserHarnessConfig, type WoodBrowserPageContext, type WoodBrowserTraceConfig, type WoodHitTestResult, type WoodRectSnapshot, type WoodRpcManifestEntryInput, type WoodSpacingAxis, type WoodViewport, browser, createBrowserBridgeFixture };
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { TraceLevel } from '../
|
|
1
|
+
import { c as TraceLevel } from '../trace_hub-Cob54qRx.js';
|
|
2
2
|
import { TraceRecorder } from '../trace-testing/trace_recorder.js';
|
|
3
|
+
import { WoodRpcTransport } from '../transport/wood_rpc_transport.js';
|
|
3
4
|
import 'rxjs';
|
|
4
5
|
import '@noego/trace/testing';
|
|
5
6
|
import '../tracing/trace_provider.js';
|
|
@@ -31,6 +32,30 @@ interface WoodBridgeFixtureInput {
|
|
|
31
32
|
operations?: Record<string, OperationHandler>;
|
|
32
33
|
events?: Record<string, unknown | unknown[]>;
|
|
33
34
|
record?: boolean;
|
|
35
|
+
/**
|
|
36
|
+
* Real-backend mode. When supplied, page `invoke` is routed through this
|
|
37
|
+
* `WoodRpcTransport` (dispatching through the REAL WoodRouter — full schema
|
|
38
|
+
* validation) instead of the fixture `operations` Map, and page `bridge.on(...)`
|
|
39
|
+
* subscriptions are relayed to `transport.subscribe(...)` so main-process push
|
|
40
|
+
* events reach page subscribers. Fixture `operations` still act as a fallback
|
|
41
|
+
* for any channel not registered on the transport, so hybrid fixtures work.
|
|
42
|
+
* Omit for the legacy fixture-only bridge (spec §4: labeled visual tests).
|
|
43
|
+
*/
|
|
44
|
+
transport?: WoodRpcTransport;
|
|
45
|
+
/**
|
|
46
|
+
* Full RPC manifest to build the page bridge tree from. Required in transport
|
|
47
|
+
* mode so every real channel is exposed on the bridge (in fixture mode the
|
|
48
|
+
* manifest is derived from `operations`). Supply the app's complete operations
|
|
49
|
+
* manifest (channel/controller/action/path/hasInput per operation).
|
|
50
|
+
*/
|
|
51
|
+
rpcManifest?: WoodRpcManifestEntryInput[];
|
|
52
|
+
}
|
|
53
|
+
interface WoodRpcManifestEntryInput {
|
|
54
|
+
channel: string;
|
|
55
|
+
controller: string;
|
|
56
|
+
action: string;
|
|
57
|
+
path: string[];
|
|
58
|
+
hasInput: boolean;
|
|
34
59
|
}
|
|
35
60
|
interface WoodBrowserPageContext {
|
|
36
61
|
page: any;
|
|
@@ -120,6 +145,43 @@ interface MountedWoodNavigation {
|
|
|
120
145
|
go(page: string, params?: Record<string, string>, query?: Record<string, string>): Promise<void>;
|
|
121
146
|
replace(page: string, params?: Record<string, string>, query?: Record<string, string>): Promise<void>;
|
|
122
147
|
}
|
|
148
|
+
/** Snapshot of one element's viewport-space box, tagged with its source selector. */
|
|
149
|
+
interface WoodRectSnapshot {
|
|
150
|
+
selector: string;
|
|
151
|
+
top: number;
|
|
152
|
+
left: number;
|
|
153
|
+
right: number;
|
|
154
|
+
bottom: number;
|
|
155
|
+
width: number;
|
|
156
|
+
height: number;
|
|
157
|
+
}
|
|
158
|
+
/** Axis along which edge-to-edge spacing is measured. */
|
|
159
|
+
type WoodSpacingAxis = 'horizontal' | 'vertical';
|
|
160
|
+
/**
|
|
161
|
+
* Description of the top-most element painted at a hit-test point, plus its
|
|
162
|
+
* relationship to the queried target. `document.elementFromPoint` honours
|
|
163
|
+
* `pointer-events`, so an element with `pointer-events: none` is transparent to
|
|
164
|
+
* the hit test even when it is painted on top (see `hitTest`/`unoccluded`).
|
|
165
|
+
*/
|
|
166
|
+
interface WoodHitTestResult {
|
|
167
|
+
/** False when no element is painted at the point (e.g. outside the document). */
|
|
168
|
+
found: boolean;
|
|
169
|
+
tag: string | null;
|
|
170
|
+
id: string | null;
|
|
171
|
+
classes: string[];
|
|
172
|
+
/** The hit element is exactly the target. */
|
|
173
|
+
isTarget: boolean;
|
|
174
|
+
/** The hit element is a descendant of the target (target paints through it). */
|
|
175
|
+
isDescendantOfTarget: boolean;
|
|
176
|
+
/** The hit element is an ancestor of the target. */
|
|
177
|
+
isAncestorOfTarget: boolean;
|
|
178
|
+
point: {
|
|
179
|
+
x: number;
|
|
180
|
+
y: number;
|
|
181
|
+
};
|
|
182
|
+
/** Human-readable one-line description of the hit element. */
|
|
183
|
+
description: string;
|
|
184
|
+
}
|
|
123
185
|
interface WoodBrowserExpect {
|
|
124
186
|
visible(selector: string): Promise<void>;
|
|
125
187
|
hidden(selector: string): Promise<void>;
|
|
@@ -128,6 +190,12 @@ interface WoodBrowserExpect {
|
|
|
128
190
|
}): Promise<void>;
|
|
129
191
|
notClipped(selector: string): Promise<void>;
|
|
130
192
|
notOverlapping(firstSelector: string, secondSelector: string): Promise<void>;
|
|
193
|
+
/**
|
|
194
|
+
* @deprecated Compares numeric computed `z-index` only, so it lies whenever
|
|
195
|
+
* stacking contexts, DOM paint order (auto/equal z-index), or
|
|
196
|
+
* transform/opacity contexts decide the real front-to-back order. Prefer
|
|
197
|
+
* `inFrontOf`, which hit-tests the actual painted pixel.
|
|
198
|
+
*/
|
|
131
199
|
zIndexAbove(topSelector: string, lowerSelector: string): Promise<void>;
|
|
132
200
|
stableAfterAnimation(selector?: string, options?: {
|
|
133
201
|
timeoutMs?: number;
|
|
@@ -138,6 +206,142 @@ interface WoodBrowserExpect {
|
|
|
138
206
|
mask?: string[];
|
|
139
207
|
threshold?: number;
|
|
140
208
|
}): Promise<void>;
|
|
209
|
+
/** Batch `getBoundingClientRect` reader — one snapshot per selector, in order. */
|
|
210
|
+
rects(selectors: string[]): Promise<WoodRectSnapshot[]>;
|
|
211
|
+
/**
|
|
212
|
+
* Hit-test at a point (default the target's center) and describe the top-most
|
|
213
|
+
* painted element and how it relates to the target.
|
|
214
|
+
*/
|
|
215
|
+
hitTest(selector: string, point?: {
|
|
216
|
+
x: number;
|
|
217
|
+
y: number;
|
|
218
|
+
} | 'center'): Promise<WoodHitTestResult>;
|
|
219
|
+
/** Assert two elements share the given edge coordinate within `tolerance` px. */
|
|
220
|
+
sharedEdge(a: string, b: string, edge: 'left' | 'right' | 'top' | 'bottom', options?: {
|
|
221
|
+
tolerance?: number;
|
|
222
|
+
}): Promise<void>;
|
|
223
|
+
/** Assert two elements share a center axis (centerX/centerY) within `tolerance` px. */
|
|
224
|
+
sharedAxis(a: string, b: string, axis: 'centerX' | 'centerY', options?: {
|
|
225
|
+
tolerance?: number;
|
|
226
|
+
}): Promise<void>;
|
|
227
|
+
/**
|
|
228
|
+
* Point-specific "does a click land here" check. Asserts the target receives
|
|
229
|
+
* the hit test at `point` (default center): the hit-test element is the target
|
|
230
|
+
* or a descendant of it. Ancestors are accepted only when the target is
|
|
231
|
+
* empty/zero-content at that point and the ancestor is what paints there — but a
|
|
232
|
+
* foreign overlay (not in the target's ancestry) fails. Honours
|
|
233
|
+
* `pointer-events: none`: an overlay so styled does not occlude, because it does
|
|
234
|
+
* not intercept the click.
|
|
235
|
+
*
|
|
236
|
+
* This is NOT the general visibility check — a `pointer-events: none` overlay
|
|
237
|
+
* that visually hides the element still passes here. For "is any foreign layer
|
|
238
|
+
* painted on top of the element", prefer `notCovered` (paint-order coverage).
|
|
239
|
+
*/
|
|
240
|
+
unoccluded(selector: string, options?: {
|
|
241
|
+
point?: {
|
|
242
|
+
x: number;
|
|
243
|
+
y: number;
|
|
244
|
+
} | 'center';
|
|
245
|
+
}): Promise<void>;
|
|
246
|
+
/**
|
|
247
|
+
* Honest front/behind primitive. DEFAULT (recommended): a whole-element
|
|
248
|
+
* paint-order comparison backed by Chromium's real paint tree (CDP
|
|
249
|
+
* `DOMSnapshot.captureSnapshot` with paint order). Passes when `topSelector`
|
|
250
|
+
* has a strictly greater global paint-order index than `lowerSelector` — i.e.
|
|
251
|
+
* it is painted later, so it is on top. This answers "which layer paints on
|
|
252
|
+
* top" for the whole element, independent of overlap or `pointer-events`, and
|
|
253
|
+
* is Chromium-only.
|
|
254
|
+
*
|
|
255
|
+
* Opt-in point form `inFrontOf(top, lower, { at })`: hit-tests a single painted
|
|
256
|
+
* pixel (`at` defaults to the center of the two rects' intersection) and passes
|
|
257
|
+
* when the painted element there is the top element (or its descendant) and is
|
|
258
|
+
* NOT the lower element. Use this only for the point-specific question ("is the
|
|
259
|
+
* top element the one painted AT THIS SPOT"); it honours `pointer-events` and
|
|
260
|
+
* requires the rects to intersect when no explicit `at` is given.
|
|
261
|
+
*
|
|
262
|
+
* If an element has multiple paint fragments, its maximum paint-order index is
|
|
263
|
+
* used. When the rects do not overlap the paint-order verdict is still valid
|
|
264
|
+
* (paint order is global), but the failure message notes there is no shared
|
|
265
|
+
* pixel where front/behind is visually observable.
|
|
266
|
+
*/
|
|
267
|
+
inFrontOf(topSelector: string, lowerSelector: string, options?: {
|
|
268
|
+
at?: {
|
|
269
|
+
x: number;
|
|
270
|
+
y: number;
|
|
271
|
+
};
|
|
272
|
+
}): Promise<void>;
|
|
273
|
+
/**
|
|
274
|
+
* Whole-element painted-coverage check: assert that NO foreign element paints
|
|
275
|
+
* on top of the target anywhere its rect overlaps. Backed by Chromium's real
|
|
276
|
+
* paint tree (CDP `DOMSnapshot.captureSnapshot` with paint order + computed
|
|
277
|
+
* styles + DOM rects), it is the honest, INSPECTABLE replacement for the old
|
|
278
|
+
* IntersectionObserver-v2 `fullyVisible` matcher, whose `isVisible` field is a
|
|
279
|
+
* black box that silently reports not-visible for any element painted on top —
|
|
280
|
+
* even a fully transparent one (see "why not IntersectionObserver v2" in the
|
|
281
|
+
* geometry docs).
|
|
282
|
+
*
|
|
283
|
+
* Algorithm (Chromium-only):
|
|
284
|
+
* 1. Find every laid-out element whose layout rect intersects the target's rect.
|
|
285
|
+
* 2. Exclude the target itself and its ancestors/descendants (they are not
|
|
286
|
+
* foreign coverage — the target paints through its own subtree).
|
|
287
|
+
* 3. Exclude candidates that paint nothing visible in the overlap, per an
|
|
288
|
+
* explicit transparent-wrapper heuristic: computed `opacity: 0` OR
|
|
289
|
+
* `visibility: hidden`, OR (no background-color alpha AND
|
|
290
|
+
* `background-image: none` AND all four border widths `0px` AND no own text
|
|
291
|
+
* or replaced/image content). This is the ONE rule that lets a transparent
|
|
292
|
+
* positioning wrapper spanning the target pass; it is intentionally
|
|
293
|
+
* documented and testable, unlike IOv2's opaque verdict. (`box-shadow`,
|
|
294
|
+
* `outline` and other purely decorative paints are NOT counted as coverage.)
|
|
295
|
+
* 4. Fail if any remaining foreign candidate has a strictly HIGHER max paint
|
|
296
|
+
* order than the target (painted later == on top). The failure names the
|
|
297
|
+
* covering element (tag/id/classes), its rect, and both paint indices.
|
|
298
|
+
*
|
|
299
|
+
* Note this tracks PAINTED coverage, so an opaque `pointer-events: none` overlay
|
|
300
|
+
* DOES fail `notCovered` (it paints pixels on top) while `unoccluded` still
|
|
301
|
+
* passes (it is transparent to hit testing) — the complementary pair of
|
|
302
|
+
* "painted coverage" vs "click reachability".
|
|
303
|
+
*/
|
|
304
|
+
notCovered(selector: string): Promise<void>;
|
|
305
|
+
/**
|
|
306
|
+
* Assert the edge-to-edge gap between two elements along `axis` satisfies a
|
|
307
|
+
* numeric constraint. The order is derived from the rects, not the argument
|
|
308
|
+
* order: the box with the smaller leading edge (left for `'horizontal'`, top
|
|
309
|
+
* for `'vertical'`) is treated as the earlier box and the gap is
|
|
310
|
+
* `later.leading - earlier.trailing` (horizontal: `later.left - earlier.right`;
|
|
311
|
+
* vertical: `later.top - earlier.bottom`).
|
|
312
|
+
*
|
|
313
|
+
* At least one of `equals` / `min` / `max` is required. `equals` passes when
|
|
314
|
+
* `|gap - equals| <= tolerance`; `min`/`max` are inclusive within `tolerance`.
|
|
315
|
+
* A negative gap means the border boxes OVERLAP along the axis; that fails
|
|
316
|
+
* clearly UNLESS the constraint explicitly allows negatives (a negative
|
|
317
|
+
* `equals` or `min`). The failure message states both rects, the computed gap,
|
|
318
|
+
* and the expected constraint.
|
|
319
|
+
*
|
|
320
|
+
* BORDER-BOX CAVEAT: rects are border boxes (`getBoundingClientRect`), so the
|
|
321
|
+
* gap is the distance between the elements' outer borders and EXCLUDES any
|
|
322
|
+
* padding inside either element. To assert visual whitespace between inner
|
|
323
|
+
* content, target the inner content elements instead of their padded wrappers.
|
|
324
|
+
*/
|
|
325
|
+
gapBetween(a: string, b: string, axis: WoodSpacingAxis, options: {
|
|
326
|
+
equals?: number;
|
|
327
|
+
min?: number;
|
|
328
|
+
max?: number;
|
|
329
|
+
tolerance?: number;
|
|
330
|
+
}): Promise<void>;
|
|
331
|
+
/**
|
|
332
|
+
* Assert three or more elements are evenly spaced along `axis`. Requires at
|
|
333
|
+
* least 3 selectors; the elements are sorted by their leading edge along the
|
|
334
|
+
* axis, adjacent edge-to-edge gaps are computed, and the assertion passes when
|
|
335
|
+
* `max gap - min gap <= tolerance`. The failure message lists every adjacent
|
|
336
|
+
* gap in sorted order and names the widest and narrowest (offending) pairs.
|
|
337
|
+
*
|
|
338
|
+
* BORDER-BOX CAVEAT: gaps are measured between border boxes
|
|
339
|
+
* (`getBoundingClientRect`), so they exclude padding inside the elements. Tests
|
|
340
|
+
* that care about visual whitespace should target inner content elements.
|
|
341
|
+
*/
|
|
342
|
+
evenlySpaced(selectors: string[], axis: WoodSpacingAxis, options?: {
|
|
343
|
+
tolerance?: number;
|
|
344
|
+
}): Promise<void>;
|
|
141
345
|
}
|
|
142
346
|
interface MountedWoodSurface {
|
|
143
347
|
page: any;
|
|
@@ -161,6 +365,12 @@ interface WoodBrowserHarness {
|
|
|
161
365
|
mountRoute(routeKey: string, options?: MountRouteOptions): Promise<MountedWoodRoute>;
|
|
162
366
|
mountComponent(component: string, options?: MountComponentOptions): Promise<MountedWoodComponent>;
|
|
163
367
|
mountTree(tree: MountTreeOptions): Promise<MountedWoodTree>;
|
|
368
|
+
/**
|
|
369
|
+
* Drain in-flight renderer `__trace` exposeBinding round-trips so the caller's
|
|
370
|
+
* trace-flush barrier (e.g. `TraceCommitWriter.requestRendererFlush`) has a
|
|
371
|
+
* definite quiescent point. Resolves immediately when no page is mounted.
|
|
372
|
+
*/
|
|
373
|
+
flushRendererTraces(): Promise<void>;
|
|
164
374
|
destroy(): Promise<void>;
|
|
165
375
|
}
|
|
166
376
|
type BridgeState = {
|
|
@@ -169,6 +379,8 @@ type BridgeState = {
|
|
|
169
379
|
calls: WoodBridgeRecordedCall[];
|
|
170
380
|
emittedEvents: WoodBridgeRecordedEvent[];
|
|
171
381
|
record: boolean;
|
|
382
|
+
transport?: WoodRpcTransport;
|
|
383
|
+
rpcManifest?: WoodRpcManifestEntryInput[];
|
|
172
384
|
};
|
|
173
385
|
type RuntimeBridgeManifestEntry = {
|
|
174
386
|
channel: string;
|
|
@@ -190,11 +402,15 @@ declare global {
|
|
|
190
402
|
interface Window {
|
|
191
403
|
__WOOD_BROWSER_APP__?: unknown;
|
|
192
404
|
__WOOD_BROWSER_DEFAULT_ROUTE__?: string;
|
|
405
|
+
__WOOD_BROWSER_NAV__?: unknown;
|
|
193
406
|
__WOOD_BROWSER_BRIDGE_MANIFEST__?: RuntimeBridgeManifestEntry[];
|
|
194
407
|
__woodBrowserInvoke?: (channel: string, input: unknown) => Promise<unknown>;
|
|
408
|
+
__woodBrowserSubscribe?: (channel: string) => void;
|
|
195
409
|
__woodBrowserEmit?: (channel: string, payload: unknown) => void;
|
|
196
|
-
__woodBrowserTrace?: (payload: unknown) => void;
|
|
410
|
+
__woodBrowserTrace?: (payload: unknown) => Promise<unknown> | void;
|
|
411
|
+
__woodBrowserTracePending?: Set<Promise<unknown>>;
|
|
412
|
+
__woodBrowserTraceFlush?: () => Promise<void>;
|
|
197
413
|
}
|
|
198
414
|
}
|
|
199
415
|
|
|
200
|
-
export { type MountComponentOptions, type MountRouteOptions, type MountTreeOptions, type MountedWoodBridge, type MountedWoodComponent, type MountedWoodNavigation, type MountedWoodRoute, type MountedWoodSurface, type MountedWoodTree, type WoodBridgeFixtureContext, type WoodBridgeFixtureInput, type WoodBridgeRecordedCall, type WoodBridgeRecordedEvent, type WoodBrowserExpect, type WoodBrowserHarness, type WoodBrowserHarnessConfig, type WoodBrowserPageContext, type WoodBrowserTraceConfig, type WoodViewport, browser, createBrowserBridgeFixture };
|
|
416
|
+
export { type MountComponentOptions, type MountRouteOptions, type MountTreeOptions, type MountedWoodBridge, type MountedWoodComponent, type MountedWoodNavigation, type MountedWoodRoute, type MountedWoodSurface, type MountedWoodTree, type WoodBridgeFixtureContext, type WoodBridgeFixtureInput, type WoodBridgeRecordedCall, type WoodBridgeRecordedEvent, type WoodBrowserExpect, type WoodBrowserHarness, type WoodBrowserHarnessConfig, type WoodBrowserPageContext, type WoodBrowserTraceConfig, type WoodHitTestResult, type WoodRectSnapshot, type WoodRpcManifestEntryInput, type WoodSpacingAxis, type WoodViewport, browser, createBrowserBridgeFixture };
|