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
@@ -9,7 +9,6 @@ import {
9
9
  TestRunResult,
10
10
  TestRunTestCaseStatus,
11
11
  TestRunTestCaseResult,
12
- TagType,
13
12
  Tag,
14
13
  } from '@prisma/client'
15
14
  import { localExecutorAdapter } from '@/lib/executor/local-executor-adapter'
@@ -18,9 +17,12 @@ import { formatLogsForStorage, parseLogsFromStorage, type LogEntry } from '@/lib
18
17
  import { processManager } from '@/lib/test-run/process-manager'
19
18
  import { createTestRunLogger, closeLogger, getLogFilePath } from '@/lib/test-run/winston-logger'
20
19
  import { promises as fs } from 'fs'
21
- import path from 'path'
22
20
  import { Prisma } from '@prisma/client'
23
21
  import { updateTestCaseMetrics, updateMetricsForTestRun } from '@/lib/metrics/metric-calculator'
22
+ import { getAutomationReportRunDir, resolveStoredPath } from '@/lib/automation/paths'
23
+ import { ensureTestSuiteIdentifierTags } from '@/lib/test-suite-identifier-service'
24
+ import { getIdentifierTagByPrefix } from '@/lib/tag-utils'
25
+ import { findMatchingTestRunTestCase } from '@/lib/test-run/matching'
24
26
 
