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,87 +1,87 @@
1
- 'use client'
2
-
3
- import { Button } from '@/components/ui/button'
4
- import { Card, CardContent, CardTitle, CardHeader } from '@/components/ui/card'
5
- import { ExternalLink } from 'lucide-react'
6
- import { useRouter } from 'next/navigation'
7
- import { useEffect, useState, useRef } from 'react'
8
- import { getRunningTestRunsCountAction } from '@/actions/dashboard/dashboard-actions'
9
-
10
- interface OngoingTestRunsCardProps {
11
- initialCount: number
12
- link: string
13
- }
14
-
15
- export default function OngoingTestRunsCard({ initialCount, link }: OngoingTestRunsCardProps) {
16
- const router = useRouter()
17
- const [count, setCount] = useState(initialCount)
18
- const pollingRef = useRef<NodeJS.Timeout | null>(null)
19
-
20
- // Poll for count updates while there are ongoing test runs
21
- useEffect(() => {
22
- // Clear any existing polling interval
23
- if (pollingRef.current) {
24
- clearInterval(pollingRef.current)
25
- pollingRef.current = null
26
- }
27
-
28
- // If no ongoing test runs, don't poll
29
- if (count === 0) {
30
- return
31
- }
32
-
33
- pollingRef.current = setInterval(async () => {
34
- try {
35
- const { data, error } = await getRunningTestRunsCountAction()
36
- if (error) {
37
- console.error('Error polling running test runs count:', error)
38
- return
39
- }
40
-
41
- const newCount = data as number
42
- setCount(newCount)
43
-
44
- // If count reaches 0, stop polling
45
- if (newCount === 0 && pollingRef.current) {
46
- clearInterval(pollingRef.current)
47
- pollingRef.current = null
48
- }
49
- } catch (error) {
50
- console.error('Error polling running test runs count:', error)
51
- }
52
- }, 2000) // Poll every 2 seconds
53
-
54
- return () => {
55
- if (pollingRef.current) {
56
- clearInterval(pollingRef.current)
57
- pollingRef.current = null
58
- }
59
- }
60
- }, [count])
61
-
62
- return (
63
- <Card className="h-fit border-gray-600/10 bg-gray-600/10 min-w-40">
64
- <CardHeader className="flex items-center justify-between flex-row p-2">
65
- <CardTitle className={`text-xs font-normal ${count > 0 ? 'text-primary' : 'text-gray-400'}`}>
66
- Ongoing Test Runs
67
- </CardTitle>
68
- <div className="flex items-center gap-2">
69
- <Button
70
- variant="outline"
71
- className="text-primary hover:text-primary/80 px-2 py-1 bg-inherit border-gray-600/15 hover:bg-emerald-400/10"
72
- disabled={count === 0}
73
- onClick={() => router.push(link)}
74
- size="sm"
75
- >
76
- <ExternalLink className="h-4 w-4" />
77
- </Button>
78
- </div>
79
- </CardHeader>
80
- <CardContent className="h-full px-2 py-1">
81
- <div className={`text-2xl h-full flex items-center font-bold ${count > 0 ? 'text-primary' : 'text-gray-400'}`}>
82
- {count}
83
- </div>
84
- </CardContent>
85
- </Card>
86
- )
87
- }
1
+ 'use client'
2
+
3
+ import { Button } from '@/components/ui/button'
4
+ import { Card, CardContent, CardTitle, CardHeader } from '@/components/ui/card'
5
+ import { ExternalLink } from 'lucide-react'
6
+ import { useRouter } from 'next/navigation'
7
+ import { useEffect, useState, useRef } from 'react'
8
+ import { getRunningTestRunsCountAction } from '@/actions/dashboard/dashboard-actions'
9
+
10
+ interface OngoingTestRunsCardProps {
11
+ initialCount: number
12
+ link: string
13
+ }
14
+
15
+ export default function OngoingTestRunsCard({ initialCount, link }: OngoingTestRunsCardProps) {
16
+ const router = useRouter()
17
+ const [count, setCount] = useState(initialCount)
18
+ const pollingRef = useRef<NodeJS.Timeout | null>(null)
19
+
20
+ // Poll for count updates while there are ongoing test runs
21
+ useEffect(() => {
22
+ // Clear any existing polling interval
23
+ if (pollingRef.current) {
24
+ clearInterval(pollingRef.current)
25
+ pollingRef.current = null
26
+ }
27
+
28
+ // If no ongoing test runs, don't poll
29
+ if (count === 0) {
30
+ return
31
+ }
32
+
33
+ pollingRef.current = setInterval(async () => {
34
+ try {
35
+ const { data, error } = await getRunningTestRunsCountAction()
36
+ if (error) {
37
+ console.error('Error polling running test runs count:', error)
38
+ return
39
+ }
40
+
41
+ const newCount = data as number
42
+ setCount(newCount)
43
+
44
+ // If count reaches 0, stop polling
45
+ if (newCount === 0 && pollingRef.current) {
46
+ clearInterval(pollingRef.current)
47
+ pollingRef.current = null
48
+ }
49
+ } catch (error) {
50
+ console.error('Error polling running test runs count:', error)
51
+ }
52
+ }, 2000) // Poll every 2 seconds
53
+
54
+ return () => {
55
+ if (pollingRef.current) {
56
+ clearInterval(pollingRef.current)
57
+ pollingRef.current = null
58
+ }
59
+ }
60
+ }, [count])
61
+
62
+ return (
63
+ <Card className="h-fit border-gray-600/10 bg-gray-600/10 min-w-40">
64
+ <CardHeader className="flex items-center justify-between flex-row p-2">
65
+ <CardTitle className={`text-xs font-normal ${count > 0 ? 'text-primary' : 'text-gray-400'}`}>
66
+ Ongoing Test Runs
67
+ </CardTitle>
68
+ <div className="flex items-center gap-2">
69
+ <Button
70
+ variant="outline"
71
+ className="text-primary hover:text-primary/80 px-2 py-1 bg-inherit border-gray-600/15 hover:bg-emerald-400/10"
72
+ disabled={count === 0}
73
+ onClick={() => router.push(link)}
74
+ size="sm"
75
+ >
76
+ <ExternalLink className="h-4 w-4" />
77
+ </Button>
78
+ </div>
79
+ </CardHeader>
80
+ <CardContent className="h-full px-2 py-1">
81
+ <div className={`text-2xl h-full flex items-center font-bold ${count > 0 ? 'text-primary' : 'text-gray-400'}`}>
82
+ {count}
83
+ </div>
84
+ </CardContent>
85
+ </Card>
86
+ )
87
+ }
@@ -1,45 +1,45 @@
1
- 'use client'
2
- import { Button } from "@/components/ui/button";
3
- import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
4
- import { Blocks, FileCheck, LayoutTemplate, ListChecks, TestTubeDiagonal, TestTubes } from "lucide-react";
5
- import { useRouter } from "next/navigation";
6
-
7
- export default function QuickActionsDrawer() {
8
- const router = useRouter()
9
- return (
10
- <Card id="container" className="w-fit border-gray-600/10 bg-gray-600/10 h-fit">
11
- <CardHeader id="header">
12
- <CardTitle className="text-primary">Quick Actions</CardTitle>
13
- <CardDescription>Quickly create new entities to get started</CardDescription>
14
- </CardHeader>
15
- <CardContent id="content">
16
- <div className="grid grid-cols-5 gap-4">
17
- <Button variant="outline" className="flex flex-col items-center gap-2 h-fit [&_svg]:!h-6 [&_svg]:!w-6 bg-emerald-500/10 hover:bg-emerald-500/25 text-emerald-500 hover:text-emerald-400 border-none" onClick={() => router.push('/test-suites/create')}>
18
- <TestTubes />
19
- <span className="text-xs font-medium">Create Suite</span>
20
- </Button>
21
- <Button variant="outline" className="flex flex-col items-center gap-2 h-fit [&_svg]:!h-6 [&_svg]:!w-6 bg-emerald-500/10 hover:bg-emerald-500/25 text-emerald-500 hover:text-emerald-400 border-none" onClick={() => router.push('/test-cases/create')}>
22
- <TestTubeDiagonal />
23
- <span className="text-xs font-medium">Create Test</span>
24
- </Button>
25
- <Button variant="outline" className="flex flex-col items-center gap-2 h-fit [&_svg]:!h-6 [&_svg]:!w-6 bg-emerald-500/10 hover:bg-emerald-500/25 text-emerald-500 hover:text-emerald-400 border-none" onClick={() => router.push('/template-steps/create')}>
26
- <LayoutTemplate />
27
- <span className="text-xs font-medium">Create Step</span>
28
- </Button>
29
- <Button variant="outline" className="flex flex-col items-center gap-2 h-fit [&_svg]:!h-6 [&_svg]:!w-6 bg-emerald-500/10 hover:bg-emerald-500/25 text-emerald-500 hover:text-emerald-400 border-none" onClick={() => router.push('/test-runs/create')}>
30
- <ListChecks />
31
- <span className="text-xs font-medium">Create Run</span>
32
- </Button>
33
- <Button variant="outline" className="flex flex-col items-center gap-2 h-fit [&_svg]:!h-6 [&_svg]:!w-6 bg-emerald-500/10 hover:bg-emerald-500/25 text-emerald-500 hover:text-emerald-400 border-none" onClick={() => router.push('/template-test-cases/create')}>
34
- <Blocks />
35
- <span className="text-xs font-medium">Create Template</span>
36
- </Button>
37
- <Button variant="outline" className="flex flex-col items-center gap-2 h-fit [&_svg]:!h-6 [&_svg]:!w-6 bg-emerald-500/10 hover:bg-emerald-500/25 text-emerald-500 hover:text-emerald-400 border-none" onClick={() => router.push('/reports')}>
38
- <FileCheck />
39
- <span className="text-xs font-medium">View Reports</span>
40
- </Button>
41
- </div>
42
- </CardContent>
43
- </Card>
44
- )
1
+ 'use client'
2
+ import { Button } from "@/components/ui/button";
3
+ import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
4
+ import { Blocks, FileCheck, LayoutTemplate, ListChecks, TestTubeDiagonal, TestTubes } from "lucide-react";
5
+ import { useRouter } from "next/navigation";
6
+
7
+ export default function QuickActionsDrawer() {
8
+ const router = useRouter()
9
+ return (
10
+ <Card id="container" className="w-fit border-gray-600/10 bg-gray-600/10 h-fit">
11
+ <CardHeader id="header">
12
+ <CardTitle className="text-primary">Quick Actions</CardTitle>
13
+ <CardDescription>Quickly create new entities to get started</CardDescription>
14
+ </CardHeader>
15
+ <CardContent id="content">
16
+ <div className="grid grid-cols-5 gap-4">
17
+ <Button variant="outline" className="flex flex-col items-center gap-2 h-fit [&_svg]:!h-6 [&_svg]:!w-6 bg-emerald-500/10 hover:bg-emerald-500/25 text-emerald-500 hover:text-emerald-400 border-none" onClick={() => router.push('/test-suites/create')}>
18
+ <TestTubes />
19
+ <span className="text-xs font-medium">Create Suite</span>
20
+ </Button>
21
+ <Button variant="outline" className="flex flex-col items-center gap-2 h-fit [&_svg]:!h-6 [&_svg]:!w-6 bg-emerald-500/10 hover:bg-emerald-500/25 text-emerald-500 hover:text-emerald-400 border-none" onClick={() => router.push('/test-cases/create')}>
22
+ <TestTubeDiagonal />
23
+ <span className="text-xs font-medium">Create Test</span>
24
+ </Button>
25
+ <Button variant="outline" className="flex flex-col items-center gap-2 h-fit [&_svg]:!h-6 [&_svg]:!w-6 bg-emerald-500/10 hover:bg-emerald-500/25 text-emerald-500 hover:text-emerald-400 border-none" onClick={() => router.push('/template-steps/create')}>
26
+ <LayoutTemplate />
27
+ <span className="text-xs font-medium">Create Step</span>
28
+ </Button>
29
+ <Button variant="outline" className="flex flex-col items-center gap-2 h-fit [&_svg]:!h-6 [&_svg]:!w-6 bg-emerald-500/10 hover:bg-emerald-500/25 text-emerald-500 hover:text-emerald-400 border-none" onClick={() => router.push('/test-runs/create')}>
30
+ <ListChecks />
31
+ <span className="text-xs font-medium">Create Run</span>
32
+ </Button>
33
+ <Button variant="outline" className="flex flex-col items-center gap-2 h-fit [&_svg]:!h-6 [&_svg]:!w-6 bg-emerald-500/10 hover:bg-emerald-500/25 text-emerald-500 hover:text-emerald-400 border-none" onClick={() => router.push('/template-test-cases/create')}>
34
+ <Blocks />
35
+ <span className="text-xs font-medium">Create Template</span>
36
+ </Button>
37
+ <Button variant="outline" className="flex flex-col items-center gap-2 h-fit [&_svg]:!h-6 [&_svg]:!w-6 bg-emerald-500/10 hover:bg-emerald-500/25 text-emerald-500 hover:text-emerald-400 border-none" onClick={() => router.push('/reports')}>
38
+ <FileCheck />
39
+ <span className="text-xs font-medium">View Reports</span>
40
+ </Button>
41
+ </div>
42
+ </CardContent>
43
+ </Card>
44
+ )
45
45
  }
@@ -0,0 +1,83 @@
1
+ import { Readable } from 'stream'
2
+ import { beforeEach, describe, expect, it, vi } from 'vitest'
3
+
4
+ const { mockAccess, mockCreateReadStream, mockFindUnique } = vi.hoisted(() => ({
5
+ mockAccess: vi.fn(),
6
+ mockCreateReadStream: vi.fn(),
7
+ mockFindUnique: vi.fn(),
8
+ }))
9
+
10
+ vi.mock('fs', () => ({
11
+ promises: {
12
+ access: mockAccess,
13
+ },
14
+ createReadStream: mockCreateReadStream,
15
+ }))
16
+
17
+ vi.mock('@/config/db-config', () => ({
18
+ default: {
19
+ reportStep: {
20
+ findUnique: mockFindUnique,
21
+ },
22
+ },
23
+ }))
24
+
25
+ vi.mock('@/lib/automation/automation-path-roots', () => ({
26
+ resolveStoredPath: vi.fn((storedPath: string) => `/resolved/${storedPath}`),
27
+ }))
28
+
29
+ import { GET } from './route'
30
+
31
+ describe('report screenshot route', () => {
32
+ beforeEach(() => {
33
+ vi.clearAllMocks()
34
+ })
35
+
36
+ it('returns 404 when the report step is missing', async () => {
37
+ mockFindUnique.mockResolvedValue(null)
38
+
39
+ const response = await GET(new Request('http://localhost/api/reports/steps/step-1/screenshot'), {
40
+ params: Promise.resolve({ stepId: 'step-1' }),
41
+ })
42
+
43
+ expect(response.status).toBe(404)
44
+ await expect(response.json()).resolves.toEqual({ error: 'Report step not found' })
45
+ })
46
+
47
+ it('returns 404 when the step has no screenshot path', async () => {
48
+ mockFindUnique.mockResolvedValue({ screenshotPath: null })
49
+
50
+ const response = await GET(new Request('http://localhost/api/reports/steps/step-1/screenshot'), {
51
+ params: Promise.resolve({ stepId: 'step-1' }),
52
+ })
53
+
54
+ expect(response.status).toBe(404)
55
+ await expect(response.json()).resolves.toEqual({ error: 'Screenshot not available for this step' })
56
+ })
57
+
58
+ it('returns 404 when the screenshot file is missing', async () => {
59
+ mockFindUnique.mockResolvedValue({ screenshotPath: 'shots/step-1.png' })
60
+ mockAccess.mockRejectedValue(new Error('missing'))
61
+
62
+ const response = await GET(new Request('http://localhost/api/reports/steps/step-1/screenshot'), {
63
+ params: Promise.resolve({ stepId: 'step-1' }),
64
+ })
65
+
66
+ expect(response.status).toBe(404)
67
+ await expect(response.json()).resolves.toEqual({ error: 'Screenshot file not found' })
68
+ })
69
+
70
+ it('streams the screenshot when the file exists', async () => {
71
+ mockFindUnique.mockResolvedValue({ screenshotPath: 'shots/step-1.png' })
72
+ mockAccess.mockResolvedValue(undefined)
73
+ mockCreateReadStream.mockReturnValue(Readable.from([Buffer.from('png')]))
74
+
75
+ const response = await GET(new Request('http://localhost/api/reports/steps/step-1/screenshot'), {
76
+ params: Promise.resolve({ stepId: 'step-1' }),
77
+ })
78
+
79
+ expect(response.status).toBe(200)
80
+ expect(response.headers.get('Content-Type')).toBe('image/png')
81
+ await expect(response.arrayBuffer()).resolves.toBeInstanceOf(ArrayBuffer)
82
+ })
83
+ })
@@ -1,52 +1,52 @@
1
- import { NextResponse } from 'next/server'
2
- import { promises as fs, createReadStream } from 'fs'
3
- import { Readable } from 'stream'
4
- import prisma from '@/config/db-config'
5
- import { resolveStoredPath } from '@/lib/automation/paths'
6
-
7
- export const runtime = 'nodejs'
8
-
9
- export async function GET(_request: Request, { params }: { params: Promise<{ stepId: string }> }) {
10
- const { stepId } = await params
11
-
12
- try {
13
- const step = await prisma.reportStep.findUnique({
14
- where: { id: stepId },
15
- select: {
16
- screenshotPath: true,
17
- },
18
- })
19
-
20
- if (!step) {
21
- return NextResponse.json({ error: 'Report step not found' }, { status: 404 })
22
- }
23
-
24
- if (!step.screenshotPath) {
25
- return NextResponse.json({ error: 'Screenshot not available for this step' }, { status: 404 })
26
- }
27
-
28
- const screenshotPath = resolveStoredPath(step.screenshotPath)
29
-
30
- try {
31
- await fs.access(screenshotPath)
32
- } catch {
33
- return NextResponse.json({ error: 'Screenshot file not found' }, { status: 404 })
34
- }
35
-
36
- return new NextResponse(Readable.toWeb(createReadStream(screenshotPath)) as ReadableStream, {
37
- headers: {
38
- 'Content-Type': 'image/png',
39
- 'Cache-Control': 'private, max-age=60',
40
- },
41
- })
42
- } catch (error) {
43
- console.error(`[ReportScreenshot] Failed to serve screenshot for step ${stepId}:`, error)
44
- return NextResponse.json(
45
- {
46
- error: 'Failed to load screenshot',
47
- details: error instanceof Error ? error.message : 'Unknown error',
48
- },
49
- { status: 500 },
50
- )
51
- }
52
- }
1
+ import { NextResponse } from 'next/server'
2
+ import { promises as fs, createReadStream } from 'fs'
3
+ import { Readable } from 'stream'
4
+ import prisma from '@/config/db-config'
5
+ import { resolveStoredPath } from '@/lib/automation/automation-path-roots'
6
+
7
+ export const runtime = 'nodejs'
8
+
9
+ export async function GET(_request: Request, { params }: { params: Promise<{ stepId: string }> }) {
10
+ const { stepId } = await params
11
+
12
+ try {
13
+ const step = await prisma.reportStep.findUnique({
14
+ where: { id: stepId },
15
+ select: {
16
+ screenshotPath: true,
17
+ },
18
+ })
19
+
20
+ if (!step) {
21
+ return NextResponse.json({ error: 'Report step not found' }, { status: 404 })
22
+ }
23
+
24
+ if (!step.screenshotPath) {
25
+ return NextResponse.json({ error: 'Screenshot not available for this step' }, { status: 404 })
26
+ }
27
+
28
+ const screenshotPath = resolveStoredPath(step.screenshotPath)
29
+
30
+ try {
31
+ await fs.access(screenshotPath)
32
+ } catch {
33
+ return NextResponse.json({ error: 'Screenshot file not found' }, { status: 404 })
34
+ }
35
+
36
+ return new NextResponse(Readable.toWeb(createReadStream(screenshotPath)) as ReadableStream, {
37
+ headers: {
38
+ 'Content-Type': 'image/png',
39
+ 'Cache-Control': 'private, max-age=60',
40
+ },
41
+ })
42
+ } catch (error) {
43
+ console.error(`[ReportScreenshot] Failed to serve screenshot for step ${stepId}:`, error)
44
+ return NextResponse.json(
45
+ {
46
+ error: 'Failed to load screenshot',
47
+ details: error instanceof Error ? error.message : 'Unknown error',
48
+ },
49
+ { status: 500 },
50
+ )
51
+ }
52
+ }
@@ -0,0 +1,169 @@
1
+ import { beforeEach, describe, expect, it, vi } from 'vitest'
2
+ import { NextRequest } from 'next/server'
3
+
4
+ const { mockReaddir, mockAccess, mockFindUnique, archiveState } = vi.hoisted(() => ({
5
+ mockReaddir: vi.fn(),
6
+ mockAccess: vi.fn(),
7
+ mockFindUnique: vi.fn(),
8
+ archiveState: { lastArchive: null as { fileCalls: ArchiveFileCall[] } | null },
9
+ }))
10
+
11
+ type ArchiveFileCall = { path: string; name: string }
12
+
13
+ function normalizeFsPath(value: string) {
14
+ return value.replace(/\\/g, '/')
15
+ }
16
+
17
+ vi.mock('archiver', () => ({
18
+ default: vi.fn(() => {
19
+ const listeners = new Map<string, Array<(value?: Buffer) => void>>()
20
+ const archive = {
21
+ fileCalls: [] as ArchiveFileCall[],
22
+ on(event: string, callback: (value?: Buffer) => void) {
23
+ const current = listeners.get(event) ?? []
24
+ current.push(callback)
25
+ listeners.set(event, current)
26
+ },
27
+ file(filePath: string, options: { name: string }) {
28
+ this.fileCalls.push({ path: filePath, name: options.name })
29
+ },
30
+ finalize() {
31
+ const buffer = Buffer.from(JSON.stringify(this.fileCalls))
32
+ for (const callback of listeners.get('data') ?? []) {
33
+ callback(buffer)
34
+ }
35
+ for (const callback of listeners.get('end') ?? []) {
36
+ callback()
37
+ }
38
+ },
39
+ }
40
+
41
+ archiveState.lastArchive = archive
42
+ return archive
43
+ }),
44
+ }))
45
+
46
+ vi.mock('@/config/db-config', () => ({
47
+ default: {
48
+ testRun: {
49
+ findUnique: mockFindUnique,
50
+ },
51
+ },
52
+ }))
53
+
54
+ vi.mock('fs', () => ({
55
+ promises: {
56
+ readdir: mockReaddir,
57
+ access: mockAccess,
58
+ },
59
+ }))
60
+
61
+ vi.mock('@/lib/automation/automation-path-roots', () => ({
62
+ getAutomationReportRunDir: vi.fn((runId: string) => `/artifacts/${runId}`),
63
+ resolveStoredPath: vi.fn((storedPath: string) => {
64
+ const mapping: Record<string, string> = {
65
+ 'legacy/cucumber.json': '/legacy/cucumber.json',
66
+ 'legacy/run.log': '/legacy/run.log',
67
+ 'legacy/trace.zip': '/legacy/trace.zip',
68
+ 'nested/cucumber.json': '/artifacts/run-1/cucumber.json',
69
+ 'nested/trace.zip': '/artifacts/run-1/traces/trace.zip',
70
+ }
71
+
72
+ return mapping[storedPath] ?? storedPath
73
+ }),
74
+ }))
75
+
76
+ import { GET } from './route'
77
+
78
+ function fileEntry(name: string) {
79
+ return {
80
+ name,
81
+ isDirectory: () => false,
82
+ }
83
+ }
84
+
85
+ function directoryEntry(name: string) {
86
+ return {
87
+ name,
88
+ isDirectory: () => true,
89
+ }
90
+ }
91
+
92
+ describe('test run download route', () => {
93
+ beforeEach(() => {
94
+ vi.clearAllMocks()
95
+ archiveState.lastArchive = null
96
+ })
97
+
98
+ it('returns 404 when the test run does not exist', async () => {
99
+ mockFindUnique.mockResolvedValue(null)
100
+
101
+ const response = await GET(new NextRequest('http://localhost/api/test-runs/run-1/download'), {
102
+ params: Promise.resolve({ runId: 'run-1' }),
103
+ })
104
+
105
+ expect(response.status).toBe(404)
106
+ await expect(response.json()).resolves.toEqual({ error: 'Test run not found' })
107
+ })
108
+
109
+ it('returns 404 when no artifact files are available', async () => {
110
+ mockFindUnique.mockResolvedValue({
111
+ logPath: null,
112
+ reportPath: null,
113
+ testCases: [],
114
+ })
115
+ mockReaddir.mockRejectedValue(new Error('missing'))
116
+
117
+ const response = await GET(new NextRequest('http://localhost/api/test-runs/run-1/download'), {
118
+ params: Promise.resolve({ runId: 'run-1' }),
119
+ })
120
+
121
+ expect(response.status).toBe(404)
122
+ await expect(response.json()).resolves.toEqual({ error: 'No run artifacts available for this test run' })
123
+ })
124
+
125
+ it('adds run-folder artifacts and only unique legacy fallback files to the archive', async () => {
126
+ mockFindUnique.mockResolvedValue({
127
+ logPath: 'legacy/run.log',
128
+ reportPath: 'nested/cucumber.json',
129
+ testCases: [{ tracePath: 'legacy/trace.zip' }, { tracePath: 'nested/trace.zip' }],
130
+ })
131
+ mockReaddir.mockImplementation(async (dir: string) => {
132
+ const normalizedDir = normalizeFsPath(dir)
133
+
134
+ if (normalizedDir === '/artifacts/run-1') {
135
+ return [fileEntry('cucumber.json'), directoryEntry('logs'), directoryEntry('traces')]
136
+ }
137
+
138
+ if (normalizedDir === '/artifacts/run-1/logs') {
139
+ return [fileEntry('folder.log')]
140
+ }
141
+
142
+ if (normalizedDir === '/artifacts/run-1/traces') {
143
+ return [fileEntry('trace.zip')]
144
+ }
145
+
146
+ return []
147
+ })
148
+ mockAccess.mockResolvedValue(undefined)
149
+
150
+ const response = await GET(new NextRequest('http://localhost/api/test-runs/run-1/download'), {
151
+ params: Promise.resolve({ runId: 'run-1' }),
152
+ })
153
+
154
+ expect(response.status).toBe(200)
155
+ expect(response.headers.get('Content-Type')).toBe('application/zip')
156
+ expect(
157
+ archiveState.lastArchive?.fileCalls.map(fileCall => ({
158
+ ...fileCall,
159
+ path: normalizeFsPath(fileCall.path),
160
+ })),
161
+ ).toEqual([
162
+ { path: '/artifacts/run-1/cucumber.json', name: 'cucumber.json' },
163
+ { path: '/artifacts/run-1/logs/folder.log', name: 'logs/folder.log' },
164
+ { path: '/artifacts/run-1/traces/trace.zip', name: 'traces/trace.zip' },
165
+ { path: '/legacy/run.log', name: 'logs/run.log' },
166
+ ])
167
+ await expect(response.arrayBuffer()).resolves.toBeInstanceOf(ArrayBuffer)
168
+ })
169
+ })
@@ -3,7 +3,7 @@ import prisma from '@/config/db-config'
3
3
  import archiver from 'archiver'
4
4
  import { promises as fs } from 'fs'
5
5
  import path from 'path'
6
- import { getAutomationReportRunDir, resolveStoredPath } from '@/lib/automation/paths'
6
+ import { getAutomationReportRunDir, resolveStoredPath } from '@/lib/automation/automation-path-roots'
7
7
 
8
8
  // Ensure this route runs in Node.js runtime (not Edge) for file system access
9
9
  export const runtime = 'nodejs'