create-appraisejs 0.2.0-alpha.6 → 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 +13 -11
  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
@@ -0,0 +1,95 @@
1
+ import { StepParameterType, TemplateStepIcon } from '@prisma/client'
2
+ import { describe, expect, it } from 'vitest'
3
+
4
+ import {
5
+ buildNodeOrderFromTestCaseSteps,
6
+ getEditableTestCase,
7
+ getTestCaseRows,
8
+ } from './test-case-route-helpers'
9
+
10
+ describe('test-case route helpers', () => {
11
+ it('narrows test case list rows from action data', () => {
12
+ expect(
13
+ getTestCaseRows([
14
+ {
15
+ id: 'case-1',
16
+ title: 'Login flow',
17
+ steps: [],
18
+ tags: [{ id: 'tag-1', name: 'smoke' }],
19
+ },
20
+ {
21
+ id: 'broken-case',
22
+ title: 'Broken row',
23
+ steps: [],
24
+ tags: ['bad-tag'],
25
+ },
26
+ ]),
27
+ ).toEqual([
28
+ {
29
+ id: 'case-1',
30
+ title: 'Login flow',
31
+ steps: [],
32
+ tags: [{ id: 'tag-1', name: 'smoke' }],
33
+ },
34
+ ])
35
+ })
36
+
37
+ it('narrows editable test cases and converts steps into node order', () => {
38
+ const editableTestCase = getEditableTestCase({
39
+ id: 'case-1',
40
+ title: 'Login flow',
41
+ description: 'Checks login',
42
+ testSuiteIds: ['suite-1'],
43
+ tagIds: ['tag-1'],
44
+ steps: [
45
+ {
46
+ id: 'step-1',
47
+ order: 1,
48
+ label: 'Fill email',
49
+ gherkinStep: 'fill email',
50
+ icon: TemplateStepIcon.INPUT,
51
+ templateStepId: 'template-step-1',
52
+ parameters: [
53
+ {
54
+ name: 'email',
55
+ value: 'qa@appraise.dev',
56
+ type: StepParameterType.STRING,
57
+ order: 1,
58
+ },
59
+ ],
60
+ },
61
+ ],
62
+ })
63
+
64
+ expect(editableTestCase).not.toBeNull()
65
+ expect(buildNodeOrderFromTestCaseSteps(editableTestCase!.steps)).toEqual({
66
+ 'step-1': {
67
+ order: 1,
68
+ label: 'Fill email',
69
+ gherkinStep: 'fill email',
70
+ icon: TemplateStepIcon.INPUT,
71
+ parameters: [
72
+ {
73
+ name: 'email',
74
+ value: 'qa@appraise.dev',
75
+ type: StepParameterType.STRING,
76
+ order: 1,
77
+ },
78
+ ],
79
+ templateStepId: 'template-step-1',
80
+ },
81
+ })
82
+ })
83
+
84
+ it('rejects malformed editable test case data', () => {
85
+ expect(
86
+ getEditableTestCase({
87
+ id: 'case-1',
88
+ title: 'Broken flow',
89
+ steps: [{ id: 'step-1', label: 'Missing params array' }],
90
+ testSuiteIds: ['suite-1'],
91
+ tagIds: ['tag-1'],
92
+ }),
93
+ ).toBeNull()
94
+ })
95
+ })
@@ -0,0 +1,147 @@
1
+ import type {
2
+ Locator,
3
+ LocatorGroup,
4
+ Tag,
5
+ TestCase,
6
+ TestCaseStep,
7
+ TestCaseStepParameter,
8
+ TestSuite,
9
+ TemplateStep,
10
+ TemplateStepParameter,
11
+ } from '@prisma/client'
12
+
13
+ import type { ActionResponseData } from '@/types/form/actionHandler'
14
+ import type { NodeOrderMap } from '@/types/diagram/diagram'
15
+ import type { TestCasePickerRow } from '@/types/test-case-picker'
16
+
17
+ export type EditableTestCase = TestCase & {
18
+ steps: (TestCaseStep & { parameters: TestCaseStepParameter[] })[]
19
+ testSuiteIds: string[]
20
+ tagIds: string[]
21
+ }
22
+
23
+ function isNamedRow(value: unknown): value is { id: string; name: string } {
24
+ return typeof value === 'object' && value !== null && 'id' in value && 'name' in value
25
+ }
26
+
27
+ function isTagRow(value: unknown): value is Tag {
28
+ return isNamedRow(value)
29
+ }
30
+
31
+ function isTestCaseStepParameterRow(value: unknown): value is TestCaseStepParameter {
32
+ return typeof value === 'object' && value !== null && 'name' in value && 'value' in value && 'type' in value
33
+ }
34
+
35
+ function isTestCaseStepRow(value: unknown): value is TestCaseStep & { parameters: TestCaseStepParameter[] } {
36
+ return (
37
+ typeof value === 'object' &&
38
+ value !== null &&
39
+ 'id' in value &&
40
+ 'label' in value &&
41
+ 'templateStepId' in value &&
42
+ 'parameters' in value &&
43
+ Array.isArray(value.parameters) &&
44
+ value.parameters.every(isTestCaseStepParameterRow)
45
+ )
46
+ }
47
+
48
+ function isTestCaseRow(value: unknown): value is TestCasePickerRow {
49
+ return (
50
+ typeof value === 'object' &&
51
+ value !== null &&
52
+ 'id' in value &&
53
+ 'title' in value &&
54
+ 'steps' in value &&
55
+ Array.isArray(value.steps) &&
56
+ 'tags' in value &&
57
+ Array.isArray(value.tags) &&
58
+ value.tags.every(isTagRow)
59
+ )
60
+ }
61
+
62
+ function isEditableTestCase(value: unknown): value is EditableTestCase {
63
+ return (
64
+ typeof value === 'object' &&
65
+ value !== null &&
66
+ 'id' in value &&
67
+ 'title' in value &&
68
+ 'steps' in value &&
69
+ Array.isArray(value.steps) &&
70
+ value.steps.every(isTestCaseStepRow) &&
71
+ 'testSuiteIds' in value &&
72
+ Array.isArray(value.testSuiteIds) &&
73
+ 'tagIds' in value &&
74
+ Array.isArray(value.tagIds)
75
+ )
76
+ }
77
+
78
+ function isTemplateStepParameterRow(value: unknown): value is TemplateStepParameter {
79
+ return typeof value === 'object' && value !== null && 'id' in value && 'templateStepId' in value
80
+ }
81
+
82
+ function isTemplateStepRow(value: unknown): value is TemplateStep {
83
+ return isNamedRow(value)
84
+ }
85
+
86
+ function isLocatorRow(value: unknown): value is Locator {
87
+ return isNamedRow(value)
88
+ }
89
+
90
+ function isTestSuiteRow(value: unknown): value is TestSuite {
91
+ return isNamedRow(value)
92
+ }
93
+
94
+ function isLocatorGroupRow(value: unknown): value is LocatorGroup {
95
+ return isNamedRow(value)
96
+ }
97
+
98
+ export function getTestCaseRows(data: ActionResponseData | undefined): TestCasePickerRow[] {
99
+ return Array.isArray(data) ? data.filter(isTestCaseRow) : []
100
+ }
101
+
102
+ export function getEditableTestCase(data: ActionResponseData | undefined) {
103
+ return isEditableTestCase(data) ? data : null
104
+ }
105
+
106
+ export function buildNodeOrderFromTestCaseSteps(steps: EditableTestCase['steps']): NodeOrderMap {
107
+ return steps.reduce<NodeOrderMap>((acc, step) => {
108
+ acc[step.id] = {
109
+ order: step.order,
110
+ label: step.label,
111
+ gherkinStep: step.gherkinStep,
112
+ icon: step.icon,
113
+ parameters: (step.parameters || []).map(parameter => ({
114
+ name: parameter.name,
115
+ value: parameter.value,
116
+ type: parameter.type,
117
+ order: parameter.order,
118
+ })),
119
+ templateStepId: step.templateStepId,
120
+ }
121
+ return acc
122
+ }, {})
123
+ }
124
+
125
+ export function getTemplateStepParamRows(data: ActionResponseData | undefined): TemplateStepParameter[] {
126
+ return Array.isArray(data) ? data.filter(isTemplateStepParameterRow) : []
127
+ }
128
+
129
+ export function getTemplateStepRows(data: ActionResponseData | undefined): TemplateStep[] {
130
+ return Array.isArray(data) ? data.filter(isTemplateStepRow) : []
131
+ }
132
+
133
+ export function getLocatorRows(data: ActionResponseData | undefined): Locator[] {
134
+ return Array.isArray(data) ? data.filter(isLocatorRow) : []
135
+ }
136
+
137
+ export function getTestSuiteRows(data: ActionResponseData | undefined): TestSuite[] {
138
+ return Array.isArray(data) ? data.filter(isTestSuiteRow) : []
139
+ }
140
+
141
+ export function getLocatorGroupRows(data: ActionResponseData | undefined): LocatorGroup[] {
142
+ return Array.isArray(data) ? data.filter(isLocatorGroupRow) : []
143
+ }
144
+
145
+ export function getTagRows(data: ActionResponseData | undefined): Tag[] {
146
+ return Array.isArray(data) ? data.filter(isTagRow) : []
147
+ }
@@ -1,17 +1,19 @@
1
1
  import { deleteTestCaseAction, getAllTestCasesAction } from '@/actions/test-case/test-case-actions'
