@skyramp/mcp 0.3.2-rc.pom-3 → 0.3.2

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 (289) hide show
  1. package/build/commands/commandLibrary.d.ts +1 -0
  2. package/build/commands/commandLibrary.js +19 -13
  3. package/build/commands/localDevTestChangesCommand.d.ts +15 -0
  4. package/build/commands/localDevTestChangesCommand.js +201 -0
  5. package/build/index.js +80 -6
  6. package/build/prompts/code-reuse.js +3 -0
  7. package/build/prompts/enhance-assertions/sharedAssertionRules.d.ts +1 -0
  8. package/build/prompts/enhance-assertions/sharedAssertionRules.js +17 -0
  9. package/build/prompts/initialize-workspace/initializeWorkspacePrompt.js +11 -9
  10. package/build/prompts/local-dev/local-dev-plan.d.ts +35 -0
  11. package/build/prompts/local-dev/local-dev-plan.js +429 -0
  12. package/build/prompts/local-dev/local-dev-prompts.d.ts +4 -0
  13. package/build/prompts/local-dev/local-dev-prompts.js +190 -0
  14. package/build/prompts/pom-aware-code-reuse.js +12 -0
  15. package/build/prompts/prompt-utils.d.ts +8 -0
  16. package/build/prompts/prompt-utils.js +33 -0
  17. package/build/prompts/sut-setup/modes/adaptWorkflowPrompt.js +37 -14
  18. package/build/prompts/sut-setup/shared.js +16 -12
  19. package/build/prompts/test-recommendation/analysisOutputPrompt.js +21 -29
  20. package/build/prompts/test-recommendation/scopeAssessment.d.ts +24 -7
  21. package/build/prompts/test-recommendation/scopeAssessment.js +111 -12
  22. package/build/prompts/test-recommendation/test-recommendation-prompt.js +41 -4
  23. package/build/prompts/testbot/testbot-prompts.d.ts +0 -5
  24. package/build/prompts/testbot/testbot-prompts.js +32 -52
  25. package/build/recommendation/planRanker.d.ts +15 -2
  26. package/build/recommendation/planRanker.js +76 -5
  27. package/build/resources/testbotResource.js +2 -1
  28. package/build/services/AnalyticsService.d.ts +1 -1
  29. package/build/services/TestExecutionService.d.ts +2 -1
  30. package/build/services/TestExecutionService.js +8 -3
  31. package/build/services/TestGenerationService.d.ts +2 -2
  32. package/build/services/TestGenerationService.js +39 -21
  33. package/build/services/containerEnv.js +3 -1
  34. package/build/tool-phases.js +6 -0
  35. package/build/tools/code-refactor/codeReuseTool.js +43 -4
  36. package/build/tools/code-refactor/enhanceAssertionsTool.js +68 -18
  37. package/build/tools/code-refactor/reuse-outcome.d.ts +109 -0
  38. package/build/tools/code-refactor/reuse-outcome.js +158 -0
  39. package/build/tools/code-refactor/reuse-state.d.ts +45 -0
  40. package/build/tools/code-refactor/reuse-state.js +140 -0
  41. package/build/tools/enrichTestWithMocksTool.d.ts +28 -0
  42. package/build/tools/enrichTestWithMocksTool.js +726 -0
  43. package/build/tools/executeSkyrampTestTool.d.ts +11 -0
  44. package/build/tools/executeSkyrampTestTool.js +62 -21
  45. package/build/tools/generate-tests/batchMockGenerationTool.d.ts +106 -0
  46. package/build/tools/generate-tests/batchMockGenerationTool.js +545 -0
  47. package/build/tools/generate-tests/generateBatchScenarioRestTool.js +25 -23
  48. package/build/tools/generate-tests/generateContractRestTool.js +2 -2
  49. package/build/tools/generate-tests/generateE2ERestTool.d.ts +1 -1
  50. package/build/tools/generate-tests/generateE2ERestTool.js +1 -1
  51. package/build/tools/generate-tests/generateLoadRestTool.d.ts +1 -1
  52. package/build/tools/generate-tests/generateLoadRestTool.js +1 -1
  53. package/build/tools/generate-tests/generateMockRestTool.d.ts +179 -6
  54. package/build/tools/generate-tests/generateMockRestTool.js +391 -22
  55. package/build/tools/generate-tests/loadTestSchema.d.ts +1 -1
  56. package/build/tools/generate-tests/planGuard.js +2 -22
  57. package/build/tools/generateEnrichedIntegrationTestTool.d.ts +25 -0
  58. package/build/tools/generateEnrichedIntegrationTestTool.js +235 -0
  59. package/build/tools/localDevWorkerComposeTool.d.ts +24 -0
  60. package/build/tools/localDevWorkerComposeTool.js +264 -0
  61. package/build/tools/one-click/oneClickTool.d.ts +13 -0
  62. package/build/tools/one-click/oneClickTool.js +195 -24
  63. package/build/tools/preflightMockCheckTool.d.ts +2 -0
  64. package/build/tools/preflightMockCheckTool.js +96 -0
  65. package/build/tools/queryProxyMocksTool.d.ts +70 -0
  66. package/build/tools/queryProxyMocksTool.js +522 -0
  67. package/build/tools/runExistingTestsTool.d.ts +31 -0
  68. package/build/tools/runExistingTestsTool.js +214 -13
  69. package/build/tools/submitReportTool.js +38 -3
  70. package/build/tools/test-management/analyzeChangesTool.d.ts +2 -1
  71. package/build/tools/test-management/analyzeChangesTool.js +63 -40
  72. package/build/tools/test-management/registerTestPlanTool.js +55 -7
  73. package/build/tools/trace/startTraceCollectionTool.js +3 -3
  74. package/build/types/FrontendIntegration.d.ts +3 -0
  75. package/build/types/FrontendIntegration.js +3 -0
  76. package/build/types/OneClickCommands.d.ts +1 -1
  77. package/build/types/Recommendation.d.ts +20 -0
  78. package/build/types/Recommendation.js +32 -6
  79. package/build/types/RepositoryAnalysis.d.ts +131 -14
  80. package/build/types/RepositoryAnalysis.js +16 -2
  81. package/build/types/ReuseOutcome.d.ts +63 -0
  82. package/build/types/ReuseOutcome.js +33 -0
  83. package/build/types/TestExecution.d.ts +1 -0
  84. package/build/types/TestTypes.d.ts +25 -7
  85. package/build/types/TestTypes.js +22 -6
  86. package/build/types/TestbotReport.d.ts +7 -0
  87. package/build/types/index.d.ts +2 -0
  88. package/build/types/index.js +1 -0
  89. package/build/utils/AnalysisStateManager.d.ts +26 -0
  90. package/build/utils/AnalysisStateManager.js +31 -1
  91. package/build/utils/analyze-openapi.js +18 -1
  92. package/build/utils/branchDiff.d.ts +17 -1
  93. package/build/utils/branchDiff.js +99 -14
  94. package/build/utils/featureFlags.d.ts +31 -0
  95. package/build/utils/featureFlags.js +37 -0
  96. package/build/utils/frontendIntegration.js +8 -1
  97. package/build/utils/grpcMockValidation.d.ts +1 -0
  98. package/build/utils/grpcMockValidation.js +49 -0
  99. package/build/utils/httpMethodValidation.d.ts +4 -0
  100. package/build/utils/httpMethodValidation.js +15 -0
  101. package/build/utils/logger.js +1 -1
  102. package/build/utils/mockCompatibility.d.ts +49 -0
  103. package/build/utils/mockCompatibility.js +82 -0
  104. package/build/utils/pom-scope/pom-files.js +7 -0
  105. package/build/utils/pom-verify/bindings.js +11 -1
  106. package/build/utils/pom-verify/re-exports.d.ts +10 -0
  107. package/build/utils/pom-verify/re-exports.js +61 -0
  108. package/build/utils/pom-verify/resolve.d.ts +4 -1
  109. package/build/utils/pom-verify/resolve.js +7 -4
  110. package/build/utils/pom-verify/verify.d.ts +5 -0
  111. package/build/utils/pom-verify/verify.js +25 -3
  112. package/build/utils/progress.js +10 -5
  113. package/build/utils/proxy-terminal.js +3 -3
  114. package/build/utils/routeParsers.d.ts +3 -9
  115. package/build/utils/routeParsers.js +79 -4
  116. package/build/utils/utils.js +2 -2
  117. package/build/utils/versions.d.ts +4 -3
  118. package/build/utils/versions.js +3 -1
  119. package/build/utils/workspaceAuth.d.ts +46 -0
  120. package/build/utils/workspaceAuth.js +156 -1
  121. package/build/workspace/testSuites.d.ts +2 -1
  122. package/build/workspace/testSuites.js +1 -1
  123. package/build/workspace/workspace.d.ts +108 -32
  124. package/build/workspace/workspace.js +32 -4
  125. package/package.json +5 -2
  126. package/build/adapters/jestAdapter.test.d.ts +0 -1
  127. package/build/adapters/jestAdapter.test.js +0 -93
  128. package/build/adapters/mochaAdapter.test.d.ts +0 -1
  129. package/build/adapters/mochaAdapter.test.js +0 -63
  130. package/build/adapters/playwrightAdapter.test.d.ts +0 -1
  131. package/build/adapters/playwrightAdapter.test.js +0 -169
  132. package/build/adapters/pytestAdapter.test.d.ts +0 -1
  133. package/build/adapters/pytestAdapter.test.js +0 -90
  134. package/build/prompts/code-reuse.test.d.ts +0 -1
  135. package/build/prompts/code-reuse.test.js +0 -62
  136. package/build/prompts/pom-aware-code-reuse.test.d.ts +0 -1
  137. package/build/prompts/pom-aware-code-reuse.test.js +0 -11
  138. package/build/prompts/test-maintenance/drift-analysis-prompt.test.d.ts +0 -1
  139. package/build/prompts/test-maintenance/drift-analysis-prompt.test.js +0 -51
  140. package/build/prompts/test-recommendation/analysisOutputPrompt.test.d.ts +0 -1
  141. package/build/prompts/test-recommendation/analysisOutputPrompt.test.js +0 -264
  142. package/build/prompts/test-recommendation/mergeEnrichedScenarios.test.d.ts +0 -1
  143. package/build/prompts/test-recommendation/mergeEnrichedScenarios.test.js +0 -126
  144. package/build/prompts/test-recommendation/promptPlan.test.d.ts +0 -1
  145. package/build/prompts/test-recommendation/promptPlan.test.js +0 -336
  146. package/build/prompts/test-recommendation/scopeAssessment.test.d.ts +0 -1
  147. package/build/prompts/test-recommendation/scopeAssessment.test.js +0 -371
  148. package/build/prompts/test-recommendation/test-recommendation-prompt.test.d.ts +0 -1
  149. package/build/prompts/test-recommendation/test-recommendation-prompt.test.js +0 -1925
  150. package/build/prompts/testbot/testbot-prompts.test.d.ts +0 -1
  151. package/build/prompts/testbot/testbot-prompts.test.js +0 -451
  152. package/build/recommendation/budgeters/diversityBalancedBudgeter.test.d.ts +0 -1
  153. package/build/recommendation/budgeters/diversityBalancedBudgeter.test.js +0 -138
  154. package/build/recommendation/budgeters/fixedNBudgeter.test.d.ts +0 -1
  155. package/build/recommendation/budgeters/fixedNBudgeter.test.js +0 -66
  156. package/build/recommendation/discriminators.test.d.ts +0 -1
  157. package/build/recommendation/discriminators.test.js +0 -324
  158. package/build/recommendation/diversity.test.d.ts +0 -1
  159. package/build/recommendation/diversity.test.js +0 -77
  160. package/build/recommendation/planRanker.test.d.ts +0 -1
  161. package/build/recommendation/planRanker.test.js +0 -110
  162. package/build/resources/testbotResource.test.d.ts +0 -1
  163. package/build/resources/testbotResource.test.js +0 -44
  164. package/build/services/AnalyticsService.test.d.ts +0 -1
  165. package/build/services/AnalyticsService.test.js +0 -86
  166. package/build/services/ScenarioGenerationService.integration.test.d.ts +0 -1
  167. package/build/services/ScenarioGenerationService.integration.test.js +0 -162
  168. package/build/services/ScenarioGenerationService.test.d.ts +0 -1
  169. package/build/services/ScenarioGenerationService.test.js +0 -414
  170. package/build/services/TestDiscoveryService.test.d.ts +0 -1
  171. package/build/services/TestDiscoveryService.test.js +0 -983
  172. package/build/services/TestExecutionService.test.d.ts +0 -1
  173. package/build/services/TestExecutionService.test.js +0 -1032
  174. package/build/services/TestGenerationService.test.d.ts +0 -1
  175. package/build/services/TestGenerationService.test.js +0 -578
  176. package/build/tool-phase-coverage.test.d.ts +0 -1
  177. package/build/tool-phase-coverage.test.js +0 -49
  178. package/build/tools/code-refactor/codeReuseTool.test.d.ts +0 -1
  179. package/build/tools/code-refactor/codeReuseTool.test.js +0 -572
  180. package/build/tools/generate-tests/generateBatchScenarioRestTool.test.d.ts +0 -1
  181. package/build/tools/generate-tests/generateBatchScenarioRestTool.test.js +0 -433
  182. package/build/tools/generate-tests/generateContractRestTool.test.d.ts +0 -1
  183. package/build/tools/generate-tests/generateContractRestTool.test.js +0 -142
  184. package/build/tools/generate-tests/generateIntegrationRestTool.test.d.ts +0 -1
  185. package/build/tools/generate-tests/generateIntegrationRestTool.test.js +0 -159
  186. package/build/tools/generate-tests/generateLoadRestTool.test.d.ts +0 -1
  187. package/build/tools/generate-tests/generateLoadRestTool.test.js +0 -169
  188. package/build/tools/generate-tests/generateUIRestTool.test.d.ts +0 -1
  189. package/build/tools/generate-tests/generateUIRestTool.test.js +0 -32
  190. package/build/tools/generate-tests/planGuard.test.d.ts +0 -1
  191. package/build/tools/generate-tests/planGuard.test.js +0 -185
  192. package/build/tools/generate-tests/scenarioLint.test.d.ts +0 -1
  193. package/build/tools/generate-tests/scenarioLint.test.js +0 -100
  194. package/build/tools/runExistingTestsTool.test.d.ts +0 -1
  195. package/build/tools/runExistingTestsTool.test.js +0 -379
  196. package/build/tools/submitReportTool.test.d.ts +0 -1
  197. package/build/tools/submitReportTool.test.js +0 -1428
  198. package/build/tools/test-management/actionsTool.test.d.ts +0 -1
  199. package/build/tools/test-management/actionsTool.test.js +0 -436
  200. package/build/tools/test-management/analyzeChangesTool.test.d.ts +0 -1
  201. package/build/tools/test-management/analyzeChangesTool.test.js +0 -522
  202. package/build/tools/test-management/analyzeTestHealthTool.test.d.ts +0 -1
  203. package/build/tools/test-management/analyzeTestHealthTool.test.js +0 -385
  204. package/build/tools/test-management/registerTestPlanTool.test.d.ts +0 -1
  205. package/build/tools/test-management/registerTestPlanTool.test.js +0 -296
  206. package/build/tools/trace/resolveSaveStoragePath.test.d.ts +0 -1
  207. package/build/tools/trace/resolveSaveStoragePath.test.js +0 -17
  208. package/build/tools/trace/resolveSessionPaths.test.d.ts +0 -1
  209. package/build/tools/trace/resolveSessionPaths.test.js +0 -104
  210. package/build/tools/trace/sessionState.test.d.ts +0 -1
  211. package/build/tools/trace/sessionState.test.js +0 -17
  212. package/build/tools/workspace/initializeWorkspaceTool.test.d.ts +0 -1
  213. package/build/tools/workspace/initializeWorkspaceTool.test.js +0 -139
  214. package/build/tools/workspace/serviceUpsert.test.d.ts +0 -1
  215. package/build/tools/workspace/serviceUpsert.test.js +0 -50
  216. package/build/utils/AnalysisStateManager.test.d.ts +0 -1
  217. package/build/utils/AnalysisStateManager.test.js +0 -134
  218. package/build/utils/dartRouteExtractor.test.d.ts +0 -1
  219. package/build/utils/dartRouteExtractor.test.js +0 -307
  220. package/build/utils/docker.test.d.ts +0 -1
  221. package/build/utils/docker.test.js +0 -114
  222. package/build/utils/featureFlags.test.d.ts +0 -1
  223. package/build/utils/featureFlags.test.js +0 -81
  224. package/build/utils/fileWalk.test.d.ts +0 -1
  225. package/build/utils/fileWalk.test.js +0 -252
  226. package/build/utils/frontendIntegration.test.d.ts +0 -1
  227. package/build/utils/frontendIntegration.test.js +0 -229
  228. package/build/utils/frontendSelectors.test.d.ts +0 -1
  229. package/build/utils/frontendSelectors.test.js +0 -118
  230. package/build/utils/gitStaging.test.d.ts +0 -1
  231. package/build/utils/gitStaging.test.js +0 -111
  232. package/build/utils/httpDefaults.test.d.ts +0 -1
  233. package/build/utils/httpDefaults.test.js +0 -21
  234. package/build/utils/importerHop.test.d.ts +0 -1
  235. package/build/utils/importerHop.test.js +0 -469
  236. package/build/utils/pathAffinityClassification.test.d.ts +0 -1
  237. package/build/utils/pathAffinityClassification.test.js +0 -208
  238. package/build/utils/planMatchKeys.test.d.ts +0 -1
  239. package/build/utils/planMatchKeys.test.js +0 -123
  240. package/build/utils/pom-scope/index.test.d.ts +0 -1
  241. package/build/utils/pom-scope/index.test.js +0 -278
  242. package/build/utils/pom-scope/pom-files.test.d.ts +0 -1
  243. package/build/utils/pom-scope/pom-files.test.js +0 -29
  244. package/build/utils/pom-scope/scoring.test.d.ts +0 -1
  245. package/build/utils/pom-scope/scoring.test.js +0 -39
  246. package/build/utils/pom-scope/selector-extractor.test.d.ts +0 -1
  247. package/build/utils/pom-scope/selector-extractor.test.js +0 -67
  248. package/build/utils/pom-verify/bindings.test.d.ts +0 -1
  249. package/build/utils/pom-verify/bindings.test.js +0 -164
  250. package/build/utils/pom-verify/calls.test.d.ts +0 -1
  251. package/build/utils/pom-verify/calls.test.js +0 -61
  252. package/build/utils/pom-verify/resolve.test.d.ts +0 -1
  253. package/build/utils/pom-verify/resolve.test.js +0 -114
  254. package/build/utils/pom-verify/verify.test.d.ts +0 -1
  255. package/build/utils/pom-verify/verify.test.js +0 -374
  256. package/build/utils/pr-comment-parser.test.d.ts +0 -1
  257. package/build/utils/pr-comment-parser.test.js +0 -428
  258. package/build/utils/progress.test.d.ts +0 -1
  259. package/build/utils/progress.test.js +0 -37
  260. package/build/utils/projectMetadata.test.d.ts +0 -1
  261. package/build/utils/projectMetadata.test.js +0 -172
  262. package/build/utils/pythonMountPrefixes.test.d.ts +0 -1
  263. package/build/utils/pythonMountPrefixes.test.js +0 -113
  264. package/build/utils/repoScanner.test.d.ts +0 -1
  265. package/build/utils/repoScanner.test.js +0 -190
  266. package/build/utils/reportVerification.test.d.ts +0 -1
  267. package/build/utils/reportVerification.test.js +0 -185
  268. package/build/utils/routeParsers.test.d.ts +0 -1
  269. package/build/utils/routeParsers.test.js +0 -1011
  270. package/build/utils/scenarioDrafting.test.d.ts +0 -1
  271. package/build/utils/scenarioDrafting.test.js +0 -876
  272. package/build/utils/sourceRouteExtractor.test.d.ts +0 -1
  273. package/build/utils/sourceRouteExtractor.test.js +0 -738
  274. package/build/utils/telemetry.test.d.ts +0 -1
  275. package/build/utils/telemetry.test.js +0 -70
  276. package/build/utils/trace-parser.test.d.ts +0 -6
  277. package/build/utils/trace-parser.test.js +0 -140
  278. package/build/utils/uiPageEnumerator.test.d.ts +0 -1
  279. package/build/utils/uiPageEnumerator.test.js +0 -824
  280. package/build/utils/utils.test.d.ts +0 -1
  281. package/build/utils/utils.test.js +0 -103
  282. package/build/utils/walkerCharacterization.test.d.ts +0 -1
  283. package/build/utils/walkerCharacterization.test.js +0 -233
  284. package/build/utils/workspaceAuth.test.d.ts +0 -1
  285. package/build/utils/workspaceAuth.test.js +0 -260
  286. package/build/workspace/testSuites.test.d.ts +0 -1
  287. package/build/workspace/testSuites.test.js +0 -23
  288. package/build/workspace/workspace.test.d.ts +0 -1
  289. package/build/workspace/workspace.test.js +0 -264
