@noego/wood 0.4.9 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +118 -42
- package/bin/axe.js +313 -98
- package/dist/{loader/__fixtures__/layouts/app.load.cjs → automation/actions.cjs} +3 -13
- package/dist/automation/actions.cjs.map +1 -0
- package/dist/automation/actions.d.cts +57 -0
- package/dist/automation/actions.d.ts +57 -0
- package/dist/automation/actions.js +1 -0
- package/dist/automation/actions.js.map +1 -0
- package/dist/automation/actions_executor.cjs +101 -0
- package/dist/automation/actions_executor.cjs.map +1 -0
- package/dist/automation/actions_executor.d.cts +16 -0
- package/dist/automation/actions_executor.d.ts +16 -0
- package/dist/automation/actions_executor.js +76 -0
- package/dist/automation/actions_executor.js.map +1 -0
- package/dist/automation/connection.cjs +86 -0
- package/dist/automation/connection.cjs.map +1 -0
- package/dist/automation/connection.d.cts +18 -0
- package/dist/automation/connection.d.ts +18 -0
- package/dist/automation/connection.js +51 -0
- package/dist/automation/connection.js.map +1 -0
- package/dist/{middleware/__fixtures__/middleware/sequence.cjs → automation/errors.cjs} +25 -22
- package/dist/automation/errors.cjs.map +1 -0
- package/dist/automation/errors.d.cts +31 -0
- package/dist/automation/errors.d.ts +31 -0
- package/dist/automation/errors.js +24 -0
- package/dist/automation/errors.js.map +1 -0
- package/dist/automation/index.cjs +49 -0
- package/dist/automation/index.cjs.map +1 -0
- package/dist/automation/index.d.cts +16 -0
- package/dist/automation/index.d.ts +16 -0
- package/dist/automation/index.js +15 -0
- package/dist/automation/index.js.map +1 -0
- package/dist/automation/introspection_reader.cjs +75 -0
- package/dist/automation/introspection_reader.cjs.map +1 -0
- package/dist/automation/introspection_reader.d.cts +20 -0
- package/dist/automation/introspection_reader.d.ts +20 -0
- package/dist/automation/introspection_reader.js +48 -0
- package/dist/automation/introspection_reader.js.map +1 -0
- package/dist/automation/locator.cjs +102 -0
- package/dist/automation/locator.cjs.map +1 -0
- package/dist/automation/locator.d.cts +51 -0
- package/dist/automation/locator.d.ts +51 -0
- package/dist/automation/locator.js +75 -0
- package/dist/automation/locator.js.map +1 -0
- package/dist/{loader/__fixtures__/views/test/page.load.cjs → automation/observation.cjs} +3 -13
- package/dist/automation/observation.cjs.map +1 -0
- package/dist/automation/observation.d.cts +44 -0
- package/dist/automation/observation.d.ts +44 -0
- package/dist/automation/observation.js +1 -0
- package/dist/automation/observation.js.map +1 -0
- package/dist/{controller/__fixtures__/controllers/test.cjs → automation/receipts.cjs} +3 -15
- package/dist/automation/receipts.cjs.map +1 -0
- package/dist/automation/receipts.d.cts +27 -0
- package/dist/automation/receipts.d.ts +27 -0
- package/dist/automation/receipts.js +1 -0
- package/dist/automation/receipts.js.map +1 -0
- package/dist/automation/scenario.cjs +696 -0
- package/dist/automation/scenario.cjs.map +1 -0
- package/dist/automation/scenario.d.cts +89 -0
- package/dist/automation/scenario.d.ts +89 -0
- package/dist/automation/scenario.js +660 -0
- package/dist/automation/scenario.js.map +1 -0
- package/dist/automation/scrolling.cjs +17 -0
- package/dist/automation/scrolling.cjs.map +1 -0
- package/dist/automation/scrolling.d.cts +51 -0
- package/dist/automation/scrolling.d.ts +51 -0
- package/dist/automation/scrolling.js +1 -0
- package/dist/automation/scrolling.js.map +1 -0
- package/dist/automation/scrolling_executor.cjs +109 -0
- package/dist/automation/scrolling_executor.cjs.map +1 -0
- package/dist/automation/scrolling_executor.d.cts +13 -0
- package/dist/automation/scrolling_executor.d.ts +13 -0
- package/dist/automation/scrolling_executor.js +84 -0
- package/dist/automation/scrolling_executor.js.map +1 -0
- package/dist/automation/target_identity.cjs +17 -0
- package/dist/automation/target_identity.cjs.map +1 -0
- package/dist/automation/target_identity.d.cts +28 -0
- package/dist/automation/target_identity.d.ts +28 -0
- package/dist/automation/target_identity.js +1 -0
- package/dist/automation/target_identity.js.map +1 -0
- package/dist/automation/target_registry.cjs +148 -0
- package/dist/automation/target_registry.cjs.map +1 -0
- package/dist/automation/target_registry.d.cts +32 -0
- package/dist/automation/target_registry.d.ts +32 -0
- package/dist/automation/target_registry.js +122 -0
- package/dist/automation/target_registry.js.map +1 -0
- package/dist/automation/waits.cjs +17 -0
- package/dist/automation/waits.cjs.map +1 -0
- package/dist/automation/waits.d.cts +44 -0
- package/dist/automation/waits.d.ts +44 -0
- package/dist/automation/waits.js +1 -0
- package/dist/automation/waits.js.map +1 -0
- package/dist/automation/waits_executor.cjs +104 -0
- package/dist/automation/waits_executor.cjs.map +1 -0
- package/dist/automation/waits_executor.d.cts +14 -0
- package/dist/automation/waits_executor.d.ts +14 -0
- package/dist/automation/waits_executor.js +79 -0
- package/dist/automation/waits_executor.js.map +1 -0
- package/dist/bridge/backend_bridge.cjs.map +1 -1
- package/dist/bridge/backend_bridge.js.map +1 -1
- package/dist/client/index.cjs +78 -21
- package/dist/client/index.cjs.map +1 -1
- package/dist/client/index.d.cts +19 -3
- package/dist/client/index.d.ts +19 -3
- package/dist/client/index.js +80 -22
- package/dist/client/index.js.map +1 -1
- package/dist/client/renderer_log_transport.cjs +151 -0
- package/dist/client/renderer_log_transport.cjs.map +1 -0
- package/dist/client/renderer_log_transport.d.cts +54 -0
- package/dist/client/renderer_log_transport.d.ts +54 -0
- package/dist/client/renderer_log_transport.js +123 -0
- package/dist/client/renderer_log_transport.js.map +1 -0
- package/dist/codegen/controller_registration_generator.cjs +13 -2
- package/dist/codegen/controller_registration_generator.cjs.map +1 -1
- package/dist/codegen/controller_registration_generator.d.cts +12 -1
- package/dist/codegen/controller_registration_generator.d.ts +12 -1
- package/dist/codegen/controller_registration_generator.js +10 -1
- package/dist/codegen/controller_registration_generator.js.map +1 -1
- package/dist/codegen/index.d.cts +1 -0
- package/dist/codegen/index.d.ts +1 -0
- package/dist/codegen/preload_generator.cjs +13 -6
- package/dist/codegen/preload_generator.cjs.map +1 -1
- package/dist/codegen/preload_generator.d.cts +11 -2
- package/dist/codegen/preload_generator.d.ts +11 -2
- package/dist/codegen/preload_generator.js +13 -6
- package/dist/codegen/preload_generator.js.map +1 -1
- package/dist/codegen/renderer_app_generator.cjs +95 -44
- package/dist/codegen/renderer_app_generator.cjs.map +1 -1
- package/dist/codegen/renderer_app_generator.js +95 -44
- package/dist/codegen/renderer_app_generator.js.map +1 -1
- package/dist/codegen/type_generator.cjs +1 -0
- package/dist/codegen/type_generator.cjs.map +1 -1
- package/dist/codegen/type_generator.js +1 -0
- package/dist/codegen/type_generator.js.map +1 -1
- package/dist/config/config_parser.cjs +95 -4
- package/dist/config/config_parser.cjs.map +1 -1
- package/dist/config/config_parser.d.cts +10 -2
- package/dist/config/config_parser.d.ts +10 -2
- package/dist/config/config_parser.js +92 -3
- package/dist/config/config_parser.js.map +1 -1
- package/dist/config/index.cjs +6 -2
- package/dist/config/index.cjs.map +1 -1
- package/dist/config/index.d.cts +2 -2
- package/dist/config/index.d.ts +2 -2
- package/dist/config/index.js +8 -2
- package/dist/config/index.js.map +1 -1
- package/dist/controller/controller_resolver.cjs +51 -3
- package/dist/controller/controller_resolver.cjs.map +1 -1
- package/dist/controller/controller_resolver.d.cts +27 -4
- package/dist/controller/controller_resolver.d.ts +27 -4
- package/dist/controller/controller_resolver.js +48 -2
- package/dist/controller/controller_resolver.js.map +1 -1
- package/dist/controller/index.cjs +6 -2
- package/dist/controller/index.cjs.map +1 -1
- package/dist/controller/index.d.cts +1 -1
- package/dist/controller/index.d.ts +1 -1
- package/dist/controller/index.js +4 -2
- package/dist/controller/index.js.map +1 -1
- package/dist/dev/wood_dev_server.cjs +4 -1
- package/dist/dev/wood_dev_server.cjs.map +1 -1
- package/dist/dev/wood_dev_server.js +5 -2
- package/dist/dev/wood_dev_server.js.map +1 -1
- package/dist/dev/yaml_watcher.cjs +1 -1
- package/dist/dev/yaml_watcher.cjs.map +1 -1
- package/dist/dev/yaml_watcher.d.cts +4 -0
- package/dist/dev/yaml_watcher.d.ts +4 -0
- package/dist/dev/yaml_watcher.js +1 -1
- package/dist/dev/yaml_watcher.js.map +1 -1
- package/dist/frontend/frontend_lifecycle.cjs +74 -0
- package/dist/frontend/frontend_lifecycle.cjs.map +1 -0
- package/dist/frontend/frontend_lifecycle.d.cts +50 -0
- package/dist/frontend/frontend_lifecycle.d.ts +50 -0
- package/dist/frontend/frontend_lifecycle.js +50 -0
- package/dist/frontend/frontend_lifecycle.js.map +1 -0
- package/dist/frontend/frontend_page.cjs +122 -0
- package/dist/frontend/frontend_page.cjs.map +1 -0
- package/dist/frontend/frontend_page.d.cts +62 -0
- package/dist/frontend/frontend_page.d.ts +62 -0
- package/dist/frontend/frontend_page.js +98 -0
- package/dist/frontend/frontend_page.js.map +1 -0
- package/dist/frontend/frontend_surface.cjs +249 -0
- package/dist/frontend/frontend_surface.cjs.map +1 -0
- package/dist/frontend/frontend_surface.d.cts +64 -0
- package/dist/frontend/frontend_surface.d.ts +64 -0
- package/dist/frontend/frontend_surface.js +224 -0
- package/dist/frontend/frontend_surface.js.map +1 -0
- package/dist/frontend/index.cjs +52 -0
- package/dist/frontend/index.cjs.map +1 -0
- package/dist/frontend/index.d.cts +10 -0
- package/dist/frontend/index.d.ts +10 -0
- package/dist/frontend/index.js +19 -0
- package/dist/frontend/index.js.map +1 -0
- package/dist/frontend/page_catalog.cjs +135 -0
- package/dist/frontend/page_catalog.cjs.map +1 -0
- package/dist/frontend/page_catalog.d.cts +56 -0
- package/dist/frontend/page_catalog.d.ts +56 -0
- package/dist/frontend/page_catalog.js +108 -0
- package/dist/frontend/page_catalog.js.map +1 -0
- package/dist/frontend/tracked_transport.cjs +55 -0
- package/dist/frontend/tracked_transport.cjs.map +1 -0
- package/dist/frontend/tracked_transport.d.cts +36 -0
- package/dist/frontend/tracked_transport.d.ts +36 -0
- package/dist/frontend/tracked_transport.js +31 -0
- package/dist/frontend/tracked_transport.js.map +1 -0
- package/dist/frontend/work_registry.cjs +153 -0
- package/dist/frontend/work_registry.cjs.map +1 -0
- package/dist/frontend/work_registry.d.cts +70 -0
- package/dist/frontend/work_registry.d.ts +70 -0
- package/dist/frontend/work_registry.js +128 -0
- package/dist/frontend/work_registry.js.map +1 -0
- package/dist/index.cjs +24 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +11 -7
- package/dist/index.d.ts +11 -7
- package/dist/index.js +27 -4
- package/dist/index.js.map +1 -1
- package/dist/main/index.cjs +10 -0
- package/dist/main/index.cjs.map +1 -1
- package/dist/main/index.d.cts +14 -2
- package/dist/main/index.d.ts +14 -2
- package/dist/main/index.js +16 -0
- package/dist/main/index.js.map +1 -1
- package/dist/middleware/middleware_resolver.cjs +22 -1
- package/dist/middleware/middleware_resolver.cjs.map +1 -1
- package/dist/middleware/middleware_resolver.d.cts +13 -1
- package/dist/middleware/middleware_resolver.d.ts +13 -1
- package/dist/middleware/middleware_resolver.js +22 -1
- package/dist/middleware/middleware_resolver.js.map +1 -1
- package/dist/navigation/automation_introspection.cjs +110 -0
- package/dist/navigation/automation_introspection.cjs.map +1 -0
- package/dist/navigation/automation_introspection.d.cts +60 -0
- package/dist/navigation/automation_introspection.d.ts +60 -0
- package/dist/navigation/automation_introspection.js +85 -0
- package/dist/navigation/automation_introspection.js.map +1 -0
- package/dist/navigation/index.cjs +10 -2
- package/dist/navigation/index.cjs.map +1 -1
- package/dist/navigation/index.d.cts +27 -1
- package/dist/navigation/index.d.ts +27 -1
- package/dist/navigation/index.js +6 -1
- package/dist/navigation/index.js.map +1 -1
- package/dist/{middleware/__fixtures__/middleware/auth.cjs → navigation/layout_preservation.cjs} +18 -20
- package/dist/navigation/layout_preservation.cjs.map +1 -0
- package/dist/navigation/layout_preservation.d.cts +2 -0
- package/dist/navigation/layout_preservation.d.ts +2 -0
- package/dist/navigation/layout_preservation.js +18 -0
- package/dist/navigation/layout_preservation.js.map +1 -0
- package/dist/parser/index.cjs +2 -0
- package/dist/parser/index.cjs.map +1 -1
- package/dist/parser/index.d.cts +1 -1
- package/dist/parser/index.d.ts +1 -1
- package/dist/parser/index.js +2 -1
- package/dist/parser/index.js.map +1 -1
- package/dist/parser/operations_parser.cjs +6 -0
- package/dist/parser/operations_parser.cjs.map +1 -1
- package/dist/parser/operations_parser.d.cts +9 -2
- package/dist/parser/operations_parser.d.ts +9 -2
- package/dist/parser/operations_parser.js +5 -0
- package/dist/parser/operations_parser.js.map +1 -1
- package/dist/parser/views_parser.cjs.map +1 -1
- package/dist/parser/views_parser.js.map +1 -1
- package/dist/router/index.d.cts +1 -0
- package/dist/router/index.d.ts +1 -0
- package/dist/router/wood_router.cjs +35 -3
- package/dist/router/wood_router.cjs.map +1 -1
- package/dist/router/wood_router.d.cts +15 -0
- package/dist/router/wood_router.d.ts +15 -0
- package/dist/router/wood_router.js +36 -4
- package/dist/router/wood_router.js.map +1 -1
- package/dist/runtime/get_container.cjs +9 -34
- package/dist/runtime/get_container.cjs.map +1 -1
- package/dist/runtime/get_container.d.cts +24 -4
- package/dist/runtime/get_container.d.ts +24 -4
- package/dist/runtime/get_container.js +8 -23
- package/dist/runtime/get_container.js.map +1 -1
- package/dist/runtime/index.cjs +9 -0
- package/dist/runtime/index.cjs.map +1 -1
- package/dist/runtime/index.d.cts +5 -2
- package/dist/runtime/index.d.ts +5 -2
- package/dist/runtime/index.js +10 -1
- package/dist/runtime/index.js.map +1 -1
- package/dist/runtime/renderer_config_extension.cjs +50 -0
- package/dist/runtime/renderer_config_extension.cjs.map +1 -0
- package/dist/runtime/renderer_config_extension.d.cts +19 -0
- package/dist/runtime/renderer_config_extension.d.ts +19 -0
- package/dist/runtime/renderer_config_extension.js +24 -0
- package/dist/runtime/renderer_config_extension.js.map +1 -0
- package/dist/runtime/renderer_log_batch_receiver.cjs +73 -0
- package/dist/runtime/renderer_log_batch_receiver.cjs.map +1 -0
- package/dist/runtime/renderer_log_batch_receiver.d.cts +29 -0
- package/dist/runtime/renderer_log_batch_receiver.d.ts +29 -0
- package/dist/runtime/renderer_log_batch_receiver.js +48 -0
- package/dist/runtime/renderer_log_batch_receiver.js.map +1 -0
- package/dist/runtime/renderer_trace_batch_receiver_registry.d.cts +1 -1
- package/dist/runtime/renderer_trace_batch_receiver_registry.d.ts +1 -1
- package/dist/runtime/runtime.cjs +14 -0
- package/dist/runtime/runtime.cjs.map +1 -1
- package/dist/runtime/runtime.d.cts +2 -1
- package/dist/runtime/runtime.d.ts +2 -1
- package/dist/runtime/runtime.js +14 -0
- package/dist/runtime/runtime.js.map +1 -1
- package/dist/stick/index.cjs.map +1 -1
- package/dist/stick/index.js.map +1 -1
- package/dist/testing/automation_assertions.cjs +417 -0
- package/dist/testing/automation_assertions.cjs.map +1 -0
- package/dist/testing/automation_assertions.d.cts +44 -0
- package/dist/testing/automation_assertions.d.ts +44 -0
- package/dist/testing/automation_assertions.js +385 -0
- package/dist/testing/automation_assertions.js.map +1 -0
- package/dist/testing/browser.cjs +130 -57
- package/dist/testing/browser.cjs.map +1 -1
- package/dist/testing/browser.d.cts +10 -4
- package/dist/testing/browser.d.ts +10 -4
- package/dist/testing/browser.js +132 -53
- package/dist/testing/browser.js.map +1 -1
- package/dist/testing/create_controller_harness.cjs +28 -8
- package/dist/testing/create_controller_harness.cjs.map +1 -1
- package/dist/testing/create_controller_harness.d.cts +18 -2
- package/dist/testing/create_controller_harness.d.ts +18 -2
- package/dist/testing/create_controller_harness.js +28 -8
- package/dist/testing/create_controller_harness.js.map +1 -1
- package/dist/testing/create_router_bridge.d.cts +1 -0
- package/dist/testing/create_router_bridge.d.ts +1 -0
- package/dist/testing/create_test_router.d.cts +1 -0
- package/dist/testing/create_test_router.d.ts +1 -0
- package/dist/testing/geometry.cjs +109 -0
- package/dist/testing/geometry.cjs.map +1 -0
- package/dist/testing/geometry.d.cts +45 -0
- package/dist/testing/geometry.d.ts +45 -0
- package/dist/testing/geometry.js +79 -0
- package/dist/testing/geometry.js.map +1 -0
- package/dist/testing/index.cjs +62 -2
- package/dist/testing/index.cjs.map +1 -1
- package/dist/testing/index.d.cts +23 -4
- package/dist/testing/index.d.ts +23 -4
- package/dist/testing/index.js +50 -2
- package/dist/testing/index.js.map +1 -1
- package/dist/{controller/__fixtures__/controllers/not_a_class.cjs → testing/test_wood.cjs} +15 -7
- package/dist/testing/test_wood.cjs.map +1 -0
- package/dist/testing/test_wood.d.cts +16 -0
- package/dist/testing/test_wood.d.ts +16 -0
- package/dist/testing/test_wood.js +12 -0
- package/dist/testing/test_wood.js.map +1 -0
- package/dist/testing/test_wood_config.cjs +272 -0
- package/dist/testing/test_wood_config.cjs.map +1 -0
- package/dist/testing/test_wood_config.d.cts +111 -0
- package/dist/testing/test_wood_config.d.ts +111 -0
- package/dist/testing/test_wood_config.js +247 -0
- package/dist/testing/test_wood_config.js.map +1 -0
- package/dist/testing/wood_config_source.cjs +146 -0
- package/dist/testing/wood_config_source.cjs.map +1 -0
- package/dist/testing/wood_config_source.d.cts +36 -0
- package/dist/testing/wood_config_source.d.ts +36 -0
- package/dist/testing/wood_config_source.js +112 -0
- package/dist/testing/wood_config_source.js.map +1 -0
- package/dist/testing/wood_env_renderer.cjs +210 -0
- package/dist/testing/wood_env_renderer.cjs.map +1 -0
- package/dist/testing/wood_env_renderer.d.cts +74 -0
- package/dist/testing/wood_env_renderer.d.ts +74 -0
- package/dist/testing/wood_env_renderer.js +188 -0
- package/dist/testing/wood_env_renderer.js.map +1 -0
- package/dist/testing/wood_test_selection.cjs +94 -0
- package/dist/testing/wood_test_selection.cjs.map +1 -0
- package/dist/testing/wood_test_selection.d.cts +39 -0
- package/dist/testing/wood_test_selection.d.ts +39 -0
- package/dist/testing/wood_test_selection.js +68 -0
- package/dist/testing/wood_test_selection.js.map +1 -0
- package/dist/trace-testing/index.d.cts +1 -2
- package/dist/trace-testing/index.d.ts +1 -2
- package/dist/trace-testing/trace_recorder.cjs +1 -1
- package/dist/trace-testing/trace_recorder.cjs.map +1 -1
- package/dist/trace-testing/trace_recorder.d.cts +1 -2
- package/dist/trace-testing/trace_recorder.d.ts +1 -2
- package/dist/trace-testing/trace_recorder.js +1 -1
- package/dist/trace-testing/trace_recorder.js.map +1 -1
- package/dist/trace-transport/index.d.cts +1 -1
- package/dist/trace-transport/index.d.ts +1 -1
- package/dist/{trace_hub-Cob54qRx.d.cts → trace_hub-Cpo_nVze.d.cts} +21 -1
- package/dist/{trace_hub-Cob54qRx.d.ts → trace_hub-Cpo_nVze.d.ts} +21 -1
- package/dist/tracing/index.cjs +9 -2
- package/dist/tracing/index.cjs.map +1 -1
- package/dist/tracing/index.d.cts +3 -2
- package/dist/tracing/index.d.ts +3 -2
- package/dist/tracing/index.js +7 -1
- package/dist/tracing/index.js.map +1 -1
- package/dist/tracing/renderer_trace_batch_host.d.cts +1 -1
- package/dist/tracing/renderer_trace_batch_host.d.ts +1 -1
- package/dist/tracing/renderer_trace_batch_transport.cjs +48 -6
- package/dist/tracing/renderer_trace_batch_transport.cjs.map +1 -1
- package/dist/tracing/renderer_trace_batch_transport.d.cts +17 -1
- package/dist/tracing/renderer_trace_batch_transport.d.ts +17 -1
- package/dist/tracing/renderer_trace_batch_transport.js +48 -6
- package/dist/tracing/renderer_trace_batch_transport.js.map +1 -1
- package/dist/tracing/trace_batch_adapter.cjs +110 -0
- package/dist/tracing/trace_batch_adapter.cjs.map +1 -0
- package/dist/tracing/trace_batch_adapter.d.cts +36 -0
- package/dist/tracing/trace_batch_adapter.d.ts +36 -0
- package/dist/tracing/trace_batch_adapter.js +86 -0
- package/dist/tracing/trace_batch_adapter.js.map +1 -0
- package/dist/tracing/trace_commit_writer.d.cts +1 -1
- package/dist/tracing/trace_commit_writer.d.ts +1 -1
- package/dist/tracing/trace_hub.cjs +87 -20
- package/dist/tracing/trace_hub.cjs.map +1 -1
- package/dist/tracing/trace_hub.d.cts +1 -1
- package/dist/tracing/trace_hub.d.ts +1 -1
- package/dist/tracing/trace_hub.js +85 -20
- package/dist/tracing/trace_hub.js.map +1 -1
- package/dist/tracing/trace_provider.cjs +21 -6
- package/dist/tracing/trace_provider.cjs.map +1 -1
- package/dist/tracing/trace_provider.d.cts +13 -4
- package/dist/tracing/trace_provider.d.ts +13 -4
- package/dist/tracing/trace_provider.js +22 -7
- package/dist/tracing/trace_provider.js.map +1 -1
- package/dist/tracing/types/wood_trace_batch.types.cjs.map +1 -1
- package/dist/tracing/types/wood_trace_batch.types.d.cts +15 -1
- package/dist/tracing/types/wood_trace_batch.types.d.ts +15 -1
- package/dist/tracing/types/wood_trace_sink.types.d.cts +1 -1
- package/dist/tracing/types/wood_trace_sink.types.d.ts +1 -1
- package/dist/tracing/wood_trace_batch_contract.cjs +2 -0
- package/dist/tracing/wood_trace_batch_contract.cjs.map +1 -1
- package/dist/tracing/wood_trace_batch_contract.d.cts +1 -1
- package/dist/tracing/wood_trace_batch_contract.d.ts +1 -1
- package/dist/tracing/wood_trace_batch_contract.js +2 -0
- package/dist/tracing/wood_trace_batch_contract.js.map +1 -1
- package/dist/transport/build_transport_bridge.cjs +4 -2
- package/dist/transport/build_transport_bridge.cjs.map +1 -1
- package/dist/transport/build_transport_bridge.d.cts +7 -1
- package/dist/transport/build_transport_bridge.d.ts +7 -1
- package/dist/transport/build_transport_bridge.js +2 -1
- package/dist/transport/build_transport_bridge.js.map +1 -1
- package/dist/transport/in_process_router_transport.d.cts +1 -0
- package/dist/transport/in_process_router_transport.d.ts +1 -0
- package/dist/transport/index.d.cts +1 -0
- package/dist/transport/index.d.ts +1 -0
- package/dist/types/config.cjs.map +1 -1
- package/dist/types/config.d.cts +47 -1
- package/dist/types/config.d.ts +47 -1
- package/dist/types/context.cjs +12 -0
- package/dist/types/context.cjs.map +1 -1
- package/dist/types/context.d.cts +27 -1
- package/dist/types/context.d.ts +27 -1
- package/dist/types/context.js +4 -0
- package/dist/types/context.js.map +1 -1
- package/dist/types/index.d.cts +2 -2
- package/dist/types/index.d.ts +2 -2
- package/dist/types/operations.cjs.map +1 -1
- package/dist/types/operations.d.cts +2 -0
- package/dist/types/operations.d.ts +2 -0
- package/docs/axe.md +706 -0
- package/package.json +19 -5
- package/src/components/NavigationShell.scopes.browser.test.ts +363 -0
- package/src/components/NavigationShell.svelte +126 -49
- package/dist/controller/__fixtures__/controllers/chat.cjs +0 -32
- package/dist/controller/__fixtures__/controllers/chat.cjs.map +0 -1
- package/dist/controller/__fixtures__/controllers/chat.d.cts +0 -11
- package/dist/controller/__fixtures__/controllers/chat.d.ts +0 -11
- package/dist/controller/__fixtures__/controllers/chat.js +0 -12
- package/dist/controller/__fixtures__/controllers/chat.js.map +0 -1
- package/dist/controller/__fixtures__/controllers/not_a_class.cjs.map +0 -1
- package/dist/controller/__fixtures__/controllers/not_a_class.d.cts +0 -3
- package/dist/controller/__fixtures__/controllers/not_a_class.d.ts +0 -3
- package/dist/controller/__fixtures__/controllers/not_a_class.js +0 -5
- package/dist/controller/__fixtures__/controllers/not_a_class.js.map +0 -1
- package/dist/controller/__fixtures__/controllers/settings.controller.cjs +0 -32
- package/dist/controller/__fixtures__/controllers/settings.controller.cjs.map +0 -1
- package/dist/controller/__fixtures__/controllers/settings.controller.d.cts +0 -12
- package/dist/controller/__fixtures__/controllers/settings.controller.d.ts +0 -12
- package/dist/controller/__fixtures__/controllers/settings.controller.js +0 -12
- package/dist/controller/__fixtures__/controllers/settings.controller.js.map +0 -1
- package/dist/controller/__fixtures__/controllers/test.cjs.map +0 -1
- package/dist/controller/__fixtures__/controllers/test.d.cts +0 -7
- package/dist/controller/__fixtures__/controllers/test.d.ts +0 -7
- package/dist/controller/__fixtures__/controllers/test.js +0 -9
- package/dist/controller/__fixtures__/controllers/test.js.map +0 -1
- package/dist/loader/__fixtures__/layouts/app.load.cjs.map +0 -1
- package/dist/loader/__fixtures__/layouts/app.load.d.cts +0 -5
- package/dist/loader/__fixtures__/layouts/app.load.d.ts +0 -5
- package/dist/loader/__fixtures__/layouts/app.load.js +0 -7
- package/dist/loader/__fixtures__/layouts/app.load.js.map +0 -1
- package/dist/loader/__fixtures__/views/test/page.load.cjs.map +0 -1
- package/dist/loader/__fixtures__/views/test/page.load.d.cts +0 -6
- package/dist/loader/__fixtures__/views/test/page.load.d.ts +0 -6
- package/dist/loader/__fixtures__/views/test/page.load.js +0 -7
- package/dist/loader/__fixtures__/views/test/page.load.js.map +0 -1
- package/dist/middleware/__fixtures__/middleware/auth.cjs.map +0 -1
- package/dist/middleware/__fixtures__/middleware/auth.d.cts +0 -6
- package/dist/middleware/__fixtures__/middleware/auth.d.ts +0 -6
- package/dist/middleware/__fixtures__/middleware/auth.js +0 -19
- package/dist/middleware/__fixtures__/middleware/auth.js.map +0 -1
- package/dist/middleware/__fixtures__/middleware/sequence.cjs.map +0 -1
- package/dist/middleware/__fixtures__/middleware/sequence.d.cts +0 -7
- package/dist/middleware/__fixtures__/middleware/sequence.d.ts +0 -7
- package/dist/middleware/__fixtures__/middleware/sequence.js +0 -21
- package/dist/middleware/__fixtures__/middleware/sequence.js.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/testing/wood_config_source.ts"],"sourcesContent":["/**\n * Config-driven test source for `testWood(configPath)`.\n *\n * Everything a test environment binds is read from the production\n * `wood.config.yml`: operations from `main.openapi` (a single document or a\n * stitch manifest), views from `renderer.openapi`, controller files from\n * `main.controllers` (same candidate rules as codegen) and renderer\n * controllers relative to `renderer.componentDir`. Tests name nothing by\n * hand — a config path is the whole source.\n */\nimport fs from 'node:fs';\nimport path from 'node:path';\nimport { pathToFileURL } from 'node:url';\nimport yaml from 'js-yaml';\nimport { globSync } from 'glob';\nimport { parseConfig } from '../config/config_parser.js';\nimport type { WoodConfig } from '../types/config.js';\nimport { parseOperations } from '../parser/operations_parser.js';\nimport { parseViews } from '../parser/views_parser.js';\nimport type { OperationDef, ViewDef } from '../types/index.js';\nimport {\n controllerFileCandidates,\n resolveControllerFile,\n} from '../codegen/controller_registration_generator.js';\nimport { TestWoodError } from './test_wood.js';\n\n/** Imports a module by absolute path; the default keeps the caller's module registry. */\nexport type ModuleImporter = (absolutePath: string) => Promise<unknown>;\n\nexport const defaultImporter: ModuleImporter = (absolutePath) =>\n import(/* @vite-ignore */ pathToFileURL(absolutePath).href);\n\nexport interface WoodConfigSource {\n readonly configPath: string;\n readonly configDir: string;\n readonly config: WoodConfig;\n /** Every production operation, stitch order, first declaration wins. */\n readonly operations: Map<string, OperationDef>;\n readonly mainControllersDir: string;\n readonly mainMiddlewareDir: string;\n readonly rendererComponentDir: string;\n /** Every production view (parsed on first use — main-only builds never read them). */\n views(): ViewDef[];\n /** Absolute file for a main controller identity, or a build error naming the candidates. */\n mainControllerFile(identity: string): string;\n /** Absolute file for a renderer controller reference (views `controller:`). */\n rendererControllerFile(reference: string): string;\n /** Absolute path of an optional config-relative hook module, if declared. */\n hookModule(relative: string | undefined): string | null;\n}\n\ninterface StitchManifest {\n stitch?: unknown;\n}\n\nconst GLOB_MAGIC = /[*?[\\]{}]/;\n\n/**\n * Expand an openapi reference into the ordered list of YAML files it names:\n * a stitch manifest (`stitch: [...]`, entries relative to the manifest, globs\n * allowed) or a single document.\n */\nexport function expandOpenapiFiles(absolutePath: string): string[] {\n const doc = yaml.load(fs.readFileSync(absolutePath, 'utf-8')) as StitchManifest | null;\n if (!doc || typeof doc !== 'object' || !('stitch' in doc)) return [absolutePath];\n if (!Array.isArray(doc.stitch)) {\n throw new TestWoodError(`${absolutePath}: \"stitch\" must be a list of YAML files or globs`);\n }\n const manifestDir = path.dirname(absolutePath);\n const files: string[] = [];\n for (const entry of doc.stitch) {\n if (typeof entry !== 'string' || !entry.length) {\n throw new TestWoodError(`${absolutePath}: every \"stitch\" entry must be a non-empty string`);\n }\n files.push(...expandStitchEntry(entry, manifestDir));\n }\n return files;\n}\n\nfunction expandStitchEntry(entry: string, manifestDir: string): string[] {\n if (!GLOB_MAGIC.test(entry)) return [path.resolve(manifestDir, entry)];\n return globSync(entry, { cwd: manifestDir, absolute: true, nodir: true }).sort();\n}\n\nfunction loadOperations(files: string[]): Map<string, OperationDef> {\n const merged = new Map<string, OperationDef>();\n for (const file of files) {\n for (const [channel, operation] of parseOperations(fs.readFileSync(file, 'utf-8'))) {\n if (!merged.has(channel)) merged.set(channel, operation);\n }\n }\n return merged;\n}\n\n/** Views documents only; a stitched directory may hold other YAML kinds. */\nfunction loadViews(files: string[]): ViewDef[] {\n const views: ViewDef[] = [];\n for (const file of files) {\n const content = fs.readFileSync(file, 'utf-8');\n if (!/^view:/m.test(content)) continue;\n views.push(...parseViews(content));\n }\n return views;\n}\n\nexport function loadWoodConfigSource(configPath: string): WoodConfigSource {\n if (typeof configPath !== 'string' || !configPath.length) {\n throw new TestWoodError('testWood(configPath) requires the path to a wood.config.yml');\n }\n const resolvedConfigPath = path.resolve(configPath);\n if (!fs.existsSync(resolvedConfigPath)) {\n throw new TestWoodError(`testWood(configPath): config file not found: ${resolvedConfigPath}`);\n }\n const config = parseConfig(resolvedConfigPath);\n const configDir = path.dirname(resolvedConfigPath);\n const fromConfig = (relative: string): string => path.resolve(configDir, relative);\n\n const mainControllersDir = fromConfig(config.main.controllers);\n const rendererComponentDir = fromConfig(config.renderer.componentDir);\n let views: ViewDef[] | null = null;\n\n return {\n configPath: resolvedConfigPath,\n configDir,\n config,\n operations: loadOperations(expandOpenapiFiles(fromConfig(config.main.openapi))),\n mainControllersDir,\n mainMiddlewareDir: fromConfig(config.main.middleware),\n rendererComponentDir,\n views: () => {\n views ??= loadViews(expandOpenapiFiles(fromConfig(config.renderer.openapi)));\n return views;\n },\n mainControllerFile: (identity) => {\n const file = resolveControllerFile(identity, mainControllersDir);\n if (file) return file;\n throw new TestWoodError(\n `no controller file for identity \"${identity}\" under ${mainControllersDir}; looked for:\\n ` +\n controllerFileCandidates(identity, mainControllersDir).join('\\n '),\n );\n },\n rendererControllerFile: (reference) => {\n const file = path.resolve(rendererComponentDir, reference);\n if (fs.existsSync(file)) return file;\n throw new TestWoodError(`renderer controller \"${reference}\" not found at ${file}`);\n },\n hookModule: (relative) => (relative ? fromConfig(relative) : null),\n };\n}\n\n/** Import a hook module declared in the config and return its default export. */\nexport async function importDefaultExport<T>(\n importer: ModuleImporter,\n absolutePath: string,\n what: string,\n): Promise<T> {\n const mod = (await importer(absolutePath)) as { default?: unknown };\n if (mod.default === undefined) {\n throw new TestWoodError(`${what} module ${absolutePath} has no default export`);\n }\n return mod.default as T;\n}\n"],"mappings":"AAUA,OAAO,QAAQ;AACf,OAAO,UAAU;AACjB,SAAS,qBAAqB;AAC9B,OAAO,UAAU;AACjB,SAAS,gBAAgB;AACzB,SAAS,mBAAmB;AAE5B,SAAS,uBAAuB;AAChC,SAAS,kBAAkB;AAE3B;AAAA,EACE;AAAA,EACA;AAAA,OACK;AACP,SAAS,qBAAqB;AAKvB,MAAM,kBAAkC,CAAC,iBAC9C;AAAA;AAAA,EAA0B,cAAc,YAAY,EAAE;AAAA;AAyBxD,MAAM,aAAa;AAOZ,SAAS,mBAAmB,cAAgC;AACjE,QAAM,MAAM,KAAK,KAAK,GAAG,aAAa,cAAc,OAAO,CAAC;AAC5D,MAAI,CAAC,OAAO,OAAO,QAAQ,YAAY,EAAE,YAAY,KAAM,QAAO,CAAC,YAAY;AAC/E,MAAI,CAAC,MAAM,QAAQ,IAAI,MAAM,GAAG;AAC9B,UAAM,IAAI,cAAc,GAAG,YAAY,kDAAkD;AAAA,EAC3F;AACA,QAAM,cAAc,KAAK,QAAQ,YAAY;AAC7C,QAAM,QAAkB,CAAC;AACzB,aAAW,SAAS,IAAI,QAAQ;AAC9B,QAAI,OAAO,UAAU,YAAY,CAAC,MAAM,QAAQ;AAC9C,YAAM,IAAI,cAAc,GAAG,YAAY,mDAAmD;AAAA,IAC5F;AACA,UAAM,KAAK,GAAG,kBAAkB,OAAO,WAAW,CAAC;AAAA,EACrD;AACA,SAAO;AACT;AAEA,SAAS,kBAAkB,OAAe,aAA+B;AACvE,MAAI,CAAC,WAAW,KAAK,KAAK,EAAG,QAAO,CAAC,KAAK,QAAQ,aAAa,KAAK,CAAC;AACrE,SAAO,SAAS,OAAO,EAAE,KAAK,aAAa,UAAU,MAAM,OAAO,KAAK,CAAC,EAAE,KAAK;AACjF;AAEA,SAAS,eAAe,OAA4C;AAClE,QAAM,SAAS,oBAAI,IAA0B;AAC7C,aAAW,QAAQ,OAAO;AACxB,eAAW,CAAC,SAAS,SAAS,KAAK,gBAAgB,GAAG,aAAa,MAAM,OAAO,CAAC,GAAG;AAClF,UAAI,CAAC,OAAO,IAAI,OAAO,EAAG,QAAO,IAAI,SAAS,SAAS;AAAA,IACzD;AAAA,EACF;AACA,SAAO;AACT;AAGA,SAAS,UAAU,OAA4B;AAC7C,QAAM,QAAmB,CAAC;AAC1B,aAAW,QAAQ,OAAO;AACxB,UAAM,UAAU,GAAG,aAAa,MAAM,OAAO;AAC7C,QAAI,CAAC,UAAU,KAAK,OAAO,EAAG;AAC9B,UAAM,KAAK,GAAG,WAAW,OAAO,CAAC;AAAA,EACnC;AACA,SAAO;AACT;AAEO,SAAS,qBAAqB,YAAsC;AACzE,MAAI,OAAO,eAAe,YAAY,CAAC,WAAW,QAAQ;AACxD,UAAM,IAAI,cAAc,6DAA6D;AAAA,EACvF;AACA,QAAM,qBAAqB,KAAK,QAAQ,UAAU;AAClD,MAAI,CAAC,GAAG,WAAW,kBAAkB,GAAG;AACtC,UAAM,IAAI,cAAc,gDAAgD,kBAAkB,EAAE;AAAA,EAC9F;AACA,QAAM,SAAS,YAAY,kBAAkB;AAC7C,QAAM,YAAY,KAAK,QAAQ,kBAAkB;AACjD,QAAM,aAAa,CAAC,aAA6B,KAAK,QAAQ,WAAW,QAAQ;AAEjF,QAAM,qBAAqB,WAAW,OAAO,KAAK,WAAW;AAC7D,QAAM,uBAAuB,WAAW,OAAO,SAAS,YAAY;AACpE,MAAI,QAA0B;AAE9B,SAAO;AAAA,IACL,YAAY;AAAA,IACZ;AAAA,IACA;AAAA,IACA,YAAY,eAAe,mBAAmB,WAAW,OAAO,KAAK,OAAO,CAAC,CAAC;AAAA,IAC9E;AAAA,IACA,mBAAmB,WAAW,OAAO,KAAK,UAAU;AAAA,IACpD;AAAA,IACA,OAAO,MAAM;AACX,wBAAU,UAAU,mBAAmB,WAAW,OAAO,SAAS,OAAO,CAAC,CAAC;AAC3E,aAAO;AAAA,IACT;AAAA,IACA,oBAAoB,CAAC,aAAa;AAChC,YAAM,OAAO,sBAAsB,UAAU,kBAAkB;AAC/D,UAAI,KAAM,QAAO;AACjB,YAAM,IAAI;AAAA,QACR,oCAAoC,QAAQ,WAAW,kBAAkB;AAAA,MACzE,yBAAyB,UAAU,kBAAkB,EAAE,KAAK,MAAM;AAAA,MACpE;AAAA,IACF;AAAA,IACA,wBAAwB,CAAC,cAAc;AACrC,YAAM,OAAO,KAAK,QAAQ,sBAAsB,SAAS;AACzD,UAAI,GAAG,WAAW,IAAI,EAAG,QAAO;AAChC,YAAM,IAAI,cAAc,wBAAwB,SAAS,kBAAkB,IAAI,EAAE;AAAA,IACnF;AAAA,IACA,YAAY,CAAC,aAAc,WAAW,WAAW,QAAQ,IAAI;AAAA,EAC/D;AACF;AAGA,eAAsB,oBACpB,UACA,cACA,MACY;AACZ,QAAM,MAAO,MAAM,SAAS,YAAY;AACxC,MAAI,IAAI,YAAY,QAAW;AAC7B,UAAM,IAAI,cAAc,GAAG,IAAI,WAAW,YAAY,wBAAwB;AAAA,EAChF;AACA,SAAO,IAAI;AACb;","names":[]}
|
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
var wood_env_renderer_exports = {};
|
|
20
|
+
__export(wood_env_renderer_exports, {
|
|
21
|
+
buildRendererTier: () => buildRendererTier
|
|
22
|
+
});
|
|
23
|
+
module.exports = __toCommonJS(wood_env_renderer_exports);
|
|
24
|
+
var import_ioc = require("@noego/ioc");
|
|
25
|
+
var import_in_process_router_transport = require("../transport/in_process_router_transport.js");
|
|
26
|
+
var import_build_transport_bridge = require("../transport/build_transport_bridge.js");
|
|
27
|
+
var import_create_router_bridge = require("./create_router_bridge.js");
|
|
28
|
+
var import_navigation = require("../navigation/index.js");
|
|
29
|
+
var import_get_container = require("../runtime/get_container.js");
|
|
30
|
+
var import_work_registry = require("../frontend/work_registry.js");
|
|
31
|
+
var import_tracked_transport = require("../frontend/tracked_transport.js");
|
|
32
|
+
var import_frontend_surface = require("../frontend/frontend_surface.js");
|
|
33
|
+
var import_test_wood = require("./test_wood.cjs");
|
|
34
|
+
var import_wood_config_source = require("./wood_config_source.cjs");
|
|
35
|
+
function controllerLoader(source, importer) {
|
|
36
|
+
const cache = /* @__PURE__ */ new Map();
|
|
37
|
+
return (identity) => {
|
|
38
|
+
let pending = cache.get(identity);
|
|
39
|
+
if (!pending) {
|
|
40
|
+
pending = (0, import_wood_config_source.importDefaultExport)(
|
|
41
|
+
importer,
|
|
42
|
+
source.rendererControllerFile(identity),
|
|
43
|
+
`renderer controller "${identity}"`
|
|
44
|
+
);
|
|
45
|
+
cache.set(identity, pending);
|
|
46
|
+
}
|
|
47
|
+
return pending;
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
async function loadPageHost(source, importer, dom) {
|
|
51
|
+
if (dom === "chromium") {
|
|
52
|
+
throw new import_test_wood.TestWoodError("select({ dom: 'chromium' }) is not available yet; use 'happy-dom'");
|
|
53
|
+
}
|
|
54
|
+
if (typeof document === "undefined") {
|
|
55
|
+
throw new import_test_wood.TestWoodError(
|
|
56
|
+
"select({ dom: 'happy-dom' }) requires a DOM environment (// @vitest-environment happy-dom)"
|
|
57
|
+
);
|
|
58
|
+
}
|
|
59
|
+
const hostPath = source.hookModule(source.config.renderer.testing?.host);
|
|
60
|
+
if (!hostPath) {
|
|
61
|
+
throw new import_test_wood.TestWoodError(
|
|
62
|
+
"select({ dom }) requires renderer.testing.host in wood.config.yml (a module whose default export mounts a page)"
|
|
63
|
+
);
|
|
64
|
+
}
|
|
65
|
+
return (0, import_wood_config_source.importDefaultExport)(importer, hostPath, "renderer.testing.host");
|
|
66
|
+
}
|
|
67
|
+
class MountKeeper {
|
|
68
|
+
constructor(host) {
|
|
69
|
+
this.host = host;
|
|
70
|
+
this.mounted = null;
|
|
71
|
+
this.mountedFor = null;
|
|
72
|
+
}
|
|
73
|
+
get target() {
|
|
74
|
+
if (!this.mounted) throw new import_test_wood.TestWoodError("no page is mounted; open(page) first");
|
|
75
|
+
return this.mounted.target;
|
|
76
|
+
}
|
|
77
|
+
async flush() {
|
|
78
|
+
await this.mounted?.flush?.();
|
|
79
|
+
}
|
|
80
|
+
sync(current) {
|
|
81
|
+
if (current === this.mountedFor) return;
|
|
82
|
+
this.unmount();
|
|
83
|
+
if (!current) return;
|
|
84
|
+
const target = document.createElement("div");
|
|
85
|
+
document.body.appendChild(target);
|
|
86
|
+
this.mounted = this.host(current.identity, current, target);
|
|
87
|
+
this.mountedFor = current;
|
|
88
|
+
}
|
|
89
|
+
unmount() {
|
|
90
|
+
this.mounted?.unmount();
|
|
91
|
+
this.mounted?.target.remove();
|
|
92
|
+
this.mounted = null;
|
|
93
|
+
this.mountedFor = null;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
function domDriver(keeper) {
|
|
97
|
+
const find = (selector) => {
|
|
98
|
+
const found = keeper.target.querySelector(selector);
|
|
99
|
+
if (!found) throw new import_test_wood.TestWoodError(`no element matches "${selector}"`);
|
|
100
|
+
return found;
|
|
101
|
+
};
|
|
102
|
+
return {
|
|
103
|
+
get target() {
|
|
104
|
+
return keeper.target;
|
|
105
|
+
},
|
|
106
|
+
async click(selector) {
|
|
107
|
+
find(selector).click();
|
|
108
|
+
await keeper.flush();
|
|
109
|
+
},
|
|
110
|
+
async type(selector, text) {
|
|
111
|
+
const input = find(selector);
|
|
112
|
+
input.focus();
|
|
113
|
+
input.value = text;
|
|
114
|
+
input.dispatchEvent(new Event("input", { bubbles: true }));
|
|
115
|
+
await keeper.flush();
|
|
116
|
+
},
|
|
117
|
+
async submit(selector) {
|
|
118
|
+
find(selector).dispatchEvent(new Event("submit", { bubbles: true, cancelable: true }));
|
|
119
|
+
await keeper.flush();
|
|
120
|
+
},
|
|
121
|
+
async text(selector) {
|
|
122
|
+
return keeper.target.querySelector(selector)?.textContent ?? "";
|
|
123
|
+
},
|
|
124
|
+
async exists(selector) {
|
|
125
|
+
return keeper.target.querySelector(selector) !== null;
|
|
126
|
+
}
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
async function buildRendererTier(options) {
|
|
130
|
+
const { source, router, catalog, operations, importer, hooks, dom } = options;
|
|
131
|
+
const keeper = dom ? new MountKeeper(await loadPageHost(source, importer, dom)) : null;
|
|
132
|
+
const rendererRoot = (0, import_get_container.createWoodRoot)();
|
|
133
|
+
await hooks?.configureRendererRoot?.(rendererRoot);
|
|
134
|
+
const registry = new import_work_registry.WorkRegistry();
|
|
135
|
+
const navigation = new import_navigation.Navigation();
|
|
136
|
+
const innerTransport = new import_in_process_router_transport.InProcessRouterTransport(router, hooks?.events ?? new import_create_router_bridge.RouterBridgeEvents());
|
|
137
|
+
let currentOwner = () => "application";
|
|
138
|
+
const transport = new import_tracked_transport.TrackedTransport(innerTransport, registry, () => currentOwner());
|
|
139
|
+
const { bridge } = (0, import_build_transport_bridge.buildTransportBridge)(operations, transport);
|
|
140
|
+
const registrable = rendererRoot;
|
|
141
|
+
registrable.registerFunction(import_navigation.Navigation, () => navigation, { loadAs: import_ioc.LoadAs.Singleton });
|
|
142
|
+
registrable.registerFunction(import_test_wood.WOOD_FRONTEND_BRIDGE, () => bridge, { loadAs: import_ioc.LoadAs.Singleton });
|
|
143
|
+
const loadController = controllerLoader(source, importer);
|
|
144
|
+
const frontend = (0, import_frontend_surface.createFrontendSurface)({
|
|
145
|
+
catalog,
|
|
146
|
+
rendererRoot,
|
|
147
|
+
registry,
|
|
148
|
+
navigation,
|
|
149
|
+
resolveController: (identity) => loadController(identity),
|
|
150
|
+
...hooks?.configurePageScope ? { configurePageScope: (scope, view, context) => hooks.configurePageScope(scope, view, context) } : {}
|
|
151
|
+
});
|
|
152
|
+
currentOwner = () => {
|
|
153
|
+
const current = frontend.current();
|
|
154
|
+
return current ? `page ${current.identity}` : "application";
|
|
155
|
+
};
|
|
156
|
+
const syncMount = async () => {
|
|
157
|
+
if (!keeper) return;
|
|
158
|
+
keeper.sync(frontend.current());
|
|
159
|
+
await keeper.flush();
|
|
160
|
+
};
|
|
161
|
+
const settle = async () => {
|
|
162
|
+
await frontend.settle();
|
|
163
|
+
if (!keeper) return;
|
|
164
|
+
await syncMount();
|
|
165
|
+
await new Promise((resolve) => setTimeout(resolve, 0));
|
|
166
|
+
await keeper.flush();
|
|
167
|
+
};
|
|
168
|
+
return {
|
|
169
|
+
frontend,
|
|
170
|
+
events: innerTransport.events,
|
|
171
|
+
rendererRoot,
|
|
172
|
+
async open(page, params, query) {
|
|
173
|
+
const opened = await frontend.open({
|
|
174
|
+
page,
|
|
175
|
+
...params ? { params } : {},
|
|
176
|
+
...query ? { query } : {}
|
|
177
|
+
});
|
|
178
|
+
await syncMount();
|
|
179
|
+
return opened;
|
|
180
|
+
},
|
|
181
|
+
async navigate(page, params, query) {
|
|
182
|
+
if (!frontend.current()) throw new import_test_wood.TestWoodError("navigate() needs an open page; call open(page) first");
|
|
183
|
+
await frontend.act(() => navigation.go(page, params, query));
|
|
184
|
+
await syncMount();
|
|
185
|
+
const current = frontend.current();
|
|
186
|
+
if (!current) throw new import_test_wood.TestWoodError(`navigate("${page}") left no page open`);
|
|
187
|
+
return current;
|
|
188
|
+
},
|
|
189
|
+
current: () => frontend.current(),
|
|
190
|
+
settle,
|
|
191
|
+
pendingWork: () => registry.pending(),
|
|
192
|
+
dom: keeper ? domDriver(keeper) : null,
|
|
193
|
+
async dispose() {
|
|
194
|
+
keeper?.unmount();
|
|
195
|
+
await import_ioc.ExecutionContext.run(rendererRoot, async () => {
|
|
196
|
+
await frontend.settle().catch(() => {
|
|
197
|
+
});
|
|
198
|
+
await frontend.dispose();
|
|
199
|
+
await frontend.settle().catch(() => {
|
|
200
|
+
});
|
|
201
|
+
await rendererRoot.dispose();
|
|
202
|
+
});
|
|
203
|
+
}
|
|
204
|
+
};
|
|
205
|
+
}
|
|
206
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
207
|
+
0 && (module.exports = {
|
|
208
|
+
buildRendererTier
|
|
209
|
+
});
|
|
210
|
+
//# sourceMappingURL=wood_env_renderer.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/testing/wood_env_renderer.ts"],"sourcesContent":["/**\n * The renderer tier of a `testWood(configPath)` environment: a fresh renderer\n * root (mirroring the production process split), an environment-local\n * Navigation, the generated bridge client over an in-process transport into\n * the main router, and the frontend application surface over the selected\n * page catalog. With a DOM mode, the page's real component is mounted by the\n * app's host module and driven through a selector-based surface.\n */\nimport type { IContainer } from '@noego/ioc';\nimport { ExecutionContext, LoadAs } from '@noego/ioc';\nimport type { WoodRouter } from '../router/wood_router.cjs';\nimport { InProcessRouterTransport } from '../transport/in_process_router_transport.js';\nimport { buildTransportBridge } from '../transport/build_transport_bridge.js';\nimport { RouterBridgeEvents } from './create_router_bridge.js';\nimport type { OperationDef, ViewDef } from '../types/index.cjs';\nimport { Navigation } from '../navigation/index.js';\nimport { createWoodRoot } from '../runtime/get_container.js';\nimport type { PageCatalog } from '../frontend/page_catalog.js';\nimport { WorkRegistry } from '../frontend/work_registry.js';\nimport { TrackedTransport } from '../frontend/tracked_transport.js';\nimport {\n createFrontendSurface,\n type FrontendApplicationSurface,\n type PageScopeContext,\n} from '../frontend/frontend_surface.js';\nimport type { FrontendPage } from '../frontend/frontend_page.js';\nimport { TestWoodError, WOOD_FRONTEND_BRIDGE } from './test_wood.cjs';\nimport { importDefaultExport, type ModuleImporter, type WoodConfigSource } from './wood_config_source.cjs';\nimport type { WoodDomMode } from './wood_test_selection.cjs';\n\n/** What the app's `main.testing.compose` module may hand back for the renderer side. */\nexport interface WoodRendererHooks {\n /** Backend push emitter feeding renderer subscriptions (default: transport-owned). */\n events?: RouterBridgeEvents;\n /** Register app-owned renderer composition on the fresh renderer root. */\n configureRendererRoot?(root: IContainer): void | Promise<void>;\n /** Register per-scope renderer builtins on a new page/layout scope. */\n configurePageScope?(scope: IContainer, view: ViewDef, context: PageScopeContext): void | Promise<void>;\n}\n\n/** A page's real component mounted under a DOM driver (`renderer.testing.host`). */\nexport interface WoodMountedPage {\n readonly target: Element;\n flush?(): void | Promise<void>;\n unmount(): void;\n}\n\nexport type WoodPageHost = (identity: string, page: FrontendPage, target: Element) => WoodMountedPage;\n\nexport interface RendererTierOptions {\n source: WoodConfigSource;\n router: WoodRouter;\n catalog: PageCatalog;\n operations: Map<string, OperationDef>;\n importer: ModuleImporter;\n hooks: WoodRendererHooks | null;\n dom: WoodDomMode | null;\n}\n\nexport interface WoodDomDriver {\n readonly target: Element;\n click(selector: string): Promise<void>;\n type(selector: string, text: string): Promise<void>;\n submit(selector: string): Promise<void>;\n text(selector: string): Promise<string>;\n exists(selector: string): Promise<boolean>;\n}\n\nexport interface RendererTier {\n readonly frontend: FrontendApplicationSurface;\n readonly events: RouterBridgeEvents;\n readonly rendererRoot: IContainer;\n open(page: string, params?: Record<string, string>, query?: Record<string, string>): Promise<FrontendPage>;\n navigate(page: string, params?: Record<string, string>, query?: Record<string, string>): Promise<FrontendPage>;\n current(): FrontendPage | null;\n settle(): Promise<void>;\n pendingWork(): ReturnType<WorkRegistry['pending']>;\n dom: WoodDomDriver | null;\n dispose(): Promise<void>;\n}\n\ntype ControllerClass = new (...args: never[]) => unknown;\n\nfunction controllerLoader(source: WoodConfigSource, importer: ModuleImporter) {\n const cache = new Map<string, Promise<ControllerClass>>();\n return (identity: string): Promise<ControllerClass> => {\n let pending = cache.get(identity);\n if (!pending) {\n pending = importDefaultExport<ControllerClass>(\n importer,\n source.rendererControllerFile(identity),\n `renderer controller \"${identity}\"`,\n );\n cache.set(identity, pending);\n }\n return pending;\n };\n}\n\nasync function loadPageHost(\n source: WoodConfigSource,\n importer: ModuleImporter,\n dom: WoodDomMode,\n): Promise<WoodPageHost> {\n if (dom === 'chromium') {\n throw new TestWoodError(\"select({ dom: 'chromium' }) is not available yet; use 'happy-dom'\");\n }\n if (typeof document === 'undefined') {\n throw new TestWoodError(\n \"select({ dom: 'happy-dom' }) requires a DOM environment (// @vitest-environment happy-dom)\",\n );\n }\n const hostPath = source.hookModule(source.config.renderer.testing?.host);\n if (!hostPath) {\n throw new TestWoodError(\n 'select({ dom }) requires renderer.testing.host in wood.config.yml (a module whose default export mounts a page)',\n );\n }\n return importDefaultExport<WoodPageHost>(importer, hostPath, 'renderer.testing.host');\n}\n\n/** Keeps the mounted component in step with the surface's current page. */\nclass MountKeeper {\n private mounted: WoodMountedPage | null = null;\n private mountedFor: FrontendPage | null = null;\n\n constructor(private readonly host: WoodPageHost) {}\n\n get target(): Element {\n if (!this.mounted) throw new TestWoodError('no page is mounted; open(page) first');\n return this.mounted.target;\n }\n\n async flush(): Promise<void> {\n await this.mounted?.flush?.();\n }\n\n sync(current: FrontendPage | null): void {\n if (current === this.mountedFor) return;\n this.unmount();\n if (!current) return;\n const target = document.createElement('div');\n document.body.appendChild(target);\n this.mounted = this.host(current.identity, current, target);\n this.mountedFor = current;\n }\n\n unmount(): void {\n this.mounted?.unmount();\n this.mounted?.target.remove();\n this.mounted = null;\n this.mountedFor = null;\n }\n}\n\nfunction domDriver(keeper: MountKeeper): WoodDomDriver {\n const find = (selector: string): Element => {\n const found = keeper.target.querySelector(selector);\n if (!found) throw new TestWoodError(`no element matches \"${selector}\"`);\n return found;\n };\n return {\n get target() {\n return keeper.target;\n },\n async click(selector) {\n (find(selector) as HTMLElement).click();\n await keeper.flush();\n },\n async type(selector, text) {\n const input = find(selector) as HTMLInputElement;\n input.focus();\n input.value = text;\n input.dispatchEvent(new Event('input', { bubbles: true }));\n await keeper.flush();\n },\n async submit(selector) {\n find(selector).dispatchEvent(new Event('submit', { bubbles: true, cancelable: true }));\n await keeper.flush();\n },\n async text(selector) {\n return keeper.target.querySelector(selector)?.textContent ?? '';\n },\n async exists(selector) {\n return keeper.target.querySelector(selector) !== null;\n },\n };\n}\n\nexport async function buildRendererTier(options: RendererTierOptions): Promise<RendererTier> {\n const { source, router, catalog, operations, importer, hooks, dom } = options;\n const keeper = dom ? new MountKeeper(await loadPageHost(source, importer, dom)) : null;\n\n const rendererRoot = createWoodRoot();\n await hooks?.configureRendererRoot?.(rendererRoot);\n\n const registry = new WorkRegistry();\n const navigation = new Navigation();\n const innerTransport = new InProcessRouterTransport(router, hooks?.events ?? new RouterBridgeEvents());\n let currentOwner: () => string = () => 'application';\n const transport = new TrackedTransport(innerTransport, registry, () => currentOwner());\n const { bridge } = buildTransportBridge(operations, transport);\n\n const registrable = rendererRoot as unknown as {\n registerFunction(token: unknown, factory: () => unknown, options: { loadAs: LoadAs }): void;\n };\n registrable.registerFunction(Navigation, () => navigation, { loadAs: LoadAs.Singleton });\n registrable.registerFunction(WOOD_FRONTEND_BRIDGE, () => bridge, { loadAs: LoadAs.Singleton });\n\n const loadController = controllerLoader(source, importer);\n const frontend = createFrontendSurface({\n catalog,\n rendererRoot: rendererRoot as never,\n registry,\n navigation,\n resolveController: (identity) => loadController(identity),\n ...(hooks?.configurePageScope\n ? { configurePageScope: (scope, view, context) => hooks.configurePageScope!(scope as IContainer, view, context) }\n : {}),\n });\n currentOwner = () => {\n const current = frontend.current();\n return current ? `page ${current.identity}` : 'application';\n };\n\n const syncMount = async (): Promise<void> => {\n if (!keeper) return;\n keeper.sync(frontend.current());\n await keeper.flush();\n };\n const settle = async (): Promise<void> => {\n await frontend.settle();\n if (!keeper) return;\n await syncMount();\n await new Promise<void>((resolve) => setTimeout(resolve, 0));\n await keeper.flush();\n };\n\n return {\n frontend,\n events: innerTransport.events,\n rendererRoot,\n async open(page, params, query) {\n const opened = await frontend.open({\n page,\n ...(params ? { params } : {}),\n ...(query ? { query } : {}),\n });\n await syncMount();\n return opened;\n },\n async navigate(page, params, query) {\n if (!frontend.current()) throw new TestWoodError('navigate() needs an open page; call open(page) first');\n await frontend.act(() => navigation.go(page, params, query));\n await syncMount();\n const current = frontend.current();\n if (!current) throw new TestWoodError(`navigate(\"${page}\") left no page open`);\n return current;\n },\n current: () => frontend.current(),\n settle,\n pendingWork: () => registry.pending(),\n dom: keeper ? domDriver(keeper) : null,\n async dispose() {\n keeper?.unmount();\n await ExecutionContext.run(rendererRoot as never, async () => {\n // Drain owned work while the transport still reaches a live main\n // root, end the pages, then drain the teardown's own deliveries.\n await frontend.settle().catch(() => {});\n await frontend.dispose();\n await frontend.settle().catch(() => {});\n await rendererRoot.dispose();\n });\n },\n };\n}\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { IContainer } from '@noego/ioc';
|
|
2
|
+
import { WoodRouter } from '../router/wood_router.cjs';
|
|
3
|
+
import { RouterBridgeEvents } from './create_router_bridge.cjs';
|
|
4
|
+
import { OperationDef } from '../types/operations.cjs';
|
|
5
|
+
import { ViewDef } from '../types/views.cjs';
|
|
6
|
+
import { PageCatalog } from '../frontend/page_catalog.cjs';
|
|
7
|
+
import { WorkRegistry } from '../frontend/work_registry.cjs';
|
|
8
|
+
import { PageScopeContext, FrontendApplicationSurface } from '../frontend/frontend_surface.cjs';
|
|
9
|
+
import { FrontendPage } from '../frontend/frontend_page.cjs';
|
|
10
|
+
import { WoodConfigSource, ModuleImporter } from './wood_config_source.cjs';
|
|
11
|
+
import { WoodDomMode } from './wood_test_selection.cjs';
|
|
12
|
+
import '../types/context.cjs';
|
|
13
|
+
import '../navigation/index.cjs';
|
|
14
|
+
import '../navigation/automation_introspection.cjs';
|
|
15
|
+
import '../frontend/frontend_lifecycle.cjs';
|
|
16
|
+
import '../types/config.cjs';
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* The renderer tier of a `testWood(configPath)` environment: a fresh renderer
|
|
20
|
+
* root (mirroring the production process split), an environment-local
|
|
21
|
+
* Navigation, the generated bridge client over an in-process transport into
|
|
22
|
+
* the main router, and the frontend application surface over the selected
|
|
23
|
+
* page catalog. With a DOM mode, the page's real component is mounted by the
|
|
24
|
+
* app's host module and driven through a selector-based surface.
|
|
25
|
+
*/
|
|
26
|
+
|
|
27
|
+
/** What the app's `main.testing.compose` module may hand back for the renderer side. */
|
|
28
|
+
interface WoodRendererHooks {
|
|
29
|
+
/** Backend push emitter feeding renderer subscriptions (default: transport-owned). */
|
|
30
|
+
events?: RouterBridgeEvents;
|
|
31
|
+
/** Register app-owned renderer composition on the fresh renderer root. */
|
|
32
|
+
configureRendererRoot?(root: IContainer): void | Promise<void>;
|
|
33
|
+
/** Register per-scope renderer builtins on a new page/layout scope. */
|
|
34
|
+
configurePageScope?(scope: IContainer, view: ViewDef, context: PageScopeContext): void | Promise<void>;
|
|
35
|
+
}
|
|
36
|
+
/** A page's real component mounted under a DOM driver (`renderer.testing.host`). */
|
|
37
|
+
interface WoodMountedPage {
|
|
38
|
+
readonly target: Element;
|
|
39
|
+
flush?(): void | Promise<void>;
|
|
40
|
+
unmount(): void;
|
|
41
|
+
}
|
|
42
|
+
type WoodPageHost = (identity: string, page: FrontendPage, target: Element) => WoodMountedPage;
|
|
43
|
+
interface RendererTierOptions {
|
|
44
|
+
source: WoodConfigSource;
|
|
45
|
+
router: WoodRouter;
|
|
46
|
+
catalog: PageCatalog;
|
|
47
|
+
operations: Map<string, OperationDef>;
|
|
48
|
+
importer: ModuleImporter;
|
|
49
|
+
hooks: WoodRendererHooks | null;
|
|
50
|
+
dom: WoodDomMode | null;
|
|
51
|
+
}
|
|
52
|
+
interface WoodDomDriver {
|
|
53
|
+
readonly target: Element;
|
|
54
|
+
click(selector: string): Promise<void>;
|
|
55
|
+
type(selector: string, text: string): Promise<void>;
|
|
56
|
+
submit(selector: string): Promise<void>;
|
|
57
|
+
text(selector: string): Promise<string>;
|
|
58
|
+
exists(selector: string): Promise<boolean>;
|
|
59
|
+
}
|
|
60
|
+
interface RendererTier {
|
|
61
|
+
readonly frontend: FrontendApplicationSurface;
|
|
62
|
+
readonly events: RouterBridgeEvents;
|
|
63
|
+
readonly rendererRoot: IContainer;
|
|
64
|
+
open(page: string, params?: Record<string, string>, query?: Record<string, string>): Promise<FrontendPage>;
|
|
65
|
+
navigate(page: string, params?: Record<string, string>, query?: Record<string, string>): Promise<FrontendPage>;
|
|
66
|
+
current(): FrontendPage | null;
|
|
67
|
+
settle(): Promise<void>;
|
|
68
|
+
pendingWork(): ReturnType<WorkRegistry['pending']>;
|
|
69
|
+
dom: WoodDomDriver | null;
|
|
70
|
+
dispose(): Promise<void>;
|
|
71
|
+
}
|
|
72
|
+
declare function buildRendererTier(options: RendererTierOptions): Promise<RendererTier>;
|
|
73
|
+
|
|
74
|
+
export { type RendererTier, type RendererTierOptions, type WoodDomDriver, type WoodMountedPage, type WoodPageHost, type WoodRendererHooks, buildRendererTier };
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { IContainer } from '@noego/ioc';
|
|
2
|
+
import { WoodRouter } from '../router/wood_router.js';
|
|
3
|
+
import { RouterBridgeEvents } from './create_router_bridge.js';
|
|
4
|
+
import { OperationDef } from '../types/operations.js';
|
|
5
|
+
import { ViewDef } from '../types/views.js';
|
|
6
|
+
import { PageCatalog } from '../frontend/page_catalog.js';
|
|
7
|
+
import { WorkRegistry } from '../frontend/work_registry.js';
|
|
8
|
+
import { PageScopeContext, FrontendApplicationSurface } from '../frontend/frontend_surface.js';
|
|
9
|
+
import { FrontendPage } from '../frontend/frontend_page.js';
|
|
10
|
+
import { WoodConfigSource, ModuleImporter } from './wood_config_source.js';
|
|
11
|
+
import { WoodDomMode } from './wood_test_selection.js';
|
|
12
|
+
import '../types/context.js';
|
|
13
|
+
import '../navigation/index.js';
|
|
14
|
+
import '../navigation/automation_introspection.js';
|
|
15
|
+
import '../frontend/frontend_lifecycle.js';
|
|
16
|
+
import '../types/config.js';
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* The renderer tier of a `testWood(configPath)` environment: a fresh renderer
|
|
20
|
+
* root (mirroring the production process split), an environment-local
|
|
21
|
+
* Navigation, the generated bridge client over an in-process transport into
|
|
22
|
+
* the main router, and the frontend application surface over the selected
|
|
23
|
+
* page catalog. With a DOM mode, the page's real component is mounted by the
|
|
24
|
+
* app's host module and driven through a selector-based surface.
|
|
25
|
+
*/
|
|
26
|
+
|
|
27
|
+
/** What the app's `main.testing.compose` module may hand back for the renderer side. */
|
|
28
|
+
interface WoodRendererHooks {
|
|
29
|
+
/** Backend push emitter feeding renderer subscriptions (default: transport-owned). */
|
|
30
|
+
events?: RouterBridgeEvents;
|
|
31
|
+
/** Register app-owned renderer composition on the fresh renderer root. */
|
|
32
|
+
configureRendererRoot?(root: IContainer): void | Promise<void>;
|
|
33
|
+
/** Register per-scope renderer builtins on a new page/layout scope. */
|
|
34
|
+
configurePageScope?(scope: IContainer, view: ViewDef, context: PageScopeContext): void | Promise<void>;
|
|
35
|
+
}
|
|
36
|
+
/** A page's real component mounted under a DOM driver (`renderer.testing.host`). */
|
|
37
|
+
interface WoodMountedPage {
|
|
38
|
+
readonly target: Element;
|
|
39
|
+
flush?(): void | Promise<void>;
|
|
40
|
+
unmount(): void;
|
|
41
|
+
}
|
|
42
|
+
type WoodPageHost = (identity: string, page: FrontendPage, target: Element) => WoodMountedPage;
|
|
43
|
+
interface RendererTierOptions {
|
|
44
|
+
source: WoodConfigSource;
|
|
45
|
+
router: WoodRouter;
|
|
46
|
+
catalog: PageCatalog;
|
|
47
|
+
operations: Map<string, OperationDef>;
|
|
48
|
+
importer: ModuleImporter;
|
|
49
|
+
hooks: WoodRendererHooks | null;
|
|
50
|
+
dom: WoodDomMode | null;
|
|
51
|
+
}
|
|
52
|
+
interface WoodDomDriver {
|
|
53
|
+
readonly target: Element;
|
|
54
|
+
click(selector: string): Promise<void>;
|
|
55
|
+
type(selector: string, text: string): Promise<void>;
|
|
56
|
+
submit(selector: string): Promise<void>;
|
|
57
|
+
text(selector: string): Promise<string>;
|
|
58
|
+
exists(selector: string): Promise<boolean>;
|
|
59
|
+
}
|
|
60
|
+
interface RendererTier {
|
|
61
|
+
readonly frontend: FrontendApplicationSurface;
|
|
62
|
+
readonly events: RouterBridgeEvents;
|
|
63
|
+
readonly rendererRoot: IContainer;
|
|
64
|
+
open(page: string, params?: Record<string, string>, query?: Record<string, string>): Promise<FrontendPage>;
|
|
65
|
+
navigate(page: string, params?: Record<string, string>, query?: Record<string, string>): Promise<FrontendPage>;
|
|
66
|
+
current(): FrontendPage | null;
|
|
67
|
+
settle(): Promise<void>;
|
|
68
|
+
pendingWork(): ReturnType<WorkRegistry['pending']>;
|
|
69
|
+
dom: WoodDomDriver | null;
|
|
70
|
+
dispose(): Promise<void>;
|
|
71
|
+
}
|
|
72
|
+
declare function buildRendererTier(options: RendererTierOptions): Promise<RendererTier>;
|
|
73
|
+
|
|
74
|
+
export { type RendererTier, type RendererTierOptions, type WoodDomDriver, type WoodMountedPage, type WoodPageHost, type WoodRendererHooks, buildRendererTier };
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
import { ExecutionContext, LoadAs } from "@noego/ioc";
|
|
2
|
+
import { InProcessRouterTransport } from "../transport/in_process_router_transport.js";
|
|
3
|
+
import { buildTransportBridge } from "../transport/build_transport_bridge.js";
|
|
4
|
+
import { RouterBridgeEvents } from "./create_router_bridge.js";
|
|
5
|
+
import { Navigation } from "../navigation/index.js";
|
|
6
|
+
import { createWoodRoot } from "../runtime/get_container.js";
|
|
7
|
+
import { WorkRegistry } from "../frontend/work_registry.js";
|
|
8
|
+
import { TrackedTransport } from "../frontend/tracked_transport.js";
|
|
9
|
+
import {
|
|
10
|
+
createFrontendSurface
|
|
11
|
+
} from "../frontend/frontend_surface.js";
|
|
12
|
+
import { TestWoodError, WOOD_FRONTEND_BRIDGE } from "./test_wood.js";
|
|
13
|
+
import { importDefaultExport } from "./wood_config_source.js";
|
|
14
|
+
function controllerLoader(source, importer) {
|
|
15
|
+
const cache = /* @__PURE__ */ new Map();
|
|
16
|
+
return (identity) => {
|
|
17
|
+
let pending = cache.get(identity);
|
|
18
|
+
if (!pending) {
|
|
19
|
+
pending = importDefaultExport(
|
|
20
|
+
importer,
|
|
21
|
+
source.rendererControllerFile(identity),
|
|
22
|
+
`renderer controller "${identity}"`
|
|
23
|
+
);
|
|
24
|
+
cache.set(identity, pending);
|
|
25
|
+
}
|
|
26
|
+
return pending;
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
async function loadPageHost(source, importer, dom) {
|
|
30
|
+
if (dom === "chromium") {
|
|
31
|
+
throw new TestWoodError("select({ dom: 'chromium' }) is not available yet; use 'happy-dom'");
|
|
32
|
+
}
|
|
33
|
+
if (typeof document === "undefined") {
|
|
34
|
+
throw new TestWoodError(
|
|
35
|
+
"select({ dom: 'happy-dom' }) requires a DOM environment (// @vitest-environment happy-dom)"
|
|
36
|
+
);
|
|
37
|
+
}
|
|
38
|
+
const hostPath = source.hookModule(source.config.renderer.testing?.host);
|
|
39
|
+
if (!hostPath) {
|
|
40
|
+
throw new TestWoodError(
|
|
41
|
+
"select({ dom }) requires renderer.testing.host in wood.config.yml (a module whose default export mounts a page)"
|
|
42
|
+
);
|
|
43
|
+
}
|
|
44
|
+
return importDefaultExport(importer, hostPath, "renderer.testing.host");
|
|
45
|
+
}
|
|
46
|
+
class MountKeeper {
|
|
47
|
+
constructor(host) {
|
|
48
|
+
this.host = host;
|
|
49
|
+
this.mounted = null;
|
|
50
|
+
this.mountedFor = null;
|
|
51
|
+
}
|
|
52
|
+
get target() {
|
|
53
|
+
if (!this.mounted) throw new TestWoodError("no page is mounted; open(page) first");
|
|
54
|
+
return this.mounted.target;
|
|
55
|
+
}
|
|
56
|
+
async flush() {
|
|
57
|
+
await this.mounted?.flush?.();
|
|
58
|
+
}
|
|
59
|
+
sync(current) {
|
|
60
|
+
if (current === this.mountedFor) return;
|
|
61
|
+
this.unmount();
|
|
62
|
+
if (!current) return;
|
|
63
|
+
const target = document.createElement("div");
|
|
64
|
+
document.body.appendChild(target);
|
|
65
|
+
this.mounted = this.host(current.identity, current, target);
|
|
66
|
+
this.mountedFor = current;
|
|
67
|
+
}
|
|
68
|
+
unmount() {
|
|
69
|
+
this.mounted?.unmount();
|
|
70
|
+
this.mounted?.target.remove();
|
|
71
|
+
this.mounted = null;
|
|
72
|
+
this.mountedFor = null;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
function domDriver(keeper) {
|
|
76
|
+
const find = (selector) => {
|
|
77
|
+
const found = keeper.target.querySelector(selector);
|
|
78
|
+
if (!found) throw new TestWoodError(`no element matches "${selector}"`);
|
|
79
|
+
return found;
|
|
80
|
+
};
|
|
81
|
+
return {
|
|
82
|
+
get target() {
|
|
83
|
+
return keeper.target;
|
|
84
|
+
},
|
|
85
|
+
async click(selector) {
|
|
86
|
+
find(selector).click();
|
|
87
|
+
await keeper.flush();
|
|
88
|
+
},
|
|
89
|
+
async type(selector, text) {
|
|
90
|
+
const input = find(selector);
|
|
91
|
+
input.focus();
|
|
92
|
+
input.value = text;
|
|
93
|
+
input.dispatchEvent(new Event("input", { bubbles: true }));
|
|
94
|
+
await keeper.flush();
|
|
95
|
+
},
|
|
96
|
+
async submit(selector) {
|
|
97
|
+
find(selector).dispatchEvent(new Event("submit", { bubbles: true, cancelable: true }));
|
|
98
|
+
await keeper.flush();
|
|
99
|
+
},
|
|
100
|
+
async text(selector) {
|
|
101
|
+
return keeper.target.querySelector(selector)?.textContent ?? "";
|
|
102
|
+
},
|
|
103
|
+
async exists(selector) {
|
|
104
|
+
return keeper.target.querySelector(selector) !== null;
|
|
105
|
+
}
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
async function buildRendererTier(options) {
|
|
109
|
+
const { source, router, catalog, operations, importer, hooks, dom } = options;
|
|
110
|
+
const keeper = dom ? new MountKeeper(await loadPageHost(source, importer, dom)) : null;
|
|
111
|
+
const rendererRoot = createWoodRoot();
|
|
112
|
+
await hooks?.configureRendererRoot?.(rendererRoot);
|
|
113
|
+
const registry = new WorkRegistry();
|
|
114
|
+
const navigation = new Navigation();
|
|
115
|
+
const innerTransport = new InProcessRouterTransport(router, hooks?.events ?? new RouterBridgeEvents());
|
|
116
|
+
let currentOwner = () => "application";
|
|
117
|
+
const transport = new TrackedTransport(innerTransport, registry, () => currentOwner());
|
|
118
|
+
const { bridge } = buildTransportBridge(operations, transport);
|
|
119
|
+
const registrable = rendererRoot;
|
|
120
|
+
registrable.registerFunction(Navigation, () => navigation, { loadAs: LoadAs.Singleton });
|
|
121
|
+
registrable.registerFunction(WOOD_FRONTEND_BRIDGE, () => bridge, { loadAs: LoadAs.Singleton });
|
|
122
|
+
const loadController = controllerLoader(source, importer);
|
|
123
|
+
const frontend = createFrontendSurface({
|
|
124
|
+
catalog,
|
|
125
|
+
rendererRoot,
|
|
126
|
+
registry,
|
|
127
|
+
navigation,
|
|
128
|
+
resolveController: (identity) => loadController(identity),
|
|
129
|
+
...hooks?.configurePageScope ? { configurePageScope: (scope, view, context) => hooks.configurePageScope(scope, view, context) } : {}
|
|
130
|
+
});
|
|
131
|
+
currentOwner = () => {
|
|
132
|
+
const current = frontend.current();
|
|
133
|
+
return current ? `page ${current.identity}` : "application";
|
|
134
|
+
};
|
|
135
|
+
const syncMount = async () => {
|
|
136
|
+
if (!keeper) return;
|
|
137
|
+
keeper.sync(frontend.current());
|
|
138
|
+
await keeper.flush();
|
|
139
|
+
};
|
|
140
|
+
const settle = async () => {
|
|
141
|
+
await frontend.settle();
|
|
142
|
+
if (!keeper) return;
|
|
143
|
+
await syncMount();
|
|
144
|
+
await new Promise((resolve) => setTimeout(resolve, 0));
|
|
145
|
+
await keeper.flush();
|
|
146
|
+
};
|
|
147
|
+
return {
|
|
148
|
+
frontend,
|
|
149
|
+
events: innerTransport.events,
|
|
150
|
+
rendererRoot,
|
|
151
|
+
async open(page, params, query) {
|
|
152
|
+
const opened = await frontend.open({
|
|
153
|
+
page,
|
|
154
|
+
...params ? { params } : {},
|
|
155
|
+
...query ? { query } : {}
|
|
156
|
+
});
|
|
157
|
+
await syncMount();
|
|
158
|
+
return opened;
|
|
159
|
+
},
|
|
160
|
+
async navigate(page, params, query) {
|
|
161
|
+
if (!frontend.current()) throw new TestWoodError("navigate() needs an open page; call open(page) first");
|
|
162
|
+
await frontend.act(() => navigation.go(page, params, query));
|
|
163
|
+
await syncMount();
|
|
164
|
+
const current = frontend.current();
|
|
165
|
+
if (!current) throw new TestWoodError(`navigate("${page}") left no page open`);
|
|
166
|
+
return current;
|
|
167
|
+
},
|
|
168
|
+
current: () => frontend.current(),
|
|
169
|
+
settle,
|
|
170
|
+
pendingWork: () => registry.pending(),
|
|
171
|
+
dom: keeper ? domDriver(keeper) : null,
|
|
172
|
+
async dispose() {
|
|
173
|
+
keeper?.unmount();
|
|
174
|
+
await ExecutionContext.run(rendererRoot, async () => {
|
|
175
|
+
await frontend.settle().catch(() => {
|
|
176
|
+
});
|
|
177
|
+
await frontend.dispose();
|
|
178
|
+
await frontend.settle().catch(() => {
|
|
179
|
+
});
|
|
180
|
+
await rendererRoot.dispose();
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
export {
|
|
186
|
+
buildRendererTier
|
|
187
|
+
};
|
|
188
|
+
//# sourceMappingURL=wood_env_renderer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/testing/wood_env_renderer.ts"],"sourcesContent":["/**\n * The renderer tier of a `testWood(configPath)` environment: a fresh renderer\n * root (mirroring the production process split), an environment-local\n * Navigation, the generated bridge client over an in-process transport into\n * the main router, and the frontend application surface over the selected\n * page catalog. With a DOM mode, the page's real component is mounted by the\n * app's host module and driven through a selector-based surface.\n */\nimport type { IContainer } from '@noego/ioc';\nimport { ExecutionContext, LoadAs } from '@noego/ioc';\nimport type { WoodRouter } from '../router/wood_router.js';\nimport { InProcessRouterTransport } from '../transport/in_process_router_transport.js';\nimport { buildTransportBridge } from '../transport/build_transport_bridge.js';\nimport { RouterBridgeEvents } from './create_router_bridge.js';\nimport type { OperationDef, ViewDef } from '../types/index.js';\nimport { Navigation } from '../navigation/index.js';\nimport { createWoodRoot } from '../runtime/get_container.js';\nimport type { PageCatalog } from '../frontend/page_catalog.js';\nimport { WorkRegistry } from '../frontend/work_registry.js';\nimport { TrackedTransport } from '../frontend/tracked_transport.js';\nimport {\n createFrontendSurface,\n type FrontendApplicationSurface,\n type PageScopeContext,\n} from '../frontend/frontend_surface.js';\nimport type { FrontendPage } from '../frontend/frontend_page.js';\nimport { TestWoodError, WOOD_FRONTEND_BRIDGE } from './test_wood.js';\nimport { importDefaultExport, type ModuleImporter, type WoodConfigSource } from './wood_config_source.js';\nimport type { WoodDomMode } from './wood_test_selection.js';\n\n/** What the app's `main.testing.compose` module may hand back for the renderer side. */\nexport interface WoodRendererHooks {\n /** Backend push emitter feeding renderer subscriptions (default: transport-owned). */\n events?: RouterBridgeEvents;\n /** Register app-owned renderer composition on the fresh renderer root. */\n configureRendererRoot?(root: IContainer): void | Promise<void>;\n /** Register per-scope renderer builtins on a new page/layout scope. */\n configurePageScope?(scope: IContainer, view: ViewDef, context: PageScopeContext): void | Promise<void>;\n}\n\n/** A page's real component mounted under a DOM driver (`renderer.testing.host`). */\nexport interface WoodMountedPage {\n readonly target: Element;\n flush?(): void | Promise<void>;\n unmount(): void;\n}\n\nexport type WoodPageHost = (identity: string, page: FrontendPage, target: Element) => WoodMountedPage;\n\nexport interface RendererTierOptions {\n source: WoodConfigSource;\n router: WoodRouter;\n catalog: PageCatalog;\n operations: Map<string, OperationDef>;\n importer: ModuleImporter;\n hooks: WoodRendererHooks | null;\n dom: WoodDomMode | null;\n}\n\nexport interface WoodDomDriver {\n readonly target: Element;\n click(selector: string): Promise<void>;\n type(selector: string, text: string): Promise<void>;\n submit(selector: string): Promise<void>;\n text(selector: string): Promise<string>;\n exists(selector: string): Promise<boolean>;\n}\n\nexport interface RendererTier {\n readonly frontend: FrontendApplicationSurface;\n readonly events: RouterBridgeEvents;\n readonly rendererRoot: IContainer;\n open(page: string, params?: Record<string, string>, query?: Record<string, string>): Promise<FrontendPage>;\n navigate(page: string, params?: Record<string, string>, query?: Record<string, string>): Promise<FrontendPage>;\n current(): FrontendPage | null;\n settle(): Promise<void>;\n pendingWork(): ReturnType<WorkRegistry['pending']>;\n dom: WoodDomDriver | null;\n dispose(): Promise<void>;\n}\n\ntype ControllerClass = new (...args: never[]) => unknown;\n\nfunction controllerLoader(source: WoodConfigSource, importer: ModuleImporter) {\n const cache = new Map<string, Promise<ControllerClass>>();\n return (identity: string): Promise<ControllerClass> => {\n let pending = cache.get(identity);\n if (!pending) {\n pending = importDefaultExport<ControllerClass>(\n importer,\n source.rendererControllerFile(identity),\n `renderer controller \"${identity}\"`,\n );\n cache.set(identity, pending);\n }\n return pending;\n };\n}\n\nasync function loadPageHost(\n source: WoodConfigSource,\n importer: ModuleImporter,\n dom: WoodDomMode,\n): Promise<WoodPageHost> {\n if (dom === 'chromium') {\n throw new TestWoodError(\"select({ dom: 'chromium' }) is not available yet; use 'happy-dom'\");\n }\n if (typeof document === 'undefined') {\n throw new TestWoodError(\n \"select({ dom: 'happy-dom' }) requires a DOM environment (// @vitest-environment happy-dom)\",\n );\n }\n const hostPath = source.hookModule(source.config.renderer.testing?.host);\n if (!hostPath) {\n throw new TestWoodError(\n 'select({ dom }) requires renderer.testing.host in wood.config.yml (a module whose default export mounts a page)',\n );\n }\n return importDefaultExport<WoodPageHost>(importer, hostPath, 'renderer.testing.host');\n}\n\n/** Keeps the mounted component in step with the surface's current page. */\nclass MountKeeper {\n private mounted: WoodMountedPage | null = null;\n private mountedFor: FrontendPage | null = null;\n\n constructor(private readonly host: WoodPageHost) {}\n\n get target(): Element {\n if (!this.mounted) throw new TestWoodError('no page is mounted; open(page) first');\n return this.mounted.target;\n }\n\n async flush(): Promise<void> {\n await this.mounted?.flush?.();\n }\n\n sync(current: FrontendPage | null): void {\n if (current === this.mountedFor) return;\n this.unmount();\n if (!current) return;\n const target = document.createElement('div');\n document.body.appendChild(target);\n this.mounted = this.host(current.identity, current, target);\n this.mountedFor = current;\n }\n\n unmount(): void {\n this.mounted?.unmount();\n this.mounted?.target.remove();\n this.mounted = null;\n this.mountedFor = null;\n }\n}\n\nfunction domDriver(keeper: MountKeeper): WoodDomDriver {\n const find = (selector: string): Element => {\n const found = keeper.target.querySelector(selector);\n if (!found) throw new TestWoodError(`no element matches \"${selector}\"`);\n return found;\n };\n return {\n get target() {\n return keeper.target;\n },\n async click(selector) {\n (find(selector) as HTMLElement).click();\n await keeper.flush();\n },\n async type(selector, text) {\n const input = find(selector) as HTMLInputElement;\n input.focus();\n input.value = text;\n input.dispatchEvent(new Event('input', { bubbles: true }));\n await keeper.flush();\n },\n async submit(selector) {\n find(selector).dispatchEvent(new Event('submit', { bubbles: true, cancelable: true }));\n await keeper.flush();\n },\n async text(selector) {\n return keeper.target.querySelector(selector)?.textContent ?? '';\n },\n async exists(selector) {\n return keeper.target.querySelector(selector) !== null;\n },\n };\n}\n\nexport async function buildRendererTier(options: RendererTierOptions): Promise<RendererTier> {\n const { source, router, catalog, operations, importer, hooks, dom } = options;\n const keeper = dom ? new MountKeeper(await loadPageHost(source, importer, dom)) : null;\n\n const rendererRoot = createWoodRoot();\n await hooks?.configureRendererRoot?.(rendererRoot);\n\n const registry = new WorkRegistry();\n const navigation = new Navigation();\n const innerTransport = new InProcessRouterTransport(router, hooks?.events ?? new RouterBridgeEvents());\n let currentOwner: () => string = () => 'application';\n const transport = new TrackedTransport(innerTransport, registry, () => currentOwner());\n const { bridge } = buildTransportBridge(operations, transport);\n\n const registrable = rendererRoot as unknown as {\n registerFunction(token: unknown, factory: () => unknown, options: { loadAs: LoadAs }): void;\n };\n registrable.registerFunction(Navigation, () => navigation, { loadAs: LoadAs.Singleton });\n registrable.registerFunction(WOOD_FRONTEND_BRIDGE, () => bridge, { loadAs: LoadAs.Singleton });\n\n const loadController = controllerLoader(source, importer);\n const frontend = createFrontendSurface({\n catalog,\n rendererRoot: rendererRoot as never,\n registry,\n navigation,\n resolveController: (identity) => loadController(identity),\n ...(hooks?.configurePageScope\n ? { configurePageScope: (scope, view, context) => hooks.configurePageScope!(scope as IContainer, view, context) }\n : {}),\n });\n currentOwner = () => {\n const current = frontend.current();\n return current ? `page ${current.identity}` : 'application';\n };\n\n const syncMount = async (): Promise<void> => {\n if (!keeper) return;\n keeper.sync(frontend.current());\n await keeper.flush();\n };\n const settle = async (): Promise<void> => {\n await frontend.settle();\n if (!keeper) return;\n await syncMount();\n await new Promise<void>((resolve) => setTimeout(resolve, 0));\n await keeper.flush();\n };\n\n return {\n frontend,\n events: innerTransport.events,\n rendererRoot,\n async open(page, params, query) {\n const opened = await frontend.open({\n page,\n ...(params ? { params } : {}),\n ...(query ? { query } : {}),\n });\n await syncMount();\n return opened;\n },\n async navigate(page, params, query) {\n if (!frontend.current()) throw new TestWoodError('navigate() needs an open page; call open(page) first');\n await frontend.act(() => navigation.go(page, params, query));\n await syncMount();\n const current = frontend.current();\n if (!current) throw new TestWoodError(`navigate(\"${page}\") left no page open`);\n return current;\n },\n current: () => frontend.current(),\n settle,\n pendingWork: () => registry.pending(),\n dom: keeper ? domDriver(keeper) : null,\n async dispose() {\n keeper?.unmount();\n await ExecutionContext.run(rendererRoot as never, async () => {\n // Drain owned work while the transport still reaches a live main\n // root, end the pages, then drain the teardown's own deliveries.\n await frontend.settle().catch(() => {});\n await frontend.dispose();\n await frontend.settle().catch(() => {});\n await rendererRoot.dispose();\n });\n },\n };\n}\n"],"mappings":"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","names":[]}
|