@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,159 +0,0 @@
1
- // @ts-nocheck - Jest ESM type inference issues
2
- import { jest } from "@jest/globals";
3
- import * as fs from "fs/promises";
4
- import * as path from "path";
5
- import * as os from "os";
6
- // TestGenerationService transitively loads the @skyramp/skyramp native library
7
- // (blocks 180s waiting for the platform dylib) — stub the base class out.
8
- jest.unstable_mockModule("../../services/TestGenerationService.js", () => ({
9
- TestGenerationService: class {
10
- async generateTest() {
11
- return { content: [{ type: "text", text: "generated" }] };
12
- }
13
- buildBaseGenerationOptions() {
14
- return {};
15
- }
16
- },
17
- }));
18
- jest.unstable_mockModule("../../services/AnalyticsService.js", () => ({
19
- AnalyticsService: {
20
- pushTestGenerationToolEvent: jest.fn().mockResolvedValue(undefined),
21
- },
22
- }));
23
- jest.unstable_mockModule("../../utils/logger.js", () => ({
24
- logger: {
25
- debug: jest.fn(),
26
- info: jest.fn(),
27
- warning: jest.fn(),
28
- error: jest.fn(),
29
- },
30
- }));
31
- const { registerIntegrationTestTool, IntegrationTestService } = await import("./generateIntegrationRestTool.js");
32
- const { setActiveRunStatePath, clearActiveRunStatePath } = await import("../../utils/AnalysisStateManager.js");
33
- const { CandidateSource } = await import("../../types/Recommendation.js");
34
- /** Build a minimal mock McpServer, register the tool, and return the captured handler. */
35
- function captureHandler() {
36
- let capturedHandler;
37
- const mockServer = {
38
- registerTool: jest.fn((_name, _meta, handler) => {
39
- capturedHandler = handler;
40
- }),
41
- };
42
- registerIntegrationTestTool(mockServer);
43
- return capturedHandler;
44
- }
45
- const APPROVED_ITEM = {
46
- candidateId: "orders-workflow-abcd1234",
47
- scenarioName: "orders_workflow",
48
- testType: "integration",
49
- category: "business_rule",
50
- source: CandidateSource.AGENT,
51
- matchKeys: ["name:orders-workflow", "ep:integration:POST:/api/v1/orders"],
52
- };
53
- async function writeStateFile(dir, approvedPlan) {
54
- const stateFile = path.join(dir, "analyze-changes-state.json");
55
- await fs.writeFile(stateFile, JSON.stringify({
56
- existingTests: [],
57
- analysisScope: "current_branch_diff",
58
- newEndpoints: [],
59
- approvedPlan,
60
- metadata: {
61
- sessionId: "test-session",
62
- stateType: "analysis",
63
- createdAt: "2026-01-01T00:00:00.000Z",
64
- updatedAt: "2026-01-01T00:00:00.000Z",
65
- },
66
- }), "utf-8");
67
- return stateFile;
68
- }
69
- const PLAN = {
70
- planId: "plan-int-1",
71
- createdAt: "2026-01-01T00:00:00.000Z",
72
- generate: [APPROVED_ITEM],
73
- additional: [],
74
- demotions: [],
75
- };
76
- describe("skyramp_integration_test_generation — plan guard on scenarioFile mode", () => {
77
- let handler;
78
- let generateSpy;
79
- let tmpDirs = [];
80
- const originalRunnerTemp = process.env.RUNNER_TEMP;
81
- beforeEach(() => {
82
- handler = captureHandler();
83
- generateSpy = jest
84
- .spyOn(IntegrationTestService.prototype, "generateTest")
85
- .mockResolvedValue({ content: [{ type: "text", text: "generated" }] });
86
- });
87
- afterEach(async () => {
88
- generateSpy.mockRestore();
89
- clearActiveRunStatePath();
90
- process.env.RUNNER_TEMP = originalRunnerTemp;
91
- for (const dir of tmpDirs) {
92
- await fs.rm(dir, { recursive: true, force: true });
93
- }
94
- tmpDirs = [];
95
- });
96
- async function mkTmpDir() {
97
- const dir = await fs.mkdtemp(path.join(os.tmpdir(), "integration-guard-test-"));
98
- tmpDirs.push(dir);
99
- return dir;
100
- }
101
- it("allows a scenarioFile whose scenarioName matches an approved GENERATE item", async () => {
102
- const dir = await mkTmpDir();
103
- setActiveRunStatePath(await writeStateFile(dir, PLAN));
104
- const scenarioFile = path.join(dir, "scenario_orders-workflow.json");
105
- await fs.writeFile(scenarioFile, JSON.stringify([{ scenarioName: "orders_workflow", method: "POST" }]), "utf-8");
106
- const result = await handler({ scenarioFile });
107
- expect(result.isError).toBeUndefined();
108
- expect(generateSpy).toHaveBeenCalled();
109
- });
110
- it("rejects (fail closed) when scenarioFile is unreadable and an approved plan is active — no gate bypass", async () => {
111
- const dir = await mkTmpDir();
112
- setActiveRunStatePath(await writeStateFile(dir, PLAN));
113
- const result = await handler({
114
- scenarioFile: path.join(dir, "does-not-exist.json"),
115
- });
116
- expect(result.isError).toBe(true);
117
- expect(result.content[0].text).toContain("plan-int-1");
118
- expect(generateSpy).not.toHaveBeenCalled();
119
- });
120
- it("rejects (fail closed) when scenarioFile parses but carries no scenarioName and an approved plan is active", async () => {
121
- const dir = await mkTmpDir();
122
- setActiveRunStatePath(await writeStateFile(dir, PLAN));
123
- const scenarioFile = path.join(dir, "scenario_nameless.json");
124
- await fs.writeFile(scenarioFile, JSON.stringify([{ method: "POST", path: "/api/v1/orders" }]), "utf-8");
125
- const result = await handler({ scenarioFile });
126
- expect(result.isError).toBe(true);
127
- expect(generateSpy).not.toHaveBeenCalled();
128
- });
129
- it("still allows an unreadable scenarioFile when there is no active run state (standalone back-compat)", async () => {
130
- clearActiveRunStatePath();
131
- delete process.env.RUNNER_TEMP;
132
- const result = await handler({
133
- scenarioFile: "/nonexistent/scenario.json",
134
- });
135
- expect(result.isError).toBeUndefined();
136
- expect(generateSpy).toHaveBeenCalled();
137
- });
138
- // SKYR-3884 — filename fallback for files with no embedded scenarioName.
139
- it("allows a scenario file with no embedded scenarioName when its filename slug matches the plan (files written by MCP <= 0.3.1)", async () => {
140
- const dir = await mkTmpDir();
141
- setActiveRunStatePath(await writeStateFile(dir, PLAN));
142
- // Bare TraceRequest array — exactly what ScenarioGenerationService wrote
143
- // before scenarioName embedding. Identity must come from the file name.
144
- const scenarioFile = path.join(dir, "scenario_orders-workflow.json");
145
- await fs.writeFile(scenarioFile, JSON.stringify([{ Method: "POST", Path: "/api/v1/orders" }]), "utf-8");
146
- const result = await handler({ scenarioFile });
147
- expect(result.isError).toBeUndefined();
148
- expect(generateSpy).toHaveBeenCalled();
149
- });
150
- it("still rejects when neither embedded name nor filename slug matches the plan", async () => {
151
- const dir = await mkTmpDir();
152
- setActiveRunStatePath(await writeStateFile(dir, PLAN));
153
- const scenarioFile = path.join(dir, "scenario_unrelated-flow.json");
154
- await fs.writeFile(scenarioFile, JSON.stringify([{ Method: "POST", Path: "/api/v1/orders" }]), "utf-8");
155
- const result = await handler({ scenarioFile });
156
- expect(result.isError).toBe(true);
157
- expect(generateSpy).not.toHaveBeenCalled();
158
- });
159
- });
@@ -1,169 +0,0 @@
1
- import { z } from "zod";
2
- import { loadTestSchema, numericString } from "./loadTestSchema.js";
3
- describe("generateLoadRestTool schema validation", () => {
4
- describe("numericString helper", () => {
5
- const testSchema = numericString("testParam");
6
- it("should accept empty string", () => {
7
- const result = testSchema.safeParse("");
8
- expect(result.success).toBe(true);
9
- });
10
- it("should accept valid positive integers", () => {
11
- expect(testSchema.safeParse("0").success).toBe(true);
12
- expect(testSchema.safeParse("1").success).toBe(true);
13
- expect(testSchema.safeParse("100").success).toBe(true);
14
- expect(testSchema.safeParse("9999").success).toBe(true);
15
- });
16
- it("should reject decimal numbers", () => {
17
- const result = testSchema.safeParse("1.5");
18
- expect(result.success).toBe(false);
19
- if (!result.success) {
20
- expect(result.error.issues[0].message).toContain("non-negative integer");
21
- }
22
- });
23
- it("should reject negative numbers", () => {
24
- const result = testSchema.safeParse("-1");
25
- expect(result.success).toBe(false);
26
- if (!result.success) {
27
- expect(result.error.issues[0].message).toContain("non-negative integer");
28
- }
29
- });
30
- it("should reject non-numeric strings", () => {
31
- const result = testSchema.safeParse("abc");
32
- expect(result.success).toBe(false);
33
- if (!result.success) {
34
- expect(result.error.issues[0].message).toContain("non-negative integer");
35
- }
36
- });
37
- it("should reject strings with mixed alphanumeric", () => {
38
- const result = testSchema.safeParse("123abc");
39
- expect(result.success).toBe(false);
40
- if (!result.success) {
41
- expect(result.error.issues[0].message).toContain("non-negative integer");
42
- }
43
- });
44
- it("should reject strings with spaces", () => {
45
- const result = testSchema.safeParse("1 0");
46
- expect(result.success).toBe(false);
47
- });
48
- it("should reject floating point notation", () => {
49
- expect(testSchema.safeParse("1e5").success).toBe(false);
50
- expect(testSchema.safeParse("1.0").success).toBe(false);
51
- });
52
- });
53
- describe("loadTestSchema validation", () => {
54
- const schema = z.object(loadTestSchema);
55
- it("should accept valid load parameters", () => {
56
- const result = schema.safeParse({
57
- endpointURL: "https://api.example.com/endpoint",
58
- method: "GET",
59
- language: "python",
60
- framework: "pytest",
61
- outputDir: "/tmp/tests",
62
- prompt: "Generate load test",
63
- loadCount: "1000",
64
- loadDuration: "60",
65
- loadNumThreads: "10",
66
- loadRampupDuration: "30",
67
- loadRampupInterval: "5",
68
- loadTargetRPS: "100",
69
- });
70
- expect(result.success).toBe(true);
71
- });
72
- it("should accept empty load parameters", () => {
73
- const result = schema.safeParse({
74
- endpointURL: "https://api.example.com/endpoint",
75
- method: "POST",
76
- language: "python",
77
- framework: "pytest",
78
- outputDir: "/tmp/tests",
79
- prompt: "Generate load test",
80
- loadCount: "",
81
- loadDuration: "",
82
- loadNumThreads: "",
83
- });
84
- expect(result.success).toBe(true);
85
- });
86
- it("should reject invalid loadDuration (decimal)", () => {
87
- const result = schema.safeParse({
88
- endpointURL: "https://api.example.com/endpoint",
89
- method: "GET",
90
- language: "python",
91
- framework: "pytest",
92
- outputDir: "/tmp/tests",
93
- prompt: "Generate load test",
94
- loadDuration: "5.5",
95
- });
96
- expect(result.success).toBe(false);
97
- if (!result.success) {
98
- expect(result.error.issues[0].message).toContain("non-negative integer");
99
- expect(result.error.issues[0].path).toContain("loadDuration");
100
- }
101
- });
102
- it("should reject invalid loadNumThreads (negative)", () => {
103
- const result = schema.safeParse({
104
- endpointURL: "https://api.example.com/endpoint",
105
- method: "GET",
106
- language: "python",
107
- framework: "pytest",
108
- outputDir: "/tmp/tests",
109
- prompt: "Generate load test",
110
- loadNumThreads: "-5",
111
- });
112
- expect(result.success).toBe(false);
113
- if (!result.success) {
114
- expect(result.error.issues[0].path).toContain("loadNumThreads");
115
- }
116
- });
117
- it("should reject invalid loadTargetRPS (non-numeric)", () => {
118
- const result = schema.safeParse({
119
- endpointURL: "https://api.example.com/endpoint",
120
- method: "GET",
121
- language: "python",
122
- framework: "pytest",
123
- outputDir: "/tmp/tests",
124
- prompt: "Generate load test",
125
- loadTargetRPS: "high",
126
- });
127
- expect(result.success).toBe(false);
128
- if (!result.success) {
129
- expect(result.error.issues[0].path).toContain("loadTargetRPS");
130
- }
131
- });
132
- it("should reject invalid loadCount (alphanumeric)", () => {
133
- const result = schema.safeParse({
134
- endpointURL: "https://api.example.com/endpoint",
135
- method: "GET",
136
- language: "python",
137
- framework: "pytest",
138
- outputDir: "/tmp/tests",
139
- prompt: "Generate load test",
140
- loadCount: "100k",
141
- });
142
- expect(result.success).toBe(false);
143
- });
144
- it("should reject invalid loadRampupDuration (with spaces)", () => {
145
- const result = schema.safeParse({
146
- endpointURL: "https://api.example.com/endpoint",
147
- method: "GET",
148
- language: "python",
149
- framework: "pytest",
150
- outputDir: "/tmp/tests",
151
- prompt: "Generate load test",
152
- loadRampupDuration: "1 0",
153
- });
154
- expect(result.success).toBe(false);
155
- });
156
- it("should reject invalid loadRampupInterval (scientific notation)", () => {
157
- const result = schema.safeParse({
158
- endpointURL: "https://api.example.com/endpoint",
159
- method: "GET",
160
- language: "python",
161
- framework: "pytest",
162
- outputDir: "/tmp/tests",
163
- prompt: "Generate load test",
164
- loadRampupInterval: "1e3",
165
- });
166
- expect(result.success).toBe(false);
167
- });
168
- });
169
- });
@@ -1,32 +0,0 @@
1
- import { z } from "zod";
2
- const { uiTestSchema, UITestService } = await import("./generateUIRestTool.js");
3
- // SKYR-4012: skyramp_ui_test_generation accepts an optional uniqueUIFormInputs list —
4
- // the create-form inputs the agent identified as unique-constrained — so Skyramp
5
- // codegen types a per-run-unique value into them and generated UI tests stay
6
- // re-runnable (the UI analogue of the REST uniqueFields mechanism).
7
- describe("uiTestSchema uniqueUIFormInputs (SKYR-4012)", () => {
8
- const field = z.object({
9
- uniqueUIFormInputs: uiTestSchema.uniqueUIFormInputs,
10
- });
11
- it("accepts an array of non-empty input identifiers", () => {
12
- expect(field.safeParse({ uniqueUIFormInputs: ["Name", "#slug"] }).success).toBe(true);
13
- });
14
- it("is optional (may be omitted)", () => {
15
- expect(field.safeParse({}).success).toBe(true);
16
- });
17
- it("rejects empty-string identifiers", () => {
18
- expect(field.safeParse({ uniqueUIFormInputs: [""] }).success).toBe(false);
19
- });
20
- });
21
- describe("UITestService threads uniqueUIFormInputs to generation options (SKYR-4012)", () => {
22
- it("forwards uniqueUIFormInputs alongside playwrightInput", () => {
23
- const service = new UITestService();
24
- const opts = service.buildGenerationOptions({
25
- playwrightInput: "/tmp/trace.zip",
26
- language: "typescript",
27
- uniqueUIFormInputs: ["Name"],
28
- });
29
- expect(opts.uniqueUIFormInputs).toEqual(["Name"]);
30
- expect(opts.playwrightInput).toBe("/tmp/trace.zip");
31
- });
32
- });
@@ -1 +0,0 @@
1
- export {};
@@ -1,185 +0,0 @@
1
- import * as fs from "fs/promises";
2
- import * as path from "path";
3
- import * as os from "os";
4
- const { guardScenarioApproved, pathFromEndpointURL } = await import("./planGuard.js");
5
- const { setActiveRunStatePath, clearActiveRunStatePath } = await import("../../utils/AnalysisStateManager.js");
6
- const { CandidateSource } = await import("../../types/Recommendation.js");
7
- async function writeStateFile(dir, data) {
8
- const stateFile = path.join(dir, "analyze-changes-state.json");
9
- await fs.writeFile(stateFile, JSON.stringify({
10
- existingTests: [],
11
- analysisScope: "current_branch_diff",
12
- newEndpoints: [],
13
- ...data,
14
- metadata: {
15
- sessionId: "test-session",
16
- stateType: "analysis",
17
- createdAt: "2026-01-01T00:00:00.000Z",
18
- updatedAt: "2026-01-01T00:00:00.000Z",
19
- },
20
- }), "utf-8");
21
- return stateFile;
22
- }
23
- const APPROVED_ITEM = {
24
- candidateId: "orders-workflow-abcd1234",
25
- scenarioName: "orders_workflow",
26
- testType: "integration",
27
- category: "business_rule",
28
- source: CandidateSource.AGENT,
29
- matchKeys: ["name:orders-workflow", "ep:integration:POST:/api/v1/orders"],
30
- };
31
- describe("guardScenarioApproved — SKYR-3879 Path B hard gate", () => {
32
- let tmpDirs = [];
33
- const originalRunnerTemp = process.env.RUNNER_TEMP;
34
- afterEach(async () => {
35
- clearActiveRunStatePath();
36
- process.env.RUNNER_TEMP = originalRunnerTemp;
37
- for (const dir of tmpDirs) {
38
- await fs.rm(dir, { recursive: true, force: true });
39
- }
40
- tmpDirs = [];
41
- });
42
- async function mkTmpDir() {
43
- const dir = await fs.mkdtemp(path.join(os.tmpdir(), "plan-guard-test-"));
44
- tmpDirs.push(dir);
45
- return dir;
46
- }
47
- it("allows (returns null) when there is no active run state at all", async () => {
48
- clearActiveRunStatePath();
49
- delete process.env.RUNNER_TEMP;
50
- const result = await guardScenarioApproved({ scenarioName: "anything" });
51
- expect(result).toBeNull();
52
- });
53
- it("allows when the active run's state has no approvedPlan (standalone / pre-registration back-compat)", async () => {
54
- const dir = await mkTmpDir();
55
- const stateFile = await writeStateFile(dir, {});
56
- setActiveRunStatePath(stateFile);
57
- const result = await guardScenarioApproved({ scenarioName: "orders_workflow", testType: "integration" });
58
- expect(result).toBeNull();
59
- });
60
- it("allows a scenarioName match against an approved GENERATE item", async () => {
61
- const dir = await mkTmpDir();
62
- const stateFile = await writeStateFile(dir, {
63
- approvedPlan: {
64
- planId: "plan-1",
65
- createdAt: "2026-01-01T00:00:00.000Z",
66
- generate: [APPROVED_ITEM],
67
- additional: [],
68
- demotions: [],
69
- },
70
- });
71
- setActiveRunStatePath(stateFile);
72
- const result = await guardScenarioApproved({ scenarioName: "orders_workflow", testType: "integration" });
73
- expect(result).toBeNull();
74
- });
75
- it("allows a testType+method+path match against an approved GENERATE item (contract fallback key)", async () => {
76
- const dir = await mkTmpDir();
77
- const stateFile = await writeStateFile(dir, {
78
- approvedPlan: {
79
- planId: "plan-1",
80
- createdAt: "2026-01-01T00:00:00.000Z",
81
- generate: [APPROVED_ITEM],
82
- additional: [],
83
- demotions: [],
84
- },
85
- });
86
- setActiveRunStatePath(stateFile);
87
- const result = await guardScenarioApproved({ testType: "integration", method: "POST", path: "/api/v1/orders" });
88
- expect(result).toBeNull();
89
- });
90
- it("allows a match against an approved ADDITIONAL item (documented backfill path)", async () => {
91
- const dir = await mkTmpDir();
92
- const stateFile = await writeStateFile(dir, {
93
- approvedPlan: {
94
- planId: "plan-1",
95
- createdAt: "2026-01-01T00:00:00.000Z",
96
- generate: [APPROVED_ITEM],
97
- additional: [
98
- {
99
- ...APPROVED_ITEM,
100
- candidateId: "backfill-efgh5678",
101
- scenarioName: "orders_backfill",
102
- matchKeys: ["name:orders-backfill", "ep:integration:GET:/api/v1/orders"],
103
- },
104
- ],
105
- demotions: [],
106
- },
107
- });
108
- setActiveRunStatePath(stateFile);
109
- const result = await guardScenarioApproved({ scenarioName: "orders_backfill", testType: "integration" });
110
- expect(result).toBeNull();
111
- });
112
- it("rejects an ADDITIONAL match when the GENERATE list is empty — zero-budget plans have nothing to backfill", async () => {
113
- const dir = await mkTmpDir();
114
- const stateFile = await writeStateFile(dir, {
115
- approvedPlan: {
116
- planId: "plan-zero-budget",
117
- createdAt: "2026-01-01T00:00:00.000Z",
118
- generate: [],
119
- additional: [APPROVED_ITEM],
120
- demotions: [],
121
- },
122
- });
123
- setActiveRunStatePath(stateFile);
124
- const result = await guardScenarioApproved({ scenarioName: "orders_workflow", testType: "integration" });
125
- expect(result).not.toBeNull();
126
- expect(result).toContain("plan-zero-budget");
127
- });
128
- it("rejects with the outstanding GENERATE list when nothing matches", async () => {
129
- const dir = await mkTmpDir();
130
- const stateFile = await writeStateFile(dir, {
131
- approvedPlan: {
132
- planId: "plan-1",
133
- createdAt: "2026-01-01T00:00:00.000Z",
134
- generate: [APPROVED_ITEM],
135
- additional: [],
136
- demotions: [],
137
- },
138
- });
139
- setActiveRunStatePath(stateFile);
140
- const result = await guardScenarioApproved({ scenarioName: "unregistered_scenario", testType: "contract" });
141
- expect(result).not.toBeNull();
142
- expect(result).toContain("plan-1");
143
- expect(result).toContain("orders_workflow");
144
- expect(result).toContain("skyramp_register_test_plan");
145
- });
146
- it("falls back to the deterministic RUNNER_TEMP state path for single-repo Testbot runs (no active-run anchor set)", async () => {
147
- const dir = await mkTmpDir();
148
- process.env.RUNNER_TEMP = dir;
149
- const skyrampDir = path.join(dir, "skyramp");
150
- await fs.mkdir(skyrampDir, { recursive: true });
151
- await fs.writeFile(path.join(skyrampDir, "analyze-changes-state.json"), JSON.stringify({
152
- existingTests: [],
153
- analysisScope: "current_branch_diff",
154
- newEndpoints: [],
155
- approvedPlan: {
156
- planId: "ci-plan",
157
- createdAt: "2026-01-01T00:00:00.000Z",
158
- generate: [APPROVED_ITEM],
159
- additional: [],
160
- demotions: [],
161
- },
162
- metadata: {
163
- sessionId: "ci-session",
164
- stateType: "analysis",
165
- createdAt: "2026-01-01T00:00:00.000Z",
166
- updatedAt: "2026-01-01T00:00:00.000Z",
167
- },
168
- }), "utf-8");
169
- clearActiveRunStatePath(); // simulate a single-repo run: never set
170
- const matched = await guardScenarioApproved({ scenarioName: "orders_workflow" });
171
- expect(matched).toBeNull();
172
- const rejected = await guardScenarioApproved({ scenarioName: "something_else" });
173
- expect(rejected).toContain("ci-plan");
174
- });
175
- });
176
- describe("pathFromEndpointURL", () => {
177
- it("preserves {param} placeholders that new URL() percent-encodes (seed-1 gate false-reject regression)", () => {
178
- expect(pathFromEndpointURL("http://localhost:8092/api/circuits/providers/{id}/summary/")).toBe("/api/circuits/providers/{id}/summary/");
179
- });
180
- it("passes through bare paths and rejects non-URL garbage", () => {
181
- expect(pathFromEndpointURL("/api/v1/products/{product_id}")).toBe("/api/v1/products/{product_id}");
182
- expect(pathFromEndpointURL("not a url")).toBeUndefined();
183
- expect(pathFromEndpointURL(undefined)).toBeUndefined();
184
- });
185
- });
@@ -1 +0,0 @@
1
- export {};
@@ -1,100 +0,0 @@
1
- import { lintScenarioChaining } from "./scenarioLint.js";
2
- /**
3
- * Write-side chaining lint (SKYR-3884 follow-through): the Go codegen chains
4
- * FKs/path params by value-matching against PRIOR steps' response bodies.
5
- * These tests pin the lint that catches unchainable or mis-ordered "bait"
6
- * values at scenario-write time instead of letting the generated test silently
7
- * hardcode them.
8
- */
9
- describe("lintScenarioChaining", () => {
10
- const providerCreate = {
11
- method: "POST",
12
- path: "/api/circuits/providers/",
13
- requestBody: JSON.stringify({ name: "Test Provider", slug: "test-provider" }),
14
- responseBody: JSON.stringify({ id: 1, name: "Test Provider", slug: "test-provider" }),
15
- };
16
- const accountCreate = {
17
- method: "POST",
18
- path: "/api/circuits/provider-accounts/",
19
- requestBody: JSON.stringify({ provider: 1, name: "Account-1" }),
20
- responseBody: JSON.stringify({ id: 7, name: "Account-1" }),
21
- };
22
- const summaryGet = {
23
- method: "GET",
24
- path: "/api/circuits/providers/1/summary/",
25
- responseBody: JSON.stringify({ circuit_count: 0 }),
26
- };
27
- it("passes a well-ordered scenario (create → reference by body FK and path param)", () => {
28
- const result = lintScenarioChaining([providerCreate, accountCreate, summaryGet]);
29
- expect(result.errors).toEqual([]);
30
- expect(result.warnings).toEqual([]);
31
- });
32
- it("errors when a step references a value only produced by a LATER step", () => {
33
- const result = lintScenarioChaining([accountCreate, providerCreate, summaryGet]);
34
- expect(result.errors.length).toBeGreaterThan(0);
35
- expect(result.errors.join("\n")).toContain("later step");
36
- expect(result.errors.join("\n")).toContain("provider");
37
- });
38
- it("warns when a path segment value appears in no response at all", () => {
39
- const result = lintScenarioChaining([
40
- providerCreate,
41
- { method: "GET", path: "/api/circuits/providers/999/summary/", responseBody: "{}" },
42
- ]);
43
- expect(result.errors).toEqual([]);
44
- expect(result.warnings.join("\n")).toContain("999");
45
- expect(result.warnings.join("\n")).toContain("hardcode");
46
- });
47
- it("warns when an id-like body field value appears in no response", () => {
48
- const result = lintScenarioChaining([
49
- providerCreate,
50
- {
51
- method: "POST",
52
- path: "/api/circuits/circuits/",
53
- requestBody: JSON.stringify({ provider_id: 555, cid: "CIR-1" }),
54
- responseBody: JSON.stringify({ id: 2 }),
55
- },
56
- ]);
57
- expect(result.errors).toEqual([]);
58
- expect(result.warnings.join("\n")).toContain("provider_id");
59
- expect(result.warnings.join("\n")).toContain("555");
60
- });
61
- it("warns on ambiguous chaining when the same id value is produced by multiple prior steps", () => {
62
- const otherCreateSameId = {
63
- method: "POST",
64
- path: "/api/circuits/circuit-types/",
65
- requestBody: JSON.stringify({ name: "Type-1" }),
66
- responseBody: JSON.stringify({ id: 1, name: "Type-1" }),
67
- };
68
- const result = lintScenarioChaining([providerCreate, otherCreateSameId, accountCreate]);
69
- expect(result.errors).toEqual([]);
70
- expect(result.warnings.join("\n")).toContain("multiple prior steps");
71
- });
72
- it("does not flag ordinary non-FK body values that coincide with response ids", () => {
73
- const result = lintScenarioChaining([
74
- providerCreate,
75
- {
76
- method: "POST",
77
- path: "/api/circuits/circuits/",
78
- requestBody: JSON.stringify({ commit_rate: 1, description: "x" }),
79
- responseBody: JSON.stringify({ id: 3 }),
80
- },
81
- ]);
82
- // "commit_rate" is neither id-like nor resource-affine to /providers/ — ignore.
83
- expect(result.errors).toEqual([]);
84
- expect(result.warnings).toEqual([]);
85
- });
86
- it("treats a value produced only by the SAME step as unchainable (Go requires strictly-prior)", () => {
87
- const result = lintScenarioChaining([
88
- { method: "GET", path: "/api/things/7/", responseBody: JSON.stringify({ id: 7 }) },
89
- ]);
90
- expect(result.errors).toEqual([]);
91
- expect(result.warnings.join("\n")).toContain("7");
92
- });
93
- it("is defensive about malformed steps (non-string path, unparseable bodies)", () => {
94
- const result = lintScenarioChaining([
95
- { method: "GET", path: undefined },
96
- { method: "POST", path: "/x/", requestBody: "not-json", responseBody: "also-not-json" },
97
- ]);
98
- expect(result.errors).toEqual([]);
99
- });
100
- });
@@ -1 +0,0 @@
1
- export {};