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
@@ -3,6 +3,7 @@ import prisma from '@/config/db-config'
3
3
  import { ParsedFeature, ParsedStep } from './gherkin-parser'
4
4
  import { buildModuleHierarchy } from './module-hierarchy-builder'
5
5
  import { TemplateStepType, TemplateStepIcon, TestCase, TagType } from '@prisma/client'
6
+ import { getTagTypeFromExpression } from './tag-utils'
6
7
 
7
8
  /**
8
9
  * Syncs feature files to the database by creating missing test suites and test cases
@@ -93,13 +94,7 @@ export async function syncFeaturesToDatabase(
93
94
  * @returns TagType - IDENTIFIER if matches pattern, FILTER otherwise
94
95
  */
95
96
  function determineTagType(tagExpression: string): TagType {
96
- // Pattern: @xx_id_xxxxxxxx where:
97
- // - @ = literal @
98
- // - xx = any 2 characters
99
- // - _id_ = literal string
100
- // - xxxxxxxx = any characters
101
- const identifierPattern = /^@.{2}_id_.+$/
102
- return identifierPattern.test(tagExpression) ? TagType.IDENTIFIER : TagType.FILTER
97
+ return getTagTypeFromExpression(tagExpression)
103
98
  }
104
99
 
105
100
  /**
@@ -1,184 +1,184 @@
1
- import { promises as fs } from 'fs'
2
- import * as path from 'path'
3
- import prisma from '@/config/db-config'
4
- import { ensureAutomationWorkspaceReady, getAutomationEnvironmentsDir } from '@/lib/automation/paths'
5
-
6
- interface EnvironmentConfig {
7
- baseUrl: string
8
- apiBaseUrl: string
9
- email: string
10
- password: string
11
- }
12
-
13
- export function getEnvironmentsFilePath(): string {
14
- return path.join(getAutomationEnvironmentsDir(), 'environments.json')
15
- }
16
-
17
- export async function ensureConfigDirectoryExists(): Promise<void> {
18
- await ensureAutomationWorkspaceReady()
19
- await fs.mkdir(path.dirname(getEnvironmentsFilePath()), { recursive: true })
20
- }
21
-
22
- export async function generateEnvironmentsContent(): Promise<Record<string, EnvironmentConfig>> {
23
- try {
24
- const environments = await prisma.environment.findMany({
25
- orderBy: { createdAt: 'asc' },
26
- })
27
-
28
- const environmentsConfig: Record<string, EnvironmentConfig> = {}
29
-
30
- environments.forEach(env => {
31
- const envKey = env.name.toLowerCase().replace(/\s+/g, '_')
32
- environmentsConfig[envKey] = {
33
- baseUrl: env.baseUrl,
34
- apiBaseUrl: env.apiBaseUrl || '',
35
- email: env.username || '',
36
- password: env.password || '',
37
- }
38
- })
39
-
40
- return environmentsConfig
41
- } catch (error) {
42
- console.error('Error generating environments content:', error)
43
- return {}
44
- }
45
- }
46
-
47
- export async function createOrUpdateEnvironmentsFile(): Promise<boolean> {
48
- try {
49
- await ensureAutomationWorkspaceReady()
50
- const filePath = getEnvironmentsFilePath()
51
- await ensureConfigDirectoryExists()
52
-
53
- const content = await generateEnvironmentsContent()
54
-
55
- if (Object.keys(content).length === 0) {
56
- await deleteEnvironmentsFile()
57
- return true
58
- }
59
-
60
- await fs.writeFile(filePath, JSON.stringify(content, null, 2))
61
- return true
62
- } catch (error) {
63
- console.error('Error creating/updating environments file:', error)
64
- return false
65
- }
66
- }
67
-
68
- export async function deleteEnvironmentsFile(): Promise<boolean> {
69
- try {
70
- await ensureAutomationWorkspaceReady()
71
- const filePath = getEnvironmentsFilePath()
72
-
73
- try {
74
- await fs.access(filePath)
75
- } catch {
76
- return true
77
- }
78
-
79
- await fs.unlink(filePath)
80
- return true
81
- } catch (error) {
82
- console.error('Error deleting environments file:', error)
83
- return false
84
- }
85
- }
86
-
87
- export async function readEnvironmentsFile(): Promise<{
88
- filePath: string
89
- content: Record<string, EnvironmentConfig>
90
- } | null> {
91
- try {
92
- await ensureAutomationWorkspaceReady()
93
- const filePath = getEnvironmentsFilePath()
94
-
95
- try {
96
- await fs.access(filePath)
97
- } catch {
98
- return null
99
- }
100
-
101
- const fileContent = await fs.readFile(filePath, 'utf-8')
102
- const jsonContent = JSON.parse(fileContent)
103
-
104
- return { filePath, content: jsonContent }
105
- } catch (error) {
106
- console.error('Error reading environments file:', error)
107
- return null
108
- }
109
- }
110
-
111
- export async function updateEnvironmentEntry(environmentId: string, oldName?: string): Promise<boolean> {
112
- try {
113
- await ensureAutomationWorkspaceReady()
114
- const environment = await prisma.environment.findUnique({
115
- where: { id: environmentId },
116
- })
117
-
118
- if (!environment) {
119
- console.error(`Environment with ID ${environmentId} not found`)
120
- return false
121
- }
122
-
123
- const filePath = getEnvironmentsFilePath()
124
- let environmentsConfig: Record<string, EnvironmentConfig> = {}
125
-
126
- try {
127
- await fs.access(filePath)
128
- const fileContent = await fs.readFile(filePath, 'utf-8')
129
- environmentsConfig = JSON.parse(fileContent)
130
- } catch {
131
- environmentsConfig = {}
132
- }
133
-
134
- if (oldName) {
135
- const oldKey = oldName.toLowerCase().replace(/\s+/g, '_')
136
- delete environmentsConfig[oldKey]
137
- }
138
-
139
- const envKey = environment.name.toLowerCase().replace(/\s+/g, '_')
140
- environmentsConfig[envKey] = {
141
- baseUrl: environment.baseUrl,
142
- apiBaseUrl: environment.apiBaseUrl || '',
143
- email: environment.username || '',
144
- password: environment.password || '',
145
- }
146
-
147
- await ensureConfigDirectoryExists()
148
- await fs.writeFile(filePath, JSON.stringify(environmentsConfig, null, 2))
149
- return true
150
- } catch (error) {
151
- console.error('Error updating environment entry:', error)
152
- return false
153
- }
154
- }
155
-
156
- export async function removeEnvironmentEntry(environmentName: string): Promise<boolean> {
157
- try {
158
- await ensureAutomationWorkspaceReady()
159
- const filePath = getEnvironmentsFilePath()
160
-
161
- try {
162
- await fs.access(filePath)
163
- } catch {
164
- return true
165
- }
166
-
167
- const fileContent = await fs.readFile(filePath, 'utf-8')
168
- const environmentsConfig: Record<string, EnvironmentConfig> = JSON.parse(fileContent)
169
-
170
- const envKey = environmentName.toLowerCase().replace(/\s+/g, '_')
171
- delete environmentsConfig[envKey]
172
-
173
- if (Object.keys(environmentsConfig).length === 0) {
174
- await deleteEnvironmentsFile()
175
- return true
176
- }
177
-
178
- await fs.writeFile(filePath, JSON.stringify(environmentsConfig, null, 2))
179
- return true
180
- } catch (error) {
181
- console.error('Error removing environment entry:', error)
182
- return false
183
- }
184
- }
1
+ import { promises as fs } from 'fs'
2
+ import * as path from 'path'
3
+ import prisma from '@/config/db-config'
4
+ import { ensureAutomationWorkspaceReady, getAutomationEnvironmentsDir } from '@/lib/automation/paths'
5
+
6
+ interface EnvironmentConfig {
7
+ baseUrl: string
8
+ apiBaseUrl: string
9
+ email: string
10
+ password: string
11
+ }
12
+
13
+ export function getEnvironmentsFilePath(): string {
14
+ return path.join(getAutomationEnvironmentsDir(), 'environments.json')
15
+ }
16
+
17
+ export async function ensureConfigDirectoryExists(): Promise<void> {
18
+ await ensureAutomationWorkspaceReady()
19
+ await fs.mkdir(path.dirname(getEnvironmentsFilePath()), { recursive: true })
20
+ }
21
+
22
+ export async function generateEnvironmentsContent(): Promise<Record<string, EnvironmentConfig>> {
23
+ try {
24
+ const environments = await prisma.environment.findMany({
25
+ orderBy: { createdAt: 'asc' },
26
+ })
27
+
28
+ const environmentsConfig: Record<string, EnvironmentConfig> = {}
29
+
30
+ environments.forEach(env => {
31
+ const envKey = env.name.toLowerCase().replace(/\s+/g, '_')
32
+ environmentsConfig[envKey] = {
33
+ baseUrl: env.baseUrl,
34
+ apiBaseUrl: env.apiBaseUrl || '',
35
+ email: env.username || '',
36
+ password: env.password || '',
37
+ }
38
+ })
39
+
40
+ return environmentsConfig
41
+ } catch (error) {
42
+ console.error('Error generating environments content:', error)
43
+ return {}
44
+ }
45
+ }
46
+
47
+ export async function createOrUpdateEnvironmentsFile(): Promise<boolean> {
48
+ try {
49
+ await ensureAutomationWorkspaceReady()
50
+ const filePath = getEnvironmentsFilePath()
51
+ await ensureConfigDirectoryExists()
52
+
53
+ const content = await generateEnvironmentsContent()
54
+
55
+ if (Object.keys(content).length === 0) {
56
+ await deleteEnvironmentsFile()
57
+ return true
58
+ }
59
+
60
+ await fs.writeFile(filePath, JSON.stringify(content, null, 2))
61
+ return true
62
+ } catch (error) {
63
+ console.error('Error creating/updating environments file:', error)
64
+ return false
65
+ }
66
+ }
67
+
68
+ export async function deleteEnvironmentsFile(): Promise<boolean> {
69
+ try {
70
+ await ensureAutomationWorkspaceReady()
71
+ const filePath = getEnvironmentsFilePath()
72
+
73
+ try {
74
+ await fs.access(filePath)
75
+ } catch {
76
+ return true
77
+ }
78
+
79
+ await fs.unlink(filePath)
80
+ return true
81
+ } catch (error) {
82
+ console.error('Error deleting environments file:', error)
83
+ return false
84
+ }
85
+ }
86
+
87
+ export async function readEnvironmentsFile(): Promise<{
88
+ filePath: string
89
+ content: Record<string, EnvironmentConfig>
90
+ } | null> {
91
+ try {
92
+ await ensureAutomationWorkspaceReady()
93
+ const filePath = getEnvironmentsFilePath()
94
+
95
+ try {
96
+ await fs.access(filePath)
97
+ } catch {
98
+ return null
99
+ }
100
+
101
+ const fileContent = await fs.readFile(filePath, 'utf-8')
102
+ const jsonContent = JSON.parse(fileContent)
103
+
104
+ return { filePath, content: jsonContent }
105
+ } catch (error) {
106
+ console.error('Error reading environments file:', error)
107
+ return null
108
+ }
109
+ }
110
+
111
+ export async function updateEnvironmentEntry(environmentId: string, oldName?: string): Promise<boolean> {
112
+ try {
113
+ await ensureAutomationWorkspaceReady()
114
+ const environment = await prisma.environment.findUnique({
115
+ where: { id: environmentId },
116
+ })
117
+
118
+ if (!environment) {
119
+ console.error(`Environment with ID ${environmentId} not found`)
120
+ return false
121
+ }
122
+
123
+ const filePath = getEnvironmentsFilePath()
124
+ let environmentsConfig: Record<string, EnvironmentConfig> = {}
125
+
126
+ try {
127
+ await fs.access(filePath)
128
+ const fileContent = await fs.readFile(filePath, 'utf-8')
129
+ environmentsConfig = JSON.parse(fileContent)
130
+ } catch {
131
+ environmentsConfig = {}
132
+ }
133
+
134
+ if (oldName) {
135
+ const oldKey = oldName.toLowerCase().replace(/\s+/g, '_')
136
+ delete environmentsConfig[oldKey]
137
+ }
138
+
139
+ const envKey = environment.name.toLowerCase().replace(/\s+/g, '_')
140
+ environmentsConfig[envKey] = {
141
+ baseUrl: environment.baseUrl,
142
+ apiBaseUrl: environment.apiBaseUrl || '',
143
+ email: environment.username || '',
144
+ password: environment.password || '',
145
+ }
146
+
147
+ await ensureConfigDirectoryExists()
148
+ await fs.writeFile(filePath, JSON.stringify(environmentsConfig, null, 2))
149
+ return true
150
+ } catch (error) {
151
+ console.error('Error updating environment entry:', error)
152
+ return false
153
+ }
154
+ }
155
+
156
+ export async function removeEnvironmentEntry(environmentName: string): Promise<boolean> {
157
+ try {
158
+ await ensureAutomationWorkspaceReady()
159
+ const filePath = getEnvironmentsFilePath()
160
+
161
+ try {
162
+ await fs.access(filePath)
163
+ } catch {
164
+ return true
165
+ }
166
+
167
+ const fileContent = await fs.readFile(filePath, 'utf-8')
168
+ const environmentsConfig: Record<string, EnvironmentConfig> = JSON.parse(fileContent)
169
+
170
+ const envKey = environmentName.toLowerCase().replace(/\s+/g, '_')
171
+ delete environmentsConfig[envKey]
172
+
173
+ if (Object.keys(environmentsConfig).length === 0) {
174
+ await deleteEnvironmentsFile()
175
+ return true
176
+ }
177
+
178
+ await fs.writeFile(filePath, JSON.stringify(environmentsConfig, null, 2))
179
+ return true
180
+ } catch (error) {
181
+ console.error('Error removing environment entry:', error)
182
+ return false
183
+ }
184
+ }
@@ -1,10 +1,17 @@
1
- import { join } from 'path'
1
+ import { dirname } from 'path'
2
2
  import { spawnTask, taskSpawner, type SpawnedProcess, waitForTask, killTask } from '@/lib/process/task-spawner'
3
- import { ensureAutomationWorkspaceReady, getAutomationReportsDir } from '@/lib/automation/paths'
3
+ import {
4
+ ensureAutomationWorkspaceReady,
5
+ getAutomationRunReportPath,
6
+ toProjectRelativePath,
7
+ } from '@/lib/automation/paths'
4
8
  import type { ExecutorAdapter, TestRunExecutionRequest, TestRunExecutionResult } from './types'
5
9
  import { processManager } from '@/lib/test-run/process-manager'
10
+ import { promises as fs } from 'fs'
6
11
 
7
- function mapBrowserEngineToName(browserEngine: TestRunExecutionRequest['browserEngine']): 'chromium' | 'firefox' | 'webkit' {
12
+ function mapBrowserEngineToName(
13
+ browserEngine: TestRunExecutionRequest['browserEngine'],
14
+ ): 'chromium' | 'firefox' | 'webkit' {
8
15
  switch (browserEngine) {
9
16
  case 'CHROMIUM':
10
17
  return 'chromium'
@@ -17,38 +24,29 @@ function mapBrowserEngineToName(browserEngine: TestRunExecutionRequest['browserE
17
24
  }
18
25
  }
19
26
 
20
- function combineTagExpressions(tags: TestRunExecutionRequest['tags']): string | null {
21
- if (tags.length === 0) {
22
- return null
23
- }
24
-
25
- if (tags.length === 1) {
26
- return tags[0].tagExpression
27
- }
28
-
29
- return tags.map(tag => `(${tag.tagExpression})`).join(' or ')
30
- }
31
-
32
27
  function generateReportPath(testRunId: string): string {
33
- const timestamp = Date.now()
34
- return join(getAutomationReportsDir(), `cucumber-${testRunId}-${timestamp}.json`)
28
+ return getAutomationRunReportPath(testRunId)
35
29
  }
36
30
 
37
31
  export class LocalExecutorAdapter implements ExecutorAdapter {
38
32
  async executeTestRun(config: TestRunExecutionRequest): Promise<TestRunExecutionResult> {
39
33
  await ensureAutomationWorkspaceReady()
40
34
 
41
- const { testRunId, environment, tags, testWorkersCount, browserEngine, headless = true } = config
35
+ const { testRunId, environment, tagExpression, testWorkersCount, browserEngine, headless = true } = config
42
36
  const reportPath = generateReportPath(testRunId)
43
37
  const browserName = mapBrowserEngineToName(browserEngine)
44
-
45
- process.env.ENVIRONMENT = environment.name
46
- process.env.HEADLESS = headless.toString()
47
- process.env.BROWSER = browserName
48
- process.env.REPORT_PATH = reportPath
38
+ await fs.mkdir(dirname(reportPath), { recursive: true })
39
+ const childEnv = {
40
+ ...process.env,
41
+ ENVIRONMENT: environment.name,
42
+ HEADLESS: headless.toString(),
43
+ BROWSER: browserName,
44
+ REPORT_PATH: reportPath,
45
+ REPORT_FORMAT: `json:${reportPath}`,
46
+ TEST_RUN_ID: testRunId,
47
+ }
49
48
 
50
49
  const cucumberArgs: string[] = ['cucumber-js']
51
- const tagExpression = combineTagExpressions(tags)
52
50
 
53
51
  if (tagExpression) {
54
52
  cucumberArgs.push('-t', tagExpression)
@@ -63,6 +61,7 @@ export class LocalExecutorAdapter implements ExecutorAdapter {
63
61
  prefixLogs: true,
64
62
  logPrefix: `test-run-${testRunId}`,
65
63
  captureOutput: true,
64
+ env: childEnv,
66
65
  })
67
66
 
68
67
  processManager.register(testRunId, spawnedProcess)
@@ -72,7 +71,7 @@ export class LocalExecutorAdapter implements ExecutorAdapter {
72
71
 
73
72
  return {
74
73
  process: spawnedProcess,
75
- reportPath,
74
+ reportPath: toProjectRelativePath(reportPath),
76
75
  }
77
76
  }
78
77
 
@@ -1,10 +1,10 @@
1
- import type { BrowserEngine, Environment, Tag } from '@prisma/client'
1
+ import type { BrowserEngine, Environment } from '@prisma/client'
2
2
  import type { SpawnedProcess } from '@/lib/process/task-spawner'
3
3
 
4
4
  export interface TestRunExecutionRequest {
5
5
  testRunId: string
6
6
  environment: Environment
7
- tags: Tag[]
7
+ tagExpression: string | null
8
8
  testWorkersCount: number
9
9
  browserEngine: BrowserEngine
10
10
  headless?: boolean
@@ -3,6 +3,7 @@ import { join, dirname } from 'path'
3
3
  import prisma from '@/config/db-config'
4
4
  import { buildModulePath } from '@/lib/path-helpers/module-path'
5
5
  import { ensureAutomationWorkspaceReady, getAutomationFeaturesDir } from '@/lib/automation/paths'
6
+ import { generateProjectedGherkinSteps, getTestSuiteFilesystemKey } from '@/lib/sync/projected-feature-utils'
6
7
 
7
8
  async function isDirectoryEmpty(dirPath: string): Promise<boolean> {
8
9
  try {
@@ -76,7 +77,7 @@ export async function generateFeatureFile(
76
77
  const moduleDir = join(featuresBaseDir, modulePath.substring(1))
77
78
  await fs.mkdir(moduleDir, { recursive: true })
78
79
 
79
- const safeFileName = generateSafeFileName(testSuiteName)
80
+ const safeFileName = getTestSuiteFilesystemKey(testSuiteName)
80
81
  const featureFilePath = join(moduleDir, `${safeFileName}.feature`)
81
82
 
82
83
  await fs.writeFile(featureFilePath, featureContent, 'utf8')
@@ -126,7 +127,7 @@ function generateFeatureContent(
126
127
 
127
128
  testCases.forEach(testCase => {
128
129
  if (testCase.steps && testCase.steps.length > 0) {
129
- const gherkinSteps = generateGherkinStepsFromTestCase(testCase.steps)
130
+ const gherkinSteps = generateProjectedGherkinSteps(testCase.steps)
130
131
 
131
132
  if (gherkinSteps.length > 0) {
132
133
  if (scenarioCount > 0) {
@@ -153,60 +154,6 @@ function generateFeatureContent(
153
154
  return lines.join('\n') + '\n'
154
155
  }
155
156
 
156
- function generateGherkinStepsFromTestCase(
157
- steps: Array<{
158
- gherkinStep: string
159
- order: number
160
- }>,
161
- ): string[] {
162
- if (!steps || steps.length === 0) {
163
- return []
164
- }
165
-
166
- const sortedSteps = steps.sort((a, b) => a.order - b.order)
167
- let hasThenInPrevious = false
168
- let hasWhenInPrevious = false
169
-
170
- return sortedSteps.map((step, index) => {
171
- const gherkinStep = step.gherkinStep?.trim() || ''
172
- const firstWord = gherkinStep.split(' ')[0].toLowerCase()
173
- const hasGherkinKeyword = ['given', 'when', 'then', 'and', 'but'].includes(firstWord)
174
- const stepWithoutKeyword = hasGherkinKeyword ? gherkinStep.split(' ').slice(1).join(' ') : gherkinStep
175
-
176
- if (index === 0) {
177
- return `Given ${stepWithoutKeyword}`
178
- }
179
-
180
- const isThenStatement =
181
- firstWord === 'then' ||
182
- stepWithoutKeyword.toLowerCase().startsWith('should') ||
183
- stepWithoutKeyword.toLowerCase().startsWith('must') ||
184
- stepWithoutKeyword.toLowerCase().startsWith('will')
185
-
186
- if (!hasThenInPrevious) {
187
- if (isThenStatement) {
188
- hasThenInPrevious = true
189
- return `Then ${stepWithoutKeyword}`
190
- }
191
-
192
- if (!hasWhenInPrevious) {
193
- hasWhenInPrevious = true
194
- return `When ${stepWithoutKeyword}`
195
- }
196
-
197
- return `And ${stepWithoutKeyword}`
198
- }
199
-
200
- if (isThenStatement) {
201
- return `And ${stepWithoutKeyword}`
202
- }
203
-
204
- hasThenInPrevious = false
205
- hasWhenInPrevious = true
206
- return `When ${stepWithoutKeyword}`
207
- })
208
- }
209
-
210
157
  export async function deleteFeatureFile(testSuiteId: string): Promise<boolean> {
211
158
  try {
212
159
  await ensureAutomationWorkspaceReady()
@@ -225,7 +172,7 @@ export async function deleteFeatureFile(testSuiteId: string): Promise<boolean> {
225
172
  }
226
173
 
227
174
  const modulePath = buildModulePath(allModules, testSuite.module)
228
- const safeFileName = generateSafeFileName(testSuite.name)
175
+ const safeFileName = getTestSuiteFilesystemKey(testSuite.name)
229
176
 
230
177
  const featuresBaseDir = getAutomationFeaturesDir()
231
178
  const moduleDir = join(featuresBaseDir, modulePath.substring(1))
@@ -295,7 +242,7 @@ export async function regenerateAllFeatureFiles(): Promise<string[]> {
295
242
  const moduleDir = join(featuresBaseDir, modulePath.substring(1))
296
243
  await fs.mkdir(moduleDir, { recursive: true })
297
244
 
298
- const safeFileName = generateSafeFileName(testSuite.name)
245
+ const safeFileName = getTestSuiteFilesystemKey(testSuite.name)
299
246
  const featureFilePath = join(moduleDir, `${safeFileName}.feature`)
300
247
 
301
248
  await fs.writeFile(featureFilePath, featureContent, 'utf8')
@@ -311,11 +258,3 @@ export async function regenerateAllFeatureFiles(): Promise<string[]> {
311
258
  throw error
312
259
  }
313
260
  }
314
-
315
- function generateSafeFileName(testSuiteName: string): string {
316
- return testSuiteName
317
- .toLowerCase()
318
- .replace(/[^a-z0-9]+/g, '-')
319
- .replace(/^-+|-+$/g, '')
320
- .replace(/-+/g, '-')
321
- }