@grest-ts/testkit 0.0.5 → 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 +418 -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,123 +1,123 @@
1
- /**
2
- * Worker-side handler for GGLocator-based service invocation.
3
- *
4
- * Receives IPC requests from tests to invoke methods on registered instances
5
- * (@testable, @contract, etc.) and returns the results.
6
- */
7
-
8
- import {GGLocator, GGLocatorKey} from "@grest-ts/locator";
9
- import {GGLog} from "@grest-ts/logger";
10
- import {SerializedContext, TestableIPC, TestableInvokePayload, TestableInvokeResult} from "./TestableIPC";
11
- import {GGTestRuntimeWorker} from "../GGTestRuntimeWorker";
12
- import {GGContext} from "@grest-ts/context";
13
-
14
- /**
15
- * Context for logging
16
- */
17
- const LOG_CONTEXT = {name: "GGLocatorWorkerHandler"};
18
-
19
- /**
20
- * Deserialize context data into a GGContext.
21
- * Directly populates the internal values map.
22
- */
23
- function deserializeContext(data: SerializedContext): GGContext {
24
- const ctx = new GGContext("ipc-context");
25
- // Access internal values map and populate directly
26
- const ctxAny = ctx as any;
27
- for (const [keyName, value] of Object.entries(data)) {
28
- ctxAny.values.set(keyName, value);
29
- }
30
- return ctx;
31
- }
32
-
33
- /**
34
- * Register the locator lookup handler on the worker.
35
- * Called during worker initialization.
36
- */
37
- export function registerOnCallHandler(worker: GGTestRuntimeWorker): void {
38
- worker.onIpcRequest(TestableIPC.invoke, async (payload: TestableInvokePayload): Promise<TestableInvokeResult> => {
39
- const {keyName, methodName, args, context} = payload;
40
-
41
- GGLog.debug(LOG_CONTEXT, `Invoking ${keyName}.${methodName}`, {args, hasContext: !!context});
42
-
43
- try {
44
- // Look up the instance in the current scope
45
- const scope = GGLocator.tryGetScope();
46
- if (!scope) {
47
- return {
48
- success: false,
49
- error: `No GGLocator scope available - is the runtime running?`
50
- };
51
- }
52
-
53
- const key = new GGLocatorKey<any>(keyName);
54
- const instance = scope.tryGet(key);
55
-
56
- if (!instance) {
57
- return {
58
- success: false,
59
- error: `Instance '${keyName}' not found in GGLocator. ` +
60
- `Make sure the class is decorated with @testable or registered during compose().`
61
- };
62
- }
63
-
64
- // Check if method exists
65
- const method = instance[methodName];
66
- if (typeof method !== 'function') {
67
- return {
68
- success: false,
69
- error: `Method '${methodName}' not found on instance '${keyName}'. ` +
70
- `Available methods: ${getMethodNames(instance).join(', ')}`
71
- };
72
- }
73
-
74
- // Invoke the method, optionally within the provided context
75
- let result: any;
76
- if (context) {
77
- const ctx = deserializeContext(context);
78
- result = await ctx.run(() => method.apply(instance, args));
79
- } else {
80
- result = await method.apply(instance, args);
81
- }
82
-
83
- GGLog.debug(LOG_CONTEXT, `Invocation ${keyName}.${methodName} completed`, {result});
84
-
85
- return {
86
- success: true,
87
- result
88
- };
89
- } catch (error: any) {
90
- GGLog.error(LOG_CONTEXT, `Error invoking ${keyName}.${methodName}`, error);
91
-
92
- return {
93
- success: false,
94
- error: error.message || String(error),
95
- stack: error.stack
96
- };
97
- }
98
- });
99
- }
100
-
101
- /**
102
- * Get method names from an instance for error messages.
103
- */
104
- function getMethodNames(instance: any): string[] {
105
- const names: string[] = [];
106
- let proto = Object.getPrototypeOf(instance);
107
-
108
- while (proto && proto !== Object.prototype) {
109
- const propNames = Object.getOwnPropertyNames(proto)
110
- .filter(name => {
111
- if (name === 'constructor') return false;
112
- try {
113
- return typeof proto[name] === 'function';
114
- } catch {
115
- return false;
116
- }
117
- });
118
- names.push(...propNames);
119
- proto = Object.getPrototypeOf(proto);
120
- }
121
-
122
- return [...new Set(names)].sort();
123
- }
1
+ /**
2
+ * Worker-side handler for GGLocator-based service invocation.
3
+ *
4
+ * Receives IPC requests from tests to invoke methods on registered instances
5
+ * (@testable, @contract, etc.) and returns the results.
6
+ */
7
+
8
+ import {GGLocator, GGLocatorKey} from "@grest-ts/locator";
9
+ import {GGLog} from "@grest-ts/logger";
10
+ import {SerializedContext, TestableIPC, TestableInvokePayload, TestableInvokeResult} from "./TestableIPC";
11
+ import {GGTestRuntimeWorker} from "../GGTestRuntimeWorker";
12
+ import {GGContext} from "@grest-ts/context";
13
+
14
+ /**
15
+ * Context for logging
16
+ */
17
+ const LOG_CONTEXT = {name: "GGLocatorWorkerHandler"};
18
+
19
+ /**
20
+ * Deserialize context data into a GGContext.
21
+ * Directly populates the internal values map.
22
+ */
23
+ function deserializeContext(data: SerializedContext): GGContext {
24
+ const ctx = new GGContext("ipc-context");
25
+ // Access internal values map and populate directly
26
+ const ctxAny = ctx as any;
27
+ for (const [keyName, value] of Object.entries(data)) {
28
+ ctxAny.values.set(keyName, value);
29
+ }
30
+ return ctx;
31
+ }
32
+
33
+ /**
34
+ * Register the locator lookup handler on the worker.
35
+ * Called during worker initialization.
36
+ */
37
+ export function registerOnCallHandler(worker: GGTestRuntimeWorker): void {
38
+ worker.onIpcRequest(TestableIPC.invoke, async (payload: TestableInvokePayload): Promise<TestableInvokeResult> => {
39
+ const {keyName, methodName, args, context} = payload;
40
+
41
+ GGLog.debug(LOG_CONTEXT, `Invoking ${keyName}.${methodName}`, {args, hasContext: !!context});
42
+
43
+ try {
44
+ // Look up the instance in the current scope
45
+ const scope = GGLocator.tryGetScope();
46
+ if (!scope) {
47
+ return {
48
+ success: false,
49
+ error: `No GGLocator scope available - is the runtime running?`
50
+ };
51
+ }
52
+
53
+ const key = new GGLocatorKey<any>(keyName);
54
+ const instance = scope.tryGet(key);
55
+
56
+ if (!instance) {
57
+ return {
58
+ success: false,
59
+ error: `Instance '${keyName}' not found in GGLocator. ` +
60
+ `Make sure the class is decorated with @testable or registered during compose().`
61
+ };
62
+ }
63
+
64
+ // Check if method exists
65
+ const method = instance[methodName];
66
+ if (typeof method !== 'function') {
67
+ return {
68
+ success: false,
69
+ error: `Method '${methodName}' not found on instance '${keyName}'. ` +
70
+ `Available methods: ${getMethodNames(instance).join(', ')}`
71
+ };
72
+ }
73
+
74
+ // Invoke the method, optionally within the provided context
75
+ let result: any;
76
+ if (context) {
77
+ const ctx = deserializeContext(context);
78
+ result = await ctx.run(() => method.apply(instance, args));
79
+ } else {
80
+ result = await method.apply(instance, args);
81
+ }
82
+
83
+ GGLog.debug(LOG_CONTEXT, `Invocation ${keyName}.${methodName} completed`, {result});
84
+
85
+ return {
86
+ success: true,
87
+ result
88
+ };
89
+ } catch (error: any) {
90
+ GGLog.error(LOG_CONTEXT, `Error invoking ${keyName}.${methodName}`, error);
91
+
92
+ return {
93
+ success: false,
94
+ error: error.message || String(error),
95
+ stack: error.stack
96
+ };
97
+ }
98
+ });
99
+ }
100
+
101
+ /**
102
+ * Get method names from an instance for error messages.
103
+ */
104
+ function getMethodNames(instance: any): string[] {
105
+ const names: string[] = [];
106
+ let proto = Object.getPrototypeOf(instance);
107
+
108
+ while (proto && proto !== Object.prototype) {
109
+ const propNames = Object.getOwnPropertyNames(proto)
110
+ .filter(name => {
111
+ if (name === 'constructor') return false;
112
+ try {
113
+ return typeof proto[name] === 'function';
114
+ } catch {
115
+ return false;
116
+ }
117
+ });
118
+ names.push(...propNames);
119
+ proto = Object.getPrototypeOf(proto);
120
+ }
121
+
122
+ return [...new Set(names)].sort();
123
+ }
package/src/index-node.ts CHANGED
@@ -1,64 +1,64 @@
1
- /**
2
- * @grest-ts/testkit - Component testing library
3
- */
4
-
5
- // Core test framework
6
- import path from "path";
7
- import {fileURLToPath} from "url";
8
- import {WorkerRunner} from "./runner/WorkerRunner";
9
- import {IsolatedRunner} from "./runner/IsolatedRunner";
10
-
11
- export * from './GGTest'
12
- export * from './GGTestRunner'
13
- export * from './IGGLocalDiscoveryServer'
14
- export * from './GGTestRuntime'
15
- export * from './testers/GGTestComponent'
16
- export * from './mockable/GGMockable'
17
- export * from './mockable/GGMockableCall'
18
- export * from './mockable/mockable'
19
- export * from './GGTestContext'
20
-
21
- // Mockable component server (import triggers factory registration)
22
- export * from './mockable/GGMockableInterceptorsServer'
23
-
24
- // Testable - direct service invocation from tests
25
- export * from './callOn/callOn'
26
- export * from './callOn/GGTestActionForLocatorOnCall'
27
- export * from './callOn/GGCallOnSelector'
28
-
29
- // Contract registration - patches GGContractClass.implement() to auto-register
30
- import './callOn/GGContractClass.implement'
31
-
32
- // Control channel for runtime config updates
33
- export * from './GGTestRuntimeWorker'
34
-
35
- // Test utilities - core infrastructure
36
- export * from './testers/IGGTestWith'
37
- export * from './testers/GGTestAction'
38
- export * from './testers/GGMockWith'
39
- export * from './testers/GGSpyWith'
40
- export * from './testers/GGCallInterceptor'
41
- export * from './utils/GGExpectations'
42
- export * from './utils/GGTestError'
43
- export {captureStackSourceFile} from './utils/captureStack'
44
- export * from './GGTestSharedRef'
45
-
46
- // Production bundle DCE verification
47
- export * from './GGBundleTest'
48
-
49
- // Mockable interceptor
50
- export * from './mockable/GGMockableInterceptor'
51
-
52
- // Selector system for runtime access
53
- export * from './testers/GGTestSelector'
54
- export * from './testers/RuntimeSelector'
55
-
56
- // Worker runner (path configured by @grest-ts/testkit-vitest)
57
- export * from './runner/WorkerRunner'
58
-
59
- export type * from "./testers/IGGTestWith";
60
- export type * from "./testers/IGGTestInterceptor";
61
-
62
- const __dirname = path.dirname(fileURLToPath(import.meta.url));
63
- WorkerRunner.setWorkerLoaderPath(path.join(__dirname, 'runner', 'worker-loader.mjs'));
64
- IsolatedRunner.setIsolatedLoaderPath(path.join(__dirname, 'runner', 'isolated-loader.mjs'));
1
+ /**
2
+ * @grest-ts/testkit - Component testing library
3
+ */
4
+
5
+ // Core test framework
6
+ import path from "path";
7
+ import {fileURLToPath} from "url";
8
+ import {WorkerRunner} from "./runner/WorkerRunner";
9
+ import {IsolatedRunner} from "./runner/IsolatedRunner";
10
+
11
+ export * from './GGTest'
12
+ export * from './GGTestRunner'
13
+ export * from './IGGLocalDiscoveryServer'
14
+ export * from './GGTestRuntime'
15
+ export * from './testers/GGTestComponent'
16
+ export * from './mockable/GGMockable'
17
+ export * from './mockable/GGMockableCall'
18
+ export * from './mockable/mockable'
19
+ export * from './GGTestContext'
20
+
21
+ // Mockable component server (import triggers factory registration)
22
+ export * from './mockable/GGMockableInterceptorsServer'
23
+
24
+ // Testable - direct service invocation from tests
25
+ export * from './callOn/callOn'
26
+ export * from './callOn/GGTestActionForLocatorOnCall'
27
+ export * from './callOn/GGCallOnSelector'
28
+
29
+ // Contract registration - patches GGContractClass.implement() to auto-register
30
+ import './callOn/GGContractClass.implement'
31
+
32
+ // Control channel for runtime config updates
33
+ export * from './GGTestRuntimeWorker'
34
+
35
+ // Test utilities - core infrastructure
36
+ export * from './testers/IGGTestWith'
37
+ export * from './testers/GGTestAction'
38
+ export * from './testers/GGMockWith'
39
+ export * from './testers/GGSpyWith'
40
+ export * from './testers/GGCallInterceptor'
41
+ export * from './utils/GGExpectations'
42
+ export * from './utils/GGTestError'
43
+ export {captureStackSourceFile} from './utils/captureStack'
44
+ export * from './GGTestSharedRef'
45
+
46
+ // Production bundle DCE verification
47
+ export * from './GGBundleTest'
48
+
49
+ // Mockable interceptor
50
+ export * from './mockable/GGMockableInterceptor'
51
+
52
+ // Selector system for runtime access
53
+ export * from './testers/GGTestSelector'
54
+ export * from './testers/RuntimeSelector'
55
+
56
+ // Worker runner (path configured by @grest-ts/testkit-vitest)
57
+ export * from './runner/WorkerRunner'
58
+
59
+ export type * from "./testers/IGGTestWith";
60
+ export type * from "./testers/IGGTestInterceptor";
61
+
62
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
63
+ WorkerRunner.setWorkerLoaderPath(path.join(__dirname, 'runner', 'worker-loader.mjs'));
64
+ IsolatedRunner.setIsolatedLoaderPath(path.join(__dirname, 'runner', 'isolated-loader.mjs'));
@@ -1,22 +1,22 @@
1
- /**
2
- * Marker interface for external API services that can be mocked in tests.
3
- * When a class implements this interface, the test framework can intercept
4
- * all method calls and provide mock responses.
5
- *
6
- * Examples: REST APIs, GraphQL clients, third-party SDKs
7
- */
8
- export interface GGMockableExternalApi {
9
- // Marker interface - no methods required
10
- }
11
-
12
- /**
13
- * Marker interface for database/storage services that can be mocked in tests.
14
- * When a class implements this interface, the test framework can intercept
15
- * all method calls and provide mock responses.
16
- *
17
- * Examples: Database clients, cache services, file storage
18
- */
19
- export interface GGMockableDatabaseApi {
20
- // Marker interface - no methods required
21
- }
22
-
1
+ /**
2
+ * Marker interface for external API services that can be mocked in tests.
3
+ * When a class implements this interface, the test framework can intercept
4
+ * all method calls and provide mock responses.
5
+ *
6
+ * Examples: REST APIs, GraphQL clients, third-party SDKs
7
+ */
8
+ export interface GGMockableExternalApi {
9
+ // Marker interface - no methods required
10
+ }
11
+
12
+ /**
13
+ * Marker interface for database/storage services that can be mocked in tests.
14
+ * When a class implements this interface, the test framework can intercept
15
+ * all method calls and provide mock responses.
16
+ *
17
+ * Examples: Database clients, cache services, file storage
18
+ */
19
+ export interface GGMockableDatabaseApi {
20
+ // Marker interface - no methods required
21
+ }
22
+
@@ -1,45 +1,45 @@
1
- import {GG_TEST_RUNTIME_WORKER} from "../GGTestRuntimeWorker";
2
- import {CALL_THROUGH} from "./GGMockableInterceptorsServer";
3
- import {GGMockableIPC} from "./GGMockableIPC";
4
-
5
- const MOCKABLE_WRAPPED = Symbol('GGMockableWrapped');
6
-
7
- export function GGMockableCall(cls: any, methodName: string, nameMapping: string[]): void {
8
- // Skip if already wrapped (happens in INLINE mode with multiple runtime instances)
9
- if (cls.prototype[methodName]?.[MOCKABLE_WRAPPED]) {
10
- return;
11
- }
12
-
13
- const originalMethod = cls.prototype[methodName];
14
- const wrappedMethod = async function (this: any, ...inputArgs: any[]) {
15
- const worker = GG_TEST_RUNTIME_WORKER.get();
16
-
17
- const args: any = {}
18
- for (let i = 0; i < inputArgs.length; i++) {
19
- if (!nameMapping[i]) break;
20
- args[nameMapping[i]] = inputArgs[i];
21
- }
22
-
23
- const result = await worker.ipcClient.sendFrameworkRequest(GGMockableIPC.testServer.call, {
24
- className: cls.name,
25
- methodName: methodName,
26
- callArgs: args
27
- });
28
-
29
- if (result === CALL_THROUGH) {
30
- const realResult = await originalMethod.apply(this, inputArgs);
31
- await worker.ipcClient.sendFrameworkRequest(GGMockableIPC.testServer.spyResult, {
32
- className: cls.name,
33
- methodName: methodName,
34
- callResult: realResult
35
- });
36
- return realResult;
37
- } else {
38
- return result;
39
- }
40
- };
41
-
42
- // Mark as wrapped and assign to prototype
43
- (wrappedMethod as any)[MOCKABLE_WRAPPED] = true;
44
- cls.prototype[methodName] = wrappedMethod;
45
- }
1
+ import {GG_TEST_RUNTIME_WORKER} from "../GGTestRuntimeWorker";
2
+ import {CALL_THROUGH} from "./GGMockableInterceptorsServer";
3
+ import {GGMockableIPC} from "./GGMockableIPC";
4
+
5
+ const MOCKABLE_WRAPPED = Symbol('GGMockableWrapped');
6
+
7
+ export function GGMockableCall(cls: any, methodName: string, nameMapping: string[]): void {
8
+ // Skip if already wrapped (happens in INLINE mode with multiple runtime instances)
9
+ if (cls.prototype[methodName]?.[MOCKABLE_WRAPPED]) {
10
+ return;
11
+ }
12
+
13
+ const originalMethod = cls.prototype[methodName];
14
+ const wrappedMethod = async function (this: any, ...inputArgs: any[]) {
15
+ const worker = GG_TEST_RUNTIME_WORKER.get();
16
+
17
+ const args: any = {}
18
+ for (let i = 0; i < inputArgs.length; i++) {
19
+ if (!nameMapping[i]) break;
20
+ args[nameMapping[i]] = inputArgs[i];
21
+ }
22
+
23
+ const result = await worker.ipcClient.sendFrameworkRequest(GGMockableIPC.testServer.call, {
24
+ className: cls.name,
25
+ methodName: methodName,
26
+ callArgs: args
27
+ });
28
+
29
+ if (result === CALL_THROUGH) {
30
+ const realResult = await originalMethod.apply(this, inputArgs);
31
+ await worker.ipcClient.sendFrameworkRequest(GGMockableIPC.testServer.spyResult, {
32
+ className: cls.name,
33
+ methodName: methodName,
34
+ callResult: realResult
35
+ });
36
+ return realResult;
37
+ } else {
38
+ return result;
39
+ }
40
+ };
41
+
42
+ // Mark as wrapped and assign to prototype
43
+ (wrappedMethod as any)[MOCKABLE_WRAPPED] = true;
44
+ cls.prototype[methodName] = wrappedMethod;
45
+ }
@@ -1,20 +1,20 @@
1
- import {IPCServer} from "@grest-ts/ipc";
2
-
3
- export interface MockableCallPayload {
4
- className: string;
5
- methodName: string;
6
- callArgs: any;
7
- }
8
-
9
- export interface MockableSpyResultPayload {
10
- className: string;
11
- methodName: string;
12
- callResult: any;
13
- }
14
-
15
- export const GGMockableIPC = {
16
- testServer: {
17
- call: IPCServer.defineRequest<MockableCallPayload, any>("mockable/call"),
18
- spyResult: IPCServer.defineRequest<MockableSpyResultPayload, any>("mockable/spy-result"),
19
- }
20
- }
1
+ import {IPCServer} from "@grest-ts/ipc";
2
+
3
+ export interface MockableCallPayload {
4
+ className: string;
5
+ methodName: string;
6
+ callArgs: any;
7
+ }
8
+
9
+ export interface MockableSpyResultPayload {
10
+ className: string;
11
+ methodName: string;
12
+ callResult: any;
13
+ }
14
+
15
+ export const GGMockableIPC = {
16
+ testServer: {
17
+ call: IPCServer.defineRequest<MockableCallPayload, any>("mockable/call"),
18
+ spyResult: IPCServer.defineRequest<MockableSpyResultPayload, any>("mockable/spy-result"),
19
+ }
20
+ }
@@ -1,44 +1,44 @@
1
- import type {GGTestRunner} from "../GGTestRunner";
2
- import {GGCallInterceptor, GGCallInterceptorConfig} from "../testers/GGCallInterceptor";
3
- import {GGMockableInterceptorsServer} from "./GGMockableInterceptorsServer";
4
-
5
- export interface MockableInterceptorConfig extends GGCallInterceptorConfig {
6
- className: string;
7
- methodName: string;
8
- }
9
-
10
- /**
11
- * Interceptor for mocking/spying on mockable class methods.
12
- * Registers with GGMockableInterceptorsServer which handles the IPC communication.
13
- *
14
- * For spy mode, the flow is two-phase:
15
- * 1. mockable/call → onRequest() validates input, returns undefined (CALL_THROUGH)
16
- * 2. mockable/spy-result → onResponse() validates output
17
- */
18
- export class GGMockableInterceptor extends GGCallInterceptor {
19
-
20
- public readonly className: string;
21
- public readonly methodName: string;
22
-
23
- constructor(test: GGTestRunner, config: MockableInterceptorConfig) {
24
- super(test, config);
25
- this.className = config.className;
26
- this.methodName = config.methodName;
27
- }
28
-
29
- public getKey(): string {
30
- return `${this.className}.${this.methodName}`;
31
- }
32
-
33
- protected doRegister(): void {
34
- this.test.getExtensionInstance(GGMockableInterceptorsServer).addInterceptor(this);
35
- }
36
-
37
- protected doUnregister(): void {
38
- this.test.getExtensionInstance(GGMockableInterceptorsServer).deleteInterceptor(this);
39
- }
40
-
41
- protected parseResponseData(result: any): any {
42
- return result;
43
- }
44
- }
1
+ import type {GGTestRunner} from "../GGTestRunner";
2
+ import {GGCallInterceptor, GGCallInterceptorConfig} from "../testers/GGCallInterceptor";
3
+ import {GGMockableInterceptorsServer} from "./GGMockableInterceptorsServer";
4
+
5
+ export interface MockableInterceptorConfig extends GGCallInterceptorConfig {
6
+ className: string;
7
+ methodName: string;
8
+ }
9
+
10
+ /**
11
+ * Interceptor for mocking/spying on mockable class methods.
12
+ * Registers with GGMockableInterceptorsServer which handles the IPC communication.
13
+ *
14
+ * For spy mode, the flow is two-phase:
15
+ * 1. mockable/call → onRequest() validates input, returns undefined (CALL_THROUGH)
16
+ * 2. mockable/spy-result → onResponse() validates output
17
+ */
18
+ export class GGMockableInterceptor extends GGCallInterceptor {
19
+
20
+ public readonly className: string;
21
+ public readonly methodName: string;
22
+
23
+ constructor(test: GGTestRunner, config: MockableInterceptorConfig) {
24
+ super(test, config);
25
+ this.className = config.className;
26
+ this.methodName = config.methodName;
27
+ }
28
+
29
+ public getKey(): string {
30
+ return `${this.className}.${this.methodName}`;
31
+ }
32
+
33
+ protected doRegister(): void {
34
+ this.test.getExtensionInstance(GGMockableInterceptorsServer).addInterceptor(this);
35
+ }
36
+
37
+ protected doUnregister(): void {
38
+ this.test.getExtensionInstance(GGMockableInterceptorsServer).deleteInterceptor(this);
39
+ }
40
+
41
+ protected parseResponseData(result: any): any {
42
+ return result;
43
+ }
44
+ }