create-appraisejs 0.1.10-alpha.8 → 0.2.0-alpha.1

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 (414) hide show
  1. package/README.md +52 -52
  2. package/dist/cli.e2e.test.d.ts +2 -0
  3. package/dist/cli.e2e.test.d.ts.map +1 -0
  4. package/dist/cli.e2e.test.js +73 -0
  5. package/dist/cli.e2e.test.js.map +1 -0
  6. package/dist/config.test.d.ts +2 -0
  7. package/dist/config.test.d.ts.map +1 -0
  8. package/dist/config.test.js +65 -0
  9. package/dist/config.test.js.map +1 -0
  10. package/dist/copy-template.test.d.ts +2 -0
  11. package/dist/copy-template.test.d.ts.map +1 -0
  12. package/dist/copy-template.test.js +71 -0
  13. package/dist/copy-template.test.js.map +1 -0
  14. package/dist/download-repo.test.d.ts +2 -0
  15. package/dist/download-repo.test.d.ts.map +1 -0
  16. package/dist/download-repo.test.js +14 -0
  17. package/dist/download-repo.test.js.map +1 -0
  18. package/dist/install.test.d.ts +2 -0
  19. package/dist/install.test.d.ts.map +1 -0
  20. package/dist/install.test.js +119 -0
  21. package/dist/install.test.js.map +1 -0
  22. package/dist/prepare-template-utils.d.ts.map +1 -1
  23. package/dist/prepare-template-utils.js +5 -0
  24. package/dist/prepare-template-utils.js.map +1 -1
  25. package/dist/prompts.test.d.ts +2 -0
  26. package/dist/prompts.test.d.ts.map +1 -0
  27. package/dist/prompts.test.js +58 -0
  28. package/dist/prompts.test.js.map +1 -0
  29. package/dist/scaffold-gitignore.d.ts +1 -0
  30. package/dist/scaffold-gitignore.d.ts.map +1 -1
  31. package/dist/scaffold-gitignore.js +3 -0
  32. package/dist/scaffold-gitignore.js.map +1 -1
  33. package/package.json +3 -2
  34. package/templates/default/.appraise-template-meta.json +2 -2
  35. package/templates/default/.env.example +2 -2
  36. package/templates/default/.vscode/settings.json +2 -1
  37. package/templates/default/README.md +53 -53
  38. package/templates/default/automation/mapping/locator-map.json +1 -14
  39. package/templates/default/automation/steps/actions/click.step.ts +58 -58
  40. package/templates/default/automation/steps/actions/hover.step.ts +27 -27
  41. package/templates/default/automation/steps/actions/input.step.ts +84 -84
  42. package/templates/default/automation/steps/actions/navigation.step.ts +70 -70
  43. package/templates/default/automation/steps/actions/random_data.step.ts +142 -142
  44. package/templates/default/automation/steps/actions/store.step.ts +86 -86
  45. package/templates/default/automation/steps/actions/wait.step.ts +90 -90
  46. package/templates/default/automation/steps/validations/active_state_assertion.step.ts +30 -30
  47. package/templates/default/automation/steps/validations/navigation_assertion.step.ts +22 -22
  48. package/templates/default/automation/steps/validations/text_assertion.step.ts +107 -107
  49. package/templates/default/automation/steps/validations/visibility_assertion.step.ts +26 -26
  50. package/templates/default/components.json +24 -24
  51. package/templates/default/cucumber.mjs +16 -16
  52. package/templates/default/eslint.config.mjs +16 -16
  53. package/templates/default/gitignore +3 -0
  54. package/templates/default/next-env.d.ts +6 -6
  55. package/templates/default/next.config.ts +11 -11
  56. package/templates/default/package-lock.json +146 -75
  57. package/templates/default/package.json +2 -1
  58. package/templates/default/packages/cucumber-runtime/package.json +13 -13
  59. package/templates/default/packages/cucumber-runtime/src/cache.util.ts +93 -93
  60. package/templates/default/packages/cucumber-runtime/src/cli.ts +68 -68
  61. package/templates/default/packages/cucumber-runtime/src/environment.util.ts +21 -21
  62. package/templates/default/packages/cucumber-runtime/src/executor.ts +32 -32
  63. package/templates/default/packages/cucumber-runtime/src/hooks.ts +25 -3
  64. package/templates/default/packages/cucumber-runtime/src/index.ts +17 -17
  65. package/templates/default/packages/cucumber-runtime/src/locator.util.ts +234 -234
  66. package/templates/default/packages/cucumber-runtime/src/parameter-types.ts +7 -7
  67. package/templates/default/packages/cucumber-runtime/src/paths.ts +66 -1
  68. package/templates/default/packages/cucumber-runtime/src/random-data.util.ts +35 -35
  69. package/templates/default/packages/cucumber-runtime/src/types.ts +13 -13
  70. package/templates/default/packages/cucumber-runtime/src/world.ts +44 -44
  71. package/templates/default/packages/cucumber-runtime/tsconfig.json +11 -11
  72. package/templates/default/packages/locator-picker-companion/dist/cli.d.ts +1 -0
  73. package/templates/default/packages/locator-picker-companion/dist/cli.js +302 -0
  74. package/templates/default/packages/locator-picker-companion/dist/index.d.ts +3 -0
  75. package/templates/default/packages/locator-picker-companion/dist/index.js +3 -0
  76. package/templates/default/packages/locator-picker-companion/dist/injected-picker-script.d.ts +1 -0
  77. package/templates/default/packages/locator-picker-companion/dist/injected-picker-script.js +615 -0
  78. package/templates/default/packages/locator-picker-companion/dist/launcher.d.ts +11 -0
  79. package/templates/default/packages/locator-picker-companion/dist/launcher.js +59 -0
  80. package/templates/default/packages/locator-picker-companion/dist/selector-generator.d.ts +3 -0
  81. package/templates/default/packages/locator-picker-companion/dist/selector-generator.js +257 -0
  82. package/templates/default/packages/locator-picker-companion/dist/session-file.d.ts +22 -0
  83. package/templates/default/packages/locator-picker-companion/dist/session-file.js +150 -0
  84. package/templates/default/packages/locator-picker-companion/dist/types.d.ts +31 -0
  85. package/templates/default/packages/locator-picker-companion/dist/types.js +1 -0
  86. package/templates/default/packages/locator-picker-companion/package.json +17 -0
  87. package/templates/default/packages/locator-picker-companion/src/cli.ts +428 -0
  88. package/templates/default/packages/locator-picker-companion/src/index.ts +3 -0
  89. package/templates/default/packages/locator-picker-companion/src/injected-picker-script.ts +771 -0
  90. package/templates/default/packages/locator-picker-companion/src/launcher.ts +77 -0
  91. package/templates/default/packages/locator-picker-companion/src/selector-generator.ts +339 -0
  92. package/templates/default/packages/locator-picker-companion/src/session-file.ts +226 -0
  93. package/templates/default/packages/locator-picker-companion/src/types.ts +42 -0
  94. package/templates/default/packages/locator-picker-companion/tsconfig.json +14 -0
  95. package/templates/default/postcss.config.mjs +8 -8
  96. package/templates/default/prisma/dev.db +0 -0
  97. package/templates/default/prisma/migrations/20251104113456_add_type_for_template_step_groups/migration.sql +16 -16
  98. package/templates/default/prisma/migrations/20251104170946_add_tags_to_test_suite_and_test_case/migration.sql +27 -27
  99. package/templates/default/prisma/migrations/20251112190024_add_cascade_delete_to_test_run_test_case/migration.sql +17 -17
  100. package/templates/default/prisma/migrations/20251113181100_add_test_run_log/migration.sql +12 -12
  101. package/templates/default/prisma/migrations/20251119191838_add_tag_type/migration.sql +28 -28
  102. package/templates/default/prisma/migrations/20251121164059_add_conflict_resolution/migration.sql +12 -12
  103. package/templates/default/prisma/migrations/20251223183400_add_report_model_to_db_schema/migration.sql +10 -10
  104. package/templates/default/prisma/migrations/20251223183637_add_report_test_case_entity_for_storing_test_results_for_individual_test_cases/migration.sql +10 -10
  105. package/templates/default/prisma/migrations/20251224083549_add_comprehensive_report_storage/migration.sql +108 -108
  106. package/templates/default/prisma/migrations/20251229194422_migrate_duration_to_string/migration.sql +55 -55
  107. package/templates/default/prisma/migrations/20251230124637_add_unique_constraint_to_test_run_name/migration.sql +27 -27
  108. package/templates/default/prisma/migrations/20260115094436_add_dashboard_metrics/migration.sql +59 -59
  109. package/templates/default/prisma/migrations/20260127172022_add_cascade_delete_to_step_parameters/migration.sql +34 -34
  110. package/templates/default/prisma/migrations/20260313093000_add_report_step_screenshot_path/migration.sql +1 -0
  111. package/templates/default/prisma/migrations/20260318120000_add_test_suite_context_to_test_run_test_case/migration.sql +20 -0
  112. package/templates/default/prisma/migrations/20260318173512_add_support_of_test_suite_level_runs/migration.sql +2 -0
  113. package/templates/default/prisma/schema.prisma +4 -0
  114. package/templates/default/scripts/install-playwright.ts +20 -0
  115. package/templates/default/scripts/protect-seeded-files.ts +38 -38
  116. package/templates/default/scripts/regenerate-features.ts +94 -94
  117. package/templates/default/scripts/setup-env.ts +19 -19
  118. package/templates/default/scripts/sync-all.ts +22 -66
  119. package/templates/default/scripts/sync-appraise-base-template.ts +57 -19
  120. package/templates/default/scripts/sync-environments.ts +40 -21
  121. package/templates/default/scripts/sync-locator-groups.ts +410 -410
  122. package/templates/default/scripts/sync-locators.ts +398 -398
  123. package/templates/default/scripts/sync-modules.ts +341 -341
  124. package/templates/default/scripts/sync-tags.ts +2 -3
  125. package/templates/default/scripts/sync-template-step-groups.ts +0 -3
  126. package/templates/default/scripts/sync-template-steps.ts +37 -11
  127. package/templates/default/scripts/sync-test-cases.ts +68 -16
  128. package/templates/default/scripts/sync-test-suites.ts +7 -5
  129. package/templates/default/src/actions/conflict/conflict.action.ts +33 -33
  130. package/templates/default/src/actions/dashboard/dashboard-actions.ts +240 -240
  131. package/templates/default/src/actions/environments/environment-actions.ts +188 -188
  132. package/templates/default/src/actions/locator/locator-actions.ts +490 -490
  133. package/templates/default/src/actions/locator-groups/locator-group-actions.ts +6 -3
  134. package/templates/default/src/actions/locator-picker/locator-picker-actions.ts +243 -0
  135. package/templates/default/src/actions/modules/module-actions.ts +135 -135
  136. package/templates/default/src/actions/reports/report-actions.ts +51 -49
  137. package/templates/default/src/actions/review/review-actions.ts +147 -147
  138. package/templates/default/src/actions/settings/sync-actions.ts +46 -0
  139. package/templates/default/src/actions/tags/tag-actions.ts +107 -107
  140. package/templates/default/src/actions/template-step/template-step-actions.ts +38 -4
  141. package/templates/default/src/actions/template-step-group/template-step-group-actions.ts +10 -3
  142. package/templates/default/src/actions/template-test-case/template-test-case-actions.ts +238 -238
  143. package/templates/default/src/actions/test-case/test-case-actions.ts +356 -356
  144. package/templates/default/src/actions/test-run/test-run-actions.ts +222 -129
  145. package/templates/default/src/actions/test-suite/test-suite-actions.ts +95 -17
  146. package/templates/default/src/actions/user/user-actions.ts +13 -13
  147. package/templates/default/src/app/(base)/environments/create/page.tsx +28 -28
  148. package/templates/default/src/app/(base)/environments/environment-form.tsx +219 -219
  149. package/templates/default/src/app/(base)/environments/environment-table-columns.tsx +96 -96
  150. package/templates/default/src/app/(base)/environments/environment-table.tsx +24 -24
  151. package/templates/default/src/app/(base)/environments/modify/[id]/page.tsx +46 -46
  152. package/templates/default/src/app/(base)/environments/page.tsx +59 -59
  153. package/templates/default/src/app/(base)/layout.tsx +10 -10
  154. package/templates/default/src/app/(base)/locator-groups/create/page.tsx +44 -44
  155. package/templates/default/src/app/(base)/locator-groups/locator-group-form.tsx +215 -215
  156. package/templates/default/src/app/(base)/locator-groups/locator-group-table-columns.tsx +77 -77
  157. package/templates/default/src/app/(base)/locator-groups/locator-group-table.tsx +28 -28
  158. package/templates/default/src/app/(base)/locator-groups/modify/[id]/page.tsx +46 -46
  159. package/templates/default/src/app/(base)/locator-groups/page.tsx +20 -8
  160. package/templates/default/src/app/(base)/locators/create/create-locator-workspace.tsx +542 -0
  161. package/templates/default/src/app/(base)/locators/create/page.tsx +32 -19
  162. package/templates/default/src/app/(base)/locators/locator-form.tsx +163 -163
  163. package/templates/default/src/app/(base)/locators/locator-table-columns.tsx +73 -73
  164. package/templates/default/src/app/(base)/locators/locator-table.tsx +28 -28
  165. package/templates/default/src/app/(base)/locators/modify/[id]/page.tsx +56 -27
  166. package/templates/default/src/app/(base)/locators/page.tsx +13 -13
  167. package/templates/default/src/app/(base)/locators/picker/page.tsx +7 -0
  168. package/templates/default/src/app/(base)/locators/sync-locators-button.tsx +66 -66
  169. package/templates/default/src/app/(base)/modules/create/page.tsx +34 -34
  170. package/templates/default/src/app/(base)/modules/modify/[id]/page.tsx +46 -46
  171. package/templates/default/src/app/(base)/modules/module-form.tsx +126 -126
  172. package/templates/default/src/app/(base)/modules/module-table-columns.tsx +85 -85
  173. package/templates/default/src/app/(base)/modules/module-table.tsx +24 -24
  174. package/templates/default/src/app/(base)/modules/page.tsx +59 -59
  175. package/templates/default/src/app/(base)/reports/[id]/page.tsx +40 -33
  176. package/templates/default/src/app/(base)/reports/duration-chart.tsx +33 -33
  177. package/templates/default/src/app/(base)/reports/feature-chart.tsx +78 -78
  178. package/templates/default/src/app/(base)/reports/overview-chart.tsx +49 -46
  179. package/templates/default/src/app/(base)/reports/page.tsx +98 -98
  180. package/templates/default/src/app/(base)/reports/report-metric-card.tsx +78 -16
  181. package/templates/default/src/app/(base)/reports/report-table-columns.tsx +189 -189
  182. package/templates/default/src/app/(base)/reports/report-table.tsx +72 -72
  183. package/templates/default/src/app/(base)/reports/report-view-table-columns.tsx +12 -1
  184. package/templates/default/src/app/(base)/reports/report-view-table.tsx +1 -0
  185. package/templates/default/src/app/(base)/reports/test-cases/page.tsx +40 -42
  186. package/templates/default/src/app/(base)/reports/test-cases/test-cases-metric-table-columns.tsx +115 -115
  187. package/templates/default/src/app/(base)/reports/test-cases/test-cases-metric-table.tsx +27 -27
  188. package/templates/default/src/app/(base)/reports/test-suites/page.tsx +42 -42
  189. package/templates/default/src/app/(base)/reports/test-suites/test-suites-metric-table-columns.tsx +79 -79
  190. package/templates/default/src/app/(base)/reports/test-suites/test-suites-metric-table.tsx +27 -27
  191. package/templates/default/src/app/(base)/reports/view-logs-button.tsx +58 -60
  192. package/templates/default/src/app/(base)/reviews/create/page.tsx +26 -26
  193. package/templates/default/src/app/(base)/reviews/created-reviews-table.tsx +15 -15
  194. package/templates/default/src/app/(base)/reviews/modify/[id]/page.tsx +26 -26
  195. package/templates/default/src/app/(base)/reviews/page.tsx +26 -26
  196. package/templates/default/src/app/(base)/reviews/review/[id]/page.tsx +26 -26
  197. package/templates/default/src/app/(base)/reviews/review-form.tsx +11 -11
  198. package/templates/default/src/app/(base)/reviews/review-table-by-creator-columns.tsx +9 -9
  199. package/templates/default/src/app/(base)/reviews/review-table-by-reviewer-columns.tsx +9 -9
  200. package/templates/default/src/app/(base)/reviews/reviewer-reviews-table.tsx +15 -15
  201. package/templates/default/src/app/(base)/settings/page.tsx +30 -0
  202. package/templates/default/src/app/(base)/settings/settings-sync-panel.tsx +261 -0
  203. package/templates/default/src/app/(base)/tags/create/page.tsx +39 -39
  204. package/templates/default/src/app/(base)/tags/modify/[id]/page.tsx +50 -50
  205. package/templates/default/src/app/(base)/tags/page.tsx +58 -58
  206. package/templates/default/src/app/(base)/tags/tag-form.tsx +147 -147
  207. package/templates/default/src/app/(base)/tags/tag-table-columns.tsx +63 -63
  208. package/templates/default/src/app/(base)/tags/tag-table.tsx +29 -29
  209. package/templates/default/src/app/(base)/template-step-groups/create/page.tsx +28 -28
  210. package/templates/default/src/app/(base)/template-step-groups/modify/[id]/page.tsx +45 -45
  211. package/templates/default/src/app/(base)/template-step-groups/page.tsx +60 -60
  212. package/templates/default/src/app/(base)/template-step-groups/template-step-group-form.tsx +167 -167
  213. package/templates/default/src/app/(base)/template-step-groups/template-step-group-table-columns.tsx +89 -89
  214. package/templates/default/src/app/(base)/template-step-groups/template-step-group-table.tsx +32 -32
  215. package/templates/default/src/app/(base)/template-steps/create/page.tsx +37 -37
  216. package/templates/default/src/app/(base)/template-steps/modify/[id]/page.tsx +49 -49
  217. package/templates/default/src/app/(base)/template-steps/page.tsx +58 -58
  218. package/templates/default/src/app/(base)/template-steps/paramChip.tsx +213 -213
  219. package/templates/default/src/app/(base)/template-steps/template-step-form.tsx +384 -384
  220. package/templates/default/src/app/(base)/template-steps/template-step-table-columns.tsx +158 -158
  221. package/templates/default/src/app/(base)/template-steps/template-step-table.tsx +24 -24
  222. package/templates/default/src/app/(base)/template-test-cases/create/page.tsx +56 -56
  223. package/templates/default/src/app/(base)/template-test-cases/modify/[id]/page.tsx +89 -89
  224. package/templates/default/src/app/(base)/template-test-cases/page.tsx +58 -58
  225. package/templates/default/src/app/(base)/template-test-cases/template-test-case-flow.tsx +84 -84
  226. package/templates/default/src/app/(base)/template-test-cases/template-test-case-form.tsx +262 -262
  227. package/templates/default/src/app/(base)/template-test-cases/template-test-case-table-columns.tsx +76 -76
  228. package/templates/default/src/app/(base)/template-test-cases/template-test-case-table.tsx +32 -32
  229. package/templates/default/src/app/(base)/test-cases/create/page.tsx +76 -76
  230. package/templates/default/src/app/(base)/test-cases/create-from-template/generate/[id]/page.tsx +96 -96
  231. package/templates/default/src/app/(base)/test-cases/create-from-template/page.tsx +38 -38
  232. package/templates/default/src/app/(base)/test-cases/create-from-template/template-selection-form.tsx +73 -73
  233. package/templates/default/src/app/(base)/test-cases/modify/[id]/page.tsx +106 -106
  234. package/templates/default/src/app/(base)/test-cases/page.tsx +2 -2
  235. package/templates/default/src/app/(base)/test-cases/test-case-flow.tsx +82 -82
  236. package/templates/default/src/app/(base)/test-cases/test-case-form.tsx +395 -395
  237. package/templates/default/src/app/(base)/test-cases/test-case-table-columns.tsx +6 -71
  238. package/templates/default/src/app/(base)/test-cases/test-case-table.tsx +2 -2
  239. package/templates/default/src/app/(base)/test-runs/[id]/page.tsx +4 -1
  240. package/templates/default/src/app/(base)/test-runs/create/page.tsx +11 -9
  241. package/templates/default/src/app/(base)/test-runs/page.tsx +60 -60
  242. package/templates/default/src/app/(base)/test-runs/test-run-form.tsx +37 -44
  243. package/templates/default/src/app/(base)/test-runs/test-run-table-columns.tsx +229 -229
  244. package/templates/default/src/app/(base)/test-runs/test-run-table.tsx +127 -127
  245. package/templates/default/src/app/(base)/test-suites/create/page.tsx +3 -2
  246. package/templates/default/src/app/(base)/test-suites/modify/[id]/page.tsx +2 -1
  247. package/templates/default/src/app/(base)/test-suites/page.tsx +57 -21
  248. package/templates/default/src/app/(base)/test-suites/test-suite-form.tsx +16 -17
  249. package/templates/default/src/app/(base)/test-suites/test-suite-table-columns.tsx +2 -1
  250. package/templates/default/src/app/(base)/test-suites/test-suite-table.tsx +29 -29
  251. package/templates/default/src/app/(dashboard-components)/app-drawer.tsx +187 -187
  252. package/templates/default/src/app/(dashboard-components)/data-card-grid.tsx +12 -12
  253. package/templates/default/src/app/(dashboard-components)/data-card.tsx +26 -26
  254. package/templates/default/src/app/(dashboard-components)/execution-health-panel.tsx +56 -56
  255. package/templates/default/src/app/(dashboard-components)/ongoing-test-runs-card.tsx +87 -87
  256. package/templates/default/src/app/(dashboard-components)/quick-actions-drawer.tsx +44 -44
  257. package/templates/default/src/app/api/reports/steps/[stepId]/screenshot/route.ts +52 -0
  258. package/templates/default/src/app/api/test-runs/[runId]/download/route.ts +97 -34
  259. package/templates/default/src/app/api/test-runs/[runId]/logs/route.ts +4 -1
  260. package/templates/default/src/app/api/test-runs/[runId]/trace/[testCaseId]/route.ts +146 -147
  261. package/templates/default/src/app/globals.css +147 -147
  262. package/templates/default/src/app/layout.tsx +4 -0
  263. package/templates/default/src/app/page.tsx +2 -0
  264. package/templates/default/src/assets/icons/empty-tube.tsx +23 -23
  265. package/templates/default/src/assets/icons/tube-plus.tsx +29 -29
  266. package/templates/default/src/components/base-node.tsx +21 -21
  267. package/templates/default/src/components/chart/pie-chart.tsx +73 -73
  268. package/templates/default/src/components/data-extraction/locator-inspector.tsx +460 -460
  269. package/templates/default/src/components/data-state/empty-state.tsx +40 -40
  270. package/templates/default/src/components/data-visualization/info-card.tsx +70 -70
  271. package/templates/default/src/components/data-visualization/info-grid.tsx +22 -22
  272. package/templates/default/src/components/diagram/button-edge.tsx +54 -54
  273. package/templates/default/src/components/diagram/dynamic-parameters.tsx +474 -474
  274. package/templates/default/src/components/diagram/edit-header-option.tsx +36 -36
  275. package/templates/default/src/components/diagram/flow-diagram.tsx +470 -470
  276. package/templates/default/src/components/diagram/node-form.tsx +262 -262
  277. package/templates/default/src/components/diagram/options-header-node.tsx +57 -57
  278. package/templates/default/src/components/diagram/template-step-combobox.tsx +155 -155
  279. package/templates/default/src/components/form/error-message.tsx +7 -7
  280. package/templates/default/src/components/kokonutui/smooth-tab.tsx +453 -453
  281. package/templates/default/src/components/loading-skeleton/data-table/data-table-skeleton.tsx +30 -30
  282. package/templates/default/src/components/loading-skeleton/form/button-skeleton.tsx +8 -8
  283. package/templates/default/src/components/loading-skeleton/form/icon-button-skeleton.tsx +8 -8
  284. package/templates/default/src/components/loading-skeleton/form/text-input-skeleton.tsx +8 -8
  285. package/templates/default/src/components/loading-skeleton/visualization/table-skeleton.tsx +14 -14
  286. package/templates/default/src/components/logo.tsx +15 -15
  287. package/templates/default/src/components/navigation/command-badge.tsx +34 -34
  288. package/templates/default/src/components/navigation/command-chain-input.tsx +51 -51
  289. package/templates/default/src/components/navigation/entity-search-command.tsx +116 -116
  290. package/templates/default/src/components/navigation/nav-card.tsx +31 -31
  291. package/templates/default/src/components/navigation/nav-command.tsx +13 -0
  292. package/templates/default/src/components/navigation/nav-link.tsx +60 -60
  293. package/templates/default/src/components/navigation/nav-menu-card-deck.tsx +112 -112
  294. package/templates/default/src/components/node-header.tsx +159 -159
  295. package/templates/default/src/components/reports/test-case-logs-modal.tsx +310 -253
  296. package/templates/default/src/components/table/table-actions.tsx +172 -172
  297. package/templates/default/src/components/test-case/test-case-columns.tsx +76 -0
  298. package/templates/default/src/components/test-case/test-case-picker.tsx +244 -0
  299. package/templates/default/src/components/test-run/download-logs-button.tsx +92 -99
  300. package/templates/default/src/components/test-run/log-viewer.tsx +1 -14
  301. package/templates/default/src/components/test-run/test-run-details.tsx +15 -2
  302. package/templates/default/src/components/test-run/test-run-header.tsx +149 -149
  303. package/templates/default/src/components/test-run/view-report-button.tsx +102 -102
  304. package/templates/default/src/components/test-suite/test-suite-picker.tsx +444 -0
  305. package/templates/default/src/components/theme/mode-toggle.tsx +54 -54
  306. package/templates/default/src/components/theme/theme-provider.tsx +8 -8
  307. package/templates/default/src/components/typography/page-header-subtitle.tsx +7 -7
  308. package/templates/default/src/components/typography/page-header.tsx +7 -7
  309. package/templates/default/src/components/ui/alert-dialog.tsx +106 -106
  310. package/templates/default/src/components/ui/alert.tsx +43 -43
  311. package/templates/default/src/components/ui/avatar.tsx +40 -40
  312. package/templates/default/src/components/ui/badge.tsx +29 -29
  313. package/templates/default/src/components/ui/button.tsx +47 -47
  314. package/templates/default/src/components/ui/calendar.tsx +158 -158
  315. package/templates/default/src/components/ui/card.tsx +43 -43
  316. package/templates/default/src/components/ui/checkbox.tsx +28 -28
  317. package/templates/default/src/components/ui/command.tsx +135 -135
  318. package/templates/default/src/components/ui/data-table-column-header.tsx +61 -61
  319. package/templates/default/src/components/ui/data-table-pagination.tsx +87 -87
  320. package/templates/default/src/components/ui/data-table-view-options.tsx +50 -50
  321. package/templates/default/src/components/ui/data-table.tsx +261 -261
  322. package/templates/default/src/components/ui/dialog.tsx +97 -97
  323. package/templates/default/src/components/ui/dropdown-menu.tsx +182 -182
  324. package/templates/default/src/components/ui/input.tsx +22 -22
  325. package/templates/default/src/components/ui/kbd.tsx +28 -28
  326. package/templates/default/src/components/ui/label.tsx +19 -19
  327. package/templates/default/src/components/ui/loading.tsx +12 -12
  328. package/templates/default/src/components/ui/multi-select-with-preview.tsx +116 -116
  329. package/templates/default/src/components/ui/multi-select.tsx +142 -142
  330. package/templates/default/src/components/ui/navigation-menu.tsx +120 -120
  331. package/templates/default/src/components/ui/popover.tsx +33 -33
  332. package/templates/default/src/components/ui/progress.tsx +25 -25
  333. package/templates/default/src/components/ui/radio-group.tsx +44 -44
  334. package/templates/default/src/components/ui/scroll-area.tsx +40 -40
  335. package/templates/default/src/components/ui/select.tsx +151 -151
  336. package/templates/default/src/components/ui/separator.tsx +22 -22
  337. package/templates/default/src/components/ui/skeleton.tsx +7 -7
  338. package/templates/default/src/components/ui/table.tsx +76 -76
  339. package/templates/default/src/components/ui/tabs.tsx +55 -55
  340. package/templates/default/src/components/ui/textarea.tsx +21 -21
  341. package/templates/default/src/components/ui/toast.tsx +113 -113
  342. package/templates/default/src/components/ui/toaster.tsx +26 -26
  343. package/templates/default/src/components/user-prompt/delete-prompt.tsx +87 -87
  344. package/templates/default/src/config/db-config.ts +10 -10
  345. package/templates/default/src/constants/form-opts/diagram/node-form.ts +30 -30
  346. package/templates/default/src/constants/form-opts/environment-form-opts.ts +24 -24
  347. package/templates/default/src/constants/form-opts/locator-form-opts.ts +20 -20
  348. package/templates/default/src/constants/form-opts/locator-group-form-opts.ts +28 -28
  349. package/templates/default/src/constants/form-opts/module-form-opts.ts +21 -21
  350. package/templates/default/src/constants/form-opts/review-form-opts.ts +23 -23
  351. package/templates/default/src/constants/form-opts/tag-form-opts.ts +42 -42
  352. package/templates/default/src/constants/form-opts/template-selection-form-opts.ts +16 -16
  353. package/templates/default/src/constants/form-opts/template-step-group-form-opts.ts +24 -24
  354. package/templates/default/src/constants/form-opts/template-test-case-form-opts.ts +39 -39
  355. package/templates/default/src/constants/form-opts/template-test-step-form-opts.ts +36 -36
  356. package/templates/default/src/constants/form-opts/test-case-form-opts.ts +43 -43
  357. package/templates/default/src/constants/form-opts/test-run-form-opts.ts +5 -3
  358. package/templates/default/src/constants/form-opts/test-suite-form-opts.ts +24 -24
  359. package/templates/default/src/hooks/use-toast.ts +187 -187
  360. package/templates/default/src/lib/automation/paths.ts +42 -12
  361. package/templates/default/src/lib/automation/projection-service.ts +2 -1
  362. package/templates/default/src/lib/bidirectional-sync.ts +432 -432
  363. package/templates/default/src/lib/database-sync.ts +2 -7
  364. package/templates/default/src/lib/environment-file-utils.ts +184 -184
  365. package/templates/default/src/lib/executor/local-executor-adapter.ts +24 -25
  366. package/templates/default/src/lib/executor/types.ts +2 -2
  367. package/templates/default/src/lib/feature-file-generator.ts +5 -66
  368. package/templates/default/src/lib/gherkin-parser.ts +259 -259
  369. package/templates/default/src/lib/locator-group-file-utils.ts +307 -307
  370. package/templates/default/src/lib/locator-picker/session-manager.ts +452 -0
  371. package/templates/default/src/lib/locator-picker/suggestions.ts +124 -0
  372. package/templates/default/src/lib/metrics/metric-calculator.ts +5 -0
  373. package/templates/default/src/lib/module-hierarchy-builder.ts +205 -205
  374. package/templates/default/src/lib/path-helpers/module-path.ts +71 -71
  375. package/templates/default/src/lib/process/task-spawner.ts +39 -2
  376. package/templates/default/src/lib/sync/projected-feature-utils.ts +113 -0
  377. package/templates/default/src/lib/sync/sync-executor.ts +130 -0
  378. package/templates/default/src/lib/sync/sync-pending-counts.test.ts +239 -0
  379. package/templates/default/src/lib/sync/sync-pending-counts.ts +1358 -0
  380. package/templates/default/src/lib/sync/sync-registry.ts +149 -0
  381. package/templates/default/src/lib/tag-utils.ts +28 -0
  382. package/templates/default/src/lib/template-sync-utils.d.ts +6 -6
  383. package/templates/default/src/lib/template-sync-utils.js +46 -46
  384. package/templates/default/src/lib/template-sync-utils.ts +63 -63
  385. package/templates/default/src/lib/test-case-utils.ts +6 -6
  386. package/templates/default/src/lib/test-run/log-formatter.ts +83 -83
  387. package/templates/default/src/lib/test-run/matching.ts +117 -0
  388. package/templates/default/src/lib/test-run/process-manager.ts +2 -0
  389. package/templates/default/src/lib/test-run/report-parser.ts +352 -316
  390. package/templates/default/src/lib/test-run/test-run-executor.ts +13 -15
  391. package/templates/default/src/lib/test-run/winston-logger.ts +64 -66
  392. package/templates/default/src/lib/test-suite-identifier-service.ts +76 -0
  393. package/templates/default/src/lib/test-suite-utils.ts +6 -0
  394. package/templates/default/src/lib/transformers/gherkin-converter.ts +42 -42
  395. package/templates/default/src/lib/transformers/key-to-icon-transformer.tsx +95 -95
  396. package/templates/default/src/lib/transformers/template-test-case-converter.ts +160 -160
  397. package/templates/default/src/lib/utils/node-param-validation.ts +81 -81
  398. package/templates/default/src/lib/utils/template-step-file-generator.ts +104 -104
  399. package/templates/default/src/lib/utils/template-step-file-manager-intelligent.ts +0 -8
  400. package/templates/default/src/lib/utils/template-step-file-manager.ts +166 -166
  401. package/templates/default/src/lib/utils.ts +31 -31
  402. package/templates/default/src/types/diagram/diagram.ts +34 -34
  403. package/templates/default/src/types/diagram/template-step.ts +11 -11
  404. package/templates/default/src/types/executor/browser.type.ts +1 -1
  405. package/templates/default/src/types/form/actionHandler.ts +6 -6
  406. package/templates/default/src/types/locator/locator.type.ts +11 -11
  407. package/templates/default/src/types/locator-picker.ts +65 -0
  408. package/templates/default/src/types/step/step.type.ts +1 -1
  409. package/templates/default/src/types/table/data-table.ts +6 -6
  410. package/templates/default/src/types/test-case-picker.ts +6 -0
  411. package/templates/default/src/types/test-suite-picker.ts +18 -0
  412. package/templates/default/tailwind.config.ts +62 -62
  413. package/templates/default/tsconfig.json +4 -1
  414. package/templates/default/appraisejs.config.json +0 -1
