create-appraisejs 0.2.0 → 0.3.0-alpha.0

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 (485) hide show
  1. package/README.md +12 -1
  2. package/package.json +1 -1
  3. package/templates/default/.appraise-template-meta.json +2 -2
  4. package/templates/default/.env.example +2 -2
  5. package/templates/default/README.md +57 -53
  6. package/templates/default/automation/steps/actions/click.step.ts +58 -58
  7. package/templates/default/automation/steps/actions/hover.step.ts +27 -27
  8. package/templates/default/automation/steps/actions/navigation.step.ts +70 -70
  9. package/templates/default/automation/steps/actions/random_data.step.ts +142 -142
  10. package/templates/default/automation/steps/actions/store.step.ts +86 -86
  11. package/templates/default/automation/steps/actions/wait.step.ts +110 -90
  12. package/templates/default/automation/steps/validations/active_state_assertion.step.ts +30 -30
  13. package/templates/default/automation/steps/validations/navigation_assertion.step.ts +22 -22
  14. package/templates/default/automation/steps/validations/text_assertion.step.ts +107 -107
  15. package/templates/default/automation/steps/validations/visibility_assertion.step.ts +26 -26
  16. package/templates/default/components.json +24 -24
  17. package/templates/default/cucumber.mjs +16 -16
  18. package/templates/default/eslint.config.mjs +20 -16
  19. package/templates/default/next-env.d.ts +6 -6
  20. package/templates/default/next.config.ts +20 -11
  21. package/templates/default/package-lock.json +1775 -74
  22. package/templates/default/package.json +8 -1
  23. package/templates/default/packages/cucumber-runtime/package.json +13 -13
  24. package/templates/default/packages/cucumber-runtime/src/cache.util.ts +93 -93
  25. package/templates/default/packages/cucumber-runtime/src/cli.ts +68 -68
  26. package/templates/default/packages/cucumber-runtime/src/environment.util.ts +21 -21
  27. package/templates/default/packages/cucumber-runtime/src/executor.ts +32 -32
  28. package/templates/default/packages/cucumber-runtime/src/index.ts +17 -17
  29. package/templates/default/packages/cucumber-runtime/src/locator.util.ts +234 -234
  30. package/templates/default/packages/cucumber-runtime/src/parameter-types.ts +7 -7
  31. package/templates/default/packages/cucumber-runtime/src/random-data.util.ts +35 -35
  32. package/templates/default/packages/cucumber-runtime/src/types.ts +13 -13
  33. package/templates/default/packages/cucumber-runtime/src/world.ts +44 -44
  34. package/templates/default/packages/cucumber-runtime/tsconfig.json +11 -11
  35. package/templates/default/postcss.config.mjs +8 -8
  36. package/templates/default/prisma/dev.db +0 -0
  37. package/templates/default/prisma/migrations/20251104113456_add_type_for_template_step_groups/migration.sql +16 -16
  38. package/templates/default/prisma/migrations/20251104170946_add_tags_to_test_suite_and_test_case/migration.sql +27 -27
  39. package/templates/default/prisma/migrations/20251112190024_add_cascade_delete_to_test_run_test_case/migration.sql +17 -17
  40. package/templates/default/prisma/migrations/20251113181100_add_test_run_log/migration.sql +12 -12
  41. package/templates/default/prisma/migrations/20251119191838_add_tag_type/migration.sql +28 -28
  42. package/templates/default/prisma/migrations/20251121164059_add_conflict_resolution/migration.sql +12 -12
  43. package/templates/default/prisma/migrations/20251223183400_add_report_model_to_db_schema/migration.sql +10 -10
  44. package/templates/default/prisma/migrations/20251223183637_add_report_test_case_entity_for_storing_test_results_for_individual_test_cases/migration.sql +10 -10
  45. package/templates/default/prisma/migrations/20251224083549_add_comprehensive_report_storage/migration.sql +108 -108
  46. package/templates/default/prisma/migrations/20251229194422_migrate_duration_to_string/migration.sql +55 -55
  47. package/templates/default/prisma/migrations/20251230124637_add_unique_constraint_to_test_run_name/migration.sql +27 -27
  48. package/templates/default/prisma/migrations/20260115094436_add_dashboard_metrics/migration.sql +59 -59
  49. package/templates/default/prisma/migrations/20260127172022_add_cascade_delete_to_step_parameters/migration.sql +34 -34
  50. package/templates/default/prisma/migrations/20260313093000_add_report_step_screenshot_path/migration.sql +1 -1
  51. package/templates/default/scripts/build-step-registry.ts +33 -0
  52. package/templates/default/scripts/install-playwright.ts +17 -8
  53. package/templates/default/scripts/install-template-step.ts +128 -0
  54. package/templates/default/scripts/lib/filename-utils.test.ts +24 -0
  55. package/templates/default/scripts/lib/filename-utils.ts +24 -0
  56. package/templates/default/scripts/lib/jsdoc-parser.test.ts +63 -0
  57. package/templates/default/scripts/lib/jsdoc-parser.ts +88 -0
  58. package/templates/default/scripts/lib/step-file-parser.test.ts +71 -0
  59. package/templates/default/scripts/lib/step-file-parser.ts +315 -0
  60. package/templates/default/scripts/lib/step-matcher.test.ts +86 -0
  61. package/templates/default/scripts/lib/step-matcher.ts +120 -0
  62. package/templates/default/scripts/lib/sync-script-runner.ts +23 -0
  63. package/templates/default/scripts/lib/sync-summary.ts +29 -0
  64. package/templates/default/scripts/lib/tag-parsing.test.ts +20 -0
  65. package/templates/default/scripts/lib/tag-parsing.ts +10 -0
  66. package/templates/default/scripts/lib/template-step-installer.test.ts +225 -0
  67. package/templates/default/scripts/lib/template-step-installer.ts +404 -0
  68. package/templates/default/scripts/lib/template-step-registry.test.ts +118 -0
  69. package/templates/default/scripts/lib/template-step-registry.ts +137 -0
  70. package/templates/default/scripts/protect-seeded-files.ts +51 -38
  71. package/templates/default/scripts/regenerate-features.ts +98 -94
  72. package/templates/default/scripts/run-vitest.ts +59 -0
  73. package/templates/default/scripts/setup-env.ts +26 -19
  74. package/templates/default/scripts/sync-all.ts +44 -54
  75. package/templates/default/scripts/sync-appraise-base-template.ts +44 -16
  76. package/templates/default/scripts/sync-environments.ts +22 -66
  77. package/templates/default/scripts/sync-locator-groups.ts +358 -410
  78. package/templates/default/scripts/sync-locators.ts +348 -398
  79. package/templates/default/scripts/sync-modules.ts +302 -341
  80. package/templates/default/scripts/sync-tags.ts +29 -65
  81. package/templates/default/scripts/sync-template-step-groups.ts +24 -182
  82. package/templates/default/scripts/sync-template-steps.ts +36 -493
  83. package/templates/default/scripts/sync-test-cases.ts +296 -539
  84. package/templates/default/scripts/sync-test-suites.ts +32 -79
  85. package/templates/default/src/actions/dashboard/dashboard-actions.ts +70 -241
  86. package/templates/default/src/actions/environments/environment-actions.ts +102 -188
  87. package/templates/default/src/actions/locator/locator-actions.ts +77 -490
  88. package/templates/default/src/actions/locator-groups/locator-group-actions.ts +34 -212
  89. package/templates/default/src/actions/locator-picker/locator-picker-actions.test.ts +81 -0
  90. package/templates/default/src/actions/locator-picker/locator-picker-actions.ts +20 -161
  91. package/templates/default/src/actions/modules/module-actions.ts +99 -135
  92. package/templates/default/src/actions/reports/report-actions.ts +28 -565
  93. package/templates/default/src/actions/settings/sync-actions.test.ts +58 -0
  94. package/templates/default/src/actions/tags/tag-actions.ts +99 -107
  95. package/templates/default/src/actions/template-step/template-step-actions.ts +33 -194
  96. package/templates/default/src/actions/template-step-group/template-step-group-actions.ts +35 -92
  97. package/templates/default/src/actions/template-test-case/template-test-case-actions.ts +98 -238
  98. package/templates/default/src/actions/test-case/test-case-actions.ts +108 -356
  99. package/templates/default/src/actions/test-run/test-run-actions.ts +74 -1081
  100. package/templates/default/src/actions/test-suite/test-suite-actions.ts +35 -202
  101. package/templates/default/src/app/(base)/environments/create/page.tsx +28 -28
  102. package/templates/default/src/app/(base)/environments/environment-form.test.tsx +92 -0
  103. package/templates/default/src/app/(base)/environments/environment-form.tsx +228 -219
  104. package/templates/default/src/app/(base)/environments/environment-helpers.ts +58 -0
  105. package/templates/default/src/app/(base)/environments/environment-table-columns.tsx +96 -96
  106. package/templates/default/src/app/(base)/environments/environment-table.tsx +25 -24
  107. package/templates/default/src/app/(base)/environments/modify/[id]/page.tsx +49 -46
  108. package/templates/default/src/app/(base)/environments/page.tsx +59 -59
  109. package/templates/default/src/app/(base)/layout.tsx +10 -10
  110. package/templates/default/src/app/(base)/locator-groups/create/page.tsx +44 -44
  111. package/templates/default/src/app/(base)/locator-groups/locator-group-form.tsx +215 -215
  112. package/templates/default/src/app/(base)/locator-groups/locator-group-table-columns.tsx +77 -77
  113. package/templates/default/src/app/(base)/locator-groups/locator-group-table.tsx +28 -28
  114. package/templates/default/src/app/(base)/locator-groups/modify/[id]/page.tsx +46 -46
  115. package/templates/default/src/app/(base)/locators/create/create-locator-workspace-helpers.test.ts +71 -0
  116. package/templates/default/src/app/(base)/locators/create/create-locator-workspace-helpers.ts +333 -0
  117. package/templates/default/src/app/(base)/locators/create/create-locator-workspace.test.tsx +125 -0
  118. package/templates/default/src/app/(base)/locators/create/create-locator-workspace.tsx +56 -274
  119. package/templates/default/src/app/(base)/locators/create/page.tsx +8 -4
  120. package/templates/default/src/app/(base)/locators/create/use-locator-workspace.ts +183 -0
  121. package/templates/default/src/app/(base)/locators/locator-helpers.test.ts +28 -0
  122. package/templates/default/src/app/(base)/locators/locator-helpers.ts +59 -0
  123. package/templates/default/src/app/(base)/locators/locator-table-columns.tsx +74 -73
  124. package/templates/default/src/app/(base)/locators/locator-table.tsx +30 -28
  125. package/templates/default/src/app/(base)/locators/modify/[id]/page.tsx +20 -8
  126. package/templates/default/src/app/(base)/locators/page.tsx +3 -6
  127. package/templates/default/src/app/(base)/locators/sync-locators-button.tsx +67 -66
  128. package/templates/default/src/app/(base)/modules/create/page.tsx +33 -34
  129. package/templates/default/src/app/(base)/modules/modify/[id]/page.tsx +43 -46
  130. package/templates/default/src/app/(base)/modules/module-form.test.tsx +84 -0
  131. package/templates/default/src/app/(base)/modules/module-form.tsx +159 -126
  132. package/templates/default/src/app/(base)/modules/module-helpers.ts +64 -0
  133. package/templates/default/src/app/(base)/modules/module-table-columns.tsx +81 -85
  134. package/templates/default/src/app/(base)/modules/module-table.tsx +25 -24
  135. package/templates/default/src/app/(base)/modules/page.tsx +59 -59
  136. package/templates/default/src/app/(base)/reports/[id]/page.tsx +20 -260
  137. package/templates/default/src/app/(base)/reports/duration-chart.tsx +33 -33
  138. package/templates/default/src/app/(base)/reports/feature-chart.tsx +79 -78
  139. package/templates/default/src/app/(base)/reports/overview-chart.tsx +49 -49
  140. package/templates/default/src/app/(base)/reports/page.tsx +98 -98
  141. package/templates/default/src/app/(base)/reports/report-detail-helpers.test.ts +109 -0
  142. package/templates/default/src/app/(base)/reports/report-detail-helpers.ts +247 -0
  143. package/templates/default/src/app/(base)/reports/report-metric-card.tsx +78 -78
  144. package/templates/default/src/app/(base)/reports/report-table-columns.tsx +189 -189
  145. package/templates/default/src/app/(base)/reports/report-table.tsx +72 -72
  146. package/templates/default/src/app/(base)/reports/test-cases/page.tsx +40 -40
  147. package/templates/default/src/app/(base)/reports/test-cases/test-cases-metric-table-columns.tsx +115 -115
  148. package/templates/default/src/app/(base)/reports/test-cases/test-cases-metric-table.tsx +27 -27
  149. package/templates/default/src/app/(base)/reports/test-suites/page.tsx +42 -42
  150. package/templates/default/src/app/(base)/reports/test-suites/test-suites-metric-table-columns.tsx +79 -79
  151. package/templates/default/src/app/(base)/reports/test-suites/test-suites-metric-table.tsx +27 -27
  152. package/templates/default/src/app/(base)/reports/view-logs-button.tsx +58 -58
  153. package/templates/default/src/app/(base)/settings/settings-sync-panel-helpers.test.tsx +40 -0
  154. package/templates/default/src/app/(base)/settings/settings-sync-panel-helpers.tsx +110 -0
  155. package/templates/default/src/app/(base)/settings/settings-sync-panel.test.tsx +127 -0
  156. package/templates/default/src/app/(base)/settings/settings-sync-panel.tsx +19 -134
  157. package/templates/default/src/app/(base)/settings/use-settings-sync.ts +66 -0
  158. package/templates/default/src/app/(base)/tags/create/page.tsx +39 -39
  159. package/templates/default/src/app/(base)/tags/modify/[id]/page.tsx +50 -50
  160. package/templates/default/src/app/(base)/tags/page.tsx +58 -58
  161. package/templates/default/src/app/(base)/tags/tag-form-helpers.ts +13 -0
  162. package/templates/default/src/app/(base)/tags/tag-form.test.tsx +83 -0
  163. package/templates/default/src/app/(base)/tags/tag-form.tsx +143 -147
  164. package/templates/default/src/app/(base)/tags/tag-table-columns.tsx +63 -63
  165. package/templates/default/src/app/(base)/tags/tag-table.tsx +29 -29
  166. package/templates/default/src/app/(base)/template-step-groups/create/page.tsx +28 -28
  167. package/templates/default/src/app/(base)/template-step-groups/modify/[id]/page.tsx +43 -45
  168. package/templates/default/src/app/(base)/template-step-groups/page.tsx +60 -60
  169. package/templates/default/src/app/(base)/template-step-groups/template-step-group-form.test.tsx +82 -0
  170. package/templates/default/src/app/(base)/template-step-groups/template-step-group-form.tsx +181 -167
  171. package/templates/default/src/app/(base)/template-step-groups/template-step-group-helpers.ts +54 -0
  172. package/templates/default/src/app/(base)/template-step-groups/template-step-group-table-columns.tsx +89 -89
  173. package/templates/default/src/app/(base)/template-step-groups/template-step-group-table.tsx +34 -32
  174. package/templates/default/src/app/(base)/template-steps/create/page.tsx +40 -37
  175. package/templates/default/src/app/(base)/template-steps/modify/[id]/page.tsx +54 -49
  176. package/templates/default/src/app/(base)/template-steps/page.tsx +59 -58
  177. package/templates/default/src/app/(base)/template-steps/paramChip.tsx +233 -213
  178. package/templates/default/src/app/(base)/template-steps/template-step-form.test.tsx +132 -0
  179. package/templates/default/src/app/(base)/template-steps/template-step-form.tsx +342 -384
  180. package/templates/default/src/app/(base)/template-steps/template-step-helpers.test.ts +99 -0
  181. package/templates/default/src/app/(base)/template-steps/template-step-helpers.ts +176 -0
  182. package/templates/default/src/app/(base)/template-steps/template-step-table-columns.tsx +153 -158
  183. package/templates/default/src/app/(base)/template-steps/template-step-table.tsx +26 -24
  184. package/templates/default/src/app/(base)/template-test-cases/create/page.tsx +56 -56
  185. package/templates/default/src/app/(base)/template-test-cases/modify/[id]/page.tsx +89 -89
  186. package/templates/default/src/app/(base)/template-test-cases/page.tsx +58 -58
  187. package/templates/default/src/app/(base)/template-test-cases/template-test-case-flow.test.tsx +109 -0
  188. package/templates/default/src/app/(base)/template-test-cases/template-test-case-flow.tsx +45 -84
  189. package/templates/default/src/app/(base)/template-test-cases/template-test-case-form.test.tsx +140 -0
  190. package/templates/default/src/app/(base)/template-test-cases/template-test-case-form.tsx +154 -262
  191. package/templates/default/src/app/(base)/template-test-cases/template-test-case-table-columns.tsx +76 -76
  192. package/templates/default/src/app/(base)/template-test-cases/template-test-case-table.tsx +32 -32
  193. package/templates/default/src/app/(base)/test-cases/create/page.tsx +90 -76
  194. package/templates/default/src/app/(base)/test-cases/create-from-template/create-from-template-helpers.test.ts +94 -0
  195. package/templates/default/src/app/(base)/test-cases/create-from-template/create-from-template-helpers.ts +171 -0
  196. package/templates/default/src/app/(base)/test-cases/create-from-template/generate/[id]/page.tsx +105 -96
  197. package/templates/default/src/app/(base)/test-cases/create-from-template/page.tsx +40 -38
  198. package/templates/default/src/app/(base)/test-cases/create-from-template/template-selection-form.test.tsx +87 -0
  199. package/templates/default/src/app/(base)/test-cases/create-from-template/template-selection-form.tsx +83 -73
  200. package/templates/default/src/app/(base)/test-cases/modify/[id]/page.tsx +106 -106
  201. package/templates/default/src/app/(base)/test-cases/page.tsx +3 -2
  202. package/templates/default/src/app/(base)/test-cases/test-case-flow.test.tsx +108 -0
  203. package/templates/default/src/app/(base)/test-cases/test-case-flow.tsx +43 -82
  204. package/templates/default/src/app/(base)/test-cases/test-case-form.test.tsx +202 -0
  205. package/templates/default/src/app/(base)/test-cases/test-case-form.tsx +263 -395
  206. package/templates/default/src/app/(base)/test-cases/test-case-route-helpers.test.ts +95 -0
  207. package/templates/default/src/app/(base)/test-cases/test-case-route-helpers.ts +147 -0
  208. package/templates/default/src/app/(base)/test-cases/test-case-table.tsx +4 -2
  209. package/templates/default/src/app/(base)/test-runs/[id]/page.tsx +11 -10
  210. package/templates/default/src/app/(base)/test-runs/create/page.tsx +4 -5
  211. package/templates/default/src/app/(base)/test-runs/page.tsx +60 -60
  212. package/templates/default/src/app/(base)/test-runs/test-run-form-helpers.test.ts +50 -0
  213. package/templates/default/src/app/(base)/test-runs/test-run-form-helpers.ts +168 -0
  214. package/templates/default/src/app/(base)/test-runs/test-run-form.test.tsx +138 -0
  215. package/templates/default/src/app/(base)/test-runs/test-run-form.tsx +111 -256
  216. package/templates/default/src/app/(base)/test-runs/test-run-table-columns.tsx +229 -229
  217. package/templates/default/src/app/(base)/test-runs/test-run-table.tsx +127 -127
  218. package/templates/default/src/app/(base)/test-runs/use-test-run-name-validation.ts +74 -0
  219. package/templates/default/src/app/(base)/test-suites/create/page.tsx +17 -12
  220. package/templates/default/src/app/(base)/test-suites/modify/[id]/page.tsx +22 -19
  221. package/templates/default/src/app/(base)/test-suites/page.tsx +14 -56
  222. package/templates/default/src/app/(base)/test-suites/test-suite-form.test.tsx +127 -0
  223. package/templates/default/src/app/(base)/test-suites/test-suite-form.tsx +45 -64
  224. package/templates/default/src/app/(base)/test-suites/test-suite-helpers.test.ts +67 -0
  225. package/templates/default/src/app/(base)/test-suites/test-suite-helpers.ts +215 -0
  226. package/templates/default/src/app/(base)/test-suites/test-suite-table.tsx +32 -29
  227. package/templates/default/src/app/(dashboard-components)/app-drawer.tsx +187 -187
  228. package/templates/default/src/app/(dashboard-components)/data-card-grid.tsx +12 -12
  229. package/templates/default/src/app/(dashboard-components)/data-card.tsx +26 -26
  230. package/templates/default/src/app/(dashboard-components)/execution-health-panel.tsx +56 -56
  231. package/templates/default/src/app/(dashboard-components)/ongoing-test-runs-card.tsx +87 -87
  232. package/templates/default/src/app/(dashboard-components)/quick-actions-drawer.tsx +44 -44
  233. package/templates/default/src/app/api/reports/steps/[stepId]/screenshot/route.test.ts +83 -0
  234. package/templates/default/src/app/api/reports/steps/[stepId]/screenshot/route.ts +52 -52
  235. package/templates/default/src/app/api/test-runs/[runId]/download/route.test.ts +169 -0
  236. package/templates/default/src/app/api/test-runs/[runId]/download/route.ts +1 -1
  237. package/templates/default/src/app/api/test-runs/[runId]/trace/[testCaseId]/route.test.ts +135 -0
  238. package/templates/default/src/app/api/test-runs/[runId]/trace/[testCaseId]/route.ts +146 -146
  239. package/templates/default/src/app/globals.css +147 -147
  240. package/templates/default/src/app/page.tsx +1 -1
  241. package/templates/default/src/assets/icons/empty-tube.tsx +23 -23
  242. package/templates/default/src/assets/icons/tube-plus.tsx +29 -29
  243. package/templates/default/src/components/base-node.tsx +21 -21
  244. package/templates/default/src/components/chart/pie-chart.tsx +73 -73
  245. package/templates/default/src/components/data-extraction/locator-inspector-helpers.test.ts +32 -0
  246. package/templates/default/src/components/data-extraction/locator-inspector-helpers.ts +183 -0
  247. package/templates/default/src/components/data-extraction/locator-inspector.tsx +349 -460
  248. package/templates/default/src/components/data-state/empty-state.tsx +40 -40
  249. package/templates/default/src/components/data-visualization/info-card.tsx +70 -70
  250. package/templates/default/src/components/data-visualization/info-grid.tsx +22 -22
  251. package/templates/default/src/components/diagram/button-edge.tsx +54 -54
  252. package/templates/default/src/components/diagram/dynamic-parameters-helpers.test.ts +83 -0
  253. package/templates/default/src/components/diagram/dynamic-parameters-helpers.ts +158 -0
  254. package/templates/default/src/components/diagram/dynamic-parameters.tsx +350 -474
  255. package/templates/default/src/components/diagram/edit-header-option.tsx +36 -36
  256. package/templates/default/src/components/diagram/flow-diagram-helpers.test.ts +117 -0
  257. package/templates/default/src/components/diagram/flow-diagram-helpers.ts +251 -0
  258. package/templates/default/src/components/diagram/flow-diagram.tsx +247 -470
  259. package/templates/default/src/components/diagram/flow-host-helpers.test.ts +74 -0
  260. package/templates/default/src/components/diagram/flow-host-helpers.ts +51 -0
  261. package/templates/default/src/components/diagram/node-form-helpers.test.ts +92 -0
  262. package/templates/default/src/components/diagram/node-form-helpers.ts +100 -0
  263. package/templates/default/src/components/diagram/node-form.test.tsx +168 -0
  264. package/templates/default/src/components/diagram/node-form.tsx +199 -262
  265. package/templates/default/src/components/diagram/options-header-node.tsx +57 -57
  266. package/templates/default/src/components/diagram/template-step-combobox.tsx +155 -155
  267. package/templates/default/src/components/diagram/use-flow-node-order.ts +49 -0
  268. package/templates/default/src/components/form/error-message.tsx +7 -7
  269. package/templates/default/src/components/kokonutui/smooth-tab.tsx +453 -453
  270. package/templates/default/src/components/loading-skeleton/data-table/data-table-skeleton.tsx +30 -30
  271. package/templates/default/src/components/loading-skeleton/form/button-skeleton.tsx +8 -8
  272. package/templates/default/src/components/loading-skeleton/form/icon-button-skeleton.tsx +8 -8
  273. package/templates/default/src/components/loading-skeleton/form/text-input-skeleton.tsx +8 -8
  274. package/templates/default/src/components/loading-skeleton/visualization/table-skeleton.tsx +14 -14
  275. package/templates/default/src/components/navigation/command-badge.tsx +34 -34
  276. package/templates/default/src/components/navigation/command-chain-input.tsx +51 -51
  277. package/templates/default/src/components/navigation/entity-search-command.tsx +118 -116
  278. package/templates/default/src/components/navigation/nav-card.tsx +31 -31
  279. package/templates/default/src/components/navigation/nav-command-helpers.ts +122 -0
  280. package/templates/default/src/components/navigation/nav-command-search.tsx +125 -0
  281. package/templates/default/src/components/navigation/nav-command.test.tsx +106 -0
  282. package/templates/default/src/components/navigation/nav-command.tsx +49 -472
  283. package/templates/default/src/components/navigation/nav-link.tsx +60 -60
  284. package/templates/default/src/components/navigation/nav-menu-card-deck.tsx +112 -112
  285. package/templates/default/src/components/navigation/use-nav-command.ts +58 -0
  286. package/templates/default/src/components/node-header.tsx +159 -159
  287. package/templates/default/src/components/reports/test-case-logs-modal.tsx +310 -310
  288. package/templates/default/src/components/table/table-actions.tsx +174 -172
  289. package/templates/default/src/components/test-case/test-case-form-helpers.test.ts +100 -0
  290. package/templates/default/src/components/test-case/test-case-form-helpers.ts +140 -0
  291. package/templates/default/src/components/test-case/test-case-picker-helpers.test.ts +40 -0
  292. package/templates/default/src/components/test-case/test-case-picker-helpers.ts +41 -0
  293. package/templates/default/src/components/test-case/test-case-picker.test.tsx +44 -0
  294. package/templates/default/src/components/test-case/test-case-picker.tsx +16 -35
  295. package/templates/default/src/components/test-case/test-scenario-preview.tsx +34 -0
  296. package/templates/default/src/components/test-run/download-logs-button.tsx +92 -92
  297. package/templates/default/src/components/test-run/log-viewer-helpers.test.ts +37 -0
  298. package/templates/default/src/components/test-run/log-viewer-helpers.ts +80 -0
  299. package/templates/default/src/components/test-run/log-viewer.test.tsx +118 -0
  300. package/templates/default/src/components/test-run/log-viewer.tsx +51 -350
  301. package/templates/default/src/components/test-run/test-run-details-helpers.test.ts +31 -0
  302. package/templates/default/src/components/test-run/test-run-details-helpers.ts +208 -0
  303. package/templates/default/src/components/test-run/test-run-details.test.tsx +174 -0
  304. package/templates/default/src/components/test-run/test-run-details.tsx +155 -457
  305. package/templates/default/src/components/test-run/test-run-header-helpers.test.ts +31 -0
  306. package/templates/default/src/components/test-run/test-run-header-helpers.ts +23 -0
  307. package/templates/default/src/components/test-run/test-run-header.test.tsx +103 -0
  308. package/templates/default/src/components/test-run/test-run-header.tsx +27 -149
  309. package/templates/default/src/components/test-run/use-log-viewer.ts +213 -0
  310. package/templates/default/src/components/test-run/use-test-run-details.ts +184 -0
  311. package/templates/default/src/components/test-run/use-test-run-header.ts +89 -0
  312. package/templates/default/src/components/test-run/view-report-button.tsx +102 -102
  313. package/templates/default/src/components/test-suite/test-suite-picker-helpers.test.ts +68 -0
  314. package/templates/default/src/components/test-suite/test-suite-picker-helpers.ts +76 -0
  315. package/templates/default/src/components/test-suite/test-suite-picker.test.tsx +65 -0
  316. package/templates/default/src/components/test-suite/test-suite-picker.tsx +4 -72
  317. package/templates/default/src/components/theme/mode-toggle.tsx +54 -54
  318. package/templates/default/src/components/theme/theme-provider.tsx +8 -8
  319. package/templates/default/src/components/typography/page-header-subtitle.tsx +7 -7
  320. package/templates/default/src/components/typography/page-header.tsx +7 -7
  321. package/templates/default/src/components/ui/alert-dialog.tsx +106 -106
  322. package/templates/default/src/components/ui/alert.tsx +43 -43
  323. package/templates/default/src/components/ui/avatar.tsx +40 -40
  324. package/templates/default/src/components/ui/badge.tsx +29 -29
  325. package/templates/default/src/components/ui/button.tsx +47 -47
  326. package/templates/default/src/components/ui/calendar.tsx +158 -158
  327. package/templates/default/src/components/ui/card.tsx +43 -43
  328. package/templates/default/src/components/ui/checkbox.tsx +28 -28
  329. package/templates/default/src/components/ui/command.tsx +135 -135
  330. package/templates/default/src/components/ui/data-table-column-header.tsx +61 -61
  331. package/templates/default/src/components/ui/data-table-pagination.tsx +87 -87
  332. package/templates/default/src/components/ui/data-table-view-options.tsx +50 -50
  333. package/templates/default/src/components/ui/data-table.test.tsx +122 -0
  334. package/templates/default/src/components/ui/data-table.tsx +298 -261
  335. package/templates/default/src/components/ui/dialog.tsx +97 -97
  336. package/templates/default/src/components/ui/dropdown-menu.tsx +182 -182
  337. package/templates/default/src/components/ui/input.tsx +22 -22
  338. package/templates/default/src/components/ui/kbd.tsx +28 -28
  339. package/templates/default/src/components/ui/label.tsx +19 -19
  340. package/templates/default/src/components/ui/loading.tsx +12 -12
  341. package/templates/default/src/components/ui/multi-select-with-preview.tsx +116 -116
  342. package/templates/default/src/components/ui/multi-select.test.tsx +45 -0
  343. package/templates/default/src/components/ui/multi-select.tsx +158 -142
  344. package/templates/default/src/components/ui/navigation-menu.tsx +120 -120
  345. package/templates/default/src/components/ui/popover.tsx +33 -33
  346. package/templates/default/src/components/ui/progress.tsx +25 -25
  347. package/templates/default/src/components/ui/radio-group.tsx +44 -44
  348. package/templates/default/src/components/ui/scroll-area.tsx +40 -40
  349. package/templates/default/src/components/ui/select.tsx +151 -151
  350. package/templates/default/src/components/ui/separator.tsx +22 -22
  351. package/templates/default/src/components/ui/skeleton.tsx +7 -7
  352. package/templates/default/src/components/ui/table.tsx +76 -76
  353. package/templates/default/src/components/ui/tabs.tsx +55 -55
  354. package/templates/default/src/components/ui/textarea.tsx +21 -21
  355. package/templates/default/src/components/ui/toast.tsx +113 -113
  356. package/templates/default/src/components/ui/toaster.tsx +26 -26
  357. package/templates/default/src/components/user-prompt/delete-prompt.test.tsx +60 -0
  358. package/templates/default/src/components/user-prompt/delete-prompt.tsx +118 -87
  359. package/templates/default/src/constants/form-opts/diagram/node-form.ts +30 -30
  360. package/templates/default/src/constants/form-opts/environment-form-opts.ts +24 -24
  361. package/templates/default/src/constants/form-opts/locator-group-form-opts.ts +28 -28
  362. package/templates/default/src/constants/form-opts/module-form-opts.ts +21 -21
  363. package/templates/default/src/constants/form-opts/tag-form-opts.ts +42 -42
  364. package/templates/default/src/constants/form-opts/template-selection-form-opts.ts +16 -16
  365. package/templates/default/src/constants/form-opts/template-step-group-form-opts.ts +24 -24
  366. package/templates/default/src/constants/form-opts/template-test-case-form-opts.ts +39 -39
  367. package/templates/default/src/constants/form-opts/template-test-step-form-opts.ts +36 -36
  368. package/templates/default/src/constants/form-opts/test-case-form-opts.ts +43 -43
  369. package/templates/default/src/constants/form-opts/test-suite-form-opts.ts +24 -24
  370. package/templates/default/src/hooks/use-toast.ts +187 -187
  371. package/templates/default/src/lib/automation/automation-path-roots.ts +95 -0
  372. package/templates/default/src/lib/automation/automation-workspace.ts +147 -0
  373. package/templates/default/src/lib/automation/paths.ts +6 -211
  374. package/templates/default/src/lib/bidirectional-sync.ts +432 -432
  375. package/templates/default/src/lib/environment-file-utils.ts +2 -1
  376. package/templates/default/src/lib/executor/local-executor-adapter.ts +2 -5
  377. package/templates/default/src/lib/feature-file-generator.ts +2 -1
  378. package/templates/default/src/lib/gherkin-parser.ts +0 -2
  379. package/templates/default/src/lib/locator-group-file-utils.ts +304 -307
  380. package/templates/default/src/lib/locator-picker/session-manager.ts +0 -21
  381. package/templates/default/src/lib/locator-picker/suggestions.ts +4 -2
  382. package/templates/default/src/lib/metrics/metric-calculator.ts +2 -6
  383. package/templates/default/src/lib/module-hierarchy-builder.ts +205 -205
  384. package/templates/default/src/lib/path-helpers/module-path.ts +71 -71
  385. package/templates/default/src/lib/sync/sync-executor.test.ts +76 -0
  386. package/templates/default/src/lib/sync/sync-pending-counts.test.ts +227 -226
  387. package/templates/default/src/lib/sync/sync-pending-counts.ts +2 -5
  388. package/templates/default/src/lib/template-sync-utils.d.ts +6 -6
  389. package/templates/default/src/lib/template-sync-utils.js +46 -46
  390. package/templates/default/src/lib/template-sync-utils.ts +63 -63
  391. package/templates/default/src/lib/test-case-utils.ts +6 -6
  392. package/templates/default/src/lib/test-run/log-formatter.ts +83 -83
  393. package/templates/default/src/lib/test-run/report-parser.ts +352 -352
  394. package/templates/default/src/lib/test-run/test-run-executor.ts +13 -13
  395. package/templates/default/src/lib/test-run/winston-logger.ts +65 -64
  396. package/templates/default/src/lib/transformers/gherkin-converter.ts +42 -42
  397. package/templates/default/src/lib/transformers/key-to-icon-transformer.tsx +95 -95
  398. package/templates/default/src/lib/transformers/template-test-case-converter.ts +160 -160
  399. package/templates/default/src/lib/utils/node-param-validation.ts +81 -81
  400. package/templates/default/src/lib/utils/template-step-file-generator.ts +2 -2
  401. package/templates/default/src/lib/utils/template-step-file-manager.ts +166 -166
  402. package/templates/default/src/lib/utils.ts +31 -31
  403. package/templates/default/src/services/dashboard/dashboard-service.test.ts +106 -0
  404. package/templates/default/src/services/dashboard/dashboard-service.ts +173 -0
  405. package/templates/default/src/services/environment/environment-service.test.ts +137 -0
  406. package/templates/default/src/services/environment/environment-service.ts +96 -0
  407. package/templates/default/src/services/locator/locator-path-utils.test.ts +14 -0
  408. package/templates/default/src/services/locator/locator-path-utils.ts +14 -0
  409. package/templates/default/src/services/locator/locator-service.test.ts +63 -0
  410. package/templates/default/src/services/locator/locator-service.ts +479 -0
  411. package/templates/default/src/services/locator/locator-sync-utils.test.ts +19 -0
  412. package/templates/default/src/services/locator/locator-sync-utils.ts +21 -0
  413. package/templates/default/src/services/locator-group/locator-group-service.test.ts +123 -0
  414. package/templates/default/src/services/locator-group/locator-group-service.ts +180 -0
  415. package/templates/default/src/services/module/module-service.test.ts +89 -0
  416. package/templates/default/src/services/module/module-service.ts +66 -0
  417. package/templates/default/src/services/report/report-service.test.ts +244 -0
  418. package/templates/default/src/services/report/report-service.ts +438 -0
  419. package/templates/default/src/services/shared/constants.ts +2 -0
  420. package/templates/default/src/services/shared/errors.test.ts +38 -0
  421. package/templates/default/src/services/shared/errors.ts +44 -0
  422. package/templates/default/src/services/shared/index.ts +7 -0
  423. package/templates/default/src/services/tag/tag-service.test.ts +22 -0
  424. package/templates/default/src/services/tag/tag-service.ts +41 -0
  425. package/templates/default/src/services/template-step/template-step-service.test.ts +22 -0
  426. package/templates/default/src/services/template-step/template-step-service.ts +171 -0
  427. package/templates/default/src/services/template-step-group/template-step-group-service.test.ts +22 -0
  428. package/templates/default/src/services/template-step-group/template-step-group-service.ts +81 -0
  429. package/templates/default/src/services/template-test-case/template-test-case-service.test.ts +22 -0
  430. package/templates/default/src/services/template-test-case/template-test-case-service.ts +128 -0
  431. package/templates/default/src/services/test-case/test-case-service.test.ts +175 -0
  432. package/templates/default/src/services/test-case/test-case-service.ts +298 -0
  433. package/templates/default/src/services/test-run/test-run-helpers.ts +61 -0
  434. package/templates/default/src/services/test-run/test-run-service.test.ts +647 -0
  435. package/templates/default/src/services/test-run/test-run-service.ts +917 -0
  436. package/templates/default/src/services/test-suite/test-suite-service.test.ts +127 -0
  437. package/templates/default/src/services/test-suite/test-suite-service.ts +197 -0
  438. package/templates/default/src/types/diagram/diagram.ts +34 -34
  439. package/templates/default/src/types/diagram/template-step.ts +11 -11
  440. package/templates/default/src/types/executor/browser.type.ts +1 -1
  441. package/templates/default/src/types/form/actionHandler.ts +19 -6
  442. package/templates/default/src/types/locator/locator.type.ts +11 -11
  443. package/templates/default/src/types/step/step.type.ts +1 -1
  444. package/templates/default/src/types/table/data-table.ts +6 -6
  445. package/templates/default/tailwind.config.ts +62 -62
  446. package/templates/default/tsconfig.json +1 -1
  447. package/dist/cli.e2e.test.d.ts +0 -2
  448. package/dist/cli.e2e.test.d.ts.map +0 -1
  449. package/dist/cli.e2e.test.js +0 -73
  450. package/dist/cli.e2e.test.js.map +0 -1
  451. package/dist/config.test.d.ts +0 -2
  452. package/dist/config.test.d.ts.map +0 -1
  453. package/dist/config.test.js +0 -65
  454. package/dist/config.test.js.map +0 -1
  455. package/dist/copy-template.test.d.ts +0 -2
  456. package/dist/copy-template.test.d.ts.map +0 -1
  457. package/dist/copy-template.test.js +0 -71
  458. package/dist/copy-template.test.js.map +0 -1
  459. package/dist/download-repo.test.d.ts +0 -2
  460. package/dist/download-repo.test.d.ts.map +0 -1
  461. package/dist/download-repo.test.js +0 -14
  462. package/dist/download-repo.test.js.map +0 -1
  463. package/dist/install.test.d.ts +0 -2
  464. package/dist/install.test.d.ts.map +0 -1
  465. package/dist/install.test.js +0 -119
  466. package/dist/install.test.js.map +0 -1
  467. package/dist/prompts.test.d.ts +0 -2
  468. package/dist/prompts.test.d.ts.map +0 -1
  469. package/dist/prompts.test.js +0 -58
  470. package/dist/prompts.test.js.map +0 -1
  471. package/templates/default/src/actions/conflict/conflict.action.ts +0 -33
  472. package/templates/default/src/actions/review/review-actions.ts +0 -147
  473. package/templates/default/src/actions/user/user-actions.ts +0 -13
  474. package/templates/default/src/app/(base)/locators/locator-form.tsx +0 -163
  475. package/templates/default/src/app/(base)/reviews/create/page.tsx +0 -26
  476. package/templates/default/src/app/(base)/reviews/created-reviews-table.tsx +0 -15
  477. package/templates/default/src/app/(base)/reviews/modify/[id]/page.tsx +0 -26
  478. package/templates/default/src/app/(base)/reviews/page.tsx +0 -26
  479. package/templates/default/src/app/(base)/reviews/review/[id]/page.tsx +0 -26
  480. package/templates/default/src/app/(base)/reviews/review-form.tsx +0 -11
  481. package/templates/default/src/app/(base)/reviews/review-table-by-creator-columns.tsx +0 -9
  482. package/templates/default/src/app/(base)/reviews/review-table-by-reviewer-columns.tsx +0 -9
  483. package/templates/default/src/app/(base)/reviews/reviewer-reviews-table.tsx +0 -15
  484. package/templates/default/src/constants/form-opts/locator-form-opts.ts +0 -20
  485. package/templates/default/src/constants/form-opts/review-form-opts.ts +0 -23