2
2
  import { DataTable } from '@/components/ui/data-table'
3
- import { TestCasePickerRow } from '@/types/test-case-picker'
4
3
  import { testCaseTableCols } from './test-case-table-columns'
5
4
  import { Cog, LayoutPanelTop } from 'lucide-react'
6
5
 
6
+ import { getTestCaseRows } from './test-case-route-helpers'
7
+
7
8
  export default async function TestCaseTable() {
8
9
  const { data: testCases } = await getAllTestCasesAction()
10
+ const testCaseRows = getTestCaseRows(testCases)
9
11
 
10
12
  return (
11
13
  <>
12
14
  <DataTable
13
15
  columns={testCaseTableCols}
14
- data={testCases as TestCasePickerRow[]}
16
+ data={testCaseRows}
15
17
  filterColumn="title"
16
18
  filterPlaceholder="Filter by title..."
17
19
  modifyLink="/test-cases/modify"
@@ -1,9 +1,9 @@
1
1
  import { getTestRunByIdAction } from '@/actions/test-run/test-run-actions'
2
2
  import { TestRunDetails } from '@/components/test-run/test-run-details'
3
3
  import { TestRunHeader } from '@/components/test-run/test-run-header'
4
+ import { getTestRunDetailsData } from '@/components/test-run/test-run-details-helpers'
4
5
  import { LogViewer } from '@/components/test-run/log-viewer'
5
6
  import { Separator } from '@/components/ui/separator'
6
- import { TestRun, TestRunTestCase, Tag, Environment, Report } from '@prisma/client'
7
7
  import { Metadata } from 'next'
8
8
 
9
9
  export const metadata: Metadata = {
@@ -32,15 +32,16 @@ export default async function TestRunDetailPage({ params }: TestRunDetailPagePro
32
32
  )
33
33
  }
34
34
 
35
- // TypeScript now knows response.data is defined
36
- const testRun = response.data as TestRun & {
37
- testCases: (TestRunTestCase & {
38
- testCase: { title: string; description: string }
39
- testSuite: { id: string; name: string } | null
40
- })[]
41
- tags: Tag[]
42
- environment: Environment
43
- reports: Report[]
35
+ const testRun = getTestRunDetailsData(response.data)
36
+ if (!testRun) {
37
+ return (
38
+ <div className="flex items-center justify-center p-8">
39
+ <div className="text-center">
40
+ <h2 className="text-2xl font-bold">Test Run Not Found</h2>
41
+ <p className="mt-2 text-muted-foreground">The test run data could not be parsed.</p>
42
+ </div>
43
+ </div>
44
+ )
44
45
  }
45
46
 
46
47
  return (
@@ -1,14 +1,13 @@
1
1
  import { createTestRunAction } from '@/actions/test-run/test-run-actions'
2
2
  import PageHeader from '@/components/typography/page-header'
3
3
  import HeaderSubtitle from '@/components/typography/page-header-subtitle'
4
- import { Environment, Tag } from '@prisma/client'
5
4
  import React from 'react'
6
5
  import TestRunForm from '../test-run-form'
7
6
  import { getAllEnvironmentsAction } from '@/actions/environments/environment-actions'
8
7
  import { getAllTagsAction } from '@/actions/tags/tag-actions'
9
8
  import { Metadata } from 'next'
10
9
  import { getAllTestSuiteTestCasesAction } from '@/actions/test-run/test-run-actions'
11
- import { TestSuitePickerRow } from '@/types/test-suite-picker'
10
+ import { getEnvironmentRows, getTagRows, getTestSuitePickerRows } from '../test-run-form-helpers'
12
11
 
13
12
  export const metadata: Metadata = {
14
13
  title: 'Appraise | Create Test Run',
@@ -24,9 +23,9 @@ const CreateTestRun = async () => {
24
23
  return <div>Error: {testSuitesError || environmentsError || tagsError}</div>
25
24
  }
26
25
 
27
- const testSuitesData = testSuites as TestSuitePickerRow[]
28
- const environmentsData = environments as Environment[]
29
- const tagsData = tags as Tag[]
26
+ const testSuitesData = getTestSuitePickerRows(testSuites)
27
+ const environmentsData = getEnvironmentRows(environments)
28
+ const tagsData = getTagRows(tags)
30
29
 
31
30
  return (
32
31
  <>
@@ -1,60 +1,60 @@
1
- import DataTableSkeleton from '@/components/loading-skeleton/data-table/data-table-skeleton'
2
- import PageHeader from '@/components/typography/page-header'
3
- import HeaderSubtitle from '@/components/typography/page-header-subtitle'
4
- import { ListChecks } from 'lucide-react'
5
- import React, { Suspense } from 'react'
6
- import TestRunTable from './test-run-table'
7
- import { getAllTestRunsAction } from '@/actions/test-run/test-run-actions'
8
- import EmptyState from '@/components/data-state/empty-state'
9
- import { Environment, Tag, TestRun, TestRunTestCase } from '@prisma/client'
10
- import { Metadata } from 'next'
11
-
12
- export const metadata: Metadata = {
13
- title: 'Appraise | Test Runs',
14
- description: 'Manage test runs and their execution results',
15
- }
16
-
17
- const TestRuns = async ({ searchParams }: { searchParams: Promise<{ filter?: string }> }) => {
18
- const resolvedSearchParams = await searchParams
19
- const filter = resolvedSearchParams?.filter
20
- const { data: testRuns, error: testRunsError } = await getAllTestRunsAction(filter)
21
-
22
- if (testRunsError) {
23
- return <div>Error: {testRunsError}</div>
24
- }
25
-
26
- const testRunsData = testRuns as (TestRun & { testCases: TestRunTestCase[]; tags: Tag[]; environment: Environment })[]
27
-
28
- if (!testRunsData || testRunsData.length === 0) {
29
- return (
30
- <div className="flex min-h-[calc(100vh-20rem)] items-center justify-center">
31
- <EmptyState
32
- icon={<ListChecks className="h-8 w-8" />}
33
- title="No test runs found"
34
- description="Get started by creating a test run to execute your test cases"
35
- createRoute="/test-runs/create"
36
- createText="Create Test Run"
37
- />
38
- </div>
39
- )
40
- }
41
-
42
- return (
43
- <>
44
- <div className="mb-8">
45
- <PageHeader>
46
- <span className="flex items-center">
47
- <ListChecks className="mr-2 h-8 w-8" />
48
- Test Runs
49
- </span>
50
- </PageHeader>
51
- <HeaderSubtitle>Orchestrate tests and track the execution progress with detailed results</HeaderSubtitle>
52
- </div>
53
- <Suspense fallback={<DataTableSkeleton />}>
54
- <TestRunTable initialData={testRunsData} filter={filter as 'recentFailed' | 'all'} />
55
- </Suspense>
56
- </>
57
- )
58
- }
59
-
60
- export default TestRuns
1
+ import DataTableSkeleton from '@/components/loading-skeleton/data-table/data-table-skeleton'
2
+ import PageHeader from '@/components/typography/page-header'
3
+ import HeaderSubtitle from '@/components/typography/page-header-subtitle'
4
+ import { ListChecks } from 'lucide-react'
5
+ import React, { Suspense } from 'react'
6
+ import TestRunTable from './test-run-table'
7
+ import { getAllTestRunsAction } from '@/actions/test-run/test-run-actions'
8
+ import EmptyState from '@/components/data-state/empty-state'
9
+ import { Environment, Tag, TestRun, TestRunTestCase } from '@prisma/client'
10
+ import { Metadata } from 'next'
11
+
12
+ export const metadata: Metadata = {
13
+ title: 'Appraise | Test Runs',
14
+ description: 'Manage test runs and their execution results',
15
+ }
16
+
17
+ const TestRuns = async ({ searchParams }: { searchParams: Promise<{ filter?: string }> }) => {
18
+ const resolvedSearchParams = await searchParams
19
+ const filter = resolvedSearchParams?.filter
20
+ const { data: testRuns, error: testRunsError } = await getAllTestRunsAction(filter)
21
+
22
+ if (testRunsError) {
23
+ return <div>Error: {testRunsError}</div>
24
+ }
25
+
26
+ const testRunsData = testRuns as (TestRun & { testCases: TestRunTestCase[]; tags: Tag[]; environment: Environment })[]
27
+
28
+ if (!testRunsData || testRunsData.length === 0) {
29
+ return (
30
+ <div className="flex min-h-[calc(100vh-20rem)] items-center justify-center">
31
+ <EmptyState
32
+ icon={<ListChecks className="h-8 w-8" />}
33
+ title="No test runs found"
34
+ description="Get started by creating a test run to execute your test cases"
35
+ createRoute="/test-runs/create"
36
+ createText="Create Test Run"
37
+ />
38
+ </div>
39
+ )
40
+ }
41
+
42
+ return (
43
+ <>
44
+ <div className="mb-8">
45
+ <PageHeader>
46
+ <span className="flex items-center">
47
+ <ListChecks className="mr-2 h-8 w-8" />
48
+ Test Runs
49
+ </span>
50
+ </PageHeader>
51
+ <HeaderSubtitle>Orchestrate tests and track the execution progress with detailed results</HeaderSubtitle>
52
+ </div>
53
+ <Suspense fallback={<DataTableSkeleton />}>
54
+ <TestRunTable initialData={testRunsData} filter={filter as 'recentFailed' | 'all'} />
55
+ </Suspense>
56
+ </>
57
+ )
58
+ }
59
+
60
+ export default TestRuns
@@ -0,0 +1,50 @@
1
+ import { BrowserEngine } from '@prisma/client'
2
+ import { describe, expect, it } from 'vitest'
3
+
4
+ import {
5
+ buildTestRunSubmitValue,
6
+ getTestRunSuccessPath,
7
+ testSelectionTypes,
8
+ validateTagSelections,
9
+ validateTestSuiteSelections,
10
+ } from './test-run-form-helpers'
11
+
12
+ describe('test-run-form helpers', () => {
13
+ it('strips tags when the test suite selection mode is active', () => {
14
+ expect(
15
+ buildTestRunSubmitValue(
16
+ {
17
+ name: 'Nightly',
18
+ environmentId: 'env-1',
19
+ tags: ['tag-1'],
20
+ testWorkersCount: 1,
21
+ browserEngine: BrowserEngine.CHROMIUM,
22
+ testSuites: [{ testSuiteId: 'suite-1', runAll: true, testCaseIds: [] }],
23
+ },
24
+ testSelectionTypes.TEST_SUITES,
25
+ ),
26
+ ).toEqual({
27
+ name: 'Nightly',
28
+ environmentId: 'env-1',
29
+ tags: [],
30
+ testWorkersCount: 1,
31
+ browserEngine: BrowserEngine.CHROMIUM,
32
+ testSuites: [{ testSuiteId: 'suite-1', runAll: true, testCaseIds: [] }],
33
+ })
34
+ })
35
+
36
+ it('returns validation messages for empty tags and invalid partial suite selections', () => {
37
+ expect(validateTagSelections([], testSelectionTypes.TAGS)).toBe('Tags are required')
38
+ expect(
39
+ validateTestSuiteSelections(
40
+ [{ testSuiteId: 'suite-1', runAll: false, testCaseIds: [] }],
41
+ testSelectionTypes.TEST_SUITES,
42
+ ),
43
+ ).toBe('Partial suite selections must include at least one test case')
44
+ })
45
+
46
+ it('builds the success route from returned action data', () => {
47
+ expect(getTestRunSuccessPath({ id: 'run-1' })).toBe('/test-runs/run-1')
48
+ expect(getTestRunSuccessPath(undefined)).toBe('/test-runs')
49
+ })
50
+ })
@@ -0,0 +1,168 @@
1
+ import { BrowserEngine, type Environment, type Tag } from '@prisma/client'
2
+
3
+ import { testRunSchema, type TestRun } from '@/constants/form-opts/test-run-form-opts'
4
+ import type { ActionResponse, ActionResponseData } from '@/types/form/actionHandler'
5
+ import type { TestSuitePickerRow, TestSuiteSelection } from '@/types/test-suite-picker'
6
+
7
+ export const testSelectionTypes = {
8
+ TAGS: 'tags',
9
+ TEST_SUITES: 'testSuites',
10
+ } as const
11
+
12
+ export type TestSelectionType = (typeof testSelectionTypes)[keyof typeof testSelectionTypes]
13
+
14
+ export type TestRunFormSubmitAction = (_prev: unknown, value: TestRun, id?: string) => Promise<ActionResponse>
15
+
16
+ export const testRunFieldValidators = {
17
+ name: testRunSchema.shape.name,
18
+ environmentId: testRunSchema.shape.environmentId,
19
+ testWorkersCount: testRunSchema.shape.testWorkersCount.unwrap(),
20
+ browserEngine: testRunSchema.shape.browserEngine,
21
+ }
22
+
23
+ export const testRunQuickTips = [
24
+ {
25
+ title: 'Choose a descriptive name',
26
+ description: 'Use clear, specific names that indicate the purpose for your test run',
27
+ },
28
+ {
29
+ title: 'Select the environment for your test run',
30
+ description: 'Choose the environment that best suits your selected tests',
31
+ },
32
+ {
33
+ title: 'Select the browser engine for your test run',
34
+ description: 'Select the browser engine that is compatible with your selected test cases',
35
+ },
36
+ {
37
+ title: 'Select the test suites or tags for your test run',
38
+ description: 'You can filter by tags or browse suites and choose full suites or child subsets',
39
+ },
40
+ {
41
+ title: 'Select the test workers count for your test run',
42
+ description: 'Parallel workers can be used to run your test cases in parallel to speed up the test execution',
43
+ },
44
+ ] as const
45
+
46
+ export function getFieldErrorMessage(error: unknown) {
47
+ if (typeof error === 'string') {
48
+ return error
49
+ }
50
+
51
+ if (error && typeof error === 'object' && 'message' in error && typeof error.message === 'string') {
52
+ return error.message
53
+ }
54
+
55
+ return String(error)
56
+ }
57
+
58
+ export function getActionErrorMessage(response: ActionResponse) {
59
+ return response.error || response.message || 'Unable to save test run.'
60
+ }
61
+
62
+ export function buildTestRunSubmitValue(value: TestRun, selectionType: TestSelectionType): TestRun {
63
+ return {
64
+ ...value,
65
+ tags: selectionType === testSelectionTypes.TAGS ? value.tags : [],
66
+ testSuites: selectionType === testSelectionTypes.TEST_SUITES ? value.testSuites : [],
67
+ }
68
+ }
69
+
70
+ export function validateTagSelections(value: string[], selectionType: TestSelectionType) {
71
+ if (selectionType === testSelectionTypes.TAGS && (!Array.isArray(value) || value.length === 0)) {
72
+ return 'Tags are required'
73
+ }
74
+
75
+ return undefined
76
+ }
77
+
78
+ export function validateTestSuiteSelections(value: TestSuiteSelection[], selectionType: TestSelectionType) {
79
+ if (selectionType !== testSelectionTypes.TEST_SUITES) {
80
+ return undefined
81
+ }
82
+
83
+ if (!Array.isArray(value) || value.length === 0) {
84
+ return 'At least one test suite is required'
85
+ }
86
+
87
+ const invalidSuite = value.find(suiteSelection => !suiteSelection.runAll && suiteSelection.testCaseIds.length === 0)
88
+ if (invalidSuite) {
89
+ return 'Partial suite selections must include at least one test case'
90
+ }
91
+
92
+ return undefined
93
+ }
94
+
95
+ export function getTestRunSuccessPath(data: ActionResponseData | undefined) {
96
+ if (typeof data === 'object' && data !== null && 'id' in data && typeof data.id === 'string') {
97
+ return `/test-runs/${data.id}`
98
+ }
99
+
100
+ return '/test-runs'
101
+ }
102
+
103
+ function isEnvironmentRow(value: unknown): value is Environment {
104
+ return typeof value === 'object' && value !== null && 'id' in value && 'name' in value
105
+ }
106
+
107
+ function isTagRow(value: unknown): value is Tag {
108
+ return typeof value === 'object' && value !== null && 'id' in value && 'name' in value
109
+ }
110
+
111
+ function isModuleRow(value: unknown) {
112
+ return typeof value === 'object' && value !== null && 'id' in value && 'name' in value
113
+ }
114
+
115
+ function isTestCaseRow(value: unknown) {
116
+ return (
117
+ typeof value === 'object' &&
118
+ value !== null &&
119
+ 'id' in value &&
120
+ 'title' in value &&
121
+ 'steps' in value &&
122
+ Array.isArray(value.steps) &&
123
+ 'tags' in value &&
124
+ Array.isArray(value.tags) &&
125
+ value.tags.every(isTagRow)
126
+ )
127
+ }
128
+
129
+ function isTestSuitePickerRow(value: unknown): value is TestSuitePickerRow {
130
+ return (
131
+ typeof value === 'object' &&
132
+ value !== null &&
133
+ 'id' in value &&
134
+ 'name' in value &&
135
+ 'module' in value &&
136
+ isModuleRow(value.module) &&
137
+ 'tags' in value &&
138
+ Array.isArray(value.tags) &&
139
+ value.tags.every(isTagRow) &&
140
+ 'testCases' in value &&
141
+ Array.isArray(value.testCases) &&
142
+ value.testCases.every(isTestCaseRow)
143
+ )
144
+ }
145
+
146
+ export function getEnvironmentRows(data: ActionResponseData | undefined): Environment[] {
147
+ return Array.isArray(data) ? data.filter(isEnvironmentRow) : []
148
+ }
149
+
150
+ export function getTagRows(data: ActionResponseData | undefined): Tag[] {
151
+ return Array.isArray(data) ? data.filter(isTagRow) : []
152
+ }
153
+
154
+ export function getTestSuitePickerRows(data: ActionResponseData | undefined): TestSuitePickerRow[] {
155
+ return Array.isArray(data) ? data.filter(isTestSuitePickerRow) : []
156
+ }
157
+
158
+ export function getInitialTestSelectionType(defaultValues?: TestRun): TestSelectionType {
159
+ return defaultValues?.testSuites?.length ? testSelectionTypes.TEST_SUITES : testSelectionTypes.TAGS
160
+ }
161
+
162
+ export function getBrowserEngineOptions() {
163
+ return [
164
+ { label: 'Chromium', value: BrowserEngine.CHROMIUM },
165
+ { label: 'Firefox', value: BrowserEngine.FIREFOX },
166
+ { label: 'WebKit', value: BrowserEngine.WEBKIT },
167
+ ] as const
168
+ }