25
27
  /**
26
28
  * Check if a test run name already exists
@@ -35,6 +37,47 @@ async function checkUniqueName(name: string, excludeId?: string): Promise<boolea
35
37
  return !!existing
36
38
  }
37
39
 
40
+ function buildOrExpression(expressions: string[]): string | null {
41
+ if (expressions.length === 0) {
42
+ return null
43
+ }
44
+
45
+ if (expressions.length === 1) {
46
+ return expressions[0]
47
+ }
48
+
49
+ return expressions.join(' or ')
50
+ }
51
+
52
+ function normalizeSuiteSelection(
53
+ selection: z.infer<typeof testRunSchema>['testSuites'][number],
54
+ availableTestCaseIds: string[],
55
+ ) {
56
+ if (selection.runAll) {
57
+ return {
58
+ testSuiteId: selection.testSuiteId,
59
+ runAll: true,
60
+ testCaseIds: [] as string[],
61
+ }
62
+ }
63
+
64
+ const selectedTestCaseIds = selection.testCaseIds.filter(testCaseId => availableTestCaseIds.includes(testCaseId))
65
+
66
+ if (selectedTestCaseIds.length === availableTestCaseIds.length) {
67
+ return {
68
+ testSuiteId: selection.testSuiteId,
69
+ runAll: true,
70
+ testCaseIds: [] as string[],
71
+ }
72
+ }
73
+
74
+ return {
75
+ testSuiteId: selection.testSuiteId,
76
+ runAll: false,
77
+ testCaseIds: selectedTestCaseIds,
78
+ }
79
+ }
80
+
38
81
  export async function getAllTestRunsAction(filter?: string): Promise<ActionResponse> {
39
82
  try {
40
83
  // Build the where clause based on filter
@@ -80,6 +123,7 @@ export async function getTestRunByIdAction(id: string): Promise<ActionResponse>
80
123
  testCases: {
81
124
  include: {
82
125
  testCase: true,
126
+ testSuite: true,
83
127
  },
84
128
  },
85
129
  tags: true,
@@ -109,45 +153,31 @@ export async function getTestRunByIdAction(id: string): Promise<ActionResponse>
109
153
 
110
154
  export async function deleteTestRunAction(id: string[]): Promise<ActionResponse> {
111
155
  try {
112
- // Get all unique test case IDs from test runs being deleted (before deletion)
113
- // This is needed to recalculate metrics after deletion
114
- const testRunTestCases = await prisma.testRunTestCase.findMany({
115
- where: {
116
- testRunId: { in: id },
117
- },
118
- select: {
119
- testCaseId: true,
120
- },
121
- })
122
- const _affectedTestCaseIds = [...new Set(testRunTestCases.map(trtc => trtc.testCaseId))]
123
-
124
- // find all trace paths for the test runs
125
- const tracePaths = await prisma.testRunTestCase.findMany({
126
- where: {
127
- testRunId: { in: id },
128
- },
129
- select: {
130
- tracePath: true,
131
- },
132
- })
133
- // delete the trace paths
134
- for (const tracePath of tracePaths) {
135
- if (tracePath.tracePath) {
136
- await fs.unlink(tracePath.tracePath)
137
- }
138
- }
139
-
140
- // find all report paths for the test runs
141
- const reportPaths = await prisma.testRun.findMany({
156
+ const testRuns = await prisma.testRun.findMany({
142
157
  where: { id: { in: id } },
143
158
  select: {
159
+ runId: true,
160
+ logPath: true,
144
161
  reportPath: true,
162
+ testCases: {
163
+ select: {
164
+ tracePath: true,
165
+ },
166
+ },
145
167
  },
146
168
  })
147
- // delete the report paths
148
- for (const reportPath of reportPaths) {
149
- if (reportPath.reportPath) {
150
- await fs.unlink(reportPath.reportPath)
169
+
170
+ for (const testRun of testRuns) {
171
+ await fs.rm(getAutomationReportRunDir(testRun.runId), { recursive: true, force: true })
172
+
173
+ const legacyArtifactPaths = [
174
+ testRun.logPath,
175
+ testRun.reportPath,
176
+ ...testRun.testCases.map(testCase => testCase.tracePath),
177
+ ].filter((artifactPath): artifactPath is string => Boolean(artifactPath))
178
+
179
+ for (const artifactPath of legacyArtifactPaths) {
180
+ await fs.rm(resolveStoredPath(artifactPath), { force: true }).catch(() => {})
151
181
  }
152
182
  }
153
183
 
@@ -161,9 +191,7 @@ export async function deleteTestRunAction(id: string[]): Promise<ActionResponse>
161
191
  // deleting a test run might affect consecutive failure counts for any test case
162
192
  // that had recent runs (e.g., if a test case had 3 consecutive failures and we
163
193
  // delete one of those failures, it might no longer be "repeatedly failing")
164
- const { recalculateMetricsForTestCases, updateDashboardMetrics } = await import(
165
- '@/lib/metrics/metric-calculator'
166
- )
194
+ const { recalculateMetricsForTestCases, updateDashboardMetrics } = await import('@/lib/metrics/metric-calculator')
167
195
 
168
196
  // Get all test case IDs that have recent test runs (last 7 days)
169
197
  // These are the ones that might be affected by the deletion
@@ -187,9 +215,7 @@ export async function deleteTestRunAction(id: string[]): Promise<ActionResponse>
187
215
  })
188
216
 
189
217
  // Get unique test case IDs
190
- const allAffectedTestCaseIds = [
191
- ...new Set(allRecentTestRunTestCases.map(trtc => trtc.testCaseId)),
192
- ]
218
+ const allAffectedTestCaseIds = [...new Set(allRecentTestRunTestCases.map(trtc => trtc.testCaseId))]
193
219
 
194
220
  // Recalculate metrics for all test cases with recent runs
195
221
  if (allAffectedTestCaseIds.length > 0) {
@@ -216,9 +242,18 @@ export async function deleteTestRunAction(id: string[]): Promise<ActionResponse>
216
242
 
217
243
  export async function getAllTestSuiteTestCasesAction(): Promise<ActionResponse> {
218
244
  try {
245
+ await ensureTestSuiteIdentifierTags()
246
+
219
247
  const testSuiteTestCases = await prisma.testSuite.findMany({
220
248
  include: {
221
- testCases: true,
249
+ module: true,
250
+ tags: true,
251
+ testCases: {
252
+ include: {
253
+ steps: true,
254
+ tags: true,
255
+ },
256
+ },
222
257
  },
223
258
  })
224
259
  return {
@@ -337,27 +372,29 @@ export async function createTestRunAction(
337
372
  }
338
373
  }
339
374
 
340
- // Determine if we're filtering by tags or test cases
375
+ // Determine if we're filtering by tags or test suites
341
376
  const isFilteringByTags = value.tags.length > 0
342
- const isFilteringByTestCases = value.testCases.length > 0 && value.tags.length === 0
377
+ const isFilteringByTestSuites = value.testSuites.length > 0 && value.tags.length === 0
343
378
 
344
379
  // Validate that at least one filtering option is provided
345
- if (!isFilteringByTags && !isFilteringByTestCases) {
380
+ if (!isFilteringByTags && !isFilteringByTestSuites) {
346
381
  return {
347
382
  status: 400,
348
- error: 'Either tags or test cases must be provided to filter the test run.',
383
+ error: 'Either tags or test suites must be provided to filter the test run.',
349
384
  }
350
385
  }
351
386
 
352
387
  let tags: Tag[] = []
353
- let testRunTestCases: Array<{ testCaseId: string }> = []
388
+ let tagExpression: string | null = null
389
+ let testRunTestCases: Array<{ testCaseId: string; testSuiteId?: string | null }> = []
354
390
 
355
391
  if (isFilteringByTags) {
356
- // Existing behavior: filter by tags
357
392
  tags = await prisma.tag.findMany({
358
393
  where: { id: { in: value.tags } },
359
394
  })
360
395
 
396
+ tagExpression = buildOrExpression(tags.map(tag => `(${tag.tagExpression})`))
397
+
361
398
  // Find test cases that have tags directly OR belong to test suites with tags
362
399
  const tagFilteredTestCases = await prisma.testCase.findMany({
363
400
  where: {
@@ -384,56 +421,120 @@ export async function createTestRunAction(
384
421
 
385
422
  testRunTestCases = tagFilteredTestCases.map(tc => ({
386
423
  testCaseId: tc.id,
424
+ testSuiteId: null,
387
425
  }))
388
- } else if (isFilteringByTestCases) {
389
- // New behavior: filter by test cases - extract identifier tags
390
- const selectedTestCases = await prisma.testCase.findMany({
426
+ } else if (isFilteringByTestSuites) {
427
+ await ensureTestSuiteIdentifierTags(value.testSuites.map(testSuite => testSuite.testSuiteId))
428
+
429
+ const selectedSuites = await prisma.testSuite.findMany({
391
430
  where: {
392
- id: { in: value.testCases.map(tc => tc.testCaseId) },
431
+ id: {
432
+ in: value.testSuites.map(testSuite => testSuite.testSuiteId),
433
+ },
393
434
  },
394
435
  include: {
395
436
  tags: true,
437
+ testCases: {
438
+ include: {
439
+ tags: true,
440
+ },
441
+ },
396
442
  },
397
443
  })
398
444
 
399
- // Extract identifier tags from selected test cases
400
- const identifierTags = selectedTestCases
401
- .flatMap(tc => tc.tags)
402
- .filter(tag => tag.type === TagType.IDENTIFIER)
403
- // Remove duplicates by id
404
- .filter((tag, index, self) => index === self.findIndex(t => t.id === tag.id))
405
-
406
- // Safety check: if no identifier tags found, this would run all tests
407
- // which is not what the user expects when they select specific test cases
408
- if (identifierTags.length === 0) {
445
+ if (selectedSuites.length !== value.testSuites.length) {
409
446
  return {
410
447
  status: 400,
411
- error: 'Selected test cases do not have identifier tags. Cannot execute specific test cases.',
448
+ error: 'One or more selected test suites could not be found.',
412
449
  }
413
450
  }
414
451
 
415
- // Filter to only include test cases that have identifier tags
416
- // Test cases without identifier tags cannot be executed and should be excluded
417
- const testCasesWithIdentifierTags = selectedTestCases.filter(tc =>
418
- tc.tags.some(tag => tag.type === TagType.IDENTIFIER),
419
- )
452
+ const selectedSuiteById = new Map(selectedSuites.map(testSuite => [testSuite.id, testSuite]))
453
+ const suiteClauses: string[] = []
420
454
 
421
- // Log warning if some test cases don't have identifier tags
422
- const testCasesWithoutIdentifierTags = selectedTestCases.filter(
423
- tc => !tc.tags.some(tag => tag.type === TagType.IDENTIFIER),
424
- )
425
- if (testCasesWithoutIdentifierTags.length > 0) {
426
- console.warn(
427
- `[TestRunAction] Some selected test cases (${testCasesWithoutIdentifierTags.length}) do not have identifier tags and will not be executed.`,
455
+ for (const suiteSelection of value.testSuites) {
456
+ const selectedSuite = selectedSuiteById.get(suiteSelection.testSuiteId)
457
+ if (!selectedSuite) {
458
+ continue
459
+ }
460
+
461
+ if (selectedSuite.testCases.length === 0) {
462
+ continue
463
+ }
464
+
465
+ const normalizedSelection = normalizeSuiteSelection(
466
+ suiteSelection,
467
+ selectedSuite.testCases.map(testCase => testCase.id),
468
+ )
469
+
470
+ if (!normalizedSelection) {
471
+ continue
472
+ }
473
+
474
+ const suiteIdentifierTag = getIdentifierTagByPrefix(selectedSuite.tags, 'ts_')
475
+ if (!suiteIdentifierTag) {
476
+ return {
477
+ status: 400,
478
+ error: `Test suite "${selectedSuite.name}" does not have an identifier tag.`,
479
+ }
480
+ }
481
+
482
+ if (normalizedSelection.runAll) {
483
+ suiteClauses.push(`(${suiteIdentifierTag.tagExpression})`)
484
+ testRunTestCases.push(
485
+ ...selectedSuite.testCases.map(testCase => ({
486
+ testCaseId: testCase.id,
487
+ testSuiteId: selectedSuite.id,
488
+ })),
489
+ )
490
+ continue
491
+ }
492
+
493
+ const selectedTestCases = selectedSuite.testCases.filter(testCase =>
494
+ normalizedSelection.testCaseIds.includes(testCase.id),
495
+ )
496
+
497
+ if (selectedTestCases.length === 0) {
498
+ return {
499
+ status: 400,
500
+ error: `Test suite "${selectedSuite.name}" requires at least one selected test case.`,
501
+ }
502
+ }
503
+
504
+ const missingIdentifierTestCase = selectedTestCases.find(
505
+ testCase => !getIdentifierTagByPrefix(testCase.tags, 'tc_'),
506
+ )
507
+ if (missingIdentifierTestCase) {
508
+ return {
509
+ status: 400,
510
+ error: `Test case "${missingIdentifierTestCase.title}" does not have an identifier tag.`,
511
+ }
512
+ }
513
+
514
+ const testCaseTagExpressions = selectedTestCases.map(testCase => {
515
+ const identifierTag = getIdentifierTagByPrefix(testCase.tags, 'tc_')
516
+ return identifierTag!.tagExpression
517
+ })
518
+
519
+ suiteClauses.push(
520
+ `(${suiteIdentifierTag.tagExpression}) and (${testCaseTagExpressions.map(tag => `(${tag})`).join(' or ')})`,
521
+ )
522
+ testRunTestCases.push(
523
+ ...selectedTestCases.map(testCase => ({
524
+ testCaseId: testCase.id,
525
+ testSuiteId: selectedSuite.id,
526
+ })),
428
527
  )
429
528
  }
430
529
 
431
- tags = identifierTags
530
+ tagExpression = buildOrExpression(suiteClauses.map(clause => `(${clause})`))
531
+ }
432
532
 
433
- // Only include test cases that have identifier tags
434
- testRunTestCases = testCasesWithIdentifierTags.map(tc => ({
435
- testCaseId: tc.id,
436
- }))
533
+ if (!tagExpression) {
534
+ return {
535
+ status: 400,
536
+ error: 'No executable tests were resolved from the selected filters.',
537
+ }
437
538
  }
438
539
 
439
540
  // Create TestRun record in database with RUNNING status
@@ -451,6 +552,7 @@ export async function createTestRunAction(
451
552
  testCases: {
452
553
  create: testRunTestCases.map(tc => ({
453
554
  testCaseId: tc.testCaseId,
555
+ testSuiteId: tc.testSuiteId ?? null,
454
556
  })),
455
557
  },
456
558
  },
@@ -473,7 +575,7 @@ export async function createTestRunAction(
473
575
  const { process: spawnedProcess, reportPath } = await localExecutorAdapter.executeTestRun({
474
576
  testRunId: testRun.runId,
475
577
  environment,
476
- tags,
578
+ tagExpression,
477
579
  testWorkersCount: value.testWorkersCount || 1,
478
580
  browserEngine: value.browserEngine,
479
581
  headless: true, // Default to headless
@@ -496,6 +598,8 @@ export async function createTestRunAction(
496
598
  scenarioName: string
497
599
  status: string
498
600
  tracePath?: string
601
+ featureName?: string
602
+ scenarioTags?: string[]
499
603
  }) => {
500
604
  // Only process events for this test run
501
605
  if (eventData.testRunId === testRun.runId) {
@@ -510,12 +614,13 @@ export async function createTestRunAction(
510
614
  }
511
615
  const mappedStatus = statusMap[eventData.status] || 'unknown'
512
616
  // Update test case status in database
513
- await updateTestRunTestCaseStatusAction(
514
- testRun.runId,
515
- eventData.scenarioName,
516
- mappedStatus,
517
- eventData.tracePath,
518
- )
617
+ await updateTestRunTestCaseStatusAction(testRun.runId, {
618
+ scenarioName: eventData.scenarioName,
619
+ status: mappedStatus,
620
+ tracePath: eventData.tracePath,
621
+ featureName: eventData.featureName,
622
+ scenarioTags: eventData.scenarioTags,
623
+ })
519
624
  }
520
625
  }
521
626
 
@@ -754,9 +859,13 @@ export async function createTestRunAction(
754
859
  */
