@ai-dev-tools/test-copilot-core 1.0.19

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 (328) hide show
  1. package/README.md +6 -0
  2. package/azure-pipelines.yml +51 -0
  3. package/out/cli/commands/appInsightTelemetry.d.ts +7 -0
  4. package/out/cli/commands/appInsightTelemetry.d.ts.map +1 -0
  5. package/out/cli/commands/appInsightTelemetry.js +76 -0
  6. package/out/cli/commands/appInsightTelemetry.js.map +1 -0
  7. package/out/cli/commands/cliConfig.d.ts +4 -0
  8. package/out/cli/commands/cliConfig.d.ts.map +1 -0
  9. package/out/cli/commands/cliConfig.js +68 -0
  10. package/out/cli/commands/cliConfig.js.map +1 -0
  11. package/out/cli/commands/prompt.d.ts +6 -0
  12. package/out/cli/commands/prompt.d.ts.map +1 -0
  13. package/out/cli/commands/prompt.js +29 -0
  14. package/out/cli/commands/prompt.js.map +1 -0
  15. package/out/cli/commands/ut.d.ts +14 -0
  16. package/out/cli/commands/ut.d.ts.map +1 -0
  17. package/out/cli/commands/ut.js +72 -0
  18. package/out/cli/commands/ut.js.map +1 -0
  19. package/out/cli/commands/utPipeCmdWrapper.d.ts +18 -0
  20. package/out/cli/commands/utPipeCmdWrapper.d.ts.map +1 -0
  21. package/out/cli/commands/utPipeCmdWrapper.js +37 -0
  22. package/out/cli/commands/utPipeCmdWrapper.js.map +1 -0
  23. package/out/cli/config/index.d.ts +15 -0
  24. package/out/cli/config/index.d.ts.map +1 -0
  25. package/out/cli/config/index.js +10 -0
  26. package/out/cli/config/index.js.map +1 -0
  27. package/out/cli/index.d.ts +3 -0
  28. package/out/cli/index.d.ts.map +1 -0
  29. package/out/cli/index.js +169 -0
  30. package/out/cli/index.js.map +1 -0
  31. package/out/cli/type.d.ts +11 -0
  32. package/out/cli/type.d.ts.map +1 -0
  33. package/out/cli/type.js +3 -0
  34. package/out/cli/type.js.map +1 -0
  35. package/out/cli/utils/ds.d.ts +3 -0
  36. package/out/cli/utils/ds.d.ts.map +1 -0
  37. package/out/cli/utils/ds.js +50 -0
  38. package/out/cli/utils/ds.js.map +1 -0
  39. package/out/cli/utils/gpt.d.ts +3 -0
  40. package/out/cli/utils/gpt.d.ts.map +1 -0
  41. package/out/cli/utils/gpt.js +63 -0
  42. package/out/cli/utils/gpt.js.map +1 -0
  43. package/out/core/analyze/cjs.d.ts +61 -0
  44. package/out/core/analyze/cjs.d.ts.map +1 -0
  45. package/out/core/analyze/cjs.js +358 -0
  46. package/out/core/analyze/cjs.js.map +1 -0
  47. package/out/core/analyze/class.d.ts +4 -0
  48. package/out/core/analyze/class.d.ts.map +1 -0
  49. package/out/core/analyze/class.js +32 -0
  50. package/out/core/analyze/class.js.map +1 -0
  51. package/out/core/analyze/declares.d.ts +7 -0
  52. package/out/core/analyze/declares.d.ts.map +1 -0
  53. package/out/core/analyze/declares.js +316 -0
  54. package/out/core/analyze/declares.js.map +1 -0
  55. package/out/core/analyze/deps.d.ts +8 -0
  56. package/out/core/analyze/deps.d.ts.map +1 -0
  57. package/out/core/analyze/deps.js +210 -0
  58. package/out/core/analyze/deps.js.map +1 -0
  59. package/out/core/analyze/functionComponent.d.ts +4 -0
  60. package/out/core/analyze/functionComponent.d.ts.map +1 -0
  61. package/out/core/analyze/functionComponent.js +77 -0
  62. package/out/core/analyze/functionComponent.js.map +1 -0
  63. package/out/core/analyze/functions.d.ts +4 -0
  64. package/out/core/analyze/functions.d.ts.map +1 -0
  65. package/out/core/analyze/functions.js +46 -0
  66. package/out/core/analyze/functions.js.map +1 -0
  67. package/out/core/analyze/index.d.ts +16 -0
  68. package/out/core/analyze/index.d.ts.map +1 -0
  69. package/out/core/analyze/index.js +149 -0
  70. package/out/core/analyze/index.js.map +1 -0
  71. package/out/core/analyze/index.type.d.ts +69 -0
  72. package/out/core/analyze/index.type.d.ts.map +1 -0
  73. package/out/core/analyze/index.type.js +14 -0
  74. package/out/core/analyze/index.type.js.map +1 -0
  75. package/out/core/analyze/utils/global.d.ts +2 -0
  76. package/out/core/analyze/utils/global.d.ts.map +1 -0
  77. package/out/core/analyze/utils/global.js +84 -0
  78. package/out/core/analyze/utils/global.js.map +1 -0
  79. package/out/core/analyzev2/declare/class.d.ts +4 -0
  80. package/out/core/analyzev2/declare/class.d.ts.map +1 -0
  81. package/out/core/analyzev2/declare/class.js +24 -0
  82. package/out/core/analyzev2/declare/class.js.map +1 -0
  83. package/out/core/analyzev2/declare/funcLike.d.ts +8 -0
  84. package/out/core/analyzev2/declare/funcLike.d.ts.map +1 -0
  85. package/out/core/analyzev2/declare/funcLike.js +71 -0
  86. package/out/core/analyzev2/declare/funcLike.js.map +1 -0
  87. package/out/core/analyzev2/declare/variable.d.ts +3 -0
  88. package/out/core/analyzev2/declare/variable.d.ts.map +1 -0
  89. package/out/core/analyzev2/declare/variable.js +15 -0
  90. package/out/core/analyzev2/declare/variable.js.map +1 -0
  91. package/out/core/analyzev2/file.d.ts +19 -0
  92. package/out/core/analyzev2/file.d.ts.map +1 -0
  93. package/out/core/analyzev2/file.js +449 -0
  94. package/out/core/analyzev2/file.js.map +1 -0
  95. package/out/core/analyzev2/index.d.ts +5 -0
  96. package/out/core/analyzev2/index.d.ts.map +1 -0
  97. package/out/core/analyzev2/index.js +30 -0
  98. package/out/core/analyzev2/index.js.map +1 -0
  99. package/out/core/analyzev2/type.d.ts +35 -0
  100. package/out/core/analyzev2/type.d.ts.map +1 -0
  101. package/out/core/analyzev2/type.js +3 -0
  102. package/out/core/analyzev2/type.js.map +1 -0
  103. package/out/core/config/index.d.ts +25 -0
  104. package/out/core/config/index.d.ts.map +1 -0
  105. package/out/core/config/index.js +14 -0
  106. package/out/core/config/index.js.map +1 -0
  107. package/out/core/constants.d.ts +9 -0
  108. package/out/core/constants.d.ts.map +1 -0
  109. package/out/core/constants.js +12 -0
  110. package/out/core/constants.js.map +1 -0
  111. package/out/core/features/common/base.d.ts +20 -0
  112. package/out/core/features/common/base.d.ts.map +1 -0
  113. package/out/core/features/common/base.js +77 -0
  114. package/out/core/features/common/base.js.map +1 -0
  115. package/out/core/features/common/types.d.ts +16 -0
  116. package/out/core/features/common/types.d.ts.map +1 -0
  117. package/out/core/features/common/types.js +12 -0
  118. package/out/core/features/common/types.js.map +1 -0
  119. package/out/core/features/generateFile.d.ts +31 -0
  120. package/out/core/features/generateFile.d.ts.map +1 -0
  121. package/out/core/features/generateFile.js +148 -0
  122. package/out/core/features/generateFile.js.map +1 -0
  123. package/out/core/features/generateSingle.d.ts +28 -0
  124. package/out/core/features/generateSingle.d.ts.map +1 -0
  125. package/out/core/features/generateSingle.js +149 -0
  126. package/out/core/features/generateSingle.js.map +1 -0
  127. package/out/core/features/index.d.ts +9 -0
  128. package/out/core/features/index.d.ts.map +1 -0
  129. package/out/core/features/index.js +16 -0
  130. package/out/core/features/index.js.map +1 -0
  131. package/out/core/features/lintFix.d.ts +2 -0
  132. package/out/core/features/lintFix.d.ts.map +1 -0
  133. package/out/core/features/lintFix.js +33 -0
  134. package/out/core/features/lintFix.js.map +1 -0
  135. package/out/core/features/mergeUTFile.d.ts +19 -0
  136. package/out/core/features/mergeUTFile.d.ts.map +1 -0
  137. package/out/core/features/mergeUTFile.js +63 -0
  138. package/out/core/features/mergeUTFile.js.map +1 -0
  139. package/out/core/features/removeFailedCases.d.ts +23 -0
  140. package/out/core/features/removeFailedCases.d.ts.map +1 -0
  141. package/out/core/features/removeFailedCases.js +81 -0
  142. package/out/core/features/removeFailedCases.js.map +1 -0
  143. package/out/core/features/updateSpec.d.ts +20 -0
  144. package/out/core/features/updateSpec.d.ts.map +1 -0
  145. package/out/core/features/updateSpec.js +98 -0
  146. package/out/core/features/updateSpec.js.map +1 -0
  147. package/out/core/features/validFix.d.ts +29 -0
  148. package/out/core/features/validFix.d.ts.map +1 -0
  149. package/out/core/features/validFix.js +219 -0
  150. package/out/core/features/validFix.js.map +1 -0
  151. package/out/core/generate/UTGen.d.ts +79 -0
  152. package/out/core/generate/UTGen.d.ts.map +1 -0
  153. package/out/core/generate/UTGen.js +795 -0
  154. package/out/core/generate/UTGen.js.map +1 -0
  155. package/out/core/llm/index.d.ts +9 -0
  156. package/out/core/llm/index.d.ts.map +1 -0
  157. package/out/core/llm/index.js +39 -0
  158. package/out/core/llm/index.js.map +1 -0
  159. package/out/core/llm/prompts/config.d.ts +6 -0
  160. package/out/core/llm/prompts/config.d.ts.map +1 -0
  161. package/out/core/llm/prompts/config.js +239 -0
  162. package/out/core/llm/prompts/config.js.map +1 -0
  163. package/out/core/llm/prompts/templates/common.d.ts +3 -0
  164. package/out/core/llm/prompts/templates/common.d.ts.map +1 -0
  165. package/out/core/llm/prompts/templates/common.js +27 -0
  166. package/out/core/llm/prompts/templates/common.js.map +1 -0
  167. package/out/core/llm/prompts/templates/fixCase.d.ts +4 -0
  168. package/out/core/llm/prompts/templates/fixCase.d.ts.map +1 -0
  169. package/out/core/llm/prompts/templates/fixCase.js +46 -0
  170. package/out/core/llm/prompts/templates/fixCase.js.map +1 -0
  171. package/out/core/llm/prompts/templates/fixLint.d.ts +3 -0
  172. package/out/core/llm/prompts/templates/fixLint.d.ts.map +1 -0
  173. package/out/core/llm/prompts/templates/fixLint.js +22 -0
  174. package/out/core/llm/prompts/templates/fixLint.js.map +1 -0
  175. package/out/core/llm/prompts/templates/genClassMemberUT.d.ts +5 -0
  176. package/out/core/llm/prompts/templates/genClassMemberUT.d.ts.map +1 -0
  177. package/out/core/llm/prompts/templates/genClassMemberUT.js +115 -0
  178. package/out/core/llm/prompts/templates/genClassMemberUT.js.map +1 -0
  179. package/out/core/llm/prompts/templates/genFuncUT.d.ts +4 -0
  180. package/out/core/llm/prompts/templates/genFuncUT.d.ts.map +1 -0
  181. package/out/core/llm/prompts/templates/genFuncUT.js +64 -0
  182. package/out/core/llm/prompts/templates/genFuncUT.js.map +1 -0
  183. package/out/core/llm/prompts/templates/mergeUT.d.ts +4 -0
  184. package/out/core/llm/prompts/templates/mergeUT.d.ts.map +1 -0
  185. package/out/core/llm/prompts/templates/mergeUT.js +106 -0
  186. package/out/core/llm/prompts/templates/mergeUT.js.map +1 -0
  187. package/out/core/llm/prompts/templates/msnStudio.d.ts +3 -0
  188. package/out/core/llm/prompts/templates/msnStudio.d.ts.map +1 -0
  189. package/out/core/llm/prompts/templates/msnStudio.js +36 -0
  190. package/out/core/llm/prompts/templates/msnStudio.js.map +1 -0
  191. package/out/core/llm/prompts/templates/snapshotUT.d.ts +4 -0
  192. package/out/core/llm/prompts/templates/snapshotUT.d.ts.map +1 -0
  193. package/out/core/llm/prompts/templates/snapshotUT.js +68 -0
  194. package/out/core/llm/prompts/templates/snapshotUT.js.map +1 -0
  195. package/out/core/llm/prompts/templates/updateSpecBlock.d.ts +3 -0
  196. package/out/core/llm/prompts/templates/updateSpecBlock.d.ts.map +1 -0
  197. package/out/core/llm/prompts/templates/updateSpecBlock.js +38 -0
  198. package/out/core/llm/prompts/templates/updateSpecBlock.js.map +1 -0
  199. package/out/core/llm/prompts/templates/updateSpecFile.d.ts +3 -0
  200. package/out/core/llm/prompts/templates/updateSpecFile.d.ts.map +1 -0
  201. package/out/core/llm/prompts/templates/updateSpecFile.js +30 -0
  202. package/out/core/llm/prompts/templates/updateSpecFile.js.map +1 -0
  203. package/out/core/llm/types.d.ts +80 -0
  204. package/out/core/llm/types.d.ts.map +1 -0
  205. package/out/core/llm/types.js +5 -0
  206. package/out/core/llm/types.js.map +1 -0
  207. package/out/core/quality/validateMockedTest.d.ts +3 -0
  208. package/out/core/quality/validateMockedTest.d.ts.map +1 -0
  209. package/out/core/quality/validateMockedTest.js +211 -0
  210. package/out/core/quality/validateMockedTest.js.map +1 -0
  211. package/out/core/utils/checkTestIgnore.d.ts +4 -0
  212. package/out/core/utils/checkTestIgnore.d.ts.map +1 -0
  213. package/out/core/utils/checkTestIgnore.js +52 -0
  214. package/out/core/utils/checkTestIgnore.js.map +1 -0
  215. package/out/core/utils/common.d.ts +4 -0
  216. package/out/core/utils/common.d.ts.map +1 -0
  217. package/out/core/utils/common.js +34 -0
  218. package/out/core/utils/common.js.map +1 -0
  219. package/out/core/utils/console.d.ts +8 -0
  220. package/out/core/utils/console.d.ts.map +1 -0
  221. package/out/core/utils/console.js +24 -0
  222. package/out/core/utils/console.js.map +1 -0
  223. package/out/core/utils/deps.d.ts +3 -0
  224. package/out/core/utils/deps.d.ts.map +1 -0
  225. package/out/core/utils/deps.js +58 -0
  226. package/out/core/utils/deps.js.map +1 -0
  227. package/out/core/utils/eslintRuleHandler.d.ts +3 -0
  228. package/out/core/utils/eslintRuleHandler.d.ts.map +1 -0
  229. package/out/core/utils/eslintRuleHandler.js +98 -0
  230. package/out/core/utils/eslintRuleHandler.js.map +1 -0
  231. package/out/core/utils/file.d.ts +18 -0
  232. package/out/core/utils/file.d.ts.map +1 -0
  233. package/out/core/utils/file.js +142 -0
  234. package/out/core/utils/file.js.map +1 -0
  235. package/out/core/utils/lint.d.ts +9 -0
  236. package/out/core/utils/lint.d.ts.map +1 -0
  237. package/out/core/utils/lint.js +95 -0
  238. package/out/core/utils/lint.js.map +1 -0
  239. package/out/core/utils/lru.d.ts +12 -0
  240. package/out/core/utils/lru.d.ts.map +1 -0
  241. package/out/core/utils/lru.js +47 -0
  242. package/out/core/utils/lru.js.map +1 -0
  243. package/out/core/utils/move.d.ts +12 -0
  244. package/out/core/utils/move.d.ts.map +1 -0
  245. package/out/core/utils/move.js +93 -0
  246. package/out/core/utils/move.js.map +1 -0
  247. package/out/core/utils/msnStudio.d.ts +13 -0
  248. package/out/core/utils/msnStudio.d.ts.map +1 -0
  249. package/out/core/utils/msnStudio.js +150 -0
  250. package/out/core/utils/msnStudio.js.map +1 -0
  251. package/out/core/utils/parseCustomizedCmd.d.ts +2 -0
  252. package/out/core/utils/parseCustomizedCmd.d.ts.map +1 -0
  253. package/out/core/utils/parseCustomizedCmd.js +32 -0
  254. package/out/core/utils/parseCustomizedCmd.js.map +1 -0
  255. package/out/core/utils/specBlock.d.ts +20 -0
  256. package/out/core/utils/specBlock.d.ts.map +1 -0
  257. package/out/core/utils/specBlock.js +231 -0
  258. package/out/core/utils/specBlock.js.map +1 -0
  259. package/out/core/utils/system.d.ts +13 -0
  260. package/out/core/utils/system.d.ts.map +1 -0
  261. package/out/core/utils/system.js +86 -0
  262. package/out/core/utils/system.js.map +1 -0
  263. package/out/core/utils/telemetry.d.ts +9 -0
  264. package/out/core/utils/telemetry.d.ts.map +1 -0
  265. package/out/core/utils/telemetry.js +32 -0
  266. package/out/core/utils/telemetry.js.map +1 -0
  267. package/out/core/utils/tsMorph.d.ts +13 -0
  268. package/out/core/utils/tsMorph.d.ts.map +1 -0
  269. package/out/core/utils/tsMorph.js +76 -0
  270. package/out/core/utils/tsMorph.js.map +1 -0
  271. package/out/core/valid/customizedLint.d.ts +2 -0
  272. package/out/core/valid/customizedLint.d.ts.map +1 -0
  273. package/out/core/valid/customizedLint.js +64 -0
  274. package/out/core/valid/customizedLint.js.map +1 -0
  275. package/out/core/valid/customizedTest.d.ts +3 -0
  276. package/out/core/valid/customizedTest.d.ts.map +1 -0
  277. package/out/core/valid/customizedTest.js +58 -0
  278. package/out/core/valid/customizedTest.js.map +1 -0
  279. package/out/core/valid/extractVitestConfig.d.ts +5 -0
  280. package/out/core/valid/extractVitestConfig.d.ts.map +1 -0
  281. package/out/core/valid/extractVitestConfig.js +97 -0
  282. package/out/core/valid/extractVitestConfig.js.map +1 -0
  283. package/out/core/valid/getViteConfig.d.ts +2 -0
  284. package/out/core/valid/getViteConfig.d.ts.map +1 -0
  285. package/out/core/valid/getViteConfig.js +65 -0
  286. package/out/core/valid/getViteConfig.js.map +1 -0
  287. package/out/core/valid/index.d.ts +15 -0
  288. package/out/core/valid/index.d.ts.map +1 -0
  289. package/out/core/valid/index.js +99 -0
  290. package/out/core/valid/index.js.map +1 -0
  291. package/out/core/valid/jest.d.ts +4 -0
  292. package/out/core/valid/jest.d.ts.map +1 -0
  293. package/out/core/valid/jest.js +121 -0
  294. package/out/core/valid/jest.js.map +1 -0
  295. package/out/core/valid/mock.d.ts +2 -0
  296. package/out/core/valid/mock.d.ts.map +1 -0
  297. package/out/core/valid/mock.js +149 -0
  298. package/out/core/valid/mock.js.map +1 -0
  299. package/out/core/valid/remove.d.ts +5 -0
  300. package/out/core/valid/remove.d.ts.map +1 -0
  301. package/out/core/valid/remove.js +109 -0
  302. package/out/core/valid/remove.js.map +1 -0
  303. package/out/core/valid/tag.d.ts +3 -0
  304. package/out/core/valid/tag.d.ts.map +1 -0
  305. package/out/core/valid/tag.js +91 -0
  306. package/out/core/valid/tag.js.map +1 -0
  307. package/out/core/valid/type.d.ts +83 -0
  308. package/out/core/valid/type.d.ts.map +1 -0
  309. package/out/core/valid/type.js +3 -0
  310. package/out/core/valid/type.js.map +1 -0
  311. package/out/core/valid/vitest.d.ts +3 -0
  312. package/out/core/valid/vitest.d.ts.map +1 -0
  313. package/out/core/valid/vitest.js +82 -0
  314. package/out/core/valid/vitest.js.map +1 -0
  315. package/out/index.d.ts +20 -0
  316. package/out/index.d.ts.map +1 -0
  317. package/out/index.js +60 -0
  318. package/out/index.js.map +1 -0
  319. package/out/setup.d.ts +11 -0
  320. package/out/setup.d.ts.map +1 -0
  321. package/out/setup.js +14 -0
  322. package/out/setup.js.map +1 -0
  323. package/out/types.d.ts +23 -0
  324. package/out/types.d.ts.map +1 -0
  325. package/out/types.js +3 -0
  326. package/out/types.js.map +1 -0
  327. package/package.json +39 -0
  328. package/package_devops.json +42 -0
