create-appraisejs 0.2.0 → 0.3.0-alpha.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (485) hide show
  1. package/README.md +12 -1
  2. package/package.json +1 -1
  3. package/templates/default/.appraise-template-meta.json +2 -2
  4. package/templates/default/.env.example +2 -2
  5. package/templates/default/README.md +57 -53
  6. package/templates/default/automation/steps/actions/click.step.ts +58 -58
  7. package/templates/default/automation/steps/actions/hover.step.ts +27 -27
  8. package/templates/default/automation/steps/actions/navigation.step.ts +70 -70
  9. package/templates/default/automation/steps/actions/random_data.step.ts +142 -142
  10. package/templates/default/automation/steps/actions/store.step.ts +86 -86
  11. package/templates/default/automation/steps/actions/wait.step.ts +110 -90
  12. package/templates/default/automation/steps/validations/active_state_assertion.step.ts +30 -30
  13. package/templates/default/automation/steps/validations/navigation_assertion.step.ts +22 -22
  14. package/templates/default/automation/steps/validations/text_assertion.step.ts +107 -107
  15. package/templates/default/automation/steps/validations/visibility_assertion.step.ts +26 -26
  16. package/templates/default/components.json +24 -24
  17. package/templates/default/cucumber.mjs +16 -16
  18. package/templates/default/eslint.config.mjs +20 -16
  19. package/templates/default/next-env.d.ts +6 -6
  20. package/templates/default/next.config.ts +20 -11
  21. package/templates/default/package-lock.json +1775 -74
  22. package/templates/default/package.json +8 -1
  23. package/templates/default/packages/cucumber-runtime/package.json +13 -13
  24. package/templates/default/packages/cucumber-runtime/src/cache.util.ts +93 -93
  25. package/templates/default/packages/cucumber-runtime/src/cli.ts +68 -68
  26. package/templates/default/packages/cucumber-runtime/src/environment.util.ts +21 -21
  27. package/templates/default/packages/cucumber-runtime/src/executor.ts +32 -32
  28. package/templates/default/packages/cucumber-runtime/src/index.ts +17 -17
  29. package/templates/default/packages/cucumber-runtime/src/locator.util.ts +234 -234
  30. package/templates/default/packages/cucumber-runtime/src/parameter-types.ts +7 -7
  31. package/templates/default/packages/cucumber-runtime/src/random-data.util.ts +35 -35
  32. package/templates/default/packages/cucumber-runtime/src/types.ts +13 -13
  33. package/templates/default/packages/cucumber-runtime/src/world.ts +44 -44
  34. package/templates/default/packages/cucumber-runtime/tsconfig.json +11 -11
  35. package/templates/default/postcss.config.mjs +8 -8
  36. package/templates/default/prisma/dev.db +0 -0
  37. package/templates/default/prisma/migrations/20251104113456_add_type_for_template_step_groups/migration.sql +16 -16
  38. package/templates/default/prisma/migrations/20251104170946_add_tags_to_test_suite_and_test_case/migration.sql +27 -27
  39. package/templates/default/prisma/migrations/20251112190024_add_cascade_delete_to_test_run_test_case/migration.sql +17 -17
  40. package/templates/default/prisma/migrations/20251113181100_add_test_run_log/migration.sql +12 -12
  41. package/templates/default/prisma/migrations/20251119191838_add_tag_type/migration.sql +28 -28
  42. package/templates/default/prisma/migrations/20251121164059_add_conflict_resolution/migration.sql +12 -12
  43. package/templates/default/prisma/migrations/20251223183400_add_report_model_to_db_schema/migration.sql +10 -10
  44. package/templates/default/prisma/migrations/20251223183637_add_report_test_case_entity_for_storing_test_results_for_individual_test_cases/migration.sql +10 -10
  45. package/templates/default/prisma/migrations/20251224083549_add_comprehensive_report_storage/migration.sql +108 -108
  46. package/templates/default/prisma/migrations/20251229194422_migrate_duration_to_string/migration.sql +55 -55
  47. package/templates/default/prisma/migrations/20251230124637_add_unique_constraint_to_test_run_name/migration.sql +27 -27
  48. package/templates/default/prisma/migrations/20260115094436_add_dashboard_metrics/migration.sql +59 -59
  49. package/templates/default/prisma/migrations/20260127172022_add_cascade_delete_to_step_parameters/migration.sql +34 -34
  50. package/templates/default/prisma/migrations/20260313093000_add_report_step_screenshot_path/migration.sql +1 -1
  51. package/templates/default/scripts/build-step-registry.ts +33 -0
  52. package/templates/default/scripts/install-playwright.ts +17 -8
  53. package/templates/default/scripts/install-template-step.ts +128 -0
  54. package/templates/default/scripts/lib/filename-utils.test.ts +24 -0
  55. package/templates/default/scripts/lib/filename-utils.ts +24 -0
  56. package/templates/default/scripts/lib/jsdoc-parser.test.ts +63 -0
  57. package/templates/default/scripts/lib/jsdoc-parser.ts +88 -0
  58. package/templates/default/scripts/lib/step-file-parser.test.ts +71 -0
  59. package/templates/default/scripts/lib/step-file-parser.ts +315 -0
  60. package/templates/default/scripts/lib/step-matcher.test.ts +86 -0
  61. package/templates/default/scripts/lib/step-matcher.ts +120 -0
  62. package/templates/default/scripts/lib/sync-script-runner.ts +23 -0
  63. package/templates/default/scripts/lib/sync-summary.ts +29 -0
  64. package/templates/default/scripts/lib/tag-parsing.test.ts +20 -0
  65. package/templates/default/scripts/lib/tag-parsing.ts +10 -0
  66. package/templates/default/scripts/lib/template-step-installer.test.ts +225 -0
  67. package/templates/default/scripts/lib/template-step-installer.ts +404 -0
  68. package/templates/default/scripts/lib/template-step-registry.test.ts +118 -0
  69. package/templates/default/scripts/lib/template-step-registry.ts +137 -0
  70. package/templates/default/scripts/protect-seeded-files.ts +51 -38
  71. package/templates/default/scripts/regenerate-features.ts +98 -94
  72. package/templates/default/scripts/run-vitest.ts +59 -0
  73. package/templates/default/scripts/setup-env.ts +26 -19
  74. package/templates/default/scripts/sync-all.ts +44 -54
  75. package/templates/default/scripts/sync-appraise-base-template.ts +44 -16
  76. package/templates/default/scripts/sync-environments.ts +22 -66
  77. package/templates/default/scripts/sync-locator-groups.ts +358 -410
  78. package/templates/default/scripts/sync-locators.ts +348 -398
  79. package/templates/default/scripts/sync-modules.ts +302 -341
  80. package/templates/default/scripts/sync-tags.ts +29 -65
  81. package/templates/default/scripts/sync-template-step-groups.ts +24 -182
  82. package/templates/default/scripts/sync-template-steps.ts +36 -493
  83. package/templates/default/scripts/sync-test-cases.ts +296 -539
  84. package/templates/default/scripts/sync-test-suites.ts +32 -79
  85. package/templates/default/src/actions/dashboard/dashboard-actions.ts +70 -241
  86. package/templates/default/src/actions/environments/environment-actions.ts +102 -188
  87. package/templates/default/src/actions/locator/locator-actions.ts +77 -490
  88. package/templates/default/src/actions/locator-groups/locator-group-actions.ts +34 -212
  89. package/templates/default/src/actions/locator-picker/locator-picker-actions.test.ts +81 -0
  90. package/templates/default/src/actions/locator-picker/locator-picker-actions.ts +20 -161
  91. package/templates/default/src/actions/modules/module-actions.ts +99 -135
  92. package/templates/default/src/actions/reports/report-actions.ts +28 -565
  93. package/templates/default/src/actions/settings/sync-actions.test.ts +58 -0
  94. package/templates/default/src/actions/tags/tag-actions.ts +99 -107
  95. package/templates/default/src/actions/template-step/template-step-actions.ts +33 -194
  96. package/templates/default/src/actions/template-step-group/template-step-group-actions.ts +35 -92
  97. package/templates/default/src/actions/template-test-case/template-test-case-actions.ts +98 -238
  98. package/templates/default/src/actions/test-case/test-case-actions.ts +108 -356
  99. package/templates/default/src/actions/test-run/test-run-actions.ts +74 -1081
  100. package/templates/default/src/actions/test-suite/test-suite-actions.ts +35 -202
  101. package/templates/default/src/app/(base)/environments/create/page.tsx +28 -28
  102. package/templates/default/src/app/(base)/environments/environment-form.test.tsx +92 -0
  103. package/templates/default/src/app/(base)/environments/environment-form.tsx +228 -219
  104. package/templates/default/src/app/(base)/environments/environment-helpers.ts +58 -0
  105. package/templates/default/src/app/(base)/environments/environment-table-columns.tsx +96 -96
  106. package/templates/default/src/app/(base)/environments/environment-table.tsx +25 -24
  107. package/templates/default/src/app/(base)/environments/modify/[id]/page.tsx +49 -46
  108. package/templates/default/src/app/(base)/environments/page.tsx +59 -59
  109. package/templates/default/src/app/(base)/layout.tsx +10 -10
  110. package/templates/default/src/app/(base)/locator-groups/create/page.tsx +44 -44
  111. package/templates/default/src/app/(base)/locator-groups/locator-group-form.tsx +215 -215
  112. package/templates/default/src/app/(base)/locator-groups/locator-group-table-columns.tsx +77 -77
  113. package/templates/default/src/app/(base)/locator-groups/locator-group-table.tsx +28 -28
  114. package/templates/default/src/app/(base)/locator-groups/modify/[id]/page.tsx +46 -46
  115. package/templates/default/src/app/(base)/locators/create/create-locator-workspace-helpers.test.ts +71 -0
  116. package/templates/default/src/app/(base)/locators/create/create-locator-workspace-helpers.ts +333 -0
  117. package/templates/default/src/app/(base)/locators/create/create-locator-workspace.test.tsx +125 -0
  118. package/templates/default/src/app/(base)/locators/create/create-locator-workspace.tsx +56 -274
  119. package/templates/default/src/app/(base)/locators/create/page.tsx +8 -4
  120. package/templates/default/src/app/(base)/locators/create/use-locator-workspace.ts +183 -0
  121. package/templates/default/src/app/(base)/locators/locator-helpers.test.ts +28 -0
  122. package/templates/default/src/app/(base)/locators/locator-helpers.ts +59 -0
  123. package/templates/default/src/app/(base)/locators/locator-table-columns.tsx +74 -73
  124. package/templates/default/src/app/(base)/locators/locator-table.tsx +30 -28
  125. package/templates/default/src/app/(base)/locators/modify/[id]/page.tsx +20 -8
  126. package/templates/default/src/app/(base)/locators/page.tsx +3 -6
  127. package/templates/default/src/app/(base)/locators/sync-locators-button.tsx +67 -66
  128. package/templates/default/src/app/(base)/modules/create/page.tsx +33 -34
  129. package/templates/default/src/app/(base)/modules/modify/[id]/page.tsx +43 -46
  130. package/templates/default/src/app/(base)/modules/module-form.test.tsx +84 -0
  131. package/templates/default/src/app/(base)/modules/module-form.tsx +159 -126
  132. package/templates/default/src/app/(base)/modules/module-helpers.ts +64 -0
  133. package/templates/default/src/app/(base)/modules/module-table-columns.tsx +81 -85
  134. package/templates/default/src/app/(base)/modules/module-table.tsx +25 -24
  135. package/templates/default/src/app/(base)/modules/page.tsx +59 -59
  136. package/templates/default/src/app/(base)/reports/[id]/page.tsx +20 -260
  137. package/templates/default/src/app/(base)/reports/duration-chart.tsx +33 -33
  138. package/templates/default/src/app/(base)/reports/feature-chart.tsx +79 -78
  139. package/templates/default/src/app/(base)/reports/overview-chart.tsx +49 -49
  140. package/templates/default/src/app/(base)/reports/page.tsx +98 -98
  141. package/templates/default/src/app/(base)/reports/report-detail-helpers.test.ts +109 -0
  142. package/templates/default/src/app/(base)/reports/report-detail-helpers.ts +247 -0
  143. package/templates/default/src/app/(base)/reports/report-metric-card.tsx +78 -78
  144. package/templates/default/src/app/(base)/reports/report-table-columns.tsx +189 -189
  145. package/templates/default/src/app/(base)/reports/report-table.tsx +72 -72
  146. package/templates/default/src/app/(base)/reports/test-cases/page.tsx +40 -40
  147. package/templates/default/src/app/(base)/reports/test-cases/test-cases-metric-table-columns.tsx +115 -115
  148. package/templates/default/src/app/(base)/reports/test-cases/test-cases-metric-table.tsx +27 -27
  149. package/templates/default/src/app/(base)/reports/test-suites/page.tsx +42 -42
  150. package/templates/default/src/app/(base)/reports/test-suites/test-suites-metric-table-columns.tsx +79 -79
  151. package/templates/default/src/app/(base)/reports/test-suites/test-suites-metric-table.tsx +27 -27
  152. package/templates/default/src/app/(base)/reports/view-logs-button.tsx +58 -58
  153. package/templates/default/src/app/(base)/settings/settings-sync-panel-helpers.test.tsx +40 -0
  154. package/templates/default/src/app/(base)/settings/settings-sync-panel-helpers.tsx +110 -0
  155. package/templates/default/src/app/(base)/settings/settings-sync-panel.test.tsx +127 -0
  156. package/templates/default/src/app/(base)/settings/settings-sync-panel.tsx +19 -134
  157. package/templates/default/src/app/(base)/settings/use-settings-sync.ts +66 -0
  158. package/templates/default/src/app/(base)/tags/create/page.tsx +39 -39
  159. package/templates/default/src/app/(base)/tags/modify/[id]/page.tsx +50 -50
  160. package/templates/default/src/app/(base)/tags/page.tsx +58 -58
  161. package/templates/default/src/app/(base)/tags/tag-form-helpers.ts +13 -0
  162. package/templates/default/src/app/(base)/tags/tag-form.test.tsx +83 -0
  163. package/templates/default/src/app/(base)/tags/tag-form.tsx +143 -147
  164. package/templates/default/src/app/(base)/tags/tag-table-columns.tsx +63 -63
  165. package/templates/default/src/app/(base)/tags/tag-table.tsx +29 -29
  166. package/templates/default/src/app/(base)/template-step-groups/create/page.tsx +28 -28
  167. package/templates/default/src/app/(base)/template-step-groups/modify/[id]/page.tsx +43 -45
  168. package/templates/default/src/app/(base)/template-step-groups/page.tsx +60 -60
  169. package/templates/default/src/app/(base)/template-step-groups/template-step-group-form.test.tsx +82 -0
  170. package/templates/default/src/app/(base)/template-step-groups/template-step-group-form.tsx +181 -167
  171. package/templates/default/src/app/(base)/template-step-groups/template-step-group-helpers.ts +54 -0
  172. package/templates/default/src/app/(base)/template-step-groups/template-step-group-table-columns.tsx +89 -89
  173. package/templates/default/src/app/(base)/template-step-groups/template-step-group-table.tsx +34 -32
  174. package/templates/default/src/app/(base)/template-steps/create/page.tsx +40 -37
  175. package/templates/default/src/app/(base)/template-steps/modify/[id]/page.tsx +54 -49
  176. package/templates/default/src/app/(base)/template-steps/page.tsx +59 -58
  177. package/templates/default/src/app/(base)/template-steps/paramChip.tsx +233 -213
  178. package/templates/default/src/app/(base)/template-steps/template-step-form.test.tsx +132 -0
  179. package/templates/default/src/app/(base)/template-steps/template-step-form.tsx +342 -384
  180. package/templates/default/src/app/(base)/template-steps/template-step-helpers.test.ts +99 -0
  181. package/templates/default/src/app/(base)/template-steps/template-step-helpers.ts +176 -0
  182. package/templates/default/src/app/(base)/template-steps/template-step-table-columns.tsx +153 -158
  183. package/templates/default/src/app/(base)/template-steps/template-step-table.tsx +26 -24
  184. package/templates/default/src/app/(base)/template-test-cases/create/page.tsx +56 -56
  185. package/templates/default/src/app/(base)/template-test-cases/modify/[id]/page.tsx +89 -89
  186. package/templates/default/src/app/(base)/template-test-cases/page.tsx +58 -58
  187. package/templates/default/src/app/(base)/template-test-cases/template-test-case-flow.test.tsx +109 -0
  188. package/templates/default/src/app/(base)/template-test-cases/template-test-case-flow.tsx +45 -84
  189. package/templates/default/src/app/(base)/template-test-cases/template-test-case-form.test.tsx +140 -0
  190. package/templates/default/src/app/(base)/template-test-cases/template-test-case-form.tsx +154 -262
  191. package/templates/default/src/app/(base)/template-test-cases/template-test-case-table-columns.tsx +76 -76
  192. package/templates/default/src/app/(base)/template-test-cases/template-test-case-table.tsx +32 -32
  193. package/templates/default/src/app/(base)/test-cases/create/page.tsx +90 -76
  194. package/templates/default/src/app/(base)/test-cases/create-from-template/create-from-template-helpers.test.ts +94 -0
  195. package/templates/default/src/app/(base)/test-cases/create-from-template/create-from-template-helpers.ts +171 -0
  196. package/templates/default/src/app/(base)/test-cases/create-from-template/generate/[id]/page.tsx +105 -96
  197. package/templates/default/src/app/(base)/test-cases/create-from-template/page.tsx +40 -38
  198. package/templates/default/src/app/(base)/test-cases/create-from-template/template-selection-form.test.tsx +87 -0
  199. package/templates/default/src/app/(base)/test-cases/create-from-template/template-selection-form.tsx +83 -73
  200. package/templates/default/src/app/(base)/test-cases/modify/[id]/page.tsx +106 -106
  201. package/templates/default/src/app/(base)/test-cases/page.tsx +3 -2
  202. package/templates/default/src/app/(base)/test-cases/test-case-flow.test.tsx +108 -0
  203. package/templates/default/src/app/(base)/test-cases/test-case-flow.tsx +43 -82
  204. package/templates/default/src/app/(base)/test-cases/test-case-form.test.tsx +202 -0
  205. package/templates/default/src/app/(base)/test-cases/test-case-form.tsx +263 -395
  206. package/templates/default/src/app/(base)/test-cases/test-case-route-helpers.test.ts +95 -0
  207. package/templates/default/src/app/(base)/test-cases/test-case-route-helpers.ts +147 -0
  208. package/templates/default/src/app/(base)/test-cases/test-case-table.tsx +4 -2
  209. package/templates/default/src/app/(base)/test-runs/[id]/page.tsx +11 -10
  210. package/templates/default/src/app/(base)/test-runs/create/page.tsx +4 -5
  211. package/templates/default/src/app/(base)/test-runs/page.tsx +60 -60
  212. package/templates/default/src/app/(base)/test-runs/test-run-form-helpers.test.ts +50 -0
  213. package/templates/default/src/app/(base)/test-runs/test-run-form-helpers.ts +168 -0
  214. package/templates/default/src/app/(base)/test-runs/test-run-form.test.tsx +138 -0
  215. package/templates/default/src/app/(base)/test-runs/test-run-form.tsx +111 -256
  216. package/templates/default/src/app/(base)/test-runs/test-run-table-columns.tsx +229 -229
  217. package/templates/default/src/app/(base)/test-runs/test-run-table.tsx +127 -127
  218. package/templates/default/src/app/(base)/test-runs/use-test-run-name-validation.ts +74 -0
  219. package/templates/default/src/app/(base)/test-suites/create/page.tsx +17 -12
  220. package/templates/default/src/app/(base)/test-suites/modify/[id]/page.tsx +22 -19
  221. package/templates/default/src/app/(base)/test-suites/page.tsx +14 -56
  222. package/templates/default/src/app/(base)/test-suites/test-suite-form.test.tsx +127 -0
  223. package/templates/default/src/app/(base)/test-suites/test-suite-form.tsx +45 -64
  224. package/templates/default/src/app/(base)/test-suites/test-suite-helpers.test.ts +67 -0
  225. package/templates/default/src/app/(base)/test-suites/test-suite-helpers.ts +215 -0
  226. package/templates/default/src/app/(base)/test-suites/test-suite-table.tsx +32 -29
  227. package/templates/default/src/app/(dashboard-components)/app-drawer.tsx +187 -187
  228. package/templates/default/src/app/(dashboard-components)/data-card-grid.tsx +12 -12
  229. package/templates/default/src/app/(dashboard-components)/data-card.tsx +26 -26
  230. package/templates/default/src/app/(dashboard-components)/execution-health-panel.tsx +56 -56
  231. package/templates/default/src/app/(dashboard-components)/ongoing-test-runs-card.tsx +87 -87
  232. package/templates/default/src/app/(dashboard-components)/quick-actions-drawer.tsx +44 -44
  233. package/templates/default/src/app/api/reports/steps/[stepId]/screenshot/route.test.ts +83 -0
  234. package/templates/default/src/app/api/reports/steps/[stepId]/screenshot/route.ts +52 -52
  235. package/templates/default/src/app/api/test-runs/[runId]/download/route.test.ts +169 -0
  236. package/templates/default/src/app/api/test-runs/[runId]/download/route.ts +1 -1
  237. package/templates/default/src/app/api/test-runs/[runId]/trace/[testCaseId]/route.test.ts +135 -0
  238. package/templates/default/src/app/api/test-runs/[runId]/trace/[testCaseId]/route.ts +146 -146
  239. package/templates/default/src/app/globals.css +147 -147
  240. package/templates/default/src/app/page.tsx +1 -1
  241. package/templates/default/src/assets/icons/empty-tube.tsx +23 -23
  242. package/templates/default/src/assets/icons/tube-plus.tsx +29 -29
  243. package/templates/default/src/components/base-node.tsx +21 -21
  244. package/templates/default/src/components/chart/pie-chart.tsx +73 -73
  245. package/templates/default/src/components/data-extraction/locator-inspector-helpers.test.ts +32 -0
  246. package/templates/default/src/components/data-extraction/locator-inspector-helpers.ts +183 -0
  247. package/templates/default/src/components/data-extraction/locator-inspector.tsx +349 -460
  248. package/templates/default/src/components/data-state/empty-state.tsx +40 -40
  249. package/templates/default/src/components/data-visualization/info-card.tsx +70 -70
  250. package/templates/default/src/components/data-visualization/info-grid.tsx +22 -22
  251. package/templates/default/src/components/diagram/button-edge.tsx +54 -54
  252. package/templates/default/src/components/diagram/dynamic-parameters-helpers.test.ts +83 -0
  253. package/templates/default/src/components/diagram/dynamic-parameters-helpers.ts +158 -0
  254. package/templates/default/src/components/diagram/dynamic-parameters.tsx +350 -474
  255. package/templates/default/src/components/diagram/edit-header-option.tsx +36 -36
  256. package/templates/default/src/components/diagram/flow-diagram-helpers.test.ts +117 -0
  257. package/templates/default/src/components/diagram/flow-diagram-helpers.ts +251 -0
  258. package/templates/default/src/components/diagram/flow-diagram.tsx +247 -470
  259. package/templates/default/src/components/diagram/flow-host-helpers.test.ts +74 -0
  260. package/templates/default/src/components/diagram/flow-host-helpers.ts +51 -0
  261. package/templates/default/src/components/diagram/node-form-helpers.test.ts +92 -0
  262. package/templates/default/src/components/diagram/node-form-helpers.ts +100 -0
  263. package/templates/default/src/components/diagram/node-form.test.tsx +168 -0
  264. package/templates/default/src/components/diagram/node-form.tsx +199 -262
  265. package/templates/default/src/components/diagram/options-header-node.tsx +57 -57
  266. package/templates/default/src/components/diagram/template-step-combobox.tsx +155 -155
  267. package/templates/default/src/components/diagram/use-flow-node-order.ts +49 -0
  268. package/templates/default/src/components/form/error-message.tsx +7 -7
  269. package/templates/default/src/components/kokonutui/smooth-tab.tsx +453 -453
  270. package/templates/default/src/components/loading-skeleton/data-table/data-table-skeleton.tsx +30 -30
  271. package/templates/default/src/components/loading-skeleton/form/button-skeleton.tsx +8 -8
  272. package/templates/default/src/components/loading-skeleton/form/icon-button-skeleton.tsx +8 -8
  273. package/templates/default/src/components/loading-skeleton/form/text-input-skeleton.tsx +8 -8
  274. package/templates/default/src/components/loading-skeleton/visualization/table-skeleton.tsx +14 -14
  275. package/templates/default/src/components/navigation/command-badge.tsx +34 -34
  276. package/templates/default/src/components/navigation/command-chain-input.tsx +51 -51
  277. package/templates/default/src/components/navigation/entity-search-command.tsx +118 -116
  278. package/templates/default/src/components/navigation/nav-card.tsx +31 -31
  279. package/templates/default/src/components/navigation/nav-command-helpers.ts +122 -0
  280. package/templates/default/src/components/navigation/nav-command-search.tsx +125 -0
  281. package/templates/default/src/components/navigation/nav-command.test.tsx +106 -0
  282. package/templates/default/src/components/navigation/nav-command.tsx +49 -472
  283. package/templates/default/src/components/navigation/nav-link.tsx +60 -60
  284. package/templates/default/src/components/navigation/nav-menu-card-deck.tsx +112 -112
  285. package/templates/default/src/components/navigation/use-nav-command.ts +58 -0
  286. package/templates/default/src/components/node-header.tsx +159 -159
  287. package/templates/default/src/components/reports/test-case-logs-modal.tsx +310 -310
  288. package/templates/default/src/components/table/table-actions.tsx +174 -172
  289. package/templates/default/src/components/test-case/test-case-form-helpers.test.ts +100 -0
  290. package/templates/default/src/components/test-case/test-case-form-helpers.ts +140 -0
  291. package/templates/default/src/components/test-case/test-case-picker-helpers.test.ts +40 -0
  292. package/templates/default/src/components/test-case/test-case-picker-helpers.ts +41 -0
  293. package/templates/default/src/components/test-case/test-case-picker.test.tsx +44 -0
  294. package/templates/default/src/components/test-case/test-case-picker.tsx +16 -35
  295. package/templates/default/src/components/test-case/test-scenario-preview.tsx +34 -0
  296. package/templates/default/src/components/test-run/download-logs-button.tsx +92 -92
  297. package/templates/default/src/components/test-run/log-viewer-helpers.test.ts +37 -0
  298. package/templates/default/src/components/test-run/log-viewer-helpers.ts +80 -0
  299. package/templates/default/src/components/test-run/log-viewer.test.tsx +118 -0
  300. package/templates/default/src/components/test-run/log-viewer.tsx +51 -350
  301. package/templates/default/src/components/test-run/test-run-details-helpers.test.ts +31 -0
  302. package/templates/default/src/components/test-run/test-run-details-helpers.ts +208 -0
  303. package/templates/default/src/components/test-run/test-run-details.test.tsx +174 -0
  304. package/templates/default/src/components/test-run/test-run-details.tsx +155 -457
  305. package/templates/default/src/components/test-run/test-run-header-helpers.test.ts +31 -0
  306. package/templates/default/src/components/test-run/test-run-header-helpers.ts +23 -0
  307. package/templates/default/src/components/test-run/test-run-header.test.tsx +103 -0
  308. package/templates/default/src/components/test-run/test-run-header.tsx +27 -149
  309. package/templates/default/src/components/test-run/use-log-viewer.ts +213 -0
  310. package/templates/default/src/components/test-run/use-test-run-details.ts +184 -0
  311. package/templates/default/src/components/test-run/use-test-run-header.ts +89 -0
  312. package/templates/default/src/components/test-run/view-report-button.tsx +102 -102
  313. package/templates/default/src/components/test-suite/test-suite-picker-helpers.test.ts +68 -0
  314. package/templates/default/src/components/test-suite/test-suite-picker-helpers.ts +76 -0
  315. package/templates/default/src/components/test-suite/test-suite-picker.test.tsx +65 -0
  316. package/templates/default/src/components/test-suite/test-suite-picker.tsx +4 -72
  317. package/templates/default/src/components/theme/mode-toggle.tsx +54 -54
  318. package/templates/default/src/components/theme/theme-provider.tsx +8 -8
  319. package/templates/default/src/components/typography/page-header-subtitle.tsx +7 -7
  320. package/templates/default/src/components/typography/page-header.tsx +7 -7
  321. package/templates/default/src/components/ui/alert-dialog.tsx +106 -106
  322. package/templates/default/src/components/ui/alert.tsx +43 -43
  323. package/templates/default/src/components/ui/avatar.tsx +40 -40
  324. package/templates/default/src/components/ui/badge.tsx +29 -29
  325. package/templates/default/src/components/ui/button.tsx +47 -47
  326. package/templates/default/src/components/ui/calendar.tsx +158 -158
  327. package/templates/default/src/components/ui/card.tsx +43 -43
  328. package/templates/default/src/components/ui/checkbox.tsx +28 -28
  329. package/templates/default/src/components/ui/command.tsx +135 -135
  330. package/templates/default/src/components/ui/data-table-column-header.tsx +61 -61
  331. package/templates/default/src/components/ui/data-table-pagination.tsx +87 -87
  332. package/templates/default/src/components/ui/data-table-view-options.tsx +50 -50
  333. package/templates/default/src/components/ui/data-table.test.tsx +122 -0
  334. package/templates/default/src/components/ui/data-table.tsx +298 -261
  335. package/templates/default/src/components/ui/dialog.tsx +97 -97
  336. package/templates/default/src/components/ui/dropdown-menu.tsx +182 -182
  337. package/templates/default/src/components/ui/input.tsx +22 -22
  338. package/templates/default/src/components/ui/kbd.tsx +28 -28
  339. package/templates/default/src/components/ui/label.tsx +19 -19
  340. package/templates/default/src/components/ui/loading.tsx +12 -12
  341. package/templates/default/src/components/ui/multi-select-with-preview.tsx +116 -116
  342. package/templates/default/src/components/ui/multi-select.test.tsx +45 -0
  343. package/templates/default/src/components/ui/multi-select.tsx +158 -142
  344. package/templates/default/src/components/ui/navigation-menu.tsx +120 -120
  345. package/templates/default/src/components/ui/popover.tsx +33 -33
  346. package/templates/default/src/components/ui/progress.tsx +25 -25
  347. package/templates/default/src/components/ui/radio-group.tsx +44 -44
  348. package/templates/default/src/components/ui/scroll-area.tsx +40 -40
  349. package/templates/default/src/components/ui/select.tsx +151 -151
  350. package/templates/default/src/components/ui/separator.tsx +22 -22
  351. package/templates/default/src/components/ui/skeleton.tsx +7 -7
  352. package/templates/default/src/components/ui/table.tsx +76 -76
  353. package/templates/default/src/components/ui/tabs.tsx +55 -55
  354. package/templates/default/src/components/ui/textarea.tsx +21 -21
  355. package/templates/default/src/components/ui/toast.tsx +113 -113
  356. package/templates/default/src/components/ui/toaster.tsx +26 -26
  357. package/templates/default/src/components/user-prompt/delete-prompt.test.tsx +60 -0
  358. package/templates/default/src/components/user-prompt/delete-prompt.tsx +118 -87
  359. package/templates/default/src/constants/form-opts/diagram/node-form.ts +30 -30
  360. package/templates/default/src/constants/form-opts/environment-form-opts.ts +24 -24
  361. package/templates/default/src/constants/form-opts/locator-group-form-opts.ts +28 -28
  362. package/templates/default/src/constants/form-opts/module-form-opts.ts +21 -21
  363. package/templates/default/src/constants/form-opts/tag-form-opts.ts +42 -42
  364. package/templates/default/src/constants/form-opts/template-selection-form-opts.ts +16 -16
  365. package/templates/default/src/constants/form-opts/template-step-group-form-opts.ts +24 -24
  366. package/templates/default/src/constants/form-opts/template-test-case-form-opts.ts +39 -39
  367. package/templates/default/src/constants/form-opts/template-test-step-form-opts.ts +36 -36
  368. package/templates/default/src/constants/form-opts/test-case-form-opts.ts +43 -43
  369. package/templates/default/src/constants/form-opts/test-suite-form-opts.ts +24 -24
  370. package/templates/default/src/hooks/use-toast.ts +187 -187
  371. package/templates/default/src/lib/automation/automation-path-roots.ts +95 -0
  372. package/templates/default/src/lib/automation/automation-workspace.ts +147 -0
  373. package/templates/default/src/lib/automation/paths.ts +6 -211
  374. package/templates/default/src/lib/bidirectional-sync.ts +432 -432
  375. package/templates/default/src/lib/environment-file-utils.ts +2 -1
  376. package/templates/default/src/lib/executor/local-executor-adapter.ts +2 -5
  377. package/templates/default/src/lib/feature-file-generator.ts +2 -1
  378. package/templates/default/src/lib/gherkin-parser.ts +0 -2
  379. package/templates/default/src/lib/locator-group-file-utils.ts +304 -307
  380. package/templates/default/src/lib/locator-picker/session-manager.ts +0 -21
  381. package/templates/default/src/lib/locator-picker/suggestions.ts +4 -2
  382. package/templates/default/src/lib/metrics/metric-calculator.ts +2 -6
  383. package/templates/default/src/lib/module-hierarchy-builder.ts +205 -205
  384. package/templates/default/src/lib/path-helpers/module-path.ts +71 -71
  385. package/templates/default/src/lib/sync/sync-executor.test.ts +76 -0
  386. package/templates/default/src/lib/sync/sync-pending-counts.test.ts +227 -226
  387. package/templates/default/src/lib/sync/sync-pending-counts.ts +2 -5
  388. package/templates/default/src/lib/template-sync-utils.d.ts +6 -6
  389. package/templates/default/src/lib/template-sync-utils.js +46 -46
  390. package/templates/default/src/lib/template-sync-utils.ts +63 -63
  391. package/templates/default/src/lib/test-case-utils.ts +6 -6
  392. package/templates/default/src/lib/test-run/log-formatter.ts +83 -83
  393. package/templates/default/src/lib/test-run/report-parser.ts +352 -352
  394. package/templates/default/src/lib/test-run/test-run-executor.ts +13 -13
  395. package/templates/default/src/lib/test-run/winston-logger.ts +65 -64
  396. package/templates/default/src/lib/transformers/gherkin-converter.ts +42 -42
  397. package/templates/default/src/lib/transformers/key-to-icon-transformer.tsx +95 -95
  398. package/templates/default/src/lib/transformers/template-test-case-converter.ts +160 -160
  399. package/templates/default/src/lib/utils/node-param-validation.ts +81 -81
  400. package/templates/default/src/lib/utils/template-step-file-generator.ts +2 -2
  401. package/templates/default/src/lib/utils/template-step-file-manager.ts +166 -166
  402. package/templates/default/src/lib/utils.ts +31 -31
  403. package/templates/default/src/services/dashboard/dashboard-service.test.ts +106 -0
  404. package/templates/default/src/services/dashboard/dashboard-service.ts +173 -0
  405. package/templates/default/src/services/environment/environment-service.test.ts +137 -0
  406. package/templates/default/src/services/environment/environment-service.ts +96 -0
  407. package/templates/default/src/services/locator/locator-path-utils.test.ts +14 -0
  408. package/templates/default/src/services/locator/locator-path-utils.ts +14 -0
  409. package/templates/default/src/services/locator/locator-service.test.ts +63 -0
  410. package/templates/default/src/services/locator/locator-service.ts +479 -0
  411. package/templates/default/src/services/locator/locator-sync-utils.test.ts +19 -0
  412. package/templates/default/src/services/locator/locator-sync-utils.ts +21 -0
  413. package/templates/default/src/services/locator-group/locator-group-service.test.ts +123 -0
  414. package/templates/default/src/services/locator-group/locator-group-service.ts +180 -0
  415. package/templates/default/src/services/module/module-service.test.ts +89 -0
  416. package/templates/default/src/services/module/module-service.ts +66 -0
  417. package/templates/default/src/services/report/report-service.test.ts +244 -0
  418. package/templates/default/src/services/report/report-service.ts +438 -0
  419. package/templates/default/src/services/shared/constants.ts +2 -0
  420. package/templates/default/src/services/shared/errors.test.ts +38 -0
  421. package/templates/default/src/services/shared/errors.ts +44 -0
  422. package/templates/default/src/services/shared/index.ts +7 -0
  423. package/templates/default/src/services/tag/tag-service.test.ts +22 -0
  424. package/templates/default/src/services/tag/tag-service.ts +41 -0
  425. package/templates/default/src/services/template-step/template-step-service.test.ts +22 -0
  426. package/templates/default/src/services/template-step/template-step-service.ts +171 -0
  427. package/templates/default/src/services/template-step-group/template-step-group-service.test.ts +22 -0
  428. package/templates/default/src/services/template-step-group/template-step-group-service.ts +81 -0
  429. package/templates/default/src/services/template-test-case/template-test-case-service.test.ts +22 -0
  430. package/templates/default/src/services/template-test-case/template-test-case-service.ts +128 -0
  431. package/templates/default/src/services/test-case/test-case-service.test.ts +175 -0
  432. package/templates/default/src/services/test-case/test-case-service.ts +298 -0
  433. package/templates/default/src/services/test-run/test-run-helpers.ts +61 -0
  434. package/templates/default/src/services/test-run/test-run-service.test.ts +647 -0
  435. package/templates/default/src/services/test-run/test-run-service.ts +917 -0
  436. package/templates/default/src/services/test-suite/test-suite-service.test.ts +127 -0
  437. package/templates/default/src/services/test-suite/test-suite-service.ts +197 -0
  438. package/templates/default/src/types/diagram/diagram.ts +34 -34
  439. package/templates/default/src/types/diagram/template-step.ts +11 -11
  440. package/templates/default/src/types/executor/browser.type.ts +1 -1
  441. package/templates/default/src/types/form/actionHandler.ts +19 -6
  442. package/templates/default/src/types/locator/locator.type.ts +11 -11
  443. package/templates/default/src/types/step/step.type.ts +1 -1
  444. package/templates/default/src/types/table/data-table.ts +6 -6
  445. package/templates/default/tailwind.config.ts +62 -62
  446. package/templates/default/tsconfig.json +1 -1
  447. package/dist/cli.e2e.test.d.ts +0 -2
  448. package/dist/cli.e2e.test.d.ts.map +0 -1
  449. package/dist/cli.e2e.test.js +0 -73
  450. package/dist/cli.e2e.test.js.map +0 -1
  451. package/dist/config.test.d.ts +0 -2
  452. package/dist/config.test.d.ts.map +0 -1
  453. package/dist/config.test.js +0 -65
  454. package/dist/config.test.js.map +0 -1
  455. package/dist/copy-template.test.d.ts +0 -2
  456. package/dist/copy-template.test.d.ts.map +0 -1
  457. package/dist/copy-template.test.js +0 -71
  458. package/dist/copy-template.test.js.map +0 -1
  459. package/dist/download-repo.test.d.ts +0 -2
  460. package/dist/download-repo.test.d.ts.map +0 -1
  461. package/dist/download-repo.test.js +0 -14
  462. package/dist/download-repo.test.js.map +0 -1
  463. package/dist/install.test.d.ts +0 -2
  464. package/dist/install.test.d.ts.map +0 -1
  465. package/dist/install.test.js +0 -119
  466. package/dist/install.test.js.map +0 -1
  467. package/dist/prompts.test.d.ts +0 -2
  468. package/dist/prompts.test.d.ts.map +0 -1
  469. package/dist/prompts.test.js +0 -58
  470. package/dist/prompts.test.js.map +0 -1
  471. package/templates/default/src/actions/conflict/conflict.action.ts +0 -33
  472. package/templates/default/src/actions/review/review-actions.ts +0 -147
  473. package/templates/default/src/actions/user/user-actions.ts +0 -13
  474. package/templates/default/src/app/(base)/locators/locator-form.tsx +0 -163
  475. package/templates/default/src/app/(base)/reviews/create/page.tsx +0 -26
  476. package/templates/default/src/app/(base)/reviews/created-reviews-table.tsx +0 -15
  477. package/templates/default/src/app/(base)/reviews/modify/[id]/page.tsx +0 -26
  478. package/templates/default/src/app/(base)/reviews/page.tsx +0 -26
  479. package/templates/default/src/app/(base)/reviews/review/[id]/page.tsx +0 -26
  480. package/templates/default/src/app/(base)/reviews/review-form.tsx +0 -11
  481. package/templates/default/src/app/(base)/reviews/review-table-by-creator-columns.tsx +0 -9
  482. package/templates/default/src/app/(base)/reviews/review-table-by-reviewer-columns.tsx +0 -9
  483. package/templates/default/src/app/(base)/reviews/reviewer-reviews-table.tsx +0 -15
  484. package/templates/default/src/constants/form-opts/locator-form-opts.ts +0 -20
  485. package/templates/default/src/constants/form-opts/review-form-opts.ts +0 -23
