@noego/wood 0.6.1 → 0.7.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 +7 -0
- package/dist/browser-test-setup.cjs +29 -0
- package/dist/browser-test-setup.cjs.map +1 -0
- package/dist/browser-test-setup.d.cts +8 -0
- package/dist/browser-test-setup.d.ts +8 -0
- package/dist/browser-test-setup.js +9 -0
- package/dist/browser-test-setup.js.map +1 -0
- package/dist/client/global_polyfill.d.cts +1 -0
- package/dist/client/global_polyfill.d.ts +1 -0
- package/dist/client/index.cjs +7 -0
- package/dist/client/index.cjs.map +1 -1
- package/dist/client/index.d.cts +8 -4
- package/dist/client/index.d.ts +8 -4
- package/dist/client/index.js +6 -1
- package/dist/client/index.js.map +1 -1
- package/dist/codegen/renderer_app_generator.cjs +97 -24
- package/dist/codegen/renderer_app_generator.cjs.map +1 -1
- package/dist/codegen/renderer_app_generator.js +97 -24
- package/dist/codegen/renderer_app_generator.js.map +1 -1
- package/dist/codegen/type_generator.cjs +9 -0
- package/dist/codegen/type_generator.cjs.map +1 -1
- package/dist/codegen/type_generator.js +9 -0
- package/dist/codegen/type_generator.js.map +1 -1
- package/dist/config/config_parser.cjs +10 -0
- package/dist/config/config_parser.cjs.map +1 -1
- package/dist/config/config_parser.js +10 -0
- package/dist/config/config_parser.js.map +1 -1
- package/dist/fetch.cjs +38 -0
- package/dist/fetch.cjs.map +1 -0
- package/dist/fetch.d.cts +7 -0
- package/dist/fetch.d.ts +7 -0
- package/dist/fetch.js +12 -0
- package/dist/fetch.js.map +1 -0
- package/dist/frontend/frontend_page.cjs +3 -3
- package/dist/frontend/frontend_page.cjs.map +1 -1
- package/dist/frontend/frontend_page.d.cts +1 -1
- package/dist/frontend/frontend_page.d.ts +1 -1
- package/dist/frontend/frontend_page.js +3 -3
- package/dist/frontend/frontend_page.js.map +1 -1
- package/dist/frontend/frontend_surface.cjs +31 -17
- package/dist/frontend/frontend_surface.cjs.map +1 -1
- package/dist/frontend/frontend_surface.d.cts +13 -2
- package/dist/frontend/frontend_surface.d.ts +13 -2
- package/dist/frontend/frontend_surface.js +37 -17
- package/dist/frontend/frontend_surface.js.map +1 -1
- package/dist/frontend/index.d.cts +3 -0
- package/dist/frontend/index.d.ts +3 -0
- package/dist/index.cjs +5 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +27 -1
- package/dist/index.d.ts +27 -1
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -1
- package/dist/loader/index.cjs +19 -2
- package/dist/loader/index.cjs.map +1 -1
- package/dist/loader/index.d.cts +1 -0
- package/dist/loader/index.d.ts +1 -0
- package/dist/loader/index.js +19 -1
- package/dist/loader/index.js.map +1 -1
- package/dist/loader/loader_orchestration.cjs +82 -0
- package/dist/loader/loader_orchestration.cjs.map +1 -0
- package/dist/loader/loader_orchestration.d.cts +66 -0
- package/dist/loader/loader_orchestration.d.ts +66 -0
- package/dist/loader/loader_orchestration.js +51 -0
- package/dist/loader/loader_orchestration.js.map +1 -0
- package/dist/loader/loader_runner.cjs +46 -41
- package/dist/loader/loader_runner.cjs.map +1 -1
- package/dist/loader/loader_runner.d.cts +12 -6
- package/dist/loader/loader_runner.d.ts +12 -6
- package/dist/loader/loader_runner.js +50 -41
- package/dist/loader/loader_runner.js.map +1 -1
- package/dist/native_browser.types-BY2daUOS.d.ts +189 -0
- package/dist/native_browser.types-vWXtE4rM.d.cts +189 -0
- package/dist/navigation/index.cjs +15 -2
- package/dist/navigation/index.cjs.map +1 -1
- package/dist/navigation/index.d.cts +6 -28
- package/dist/navigation/index.d.ts +6 -28
- package/dist/navigation/index.js +8 -1
- package/dist/navigation/index.js.map +1 -1
- package/dist/navigation/layout_preservation.cjs.map +1 -1
- package/dist/navigation/layout_preservation.d.cts +27 -2
- package/dist/navigation/layout_preservation.d.ts +27 -2
- package/dist/navigation/layout_preservation.js.map +1 -1
- package/dist/runtime/get_container.cjs +2 -0
- package/dist/runtime/get_container.cjs.map +1 -1
- package/dist/runtime/get_container.js +2 -0
- package/dist/runtime/get_container.js.map +1 -1
- package/dist/runtime/index.cjs +5 -0
- package/dist/runtime/index.cjs.map +1 -1
- package/dist/runtime/index.d.cts +2 -0
- package/dist/runtime/index.d.ts +2 -0
- package/dist/runtime/index.js +3 -0
- package/dist/runtime/index.js.map +1 -1
- package/dist/runtime/runtime_capabilities.cjs +35 -0
- package/dist/runtime/runtime_capabilities.cjs.map +1 -0
- package/dist/runtime/runtime_capabilities.d.cts +6 -0
- package/dist/runtime/runtime_capabilities.d.ts +6 -0
- package/dist/runtime/runtime_capabilities.js +11 -0
- package/dist/runtime/runtime_capabilities.js.map +1 -0
- package/dist/runtime/runtime_module.cjs +2 -0
- package/dist/runtime/runtime_module.cjs.map +1 -1
- package/dist/runtime/runtime_module.js +2 -0
- package/dist/runtime/runtime_module.js.map +1 -1
- package/dist/test-wood.cjs +150 -0
- package/dist/test-wood.cjs.map +1 -0
- package/dist/test-wood.d.cts +62 -0
- package/dist/test-wood.d.ts +62 -0
- package/dist/test-wood.js +115 -0
- package/dist/test-wood.js.map +1 -0
- package/dist/testing/browser.cjs +92 -163
- package/dist/testing/browser.cjs.map +1 -1
- package/dist/testing/browser.d.cts +14 -13
- package/dist/testing/browser.d.ts +14 -13
- package/dist/testing/browser.js +88 -162
- package/dist/testing/browser.js.map +1 -1
- package/dist/testing/create_controller_harness.d.cts +3 -1
- package/dist/testing/create_controller_harness.d.ts +3 -1
- package/dist/testing/create_router_bridge.cjs +19 -15
- package/dist/testing/create_router_bridge.cjs.map +1 -1
- package/dist/testing/create_router_bridge.d.cts +8 -1
- package/dist/testing/create_router_bridge.d.ts +8 -1
- package/dist/testing/create_router_bridge.js +18 -15
- package/dist/testing/create_router_bridge.js.map +1 -1
- package/dist/testing/index.cjs +12 -4
- package/dist/testing/index.cjs.map +1 -1
- package/dist/testing/index.d.cts +12 -5
- package/dist/testing/index.d.ts +12 -5
- package/dist/testing/index.js +9 -3
- package/dist/testing/index.js.map +1 -1
- package/dist/testing/native_browser/browser_pool.cjs +31 -0
- package/dist/testing/native_browser/browser_pool.cjs.map +1 -0
- package/dist/testing/native_browser/browser_pool.d.cts +1 -0
- package/dist/testing/native_browser/browser_pool.d.ts +1 -0
- package/dist/testing/native_browser/browser_pool.js +6 -0
- package/dist/testing/native_browser/browser_pool.js.map +1 -0
- package/dist/testing/native_browser/happy_dom_tab.cjs +107 -0
- package/dist/testing/native_browser/happy_dom_tab.cjs.map +1 -0
- package/dist/testing/native_browser/happy_dom_tab.d.cts +35 -0
- package/dist/testing/native_browser/happy_dom_tab.d.ts +35 -0
- package/dist/testing/native_browser/happy_dom_tab.js +73 -0
- package/dist/testing/native_browser/happy_dom_tab.js.map +1 -0
- package/dist/testing/native_browser/happy_dom_transfer.cjs +29 -0
- package/dist/testing/native_browser/happy_dom_transfer.cjs.map +1 -0
- package/dist/testing/native_browser/happy_dom_transfer.d.cts +1 -0
- package/dist/testing/native_browser/happy_dom_transfer.d.ts +1 -0
- package/dist/testing/native_browser/happy_dom_transfer.js +5 -0
- package/dist/testing/native_browser/happy_dom_transfer.js.map +1 -0
- package/dist/testing/native_browser/host_transport.cjs +89 -0
- package/dist/testing/native_browser/host_transport.cjs.map +1 -0
- package/dist/testing/native_browser/host_transport.d.cts +44 -0
- package/dist/testing/native_browser/host_transport.d.ts +44 -0
- package/dist/testing/native_browser/host_transport.js +65 -0
- package/dist/testing/native_browser/host_transport.js.map +1 -0
- package/dist/testing/native_browser/native_browser.types.cjs +17 -0
- package/dist/testing/native_browser/native_browser.types.cjs.map +1 -0
- package/dist/testing/native_browser/native_browser.types.d.cts +31 -0
- package/dist/testing/native_browser/native_browser.types.d.ts +31 -0
- package/dist/testing/native_browser/native_browser.types.js +1 -0
- package/dist/testing/native_browser/native_browser.types.js.map +1 -0
- package/dist/testing/native_browser/native_browser_environment.cjs +143 -0
- package/dist/testing/native_browser/native_browser_environment.cjs.map +1 -0
- package/dist/testing/native_browser/native_browser_environment.d.cts +36 -0
- package/dist/testing/native_browser/native_browser_environment.d.ts +36 -0
- package/dist/testing/native_browser/native_browser_environment.js +109 -0
- package/dist/testing/native_browser/native_browser_environment.js.map +1 -0
- package/dist/testing/native_browser/native_browser_lifecycle.cjs +31 -0
- package/dist/testing/native_browser/native_browser_lifecycle.cjs.map +1 -0
- package/dist/testing/native_browser/native_browser_lifecycle.d.cts +1 -0
- package/dist/testing/native_browser/native_browser_lifecycle.d.ts +1 -0
- package/dist/testing/native_browser/native_browser_lifecycle.js +6 -0
- package/dist/testing/native_browser/native_browser_lifecycle.js.map +1 -0
- package/dist/testing/native_browser/playwright_tab.cjs +124 -0
- package/dist/testing/native_browser/playwright_tab.cjs.map +1 -0
- package/dist/testing/native_browser/playwright_tab.d.cts +35 -0
- package/dist/testing/native_browser/playwright_tab.d.ts +35 -0
- package/dist/testing/native_browser/playwright_tab.js +100 -0
- package/dist/testing/native_browser/playwright_tab.js.map +1 -0
- package/dist/testing/native_browser/renderer_compilation.cjs +149 -0
- package/dist/testing/native_browser/renderer_compilation.cjs.map +1 -0
- package/dist/testing/native_browser/renderer_compilation.d.cts +35 -0
- package/dist/testing/native_browser/renderer_compilation.d.ts +35 -0
- package/dist/testing/native_browser/renderer_compilation.js +115 -0
- package/dist/testing/native_browser/renderer_compilation.js.map +1 -0
- package/dist/testing/native_browser/renderer_entry.cjs +148 -0
- package/dist/testing/native_browser/renderer_entry.cjs.map +1 -0
- package/dist/testing/native_browser/renderer_entry.d.cts +13 -0
- package/dist/testing/native_browser/renderer_entry.d.ts +13 -0
- package/dist/testing/native_browser/renderer_entry.js +114 -0
- package/dist/testing/native_browser/renderer_entry.js.map +1 -0
- package/dist/testing/registration_only_root.cjs +61 -5
- package/dist/testing/registration_only_root.cjs.map +1 -1
- package/dist/testing/registration_only_root.d.cts +25 -4
- package/dist/testing/registration_only_root.d.ts +25 -4
- package/dist/testing/registration_only_root.js +60 -5
- package/dist/testing/registration_only_root.js.map +1 -1
- package/dist/testing/runner_importer.cjs +75 -0
- package/dist/testing/runner_importer.cjs.map +1 -0
- package/dist/testing/runner_importer.d.cts +8 -0
- package/dist/testing/runner_importer.d.ts +8 -0
- package/dist/testing/runner_importer.js +41 -0
- package/dist/testing/runner_importer.js.map +1 -0
- package/dist/testing/test_wood_config.cjs +387 -272
- package/dist/testing/test_wood_config.cjs.map +1 -1
- package/dist/testing/test_wood_config.d.cts +19 -123
- package/dist/testing/test_wood_config.d.ts +19 -123
- package/dist/testing/test_wood_config.js +396 -270
- package/dist/testing/test_wood_config.js.map +1 -1
- package/dist/testing/wood_config_source.cjs +12 -0
- package/dist/testing/wood_config_source.cjs.map +1 -1
- package/dist/testing/wood_config_source.d.cts +10 -0
- package/dist/testing/wood_config_source.d.ts +10 -0
- package/dist/testing/wood_config_source.js +12 -0
- package/dist/testing/wood_config_source.js.map +1 -1
- package/dist/testing/wood_env_renderer.cjs +28 -3
- package/dist/testing/wood_env_renderer.cjs.map +1 -1
- package/dist/testing/wood_env_renderer.d.cts +13 -1
- package/dist/testing/wood_env_renderer.d.ts +13 -1
- package/dist/testing/wood_env_renderer.js +28 -3
- package/dist/testing/wood_env_renderer.js.map +1 -1
- package/dist/testing/wood_lazy_runtime.cjs +109 -0
- package/dist/testing/wood_lazy_runtime.cjs.map +1 -0
- package/dist/testing/wood_lazy_runtime.d.cts +36 -0
- package/dist/testing/wood_lazy_runtime.d.ts +36 -0
- package/dist/testing/wood_lazy_runtime.js +84 -0
- package/dist/testing/wood_lazy_runtime.js.map +1 -0
- package/dist/testing/wood_test_selection.cjs +34 -55
- package/dist/testing/wood_test_selection.cjs.map +1 -1
- package/dist/testing/wood_test_selection.d.cts +18 -24
- package/dist/testing/wood_test_selection.d.ts +18 -24
- package/dist/testing/wood_test_selection.js +30 -54
- package/dist/testing/wood_test_selection.js.map +1 -1
- package/dist/testing-api.cjs +17 -0
- package/dist/testing-api.cjs.map +1 -0
- package/dist/testing-api.d.cts +18 -0
- package/dist/testing-api.d.ts +18 -0
- package/dist/testing-api.js +1 -0
- package/dist/testing-api.js.map +1 -0
- package/dist/types/config.cjs.map +1 -1
- package/dist/types/config.d.cts +4 -0
- package/dist/types/config.d.ts +4 -0
- package/docs/native-browser-testing.md +164 -0
- package/package.json +31 -5
- package/src/components/NavigationShell.browser.test.ts +10 -10
- package/src/components/NavigationShell.cleanup.browser.test.ts +57 -0
- package/src/components/NavigationShell.scopes.browser.test.ts +5 -5
- package/src/components/NavigationShell.svelte +50 -24
- package/src/navigation/layout_preservation.ts +3 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/test-wood.ts"],"sourcesContent":["import type { ConfigureFetch } from '@noego/testing/fetch';\n/**\n * Production-safe Wood testing facade, exported from the `@noego/wood` root.\n *\n * Importing `@noego/wood` or declaring a test loads no testing, DOM,\n * Playwright or Electron modules: every call is recorded on an immutable\n * builder and replayed onto the real `@noego/wood/testing` implementation\n * only inside `build()`.\n *\n * The canonical surface is exactly:\n *\n * select({ main?, renderer? }) what exists (module | path | {} per owner)\n * use(testStub()) compose a shared replacement description\n * class / function / method / value exact declared tokens\n * middleware(identity, …) the executable behind a source middleware id\n * load(identity, …) the page/layout companion data loader\n * browser([happy_dom]) native Page (default) or happy-dom Window\n * build() no selection = every declared owner, whole\n *\n * Explicit browser() selects a native renderer host. Without it, renderer\n * selection stays in the fast in-process Node controller tier.\n */\nimport { fileURLToPath } from 'node:url';\nimport type {\n ExecutableReplacement,\n LoaderIdentity,\n MethodDescriptor,\n OwnerSelection,\n ClassToken, ReplacementClass,\n ReplacementFunction,\n ReplacementOptions,\n TestStub,\n} from '@noego/testing';\nimport type { TestWoodBuilder } from './testing/index.js';\nimport type { WoodBrowserHost, WoodTestEnvironmentFor } from './testing/native_browser/native_browser.types.js';\n\nexport interface WoodTestSelection {\n readonly main?: OwnerSelection;\n readonly renderer?: OwnerSelection;\n}\n\ntype Method = 'select' | 'use' | 'class' | 'function' | 'method' | 'value' | 'middleware' | 'load' | 'browser' | 'fetch';\ntype Command = Readonly<{ method: Method; args: readonly unknown[] }>;\nconst logs = new WeakMap<object, { config: string; commands: readonly Command[] }>();\n\nfunction derive<H extends WoodBrowserHost | null>(builder: WoodTestBuilder<H>, method: Method, args: readonly unknown[]): WoodTestBuilder<H> {\n const state = logs.get(builder)!;\n const copied = [...args];\n const optionsIndex = method === 'method' ? 3 : 2;\n if (!['select', 'use'].includes(method) && copied[optionsIndex] !== undefined) {\n copied[optionsIndex] = Object.freeze({ ...(copied[optionsIndex] as ReplacementOptions) });\n }\n if (method === 'load' && typeof copied[0] !== 'string') copied[0] = Object.freeze({ ...(copied[0] as object) });\n const child = Object.create(WoodTestBuilder.prototype) as WoodTestBuilder<H>;\n logs.set(child, {\n config: state.config,\n commands: Object.freeze([...state.commands, Object.freeze({ method, args: Object.freeze(copied) })]),\n });\n return Object.freeze(child);\n}\n\nfunction plain(value: unknown): value is Record<string, unknown> {\n return !!value && typeof value === 'object' && !Array.isArray(value)\n && (Object.getPrototypeOf(value) === Object.prototype || Object.getPrototypeOf(value) === null);\n}\nfunction copyOwner(owner: string, input: unknown): OwnerSelection {\n if (!plain(input)\n || Reflect.ownKeys(input).some(key => key !== 'module' && key !== 'path')\n || Reflect.ownKeys(input).length > 1) {\n throw new TypeError(`select({ ${owner} }) takes module OR path, or {}`);\n }\n const value = { ...(input as Record<string, unknown>) };\n if (typeof value.module === 'string') value.module = Object.freeze([value.module]);\n else if (Array.isArray(value.module)) value.module = Object.freeze([...value.module]);\n if (Array.isArray(value.path)) value.path = Object.freeze([...value.path]);\n return Object.freeze(value) as OwnerSelection;\n}\n\n/** Structural copy only; owner contents are validated by the shared contract at build. */\nfunction copySelection(selection: WoodTestSelection): WoodTestSelection {\n if (!plain(selection)\n || Reflect.ownKeys(selection).some(key => key !== 'main' && key !== 'renderer')) {\n throw new TypeError('select requires { main } and/or { renderer }');\n }\n const out: { main?: OwnerSelection; renderer?: OwnerSelection } = {};\n if ('main' in selection) out.main = copyOwner('main', selection.main);\n if ('renderer' in selection) out.renderer = copyOwner('renderer', selection.renderer);\n if (!('main' in out) && !('renderer' in out)) throw new TypeError('select requires { main } and/or { renderer }');\n return Object.freeze(out);\n}\n\nfunction identity(value: unknown, what: string): void {\n if (typeof value !== 'string' || !value.trim()) throw new TypeError(`${what} requires a nonempty identity`);\n}\n\n/** The root-export builder: a recorder over the `@noego/wood/testing` builder's canonical surface. */\nexport class WoodTestBuilder<H extends WoodBrowserHost | null = null> {\n private constructor() {}\n fetch(configure: ConfigureFetch): WoodTestBuilder<H> {\n if (typeof configure !== 'function') throw new TypeError('fetch() requires a route configuration callback');\n return derive(this, 'fetch', [configure]);\n }\n /** No argument = Playwright/Chromium; happy_dom = a native happy-dom Window. */\n browser(): WoodTestBuilder<'playwright'>;\n browser(host: 'playwright'): WoodTestBuilder<'playwright'>;\n browser(host: 'happy_dom'): WoodTestBuilder<'happy_dom'>;\n browser(host: WoodBrowserHost = 'playwright'): WoodTestBuilder<WoodBrowserHost> {\n if (host !== 'playwright' && host !== 'happy_dom') throw new TypeError('browser() accepts playwright or happy_dom');\n return derive(this, 'browser', [host]) as WoodTestBuilder<WoodBrowserHost>;\n }\n select(selection: WoodTestSelection): WoodTestBuilder<H> { return derive(this, 'select', [copySelection(selection)]); }\n use(stub: TestStub): WoodTestBuilder<H> {\n if (!stub || typeof stub !== 'object') throw new TypeError('use() expects a testStub() description');\n return derive(this, 'use', [stub]);\n }\n class<T>(target: ClassToken<T>, replacement: ReplacementClass<T>, options?: ReplacementOptions): WoodTestBuilder<H> {\n return derive(this, 'class', options === undefined ? [target, replacement] : [target, replacement, options]);\n }\n function(target: unknown, replacement: ReplacementFunction, options?: ReplacementOptions): WoodTestBuilder<H> {\n return derive(this, 'function', options === undefined ? [target, replacement] : [target, replacement, options]);\n }\n method(target: unknown, method: string, replacement: MethodDescriptor, options?: ReplacementOptions): WoodTestBuilder<H> {\n identity(method, 'method()');\n return derive(this, 'method', options === undefined ? [target, method, replacement] : [target, method, replacement, options]);\n }\n value(target: unknown, replacement: unknown, options?: ReplacementOptions): WoodTestBuilder<H> {\n return derive(this, 'value', options === undefined ? [target, replacement] : [target, replacement, options]);\n }\n middleware(identity_: string, replacement: ExecutableReplacement, options?: ReplacementOptions): WoodTestBuilder<H> {\n identity(identity_, 'middleware()');\n return derive(this, 'middleware', options === undefined ? [identity_, replacement] : [identity_, replacement, options]);\n }\n load(identity_: LoaderIdentity, replacement: ExecutableReplacement, options?: ReplacementOptions): WoodTestBuilder<H> {\n return derive(this, 'load', options === undefined ? [identity_, replacement] : [identity_, replacement, options]);\n }\n /**\n * Load the implementation and replay the recorded calls in order. Under\n * Vitest the build binds to the project-local runner's module registry so\n * production modules keep the identity the test file imported.\n */\n async build(): Promise<WoodTestEnvironmentFor<H>> {\n const state = logs.get(this)!;\n const implementation = await import('./testing/index.js');\n let builder: TestWoodBuilder = implementation.testWood(state.config);\n if (process.env.VITEST) builder = builder.importer(await implementation.vitestModuleImporter(state.config));\n for (const command of state.commands) {\n if (command.method === 'use') {\n const { stubEntries } = await import('@noego/testing');\n stubEntries(command.args[0] as TestStub); // reject legacy IoC presets on the canonical root facade\n }\n builder = (builder[command.method] as (...args: unknown[]) => TestWoodBuilder).apply(builder, [...command.args]);\n }\n const environment = await builder.build();\n const { registerTestResource } = await import('@noego/testing');\n return await registerTestResource(environment, 'testWood') as WoodTestEnvironmentFor<H>;\n }\n}\n\nexport function testWood(configPath: string | URL): WoodTestBuilder {\n const config = configPath instanceof URL ? fileURLToPath(configPath)\n : typeof configPath === 'string' && configPath.startsWith('file:') ? fileURLToPath(configPath) : configPath;\n if (typeof config !== 'string' || !config.trim()) throw new TypeError('testWood requires an original wood.config.yml path or file URL');\n const builder = Object.create(WoodTestBuilder.prototype) as WoodTestBuilder;\n logs.set(builder, { config, commands: Object.freeze([]) });\n return Object.freeze(builder);\n}\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { ConfigureFetch } from '@noego/testing/fetch';
|
|
2
|
+
import { OwnerSelection, TestStub, ClassToken, ReplacementClass, ReplacementOptions, ReplacementFunction, MethodDescriptor, ExecutableReplacement, LoaderIdentity } from '@noego/testing';
|
|
3
|
+
import { W as WoodBrowserHost, c as WoodTestEnvironmentFor } from './native_browser.types-vWXtE4rM.cjs';
|
|
4
|
+
import 'playwright';
|
|
5
|
+
import 'happy-dom';
|
|
6
|
+
import './testing/wood_config_source.cjs';
|
|
7
|
+
import './types/config.cjs';
|
|
8
|
+
import './types/operations.cjs';
|
|
9
|
+
import './types/views.cjs';
|
|
10
|
+
import './testing/create_router_bridge.cjs';
|
|
11
|
+
import './router/wood_router.cjs';
|
|
12
|
+
import './types/context.cjs';
|
|
13
|
+
import './validation/schema_validator.cjs';
|
|
14
|
+
import './middleware/middleware_resolver.cjs';
|
|
15
|
+
import './controller/controller_resolver.cjs';
|
|
16
|
+
import './testing-api.cjs';
|
|
17
|
+
import '@noego/ioc';
|
|
18
|
+
import './frontend/frontend_surface.cjs';
|
|
19
|
+
import './navigation/index.cjs';
|
|
20
|
+
import './navigation/layout_preservation.cjs';
|
|
21
|
+
import './navigation/automation_introspection.cjs';
|
|
22
|
+
import './loader/loader_orchestration.cjs';
|
|
23
|
+
import './frontend/page_catalog.cjs';
|
|
24
|
+
import './frontend/work_registry.cjs';
|
|
25
|
+
import './frontend/frontend_lifecycle.cjs';
|
|
26
|
+
import './frontend/frontend_page.cjs';
|
|
27
|
+
import './testing/wood_test_selection.cjs';
|
|
28
|
+
import './testing/wood_env_renderer.cjs';
|
|
29
|
+
import './testing/wood_dom_animation.cjs';
|
|
30
|
+
import './testing/registration_only_root.cjs';
|
|
31
|
+
import './testing/test_wood.cjs';
|
|
32
|
+
|
|
33
|
+
interface WoodTestSelection {
|
|
34
|
+
readonly main?: OwnerSelection;
|
|
35
|
+
readonly renderer?: OwnerSelection;
|
|
36
|
+
}
|
|
37
|
+
/** The root-export builder: a recorder over the `@noego/wood/testing` builder's canonical surface. */
|
|
38
|
+
declare class WoodTestBuilder<H extends WoodBrowserHost | null = null> {
|
|
39
|
+
private constructor();
|
|
40
|
+
fetch(configure: ConfigureFetch): WoodTestBuilder<H>;
|
|
41
|
+
/** No argument = Playwright/Chromium; happy_dom = a native happy-dom Window. */
|
|
42
|
+
browser(): WoodTestBuilder<'playwright'>;
|
|
43
|
+
browser(host: 'playwright'): WoodTestBuilder<'playwright'>;
|
|
44
|
+
browser(host: 'happy_dom'): WoodTestBuilder<'happy_dom'>;
|
|
45
|
+
select(selection: WoodTestSelection): WoodTestBuilder<H>;
|
|
46
|
+
use(stub: TestStub): WoodTestBuilder<H>;
|
|
47
|
+
class<T>(target: ClassToken<T>, replacement: ReplacementClass<T>, options?: ReplacementOptions): WoodTestBuilder<H>;
|
|
48
|
+
function(target: unknown, replacement: ReplacementFunction, options?: ReplacementOptions): WoodTestBuilder<H>;
|
|
49
|
+
method(target: unknown, method: string, replacement: MethodDescriptor, options?: ReplacementOptions): WoodTestBuilder<H>;
|
|
50
|
+
value(target: unknown, replacement: unknown, options?: ReplacementOptions): WoodTestBuilder<H>;
|
|
51
|
+
middleware(identity_: string, replacement: ExecutableReplacement, options?: ReplacementOptions): WoodTestBuilder<H>;
|
|
52
|
+
load(identity_: LoaderIdentity, replacement: ExecutableReplacement, options?: ReplacementOptions): WoodTestBuilder<H>;
|
|
53
|
+
/**
|
|
54
|
+
* Load the implementation and replay the recorded calls in order. Under
|
|
55
|
+
* Vitest the build binds to the project-local runner's module registry so
|
|
56
|
+
* production modules keep the identity the test file imported.
|
|
57
|
+
*/
|
|
58
|
+
build(): Promise<WoodTestEnvironmentFor<H>>;
|
|
59
|
+
}
|
|
60
|
+
declare function testWood(configPath: string | URL): WoodTestBuilder;
|
|
61
|
+
|
|
62
|
+
export { WoodTestBuilder, type WoodTestSelection, testWood };
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { ConfigureFetch } from '@noego/testing/fetch';
|
|
2
|
+
import { OwnerSelection, TestStub, ClassToken, ReplacementClass, ReplacementOptions, ReplacementFunction, MethodDescriptor, ExecutableReplacement, LoaderIdentity } from '@noego/testing';
|
|
3
|
+
import { W as WoodBrowserHost, c as WoodTestEnvironmentFor } from './native_browser.types-BY2daUOS.js';
|
|
4
|
+
import 'playwright';
|
|
5
|
+
import 'happy-dom';
|
|
6
|
+
import './testing/wood_config_source.js';
|
|
7
|
+
import './types/config.js';
|
|
8
|
+
import './types/operations.js';
|
|
9
|
+
import './types/views.js';
|
|
10
|
+
import './testing/create_router_bridge.js';
|
|
11
|
+
import './router/wood_router.js';
|
|
12
|
+
import './types/context.js';
|
|
13
|
+
import './validation/schema_validator.js';
|
|
14
|
+
import './middleware/middleware_resolver.js';
|
|
15
|
+
import './controller/controller_resolver.js';
|
|
16
|
+
import './testing-api.js';
|
|
17
|
+
import '@noego/ioc';
|
|
18
|
+
import './frontend/frontend_surface.js';
|
|
19
|
+
import './navigation/index.js';
|
|
20
|
+
import './navigation/layout_preservation.js';
|
|
21
|
+
import './navigation/automation_introspection.js';
|
|
22
|
+
import './loader/loader_orchestration.js';
|
|
23
|
+
import './frontend/page_catalog.js';
|
|
24
|
+
import './frontend/work_registry.js';
|
|
25
|
+
import './frontend/frontend_lifecycle.js';
|
|
26
|
+
import './frontend/frontend_page.js';
|
|
27
|
+
import './testing/wood_test_selection.js';
|
|
28
|
+
import './testing/wood_env_renderer.js';
|
|
29
|
+
import './testing/wood_dom_animation.js';
|
|
30
|
+
import './testing/registration_only_root.js';
|
|
31
|
+
import './testing/test_wood.js';
|
|
32
|
+
|
|
33
|
+
interface WoodTestSelection {
|
|
34
|
+
readonly main?: OwnerSelection;
|
|
35
|
+
readonly renderer?: OwnerSelection;
|
|
36
|
+
}
|
|
37
|
+
/** The root-export builder: a recorder over the `@noego/wood/testing` builder's canonical surface. */
|
|
38
|
+
declare class WoodTestBuilder<H extends WoodBrowserHost | null = null> {
|
|
39
|
+
private constructor();
|
|
40
|
+
fetch(configure: ConfigureFetch): WoodTestBuilder<H>;
|
|
41
|
+
/** No argument = Playwright/Chromium; happy_dom = a native happy-dom Window. */
|
|
42
|
+
browser(): WoodTestBuilder<'playwright'>;
|
|
43
|
+
browser(host: 'playwright'): WoodTestBuilder<'playwright'>;
|
|
44
|
+
browser(host: 'happy_dom'): WoodTestBuilder<'happy_dom'>;
|
|
45
|
+
select(selection: WoodTestSelection): WoodTestBuilder<H>;
|
|
46
|
+
use(stub: TestStub): WoodTestBuilder<H>;
|
|
47
|
+
class<T>(target: ClassToken<T>, replacement: ReplacementClass<T>, options?: ReplacementOptions): WoodTestBuilder<H>;
|
|
48
|
+
function(target: unknown, replacement: ReplacementFunction, options?: ReplacementOptions): WoodTestBuilder<H>;
|
|
49
|
+
method(target: unknown, method: string, replacement: MethodDescriptor, options?: ReplacementOptions): WoodTestBuilder<H>;
|
|
50
|
+
value(target: unknown, replacement: unknown, options?: ReplacementOptions): WoodTestBuilder<H>;
|
|
51
|
+
middleware(identity_: string, replacement: ExecutableReplacement, options?: ReplacementOptions): WoodTestBuilder<H>;
|
|
52
|
+
load(identity_: LoaderIdentity, replacement: ExecutableReplacement, options?: ReplacementOptions): WoodTestBuilder<H>;
|
|
53
|
+
/**
|
|
54
|
+
* Load the implementation and replay the recorded calls in order. Under
|
|
55
|
+
* Vitest the build binds to the project-local runner's module registry so
|
|
56
|
+
* production modules keep the identity the test file imported.
|
|
57
|
+
*/
|
|
58
|
+
build(): Promise<WoodTestEnvironmentFor<H>>;
|
|
59
|
+
}
|
|
60
|
+
declare function testWood(configPath: string | URL): WoodTestBuilder;
|
|
61
|
+
|
|
62
|
+
export { WoodTestBuilder, type WoodTestSelection, testWood };
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import { fileURLToPath } from "node:url";
|
|
2
|
+
const logs = /* @__PURE__ */ new WeakMap();
|
|
3
|
+
function derive(builder, method, args) {
|
|
4
|
+
const state = logs.get(builder);
|
|
5
|
+
const copied = [...args];
|
|
6
|
+
const optionsIndex = method === "method" ? 3 : 2;
|
|
7
|
+
if (!["select", "use"].includes(method) && copied[optionsIndex] !== void 0) {
|
|
8
|
+
copied[optionsIndex] = Object.freeze({ ...copied[optionsIndex] });
|
|
9
|
+
}
|
|
10
|
+
if (method === "load" && typeof copied[0] !== "string") copied[0] = Object.freeze({ ...copied[0] });
|
|
11
|
+
const child = Object.create(WoodTestBuilder.prototype);
|
|
12
|
+
logs.set(child, {
|
|
13
|
+
config: state.config,
|
|
14
|
+
commands: Object.freeze([...state.commands, Object.freeze({ method, args: Object.freeze(copied) })])
|
|
15
|
+
});
|
|
16
|
+
return Object.freeze(child);
|
|
17
|
+
}
|
|
18
|
+
function plain(value) {
|
|
19
|
+
return !!value && typeof value === "object" && !Array.isArray(value) && (Object.getPrototypeOf(value) === Object.prototype || Object.getPrototypeOf(value) === null);
|
|
20
|
+
}
|
|
21
|
+
function copyOwner(owner, input) {
|
|
22
|
+
if (!plain(input) || Reflect.ownKeys(input).some((key) => key !== "module" && key !== "path") || Reflect.ownKeys(input).length > 1) {
|
|
23
|
+
throw new TypeError(`select({ ${owner} }) takes module OR path, or {}`);
|
|
24
|
+
}
|
|
25
|
+
const value = { ...input };
|
|
26
|
+
if (typeof value.module === "string") value.module = Object.freeze([value.module]);
|
|
27
|
+
else if (Array.isArray(value.module)) value.module = Object.freeze([...value.module]);
|
|
28
|
+
if (Array.isArray(value.path)) value.path = Object.freeze([...value.path]);
|
|
29
|
+
return Object.freeze(value);
|
|
30
|
+
}
|
|
31
|
+
function copySelection(selection) {
|
|
32
|
+
if (!plain(selection) || Reflect.ownKeys(selection).some((key) => key !== "main" && key !== "renderer")) {
|
|
33
|
+
throw new TypeError("select requires { main } and/or { renderer }");
|
|
34
|
+
}
|
|
35
|
+
const out = {};
|
|
36
|
+
if ("main" in selection) out.main = copyOwner("main", selection.main);
|
|
37
|
+
if ("renderer" in selection) out.renderer = copyOwner("renderer", selection.renderer);
|
|
38
|
+
if (!("main" in out) && !("renderer" in out)) throw new TypeError("select requires { main } and/or { renderer }");
|
|
39
|
+
return Object.freeze(out);
|
|
40
|
+
}
|
|
41
|
+
function identity(value, what) {
|
|
42
|
+
if (typeof value !== "string" || !value.trim()) throw new TypeError(`${what} requires a nonempty identity`);
|
|
43
|
+
}
|
|
44
|
+
class WoodTestBuilder {
|
|
45
|
+
constructor() {
|
|
46
|
+
}
|
|
47
|
+
fetch(configure) {
|
|
48
|
+
if (typeof configure !== "function") throw new TypeError("fetch() requires a route configuration callback");
|
|
49
|
+
return derive(this, "fetch", [configure]);
|
|
50
|
+
}
|
|
51
|
+
browser(host = "playwright") {
|
|
52
|
+
if (host !== "playwright" && host !== "happy_dom") throw new TypeError("browser() accepts playwright or happy_dom");
|
|
53
|
+
return derive(this, "browser", [host]);
|
|
54
|
+
}
|
|
55
|
+
select(selection) {
|
|
56
|
+
return derive(this, "select", [copySelection(selection)]);
|
|
57
|
+
}
|
|
58
|
+
use(stub) {
|
|
59
|
+
if (!stub || typeof stub !== "object") throw new TypeError("use() expects a testStub() description");
|
|
60
|
+
return derive(this, "use", [stub]);
|
|
61
|
+
}
|
|
62
|
+
class(target, replacement, options) {
|
|
63
|
+
return derive(this, "class", options === void 0 ? [target, replacement] : [target, replacement, options]);
|
|
64
|
+
}
|
|
65
|
+
function(target, replacement, options) {
|
|
66
|
+
return derive(this, "function", options === void 0 ? [target, replacement] : [target, replacement, options]);
|
|
67
|
+
}
|
|
68
|
+
method(target, method, replacement, options) {
|
|
69
|
+
identity(method, "method()");
|
|
70
|
+
return derive(this, "method", options === void 0 ? [target, method, replacement] : [target, method, replacement, options]);
|
|
71
|
+
}
|
|
72
|
+
value(target, replacement, options) {
|
|
73
|
+
return derive(this, "value", options === void 0 ? [target, replacement] : [target, replacement, options]);
|
|
74
|
+
}
|
|
75
|
+
middleware(identity_, replacement, options) {
|
|
76
|
+
identity(identity_, "middleware()");
|
|
77
|
+
return derive(this, "middleware", options === void 0 ? [identity_, replacement] : [identity_, replacement, options]);
|
|
78
|
+
}
|
|
79
|
+
load(identity_, replacement, options) {
|
|
80
|
+
return derive(this, "load", options === void 0 ? [identity_, replacement] : [identity_, replacement, options]);
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Load the implementation and replay the recorded calls in order. Under
|
|
84
|
+
* Vitest the build binds to the project-local runner's module registry so
|
|
85
|
+
* production modules keep the identity the test file imported.
|
|
86
|
+
*/
|
|
87
|
+
async build() {
|
|
88
|
+
const state = logs.get(this);
|
|
89
|
+
const implementation = await import("./testing/index.js");
|
|
90
|
+
let builder = implementation.testWood(state.config);
|
|
91
|
+
if (process.env.VITEST) builder = builder.importer(await implementation.vitestModuleImporter(state.config));
|
|
92
|
+
for (const command of state.commands) {
|
|
93
|
+
if (command.method === "use") {
|
|
94
|
+
const { stubEntries } = await import("@noego/testing");
|
|
95
|
+
stubEntries(command.args[0]);
|
|
96
|
+
}
|
|
97
|
+
builder = builder[command.method].apply(builder, [...command.args]);
|
|
98
|
+
}
|
|
99
|
+
const environment = await builder.build();
|
|
100
|
+
const { registerTestResource } = await import("@noego/testing");
|
|
101
|
+
return await registerTestResource(environment, "testWood");
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
function testWood(configPath) {
|
|
105
|
+
const config = configPath instanceof URL ? fileURLToPath(configPath) : typeof configPath === "string" && configPath.startsWith("file:") ? fileURLToPath(configPath) : configPath;
|
|
106
|
+
if (typeof config !== "string" || !config.trim()) throw new TypeError("testWood requires an original wood.config.yml path or file URL");
|
|
107
|
+
const builder = Object.create(WoodTestBuilder.prototype);
|
|
108
|
+
logs.set(builder, { config, commands: Object.freeze([]) });
|
|
109
|
+
return Object.freeze(builder);
|
|
110
|
+
}
|
|
111
|
+
export {
|
|
112
|
+
WoodTestBuilder,
|
|
113
|
+
testWood
|
|
114
|
+
};
|
|
115
|
+
//# sourceMappingURL=test-wood.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/test-wood.ts"],"sourcesContent":["import type { ConfigureFetch } from '@noego/testing/fetch';\n/**\n * Production-safe Wood testing facade, exported from the `@noego/wood` root.\n *\n * Importing `@noego/wood` or declaring a test loads no testing, DOM,\n * Playwright or Electron modules: every call is recorded on an immutable\n * builder and replayed onto the real `@noego/wood/testing` implementation\n * only inside `build()`.\n *\n * The canonical surface is exactly:\n *\n * select({ main?, renderer? }) what exists (module | path | {} per owner)\n * use(testStub()) compose a shared replacement description\n * class / function / method / value exact declared tokens\n * middleware(identity, …) the executable behind a source middleware id\n * load(identity, …) the page/layout companion data loader\n * browser([happy_dom]) native Page (default) or happy-dom Window\n * build() no selection = every declared owner, whole\n *\n * Explicit browser() selects a native renderer host. Without it, renderer\n * selection stays in the fast in-process Node controller tier.\n */\nimport { fileURLToPath } from 'node:url';\nimport type {\n ExecutableReplacement,\n LoaderIdentity,\n MethodDescriptor,\n OwnerSelection,\n ClassToken, ReplacementClass,\n ReplacementFunction,\n ReplacementOptions,\n TestStub,\n} from '@noego/testing';\nimport type { TestWoodBuilder } from './testing/index.js';\nimport type { WoodBrowserHost, WoodTestEnvironmentFor } from './testing/native_browser/native_browser.types.js';\n\nexport interface WoodTestSelection {\n readonly main?: OwnerSelection;\n readonly renderer?: OwnerSelection;\n}\n\ntype Method = 'select' | 'use' | 'class' | 'function' | 'method' | 'value' | 'middleware' | 'load' | 'browser' | 'fetch';\ntype Command = Readonly<{ method: Method; args: readonly unknown[] }>;\nconst logs = new WeakMap<object, { config: string; commands: readonly Command[] }>();\n\nfunction derive<H extends WoodBrowserHost | null>(builder: WoodTestBuilder<H>, method: Method, args: readonly unknown[]): WoodTestBuilder<H> {\n const state = logs.get(builder)!;\n const copied = [...args];\n const optionsIndex = method === 'method' ? 3 : 2;\n if (!['select', 'use'].includes(method) && copied[optionsIndex] !== undefined) {\n copied[optionsIndex] = Object.freeze({ ...(copied[optionsIndex] as ReplacementOptions) });\n }\n if (method === 'load' && typeof copied[0] !== 'string') copied[0] = Object.freeze({ ...(copied[0] as object) });\n const child = Object.create(WoodTestBuilder.prototype) as WoodTestBuilder<H>;\n logs.set(child, {\n config: state.config,\n commands: Object.freeze([...state.commands, Object.freeze({ method, args: Object.freeze(copied) })]),\n });\n return Object.freeze(child);\n}\n\nfunction plain(value: unknown): value is Record<string, unknown> {\n return !!value && typeof value === 'object' && !Array.isArray(value)\n && (Object.getPrototypeOf(value) === Object.prototype || Object.getPrototypeOf(value) === null);\n}\nfunction copyOwner(owner: string, input: unknown): OwnerSelection {\n if (!plain(input)\n || Reflect.ownKeys(input).some(key => key !== 'module' && key !== 'path')\n || Reflect.ownKeys(input).length > 1) {\n throw new TypeError(`select({ ${owner} }) takes module OR path, or {}`);\n }\n const value = { ...(input as Record<string, unknown>) };\n if (typeof value.module === 'string') value.module = Object.freeze([value.module]);\n else if (Array.isArray(value.module)) value.module = Object.freeze([...value.module]);\n if (Array.isArray(value.path)) value.path = Object.freeze([...value.path]);\n return Object.freeze(value) as OwnerSelection;\n}\n\n/** Structural copy only; owner contents are validated by the shared contract at build. */\nfunction copySelection(selection: WoodTestSelection): WoodTestSelection {\n if (!plain(selection)\n || Reflect.ownKeys(selection).some(key => key !== 'main' && key !== 'renderer')) {\n throw new TypeError('select requires { main } and/or { renderer }');\n }\n const out: { main?: OwnerSelection; renderer?: OwnerSelection } = {};\n if ('main' in selection) out.main = copyOwner('main', selection.main);\n if ('renderer' in selection) out.renderer = copyOwner('renderer', selection.renderer);\n if (!('main' in out) && !('renderer' in out)) throw new TypeError('select requires { main } and/or { renderer }');\n return Object.freeze(out);\n}\n\nfunction identity(value: unknown, what: string): void {\n if (typeof value !== 'string' || !value.trim()) throw new TypeError(`${what} requires a nonempty identity`);\n}\n\n/** The root-export builder: a recorder over the `@noego/wood/testing` builder's canonical surface. */\nexport class WoodTestBuilder<H extends WoodBrowserHost | null = null> {\n private constructor() {}\n fetch(configure: ConfigureFetch): WoodTestBuilder<H> {\n if (typeof configure !== 'function') throw new TypeError('fetch() requires a route configuration callback');\n return derive(this, 'fetch', [configure]);\n }\n /** No argument = Playwright/Chromium; happy_dom = a native happy-dom Window. */\n browser(): WoodTestBuilder<'playwright'>;\n browser(host: 'playwright'): WoodTestBuilder<'playwright'>;\n browser(host: 'happy_dom'): WoodTestBuilder<'happy_dom'>;\n browser(host: WoodBrowserHost = 'playwright'): WoodTestBuilder<WoodBrowserHost> {\n if (host !== 'playwright' && host !== 'happy_dom') throw new TypeError('browser() accepts playwright or happy_dom');\n return derive(this, 'browser', [host]) as WoodTestBuilder<WoodBrowserHost>;\n }\n select(selection: WoodTestSelection): WoodTestBuilder<H> { return derive(this, 'select', [copySelection(selection)]); }\n use(stub: TestStub): WoodTestBuilder<H> {\n if (!stub || typeof stub !== 'object') throw new TypeError('use() expects a testStub() description');\n return derive(this, 'use', [stub]);\n }\n class<T>(target: ClassToken<T>, replacement: ReplacementClass<T>, options?: ReplacementOptions): WoodTestBuilder<H> {\n return derive(this, 'class', options === undefined ? [target, replacement] : [target, replacement, options]);\n }\n function(target: unknown, replacement: ReplacementFunction, options?: ReplacementOptions): WoodTestBuilder<H> {\n return derive(this, 'function', options === undefined ? [target, replacement] : [target, replacement, options]);\n }\n method(target: unknown, method: string, replacement: MethodDescriptor, options?: ReplacementOptions): WoodTestBuilder<H> {\n identity(method, 'method()');\n return derive(this, 'method', options === undefined ? [target, method, replacement] : [target, method, replacement, options]);\n }\n value(target: unknown, replacement: unknown, options?: ReplacementOptions): WoodTestBuilder<H> {\n return derive(this, 'value', options === undefined ? [target, replacement] : [target, replacement, options]);\n }\n middleware(identity_: string, replacement: ExecutableReplacement, options?: ReplacementOptions): WoodTestBuilder<H> {\n identity(identity_, 'middleware()');\n return derive(this, 'middleware', options === undefined ? [identity_, replacement] : [identity_, replacement, options]);\n }\n load(identity_: LoaderIdentity, replacement: ExecutableReplacement, options?: ReplacementOptions): WoodTestBuilder<H> {\n return derive(this, 'load', options === undefined ? [identity_, replacement] : [identity_, replacement, options]);\n }\n /**\n * Load the implementation and replay the recorded calls in order. Under\n * Vitest the build binds to the project-local runner's module registry so\n * production modules keep the identity the test file imported.\n */\n async build(): Promise<WoodTestEnvironmentFor<H>> {\n const state = logs.get(this)!;\n const implementation = await import('./testing/index.js');\n let builder: TestWoodBuilder = implementation.testWood(state.config);\n if (process.env.VITEST) builder = builder.importer(await implementation.vitestModuleImporter(state.config));\n for (const command of state.commands) {\n if (command.method === 'use') {\n const { stubEntries } = await import('@noego/testing');\n stubEntries(command.args[0] as TestStub); // reject legacy IoC presets on the canonical root facade\n }\n builder = (builder[command.method] as (...args: unknown[]) => TestWoodBuilder).apply(builder, [...command.args]);\n }\n const environment = await builder.build();\n const { registerTestResource } = await import('@noego/testing');\n return await registerTestResource(environment, 'testWood') as WoodTestEnvironmentFor<H>;\n }\n}\n\nexport function testWood(configPath: string | URL): WoodTestBuilder {\n const config = configPath instanceof URL ? fileURLToPath(configPath)\n : typeof configPath === 'string' && configPath.startsWith('file:') ? fileURLToPath(configPath) : configPath;\n if (typeof config !== 'string' || !config.trim()) throw new TypeError('testWood requires an original wood.config.yml path or file URL');\n const builder = Object.create(WoodTestBuilder.prototype) as WoodTestBuilder;\n logs.set(builder, { config, commands: Object.freeze([]) });\n return Object.freeze(builder);\n}\n"],"mappings":"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","names":[]}
|