@noego/wood 0.4.6 → 0.4.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (243) hide show
  1. package/bin/wood.js +6 -1
  2. package/dist/client/app_env.cjs +39 -0
  3. package/dist/client/app_env.cjs.map +1 -0
  4. package/dist/client/app_env.d.cts +7 -0
  5. package/dist/client/app_env.d.ts +7 -0
  6. package/dist/client/app_env.js +14 -0
  7. package/dist/client/app_env.js.map +1 -0
  8. package/dist/client/index.cjs +33 -9
  9. package/dist/client/index.cjs.map +1 -1
  10. package/dist/client/index.d.cts +5 -1
  11. package/dist/client/index.d.ts +5 -1
  12. package/dist/client/index.js +32 -9
  13. package/dist/client/index.js.map +1 -1
  14. package/dist/codegen/channel_map_generator.cjs +102 -0
  15. package/dist/codegen/channel_map_generator.cjs.map +1 -0
  16. package/dist/codegen/channel_map_generator.d.cts +6 -0
  17. package/dist/codegen/channel_map_generator.d.ts +6 -0
  18. package/dist/codegen/channel_map_generator.js +78 -0
  19. package/dist/codegen/channel_map_generator.js.map +1 -0
  20. package/dist/codegen/controller_registration_generator.cjs +6 -1
  21. package/dist/codegen/controller_registration_generator.cjs.map +1 -1
  22. package/dist/codegen/controller_registration_generator.js +6 -1
  23. package/dist/codegen/controller_registration_generator.js.map +1 -1
  24. package/dist/codegen/generated_file_notice.cjs +40 -0
  25. package/dist/codegen/generated_file_notice.cjs.map +1 -0
  26. package/dist/codegen/generated_file_notice.d.cts +3 -0
  27. package/dist/codegen/generated_file_notice.d.ts +3 -0
  28. package/dist/codegen/generated_file_notice.js +16 -0
  29. package/dist/codegen/generated_file_notice.js.map +1 -0
  30. package/dist/codegen/index.cjs +3 -0
  31. package/dist/codegen/index.cjs.map +1 -1
  32. package/dist/codegen/index.d.cts +1 -0
  33. package/dist/codegen/index.d.ts +1 -0
  34. package/dist/codegen/index.js +2 -0
  35. package/dist/codegen/index.js.map +1 -1
  36. package/dist/codegen/preload_generator.cjs +97 -1
  37. package/dist/codegen/preload_generator.cjs.map +1 -1
  38. package/dist/codegen/preload_generator.js +97 -1
  39. package/dist/codegen/preload_generator.js.map +1 -1
  40. package/dist/codegen/renderer_app_generator.cjs +6 -1
  41. package/dist/codegen/renderer_app_generator.cjs.map +1 -1
  42. package/dist/codegen/renderer_app_generator.js +6 -1
  43. package/dist/codegen/renderer_app_generator.js.map +1 -1
  44. package/dist/codegen/renderer_controller_registration_generator.cjs +6 -1
  45. package/dist/codegen/renderer_controller_registration_generator.cjs.map +1 -1
  46. package/dist/codegen/renderer_controller_registration_generator.js +6 -1
  47. package/dist/codegen/renderer_controller_registration_generator.js.map +1 -1
  48. package/dist/codegen/renderer_view_manifest_generator.cjs +6 -1
  49. package/dist/codegen/renderer_view_manifest_generator.cjs.map +1 -1
  50. package/dist/codegen/renderer_view_manifest_generator.js +6 -1
  51. package/dist/codegen/renderer_view_manifest_generator.js.map +1 -1
  52. package/dist/codegen/runtime_generator.cjs +6 -1
  53. package/dist/codegen/runtime_generator.cjs.map +1 -1
  54. package/dist/codegen/runtime_generator.js +6 -1
  55. package/dist/codegen/runtime_generator.js.map +1 -1
  56. package/dist/codegen/test_mock_generator.cjs +5 -1
  57. package/dist/codegen/test_mock_generator.cjs.map +1 -1
  58. package/dist/codegen/test_mock_generator.js +5 -1
  59. package/dist/codegen/test_mock_generator.js.map +1 -1
  60. package/dist/codegen/type_generator.cjs +6 -1
  61. package/dist/codegen/type_generator.cjs.map +1 -1
  62. package/dist/codegen/type_generator.js +6 -1
  63. package/dist/codegen/type_generator.js.map +1 -1
  64. package/dist/index.cjs +19 -6
  65. package/dist/index.cjs.map +1 -1
  66. package/dist/index.d.cts +7 -1
  67. package/dist/index.d.ts +7 -1
  68. package/dist/index.js +13 -1
  69. package/dist/index.js.map +1 -1
  70. package/dist/main/index.cjs +133 -55
  71. package/dist/main/index.cjs.map +1 -1
  72. package/dist/main/index.d.cts +30 -2
  73. package/dist/main/index.d.ts +30 -2
  74. package/dist/main/index.js +134 -55
  75. package/dist/main/index.js.map +1 -1
  76. package/dist/main/renderer_trace_drain_coordinator.cjs +127 -0
  77. package/dist/main/renderer_trace_drain_coordinator.cjs.map +1 -0
  78. package/dist/main/renderer_trace_drain_coordinator.d.cts +46 -0
  79. package/dist/main/renderer_trace_drain_coordinator.d.ts +46 -0
  80. package/dist/main/renderer_trace_drain_coordinator.js +101 -0
  81. package/dist/main/renderer_trace_drain_coordinator.js.map +1 -0
  82. package/dist/router/wood_router.cjs +9 -1
  83. package/dist/router/wood_router.cjs.map +1 -1
  84. package/dist/router/wood_router.d.cts +1 -1
  85. package/dist/router/wood_router.d.ts +1 -1
  86. package/dist/router/wood_router.js +9 -1
  87. package/dist/router/wood_router.js.map +1 -1
  88. package/dist/runtime/app_env.cjs +52 -0
  89. package/dist/runtime/app_env.cjs.map +1 -0
  90. package/dist/runtime/app_env.d.cts +10 -0
  91. package/dist/runtime/app_env.d.ts +10 -0
  92. package/dist/runtime/app_env.js +18 -0
  93. package/dist/runtime/app_env.js.map +1 -0
  94. package/dist/runtime/index.cjs +9 -2
  95. package/dist/runtime/index.cjs.map +1 -1
  96. package/dist/runtime/index.d.cts +5 -1
  97. package/dist/runtime/index.d.ts +5 -1
  98. package/dist/runtime/index.js +9 -1
  99. package/dist/runtime/index.js.map +1 -1
  100. package/dist/runtime/renderer_log_dispatcher.cjs.map +1 -1
  101. package/dist/runtime/renderer_log_dispatcher.d.cts +1 -1
  102. package/dist/runtime/renderer_log_dispatcher.d.ts +1 -1
  103. package/dist/runtime/renderer_log_dispatcher.js.map +1 -1
  104. package/dist/runtime/renderer_trace_batch_receiver_registry.cjs +50 -0
  105. package/dist/runtime/renderer_trace_batch_receiver_registry.cjs.map +1 -0
  106. package/dist/runtime/renderer_trace_batch_receiver_registry.d.cts +10 -0
  107. package/dist/runtime/renderer_trace_batch_receiver_registry.d.ts +10 -0
  108. package/dist/runtime/renderer_trace_batch_receiver_registry.js +24 -0
  109. package/dist/runtime/renderer_trace_batch_receiver_registry.js.map +1 -0
  110. package/dist/runtime/runtime.cjs +75 -57
  111. package/dist/runtime/runtime.cjs.map +1 -1
  112. package/dist/runtime/runtime.d.cts +8 -1
  113. package/dist/runtime/runtime.d.ts +8 -1
  114. package/dist/runtime/runtime.js +80 -58
  115. package/dist/runtime/runtime.js.map +1 -1
  116. package/dist/testing/browser.cjs +540 -11
  117. package/dist/testing/browser.cjs.map +1 -1
  118. package/dist/testing/browser.d.cts +219 -3
  119. package/dist/testing/browser.d.ts +219 -3
  120. package/dist/testing/browser.js +540 -11
  121. package/dist/testing/browser.js.map +1 -1
  122. package/dist/testing/create_controller_harness.d.cts +1 -1
  123. package/dist/testing/create_controller_harness.d.ts +1 -1
  124. package/dist/testing/index.cjs +13 -0
  125. package/dist/testing/index.cjs.map +1 -1
  126. package/dist/testing/index.d.cts +7 -2
  127. package/dist/testing/index.d.ts +7 -2
  128. package/dist/testing/index.js +14 -0
  129. package/dist/testing/index.js.map +1 -1
  130. package/dist/trace-testing/index.d.cts +1 -1
  131. package/dist/trace-testing/index.d.ts +1 -1
  132. package/dist/trace-testing/trace_recorder.d.cts +1 -1
  133. package/dist/trace-testing/trace_recorder.d.ts +1 -1
  134. package/dist/trace-transport/index.cjs +32 -0
  135. package/dist/trace-transport/index.cjs.map +1 -0
  136. package/dist/trace-transport/index.d.cts +6 -0
  137. package/dist/trace-transport/index.d.ts +6 -0
  138. package/dist/trace-transport/index.js +7 -0
  139. package/dist/trace-transport/index.js.map +1 -0
  140. package/dist/trace_hub-Cob54qRx.d.cts +56 -0
  141. package/dist/trace_hub-Cob54qRx.d.ts +56 -0
  142. package/dist/tracing/index.cjs +14 -0
  143. package/dist/tracing/index.cjs.map +1 -1
  144. package/dist/tracing/index.d.cts +7 -1
  145. package/dist/tracing/index.d.ts +7 -1
  146. package/dist/tracing/index.js +12 -0
  147. package/dist/tracing/index.js.map +1 -1
  148. package/dist/tracing/renderer_trace_batch_host.cjs +80 -0
  149. package/dist/tracing/renderer_trace_batch_host.cjs.map +1 -0
  150. package/dist/tracing/renderer_trace_batch_host.d.cts +16 -0
  151. package/dist/tracing/renderer_trace_batch_host.d.ts +16 -0
  152. package/dist/tracing/renderer_trace_batch_host.js +56 -0
  153. package/dist/tracing/renderer_trace_batch_host.js.map +1 -0
  154. package/dist/tracing/renderer_trace_batch_transport.cjs +313 -0
  155. package/dist/tracing/renderer_trace_batch_transport.cjs.map +1 -0
  156. package/dist/tracing/renderer_trace_batch_transport.d.cts +53 -0
  157. package/dist/tracing/renderer_trace_batch_transport.d.ts +53 -0
  158. package/dist/tracing/renderer_trace_batch_transport.js +292 -0
  159. package/dist/tracing/renderer_trace_batch_transport.js.map +1 -0
  160. package/dist/tracing/trace_commit_writer.cjs +159 -0
  161. package/dist/tracing/trace_commit_writer.cjs.map +1 -0
  162. package/dist/tracing/trace_commit_writer.d.cts +97 -0
  163. package/dist/tracing/trace_commit_writer.d.ts +97 -0
  164. package/dist/tracing/trace_commit_writer.js +135 -0
  165. package/dist/tracing/trace_commit_writer.js.map +1 -0
  166. package/dist/tracing/trace_hub.cjs +58 -3
  167. package/dist/tracing/trace_hub.cjs.map +1 -1
  168. package/dist/tracing/trace_hub.d.cts +2 -46
  169. package/dist/tracing/trace_hub.d.ts +2 -46
  170. package/dist/tracing/trace_hub.js +56 -3
  171. package/dist/tracing/trace_hub.js.map +1 -1
  172. package/dist/tracing/trace_provider.cjs +42 -12
  173. package/dist/tracing/trace_provider.cjs.map +1 -1
  174. package/dist/tracing/trace_provider.d.cts +15 -1
  175. package/dist/tracing/trace_provider.d.ts +15 -1
  176. package/dist/tracing/trace_provider.js +43 -12
  177. package/dist/tracing/trace_provider.js.map +1 -1
  178. package/dist/tracing/types/wood_trace_batch.types.cjs +17 -0
  179. package/dist/tracing/types/wood_trace_batch.types.cjs.map +1 -0
  180. package/dist/tracing/types/wood_trace_batch.types.d.cts +124 -0
  181. package/dist/tracing/types/wood_trace_batch.types.d.ts +124 -0
  182. package/dist/tracing/types/wood_trace_batch.types.js +1 -0
  183. package/dist/tracing/types/wood_trace_batch.types.js.map +1 -0
  184. package/dist/tracing/types/wood_trace_sink.types.cjs +17 -0
  185. package/dist/tracing/types/wood_trace_sink.types.cjs.map +1 -0
  186. package/dist/tracing/types/wood_trace_sink.types.d.cts +2 -0
  187. package/dist/tracing/types/wood_trace_sink.types.d.ts +2 -0
  188. package/dist/tracing/types/wood_trace_sink.types.js +1 -0
  189. package/dist/tracing/types/wood_trace_sink.types.js.map +1 -0
  190. package/dist/tracing/wood_trace_batch_contract.cjs +229 -0
  191. package/dist/tracing/wood_trace_batch_contract.cjs.map +1 -0
  192. package/dist/tracing/wood_trace_batch_contract.d.cts +23 -0
  193. package/dist/tracing/wood_trace_batch_contract.d.ts +23 -0
  194. package/dist/tracing/wood_trace_batch_contract.js +205 -0
  195. package/dist/tracing/wood_trace_batch_contract.js.map +1 -0
  196. package/dist/transport/build_transport_bridge.cjs +62 -0
  197. package/dist/transport/build_transport_bridge.cjs.map +1 -0
  198. package/dist/transport/build_transport_bridge.d.cts +29 -0
  199. package/dist/transport/build_transport_bridge.d.ts +29 -0
  200. package/dist/transport/build_transport_bridge.js +38 -0
  201. package/dist/transport/build_transport_bridge.js.map +1 -0
  202. package/dist/transport/in_process_router_transport.cjs +41 -0
  203. package/dist/transport/in_process_router_transport.cjs.map +1 -0
  204. package/dist/transport/in_process_router_transport.d.cts +31 -0
  205. package/dist/transport/in_process_router_transport.d.ts +31 -0
  206. package/dist/transport/in_process_router_transport.js +17 -0
  207. package/dist/transport/in_process_router_transport.js.map +1 -0
  208. package/dist/transport/index.cjs +42 -0
  209. package/dist/transport/index.cjs.map +1 -0
  210. package/dist/transport/index.d.cts +8 -0
  211. package/dist/transport/index.d.ts +8 -0
  212. package/dist/transport/index.js +19 -0
  213. package/dist/transport/index.js.map +1 -0
  214. package/dist/transport/loopback_remote_transport.cjs +270 -0
  215. package/dist/transport/loopback_remote_transport.cjs.map +1 -0
  216. package/dist/transport/loopback_remote_transport.d.cts +49 -0
  217. package/dist/transport/loopback_remote_transport.d.ts +49 -0
  218. package/dist/transport/loopback_remote_transport.js +237 -0
  219. package/dist/transport/loopback_remote_transport.js.map +1 -0
  220. package/dist/transport/loopback_serialization.cjs +116 -0
  221. package/dist/transport/loopback_serialization.cjs.map +1 -0
  222. package/dist/transport/loopback_serialization.d.cts +28 -0
  223. package/dist/transport/loopback_serialization.d.ts +28 -0
  224. package/dist/transport/loopback_serialization.js +91 -0
  225. package/dist/transport/loopback_serialization.js.map +1 -0
  226. package/dist/transport/transport_contract_suite.cjs +110 -0
  227. package/dist/transport/transport_contract_suite.cjs.map +1 -0
  228. package/dist/transport/transport_contract_suite.d.cts +23 -0
  229. package/dist/transport/transport_contract_suite.d.ts +23 -0
  230. package/dist/transport/transport_contract_suite.js +85 -0
  231. package/dist/transport/transport_contract_suite.js.map +1 -0
  232. package/dist/transport/wood_rpc_transport.cjs +17 -0
  233. package/dist/transport/wood_rpc_transport.cjs.map +1 -0
  234. package/dist/transport/wood_rpc_transport.d.cts +44 -0
  235. package/dist/transport/wood_rpc_transport.d.ts +44 -0
  236. package/dist/transport/wood_rpc_transport.js +1 -0
  237. package/dist/transport/wood_rpc_transport.js.map +1 -0
  238. package/docs/browser-testing.md +139 -1
  239. package/package.json +25 -4
  240. package/src/client/app_env.ts +21 -0
  241. package/src/components/NavigationShell.browser.test.ts +236 -0
  242. package/src/components/NavigationShell.svelte +162 -49
  243. package/src/runtime/app_env.ts +27 -0
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/testing/browser.ts"],"sourcesContent":["import fs from 'node:fs';\nimport os from 'node:os';\nimport { createRequire } from 'node:module';\nimport path from 'node:path';\nimport { pathToFileURL } from 'node:url';\nimport {\n dispatchRendererTracePayload,\n type TraceLevel,\n type TraceRuntimeContext,\n} from '../tracing/index.js';\nimport { TraceRecorder } from '../trace-testing/index.js';\nimport type { ViewDef } from '../types/views.js';\n\ntype MaybePromise<T> = T | Promise<T>;\ntype BrowserName = 'chromium' | 'firefox' | 'webkit';\ntype OperationHandler = unknown | ((\n input: unknown,\n context: WoodBridgeFixtureContext,\n) => MaybePromise<unknown>);\n\nexport interface WoodViewport {\n width: number;\n height: number;\n deviceScaleFactor?: number;\n}\n\nexport interface WoodBridgeRecordedCall {\n channel: string;\n input: unknown;\n timestamp: string;\n}\n\nexport interface WoodBridgeRecordedEvent {\n channel: string;\n payload: unknown;\n timestamp: string;\n}\n\nexport interface WoodBridgeFixtureContext {\n channel: string;\n calls: WoodBridgeRecordedCall[];\n}\n\nexport interface WoodBridgeFixtureInput {\n operations?: Record<string, OperationHandler>;\n events?: Record<string, unknown | unknown[]>;\n record?: boolean;\n}\n\nexport interface WoodBrowserPageContext {\n page: any;\n bridge: MountedWoodBridge;\n route?: {\n key: string;\n params: Record<string, string>;\n query: Record<string, string>;\n };\n}\n\nexport interface WoodBrowserHarnessConfig {\n rootDir?: string;\n generatedApp?: string;\n componentDir?: string;\n viewsConfig?: string;\n css?: string[];\n viewport?: WoodViewport;\n bridge?: WoodBridgeFixtureInput;\n page?: {\n beforeMount?: (context: WoodBrowserPageContext) => MaybePromise<void>;\n afterMount?: (context: WoodBrowserPageContext) => MaybePromise<void>;\n };\n browser?: {\n browserName?: BrowserName;\n headless?: boolean;\n };\n trace?: WoodBrowserTraceConfig;\n}\n\nexport interface WoodBrowserTraceConfig {\n enabled?: boolean;\n maxEvents?: number;\n minLevel?: TraceLevel;\n windowId?: string;\n harnessId?: string;\n}\n\nexport interface MountRouteOptions {\n route?: {\n params?: Record<string, string>;\n query?: Record<string, string>;\n };\n bridge?: WoodBridgeFixtureInput;\n viewport?: WoodViewport;\n page?: {\n beforeMount?: (context: WoodBrowserPageContext) => MaybePromise<void>;\n afterMount?: (context: WoodBrowserPageContext) => MaybePromise<void>;\n };\n}\n\nexport interface MountComponentOptions {\n props?: Record<string, unknown>;\n bridge?: WoodBridgeFixtureInput;\n viewport?: WoodViewport;\n page?: {\n beforeMount?: (context: WoodBrowserPageContext) => MaybePromise<void>;\n afterMount?: (context: WoodBrowserPageContext) => MaybePromise<void>;\n };\n}\n\nexport interface MountTreeOptions {\n layouts?: Array<{\n component: string;\n props?: Record<string, unknown>;\n }>;\n view: {\n component: string;\n props?: Record<string, unknown>;\n };\n page?: {\n key?: string;\n params?: Record<string, string>;\n query?: Record<string, string>;\n };\n bridge?: WoodBridgeFixtureInput;\n viewport?: WoodViewport;\n}\n\nexport interface MountedWoodBridge {\n emit(channel: string, payload: unknown): Promise<void>;\n calls(channel?: string): WoodBridgeRecordedCall[];\n events(channel?: string): WoodBridgeRecordedEvent[];\n setOperation(channel: string, handler: OperationHandler): void;\n clearCalls(): void;\n}\n\nexport interface MountedWoodNavigation {\n current(): Promise<{\n page: string;\n params: Record<string, string>;\n query: Record<string, string>;\n } | null>;\n go(\n page: string,\n params?: Record<string, string>,\n query?: Record<string, string>,\n ): Promise<void>;\n replace(\n page: string,\n params?: Record<string, string>,\n query?: Record<string, string>,\n ): Promise<void>;\n}\n\nexport interface WoodBrowserExpect {\n visible(selector: string): Promise<void>;\n hidden(selector: string): Promise<void>;\n insideViewport(selector: string, options?: { margin?: number }): Promise<void>;\n notClipped(selector: string): Promise<void>;\n notOverlapping(firstSelector: string, secondSelector: string): Promise<void>;\n zIndexAbove(topSelector: string, lowerSelector: string): Promise<void>;\n stableAfterAnimation(selector?: string, options?: {\n timeoutMs?: number;\n frameCount?: number;\n }): Promise<void>;\n screenshot(name: string, options?: {\n fullPage?: boolean;\n mask?: string[];\n threshold?: number;\n }): Promise<void>;\n}\n\nexport interface MountedWoodSurface {\n page: any;\n bridge: MountedWoodBridge;\n navigation: MountedWoodNavigation;\n expect: WoodBrowserExpect;\n locator(selector: string): any;\n click(selector: string): Promise<void>;\n fill(selector: string, value: string): Promise<void>;\n evaluate<T>(fn: () => T | Promise<T>): Promise<T>;\n destroy(): Promise<void>;\n}\n\nexport interface MountedWoodRoute extends MountedWoodSurface {\n routeKey: string;\n}\n\nexport type MountedWoodComponent = MountedWoodSurface;\nexport type MountedWoodTree = MountedWoodSurface;\n\nexport interface WoodBrowserHarness {\n page: any;\n traceRecorder?: TraceRecorder;\n mountRoute(routeKey: string, options?: MountRouteOptions): Promise<MountedWoodRoute>;\n mountComponent(component: string, options?: MountComponentOptions): Promise<MountedWoodComponent>;\n mountTree(tree: MountTreeOptions): Promise<MountedWoodTree>;\n destroy(): Promise<void>;\n}\n\ntype BridgeState = {\n operations: Map<string, OperationHandler>;\n initialEvents: WoodBridgeRecordedEvent[];\n calls: WoodBridgeRecordedCall[];\n emittedEvents: WoodBridgeRecordedEvent[];\n record: boolean;\n};\n\ntype RuntimeBridgeManifestEntry = {\n channel: string;\n controller: string;\n action: string;\n path: string[];\n hasInput: boolean;\n};\n\ntype HarnessRuntime = {\n context: any;\n server: any;\n page: any;\n tempDir: string;\n rootDir: string;\n};\n\ntype BrowserWorkerRuntime = {\n browser: any;\n server: any;\n cacheDir: string;\n rootDir: string;\n key: string;\n activeHarnesses: number;\n closing: boolean;\n idleCloseTimer: NodeJS.Timeout | null;\n};\n\ntype BrowserWorkerRuntimeEntry = {\n promise: Promise<BrowserWorkerRuntime>;\n};\n\nconst DEFAULT_VIEWPORT: WoodViewport = {\n width: 1280,\n height: 800,\n};\nconst DEFAULT_EXPECT_TIMEOUT_MS = 10_000;\nconst DEFAULT_RESOURCE_CLOSE_TIMEOUT_MS = 5_000;\nconst WORKER_RUNTIME_IDLE_CLOSE_MS = 5_000;\nconst browserWorkerRuntimes = new Map<string, BrowserWorkerRuntimeEntry>();\nconst browserWorkerCacheDirs = new Set<string>();\n\n// Synchronous cleanup on process exit (SIGINT, SIGTERM, etc.) to prevent\n// orphaned temp directories in OS tmpdir.\nprocess.on('exit', () => {\n for (const cacheDir of browserWorkerCacheDirs) {\n try {\n fs.rmSync(cacheDir, { recursive: true, force: true });\n } catch {\n // Best-effort cleanup — ignore errors during exit.\n }\n }\n browserWorkerCacheDirs.clear();\n browserWorkerRuntimes.clear();\n});\n\nfunction normalizeRoot(rootDir: string | undefined): string {\n return path.resolve(rootDir ?? process.cwd());\n}\n\nfunction resolveFromRoot(rootDir: string, filePath: string): string {\n return path.isAbsolute(filePath) ? filePath : path.resolve(rootDir, filePath);\n}\n\nfunction viteImport(filePath: string): string {\n return `/@fs/${filePath.replace(/\\\\/g, '/').replace(/^\\/+/, '')}`;\n}\n\nfunction mergeBridge(\n base: WoodBridgeFixtureInput | undefined,\n override: WoodBridgeFixtureInput | undefined,\n): WoodBridgeFixtureInput {\n return {\n operations: {\n ...(base?.operations ?? {}),\n ...(override?.operations ?? {}),\n },\n events: {\n ...(base?.events ?? {}),\n ...(override?.events ?? {}),\n },\n record: override?.record ?? base?.record,\n };\n}\n\nasync function waitForBoundedClose(promise: Promise<unknown>, timeoutMs = DEFAULT_RESOURCE_CLOSE_TIMEOUT_MS): Promise<void> {\n let timeout: NodeJS.Timeout | undefined;\n await Promise.race([\n promise.catch(() => undefined),\n new Promise<void>((resolve) => {\n timeout = setTimeout(resolve, timeoutMs);\n }),\n ]);\n if (timeout) {\n clearTimeout(timeout);\n }\n}\n\nfunction channelToManifestEntry(channel: string, handler: OperationHandler): RuntimeBridgeManifestEntry {\n const pathSegments = channel.split('.').filter(Boolean);\n const action = pathSegments.length > 0 ? pathSegments[pathSegments.length - 1] : channel;\n const controller = pathSegments.length > 1 ? pathSegments[0] : channel;\n\n return {\n channel,\n controller,\n action,\n path: pathSegments,\n hasInput: typeof handler === 'function',\n };\n}\n\nfunction createBridgeState(input: WoodBridgeFixtureInput | undefined): BridgeState {\n const initialEvents = Object.entries(input?.events ?? {}).flatMap(([channel, payloadOrList]) => {\n const payloads = Array.isArray(payloadOrList) ? payloadOrList : [payloadOrList];\n return payloads.map((payload) => ({\n channel,\n payload,\n timestamp: new Date().toISOString(),\n }));\n });\n\n return {\n operations: new Map(Object.entries(input?.operations ?? {})),\n initialEvents,\n calls: [],\n emittedEvents: [],\n record: input?.record ?? true,\n };\n}\n\nexport function createBrowserBridgeFixture(input: WoodBridgeFixtureInput | undefined): {\n state: BridgeState;\n manifest: RuntimeBridgeManifestEntry[];\n bridgeInit: string;\n} {\n return createBrowserBridgeFixtureWithTrace(input, undefined);\n}\n\nfunction createBrowserBridgeFixtureWithTrace(\n input: WoodBridgeFixtureInput | undefined,\n traceConfig: WoodBrowserTraceConfig | undefined,\n): {\n state: BridgeState;\n manifest: RuntimeBridgeManifestEntry[];\n bridgeInit: string;\n} {\n const state = createBridgeState(input);\n const manifest = Array.from(state.operations.entries())\n .map(([channel, handler]) => channelToManifestEntry(channel, handler));\n\n return {\n state,\n manifest,\n bridgeInit: buildBridgeInitScript(manifest, traceConfig),\n };\n}\n\nfunction buildBridgeInitScript(\n manifest: RuntimeBridgeManifestEntry[],\n traceConfig: WoodBrowserTraceConfig | undefined,\n): string {\n const traceEnabled = traceConfig?.enabled === true;\n const traceMinLevel = traceConfig?.minLevel ?? 'debug';\n return `\n(() => {\n const manifest = ${JSON.stringify(manifest)};\n const listeners = new Map();\n const bridge = {\n __rpcManifest: manifest,\n __woodConfig: async () => ({\n rendererTraceEnabled: ${JSON.stringify(traceEnabled)},\n rendererTraceMinLevel: ${JSON.stringify(traceMinLevel)}\n }),\n __log: () => {},\n __trace: (payload) => window.__woodBrowserTrace?.(payload),\n __window: {\n current: async () => ({ ok: true, windowId: 'wood-browser-harness', defaultRoute: window.__WOOD_BROWSER_DEFAULT_ROUTE__ }),\n open: async () => ({}),\n close: async () => ({}),\n focus: async () => ({}),\n minimize: async () => ({}),\n maximize: async () => ({}),\n },\n on(channel, callback) {\n if (!listeners.has(channel)) listeners.set(channel, new Set());\n listeners.get(channel).add(callback);\n return () => listeners.get(channel)?.delete(callback);\n },\n };\n\n for (const entry of manifest) {\n let current = bridge;\n for (let i = 0; i < entry.path.length - 1; i += 1) {\n const segment = entry.path[i];\n current[segment] ??= {};\n current = current[segment];\n }\n const leaf = entry.path[entry.path.length - 1];\n current[leaf] = async (data) => window.__woodBrowserInvoke(entry.channel, data);\n }\n\n window.__woodBrowserEmit = (channel, payload) => {\n const handlers = listeners.get(channel);\n if (!handlers) return;\n for (const handler of handlers) handler(payload);\n };\n window.__NOEGO_WOOD_BRIDGE__ = bridge;\n window.wood = bridge;\n globalThis.__NOEGO_WOOD_BRIDGE__ = bridge;\n globalThis.wood = bridge;\n})();\n`;\n}\n\nasync function loadPlaywright(browserName: BrowserName): Promise<any> {\n const playwright = await import('playwright');\n return playwright[browserName];\n}\n\nasync function loadVite(): Promise<any> {\n return await import('vite');\n}\n\nfunction createPackageRequire(rootDir: string): NodeJS.Require {\n return createRequire(path.join(rootDir, 'package.json'));\n}\n\nfunction resolvePackageModule(rootDir: string, source: string): string | null {\n const rootRequire = createPackageRequire(rootDir);\n const processRequire = createRequire(path.join(process.cwd(), 'package.json'));\n try {\n return rootRequire.resolve(source);\n } catch {\n try {\n return processRequire.resolve(source);\n } catch {\n return null;\n }\n }\n}\n\nfunction resolvePackageDir(rootDir: string, packageName: string): string | null {\n const packageJson = resolvePackageModule(rootDir, `${packageName}/package.json`);\n return packageJson ? path.dirname(packageJson) : null;\n}\n\nfunction createWoodBrowserResolver(rootDir: string): any {\n const sveltePackageDir = resolvePackageDir(rootDir, 'svelte');\n const svelteClientEntry = sveltePackageDir\n ? path.join(sveltePackageDir, 'src', 'index-client.js')\n : null;\n const svelteLegacyClientEntry = sveltePackageDir\n ? path.join(sveltePackageDir, 'src', 'legacy', 'legacy-client.js')\n : null;\n const svelteReactivityClientEntry = sveltePackageDir\n ? path.join(sveltePackageDir, 'src', 'reactivity', 'index-client.js')\n : null;\n\n return {\n name: 'wood-browser-resolver',\n enforce: 'pre',\n resolveId(source: string): string | null {\n if (source === 'svelte') {\n return svelteClientEntry;\n }\n if (source === 'svelte/legacy') {\n return svelteLegacyClientEntry;\n }\n if (source === 'svelte/reactivity') {\n return svelteReactivityClientEntry;\n }\n if (source.startsWith('svelte/')) {\n return resolvePackageModule(rootDir, source);\n }\n return null;\n },\n };\n}\n\nasync function loadSveltePlugin(rootDir: string): Promise<any | null> {\n try {\n const rootPluginPath = path.join(\n rootDir,\n 'node_modules',\n '@sveltejs',\n 'vite-plugin-svelte',\n 'src',\n 'index.js',\n );\n if (fs.existsSync(rootPluginPath)) {\n const mod = await import(pathToFileURL(rootPluginPath).href);\n return mod.svelte;\n }\n const rootRequire = createRequire(path.join(rootDir, 'package.json'));\n const mod = await import(pathToFileURL(rootRequire.resolve('@sveltejs/vite-plugin-svelte')).href);\n return mod.svelte;\n } catch {\n try {\n const mod = await import('@sveltejs/vite-plugin-svelte');\n return mod.svelte;\n } catch {\n return null;\n }\n }\n}\n\nasync function loadViews(viewsPath: string): Promise<ViewDef[]> {\n const parser = await import('../parser/views_parser.js');\n return parser.parseViewsFile(viewsPath);\n}\n\nasync function createViteServer(rootDir: string, cacheDir: string): Promise<any> {\n const vite = await loadVite();\n const svelte = await loadSveltePlugin(rootDir);\n const plugins = [\n createWoodBrowserResolver(rootDir),\n ...(svelte ? [svelte()] : []),\n ];\n const server = await vite.createServer({\n root: rootDir,\n cacheDir,\n logLevel: process.env.WOOD_BROWSER_TEST_DEBUG ? 'info' : 'silent',\n plugins,\n resolve: {\n dedupe: ['svelte'],\n },\n server: { port: 0, fs: { allow: [rootDir, os.tmpdir()] } },\n });\n await server.listen();\n return server;\n}\n\nfunction workerRuntimeKey(input: {\n rootDir: string;\n browserName: BrowserName;\n headless: boolean;\n}): string {\n return [\n input.rootDir,\n input.browserName,\n input.headless ? 'headless' : 'headed',\n ].join('::');\n}\n\nasync function createBrowserWorkerRuntime(input: {\n rootDir: string;\n browserName: BrowserName;\n headless: boolean;\n key: string;\n}): Promise<BrowserWorkerRuntime> {\n const cacheRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'wood-browser-vite-'));\n browserWorkerCacheDirs.add(cacheRoot);\n let browser: any | null = null;\n try {\n const playwrightBrowser = await loadPlaywright(input.browserName);\n browser = await playwrightBrowser.launch({ headless: input.headless });\n const server = await createViteServer(input.rootDir, path.join(cacheRoot, '.vite'));\n return {\n browser,\n server,\n cacheDir: cacheRoot,\n rootDir: input.rootDir,\n key: input.key,\n activeHarnesses: 0,\n closing: false,\n idleCloseTimer: null,\n };\n } catch (error) {\n await browser?.close().catch(() => undefined);\n fs.rmSync(cacheRoot, { recursive: true, force: true });\n browserWorkerCacheDirs.delete(cacheRoot);\n throw error;\n }\n}\n\nasync function acquireBrowserWorkerRuntime(input: {\n rootDir: string;\n browserName: BrowserName;\n headless: boolean;\n}): Promise<BrowserWorkerRuntime> {\n const key = workerRuntimeKey(input);\n let entry = browserWorkerRuntimes.get(key);\n if (!entry) {\n entry = {\n promise: createBrowserWorkerRuntime({ ...input, key }),\n };\n browserWorkerRuntimes.set(key, entry);\n }\n\n const runtime = await entry.promise;\n if (runtime.closing) {\n browserWorkerRuntimes.delete(key);\n return await acquireBrowserWorkerRuntime(input);\n }\n if (runtime.idleCloseTimer) {\n clearTimeout(runtime.idleCloseTimer);\n runtime.idleCloseTimer = null;\n }\n runtime.activeHarnesses += 1;\n return runtime;\n}\n\nasync function closeBrowserWorkerRuntime(runtime: BrowserWorkerRuntime): Promise<void> {\n if (runtime.closing) {\n return;\n }\n runtime.closing = true;\n try {\n await Promise.all([\n waitForBoundedClose(runtime.server.close()),\n waitForBoundedClose(runtime.browser.close()),\n ]);\n } finally {\n fs.rmSync(runtime.cacheDir, { recursive: true, force: true });\n browserWorkerCacheDirs.delete(runtime.cacheDir);\n const entry = browserWorkerRuntimes.get(runtime.key);\n const current = entry ? await entry.promise.catch(() => null) : null;\n if (current === runtime) {\n browserWorkerRuntimes.delete(runtime.key);\n }\n }\n}\n\nfunction scheduleBrowserWorkerRuntimeClose(runtime: BrowserWorkerRuntime): void {\n if (runtime.closing || runtime.activeHarnesses > 0 || runtime.idleCloseTimer) {\n return;\n }\n runtime.idleCloseTimer = setTimeout(() => {\n runtime.idleCloseTimer = null;\n if (runtime.activeHarnesses === 0) {\n void closeBrowserWorkerRuntime(runtime);\n }\n }, WORKER_RUNTIME_IDLE_CLOSE_MS);\n runtime.idleCloseTimer.unref?.();\n}\n\nfunction releaseBrowserWorkerRuntime(runtime: BrowserWorkerRuntime): void {\n runtime.activeHarnesses = Math.max(0, runtime.activeHarnesses - 1);\n scheduleBrowserWorkerRuntimeClose(runtime);\n}\n\nfunction serverBaseUrl(server: any): string {\n return server.resolvedUrls?.local?.[0] ?? 'http://127.0.0.1:5173';\n}\n\nfunction assertFileExists(filePath: string, label: string): void {\n if (!fs.existsSync(filePath)) {\n throw new Error(`${label} does not exist: ${filePath}`);\n }\n}\n\nfunction writeEntry(tempDir: string, name: string, source: string): string {\n fs.mkdirSync(tempDir, { recursive: true });\n const entryPath = path.join(tempDir, `${name}.ts`);\n fs.writeFileSync(entryPath, source);\n return entryPath;\n}\n\nfunction writeHtml(tempDir: string, name: string, entryPath: string, cssFiles: string[]): string {\n const styles = cssFiles\n .map((cssPath) => `<link rel=\"stylesheet\" href=\"${viteImport(cssPath)}\" />`)\n .join('\\n');\n const htmlPath = path.join(tempDir, `${name}.html`);\n fs.writeFileSync(htmlPath, `<!doctype html>\n<html>\n <head>\n <meta charset=\"utf-8\" />\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n ${styles}\n </head>\n <body>\n <div id=\"app\"></div>\n <script type=\"module\" src=\"${viteImport(entryPath)}\"></script>\n </body>\n</html>\n`);\n return htmlPath;\n}\n\nfunction viewKey(view: ViewDef): string {\n return `${view.windowName}.${view.pageName}`;\n}\n\nfunction findView(views: ViewDef[], routeKey: string): ViewDef {\n const found = views.find((view) => viewKey(view) === routeKey);\n if (!found) {\n throw new Error(\n `Unknown Wood route \"${routeKey}\". Available routes: ${views.map(viewKey).join(', ')}`,\n );\n }\n return found;\n}\n\nfunction resolveComponentPath(rootDir: string, componentDir: string | undefined, filePath: string): string {\n if (path.isAbsolute(filePath)) return filePath;\n const base = componentDir ? resolveFromRoot(rootDir, componentDir) : rootDir;\n const componentDirName = componentDir ? path.basename(componentDir) : '';\n if (componentDirName && filePath.replace(/\\\\/g, '/').startsWith(`${componentDirName}/`)) {\n return path.resolve(base, filePath.slice(componentDirName.length + 1));\n }\n return path.resolve(base, filePath);\n}\n\nfunction buildRouteEntrySource(input: {\n routeKey: string;\n view: ViewDef;\n rootDir: string;\n componentDir?: string;\n route: {\n params: Record<string, string>;\n query: Record<string, string>;\n };\n}): string {\n const { view, rootDir, componentDir, routeKey, route } = input;\n const viewPath = resolveComponentPath(rootDir, componentDir, view.viewPath);\n const layoutPaths = view.layouts.map((layout) => resolveComponentPath(rootDir, componentDir, layout));\n const controllerPath = view.controller\n ? resolveComponentPath(rootDir, componentDir, view.controller)\n : null;\n const layoutControllerPaths = view.layoutControllers?.map((controller) =>\n controller ? resolveComponentPath(rootDir, componentDir, controller) : null,\n ) ?? [];\n\n const imports = [\n `import { mount } from 'svelte';`,\n `import NavigationShell from '@noego/wood/navigation-shell';`,\n `import { getContainer } from '@noego/wood/client';`,\n `import { getNavigation } from '@noego/wood/navigation';`,\n `import ViewComponent from '${viteImport(viewPath)}';`,\n ...layoutPaths.map((layoutPath, index) => `import Layout${index} from '${viteImport(layoutPath)}';`),\n ...(controllerPath ? [`import PageController from '${viteImport(controllerPath)}';`] : []),\n ...layoutControllerPaths.map((controllerPath, index) =>\n controllerPath ? `import LayoutController${index} from '${viteImport(controllerPath)}';` : '',\n ).filter(Boolean),\n ];\n\n const layoutControllerClasses = layoutControllerPaths.map((controllerPath, index) =>\n controllerPath ? `LayoutController${index}` : 'undefined',\n );\n\n return `${imports.join('\\n')}\n\nconst entry = {\n key: ${JSON.stringify(routeKey)},\n windowName: ${JSON.stringify(view.windowName)},\n pageName: ${JSON.stringify(view.pageName)},\n viewPath: ${JSON.stringify(view.viewPath)},\n layoutPaths: ${JSON.stringify(view.layouts)},\n layoutControllers: ${JSON.stringify(view.layoutControllers ?? [])},\n controller: ${JSON.stringify(view.controller)},\n layoutControllerClasses: [${layoutControllerClasses.join(', ')}],\n controllerClass: ${controllerPath ? 'PageController' : 'undefined'},\n view: ViewComponent,\n layouts: [${layoutPaths.map((_, index) => `Layout${index}`).join(', ')}],\n};\n\nfunction createScopedContainer() {\n const root = getContainer();\n const scope = root.extend();\n return scope;\n}\n\nasync function resolveController(ControllerClass) {\n if (!ControllerClass) return undefined;\n const scope = createScopedContainer();\n scope.registerClass?.(ControllerClass);\n return await scope.get(ControllerClass);\n}\n\nasync function createViewController(nextEntry) {\n return await resolveController(nextEntry.controllerClass);\n}\n\nasync function createLayoutControllers(nextEntry) {\n const controllers = [];\n for (const ControllerClass of nextEntry.layoutControllerClasses) {\n controllers.push(await resolveController(ControllerClass));\n }\n return controllers;\n}\n\nfunction getViewManifestEntry(nextKey) {\n return nextKey === entry.key ? entry : null;\n}\n\nconst navigation = getNavigation();\nnavigation.replace(entry.key, ${JSON.stringify(route.params)}, ${JSON.stringify(route.query)});\n\nconst controller = await createViewController(entry);\nconst layoutControllers = await createLayoutControllers(entry);\n\nwindow.__WOOD_BROWSER_APP__ = mount(NavigationShell, {\n target: document.getElementById('app'),\n props: {\n manifest: { [entry.key]: entry },\n initialEntry: entry,\n initialController: controller,\n initialLayoutControllers: layoutControllers,\n createViewControllerFn: createViewController,\n createLayoutControllersFn: createLayoutControllers,\n getViewManifestEntryFn: getViewManifestEntry,\n },\n});\n`;\n}\n\nfunction buildGeneratedAppEntrySource(input: {\n generatedApp: string;\n routeKey: string;\n}): string {\n return `import { app } from '${viteImport(input.generatedApp)}';\nwindow.__WOOD_BROWSER_DEFAULT_ROUTE__ = ${JSON.stringify(input.routeKey)};\nwindow.__WOOD_BROWSER_APP__ = await app(document.getElementById('app'));\n`;\n}\n\nfunction buildComponentEntrySource(input: {\n componentPath: string;\n props: Record<string, unknown>;\n}): string {\n return `import { mount } from 'svelte';\nimport Component from '${viteImport(input.componentPath)}';\nwindow.__WOOD_BROWSER_APP__ = mount(Component, {\n target: document.getElementById('app'),\n props: ${JSON.stringify(input.props)},\n});\n`;\n}\n\nfunction buildTreeEntrySource(input: {\n layouts: Array<{ component: string; props?: Record<string, unknown> }>;\n view: { component: string; props?: Record<string, unknown> };\n}): string {\n const imports = [\n `import { mount } from 'svelte';`,\n `import WoodRecursiveRender from '@noego/wood/recursive-render';`,\n `import ViewComponent from '${viteImport(input.view.component)}';`,\n ...input.layouts.map((layout, index) => `import Layout${index} from '${viteImport(layout.component)}';`),\n ];\n const layoutControllers = input.layouts.map((layout) => ({\n data: layout.props?.data,\n input: layout.props?.input,\n events: layout.props?.events,\n }));\n const viewController = {\n data: input.view.props?.data,\n input: input.view.props?.input,\n events: input.view.props?.events,\n };\n\n return `${imports.join('\\n')}\nwindow.__WOOD_BROWSER_APP__ = mount(WoodRecursiveRender, {\n target: document.getElementById('app'),\n props: {\n layouts: [${input.layouts.map((_, index) => `Layout${index}`).join(', ')}],\n layoutControllers: ${JSON.stringify(layoutControllers)},\n view: ViewComponent,\n controller: ${JSON.stringify(viewController)},\n },\n});\n`;\n}\n\nasync function installBridge(page: any, bridgeState: BridgeState, manifest: RuntimeBridgeManifestEntry[], bridgeInit: string): Promise<void> {\n await page.exposeBinding('__woodBrowserInvoke', async (_source: unknown, channel: string, input: unknown) => {\n const call = {\n channel,\n input,\n timestamp: new Date().toISOString(),\n };\n if (bridgeState.record) {\n bridgeState.calls.push(call);\n }\n const handler = bridgeState.operations.get(channel);\n if (typeof handler === 'function') {\n return await handler(input, { channel, calls: bridgeState.calls });\n }\n return handler;\n });\n await page.addInitScript(bridgeInit);\n await page.addInitScript((entries: RuntimeBridgeManifestEntry[]) => {\n window.__WOOD_BROWSER_BRIDGE_MANIFEST__ = entries;\n }, manifest);\n}\n\nasync function installTraceBinding(\n page: any,\n traceRecorder: TraceRecorder | undefined,\n context: TraceRuntimeContext,\n): Promise<void> {\n if (!traceRecorder) {\n return;\n }\n await page.exposeBinding('__woodBrowserTrace', async (_source: unknown, payload: unknown) => {\n dispatchRendererTracePayload(payload, context);\n });\n}\n\nfunction createMountedBridge(page: any, state: BridgeState): MountedWoodBridge {\n return {\n async emit(channel: string, payload: unknown): Promise<void> {\n state.emittedEvents.push({\n channel,\n payload,\n timestamp: new Date().toISOString(),\n });\n await page.evaluate(({ eventChannel, eventPayload }: { eventChannel: string; eventPayload: unknown }) => {\n window.__woodBrowserEmit?.(eventChannel, eventPayload);\n }, { eventChannel: channel, eventPayload: payload });\n },\n calls(channel?: string): WoodBridgeRecordedCall[] {\n return channel ? state.calls.filter((call) => call.channel === channel) : [...state.calls];\n },\n events(channel?: string): WoodBridgeRecordedEvent[] {\n return channel\n ? state.emittedEvents.filter((event) => event.channel === channel)\n : [...state.emittedEvents];\n },\n setOperation(channel: string, handler: OperationHandler): void {\n state.operations.set(channel, handler);\n },\n clearCalls(): void {\n state.calls.length = 0;\n },\n };\n}\n\nfunction createMountedNavigation(page: any): MountedWoodNavigation {\n return {\n async current() {\n return await page.evaluate(async () => {\n const specifier = '@noego/wood/navigation';\n const mod = await import(/* @vite-ignore */ specifier);\n return mod.getNavigation().getCurrent();\n });\n },\n async go(routePage, params = {}, query = {}) {\n await page.evaluate(async (payload: {\n routePage: string;\n params: Record<string, string>;\n query: Record<string, string>;\n }) => {\n const { routePage: nextPage, params: nextParams, query: nextQuery } = payload;\n const specifier = '@noego/wood/navigation';\n const mod = await import(/* @vite-ignore */ specifier);\n mod.getNavigation().go(nextPage, nextParams, nextQuery);\n }, { routePage, params, query });\n },\n async replace(routePage, params = {}, query = {}) {\n await page.evaluate(async (payload: {\n routePage: string;\n params: Record<string, string>;\n query: Record<string, string>;\n }) => {\n const { routePage: nextPage, params: nextParams, query: nextQuery } = payload;\n const specifier = '@noego/wood/navigation';\n const mod = await import(/* @vite-ignore */ specifier);\n mod.getNavigation().replace(nextPage, nextParams, nextQuery);\n }, { routePage, params, query });\n },\n };\n}\n\nasync function elementRect(page: any, selector: string): Promise<{\n top: number;\n left: number;\n right: number;\n bottom: number;\n width: number;\n height: number;\n} | null> {\n return await page.locator(selector).evaluate((element: Element) => {\n const rect = element.getBoundingClientRect();\n return {\n top: rect.top,\n left: rect.left,\n right: rect.right,\n bottom: rect.bottom,\n width: rect.width,\n height: rect.height,\n };\n }).catch(() => null);\n}\n\nfunction createExpect(page: any, outputDir: string): WoodBrowserExpect {\n async function waitForVisible(selector: string): Promise<void> {\n const locator = page.locator(selector).first();\n try {\n await locator.waitFor({ state: 'attached', timeout: DEFAULT_EXPECT_TIMEOUT_MS });\n } catch {\n throw new Error(`Expected \"${selector}\" to exist.`);\n }\n try {\n await locator.waitFor({ state: 'visible', timeout: DEFAULT_EXPECT_TIMEOUT_MS });\n } catch {\n throw new Error(`Expected \"${selector}\" to be visible.`);\n }\n }\n\n return {\n async visible(selector: string): Promise<void> {\n await waitForVisible(selector);\n },\n async hidden(selector: string): Promise<void> {\n try {\n await page.locator(selector).first().waitFor({\n state: 'hidden',\n timeout: DEFAULT_EXPECT_TIMEOUT_MS,\n });\n } catch {\n throw new Error(`Expected \"${selector}\" to be hidden.`);\n }\n },\n async insideViewport(selector: string, options: { margin?: number } = {}): Promise<void> {\n await waitForVisible(selector);\n const margin = options.margin ?? 0;\n const rect = await elementRect(page, selector);\n if (!rect) throw new Error(`Expected \"${selector}\" to exist.`);\n const viewport = page.viewportSize();\n if (!viewport) throw new Error('Cannot assert viewport bounds without a viewport.');\n if (\n rect.left < margin ||\n rect.top < margin ||\n rect.right > viewport.width - margin ||\n rect.bottom > viewport.height - margin\n ) {\n throw new Error(`Expected \"${selector}\" to be inside viewport. Rect: ${JSON.stringify(rect)}, viewport: ${JSON.stringify(viewport)}`);\n }\n },\n async notClipped(selector: string): Promise<void> {\n await waitForVisible(selector);\n const result = await page.locator(selector).first().evaluate((element: Element) => {\n const rect = element.getBoundingClientRect();\n let parent = element.parentElement;\n while (parent) {\n const style = window.getComputedStyle(parent);\n const clips = /(auto|hidden|scroll|clip)/.test(`${style.overflow}${style.overflowX}${style.overflowY}`);\n if (clips) {\n const parentRect = parent.getBoundingClientRect();\n if (\n rect.left < parentRect.left ||\n rect.top < parentRect.top ||\n rect.right > parentRect.right ||\n rect.bottom > parentRect.bottom\n ) {\n return { ok: false, parent: parent.tagName, rect, parentRect };\n }\n }\n parent = parent.parentElement;\n }\n return { ok: true };\n });\n if (!result.ok) {\n throw new Error(`Expected \"${selector}\" not to be clipped. ${JSON.stringify(result)}`);\n }\n },\n async notOverlapping(firstSelector: string, secondSelector: string): Promise<void> {\n await waitForVisible(firstSelector);\n await waitForVisible(secondSelector);\n const first = await elementRect(page, firstSelector);\n const second = await elementRect(page, secondSelector);\n if (!first || !second) throw new Error(`Expected both \"${firstSelector}\" and \"${secondSelector}\" to exist.`);\n const overlaps = first.left < second.right\n && first.right > second.left\n && first.top < second.bottom\n && first.bottom > second.top;\n if (overlaps) {\n throw new Error(`Expected \"${firstSelector}\" not to overlap \"${secondSelector}\".`);\n }\n },\n async zIndexAbove(topSelector: string, lowerSelector: string): Promise<void> {\n await waitForVisible(topSelector);\n await waitForVisible(lowerSelector);\n const values = await page.evaluate((payload: { topSelector: string; lowerSelector: string }) => {\n const { topSelector: top, lowerSelector: lower } = payload;\n const topElement = document.querySelector(top);\n const lowerElement = document.querySelector(lower);\n if (!topElement || !lowerElement) return null;\n return {\n top: Number(window.getComputedStyle(topElement).zIndex) || 0,\n lower: Number(window.getComputedStyle(lowerElement).zIndex) || 0,\n };\n }, { topSelector, lowerSelector });\n if (!values) throw new Error(`Expected both \"${topSelector}\" and \"${lowerSelector}\" to exist.`);\n if (values.top <= values.lower) {\n throw new Error(`Expected \"${topSelector}\" z-index (${values.top}) to be above \"${lowerSelector}\" (${values.lower}).`);\n }\n },\n async stableAfterAnimation(selector = 'body', options = {}): Promise<void> {\n const frameCount = options.frameCount ?? 3;\n const timeoutMs = options.timeoutMs ?? 2000;\n const startedAt = Date.now();\n let previous = '';\n let stableFrames = 0;\n while (Date.now() - startedAt < timeoutMs) {\n const current = JSON.stringify(await elementRect(page, selector));\n if (current === previous) {\n stableFrames += 1;\n if (stableFrames >= frameCount) return;\n } else {\n stableFrames = 0;\n previous = current;\n }\n await page.evaluate(() => new Promise((resolve) => requestAnimationFrame(() => resolve(undefined))));\n }\n throw new Error(`Expected \"${selector}\" to become stable within ${timeoutMs}ms.`);\n },\n async screenshot(name: string, options = {}): Promise<void> {\n const outputPath = path.join(outputDir, `${name}.png`);\n await fs.promises.mkdir(outputDir, { recursive: true });\n const masks = options.mask?.map((selector) => page.locator(selector)) ?? [];\n await page.screenshot({\n path: outputPath,\n fullPage: options.fullPage ?? true,\n mask: masks,\n });\n },\n };\n}\n\nfunction createSurface(input: {\n page: any;\n bridge: MountedWoodBridge;\n outputDir: string;\n destroy: () => Promise<void>;\n}): MountedWoodSurface {\n return {\n page: input.page,\n bridge: input.bridge,\n navigation: createMountedNavigation(input.page),\n expect: createExpect(input.page, input.outputDir),\n locator(selector: string): any {\n return input.page.locator(selector);\n },\n async click(selector: string): Promise<void> {\n await input.page.locator(selector).click();\n },\n async fill(selector: string, value: string): Promise<void> {\n await input.page.locator(selector).fill(value);\n },\n async evaluate<T>(fn: () => T | Promise<T>): Promise<T> {\n return await input.page.evaluate(fn);\n },\n destroy: input.destroy,\n };\n}\n\nasync function openMountPage(input: {\n runtime: HarnessRuntime;\n entrySource: string;\n name: string;\n css: string[];\n viewport?: WoodViewport;\n bridge: {\n state: BridgeState;\n manifest: RuntimeBridgeManifestEntry[];\n bridgeInit: string;\n };\n traceRecorder?: TraceRecorder;\n traceContext?: TraceRuntimeContext;\n context: Omit<WoodBrowserPageContext, 'page' | 'bridge'>;\n hooks?: WoodBrowserHarnessConfig['page'];\n}): Promise<MountedWoodSurface> {\n const page = input.runtime.page;\n const viewport = input.viewport ?? DEFAULT_VIEWPORT;\n await page.setViewportSize({ width: viewport.width, height: viewport.height });\n const entryPath = writeEntry(input.runtime.tempDir, input.name, input.entrySource);\n const htmlPath = writeHtml(input.runtime.tempDir, input.name, entryPath, input.css);\n await installTraceBinding(input.runtime.page, input.traceRecorder, input.traceContext ?? {});\n await installBridge(page, input.bridge.state, input.bridge.manifest, input.bridge.bridgeInit);\n const mountedBridge = createMountedBridge(page, input.bridge.state);\n const context: WoodBrowserPageContext = {\n page,\n bridge: mountedBridge,\n ...input.context,\n };\n await input.hooks?.beforeMount?.(context);\n await page.goto(`${serverBaseUrl(input.runtime.server)}${viteImport(htmlPath)}`, {\n waitUntil: 'domcontentloaded',\n });\n for (const event of input.bridge.state.initialEvents) {\n await mountedBridge.emit(event.channel, event.payload);\n }\n await input.hooks?.afterMount?.(context);\n\n return createSurface({\n page,\n bridge: mountedBridge,\n outputDir: path.join(input.runtime.rootDir, 'test-results', 'wood-browser'),\n destroy: async () => {\n await page.evaluate(() => {\n const app = window.__WOOD_BROWSER_APP__;\n if (app && typeof app === 'object' && typeof (app as { $destroy?: () => void }).$destroy === 'function') {\n (app as { $destroy: () => void }).$destroy();\n }\n }).catch(() => undefined);\n },\n });\n}\n\nasync function createHarness(config: WoodBrowserHarnessConfig = {}): Promise<WoodBrowserHarness> {\n const rootDir = normalizeRoot(config.rootDir);\n const browserName = config.browser?.browserName ?? 'chromium';\n const headless = config.browser?.headless ?? true;\n const workerRuntime = await acquireBrowserWorkerRuntime({\n rootDir,\n browserName,\n headless,\n });\n let released = false;\n let destroyed = false;\n let tempDir: string | null = null;\n let context: any | null = null;\n let page: any | null = null;\n let traceRecorder: TraceRecorder | undefined;\n\n function releaseRuntimeOnce(): void {\n if (released) {\n return;\n }\n released = true;\n releaseBrowserWorkerRuntime(workerRuntime);\n }\n\n try {\n tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'wood-browser-harness-'));\n context = await workerRuntime.browser.newContext({\n viewport: {\n width: config.viewport?.width ?? DEFAULT_VIEWPORT.width,\n height: config.viewport?.height ?? DEFAULT_VIEWPORT.height,\n deviceScaleFactor: config.viewport?.deviceScaleFactor,\n },\n });\n page = await context.newPage();\n traceRecorder = config.trace?.enabled === true\n ? new TraceRecorder()\n : undefined;\n traceRecorder?.enable({ maxEvents: config.trace?.maxEvents });\n } catch (error) {\n if (page) await waitForBoundedClose(page.close());\n if (context) await waitForBoundedClose(context.close());\n if (tempDir) fs.rmSync(tempDir, { recursive: true, force: true });\n releaseRuntimeOnce();\n throw error;\n }\n\n const runtime: HarnessRuntime = {\n context,\n server: workerRuntime.server,\n page,\n tempDir,\n rootDir,\n };\n const css = (config.css ?? []).map((cssPath) => {\n const resolved = resolveFromRoot(rootDir, cssPath);\n assertFileExists(resolved, 'CSS file');\n return resolved;\n });\n\n return {\n page,\n ...(traceRecorder ? { traceRecorder } : {}),\n async mountRoute(routeKey: string, options: MountRouteOptions = {}): Promise<MountedWoodRoute> {\n const bridge = createBrowserBridgeFixtureWithTrace(mergeBridge(config.bridge, options.bridge), config.trace);\n const route = {\n params: options.route?.params ?? {},\n query: options.route?.query ?? {},\n };\n let entrySource: string;\n if (config.viewsConfig) {\n const viewsPath = resolveFromRoot(rootDir, config.viewsConfig);\n const views = await loadViews(viewsPath);\n const view = findView(views, routeKey);\n entrySource = buildRouteEntrySource({\n routeKey,\n view,\n rootDir,\n componentDir: config.componentDir,\n route,\n });\n } else if (config.generatedApp) {\n const generatedApp = resolveFromRoot(rootDir, config.generatedApp);\n assertFileExists(generatedApp, 'Generated app');\n entrySource = buildGeneratedAppEntrySource({ generatedApp, routeKey });\n } else {\n throw new Error('mountRoute requires either viewsConfig or generatedApp in browser.createHarness().');\n }\n\n const mounted = await openMountPage({\n runtime,\n entrySource,\n name: `route-${routeKey.replace(/[^a-zA-Z0-9_-]/g, '-')}`,\n css,\n viewport: options.viewport ?? config.viewport,\n bridge,\n traceRecorder,\n traceContext: {\n windowId: config.trace?.windowId ?? routeKey.split('.')[0],\n routeKey,\n harnessId: config.trace?.harnessId,\n },\n context: {\n route: {\n key: routeKey,\n params: route.params,\n query: route.query,\n },\n },\n hooks: {\n beforeMount: options.page?.beforeMount ?? config.page?.beforeMount,\n afterMount: options.page?.afterMount ?? config.page?.afterMount,\n },\n });\n return {\n ...mounted,\n routeKey,\n };\n },\n async mountComponent(component: string, options: MountComponentOptions = {}): Promise<MountedWoodComponent> {\n const componentPath = resolveFromRoot(rootDir, component);\n assertFileExists(componentPath, 'Component');\n const bridge = createBrowserBridgeFixtureWithTrace(mergeBridge(config.bridge, options.bridge), config.trace);\n return await openMountPage({\n runtime,\n entrySource: buildComponentEntrySource({\n componentPath,\n props: options.props ?? {},\n }),\n name: `component-${path.basename(componentPath).replace(/[^a-zA-Z0-9_-]/g, '-')}`,\n css,\n viewport: options.viewport ?? config.viewport,\n bridge,\n traceRecorder,\n traceContext: {\n windowId: config.trace?.windowId ?? 'wood-browser-harness',\n harnessId: config.trace?.harnessId,\n },\n context: {},\n hooks: {\n beforeMount: options.page?.beforeMount ?? config.page?.beforeMount,\n afterMount: options.page?.afterMount ?? config.page?.afterMount,\n },\n });\n },\n async mountTree(tree: MountTreeOptions): Promise<MountedWoodTree> {\n const bridge = createBrowserBridgeFixtureWithTrace(mergeBridge(config.bridge, tree.bridge), config.trace);\n const layouts = (tree.layouts ?? []).map((layout) => ({\n component: resolveFromRoot(rootDir, layout.component),\n props: layout.props,\n }));\n for (const layout of layouts) {\n assertFileExists(layout.component, 'Layout component');\n }\n const view = {\n component: resolveFromRoot(rootDir, tree.view.component),\n props: tree.view.props,\n };\n assertFileExists(view.component, 'View component');\n return await openMountPage({\n runtime,\n entrySource: buildTreeEntrySource({ layouts, view }),\n name: `tree-${path.basename(view.component).replace(/[^a-zA-Z0-9_-]/g, '-')}`,\n css,\n viewport: tree.viewport ?? config.viewport,\n bridge,\n traceRecorder,\n traceContext: {\n windowId: config.trace?.windowId ?? tree.page?.key?.split('.')[0] ?? 'wood-browser-harness',\n routeKey: tree.page?.key,\n harnessId: config.trace?.harnessId,\n },\n context: tree.page?.key\n ? {\n route: {\n key: tree.page.key,\n params: tree.page.params ?? {},\n query: tree.page.query ?? {},\n },\n }\n : {},\n hooks: config.page,\n });\n },\n async destroy(): Promise<void> {\n if (destroyed) {\n return;\n }\n destroyed = true;\n await Promise.all([\n waitForBoundedClose(page.close()),\n waitForBoundedClose(context.close()),\n ]);\n traceRecorder?.disable();\n fs.rmSync(tempDir, { recursive: true, force: true });\n releaseRuntimeOnce();\n },\n };\n}\n\nexport const browser = {\n createHarness,\n};\n\ndeclare global {\n interface Window {\n __WOOD_BROWSER_APP__?: unknown;\n __WOOD_BROWSER_DEFAULT_ROUTE__?: string;\n __WOOD_BROWSER_BRIDGE_MANIFEST__?: RuntimeBridgeManifestEntry[];\n __woodBrowserInvoke?: (channel: string, input: unknown) => Promise<unknown>;\n __woodBrowserEmit?: (channel: string, payload: unknown) => void;\n __woodBrowserTrace?: (payload: unknown) => void;\n }\n}\n"],"mappings":"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","names":["mod","browser","controllerPath"]}
1
+ {"version":3,"sources":["../../src/testing/browser.ts"],"sourcesContent":["import fs from 'node:fs';\nimport os from 'node:os';\nimport { createRequire } from 'node:module';\nimport path from 'node:path';\nimport { pathToFileURL } from 'node:url';\nimport {\n dispatchRendererTracePayload,\n type TraceLevel,\n type TraceRuntimeContext,\n} from '../tracing/index.js';\nimport { TraceRecorder } from '../trace-testing/index.js';\nimport type { WoodRpcTransport } from '../transport/wood_rpc_transport.js';\nimport type { ViewDef } from '../types/views.js';\n\ntype MaybePromise<T> = T | Promise<T>;\ntype BrowserName = 'chromium' | 'firefox' | 'webkit';\ntype OperationHandler = unknown | ((\n input: unknown,\n context: WoodBridgeFixtureContext,\n) => MaybePromise<unknown>);\n\nexport interface WoodViewport {\n width: number;\n height: number;\n deviceScaleFactor?: number;\n}\n\nexport interface WoodBridgeRecordedCall {\n channel: string;\n input: unknown;\n timestamp: string;\n}\n\nexport interface WoodBridgeRecordedEvent {\n channel: string;\n payload: unknown;\n timestamp: string;\n}\n\nexport interface WoodBridgeFixtureContext {\n channel: string;\n calls: WoodBridgeRecordedCall[];\n}\n\nexport interface WoodBridgeFixtureInput {\n operations?: Record<string, OperationHandler>;\n events?: Record<string, unknown | unknown[]>;\n record?: boolean;\n /**\n * Real-backend mode. When supplied, page `invoke` is routed through this\n * `WoodRpcTransport` (dispatching through the REAL WoodRouter — full schema\n * validation) instead of the fixture `operations` Map, and page `bridge.on(...)`\n * subscriptions are relayed to `transport.subscribe(...)` so main-process push\n * events reach page subscribers. Fixture `operations` still act as a fallback\n * for any channel not registered on the transport, so hybrid fixtures work.\n * Omit for the legacy fixture-only bridge (spec §4: labeled visual tests).\n */\n transport?: WoodRpcTransport;\n /**\n * Full RPC manifest to build the page bridge tree from. Required in transport\n * mode so every real channel is exposed on the bridge (in fixture mode the\n * manifest is derived from `operations`). Supply the app's complete operations\n * manifest (channel/controller/action/path/hasInput per operation).\n */\n rpcManifest?: WoodRpcManifestEntryInput[];\n}\n\nexport interface WoodRpcManifestEntryInput {\n channel: string;\n controller: string;\n action: string;\n path: string[];\n hasInput: boolean;\n}\n\nexport interface WoodBrowserPageContext {\n page: any;\n bridge: MountedWoodBridge;\n route?: {\n key: string;\n params: Record<string, string>;\n query: Record<string, string>;\n };\n}\n\nexport interface WoodBrowserHarnessConfig {\n rootDir?: string;\n generatedApp?: string;\n componentDir?: string;\n viewsConfig?: string;\n css?: string[];\n viewport?: WoodViewport;\n bridge?: WoodBridgeFixtureInput;\n page?: {\n beforeMount?: (context: WoodBrowserPageContext) => MaybePromise<void>;\n afterMount?: (context: WoodBrowserPageContext) => MaybePromise<void>;\n };\n browser?: {\n browserName?: BrowserName;\n headless?: boolean;\n };\n trace?: WoodBrowserTraceConfig;\n}\n\nexport interface WoodBrowserTraceConfig {\n enabled?: boolean;\n maxEvents?: number;\n minLevel?: TraceLevel;\n windowId?: string;\n harnessId?: string;\n}\n\nexport interface MountRouteOptions {\n route?: {\n params?: Record<string, string>;\n query?: Record<string, string>;\n };\n bridge?: WoodBridgeFixtureInput;\n viewport?: WoodViewport;\n page?: {\n beforeMount?: (context: WoodBrowserPageContext) => MaybePromise<void>;\n afterMount?: (context: WoodBrowserPageContext) => MaybePromise<void>;\n };\n}\n\nexport interface MountComponentOptions {\n props?: Record<string, unknown>;\n bridge?: WoodBridgeFixtureInput;\n viewport?: WoodViewport;\n page?: {\n beforeMount?: (context: WoodBrowserPageContext) => MaybePromise<void>;\n afterMount?: (context: WoodBrowserPageContext) => MaybePromise<void>;\n };\n}\n\nexport interface MountTreeOptions {\n layouts?: Array<{\n component: string;\n props?: Record<string, unknown>;\n }>;\n view: {\n component: string;\n props?: Record<string, unknown>;\n };\n page?: {\n key?: string;\n params?: Record<string, string>;\n query?: Record<string, string>;\n };\n bridge?: WoodBridgeFixtureInput;\n viewport?: WoodViewport;\n}\n\nexport interface MountedWoodBridge {\n emit(channel: string, payload: unknown): Promise<void>;\n calls(channel?: string): WoodBridgeRecordedCall[];\n events(channel?: string): WoodBridgeRecordedEvent[];\n setOperation(channel: string, handler: OperationHandler): void;\n clearCalls(): void;\n}\n\nexport interface MountedWoodNavigation {\n current(): Promise<{\n page: string;\n params: Record<string, string>;\n query: Record<string, string>;\n } | null>;\n go(\n page: string,\n params?: Record<string, string>,\n query?: Record<string, string>,\n ): Promise<void>;\n replace(\n page: string,\n params?: Record<string, string>,\n query?: Record<string, string>,\n ): Promise<void>;\n}\n\n/** Snapshot of one element's viewport-space box, tagged with its source selector. */\nexport interface WoodRectSnapshot {\n selector: string;\n top: number;\n left: number;\n right: number;\n bottom: number;\n width: number;\n height: number;\n}\n\n/** Axis along which edge-to-edge spacing is measured. */\nexport type WoodSpacingAxis = 'horizontal' | 'vertical';\n\n/**\n * Description of the top-most element painted at a hit-test point, plus its\n * relationship to the queried target. `document.elementFromPoint` honours\n * `pointer-events`, so an element with `pointer-events: none` is transparent to\n * the hit test even when it is painted on top (see `hitTest`/`unoccluded`).\n */\nexport interface WoodHitTestResult {\n /** False when no element is painted at the point (e.g. outside the document). */\n found: boolean;\n tag: string | null;\n id: string | null;\n classes: string[];\n /** The hit element is exactly the target. */\n isTarget: boolean;\n /** The hit element is a descendant of the target (target paints through it). */\n isDescendantOfTarget: boolean;\n /** The hit element is an ancestor of the target. */\n isAncestorOfTarget: boolean;\n point: { x: number; y: number };\n /** Human-readable one-line description of the hit element. */\n description: string;\n}\n\nexport interface WoodBrowserExpect {\n visible(selector: string): Promise<void>;\n hidden(selector: string): Promise<void>;\n insideViewport(selector: string, options?: { margin?: number }): Promise<void>;\n notClipped(selector: string): Promise<void>;\n notOverlapping(firstSelector: string, secondSelector: string): Promise<void>;\n /**\n * @deprecated Compares numeric computed `z-index` only, so it lies whenever\n * stacking contexts, DOM paint order (auto/equal z-index), or\n * transform/opacity contexts decide the real front-to-back order. Prefer\n * `inFrontOf`, which hit-tests the actual painted pixel.\n */\n zIndexAbove(topSelector: string, lowerSelector: string): Promise<void>;\n stableAfterAnimation(selector?: string, options?: {\n timeoutMs?: number;\n frameCount?: number;\n }): Promise<void>;\n screenshot(name: string, options?: {\n fullPage?: boolean;\n mask?: string[];\n threshold?: number;\n }): Promise<void>;\n /** Batch `getBoundingClientRect` reader — one snapshot per selector, in order. */\n rects(selectors: string[]): Promise<WoodRectSnapshot[]>;\n /**\n * Hit-test at a point (default the target's center) and describe the top-most\n * painted element and how it relates to the target.\n */\n hitTest(\n selector: string,\n point?: { x: number; y: number } | 'center',\n ): Promise<WoodHitTestResult>;\n /** Assert two elements share the given edge coordinate within `tolerance` px. */\n sharedEdge(\n a: string,\n b: string,\n edge: 'left' | 'right' | 'top' | 'bottom',\n options?: { tolerance?: number },\n ): Promise<void>;\n /** Assert two elements share a center axis (centerX/centerY) within `tolerance` px. */\n sharedAxis(\n a: string,\n b: string,\n axis: 'centerX' | 'centerY',\n options?: { tolerance?: number },\n ): Promise<void>;\n /**\n * Point-specific \"does a click land here\" check. Asserts the target receives\n * the hit test at `point` (default center): the hit-test element is the target\n * or a descendant of it. Ancestors are accepted only when the target is\n * empty/zero-content at that point and the ancestor is what paints there — but a\n * foreign overlay (not in the target's ancestry) fails. Honours\n * `pointer-events: none`: an overlay so styled does not occlude, because it does\n * not intercept the click.\n *\n * This is NOT the general visibility check — a `pointer-events: none` overlay\n * that visually hides the element still passes here. For \"is any foreign layer\n * painted on top of the element\", prefer `notCovered` (paint-order coverage).\n */\n unoccluded(\n selector: string,\n options?: { point?: { x: number; y: number } | 'center' },\n ): Promise<void>;\n /**\n * Honest front/behind primitive. DEFAULT (recommended): a whole-element\n * paint-order comparison backed by Chromium's real paint tree (CDP\n * `DOMSnapshot.captureSnapshot` with paint order). Passes when `topSelector`\n * has a strictly greater global paint-order index than `lowerSelector` — i.e.\n * it is painted later, so it is on top. This answers \"which layer paints on\n * top\" for the whole element, independent of overlap or `pointer-events`, and\n * is Chromium-only.\n *\n * Opt-in point form `inFrontOf(top, lower, { at })`: hit-tests a single painted\n * pixel (`at` defaults to the center of the two rects' intersection) and passes\n * when the painted element there is the top element (or its descendant) and is\n * NOT the lower element. Use this only for the point-specific question (\"is the\n * top element the one painted AT THIS SPOT\"); it honours `pointer-events` and\n * requires the rects to intersect when no explicit `at` is given.\n *\n * If an element has multiple paint fragments, its maximum paint-order index is\n * used. When the rects do not overlap the paint-order verdict is still valid\n * (paint order is global), but the failure message notes there is no shared\n * pixel where front/behind is visually observable.\n */\n inFrontOf(\n topSelector: string,\n lowerSelector: string,\n options?: { at?: { x: number; y: number } },\n ): Promise<void>;\n /**\n * Whole-element painted-coverage check: assert that NO foreign element paints\n * on top of the target anywhere its rect overlaps. Backed by Chromium's real\n * paint tree (CDP `DOMSnapshot.captureSnapshot` with paint order + computed\n * styles + DOM rects), it is the honest, INSPECTABLE replacement for the old\n * IntersectionObserver-v2 `fullyVisible` matcher, whose `isVisible` field is a\n * black box that silently reports not-visible for any element painted on top —\n * even a fully transparent one (see \"why not IntersectionObserver v2\" in the\n * geometry docs).\n *\n * Algorithm (Chromium-only):\n * 1. Find every laid-out element whose layout rect intersects the target's rect.\n * 2. Exclude the target itself and its ancestors/descendants (they are not\n * foreign coverage — the target paints through its own subtree).\n * 3. Exclude candidates that paint nothing visible in the overlap, per an\n * explicit transparent-wrapper heuristic: computed `opacity: 0` OR\n * `visibility: hidden`, OR (no background-color alpha AND\n * `background-image: none` AND all four border widths `0px` AND no own text\n * or replaced/image content). This is the ONE rule that lets a transparent\n * positioning wrapper spanning the target pass; it is intentionally\n * documented and testable, unlike IOv2's opaque verdict. (`box-shadow`,\n * `outline` and other purely decorative paints are NOT counted as coverage.)\n * 4. Fail if any remaining foreign candidate has a strictly HIGHER max paint\n * order than the target (painted later == on top). The failure names the\n * covering element (tag/id/classes), its rect, and both paint indices.\n *\n * Note this tracks PAINTED coverage, so an opaque `pointer-events: none` overlay\n * DOES fail `notCovered` (it paints pixels on top) while `unoccluded` still\n * passes (it is transparent to hit testing) — the complementary pair of\n * \"painted coverage\" vs \"click reachability\".\n */\n notCovered(selector: string): Promise<void>;\n /**\n * Assert the edge-to-edge gap between two elements along `axis` satisfies a\n * numeric constraint. The order is derived from the rects, not the argument\n * order: the box with the smaller leading edge (left for `'horizontal'`, top\n * for `'vertical'`) is treated as the earlier box and the gap is\n * `later.leading - earlier.trailing` (horizontal: `later.left - earlier.right`;\n * vertical: `later.top - earlier.bottom`).\n *\n * At least one of `equals` / `min` / `max` is required. `equals` passes when\n * `|gap - equals| <= tolerance`; `min`/`max` are inclusive within `tolerance`.\n * A negative gap means the border boxes OVERLAP along the axis; that fails\n * clearly UNLESS the constraint explicitly allows negatives (a negative\n * `equals` or `min`). The failure message states both rects, the computed gap,\n * and the expected constraint.\n *\n * BORDER-BOX CAVEAT: rects are border boxes (`getBoundingClientRect`), so the\n * gap is the distance between the elements' outer borders and EXCLUDES any\n * padding inside either element. To assert visual whitespace between inner\n * content, target the inner content elements instead of their padded wrappers.\n */\n gapBetween(\n a: string,\n b: string,\n axis: WoodSpacingAxis,\n options: { equals?: number; min?: number; max?: number; tolerance?: number },\n ): Promise<void>;\n /**\n * Assert three or more elements are evenly spaced along `axis`. Requires at\n * least 3 selectors; the elements are sorted by their leading edge along the\n * axis, adjacent edge-to-edge gaps are computed, and the assertion passes when\n * `max gap - min gap <= tolerance`. The failure message lists every adjacent\n * gap in sorted order and names the widest and narrowest (offending) pairs.\n *\n * BORDER-BOX CAVEAT: gaps are measured between border boxes\n * (`getBoundingClientRect`), so they exclude padding inside the elements. Tests\n * that care about visual whitespace should target inner content elements.\n */\n evenlySpaced(\n selectors: string[],\n axis: WoodSpacingAxis,\n options?: { tolerance?: number },\n ): Promise<void>;\n}\n\nexport interface MountedWoodSurface {\n page: any;\n bridge: MountedWoodBridge;\n navigation: MountedWoodNavigation;\n expect: WoodBrowserExpect;\n locator(selector: string): any;\n click(selector: string): Promise<void>;\n fill(selector: string, value: string): Promise<void>;\n evaluate<T>(fn: () => T | Promise<T>): Promise<T>;\n destroy(): Promise<void>;\n}\n\nexport interface MountedWoodRoute extends MountedWoodSurface {\n routeKey: string;\n}\n\nexport type MountedWoodComponent = MountedWoodSurface;\nexport type MountedWoodTree = MountedWoodSurface;\n\nexport interface WoodBrowserHarness {\n page: any;\n traceRecorder?: TraceRecorder;\n mountRoute(routeKey: string, options?: MountRouteOptions): Promise<MountedWoodRoute>;\n mountComponent(component: string, options?: MountComponentOptions): Promise<MountedWoodComponent>;\n mountTree(tree: MountTreeOptions): Promise<MountedWoodTree>;\n /**\n * Drain in-flight renderer `__trace` exposeBinding round-trips so the caller's\n * trace-flush barrier (e.g. `TraceCommitWriter.requestRendererFlush`) has a\n * definite quiescent point. Resolves immediately when no page is mounted.\n */\n flushRendererTraces(): Promise<void>;\n destroy(): Promise<void>;\n}\n\ntype BridgeState = {\n operations: Map<string, OperationHandler>;\n initialEvents: WoodBridgeRecordedEvent[];\n calls: WoodBridgeRecordedCall[];\n emittedEvents: WoodBridgeRecordedEvent[];\n record: boolean;\n transport?: WoodRpcTransport;\n rpcManifest?: WoodRpcManifestEntryInput[];\n};\n\ntype RuntimeBridgeManifestEntry = {\n channel: string;\n controller: string;\n action: string;\n path: string[];\n hasInput: boolean;\n};\n\ntype HarnessRuntime = {\n context: any;\n server: any;\n page: any;\n tempDir: string;\n rootDir: string;\n transportCleanups: Array<() => void>;\n};\n\ntype BrowserWorkerRuntime = {\n browser: any;\n server: any;\n cacheDir: string;\n rootDir: string;\n key: string;\n activeHarnesses: number;\n closing: boolean;\n idleCloseTimer: NodeJS.Timeout | null;\n};\n\ntype BrowserWorkerRuntimeEntry = {\n promise: Promise<BrowserWorkerRuntime>;\n};\n\nconst DEFAULT_VIEWPORT: WoodViewport = {\n width: 1280,\n height: 800,\n};\nconst DEFAULT_EXPECT_TIMEOUT_MS = 10_000;\nconst DEFAULT_RESOURCE_CLOSE_TIMEOUT_MS = 5_000;\nconst WORKER_RUNTIME_IDLE_CLOSE_MS = 5_000;\nconst browserWorkerRuntimes = new Map<string, BrowserWorkerRuntimeEntry>();\nconst browserWorkerCacheDirs = new Set<string>();\n\n// Synchronous cleanup on process exit (SIGINT, SIGTERM, etc.) to prevent\n// orphaned temp directories in OS tmpdir.\nprocess.on('exit', () => {\n for (const cacheDir of browserWorkerCacheDirs) {\n try {\n fs.rmSync(cacheDir, { recursive: true, force: true });\n } catch {\n // Best-effort cleanup — ignore errors during exit.\n }\n }\n browserWorkerCacheDirs.clear();\n browserWorkerRuntimes.clear();\n});\n\nfunction normalizeRoot(rootDir: string | undefined): string {\n return path.resolve(rootDir ?? process.cwd());\n}\n\nfunction resolveFromRoot(rootDir: string, filePath: string): string {\n return path.isAbsolute(filePath) ? filePath : path.resolve(rootDir, filePath);\n}\n\nfunction viteImport(filePath: string): string {\n return `/@fs/${filePath.replace(/\\\\/g, '/').replace(/^\\/+/, '')}`;\n}\n\nfunction mergeBridge(\n base: WoodBridgeFixtureInput | undefined,\n override: WoodBridgeFixtureInput | undefined,\n): WoodBridgeFixtureInput {\n return {\n operations: {\n ...(base?.operations ?? {}),\n ...(override?.operations ?? {}),\n },\n events: {\n ...(base?.events ?? {}),\n ...(override?.events ?? {}),\n },\n record: override?.record ?? base?.record,\n ...(override?.transport ?? base?.transport\n ? { transport: override?.transport ?? base?.transport }\n : {}),\n ...(override?.rpcManifest ?? base?.rpcManifest\n ? { rpcManifest: override?.rpcManifest ?? base?.rpcManifest }\n : {}),\n };\n}\n\nasync function waitForBoundedClose(promise: Promise<unknown>, timeoutMs = DEFAULT_RESOURCE_CLOSE_TIMEOUT_MS): Promise<void> {\n let timeout: NodeJS.Timeout | undefined;\n await Promise.race([\n promise.catch(() => undefined),\n new Promise<void>((resolve) => {\n timeout = setTimeout(resolve, timeoutMs);\n }),\n ]);\n if (timeout) {\n clearTimeout(timeout);\n }\n}\n\nfunction channelToManifestEntry(channel: string, handler: OperationHandler): RuntimeBridgeManifestEntry {\n const pathSegments = channel.split('.').filter(Boolean);\n const action = pathSegments.length > 0 ? pathSegments[pathSegments.length - 1] : channel;\n const controller = pathSegments.length > 1 ? pathSegments[0] : channel;\n\n return {\n channel,\n controller,\n action,\n path: pathSegments,\n hasInput: typeof handler === 'function',\n };\n}\n\nfunction createBridgeState(input: WoodBridgeFixtureInput | undefined): BridgeState {\n const initialEvents = Object.entries(input?.events ?? {}).flatMap(([channel, payloadOrList]) => {\n const payloads = Array.isArray(payloadOrList) ? payloadOrList : [payloadOrList];\n return payloads.map((payload) => ({\n channel,\n payload,\n timestamp: new Date().toISOString(),\n }));\n });\n\n return {\n operations: new Map(Object.entries(input?.operations ?? {})),\n initialEvents,\n calls: [],\n emittedEvents: [],\n record: input?.record ?? true,\n ...(input?.transport ? { transport: input.transport } : {}),\n ...(input?.rpcManifest ? { rpcManifest: input.rpcManifest } : {}),\n };\n}\n\nexport function createBrowserBridgeFixture(input: WoodBridgeFixtureInput | undefined): {\n state: BridgeState;\n manifest: RuntimeBridgeManifestEntry[];\n bridgeInit: string;\n} {\n return createBrowserBridgeFixtureWithTrace(input, undefined);\n}\n\nfunction createBrowserBridgeFixtureWithTrace(\n input: WoodBridgeFixtureInput | undefined,\n traceConfig: WoodBrowserTraceConfig | undefined,\n): {\n state: BridgeState;\n manifest: RuntimeBridgeManifestEntry[];\n bridgeInit: string;\n} {\n const state = createBridgeState(input);\n const manifest = state.rpcManifest\n ?? Array.from(state.operations.entries())\n .map(([channel, handler]) => channelToManifestEntry(channel, handler));\n\n return {\n state,\n manifest,\n bridgeInit: buildBridgeInitScript(manifest, traceConfig, Boolean(state.transport)),\n };\n}\n\nfunction buildBridgeInitScript(\n manifest: RuntimeBridgeManifestEntry[],\n traceConfig: WoodBrowserTraceConfig | undefined,\n transportMode: boolean,\n): string {\n const traceEnabled = traceConfig?.enabled === true;\n const traceMinLevel = traceConfig?.minLevel ?? 'debug';\n return `\n(() => {\n const manifest = ${JSON.stringify(manifest)};\n const transportMode = ${JSON.stringify(transportMode)};\n const listeners = new Map();\n window.__woodBrowserTracePending = new Set();\n window.__woodBrowserTraceFlush = async () => {\n // Drain in-flight __trace exposeBinding round-trips so the test-process\n // renderer-trace ack loop can barrier on a definite quiescent point.\n while (window.__woodBrowserTracePending.size > 0) {\n await Promise.allSettled(Array.from(window.__woodBrowserTracePending));\n }\n };\n const bridge = {\n __rpcManifest: manifest,\n __woodConfig: async () => ({\n rendererTraceEnabled: ${JSON.stringify(traceEnabled)},\n rendererTraceMinLevel: ${JSON.stringify(traceMinLevel)}\n }),\n __log: () => {},\n __trace: (payload) => {\n const result = window.__woodBrowserTrace?.(payload);\n if (result && typeof result.then === 'function') {\n window.__woodBrowserTracePending.add(result);\n result.finally(() => window.__woodBrowserTracePending.delete(result));\n }\n return result;\n },\n __window: {\n current: async () => ({ ok: true, windowId: 'wood-browser-harness', defaultRoute: window.__WOOD_BROWSER_DEFAULT_ROUTE__ }),\n open: async () => ({}),\n close: async () => ({}),\n focus: async () => ({}),\n minimize: async () => ({}),\n maximize: async () => ({}),\n },\n on(channel, callback) {\n const first = !listeners.has(channel);\n if (first) listeners.set(channel, new Set());\n listeners.get(channel).add(callback);\n // In real-backend mode, relay the first subscription per channel to the\n // test process so it can subscribe on the WoodRpcTransport and forward\n // main-process push events back into __woodBrowserEmit.\n if (transportMode && first) window.__woodBrowserSubscribe?.(channel);\n return () => listeners.get(channel)?.delete(callback);\n },\n };\n\n for (const entry of manifest) {\n let current = bridge;\n for (let i = 0; i < entry.path.length - 1; i += 1) {\n const segment = entry.path[i];\n current[segment] ??= {};\n current = current[segment];\n }\n const leaf = entry.path[entry.path.length - 1];\n current[leaf] = async (data) => window.__woodBrowserInvoke(entry.channel, data);\n }\n\n window.__woodBrowserEmit = (channel, payload) => {\n const handlers = listeners.get(channel);\n if (!handlers) return;\n for (const handler of handlers) handler(payload);\n };\n window.__NOEGO_WOOD_BRIDGE__ = bridge;\n window.wood = bridge;\n globalThis.__NOEGO_WOOD_BRIDGE__ = bridge;\n globalThis.wood = bridge;\n})();\n`;\n}\n\nasync function loadPlaywright(browserName: BrowserName): Promise<any> {\n const playwright = await import('playwright');\n return playwright[browserName];\n}\n\nasync function loadVite(): Promise<any> {\n return await import('vite');\n}\n\nfunction createPackageRequire(rootDir: string): NodeJS.Require {\n return createRequire(path.join(rootDir, 'package.json'));\n}\n\nfunction resolvePackageModule(rootDir: string, source: string): string | null {\n const rootRequire = createPackageRequire(rootDir);\n const processRequire = createRequire(path.join(process.cwd(), 'package.json'));\n try {\n return rootRequire.resolve(source);\n } catch {\n try {\n return processRequire.resolve(source);\n } catch {\n return null;\n }\n }\n}\n\n/**\n * Resolve a package subpath to a Vite-servable `/@fs` ESM URL. `require.resolve`\n * yields the CJS build (`.cjs`), which has no named exports under Vite's ESM\n * interop; prefer the sibling `.js`. Falls back to the bare specifier when the\n * module cannot be resolved on disk (Vite resolves it from the root instead).\n */\nfunction resolveEsmModule(rootDir: string, source: string): string {\n const resolved = resolvePackageModule(rootDir, source);\n const esm = resolved?.endsWith('.cjs') ? resolved.replace(/\\.cjs$/, '.js') : resolved;\n return esm && fs.existsSync(esm) ? viteImport(esm) : source;\n}\n\nfunction resolvePackageDir(rootDir: string, packageName: string): string | null {\n const packageJson = resolvePackageModule(rootDir, `${packageName}/package.json`);\n return packageJson ? path.dirname(packageJson) : null;\n}\n\nfunction createWoodBrowserResolver(rootDir: string): any {\n const sveltePackageDir = resolvePackageDir(rootDir, 'svelte');\n const svelteClientEntry = sveltePackageDir\n ? path.join(sveltePackageDir, 'src', 'index-client.js')\n : null;\n const svelteLegacyClientEntry = sveltePackageDir\n ? path.join(sveltePackageDir, 'src', 'legacy', 'legacy-client.js')\n : null;\n const svelteReactivityClientEntry = sveltePackageDir\n ? path.join(sveltePackageDir, 'src', 'reactivity', 'index-client.js')\n : null;\n\n return {\n name: 'wood-browser-resolver',\n enforce: 'pre',\n resolveId(source: string): string | null {\n if (source === 'svelte') {\n return svelteClientEntry;\n }\n if (source === 'svelte/legacy') {\n return svelteLegacyClientEntry;\n }\n if (source === 'svelte/reactivity') {\n return svelteReactivityClientEntry;\n }\n if (source.startsWith('svelte/')) {\n return resolvePackageModule(rootDir, source);\n }\n return null;\n },\n };\n}\n\nasync function loadSveltePlugin(rootDir: string): Promise<any | null> {\n try {\n const rootPluginPath = path.join(\n rootDir,\n 'node_modules',\n '@sveltejs',\n 'vite-plugin-svelte',\n 'src',\n 'index.js',\n );\n if (fs.existsSync(rootPluginPath)) {\n const mod = await import(pathToFileURL(rootPluginPath).href);\n return mod.svelte;\n }\n const rootRequire = createRequire(path.join(rootDir, 'package.json'));\n const mod = await import(pathToFileURL(rootRequire.resolve('@sveltejs/vite-plugin-svelte')).href);\n return mod.svelte;\n } catch {\n try {\n const mod = await import('@sveltejs/vite-plugin-svelte');\n return mod.svelte;\n } catch {\n return null;\n }\n }\n}\n\nasync function loadViews(viewsPath: string): Promise<ViewDef[]> {\n const parser = await import('../parser/views_parser.js');\n return parser.parseViewsFile(viewsPath);\n}\n\nasync function createViteServer(rootDir: string, cacheDir: string): Promise<any> {\n const vite = await loadVite();\n const svelte = await loadSveltePlugin(rootDir);\n const plugins = [\n createWoodBrowserResolver(rootDir),\n ...(svelte ? [svelte()] : []),\n ];\n const server = await vite.createServer({\n root: rootDir,\n cacheDir,\n logLevel: process.env.WOOD_BROWSER_TEST_DEBUG ? 'info' : 'silent',\n plugins,\n resolve: {\n dedupe: ['svelte'],\n },\n server: { port: 0, fs: { allow: [rootDir, os.tmpdir()] } },\n });\n await server.listen();\n return server;\n}\n\nfunction workerRuntimeKey(input: {\n rootDir: string;\n browserName: BrowserName;\n headless: boolean;\n}): string {\n return [\n input.rootDir,\n input.browserName,\n input.headless ? 'headless' : 'headed',\n ].join('::');\n}\n\nasync function createBrowserWorkerRuntime(input: {\n rootDir: string;\n browserName: BrowserName;\n headless: boolean;\n key: string;\n}): Promise<BrowserWorkerRuntime> {\n const cacheRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'wood-browser-vite-'));\n browserWorkerCacheDirs.add(cacheRoot);\n let browser: any | null = null;\n try {\n const playwrightBrowser = await loadPlaywright(input.browserName);\n browser = await playwrightBrowser.launch({ headless: input.headless });\n const server = await createViteServer(input.rootDir, path.join(cacheRoot, '.vite'));\n return {\n browser,\n server,\n cacheDir: cacheRoot,\n rootDir: input.rootDir,\n key: input.key,\n activeHarnesses: 0,\n closing: false,\n idleCloseTimer: null,\n };\n } catch (error) {\n await browser?.close().catch(() => undefined);\n fs.rmSync(cacheRoot, { recursive: true, force: true });\n browserWorkerCacheDirs.delete(cacheRoot);\n throw error;\n }\n}\n\nasync function acquireBrowserWorkerRuntime(input: {\n rootDir: string;\n browserName: BrowserName;\n headless: boolean;\n}): Promise<BrowserWorkerRuntime> {\n const key = workerRuntimeKey(input);\n let entry = browserWorkerRuntimes.get(key);\n if (!entry) {\n entry = {\n promise: createBrowserWorkerRuntime({ ...input, key }),\n };\n browserWorkerRuntimes.set(key, entry);\n }\n\n const runtime = await entry.promise;\n if (runtime.closing) {\n browserWorkerRuntimes.delete(key);\n return await acquireBrowserWorkerRuntime(input);\n }\n if (runtime.idleCloseTimer) {\n clearTimeout(runtime.idleCloseTimer);\n runtime.idleCloseTimer = null;\n }\n runtime.activeHarnesses += 1;\n return runtime;\n}\n\nasync function closeBrowserWorkerRuntime(runtime: BrowserWorkerRuntime): Promise<void> {\n if (runtime.closing) {\n return;\n }\n runtime.closing = true;\n try {\n await Promise.all([\n waitForBoundedClose(runtime.server.close()),\n waitForBoundedClose(runtime.browser.close()),\n ]);\n } finally {\n fs.rmSync(runtime.cacheDir, { recursive: true, force: true });\n browserWorkerCacheDirs.delete(runtime.cacheDir);\n const entry = browserWorkerRuntimes.get(runtime.key);\n const current = entry ? await entry.promise.catch(() => null) : null;\n if (current === runtime) {\n browserWorkerRuntimes.delete(runtime.key);\n }\n }\n}\n\nfunction scheduleBrowserWorkerRuntimeClose(runtime: BrowserWorkerRuntime): void {\n if (runtime.closing || runtime.activeHarnesses > 0 || runtime.idleCloseTimer) {\n return;\n }\n runtime.idleCloseTimer = setTimeout(() => {\n runtime.idleCloseTimer = null;\n if (runtime.activeHarnesses === 0) {\n void closeBrowserWorkerRuntime(runtime);\n }\n }, WORKER_RUNTIME_IDLE_CLOSE_MS);\n runtime.idleCloseTimer.unref?.();\n}\n\nfunction releaseBrowserWorkerRuntime(runtime: BrowserWorkerRuntime): void {\n runtime.activeHarnesses = Math.max(0, runtime.activeHarnesses - 1);\n scheduleBrowserWorkerRuntimeClose(runtime);\n}\n\nfunction serverBaseUrl(server: any): string {\n return server.resolvedUrls?.local?.[0] ?? 'http://127.0.0.1:5173';\n}\n\nfunction assertFileExists(filePath: string, label: string): void {\n if (!fs.existsSync(filePath)) {\n throw new Error(`${label} does not exist: ${filePath}`);\n }\n}\n\nfunction writeEntry(tempDir: string, name: string, source: string): string {\n fs.mkdirSync(tempDir, { recursive: true });\n const entryPath = path.join(tempDir, `${name}.ts`);\n fs.writeFileSync(entryPath, source);\n return entryPath;\n}\n\nfunction writeHtml(tempDir: string, name: string, entryPath: string, cssFiles: string[]): string {\n const styles = cssFiles\n .map((cssPath) => `<link rel=\"stylesheet\" href=\"${viteImport(cssPath)}\" />`)\n .join('\\n');\n const htmlPath = path.join(tempDir, `${name}.html`);\n fs.writeFileSync(htmlPath, `<!doctype html>\n<html>\n <head>\n <meta charset=\"utf-8\" />\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n ${styles}\n </head>\n <body>\n <div id=\"app\"></div>\n <script type=\"module\" src=\"${viteImport(entryPath)}\"></script>\n </body>\n</html>\n`);\n return htmlPath;\n}\n\nfunction viewKey(view: ViewDef): string {\n return `${view.windowName}.${view.pageName}`;\n}\n\nfunction findView(views: ViewDef[], routeKey: string): ViewDef {\n const found = views.find((view) => viewKey(view) === routeKey);\n if (!found) {\n throw new Error(\n `Unknown Wood route \"${routeKey}\". Available routes: ${views.map(viewKey).join(', ')}`,\n );\n }\n return found;\n}\n\nfunction resolveComponentPath(rootDir: string, componentDir: string | undefined, filePath: string): string {\n if (path.isAbsolute(filePath)) return filePath;\n const base = componentDir ? resolveFromRoot(rootDir, componentDir) : rootDir;\n const componentDirName = componentDir ? path.basename(componentDir) : '';\n if (componentDirName && filePath.replace(/\\\\/g, '/').startsWith(`${componentDirName}/`)) {\n return path.resolve(base, filePath.slice(componentDirName.length + 1));\n }\n return path.resolve(base, filePath);\n}\n\nfunction buildRouteEntrySource(input: {\n routeKey: string;\n view: ViewDef;\n rootDir: string;\n componentDir?: string;\n route: {\n params: Record<string, string>;\n query: Record<string, string>;\n };\n}): string {\n const { view, rootDir, componentDir, routeKey, route } = input;\n const viewPath = resolveComponentPath(rootDir, componentDir, view.viewPath);\n const layoutPaths = view.layouts.map((layout) => resolveComponentPath(rootDir, componentDir, layout));\n const controllerPath = view.controller\n ? resolveComponentPath(rootDir, componentDir, view.controller)\n : null;\n const layoutControllerPaths = view.layoutControllers?.map((controller) =>\n controller ? resolveComponentPath(rootDir, componentDir, controller) : null,\n ) ?? [];\n\n const imports = [\n `import { mount } from 'svelte';`,\n `import NavigationShell from '@noego/wood/navigation-shell';`,\n `import { getContainer } from '@noego/wood/client';`,\n `import { getNavigation } from '@noego/wood/navigation';`,\n `import ViewComponent from '${viteImport(viewPath)}';`,\n ...layoutPaths.map((layoutPath, index) => `import Layout${index} from '${viteImport(layoutPath)}';`),\n ...(controllerPath ? [`import PageController from '${viteImport(controllerPath)}';`] : []),\n ...layoutControllerPaths.map((controllerPath, index) =>\n controllerPath ? `import LayoutController${index} from '${viteImport(controllerPath)}';` : '',\n ).filter(Boolean),\n ];\n\n const layoutControllerClasses = layoutControllerPaths.map((controllerPath, index) =>\n controllerPath ? `LayoutController${index}` : 'undefined',\n );\n\n return `${imports.join('\\n')}\n\nconst entry = {\n key: ${JSON.stringify(routeKey)},\n windowName: ${JSON.stringify(view.windowName)},\n pageName: ${JSON.stringify(view.pageName)},\n viewPath: ${JSON.stringify(view.viewPath)},\n layoutPaths: ${JSON.stringify(view.layouts)},\n layoutControllers: ${JSON.stringify(view.layoutControllers ?? [])},\n controller: ${JSON.stringify(view.controller)},\n layoutControllerClasses: [${layoutControllerClasses.join(', ')}],\n controllerClass: ${controllerPath ? 'PageController' : 'undefined'},\n view: ViewComponent,\n layouts: [${layoutPaths.map((_, index) => `Layout${index}`).join(', ')}],\n};\n\nfunction createScopedContainer() {\n const root = getContainer();\n const scope = root.extend();\n return scope;\n}\n\nasync function resolveController(ControllerClass) {\n if (!ControllerClass) return undefined;\n const scope = createScopedContainer();\n scope.registerClass?.(ControllerClass);\n return await scope.get(ControllerClass);\n}\n\nasync function createViewController(nextEntry) {\n return await resolveController(nextEntry.controllerClass);\n}\n\nasync function createLayoutControllers(nextEntry) {\n const controllers = [];\n for (const ControllerClass of nextEntry.layoutControllerClasses) {\n controllers.push(await resolveController(ControllerClass));\n }\n return controllers;\n}\n\nfunction getViewManifestEntry(nextKey) {\n return nextKey === entry.key ? entry : null;\n}\n\nconst navigation = getNavigation();\nnavigation.replace(entry.key, ${JSON.stringify(route.params)}, ${JSON.stringify(route.query)});\n\nconst controller = await createViewController(entry);\nconst layoutControllers = await createLayoutControllers(entry);\n\nwindow.__WOOD_BROWSER_APP__ = mount(NavigationShell, {\n target: document.getElementById('app'),\n props: {\n manifest: { [entry.key]: entry },\n initialEntry: entry,\n initialController: controller,\n initialLayoutControllers: layoutControllers,\n createViewControllerFn: createViewController,\n createLayoutControllersFn: createLayoutControllers,\n getViewManifestEntryFn: getViewManifestEntry,\n },\n});\n`;\n}\n\nfunction buildGeneratedAppEntrySource(input: {\n generatedApp: string;\n routeKey: string;\n navigationModule: string;\n clientModule: string;\n enableRendererTrace: boolean;\n traceMinLevel: string;\n route: {\n params: Record<string, string>;\n query: Record<string, string>;\n };\n}): string {\n const hasRouteContext =\n Object.keys(input.route.params).length > 0 || Object.keys(input.route.query).length > 0;\n // Enable renderer tracing in the page. The generated `app()` bootstrap does not\n // run wood's `getApp` `__woodConfig` step, so the renderer TraceProvider stays\n // disabled by default; enabling it here makes `RendererTracer.emitRendererTrace`\n // route renderer-origin traces through `bridge.__trace` -> the test process ->\n // `dispatchRendererTracePayload` -> the global hub sink -> the test trace DB.\n const rendererTraceEnable = input.enableRendererTrace\n ? `try {\n const traceConfiguration = await getContainer().instance(TraceProviderConfiguration);\n traceConfiguration.configureRuntime('renderer');\n traceConfiguration.configureMinLevel(${JSON.stringify(input.traceMinLevel)});\n traceConfiguration.configureEnabled(true);\n} catch (error) { /* best-effort renderer-trace enable */ }`\n : '';\n // Applying route params/query in the ENTRY MODULE (Vite-transformed) drives the\n // real client `getNavigation()` singleton the app already imports, so the\n // production watchNavigation -> route-context path runs. A page.evaluate cannot\n // do this: a raw browser context cannot resolve the bare `@noego/wood/navigation`\n // specifier, only a Vite-served module can. The navigation module is imported by\n // its resolved `/@fs` path because this entry lives outside the Vite root, where\n // bare-specifier resolution is unreliable.\n const navigationApply = hasRouteContext\n ? `getNavigation().replace(${JSON.stringify(input.routeKey)}, ${JSON.stringify(input.route.params)}, ${JSON.stringify(input.route.query)});`\n : '';\n return `import { app } from '${viteImport(input.generatedApp)}';\nimport { getNavigation } from '${input.navigationModule}';\nimport { getContainer, TraceProviderConfiguration } from '${input.clientModule}';\nwindow.__WOOD_BROWSER_DEFAULT_ROUTE__ = ${JSON.stringify(input.routeKey)};\nwindow.__WOOD_BROWSER_APP__ = await app(document.getElementById('app'));\nwindow.__WOOD_BROWSER_NAV__ = getNavigation();\n${rendererTraceEnable}\n${navigationApply}\n`;\n}\n\nfunction buildComponentEntrySource(input: {\n componentPath: string;\n props: Record<string, unknown>;\n}): string {\n return `import { mount } from 'svelte';\nimport Component from '${viteImport(input.componentPath)}';\nwindow.__WOOD_BROWSER_APP__ = mount(Component, {\n target: document.getElementById('app'),\n props: ${JSON.stringify(input.props)},\n});\n`;\n}\n\nfunction buildTreeEntrySource(input: {\n layouts: Array<{ component: string; props?: Record<string, unknown> }>;\n view: { component: string; props?: Record<string, unknown> };\n}): string {\n const imports = [\n `import { mount } from 'svelte';`,\n `import WoodRecursiveRender from '@noego/wood/recursive-render';`,\n `import ViewComponent from '${viteImport(input.view.component)}';`,\n ...input.layouts.map((layout, index) => `import Layout${index} from '${viteImport(layout.component)}';`),\n ];\n const layoutControllers = input.layouts.map((layout) => ({\n data: layout.props?.data,\n input: layout.props?.input,\n events: layout.props?.events,\n }));\n const viewController = {\n data: input.view.props?.data,\n input: input.view.props?.input,\n events: input.view.props?.events,\n };\n\n return `${imports.join('\\n')}\nwindow.__WOOD_BROWSER_APP__ = mount(WoodRecursiveRender, {\n target: document.getElementById('app'),\n props: {\n layouts: [${input.layouts.map((_, index) => `Layout${index}`).join(', ')}],\n layoutControllers: ${JSON.stringify(layoutControllers)},\n view: ViewComponent,\n controller: ${JSON.stringify(viewController)},\n },\n});\n`;\n}\n\nasync function installBridge(\n page: any,\n bridgeState: BridgeState,\n manifest: RuntimeBridgeManifestEntry[],\n bridgeInit: string,\n transportCleanups: Array<() => void>,\n): Promise<void> {\n await page.exposeBinding('__woodBrowserInvoke', async (_source: unknown, channel: string, input: unknown) => {\n const call = {\n channel,\n input,\n timestamp: new Date().toISOString(),\n };\n if (bridgeState.record) {\n bridgeState.calls.push(call);\n }\n if (bridgeState.transport && !bridgeState.operations.has(channel)) {\n // Real-backend mode: dispatch through the WoodRouter (full schema\n // validation). Fixture operations, when present, override per channel.\n return await bridgeState.transport.invoke(channel, input);\n }\n const handler = bridgeState.operations.get(channel);\n if (typeof handler === 'function') {\n return await handler(input, { channel, calls: bridgeState.calls });\n }\n return handler;\n });\n await installTransportEventForwarding(page, bridgeState, transportCleanups);\n await page.addInitScript(bridgeInit);\n await page.addInitScript((entries: RuntimeBridgeManifestEntry[]) => {\n window.__WOOD_BROWSER_BRIDGE_MANIFEST__ = entries;\n }, manifest);\n}\n\n/**\n * Relay page `bridge.on(channel)` subscriptions to `transport.subscribe(channel)`\n * and forward each main-process push event back into the page's\n * `__woodBrowserEmit`. Subscribing once per channel keeps the transport's\n * listener set minimal; unsubscribers are cleaned up on harness destroy.\n */\nasync function installTransportEventForwarding(\n page: any,\n bridgeState: BridgeState,\n transportCleanups: Array<() => void>,\n): Promise<void> {\n const transport = bridgeState.transport;\n if (!transport) return;\n const subscribed = new Set<string>();\n await page.exposeBinding('__woodBrowserSubscribe', (_source: unknown, channel: string) => {\n if (subscribed.has(channel)) return;\n subscribed.add(channel);\n const unsubscribe = transport.subscribe(channel, (payload: unknown) => {\n void page\n .evaluate(\n ({ eventChannel, eventPayload }: { eventChannel: string; eventPayload: unknown }) => {\n window.__woodBrowserEmit?.(eventChannel, eventPayload);\n },\n { eventChannel: channel, eventPayload: payload },\n )\n .catch(() => undefined);\n });\n transportCleanups.push(unsubscribe);\n });\n}\n\nasync function installTraceBinding(\n page: any,\n traceRecorder: TraceRecorder | undefined,\n context: TraceRuntimeContext,\n): Promise<void> {\n if (!traceRecorder) {\n return;\n }\n await page.exposeBinding('__woodBrowserTrace', async (_source: unknown, payload: unknown) => {\n dispatchRendererTracePayload(payload, context);\n });\n}\n\nfunction createMountedBridge(page: any, state: BridgeState): MountedWoodBridge {\n return {\n async emit(channel: string, payload: unknown): Promise<void> {\n state.emittedEvents.push({\n channel,\n payload,\n timestamp: new Date().toISOString(),\n });\n await page.evaluate(({ eventChannel, eventPayload }: { eventChannel: string; eventPayload: unknown }) => {\n window.__woodBrowserEmit?.(eventChannel, eventPayload);\n }, { eventChannel: channel, eventPayload: payload });\n },\n calls(channel?: string): WoodBridgeRecordedCall[] {\n return channel ? state.calls.filter((call) => call.channel === channel) : [...state.calls];\n },\n events(channel?: string): WoodBridgeRecordedEvent[] {\n return channel\n ? state.emittedEvents.filter((event) => event.channel === channel)\n : [...state.emittedEvents];\n },\n setOperation(channel: string, handler: OperationHandler): void {\n state.operations.set(channel, handler);\n },\n clearCalls(): void {\n state.calls.length = 0;\n },\n };\n}\n\nfunction createMountedNavigation(page: any): MountedWoodNavigation {\n return {\n async current() {\n return await page.evaluate(async () => {\n const specifier = '@noego/wood/navigation';\n const mod = await import(/* @vite-ignore */ specifier);\n return mod.getNavigation().getCurrent();\n });\n },\n async go(routePage, params = {}, query = {}) {\n await page.evaluate(async (payload: {\n routePage: string;\n params: Record<string, string>;\n query: Record<string, string>;\n }) => {\n const { routePage: nextPage, params: nextParams, query: nextQuery } = payload;\n const specifier = '@noego/wood/navigation';\n const mod = await import(/* @vite-ignore */ specifier);\n mod.getNavigation().go(nextPage, nextParams, nextQuery);\n }, { routePage, params, query });\n },\n async replace(routePage, params = {}, query = {}) {\n await page.evaluate(async (payload: {\n routePage: string;\n params: Record<string, string>;\n query: Record<string, string>;\n }) => {\n const { routePage: nextPage, params: nextParams, query: nextQuery } = payload;\n const specifier = '@noego/wood/navigation';\n const mod = await import(/* @vite-ignore */ specifier);\n mod.getNavigation().replace(nextPage, nextParams, nextQuery);\n }, { routePage, params, query });\n },\n };\n}\n\nasync function elementRect(page: any, selector: string): Promise<{\n top: number;\n left: number;\n right: number;\n bottom: number;\n width: number;\n height: number;\n} | null> {\n return await page.locator(selector).evaluate((element: Element) => {\n const rect = element.getBoundingClientRect();\n return {\n top: rect.top,\n left: rect.left,\n right: rect.right,\n bottom: rect.bottom,\n width: rect.width,\n height: rect.height,\n };\n }).catch(() => null);\n}\n\ntype RectBox = {\n top: number;\n left: number;\n right: number;\n bottom: number;\n width: number;\n height: number;\n};\n\n/** Read the first match's box, or null when the selector resolves to nothing. */\nasync function firstRect(page: any, selector: string): Promise<RectBox | null> {\n return await page.locator(selector).first().evaluate((element: Element) => {\n const rect = element.getBoundingClientRect();\n return {\n top: rect.top,\n left: rect.left,\n right: rect.right,\n bottom: rect.bottom,\n width: rect.width,\n height: rect.height,\n };\n }).catch(() => null);\n}\n\nfunction describeHitElement(hit: {\n tag: string | null;\n id: string | null;\n classes: string[];\n}): string {\n if (!hit.tag) return '<no element at point>';\n const id = hit.id ? `#${hit.id}` : '';\n const classes = hit.classes.length > 0 ? `.${hit.classes.join('.')}` : '';\n return `<${hit.tag.toLowerCase()}${id}${classes}>`;\n}\n\ntype PaintOrderResult = { paintOrder: number | null; found: boolean };\n\n/**\n * Read the global paint-order index of each selector's first match from\n * Chromium's real paint tree via CDP `DOMSnapshot.captureSnapshot`.\n *\n * Higher paint-order index == painted later == on top (verified empirically\n * against the stacking-context trap: the root-context sibling that visually\n * paints over a `z-index:9999` descendant of a `z-index:1` parent carries the\n * HIGHER index, agreeing with the pixel hit test).\n *\n * Mapping: `DOM.querySelector` + `DOM.describeNode` give each target's\n * `backendNodeId`; the snapshot's `nodes.backendNodeId[nodeIndex]` correlates a\n * layout entry back to that DOM node, and `layout.paintOrders[i]` is its paint\n * index. Elements with multiple paint fragments collapse to their max index.\n * Chromium-only (throws when no CDP session is available).\n */\nasync function capturePaintOrders(\n page: any,\n selectors: string[],\n): Promise<Map<string, PaintOrderResult>> {\n const context = page.context?.();\n if (!context || typeof context.newCDPSession !== 'function') {\n throw new Error(\n 'inFrontOf paint-order comparison requires a Chromium CDP session '\n + '(page.context().newCDPSession). It is Chromium-only; pass { at } to use '\n + 'the point hit-test form on other browsers.',\n );\n }\n const cdp = await context.newCDPSession(page);\n try {\n await cdp.send('DOM.enable');\n const { root } = await cdp.send('DOM.getDocument', { depth: -1 });\n const backendIds = new Map<string, number | null>();\n for (const selector of selectors) {\n let backendNodeId: number | null = null;\n try {\n const { nodeId } = await cdp.send('DOM.querySelector', { nodeId: root.nodeId, selector });\n if (nodeId) {\n const described = await cdp.send('DOM.describeNode', { nodeId });\n backendNodeId = described.node?.backendNodeId ?? null;\n }\n } catch {\n backendNodeId = null;\n }\n backendIds.set(selector, backendNodeId);\n }\n const snapshot = await cdp.send('DOMSnapshot.captureSnapshot', {\n computedStyles: [],\n includePaintOrder: true,\n includeDOMRects: false,\n });\n const paintByBackend = collectMaxPaintOrders(snapshot);\n const result = new Map<string, PaintOrderResult>();\n for (const selector of selectors) {\n const backendId = backendIds.get(selector) ?? null;\n const paint = backendId == null ? undefined : paintByBackend.get(backendId);\n result.set(selector, { paintOrder: paint ?? null, found: paint !== undefined });\n }\n return result;\n } finally {\n await cdp.detach().catch(() => undefined);\n }\n}\n\n/** Collapse every document's layout paint orders to a max-per-backendNodeId map. */\nfunction collectMaxPaintOrders(snapshot: any): Map<number, number> {\n const paintByBackend = new Map<number, number>();\n for (const doc of snapshot.documents ?? []) {\n const backendOfNode: number[] = doc.nodes?.backendNodeId ?? [];\n const nodeIndex: number[] = doc.layout?.nodeIndex ?? [];\n const paintOrders: number[] = doc.layout?.paintOrders ?? [];\n for (let i = 0; i < nodeIndex.length; i += 1) {\n const paint = paintOrders[i];\n const backendId = backendOfNode[nodeIndex[i]];\n if (paint === undefined || backendId === undefined) continue;\n const prev = paintByBackend.get(backendId);\n if (prev === undefined || paint > prev) paintByBackend.set(backendId, paint);\n }\n }\n return paintByBackend;\n}\n\n/** Leading/trailing edge coordinates of a box along a spacing axis. */\nfunction axisEdges(rect: RectBox, axis: WoodSpacingAxis): { 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 along `axis`. The box with the\n * smaller leading edge is the earlier box; the gap is `later.leading -\n * earlier.trailing`. A negative result means the boxes overlap along the axis.\n */\nfunction axisGap(first: RectBox, second: RectBox, axis: WoodSpacingAxis): 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\ntype GapConstraint = { equals?: number; min?: number; max?: number };\n\n/** Human-readable summary of a gap constraint, e.g. `equals 50, max 60`. */\nfunction describeGapConstraint(constraint: GapConstraint): string {\n const parts: string[] = [];\n if (constraint.equals !== undefined) parts.push(`equals ${constraint.equals}`);\n if (constraint.min !== undefined) parts.push(`min ${constraint.min}`);\n if (constraint.max !== undefined) parts.push(`max ${constraint.max}`);\n return parts.join(', ');\n}\n\n/** The specific clause a gap violates, or null when it satisfies the constraint. */\nfunction gapConstraintViolation(gap: number, constraint: GapConstraint, tolerance: number): string | null {\n if (constraint.equals !== undefined && Math.abs(gap - constraint.equals) > tolerance) {\n return `expected gap to equal ${constraint.equals} (±${tolerance})`;\n }\n if (constraint.min !== undefined && gap < constraint.min - tolerance) {\n return `expected gap >= ${constraint.min}`;\n }\n if (constraint.max !== undefined && gap > constraint.max + tolerance) {\n return `expected gap <= ${constraint.max}`;\n }\n return null;\n}\n\nfunction rectsOverlap(a: RectBox | null, b: RectBox | null): 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/** Snapshot layout box in document space: [x, y, width, height]. */\ntype SnapshotRect = { x: number; y: number; w: number; h: number };\n\n/** One covering candidate found by `captureCoverage`. */\ntype CoverageCandidate = { description: string; paint: number; rect: SnapshotRect };\n\n/** Result of the paint-order coverage analysis backing `notCovered`. */\ntype CoverageResult = { targetPaint: number; targetRect: SnapshotRect; covers: CoverageCandidate[] };\n\n/**\n * Computed-style keys requested in the coverage snapshot. Order matters: it maps\n * 1:1 onto `layout.styles[k]` string indices.\n */\nconst COVERAGE_STYLE_KEYS = [\n 'opacity',\n 'visibility',\n 'background-color',\n 'background-image',\n 'border-top-width',\n 'border-right-width',\n 'border-bottom-width',\n 'border-left-width',\n] as const;\n\n/** True when a CSS color string resolves to a fully transparent alpha channel. */\nfunction colorAlphaIsZero(color: string): boolean {\n if (color === 'transparent') return true;\n const match = color.match(/^rgba?\\(([^)]*)\\)/);\n if (!match) return false;\n const parts = match[1].split(',').map((s) => s.trim());\n return parts.length >= 4 && parseFloat(parts[3]) === 0;\n}\n\n/** Two `[x,y,w,h]` snapshot rects overlap on both axes. */\nfunction snapshotRectsOverlap(a: SnapshotRect, b: SnapshotRect): boolean {\n 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;\n}\n\n/** Build a `nodeIndex -> { rect, paint, styles }` map from one snapshot document. */\nfunction indexLayoutNodes(doc: any, strings: string[]): Map<number, { rect: SnapshotRect; paint: number; styles: Record<string, string> }> {\n const byNode = new Map<number, { rect: SnapshotRect; paint: number; styles: Record<string, string> }>();\n const nodeIndex: number[] = doc.layout?.nodeIndex ?? [];\n const bounds: number[][] = doc.layout?.bounds ?? [];\n const paintOrders: number[] = doc.layout?.paintOrders ?? [];\n const styleRows: number[][] = doc.layout?.styles ?? [];\n for (let k = 0; k < nodeIndex.length; k += 1) {\n const ni = nodeIndex[k];\n const paint = paintOrders[k] ?? 0;\n const existing = byNode.get(ni);\n if (existing) {\n if (paint > existing.paint) existing.paint = paint;\n continue;\n }\n const b = bounds[k] ?? [0, 0, 0, 0];\n const styles: Record<string, string> = {};\n const row = styleRows[k] ?? [];\n COVERAGE_STYLE_KEYS.forEach((key, j) => { styles[key] = row[j] === undefined ? '' : strings[row[j]]; });\n byNode.set(ni, { rect: { x: b[0], y: b[1], w: b[2], h: b[3] }, paint, styles });\n }\n return byNode;\n}\n\n/** Locate the flat node index whose backendNodeId matches the resolved target. */\nfunction nodeIndexForBackendId(nodes: any, backendId: number): number {\n const backendIds: number[] = nodes.backendNodeId ?? [];\n for (let i = 0; i < backendIds.length; i += 1) if (backendIds[i] === backendId) return i;\n return -1;\n}\n\n/** `a` is a tree ancestor of `b` via the snapshot `parentIndex` chain. */\nfunction isSnapshotAncestor(parentIndex: number[], a: number, b: number): boolean {\n let cursor = parentIndex[b];\n while (cursor >= 0) {\n if (cursor === a) return true;\n cursor = parentIndex[cursor];\n }\n return false;\n}\n\n/** Element paints its own text or replaced content (image/media/form control). */\nfunction snapshotNodeHasOwnContent(nodes: any, strings: string[], i: number): boolean {\n const tag = (strings[nodes.nodeName[i]] ?? '').toUpperCase();\n if (['IMG', 'SVG', 'CANVAS', 'VIDEO', 'INPUT', 'TEXTAREA', 'SELECT', 'PICTURE'].includes(tag)) return true;\n const parentIndex: number[] = nodes.parentIndex ?? [];\n const nodeType: number[] = nodes.nodeType ?? [];\n const nodeValue: number[] = nodes.nodeValue ?? [];\n for (let c = 0; c < parentIndex.length; c += 1) {\n if (parentIndex[c] === i && nodeType[c] === 3) {\n const v = nodeValue[c];\n if (v >= 0 && (strings[v] ?? '').trim().length > 0) return true;\n }\n }\n return false;\n}\n\n/**\n * The transparent-wrapper heuristic: an element paints nothing visible when it is\n * `opacity:0`/`visibility:hidden`, or has no background colour alpha, no\n * background image, no borders, and no own text/replaced content. Documented as\n * the ONE inspectable rule that exempts a bare positioning wrapper from coverage.\n */\nfunction snapshotNodePaintsNothing(styles: Record<string, string>, hasOwnContent: boolean): boolean {\n if (styles.opacity === '0') return true;\n if (styles.visibility === 'hidden') return true;\n const noBackground = colorAlphaIsZero(styles['background-color'] ?? '')\n && (styles['background-image'] === 'none' || !styles['background-image']);\n const noBorder = ['border-top-width', 'border-right-width', 'border-bottom-width', 'border-left-width']\n .every((key) => (styles[key] || '0px') === '0px');\n return noBackground && noBorder && !hasOwnContent;\n}\n\n/** One-line `<tag#id.class>` description of a snapshot element node. */\nfunction describeSnapshotNode(nodes: any, strings: string[], i: number): string {\n const tag = (strings[nodes.nodeName[i]] ?? '').toLowerCase();\n const attrs: number[] = nodes.attributes?.[i] ?? [];\n let id = '';\n let classes = '';\n for (let a = 0; a + 1 < attrs.length; a += 2) {\n const name = strings[attrs[a]];\n const value = strings[attrs[a + 1]] ?? '';\n if (name === 'id') id = value ? `#${value}` : '';\n else if (name === 'class') classes = value ? `.${value.trim().split(/\\s+/).join('.')}` : '';\n }\n const pseudo = nodes.pseudoType?.[i] !== undefined && nodes.pseudoType[i] !== null\n ? `::${strings[nodes.pseudoType[i]] ?? 'pseudo'}`\n : '';\n return `<${tag}${id}${classes}${pseudo}>`;\n}\n\n/** Collect foreign elements that overlap and paint over the target's rect. */\nfunction collectCoverageCandidates(doc: any, strings: string[], targetNodeIndex: number): CoverageResult {\n const nodes = doc.nodes;\n const parentIndex: number[] = nodes.parentIndex ?? [];\n const nodeType: number[] = nodes.nodeType ?? [];\n const layout = indexLayoutNodes(doc, strings);\n const target = layout.get(targetNodeIndex);\n if (!target) return { targetPaint: 0, targetRect: { x: 0, y: 0, w: 0, h: 0 }, covers: [] };\n const covers: CoverageCandidate[] = [];\n for (const [ni, rec] of layout) {\n if (nodeType[ni] !== 1) continue;\n if (ni === targetNodeIndex) continue;\n if (isSnapshotAncestor(parentIndex, ni, targetNodeIndex) || isSnapshotAncestor(parentIndex, targetNodeIndex, ni)) continue;\n if (!snapshotRectsOverlap(rec.rect, target.rect)) continue;\n const hasContent = snapshotNodeHasOwnContent(nodes, strings, ni);\n if (snapshotNodePaintsNothing(rec.styles, hasContent)) continue;\n covers.push({ description: describeSnapshotNode(nodes, strings, ni), paint: rec.paint, rect: rec.rect });\n }\n return { targetPaint: target.paint, targetRect: target.rect, covers };\n}\n\n/**\n * Paint-order coverage analysis backing `notCovered`. Resolves the target's\n * backendNodeId, captures ONE `DOMSnapshot` (paint order + computed styles + DOM\n * rects), and reports every foreign element that paints visible pixels over the\n * target's rect. Chromium-only (needs a CDP session).\n */\nasync function captureCoverage(page: any, selector: string): Promise<CoverageResult> {\n const context = page.context?.();\n if (!context || typeof context.newCDPSession !== 'function') {\n throw new Error(\n 'notCovered requires a Chromium CDP session (page.context().newCDPSession); it is Chromium-only.',\n );\n }\n const cdp = await context.newCDPSession(page);\n try {\n await cdp.send('DOM.enable');\n const { root } = await cdp.send('DOM.getDocument', { depth: -1 });\n const { nodeId } = await cdp.send('DOM.querySelector', { nodeId: root.nodeId, selector });\n if (!nodeId) throw new Error(`Expected \"${selector}\" to exist for notCovered.`);\n const described = await cdp.send('DOM.describeNode', { nodeId });\n const backendId = described.node?.backendNodeId;\n if (backendId == null) throw new Error(`Could not resolve backendNodeId for \"${selector}\".`);\n const snapshot = await cdp.send('DOMSnapshot.captureSnapshot', {\n computedStyles: [...COVERAGE_STYLE_KEYS],\n includePaintOrder: true,\n includeDOMRects: true,\n });\n const doc = snapshot.documents?.[0];\n if (!doc) throw new Error('DOMSnapshot returned no documents.');\n const targetNodeIndex = nodeIndexForBackendId(doc.nodes, backendId);\n if (targetNodeIndex < 0) {\n throw new Error(`Expected \"${selector}\" to be laid out and painted for notCovered, but it was not in the paint tree.`);\n }\n return collectCoverageCandidates(doc, snapshot.strings ?? [], targetNodeIndex);\n } finally {\n await cdp.detach().catch(() => undefined);\n }\n}\n\nfunction createExpect(page: any, outputDir: string): WoodBrowserExpect {\n async function waitForVisible(selector: string): Promise<void> {\n const locator = page.locator(selector).first();\n try {\n await locator.waitFor({ state: 'attached', timeout: DEFAULT_EXPECT_TIMEOUT_MS });\n } catch {\n throw new Error(`Expected \"${selector}\" to exist.`);\n }\n try {\n await locator.waitFor({ state: 'visible', timeout: DEFAULT_EXPECT_TIMEOUT_MS });\n } catch {\n throw new Error(`Expected \"${selector}\" to be visible.`);\n }\n }\n\n async function hitTestAtPoint(\n selector: string,\n x: number,\n y: number,\n ): Promise<WoodHitTestResult> {\n const locator = page.locator(selector).first();\n const raw = await locator.evaluate((target: Element, coords: { x: number; y: number }) => {\n const hit = document.elementFromPoint(coords.x, coords.y);\n if (!hit) {\n return { found: false, tag: null, id: null, classes: [] as string[], isTarget: false, isDescendantOfTarget: false, isAncestorOfTarget: false };\n }\n return {\n found: true,\n tag: hit.tagName,\n id: hit.id || null,\n classes: Array.from(hit.classList),\n isTarget: hit === target,\n isDescendantOfTarget: hit !== target && target.contains(hit),\n isAncestorOfTarget: hit !== target && hit.contains(target),\n };\n }, { x, y });\n return {\n ...raw,\n point: { x, y },\n description: describeHitElement(raw),\n };\n }\n\n async function resolvePoint(\n selector: string,\n point: { x: number; y: number } | 'center' | undefined,\n ): Promise<{ x: number; y: number }> {\n if (point && point !== 'center') return point;\n const rect = await firstRect(page, selector);\n if (!rect) throw new Error(`Expected \"${selector}\" to exist.`);\n return { x: rect.left + rect.width / 2, y: rect.top + rect.height / 2 };\n }\n\n async function inFrontOfByPaintOrder(topSelector: string, lowerSelector: string): Promise<void> {\n const orders = await capturePaintOrders(page, [topSelector, lowerSelector]);\n const top = orders.get(topSelector)!;\n const lower = orders.get(lowerSelector)!;\n if (!top.found || top.paintOrder === null) {\n throw new Error(`Expected \"${topSelector}\" to have a paint-order entry, but it was not found in the paint tree (not laid out / not painted).`);\n }\n if (!lower.found || lower.paintOrder === null) {\n throw new Error(`Expected \"${lowerSelector}\" to have a paint-order entry, but it was not found in the paint tree (not laid out / not painted).`);\n }\n if (top.paintOrder > lower.paintOrder) return;\n const topRect = await firstRect(page, topSelector);\n const lowerRect = await firstRect(page, lowerSelector);\n const overlapNote = rectsOverlap(topRect, lowerRect)\n ? ''\n : ` (Note: the rects do not overlap, so there is no shared pixel where front/behind is visually observable — this is a global paint-order verdict.)`;\n throw new Error(\n `Expected \"${topSelector}\" (paint order ${top.paintOrder}) to paint in front of `\n + `\"${lowerSelector}\" (paint order ${lower.paintOrder}), but it paints at or behind it `\n + `(higher paint order == on top).${overlapNote}`,\n );\n }\n\n async function inFrontOfAtPoint(topSelector: string, lowerSelector: string, at: { x: number; y: number }): Promise<void> {\n const topHit = await hitTestAtPoint(topSelector, at.x, at.y);\n const lowerHit = await hitTestAtPoint(lowerSelector, at.x, at.y);\n const hitsTop = topHit.isTarget || topHit.isDescendantOfTarget;\n const hitsLower = lowerHit.isTarget || lowerHit.isDescendantOfTarget;\n if (!hitsTop || hitsLower) {\n throw new Error(\n `Expected \"${topSelector}\" to be painted in front of \"${lowerSelector}\" at (${at.x.toFixed(1)}, ${at.y.toFixed(1)}), `\n + `but the top-most painted element there was ${topHit.description} `\n + `(is/descends-from \"${topSelector}\": ${hitsTop}; is/descends-from \"${lowerSelector}\": ${hitsLower}).`,\n );\n }\n }\n\n return {\n async visible(selector: string): Promise<void> {\n await waitForVisible(selector);\n },\n async hidden(selector: string): Promise<void> {\n try {\n await page.locator(selector).first().waitFor({\n state: 'hidden',\n timeout: DEFAULT_EXPECT_TIMEOUT_MS,\n });\n } catch {\n throw new Error(`Expected \"${selector}\" to be hidden.`);\n }\n },\n async insideViewport(selector: string, options: { margin?: number } = {}): Promise<void> {\n await waitForVisible(selector);\n const margin = options.margin ?? 0;\n const rect = await elementRect(page, selector);\n if (!rect) throw new Error(`Expected \"${selector}\" to exist.`);\n const viewport = page.viewportSize();\n if (!viewport) throw new Error('Cannot assert viewport bounds without a viewport.');\n if (\n rect.left < margin ||\n rect.top < margin ||\n rect.right > viewport.width - margin ||\n rect.bottom > viewport.height - margin\n ) {\n throw new Error(`Expected \"${selector}\" to be inside viewport. Rect: ${JSON.stringify(rect)}, viewport: ${JSON.stringify(viewport)}`);\n }\n },\n async notClipped(selector: string): Promise<void> {\n await waitForVisible(selector);\n const result = await page.locator(selector).first().evaluate((element: Element) => {\n const rect = element.getBoundingClientRect();\n let parent = element.parentElement;\n while (parent) {\n const style = window.getComputedStyle(parent);\n const clips = /(auto|hidden|scroll|clip)/.test(`${style.overflow}${style.overflowX}${style.overflowY}`);\n if (clips) {\n const parentRect = parent.getBoundingClientRect();\n if (\n rect.left < parentRect.left ||\n rect.top < parentRect.top ||\n rect.right > parentRect.right ||\n rect.bottom > parentRect.bottom\n ) {\n return { ok: false, parent: parent.tagName, rect, parentRect };\n }\n }\n parent = parent.parentElement;\n }\n return { ok: true };\n });\n if (!result.ok) {\n throw new Error(`Expected \"${selector}\" not to be clipped. ${JSON.stringify(result)}`);\n }\n },\n async notOverlapping(firstSelector: string, secondSelector: string): Promise<void> {\n await waitForVisible(firstSelector);\n await waitForVisible(secondSelector);\n const first = await elementRect(page, firstSelector);\n const second = await elementRect(page, secondSelector);\n if (!first || !second) throw new Error(`Expected both \"${firstSelector}\" and \"${secondSelector}\" to exist.`);\n const overlaps = first.left < second.right\n && first.right > second.left\n && first.top < second.bottom\n && first.bottom > second.top;\n if (overlaps) {\n throw new Error(`Expected \"${firstSelector}\" not to overlap \"${secondSelector}\".`);\n }\n },\n async zIndexAbove(topSelector: string, lowerSelector: string): Promise<void> {\n await waitForVisible(topSelector);\n await waitForVisible(lowerSelector);\n const values = await page.evaluate((payload: { topSelector: string; lowerSelector: string }) => {\n const { topSelector: top, lowerSelector: lower } = payload;\n const topElement = document.querySelector(top);\n const lowerElement = document.querySelector(lower);\n if (!topElement || !lowerElement) return null;\n return {\n top: Number(window.getComputedStyle(topElement).zIndex) || 0,\n lower: Number(window.getComputedStyle(lowerElement).zIndex) || 0,\n };\n }, { topSelector, lowerSelector });\n if (!values) throw new Error(`Expected both \"${topSelector}\" and \"${lowerSelector}\" to exist.`);\n if (values.top <= values.lower) {\n throw new Error(`Expected \"${topSelector}\" z-index (${values.top}) to be above \"${lowerSelector}\" (${values.lower}).`);\n }\n },\n async rects(selectors: string[]): Promise<WoodRectSnapshot[]> {\n const snapshots: WoodRectSnapshot[] = [];\n for (const selector of selectors) {\n const rect = await firstRect(page, selector);\n if (!rect) throw new Error(`Expected \"${selector}\" to exist.`);\n snapshots.push({ selector, ...rect });\n }\n return snapshots;\n },\n async hitTest(selector: string, point: { x: number; y: number } | 'center' = 'center'): Promise<WoodHitTestResult> {\n await waitForVisible(selector);\n const resolved = await resolvePoint(selector, point);\n return hitTestAtPoint(selector, resolved.x, resolved.y);\n },\n async sharedEdge(a: string, b: string, edge: 'left' | 'right' | 'top' | 'bottom', options: { tolerance?: number } = {}): Promise<void> {\n await waitForVisible(a);\n await waitForVisible(b);\n const tolerance = options.tolerance ?? 1;\n const first = await firstRect(page, a);\n const second = await firstRect(page, b);\n if (!first || !second) throw new Error(`Expected both \"${a}\" and \"${b}\" to exist.`);\n const delta = Math.abs(first[edge] - second[edge]);\n if (delta > tolerance) {\n throw new Error(\n `Expected \"${a}\" and \"${b}\" to share ${edge} edge within ${tolerance}px, but delta was ${delta.toFixed(2)}px `\n + `(\"${a}\".${edge}=${first[edge].toFixed(2)}, \"${b}\".${edge}=${second[edge].toFixed(2)}). `\n + `Rects: ${a}=${JSON.stringify(first)}, ${b}=${JSON.stringify(second)}`,\n );\n }\n },\n async sharedAxis(a: string, b: string, axis: 'centerX' | 'centerY', options: { tolerance?: number } = {}): Promise<void> {\n await waitForVisible(a);\n await waitForVisible(b);\n const tolerance = options.tolerance ?? 1;\n const first = await firstRect(page, a);\n const second = await firstRect(page, b);\n if (!first || !second) throw new Error(`Expected both \"${a}\" and \"${b}\" to exist.`);\n const center = (rect: RectBox): number => axis === 'centerX'\n ? rect.left + rect.width / 2\n : rect.top + rect.height / 2;\n const firstCenter = center(first);\n const secondCenter = center(second);\n const delta = Math.abs(firstCenter - secondCenter);\n if (delta > tolerance) {\n throw new Error(\n `Expected \"${a}\" and \"${b}\" to share ${axis} within ${tolerance}px, but delta was ${delta.toFixed(2)}px `\n + `(\"${a}\".${axis}=${firstCenter.toFixed(2)}, \"${b}\".${axis}=${secondCenter.toFixed(2)}). `\n + `Rects: ${a}=${JSON.stringify(first)}, ${b}=${JSON.stringify(second)}`,\n );\n }\n },\n async unoccluded(selector: string, options: { point?: { x: number; y: number } | 'center' } = {}): Promise<void> {\n await waitForVisible(selector);\n const resolved = await resolvePoint(selector, options.point ?? 'center');\n const hit = await hitTestAtPoint(selector, resolved.x, resolved.y);\n if (!hit.found) {\n throw new Error(`Expected \"${selector}\" to receive pixels at (${resolved.x.toFixed(1)}, ${resolved.y.toFixed(1)}), but no element was painted there.`);\n }\n if (hit.isTarget || hit.isDescendantOfTarget || hit.isAncestorOfTarget) return;\n throw new Error(\n `Expected \"${selector}\" to be unoccluded at (${resolved.x.toFixed(1)}, ${resolved.y.toFixed(1)}), `\n + `but the painted element there was ${hit.description} — a foreign element occluding the target.`,\n );\n },\n async inFrontOf(topSelector: string, lowerSelector: string, options: { at?: { x: number; y: number } } = {}): Promise<void> {\n await waitForVisible(topSelector);\n await waitForVisible(lowerSelector);\n if (options.at) {\n await inFrontOfAtPoint(topSelector, lowerSelector, options.at);\n return;\n }\n await inFrontOfByPaintOrder(topSelector, lowerSelector);\n },\n async notCovered(selector: string): Promise<void> {\n await waitForVisible(selector);\n const coverage = await captureCoverage(page, selector);\n const covering = coverage.covers.filter((c) => c.paint > coverage.targetPaint);\n if (covering.length === 0) return;\n const worst = covering.reduce((a, b) => (b.paint > a.paint ? b : a));\n throw new Error(\n `Expected \"${selector}\" (paint order ${coverage.targetPaint}, rect `\n + `${JSON.stringify(coverage.targetRect)}) not to be covered, but ${worst.description} `\n + `paints on top (paint order ${worst.paint}, rect ${JSON.stringify(worst.rect)}). `\n + `notCovered tracks PAINTED coverage from the real paint tree; a foreign element `\n + `with a higher paint order that overlaps the target and paints visible pixels `\n + `(background/border/text/image — the transparent-wrapper heuristic did not exempt it) `\n + `fails here.`,\n );\n },\n async gapBetween(\n a: string,\n b: string,\n axis: WoodSpacingAxis,\n options: { equals?: number; min?: number; max?: number; tolerance?: number },\n ): Promise<void> {\n if (options.equals === undefined && options.min === undefined && options.max === undefined) {\n throw new Error('gapBetween requires at least one of { equals, min, max }.');\n }\n await waitForVisible(a);\n await waitForVisible(b);\n const tolerance = options.tolerance ?? 1;\n const first = await firstRect(page, a);\n const second = await firstRect(page, b);\n if (!first || !second) throw new Error(`Expected both \"${a}\" and \"${b}\" to exist.`);\n const gap = axisGap(first, second, axis);\n const allowsNegative = (options.equals !== undefined && options.equals < 0)\n || (options.min !== undefined && options.min < 0);\n const rectsNote = `Rects: ${a}=${JSON.stringify(first)}, ${b}=${JSON.stringify(second)}`;\n if (gap < -tolerance && !allowsNegative) {\n throw new Error(\n `Expected \"${a}\" and \"${b}\" to have a non-negative ${axis} gap, but their border boxes overlap by `\n + `${(-gap).toFixed(2)}px (gap ${gap.toFixed(2)}px). Pass a negative min/equals to assert an overlap `\n + `intentionally. ${rectsNote}`,\n );\n }\n const violation = gapConstraintViolation(gap, options, tolerance);\n if (violation) {\n throw new Error(\n `Expected \"${a}\" and \"${b}\" ${axis} gap to satisfy ${describeGapConstraint(options)} within ${tolerance}px, `\n + `but ${violation} (actual gap ${gap.toFixed(2)}px). ${rectsNote}`,\n );\n }\n },\n async evenlySpaced(\n selectors: string[],\n axis: WoodSpacingAxis,\n options: { tolerance?: number } = {},\n ): Promise<void> {\n if (selectors.length < 3) {\n throw new Error(`evenlySpaced requires at least 3 elements, got ${selectors.length}.`);\n }\n const tolerance = options.tolerance ?? 1;\n const boxes: Array<{ selector: string; rect: RectBox }> = [];\n for (const selector of selectors) {\n await waitForVisible(selector);\n const rect = await firstRect(page, selector);\n if (!rect) throw new Error(`Expected \"${selector}\" to exist.`);\n boxes.push({ selector, rect });\n }\n const sorted = [...boxes].sort((x, y) => axisEdges(x.rect, axis).leading - axisEdges(y.rect, axis).leading);\n const gaps = sorted.slice(1).map((box, i) => ({\n from: sorted[i].selector,\n to: box.selector,\n gap: axisGap(sorted[i].rect, box.rect, axis),\n }));\n const widest = gaps.reduce((acc, g) => (g.gap > acc.gap ? g : acc));\n const narrowest = gaps.reduce((acc, g) => (g.gap < acc.gap ? g : acc));\n const spread = widest.gap - narrowest.gap;\n if (spread > tolerance) {\n const list = gaps.map((g) => `${g.from}→${g.to}=${g.gap.toFixed(2)}px`).join(', ');\n throw new Error(\n `Expected elements to be evenly spaced along ${axis} within ${tolerance}px, but gap spread was `\n + `${spread.toFixed(2)}px (widest ${widest.from}→${widest.to}=${widest.gap.toFixed(2)}px, narrowest `\n + `${narrowest.from}→${narrowest.to}=${narrowest.gap.toFixed(2)}px). Gaps: ${list}`,\n );\n }\n },\n async stableAfterAnimation(selector = 'body', options = {}): Promise<void> {\n const frameCount = options.frameCount ?? 3;\n const timeoutMs = options.timeoutMs ?? 2000;\n const startedAt = Date.now();\n let previous = '';\n let stableFrames = 0;\n while (Date.now() - startedAt < timeoutMs) {\n const current = JSON.stringify(await elementRect(page, selector));\n if (current === previous) {\n stableFrames += 1;\n if (stableFrames >= frameCount) return;\n } else {\n stableFrames = 0;\n previous = current;\n }\n await page.evaluate(() => new Promise((resolve) => requestAnimationFrame(() => resolve(undefined))));\n }\n throw new Error(`Expected \"${selector}\" to become stable within ${timeoutMs}ms.`);\n },\n async screenshot(name: string, options = {}): Promise<void> {\n const outputPath = path.join(outputDir, `${name}.png`);\n await fs.promises.mkdir(outputDir, { recursive: true });\n const masks = options.mask?.map((selector) => page.locator(selector)) ?? [];\n await page.screenshot({\n path: outputPath,\n fullPage: options.fullPage ?? true,\n mask: masks,\n });\n },\n };\n}\n\nfunction createSurface(input: {\n page: any;\n bridge: MountedWoodBridge;\n outputDir: string;\n destroy: () => Promise<void>;\n}): MountedWoodSurface {\n return {\n page: input.page,\n bridge: input.bridge,\n navigation: createMountedNavigation(input.page),\n expect: createExpect(input.page, input.outputDir),\n locator(selector: string): any {\n return input.page.locator(selector);\n },\n async click(selector: string): Promise<void> {\n await input.page.locator(selector).click();\n },\n async fill(selector: string, value: string): Promise<void> {\n await input.page.locator(selector).fill(value);\n },\n async evaluate<T>(fn: () => T | Promise<T>): Promise<T> {\n return await input.page.evaluate(fn);\n },\n destroy: input.destroy,\n };\n}\n\nasync function openMountPage(input: {\n runtime: HarnessRuntime;\n entrySource: string;\n name: string;\n css: string[];\n viewport?: WoodViewport;\n bridge: {\n state: BridgeState;\n manifest: RuntimeBridgeManifestEntry[];\n bridgeInit: string;\n };\n traceRecorder?: TraceRecorder;\n traceContext?: TraceRuntimeContext;\n context: Omit<WoodBrowserPageContext, 'page' | 'bridge'>;\n hooks?: WoodBrowserHarnessConfig['page'];\n}): Promise<MountedWoodSurface> {\n const page = input.runtime.page;\n const viewport = input.viewport ?? DEFAULT_VIEWPORT;\n await page.setViewportSize({ width: viewport.width, height: viewport.height });\n const entryPath = writeEntry(input.runtime.tempDir, input.name, input.entrySource);\n const htmlPath = writeHtml(input.runtime.tempDir, input.name, entryPath, input.css);\n await installTraceBinding(input.runtime.page, input.traceRecorder, input.traceContext ?? {});\n await installBridge(\n page,\n input.bridge.state,\n input.bridge.manifest,\n input.bridge.bridgeInit,\n input.runtime.transportCleanups,\n );\n const mountedBridge = createMountedBridge(page, input.bridge.state);\n const context: WoodBrowserPageContext = {\n page,\n bridge: mountedBridge,\n ...input.context,\n };\n await input.hooks?.beforeMount?.(context);\n await page.goto(`${serverBaseUrl(input.runtime.server)}${viteImport(htmlPath)}`, {\n waitUntil: 'domcontentloaded',\n });\n for (const event of input.bridge.state.initialEvents) {\n await mountedBridge.emit(event.channel, event.payload);\n }\n await input.hooks?.afterMount?.(context);\n\n return createSurface({\n page,\n bridge: mountedBridge,\n outputDir: path.join(input.runtime.rootDir, 'test-results', 'wood-browser'),\n destroy: async () => {\n await page.evaluate(() => {\n const app = window.__WOOD_BROWSER_APP__;\n if (app && typeof app === 'object' && typeof (app as { $destroy?: () => void }).$destroy === 'function') {\n (app as { $destroy: () => void }).$destroy();\n }\n }).catch(() => undefined);\n },\n });\n}\n\nasync function createHarness(config: WoodBrowserHarnessConfig = {}): Promise<WoodBrowserHarness> {\n const rootDir = normalizeRoot(config.rootDir);\n const browserName = config.browser?.browserName ?? 'chromium';\n const headless = config.browser?.headless ?? true;\n const workerRuntime = await acquireBrowserWorkerRuntime({\n rootDir,\n browserName,\n headless,\n });\n let released = false;\n let destroyed = false;\n let tempDir: string | null = null;\n let context: any | null = null;\n let page: any | null = null;\n let traceRecorder: TraceRecorder | undefined;\n\n function releaseRuntimeOnce(): void {\n if (released) {\n return;\n }\n released = true;\n releaseBrowserWorkerRuntime(workerRuntime);\n }\n\n try {\n tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'wood-browser-harness-'));\n context = await workerRuntime.browser.newContext({\n viewport: {\n width: config.viewport?.width ?? DEFAULT_VIEWPORT.width,\n height: config.viewport?.height ?? DEFAULT_VIEWPORT.height,\n deviceScaleFactor: config.viewport?.deviceScaleFactor,\n },\n });\n page = await context.newPage();\n traceRecorder = config.trace?.enabled === true\n ? new TraceRecorder()\n : undefined;\n traceRecorder?.enable({ maxEvents: config.trace?.maxEvents });\n } catch (error) {\n if (page) await waitForBoundedClose(page.close());\n if (context) await waitForBoundedClose(context.close());\n if (tempDir) fs.rmSync(tempDir, { recursive: true, force: true });\n releaseRuntimeOnce();\n throw error;\n }\n\n const runtime: HarnessRuntime = {\n context,\n server: workerRuntime.server,\n page,\n tempDir,\n rootDir,\n transportCleanups: [],\n };\n const css = (config.css ?? []).map((cssPath) => {\n const resolved = resolveFromRoot(rootDir, cssPath);\n assertFileExists(resolved, 'CSS file');\n return resolved;\n });\n\n return {\n page,\n ...(traceRecorder ? { traceRecorder } : {}),\n async mountRoute(routeKey: string, options: MountRouteOptions = {}): Promise<MountedWoodRoute> {\n const bridge = createBrowserBridgeFixtureWithTrace(mergeBridge(config.bridge, options.bridge), config.trace);\n const route = {\n params: options.route?.params ?? {},\n query: options.route?.query ?? {},\n };\n let entrySource: string;\n if (config.viewsConfig) {\n const viewsPath = resolveFromRoot(rootDir, config.viewsConfig);\n const views = await loadViews(viewsPath);\n const view = findView(views, routeKey);\n entrySource = buildRouteEntrySource({\n routeKey,\n view,\n rootDir,\n componentDir: config.componentDir,\n route,\n });\n } else if (config.generatedApp) {\n const generatedApp = resolveFromRoot(rootDir, config.generatedApp);\n assertFileExists(generatedApp, 'Generated app');\n // Prefer the ESM entry: require.resolve yields the CJS build, which has\n // no named `getNavigation` export under Vite's ESM interop.\n entrySource = buildGeneratedAppEntrySource({\n generatedApp,\n routeKey,\n route,\n navigationModule: resolveEsmModule(rootDir, '@noego/wood/navigation'),\n clientModule: resolveEsmModule(rootDir, '@noego/wood/client'),\n enableRendererTrace: config.trace?.enabled === true,\n traceMinLevel: config.trace?.minLevel ?? 'debug',\n });\n } else {\n throw new Error('mountRoute requires either viewsConfig or generatedApp in browser.createHarness().');\n }\n\n const mounted = await openMountPage({\n runtime,\n entrySource,\n name: `route-${routeKey.replace(/[^a-zA-Z0-9_-]/g, '-')}`,\n css,\n viewport: options.viewport ?? config.viewport,\n bridge,\n traceRecorder,\n traceContext: {\n windowId: config.trace?.windowId ?? routeKey.split('.')[0],\n routeKey,\n harnessId: config.trace?.harnessId,\n },\n context: {\n route: {\n key: routeKey,\n params: route.params,\n query: route.query,\n },\n },\n hooks: {\n beforeMount: options.page?.beforeMount ?? config.page?.beforeMount,\n afterMount: options.page?.afterMount ?? config.page?.afterMount,\n },\n });\n return {\n ...mounted,\n routeKey,\n };\n },\n async mountComponent(component: string, options: MountComponentOptions = {}): Promise<MountedWoodComponent> {\n const componentPath = resolveFromRoot(rootDir, component);\n assertFileExists(componentPath, 'Component');\n const bridge = createBrowserBridgeFixtureWithTrace(mergeBridge(config.bridge, options.bridge), config.trace);\n return await openMountPage({\n runtime,\n entrySource: buildComponentEntrySource({\n componentPath,\n props: options.props ?? {},\n }),\n name: `component-${path.basename(componentPath).replace(/[^a-zA-Z0-9_-]/g, '-')}`,\n css,\n viewport: options.viewport ?? config.viewport,\n bridge,\n traceRecorder,\n traceContext: {\n windowId: config.trace?.windowId ?? 'wood-browser-harness',\n harnessId: config.trace?.harnessId,\n },\n context: {},\n hooks: {\n beforeMount: options.page?.beforeMount ?? config.page?.beforeMount,\n afterMount: options.page?.afterMount ?? config.page?.afterMount,\n },\n });\n },\n async mountTree(tree: MountTreeOptions): Promise<MountedWoodTree> {\n const bridge = createBrowserBridgeFixtureWithTrace(mergeBridge(config.bridge, tree.bridge), config.trace);\n const layouts = (tree.layouts ?? []).map((layout) => ({\n component: resolveFromRoot(rootDir, layout.component),\n props: layout.props,\n }));\n for (const layout of layouts) {\n assertFileExists(layout.component, 'Layout component');\n }\n const view = {\n component: resolveFromRoot(rootDir, tree.view.component),\n props: tree.view.props,\n };\n assertFileExists(view.component, 'View component');\n return await openMountPage({\n runtime,\n entrySource: buildTreeEntrySource({ layouts, view }),\n name: `tree-${path.basename(view.component).replace(/[^a-zA-Z0-9_-]/g, '-')}`,\n css,\n viewport: tree.viewport ?? config.viewport,\n bridge,\n traceRecorder,\n traceContext: {\n windowId: config.trace?.windowId ?? tree.page?.key?.split('.')[0] ?? 'wood-browser-harness',\n routeKey: tree.page?.key,\n harnessId: config.trace?.harnessId,\n },\n context: tree.page?.key\n ? {\n route: {\n key: tree.page.key,\n params: tree.page.params ?? {},\n query: tree.page.query ?? {},\n },\n }\n : {},\n hooks: config.page,\n });\n },\n async flushRendererTraces(): Promise<void> {\n await page\n .evaluate(() => window.__woodBrowserTraceFlush?.())\n .catch(() => undefined);\n },\n async destroy(): Promise<void> {\n if (destroyed) {\n return;\n }\n destroyed = true;\n for (const cleanup of runtime.transportCleanups.splice(0)) {\n try {\n cleanup();\n } catch {\n // Best-effort transport unsubscribe.\n }\n }\n await Promise.all([\n waitForBoundedClose(page.close()),\n waitForBoundedClose(context.close()),\n ]);\n traceRecorder?.disable();\n fs.rmSync(tempDir, { recursive: true, force: true });\n releaseRuntimeOnce();\n },\n };\n}\n\nexport const browser = {\n createHarness,\n};\n\ndeclare global {\n interface Window {\n __WOOD_BROWSER_APP__?: unknown;\n __WOOD_BROWSER_DEFAULT_ROUTE__?: string;\n __WOOD_BROWSER_NAV__?: unknown;\n __WOOD_BROWSER_BRIDGE_MANIFEST__?: RuntimeBridgeManifestEntry[];\n __woodBrowserInvoke?: (channel: string, input: unknown) => Promise<unknown>;\n __woodBrowserSubscribe?: (channel: string) => void;\n __woodBrowserEmit?: (channel: string, payload: unknown) => void;\n __woodBrowserTrace?: (payload: unknown) => Promise<unknown> | void;\n __woodBrowserTracePending?: Set<Promise<unknown>>;\n __woodBrowserTraceFlush?: () => Promise<void>;\n }\n}\n"],"mappings":"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","names":["mod","browser","controllerPath"]}
@@ -3,7 +3,7 @@ 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
5
  import '@noego/trace/testing';