@@ -1,400 +1,74 @@
1
1
  'use client'
2
2
 
3
- import { useEffect, useState, useRef } from 'react'
4
- import {
5
- TestRun,
6
- TestRunStatus,
7
- TestRunResult,
8
- Environment,
9
- Tag,
10
- TestRunTestCase,
11
- TestRunTestCaseStatus,
12
- TestRunTestCaseResult,
13
- Report,
14
- } from '@prisma/client'
15
- import { Badge } from '@/components/ui/badge'
16
- import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'
17
- import { Progress } from '@/components/ui/progress'
18
- import { cn, formatDateTime } from '@/lib/utils'
3
+ import { AnimatePresence, motion } from 'motion/react'
4
+ import { TestRunStatus, TestRunTestCaseResult } from '@prisma/client'
19
5
  import {
6
+ Binoculars,
20
7
  CheckCircle,
21
- XCircle,
8
+ ExternalLink,
9
+ Info,
22
10
  LoaderCircle,
23
- Clock,
24
- ListEnd,
25
- ClipboardCheck,
26
- ClipboardX,
27
- TestTubeDiagonal,
28
- TestTubes,
29
11
  Tag as TagIcon,
30
12
  Tags,
31
- Info,
13
+ TestTubeDiagonal,
14
+ TestTubes,
32
15
  Timer,
33
- Binoculars,
34
- ExternalLink,
35
16
  Trash,
17
+ XCircle,
36
18
  } from 'lucide-react'
