@grest-ts/testkit 0.0.6 → 0.0.7

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 (46) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +413 -413
  3. package/dist/src/runner/isolated-loader.mjs +91 -91
  4. package/dist/src/runner/worker-loader.mjs +49 -49
  5. package/dist/tsconfig.publish.tsbuildinfo +1 -1
  6. package/package.json +12 -12
  7. package/src/GGBundleTest.ts +89 -89
  8. package/src/GGTest.ts +318 -318
  9. package/src/GGTestContext.ts +74 -74
  10. package/src/GGTestRunner.ts +308 -308
  11. package/src/GGTestRuntime.ts +265 -265
  12. package/src/GGTestRuntimeWorker.ts +159 -159
  13. package/src/GGTestSharedRef.ts +116 -116
  14. package/src/GGTestkitExtensionsDiscovery.ts +26 -26
  15. package/src/IGGLocalDiscoveryServer.ts +16 -16
  16. package/src/callOn/GGCallOnSelector.ts +61 -61
  17. package/src/callOn/GGContractClass.implement.ts +43 -43
  18. package/src/callOn/GGTestActionForLocatorOnCall.ts +134 -134
  19. package/src/callOn/TestableIPC.ts +81 -81
  20. package/src/callOn/callOn.ts +224 -224
  21. package/src/callOn/registerOnCallHandler.ts +123 -123
  22. package/src/index-node.ts +64 -64
  23. package/src/mockable/GGMockable.ts +22 -22
  24. package/src/mockable/GGMockableCall.ts +45 -45
  25. package/src/mockable/GGMockableIPC.ts +20 -20
  26. package/src/mockable/GGMockableInterceptor.ts +44 -44
  27. package/src/mockable/GGMockableInterceptorsServer.ts +69 -69
  28. package/src/mockable/mockable.ts +71 -71
  29. package/src/runner/InlineRunner.ts +47 -47
  30. package/src/runner/IsolatedRunner.ts +179 -179
  31. package/src/runner/RuntimeRunner.ts +15 -15
  32. package/src/runner/WorkerRunner.ts +179 -179
  33. package/src/runner/isolated-loader.mjs +91 -91
  34. package/src/runner/worker-loader.mjs +49 -49
  35. package/src/testers/GGCallInterceptor.ts +224 -224
  36. package/src/testers/GGMockWith.ts +92 -92
  37. package/src/testers/GGSpyWith.ts +115 -115
  38. package/src/testers/GGTestAction.ts +332 -332
  39. package/src/testers/GGTestComponent.ts +16 -16
  40. package/src/testers/GGTestSelector.ts +223 -223
  41. package/src/testers/IGGTestInterceptor.ts +10 -10
  42. package/src/testers/IGGTestWith.ts +15 -15
  43. package/src/testers/RuntimeSelector.ts +151 -151
  44. package/src/utils/GGExpectations.ts +78 -78
  45. package/src/utils/GGTestError.ts +36 -36
  46. package/src/utils/captureStack.ts +53 -53
