@grest-ts/testkit 0.0.5

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 (200) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +413 -0
  3. package/dist/src/GGBundleTest.d.ts +8 -0
  4. package/dist/src/GGBundleTest.d.ts.map +1 -0
  5. package/dist/src/GGBundleTest.js +75 -0
  6. package/dist/src/GGBundleTest.js.map +1 -0
  7. package/dist/src/GGTest.d.ts +131 -0
  8. package/dist/src/GGTest.d.ts.map +1 -0
  9. package/dist/src/GGTest.js +245 -0
  10. package/dist/src/GGTest.js.map +1 -0
  11. package/dist/src/GGTestContext.d.ts +36 -0
  12. package/dist/src/GGTestContext.d.ts.map +1 -0
  13. package/dist/src/GGTestContext.js +63 -0
  14. package/dist/src/GGTestContext.js.map +1 -0
  15. package/dist/src/GGTestRunner.d.ts +108 -0
  16. package/dist/src/GGTestRunner.d.ts.map +1 -0
  17. package/dist/src/GGTestRunner.js +242 -0
  18. package/dist/src/GGTestRunner.js.map +1 -0
  19. package/dist/src/GGTestRuntime.d.ts +103 -0
  20. package/dist/src/GGTestRuntime.d.ts.map +1 -0
  21. package/dist/src/GGTestRuntime.js +219 -0
  22. package/dist/src/GGTestRuntime.js.map +1 -0
  23. package/dist/src/GGTestRuntimeWorker.d.ts +41 -0
  24. package/dist/src/GGTestRuntimeWorker.d.ts.map +1 -0
  25. package/dist/src/GGTestRuntimeWorker.js +136 -0
  26. package/dist/src/GGTestRuntimeWorker.js.map +1 -0
  27. package/dist/src/GGTestSharedRef.d.ts +35 -0
  28. package/dist/src/GGTestSharedRef.d.ts.map +1 -0
  29. package/dist/src/GGTestSharedRef.js +126 -0
  30. package/dist/src/GGTestSharedRef.js.map +1 -0
  31. package/dist/src/GGTestkitExtensionsDiscovery.d.ts +21 -0
  32. package/dist/src/GGTestkitExtensionsDiscovery.d.ts.map +1 -0
  33. package/dist/src/GGTestkitExtensionsDiscovery.js +24 -0
  34. package/dist/src/GGTestkitExtensionsDiscovery.js.map +1 -0
  35. package/dist/src/IGGLocalDiscoveryServer.d.ts +16 -0
  36. package/dist/src/IGGLocalDiscoveryServer.d.ts.map +1 -0
  37. package/dist/src/IGGLocalDiscoveryServer.js +2 -0
  38. package/dist/src/IGGLocalDiscoveryServer.js.map +1 -0
  39. package/dist/src/callOn/GGCallOnSelector.d.ts +42 -0
  40. package/dist/src/callOn/GGCallOnSelector.d.ts.map +1 -0
  41. package/dist/src/callOn/GGCallOnSelector.js +35 -0
  42. package/dist/src/callOn/GGCallOnSelector.js.map +1 -0
  43. package/dist/src/callOn/GGContractClass.implement.d.ts +8 -0
  44. package/dist/src/callOn/GGContractClass.implement.d.ts.map +1 -0
  45. package/dist/src/callOn/GGContractClass.implement.js +31 -0
  46. package/dist/src/callOn/GGContractClass.implement.js.map +1 -0
  47. package/dist/src/callOn/GGTestActionForLocatorOnCall.d.ts +28 -0
  48. package/dist/src/callOn/GGTestActionForLocatorOnCall.d.ts.map +1 -0
  49. package/dist/src/callOn/GGTestActionForLocatorOnCall.js +118 -0
  50. package/dist/src/callOn/GGTestActionForLocatorOnCall.js.map +1 -0
  51. package/dist/src/callOn/TestableIPC.d.ts +72 -0
  52. package/dist/src/callOn/TestableIPC.d.ts.map +1 -0
  53. package/dist/src/callOn/TestableIPC.js +34 -0
  54. package/dist/src/callOn/TestableIPC.js.map +1 -0
  55. package/dist/src/callOn/callOn.d.ts +113 -0
  56. package/dist/src/callOn/callOn.d.ts.map +1 -0
  57. package/dist/src/callOn/callOn.js +122 -0
  58. package/dist/src/callOn/callOn.js.map +1 -0
  59. package/dist/src/callOn/registerOnCallHandler.d.ts +13 -0
  60. package/dist/src/callOn/registerOnCallHandler.d.ts.map +1 -0
  61. package/dist/src/callOn/registerOnCallHandler.js +111 -0
  62. package/dist/src/callOn/registerOnCallHandler.js.map +1 -0
  63. package/dist/src/index-node.d.ts +35 -0
  64. package/dist/src/index-node.d.ts.map +1 -0
  65. package/dist/src/index-node.js +50 -0
  66. package/dist/src/index-node.js.map +1 -0
  67. package/dist/src/mockable/GGMockable.d.ts +19 -0
  68. package/dist/src/mockable/GGMockable.d.ts.map +1 -0
  69. package/dist/src/mockable/GGMockable.js +2 -0
  70. package/dist/src/mockable/GGMockable.js.map +1 -0
  71. package/dist/src/mockable/GGMockableCall.d.ts +2 -0
  72. package/dist/src/mockable/GGMockableCall.d.ts.map +1 -0
  73. package/dist/src/mockable/GGMockableCall.js +41 -0
  74. package/dist/src/mockable/GGMockableCall.js.map +1 -0
  75. package/dist/src/mockable/GGMockableIPC.d.ts +17 -0
  76. package/dist/src/mockable/GGMockableIPC.d.ts.map +1 -0
  77. package/dist/src/mockable/GGMockableIPC.js +8 -0
  78. package/dist/src/mockable/GGMockableIPC.js.map +1 -0
  79. package/dist/src/mockable/GGMockableInterceptor.d.ts +24 -0
  80. package/dist/src/mockable/GGMockableInterceptor.d.ts.map +1 -0
  81. package/dist/src/mockable/GGMockableInterceptor.js +32 -0
  82. package/dist/src/mockable/GGMockableInterceptor.js.map +1 -0
  83. package/dist/src/mockable/GGMockableInterceptorsServer.d.ts +12 -0
  84. package/dist/src/mockable/GGMockableInterceptorsServer.d.ts.map +1 -0
  85. package/dist/src/mockable/GGMockableInterceptorsServer.js +55 -0
  86. package/dist/src/mockable/GGMockableInterceptorsServer.js.map +1 -0
  87. package/dist/src/mockable/mockable.d.ts +46 -0
  88. package/dist/src/mockable/mockable.d.ts.map +1 -0
  89. package/dist/src/mockable/mockable.js +47 -0
  90. package/dist/src/mockable/mockable.js.map +1 -0
  91. package/dist/src/runner/InlineRunner.d.ts +12 -0
  92. package/dist/src/runner/InlineRunner.d.ts.map +1 -0
  93. package/dist/src/runner/InlineRunner.js +42 -0
  94. package/dist/src/runner/InlineRunner.js.map +1 -0
  95. package/dist/src/runner/IsolatedRunner.d.ts +17 -0
  96. package/dist/src/runner/IsolatedRunner.d.ts.map +1 -0
  97. package/dist/src/runner/IsolatedRunner.js +155 -0
  98. package/dist/src/runner/IsolatedRunner.js.map +1 -0
  99. package/dist/src/runner/RuntimeRunner.d.ts +14 -0
  100. package/dist/src/runner/RuntimeRunner.d.ts.map +1 -0
  101. package/dist/src/runner/RuntimeRunner.js +2 -0
  102. package/dist/src/runner/RuntimeRunner.js.map +1 -0
  103. package/dist/src/runner/WorkerRunner.d.ts +17 -0
  104. package/dist/src/runner/WorkerRunner.d.ts.map +1 -0
  105. package/dist/src/runner/WorkerRunner.js +155 -0
  106. package/dist/src/runner/WorkerRunner.js.map +1 -0
  107. package/dist/src/runner/isolated-loader.mjs +91 -0
  108. package/dist/src/runner/worker-loader.mjs +49 -0
  109. package/dist/src/testers/GGCallInterceptor.d.ts +71 -0
  110. package/dist/src/testers/GGCallInterceptor.d.ts.map +1 -0
  111. package/dist/src/testers/GGCallInterceptor.js +170 -0
  112. package/dist/src/testers/GGCallInterceptor.js.map +1 -0
  113. package/dist/src/testers/GGMockWith.d.ts +30 -0
  114. package/dist/src/testers/GGMockWith.d.ts.map +1 -0
  115. package/dist/src/testers/GGMockWith.js +70 -0
  116. package/dist/src/testers/GGMockWith.js.map +1 -0
  117. package/dist/src/testers/GGSpyWith.d.ts +40 -0
  118. package/dist/src/testers/GGSpyWith.d.ts.map +1 -0
  119. package/dist/src/testers/GGSpyWith.js +90 -0
  120. package/dist/src/testers/GGSpyWith.js.map +1 -0
  121. package/dist/src/testers/GGTestAction.d.ts +126 -0
  122. package/dist/src/testers/GGTestAction.d.ts.map +1 -0
  123. package/dist/src/testers/GGTestAction.js +245 -0
  124. package/dist/src/testers/GGTestAction.js.map +1 -0
  125. package/dist/src/testers/GGTestComponent.d.ts +15 -0
  126. package/dist/src/testers/GGTestComponent.d.ts.map +1 -0
  127. package/dist/src/testers/GGTestComponent.js +2 -0
  128. package/dist/src/testers/GGTestComponent.js.map +1 -0
  129. package/dist/src/testers/GGTestSelector.d.ts +54 -0
  130. package/dist/src/testers/GGTestSelector.d.ts.map +1 -0
  131. package/dist/src/testers/GGTestSelector.js +179 -0
  132. package/dist/src/testers/GGTestSelector.js.map +1 -0
  133. package/dist/src/testers/IGGTestInterceptor.d.ts +8 -0
  134. package/dist/src/testers/IGGTestInterceptor.d.ts.map +1 -0
  135. package/dist/src/testers/IGGTestInterceptor.js +2 -0
  136. package/dist/src/testers/IGGTestInterceptor.js.map +1 -0
  137. package/dist/src/testers/IGGTestWith.d.ts +13 -0
  138. package/dist/src/testers/IGGTestWith.d.ts.map +1 -0
  139. package/dist/src/testers/IGGTestWith.js +2 -0
  140. package/dist/src/testers/IGGTestWith.js.map +1 -0
  141. package/dist/src/testers/RuntimeSelector.d.ts +117 -0
  142. package/dist/src/testers/RuntimeSelector.d.ts.map +1 -0
  143. package/dist/src/testers/RuntimeSelector.js +2 -0
  144. package/dist/src/testers/RuntimeSelector.js.map +1 -0
  145. package/dist/src/tsconfig.json +17 -0
  146. package/dist/src/utils/GGExpectations.d.ts +18 -0
  147. package/dist/src/utils/GGExpectations.d.ts.map +1 -0
  148. package/dist/src/utils/GGExpectations.js +59 -0
  149. package/dist/src/utils/GGExpectations.js.map +1 -0
  150. package/dist/src/utils/GGTestError.d.ts +13 -0
  151. package/dist/src/utils/GGTestError.d.ts.map +1 -0
  152. package/dist/src/utils/GGTestError.js +26 -0
  153. package/dist/src/utils/GGTestError.js.map +1 -0
  154. package/dist/src/utils/captureStack.d.ts +9 -0
  155. package/dist/src/utils/captureStack.d.ts.map +1 -0
  156. package/dist/src/utils/captureStack.js +51 -0
  157. package/dist/src/utils/captureStack.js.map +1 -0
  158. package/dist/tsconfig.publish.tsbuildinfo +1 -0
  159. package/package.json +66 -0
  160. package/src/GGBundleTest.ts +89 -0
  161. package/src/GGTest.ts +318 -0
  162. package/src/GGTestContext.ts +74 -0
  163. package/src/GGTestRunner.ts +308 -0
  164. package/src/GGTestRuntime.ts +265 -0
  165. package/src/GGTestRuntimeWorker.ts +159 -0
  166. package/src/GGTestSharedRef.ts +116 -0
  167. package/src/GGTestkitExtensionsDiscovery.ts +26 -0
  168. package/src/IGGLocalDiscoveryServer.ts +16 -0
  169. package/src/callOn/GGCallOnSelector.ts +61 -0
  170. package/src/callOn/GGContractClass.implement.ts +43 -0
  171. package/src/callOn/GGTestActionForLocatorOnCall.ts +134 -0
  172. package/src/callOn/TestableIPC.ts +81 -0
  173. package/src/callOn/callOn.ts +224 -0
  174. package/src/callOn/registerOnCallHandler.ts +123 -0
  175. package/src/index-node.ts +64 -0
  176. package/src/mockable/GGMockable.ts +22 -0
  177. package/src/mockable/GGMockableCall.ts +45 -0
  178. package/src/mockable/GGMockableIPC.ts +20 -0
  179. package/src/mockable/GGMockableInterceptor.ts +44 -0
  180. package/src/mockable/GGMockableInterceptorsServer.ts +69 -0
  181. package/src/mockable/mockable.ts +71 -0
  182. package/src/runner/InlineRunner.ts +47 -0
  183. package/src/runner/IsolatedRunner.ts +179 -0
  184. package/src/runner/RuntimeRunner.ts +15 -0
  185. package/src/runner/WorkerRunner.ts +179 -0
  186. package/src/runner/isolated-loader.mjs +91 -0
  187. package/src/runner/worker-loader.mjs +49 -0
  188. package/src/testers/GGCallInterceptor.ts +224 -0
  189. package/src/testers/GGMockWith.ts +92 -0
  190. package/src/testers/GGSpyWith.ts +115 -0
  191. package/src/testers/GGTestAction.ts +333 -0
  192. package/src/testers/GGTestComponent.ts +16 -0
  193. package/src/testers/GGTestSelector.ts +223 -0
  194. package/src/testers/IGGTestInterceptor.ts +11 -0
  195. package/src/testers/IGGTestWith.ts +15 -0
  196. package/src/testers/RuntimeSelector.ts +151 -0
  197. package/src/tsconfig.json +17 -0
  198. package/src/utils/GGExpectations.ts +78 -0
  199. package/src/utils/GGTestError.ts +37 -0
  200. package/src/utils/captureStack.ts +54 -0
