@zhin.js/testing 0.0.0-stage → 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +115 -2
  3. package/lib/delivery-capture.d.ts +3 -0
  4. package/lib/delivery-capture.d.ts.map +1 -0
  5. package/lib/delivery-capture.js +54 -0
  6. package/lib/delivery-capture.js.map +1 -0
  7. package/lib/fake-clock.d.ts +36 -0
  8. package/lib/fake-clock.d.ts.map +1 -0
  9. package/lib/fake-clock.js +100 -0
  10. package/lib/fake-clock.js.map +1 -0
  11. package/lib/fake-hosts.d.ts +51 -0
  12. package/lib/fake-hosts.d.ts.map +1 -0
  13. package/lib/fake-hosts.js +113 -0
  14. package/lib/fake-hosts.js.map +1 -0
  15. package/lib/fake-plugin.d.ts +83 -0
  16. package/lib/fake-plugin.d.ts.map +1 -0
  17. package/lib/fake-plugin.js +130 -0
  18. package/lib/fake-plugin.js.map +1 -0
  19. package/lib/fake-runners.d.ts +47 -0
  20. package/lib/fake-runners.d.ts.map +1 -0
  21. package/lib/fake-runners.js +60 -0
  22. package/lib/fake-runners.js.map +1 -0
  23. package/lib/index.d.ts +74 -0
  24. package/lib/index.d.ts.map +1 -0
  25. package/lib/index.js +168 -0
  26. package/lib/index.js.map +1 -0
  27. package/lib/partial.d.ts +7 -0
  28. package/lib/partial.d.ts.map +1 -0
  29. package/lib/partial.js +9 -0
  30. package/lib/partial.js.map +1 -0
  31. package/lib/test-module-runtime.d.ts +5 -0
  32. package/lib/test-module-runtime.d.ts.map +1 -0
  33. package/lib/test-module-runtime.js +34 -0
  34. package/lib/test-module-runtime.js.map +1 -0
  35. package/package.json +50 -3
  36. package/src/delivery-capture.ts +48 -0
  37. package/src/fake-clock.ts +116 -0
  38. package/src/fake-hosts.ts +131 -0
  39. package/src/fake-plugin.ts +171 -0
  40. package/src/fake-runners.ts +117 -0
  41. package/src/index.ts +202 -0
  42. package/src/partial.ts +8 -0
  43. package/src/test-module-runtime.ts +38 -0