755
860
  export async function updateTestRunTestCaseStatusAction(
756
861
  testRunId: string,
757
- scenarioName: string,
758
- status: 'passed' | 'failed' | 'skipped' | 'unknown',
759
- tracePath?: string,
862
+ scenario: {
863
+ scenarioName: string
864
+ status: 'passed' | 'failed' | 'skipped' | 'unknown'
865
+ tracePath?: string
866
+ featureName?: string
867
+ scenarioTags?: string[]
868
+ },
760
869
  ): Promise<ActionResponse> {
761
870
  try {
762
871
  // Find the test run by runId
@@ -765,7 +874,16 @@ export async function updateTestRunTestCaseStatusAction(
765
874
  include: {
766
875
  testCases: {
767
876
  include: {
768
- testCase: true,
877
+ testCase: {
878
+ include: {
879
+ tags: true,
880
+ },
881
+ },
882
+ testSuite: {
883
+ include: {
884
+ tags: true,
885
+ },
886
+ },
769
887
  },
770
888
  },
771
889
  },
@@ -778,38 +896,18 @@ export async function updateTestRunTestCaseStatusAction(
778
896
  }
779
897
  }
780
898
 
781
- // Parse scenario name to extract test case title
782
- // Format: "[Test Case Title] Description" or just "Test Case Title"
783
- let testCaseTitle: string | null = null
784
-
785
- // Try to extract title from [brackets]
786
- const bracketMatch = scenarioName.match(/^\[([^\]]+)\]/)
787
- if (bracketMatch) {
788
- testCaseTitle = bracketMatch[1].trim()
789
- } else {
790
- // If no brackets, use the full scenario name (might be just the title)
791
- testCaseTitle = scenarioName.trim()
792
- }
793
-
794
- if (!testCaseTitle) {
795
- return {
796
- status: 400,
797
- error: 'Could not extract test case title from scenario name',
798
- }
799
- }
800
-
801
- // Find matching test case by title
802
- const matchingTestCase = testRun.testCases.find(trtc => trtc.testCase.title === testCaseTitle)
899
+ const matchingTestCase = findMatchingTestRunTestCase(testRun.testCases, {
900
+ scenarioName: scenario.scenarioName,
901
+ scenarioTags: scenario.scenarioTags,
902
+ })
803
903
 
804
904
  if (!matchingTestCase) {
805
- // This is expected when scenarios run without corresponding test cases (e.g., when filtered by tags)
806
- // Return success status to indicate this was handled gracefully
807
905
  console.log(
808
- `[TestRunAction] No matching test case found for scenario: ${scenarioName} (extracted title: ${testCaseTitle}). This is expected when scenarios run without corresponding test cases.`,
906
+ `[TestRunAction] No matching test case found for scenario: ${scenario.scenarioName}. This is expected when scenarios run without corresponding test cases in this test run.`,
809
907
  )
810
908
  return {
811
909
  status: 200,
812
- message: `Scenario "${scenarioName}" completed but has no corresponding test case in this test run (likely filtered by tags)`,
910
+ message: `Scenario "${scenario.scenarioName}" completed but has no corresponding test case in this test run`,
813
911
  }
814
912
  }
815
913
 
@@ -817,7 +915,7 @@ export async function updateTestRunTestCaseStatusAction(
817
915
  const testCaseStatus: TestRunTestCaseStatus = TestRunTestCaseStatus.COMPLETED
818
916
  let testCaseResult: TestRunTestCaseResult
819
917
 
820
- switch (status) {
918
+ switch (scenario.status) {
821
919
  case 'passed':
822
920
  testCaseResult = TestRunTestCaseResult.PASSED
823
921
  break
@@ -837,7 +935,7 @@ export async function updateTestRunTestCaseStatusAction(
837
935
  data: {
838
936
  status: testCaseStatus,
839
937
  result: testCaseResult,
840
- tracePath: tracePath || null,
938
+ tracePath: scenario.tracePath || null,
841
939
  },
842
940
  })
843
941
 
@@ -859,7 +957,7 @@ export async function updateTestRunTestCaseStatusAction(
859
957
  }
860
958
  } catch (error) {
861
959
  console.error(
862
- `[TestRunAction] Error updating test case status for testRunId: ${testRunId}, scenario: ${scenarioName}:`,
960
+ `[TestRunAction] Error updating test case status for testRunId: ${testRunId}, scenario: ${scenario.scenarioName}:`,
863
961
  error,
864
962
  )
865
963
  return {
@@ -973,9 +1071,11 @@ export async function spawnTraceViewerAction(testRunId: string, testCaseId: stri
973
1071
  }
974
1072
  }
975
1073
 
1074
+ const absoluteTracePath = resolveStoredPath(tracePath)
1075
+
976
1076
  // Validate trace file exists
977
1077
  try {
978
- await fs.access(tracePath)
1078
+ await fs.access(absoluteTracePath)
979
1079
  } catch {
980
1080
  return {
981
1081
  status: 404,
@@ -983,9 +1083,6 @@ export async function spawnTraceViewerAction(testRunId: string, testCaseId: stri
983
1083
  }
984
1084
  }
985
1085
 
986
- // Resolve absolute path if relative
987
- const absoluteTracePath = path.isAbsolute(tracePath) ? tracePath : path.join(process.cwd(), tracePath)
988
-
989
1086
  // Spawn playwright show-trace command
990
1087
  // The process is self-closing when the user closes the trace viewer
991
1088
  const spawnedProcess = await localExecutorAdapter.spawnTraceViewer(testCaseId, absoluteTracePath)
@@ -1177,7 +1274,3 @@ export async function checkTestRunNameUniqueAction(name: string, excludeId?: str
1177
1274
  }
1178
1275
  }
1179
1276
  }
1180
-
1181
-
1182
-
1183
-