@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,113 +0,0 @@
1
- import * as fs from "fs";
2
- import * as os from "os";
3
- import * as path from "path";
4
- import { joinRoutePrefix, resolvePythonMountPrefixes } from "./pythonMountPrefixes.js";
5
- describe("joinRoutePrefix", () => {
6
- it("composes with exactly one slash regardless of surrounding slashes", () => {
7
- expect(joinRoutePrefix("/api", "/recipes")).toBe("/api/recipes");
8
- expect(joinRoutePrefix("/api/", "recipes")).toBe("/api/recipes");
9
- expect(joinRoutePrefix("/api", "recipes/")).toBe("/api/recipes/");
10
- });
11
- it("returns the prefix unchanged for an empty child", () => {
12
- expect(joinRoutePrefix("/api", "")).toBe("/api");
13
- });
14
- it("makes the child absolute for an empty prefix", () => {
15
- expect(joinRoutePrefix("", "/recipes")).toBe("/recipes");
16
- expect(joinRoutePrefix("", "recipes")).toBe("/recipes");
17
- });
18
- });
19
- describe("resolvePythonMountPrefixes", () => {
20
- const tempRepos = [];
21
- afterEach(() => {
22
- for (const repo of tempRepos.splice(0)) {
23
- fs.rmSync(repo, { recursive: true, force: true });
24
- }
25
- });
26
- function makeRepo(files) {
27
- const repo = fs.mkdtempSync(path.join(os.tmpdir(), "py-mount-"));
28
- tempRepos.push(repo);
29
- for (const [rel, content] of Object.entries(files)) {
30
- const full = path.join(repo, rel);
31
- fs.mkdirSync(path.dirname(full), { recursive: true });
32
- fs.writeFileSync(full, content);
33
- }
34
- return repo;
35
- }
36
- it("resolves a relative-import mount chain to the ancestor prefix", () => {
37
- const repo = makeRepo({
38
- "app/__init__.py": `
39
- from fastapi import APIRouter
40
- from . import users
41
-
42
- router = APIRouter(prefix="/api")
43
- router.include_router(users.router)
44
- `,
45
- "app/users.py": `
46
- from fastapi import APIRouter
47
- router = APIRouter(prefix="/users")
48
- @router.get("")
49
- def list_users(): pass
50
- `,
51
- });
52
- const result = resolvePythonMountPrefixes(repo);
53
- // users.router inherits "/api" (aggregator own prefix); its own "/users" is
54
- // applied later by parseFileEndpoints, so it is NOT part of the ancestor.
55
- expect(result.get("app/users.py")?.get("router")).toBe("/api");
56
- // The root aggregator has no ancestor prefix, so it's omitted entirely.
57
- expect(result.get("app/__init__.py")).toBeUndefined();
58
- });
59
- it("resolves a mount prefix given as a module-level string constant", () => {
60
- const repo = makeRepo({
61
- "svc/__init__.py": `
62
- from fastapi import APIRouter
63
- from . import billing
64
-
65
- BILLING = "/billing"
66
- router = APIRouter()
67
- router.include_router(billing.router, prefix=BILLING)
68
- `,
69
- "svc/billing.py": `
70
- from fastapi import APIRouter
71
- router = APIRouter()
72
- @router.get("/invoices")
73
- def invoices(): pass
74
- `,
75
- });
76
- const result = resolvePythonMountPrefixes(repo);
77
- expect(result.get("svc/billing.py")?.get("router")).toBe("/billing");
78
- });
79
- it("fails safe (no ancestor prefix) when the mounted module can't be resolved", () => {
80
- const repo = makeRepo({
81
- "app/main.py": `
82
- from fastapi import FastAPI
83
- from some_external_pkg import router as ext_router
84
-
85
- app = FastAPI()
86
- app.include_router(ext_router, prefix="/api")
87
- `,
88
- });
89
- // The external module isn't in the repo, so the edge is dropped and nothing
90
- // is returned — the scanner then behaves exactly as it does today.
91
- const result = resolvePythonMountPrefixes(repo);
92
- expect(result.size).toBe(0);
93
- });
94
- it("does not loop forever on a mutually-recursive mount cycle", () => {
95
- const repo = makeRepo({
96
- "a.py": `
97
- from fastapi import APIRouter
98
- from b import router as b_router
99
- router = APIRouter(prefix="/a")
100
- router.include_router(b_router)
101
- `,
102
- "b.py": `
103
- from fastapi import APIRouter
104
- from a import router as a_router
105
- router = APIRouter(prefix="/b")
106
- router.include_router(a_router)
107
- `,
108
- });
109
- // Should terminate; the exact prefixes are unimportant, only that it returns.
110
- const result = resolvePythonMountPrefixes(repo);
111
- expect(result).toBeInstanceOf(Map);
112
- });
113
- });
@@ -1 +0,0 @@
1
- export {};
@@ -1,190 +0,0 @@
1
- import * as fs from "fs";
2
- import * as os from "os";
3
- import * as path from "path";
4
- import { scanAllRepoEndpoints, scanRelatedEndpoints } from "./repoScanner.js";
5
- import { classifyEndpointsByChangedFiles } from "./routeParsers.js";
6
- describe("scanAllRepoEndpoints", () => {
7
- const tempRepos = [];
8
- afterEach(() => {
9
- for (const repo of tempRepos.splice(0)) {
10
- fs.rmSync(repo, { recursive: true, force: true });
11
- }
12
- });
13
- function makeTempRepo() {
14
- const repo = fs.mkdtempSync(path.join(os.tmpdir(), "repo-scanner-"));
15
- tempRepos.push(repo);
16
- return repo;
17
- }
18
- it("preserves same router-relative paths from different source files", () => {
19
- const repo = makeTempRepo();
20
- const apiDir = path.join(repo, "src/prefect/server/api");
21
- fs.mkdirSync(apiDir, { recursive: true });
22
- fs.writeFileSync(path.join(apiDir, "flows.py"), `
23
- @router.delete(
24
- "/{id:uuid}",
25
- status_code=204,
26
- )
27
- async def delete_flow(): pass
28
-
29
- @router.post("/bulk_delete")
30
- async def bulk_delete_flows(): pass
31
- `);
32
- fs.writeFileSync(path.join(apiDir, "deployments.py"), `
33
- @router.delete(
34
- "/{id:uuid}",
35
- status_code=204,
36
- )
37
- async def delete_deployment(): pass
38
-
39
- @router.post("/bulk_delete")
40
- async def bulk_delete_deployments(): pass
41
- `);
42
- const endpoints = scanAllRepoEndpoints(repo);
43
- const relatedEndpoints = scanRelatedEndpoints(repo, ["src/prefect/server/api/flows.py"]);
44
- expect(endpoints).toEqual(expect.arrayContaining([
45
- expect.objectContaining({ path: "/{id:uuid}", methods: ["DELETE"], sourceFile: "src/prefect/server/api/flows.py" }),
46
- expect.objectContaining({ path: "/bulk_delete", methods: ["POST"], sourceFile: "src/prefect/server/api/flows.py" }),
47
- expect.objectContaining({ path: "/{id:uuid}", methods: ["DELETE"], sourceFile: "src/prefect/server/api/deployments.py" }),
48
- expect.objectContaining({ path: "/bulk_delete", methods: ["POST"], sourceFile: "src/prefect/server/api/deployments.py" }),
49
- ]));
50
- expect(relatedEndpoints).toEqual(expect.arrayContaining([
51
- expect.objectContaining({ path: "/{id:uuid}", methods: ["DELETE"], sourceFile: "src/prefect/server/api/flows.py" }),
52
- expect.objectContaining({ path: "/bulk_delete", methods: ["POST"], sourceFile: "src/prefect/server/api/flows.py" }),
53
- ]));
54
- const classified = classifyEndpointsByChangedFiles({
55
- currentBranch: "feature/admin-key",
56
- baseBranch: "origin/main",
57
- changedFiles: ["src/prefect/server/api/flows.py"],
58
- diffContent: "",
59
- diffStat: "",
60
- newFiles: [],
61
- deletedFiles: [],
62
- }, endpoints);
63
- expect(classified.changedEndpoints).toEqual(expect.arrayContaining([
64
- expect.objectContaining({ path: "/{id:uuid}", methods: ["DELETE"], sourceFile: "src/prefect/server/api/flows.py" }),
65
- expect.objectContaining({ path: "/bulk_delete", methods: ["POST"], sourceFile: "src/prefect/server/api/flows.py" }),
66
- ]));
67
- expect(classified.changedEndpoints).not.toEqual(expect.arrayContaining([
68
- expect.objectContaining({ path: "/{id:uuid}", methods: ["DELETE"], sourceFile: "src/prefect/server/api/deployments.py" }),
69
- ]));
70
- });
71
- it("does not suppress removed router-relative endpoints with same-path siblings", () => {
72
- const classified = classifyEndpointsByChangedFiles({
73
- currentBranch: "feature/remove-flows",
74
- baseBranch: "origin/main",
75
- changedFiles: ["src/prefect/server/api/flows.py"],
76
- diffContent: "",
77
- diffStat: "",
78
- newFiles: [],
79
- deletedFiles: ["src/prefect/server/api/flows.py"],
80
- }, [
81
- { path: "/{id:uuid}", methods: ["DELETE"], sourceFile: "src/prefect/server/api/deployments.py" },
82
- { path: "/bulk_delete", methods: ["POST"], sourceFile: "src/prefect/server/api/deployments.py" },
83
- ], [
84
- { path: "/{id:uuid}", methods: ["DELETE"], sourceFile: "src/prefect/server/api/flows.py" },
85
- { path: "/bulk_delete", methods: ["POST"], sourceFile: "src/prefect/server/api/flows.py" },
86
- ]);
87
- expect(classified.removedEndpoints).toEqual(expect.arrayContaining([
88
- { path: "/{id:uuid}", methods: ["DELETE"], sourceFile: "src/prefect/server/api/flows.py" },
89
- { path: "/bulk_delete", methods: ["POST"], sourceFile: "src/prefect/server/api/flows.py" },
90
- ]));
91
- });
92
- // FastAPI composes a route's full URL from prefixes applied at include_router()
93
- // mount points that live in *other* files — the single-file parser can't see
94
- // them. Mealie mounts its whole API under a top-level APIRouter(prefix="/api"),
95
- // so a leaf router's own prefix ("/recipes") must be composed with the ancestor
96
- // "/api" or generated tests hit the un-prefixed URL and 405.
97
- it("composes cross-file include_router mount prefixes into FastAPI route paths", () => {
98
- const repo = makeTempRepo();
99
- const routesDir = path.join(repo, "mealie/routes");
100
- const recipeDir = path.join(routesDir, "recipe");
101
- fs.mkdirSync(recipeDir, { recursive: true });
102
- // Top-level app: mounts the API router with no extra prefix.
103
- fs.writeFileSync(path.join(repo, "mealie/app.py"), `
104
- from fastapi import FastAPI
105
- from mealie.routes import router
106
-
107
- app = FastAPI()
108
- app.include_router(router)
109
- `);
110
- // API aggregator: APIRouter(prefix="/api") includes each resource router.
111
- fs.writeFileSync(path.join(routesDir, "__init__.py"), `
112
- from fastapi import APIRouter
113
- from . import recipe
114
-
115
- router = APIRouter(prefix="/api")
116
- router.include_router(recipe.router)
117
- `);
118
- // Recipe aggregator: no own prefix; mounts the CRUD router directly and the
119
- // comments router under a "/recipes" mount prefix drawn from a local const.
120
- fs.writeFileSync(path.join(recipeDir, "__init__.py"), `
121
- from fastapi import APIRouter
122
- from . import recipe_crud_routes, comments
123
-
124
- prefix = "/recipes"
125
-
126
- router = APIRouter()
127
- router.include_router(recipe_crud_routes.router, tags=["Recipe: CRUD"])
128
- router.include_router(comments.router, prefix=prefix, tags=["Recipe: Comments"])
129
- `);
130
- // Leaf CRUD router declared via a custom APIRouter *subclass* with its own
131
- // "/recipes" prefix.
132
- fs.writeFileSync(path.join(recipeDir, "recipe_crud_routes.py"), `
133
- from mealie.routes._base.routers import UserAPIRouter
134
-
135
- router = UserAPIRouter(prefix="/recipes")
136
-
137
- @router.get("")
138
- async def get_all(): pass
139
-
140
- @router.get("/{slug}")
141
- async def get_one(): pass
142
- `);
143
- // Comments router: no own prefix — its "/recipes" comes only from the mount.
144
- fs.writeFileSync(path.join(recipeDir, "comments.py"), `
145
- from fastapi import APIRouter
146
-
147
- router = APIRouter()
148
-
149
- @router.get("/{slug}/comments")
150
- async def get_comments(): pass
151
- `);
152
- const endpoints = scanAllRepoEndpoints(repo);
153
- // CRUD: /api (aggregator) + /recipes (leaf subclass own prefix)
154
- expect(endpoints).toEqual(expect.arrayContaining([
155
- expect.objectContaining({ path: "/api/recipes", methods: ["GET"], sourceFile: "mealie/routes/recipe/recipe_crud_routes.py" }),
156
- expect.objectContaining({ path: "/api/recipes/{slug}", methods: ["GET"], sourceFile: "mealie/routes/recipe/recipe_crud_routes.py" }),
157
- ]));
158
- // Comments: /api (aggregator) + /recipes (mount prefix from a local const) + own path
159
- expect(endpoints).toEqual(expect.arrayContaining([
160
- expect.objectContaining({ path: "/api/recipes/{slug}/comments", methods: ["GET"], sourceFile: "mealie/routes/recipe/comments.py" }),
161
- ]));
162
- // The un-prefixed path must NOT appear (the 405 bug).
163
- expect(endpoints).not.toContainEqual(expect.objectContaining({ path: "/recipes" }));
164
- });
165
- it("composes an app-level include_router(prefix=...) mount", () => {
166
- const repo = makeTempRepo();
167
- const apiDir = path.join(repo, "src/api");
168
- fs.mkdirSync(apiDir, { recursive: true });
169
- // Prefix applied at the app mount point rather than on the APIRouter itself.
170
- fs.writeFileSync(path.join(repo, "src/main.py"), `
171
- from fastapi import FastAPI
172
- from src.api.users import router as users_router
173
-
174
- app = FastAPI()
175
- app.include_router(users_router, prefix="/api/v1")
176
- `);
177
- fs.writeFileSync(path.join(apiDir, "users.py"), `
178
- from fastapi import APIRouter
179
-
180
- router = APIRouter(prefix="/users")
181
-
182
- @router.get("/{id}")
183
- async def get_user(): pass
184
- `);
185
- const endpoints = scanAllRepoEndpoints(repo);
186
- expect(endpoints).toEqual(expect.arrayContaining([
187
- expect.objectContaining({ path: "/api/v1/users/{id}", methods: ["GET"], sourceFile: "src/api/users.py" }),
188
- ]));
189
- });
190
- });
@@ -1 +0,0 @@
1
- export {};
@@ -1,185 +0,0 @@
1
- import { describe, it, expect } from "@jest/globals";
2
- import { execFileSync } from "child_process";
3
- import * as fs from "fs";
4
- import * as os from "os";
5
- import * as path from "path";
6
- import { DriftAction } from "../types/TestAnalysis.js";
7
- import { findUnbackedClaims, listChangedFiles } from "./reportVerification.js";
8
- const REPO = "/repo";
9
- describe("findUnbackedClaims", () => {
10
- it("returns [] when every claim is backed by a working-tree change", () => {
11
- const unbacked = findUnbackedClaims({
12
- repoRoot: REPO,
13
- changedFiles: [
14
- "tests/skyramp/products_contract_test.py",
15
- "dcim/tests/test_filtersets.py",
16
- ],
17
- newTests: [
18
- {
19
- testId: "contract-get-products",
20
- fileName: "products_contract_test.py",
21
- },
22
- ],
23
- verdicts: [
24
- {
25
- action: DriftAction.Update,
26
- testFilePath: "/repo/dcim/tests/test_filtersets.py",
27
- },
28
- ],
29
- });
30
- expect(unbacked).toEqual([]);
31
- });
32
- it("flags a newTestsCreated claim whose file was never created (hallucination)", () => {
33
- const unbacked = findUnbackedClaims({
34
- repoRoot: REPO,
35
- changedFiles: ["tests/skyramp/products_contract_test.py"],
36
- newTests: [
37
- {
38
- testId: "integration-phantom",
39
- fileName: "phantom_integration_test.py",
40
- },
41
- ],
42
- verdicts: [],
43
- });
44
- expect(unbacked).toHaveLength(1);
45
- expect(unbacked[0]).toContain("phantom_integration_test.py");
46
- });
47
- it("flags an UPDATE verdict whose file has no working-tree change (the SKYR-3883 case)", () => {
48
- const unbacked = findUnbackedClaims({
49
- repoRoot: REPO,
50
- changedFiles: ["tests/skyramp/site_filter_integration_test.py"],
51
- newTests: [],
52
- verdicts: [
53
- {
54
- action: DriftAction.Update,
55
- testFilePath: "/repo/dcim/tests/test_filtersets.py",
56
- },
57
- ],
58
- });
59
- expect(unbacked).toHaveLength(1);
60
- expect(unbacked[0]).toContain("test_filtersets.py");
61
- });
62
- it("never flags REGENERATE/DELETE/IGNORE/VERIFY verdicts even when absent from the tree", () => {
63
- // REGENERATE is exempt: external (user-authored) regenerations are report-only
64
- // with no working-tree change, and internal ones may regenerate identically.
65
- const unbacked = findUnbackedClaims({
66
- repoRoot: REPO,
67
- changedFiles: [],
68
- newTests: [],
69
- verdicts: [
70
- {
71
- action: DriftAction.Regenerate,
72
- testFilePath: "/repo/frontend/tests/cart_pom.spec.ts",
73
- },
74
- { action: DriftAction.Delete, testFilePath: "/repo/tests/gone.py" },
75
- { action: DriftAction.Ignore, testFilePath: "/repo/tests/kept.py" },
76
- { action: DriftAction.Verify, testFilePath: "/repo/tests/checked.py" },
77
- ],
78
- });
79
- expect(unbacked).toEqual([]);
80
- });
81
- it("exempts a cross-repo newTest claim (repository differs from the primary)", () => {
82
- const unbacked = findUnbackedClaims({
83
- repoRoot: REPO,
84
- changedFiles: [],
85
- newTests: [
86
- {
87
- testId: "contract-related",
88
- fileName: "related_contract_test.py",
89
- repository: "acme/related-repo",
90
- },
91
- ],
92
- verdicts: [],
93
- primaryRepository: "acme/primary-repo",
94
- });
95
- expect(unbacked).toEqual([]);
96
- });
97
- it("exempts a cross-repo newTest claim even when the primary repo is unknown", () => {
98
- // primaryRepository omitted: we can't confirm the file belongs to this
99
- // checkout, so an explicitly-attributed claim must not be validated here.
100
- const unbacked = findUnbackedClaims({
101
- repoRoot: REPO,
102
- changedFiles: [],
103
- newTests: [
104
- {
105
- testId: "contract-related",
106
- fileName: "related_contract_test.py",
107
- repository: "acme/related-repo",
108
- },
109
- ],
110
- verdicts: [],
111
- });
112
- expect(unbacked).toEqual([]);
113
- });
114
- it("exempts a verdict whose absolute path resolves outside the checkout", () => {
115
- const unbacked = findUnbackedClaims({
116
- repoRoot: REPO,
117
- changedFiles: [],
118
- newTests: [],
119
- verdicts: [
120
- {
121
- action: DriftAction.Update,
122
- testFilePath: "/somewhere/else/outside_test.py",
123
- },
124
- ],
125
- });
126
- expect(unbacked).toEqual([]);
127
- });
128
- it("matches a nested newTest fileName by basename against the changed path", () => {
129
- const backed = findUnbackedClaims({
130
- repoRoot: REPO,
131
- changedFiles: ["tests/skyramp/deep/nested_contract_test.py"],
132
- newTests: [{ testId: "c", fileName: "nested_contract_test.py" }],
133
- verdicts: [],
134
- });
135
- expect(backed).toEqual([]);
136
- });
137
- });
138
- describe("listChangedFiles", () => {
139
- it("lists staged, unstaged, and untracked paths as repo-relative strings", async () => {
140
- const repo = fs.mkdtempSync(path.join(os.tmpdir(), "rv-repo-"));
141
- const git = (args) => execFileSync("git", args, { cwd: repo, stdio: "pipe" });
142
- git(["init", "-q"]);
143
- git(["config", "user.email", "t@t.dev"]);
144
- git(["config", "user.name", "t"]);
145
- // committed baseline
146
- fs.mkdirSync(path.join(repo, "dcim/tests"), { recursive: true });
147
- fs.writeFileSync(path.join(repo, "dcim/tests/test_filtersets.py"), "orig\n");
148
- git(["add", "-A"]);
149
- git(["commit", "-q", "-m", "base"]);
150
- // modify a tracked file (unstaged) + add an untracked file
151
- fs.writeFileSync(path.join(repo, "dcim/tests/test_filtersets.py"), "edited\n");
152
- fs.mkdirSync(path.join(repo, "tests/skyramp"), { recursive: true });
153
- fs.writeFileSync(path.join(repo, "tests/skyramp/new_contract_test.py"), "new\n");
154
- const changed = await listChangedFiles(repo);
155
- expect(changed).toContain("dcim/tests/test_filtersets.py");
156
- expect(changed).toContain("tests/skyramp/new_contract_test.py");
157
- });
158
- it("attributes a renamed file to its destination path and skips the original", async () => {
159
- const repo = fs.mkdtempSync(path.join(os.tmpdir(), "rv-repo-"));
160
- const git = (args) => execFileSync("git", args, { cwd: repo, stdio: "pipe" });
161
- git(["init", "-q"]);
162
- git(["config", "user.email", "t@t.dev"]);
163
- git(["config", "user.name", "t"]);
164
- fs.mkdirSync(path.join(repo, "dcim/tests"), { recursive: true });
165
- fs.writeFileSync(path.join(repo, "dcim/tests/old_test.py"), "def test_x(): pass\n");
166
- git(["add", "-A"]);
167
- git(["commit", "-q", "-m", "base"]);
168
- // Staged rename (identical content → git detects it as R100).
169
- git(["mv", "dcim/tests/old_test.py", "dcim/tests/new_test.py"]);
170
- const changed = await listChangedFiles(repo);
171
- expect(changed).toContain("dcim/tests/new_test.py");
172
- expect(changed).not.toContain("dcim/tests/old_test.py");
173
- });
174
- it("preserves a path containing spaces (NUL-delimited, no quoting)", async () => {
175
- const repo = fs.mkdtempSync(path.join(os.tmpdir(), "rv-repo-"));
176
- const git = (args) => execFileSync("git", args, { cwd: repo, stdio: "pipe" });
177
- git(["init", "-q"]);
178
- git(["config", "user.email", "t@t.dev"]);
179
- git(["config", "user.name", "t"]);
180
- fs.mkdirSync(path.join(repo, "tests/skyramp"), { recursive: true });
181
- fs.writeFileSync(path.join(repo, "tests/skyramp/my new test.py"), "new\n");
182
- const changed = await listChangedFiles(repo);
183
- expect(changed).toContain("tests/skyramp/my new test.py");
184
- });
185
- });
@@ -1 +0,0 @@
1
- export {};