@@ -1,307 +1,307 @@
1
- import { promises as fs } from 'fs'
2
- import path from 'path'
3
- import prisma from '@/config/db-config'
4
- import { buildModulePath } from '@/lib/path-helpers/module-path'
5
- import {
6
- ensureAutomationWorkspaceReady,
7
- getAutomationLocatorsDir,
8
- getAutomationMappingDir,
9
- } from '@/lib/automation/paths'
10
-
11
- export async function getLocatorGroupFilePath(locatorGroupId: string): Promise<string | null> {
12
- try {
13
- await ensureAutomationWorkspaceReady()
14
- const locatorGroup = await prisma.locatorGroup.findUnique({
15
- where: { id: locatorGroupId },
16
- include: { module: true },
17
- })
18
-
19
- if (!locatorGroup) {
20
- return null
21
- }
22
-
23
- const allModules = await prisma.module.findMany()
24
- const modulePath = buildModulePath(allModules, locatorGroup.module)
25
- const sanitizedPath = modulePath.replace(/^\//, '').replace(/\//g, path.sep)
26
- const fileName = `${locatorGroup.name}.json`
27
-
28
- return path.join(getAutomationLocatorsDir(), sanitizedPath, fileName)
29
- } catch (error) {
30
- console.error('Error getting locator group file path:', error)
31
- return null
32
- }
33
- }
34
-
35
- export async function generateLocatorGroupContent(locatorGroupId: string): Promise<Record<string, string>> {
36
- try {
37
- const locatorGroup = await prisma.locatorGroup.findUnique({
38
- where: { id: locatorGroupId },
39
- include: {
40
- locators: {
41
- select: { name: true, value: true },
42
- },
43
- },
44
- })
45
-
46
- if (!locatorGroup) {
47
- return {}
48
- }
49
-
50
- return Object.fromEntries(locatorGroup.locators.map(locator => [locator.name, locator.value]))
51
- } catch (error) {
52
- console.error('Error generating locator group content:', error)
53
- return {}
54
- }
55
- }
56
-
57
- export async function ensureDirectoryExists(filePath: string): Promise<void> {
58
- await ensureAutomationWorkspaceReady()
59
- await fs.mkdir(path.dirname(filePath), { recursive: true })
60
- }
61
-
62
- export async function createOrUpdateLocatorGroupFile(locatorGroupId: string): Promise<boolean> {
63
- try {
64
- await ensureAutomationWorkspaceReady()
65
- const filePath = await getLocatorGroupFilePath(locatorGroupId)
66
- if (!filePath) {
67
- return false
68
- }
69
-
70
- await ensureDirectoryExists(filePath)
71
- const content = await generateLocatorGroupContent(locatorGroupId)
72
- await fs.writeFile(filePath, JSON.stringify(content, null, 2))
73
- return true
74
- } catch (error) {
75
- console.error('Error creating/updating locator group file:', error)
76
- return false
77
- }
78
- }
79
-
80
- export async function deleteLocatorGroupFile(locatorGroupId: string, filePathOverride?: string): Promise<boolean> {
81
- try {
82
- await ensureAutomationWorkspaceReady()
83
- const filePath = filePathOverride ?? (await getLocatorGroupFilePath(locatorGroupId))
84
- if (!filePath) {
85
- return false
86
- }
87
-
88
- try {
89
- await fs.access(filePath)
90
- } catch {
91
- return true
92
- }
93
-
94
- await fs.unlink(filePath)
95
- await cleanupEmptyDirectories(filePath)
96
- return true
97
- } catch (error) {
98
- console.error('Error deleting locator group file:', error)
99
- return false
100
- }
101
- }
102
-
103
- export async function renameLocatorGroupFile(
104
- locatorGroupId: string,
105
- newName: string,
106
- oldName?: string,
107
- ): Promise<boolean> {
108
- try {
109
- await ensureAutomationWorkspaceReady()
110
- const currentFilePath = await getLocatorGroupFilePath(locatorGroupId)
111
- if (!currentFilePath) {
112
- return false
113
- }
114
-
115
- const oldFilePath = oldName ? path.join(path.dirname(currentFilePath), `${oldName}.json`) : currentFilePath
116
- const newFilePath = path.join(path.dirname(currentFilePath), `${newName}.json`)
117
-
118
- try {
119
- await fs.access(oldFilePath)
120
- await fs.rename(oldFilePath, newFilePath)
121
- } catch {
122
- return createOrUpdateLocatorGroupFile(locatorGroupId)
123
- }
124
-
125
- return true
126
- } catch (error) {
127
- console.error('Error renaming locator group file:', error)
128
- return false
129
- }
130
- }
131
-
132
- export async function moveLocatorGroupFile(locatorGroupId: string, previousFilePath?: string): Promise<boolean> {
133
- try {
134
- await ensureAutomationWorkspaceReady()
135
- if (previousFilePath) {
136
- await deleteLocatorGroupFile(locatorGroupId, previousFilePath)
137
- }
138
-
139
- return createOrUpdateLocatorGroupFile(locatorGroupId)
140
- } catch (error) {
141
- console.error('Error moving locator group file:', error)
142
- return false
143
- }
144
- }
145
-
146
- async function cleanupEmptyDirectories(filePath: string): Promise<void> {
147
- let currentDir = path.dirname(filePath)
148
- const locatorsRoot = getAutomationLocatorsDir()
149
-
150
- while (currentDir.startsWith(locatorsRoot) && currentDir !== locatorsRoot && currentDir !== path.dirname(currentDir)) {
151
- try {
152
- const files = await fs.readdir(currentDir)
153
- if (files.length === 0) {
154
- await fs.rmdir(currentDir)
155
- currentDir = path.dirname(currentDir)
156
- } else {
157
- break
158
- }
159
- } catch {
160
- break
161
- }
162
- }
163
- }
164
-
165
- export async function createEmptyLocatorGroupFile(locatorGroupId: string): Promise<boolean> {
166
- try {
167
- await ensureAutomationWorkspaceReady()
168
- const filePath = await getLocatorGroupFilePath(locatorGroupId)
169
- if (!filePath) {
170
- return false
171
- }
172
-
173
- await ensureDirectoryExists(filePath)
174
- await fs.writeFile(filePath, JSON.stringify({}, null, 2))
175
- return true
176
- } catch (error) {
177
- console.error('Error creating empty locator group file:', error)
178
- return false
179
- }
180
- }
181
-
182
- export async function readLocatorGroupFile(
183
- locatorGroupId: string,
184
- ): Promise<{ filePath: string; content: Record<string, string> } | null> {
185
- try {
186
- await ensureAutomationWorkspaceReady()
187
- const filePath = await getLocatorGroupFilePath(locatorGroupId)
188
- if (!filePath) {
189
- return null
190
- }
191
-
192
- const fileContent = await fs.readFile(filePath, 'utf-8')
193
- return { filePath, content: JSON.parse(fileContent) }
194
- } catch (error) {
195
- console.error('Error reading locator group file:', error)
196
- return null
197
- }
198
- }
199
-
200
- export async function updateLocatorMapFile(
201
- currentLocatorGroupRoute: string,
202
- newLocatorGroupRoute: string,
203
- currentLocatorGroupName: string,
204
- newLocatorGroupName: string,
205
- ): Promise<boolean>
206
- export async function updateLocatorMapFile(newLocatorGroupName: string, newLocatorGroupRoute: string): Promise<boolean>
207
- export async function updateLocatorMapFile(
208
- param1: string,
209
- param2: string,
210
- param3?: string,
211
- param4?: string,
212
- ): Promise<boolean> {
213
- try {
214
- await ensureAutomationWorkspaceReady()
215
- const locatorMapPath = path.join(getAutomationMappingDir(), 'locator-map.json')
216
- await ensureDirectoryExists(locatorMapPath)
217
-
218
- let locatorMap: Array<{ name: string; path: string }> = []
219
-
220
- try {
221
- const fileContent = await fs.readFile(locatorMapPath, 'utf-8')
222
- locatorMap = JSON.parse(fileContent)
223
- } catch {
224
- locatorMap = []
225
- }
226
-
227
- const isNewEntry = param3 === undefined && param4 === undefined
228
-
229
- if (isNewEntry) {
230
- const name = param1
231
- const route = param2
232
- const existingEntry = locatorMap.find(entry => entry.name === name)
233
- if (existingEntry) {
234
- console.error(`Locator group with name "${name}" already exists in locator map`)
235
- return false
236
- }
237
-
238
- locatorMap.push({ name, path: route })
239
- } else {
240
- const currentLocatorGroupRoute = param1
241
- const newLocatorGroupRoute = param2
242
- const currentLocatorGroupName = param3!
243
- const newLocatorGroupName = param4!
244
-
245
- const entryIndex = locatorMap.findIndex(entry => entry.name === currentLocatorGroupName)
246
- if (entryIndex === -1) {
247
- console.error(`Locator group with name "${currentLocatorGroupName}" not found in locator map`)
248
- return false
249
- }
250
-
251
- if (currentLocatorGroupName !== newLocatorGroupName) {
252
- const existingEntry = locatorMap.find(entry => entry.name === newLocatorGroupName)
253
- if (existingEntry) {
254
- console.error(`Locator group with name "${newLocatorGroupName}" already exists in locator map`)
255
- return false
256
- }
257
- }
258
-
259
- const updatedEntry = { ...locatorMap[entryIndex] }
260
-
261
- if (currentLocatorGroupName !== newLocatorGroupName) {
262
- updatedEntry.name = newLocatorGroupName
263
- }
264
-
265
- if (currentLocatorGroupRoute !== newLocatorGroupRoute) {
266
- updatedEntry.path = newLocatorGroupRoute
267
- }
268
-
269
- locatorMap[entryIndex] = updatedEntry
270
- }
271
-
272
- await fs.writeFile(locatorMapPath, JSON.stringify(locatorMap, null, 2))
273
- return true
274
- } catch (error) {
275
- console.error('Error updating locator map file:', error)
276
- return false
277
- }
278
- }
279
-
280
- export async function removeLocatorMapEntry(locatorGroupNames: string[]): Promise<boolean> {
281
- try {
282
- await ensureAutomationWorkspaceReady()
283
- const locatorMapPath = path.join(getAutomationMappingDir(), 'locator-map.json')
284
-
285
- try {
286
- await fs.access(locatorMapPath)
287
- } catch {
288
- return true
289
- }
290
-
291
- const fileContent = await fs.readFile(locatorMapPath, 'utf-8')
292
- let locatorMap: Array<{ name: string; path: string }> = JSON.parse(fileContent)
293
-
294
- const originalLength = locatorMap.length
295
- locatorMap = locatorMap.filter(entry => !locatorGroupNames.includes(entry.name))
296
-
297
- if (originalLength === locatorMap.length) {
298
- return true
299
- }
300
-
301
- await fs.writeFile(locatorMapPath, JSON.stringify(locatorMap, null, 2))
302
- return true
303
- } catch (error) {
304
- console.error('Error removing locator map entries:', error)
305
- return false
306
- }
307
- }
1
+ import { promises as fs } from 'fs'
2
+ import path from 'path'
3
+ import prisma from '@/config/db-config'
4
+ import { buildModulePath } from '@/lib/path-helpers/module-path'
5
+ import {
6
+ ensureAutomationWorkspaceReady,
7
+ getAutomationLocatorsDir,
8
+ getAutomationMappingDir,
9
+ } from '@/lib/automation/paths'
10
+
11
+ export async function getLocatorGroupFilePath(locatorGroupId: string): Promise<string | null> {
12
+ try {
13
+ await ensureAutomationWorkspaceReady()
14
+ const locatorGroup = await prisma.locatorGroup.findUnique({
15
+ where: { id: locatorGroupId },
16
+ include: { module: true },
17
+ })
18
+
19
+ if (!locatorGroup) {
20
+ return null
21
+ }
22
+
23
+ const allModules = await prisma.module.findMany()
24
+ const modulePath = buildModulePath(allModules, locatorGroup.module)
25
+ const sanitizedPath = modulePath.replace(/^\//, '').replace(/\//g, path.sep)
26
+ const fileName = `${locatorGroup.name}.json`
27
+
28
+ return path.join(getAutomationLocatorsDir(), sanitizedPath, fileName)
29
+ } catch (error) {
30
+ console.error('Error getting locator group file path:', error)
31
+ return null
32
+ }
33
+ }
34
+
35
+ export async function generateLocatorGroupContent(locatorGroupId: string): Promise<Record<string, string>> {
36
+ try {
37
+ const locatorGroup = await prisma.locatorGroup.findUnique({
38
+ where: { id: locatorGroupId },
39
+ include: {
40
+ locators: {
41
+ select: { name: true, value: true },
42
+ },
43
+ },
44
+ })
45
+
46
+ if (!locatorGroup) {
47
+ return {}
48
+ }
49
+
50
+ return Object.fromEntries(locatorGroup.locators.map(locator => [locator.name, locator.value]))
51
+ } catch (error) {
52
+ console.error('Error generating locator group content:', error)
53
+ return {}
54
+ }
55
+ }
56
+
57
+ export async function ensureDirectoryExists(filePath: string): Promise<void> {
58
+ await ensureAutomationWorkspaceReady()
59
+ await fs.mkdir(path.dirname(filePath), { recursive: true })
60
+ }
61
+
62
+ export async function createOrUpdateLocatorGroupFile(locatorGroupId: string): Promise<boolean> {
63
+ try {
64
+ await ensureAutomationWorkspaceReady()
65
+ const filePath = await getLocatorGroupFilePath(locatorGroupId)
66
+ if (!filePath) {
67
+ return false
68
+ }
69
+
70
+ await ensureDirectoryExists(filePath)
71
+ const content = await generateLocatorGroupContent(locatorGroupId)
72
+ await fs.writeFile(filePath, JSON.stringify(content, null, 2))
73
+ return true
74
+ } catch (error) {
75
+ console.error('Error creating/updating locator group file:', error)
76
+ return false
77
+ }
78
+ }
79
+
80
+ export async function deleteLocatorGroupFile(locatorGroupId: string, filePathOverride?: string): Promise<boolean> {
81
+ try {
82
+ await ensureAutomationWorkspaceReady()
83
+ const filePath = filePathOverride ?? (await getLocatorGroupFilePath(locatorGroupId))
84
+ if (!filePath) {
85
+ return false
86
+ }
87
+
88
+ try {
89
+ await fs.access(filePath)
90
+ } catch {
91
+ return true
92
+ }
93
+
94
+ await fs.unlink(filePath)
95
+ await cleanupEmptyDirectories(filePath)
96
+ return true
97
+ } catch (error) {
98
+ console.error('Error deleting locator group file:', error)
99
+ return false
100
+ }
101
+ }
102
+
103
+ export async function renameLocatorGroupFile(
104
+ locatorGroupId: string,
105
+ newName: string,
106
+ oldName?: string,
107
+ ): Promise<boolean> {
108
+ try {
109
+ await ensureAutomationWorkspaceReady()
110
+ const currentFilePath = await getLocatorGroupFilePath(locatorGroupId)
111
+ if (!currentFilePath) {
112
+ return false
113
+ }
114
+
115
+ const oldFilePath = oldName ? path.join(path.dirname(currentFilePath), `${oldName}.json`) : currentFilePath
116
+ const newFilePath = path.join(path.dirname(currentFilePath), `${newName}.json`)
117
+
118
+ try {
119
+ await fs.access(oldFilePath)
120
+ await fs.rename(oldFilePath, newFilePath)
121
+ } catch {
122
+ return createOrUpdateLocatorGroupFile(locatorGroupId)
123
+ }
124
+
125
+ return true
126
+ } catch (error) {
127
+ console.error('Error renaming locator group file:', error)
128
+ return false
129
+ }
130
+ }
131
+
132
+ export async function moveLocatorGroupFile(locatorGroupId: string, previousFilePath?: string): Promise<boolean> {
133
+ try {
134
+ await ensureAutomationWorkspaceReady()
135
+ if (previousFilePath) {
136
+ await deleteLocatorGroupFile(locatorGroupId, previousFilePath)
137
+ }
138
+
139
+ return createOrUpdateLocatorGroupFile(locatorGroupId)
140
+ } catch (error) {
141
+ console.error('Error moving locator group file:', error)
142
+ return false
143
+ }
144
+ }
145
+
146
+ async function cleanupEmptyDirectories(filePath: string): Promise<void> {
147
+ let currentDir = path.dirname(filePath)
148
+ const locatorsRoot = getAutomationLocatorsDir()
149
+
150
+ while (currentDir.startsWith(locatorsRoot) && currentDir !== locatorsRoot && currentDir !== path.dirname(currentDir)) {
151
+ try {
152
+ const files = await fs.readdir(currentDir)
153
+ if (files.length === 0) {
154
+ await fs.rmdir(currentDir)
155
+ currentDir = path.dirname(currentDir)
156
+ } else {
157
+ break
158
+ }
159
+ } catch {
160
+ break
161
+ }
162
+ }
163
+ }
164
+
165
+ export async function createEmptyLocatorGroupFile(locatorGroupId: string): Promise<boolean> {
166
+ try {
167
+ await ensureAutomationWorkspaceReady()
168
+ const filePath = await getLocatorGroupFilePath(locatorGroupId)
169
+ if (!filePath) {
170
+ return false
171
+ }
172
+
173
+ await ensureDirectoryExists(filePath)
174
+ await fs.writeFile(filePath, JSON.stringify({}, null, 2))
175
+ return true
176
+ } catch (error) {
177
+ console.error('Error creating empty locator group file:', error)
178
+ return false
179
+ }
180
+ }
181
+
182
+ export async function readLocatorGroupFile(
183
+ locatorGroupId: string,
184
+ ): Promise<{ filePath: string; content: Record<string, string> } | null> {
185
+ try {
186
+ await ensureAutomationWorkspaceReady()
187
+ const filePath = await getLocatorGroupFilePath(locatorGroupId)
188
+ if (!filePath) {
189
+ return null
190
+ }
191
+
192
+ const fileContent = await fs.readFile(filePath, 'utf-8')
193
+ return { filePath, content: JSON.parse(fileContent) }
194
+ } catch (error) {
195
+ console.error('Error reading locator group file:', error)
196
+ return null
197
+ }
198
+ }
199
+
200
+ export async function updateLocatorMapFile(
201
+ currentLocatorGroupRoute: string,
202
+ newLocatorGroupRoute: string,
203
+ currentLocatorGroupName: string,
204
+ newLocatorGroupName: string,
205
+ ): Promise<boolean>
206
+ export async function updateLocatorMapFile(newLocatorGroupName: string, newLocatorGroupRoute: string): Promise<boolean>
207
+ export async function updateLocatorMapFile(
208
+ param1: string,
209
+ param2: string,
210
+ param3?: string,
211
+ param4?: string,
212
+ ): Promise<boolean> {
213
+ try {
214
+ await ensureAutomationWorkspaceReady()
215
+ const locatorMapPath = path.join(getAutomationMappingDir(), 'locator-map.json')
216
+ await ensureDirectoryExists(locatorMapPath)
217
+
218
+ let locatorMap: Array<{ name: string; path: string }> = []
219
+
220
+ try {
221
+ const fileContent = await fs.readFile(locatorMapPath, 'utf-8')
222
+ locatorMap = JSON.parse(fileContent)
223
+ } catch {
224
+ locatorMap = []
225
+ }
226
+
227
+ const isNewEntry = param3 === undefined && param4 === undefined
228
+
229
+ if (isNewEntry) {
230
+ const name = param1
231
+ const route = param2
232
+ const existingEntry = locatorMap.find(entry => entry.name === name)
233
+ if (existingEntry) {
234
+ console.error(`Locator group with name "${name}" already exists in locator map`)
235
+ return false
236
+ }
237
+
238
+ locatorMap.push({ name, path: route })
239
+ } else {
240
+ const currentLocatorGroupRoute = param1
241
+ const newLocatorGroupRoute = param2
242
+ const currentLocatorGroupName = param3!
243
+ const newLocatorGroupName = param4!
244
+
245
+ const entryIndex = locatorMap.findIndex(entry => entry.name === currentLocatorGroupName)
246
+ if (entryIndex === -1) {
247
+ console.error(`Locator group with name "${currentLocatorGroupName}" not found in locator map`)
248
+ return false
249
+ }
250
+
251
+ if (currentLocatorGroupName !== newLocatorGroupName) {
252
+ const existingEntry = locatorMap.find(entry => entry.name === newLocatorGroupName)
253
+ if (existingEntry) {
254
+ console.error(`Locator group with name "${newLocatorGroupName}" already exists in locator map`)
255
+ return false
256
+ }
257
+ }
258
+
259
+ const updatedEntry = { ...locatorMap[entryIndex] }
260
+
261
+ if (currentLocatorGroupName !== newLocatorGroupName) {
262
+ updatedEntry.name = newLocatorGroupName
263
+ }
264
+
265
+ if (currentLocatorGroupRoute !== newLocatorGroupRoute) {
266
+ updatedEntry.path = newLocatorGroupRoute
267
+ }
268
+
269
+ locatorMap[entryIndex] = updatedEntry
270
+ }
271
+
272
+ await fs.writeFile(locatorMapPath, JSON.stringify(locatorMap, null, 2))
273
+ return true
274
+ } catch (error) {
275
+ console.error('Error updating locator map file:', error)
276
+ return false
277
+ }
278
+ }
279
+
280
+ export async function removeLocatorMapEntry(locatorGroupNames: string[]): Promise<boolean> {
281
+ try {
282
+ await ensureAutomationWorkspaceReady()
283
+ const locatorMapPath = path.join(getAutomationMappingDir(), 'locator-map.json')
284
+
285
+ try {
286
+ await fs.access(locatorMapPath)
287
+ } catch {
288
+ return true
289
+ }
290
+
291
+ const fileContent = await fs.readFile(locatorMapPath, 'utf-8')
292
+ let locatorMap: Array<{ name: string; path: string }> = JSON.parse(fileContent)
293
+
294
+ const originalLength = locatorMap.length
295
+ locatorMap = locatorMap.filter(entry => !locatorGroupNames.includes(entry.name))
296
+
297
+ if (originalLength === locatorMap.length) {
298
+ return true
299
+ }
300
+
301
+ await fs.writeFile(locatorMapPath, JSON.stringify(locatorMap, null, 2))
302
+ return true
303
+ } catch (error) {
304
+ console.error('Error removing locator map entries:', error)
305
+ return false
306
+ }
307
+ }