@@ -0,0 +1,155 @@
1
+ import { spawn } from "child_process";
2
+ import { GGLog } from "@grest-ts/logger";
3
+ const PROCESS_READY = "IsolatedRunner:READY";
4
+ const GG_ISOLATED_CONFIG = "GG_ISOLATED_CONFIG";
5
+ export class IsolatedRunner {
6
+ config;
7
+ process;
8
+ static isolatedLoaderPath;
9
+ /**
10
+ * Set the path to the isolated-loader.mjs file.
11
+ * Called by @grest-ts/testkit-vitest to inject the path.
12
+ */
13
+ static setIsolatedLoaderPath(path) {
14
+ this.isolatedLoaderPath = path;
15
+ }
16
+ constructor(config) {
17
+ this.config = config;
18
+ }
19
+ async start() {
20
+ if (!IsolatedRunner.isolatedLoaderPath) {
21
+ throw new Error("Isolated loader path not set!\n" +
22
+ "Make sure to import '@grest-ts/testkit-vitest' in your vitest setup.");
23
+ }
24
+ GGLog.debug(this, 'Starting isolated process for: ' + this.config.executablePath);
25
+ this.process = spawn('npx', ['tsx', IsolatedRunner.isolatedLoaderPath, this.config.executablePath], {
26
+ env: {
27
+ ...process.env,
28
+ [GG_ISOLATED_CONFIG]: JSON.stringify(this.config)
29
+ },
30
+ stdio: ['pipe', 'pipe', 'pipe'], // pipe all streams so we can forward them properly
31
+ shell: true // Required for Windows to find npx
32
+ });
33
+ // Forward stderr to console.error so vitest can capture and sequence it
34
+ this.process.stderr?.setEncoding('utf8');
35
+ this.process.stderr?.on('data', (data) => {
36
+ const lines = data.split('\n');
37
+ for (const line of lines) {
38
+ if (line)
39
+ console.error(line);
40
+ }
41
+ });
42
+ // Wait for process to signal ready via stdout
43
+ await new Promise((resolve, reject) => {
44
+ if (!this.process) {
45
+ reject(new Error('Process failed to start'));
46
+ return;
47
+ }
48
+ const timeout = setTimeout(() => {
49
+ this.process?.kill('SIGKILL');
50
+ reject(new Error(`Process did not send READY signal within 10 seconds`));
51
+ }, 10000);
52
+ // Watch stdout for READY signal and forward all output using console.log
53
+ // so vitest can capture and sequence it properly with test output
54
+ this.process.stdout?.setEncoding('utf8');
55
+ let ready = false;
56
+ const onData = (data) => {
57
+ const lines = data.split('\n');
58
+ for (const line of lines) {
59
+ if (line)
60
+ console.log(line);
61
+ }
62
+ if (!ready && data.includes(PROCESS_READY)) {
63
+ clearTimeout(timeout);
64
+ GGLog.debug(this, 'Process ready');
65
+ ready = true;
66
+ resolve();
67
+ }
68
+ };
69
+ this.process.stdout?.on('data', onData);
70
+ this.process.once('error', (err) => {
71
+ clearTimeout(timeout);
72
+ reject(err);
73
+ });
74
+ this.process.once('exit', (code) => {
75
+ if (code !== 0 && code !== null) {
76
+ clearTimeout(timeout);
77
+ reject(new Error(`Process exited with code ${code} before sending READY signal`));
78
+ }
79
+ });
80
+ });
81
+ }
82
+ async stopRuntime() {
83
+ if (!this.process) {
84
+ return;
85
+ }
86
+ GGLog.debug(this, 'Stopping runtime in process...');
87
+ const RUNTIME_STOPPED = 'IsolatedRunner:RUNTIME_STOPPED';
88
+ return new Promise((resolve, reject) => {
89
+ if (!this.process) {
90
+ resolve();
91
+ return;
92
+ }
93
+ const timeout = setTimeout(() => {
94
+ GGLog.error(this, 'Timeout waiting for runtime to stop');
95
+ reject(new Error('Timeout waiting for runtime to stop'));
96
+ }, 5000);
97
+ // Listen for RUNTIME_STOPPED signal in stdout
98
+ const onData = (data) => {
99
+ if (data.includes(RUNTIME_STOPPED)) {
100
+ clearTimeout(timeout);
101
+ this.process?.stdout?.off('data', onData);
102
+ GGLog.debug(this, 'Runtime stopped in process');
103
+ resolve();
104
+ }
105
+ };
106
+ this.process.stdout?.on('data', onData);
107
+ // Send stop runtime command via stdin
108
+ try {
109
+ this.process.stdin?.write('STOP_RUNTIME\n');
110
+ GGLog.debug(this, 'Sent stop runtime command via stdin');
111
+ }
112
+ catch (error) {
113
+ clearTimeout(timeout);
114
+ GGLog.error(this, 'Error sending stop runtime command', error);
115
+ reject(error);
116
+ }
117
+ });
118
+ }
119
+ async shutdown() {
120
+ if (!this.process) {
121
+ return;
122
+ }
123
+ GGLog.debug(this, 'Shutting down process...');
124
+ return new Promise((resolve) => {
125
+ if (!this.process) {
126
+ resolve();
127
+ return;
128
+ }
129
+ this.process.once('exit', () => {
130
+ clearTimeout(forceKillTimeout);
131
+ this.process = undefined;
132
+ GGLog.debug(this, 'Process shut down');
133
+ resolve();
134
+ });
135
+ // Send shutdown message via stdin (works cross-platform, unlike SIGTERM on Windows)
136
+ try {
137
+ this.process.stdin?.write('SHUTDOWN\n');
138
+ this.process.stdin?.end();
139
+ GGLog.debug(this, 'Sent shutdown command via stdin');
140
+ }
141
+ catch (error) {
142
+ GGLog.error(this, 'Error sending shutdown command', error);
143
+ }
144
+ // Force kill after 2 seconds if still running
145
+ const forceKillTimeout = setTimeout(() => {
146
+ if (this.process && !this.process.killed) {
147
+ GGLog.debug(this, 'Process did not exit gracefully, force killing');
148
+ this.process.kill('SIGKILL');
149
+ this.process = undefined;
150
+ }
151
+ }, 2000);
152
+ });
153
+ }
154
+ }
155
+ //# sourceMappingURL=IsolatedRunner.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"IsolatedRunner.js","sourceRoot":"","sources":["../../../src/runner/IsolatedRunner.ts"],"names":[],"mappings":"AACA,OAAO,EAAoB,KAAK,EAAC,MAAM,eAAe,CAAC;AACvD,OAAO,EAAC,KAAK,EAAC,MAAM,kBAAkB,CAAC;AAGvC,MAAM,aAAa,GAAG,sBAAsB,CAAA;AAC5C,MAAM,kBAAkB,GAAG,oBAAoB,CAAC;AAEhD,MAAM,OAAO,cAAc;IAaH;IAZZ,OAAO,CAAgB;IAEvB,MAAM,CAAC,kBAAkB,CAAqB;IAEtD;;;OAGG;IACI,MAAM,CAAC,qBAAqB,CAAC,IAAY;QAC5C,IAAI,CAAC,kBAAkB,GAAG,IAAI,CAAC;IACnC,CAAC;IAED,YAAoB,MAAuB;QAAvB,WAAM,GAAN,MAAM,CAAiB;IAC3C,CAAC;IAED,KAAK,CAAC,KAAK;QACP,IAAI,CAAC,cAAc,CAAC,kBAAkB,EAAE,CAAC;YACrC,MAAM,IAAI,KAAK,CACX,iCAAiC;gBACjC,sEAAsE,CACzE,CAAC;QACN,CAAC;QAED,KAAK,CAAC,KAAK,CAAC,IAAI,EAAE,iCAAiC,GAAG,IAAI,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC;QAElF,IAAI,CAAC,OAAO,GAAG,KAAK,CAAC,KAAK,EAAE,CAAC,KAAK,EAAE,cAAc,CAAC,kBAAmB,EAAE,IAAI,CAAC,MAAM,CAAC,cAAc,CAAC,EAAE;YACjG,GAAG,EAAE;gBACD,GAAG,OAAO,CAAC,GAAG;gBACd,CAAC,kBAAkB,CAAC,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,MAAM,CAAC;aACpD;YACD,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,mDAAmD;YACpF,KAAK,EAAE,IAAI,CAAC,mCAAmC;SAClD,CAAC,CAAC;QAEH,wEAAwE;QACxE,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;QACzC,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,EAAE,CAAC,IAAY,EAAE,EAAE;YAC7C,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;YAC/B,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;gBACvB,IAAI,IAAI;oBAAE,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;YAClC,CAAC;QACL,CAAC,CAAC,CAAC;QAEH,8CAA8C;QAC9C,MAAM,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YACxC,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC;gBAChB,MAAM,CAAC,IAAI,KAAK,CAAC,yBAAyB,CAAC,CAAC,CAAC;gBAC7C,OAAO;YACX,CAAC;YAED,MAAM,OAAO,GAAG,UAAU,CAAC,GAAG,EAAE;gBAC5B,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC;gBAC9B,MAAM,CAAC,IAAI,KAAK,CAAC,qDAAqD,CAAC,CAAC,CAAC;YAC7E,CAAC,EAAE,KAAK,CAAC,CAAC;YAEV,yEAAyE;YACzE,kEAAkE;YAClE,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;YACzC,IAAI,KAAK,GAAG,KAAK,CAAC;YAClB,MAAM,MAAM,GAAG,CAAC,IAAY,EAAE,EAAE;gBAC5B,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;gBAC/B,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;oBACvB,IAAI,IAAI;wBAAE,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;gBAChC,CAAC;gBACD,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,QAAQ,CAAC,aAAa,CAAC,EAAE,CAAC;oBACzC,YAAY,CAAC,OAAO,CAAC,CAAC;oBACtB,KAAK,CAAC,KAAK,CAAC,IAAI,EAAE,eAAe,CAAC,CAAC;oBACnC,KAAK,GAAG,IAAI,CAAC;oBACb,OAAO,EAAE,CAAC;gBACd,CAAC;YACL,CAAC,CAAC;YACF,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;YAExC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,GAAG,EAAE,EAAE;gBAC/B,YAAY,CAAC,OAAO,CAAC,CAAC;gBACtB,MAAM,CAAC,GAAG,CAAC,CAAC;YAChB,CAAC,CAAC,CAAC;YAEH,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,EAAE;gBAC/B,IAAI,IAAI,KAAK,CAAC,IAAI,IAAI,KAAK,IAAI,EAAE,CAAC;oBAC9B,YAAY,CAAC,OAAO,CAAC,CAAC;oBACtB,MAAM,CAAC,IAAI,KAAK,CAAC,4BAA4B,IAAI,8BAA8B,CAAC,CAAC,CAAC;gBACtF,CAAC;YACL,CAAC,CAAC,CAAC;QACP,CAAC,CAAC,CAAC;IACP,CAAC;IAED,KAAK,CAAC,WAAW;QACb,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC;YAChB,OAAO;QACX,CAAC;QAED,KAAK,CAAC,KAAK,CAAC,IAAI,EAAE,gCAAgC,CAAC,CAAC;QAEpD,MAAM,eAAe,GAAG,gCAAgC,CAAC;QAEzD,OAAO,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YACzC,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC;gBAChB,OAAO,EAAE,CAAC;gBACV,OAAO;YACX,CAAC;YAED,MAAM,OAAO,GAAG,UAAU,CAAC,GAAG,EAAE;gBAC5B,KAAK,CAAC,KAAK,CAAC,IAAI,EAAE,qCAAqC,CAAC,CAAC;gBACzD,MAAM,CAAC,IAAI,KAAK,CAAC,qCAAqC,CAAC,CAAC,CAAC;YAC7D,CAAC,EAAE,IAAI,CAAC,CAAC;YAET,8CAA8C;YAC9C,MAAM,MAAM,GAAG,CAAC,IAAY,EAAE,EAAE;gBAC5B,IAAI,IAAI,CAAC,QAAQ,CAAC,eAAe,CAAC,EAAE,CAAC;oBACjC,YAAY,CAAC,OAAO,CAAC,CAAC;oBACtB,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;oBAC1C,KAAK,CAAC,KAAK,CAAC,IAAI,EAAE,4BAA4B,CAAC,CAAC;oBAChD,OAAO,EAAE,CAAC;gBACd,CAAC;YACL,CAAC,CAAC;YACF,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;YAExC,sCAAsC;YACtC,IAAI,CAAC;gBACD,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,KAAK,CAAC,gBAAgB,CAAC,CAAC;gBAC5C,KAAK,CAAC,KAAK,CAAC,IAAI,EAAE,qCAAqC,CAAC,CAAC;YAC7D,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACb,YAAY,CAAC,OAAO,CAAC,CAAC;gBACtB,KAAK,CAAC,KAAK,CAAC,IAAI,EAAE,oCAAoC,EAAE,KAAK,CAAC,CAAC;gBAC/D,MAAM,CAAC,KAAK,CAAC,CAAC;YAClB,CAAC;QACL,CAAC,CAAC,CAAC;IACP,CAAC;IAED,KAAK,CAAC,QAAQ;QACV,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC;YAChB,OAAO;QACX,CAAC;QAED,KAAK,CAAC,KAAK,CAAC,IAAI,EAAE,0BAA0B,CAAC,CAAC;QAE9C,OAAO,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,EAAE;YACjC,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC;gBAChB,OAAO,EAAE,CAAC;gBACV,OAAO;YACX,CAAC;YAED,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,EAAE;gBAC3B,YAAY,CAAC,gBAAgB,CAAC,CAAC;gBAC/B,IAAI,CAAC,OAAO,GAAG,SAAS,CAAC;gBACzB,KAAK,CAAC,KAAK,CAAC,IAAI,EAAE,mBAAmB,CAAC,CAAC;gBACvC,OAAO,EAAE,CAAC;YACd,CAAC,CAAC,CAAC;YAEH,oFAAoF;YACpF,IAAI,CAAC;gBACD,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,KAAK,CAAC,YAAY,CAAC,CAAC;gBACxC,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,EAAE,CAAC;gBAC1B,KAAK,CAAC,KAAK,CAAC,IAAI,EAAE,iCAAiC,CAAC,CAAC;YACzD,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACb,KAAK,CAAC,KAAK,CAAC,IAAI,EAAE,gCAAgC,EAAE,KAAK,CAAC,CAAC;YAC/D,CAAC;YAED,8CAA8C;YAC9C,MAAM,gBAAgB,GAAG,UAAU,CAAC,GAAG,EAAE;gBACrC,IAAI,IAAI,CAAC,OAAO,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC;oBACvC,KAAK,CAAC,KAAK,CAAC,IAAI,EAAE,gDAAgD,CAAC,CAAC;oBACpE,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;oBAC7B,IAAI,CAAC,OAAO,GAAG,SAAS,CAAC;gBAC7B,CAAC;YACL,CAAC,EAAE,IAAI,CAAC,CAAC;QACb,CAAC,CAAC,CAAC;IACP,CAAC;CACJ"}
@@ -0,0 +1,14 @@
1
+ export interface RuntimeRunner {
2
+ start(): Promise<void>;
3
+ /**
4
+ * Stop the GGRuntime (teardown services) but keep the worker/IPC alive.
5
+ * This allows log retrieval after the runtime has stopped.
6
+ */
7
+ stopRuntime(): Promise<void>;
8
+ /**
9
+ * Fully shutdown the worker, including IPC disconnection.
10
+ * After this, no commands can be sent.
11
+ */
12
+ shutdown(): Promise<void>;
13
+ }
14
+ //# sourceMappingURL=RuntimeRunner.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RuntimeRunner.d.ts","sourceRoot":"","sources":["../../../src/runner/RuntimeRunner.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,aAAa;IAC1B,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAEvB;;;OAGG;IACH,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAE7B;;;OAGG;IACH,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CAC7B"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=RuntimeRunner.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RuntimeRunner.js","sourceRoot":"","sources":["../../../src/runner/RuntimeRunner.ts"],"names":[],"mappings":""}
@@ -0,0 +1,17 @@
1
+ import type { RuntimeRunner } from "./RuntimeRunner";
2
+ import { GGTestEnvConfig } from "../GGTestRuntime";
3
+ export declare class WorkerRunner implements RuntimeRunner {
4
+ private readonly config;
5
+ private worker?;
6
+ private static workerLoaderPath;
7
+ /**
8
+ * Set the path to the worker-loader.mjs file.
9
+ * Called by @grest-ts/testkit-vitest to inject the path.
10
+ */
11
+ static setWorkerLoaderPath(path: string): void;
12
+ constructor(config: GGTestEnvConfig);
13
+ start(): Promise<void>;
14
+ stopRuntime(): Promise<void>;
15
+ shutdown(): Promise<void>;
16
+ }
17
+ //# sourceMappingURL=WorkerRunner.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"WorkerRunner.d.ts","sourceRoot":"","sources":["../../../src/runner/WorkerRunner.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,aAAa,EAAC,MAAM,iBAAiB,CAAC;AAGnD,OAAO,EAAC,eAAe,EAAC,MAAM,kBAAkB,CAAC;AAEjD,qBAAa,YAAa,YAAW,aAAa;IAalC,OAAO,CAAC,QAAQ,CAAC,MAAM;IAZnC,OAAO,CAAC,MAAM,CAAC,CAAS;IAExB,OAAO,CAAC,MAAM,CAAC,gBAAgB,CAAqB;IAEpD;;;OAGG;WACW,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;gBAIxB,MAAM,EAAE,eAAe;IAG9C,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IA2FtB,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC;IAgC5B,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;CAkClC"}
@@ -0,0 +1,155 @@
1
+ import { Worker } from "worker_threads";
2
+ import { GGLog } from "@grest-ts/logger";
3
+ export class WorkerRunner {
4
+ config;
5
+ worker;
6
+ static workerLoaderPath;
7
+ /**
8
+ * Set the path to the worker-loader.mjs file.
9
+ * Called by @grest-ts/testkit-vitest to inject the path.
10
+ */
11
+ static setWorkerLoaderPath(path) {
12
+ this.workerLoaderPath = path;
13
+ }
14
+ constructor(config) {
15
+ this.config = config;
16
+ }
17
+ async start() {
18
+ GGLog.debug(this, 'Starting worker: ' + this.config.executablePath);
19
+ if (!WorkerRunner.workerLoaderPath) {
20
+ throw new Error("Worker loader path not set!\n" +
21
+ "Make sure to import '@grest-ts/testkit-vitest' in your vitest setup.");
22
+ }
23
+ const workerLoaderPath = WorkerRunner.workerLoaderPath;
24
+ this.worker = new Worker(workerLoaderPath, {
25
+ workerData: this.config,
26
+ stdout: true,
27
+ stderr: true
28
+ });
29
+ // Forward worker stdout to parent's console using console.log
30
+ // so vitest can capture and sequence it properly with test output
31
+ this.worker.stdout.on('data', (data) => {
32
+ const str = data.toString();
33
+ // Split by newlines and log each line (trimming trailing newline)
34
+ const lines = str.split('\n');
35
+ for (const line of lines) {
36
+ if (line)
37
+ console.log(line);
38
+ }
39
+ });
40
+ // Forward worker stderr to parent's console
41
+ this.worker.stderr.on('data', (data) => {
42
+ const str = data.toString();
43
+ const lines = str.split('\n');
44
+ for (const line of lines) {
45
+ if (line)
46
+ console.error(line);
47
+ }
48
+ });
49
+ // Wait for worker to signal ready
50
+ try {
51
+ await new Promise((resolve, reject) => {
52
+ if (!this.worker) {
53
+ reject(new Error('Worker failed to start'));
54
+ return;
55
+ }
56
+ const timeout = setTimeout(() => {
57
+ // CRITICAL: Terminate worker on timeout to prevent leak
58
+ this.worker?.terminate();
59
+ reject(new Error('Worker did not start within 10 seconds'));
60
+ }, 10000);
61
+ const messageHandler = (msg) => {
62
+ if (msg.type === 'ready') {
63
+ clearTimeout(timeout);
64
+ this.worker?.off('message', messageHandler);
65
+ // Monitor for unexpected worker exit after successful startup
66
+ this.worker?.on('exit', (code) => {
67
+ GGLog.error(this, `Worker exited unexpectedly with code ${code}`);
68
+ });
69
+ GGLog.debug(this, 'Worker ready');
70
+ resolve();
71
+ }
72
+ else if (msg.type === 'error') {
73
+ clearTimeout(timeout);
74
+ this.worker?.off('message', messageHandler);
75
+ this.worker?.terminate();
76
+ reject(new Error(`Runtime worker startup failed! ${msg.error}`));
77
+ }
78
+ };
79
+ this.worker.on('message', messageHandler);
80
+ this.worker.once('error', (err) => {
81
+ clearTimeout(timeout);
82
+ this.worker?.terminate();
83
+ reject(err);
84
+ });
85
+ this.worker.once('exit', (code) => {
86
+ if (code !== 0) {
87
+ clearTimeout(timeout);
88
+ reject(new Error(`Worker exited with code ${code}`));
89
+ }
90
+ });
91
+ });
92
+ }
93
+ catch (error) {
94
+ // Ensure worker is cleaned up on any error
95
+ this.worker = undefined;
96
+ throw error;
97
+ }
98
+ }
99
+ async stopRuntime() {
100
+ if (!this.worker) {
101
+ return;
102
+ }
103
+ GGLog.debug(this, 'Stopping runtime in worker...');
104
+ return new Promise((resolve, reject) => {
105
+ if (!this.worker) {
106
+ resolve();
107
+ return;
108
+ }
109
+ const timeout = setTimeout(() => {
110
+ GGLog.error(this, 'Timeout waiting for runtime to stop');
111
+ reject(new Error('Timeout waiting for runtime to stop'));
112
+ }, 5000);
113
+ const messageHandler = (msg) => {
114
+ if (msg.type === 'runtimeStopped') {
115
+ clearTimeout(timeout);
116
+ this.worker?.off('message', messageHandler);
117
+ GGLog.debug(this, 'Runtime stopped in worker');
118
+ resolve();
119
+ }
120
+ };
121
+ this.worker.on('message', messageHandler);
122
+ this.worker.postMessage({ type: 'stopRuntime' });
123
+ });
124
+ }
125
+ async shutdown() {
126
+ if (!this.worker) {
127
+ return;
128
+ }
129
+ GGLog.debug(this, 'Shutting down worker...');
130
+ return new Promise((resolve) => {
131
+ if (!this.worker) {
132
+ resolve();
133
+ return;
134
+ }
135
+ this.worker.once('exit', () => {
136
+ clearTimeout(forceTerminateTimeout);
137
+ this.worker = undefined;
138
+ GGLog.debug(this, 'Worker shut down');
139
+ resolve();
140
+ });
141
+ // Send shutdown message for graceful shutdown
142
+ this.worker.postMessage({ type: 'shutdown' });
143
+ // Force terminate after 2 seconds if graceful shutdown doesn't work
144
+ const forceTerminateTimeout = setTimeout(() => {
145
+ if (this.worker) {
146
+ GGLog.debug(this, 'Force terminating worker (timeout)');
147
+ this.worker.terminate();
148
+ this.worker = undefined;
149
+ resolve();
150
+ }
151
+ }, 2000);
152
+ });
153
+ }
154
+ }
155
+ //# sourceMappingURL=WorkerRunner.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"WorkerRunner.js","sourceRoot":"","sources":["../../../src/runner/WorkerRunner.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,91 @@
1
+ /**
2
+ * Isolated process loader for ES modules
3
+ * This file is the entry point for isolated test processes
4
+ *
5
+ * Usage: npx tsx isolated-loader.mjs <runtime-source-url>
6
+ * Environment: GG_ISOLATED_CONFIG must be set with JSON config
7
+ */
8
+ import {register} from 'tsx/esm/api';
9
+ import {pathToFileURL} from 'url';
10
+
11
+ // Register tsx to handle TypeScript with ESM
12
+ register();
13
+
14
+ // Get the runtime source URL from command line args (can be file:// URL or path)
15
+ let runtimeSourceUrl = process.argv[2];
16
+ if (!runtimeSourceUrl) {
17
+ console.error('Usage: npx tsx isolated-loader.mjs <runtime-source-url>');
18
+ process.exit(1);
19
+ }
20
+
21
+ // Convert to file:// URL if it's a path
22
+ if (!runtimeSourceUrl.startsWith('file:')) {
23
+ runtimeSourceUrl = pathToFileURL(runtimeSourceUrl).href;
24
+ }
25
+
26
+ const GG_ISOLATED_CONFIG = "GG_ISOLATED_CONFIG";
27
+ const PROCESS_READY = "IsolatedRunner:READY";
28
+
29
+ // Get config from environment
30
+ const configJson = process.env[GG_ISOLATED_CONFIG];
31
+ if (!configJson) {
32
+ console.error('GG_ISOLATED_CONFIG not set');
33
+ process.exit(1);
34
+ }
35
+
36
+ // Import runtime and testkit dependencies
37
+ const {GGRuntime} = await import('@grest-ts/runtime');
38
+ const {GGTestRuntimeWorker} = await import('@grest-ts/testkit');
39
+ const {GGLog} = await import('@grest-ts/logger');
40
+
41
+ const config = JSON.parse(configJson);
42
+
43
+ // Override cli() to intercept runtime startup in isolated mode
44
+
45
+ GGRuntime.cli = async function(moduleUrl) {
46
+ // Still set SOURCE_MODULE_URL for testkit compatibility
47
+ this.SOURCE_MODULE_URL = moduleUrl;
48
+
49
+ // Start the runtime via test worker instead of normal startup
50
+ const controlClient = new GGTestRuntimeWorker(config);
51
+
52
+ try {
53
+ await controlClient.start(() => new this());
54
+
55
+ // Signal to parent process that we're ready
56
+ console.log(PROCESS_READY);
57
+
58
+ const stopRuntime = async () => {
59
+ // Stop the GGRuntime but keep process alive for log retrieval
60
+ await controlClient.stopRuntime();
61
+ console.log('IsolatedRunner:RUNTIME_STOPPED');
62
+ };
63
+
64
+ const shutdown = async () => {
65
+ // Fully shutdown process
66
+ await controlClient.shutdown();
67
+ process.exit(0);
68
+ };
69
+
70
+ // Listen for commands via stdin
71
+ process.stdin.setEncoding('utf8');
72
+ process.stdin.on('data', (data) => {
73
+ const message = data.toString().trim();
74
+ if (message === 'STOP_RUNTIME') {
75
+ GGLog.debug({name: 'IsolatedLoader'}, 'Received stop runtime command');
76
+ stopRuntime();
77
+ } else if (message === 'SHUTDOWN') {
78
+ GGLog.debug({name: 'IsolatedLoader'}, 'Received shutdown command');
79
+ shutdown();
80
+ }
81
+ });
82
+ process.on('SIGTERM', shutdown);
83
+ process.on('SIGINT', shutdown);
84
+ } catch (err) {
85
+ GGLog.error({name: 'IsolatedLoader'}, 'Failed to start isolated runtime', err);
86
+ process.exit(1);
87
+ }
88
+ };
89
+
90
+ // Import the runtime source - this will call the overridden cli()
91
+ await import(runtimeSourceUrl);
@@ -0,0 +1,49 @@
1
+ /**
2
+ * Worker loader for ES modules
3
+ * This file is loaded by worker threads to execute test runtimes
4
+ *
5
+ * workerData is GGTestEnvConfig: { executablePath, testRouterPort, testId, runtimeId, initialCommands }
6
+ */
7
+ import {register} from 'tsx/esm/api';
8
+ import {parentPort, workerData} from 'worker_threads';
9
+
10
+ // Register tsx to handle TypeScript with ESM
11
+ register();
12
+
13
+ // Catch unhandled errors in worker thread
14
+ process.on('uncaughtException', (err) => {
15
+ console.error(`[WorkerThread ${workerData?.runtimeId}] Uncaught exception:`, err);
16
+ });
17
+ process.on('unhandledRejection', (reason) => {
18
+ console.error(`[WorkerThread ${workerData?.runtimeId}] Unhandled rejection:`, reason);
19
+ });
20
+
21
+ // workerData is GGTestEnvConfig directly
22
+ const config = workerData;
23
+
24
+ // Import control client from @grest-ts/testkit
25
+ const {GGTestRuntimeWorker} = await import('@grest-ts/testkit');
26
+
27
+ // Create control client
28
+ const controlClient = new GGTestRuntimeWorker(config);
29
+
30
+ // Start the runtime
31
+ try {
32
+ await controlClient.start();
33
+ parentPort.postMessage({type: 'ready'});
34
+ } catch (err) {
35
+ parentPort.postMessage({type: 'error', error: err.stack || err.message});
36
+ }
37
+
38
+ // Handle messages from parent
39
+ parentPort.on('message', async (msg) => {
40
+ if (msg.type === 'stopRuntime') {
41
+ // Stop the GGRuntime but keep worker alive for log retrieval
42
+ await controlClient.stopRuntime();
43
+ parentPort.postMessage({type: 'runtimeStopped'});
44
+ } else if (msg.type === 'shutdown') {
45
+ // Fully shutdown worker
46
+ await controlClient.shutdown();
47
+ process.exit(0);
48
+ }
49
+ });
@@ -0,0 +1,71 @@
1
+ import type { GGTestRunner } from "../GGTestRunner";
2
+ import { GGExpectations } from "../utils/GGExpectations";
3
+ import { IGGTestInterceptor } from "./IGGTestInterceptor";
4
+ /**
5
+ * Configuration for creating an interceptor.
6
+ * Used by both mock and spy modes - passThrough determines behavior.
7
+ */
8
+ export interface GGCallInterceptorConfig {
9
+ definedInSourceFile: string;
10
+ sleep: number;
11
+ times: number;
12
+ passThrough: boolean;
13
+ inputExpectations?: GGExpectations<any>;
14
+ outputExpectations?: GGExpectations<any>;
15
+ returnData?: any;
16
+ expectError?: any;
17
+ }
18
+ /**
19
+ * Unified base class for mock/spy interceptors.
20
+ *
21
+ * - Mock mode (passThrough=false): validates input, returns fake data
22
+ * - Spy mode (passThrough=true): validates input, calls through, validates output
23
+ *
24
+ * Transport-specific subclasses provide register/unregister/getKey.
25
+ */
26
+ export declare abstract class GGCallInterceptor implements IGGTestInterceptor {
27
+ protected readonly test: GGTestRunner;
28
+ private readonly definedInSourceFile;
29
+ private readonly _sleep;
30
+ private readonly times;
31
+ readonly passThrough: boolean;
32
+ private readonly inputExpectations?;
33
+ private readonly outputExpectations?;
34
+ private readonly returnData?;
35
+ private noOfTimesCalled;
36
+ private isRegistered;
37
+ private validationError;
38
+ protected constructor(test: GGTestRunner, config: GGCallInterceptorConfig);
39
+ abstract getKey(): string;
40
+ protected abstract doRegister(): void;
41
+ protected abstract doUnregister(): void;
42
+ protected abstract parseResponseData(result: any): any;
43
+ /**
44
+ * Transform request body before checking expectations.
45
+ * Override to extract/transform the input for validation.
46
+ * Default: returns body unchanged.
47
+ */
48
+ protected transformInput(body: any): any;
49
+ register(): void;
50
+ unregister(): void;
51
+ /**
52
+ * Handle incoming request.
53
+ * - Validates input expectations
54
+ * - For mock: returns configured returnData
55
+ * - For spy: returns undefined (signal to pass through)
56
+ */
57
+ onRequest(body: any): Promise<any>;
58
+ /**
59
+ * Handle response (spy mode only).
60
+ * Called after pass-through completes with the real response.
61
+ * Parses response via transport-specific method, then validates.
62
+ */
63
+ onResponse(result: any): Promise<void>;
64
+ validate(): void;
65
+ getMockValidationError(): Error | undefined;
66
+ isCalled(): boolean;
67
+ protected sleepIfNeeded(): Promise<void>;
68
+ protected checkNoOfTimesCalled(): void;
69
+ protected setMockValidationError(originalError: Error, type: string): void;
70
+ }
71
+ //# sourceMappingURL=GGCallInterceptor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"GGCallInterceptor.d.ts","sourceRoot":"","sources":["../../../src/testers/GGCallInterceptor.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,YAAY,EAAC,MAAM,iBAAiB,CAAC;AAClD,OAAO,EAAC,cAAc,EAAC,MAAM,yBAAyB,CAAC;AAIvD,OAAO,EAAC,kBAAkB,EAAC,MAAM,sBAAsB,CAAC;AAExD;;;GAGG;AACH,MAAM,WAAW,uBAAuB;IACpC,mBAAmB,EAAE,MAAM,CAAC;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,OAAO,CAAC;IACrB,iBAAiB,CAAC,EAAE,cAAc,CAAC,GAAG,CAAC,CAAC;IACxC,kBAAkB,CAAC,EAAE,cAAc,CAAC,GAAG,CAAC,CAAC;IACzC,UAAU,CAAC,EAAE,GAAG,CAAC;IACjB,WAAW,CAAC,EAAE,GAAG,CAAC;CACrB;AAED;;;;;;;GAOG;AACH,8BAAsB,iBAAkB,YAAW,kBAAkB;IAEjE,SAAS,CAAC,QAAQ,CAAC,IAAI,EAAE,YAAY,CAAC;IACtC,OAAO,CAAC,QAAQ,CAAC,mBAAmB,CAAS;IAC7C,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;IAChC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAS;IAC/B,SAAgB,WAAW,EAAE,OAAO,CAAC;IACrC,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAAC,CAAsB;IACzD,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAAC,CAAsB;IAC1D,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAM;IAElC,OAAO,CAAC,eAAe,CAAK;IAC5B,OAAO,CAAC,YAAY,CAAS;IAC7B,OAAO,CAAC,eAAe,CAAoB;IAE3C,SAAS,aAAa,IAAI,EAAE,YAAY,EAAE,MAAM,EAAE,uBAAuB;aAwBzD,MAAM,IAAI,MAAM;IAEhC,SAAS,CAAC,QAAQ,CAAC,UAAU,IAAI,IAAI;IAErC,SAAS,CAAC,QAAQ,CAAC,YAAY,IAAI,IAAI;IAEvC,SAAS,CAAC,QAAQ,CAAC,iBAAiB,CAAC,MAAM,EAAE,GAAG,GAAG,GAAG;IAEtD;;;;OAIG;IACH,SAAS,CAAC,cAAc,CAAC,IAAI,EAAE,GAAG,GAAG,GAAG;IAQjC,QAAQ,IAAI,IAAI;IAehB,UAAU,IAAI,IAAI;IAgBzB;;;;;OAKG;IACU,SAAS,CAAC,IAAI,EAAE,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC;IAmB/C;;;;OAIG;IACU,UAAU,CAAC,MAAM,EAAE,GAAG,GAAG,OAAO,CAAC,IAAI,CAAC;IAkB5C,QAAQ,IAAI,IAAI;IAWhB,sBAAsB,IAAI,KAAK,GAAG,SAAS;IAI3C,QAAQ,IAAI,OAAO;cAQV,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC;IAM9C,SAAS,CAAC,oBAAoB,IAAI,IAAI;IAatC,SAAS,CAAC,sBAAsB,CAAC,aAAa,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI;CAY7E"}