@@ -1,61 +1,61 @@
1
- /**
2
- * Selector extension that adds targeted callOn to selectors.
3
- *
4
- * This allows explicitly targeting specific runtimes when multiple
5
- * different runtime classes have the same service registered.
6
- *
7
- * @example
8
- * const f = GGTest.startWorker({chain: ChainRuntime, weather: WeatherOnlyRuntime});
9
- *
10
- * // Both have WeatherService - explicitly target one:
11
- * await f.chain.callOn(WeatherService).getWeather("Test").toMatchObject({...})
12
- * await f.weather.callOn(WeatherService).getWeather("Test").toMatchObject({...})
13
- */
14
-
15
- import {GGContext} from "@grest-ts/context";
16
- import {GGTestSelector, GGTestSelectorExtension} from "../testers/GGTestSelector";
17
- import {RuntimeConstructor} from "../testers/RuntimeSelector";
18
- import {callOnTargeted, GGTestCallOn} from "./callOn";
19
- import type {GGTestRuntime} from "../GGTestRuntime";
20
-
21
- /**
22
- * Type for the callable callOn extension.
23
- * Can be called as a function to invoke targeted callOn.
24
- */
25
- export interface GGCallOnSelectorCallable {
26
- <T>(target: T, ctx?: GGContext): GGTestCallOn<T>;
27
- }
28
-
29
- /**
30
- * Extension that adds .callOn() as a callable to Selectors.
31
- * Uses the selector's runtimes to target specific instances.
32
- *
33
- * Returns a callable that can be used directly: f.chain.callOn(WeatherService)
34
- */
35
- export class GGCallOnSelector extends GGTestSelectorExtension {
36
-
37
- public static readonly PROPERTY_NAME = "callOn";
38
-
39
- constructor(runtimes: GGTestRuntime[]) {
40
- super(runtimes);
41
- // Return a callable function instead of this instance
42
- const callable = <T>(target: T, ctx?: GGContext): GGTestCallOn<T> => {
43
- return callOnTargeted(target, runtimes, ctx);
44
- };
45
- return callable as unknown as this;
46
- }
47
- }
48
-
49
- // Declaration merging to add 'callOn' to SelectorExtensions
50
- declare module "@grest-ts/testkit" {
51
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
52
- interface SelectorExtensions<T extends RuntimeConstructor[]> {
53
- callOn: GGCallOnSelectorCallable;
54
- }
55
- }
56
-
57
- // Ensure RuntimeConstructor import is recognized (for declaration merging above)
58
- export type _RuntimeConstructorRef = RuntimeConstructor;
59
-
60
- // Register the extension
61
- GGTestSelector.addExtension(GGCallOnSelector);
1
+ /**
2
+ * Selector extension that adds targeted callOn to selectors.
3
+ *
4
+ * This allows explicitly targeting specific runtimes when multiple
5
+ * different runtime classes have the same service registered.
6
+ *
7
+ * @example
8
+ * const f = GGTest.startWorker({chain: ChainRuntime, weather: WeatherOnlyRuntime});
9
+ *
10
+ * // Both have WeatherService - explicitly target one:
11
+ * await f.chain.callOn(WeatherService).getWeather("Test").toMatchObject({...})
12
+ * await f.weather.callOn(WeatherService).getWeather("Test").toMatchObject({...})
13
+ */
14
+
15
+ import {GGContext} from "@grest-ts/context";
16
+ import {GGTestSelector, GGTestSelectorExtension} from "../testers/GGTestSelector";
17
+ import {RuntimeConstructor} from "../testers/RuntimeSelector";
18
+ import {callOnTargeted, GGTestCallOn} from "./callOn";
19
+ import type {GGTestRuntime} from "../GGTestRuntime";
20
+
21
+ /**
22
+ * Type for the callable callOn extension.
23
+ * Can be called as a function to invoke targeted callOn.
24
+ */
25
+ export interface GGCallOnSelectorCallable {
26
+ <T>(target: T, ctx?: GGContext): GGTestCallOn<T>;
27
+ }
28
+
29
+ /**
30
+ * Extension that adds .callOn() as a callable to Selectors.
31
+ * Uses the selector's runtimes to target specific instances.
32
+ *
33
+ * Returns a callable that can be used directly: f.chain.callOn(WeatherService)
34
+ */
35
+ export class GGCallOnSelector extends GGTestSelectorExtension {
36
+
37
+ public static readonly PROPERTY_NAME = "callOn";
38
+
39
+ constructor(runtimes: GGTestRuntime[]) {
40
+ super(runtimes);
41
+ // Return a callable function instead of this instance
42
+ const callable = <T>(target: T, ctx?: GGContext): GGTestCallOn<T> => {
43
+ return callOnTargeted(target, runtimes, ctx);
44
+ };
45
+ return callable as unknown as this;
46
+ }
47
+ }
48
+
49
+ // Declaration merging to add 'callOn' to SelectorExtensions
50
+ declare module "@grest-ts/testkit" {
51
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
52
+ interface SelectorExtensions<T extends RuntimeConstructor[]> {
53
+ callOn: GGCallOnSelectorCallable;
54
+ }
55
+ }
56
+
57
+ // Ensure RuntimeConstructor import is recognized (for declaration merging above)
58
+ export type _RuntimeConstructorRef = RuntimeConstructor;
59
+
60
+ // Register the extension
61
+ GGTestSelector.addExtension(GGCallOnSelector);
@@ -1,43 +1,43 @@
1
- /**
2
- * Patches GGContractClass.implement() to auto-register contract instances in GGLocator.
3
- *
4
- * This enables callOn(ContractClass) to work without each protocol (HTTP, WebSocket, etc.)
5
- * needing to manually register the contract instance.
6
- */
7
-
8
- import {GGContractClass} from "@grest-ts/schema";
9
- import {GGLocator, GGLocatorKey} from "@grest-ts/locator";
10
-
11
- // Store the original implement method
12
- const originalImplement = GGContractClass.prototype.implement;
13
-
14
- export const LOCATOR_KEY_PREFIX_FOR_CONTRACT = "@contract:"
15
-
16
- /**
17
- * Patched implement() that registers the returned client in GGLocator.
18
- */
19
- GGContractClass.prototype.implement = function (
20
- this: GGContractClass<any>,
21
- instance: any,
22
- options?: any
23
- ) {
24
- const contractName = this.name;
25
-
26
- // Get the client from original implement
27
- const client = originalImplement.call(this, instance, options);
28
-
29
- // Register in GGLocator for callOn(Contract) access
30
- const scope = GGLocator.tryGetScope();
31
- if (scope) {
32
- const key = new GGLocatorKey<typeof client>(LOCATOR_KEY_PREFIX_FOR_CONTRACT + contractName);
33
- if (scope.has(key)) {
34
- throw new Error(
35
- `Contract '${contractName}' is already registered in this scope. ` +
36
- `If you need multiple instances, use different contract names.`
37
- );
38
- }
39
- scope.set(key, client);
40
- }
41
-
42
- return client;
43
- };
1
+ /**
2
+ * Patches GGContractClass.implement() to auto-register contract instances in GGLocator.
3
+ *
4
+ * This enables callOn(ContractClass) to work without each protocol (HTTP, WebSocket, etc.)
5
+ * needing to manually register the contract instance.
6
+ */
7
+
8
+ import {GGContractClass} from "@grest-ts/schema";
9
+ import {GGLocator, GGLocatorKey} from "@grest-ts/locator";
10
+
11
+ // Store the original implement method
12
+ const originalImplement = GGContractClass.prototype.implement;
13
+
14
+ export const LOCATOR_KEY_PREFIX_FOR_CONTRACT = "@contract:"
15
+
16
+ /**
17
+ * Patched implement() that registers the returned client in GGLocator.
18
+ */
19
+ GGContractClass.prototype.implement = function (
20
+ this: GGContractClass<any>,
21
+ instance: any,
22
+ options?: any
23
+ ) {
24
+ const contractName = this.name;
25
+
26
+ // Get the client from original implement
27
+ const client = originalImplement.call(this, instance, options);
28
+
29
+ // Register in GGLocator for callOn(Contract) access
30
+ const scope = GGLocator.tryGetScope();
31
+ if (scope) {
32
+ const key = new GGLocatorKey<typeof client>(LOCATOR_KEY_PREFIX_FOR_CONTRACT + contractName);
33
+ if (scope.has(key)) {
34
+ throw new Error(
35
+ `Contract '${contractName}' is already registered in this scope. ` +
36
+ `If you need multiple instances, use different contract names.`
37
+ );
38
+ }
39
+ scope.set(key, client);
40
+ }
41
+
42
+ return client;
43
+ };
@@ -1,134 +1,134 @@
1
- /**
2
- * Test action for invoking methods via GGLocator lookup.
3
- *
4
- * Used for:
5
- * - @testable services (key: @testable:ClassName)
6
- * - Direct contract calls (key: @contract:ContractName)
7
- * - Custom GGLocatorKey lookups
8
- *
9
- * Extends GGTestAction to support .with() for mocks/spies and
10
- * response expectations like .toMatchObject(), .toEqual().
11
- */
12
-
13
- import {GGTestAction, GGTestActionConfig, tActionRawData} from "../testers/GGTestAction";
14
- import {GG_TEST_RUNNER} from "../GGTestRunner";
15
- import {SerializedContext, TestableInvokeResult, TestableIPC} from "./TestableIPC";
16
- import {GGTestError} from "../utils/GGTestError";
17
- import {GGContext} from "@grest-ts/context";
18
- import type {GGTestRuntime} from "../GGTestRuntime";
19
-
20
- /**
21
- * Serialize a GGContext to a plain object for IPC transfer.
22
- * Flattens the context hierarchy into a single object.
23
- */
24
- function serializeContext(ctx: GGContext): SerializedContext {
25
- const result: SerializedContext = {};
26
- // Access the private values map via type assertion
27
- const ctxAny = ctx as any;
28
- if (ctxAny.values instanceof Map) {
29
- for (const [key, value] of ctxAny.values) {
30
- result[key] = value;
31
- }
32
- }
33
- // Also serialize parent context values (child values take precedence)
34
- if (ctxAny.parent) {
35
- const parentValues = serializeContext(ctxAny.parent);
36
- return {...parentValues, ...result};
37
- }
38
- return result;
39
- }
40
-
41
- /**
42
- * Action for invoking a method via GGLocator lookup over IPC.
43
- *
44
- * @typeParam T - The expected return type of the method
45
- */
46
- export class GGTestActionForLocatorOnCall<T> extends GGTestAction<T> {
47
-
48
- private readonly keyName: string;
49
- private readonly methodName: string;
50
- private readonly args: any[];
51
- private readonly targetRuntimes?: GGTestRuntime[];
52
-
53
- constructor(ctx: GGContext, keyName: string, methodName: string, args: any[], targetRuntimes?: GGTestRuntime[]) {
54
- const config: GGTestActionConfig = {
55
- noResponse: false,
56
- logData: {
57
- message: `[${keyName}.${methodName}]`,
58
- request: args.length > 0 ? args : undefined
59
- }
60
- };
61
- super(ctx, config);
62
- this.keyName = keyName;
63
- this.methodName = methodName;
64
- this.args = args;
65
- this.targetRuntimes = targetRuntimes;
66
- }
67
-
68
- // -------------------------------------------------
69
- // Action execution
70
- // -------------------------------------------------
71
-
72
- protected async executeAction(): Promise<tActionRawData> {
73
- const runner = GG_TEST_RUNNER.get();
74
-
75
- // Use target runtimes if provided, otherwise all runtimes
76
- const searchRuntimes = this.targetRuntimes ?? runner.getAllRuntimes();
77
-
78
- // Find runtimes that have this key registered
79
- const candidates = searchRuntimes.filter(r => r.hasLocatorKey(this.keyName));
80
-
81
- if (candidates.length === 0) {
82
- // No runtime has this key - provide helpful error
83
- const allRuntimes = runner.getAllRuntimes();
84
- if (allRuntimes.length === 0) {
85
- throw new GGTestError({
86
- test: `No runtimes available to invoke ${this.keyName}.${this.methodName}`,
87
- expected: "At least one runtime to be started",
88
- received: "No runtimes found"
89
- });
90
- }
91
- throw new GGTestError({
92
- test: `Instance '${this.keyName}' not found in any runtime`,
93
- expected: `A @testable instance registered with key '${this.keyName}'`,
94
- received: `Key not registered in any of ${allRuntimes.length} runtime(s): ${allRuntimes.map(r => r.name).join(', ')}`
95
- });
96
- }
97
-
98
- if (candidates.length > 1) {
99
- // Check if all candidates are the same runtime class - if so, just use first one
100
- const uniqueClassNames = new Set(candidates.map(r => r.className));
101
- if (uniqueClassNames.size > 1) {
102
- // Different runtime classes have this key - actual ambiguity
103
- throw new GGTestError({
104
- test: `Multiple different runtimes have '${this.keyName}' registered`,
105
- expected: `Key '${this.keyName}' to be unique across different runtime classes, or use explicit runtime targeting`,
106
- received: `Found in ${candidates.length} runtimes with different classes: ${[...uniqueClassNames].join(', ')}`
107
- });
108
- }
109
- // Same runtime class - just use first instance (they're identical)
110
- }
111
-
112
- // Exactly one runtime has this key - send IPC directly
113
- const runtime = candidates[0];
114
- const context = this.ctx ? serializeContext(this.ctx) : undefined;
115
-
116
- const result: TestableInvokeResult = await runtime.sendCommand(TestableIPC.invoke, {
117
- keyName: this.keyName,
118
- methodName: this.methodName,
119
- args: this.args,
120
- context
121
- });
122
-
123
- if (result.success) {
124
- return result.result as tActionRawData;
125
- }
126
-
127
- throw new GGTestError({
128
- test: `Error invoking ${this.keyName}.${this.methodName}`,
129
- expected: "Method to execute successfully",
130
- received: result.error || "Unknown error",
131
- extra: result.stack
132
- });
133
- }
134
- }
1
+ /**
2
+ * Test action for invoking methods via GGLocator lookup.
3
+ *
4
+ * Used for:
5
+ * - @testable services (key: @testable:ClassName)
6
+ * - Direct contract calls (key: @contract:ContractName)
7
+ * - Custom GGLocatorKey lookups
8
+ *
9
+ * Extends GGTestAction to support .with() for mocks/spies and
10
+ * response expectations like .toMatchObject(), .toEqual().
11
+ */
12
+
13
+ import {GGTestAction, GGTestActionConfig, tActionRawData} from "../testers/GGTestAction";
14
+ import {GG_TEST_RUNNER} from "../GGTestRunner";
15
+ import {SerializedContext, TestableInvokeResult, TestableIPC} from "./TestableIPC";
16
+ import {GGTestError} from "../utils/GGTestError";
17
+ import {GGContext} from "@grest-ts/context";
18
+ import type {GGTestRuntime} from "../GGTestRuntime";
19
+
20
+ /**
21
+ * Serialize a GGContext to a plain object for IPC transfer.
22
+ * Flattens the context hierarchy into a single object.
23
+ */
24
+ function serializeContext(ctx: GGContext): SerializedContext {
25
+ const result: SerializedContext = {};
26
+ // Access the private values map via type assertion
27
+ const ctxAny = ctx as any;
28
+ if (ctxAny.values instanceof Map) {
29
+ for (const [key, value] of ctxAny.values) {
30
+ result[key] = value;
31
+ }
32
+ }
33
+ // Also serialize parent context values (child values take precedence)
34
+ if (ctxAny.parent) {
35
+ const parentValues = serializeContext(ctxAny.parent);
36
+ return {...parentValues, ...result};
37
+ }
38
+ return result;
39
+ }
40
+
41
+ /**
42
+ * Action for invoking a method via GGLocator lookup over IPC.
43
+ *
44
+ * @typeParam T - The expected return type of the method
45
+ */
46
+ export class GGTestActionForLocatorOnCall<T> extends GGTestAction<T> {
47
+
48
+ private readonly keyName: string;
49
+ private readonly methodName: string;
50
+ private readonly args: any[];
51
+ private readonly targetRuntimes?: GGTestRuntime[];
52
+
53
+ constructor(ctx: GGContext, keyName: string, methodName: string, args: any[], targetRuntimes?: GGTestRuntime[]) {
54
+ const config: GGTestActionConfig = {
55
+ noResponse: false,
56
+ logData: {
57
+ message: `[${keyName}.${methodName}]`,
58
+ request: args.length > 0 ? args : undefined
59
+ }
60
+ };
61
+ super(ctx, config);
62
+ this.keyName = keyName;
63
+ this.methodName = methodName;
64
+ this.args = args;
65
+ this.targetRuntimes = targetRuntimes;
66
+ }
67
+
68
+ // -------------------------------------------------
69
+ // Action execution
70
+ // -------------------------------------------------
71
+
72
+ protected async executeAction(): Promise<tActionRawData> {
73
+ const runner = GG_TEST_RUNNER.get();
74
+
75
+ // Use target runtimes if provided, otherwise all runtimes
76
+ const searchRuntimes = this.targetRuntimes ?? runner.getAllRuntimes();
77
+
78
+ // Find runtimes that have this key registered
79
+ const candidates = searchRuntimes.filter(r => r.hasLocatorKey(this.keyName));
80
+
81
+ if (candidates.length === 0) {
82
+ // No runtime has this key - provide helpful error
83
+ const allRuntimes = runner.getAllRuntimes();
84
+ if (allRuntimes.length === 0) {
85
+ throw new GGTestError({
86
+ test: `No runtimes available to invoke ${this.keyName}.${this.methodName}`,
87
+ expected: "At least one runtime to be started",
88
+ received: "No runtimes found"
89
+ });
90
+ }
91
+ throw new GGTestError({
92
+ test: `Instance '${this.keyName}' not found in any runtime`,
93
+ expected: `A @testable instance registered with key '${this.keyName}'`,
94
+ received: `Key not registered in any of ${allRuntimes.length} runtime(s): ${allRuntimes.map(r => r.name).join(', ')}`
95
+ });
96
+ }
97
+
98
+ if (candidates.length > 1) {
99
+ // Check if all candidates are the same runtime class - if so, just use first one
100
+ const uniqueClassNames = new Set(candidates.map(r => r.className));
101
+ if (uniqueClassNames.size > 1) {
102
+ // Different runtime classes have this key - actual ambiguity
103
+ throw new GGTestError({
104
+ test: `Multiple different runtimes have '${this.keyName}' registered`,
105
+ expected: `Key '${this.keyName}' to be unique across different runtime classes, or use explicit runtime targeting`,
106
+ received: `Found in ${candidates.length} runtimes with different classes: ${[...uniqueClassNames].join(', ')}`
107
+ });
108
+ }
109
+ // Same runtime class - just use first instance (they're identical)
110
+ }
111
+
112
+ // Exactly one runtime has this key - send IPC directly
113
+ const runtime = candidates[0];
114
+ const context = this.ctx ? serializeContext(this.ctx) : undefined;
115
+
116
+ const result: TestableInvokeResult = await runtime.sendCommand(TestableIPC.invoke, {
117
+ keyName: this.keyName,
118
+ methodName: this.methodName,
119
+ args: this.args,
120
+ context
121
+ });
122
+
123
+ if (result.success) {
124
+ return result.result as tActionRawData;
125
+ }
126
+
127
+ throw new GGTestError({
128
+ test: `Error invoking ${this.keyName}.${this.methodName}`,
129
+ expected: "Method to execute successfully",
130
+ received: result.error || "Unknown error",
131
+ extra: result.stack
132
+ });
133
+ }
134
+ }
@@ -1,81 +1,81 @@
1
- /**
2
- * IPC protocol definitions for GGLocator-based service invocation.
3
- *
4
- * Defines the messages exchanged between test runner and runtime worker
5
- * for invoking methods on registered instances (@testable, @contract, etc.).
6
- */
7
-
8
- import {IPCClient, IPCServer} from "@grest-ts/ipc";
9
-
10
- /**
11
- * Serialized context data for IPC transfer.
12
- * Contains flattened key-value pairs from GGContext.
13
- */
14
- export type SerializedContext = Record<string, any>;
15
-
16
- /**
17
- * Payload for invoking a method on a registered instance.
18
- */
19
- export interface TestableInvokePayload {
20
- /** The GGLocatorKey name (e.g., "@testable:ServiceB", "@contract:ChainApi", or custom key) */
21
- keyName: string;
22
- /** The method name to invoke */
23
- methodName: string;
24
- /** Arguments to pass to the method (as array) */
25
- args: any[];
26
- /** Serialized GGContext data to restore on the worker side */
27
- context?: SerializedContext;
28
- }
29
-
30
- /**
31
- * Result from invoking a testable method.
32
- */
33
- export interface TestableInvokeResult {
34
- /** Whether the invocation succeeded */
35
- success: boolean;
36
- /** The return value from the method (if success) */
37
- result?: any;
38
- /** Error message (if failed) */
39
- error?: string;
40
- /** Error stack trace (if failed) */
41
- stack?: string;
42
- }
43
-
44
- /**
45
- * Payload for registering locator keys from a runtime.
46
- */
47
- export interface KeyRegistrationPayload {
48
- /** Runtime ID sending the registration */
49
- runtimeId: string;
50
- /** All GGLocatorKey names registered in this runtime */
51
- keys: string[];
52
- }
53
-
54
- /**
55
- * IPC endpoints for testable service invocation.
56
- */
57
- export const TestableIPC = {
58
- /**
59
- * Messages FROM test server TO worker.
60
- */
61
- client: {
62
- /**
63
- * Invoke a method on a testable service instance.
64
- */
65
- invoke: IPCClient.defineRequest<TestableInvokePayload, TestableInvokeResult>("testable/invoke"),
66
- },
67
-
68
- /**
69
- * Messages FROM worker TO test server.
70
- */
71
- server: {
72
- /**
73
- * Register all locator keys available in a runtime.
74
- * Sent from worker to test runner after compose completes.
75
- */
76
- registerKeys: IPCServer.defineRequest<KeyRegistrationPayload, void>("testable/register-keys"),
77
- },
78
-
79
- // Legacy alias for backwards compatibility
80
- invoke: IPCClient.defineRequest<TestableInvokePayload, TestableInvokeResult>("testable/invoke"),
81
- };
1
+ /**
2
+ * IPC protocol definitions for GGLocator-based service invocation.
3
+ *
4
+ * Defines the messages exchanged between test runner and runtime worker
5
+ * for invoking methods on registered instances (@testable, @contract, etc.).
6
+ */
7
+
8
+ import {IPCClient, IPCServer} from "@grest-ts/ipc";
9
+
10
+ /**
11
+ * Serialized context data for IPC transfer.
12
+ * Contains flattened key-value pairs from GGContext.
13
+ */
14
+ export type SerializedContext = Record<string, any>;
15
+
16
+ /**
17
+ * Payload for invoking a method on a registered instance.
18
+ */
19
+ export interface TestableInvokePayload {
20
+ /** The GGLocatorKey name (e.g., "@testable:ServiceB", "@contract:ChainApi", or custom key) */
21
+ keyName: string;
22
+ /** The method name to invoke */
23
+ methodName: string;
24
+ /** Arguments to pass to the method (as array) */
25
+ args: any[];
26
+ /** Serialized GGContext data to restore on the worker side */
27
+ context?: SerializedContext;
28
+ }
29
+
30
+ /**
31
+ * Result from invoking a testable method.
32
+ */
33
+ export interface TestableInvokeResult {
34
+ /** Whether the invocation succeeded */
35
+ success: boolean;
36
+ /** The return value from the method (if success) */
37
+ result?: any;
38
+ /** Error message (if failed) */
39
+ error?: string;
40
+ /** Error stack trace (if failed) */
41
+ stack?: string;
42
+ }
43
+
44
+ /**
45
+ * Payload for registering locator keys from a runtime.
46
+ */
47
+ export interface KeyRegistrationPayload {
48
+ /** Runtime ID sending the registration */
49
+ runtimeId: string;
50
+ /** All GGLocatorKey names registered in this runtime */
51
+ keys: string[];
52
+ }
53
+
54
+ /**
55
+ * IPC endpoints for testable service invocation.
56
+ */
57
+ export const TestableIPC = {
58
+ /**
59
+ * Messages FROM test server TO worker.
60
+ */
61
+ client: {
62
+ /**
63
+ * Invoke a method on a testable service instance.
64
+ */
65
+ invoke: IPCClient.defineRequest<TestableInvokePayload, TestableInvokeResult>("testable/invoke"),
66
+ },
67
+
68
+ /**
69
+ * Messages FROM worker TO test server.
70
+ */
71
+ server: {
72
+ /**
73
+ * Register all locator keys available in a runtime.
74
+ * Sent from worker to test runner after compose completes.
75
+ */
76
+ registerKeys: IPCServer.defineRequest<KeyRegistrationPayload, void>("testable/register-keys"),
77
+ },
78
+
79
+ // Legacy alias for backwards compatibility
80
+ invoke: IPCClient.defineRequest<TestableInvokePayload, TestableInvokeResult>("testable/invoke"),
81
+ };