@@ -0,0 +1,130 @@
1
+ import { DisposeStack, GenerationHandoffStack, PluginDatabaseHost, PluginOutboundHost, PluginScheduleHost, Scope, databaseHostToken, outboundHostToken, qualifyPluginResourceName, rootPluginId, scheduleHostToken, } from '@zhin.js/plugin-runtime';
2
+ import { FakeClock, FakeScheduleRootHost } from './fake-clock.js';
3
+ import { FakeDatabaseRootHost, FakeOutboundRootHost } from './fake-hosts.js';
4
+ /** Bind a value to a token with the token's own type, so tests need no cast. */
5
+ export function fakeResource(token, value) {
6
+ return { token: token, value };
7
+ }
8
+ /**
9
+ * Typed fake of one plugin's runtime surface. Built from the real `Scope`, `DisposeStack`,
10
+ * `GenerationHandoffStack` and the real owner-bound `PluginDatabaseHost` / `PluginScheduleHost` /
11
+ * `PluginOutboundHost` facades, over in-memory process hosts. No `as never` needed in tests.
12
+ */
13
+ export class FakePlugin {
14
+ id = rootPluginId();
15
+ name;
16
+ config;
17
+ resources;
18
+ lifecycle = new DisposeStack();
19
+ handoff = new GenerationHandoffStack();
20
+ clock;
21
+ generation;
22
+ projections;
23
+ /** Features registered by `setup()` through `addFeature` / `addCommand` / `addMiddleware` ... */
24
+ features = [];
25
+ /** Process-level fakes behind the facades. */
26
+ databaseHost = new FakeDatabaseRootHost();
27
+ outboundHost = new FakeOutboundRootHost();
28
+ scheduleHost;
29
+ /** Facades exactly as `resources.use(token)` returns them. */
30
+ database;
31
+ schedule;
32
+ outbound;
33
+ #abort = new AbortController();
34
+ #context;
35
+ constructor(options = {}) {
36
+ this.name = options.name ?? 'test-plugin';
37
+ this.config = (options.config ?? {});
38
+ this.generation = options.generation ?? 1;
39
+ this.projections = options.projections ?? new Map();
40
+ this.clock = options.clock instanceof FakeClock ? options.clock : new FakeClock(options.clock);
41
+ this.scheduleHost = new FakeScheduleRootHost(this.clock);
42
+ this.resources = new Scope(this.id, undefined, this.lifecycle);
43
+ this.database = new PluginDatabaseHost(this.id, this.databaseHost);
44
+ this.schedule = new PluginScheduleHost(this.id, this.scheduleHost);
45
+ this.outbound = new PluginOutboundHost(this.id, this.outboundHost);
46
+ const hosts = options.hosts ?? {};
47
+ if (hosts.database !== false)
48
+ this.resources.provide(databaseHostToken, this.database);
49
+ if (hosts.schedule !== false)
50
+ this.resources.provide(scheduleHostToken, this.schedule);
51
+ if (hosts.outbound !== false)
52
+ this.resources.provide(outboundHostToken, this.outbound);
53
+ for (const { token, value } of options.resources ?? [])
54
+ this.resources.provide(token, value);
55
+ this.#context = this.#createSetupContext();
56
+ }
57
+ /** The `context` argument `setup()` receives. */
58
+ get context() { return this.#context; }
59
+ get signal() { return this.#abort.signal; }
60
+ /** Messages recorded by the fake outbound host (every kind of call). */
61
+ get sent() { return this.outboundHost.calls; }
62
+ /** Rows of a table the plugin created with `database.define(name, ...)`. */
63
+ rows(name) {
64
+ return this.databaseHost.rowsOf(qualifyPluginResourceName(this.id, name));
65
+ }
66
+ /** Run `definition.setup()` against this fake; a returned disposer joins `lifecycle`. */
67
+ async setup(definition) {
68
+ const dispose = await definition.setup?.(this.#context);
69
+ if (dispose)
70
+ this.lifecycle.add(dispose);
71
+ }
72
+ /** Tokens declared in `requires` that this fake did not provide. */
73
+ missingRequirements(definition) {
74
+ return (definition.requires ?? []).filter(token => !this.resources.has(token));
75
+ }
76
+ /** A `CapabilityContext` for running commands / middleware / handlers against this fake. */
77
+ capabilityContext() {
78
+ const owner = Object.freeze({
79
+ id: this.id, instanceKey: this.name, packageName: this.name, packageRoot: '/fake', children: [],
80
+ });
81
+ return Object.freeze({
82
+ signal: this.signal, owner, generation: this.generation,
83
+ config: this.config,
84
+ use: (token) => this.resources.use(token),
85
+ project: (feature) => {
86
+ if (!this.projections.has(feature))
87
+ throw new Error(`Missing Feature projection ${feature}`);
88
+ return this.projections.get(feature);
89
+ },
90
+ });
91
+ }
92
+ /** Abort `signal` and run every disposer (reverse order). */
93
+ async dispose() {
94
+ this.#abort.abort();
95
+ await this.lifecycle.dispose();
96
+ }
97
+ #createSetupContext() {
98
+ const base = {
99
+ signal: this.signal,
100
+ plugin: Object.freeze({ id: this.id, instanceKey: this.name, root: this.id, role: 'root' }),
101
+ config: Object.freeze({ get: () => this.config }),
102
+ resources: this.resources,
103
+ lifecycle: this.lifecycle,
104
+ handoff: this.handoff,
105
+ addFeature: (feature, localName, definition) => {
106
+ this.features.push({ kind: String(feature), localName, definition });
107
+ },
108
+ };
109
+ // Feature packages augment the setup context with `addCommand` / `addMiddleware` / ...; record them all.
110
+ return new Proxy(base, {
111
+ get: (target, key, receiver) => {
112
+ if (Reflect.has(target, key) || typeof key !== 'string' || !/^add[A-Z]/.test(key)) {
113
+ return Reflect.get(target, key, receiver);
114
+ }
115
+ const kind = key.slice(3).toLowerCase();
116
+ return (localName, definition) => { this.features.push({ kind, localName, definition }); };
117
+ },
118
+ });
119
+ }
120
+ }
121
+ export function createFakePlugin(options) {
122
+ return new FakePlugin(options);
123
+ }
124
+ /** Create a fake and run `definition.setup()` in one step. Call `dispose()` when done. */
125
+ export async function runPluginSetup(definition, options) {
126
+ const fake = new FakePlugin({ ...options, name: definition.name });
127
+ await fake.setup(definition);
128
+ return fake;
129
+ }
130
+ //# sourceMappingURL=fake-plugin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fake-plugin.js","sourceRoot":"","sources":["../src/fake-plugin.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,47 @@
1
+ import type { CommandContext, CommandDefinition, CommandMessage, CommandParameterValue } from '@zhin.js/command';
2
+ import type { HandlerDefinition } from '@zhin.js/handler';
3
+ import type { MiddlewareDefinition } from '@zhin.js/middleware';
4
+ import type { FakePlugin } from './fake-plugin.js';
5
+ /** Inbound message with recorded replies. */
6
+ export interface FakeMessage extends CommandMessage {
7
+ /** Everything passed to `$reply`, in order. */
8
+ readonly replies: unknown[];
9
+ }
10
+ export interface FakeMessageInit {
11
+ readonly content?: string;
12
+ readonly sender?: {
13
+ readonly id: string;
14
+ readonly name?: string;
15
+ readonly roles?: readonly string[];
16
+ };
17
+ readonly conversation?: Partial<CommandMessage['conversation']>;
18
+ readonly id?: string;
19
+ readonly metadata?: Readonly<Record<string, unknown>>;
20
+ readonly $client?: unknown;
21
+ }
22
+ export declare function createFakeMessage(init?: FakeMessageInit): FakeMessage;
23
+ export interface RunCommandOptions<TInput extends CommandMessage = FakeMessage> {
24
+ readonly input?: TInput;
25
+ readonly args?: readonly string[];
26
+ readonly params?: Readonly<Record<string, CommandParameterValue>>;
27
+ readonly options?: Readonly<Record<string, CommandParameterValue>>;
28
+ readonly segments?: CommandContext['segments'];
29
+ readonly interaction?: CommandContext['interaction'];
30
+ }
31
+ /** Build the context a command receives from the fake plugin; usable for direct `execute()` calls. */
32
+ export declare function createCommandContext<TConfig, TInput extends CommandMessage = FakeMessage>(fake: FakePlugin<TConfig>, options?: RunCommandOptions<TInput>): CommandContext<TConfig, TInput, string | undefined>;
33
+ /**
34
+ * Execute a command definition against the fake. This calls `execute()` directly: it does NOT run
35
+ * route matching, parameter parsing, `permit`, or admission. Use `PluginTestKit` for those.
36
+ */
37
+ export declare function runCommand<TConfig, TResult, TInput extends CommandMessage = FakeMessage>(fake: FakePlugin<TConfig>, definition: CommandDefinition<TConfig, TResult, TInput, string | undefined>, options?: RunCommandOptions<TInput>): Promise<TResult>;
38
+ export interface RunMiddlewareResult {
39
+ /** `true` when the middleware called `next()`. */
40
+ readonly continued: boolean;
41
+ readonly result: unknown;
42
+ }
43
+ /** Execute an inbound or outbound middleware's `handle()`; `next` records whether it was called. */
44
+ export declare function runMiddleware<TConfig, TInput = FakeMessage>(fake: FakePlugin<TConfig>, definition: MiddlewareDefinition<TInput, TConfig, string | undefined>, input?: TInput): Promise<RunMiddlewareResult>;
45
+ /** Execute a handler's `handle()` with `this` bound to a capability context. */
46
+ export declare function runHandler<TConfig>(fake: FakePlugin<TConfig>, definition: HandlerDefinition, ...args: unknown[]): Promise<void>;
47
+ //# sourceMappingURL=fake-runners.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fake-runners.d.ts","sourceRoot":"","sources":["../src/fake-runners.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,60 @@
1
+ export function createFakeMessage(init = {}) {
2
+ const replies = [];
3
+ const conversation = {
4
+ endpoint: { id: 'test', adapter: 'test' }, kind: 'group', id: 'test-group', ...init.conversation,
5
+ };
6
+ return {
7
+ conversation, content: init.content ?? '',
8
+ sender: init.sender ?? { id: 'test-user', name: 'Tester', roles: [] },
9
+ ...(init.id === undefined ? {} : { id: init.id }),
10
+ ...(init.metadata === undefined ? {} : { metadata: init.metadata }),
11
+ ...(init.$client === undefined ? {} : { $client: init.$client }),
12
+ replies,
13
+ async $reply(content) { replies.push(content); return `reply-${replies.length}`; },
14
+ };
15
+ }
16
+ /** Build the context a command receives from the fake plugin; usable for direct `execute()` calls. */
17
+ export function createCommandContext(fake, options = {}) {
18
+ const input = (options.input ?? createFakeMessage());
19
+ const conversation = input.conversation;
20
+ const sender = input.sender;
21
+ return {
22
+ ...fake.capabilityContext(),
23
+ args: options.args ?? [],
24
+ params: options.params ?? {},
25
+ options: options.options ?? {},
26
+ segments: options.segments ?? [],
27
+ input,
28
+ $client: input.$client,
29
+ interaction: options.interaction,
30
+ adapter: conversation.endpoint.adapter,
31
+ endpoint: conversation.endpoint.id,
32
+ scene: input.scene ?? { id: conversation.id, type: conversation.kind },
33
+ ...(sender ? { sender: { id: sender.id, name: sender.name, role: sender.roles ?? [] } } : {}),
34
+ };
35
+ }
36
+ /**
37
+ * Execute a command definition against the fake. This calls `execute()` directly: it does NOT run
38
+ * route matching, parameter parsing, `permit`, or admission. Use `PluginTestKit` for those.
39
+ */
40
+ export async function runCommand(fake, definition, options) {
41
+ return definition.execute(createCommandContext(fake, options));
42
+ }
43
+ /** Execute an inbound or outbound middleware's `handle()`; `next` records whether it was called. */
44
+ export async function runMiddleware(fake, definition, input = createFakeMessage()) {
45
+ let continued = false;
46
+ const context = {
47
+ ...fake.capabilityContext(),
48
+ input,
49
+ $client: input?.$client,
50
+ };
51
+ const next = (async () => { continued = true; return undefined; });
52
+ const result = await definition.handle(context, next);
53
+ return { continued, result };
54
+ }
55
+ /** Execute a handler's `handle()` with `this` bound to a capability context. */
56
+ export async function runHandler(fake, definition, ...args) {
57
+ const context = fake.capabilityContext();
58
+ await definition.handle.call(context, ...args);
59
+ }
60
+ //# sourceMappingURL=fake-runners.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fake-runners.js","sourceRoot":"","sources":["../src/fake-runners.ts"],"names":[],"mappings":"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"}
package/lib/index.d.ts ADDED
@@ -0,0 +1,74 @@
1
+ import { type AdapterSegmentPolicy, type EndpointIncomingMessage } from '@zhin.js/adapter';
2
+ import { ImRuntime, type ConversationAddress, type MessageDispatchResult, type SendContent } from '@zhin.js/core/runtime';
3
+ import { type ConversationRef, type DeliveryReceipt } from '@zhin.js/im-contract';
4
+ import { type ConfigPatch, type PluginId, type RuntimeConfigDocument } from '@zhin.js/plugin-runtime';
5
+ import { type ModuleRuntime, type RootResourceInstaller } from '@zhin.js/runtime';
6
+ export { FakeClock, FakeScheduleRootHost, parseCron, type FakeScheduledJob } from './fake-clock.js';
7
+ export { FakeDatabaseRootHost, FakeOutboundRootHost, type FakeOutboundCall } from './fake-hosts.js';
8
+ export { FakePlugin, createFakePlugin, runPluginSetup, fakeResource, type FakePluginOptions, type FakeResource, type FakeRegisteredFeature } from './fake-plugin.js';
9
+ export { fakeOf } from './partial.js';
10
+ export { createFakeMessage, createCommandContext, runCommand, runMiddleware, runHandler, type FakeMessage, type FakeMessageInit, type RunCommandOptions, type RunMiddlewareResult } from './fake-runners.js';
11
+ export interface PluginTestKitOptions {
12
+ /** A real, disposable test app with its own package.json, plugin entry, dependencies and mounts. */
13
+ readonly projectRoot: string;
14
+ readonly config?: RuntimeConfigDocument;
15
+ /** Adapter names reserved for synthetic transports, default: ['test']. */
16
+ readonly endpoints?: readonly string[];
17
+ /** Default endpoint renders HTML and buttons as text; override to verify negotiated capabilities. */
18
+ readonly segments?: AdapterSegmentPolicy;
19
+ readonly commandPrefix?: string;
20
+ /** Supply your test runner's module adapter if it owns ESM loading. Native Node is the default. */
21
+ readonly modules?: ModuleRuntime;
22
+ readonly installResources?: RootResourceInstaller;
23
+ }
24
+ /** A terminal send attempt, after the real renderer, policy negotiation and outbound middleware. */
25
+ export interface TestDelivery {
26
+ readonly endpoint: string;
27
+ readonly conversation: ConversationRef;
28
+ readonly payload: unknown;
29
+ readonly id: string;
30
+ }
31
+ export type TestReceiveInput = EndpointIncomingMessage & {
32
+ readonly endpoint?: string;
33
+ };
34
+ export type TestReloadResult = Readonly<{
35
+ status: 'reloaded' | 'unchanged';
36
+ generation: number;
37
+ }> | Readonly<{
38
+ status: 'failed';
39
+ generation: number;
40
+ error: unknown;
41
+ }> | Readonly<{
42
+ status: 'restart-required';
43
+ generation: number;
44
+ reasons: readonly string[];
45
+ }>;
46
+ /**
47
+ * Owns a test IM host and synthetic transports. Every operation enters the real Root Runtime.
48
+ * It does not install dependencies or replace providers. Discovered plugins still execute normally;
49
+ * use disposable applications without real credentials or adapters. This is not a sandbox.
50
+ */
51
+ export declare class PluginTestKit {
52
+ #private;
53
+ private constructor();
54
+ static create(options: PluginTestKitOptions): Promise<PluginTestKit>;
55
+ /** The same PermissionHost consumed by real command admission. */
56
+ get permissions(): ImRuntime['permissionHost'];
57
+ get generation(): number;
58
+ get deliveries(): readonly TestDelivery[];
59
+ clearDeliveries(): void;
60
+ start(): Promise<number>;
61
+ receive(input: TestReceiveInput): Promise<MessageDispatchResult | undefined>;
62
+ emit(name: string, payload: unknown, endpoint?: string): Promise<unknown>;
63
+ send(input: {
64
+ readonly conversation: ConversationAddress;
65
+ readonly content: SendContent;
66
+ readonly requester?: PluginId;
67
+ readonly endpoint?: string;
68
+ }): Promise<DeliveryReceipt>;
69
+ /** Call after editing a file in your test app; returns the real HMR transaction outcome. */
70
+ reloadSource(source: string): Promise<TestReloadResult>;
71
+ patchConfig(patches: readonly ConfigPatch[]): Promise<number>;
72
+ close(): Promise<void>;
73
+ }
74
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/lib/index.js ADDED
@@ -0,0 +1,168 @@
1
+ import { realpath } from 'node:fs/promises';
2
+ import { resolve } from 'node:path';
3
+ import { defineAdapter } from '@zhin.js/adapter';
4
+ import { ImRuntime } from '@zhin.js/core/runtime';
5
+ import { rootPluginId } from '@zhin.js/plugin-runtime';
6
+ import { NativeDevelopmentModuleRuntime, NodePackageResolver, RootRuntime } from '@zhin.js/runtime';
7
+ import { captureDeliveryValue } from './delivery-capture.js';
8
+ import { withTestEndpoints } from './test-module-runtime.js';
9
+ export { FakeClock, FakeScheduleRootHost, parseCron } from './fake-clock.js';
10
+ export { FakeDatabaseRootHost, FakeOutboundRootHost } from './fake-hosts.js';
11
+ export { FakePlugin, createFakePlugin, runPluginSetup, fakeResource } from './fake-plugin.js';
12
+ export { fakeOf } from './partial.js';
13
+ export { createFakeMessage, createCommandContext, runCommand, runMiddleware, runHandler } from './fake-runners.js';
14
+ /**
15
+ * Owns a test IM host and synthetic transports. Every operation enters the real Root Runtime.
16
+ * It does not install dependencies or replace providers. Discovered plugins still execute normally;
17
+ * use disposable applications without real credentials or adapters. This is not a sandbox.
18
+ */
19
+ export class PluginTestKit {
20
+ #im;
21
+ #root;
22
+ #sinks = new Map();
23
+ #identities = new Map();
24
+ #nextDelivery = 1;
25
+ #attempts = [];
26
+ #defaultEndpoint;
27
+ #hmr;
28
+ #restartReasons;
29
+ #started = false;
30
+ #closed = false;
31
+ #startResult;
32
+ #closeResult;
33
+ constructor(options, projectRoot, rootEntry) {
34
+ this.#im = new ImRuntime({ commandPrefix: options.commandPrefix });
35
+ const names = options.endpoints ?? ['test'];
36
+ if (!names.length || new Set(names).size !== names.length
37
+ || names.some(name => !/^[a-z][a-z0-9-]*$/.test(name))) {
38
+ throw new TypeError('Test endpoints must have unique lowercase names');
39
+ }
40
+ this.#defaultEndpoint = names[0];
41
+ const definitions = new Map(names.map(name => [name, defineAdapter({
42
+ capabilities: ['inbound', 'outbound'],
43
+ segments: options.segments ?? { html: 'text', interactive: 'text', markdown: 'text' },
44
+ create: () => ({
45
+ client: Object.freeze({ synthetic: true }),
46
+ connect: ({ events, identity }) => {
47
+ this.#identities.set(name, identity);
48
+ this.#sinks.set(name, events);
49
+ return () => { if (this.#sinks.get(name) === events) {
50
+ this.#sinks.delete(name);
51
+ this.#identities.delete(name);
52
+ } };
53
+ },
54
+ send: (request) => {
55
+ const id = `test-${this.#nextDelivery++}`;
56
+ this.#attempts.push(Object.freeze({ endpoint: name, id,
57
+ conversation: captureDeliveryValue(request.conversation),
58
+ payload: captureDeliveryValue(request.payload),
59
+ }));
60
+ return id;
61
+ },
62
+ }),
63
+ })]));
64
+ const modules = options.modules ?? new NativeDevelopmentModuleRuntime({ projectRoot, watch: false });
65
+ this.#root = new RootRuntime({ projectRoot,
66
+ modules: withTestEndpoints(modules, rootEntry, definitions),
67
+ environment: { name: 'test', mode: 'test', platform: 'node' },
68
+ config: options.config,
69
+ installResources: async (context) => {
70
+ this.#im.install(context.resources);
71
+ await options.installResources?.(context);
72
+ },
73
+ });
74
+ this.#im.attach(this.#root.snapshots);
75
+ this.#hmr = this.#root.createHmrCoordinator({
76
+ onRestartRequired: plan => { this.#restartReasons = plan.reasons; },
77
+ onError: () => undefined,
78
+ });
79
+ }
80
+ static async create(options) {
81
+ const projectRoot = await realpath(resolve(options.projectRoot));
82
+ const resolver = await NodePackageResolver.create(projectRoot);
83
+ const root = await resolver.root(projectRoot);
84
+ if (root.packageJson.zhin.type !== 'plugin' || root.packageJson.zhin.runtime === 'isolated') {
85
+ throw new TypeError('Test application must be a trusted Plugin root');
86
+ }
87
+ return new PluginTestKit(options, projectRoot, resolve(projectRoot, root.packageJson.zhin.entry));
88
+ }
89
+ /** The same PermissionHost consumed by real command admission. */
90
+ get permissions() { return this.#im.permissionHost; }
91
+ get generation() { return this.#root.snapshot.generation; }
92
+ get deliveries() { return Object.freeze(this.#attempts.map(item => captureDeliveryValue(item))); }
93
+ clearDeliveries() { this.#attempts.splice(0); }
94
+ start() {
95
+ if (this.#closed)
96
+ return Promise.reject(new Error('Plugin test kit is closed'));
97
+ if (this.#startResult)
98
+ return this.#startResult;
99
+ this.#startResult = this.#root.start().then(snapshot => {
100
+ this.#started = true;
101
+ return snapshot.generation;
102
+ });
103
+ return this.#startResult;
104
+ }
105
+ async receive(input) {
106
+ this.#assertStarted();
107
+ const { endpoint, ...message } = input;
108
+ return await this.#sink(endpoint).message(message);
109
+ }
110
+ async emit(name, payload, endpoint) {
111
+ this.#assertStarted();
112
+ return this.#sink(endpoint).emit(name, payload);
113
+ }
114
+ async send(input) {
115
+ this.#assertStarted();
116
+ const name = input.endpoint ?? this.#defaultEndpoint;
117
+ this.#sink(name);
118
+ const identity = this.#identities.get(name);
119
+ return this.#im.send({ conversation: { ...input.conversation, endpoint: {
120
+ id: String(identity.id), adapter: identity.adapter,
121
+ } }, content: input.content, requester: input.requester ?? rootPluginId() });
122
+ }
123
+ /** Call after editing a file in your test app; returns the real HMR transaction outcome. */
124
+ async reloadSource(source) {
125
+ this.#assertStarted();
126
+ const previous = this.generation;
127
+ this.#restartReasons = undefined;
128
+ try {
129
+ await this.#hmr.enqueue(source);
130
+ if (this.#restartReasons)
131
+ return Object.freeze({ status: 'restart-required',
132
+ generation: this.generation, reasons: Object.freeze([...this.#restartReasons]) });
133
+ return Object.freeze({ status: this.generation === previous ? 'unchanged' : 'reloaded', generation: this.generation });
134
+ }
135
+ catch (error) {
136
+ return Object.freeze({ status: 'failed', generation: this.generation, error });
137
+ }
138
+ }
139
+ async patchConfig(patches) {
140
+ this.#assertStarted();
141
+ return (await this.#root.patchConfig(patches)).generation;
142
+ }
143
+ close() {
144
+ if (this.#closeResult)
145
+ return this.#closeResult;
146
+ this.#closed = true;
147
+ this.#closeResult = (async () => {
148
+ try {
149
+ await this.#hmr.stop();
150
+ }
151
+ finally {
152
+ await this.#root.stop();
153
+ }
154
+ })();
155
+ return this.#closeResult;
156
+ }
157
+ #assertStarted() {
158
+ if (this.#closed || !this.#started)
159
+ throw new Error('Plugin test kit is not running');
160
+ }
161
+ #sink(endpoint = this.#defaultEndpoint) {
162
+ const sink = this.#sinks.get(endpoint);
163
+ if (!sink)
164
+ throw new Error(`Unknown test endpoint: ${endpoint}`);
165
+ return sink;
166
+ }
167
+ }
168
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Typed partial fake: the one deliberate cast lives here so tests do not need `as never`.
3
+ * Only the members you list exist; touching any other member of a real `T` is your test's bug.
4
+ * Prefer a real or kit-provided fake when one exists; use this for narrow collaborators and payloads.
5
+ */
6
+ export declare function fakeOf<T extends object>(partial: Partial<T>): T;
7
+ //# sourceMappingURL=partial.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"partial.d.ts","sourceRoot":"","sources":["../src/partial.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,wBAAgB,MAAM,CAAC,CAAC,SAAS,MAAM,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAE/D"}
package/lib/partial.js ADDED
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Typed partial fake: the one deliberate cast lives here so tests do not need `as never`.
3
+ * Only the members you list exist; touching any other member of a real `T` is your test's bug.
4
+ * Prefer a real or kit-provided fake when one exists; use this for narrow collaborators and payloads.
5
+ */
6
+ export function fakeOf(partial) {
7
+ return partial;
8
+ }
9
+ //# sourceMappingURL=partial.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"partial.js","sourceRoot":"","sources":["../src/partial.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,MAAM,UAAU,MAAM,CAAmB,OAAmB;IAC1D,OAAO,OAAY,CAAC;AACtB,CAAC"}
@@ -0,0 +1,5 @@
1
+ import type { AdapterDefinition } from '@zhin.js/adapter';
2
+ import type { ModuleRuntime } from '@zhin.js/runtime';
3
+ /** Only the test application's setup is decorated; discovery and module caching stay native. */
4
+ export declare function withTestEndpoints(delegate: ModuleRuntime, rootEntry: string, endpoints: ReadonlyMap<string, AdapterDefinition>): ModuleRuntime;
5
+ //# sourceMappingURL=test-module-runtime.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"test-module-runtime.d.ts","sourceRoot":"","sources":["../src/test-module-runtime.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAC1D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAEtD,gGAAgG;AAChG,wBAAgB,iBAAiB,CAC/B,QAAQ,EAAE,aAAa,EACvB,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,WAAW,CAAC,MAAM,EAAE,iBAAiB,CAAC,GAChD,aAAa,CA2Bf"}
@@ -0,0 +1,34 @@
1
+ import { resolve } from 'node:path';
2
+ import { definePlugin } from '@zhin.js/plugin-runtime';
3
+ /** Only the test application's setup is decorated; discovery and module caching stay native. */
4
+ export function withTestEndpoints(delegate, rootEntry, endpoints) {
5
+ return {
6
+ async load(source) {
7
+ const loaded = await delegate.load(source);
8
+ const candidate = loaded;
9
+ if (resolve(source) !== rootEntry || !candidate.default)
10
+ return loaded;
11
+ const original = candidate.default;
12
+ const definition = definePlugin({
13
+ ...original,
14
+ async setup(context) {
15
+ for (const [name, endpoint] of endpoints)
16
+ context.addAdapter(name, endpoint);
17
+ return original.setup?.(context);
18
+ },
19
+ });
20
+ return { ...loaded, default: definition };
21
+ },
22
+ ...(delegate.loadClientModule ? { loadClientModule: delegate.loadClientModule.bind(delegate) } : {}),
23
+ ...(delegate.invalidate ? { invalidate: delegate.invalidate.bind(delegate) } : {}),
24
+ ...(delegate.affectedSources ? { affectedSources: delegate.affectedSources.bind(delegate) } : {}),
25
+ ...(delegate.requiresProcessRestart ? { requiresProcessRestart: delegate.requiresProcessRestart.bind(delegate) } : {}),
26
+ ...(delegate.beginGeneration ? { beginGeneration: delegate.beginGeneration.bind(delegate) } : {}),
27
+ ...(delegate.commitGeneration ? { commitGeneration: delegate.commitGeneration.bind(delegate) } : {}),
28
+ ...(delegate.rollbackGeneration ? { rollbackGeneration: delegate.rollbackGeneration.bind(delegate) } : {}),
29
+ ...(delegate.updateWatchRoots ? { updateWatchRoots: delegate.updateWatchRoots.bind(delegate) } : {}),
30
+ ...(delegate.watch ? { watch: delegate.watch.bind(delegate) } : {}),
31
+ close: () => delegate.close(),
32
+ };
33
+ }
34
+ //# sourceMappingURL=test-module-runtime.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"test-module-runtime.js","sourceRoot":"","sources":["../src/test-module-runtime.ts"],"names":[],"mappings":"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"}