37
- import {
38
- getTestRunByIdAction,
39
- spawnTraceViewerAction,
40
- checkTraceViewerStatusAction,
41
- cancelTestRunAction,
42
- } from '@/actions/test-run/test-run-actions'
19
+
20
+ import { Badge } from '@/components/ui/badge'
43
21
  import { Button } from '@/components/ui/button'
44
- import { AnimatePresence, motion } from 'motion/react'
45
- import { toast } from '@/hooks/use-toast'
22
+ import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'
23
+ import { Progress } from '@/components/ui/progress'
24
+ import { cn, formatDateTime } from '@/lib/utils'
46
25
 
47
- interface TestRunDetailsProps {
48
- testRun: TestRun & {
49
- testCases: (TestRunTestCase & {
50
- testCase: { title: string; description: string }
51
- testSuite: { id: string; name: string } | null
52
- })[]
53
- tags: Tag[]
54
- environment: Environment
55
- reports: Report[]
56
- }
26
+ import {
27
+ getDurationSeconds,
28
+ getProgressStats,
29
+ getTestCaseResultMeta,
30
+ getTestCaseStatusMeta,
31
+ getTestRunResultText,
32
+ getTestRunStatusMeta,
33
+ type TestRunDetailsData,
34
+ } from './test-run-details-helpers'
35
+ import { useTestRunDetails } from './use-test-run-details'
36
+
37
+ type TestRunDetailsProps = {
38
+ testRun: TestRunDetailsData
57
39
  }
58
40
 
59
41
  export function TestRunDetails({ testRun: initialTestRun }: TestRunDetailsProps) {
60
- const [testRun, setTestRun] = useState(initialTestRun)
61
- const [loadingTraceViewer, setLoadingTraceViewer] = useState<string | null>(null)
62
- const [runningTraceViewers, setRunningTraceViewers] = useState<Set<string>>(new Set())
63
- const [isCancelling, setIsCancelling] = useState(false)
64
- const runningTraceViewersRef = useRef<Set<string>>(new Set())
65
-
66
- // Keep ref in sync with state
67
- useEffect(() => {
68
- runningTraceViewersRef.current = runningTraceViewers
69
- }, [runningTraceViewers])
70
-
71
- // Poll for status updates while test run is running
72
- useEffect(() => {
73
- // Only poll if test run is not completed
74
- if (testRun.status === TestRunStatus.COMPLETED || testRun.status === TestRunStatus.CANCELLED) {
75
- return
76
- }
77
-
78
- const pollInterval = setInterval(async () => {
79
- try {
80
- const { data: updatedTestRun, error } = await getTestRunByIdAction(testRun.id)
81
- if (error || !updatedTestRun) {
82
- console.error('Error polling test run status:', error)
83
- return
84
- }
85
- // TypeScript now knows updatedTestRun is defined - cast to proper type
86
- const typedTestRun = updatedTestRun as TestRun & {
87
- testCases: (TestRunTestCase & {
88
- testCase: { title: string; description: string }
89
- testSuite: { id: string; name: string } | null
90
- })[]
91
- tags: Tag[]
92
- environment: Environment
93
- reports: Report[]
94
- }
95
- setTestRun(typedTestRun)
96
- // Stop polling if test run is completed
97
- if (typedTestRun.status === TestRunStatus.COMPLETED || typedTestRun.status === TestRunStatus.CANCELLED) {
98
- clearInterval(pollInterval)
99
- }
100
- } catch (error) {
101
- console.error('Error polling test run status:', error)
102
- }
103
- }, 2000) // Poll every 2 seconds
104
-
105
- return () => clearInterval(pollInterval)
106
- }, [testRun.id, testRun.status])
107
- const getStatusIcon = () => {
108
- switch (testRun.status) {
109
- case TestRunStatus.QUEUED:
110
- return <ListEnd className="h-4 w-4" />
111
- case TestRunStatus.RUNNING:
112
- return <LoaderCircle className="h-4 w-4 animate-spin" />
113
- case TestRunStatus.COMPLETED:
114
- return testRun.result === TestRunResult.PASSED ? (
115
- <CheckCircle className="h-4 w-4" />
116
- ) : (
117
- <XCircle className="h-4 w-4" />
118
- )
119
- case TestRunStatus.CANCELLED:
120
- return <XCircle className="h-4 w-4" />
121
- default:
122
- return <Clock className="h-4 w-4" />
123
- }
124
- }
125
-
126
- const getStatusColor = () => {
127
- switch (testRun.status) {
128
- case TestRunStatus.QUEUED:
129
- return 'bg-gray-500'
130
- case TestRunStatus.RUNNING:
131
- return 'bg-blue-500'
132
- case TestRunStatus.COMPLETED:
133
- return testRun.result === TestRunResult.PASSED ? 'bg-green-700' : 'bg-red-500'
134
- case TestRunStatus.CANCELLED:
135
- return 'bg-red-500'
136
- default:
137
- return 'bg-gray-500'
138
- }
139
- }
140
-
141
- const getStatusText = () => {
142
- switch (testRun.status) {
143
- case TestRunStatus.QUEUED:
144
- return 'Queued'
145
- case TestRunStatus.RUNNING:
146
- return 'Running'
147
- case TestRunStatus.COMPLETED:
148
- return 'Completed'
149
- case TestRunStatus.CANCELLED:
150
- return 'Cancelled'
151
- default:
152
- return 'Unknown'
153
- }
154
- }
155
-
156
- const getResultText = () => {
157
- switch (testRun.result) {
158
- case TestRunResult.PENDING:
159
- return 'Pending'
160
- case TestRunResult.PASSED:
161
- return 'Passed'
162
- case TestRunResult.FAILED:
163
- return 'Failed'
164
- case TestRunResult.CANCELLED:
165
- return 'Cancelled'
166
- default:
167
- return 'Unknown'
168
- }
169
- }
170
-
171
- const getFormattedTestRunTestCaseStatus = (status: TestRunTestCaseStatus) => {
172
- switch (status) {
173
- case TestRunTestCaseStatus.PENDING:
174
- return (
175
- <div className="flex min-w-20 items-center gap-2 p-1.5">
176
- <LoaderCircle className="h-4 w-4 animate-spin" />
177
- <span>Pending</span>
178
- </div>
179
- )
180
- case TestRunTestCaseStatus.RUNNING:
181
- return (
182
- <div className="flex min-w-20 items-center gap-2 p-1.5">
183
- <LoaderCircle className="h-4 w-4 animate-spin" />
184
- <span>Running</span>
185
- </div>
186
- )
187
- case TestRunTestCaseStatus.COMPLETED:
188
- return (
189
- <div className="flex min-w-20 items-center gap-2 p-1.5">
190
- <CheckCircle className="h-4 w-4 text-green-500" />
191
- <span>Completed</span>
192
- </div>
193
- )
194
- case TestRunTestCaseStatus.CANCELLED:
195
- return (
196
- <div className="flex min-w-20 items-center gap-2 p-1.5">
197
- <XCircle className="h-4 w-4" />
198
- <span>Cancelled</span>
199
- </div>
200
- )
201
- default:
202
- return (
203
- <div className="flex min-w-20 items-center gap-2 p-1.5">
204
- <Clock className="h-4 w-4" />
205
- <span>Unknown</span>
206
- </div>
207
- )
208
- }
209
- }
210
-
211
- const getFormattedTestRunTestCaseResult = (result: TestRunTestCaseResult) => {
212
- switch (result) {
213
- case TestRunTestCaseResult.PASSED:
214
- return (
215
- <div className="flex min-w-20 items-center gap-2 p-1.5">
216
- <ClipboardCheck className="h-4 w-4 text-green-500" />
217
- <span>Passed</span>
218
- </div>
219
- )
220
- case TestRunTestCaseResult.FAILED:
221
- return (
222
- <div className="flex min-w-20 items-center gap-2 p-1.5">
223
- <ClipboardX className="h-4 w-4 text-red-500" />
224
- <span>Failed</span>
225
- </div>
226
- )
227
- case TestRunTestCaseResult.UNTESTED:
228
- return (
229
- <div className="flex min-w-20 items-center gap-2 p-1.5">
230
- <Clock className="h-4 w-4" />
231
- <span>Untested</span>
232
- </div>
233
- )
234
- default:
235
- return (
236
- <div className="flex min-w-20 items-center gap-2 p-1.5">
237
- <Clock className="h-4 w-4" />
238
- <span>Unknown</span>
239
- </div>
240
- )
241
- }
242
- }
243
-
244
- // Calculate progress
245
- const totalTests = testRun.testCases.length
246
- const completedTests = testRun.testCases.filter(
247
- testCase =>
248
- testCase.status === TestRunTestCaseStatus.COMPLETED || testCase.status === TestRunTestCaseStatus.CANCELLED,
249
- ).length
250
- const progressPercentage = totalTests > 0 ? (completedTests / totalTests) * 100 : 0
251
-
252
- const handleViewTrace = async (testCaseId: string) => {
253
- setLoadingTraceViewer(testCaseId)
254
- try {
255
- const response = await spawnTraceViewerAction(testRun.runId, testCaseId)
256
- if (response.error) {
257
- console.error('Error spawning trace viewer:', response.error)
258
- // TODO: Show error toast/notification to user
259
- setLoadingTraceViewer(null)
260
- } else {
261
- // Trace viewer spawned successfully, mark it as running
262
- setRunningTraceViewers(prev => new Set(prev).add(testCaseId))
263
- setLoadingTraceViewer(null)
264
- }
265
- } catch (error) {
266
- console.error('Error spawning trace viewer:', error)
267
- // TODO: Show error toast/notification to user
268
- setLoadingTraceViewer(null)
269
- }
270
- }
271
-
272
- // Poll for trace viewer status for test cases that have trace viewers
273
- useEffect(() => {
274
- const failedTestCasesWithTraces = testRun.testCases.filter(
275
- tc => tc.result === TestRunTestCaseResult.FAILED && tc.tracePath,
276
- )
277
-
278
- if (failedTestCasesWithTraces.length === 0) {
279
- return
280
- }
281
-
282
- let isMounted = true
283
-
284
- const checkTraceViewers = async () => {
285
- // Get current running trace viewers from ref
286
- const currentRunning = runningTraceViewersRef.current
287
-
288
- if (!currentRunning || currentRunning.size === 0) {
289
- return
290
- }
291
-
292
- // Check each test case asynchronously
293
- const checkPromises = Array.from(currentRunning).map(async testCaseId => {
294
- const testCase = failedTestCasesWithTraces.find(tc => tc.id === testCaseId)
295
- if (!testCase) {
296
- return { testCaseId, isRunning: false }
297
- }
298
-
299
- try {
300
- const response = await checkTraceViewerStatusAction(testRun.runId, testCase.id)
301
- const isRunning = response.data && (response.data as { isRunning: boolean }).isRunning
302
- return { testCaseId, isRunning: isRunning ?? false }
303
- } catch (error) {
304
- console.error(`Error checking trace viewer status for test case ${testCase.id}:`, error)
305
- // If we can't check, assume it's still running if we thought it was
306
- return { testCaseId, isRunning: true }
307
- }
308
- })
309
-
310
- const results = await Promise.all(checkPromises)
311
- if (!isMounted) return
312
-
313
- const actuallyRunning = new Set<string>()
314
- results.forEach(({ testCaseId, isRunning }) => {
315
- if (isRunning) {
316
- actuallyRunning.add(testCaseId)
317
- }
318
- })
319
-
320
- setRunningTraceViewers(prev => {
321
- // Only update if there's a change
322
- if (actuallyRunning.size === prev.size && Array.from(actuallyRunning).every(id => prev.has(id))) {
323
- return prev
324
- }
325
- return actuallyRunning
326
- })
327
- }
328
-
329
- // Only start polling if we have running trace viewers
330
- if (runningTraceViewers.size === 0) {
331
- return
332
- }
42
+ const { testRun, loadingTraceViewer, runningTraceViewers, isCancelling, handleViewTrace, handleCancelRun } =
43
+ useTestRunDetails({ initialTestRun })
333
44
 
334
- // Check immediately
335
- checkTraceViewers()
336
-
337
- // Then poll every 2 seconds
338
- const interval = setInterval(() => {
339
- if (isMounted) {
340
- checkTraceViewers()
341
- }
342
- }, 2000)
343
-
344
- return () => {
345
- isMounted = false
346
- clearInterval(interval)
347
- }
348
- }, [testRun.runId, testRun.testCases, runningTraceViewers.size])
349
-
350
- const handleCancelRun = async () => {
351
- setIsCancelling(true)
352
- try {
353
- const response = await cancelTestRunAction(testRun.runId)
354
- if (response.error) {
355
- throw new Error(response.error)
356
- } else {
357
- toast({
358
- title: 'Test run cancelled',
359
- description: response.message,
360
- })
361
- await new Promise(resolve => setTimeout(resolve, 2000))
362
- setIsCancelling(false)
363
- }
364
- } catch (error) {
365
- toast({
366
- title: 'Error canceling test run',
367
- description: error instanceof Error ? error.message : 'An unexpected error occurred',
368
- variant: 'destructive',
369
- })
370
- setIsCancelling(false)
371
- }
372
- }
45
+ const statusMeta = getTestRunStatusMeta(testRun.status, testRun.result)
46
+ const progress = getProgressStats(testRun.testCases)
47
+ const durationSeconds = getDurationSeconds(testRun.startedAt, testRun.completedAt)
48
+ const StatusIcon = statusMeta.icon
373
49
 
374
50
  return (
375
51
  <div className="space-y-4">
376
52
  <Card>
377
53
  <CardHeader>
378
54
  <CardTitle className="flex items-center justify-between">
379
- {testRun.status === TestRunStatus.RUNNING && (
55
+ {testRun.status === TestRunStatus.RUNNING ? (
380
56
  <div className="flex items-center gap-2">
381
57
  <LoaderCircle className="h-6 w-6 animate-spin text-blue-500" />
382
58
  <span>Executing</span>
383
59
  </div>
384
- )}
385
- {testRun.status === TestRunStatus.COMPLETED && (
60
+ ) : testRun.status === TestRunStatus.COMPLETED ? (
386
61
  <div className="flex items-center gap-2 duration-300 animate-in fade-in-0">
387
62
  <CheckCircle className="h-6 w-6 text-green-500" />
388
63
  <span>Finished</span>
389
64
  </div>
390
- )}
391
- {testRun.status === TestRunStatus.CANCELLED && (
65
+ ) : testRun.status === TestRunStatus.CANCELLED ? (
392
66
  <div className="flex items-center gap-2 duration-300 animate-in fade-in-0">
393
67
  <XCircle className="h-6 w-6 text-red-500 duration-300 animate-in fade-in-0" />
394
68
  <span>Interrupted</span>
395
69
  </div>
396
- )}
397
- {testRun.status === TestRunStatus.RUNNING && (
70
+ ) : null}
71
+ {testRun.status === TestRunStatus.RUNNING ? (
398
72
  <Button
399
73
  onClick={handleCancelRun}
400
74
  disabled={isCancelling}
@@ -413,16 +87,16 @@ export function TestRunDetails({ testRun: initialTestRun }: TestRunDetailsProps)
413
87
  </>
414
88
  )}
415
89
  </Button>
416
- )}
90
+ ) : null}
417
91
  </CardTitle>
418
92
  </CardHeader>
419
93
  <CardContent>
420
94
  <div className="flex items-center gap-4">
421
95
  <div className="flex-1">
422
- <Progress value={progressPercentage} />
96
+ <Progress value={progress.percentage} />
423
97
  </div>
424
98
  <div className="whitespace-nowrap text-sm font-medium">
425
- {completedTests} of {totalTests} tests finished
99
+ {progress.completed} of {progress.total} tests finished
426
100
  </div>
427
101
  </div>
428
102
  </CardContent>
@@ -437,16 +111,22 @@ export function TestRunDetails({ testRun: initialTestRun }: TestRunDetailsProps)
437
111
  </CardTitle>
438
112
  </CardHeader>
439
113
  <CardContent className="space-y-4">
114
+ <div className="flex items-center justify-between">
115
+ <span className="text-sm font-medium">Name</span>
116
+ <span className="text-sm">{testRun.name}</span>
117
+ </div>
440
118
  <div className="flex items-center justify-between">
441
119
  <span className="text-sm font-medium">Status</span>
442
- <Badge variant="outline" className={`${getStatusColor()} py-1`}>
443
- <span className="mr-1 text-white">{getStatusIcon()}</span>
444
- <span className="text-white">{getStatusText()}</span>
120
+ <Badge variant="outline" className={cn(statusMeta.badgeClassName, 'py-1')}>
121
+ <span className="mr-1 text-white">
122
+ <StatusIcon className={cn('h-4 w-4', testRun.status === TestRunStatus.RUNNING && 'animate-spin')} />
123
+ </span>
124
+ <span className="text-white">{statusMeta.label}</span>
445
125
  </Badge>
446
126
  </div>
447
127
  <div className="flex items-center justify-between">
448
128
  <span className="text-sm font-medium">Result</span>
449
- <Badge variant="outline">{getResultText()}</Badge>
129
+ <Badge variant="outline">{getTestRunResultText(testRun.result)}</Badge>
450
130
  </div>
451
131
  <div className="flex items-center justify-between">
452
132
  <span className="text-sm font-medium">Run ID</span>
@@ -479,20 +159,18 @@ export function TestRunDetails({ testRun: initialTestRun }: TestRunDetailsProps)
479
159
  <span className="text-sm font-medium">Started At</span>
480
160
  <span className="text-sm">{formatDateTime(testRun.startedAt)}</span>
481
161
  </div>
482
- {testRun.completedAt && (
162
+ {testRun.completedAt ? (
483
163
  <div className="flex items-center justify-between">
484
164
  <span className="text-sm font-medium">Completed At</span>
485
165
  <span className="text-sm">{formatDateTime(testRun.completedAt)}</span>
486
166
  </div>
487
- )}
488
- {testRun.completedAt && (
167
+ ) : null}
168
+ {durationSeconds !== null ? (
489
169
  <div className="flex items-center justify-between">
490
170
  <span className="text-sm font-medium">Duration</span>
491
- <span className="text-sm">
492
- {Math.round((testRun.completedAt.getTime() - testRun.startedAt.getTime()) / 1000)}s
493
- </span>
171
+ <span className="text-sm">{durationSeconds}s</span>
494
172
  </div>
495
- )}
173
+ ) : null}
496
174
  </CardContent>
497
175
  </Card>
498
176
 
@@ -529,89 +207,109 @@ export function TestRunDetails({ testRun: initialTestRun }: TestRunDetailsProps)
529
207
  <CardContent>
530
208
  {testRun.testCases.length > 0 ? (
531
209
  <div className="space-y-2">
532
- {testRun.testCases.map(testCase => (
533
- <div
534
- key={testCase.id}
535
- className="flex items-center justify-between rounded-md bg-muted p-2 shadow-md"
536
- >
537
- <div className="flex items-center gap-2">
538
- <TestTubeDiagonal
539
- className={cn(
540
- 'mr-2 h-6 w-6 text-white',
541
- testCase.result === TestRunTestCaseResult.PASSED
542
- ? 'text-green-500'
543
- : testCase.result === TestRunTestCaseResult.FAILED
544
- ? 'text-red-500'
545
- : testCase.result === TestRunTestCaseResult.UNTESTED
546
- ? 'text-blue-500'
547
- : 'text-gray-500',
548
- )}
549
- />
550
- <div className="flex flex-col gap-1">
551
- <span className="text-sm font-semibold">{testCase.testCase.title}</span>
552
- <span className="text-xs text-muted-foreground">{testCase.testCase.description}</span>
553
- {testCase.testSuite && (
554
- <div className="pt-1">
555
- <Badge variant="outline" className="w-fit text-[11px]">
556
- Suite: {testCase.testSuite.name}
557
- </Badge>
558
- </div>
559
- )}
210
+ {testRun.testCases.map(testCase => {
211
+ const testCaseStatusMeta = getTestCaseStatusMeta(testCase.status)
212
+ const testCaseResultMeta = getTestCaseResultMeta(testCase.result)
213
+ const TestCaseStatusIcon = testCaseStatusMeta.icon
214
+ const TestCaseResultIcon = testCaseResultMeta.icon
215
+
216
+ return (
217
+ <div
218
+ key={testCase.id}
219
+ className="flex items-center justify-between rounded-md bg-muted p-2 shadow-md"
220
+ >
221
+ <div className="flex items-center gap-2">
222
+ <TestTubeDiagonal
223
+ className={cn(
224
+ 'mr-2 h-6 w-6 text-white',
225
+ testCase.result === TestRunTestCaseResult.PASSED
226
+ ? 'text-green-500'
227
+ : testCase.result === TestRunTestCaseResult.FAILED
228
+ ? 'text-red-500'
229
+ : testCase.result === TestRunTestCaseResult.UNTESTED
230
+ ? 'text-blue-500'
231
+ : 'text-gray-500',
232
+ )}
233
+ />
234
+ <div className="flex flex-col gap-1">
235
+ <span className="text-sm font-semibold">{testCase.testCase.title}</span>
236
+ <span className="text-xs text-muted-foreground">{testCase.testCase.description}</span>
237
+ {testCase.testSuite ? (
238
+ <div className="pt-1">
239
+ <Badge variant="outline" className="w-fit text-[11px]">
240
+ Suite: {testCase.testSuite.name}
241
+ </Badge>
242
+ </div>
243
+ ) : null}
244
+ </div>
560
245
  </div>
561
- </div>
562
- <div className="flex items-center gap-2">
563
- <Badge variant="outline" className="bg-gray-700 text-xs text-white">
564
- {getFormattedTestRunTestCaseStatus(testCase.status)}
565
- </Badge>
566
- <Badge variant="outline" className="bg-gray-700 text-xs text-white">
567
- {getFormattedTestRunTestCaseResult(testCase.result)}
568
- </Badge>
569
- {testCase.result === TestRunTestCaseResult.FAILED && testCase.tracePath && (
570
- <Button
571
- variant="outline"
572
- size="sm"
573
- onClick={() => handleViewTrace(testCase.id)}
574
- disabled={loadingTraceViewer === testCase.id || runningTraceViewers.has(testCase.id)}
575
- className="w-28 bg-transparent text-xs"
576
- >
577
- <AnimatePresence mode="wait" initial={false}>
578
- <motion.div
579
- key={
580
- loadingTraceViewer === testCase.id
581
- ? 'opening'
582
- : runningTraceViewers.has(testCase.id)
583
- ? 'running'
584
- : 'idle'
585
- }
586
- initial={{ opacity: 0, y: 4 }}
587
- animate={{ opacity: 1, y: 0 }}
588
- exit={{ opacity: 0, y: -4 }}
589
- transition={{ duration: 0.15 }}
590
- className="flex w-full items-center justify-center gap-1"
591
- >
592
- {loadingTraceViewer === testCase.id ? (
593
- <>
594
- <ExternalLink className="h-3 w-3 animate-pulse text-gray-500" />
595
- Opening
596
- </>
597
- ) : runningTraceViewers.has(testCase.id) ? (
598
- <>
599
- <LoaderCircle className="text-white-500 h-3 w-3 animate-spin" />
600
- Running
601
- </>
602
- ) : (
603
- <>
604
- <Binoculars className="h-3 w-3 text-blue-500" />
605
- View Trace
606
- </>
246
+ <div className="flex items-center gap-2">
247
+ <Badge variant="outline" className="bg-gray-700 text-xs text-white">
248
+ <div className="flex min-w-20 items-center gap-2 p-1.5">
249
+ <TestCaseStatusIcon
250
+ className={cn(
251
+ 'h-4 w-4',
252
+ testCase.status === 'PENDING' || testCase.status === 'RUNNING'
253
+ ? 'animate-spin'
254
+ : testCaseStatusMeta.iconClassName,
607
255
  )}
608
- </motion.div>
609
- </AnimatePresence>
610
- </Button>
611
- )}
256
+ />
257
+ <span>{testCaseStatusMeta.label}</span>
258
+ </div>
259
+ </Badge>
260
+ <Badge variant="outline" className="bg-gray-700 text-xs text-white">
261
+ <div className="flex min-w-20 items-center gap-2 p-1.5">
262
+ <TestCaseResultIcon className={cn('h-4 w-4', testCaseResultMeta.iconClassName)} />
263
+ <span>{testCaseResultMeta.label}</span>
264
+ </div>
265
+ </Badge>
266
+ {testCase.result === TestRunTestCaseResult.FAILED && testCase.tracePath ? (
267
+ <Button
268
+ variant="outline"
269
+ size="sm"
270
+ onClick={() => handleViewTrace(testCase.id)}
271
+ disabled={loadingTraceViewer === testCase.id || runningTraceViewers.has(testCase.id)}
272
+ className="w-28 bg-transparent text-xs"
273
+ >
274
+ <AnimatePresence mode="wait" initial={false}>
275
+ <motion.div
276
+ key={
277
+ loadingTraceViewer === testCase.id
278
+ ? 'opening'
279
+ : runningTraceViewers.has(testCase.id)
280
+ ? 'running'
281
+ : 'idle'
282
+ }
283
+ initial={{ opacity: 0, y: 4 }}
284
+ animate={{ opacity: 1, y: 0 }}
285
+ exit={{ opacity: 0, y: -4 }}
286
+ transition={{ duration: 0.15 }}
287
+ className="flex w-full items-center justify-center gap-1"
288
+ >
289
+ {loadingTraceViewer === testCase.id ? (
290
+ <>
291
+ <ExternalLink className="h-3 w-3 animate-pulse text-gray-500" />
292
+ Opening
293
+ </>
294
+ ) : runningTraceViewers.has(testCase.id) ? (
295
+ <>
296
+ <LoaderCircle className="text-white-500 h-3 w-3 animate-spin" />
297
+ Running
298
+ </>
299
+ ) : (
300
+ <>
301
+ <Binoculars className="h-3 w-3 text-blue-500" />
302
+ View Trace
303
+ </>
304
+ )}
305
+ </motion.div>
306
+ </AnimatePresence>
307
+ </Button>
308
+ ) : null}
309
+ </div>
612
310
  </div>
613
- </div>
614
- ))}
311
+ )
312
+ })}
615
313
  </div>
616
314
  ) : (
617
315
  <span className="text-sm text-muted-foreground">No test cases</span>