@@ -0,0 +1,795 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.UTGen = void 0;
7
+ const analyze_1 = require("../analyze");
8
+ const llm_1 = require("../llm");
9
+ const common_1 = require("../utils/common");
10
+ const file_1 = require("../utils/file");
11
+ const system_1 = require("../utils/system");
12
+ const lint_1 = require("../utils/lint");
13
+ const validateMockedTest_1 = require("../quality/validateMockedTest");
14
+ const removeFailedCases_1 = require("../features/removeFailedCases");
15
+ const validFix_1 = require("../features/validFix");
16
+ const tag_1 = require("../valid/tag");
17
+ const mock_1 = require("../valid/mock");
18
+ const extractVitestConfig_1 = require("../valid/extractVitestConfig");
19
+ const fs_1 = __importDefault(require("fs"));
20
+ const config_1 = require("../config");
21
+ const console_1 = require("../utils/console");
22
+ const deps_1 = require("../utils/deps");
23
+ const tsMorph_1 = require("../utils/tsMorph");
24
+ const getViteConfig_1 = require("../valid/getViteConfig");
25
+ const path_1 = __importDefault(require("path"));
26
+ const telemetry_1 = require("../utils/telemetry");
27
+ const move_1 = require("../utils/move");
28
+ const reactFunctionSet = new Set([
29
+ 'componentDidMount',
30
+ 'componentDidUpdate',
31
+ 'componentWillUnmount',
32
+ 'componentWillReceiveProps',
33
+ 'componentWillUpdate',
34
+ 'componentWillMount',
35
+ 'componentWillUpdate',
36
+ 'shouldComponentUpdate',
37
+ 'componentDidCatch',
38
+ 'getDerivedStateFromProps',
39
+ 'getSnapshotBeforeUpdate'
40
+ ]);
41
+ class UTGen {
42
+ filePath;
43
+ projectFolder;
44
+ options;
45
+ #sourceFile;
46
+ #fileDir;
47
+ // file name with extension
48
+ #fileName;
49
+ // file name without extension
50
+ #filePrefix;
51
+ // file extension
52
+ #fileSuffix;
53
+ // ${this.#filePrefix}.spec or custom test folder
54
+ #specDir;
55
+ #testFileSpecifier = 'web.spec';
56
+ #stopped = false;
57
+ #status;
58
+ #count = {
59
+ unknown: 0,
60
+ success: 0,
61
+ funFailed: 0,
62
+ classMemberFailed: 0,
63
+ skip: 0,
64
+ exception: 0,
65
+ testException: 0,
66
+ gptException: 0,
67
+ };
68
+ #generatedFiles = [];
69
+ #memoResult = {};
70
+ #isInWSL = false;
71
+ vitestConfig;
72
+ tempTestFileDir;
73
+ get status() {
74
+ return this.#status;
75
+ }
76
+ get generatedFiles() {
77
+ return this.#generatedFiles;
78
+ }
79
+ get count() {
80
+ return this.#count;
81
+ }
82
+ get memoResult() {
83
+ return this.#memoResult;
84
+ }
85
+ get testFramework() {
86
+ return (0, config_1.getConfig)().common.testFramework || 'jest';
87
+ }
88
+ get sourceFile() {
89
+ return this.#sourceFile;
90
+ }
91
+ get specDir() {
92
+ return this.#specDir;
93
+ }
94
+ constructor(filePath, projectFolder, options) {
95
+ this.filePath = filePath;
96
+ this.projectFolder = projectFolder;
97
+ this.options = options;
98
+ this.#sourceFile = (0, file_1.toUnixStyle)(filePath);
99
+ this.#fileDir = (0, file_1.toUnixStyle)(path_1.default.dirname(filePath));
100
+ this.#fileName = (0, file_1.toUnixStyle)(path_1.default.basename(filePath));
101
+ this.#filePrefix = this.#fileName.replace(/(\.[jt]sx?)$/, '');
102
+ this.#fileSuffix = this.#fileName.replace(this.#filePrefix, '');
103
+ this.projectFolder = projectFolder || (0, file_1.findProjectRoot)(filePath) || this.#fileDir;
104
+ const { testFolder, testFileSpecifier } = (0, config_1.getConfig)().common;
105
+ this.#testFileSpecifier = testFileSpecifier || 'web.spec';
106
+ if (testFolder) {
107
+ const srcFolder = path_1.default.resolve(this.projectFolder, 'src');
108
+ const srcExists = fs_1.default.existsSync(srcFolder) && fs_1.default.statSync(srcFolder).isDirectory();
109
+ const relatedFolder = path_1.default.relative(srcExists ? srcFolder : this.projectFolder, this.#fileDir);
110
+ this.#specDir = path_1.default.resolve(this.projectFolder, testFolder, relatedFolder, this.#filePrefix);
111
+ }
112
+ else {
113
+ this.#specDir = path_1.default.resolve(this.#fileDir, this.#fileName.replace(/(\.[jt]sx?)$/, `.spec`));
114
+ }
115
+ this.#isInWSL = /^(\\|\/\/)wsl.localhost(\\|\/)/.test(this.#fileDir);
116
+ this.tempTestFileDir = this.#fileDir;
117
+ if (this.testFramework === 'vitest') {
118
+ const vitestConfigPath = (0, getViteConfig_1.getViteConfigPath)(this.#fileDir);
119
+ if (vitestConfigPath) {
120
+ const vitestConfig = (0, extractVitestConfig_1.extractTestConfigWithAST)(vitestConfigPath);
121
+ if (vitestConfig.testDir) {
122
+ // reset the spec dir with test dir
123
+ this.#specDir = testFolder ? this.#specDir : path_1.default.normalize(this.#specDir.replace('src', vitestConfig.testDir));
124
+ this.tempTestFileDir = path_1.default.normalize(this.tempTestFileDir.replace('src', vitestConfig.testDir));
125
+ }
126
+ if (vitestConfig.testSpecifier) {
127
+ this.#testFileSpecifier = testFileSpecifier || vitestConfig.testSpecifier;
128
+ }
129
+ }
130
+ }
131
+ if ((0, config_1.getConfig)().common.testDirRelativeToPackage) {
132
+ const packageRoot = (0, file_1.findProjectRoot)(this.#fileDir);
133
+ this.#specDir = path_1.default.resolve(packageRoot, (0, config_1.getConfig)().common.testDirRelativeToPackage, this.#fileName.replace(/(\.[jt]sx?)$/, `.spec`));
134
+ this.tempTestFileDir = path_1.default.resolve(packageRoot, (0, config_1.getConfig)().common.testDirRelativeToPackage);
135
+ }
136
+ }
137
+ log(...args) {
138
+ (0, console_1.getConsole)().log(...args);
139
+ }
140
+ error(...args) {
141
+ (0, console_1.getConsole)().error(...args);
142
+ }
143
+ progress(message, options) {
144
+ this.options?.progress?.({
145
+ message,
146
+ ...options
147
+ });
148
+ }
149
+ stop = () => {
150
+ this.#stopped = true;
151
+ };
152
+ #sendTelemetry = (type, properties, measurements) => {
153
+ (0, telemetry_1.sendTelemetry)('UTGen', {
154
+ type,
155
+ runTest: this.options?.runTest ? 'true' : 'false',
156
+ ...properties
157
+ }, measurements);
158
+ };
159
+ #updateCount(status, isClassMember) {
160
+ if (status === 2 /* GenerateResult.Success */) {
161
+ this.#count.success++;
162
+ }
163
+ else if (status === 1 /* GenerateResult.Failed */) {
164
+ if (isClassMember) {
165
+ this.#count.classMemberFailed++;
166
+ }
167
+ else {
168
+ this.#count.funFailed++;
169
+ }
170
+ }
171
+ else if (status === 4 /* GenerateResult.Exception */) {
172
+ this.#count.exception++;
173
+ }
174
+ else if (status === 5 /* GenerateResult.TestException */) {
175
+ this.#count.testException++;
176
+ }
177
+ else if (status === 6 /* GenerateResult.GPTException */) {
178
+ this.#count.gptException++;
179
+ }
180
+ else if (status === 3 /* GenerateResult.Skip */) {
181
+ this.#count.skip++;
182
+ }
183
+ else {
184
+ this.#count.unknown++;
185
+ }
186
+ }
187
+ async run() {
188
+ if (this.options?.abortSignal) {
189
+ this.options.abortSignal.addEventListener('abort', this.stop, { once: true });
190
+ }
191
+ const start = Date.now();
192
+ try {
193
+ this.progress(`Analyzing ${this.#fileName}`);
194
+ const { project: cachedProject } = (0, tsMorph_1.getProject)(this.filePath);
195
+ // analyze may take a long time, put the rest actions to the next loop
196
+ await (0, system_1.sleep)(10);
197
+ if (this.#stopped) {
198
+ return;
199
+ }
200
+ this.#sendTelemetry("start" /* Events.Start */);
201
+ const exporteds = await (0, analyze_1.read)(this.filePath, {
202
+ deepTypesCheck: false,
203
+ cachedProject
204
+ });
205
+ const processEndTime = Date.now();
206
+ const processTime = processEndTime - start;
207
+ if (!exporteds.length) {
208
+ if (this.#fileName === "index.ts" && (0, config_1.getConfig)().common.createIndexSpec) {
209
+ const testCode = `import * as Exports from './${this.#filePrefix}';\ndescribe("Exports", () => {\n it("should be defined", () => {\n expect(Exports).toBeDefined();\n });\n});`;
210
+ const specFile = this.filePath.replace(/(\.[jt]sx?)$/, `.${this.#testFileSpecifier}$1`);
211
+ if (!fs_1.default.existsSync(specFile) && !fs_1.default.existsSync(specFile.replace(/\.web\./, '.node.')) && !fs_1.default.existsSync(specFile.replace(/\.web\./, '.'))) {
212
+ fs_1.default.writeFileSync(specFile, testCode, 'utf-8');
213
+ }
214
+ this.#status = 2 /* GenerateResult.Success */;
215
+ this.#sendTelemetry("index" /* Events.GenIndex */, {}, {
216
+ processTime,
217
+ totalTime: Date.now() - start
218
+ });
219
+ }
220
+ else {
221
+ this.progress(`No export function/class found in ${this.#fileName}`);
222
+ this.#status = 3 /* GenerateResult.Skip */;
223
+ this.#sendTelemetry("skipConst" /* Events.SkipConstants */, {}, {
224
+ processTime,
225
+ totalTime: Date.now() - start
226
+ });
227
+ return;
228
+ }
229
+ }
230
+ for (let i = 0; i < exporteds.length && !this.#stopped; i++) {
231
+ const exportData = exporteds[i];
232
+ await (0, system_1.sleep)(10);
233
+ this.log(`Exported: ${i + 1}/${exporteds.length} ${exportData.name}`);
234
+ if (exportData.type === analyze_1.CodeType.Function) {
235
+ this.#updateCount(await this.genFunctionTestCode(exportData), false);
236
+ }
237
+ else {
238
+ const res = await this.genClassTestCode(exportData);
239
+ res.forEach(r => this.#updateCount(r, true));
240
+ }
241
+ }
242
+ let mark = '';
243
+ if (this.#count.success) {
244
+ mark = 'Success';
245
+ this.progress('Success', { finish: 1 });
246
+ this.#status = 2 /* GenerateResult.Success */;
247
+ }
248
+ else if (!(this.#count.funFailed || this.#count.classMemberFailed)) {
249
+ mark = 'Skip';
250
+ this.#status = 3 /* GenerateResult.Skip */;
251
+ this.progress('Skipped', { finish: 1 });
252
+ }
253
+ else {
254
+ mark = 'Failed';
255
+ this.progress('Failed', { finish: 2, lastFailed: true });
256
+ this.#status = 1 /* GenerateResult.Failed */;
257
+ }
258
+ const totalTime = Date.now() - start;
259
+ const seconds = totalTime / 1000;
260
+ const timeStr = seconds < 60 ? `${seconds} sec` : `${Math.floor(seconds / 60)} min ${Math.floor(seconds % 60)} sec`;
261
+ this.log(`[${mark}] Generated test files for ${this.#fileName} in ${timeStr}`);
262
+ this.#sendTelemetry("finish" /* Events.Finish */, {}, {
263
+ processTime,
264
+ totalTime,
265
+ ...this.#count
266
+ });
267
+ }
268
+ catch (e) {
269
+ this.progress(`Error: ${e.message}`, { finish: 2, lastFailed: true });
270
+ }
271
+ finally {
272
+ if (this.options?.abortSignal) {
273
+ this.options.abortSignal.removeEventListener('abort', this.stop);
274
+ }
275
+ }
276
+ }
277
+ async writeSpecFile(code, testName, existsSpec) {
278
+ // TODO: check new test cases coverage should be greater than existing
279
+ const specName = this.getSpecName(testName);
280
+ let targetPath;
281
+ if (existsSpec?.isFileLevel) {
282
+ targetPath = existsSpec.filePath;
283
+ }
284
+ else {
285
+ targetPath = path_1.default.resolve(this.#specDir, specName);
286
+ }
287
+ const specDir = path_1.default.dirname(targetPath);
288
+ if (!fs_1.default.existsSync(specDir) && !this.options?.saveInMemo) {
289
+ fs_1.default.mkdirSync(specDir, { recursive: true });
290
+ }
291
+ let newCode = code;
292
+ if (!existsSpec?.isFileLevel) {
293
+ newCode = (0, tag_1.addTag)(newCode);
294
+ }
295
+ newCode = await (0, move_1.updateCodeReferences)(this.#fileDir, specDir, specName, newCode);
296
+ const targetRelatedPath = path_1.default.relative(this.projectFolder, targetPath);
297
+ this.log(`Writing test file: ${targetPath}`);
298
+ if (this.options?.saveInMemo) {
299
+ this.#memoResult[testName] = {
300
+ code: newCode,
301
+ targetPath,
302
+ };
303
+ return targetPath;
304
+ }
305
+ const existsSpecPath = fs_1.default.existsSync(targetPath) ? targetPath : undefined;
306
+ let oldSpec = undefined;
307
+ if (this.options?.saveOldSpec && existsSpecPath) {
308
+ oldSpec = fs_1.default.readFileSync(existsSpecPath, 'utf8').toString();
309
+ }
310
+ this.progress(`Writing test file to ${targetRelatedPath}`);
311
+ fs_1.default.writeFileSync(targetPath, newCode, 'utf-8');
312
+ this.#generatedFiles.push({
313
+ filePath: targetPath,
314
+ status: existsSpecPath ? 'modify' : 'add',
315
+ oldSpec: oldSpec
316
+ });
317
+ return targetPath;
318
+ }
319
+ async genFunctionTestCode(data) {
320
+ if (!this.isFunctionMatch(data.name)) {
321
+ return 3 /* GenerateResult.Skip */;
322
+ }
323
+ if (!this.isLineMatch(data.linesRange)) {
324
+ return 3 /* GenerateResult.Skip */;
325
+ }
326
+ if (!this.isLineRangeMatch(data.linesRange)) {
327
+ return 3 /* GenerateResult.Skip */;
328
+ }
329
+ if ((0, config_1.getConfig)().common.ignoreFuncs?.has(data.name)) {
330
+ return 3 /* GenerateResult.Skip */;
331
+ }
332
+ let mockString = (0, deps_1.getPackageMocks)(data.importDeclares);
333
+ let existsSpec = this.isSpecExists(data.name);
334
+ let specCode;
335
+ if (existsSpec) {
336
+ if (!this.options?.repair) {
337
+ this.progress(`Spec file exists (${existsSpec.filePath}), please use "Update test" to fix`);
338
+ return 3 /* GenerateResult.Skip */;
339
+ }
340
+ specCode = await this.readExistingSpec(existsSpec.filePath);
341
+ }
342
+ this.progress(`Generating test code for ${data.name}`);
343
+ const specName = `./${this.#filePrefix}.${this.#testFileSpecifier}${this.#fileSuffix}`;
344
+ const code = (0, analyze_1.getCode)(data, {
345
+ beforeImports: '// external import declarations:\n',
346
+ beforeLocal: `// dependencies in the same file (./${this.#fileName}):\n`,
347
+ beforeCode: '// test target code:\n'
348
+ });
349
+ const promptKey = specCode ? "RepairFuncUT" /* PromptKey.RepairFuncUT */ : "GenFuncUT" /* PromptKey.GenFuncUT */;
350
+ const messages = (0, llm_1.getPrompt)(promptKey, {
351
+ ["<<<SourceFileName>>>" /* PromptPlaceholder.SourceFileName */]: this.#fileName,
352
+ ["<<<FunctionName>>>" /* PromptPlaceholder.FunctionName */]: (0, common_1.formatImportName)(data.name, data.isDefaultExport),
353
+ ["<<<SpecFileName>>>" /* PromptPlaceholder.SpecFileName */]: specName,
354
+ ["<<<SourceCode>>>" /* PromptPlaceholder.SourceCode */]: code,
355
+ ["<<<MockCode>>>" /* PromptPlaceholder.MockCode */]: mockString,
356
+ ["<<<Spec>>>" /* PromptPlaceholder.SpecCode */]: specCode,
357
+ ["<<<Language>>>" /* PromptPlaceholder.Language */]: (0, common_1.getLanguage)(this.#fileSuffix),
358
+ ["<<<ModuleType>>>" /* PromptPlaceholder.ModuleType */]: data.isCommonJS ? "cjs" /* ModuleType.CJS */ : "esm" /* ModuleType.ESM */,
359
+ ["<<<TestFramework>>>" /* PromptPlaceholder.TestFramework */]: this.testFramework,
360
+ }, this.options?.promptConfigs?.[promptKey]);
361
+ const testName = (0, config_1.getConfig)().common?.kebabCaseTestFileName ? this.toKebabCase(data.name) : data.name;
362
+ return await this.runTask({
363
+ messages,
364
+ testName: testName,
365
+ targetCode: code,
366
+ mockString,
367
+ testFuncName: data.name,
368
+ moduleName: this.#fileName,
369
+ existsSpec
370
+ });
371
+ }
372
+ async genClassTestCode(data) {
373
+ if (!data.classFunctions.length) {
374
+ return [3 /* GenerateResult.Skip */];
375
+ }
376
+ if (!this.isLineMatch(data.linesRange)) {
377
+ return [3 /* GenerateResult.Skip */];
378
+ }
379
+ if (!this.isLineRangeMatch(data.linesRange)) {
380
+ return [3 /* GenerateResult.Skip */];
381
+ }
382
+ if ((0, config_1.getConfig)().common.ignoreFuncs?.has(`${data.name}.*`)) {
383
+ return [3 /* GenerateResult.Skip */];
384
+ }
385
+ const isDataConnector = this.#fileName.includes('.connector.') && data.name.endsWith('Connector');
386
+ const classDeclare = (0, analyze_1.getCode)(data, {
387
+ beforeImports: '// external import declarations:\n',
388
+ beforeLocal: `// dependencies in the same file (./${this.#fileName}):\n`,
389
+ beforeCode: '// test target code:\n'
390
+ });
391
+ const res = [];
392
+ const declareMap = {};
393
+ // for wc
394
+ const commonDeclares = {};
395
+ for (const module in data.importDeclares) {
396
+ const declares = data.importDeclares[module];
397
+ for (const declare of declares) {
398
+ if ((module === '@msnews/experiences-web-component' && declare.name === 'WebComponentExperience')
399
+ || (module === '@cs-core/foundation' && ['attr', 'observable', 'volatile', 'FASTElement'].includes(declare.name))) {
400
+ if (!commonDeclares[module]) {
401
+ commonDeclares[module] = [];
402
+ }
403
+ commonDeclares[module].push(declare);
404
+ // skip the declares of web component
405
+ continue;
406
+ }
407
+ declareMap[declare.name] = module;
408
+ }
409
+ }
410
+ const ignoreFuncs = (0, config_1.getConfig)().common.ignoreFuncs;
411
+ for (let i = 0; i < data.classFunctions.length; i++) {
412
+ const member = data.classFunctions[i];
413
+ if (!this.isLineMatch(member.linesRange)) {
414
+ res.push(3 /* GenerateResult.Skip */);
415
+ continue;
416
+ }
417
+ if (!this.isLineRangeMatch(member.linesRange)) {
418
+ res.push(3 /* GenerateResult.Skip */);
419
+ continue;
420
+ }
421
+ // if this.options?.methods is not empty && current function is not in the methods set to gen test, skip it
422
+ if (this.options?.methods?.size && !this.options.methods.has(member.name)) {
423
+ continue;
424
+ }
425
+ if (ignoreFuncs?.has(`${data.name}.${member.name}`)
426
+ || ignoreFuncs?.has(`*.${member.name}`)) {
427
+ continue;
428
+ }
429
+ if (reactFunctionSet.has(member.name)) {
430
+ continue;
431
+ }
432
+ let existsSpec = this.isSpecExists(member.name, data.name);
433
+ let specCode;
434
+ if (existsSpec) {
435
+ if (!this.options?.repair) {
436
+ this.progress(`Spec file exists (${existsSpec.filePath}), please use "Update test" to fix`);
437
+ res.push(3 /* GenerateResult.Skip */);
438
+ continue;
439
+ }
440
+ specCode = await this.readExistingSpec(existsSpec.filePath);
441
+ }
442
+ this.progress(`Generating test code for ${data.name}.${member.name}`);
443
+ // get mocks
444
+ const declares = {
445
+ ...commonDeclares
446
+ };
447
+ for (const [id] of member.externalIdentifiers || []) {
448
+ const module = declareMap[id];
449
+ if (!module) {
450
+ continue;
451
+ }
452
+ if (!declares[module]) {
453
+ declares[module] = [];
454
+ }
455
+ declares[module].push({ name: id, declare: '' });
456
+ }
457
+ const mockString = (0, deps_1.getPackageMocks)(declares);
458
+ let codeTmpl = mockString;
459
+ if (isDataConnector) {
460
+ codeTmpl += `\n${llm_1.Templates.dataConnector(data.name, member.name)}`;
461
+ }
462
+ const promptKey = specCode ? "RepairClassMemberUT" /* PromptKey.RepairClassMemberUT */ : "GenClassMemberUT" /* PromptKey.GenClassMemberUT */;
463
+ const messages = (0, llm_1.getPrompt)(promptKey, {
464
+ ["<<<SourceFileName>>>" /* PromptPlaceholder.SourceFileName */]: this.#fileName,
465
+ ["<<<ClassName>>>" /* PromptPlaceholder.ClassName */]: (0, common_1.formatImportName)(data.name, data.isDefaultExport),
466
+ ["<<<FunctionName>>>" /* PromptPlaceholder.FunctionName */]: member.name,
467
+ ["<<<SpecFileName>>>" /* PromptPlaceholder.SpecFileName */]: `./${this.#filePrefix}.${this.#testFileSpecifier}${this.#fileSuffix}`,
468
+ ["<<<ClassDeclare>>>" /* PromptPlaceholder.ClassDeclare */]: classDeclare,
469
+ ["<<<SourceCode>>>" /* PromptPlaceholder.SourceCode */]: member.body,
470
+ ["<<<MockCode>>>" /* PromptPlaceholder.MockCode */]: codeTmpl,
471
+ ["<<<Spec>>>" /* PromptPlaceholder.SpecCode */]: specCode,
472
+ ["<<<Language>>>" /* PromptPlaceholder.Language */]: (0, common_1.getLanguage)(this.#fileSuffix),
473
+ ["<<<ModuleType>>>" /* PromptPlaceholder.ModuleType */]: data.isCommonJS ? "cjs" /* ModuleType.CJS */ : "esm" /* ModuleType.ESM */,
474
+ ["<<<TestFramework>>>" /* PromptPlaceholder.TestFramework */]: this.testFramework,
475
+ }, this.options?.promptConfigs?.[promptKey]);
476
+ const taskRes = await this.runTask({
477
+ messages,
478
+ testName: `${data.name}.${member.name}`,
479
+ targetCode: member.body,
480
+ mockString,
481
+ className: data.name,
482
+ testFuncName: member.name,
483
+ moduleName: this.#fileName,
484
+ existsSpec
485
+ });
486
+ res.push(taskRes);
487
+ }
488
+ return res;
489
+ }
490
+ isLineMatch(pos) {
491
+ if (!this.options?.selectedLine) {
492
+ return true;
493
+ }
494
+ return this.options.selectedLine >= pos[0] && this.options.selectedLine <= pos[1];
495
+ }
496
+ isLineRangeMatch(pos) {
497
+ if (!this.options?.lineRanges || this.options?.lineRanges.length === 0) {
498
+ return true;
499
+ }
500
+ return this.options?.lineRanges.some(([start, end]) => {
501
+ return !(pos[1] < start || pos[0] > end);
502
+ });
503
+ }
504
+ isFunctionMatch(functionName) {
505
+ if (!this.options?.methods || this.options.methods.size === 0) {
506
+ return true;
507
+ }
508
+ return this.options.methods?.has(functionName);
509
+ }
510
+ async runTask(params) {
511
+ const retry = (0, config_1.getConfig)().common.retryCount ?? 0;
512
+ let result;
513
+ for (let i = 0; i <= retry; ++i) {
514
+ await (0, system_1.sleep)(10);
515
+ result = await this._runTask(params);
516
+ if (result !== 1 /* GenerateResult.Failed */) {
517
+ return result;
518
+ }
519
+ }
520
+ return result;
521
+ }
522
+ async _runTask(params) {
523
+ const { messages, testName, testFuncName, targetCode, mockString, existsSpec, className } = params;
524
+ if (this.#stopped) {
525
+ return 3 /* GenerateResult.Skip */;
526
+ }
527
+ const tempSpecFileName = path_1.default.resolve(this.tempTestFileDir, `${this.#filePrefix}.${testName}.gptgen.${this.#testFileSpecifier}${this.#fileSuffix}`);
528
+ let testCode = '';
529
+ try {
530
+ this.log(`Generating test code from GPT: ${testName}`);
531
+ this.progress(`Fetching code from AI`);
532
+ const res = await (0, llm_1.getLLMResponse)(messages, {
533
+ momentum: true,
534
+ flag: 'generateTestCode'
535
+ });
536
+ if (!res.success) {
537
+ this.progress(`Failed to get code from AI: ${res.message}`, { lastFailed: true, failed: true });
538
+ this.error('Unknown AI response', res);
539
+ return 6 /* GenerateResult.GPTException */;
540
+ }
541
+ testCode = (0, common_1.extractCodeFromResponse)(res.content);
542
+ if (!testCode) {
543
+ this.progress(`Failed to get code from AI`, { lastFailed: true });
544
+ this.error('Unknown AI response format', res);
545
+ return 6 /* GenerateResult.GPTException */;
546
+ }
547
+ testCode = (0, mock_1.checkMock)(testCode) || testCode;
548
+ }
549
+ catch (error) {
550
+ this.error('Error when generating test code', error);
551
+ return 6 /* GenerateResult.GPTException */;
552
+ }
553
+ if (this.#stopped) {
554
+ return 3 /* GenerateResult.Skip */;
555
+ }
556
+ let needRunTest = this.options?.runTest && !this.#isInWSL;
557
+ if (this.#isInWSL) {
558
+ this.progress(`Detected file in WSL environment, skip running test, please run test manually in WSL`, {
559
+ failed: true,
560
+ link: {
561
+ url: 'https://eng.ms/docs/microsoft-ai/microsoft-ads-msn/feed-verticals/content-verticals/microsoft-weather/test-copilot/faq',
562
+ title: 'FAQ'
563
+ }
564
+ });
565
+ }
566
+ if (!needRunTest) {
567
+ (0, console_1.getConsole)().log('Generated test code:', testCode);
568
+ (0, console_1.getConsole)().log('Skip running test');
569
+ const testFilePath = await this.writeSpecFile(testCode, testName);
570
+ this.progress(`Running Lint for ${testName}`);
571
+ await (0, lint_1.runLint)(testFilePath, this.projectFolder);
572
+ return 2 /* GenerateResult.Success */;
573
+ }
574
+ // Use ValidFix to validate and fix test code
575
+ const validFix = new validFix_1.ValidFix({
576
+ progress: this.options?.progress,
577
+ promptConfigs: this.options?.promptConfigs,
578
+ abortSignal: this.options?.abortSignal,
579
+ testFramework: this.testFramework
580
+ });
581
+ const validResult = await validFix.run({
582
+ targetName: testName,
583
+ targetSourceCode: targetCode,
584
+ sourceMockCode: mockString,
585
+ inputSpecCode: testCode,
586
+ sourceFilePath: this.filePath,
587
+ specFilePath: tempSpecFileName,
588
+ projectFolder: this.projectFolder,
589
+ testFileSpecifier: this.#testFileSpecifier,
590
+ maxRetry: 3,
591
+ });
592
+ let finalTestCode = validResult.code;
593
+ let testResult = validResult.testResult;
594
+ let success = validResult.status === 'valid';
595
+ if (fs_1.default.existsSync(tempSpecFileName)) {
596
+ const saveFailed = (0, config_1.getConfig)().common.saveFailed;
597
+ if (success || !saveFailed || this.#stopped) {
598
+ if (!saveFailed) {
599
+ this.progress(`Removing temporary spec file: ${tempSpecFileName}`);
600
+ }
601
+ (0, system_1.removeFile)(tempSpecFileName);
602
+ }
603
+ else if (saveFailed) {
604
+ const newFile = tempSpecFileName.replace('.gptgen', '.failed');
605
+ fs_1.default.renameSync(tempSpecFileName, newFile);
606
+ fs_1.default.appendFileSync(newFile, `\n/*\n${JSON.stringify(testResult, null, 4)}\n*/`);
607
+ }
608
+ }
609
+ if (this.#stopped) {
610
+ return 3 /* GenerateResult.Skip */;
611
+ }
612
+ let validationRes = true;
613
+ try {
614
+ if (className) {
615
+ validationRes = (0, validateMockedTest_1.validateMockedClassTest)(finalTestCode, testFuncName, className, this.#fileName);
616
+ }
617
+ else {
618
+ validationRes = (0, validateMockedTest_1.validateMockedFuncTest)(finalTestCode, testFuncName, this.#fileName);
619
+ }
620
+ }
621
+ catch (error) {
622
+ this.error('Error when validating test code', error);
623
+ }
624
+ if (success && validationRes) {
625
+ const testFilePath = await this.writeSpecFile(finalTestCode, testName, existsSpec);
626
+ this.progress(`Running Lint autofix for ${testName}`);
627
+ const lintResult = await (0, lint_1.runLintWithAutofix)(testFilePath, this.testFramework, this.options?.abortSignal, this.projectFolder);
628
+ if (!lintResult.success) {
629
+ this.error(`Lint autofix failed for generated test file: ${testFilePath}`);
630
+ (0, system_1.removeFile)(testFilePath);
631
+ this.progress(`Lint autofix failed for ${testName}, removed the generated test file`, {
632
+ failed: true,
633
+ extra: {
634
+ title: 'Lint info',
635
+ content: `[Lint] Lint issues can't be autofixed for ${testName}, errors: ${lintResult.errors?.join('\n')}`
636
+ }
637
+ });
638
+ return 1 /* GenerateResult.Failed */;
639
+ }
640
+ this.progress(`Success to generate test code for ${testName}`);
641
+ return 2 /* GenerateResult.Success */;
642
+ }
643
+ if (!testResult) {
644
+ this.error('[Remove] Unknown error when running test: undefined');
645
+ return 4 /* GenerateResult.Exception */;
646
+ }
647
+ if (!validationRes) {
648
+ this.log(`[Validate] The test for ${testName} does not test real logic`);
649
+ this.progress(`Failed to generate test code for ${testName}`, {
650
+ lastFailed: true,
651
+ extra: {
652
+ title: 'Test info',
653
+ content: `[Validate] The test for ${testName} does not test real logic`
654
+ }
655
+ });
656
+ return 1 /* GenerateResult.Failed */;
657
+ }
658
+ if (testResult.numFailedTestSuites === testResult.numTotalTestSuites && testResult.numFailedTests === testResult.numTotalTests) {
659
+ this.log('All test cases failed, skip');
660
+ this.progress(`Failed to generate test code for ${testName}`, {
661
+ lastFailed: true,
662
+ extra: {
663
+ title: 'Test info',
664
+ content: JSON.stringify(testResult, null, 4)
665
+ }
666
+ });
667
+ return 1 /* GenerateResult.Failed */;
668
+ }
669
+ // Use RemoveFailedCases to remove failed test cases
670
+ this.progress(`Removing failed cases`, { lastFailed: true });
671
+ const removeFailedCases = new removeFailedCases_1.RemoveFailedCases({
672
+ progress: this.options?.progress,
673
+ abortSignal: this.options?.abortSignal
674
+ });
675
+ const removeResult = await removeFailedCases.run({
676
+ inputSpecCode: finalTestCode,
677
+ targetName: testName,
678
+ inputFailedCases: validResult.failedCases || [],
679
+ sourceFilePath: this.filePath,
680
+ specFilePath: tempSpecFileName,
681
+ projectFolder: this.projectFolder
682
+ });
683
+ if (this.#stopped) {
684
+ return 3 /* GenerateResult.Skip */;
685
+ }
686
+ if (removeResult.status === 'success') {
687
+ const testFilePath = await this.writeSpecFile(removeResult.code, testName);
688
+ this.progress(`Running Lint autofix for ${testName}`);
689
+ const lintResult = await (0, lint_1.runLintWithAutofix)(testFilePath, this.testFramework, this.options?.abortSignal, this.projectFolder);
690
+ if (!lintResult.success) {
691
+ this.error(`Lint autofix failed for generated test file: ${testFilePath}`);
692
+ (0, system_1.removeFile)(testFilePath);
693
+ this.progress(`Lint autofix failed for ${testName}, removed the generated test file`, {
694
+ failed: true,
695
+ extra: {
696
+ title: 'Lint info',
697
+ content: `[Lint] Lint issues can't be autofixed for ${testName}, errors: ${lintResult.errors?.join('\n')}`
698
+ }
699
+ });
700
+ return 1 /* GenerateResult.Failed */;
701
+ }
702
+ this.progress(`Success to generate test code for ${testName}`);
703
+ return 2 /* GenerateResult.Success */;
704
+ }
705
+ this.progress(`Failed to generate test code for ${testName}`, {
706
+ lastFailed: true,
707
+ extra: {
708
+ title: 'Test info',
709
+ content: JSON.stringify(testResult, null, 4)
710
+ }
711
+ });
712
+ return 1 /* GenerateResult.Failed */;
713
+ }
714
+ isSpecExists(targetFunctionName, className) {
715
+ // Check function level test file exists first
716
+ let filePath = this.isFunctionLevelTestExists(targetFunctionName, className);
717
+ if (filePath) {
718
+ this.progress(`Found [function level] test file: ${filePath}`);
719
+ return {
720
+ filePath,
721
+ isFileLevel: false
722
+ };
723
+ }
724
+ // If skip file level check, return directly
725
+ if (this.options?.skipFileLevelCheck) {
726
+ return undefined;
727
+ }
728
+ // If not found, check file level test file exists
729
+ filePath = this.isFileLevelTestExists(targetFunctionName);
730
+ if (filePath) {
731
+ this.progress(`Found [file level] test file: ${filePath}`);
732
+ return {
733
+ filePath,
734
+ isFileLevel: true
735
+ };
736
+ }
737
+ return undefined;
738
+ }
739
+ async readExistingSpec(specFilePath) {
740
+ let specCode = fs_1.default.readFileSync(specFilePath, 'utf8').toString();
741
+ const specDir = path_1.default.dirname(specFilePath);
742
+ // temporarily remove the file to the same directory as the source file
743
+ specCode = await (0, move_1.updateCodeReferences)(specDir, this.#fileDir, this.#fileName, specCode);
744
+ return specCode;
745
+ }
746
+ getSpecName(testName) {
747
+ return `${testName}.${this.#testFileSpecifier}${this.#fileSuffix}`;
748
+ }
749
+ isFileLevelTestExists(targetFunctionName) {
750
+ const fileNames = [`${this.#filePrefix}.${this.#testFileSpecifier}${this.#fileSuffix}`];
751
+ // for pergrine
752
+ if (this.#testFileSpecifier === 'web.spec') {
753
+ fileNames.push(`${this.#filePrefix}.${this.#testFileSpecifier.replace('.web', '')}${this.#fileSuffix}`);
754
+ }
755
+ else if (this.#testFileSpecifier === 'spec') {
756
+ fileNames.push(`${this.#filePrefix}.web.${this.#testFileSpecifier}${this.#fileSuffix}`);
757
+ }
758
+ const specDirs = [this.#fileDir];
759
+ if (this.#specDir !== this.#fileDir) {
760
+ specDirs.push(this.#specDir);
761
+ }
762
+ const checkList = specDirs.flatMap(dir => fileNames.map(fileName => path_1.default.resolve(dir, fileName)));
763
+ const filePath = this.checkFilesExist(checkList);
764
+ if (!filePath) {
765
+ return undefined;
766
+ }
767
+ const fileContent = fs_1.default.readFileSync(filePath, 'utf8').toString();
768
+ const regex = new RegExp(`\\b${targetFunctionName}\\b`, 'g');
769
+ return regex.test(fileContent) ? filePath : undefined;
770
+ }
771
+ isFunctionLevelTestExists(targetFunctionName, className) {
772
+ const testName = className ? `${className}.${targetFunctionName}` : targetFunctionName;
773
+ const filename = this.getSpecName(testName);
774
+ const oldSpecName = `${this.#filePrefix}.${testName}.${this.#testFileSpecifier}${this.#fileSuffix}`;
775
+ const oldWebSpecName = `${this.#filePrefix}.${testName}.web.${this.#testFileSpecifier}${this.#fileSuffix}`;
776
+ const rawSpecName = `${this.#filePrefix}.${this.#testFileSpecifier}${this.#fileSuffix}`;
777
+ return this.checkFilesExist([
778
+ path_1.default.resolve(this.#specDir, filename),
779
+ path_1.default.resolve(this.#specDir, rawSpecName),
780
+ path_1.default.resolve(this.#specDir, oldSpecName),
781
+ path_1.default.resolve(this.#specDir, oldWebSpecName),
782
+ ]);
783
+ }
784
+ checkFilesExist(files) {
785
+ return files.find(fs_1.default.existsSync);
786
+ }
787
+ toKebabCase(input) {
788
+ return input
789
+ .replace(/([a-z0-9])([A-Z])/g, '$1-$2') // insert - between lower & upper
790
+ .replace(/([A-Z])([A-Z][a-z])/g, '$1-$2') // handle consecutive uppercase scenarios, e.g. "TrackIDScroll" → "track-id-scroll"
791
+ .toLowerCase();
792
+ }
793
+ }
794
+ exports.UTGen = UTGen;
795
+ //# sourceMappingURL=UTGen.js.map