6
- import '../tracing/trace_hub.cjs';
6
+ import '../trace_hub-Cob54qRx.cjs';
7
7
  import 'rxjs';
8
8
  import '../tracing/trace_provider.cjs';
9
9
  import '@noego/ioc';
@@ -3,7 +3,7 @@ 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
5
  import '@noego/trace/testing';
6
- import '../tracing/trace_hub.js';
6
+ import '../trace_hub-Cob54qRx.js';
7
7
  import 'rxjs';
8
8
  import '../tracing/trace_provider.js';
9
9
  import '@noego/ioc';
@@ -18,9 +18,15 @@ var __copyProps = (to, from, except, desc) => {
18
18
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
19
  var testing_exports = {};
20
20
  __export(testing_exports, {
21
+ InProcessRouterTransport: () => import_transport.InProcessRouterTransport,
22
+ LoopbackRemoteTransport: () => import_transport.LoopbackRemoteTransport,
23
+ LoopbackRemoteTransportServer: () => import_transport.LoopbackRemoteTransportServer,
24
+ LoopbackSerializationError: () => import_transport.LoopbackSerializationError,
21
25
  RouterBridgeEvents: () => import_create_router_bridge.RouterBridgeEvents,
22
26
  TraceRecorder: () => import_trace_testing.TraceRecorder,
27
+ assertLoopbackSerializable: () => import_transport.assertLoopbackSerializable,
23
28
  browser: () => import_browser.browser,
29
+ buildTransportBridge: () => import_transport.buildTransportBridge,
24
30
  createBrowserBridgeFixture: () => import_browser.createBrowserBridgeFixture,
25
31
  createControllerHarness: () => import_create_controller_harness.createControllerHarness,
26
32
  createRouterBridge: () => import_create_router_bridge.createRouterBridge,
@@ -36,12 +42,19 @@ var import_create_test_router = require("./create_test_router.js");
36
42
  var import_mock_electron = require("./mock_electron.js");
37
43
  var import_create_router_bridge = require("./create_router_bridge.js");
38
44
  var import_browser = require("./browser.js");
45
+ var import_transport = require("../transport/index.js");
39
46
  var import_trace_testing = require("../trace-testing/index.js");
40
47
  // Annotate the CommonJS export names for ESM import in node:
41
48
  0 && (module.exports = {
49
+ InProcessRouterTransport,
50
+ LoopbackRemoteTransport,
51
+ LoopbackRemoteTransportServer,
52
+ LoopbackSerializationError,
42
53
  RouterBridgeEvents,
43
54
  TraceRecorder,
55
+ assertLoopbackSerializable,
44
56
  browser,
57
+ buildTransportBridge,
45
58
  createBrowserBridgeFixture,
46
59
  createControllerHarness,
47
60
  createRouterBridge,
@@ -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 WoodBrowserExpect,\n type WoodBrowserHarness,\n type WoodBrowserHarnessConfig,\n type WoodBrowserPageContext,\n type WoodBrowserTraceConfig,\n type WoodViewport,\n} from './browser.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,mCAAoC;AACpC,uCAIO;AACP,gCAAwD;AACxD,2BAAqD;AACrD,kCAIO;AACP,qBAsBO;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 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":[]}
@@ -3,9 +3,14 @@ export { ControllerHarnessResult, CreateControllerHarnessOptions, createControll
3
3
  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
- export { MountComponentOptions, MountRouteOptions, MountTreeOptions, MountedWoodBridge, MountedWoodComponent, MountedWoodNavigation, MountedWoodRoute, MountedWoodSurface, MountedWoodTree, WoodBridgeFixtureContext, WoodBridgeFixtureInput, WoodBridgeRecordedCall, WoodBridgeRecordedEvent, WoodBrowserExpect, WoodBrowserHarness, WoodBrowserHarnessConfig, WoodBrowserPageContext, WoodBrowserTraceConfig, WoodViewport, browser, createBrowserBridgeFixture } from './browser.cjs';
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 { TypedCall, WoodChannelContract, WoodChannelInput, WoodChannelMapLike, WoodChannelOutput, WoodRpcTransport } from '../transport/wood_rpc_transport.cjs';
8
+ export { InProcessRouterTransport } from '../transport/in_process_router_transport.cjs';
9
+ export { LoopbackRemoteTransport, LoopbackRemoteTransportServer } from '../transport/loopback_remote_transport.cjs';
10
+ export { LoopbackSerializationError, assertLoopbackSerializable } from '../transport/loopback_serialization.cjs';
11
+ export { TransportBridgeResult, buildTransportBridge } from '../transport/build_transport_bridge.cjs';
7
12
  export { TraceRecorder } from '../trace-testing/trace_recorder.cjs';
8
- export { TraceDispatchResult, TraceEvent, TraceInput, TraceWaitOptions } from '../tracing/trace_hub.cjs';
13
+ export { T as TraceDispatchResult, a as TraceEvent, b as TraceInput, f as TraceWaitOptions } from '../trace_hub-Cob54qRx.cjs';
9
14
  import '../navigation/index.cjs';
10
15
  import '../router/wood_router.cjs';
11
16
  import '../types/operations.cjs';
@@ -3,9 +3,14 @@ export { ControllerHarnessResult, CreateControllerHarnessOptions, createControll
3
3
  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
- export { MountComponentOptions, MountRouteOptions, MountTreeOptions, MountedWoodBridge, MountedWoodComponent, MountedWoodNavigation, MountedWoodRoute, MountedWoodSurface, MountedWoodTree, WoodBridgeFixtureContext, WoodBridgeFixtureInput, WoodBridgeRecordedCall, WoodBridgeRecordedEvent, WoodBrowserExpect, WoodBrowserHarness, WoodBrowserHarnessConfig, WoodBrowserPageContext, WoodBrowserTraceConfig, WoodViewport, browser, createBrowserBridgeFixture } from './browser.js';
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 { TypedCall, WoodChannelContract, WoodChannelInput, WoodChannelMapLike, WoodChannelOutput, WoodRpcTransport } from '../transport/wood_rpc_transport.js';
8
+ export { InProcessRouterTransport } from '../transport/in_process_router_transport.js';
9
+ export { LoopbackRemoteTransport, LoopbackRemoteTransportServer } from '../transport/loopback_remote_transport.js';
10
+ export { LoopbackSerializationError, assertLoopbackSerializable } from '../transport/loopback_serialization.js';
11
+ export { TransportBridgeResult, buildTransportBridge } from '../transport/build_transport_bridge.js';
7
12
  export { TraceRecorder } from '../trace-testing/trace_recorder.js';
8
- export { TraceDispatchResult, TraceEvent, TraceInput, TraceWaitOptions } from '../tracing/trace_hub.js';
13
+ export { T as TraceDispatchResult, a as TraceEvent, b as TraceInput, f as TraceWaitOptions } from '../trace_hub-Cob54qRx.js';
9
14
  import '../navigation/index.js';
10
15
  import '../router/wood_router.js';
11
16
  import '../types/operations.js';