@@ -1,410 +1,358 @@
1
- #!/usr/bin/env tsx
2
-
3
- /**
4
- * Script to synchronize locator groups from filesystem to database
5
- * Scans locator-map.json and locators directory to ensure all locator groups exist in DB
6
- * Filesystem is the source of truth - locator groups in DB but not in FS will be deleted
7
- * Run this after merging changes to ensure locator group sync
8
- *
9
- * Usage: npx tsx scripts/sync-locator-groups.ts
10
- */
11
-
12
- import { promises as fs } from 'fs'
13
- import { join } from 'path'
14
- import { glob } from 'glob'
15
- import prisma from '../src/config/db-config'
16
- import { findModuleByPath, buildModuleHierarchy } from '../src/lib/module-hierarchy-builder'
17
- import { extractModulePathFromAutomationFile, getAutomationLocatorMapPath } from '../src/lib/template-sync-utils'
18
-
19
- /**
20
- * Represents a locator group from the filesystem
21
- */
22
- interface LocatorGroupFromFS {
23
- name: string
24
- route: string
25
- modulePath: string
26
- filePath: string
27
- }
28
-
29
- /**
30
- * Represents a locator group entry from locator-map.json
31
- */
32
- interface LocatorMapEntry {
33
- name: string
34
- path: string
35
- }
36
-
37
- /**
38
- * Sync result summary
39
- */
40
- interface SyncResult {
41
- locatorGroupsScanned: number
42
- locatorGroupsExisting: number
43
- locatorGroupsCreated: number
44
- locatorGroupsUpdated: number
45
- locatorGroupsDeleted: number
46
- errors: string[]
47
- createdLocatorGroups: string[]
48
- updatedLocatorGroups: string[]
49
- deletedLocatorGroups: Array<{ name: string; locatorCount: number }>
50
- }
51
-
52
- /**
53
- * Reads and parses the locator-map.json file
54
- */
55
- async function readLocatorMap(baseDir: string): Promise<LocatorMapEntry[]> {
56
- const locatorMapPath = getAutomationLocatorMapPath(baseDir)
57
-
58
- try {
59
- await fs.access(locatorMapPath)
60
- } catch {
61
- console.warn(` āš ļø Locator map file not found at ${locatorMapPath}, continuing without it`)
62
- return []
63
- }
64
-
65
- try {
66
- const fileContent = await fs.readFile(locatorMapPath, 'utf-8')
67
- const locatorMap = JSON.parse(fileContent) as LocatorMapEntry[]
68
-
69
- if (!Array.isArray(locatorMap)) {
70
- throw new Error('Invalid locator map format: expected an array')
71
- }
72
-
73
- return locatorMap
74
- } catch (error) {
75
- if (error instanceof SyntaxError) {
76
- throw new Error(`Invalid JSON in locator map file: ${error.message}`)
77
- }
78
- throw error
79
- }
80
- }
81
-
82
- /**
83
- * Scans the locators directory to find all locator group files
84
- */
85
- async function scanLocatorGroupFiles(baseDir: string): Promise<string[]> {
86
- const pattern = 'automation/locators/**/*.json'
87
-
88
- try {
89
- const files = await glob(pattern, {
90
- cwd: baseDir,
91
- })
92
- return files.map(file => join(baseDir, file))
93
- } catch (error) {
94
- throw new Error(`Error scanning locator group files: ${error}`)
95
- }
96
- }
97
-
98
- /**
99
- * Extracts module path from locator file path
100
- * Example: automation/locators/home/home.json -> /home
101
- * Example: automation/locators/users/admins/directors.json -> /users/admins
102
- */
103
- function extractModulePathFromLocatorFile(filePath: string, baseDir: string): string {
104
- return extractModulePathFromAutomationFile(filePath, baseDir, 'locators')
105
- }
106
-
107
- /**
108
- * Extracts locator group name from file path
109
- * The group name is the filename without extension
110
- */
111
- function extractLocatorGroupName(filePath: string): string {
112
- const fileName = filePath.split(/[/\\]/).pop() || ''
113
- return fileName.replace('.json', '')
114
- }
115
-
116
- /**
117
- * Builds a map of locator group names to routes from locator-map.json
118
- */
119
- function buildLocatorMapRouteMap(locatorMap: LocatorMapEntry[]): Map<string, string> {
120
- const routeMap = new Map<string, string>()
121
-
122
- for (const entry of locatorMap) {
123
- routeMap.set(entry.name, entry.path)
124
- }
125
-
126
- return routeMap
127
- }
128
-
129
- /**
130
- * Builds locator groups from filesystem
131
- * Combines information from locator-map.json and directory structure
132
- */
133
- async function buildLocatorGroupsFromFS(
134
- baseDir: string,
135
- locatorMap: LocatorMapEntry[],
136
- ): Promise<LocatorGroupFromFS[]> {
137
- const locatorGroups: LocatorGroupFromFS[] = []
138
- const routeMap = buildLocatorMapRouteMap(locatorMap)
139
-
140
- // Scan all locator group files
141
- const files = await scanLocatorGroupFiles(baseDir)
142
-
143
- for (const filePath of files) {
144
- const modulePath = extractModulePathFromLocatorFile(filePath, baseDir)
145
- const groupName = extractLocatorGroupName(filePath)
146
-
147
- // Get route from locator-map.json, or default to /{groupName}
148
- const route = routeMap.get(groupName) || `/${groupName}`
149
-
150
- locatorGroups.push({
151
- name: groupName,
152
- route,
153
- modulePath,
154
- filePath,
155
- })
156
- }
157
-
158
- return locatorGroups
159
- }
160
-
161
- /**
162
- * Creates or updates a locator group in the database
163
- */
164
- async function createOrUpdateLocatorGroup(
165
- locatorGroup: LocatorGroupFromFS,
166
- moduleId: string,
167
- result: SyncResult,
168
- ): Promise<void> {
169
- try {
170
- // Check if locator group already exists
171
- const existingGroup = await prisma.locatorGroup.findUnique({
172
- where: { name: locatorGroup.name },
173
- })
174
-
175
- if (existingGroup) {
176
- // Check if update is needed
177
- const needsUpdate = existingGroup.route !== locatorGroup.route || existingGroup.moduleId !== moduleId
178
-
179
- if (needsUpdate) {
180
- await prisma.locatorGroup.update({
181
- where: { id: existingGroup.id },
182
- data: {
183
- route: locatorGroup.route,
184
- moduleId: moduleId,
185
- },
186
- })
187
-
188
- result.locatorGroupsUpdated++
189
- result.updatedLocatorGroups.push(locatorGroup.name)
190
- console.log(` šŸ”„ Updated locator group '${locatorGroup.name}' (route: ${locatorGroup.route})`)
191
- } else {
192
- result.locatorGroupsExisting++
193
- console.log(` āœ“ Locator group '${locatorGroup.name}' already exists and is up to date`)
194
- }
195
- } else {
196
- // Create new locator group
197
- await prisma.locatorGroup.create({
198
- data: {
199
- name: locatorGroup.name,
200
- route: locatorGroup.route,
201
- moduleId: moduleId,
202
- },
203
- })
204
-
205
- result.locatorGroupsCreated++
206
- result.createdLocatorGroups.push(locatorGroup.name)
207
- console.log(` āž• Created locator group '${locatorGroup.name}' (route: ${locatorGroup.route})`)
208
- }
209
- } catch (error) {
210
- const errorMsg = `Error syncing locator group '${locatorGroup.name}': ${error}`
211
- result.errors.push(errorMsg)
212
- console.error(` āŒ ${errorMsg}`)
213
- }
214
- }
215
-
216
- /**
217
- * Syncs locator groups from filesystem to database
218
- */
219
- async function syncLocatorGroupsToDatabase(
220
- locatorGroups: LocatorGroupFromFS[],
221
- result: SyncResult,
222
- ): Promise<void> {
223
- console.log('\nāœ… Syncing locator groups to database...')
224
-
225
- for (const locatorGroup of locatorGroups) {
226
- try {
227
- // Ensure module exists (create if needed)
228
- let moduleId = await findModuleByPath(locatorGroup.modulePath)
229
-
230
- if (!moduleId) {
231
- console.log(` šŸ“¦ Creating module hierarchy for path: ${locatorGroup.modulePath}`)
232
- moduleId = await buildModuleHierarchy(locatorGroup.modulePath)
233
- }
234
-
235
- // Create or update locator group
236
- await createOrUpdateLocatorGroup(locatorGroup, moduleId, result)
237
- } catch (error) {
238
- const errorMsg = `Error processing locator group '${locatorGroup.name}': ${error}`
239
- result.errors.push(errorMsg)
240
- console.error(` āŒ ${errorMsg}`)
241
- }
242
- }
243
- }
244
-
245
- /**
246
- * Deletes orphaned locator groups (groups in DB but not in FS)
247
- */
248
- async function deleteOrphanedLocatorGroups(
249
- fsLocatorGroupNames: Set<string>,
250
- result: SyncResult,
251
- ): Promise<void> {
252
- console.log('\nšŸ” Checking for orphaned locator groups (not in filesystem)...')
253
-
254
- try {
255
- // Get all locator groups from database
256
- const dbLocatorGroups = await prisma.locatorGroup.findMany({
257
- include: {
258
- locators: {
259
- select: { id: true },
260
- },
261
- },
262
- })
263
-
264
- for (const dbGroup of dbLocatorGroups) {
265
- // Check if locator group exists in filesystem
266
- if (!fsLocatorGroupNames.has(dbGroup.name)) {
267
- try {
268
- const locatorCount = dbGroup.locators.length
269
-
270
- if (locatorCount > 0) {
271
- console.log(
272
- ` āš ļø Locator group '${dbGroup.name}' has ${locatorCount} locator(s) - will be cascade deleted`,
273
- )
274
- }
275
-
276
- // Delete the locator group (Prisma cascade will handle locators)
277
- await prisma.locatorGroup.delete({
278
- where: { id: dbGroup.id },
279
- })
280
-
281
- result.locatorGroupsDeleted++
282
- result.deletedLocatorGroups.push({
283
- name: dbGroup.name,
284
- locatorCount,
285
- })
286
- console.log(` šŸ—‘ļø Deleted locator group '${dbGroup.name}' (not in filesystem)`)
287
- } catch (error) {
288
- const errorMsg = `Error deleting locator group '${dbGroup.name}': ${error}`
289
- result.errors.push(errorMsg)
290
- console.error(` āŒ ${errorMsg}`)
291
- }
292
- }
293
- }
294
- } catch (error) {
295
- const errorMsg = `Error checking for orphaned locator groups: ${error}`
296
- result.errors.push(errorMsg)
297
- console.error(` āŒ ${errorMsg}`)
298
- }
299
- }
300
-
301
- /**
302
- * Generates and displays sync summary
303
- */
304
- function generateSummary(result: SyncResult): void {
305
- console.log('\nšŸ“Š Sync Summary:')
306
- console.log(` šŸ“ Locator groups scanned: ${result.locatorGroupsScanned}`)
307
- console.log(` āœ… Locator groups existing: ${result.locatorGroupsExisting}`)
308
- console.log(` āž• Locator groups created: ${result.locatorGroupsCreated}`)
309
- console.log(` šŸ”„ Locator groups updated: ${result.locatorGroupsUpdated}`)
310
- console.log(` šŸ—‘ļø Locator groups deleted: ${result.locatorGroupsDeleted}`)
311
- console.log(` āŒ Errors: ${result.errors.length}`)
312
-
313
- if (result.createdLocatorGroups.length > 0) {
314
- console.log('\n Created locator groups:')
315
- result.createdLocatorGroups.forEach((name, index) => {
316
- console.log(` ${index + 1}. ${name}`)
317
- })
318
- }
319
-
320
- if (result.updatedLocatorGroups.length > 0) {
321
- console.log('\n Updated locator groups:')
322
- result.updatedLocatorGroups.forEach((name, index) => {
323
- console.log(` ${index + 1}. ${name}`)
324
- })
325
- }
326
-
327
- if (result.deletedLocatorGroups.length > 0) {
328
- console.log('\n Deleted locator groups:')
329
- result.deletedLocatorGroups.forEach((group, index) => {
330
- console.log(
331
- ` ${index + 1}. ${group.name} (${group.locatorCount} locator(s) cascade deleted)`,
332
- )
333
- })
334
- }
335
-
336
- if (result.errors.length > 0) {
337
- console.log('\n Errors:')
338
- result.errors.forEach((error, index) => {
339
- console.log(` ${index + 1}. ${error}`)
340
- })
341
- }
342
- }
343
-
344
- /**
345
- * Main function
346
- */
347
- async function main() {
348
- try {
349
- console.log('šŸ”„ Starting locator groups sync...')
350
- console.log('This will scan filesystem directories and sync locator groups to database.')
351
- console.log('Filesystem is the source of truth - locator groups in DB but not in FS will be deleted.\n')
352
-
353
- const baseDir = process.cwd()
354
-
355
- // Initialize result
356
- const result: SyncResult = {
357
- locatorGroupsScanned: 0,
358
- locatorGroupsExisting: 0,
359
- locatorGroupsCreated: 0,
360
- locatorGroupsUpdated: 0,
361
- locatorGroupsDeleted: 0,
362
- errors: [],
363
- createdLocatorGroups: [],
364
- updatedLocatorGroups: [],
365
- deletedLocatorGroups: [],
366
- }
367
-
368
- // Read locator map
369
- console.log('šŸ“„ Reading locator-map.json...')
370
- const locatorMap = await readLocatorMap(baseDir)
371
- console.log(` Found ${locatorMap.length} entry(ies) in locator map`)
372
-
373
- // Build locator groups from filesystem
374
- console.log('\nšŸ“ Scanning automation/locators directory...')
375
- const locatorGroups = await buildLocatorGroupsFromFS(baseDir, locatorMap)
376
- result.locatorGroupsScanned = locatorGroups.length
377
- console.log(` Found ${locatorGroups.length} locator group(s) in filesystem`)
378
-
379
- if (locatorGroups.length > 0) {
380
- console.log('\n Locator groups found:')
381
- locatorGroups.forEach((group, index) => {
382
- console.log(` ${index + 1}. ${group.name} (route: ${group.route}, module: ${group.modulePath})`)
383
- })
384
- }
385
-
386
- // Sync to database
387
- await syncLocatorGroupsToDatabase(locatorGroups, result)
388
-
389
- // Delete orphaned locator groups
390
- const fsLocatorGroupNames = new Set(locatorGroups.map(g => g.name))
391
- await deleteOrphanedLocatorGroups(fsLocatorGroupNames, result)
392
-
393
- // Generate summary
394
- generateSummary(result)
395
-
396
- if (result.errors.length === 0) {
397
- console.log('\nāœ… Sync completed successfully!')
398
- } else {
399
- console.log('\nāš ļø Sync completed with errors. Please review the errors above.')
400
- process.exit(1)
401
- }
402
- } catch (error) {
403
- console.error('\nāŒ Error during sync:', error)
404
- process.exit(1)
405
- } finally {
406
- await prisma.$disconnect()
407
- }
408
- }
409
-
410
- main()
1
+ #!/usr/bin/env tsx
2
+
3
+ /**
4
+ * Script to synchronize locator groups from filesystem to database
5
+ * Scans locator-map.json and locators directory to ensure all locator groups exist in DB
6
+ * Filesystem is the source of truth - locator groups in DB but not in FS will be deleted
7
+ * Run this after merging changes to ensure locator group sync
8
+ *
9
+ * Usage: npx tsx scripts/sync-locator-groups.ts
10
+ */
11
+
12
+ import { promises as fs } from 'fs'
13
+ import { join } from 'path'
14
+ import { glob } from 'glob'
15
+ import prisma from '../src/config/db-config'
16
+ import { findModuleByPath, buildModuleHierarchy } from '../src/lib/module-hierarchy-builder'
17
+ import { getAutomationLocatorMapPath } from '../src/lib/template-sync-utils'
18
+ import { extractLocatorGroupName, extractModulePathFromLocatorFile } from './lib/filename-utils'
19
+ import { printSyncSummary } from './lib/sync-summary'
20
+ import { runSyncScript } from './lib/sync-script-runner'
21
+
22
+ /**
23
+ * Represents a locator group from the filesystem
24
+ */
25
+ interface LocatorGroupFromFS {
26
+ name: string
27
+ route: string
28
+ modulePath: string
29
+ filePath: string
30
+ }
31
+
32
+ /**
33
+ * Represents a locator group entry from locator-map.json
34
+ */
35
+ interface LocatorMapEntry {
36
+ name: string
37
+ path: string
38
+ }
39
+
40
+ /**
41
+ * Sync result summary
42
+ */
43
+ interface SyncResult {
44
+ locatorGroupsScanned: number
45
+ locatorGroupsExisting: number
46
+ locatorGroupsCreated: number
47
+ locatorGroupsUpdated: number
48
+ locatorGroupsDeleted: number
49
+ errors: string[]
50
+ createdLocatorGroups: string[]
51
+ updatedLocatorGroups: string[]
52
+ deletedLocatorGroups: Array<{ name: string; locatorCount: number }>
53
+ }
54
+
55
+ /**
56
+ * Reads and parses the locator-map.json file
57
+ */
58
+ async function readLocatorMap(baseDir: string): Promise<LocatorMapEntry[]> {
59
+ const locatorMapPath = getAutomationLocatorMapPath(baseDir)
60
+
61
+ try {
62
+ await fs.access(locatorMapPath)
63
+ } catch {
64
+ console.warn(` āš ļø Locator map file not found at ${locatorMapPath}, continuing without it`)
65
+ return []
66
+ }
67
+
68
+ try {
69
+ const fileContent = await fs.readFile(locatorMapPath, 'utf-8')
70
+ const locatorMap = JSON.parse(fileContent) as LocatorMapEntry[]
71
+
72
+ if (!Array.isArray(locatorMap)) {
73
+ throw new Error('Invalid locator map format: expected an array')
74
+ }
75
+
76
+ return locatorMap
77
+ } catch (error) {
78
+ if (error instanceof SyntaxError) {
79
+ throw new Error(`Invalid JSON in locator map file: ${error.message}`)
80
+ }
81
+ throw error
82
+ }
83
+ }
84
+
85
+ /**
86
+ * Scans the locators directory to find all locator group files
87
+ */
88
+ async function scanLocatorGroupFiles(baseDir: string): Promise<string[]> {
89
+ const pattern = 'automation/locators/**/*.json'
90
+
91
+ try {
92
+ const files = await glob(pattern, {
93
+ cwd: baseDir,
94
+ })
95
+ return files.map(file => join(baseDir, file))
96
+ } catch (error) {
97
+ throw new Error(`Error scanning locator group files: ${error}`)
98
+ }
99
+ }
100
+
101
+ /**
102
+ * Builds a map of locator group names to routes from locator-map.json
103
+ */
104
+ function buildLocatorMapRouteMap(locatorMap: LocatorMapEntry[]): Map<string, string> {
105
+ const routeMap = new Map<string, string>()
106
+
107
+ for (const entry of locatorMap) {
108
+ routeMap.set(entry.name, entry.path)
109
+ }
110
+
111
+ return routeMap
112
+ }
113
+
114
+ /**
115
+ * Builds locator groups from filesystem
116
+ * Combines information from locator-map.json and directory structure
117
+ */
118
+ async function buildLocatorGroupsFromFS(
119
+ baseDir: string,
120
+ locatorMap: LocatorMapEntry[],
121
+ ): Promise<LocatorGroupFromFS[]> {
122
+ const locatorGroups: LocatorGroupFromFS[] = []
123
+ const routeMap = buildLocatorMapRouteMap(locatorMap)
124
+
125
+ // Scan all locator group files
126
+ const files = await scanLocatorGroupFiles(baseDir)
127
+
128
+ for (const filePath of files) {
129
+ const modulePath = extractModulePathFromLocatorFile(filePath, baseDir)
130
+ const groupName = extractLocatorGroupName(filePath)
131
+
132
+ // Get route from locator-map.json, or default to /{groupName}
133
+ const route = routeMap.get(groupName) || `/${groupName}`
134
+
135
+ locatorGroups.push({
136
+ name: groupName,
137
+ route,
138
+ modulePath,
139
+ filePath,
140
+ })
141
+ }
142
+
143
+ return locatorGroups
144
+ }
145
+
146
+ /**
147
+ * Creates or updates a locator group in the database
148
+ */
149
+ async function createOrUpdateLocatorGroup(
150
+ locatorGroup: LocatorGroupFromFS,
151
+ moduleId: string,
152
+ result: SyncResult,
153
+ ): Promise<void> {
154
+ try {
155
+ // Check if locator group already exists
156
+ const existingGroup = await prisma.locatorGroup.findUnique({
157
+ where: { name: locatorGroup.name },
158
+ })
159
+
160
+ if (existingGroup) {
161
+ // Check if update is needed
162
+ const needsUpdate = existingGroup.route !== locatorGroup.route || existingGroup.moduleId !== moduleId
163
+
164
+ if (needsUpdate) {
165
+ await prisma.locatorGroup.update({
166
+ where: { id: existingGroup.id },
167
+ data: {
168
+ route: locatorGroup.route,
169
+ moduleId: moduleId,
170
+ },
171
+ })
172
+
173
+ result.locatorGroupsUpdated++
174
+ result.updatedLocatorGroups.push(locatorGroup.name)
175
+ console.log(` šŸ”„ Updated locator group '${locatorGroup.name}' (route: ${locatorGroup.route})`)
176
+ } else {
177
+ result.locatorGroupsExisting++
178
+ console.log(` āœ“ Locator group '${locatorGroup.name}' already exists and is up to date`)
179
+ }
180
+ } else {
181
+ // Create new locator group
182
+ await prisma.locatorGroup.create({
183
+ data: {
184
+ name: locatorGroup.name,
185
+ route: locatorGroup.route,
186
+ moduleId: moduleId,
187
+ },
188
+ })
189
+
190
+ result.locatorGroupsCreated++
191
+ result.createdLocatorGroups.push(locatorGroup.name)
192
+ console.log(` āž• Created locator group '${locatorGroup.name}' (route: ${locatorGroup.route})`)
193
+ }
194
+ } catch (error) {
195
+ const errorMsg = `Error syncing locator group '${locatorGroup.name}': ${error}`
196
+ result.errors.push(errorMsg)
197
+ console.error(` āŒ ${errorMsg}`)
198
+ }
199
+ }
200
+
201
+ /**
202
+ * Syncs locator groups from filesystem to database
203
+ */
204
+ async function syncLocatorGroupsToDatabase(
205
+ locatorGroups: LocatorGroupFromFS[],
206
+ result: SyncResult,
207
+ ): Promise<void> {
208
+ console.log('\nāœ… Syncing locator groups to database...')
209
+
210
+ for (const locatorGroup of locatorGroups) {
211
+ try {
212
+ // Ensure module exists (create if needed)
213
+ let moduleId = await findModuleByPath(locatorGroup.modulePath)
214
+
215
+ if (!moduleId) {
216
+ console.log(` šŸ“¦ Creating module hierarchy for path: ${locatorGroup.modulePath}`)
217
+ moduleId = await buildModuleHierarchy(locatorGroup.modulePath)
218
+ }
219
+
220
+ // Create or update locator group
221
+ await createOrUpdateLocatorGroup(locatorGroup, moduleId, result)
222
+ } catch (error) {
223
+ const errorMsg = `Error processing locator group '${locatorGroup.name}': ${error}`
224
+ result.errors.push(errorMsg)
225
+ console.error(` āŒ ${errorMsg}`)
226
+ }
227
+ }
228
+ }
229
+
230
+ /**
231
+ * Deletes orphaned locator groups (groups in DB but not in FS)
232
+ */
233
+ async function deleteOrphanedLocatorGroups(
234
+ fsLocatorGroupNames: Set<string>,
235
+ result: SyncResult,
236
+ ): Promise<void> {
237
+ console.log('\nšŸ” Checking for orphaned locator groups (not in filesystem)...')
238
+
239
+ try {
240
+ // Get all locator groups from database
241
+ const dbLocatorGroups = await prisma.locatorGroup.findMany({
242
+ include: {
243
+ locators: {
244
+ select: { id: true },
245
+ },
246
+ },
247
+ })
248
+
249
+ for (const dbGroup of dbLocatorGroups) {
250
+ // Check if locator group exists in filesystem
251
+ if (!fsLocatorGroupNames.has(dbGroup.name)) {
252
+ try {
253
+ const locatorCount = dbGroup.locators.length
254
+
255
+ if (locatorCount > 0) {
256
+ console.log(
257
+ ` āš ļø Locator group '${dbGroup.name}' has ${locatorCount} locator(s) - will be cascade deleted`,
258
+ )
259
+ }
260
+
261
+ // Delete the locator group (Prisma cascade will handle locators)
262
+ await prisma.locatorGroup.delete({
263
+ where: { id: dbGroup.id },
264
+ })
265
+
266
+ result.locatorGroupsDeleted++
267
+ result.deletedLocatorGroups.push({
268
+ name: dbGroup.name,
269
+ locatorCount,
270
+ })
271
+ console.log(` šŸ—‘ļø Deleted locator group '${dbGroup.name}' (not in filesystem)`)
272
+ } catch (error) {
273
+ const errorMsg = `Error deleting locator group '${dbGroup.name}': ${error}`
274
+ result.errors.push(errorMsg)
275
+ console.error(` āŒ ${errorMsg}`)
276
+ }
277
+ }
278
+ }
279
+ } catch (error) {
280
+ const errorMsg = `Error checking for orphaned locator groups: ${error}`
281
+ result.errors.push(errorMsg)
282
+ console.error(` āŒ ${errorMsg}`)
283
+ }
284
+ }
285
+
286
+ /**
287
+ * Generates and displays sync summary
288
+ */
289
+ async function main(): Promise<SyncResult> {
290
+ console.log('šŸ”„ Starting locator groups sync...')
291
+ console.log('This will scan filesystem directories and sync locator groups to database.')
292
+ console.log('Filesystem is the source of truth - locator groups in DB but not in FS will be deleted.\n')
293
+
294
+ const baseDir = process.cwd()
295
+
296
+ // Initialize result
297
+ const result: SyncResult = {
298
+ locatorGroupsScanned: 0,
299
+ locatorGroupsExisting: 0,
300
+ locatorGroupsCreated: 0,
301
+ locatorGroupsUpdated: 0,
302
+ locatorGroupsDeleted: 0,
303
+ errors: [],
304
+ createdLocatorGroups: [],
305
+ updatedLocatorGroups: [],
306
+ deletedLocatorGroups: [],
307
+ }
308
+
309
+ // Read locator map
310
+ console.log('šŸ“„ Reading locator-map.json...')
311
+ const locatorMap = await readLocatorMap(baseDir)
312
+ console.log(` Found ${locatorMap.length} entry(ies) in locator map`)
313
+
314
+ // Build locator groups from filesystem
315
+ console.log('\nšŸ“ Scanning automation/locators directory...')
316
+ const locatorGroups = await buildLocatorGroupsFromFS(baseDir, locatorMap)
317
+ result.locatorGroupsScanned = locatorGroups.length
318
+ console.log(` Found ${locatorGroups.length} locator group(s) in filesystem`)
319
+
320
+ if (locatorGroups.length > 0) {
321
+ console.log('\n Locator groups found:')
322
+ locatorGroups.forEach((group, index) => {
323
+ console.log(` ${index + 1}. ${group.name} (route: ${group.route}, module: ${group.modulePath})`)
324
+ })
325
+ }
326
+
327
+ // Sync to database
328
+ await syncLocatorGroupsToDatabase(locatorGroups, result)
329
+
330
+ // Delete orphaned locator groups
331
+ const fsLocatorGroupNames = new Set(locatorGroups.map(g => g.name))
332
+ await deleteOrphanedLocatorGroups(fsLocatorGroupNames, result)
333
+
334
+ printSyncSummary(
335
+ [
336
+ { label: 'šŸ“ Locator groups scanned', value: result.locatorGroupsScanned },
337
+ { label: 'āœ… Locator groups existing', value: result.locatorGroupsExisting },
338
+ { label: 'āž• Locator groups created', value: result.locatorGroupsCreated },
339
+ { label: 'šŸ”„ Locator groups updated', value: result.locatorGroupsUpdated },
340
+ { label: 'šŸ—‘ļø Locator groups deleted', value: result.locatorGroupsDeleted },
341
+ { label: 'āŒ Errors', value: result.errors.length },
342
+ ],
343
+ [
344
+ { title: 'Created locator groups', items: result.createdLocatorGroups },
345
+ { title: 'Updated locator groups', items: result.updatedLocatorGroups },
346
+ {
347
+ title: 'Deleted locator groups',
348
+ items: result.deletedLocatorGroups.map(
349
+ group => `${group.name} (${group.locatorCount} locator(s) cascade deleted)`,
350
+ ),
351
+ },
352
+ { title: 'Errors', items: result.errors },
353
+ ],
354
+ )
355
+ return result
356
+ }
357
+
358
+ runSyncScript(main)