@qilin-agent/client-test-runtime 0.0.0-stage → 3.1.4

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.
@@ -0,0 +1,15 @@
1
+ import { ClientRoster } from './roster.ts';
2
+ /** The `web` profile's bundle layers, in the order `qilin --profile web` applies them (app-boot `PROFILE_TEMPLATES.web`). */
3
+ export declare const WEB_PROFILE_BUNDLES: readonly string[];
4
+ /**
5
+ * Compose the browser roster of `bundles`, applied in order.
6
+ * @param bundles - bundle package names in application order.
7
+ * @param anchor - file whose package resolution locates the bundles; default this package.
8
+ * @returns the roster in composition order, one row per package.
9
+ * @throws {Error} when a bundle, its patch file, or an enabled row's package does not resolve, when the patch list
10
+ * is not a list or does not apply as written, or when a browser row's `disabled` is a `!!js` expression.
11
+ */
12
+ export declare function bundleRoster(bundles: readonly string[], anchor?: string): ClientRoster;
13
+ /** The `web` profile's browser roster, composed from its bundles at import. */
14
+ export declare const webApp: ClientRoster;
15
+ //# sourceMappingURL=bundle-roster.d.ts.map
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Whole-client tier entry (deep import only:
3
+ * `@qilin-agent/client-test-runtime/src/assembly/index.ts`). Kept out of
4
+ * the package root so slot-tier specs do not load the assembly machinery.
5
+ * @module @qilin-agent/client-test-runtime/src/assembly
6
+ */
7
+ export { ClientRoster } from './roster.ts';
8
+ export type { AssemblyPlan, ClientPluginModule, ClientRosterRow } from './roster.ts';
9
+ export { TestClient } from './test-client.ts';
10
+ export type { TestClientOptions } from './test-client.ts';
11
+ export { remoteDefaultResponses } from './remote-default-responses.ts';
12
+ export { bundleRoster, webApp } from './bundle-roster.ts';
13
+ export { createClientTest } from './vitest.ts';
14
+ export type { ClientTestFixtures } from './vitest.ts';
15
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1,25 @@
1
+ import type { ClientModuleLoader, WebBootGraph } from '@qilin-agent/client-modules/client';
2
+ import type { AssemblyPlan, ClientPluginModule } from './roster.ts';
3
+ /** The bootstrap row: always this process's static namespace, never a dynamic import or a `provide` replacement. */
4
+ export declare const MODULES_PACKAGE = "@qilin-agent/client-modules";
5
+ /**
6
+ * Resolve each roster row to its plugin module: `plan.provide[name]` when
7
+ * present, otherwise a `/client` import resolved by the repository's tsconfig
8
+ * path aliases under Vitest. The bootstrap row is the
9
+ * statically imported `@qilin-agent/client-modules/client` namespace.
10
+ * @param plan - validated plan.
11
+ * @returns package name → module, in roster order.
12
+ * @throws {Error} when an import fails (the package name prefixes the original message) or the bootstrap row is provided.
13
+ */
14
+ export declare function loadPluginModules(plan: AssemblyPlan): Promise<ReadonlyMap<string, ClientPluginModule>>;
15
+ /**
16
+ * Build the production module system over queued factories returning the
17
+ * loaded namespaces. The bootstrap row uses `bootstrapModule`; `staticModules`
18
+ * is empty because namespaces already hold their own imports. Missing factories
19
+ * reject through `loadBundle` without fetching.
20
+ * @param graph - raw boot graph from `graphFromRoster`; `createClientModuleSystem` parses it.
21
+ * @param modules - loaded plugin modules keyed by package name.
22
+ * @returns module system to install as `loader.internal`; its `manifest` is the parsed graph.
23
+ */
24
+ export declare function createInProcessModules(graph: WebBootGraph, modules: ReadonlyMap<string, ClientPluginModule>): ClientModuleLoader;
25
+ //# sourceMappingURL=modules.d.ts.map
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Default responses for every Remote endpoint the web assembly calls while
3
+ * booting and rendering with no sessions, no workspaces, and default settings.
4
+ * The comment above each row names the plugin that calls it; endpoints boot
5
+ * never touches stay absent so a new call fails loud. `$events` is built into
6
+ * `RemoteMock`.
7
+ * @module @qilin-agent/client-test-runtime/src/assembly/remote-default-responses
8
+ */
9
+ import { type RemoteTable } from '@qilin-agent/remote-mock';
10
+ /** Default responses of the boot-time Remote endpoints; a spec loads it first and layers its own table on top. */
11
+ export declare const remoteDefaultResponses: RemoteTable;
12
+ //# sourceMappingURL=remote-default-responses.d.ts.map
@@ -0,0 +1,20 @@
1
+ import type { RemoteMock } from '@qilin-agent/remote-mock';
2
+ import type { ClientPluginModule } from './roster.ts';
3
+ /** The assembly row the proxies stand in for; its generated clients exist only in built `lib/`. */
4
+ export declare const REMOTES_PACKAGE = "@qilin-agent/api-remotes";
5
+ /**
6
+ * Namespaces to provide: every `remote.<ns>` a roster module injects, plus the
7
+ * namespace of every endpoint the mock has a rule for.
8
+ * @param modules - loaded roster modules.
9
+ * @param mock - the spec's mock.
10
+ * @returns sorted namespace names.
11
+ */
12
+ export declare function remoteNamespacesOf(modules: Iterable<ClientPluginModule>, mock: RemoteMock): readonly string[];
13
+ /**
14
+ * Plugin providing the namespace proxies; `TestClient.start` mounts it before the Loader rows.
15
+ * @param namespaces - namespaces to provide.
16
+ * @param mock - the spec's mock, asked for each endpoint's mode.
17
+ * @returns the plugin.
18
+ */
19
+ export declare function remoteProxiesPlugin(namespaces: readonly string[], mock: RemoteMock): ClientPluginModule;
20
+ //# sourceMappingURL=remote-proxies.d.ts.map
@@ -0,0 +1,80 @@
1
+ /**
2
+ * Client roster: the ordered package-name rows a whole-client test boots, and
3
+ * the plan that annotates one with the rows the test provides itself. `webApp`
4
+ * and `bundleRoster` (`./bundle-roster.ts`) read rosters from the bundle patch
5
+ * files; a spec may also build one inline with {@link ClientRoster.of}.
6
+ * @module @qilin-agent/client-test-runtime/src/assembly/roster
7
+ */
8
+ import type { Context } from '@qilin-agent/kylin';
9
+ import type { WebBootGraph } from '@qilin-agent/client-modules/client';
10
+ /** One browser plugin row as `qilin.client` declares it, keyed by package name. */
11
+ export interface ClientRosterRow {
12
+ /** Package name (== manifest entry id == Loader entry name). */
13
+ readonly name: string;
14
+ /** Package-name dependency edges from `qilin.client.inject` ([] when absent). */
15
+ readonly inject: readonly string[];
16
+ /** Stage-one prefetch mark from `qilin.client.immediately` (false when absent). */
17
+ readonly immediately: boolean;
18
+ }
19
+ /**
20
+ * Synthesize the raw `WebBootGraph` for `rows`: one `application` batch
21
+ * holding every row, `rev: 'local'`, placeholder `/plugins/<name>/client.js`
22
+ * URLs, since every module is seeded in process and never fetched. Validation
23
+ * stays with the production `parseBootManifest` inside the module system:
24
+ * duplicate names and an empty roster are rejected there, not here.
25
+ * @param rows - roster rows in composition order.
26
+ * @returns the unparsed graph, as `createClientModuleSystem` consumes it.
27
+ */
28
+ export declare function graphFromRoster(rows: readonly ClientRosterRow[]): WebBootGraph;
29
+ /** Immutable, name-addressable roster. */
30
+ export declare class ClientRoster {
31
+ readonly rows: readonly ClientRosterRow[];
32
+ /**
33
+ * Build a roster from rows; duplicate names throw.
34
+ * @param rows - roster rows in composition order.
35
+ * @returns roster.
36
+ */
37
+ static of(rows: readonly ClientRosterRow[]): ClientRoster;
38
+ private constructor();
39
+ /**
40
+ * Keep only `names`, preserving roster order; an unknown name throws with the roster listed.
41
+ * @param names - package names to keep.
42
+ * @returns sub-roster.
43
+ */
44
+ pick(names: readonly string[]): ClientRoster;
45
+ /**
46
+ * The named rows plus every row they inject, transitively, in roster order: the rows a spec needs to boot the
47
+ * named plugins as the bundle composes them. The shell's platform modules (`PLATFORM_MODULES`, seeded statically
48
+ * rather than loaded as rows) end the walk. An unknown name throws with the roster listed; a row injecting any
49
+ * other package outside the roster throws, since the bundle itself would not boot.
50
+ * @param names - package names whose dependency cone to keep.
51
+ * @returns sub-roster.
52
+ */
53
+ closure(names: readonly string[]): ClientRoster;
54
+ /**
55
+ * Drop `names`; an unknown name throws with the roster listed.
56
+ * @param names - package names to drop.
57
+ * @returns sub-roster.
58
+ */
59
+ without(names: readonly string[]): ClientRoster;
60
+ private known;
61
+ }
62
+ /** The module face the Loader materializes for one client plugin row. */
63
+ export interface ClientPluginModule {
64
+ apply(ctx: Context, config?: unknown): unknown;
65
+ readonly inject?: readonly string[] | Readonly<Record<string, unknown>>;
66
+ readonly Config?: unknown;
67
+ }
68
+ /** What to boot and what the test supplies itself. */
69
+ export interface AssemblyPlan {
70
+ readonly roster: ClientRoster;
71
+ /** Row replacements by package name (the test's own implementation of that row). Names outside the roster throw. */
72
+ readonly provide?: Readonly<Record<string, ClientPluginModule>>;
73
+ }
74
+ /**
75
+ * Validate a plan against its roster.
76
+ * @param plan - plan to check.
77
+ * @throws {Error} naming any `provide` key outside the roster.
78
+ */
79
+ export declare function assertPlan(plan: AssemblyPlan): void;
80
+ //# sourceMappingURL=roster.d.ts.map
@@ -0,0 +1,83 @@
1
+ /**
2
+ * Whole-client test carrier: boots an {@link AssemblyPlan} through the
3
+ * production `bootClient` over an in-process module table, with a
4
+ * `RemoteMock` bound to that client's Connection plugin instance.
5
+ * @module @qilin-agent/client-test-runtime/src/assembly/test-client
6
+ */
7
+ import { Context } from '@qilin-agent/kylin';
8
+ import { type ConnectionHandle } from '@qilin-agent/client-connection/client';
9
+ import type { RemoteMock } from '@qilin-agent/remote-mock';
10
+ import { type AssemblyPlan } from './roster.ts';
11
+ /** Carrier options. */
12
+ export interface TestClientOptions {
13
+ /**
14
+ * Mount `uiRenderer` into an element (a fresh `document.body` child when `true`); requires jsdom and a roster
15
+ * that provides `uiRenderer`. Default false.
16
+ */
17
+ readonly mount?: boolean | HTMLElement;
18
+ /** Wait for `ctx.connection.state === 'connected'` before returning. Default true. */
19
+ readonly awaitConnected?: boolean;
20
+ /** Readiness budget in milliseconds before `start` rejects with the mock log summary. Default 5000. */
21
+ readonly connectTimeoutMs?: number;
22
+ }
23
+ /** A booted client under test. */
24
+ export declare class TestClient {
25
+ readonly ctx: Context;
26
+ readonly mock: RemoteMock;
27
+ readonly container: HTMLElement | undefined;
28
+ private readonly restore;
29
+ /**
30
+ * Load the roster's modules, bind this client's mock to its Connection row,
31
+ * hold the jsdom shims, and boot through `bootClient` over the synthesized
32
+ * boot graph; afterwards optionally mount and wait for the connection. The
33
+ * bound row replaces only the page-global input adapter: both paths call
34
+ * `installConnection`, while this path supplies the mock carrier, uses
35
+ * default recovery timings, and captures the current page hostname once for
36
+ * later reloads. A caller-provided Connection row remains unchanged and owns
37
+ * its readiness behavior. The `@qilin-agent/api-remotes` row is
38
+ * dropped from the roster: its generated Remote clients exist only in built
39
+ * `lib/`, and the `remote.<ns>` services the roster injects (plus the
40
+ * namespaces the mock has rules for at this point) are provided as
41
+ * contract-free proxies over the same Connection instead; a `provide` entry
42
+ * for that row is refused. On any failure the context is disposed, an owned
43
+ * mount removed, and this client's hold on the shims released before the
44
+ * original error is rethrown.
45
+ * @param plan - roster and annotations.
46
+ * @param mock - Remote mock answering every Gateway call.
47
+ * @param options - mount and readiness options.
48
+ * @returns the booted client.
49
+ */
50
+ static start(plan: AssemblyPlan, mock: RemoteMock, options?: TestClientOptions): Promise<TestClient>;
51
+ private disposing;
52
+ private constructor();
53
+ /** The roster's Connection service (no `Context` augmentation declares it); throws when the roster provides none. */
54
+ get connection(): ConnectionHandle;
55
+ /** Flush pending React work and microtasks inside `act` (plain microtask flush without a DOM). */
56
+ flush(): Promise<void>;
57
+ /**
58
+ * Rebuild one Loader entry: Client Modules' registry-first fiber teardown, then
59
+ * `entry.refresh()`. Each client's module table retains its own instance-bound
60
+ * Connection plugin, so reloads do not coordinate through process globals.
61
+ * Requires a live client: after `dispose()` the Loader holds no entries and
62
+ * the lookup throws before teardown.
63
+ * @param name - package name of the row.
64
+ */
65
+ reload(name: string): Promise<void>;
66
+ /**
67
+ * Remove one Loader entry and wait for its plugin cleanup.
68
+ * @param name - package name of the row.
69
+ */
70
+ unload(name: string): Promise<void>;
71
+ /**
72
+ * Dispose the plugin tree, then drop an owned mount and release this
73
+ * client's hold on the shared jsdom shims even when the tree fails to dispose,
74
+ * then `mock.assertNoUnmatched()` last so its failure is the test's reason
75
+ * without skipping the cleanup; when both the tree and the check fail, one
76
+ * error carries both messages. The first call owns the teardown and reports
77
+ * its failure; every later call waits for that teardown and resolves.
78
+ */
79
+ dispose(): Promise<void>;
80
+ private teardown;
81
+ private entryOf;
82
+ }
83
+ //# sourceMappingURL=test-client.d.ts.map
@@ -0,0 +1,24 @@
1
+ /** Test-scoped Remote mock and lazy client boot, owned by native Vitest fixtures. */
2
+ import { type TestAPI } from 'vitest';
3
+ import { RemoteMock, type MockedRemote } from '@qilin-agent/remote-mock';
4
+ import type { AssemblyPlan } from './roster.ts';
5
+ import { TestClient, type TestClientOptions } from './test-client.ts';
6
+ /** Per-test controls; configure the mock before awaiting `start()`. */
7
+ export interface ClientTestFixtures {
8
+ /** Fresh mock with the assembly's default responses already loaded. */
9
+ mock: RemoteMock;
10
+ /** Namespace proxy backed by the same native mocks used by the Connection carrier. */
11
+ remote: MockedRemote;
12
+ /** Await the one client owned by this test; rejects after the fixture closes. */
13
+ start: () => Promise<TestClient>;
14
+ }
15
+ /**
16
+ * Extend Vitest with a fresh mock and a lazy, automatically disposed client. Repeated `start()` calls share one
17
+ * promise. Await it to observe startup failures; cleanup waits for startup but does not rethrow its rejection.
18
+ * Missing mock responses still fail teardown even when no client was started. Page globals remain environment-owned.
19
+ * @param plan - roster and replacement modules, shared as configuration rather than as a running client.
20
+ * @param options - mount and readiness settings passed to `TestClient.start`.
21
+ * @returns Vitest's test function with test-scoped `mock` and `start` fixtures.
22
+ */
23
+ export declare function createClientTest(plan: AssemblyPlan, options?: TestClientOptions): TestAPI<ClientTestFixtures>;
24
+ //# sourceMappingURL=vitest.d.ts.map
@@ -0,0 +1,29 @@
1
+ /** Test doubles for settings transport. */
2
+ import { vi } from 'vitest';
3
+ import type { ConfigForm, ConfigFormSnapshot } from '@qilin-agent/client-ui-settings/client';
4
+ /** Handle over one stubbed scope: the scope, its write spy, and publication controls. */
5
+ export interface StubConfigForm<T> {
6
+ /** The scope face handed to the service under test. */
7
+ scope: ConfigForm<T>;
8
+ /** Spy behind `scope.set`; resolves immediately. */
9
+ set: ReturnType<typeof vi.fn>;
10
+ /** Spy behind `scope.mutate`; resolves immediately. */
11
+ mutate: ReturnType<typeof vi.fn<ConfigForm<T>['mutate']>>;
12
+ /** Spy behind `scope.unset`; resolves immediately. */
13
+ unset: ReturnType<typeof vi.fn>;
14
+ /** @returns how many listeners are currently subscribed (disposal assertions). */
15
+ listenerCount(): number;
16
+ /**
17
+ * Replace part of the snapshot and notify subscribers, as a Host
18
+ * acceptance would.
19
+ * @param next - snapshot fields to replace.
20
+ */
21
+ publish(next: Partial<ConfigFormSnapshot<T>>): void;
22
+ }
23
+ /**
24
+ * Build an in-memory settings scope for service specs: starts in the host
25
+ * loading state, records writes, and lets the test publish Host acceptances.
26
+ * @returns the stub handle.
27
+ */
28
+ export declare function stubConfigForm<T>(): StubConfigForm<T>;
29
+ //# sourceMappingURL=config-form.d.ts.map
@@ -0,0 +1,73 @@
1
+ /** Controller and UI-domain fixture shapes for the client test runtime. */
2
+ import type { ISession, SessionEventLikeEntry, SessionSnapshot, SessionSummary } from '@qilin-agent/api-session-controller/client';
3
+ import type { WorkspaceSnapshot } from '@qilin-agent/api-workspace-controller/client';
4
+ import type { SessionId } from '@qilin-agent/session/types';
5
+ import { type ConversationSnapshot } from '@qilin-agent/client-ui-conversation/client';
6
+ import { type ChatSnapshot } from '@qilin-agent/client-ui-chat/client';
7
+ /**
8
+ * Fixture overrides for the session behavior face: any subset of the
9
+ * production ISession verbs (typed against it, so a face change surfaces
10
+ * here at compile time), plus extra members feature-specific casts consume.
11
+ * The open Record tail means a misnamed EXTRA member is not caught by the
12
+ * compiler (it grafts as dead weight); the ISession verbs stay safe — a
13
+ * misnamed verb leaves the fail-loud stub in place, which names itself at
14
+ * the first call.
15
+ */
16
+ export type SessionBehaviorOverrides = Partial<ISession> & Record<string, unknown>;
17
+ /**
18
+ * act-wrapped mutation runner shared by every runtime object: public mutators
19
+ * funnel through it so tests never handle SlotCore microtask batching or
20
+ * React act themselves.
21
+ */
22
+ export type Stabilizer = (fn: () => void | Promise<void>) => Promise<void>;
23
+ /** Mutable top-level snapshot fields accepted by fixture update callbacks. */
24
+ export type FixtureSnapshot<T> = {
25
+ -readonly [Key in keyof T]: T[Key];
26
+ };
27
+ /** Writable test representation of the immutable Session Controller snapshot. */
28
+ export type SessionFixtureSnapshot = FixtureSnapshot<SessionSnapshot>;
29
+ /**
30
+ * Session fixture accepted by {@link TestSessions.add}: identity plus optional
31
+ * snapshot/list-row overrides and the session behavior face the feature under
32
+ * test actually calls (kept open — the runtime never fakes methods a test did
33
+ * not supply, so an unstubbed call fails loud at the call site).
34
+ */
35
+ export interface SessionFixture {
36
+ id: string;
37
+ /** Overrides merged over {@link sessionSnapshot}; Conversation data arrives through the event feed. */
38
+ snapshot?: Partial<Omit<SessionSnapshot, 'sessionId'>>;
39
+ /** List-row overrides merged over the defaults derived from `id`. */
40
+ summary?: Partial<Omit<SessionSummary, 'id'>>;
41
+ /** Session behavior face: exactly the methods the feature under test calls (ISession subset + extras). */
42
+ session?: SessionBehaviorOverrides;
43
+ /** Initial contiguous event window consumed by Conversation assembly. */
44
+ events?: readonly SessionEventLikeEntry[];
45
+ /** Whether the initial event window has an older page. */
46
+ hasMore?: boolean;
47
+ /** Optional shared initial-opening barrier for the fixture's Client generation. */
48
+ initialOpen?: (signal: AbortSignal) => void | Promise<void>;
49
+ }
50
+ /**
51
+ * A complete quiescent Session Controller snapshot.
52
+ * @param sessionId - owning session id.
53
+ * @returns the snapshot; spread fixture overrides on top.
54
+ */
55
+ export declare function sessionSnapshot(sessionId: SessionId): SessionSnapshot;
56
+ /**
57
+ * A target-neutral Conversation snapshot.
58
+ * @param overrides - target roster or activity overrides.
59
+ * @returns an immutable fixture value.
60
+ */
61
+ export declare function conversationSnapshot(overrides?: Partial<ConversationSnapshot>): ConversationSnapshot;
62
+ /**
63
+ * A Chat target snapshot.
64
+ * @param overrides - Chat target overrides.
65
+ * @returns an immutable fixture value.
66
+ */
67
+ export declare function chatSnapshot(overrides?: Partial<ChatSnapshot>): ChatSnapshot;
68
+ /**
69
+ * A ready Workspace Controller snapshot with no Workspace rows.
70
+ * @returns the initial state of the test Workspace source.
71
+ */
72
+ export declare function workspaceSnapshot(): WorkspaceSnapshot;
73
+ //# sourceMappingURL=fixtures.d.ts.map
@@ -0,0 +1,236 @@
1
+ /**
2
+ * jsdom slot test runtime: a real small runtime — Cordis `Context`, the
3
+ * renderer-owned `SlotRegistry`, the `ui-session` adapter, and the UI renderer — assembled around
4
+ * test-owned session/workspace doubles and a fail-loud file-upload stub, so feature specs exercise
5
+ * declaration, registration, scope, store, inject, rendering, updates, and
6
+ * disposal without hand-building the machinery per suite.
7
+ *
8
+ * Not part of the product plugin graph (no `qilin.client`); feature packages
9
+ * depend on it in devDependencies only. It copies no SlotCore/renderer/store
10
+ * machinery — everything mounts the production implementations.
11
+ * @module @qilin-agent/client-test-runtime
12
+ */
13
+ import { Context } from '@qilin-agent/kylin';
14
+ import type { Fiber, Plugin } from '@qilin-agent/kylin';
15
+ import type { RenderResult } from '@testing-library/react';
16
+ import type { queries } from '@testing-library/dom';
17
+ import type { BoundFunctions } from '@testing-library/dom';
18
+ import { SlotRegistry } from '@qilin-agent/client-ui-renderer/client';
19
+ import type { SessionReference } from '@qilin-agent/api-session-controller/client';
20
+ import type { SessionId } from '@qilin-agent/session/types';
21
+ import type { PanelInfo } from '@qilin-agent/client-ui-layout/client';
22
+ import type { ChildrenDecl, ComposedProps, HostObservable, OwnerOf, RenderOpts, SlotComponent, SlotMap, SlotRenderer, SlotFactoryMap, SnapshotSelectorHook, StoredFactory, StoreInstanceLike } from '@qilin-agent/client-ui-slots';
23
+ import { TestRemote } from './remote.ts';
24
+ import { TestSessions } from './sessions.ts';
25
+ import { TestWorkspaces } from './workspaces.ts';
26
+ import type { Stabilizer } from './fixtures.ts';
27
+ export type { UseSession } from '@qilin-agent/client-ui-session/client';
28
+ export { domSnapshotSerializer, registerDomSnapshotSerializer } from './snapshot.ts';
29
+ export { FixtureSession, TestSessions } from './sessions.ts';
30
+ export { stubConfigForm } from './config-form.ts';
31
+ export type { StubConfigForm } from './config-form.ts';
32
+ export { scriptedSettingsRemote } from './settings-remote.ts';
33
+ export type { ScriptedNamespace, ScriptedSettingsRemote } from './settings-remote.ts';
34
+ export { TestWorkspaces } from './workspaces.ts';
35
+ export { RemoteError, TestRemote } from './remote.ts';
36
+ export { chatSnapshot, conversationSnapshot, sessionSnapshot, workspaceSnapshot, } from './fixtures.ts';
37
+ export type { FixtureSnapshot, SessionBehaviorOverrides, SessionFixture, SessionFixtureSnapshot, Stabilizer, } from './fixtures.ts';
38
+ export { makeTranslate } from './translate.ts';
39
+ export { usePinnedBrowserLanguages } from './locale-env.ts';
40
+ /**
41
+ * Bind an observable source to the production renderer's selector hook.
42
+ * @param source - Observable snapshot source.
43
+ * @returns Typed React selector hook.
44
+ */
45
+ export declare function bindSnapshotSelector<T>(source: HostObservable<T>): SnapshotSelectorHook<T>;
46
+ /**
47
+ * Create the production slot renderer used by client feature tests.
48
+ * @returns Slot renderer instance.
49
+ */
50
+ export declare function createSlotRenderer(): SlotRenderer;
51
+ /** Per-view render options; the caller owns the explicitly supplied Session reference. */
52
+ export interface SlotTestRenderOptions extends RenderOpts {
53
+ readonly session?: SessionReference | undefined;
54
+ }
55
+ /**
56
+ * One rendered slot's local view, from {@link SlotTestRuntime.renderSlot}:
57
+ * the renderer's own `[data-slot]` outlet anchor is the snapshot root
58
+ * (`expect(view.container).toMatchSnapshot()` captures exactly this slot's
59
+ * output), Testing Library queries are bound inside it, and `update`
60
+ * re-renders with new owner props.
61
+ */
62
+ export interface SlotView<K extends keyof SlotMap & string> {
63
+ /** The renderer's `<div data-slot="<key>">` anchor around the slot's rendered output. */
64
+ readonly container: HTMLElement;
65
+ /** Testing Library queries scoped to {@link SlotView.container}. */
66
+ readonly view: BoundFunctions<typeof queries>;
67
+ /**
68
+ * Replace the owner props and flush the re-render (the render-site update:
69
+ * in production the owner recomputes the share and React re-renders).
70
+ * @param owner - the next owner props share.
71
+ * @param opts - replacement render options and borrowed reference; omission keeps this view's options.
72
+ */
73
+ update(owner: OwnerOf<K>, opts?: SlotTestRenderOptions): void;
74
+ }
75
+ /**
76
+ * Mounted feature plugin handle: the live fiber plus an act-wrapped,
77
+ * idempotent dispose (unload cascade: entries, declared child slots, store
78
+ * instances, and provided services all fall together).
79
+ */
80
+ export interface FeatureHandle {
81
+ /** The plugin's live Cordis fiber (state assertions, escape hatch). */
82
+ readonly fiber: Fiber;
83
+ /**
84
+ * Dispose the plugin fiber inside React act; repeated calls no-op.
85
+ * @returns completion of the unload cascade.
86
+ */
87
+ dispose(): Promise<void>;
88
+ }
89
+ /** Mutable fail-loud file-upload stub installed by {@link SlotTestRuntime}. */
90
+ export interface TestFileUpload {
91
+ /** Test-supplied upload behavior; the default rejects every call. */
92
+ upload: (sessionId: SessionId, ...args: unknown[]) => Promise<unknown>;
93
+ }
94
+ /**
95
+ * The test-owned 'root' occupant: declares the child slots a suite needs
96
+ * through the REAL `slots.register`, with a caller-supplied minimal frame —
97
+ * the runtime never guesses a feature's page structure.
98
+ */
99
+ export declare class TestRoot {
100
+ private readonly slots;
101
+ private readonly stabilize;
102
+ private disposeEntry;
103
+ /**
104
+ * @param slots - the runtime SlotRegistry.
105
+ * @param stabilize - the owning runtime's act wrapper.
106
+ */
107
+ constructor(slots: SlotRegistry, stabilize: Stabilizer);
108
+ /**
109
+ * Register the root frame, declaring (and thereby claiming) the child
110
+ * slots. One declaration per runtime — a second call fails loud in the
111
+ * core ('root' is a single slot).
112
+ * @param children - child-slot declaration table (declaration + render authorization + runtime spec).
113
+ * @param frame - minimal frame component; its props derive from the declared keys (composed-props contract).
114
+ * @returns completion of the act-wrapped registration.
115
+ */
116
+ declare<const D extends ChildrenDecl>(children: D, frame: SlotComponent<ComposedProps<'root', never, keyof NoInfer<D> & keyof SlotMap & string, undefined, object>>): Promise<void>;
117
+ /** Remove the root registration and collapse its declarations (runtime dispose path). */
118
+ release(): void;
119
+ }
120
+ /**
121
+ * The assembled test runtime. Obtain via {@link SlotTestRuntime.create};
122
+ * dispose with {@link SlotTestRuntime.dispose} (afterEach). Public mutators
123
+ * are act-wrapped throughout — tests never handle SlotCore microtask
124
+ * batching or React act themselves.
125
+ */
126
+ export declare class SlotTestRuntime {
127
+ /** The runtime's Cordis root for owner APIs and explicit test-only services. */
128
+ readonly ctx: Context;
129
+ /** The production SlotRegistry mounted on {@link SlotTestRuntime.ctx}. */
130
+ readonly slots: SlotRegistry;
131
+ /** The test-owned 'root' occupant. */
132
+ readonly root: TestRoot;
133
+ /** Fixture catalog, explicit references, scoped contexts, and behavior faces. */
134
+ readonly sessions: TestSessions;
135
+ /** One Remote double shared by every feature mounted in this runtime. */
136
+ readonly remote: TestRemote;
137
+ /** Workspaces double (list observable, recorded intent actions). */
138
+ readonly workspaces: TestWorkspaces;
139
+ /** Test-owned panel selection used by the framework's usePanelInfo hook. */
140
+ readonly panelInfo: import("@qilin-agent/client-store").SnapshotStore<PanelInfo>;
141
+ /** Mutable file-upload stub; replace `upload` in suites that exercise the capability. */
142
+ readonly fileUpload: TestFileUpload;
143
+ private readonly stabilizer;
144
+ private host;
145
+ private readonly views;
146
+ private readonly handles;
147
+ private disposed;
148
+ /** Auto-frame state ({@link SlotTestRuntime.declare} / {@link SlotTestRuntime.renderSlot}). */
149
+ private readonly ownerCell;
150
+ private readonly autoDeclared;
151
+ private autoRootView;
152
+ private readonly disposeWorkspaceSource;
153
+ private readonly disposePanelInfoSource;
154
+ private constructor();
155
+ /**
156
+ * Assemble a runtime: real Context, mounted SlotRegistry, installed
157
+ * renderer, and the session/workspace doubles provided as services.
158
+ * @param options - the shortcuts stub is mounted unless `shortcuts: false`,
159
+ * which lets a spec provide the real shortcuts service instead.
160
+ * @returns the ready runtime.
161
+ */
162
+ static create(options?: {
163
+ shortcuts?: boolean;
164
+ }): Promise<SlotTestRuntime>;
165
+ /**
166
+ * Mount a feature plugin on a real fiber. Required services are prechecked
167
+ * so a missing provider fails loud instead of suspending the fiber forever
168
+ * (deliberate load-order suspension tests use `ctx.plugin` directly).
169
+ * @param plugin - plugin value (function, class, or `{ inject, apply }` object).
170
+ * @returns handle owning the fiber's explicit disposal.
171
+ */
172
+ mount(plugin: Plugin): Promise<FeatureHandle>;
173
+ /** Release the default Workspace hook before mounting its production owner. */
174
+ releaseWorkspaceSource(): void;
175
+ /** Release the default panel hook before mounting the production Layout owner. */
176
+ releasePanelInfoSource(): void;
177
+ /**
178
+ * Render the root slot tree through the ctx-level entry (the shell's own
179
+ * entry point): `ctx.slots.renderSlot('root', {})` under Testing Library.
180
+ * @returns the Testing Library view.
181
+ */
182
+ renderRoot(): RenderResult;
183
+ /**
184
+ * Declare child slots under an auto-generated root frame — the single-slot
185
+ * mounting path for local DOM snapshots. Each key later supplied through
186
+ * {@link SlotTestRuntime.renderSlot} renders inside the renderer's own
187
+ * `<div data-slot="<key>">` outlet anchor (the snapshot root — the frame
188
+ * adds no wrapper of its own). Mutually exclusive with
189
+ * {@link TestRoot.declare} ('root' is a single slot); one call per runtime.
190
+ * @param children - child-slot declaration table (same contract as TestRoot.declare).
191
+ * @returns completion of the act-wrapped registration.
192
+ */
193
+ declare(children: ChildrenDecl): Promise<void>;
194
+ /**
195
+ * Render one declared slot with its owner props and return the local view.
196
+ * The whole root tree mounts through the production assembly path
197
+ * (renderer, scope providers, store axis); only this key's output lands in
198
+ * the returned container. Call again with another key to view a sibling
199
+ * slot of the same tree.
200
+ * @param key - a key declared through {@link SlotTestRuntime.declare}.
201
+ * @param owner - owner props share for the render site.
202
+ * @param opts - explicit entry selection and borrowed Session reference; retained by view updates.
203
+ * @returns the slot-local view (snapshot container, scoped queries, owner updates).
204
+ */
205
+ renderSlot<K extends keyof SlotMap & string>(key: K, owner: OwnerOf<K>, opts?: SlotTestRenderOptions): SlotView<K>;
206
+ /**
207
+ * Resolve the store instance the renderer would hand a slot's component
208
+ * (identity assertions, action-driven writes). Requires a prior
209
+ * {@link SlotTestRuntime.renderRoot} — the host face exists only inside the
210
+ * installed renderer, exactly as in production.
211
+ * @param key - slot key whose first entry declares the store.
212
+ * @param session - retained Session reference for session-scope slots; omit for root scope.
213
+ * @returns the live store instance.
214
+ */
215
+ storeOf(key: keyof SlotMap & string, session?: SessionReference): StoreInstanceLike;
216
+ /**
217
+ * Read one registered Factory definition for direct contract assertions.
218
+ * @param name - registered Factory name.
219
+ * @returns the live Factory definition.
220
+ */
221
+ factoryOf(name: keyof SlotFactoryMap & string): StoredFactory;
222
+ /**
223
+ * Flush pending ledger/store notifications inside act — for mutations made
224
+ * outside the runtime's own methods (e.g. a direct `slots.register`).
225
+ * @returns completion of the act pass.
226
+ */
227
+ flush(): Promise<void>;
228
+ /**
229
+ * Tear down: unmount React trees first, then dispose feature fibers, the
230
+ * root registration and standard sources, minted session scopes, and persisted test state.
231
+ * Idempotent.
232
+ * @returns completion of the teardown.
233
+ */
234
+ dispose(): Promise<void>;
235
+ }
236
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Pin `navigator.languages`/`navigator.language` for every test in the
3
+ * calling file (or describe block), restoring the environment's own values
4
+ * afterwards. Call at suite level, like the other vitest hooks.
5
+ * @param primary - most preferred BCP 47 tag; also becomes `navigator.language`.
6
+ * @param rest - further tags in preference order.
7
+ */
8
+ export declare function usePinnedBrowserLanguages(primary: string, ...rest: string[]): void;
9
+ //# sourceMappingURL=locale-env.d.ts.map