@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,252 +0,0 @@
1
- import * as fs from "fs";
2
- import * as os from "os";
3
- import * as path from "path";
4
- import { collectFiles, walkDir, walkSourceFiles } from "./fileWalk.js";
5
- /** Materialize a file tree under a fresh temp dir. Keys are relative paths;
6
- * a value of `null` creates an (empty) directory instead of a file. */
7
- function makeTree(files) {
8
- const root = fs.mkdtempSync(path.join(os.tmpdir(), "filewalk-"));
9
- for (const [rel, content] of Object.entries(files)) {
10
- const abs = path.join(root, rel);
11
- if (content === null) {
12
- fs.mkdirSync(abs, { recursive: true });
13
- }
14
- else {
15
- fs.mkdirSync(path.dirname(abs), { recursive: true });
16
- fs.writeFileSync(abs, content);
17
- }
18
- }
19
- return root;
20
- }
21
- /** Sort + make paths relative to root for stable comparison. */
22
- function rel(root, abs) {
23
- return abs.map((p) => path.relative(root, p).replace(/\\/g, "/")).sort();
24
- }
25
- // `chmod 000` only makes a directory unreadable where the OS enforces the
26
- // permission bits: not on Windows, and not for root (which bypasses them). Skip
27
- // the best-effort-on-unreadable-dir tests where the setup can't actually fail a
28
- // readdir, rather than let them false-fail. `it`/`it.skip` chosen at load time.
29
- const permsEnforced = process.platform !== "win32" &&
30
- (typeof process.getuid !== "function" || process.getuid() !== 0);
31
- const itIfPerms = permsEnforced ? it : it.skip;
32
- /** Collect the absolute file paths a walkDir generator yields. */
33
- function walkPaths(root, opts) {
34
- const seen = [];
35
- for (const [, full] of walkDir(root, opts))
36
- seen.push(full);
37
- return seen;
38
- }
39
- describe("walkDir", () => {
40
- it("yields every file depth-first as [entry, absolute path]", () => {
41
- const root = makeTree({
42
- "a.txt": "a",
43
- "sub/b.txt": "b",
44
- "sub/deep/c.txt": "c",
45
- });
46
- const seen = [];
47
- for (const [entry, full] of walkDir(root)) {
48
- expect(entry.isFile()).toBe(true);
49
- expect(path.isAbsolute(full)).toBe(true);
50
- seen.push(full);
51
- }
52
- expect(rel(root, seen)).toEqual(["a.txt", "sub/b.txt", "sub/deep/c.txt"]);
53
- });
54
- it("yields only files, never directory entries", () => {
55
- const root = makeTree({ "sub/b.txt": "b", emptydir: null });
56
- const names = [...walkDir(root)].map(([entry]) => entry.name);
57
- expect(names).toEqual(["b.txt"]);
58
- });
59
- it("honors maxDepth = 0 (root files only, no descent)", () => {
60
- const root = makeTree({ "a.txt": "a", "sub/b.txt": "b" });
61
- expect(rel(root, walkPaths(root, { maxDepth: 0 }))).toEqual(["a.txt"]);
62
- });
63
- it("honors maxDepth = 1 (root + one level down)", () => {
64
- const root = makeTree({
65
- "a.txt": "a",
66
- "sub/b.txt": "b",
67
- "sub/deep/c.txt": "c",
68
- });
69
- expect(rel(root, walkPaths(root, { maxDepth: 1 }))).toEqual([
70
- "a.txt",
71
- "sub/b.txt",
72
- ]);
73
- });
74
- it("skips directories for which shouldSkipDir returns true", () => {
75
- const root = makeTree({
76
- "keep/a.txt": "a",
77
- "node_modules/x.txt": "x",
78
- });
79
- const out = walkPaths(root, {
80
- shouldSkipDir: (entry) => entry.name === "node_modules",
81
- });
82
- expect(rel(root, out)).toEqual(["keep/a.txt"]);
83
- });
84
- it("passes the directory's absolute path to shouldSkipDir", () => {
85
- const root = makeTree({ "sub/a.txt": "a" });
86
- [
87
- ...walkDir(root, {
88
- shouldSkipDir: (entry, full) => {
89
- expect(path.isAbsolute(full)).toBe(true);
90
- expect(path.basename(full)).toBe(entry.name);
91
- return false;
92
- },
93
- }),
94
- ];
95
- });
96
- it("stops immediately when the consumer breaks (no further reads)", () => {
97
- const root = makeTree({
98
- "1.txt": "",
99
- "2.txt": "",
100
- "3.txt": "",
101
- "sub/4.txt": "",
102
- });
103
- const seen = [];
104
- for (const [, full] of walkDir(root)) {
105
- seen.push(full);
106
- break; // stop after the very first file
107
- }
108
- expect(seen.length).toBe(1);
109
- });
110
- it("yields all files when the consumer never breaks", () => {
111
- const root = makeTree({ "1.txt": "", "2.txt": "" });
112
- expect(walkPaths(root).length).toBe(2);
113
- });
114
- itIfPerms("is best-effort: an unreadable subdirectory is skipped, not fatal", () => {
115
- const root = makeTree({ "a.txt": "a", "bad/b.txt": "b", "c.txt": "c" });
116
- const badDir = path.join(root, "bad");
117
- fs.chmodSync(badDir, 0o000);
118
- try {
119
- // Should not throw despite `bad` being unreadable, and should skip its
120
- // contents while still visiting siblings.
121
- expect(rel(root, walkPaths(root))).toEqual(["a.txt", "c.txt"]);
122
- }
123
- finally {
124
- fs.chmodSync(badDir, 0o755);
125
- }
126
- });
127
- it("does not throw when the root itself is unreadable/missing", () => {
128
- expect(() => walkPaths(path.join(os.tmpdir(), "filewalk-does-not-exist-xyz"))).not.toThrow();
129
- });
130
- });
131
- describe("walkSourceFiles (characterization — existing contract)", () => {
132
- it("collects only files matching one of the extensions, as absolute paths", () => {
133
- const root = makeTree({
134
- "a.ts": "",
135
- "b.tsx": "",
136
- "c.js": "",
137
- "d.py": "",
138
- "sub/e.ts": "",
139
- });
140
- const out = walkSourceFiles(root, {
141
- extensions: [".ts", ".tsx"],
142
- skipDirs: new Set(),
143
- });
144
- expect(out.every((p) => path.isAbsolute(p))).toBe(true);
145
- expect(rel(root, out)).toEqual(["a.ts", "b.tsx", "sub/e.ts"]);
146
- });
147
- it("skips directories named in skipDirs (matched on basename)", () => {
148
- const root = makeTree({
149
- "a.ts": "",
150
- "node_modules/x.ts": "",
151
- "src/b.ts": "",
152
- });
153
- const out = walkSourceFiles(root, {
154
- extensions: [".ts"],
155
- skipDirs: new Set(["node_modules"]),
156
- });
157
- expect(rel(root, out)).toEqual(["a.ts", "src/b.ts"]);
158
- });
159
- it("stops at exactly `limit` files when the cap is hit", () => {
160
- const root = makeTree({
161
- "a.ts": "",
162
- "b.ts": "",
163
- "c.ts": "",
164
- "d.ts": "",
165
- });
166
- const out = walkSourceFiles(root, {
167
- extensions: [".ts"],
168
- skipDirs: new Set(),
169
- limit: 2,
170
- });
171
- expect(out.length).toBe(2);
172
- });
173
- it("returns all matches when under the limit", () => {
174
- const root = makeTree({ "a.ts": "", "b.ts": "" });
175
- const out = walkSourceFiles(root, {
176
- extensions: [".ts"],
177
- skipDirs: new Set(),
178
- limit: 100,
179
- });
180
- expect(out.length).toBe(2);
181
- });
182
- it("does NOT skip dotfile directories by default", () => {
183
- const root = makeTree({ ".hidden/a.ts": "", "b.ts": "" });
184
- const out = walkSourceFiles(root, {
185
- extensions: [".ts"],
186
- skipDirs: new Set(),
187
- });
188
- expect(rel(root, out)).toEqual([".hidden/a.ts", "b.ts"]);
189
- });
190
- itIfPerms("is best-effort on unreadable directories", () => {
191
- const root = makeTree({ "a.ts": "", "bad/b.ts": "" });
192
- const badDir = path.join(root, "bad");
193
- fs.chmodSync(badDir, 0o000);
194
- try {
195
- const out = walkSourceFiles(root, {
196
- extensions: [".ts"],
197
- skipDirs: new Set(),
198
- });
199
- expect(rel(root, out)).toEqual(["a.ts"]);
200
- }
201
- finally {
202
- fs.chmodSync(badDir, 0o755);
203
- }
204
- });
205
- });
206
- describe("collectFiles", () => {
207
- it("collects files matching the predicate as absolute paths", () => {
208
- const root = makeTree({ "a.dart": "", "b.txt": "", "sub/c.dart": "" });
209
- const out = collectFiles(root, {
210
- match: (entry) => entry.name.endsWith(".dart"),
211
- });
212
- expect(out.every((p) => path.isAbsolute(p))).toBe(true);
213
- expect(rel(root, out)).toEqual(["a.dart", "sub/c.dart"]);
214
- });
215
- it("passes the absolute path to the matcher", () => {
216
- const root = makeTree({ "keep/x.ts": "", "modules/y/index.ts": "" });
217
- const out = collectFiles(root, {
218
- match: (_entry, full) => full.includes(`${path.sep}modules${path.sep}`),
219
- });
220
- expect(rel(root, out)).toEqual(["modules/y/index.ts"]);
221
- });
222
- it("returns exactly `limit` files when the cap is hit", () => {
223
- const root = makeTree({ "a.ts": "", "b.ts": "", "c.ts": "" });
224
- const out = collectFiles(root, {
225
- match: (entry) => entry.name.endsWith(".ts"),
226
- limit: 2,
227
- });
228
- expect(out.length).toBe(2);
229
- });
230
- it("returns nothing for `limit: 0` (does not collect a single file)", () => {
231
- const root = makeTree({ "a.ts": "", "b.ts": "" });
232
- const out = collectFiles(root, {
233
- match: () => true,
234
- limit: 0,
235
- });
236
- expect(out).toEqual([]);
237
- });
238
- it("forwards maxDepth and shouldSkipDir to the walk", () => {
239
- const root = makeTree({
240
- "a.ts": "",
241
- "skip/b.ts": "",
242
- "sub/deep/c.ts": "",
243
- });
244
- const out = collectFiles(root, {
245
- match: (entry) => entry.name.endsWith(".ts"),
246
- maxDepth: 1,
247
- shouldSkipDir: (entry) => entry.name === "skip",
248
- });
249
- // maxDepth: 1 excludes sub/deep/c.ts; shouldSkipDir excludes skip/b.ts.
250
- expect(rel(root, out)).toEqual(["a.ts"]);
251
- });
252
- });
@@ -1 +0,0 @@
1
- export {};
@@ -1,229 +0,0 @@
1
- import * as fs from "fs";
2
- import * as os from "os";
3
- import * as path from "path";
4
- import { execFileSync } from "child_process";
5
- import { checkFrontendFileIntegration } from "./frontendIntegration.js";
6
- /** Creates a temp git repo, writes the given files, and stages them so
7
- * `git grep` (which only searches tracked files by default) can find them. */
8
- function makeFixtureRepo(files) {
9
- const dir = fs.mkdtempSync(path.join(os.tmpdir(), "frontend-integration-"));
10
- execFileSync("git", ["init", "-q"], { cwd: dir });
11
- for (const [relPath, content] of Object.entries(files)) {
12
- const abs = path.join(dir, relPath);
13
- fs.mkdirSync(path.dirname(abs), { recursive: true });
14
- fs.writeFileSync(abs, content);
15
- }
16
- execFileSync("git", ["add", "-A"], { cwd: dir });
17
- return dir;
18
- }
19
- /** Same as makeFixtureRepo but NOT a git repo, to exercise the manual-walk
20
- * fallback (`git grep` fails outright when the directory isn't a repo). */
21
- function makeNonGitFixture(files) {
22
- const dir = fs.mkdtempSync(path.join(os.tmpdir(), "frontend-integration-nogit-"));
23
- for (const [relPath, content] of Object.entries(files)) {
24
- const abs = path.join(dir, relPath);
25
- fs.mkdirSync(path.dirname(abs), { recursive: true });
26
- fs.writeFileSync(abs, content);
27
- }
28
- return dir;
29
- }
30
- describe("checkFrontendFileIntegration", () => {
31
- it("marks a component imported by a production file as integrated, listing the importer", () => {
32
- const repo = makeFixtureRepo({
33
- "src/components/Foo.tsx": `export function Foo() { return null; }\n`,
34
- "src/components/Bar.tsx": `import { Foo } from './Foo';\nexport function Bar() { return Foo(); }\n`,
35
- });
36
- const [result] = checkFrontendFileIntegration(repo, ["src/components/Foo.tsx"]);
37
- expect(result.integrated).toBe(true);
38
- expect(result.reason).toBe("imported");
39
- expect(result.importers).toEqual(["src/components/Bar.tsx"]);
40
- });
41
- it("marks a component imported ONLY by test files as unintegrated", () => {
42
- const repo = makeFixtureRepo({
43
- "src/components/Foo.tsx": `export function Foo() { return null; }\n`,
44
- "src/components/Foo.test.tsx": `import { Foo } from './Foo';\ntest('renders', () => Foo());\n`,
45
- "src/components/__tests__/Foo.spec.tsx": `import { Foo } from './Foo';\n`,
46
- });
47
- const [result] = checkFrontendFileIntegration(repo, ["src/components/Foo.tsx"]);
48
- expect(result.integrated).toBe(false);
49
- expect(result.reason).toBe("no-importers");
50
- expect(result.importers).toEqual([]);
51
- });
52
- it("short-circuits route/entrypoint files as integrated without grepping", () => {
53
- const repo = makeFixtureRepo({
54
- "src/pages/Dashboard.tsx": `export default function Dashboard() { return null; }\n`,
55
- });
56
- const [result] = checkFrontendFileIntegration(repo, ["src/pages/Dashboard.tsx"]);
57
- expect(result).toEqual({
58
- file: "src/pages/Dashboard.tsx",
59
- integrated: true,
60
- importers: [],
61
- reason: "route-or-entrypoint",
62
- });
63
- });
64
- it("counts a re-export barrel as an importer", () => {
65
- const repo = makeFixtureRepo({
66
- "src/components/Foo.tsx": `export function Foo() { return null; }\n`,
67
- "src/components/index.ts": `export { Foo } from './Foo';\n`,
68
- });
69
- const [result] = checkFrontendFileIntegration(repo, ["src/components/Foo.tsx"]);
70
- expect(result.integrated).toBe(true);
71
- expect(result.importers).toEqual(["src/components/index.ts"]);
72
- });
73
- it("counts an oversized single-line bundle referencing the module path as an importer, unread", () => {
74
- // A minified >512KB one-line file. Node never opens candidates — git
75
- // grep -l only returns the path — so file size cannot cause a large
76
- // allocation or blow the subprocess buffer.
77
- const hugeBundle = `var m=require("./components/Foo");` + "a".repeat(600 * 1024);
78
- const repo = makeFixtureRepo({
79
- "src/components/Foo.tsx": `export function Foo() { return null; }\n`,
80
- "src/vendor/bundle.js": hugeBundle,
81
- });
82
- const [result] = checkFrontendFileIntegration(repo, ["src/components/Foo.tsx"]);
83
- expect(result.integrated).toBe(true);
84
- expect(result.importers).toEqual(["src/vendor/bundle.js"]);
85
- });
86
- it("resolves importers of an oversized changed file (the changed file is never read)", () => {
87
- const hugeComponent = `export function Foo() { return null; }\n// ` + "b".repeat(600 * 1024) + `\n`;
88
- const repo = makeFixtureRepo({
89
- "src/components/Foo.tsx": hugeComponent,
90
- "src/components/Bar.tsx": `import Foo from './Foo';\nexport function Bar() { return Foo(); }\n`,
91
- });
92
- const [result] = checkFrontendFileIntegration(repo, ["src/components/Foo.tsx"]);
93
- expect(result.integrated).toBe(true);
94
- expect(result.reason).toBe("imported");
95
- expect(result.importers).toEqual(["src/components/Bar.tsx"]);
96
- });
97
- it("catches multiline imports (the from-line carries the path signature)", () => {
98
- const repo = makeFixtureRepo({
99
- "src/components/Foo.tsx": `export function Foo() { return null; }\n`,
100
- "src/components/Bar.tsx": `import {\n Foo,\n} from "./Foo";\nexport function Bar() { return Foo(); }\n`,
101
- });
102
- const [result] = checkFrontendFileIntegration(repo, ["src/components/Foo.tsx"]);
103
- expect(result.integrated).toBe(true);
104
- expect(result.importers).toEqual(["src/components/Bar.tsx"]);
105
- });
106
- it("does not count bare-name mentions (comments, strings) as importers", () => {
107
- // The precision property of the path-signature design: a dead component
108
- // whose NAME appears in prose elsewhere must still read as unintegrated.
109
- const repo = makeFixtureRepo({
110
- "src/components/Foo.tsx": `export function Foo() { return null; }\n`,
111
- "src/components/Other.tsx": `// TODO: consolidate with Foo someday\nconst label = "Foo";\nexport function Other() { return label; }\n`,
112
- });
113
- const [result] = checkFrontendFileIntegration(repo, ["src/components/Foo.tsx"]);
114
- expect(result.integrated).toBe(false);
115
- expect(result.reason).toBe("no-importers");
116
- expect(result.importers).toEqual([]);
117
- });
118
- it("does not short-circuit components under a generic top-level app/ monorepo dir", () => {
119
- // Regression: appsmith's repo root is `app/` — matching it as a framework
120
- // route dir made the check inert for the whole repo (eval 28618761653).
121
- const repo = makeFixtureRepo({
122
- "app/client/src/components/Orphan.tsx": `export function Orphan() { return null; }\n`,
123
- });
124
- const [result] = checkFrontendFileIntegration(repo, ["app/client/src/components/Orphan.tsx"]);
125
- expect(result.integrated).toBe(false);
126
- expect(result.reason).toBe("no-importers");
127
- });
128
- it("still short-circuits Next.js App Router route files via their basenames", () => {
129
- const repo = makeFixtureRepo({
130
- "src/app/dashboard/page.tsx": `export default function Dashboard() { return null; }\n`,
131
- });
132
- const [result] = checkFrontendFileIntegration(repo, ["src/app/dashboard/page.tsx"]);
133
- expect(result.integrated).toBe(true);
134
- expect(result.reason).toBe("route-or-entrypoint");
135
- });
136
- it("fails open (scan-error, integrated: true) when the changed file does not exist on disk", () => {
137
- const repo = makeFixtureRepo({
138
- "src/components/Bar.tsx": `export function Bar() { return null; }\n`,
139
- });
140
- const [result] = checkFrontendFileIntegration(repo, ["src/components/Deleted.tsx"]);
141
- expect(result).toEqual({
142
- file: "src/components/Deleted.tsx",
143
- integrated: true,
144
- importers: [],
145
- reason: "scan-error",
146
- });
147
- });
148
- it("finds an importer of a .d.ts declaration file", () => {
149
- // Regression: path.extname("Foo.d.ts") is ".ts", so a naive basename/ext
150
- // split would build a signature for "Foo.d" instead of "Foo" and never
151
- // match a real `from "./Foo"` import.
152
- const repo = makeFixtureRepo({
153
- "src/components/Foo.d.ts": `export declare function Foo(): null;\n`,
154
- "src/components/Bar.tsx": `import { Foo } from './Foo';\nexport function Bar() { return Foo(); }\n`,
155
- });
156
- const [result] = checkFrontendFileIntegration(repo, ["src/components/Foo.d.ts"]);
157
- expect(result.integrated).toBe(true);
158
- expect(result.reason).toBe("imported");
159
- expect(result.importers).toEqual(["src/components/Bar.tsx"]);
160
- });
161
- describe("basename short-circuit precision", () => {
162
- it("does NOT short-circuit a folder-per-component index.tsx as a route/entrypoint", () => {
163
- // Regression: matching "index"/"main"/"app" basenames anywhere in the
164
- // tree (not just at the root or src/) would short-circuit the common
165
- // React folder-per-component convention (Button/index.tsx) as always
166
- // integrated, defeating the check for exactly the files it targets.
167
- const repo = makeFixtureRepo({
168
- "src/components/Button/index.tsx": `export function Button() { return null; }\n`,
169
- });
170
- const [result] = checkFrontendFileIntegration(repo, ["src/components/Button/index.tsx"]);
171
- expect(result.integrated).toBe(false);
172
- expect(result.reason).toBe("no-importers");
173
- });
174
- it("still short-circuits a root-level src/index.tsx entrypoint", () => {
175
- const repo = makeFixtureRepo({
176
- "src/index.tsx": `export default function App() { return null; }\n`,
177
- });
178
- const [result] = checkFrontendFileIntegration(repo, ["src/index.tsx"]);
179
- expect(result).toEqual({
180
- file: "src/index.tsx",
181
- integrated: true,
182
- importers: [],
183
- reason: "route-or-entrypoint",
184
- });
185
- });
186
- it("does NOT short-circuit a page.tsx outside an app/ segment", () => {
187
- // "page"/"layout" are App Router-specific; outside an app/ segment they
188
- // are ordinary component filenames with no framework meaning.
189
- const repo = makeFixtureRepo({
190
- "src/components/page.tsx": `export function Page() { return null; }\n`,
191
- });
192
- const [result] = checkFrontendFileIntegration(repo, ["src/components/page.tsx"]);
193
- expect(result.integrated).toBe(false);
194
- expect(result.reason).toBe("no-importers");
195
- });
196
- });
197
- describe("manual-walk fallback (non-git repos)", () => {
198
- it("falls back to a manual walk and finds an importer when the directory isn't a git repo", () => {
199
- const repo = makeNonGitFixture({
200
- "src/components/Foo.tsx": `export function Foo() { return null; }\n`,
201
- "src/components/Bar.tsx": `import { Foo } from './Foo';\nexport function Bar() { return Foo(); }\n`,
202
- });
203
- const [result] = checkFrontendFileIntegration(repo, ["src/components/Foo.tsx"]);
204
- expect(result.integrated).toBe(true);
205
- expect(result.reason).toBe("imported");
206
- expect(result.importers).toEqual(["src/components/Bar.tsx"]);
207
- });
208
- it("fails open (scan-error) when the fallback walk is truncated before finding an importer", () => {
209
- // Regression: the module doc promises fail-open on any scan error/
210
- // uncertainty, but a truncated manual walk used to just return its
211
- // partial (empty) result set, reporting a confident "no-importers"
212
- // even though an importer could exist past the file cap.
213
- const files = {
214
- "src/components/Foo.tsx": `export function Foo() { return null; }\n`,
215
- };
216
- for (let i = 0; i < 3005; i++) {
217
- files[`src/generated/File${i}.tsx`] = `export const noop${i} = 0;\n`;
218
- }
219
- const repo = makeNonGitFixture(files);
220
- const [result] = checkFrontendFileIntegration(repo, ["src/components/Foo.tsx"]);
221
- expect(result).toEqual({
222
- file: "src/components/Foo.tsx",
223
- integrated: true,
224
- importers: [],
225
- reason: "scan-error",
226
- });
227
- });
228
- });
229
- });
@@ -1 +0,0 @@
1
- export {};
@@ -1,118 +0,0 @@
1
- import { describe, it, expect } from "@jest/globals";
2
- import { extractChangedSelectors } from "./frontendSelectors.js";
3
- describe("extractChangedSelectors", () => {
4
- it("captures both the old (removed) and new (added) value of a renamed data-testid", () => {
5
- const diff = [
6
- "@@ -175,7 +175,7 @@",
7
- '- dataTestId="confirmation-modal-confirm-button"',
8
- '+ dataTestId="confirmation-modal-primary-button"',
9
- ].join("\n");
10
- const sel = extractChangedSelectors(diff);
11
- // dataTestId isn't a data-* attribute, but both are distinctive kebab class-ish tokens
12
- expect(sel).toEqual(expect.arrayContaining([
13
- "confirmation-modal-confirm-button",
14
- "confirmation-modal-primary-button",
15
- ]));
16
- });
17
- it("captures data-testid attribute values", () => {
18
- const diff = '+ <input data-testid="members-search-field" />\n- <input data-testid="members-search-input" />';
19
- const sel = extractChangedSelectors(diff);
20
- expect(sel).toEqual(expect.arrayContaining(["members-search-field", "members-search-input"]));
21
- });
22
- it("captures CSS class rename with BEM `--` and multi-segment kebab", () => {
23
- const diff = [
24
- '- <div className="t--table-filter-columns-dropdown">',
25
- '+ <div className="t--tbl-filter-column-select">',
26
- '+ <button className="ads-button--primary">',
27
- ].join("\n");
28
- const sel = extractChangedSelectors(diff);
29
- expect(sel).toEqual(expect.arrayContaining([
30
- "t--table-filter-columns-dropdown",
31
- "t--tbl-filter-column-select",
32
- "ads-button--primary",
33
- ]));
34
- });
35
- it("captures the BEM base prefix of a dynamically-composed modifier class", () => {
36
- const diff = [
37
- "- className={clsx(ButtonClassName, className)}",
38
- "+ className={clsx(ButtonClassName, kind && `ads-button--${kind}`, className)}",
39
- ].join("\n");
40
- const sel = extractChangedSelectors(diff);
41
- // no concrete `ads-button--primary` literal exists in the diff — capture the base prefix
42
- expect(sel).toContain("ads-button--");
43
- });
44
- it("captures the BEM base from string-concatenation too, but leaves STATIC modifiers to the kebab pass", () => {
45
- const concat = extractChangedSelectors('+ const cls = "ads-button--" + kind;');
46
- expect(concat).toContain("ads-button--");
47
- // a fully static modifier is captured whole (not as a bare `foo-bar--` prefix)
48
- const staticMod = extractChangedSelectors('+ <div className="t--tbl-filter-column-select" />');
49
- expect(staticMod).toContain("t--tbl-filter-column-select");
50
- expect(staticMod).not.toContain("t--tbl-filter-column-select--");
51
- });
52
- it("captures getByTestId arguments", () => {
53
- const diff = "+ const btn = page.getByTestId('workflow-settings-modal');";
54
- expect(extractChangedSelectors(diff)).toContain("workflow-settings-modal");
55
- });
56
- it("drops single-hyphen styling utilities and short/generic tokens", () => {
57
- const diff = [
58
- '+ <div className="flex-start space-between text-align" />',
59
- '+ const gap = "sans-serif";',
60
- ].join("\n");
61
- expect(extractChangedSelectors(diff)).toEqual([]);
62
- });
63
- it("drops multi-hyphen utility / design-token classes (numeric scale + utility roots)", () => {
64
- const diff = [
65
- '- <div className="text-gray-500 bg-blue-600 flex-row-reverse" />',
66
- '+ <div className="text-gray-600 bg-blue-700 grid-cols-3" />',
67
- ].join("\n");
68
- const sel = extractChangedSelectors(diff);
69
- for (const util of ["text-gray-500", "text-gray-600", "bg-blue-600", "bg-blue-700", "flex-row-reverse", "grid-cols-3"]) {
70
- expect(sel).not.toContain(util);
71
- }
72
- });
73
- it("keeps semantic multi-hyphen identifiers and BEM classes (not utility)", () => {
74
- const diff = [
75
- '+ <div className="confirmation-modal-confirm-button user-profile-header" />',
76
- '+ <div className="t--tbl-filter-column-select" />',
77
- ].join("\n");
78
- const sel = extractChangedSelectors(diff);
79
- expect(sel).toEqual(expect.arrayContaining([
80
- "confirmation-modal-confirm-button",
81
- "user-profile-header",
82
- "t--tbl-filter-column-select",
83
- ]));
84
- });
85
- it("ignores context (unchanged) lines and file headers", () => {
86
- const diff = [
87
- "--- a/src/Component.tsx",
88
- "+++ b/src/Component.tsx",
89
- ' <div className="t--unchanged-context-selector" />', // context line (leading space)
90
- '+ <div className="t--added-real-selector" />',
91
- ].join("\n");
92
- const sel = extractChangedSelectors(diff);
93
- expect(sel).toContain("t--added-real-selector");
94
- expect(sel).not.toContain("t--unchanged-context-selector");
95
- expect(sel).not.toContain("Component"); // +++/--- headers ignored
96
- });
97
- it("does not leak a partial prefix from an interpolated template-literal attribute value", () => {
98
- const diff = [
99
- "+ <input data-testid={`members-search-${id}`} />",
100
- "+ <button data-testid={`confirmation-modal-${kind}`} />",
101
- ].join("\n");
102
- const sel = extractChangedSelectors(diff);
103
- expect(sel).not.toContain("members-search-");
104
- expect(sel).not.toContain("confirmation-modal-");
105
- });
106
- it("does not capture non-literal expression attribute values (data-testid={someVar})", () => {
107
- const diff = [
108
- "+ <div data-testid={someVariableName} />",
109
- "+ <div data-testid={'members-search-field'} />",
110
- ].join("\n");
111
- const sel = extractChangedSelectors(diff);
112
- expect(sel).not.toContain("someVariableName"); // variable name, not a literal
113
- expect(sel).toContain("members-search-field"); // quoted literal still captured
114
- });
115
- it("returns [] for an empty diff", () => {
116
- expect(extractChangedSelectors("")).toEqual([]);
117
- });
118
- });
@@ -1 +0,0 @@
1
- export {};