@@ -1,86 +0,0 @@
1
- // @ts-nocheck - Jest ESM type inference issues
2
- import { jest } from "@jest/globals";
3
- import * as fs from "fs";
4
- import * as path from "path";
5
- import { fileURLToPath } from "url";
6
- // AnalyticsService resolves the MCP version with
7
- // `fileURLToPath(import.meta.url)` at module scope. Under ts-jest's old
8
- // CommonJS transform that top-level import.meta failed to compile with TS1343,
9
- // so this module — and therefore this test — could not exist. The native-ESM
10
- // Jest config (SKYR-3799) is what makes it loadable.
11
- // pushToolEvent lives in @skyramp/skyramp, which pulls the native dylib. Mock
12
- // it so we can assert on the event payload without loading the binary. Under
13
- // native ESM jest.mock is not hoisted — use unstable_mockModule + dynamic
14
- // import of the subject below.
15
- const pushToolEvent = jest.fn();
16
- jest.unstable_mockModule("@skyramp/skyramp", () => ({ pushToolEvent }));
17
- jest.unstable_mockModule("../utils/telemetry.js", () => ({
18
- getEntryPoint: jest.fn(() => "mcp"),
19
- getCIPlatform: jest.fn(() => undefined),
20
- getRepositoryInfo: jest.fn(async () => ({})),
21
- }));
22
- jest.unstable_mockModule("../utils/logger.js", () => ({
23
- logger: { info: jest.fn(), error: jest.fn(), debug: jest.fn(), warn: jest.fn() },
24
- }));
25
- const { AnalyticsService } = await import("./AnalyticsService.js");
26
- const telemetry = await import("../utils/telemetry.js");
27
- // The version the production code should resolve: package.json two levels up
28
- // from this module's own location — the same lookup getMCPPackageVersion does
29
- // via import.meta.url. Computing it the same way here proves the test harness
30
- // itself supports import.meta now.
31
- const expectedVersion = JSON.parse(fs.readFileSync(path.join(path.dirname(fileURLToPath(import.meta.url)), "../../package.json"), "utf8")).version;
32
- describe("AnalyticsService — import.meta-based version resolution", () => {
33
- beforeEach(() => {
34
- jest.clearAllMocks();
35
- telemetry.getEntryPoint.mockReturnValue("mcp");
36
- telemetry.getCIPlatform.mockReturnValue(undefined);
37
- telemetry.getRepositoryInfo.mockResolvedValue({});
38
- });
39
- it("stamps the package.json version (resolved via import.meta.url) into the event params", async () => {
40
- const params = {};
41
- await AnalyticsService.pushMCPToolEvent("skyramp_smoke_test_generation", undefined, params);
42
- expect(pushToolEvent).toHaveBeenCalledTimes(1);
43
- const [, toolName, , sentParams] = pushToolEvent.mock.calls[0];
44
- expect(toolName).toBe("skyramp_smoke_test_generation");
45
- expect(sentParams.mcpServerVersion).toBe(expectedVersion);
46
- // Sanity: a real semver-ish string, not an empty/undefined fallback.
47
- expect(sentParams.mcpServerVersion).toMatch(/^\d+\.\d+\.\d+/);
48
- });
49
- it("concatenates error text from an isError result into the event error message", async () => {
50
- const result = {
51
- isError: true,
52
- content: [
53
- { type: "text", text: "first failure" },
54
- { type: "text", text: "second failure" },
55
- ],
56
- };
57
- await AnalyticsService.pushMCPToolEvent("skyramp_execute_test", result, {});
58
- const [, , errorMessage] = pushToolEvent.mock.calls[0];
59
- expect(errorMessage).toBe("first failure, second failure");
60
- });
61
- it("sends an empty error message for a successful result", async () => {
62
- const result = { isError: false, content: [{ type: "text", text: "ok" }] };
63
- await AnalyticsService.pushMCPToolEvent("skyramp_execute_test", result, {});
64
- const [, , errorMessage] = pushToolEvent.mock.calls[0];
65
- expect(errorMessage).toBe("");
66
- });
67
- it("includes ciPlatform in the params when running in CI", async () => {
68
- telemetry.getCIPlatform.mockReturnValue("github_actions");
69
- const params = {};
70
- await AnalyticsService.pushMCPToolEvent("skyramp_init_workspace", undefined, params);
71
- const [, , , sentParams] = pushToolEvent.mock.calls[0];
72
- expect(sentParams.ciPlatform).toBe("github_actions");
73
- });
74
- it("merges repository info into the params", async () => {
75
- telemetry.getRepositoryInfo.mockResolvedValue({ repoName: "letsramp/mcp", repoOwner: "letsramp" });
76
- const params = { repositoryPath: "/repo" };
77
- await AnalyticsService.pushMCPToolEvent("skyramp_analyze_changes", undefined, params);
78
- expect(telemetry.getRepositoryInfo).toHaveBeenCalledWith("/repo");
79
- const [, , , sentParams] = pushToolEvent.mock.calls[0];
80
- expect(sentParams.repoName).toBe("letsramp/mcp");
81
- });
82
- it("swallows errors from pushToolEvent (telemetry must never break a tool call)", async () => {
83
- pushToolEvent.mockRejectedValueOnce(new Error("network down"));
84
- await expect(AnalyticsService.pushMCPToolEvent("skyramp_smoke_test_generation", undefined, {})).resolves.toBeUndefined();
85
- });
86
- });
@@ -1,162 +0,0 @@
1
- /**
2
- * Integration test: verifies query params survive the full pipeline
3
- * TS (ScenarioGenerationService) → JSON file → Go binary → generated test code
4
- *
5
- * Requires: @skyramp/skyramp native dylib (skips if not available)
6
- */
7
- import { jest } from "@jest/globals";
8
- import fs from "fs";
9
- import path from "path";
10
- import os from "os";
11
- import { createRequire } from "module";
12
- import { ScenarioGenerationService } from "./ScenarioGenerationService.js";
13
- // Native dylib is a CommonJS addon — load it via createRequire under ESM.
14
- const require = createRequire(import.meta.url);
15
- let SkyrampClient;
16
- try {
17
- SkyrampClient = require("@skyramp/skyramp").SkyrampClient;
18
- }
19
- catch {
20
- SkyrampClient = null;
21
- }
22
- // These tests require the native Go binary which is platform-specific.
23
- // Skip in CI or when the binary isn't available for this OS/arch.
24
- const isCI = Boolean(process.env.CI || process.env.GITHUB_ACTIONS);
25
- const describeIfBinary = SkyrampClient && !isCI ? describe : describe.skip;
26
- function buildTrace(overrides) {
27
- const service = new ScenarioGenerationService();
28
- return service.generateTraceRequestFromInput({
29
- scenarioName: "integration-qp-test",
30
- destination: "localhost",
31
- baseURL: "http://localhost:8080",
32
- method: "GET",
33
- path: "/api/v1/items",
34
- outputDir: os.tmpdir(),
35
- authHeader: "",
36
- authScheme: "",
37
- ...overrides,
38
- });
39
- }
40
- describeIfBinary("QueryParams integration: TS → JSON → Go binary → generated code", () => {
41
- let tmpDir;
42
- let outputDir;
43
- let client;
44
- // Go dylib cold-starts can take a few seconds
45
- jest.setTimeout(15000);
46
- beforeAll(() => {
47
- client = new SkyrampClient();
48
- });
49
- afterAll(() => {
50
- client?.close?.();
51
- });
52
- beforeEach(() => {
53
- tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "skyramp-qp-integration-"));
54
- outputDir = path.join(tmpDir, "output");
55
- fs.mkdirSync(outputDir);
56
- });
57
- afterEach(() => {
58
- fs.rmSync(tmpDir, { recursive: true, force: true });
59
- });
60
- async function generateFromTrace(trace) {
61
- const traceFile = path.join(tmpDir, "scenario.json");
62
- fs.writeFileSync(traceFile, JSON.stringify([trace], null, 2));
63
- await client.generateRestTest({
64
- testType: "integration",
65
- language: "python",
66
- framework: "pytest",
67
- outputDir,
68
- force: true,
69
- traceFilePath: traceFile,
70
- });
71
- const files = fs.readdirSync(outputDir).filter((f) => f.endsWith(".py"));
72
- if (files.length === 0)
73
- throw new Error("No generated test file found");
74
- return fs.readFileSync(path.join(outputDir, files[0]), "utf8");
75
- }
76
- it("bracket-notation keys pass through to generated test code", async () => {
77
- // Simulates: GET /api/v1/items?filter[status][_eq]=published&limit=25
78
- const trace = buildTrace({
79
- queryParams: '{"filter[status][_eq]":"published","limit":25}',
80
- });
81
- expect(trace).not.toBeNull();
82
- expect(trace.QueryParams).toEqual({
83
- "filter[status][_eq]": ["published"],
84
- "limit": ["25"],
85
- });
86
- const code = await generateFromTrace(trace);
87
- expect(code).toContain("filter[status][_eq]");
88
- expect(code).toContain("published");
89
- expect(code).toContain("limit");
90
- expect(code).toContain("25");
91
- });
92
- it("simple flat params pass through to generated test code", async () => {
93
- // Simulates: GET /api/v1/items?page=2&status=active
94
- const trace = buildTrace({
95
- queryParams: '{"page":2,"status":"active"}',
96
- });
97
- expect(trace).not.toBeNull();
98
- expect(trace.QueryParams).toEqual({
99
- page: ["2"],
100
- status: ["active"],
101
- });
102
- const code = await generateFromTrace(trace);
103
- expect(code).toContain("page");
104
- expect(code).toContain("2");
105
- expect(code).toContain("status");
106
- expect(code).toContain("active");
107
- });
108
- it("JSON-encoded string value (Elasticsearch-style) passes through intact", async () => {
109
- // Simulates: GET /search?source={"query":{"match":{"name":"bear"}}}
110
- const trace = buildTrace({
111
- queryParams: '{"source":"{\\"query\\":{\\"match\\":{\\"name\\":\\"bear\\"}}}"}',
112
- });
113
- expect(trace).not.toBeNull();
114
- expect(trace.QueryParams).toEqual({
115
- source: ['{"query":{"match":{"name":"bear"}}}'],
116
- });
117
- const code = await generateFromTrace(trace);
118
- expect(code).toContain("source");
119
- expect(code).toMatch(/query.*match.*name.*bear/);
120
- });
121
- it("array params are comma-joined into a single value in generated code", async () => {
122
- // Simulates: GET /products?tags=sale,new
123
- const trace = buildTrace({
124
- queryParams: '{"tags":["sale","new"]}',
125
- });
126
- expect(trace).not.toBeNull();
127
- expect(trace.QueryParams).toEqual({
128
- tags: ["sale,new"],
129
- });
130
- const code = await generateFromTrace(trace);
131
- expect(code).toContain("tags");
132
- expect(code).toContain("sale,new");
133
- });
134
- it("null params are omitted — not present in generated code", async () => {
135
- // null means "don't include this param" — same as axios/fetch omitting undefined
136
- const trace = buildTrace({
137
- queryParams: '{"limit":10,"cursor":null}',
138
- });
139
- expect(trace).not.toBeNull();
140
- expect(trace.QueryParams).toEqual({
141
- limit: ["10"],
142
- });
143
- const code = await generateFromTrace(trace);
144
- expect(code).toContain("limit");
145
- expect(code).toContain("10");
146
- expect(code).not.toContain("cursor");
147
- });
148
- it("nested object fallback produces valid JSON string in generated code", async () => {
149
- // LLM mistakenly sends nested object — service JSON-stringifies it
150
- const trace = buildTrace({
151
- queryParams: '{"filter":{"status":"active"}}',
152
- });
153
- expect(trace).not.toBeNull();
154
- expect(trace.QueryParams).toEqual({
155
- filter: ['{"status":"active"}'],
156
- });
157
- const code = await generateFromTrace(trace);
158
- expect(code).toContain("filter");
159
- expect(code).not.toContain("[object Object]");
160
- expect(code).not.toContain("map[");
161
- });
162
- });
@@ -1 +0,0 @@
1
- export {};
@@ -1,414 +0,0 @@
1
- import { ScenarioGenerationService } from "./ScenarioGenerationService.js";
2
- import { AUTH_PLACEHOLDER_TOKEN } from "../types/TestTypes.js";
3
- const BASE_PARAMS = {
4
- scenarioName: "test-scenario",
5
- destination: "api.example.com",
6
- method: "GET",
7
- path: "/api/v1/items",
8
- outputDir: "/tmp/skyramp-test",
9
- baseURL: "http://localhost:8000",
10
- };
11
- function generateTrace(overrides = {}) {
12
- const service = new ScenarioGenerationService();
13
- return service["generateTraceRequestFromInput"]({
14
- ...BASE_PARAMS,
15
- ...overrides,
16
- });
17
- }
18
- function getAuthHeaders(trace) {
19
- const { "Content-Type": _, ...rest } = trace.RequestHeaders;
20
- return rest;
21
- }
22
- describe("ScenarioGenerationService — auth header flavors", () => {
23
- // 1. Public API — no auth (explicit empty string)
24
- it("skips auth header when authHeader is empty string", () => {
25
- const trace = generateTrace({ authHeader: "" });
26
- expect(trace).not.toBeNull();
27
- const auth = getAuthHeaders(trace);
28
- expect(auth).toEqual({});
29
- expect(trace.RequestHeaders["Authorization"]).toBeUndefined();
30
- });
31
- // 2. Public API — no auth params at all (undefined)
32
- it("skips auth header when authHeader is undefined", () => {
33
- const trace = generateTrace({ authHeader: undefined });
34
- expect(trace).not.toBeNull();
35
- const auth = getAuthHeaders(trace);
36
- expect(auth).toEqual({});
37
- });
38
- // 3. Bearer token — Authorization with scheme embedded in trace for CLI compatibility
39
- it("generates Authorization: Bearer <token> header in trace", () => {
40
- const trace = generateTrace({
41
- authHeader: "Authorization",
42
- authScheme: "Bearer",
43
- });
44
- expect(trace).not.toBeNull();
45
- expect(trace.RequestHeaders["Authorization"]).toEqual([
46
- `Bearer ${AUTH_PLACEHOLDER_TOKEN}`,
47
- ]);
48
- });
49
- // 4. DRF Token — Authorization with Token scheme embedded in trace
50
- it("generates Authorization: Token <token> header in trace", () => {
51
- const trace = generateTrace({
52
- authHeader: "Authorization",
53
- authScheme: "Token",
54
- });
55
- expect(trace).not.toBeNull();
56
- expect(trace.RequestHeaders["Authorization"]).toEqual([
57
- `Token ${AUTH_PLACEHOLDER_TOKEN}`,
58
- ]);
59
- });
60
- // 5. Basic auth — Authorization with Basic scheme embedded in trace
61
- it("generates Authorization: Basic <token> header in trace", () => {
62
- const trace = generateTrace({
63
- authHeader: "Authorization",
64
- authScheme: "Basic",
65
- });
66
- expect(trace).not.toBeNull();
67
- expect(trace.RequestHeaders["Authorization"]).toEqual([
68
- `Basic ${AUTH_PLACEHOLDER_TOKEN}`,
69
- ]);
70
- });
71
- // 6. Raw token — Authorization with no scheme, placeholder only
72
- it("generates Authorization with raw placeholder when authScheme is empty", () => {
73
- const trace = generateTrace({
74
- authHeader: "Authorization",
75
- authScheme: "",
76
- });
77
- expect(trace).not.toBeNull();
78
- expect(trace.RequestHeaders["Authorization"]).toEqual([
79
- AUTH_PLACEHOLDER_TOKEN,
80
- ]);
81
- });
82
- // 7. X-API-Key header with explicit token
83
- it("includes X-API-Key with explicit token in trace", () => {
84
- const trace = generateTrace({
85
- authHeader: "X-API-Key",
86
- authToken: AUTH_PLACEHOLDER_TOKEN,
87
- });
88
- expect(trace).not.toBeNull();
89
- expect(trace.RequestHeaders["X-API-Key"]).toEqual([
90
- AUTH_PLACEHOLDER_TOKEN,
91
- ]);
92
- expect(trace.RequestHeaders["Authorization"]).toBeUndefined();
93
- });
94
- // 8. Cookie-based auth (e.g. NextAuth)
95
- it("includes Cookie with session token in trace", () => {
96
- const trace = generateTrace({
97
- authHeader: "Cookie",
98
- authToken: `session=${AUTH_PLACEHOLDER_TOKEN}`,
99
- });
100
- expect(trace).not.toBeNull();
101
- expect(trace.RequestHeaders["Cookie"]).toEqual([
102
- `session=${AUTH_PLACEHOLDER_TOKEN}`,
103
- ]);
104
- expect(trace.RequestHeaders["Authorization"]).toBeUndefined();
105
- });
106
- // 9. Custom header (e.g. internal microservice)
107
- it("includes custom auth header with token in trace", () => {
108
- const trace = generateTrace({
109
- authHeader: "X-Internal-Service-Key",
110
- authToken: AUTH_PLACEHOLDER_TOKEN,
111
- });
112
- expect(trace).not.toBeNull();
113
- expect(trace.RequestHeaders["X-Internal-Service-Key"]).toEqual([
114
- AUTH_PLACEHOLDER_TOKEN,
115
- ]);
116
- expect(trace.RequestHeaders["Authorization"]).toBeUndefined();
117
- });
118
- // 10. OAuth — Authorization with OAuth scheme embedded in trace
119
- it("generates Authorization: OAuth <token> header in trace", () => {
120
- const trace = generateTrace({
121
- authHeader: "Authorization",
122
- authScheme: "OAuth",
123
- });
124
- expect(trace).not.toBeNull();
125
- expect(trace.RequestHeaders["Authorization"]).toEqual([
126
- `OAuth ${AUTH_PLACEHOLDER_TOKEN}`,
127
- ]);
128
- });
129
- // 11. Explicit token overrides scheme auto-generation
130
- it("uses explicit authToken and ignores authScheme when both provided", () => {
131
- const trace = generateTrace({
132
- authHeader: "Authorization",
133
- authScheme: "Bearer",
134
- authToken: "my-hardcoded-token-123",
135
- });
136
- expect(trace).not.toBeNull();
137
- expect(trace.RequestHeaders["Authorization"]).toEqual([
138
- "my-hardcoded-token-123",
139
- ]);
140
- });
141
- // 12. Non-Authorization header without token — placeholder in trace (CLI parameterizes it)
142
- it("includes X-API-Key with placeholder when authToken is missing", () => {
143
- const trace = generateTrace({
144
- authHeader: "X-API-Key",
145
- });
146
- expect(trace).not.toBeNull();
147
- expect(trace.RequestHeaders["X-API-Key"]).toEqual([AUTH_PLACEHOLDER_TOKEN]);
148
- });
149
- // 16. Cookie header without explicit token — placeholder in trace (CLI parameterizes it)
150
- it("includes Cookie with placeholder when authToken is missing", () => {
151
- const trace = generateTrace({
152
- authHeader: "Cookie",
153
- });
154
- expect(trace).not.toBeNull();
155
- expect(trace.RequestHeaders["Cookie"]).toEqual([AUTH_PLACEHOLDER_TOKEN]);
156
- });
157
- // 17. Custom header without explicit token — placeholder in trace (CLI parameterizes it)
158
- it("includes custom auth header with placeholder when authToken is missing", () => {
159
- const trace = generateTrace({
160
- authHeader: "X-Internal-Service-Key",
161
- });
162
- expect(trace).not.toBeNull();
163
- expect(trace.RequestHeaders["X-Internal-Service-Key"]).toEqual([AUTH_PLACEHOLDER_TOKEN]);
164
- });
165
- // 13. Content-Type always present regardless of auth
166
- it("always includes Content-Type regardless of auth config", () => {
167
- const noAuth = generateTrace({ authHeader: "" });
168
- const bearer = generateTrace({ authHeader: "Authorization", authScheme: "Bearer" });
169
- const apiKey = generateTrace({ authHeader: "X-API-Key", authToken: "key123" });
170
- expect(noAuth.RequestHeaders["Content-Type"]).toEqual(["application/json"]);
171
- expect(bearer.RequestHeaders["Content-Type"]).toEqual(["application/json"]);
172
- expect(apiKey.RequestHeaders["Content-Type"]).toEqual(["application/json"]);
173
- });
174
- // 14. Firebase AppCheck custom header
175
- it("includes X-Firebase-AppCheck with token in trace", () => {
176
- const trace = generateTrace({
177
- authHeader: "X-Firebase-AppCheck",
178
- authToken: AUTH_PLACEHOLDER_TOKEN,
179
- });
180
- expect(trace).not.toBeNull();
181
- expect(trace.RequestHeaders["X-Firebase-AppCheck"]).toEqual([
182
- AUTH_PLACEHOLDER_TOKEN,
183
- ]);
184
- expect(trace.RequestHeaders["Authorization"]).toBeUndefined();
185
- });
186
- // 15. Proxy-Authorization header with explicit token
187
- it("includes Proxy-Authorization with explicit token in trace", () => {
188
- const trace = generateTrace({
189
- authHeader: "Proxy-Authorization",
190
- authToken: "Bearer proxy-token-abc",
191
- });
192
- expect(trace).not.toBeNull();
193
- expect(trace.RequestHeaders["Proxy-Authorization"]).toEqual([
194
- "Bearer proxy-token-abc",
195
- ]);
196
- expect(trace.RequestHeaders["Authorization"]).toBeUndefined();
197
- });
198
- });
199
- describe("ScenarioGenerationService — queryParams handling", () => {
200
- // --- Primitive values (strings, numbers, booleans) ---
201
- it("coerces string values into single-element arrays", () => {
202
- const trace = generateTrace({ queryParams: '{"status":"active"}' });
203
- expect(trace.QueryParams).toEqual({ status: ["active"] });
204
- });
205
- it("coerces numeric values to string", () => {
206
- const trace = generateTrace({ queryParams: '{"limit":10,"offset":0}' });
207
- expect(trace.QueryParams).toEqual({ limit: ["10"], offset: ["0"] });
208
- });
209
- it("coerces boolean values to string", () => {
210
- const trace = generateTrace({ queryParams: '{"active":true,"deleted":false}' });
211
- expect(trace.QueryParams).toEqual({ active: ["true"], deleted: ["false"] });
212
- });
213
- it("coerces empty string to single-element array", () => {
214
- const trace = generateTrace({ queryParams: '{"q":""}' });
215
- expect(trace.QueryParams).toEqual({ q: [""] });
216
- });
217
- it("passes bracket-notation keys through verbatim (Directus regression)", () => {
218
- // Root cause of the original P0: filter[title][_neq] must reach the Go backend
219
- // as the literal key string, not as a nested object or [object Object].
220
- const trace = generateTrace({
221
- queryParams: '{"filter[status][_eq]":"published","filter[date_created][_gte]":"2024-01-01","limit":25}',
222
- });
223
- expect(trace.QueryParams["filter[status][_eq]"]).toEqual(["published"]);
224
- expect(trace.QueryParams["filter[date_created][_gte]"]).toEqual(["2024-01-01"]);
225
- expect(trace.QueryParams["limit"]).toEqual(["25"]);
226
- });
227
- // --- Null omission ---
228
- it("omits null values entirely (prevents ?status=null in URL)", () => {
229
- // null means "omit this param" — same convention as axios/fetch omitting undefined params
230
- const trace = generateTrace({ queryParams: '{"cursor":null,"limit":20}' });
231
- expect(trace.QueryParams["cursor"]).toBeUndefined();
232
- expect(trace.QueryParams["limit"]).toEqual(["20"]);
233
- });
234
- it("omits all-null object leaving only non-null keys", () => {
235
- const trace = generateTrace({ queryParams: '{"a":null,"b":null,"c":"keep"}' });
236
- expect(trace.QueryParams).toEqual({ c: ["keep"] });
237
- });
238
- // --- Array values: filter nulls, comma-join into single element ---
239
- it("array of strings joins into single comma-separated value", () => {
240
- const trace = generateTrace({ queryParams: '{"tags":["sale","new","featured"]}' });
241
- expect(trace.QueryParams["tags"]).toEqual(["sale,new,featured"]);
242
- });
243
- it("array of mixed primitives coerces each to string then joins", () => {
244
- const trace = generateTrace({ queryParams: '{"ids":[1,2,"three",true,0,false]}' });
245
- expect(trace.QueryParams["ids"]).toEqual(["1,2,three,true,0,false"]);
246
- });
247
- it("array with null items filters nulls before joining", () => {
248
- const trace = generateTrace({ queryParams: '{"tags":[null,"active",null,"pending"]}' });
249
- expect(trace.QueryParams["tags"]).toEqual(["active,pending"]);
250
- });
251
- it("array with all-null items omits the key entirely", () => {
252
- const trace = generateTrace({ queryParams: '{"tags":[null,null],"limit":5}' });
253
- expect(trace.QueryParams["tags"]).toBeUndefined();
254
- expect(trace.QueryParams["limit"]).toEqual(["5"]);
255
- });
256
- it("empty array omits the key (no items after filtering)", () => {
257
- const trace = generateTrace({ queryParams: '{"ids":[],"limit":10}' });
258
- expect(trace.QueryParams["ids"]).toBeUndefined();
259
- expect(trace.QueryParams["limit"]).toEqual(["10"]);
260
- });
261
- it("array containing objects JSON-stringifies each then joins", () => {
262
- const trace = generateTrace({
263
- queryParams: '{"filters":[{"field":"status","value":"active"},{"field":"price","op":"gte","value":"10"}]}',
264
- });
265
- expect(trace.QueryParams["filters"]).toEqual([
266
- '{"field":"status","value":"active"},{"field":"price","op":"gte","value":"10"}',
267
- ]);
268
- });
269
- it("array mixing objects, primitives, and nulls: filters nulls, stringifies objects, joins all", () => {
270
- const trace = generateTrace({
271
- queryParams: '{"mixed":[null,{"nested":true},"plain",42,null]}',
272
- });
273
- expect(trace.QueryParams["mixed"]).toEqual(['{"nested":true},plain,42']);
274
- });
275
- // --- Nested object fallback: JSON.stringify ---
276
- it("nested object is JSON-stringified as fallback", () => {
277
- const trace = generateTrace({
278
- queryParams: '{"filter":{"status":"active","min_price":10}}',
279
- });
280
- expect(trace.QueryParams["filter"]).toEqual(['{"status":"active","min_price":10}']);
281
- });
282
- it("deeply nested object is fully JSON-stringified", () => {
283
- const trace = generateTrace({
284
- queryParams: '{"filter":{"title":{"_neq":"not-a-number"}}}',
285
- });
286
- expect(trace.QueryParams["filter"]).toEqual(['{"title":{"_neq":"not-a-number"}}']);
287
- });
288
- it("empty nested object is JSON-stringified to '{}'", () => {
289
- const trace = generateTrace({ queryParams: '{"filter":{}}' });
290
- expect(trace.QueryParams["filter"]).toEqual(["{}"]);
291
- });
292
- // --- JSON parsing and object validation ---
293
- it("omitted queryParams produces empty QueryParams", () => {
294
- const trace = generateTrace({});
295
- expect(trace.QueryParams).toEqual({});
296
- });
297
- it("invalid JSON produces empty QueryParams without throwing", () => {
298
- const trace = generateTrace({ queryParams: "not-valid-json{" });
299
- expect(trace).not.toBeNull();
300
- expect(trace.QueryParams).toEqual({});
301
- });
302
- it("JSON array (not object) produces empty QueryParams", () => {
303
- const trace = generateTrace({ queryParams: '["limit","10"]' });
304
- expect(trace.QueryParams).toEqual({});
305
- });
306
- it("JSON null produces empty QueryParams", () => {
307
- const trace = generateTrace({ queryParams: "null" });
308
- expect(trace.QueryParams).toEqual({});
309
- });
310
- it("JSON number produces empty QueryParams", () => {
311
- const trace = generateTrace({ queryParams: "42" });
312
- expect(trace.QueryParams).toEqual({});
313
- });
314
- it("JSON string produces empty QueryParams", () => {
315
- const trace = generateTrace({ queryParams: '"just a string"' });
316
- expect(trace.QueryParams).toEqual({});
317
- });
318
- it("empty object produces empty QueryParams", () => {
319
- const trace = generateTrace({ queryParams: '{}' });
320
- expect(trace.QueryParams).toEqual({});
321
- });
322
- // --- Security: PROTO_KEYS guard ---
323
- it("skips __proto__ key to prevent prototype pollution via setter", () => {
324
- const trace = generateTrace({
325
- queryParams: '{"__proto__":{"polluted":true},"limit":10}',
326
- });
327
- expect(Object.hasOwn(trace.QueryParams, "__proto__")).toBe(false);
328
- expect(Object.getPrototypeOf(trace.QueryParams)).toBe(Object.prototype);
329
- expect(trace.QueryParams["limit"]).toEqual(["10"]);
330
- });
331
- it("skips constructor and prototype keys", () => {
332
- const trace = generateTrace({
333
- queryParams: '{"constructor":"pwned","prototype":"evil","valid":"yes"}',
334
- });
335
- expect(Object.hasOwn(trace.QueryParams, "constructor")).toBe(false);
336
- expect(Object.hasOwn(trace.QueryParams, "prototype")).toBe(false);
337
- expect(trace.QueryParams["valid"]).toEqual(["yes"]);
338
- });
339
- });
340
- describe("ScenarioGenerationService — baseURL parsing", () => {
341
- it("parses http baseURL correctly", () => {
342
- const trace = generateTrace({
343
- baseURL: "http://localhost:3000",
344
- authHeader: "",
345
- });
346
- expect(trace).not.toBeNull();
347
- expect(trace.Scheme).toBe("http");
348
- expect(trace.Destination).toBe("localhost");
349
- expect(trace.Port).toBe(3000);
350
- });
351
- it("parses https baseURL with default port", () => {
352
- const trace = generateTrace({
353
- baseURL: "https://api.example.com",
354
- authHeader: "",
355
- });
356
- expect(trace).not.toBeNull();
357
- expect(trace.Scheme).toBe("https");
358
- expect(trace.Destination).toBe("api.example.com");
359
- expect(trace.Port).toBe(443);
360
- });
361
- it("parses http baseURL with default port", () => {
362
- const trace = generateTrace({
363
- baseURL: "http://api.example.com",
364
- authHeader: "",
365
- });
366
- expect(trace).not.toBeNull();
367
- expect(trace.Scheme).toBe("http");
368
- expect(trace.Port).toBe(80);
369
- });
370
- });
371
- describe("ScenarioGenerationService — unique fields (SKYR-3882)", () => {
372
- it("carries uniqueFields onto the trace request", () => {
373
- const trace = generateTrace({ uniqueFields: ["name", "slug"] });
374
- expect(trace).not.toBeNull();
375
- expect(trace.UniqueFields).toEqual(["name", "slug"]);
376
- });
377
- it("omits UniqueFields when none are provided", () => {
378
- const trace = generateTrace({});
379
- expect(trace).not.toBeNull();
380
- expect(trace.UniqueFields).toBeUndefined();
381
- });
382
- });
383
- describe("ScenarioGenerationService — step timestamps (SKYR-3884)", () => {
384
- it("stamps consecutive traces from one instance with strictly increasing timestamps", () => {
385
- // All steps of a batch are generated within the same millisecond, so a bare
386
- // new Date().toISOString() gives every step the identical timestamp. The Go
387
- // codegen treats "earlier timestamp" as "prior step" when chaining FKs and
388
- // path params from create responses — equal stamps break every chain. The
389
- // service owns the invariant, so callers cannot forget to thread an index.
390
- const service = new ScenarioGenerationService();
391
- const traces = [0, 1, 2].map(() => service.generateTraceRequestFromInput(BASE_PARAMS));
392
- for (let i = 1; i < traces.length; i++) {
393
- expect(new Date(traces[i].Timestamp).getTime()).toBeGreaterThan(new Date(traces[i - 1].Timestamp).getTime());
394
- }
395
- });
396
- it("stamps the first trace of a fresh instance at the current time", () => {
397
- const before = Date.now();
398
- const trace = generateTrace({});
399
- const after = Date.now();
400
- const ts = new Date(trace.Timestamp).getTime();
401
- expect(ts).toBeGreaterThanOrEqual(before);
402
- expect(ts).toBeLessThanOrEqual(after);
403
- });
404
- });
405
- describe("ScenarioGenerationService — scenarioName embedding (SKYR-3884)", () => {
406
- it("writes scenarioName into each trace request so the plan guard can identify the file", () => {
407
- // readScenarioNameFromFile (generateIntegrationRestTool) reads
408
- // parsed[0].scenarioName to match the file against the approved plan.
409
- // Without this field every scenarioFile-mode generation is rejected
410
- // fail-closed whenever a plan is active.
411
- const trace = generateTrace({});
412
- expect(trace.scenarioName).toBe("test-scenario");
413
- });
414
- });
@@ -1 +0,0 @@
1
- export {};