create-appraisejs 0.1.10-alpha.8 → 0.2.0-alpha.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (414) hide show
  1. package/README.md +52 -52
  2. package/dist/cli.e2e.test.d.ts +2 -0
  3. package/dist/cli.e2e.test.d.ts.map +1 -0
  4. package/dist/cli.e2e.test.js +73 -0
  5. package/dist/cli.e2e.test.js.map +1 -0
  6. package/dist/config.test.d.ts +2 -0
  7. package/dist/config.test.d.ts.map +1 -0
  8. package/dist/config.test.js +65 -0
  9. package/dist/config.test.js.map +1 -0
  10. package/dist/copy-template.test.d.ts +2 -0
  11. package/dist/copy-template.test.d.ts.map +1 -0
  12. package/dist/copy-template.test.js +71 -0
  13. package/dist/copy-template.test.js.map +1 -0
  14. package/dist/download-repo.test.d.ts +2 -0
  15. package/dist/download-repo.test.d.ts.map +1 -0
  16. package/dist/download-repo.test.js +14 -0
  17. package/dist/download-repo.test.js.map +1 -0
  18. package/dist/install.test.d.ts +2 -0
  19. package/dist/install.test.d.ts.map +1 -0
  20. package/dist/install.test.js +119 -0
  21. package/dist/install.test.js.map +1 -0
  22. package/dist/prepare-template-utils.d.ts.map +1 -1
  23. package/dist/prepare-template-utils.js +5 -0
  24. package/dist/prepare-template-utils.js.map +1 -1
  25. package/dist/prompts.test.d.ts +2 -0
  26. package/dist/prompts.test.d.ts.map +1 -0
  27. package/dist/prompts.test.js +58 -0
  28. package/dist/prompts.test.js.map +1 -0
  29. package/dist/scaffold-gitignore.d.ts +1 -0
  30. package/dist/scaffold-gitignore.d.ts.map +1 -1
  31. package/dist/scaffold-gitignore.js +3 -0
  32. package/dist/scaffold-gitignore.js.map +1 -1
  33. package/package.json +3 -2
  34. package/templates/default/.appraise-template-meta.json +2 -2
  35. package/templates/default/.env.example +2 -2
  36. package/templates/default/.vscode/settings.json +2 -1
  37. package/templates/default/README.md +53 -53
  38. package/templates/default/automation/mapping/locator-map.json +1 -14
  39. package/templates/default/automation/steps/actions/click.step.ts +58 -58
  40. package/templates/default/automation/steps/actions/hover.step.ts +27 -27
  41. package/templates/default/automation/steps/actions/input.step.ts +84 -84
  42. package/templates/default/automation/steps/actions/navigation.step.ts +70 -70
  43. package/templates/default/automation/steps/actions/random_data.step.ts +142 -142
  44. package/templates/default/automation/steps/actions/store.step.ts +86 -86
  45. package/templates/default/automation/steps/actions/wait.step.ts +90 -90
  46. package/templates/default/automation/steps/validations/active_state_assertion.step.ts +30 -30
  47. package/templates/default/automation/steps/validations/navigation_assertion.step.ts +22 -22
  48. package/templates/default/automation/steps/validations/text_assertion.step.ts +107 -107
  49. package/templates/default/automation/steps/validations/visibility_assertion.step.ts +26 -26
  50. package/templates/default/components.json +24 -24
  51. package/templates/default/cucumber.mjs +16 -16
  52. package/templates/default/eslint.config.mjs +16 -16
  53. package/templates/default/gitignore +3 -0
  54. package/templates/default/next-env.d.ts +6 -6
  55. package/templates/default/next.config.ts +11 -11
  56. package/templates/default/package-lock.json +146 -75
  57. package/templates/default/package.json +2 -1
  58. package/templates/default/packages/cucumber-runtime/package.json +13 -13
  59. package/templates/default/packages/cucumber-runtime/src/cache.util.ts +93 -93
  60. package/templates/default/packages/cucumber-runtime/src/cli.ts +68 -68
  61. package/templates/default/packages/cucumber-runtime/src/environment.util.ts +21 -21
  62. package/templates/default/packages/cucumber-runtime/src/executor.ts +32 -32
  63. package/templates/default/packages/cucumber-runtime/src/hooks.ts +25 -3
  64. package/templates/default/packages/cucumber-runtime/src/index.ts +17 -17
  65. package/templates/default/packages/cucumber-runtime/src/locator.util.ts +234 -234
  66. package/templates/default/packages/cucumber-runtime/src/parameter-types.ts +7 -7
  67. package/templates/default/packages/cucumber-runtime/src/paths.ts +66 -1
  68. package/templates/default/packages/cucumber-runtime/src/random-data.util.ts +35 -35
  69. package/templates/default/packages/cucumber-runtime/src/types.ts +13 -13
  70. package/templates/default/packages/cucumber-runtime/src/world.ts +44 -44
  71. package/templates/default/packages/cucumber-runtime/tsconfig.json +11 -11
  72. package/templates/default/packages/locator-picker-companion/dist/cli.d.ts +1 -0
  73. package/templates/default/packages/locator-picker-companion/dist/cli.js +302 -0
  74. package/templates/default/packages/locator-picker-companion/dist/index.d.ts +3 -0
  75. package/templates/default/packages/locator-picker-companion/dist/index.js +3 -0
  76. package/templates/default/packages/locator-picker-companion/dist/injected-picker-script.d.ts +1 -0
  77. package/templates/default/packages/locator-picker-companion/dist/injected-picker-script.js +615 -0
  78. package/templates/default/packages/locator-picker-companion/dist/launcher.d.ts +11 -0
  79. package/templates/default/packages/locator-picker-companion/dist/launcher.js +59 -0
  80. package/templates/default/packages/locator-picker-companion/dist/selector-generator.d.ts +3 -0
  81. package/templates/default/packages/locator-picker-companion/dist/selector-generator.js +257 -0
  82. package/templates/default/packages/locator-picker-companion/dist/session-file.d.ts +22 -0
  83. package/templates/default/packages/locator-picker-companion/dist/session-file.js +150 -0
  84. package/templates/default/packages/locator-picker-companion/dist/types.d.ts +31 -0
  85. package/templates/default/packages/locator-picker-companion/dist/types.js +1 -0
  86. package/templates/default/packages/locator-picker-companion/package.json +17 -0
  87. package/templates/default/packages/locator-picker-companion/src/cli.ts +428 -0
  88. package/templates/default/packages/locator-picker-companion/src/index.ts +3 -0
  89. package/templates/default/packages/locator-picker-companion/src/injected-picker-script.ts +771 -0
  90. package/templates/default/packages/locator-picker-companion/src/launcher.ts +77 -0
  91. package/templates/default/packages/locator-picker-companion/src/selector-generator.ts +339 -0
  92. package/templates/default/packages/locator-picker-companion/src/session-file.ts +226 -0
  93. package/templates/default/packages/locator-picker-companion/src/types.ts +42 -0
  94. package/templates/default/packages/locator-picker-companion/tsconfig.json +14 -0
  95. package/templates/default/postcss.config.mjs +8 -8
  96. package/templates/default/prisma/dev.db +0 -0
  97. package/templates/default/prisma/migrations/20251104113456_add_type_for_template_step_groups/migration.sql +16 -16
  98. package/templates/default/prisma/migrations/20251104170946_add_tags_to_test_suite_and_test_case/migration.sql +27 -27
  99. package/templates/default/prisma/migrations/20251112190024_add_cascade_delete_to_test_run_test_case/migration.sql +17 -17
  100. package/templates/default/prisma/migrations/20251113181100_add_test_run_log/migration.sql +12 -12
  101. package/templates/default/prisma/migrations/20251119191838_add_tag_type/migration.sql +28 -28
  102. package/templates/default/prisma/migrations/20251121164059_add_conflict_resolution/migration.sql +12 -12
  103. package/templates/default/prisma/migrations/20251223183400_add_report_model_to_db_schema/migration.sql +10 -10
  104. package/templates/default/prisma/migrations/20251223183637_add_report_test_case_entity_for_storing_test_results_for_individual_test_cases/migration.sql +10 -10
  105. package/templates/default/prisma/migrations/20251224083549_add_comprehensive_report_storage/migration.sql +108 -108
  106. package/templates/default/prisma/migrations/20251229194422_migrate_duration_to_string/migration.sql +55 -55
  107. package/templates/default/prisma/migrations/20251230124637_add_unique_constraint_to_test_run_name/migration.sql +27 -27
  108. package/templates/default/prisma/migrations/20260115094436_add_dashboard_metrics/migration.sql +59 -59
  109. package/templates/default/prisma/migrations/20260127172022_add_cascade_delete_to_step_parameters/migration.sql +34 -34
  110. package/templates/default/prisma/migrations/20260313093000_add_report_step_screenshot_path/migration.sql +1 -0
  111. package/templates/default/prisma/migrations/20260318120000_add_test_suite_context_to_test_run_test_case/migration.sql +20 -0
  112. package/templates/default/prisma/migrations/20260318173512_add_support_of_test_suite_level_runs/migration.sql +2 -0
  113. package/templates/default/prisma/schema.prisma +4 -0
  114. package/templates/default/scripts/install-playwright.ts +20 -0
  115. package/templates/default/scripts/protect-seeded-files.ts +38 -38
  116. package/templates/default/scripts/regenerate-features.ts +94 -94
  117. package/templates/default/scripts/setup-env.ts +19 -19
  118. package/templates/default/scripts/sync-all.ts +22 -66
  119. package/templates/default/scripts/sync-appraise-base-template.ts +57 -19
  120. package/templates/default/scripts/sync-environments.ts +40 -21
  121. package/templates/default/scripts/sync-locator-groups.ts +410 -410
  122. package/templates/default/scripts/sync-locators.ts +398 -398
  123. package/templates/default/scripts/sync-modules.ts +341 -341
  124. package/templates/default/scripts/sync-tags.ts +2 -3
  125. package/templates/default/scripts/sync-template-step-groups.ts +0 -3
  126. package/templates/default/scripts/sync-template-steps.ts +37 -11
  127. package/templates/default/scripts/sync-test-cases.ts +68 -16
  128. package/templates/default/scripts/sync-test-suites.ts +7 -5
  129. package/templates/default/src/actions/conflict/conflict.action.ts +33 -33
  130. package/templates/default/src/actions/dashboard/dashboard-actions.ts +240 -240
  131. package/templates/default/src/actions/environments/environment-actions.ts +188 -188
  132. package/templates/default/src/actions/locator/locator-actions.ts +490 -490
  133. package/templates/default/src/actions/locator-groups/locator-group-actions.ts +6 -3
  134. package/templates/default/src/actions/locator-picker/locator-picker-actions.ts +243 -0
  135. package/templates/default/src/actions/modules/module-actions.ts +135 -135
  136. package/templates/default/src/actions/reports/report-actions.ts +51 -49
  137. package/templates/default/src/actions/review/review-actions.ts +147 -147
  138. package/templates/default/src/actions/settings/sync-actions.ts +46 -0
  139. package/templates/default/src/actions/tags/tag-actions.ts +107 -107
  140. package/templates/default/src/actions/template-step/template-step-actions.ts +38 -4
  141. package/templates/default/src/actions/template-step-group/template-step-group-actions.ts +10 -3
  142. package/templates/default/src/actions/template-test-case/template-test-case-actions.ts +238 -238
  143. package/templates/default/src/actions/test-case/test-case-actions.ts +356 -356
  144. package/templates/default/src/actions/test-run/test-run-actions.ts +222 -129
  145. package/templates/default/src/actions/test-suite/test-suite-actions.ts +95 -17
  146. package/templates/default/src/actions/user/user-actions.ts +13 -13
  147. package/templates/default/src/app/(base)/environments/create/page.tsx +28 -28
  148. package/templates/default/src/app/(base)/environments/environment-form.tsx +219 -219
  149. package/templates/default/src/app/(base)/environments/environment-table-columns.tsx +96 -96
  150. package/templates/default/src/app/(base)/environments/environment-table.tsx +24 -24
  151. package/templates/default/src/app/(base)/environments/modify/[id]/page.tsx +46 -46
  152. package/templates/default/src/app/(base)/environments/page.tsx +59 -59
  153. package/templates/default/src/app/(base)/layout.tsx +10 -10
  154. package/templates/default/src/app/(base)/locator-groups/create/page.tsx +44 -44
  155. package/templates/default/src/app/(base)/locator-groups/locator-group-form.tsx +215 -215
  156. package/templates/default/src/app/(base)/locator-groups/locator-group-table-columns.tsx +77 -77
  157. package/templates/default/src/app/(base)/locator-groups/locator-group-table.tsx +28 -28
  158. package/templates/default/src/app/(base)/locator-groups/modify/[id]/page.tsx +46 -46
  159. package/templates/default/src/app/(base)/locator-groups/page.tsx +20 -8
  160. package/templates/default/src/app/(base)/locators/create/create-locator-workspace.tsx +542 -0
  161. package/templates/default/src/app/(base)/locators/create/page.tsx +32 -19
  162. package/templates/default/src/app/(base)/locators/locator-form.tsx +163 -163
  163. package/templates/default/src/app/(base)/locators/locator-table-columns.tsx +73 -73
  164. package/templates/default/src/app/(base)/locators/locator-table.tsx +28 -28
  165. package/templates/default/src/app/(base)/locators/modify/[id]/page.tsx +56 -27
  166. package/templates/default/src/app/(base)/locators/page.tsx +13 -13
  167. package/templates/default/src/app/(base)/locators/picker/page.tsx +7 -0
  168. package/templates/default/src/app/(base)/locators/sync-locators-button.tsx +66 -66
  169. package/templates/default/src/app/(base)/modules/create/page.tsx +34 -34
  170. package/templates/default/src/app/(base)/modules/modify/[id]/page.tsx +46 -46
  171. package/templates/default/src/app/(base)/modules/module-form.tsx +126 -126
  172. package/templates/default/src/app/(base)/modules/module-table-columns.tsx +85 -85
  173. package/templates/default/src/app/(base)/modules/module-table.tsx +24 -24
  174. package/templates/default/src/app/(base)/modules/page.tsx +59 -59
  175. package/templates/default/src/app/(base)/reports/[id]/page.tsx +40 -33
  176. package/templates/default/src/app/(base)/reports/duration-chart.tsx +33 -33
  177. package/templates/default/src/app/(base)/reports/feature-chart.tsx +78 -78
  178. package/templates/default/src/app/(base)/reports/overview-chart.tsx +49 -46
  179. package/templates/default/src/app/(base)/reports/page.tsx +98 -98
  180. package/templates/default/src/app/(base)/reports/report-metric-card.tsx +78 -16
  181. package/templates/default/src/app/(base)/reports/report-table-columns.tsx +189 -189
  182. package/templates/default/src/app/(base)/reports/report-table.tsx +72 -72
  183. package/templates/default/src/app/(base)/reports/report-view-table-columns.tsx +12 -1
  184. package/templates/default/src/app/(base)/reports/report-view-table.tsx +1 -0
  185. package/templates/default/src/app/(base)/reports/test-cases/page.tsx +40 -42
  186. package/templates/default/src/app/(base)/reports/test-cases/test-cases-metric-table-columns.tsx +115 -115
  187. package/templates/default/src/app/(base)/reports/test-cases/test-cases-metric-table.tsx +27 -27
  188. package/templates/default/src/app/(base)/reports/test-suites/page.tsx +42 -42
  189. package/templates/default/src/app/(base)/reports/test-suites/test-suites-metric-table-columns.tsx +79 -79
  190. package/templates/default/src/app/(base)/reports/test-suites/test-suites-metric-table.tsx +27 -27
  191. package/templates/default/src/app/(base)/reports/view-logs-button.tsx +58 -60
  192. package/templates/default/src/app/(base)/reviews/create/page.tsx +26 -26
  193. package/templates/default/src/app/(base)/reviews/created-reviews-table.tsx +15 -15
  194. package/templates/default/src/app/(base)/reviews/modify/[id]/page.tsx +26 -26
  195. package/templates/default/src/app/(base)/reviews/page.tsx +26 -26
  196. package/templates/default/src/app/(base)/reviews/review/[id]/page.tsx +26 -26
  197. package/templates/default/src/app/(base)/reviews/review-form.tsx +11 -11
  198. package/templates/default/src/app/(base)/reviews/review-table-by-creator-columns.tsx +9 -9
  199. package/templates/default/src/app/(base)/reviews/review-table-by-reviewer-columns.tsx +9 -9
  200. package/templates/default/src/app/(base)/reviews/reviewer-reviews-table.tsx +15 -15
  201. package/templates/default/src/app/(base)/settings/page.tsx +30 -0
  202. package/templates/default/src/app/(base)/settings/settings-sync-panel.tsx +261 -0
  203. package/templates/default/src/app/(base)/tags/create/page.tsx +39 -39
  204. package/templates/default/src/app/(base)/tags/modify/[id]/page.tsx +50 -50
  205. package/templates/default/src/app/(base)/tags/page.tsx +58 -58
  206. package/templates/default/src/app/(base)/tags/tag-form.tsx +147 -147
  207. package/templates/default/src/app/(base)/tags/tag-table-columns.tsx +63 -63
  208. package/templates/default/src/app/(base)/tags/tag-table.tsx +29 -29
  209. package/templates/default/src/app/(base)/template-step-groups/create/page.tsx +28 -28
  210. package/templates/default/src/app/(base)/template-step-groups/modify/[id]/page.tsx +45 -45
  211. package/templates/default/src/app/(base)/template-step-groups/page.tsx +60 -60
  212. package/templates/default/src/app/(base)/template-step-groups/template-step-group-form.tsx +167 -167
  213. package/templates/default/src/app/(base)/template-step-groups/template-step-group-table-columns.tsx +89 -89
  214. package/templates/default/src/app/(base)/template-step-groups/template-step-group-table.tsx +32 -32
  215. package/templates/default/src/app/(base)/template-steps/create/page.tsx +37 -37
  216. package/templates/default/src/app/(base)/template-steps/modify/[id]/page.tsx +49 -49
  217. package/templates/default/src/app/(base)/template-steps/page.tsx +58 -58
  218. package/templates/default/src/app/(base)/template-steps/paramChip.tsx +213 -213
  219. package/templates/default/src/app/(base)/template-steps/template-step-form.tsx +384 -384
  220. package/templates/default/src/app/(base)/template-steps/template-step-table-columns.tsx +158 -158
  221. package/templates/default/src/app/(base)/template-steps/template-step-table.tsx +24 -24
  222. package/templates/default/src/app/(base)/template-test-cases/create/page.tsx +56 -56
  223. package/templates/default/src/app/(base)/template-test-cases/modify/[id]/page.tsx +89 -89
  224. package/templates/default/src/app/(base)/template-test-cases/page.tsx +58 -58
  225. package/templates/default/src/app/(base)/template-test-cases/template-test-case-flow.tsx +84 -84
  226. package/templates/default/src/app/(base)/template-test-cases/template-test-case-form.tsx +262 -262
  227. package/templates/default/src/app/(base)/template-test-cases/template-test-case-table-columns.tsx +76 -76
  228. package/templates/default/src/app/(base)/template-test-cases/template-test-case-table.tsx +32 -32
  229. package/templates/default/src/app/(base)/test-cases/create/page.tsx +76 -76
  230. package/templates/default/src/app/(base)/test-cases/create-from-template/generate/[id]/page.tsx +96 -96
  231. package/templates/default/src/app/(base)/test-cases/create-from-template/page.tsx +38 -38
  232. package/templates/default/src/app/(base)/test-cases/create-from-template/template-selection-form.tsx +73 -73
  233. package/templates/default/src/app/(base)/test-cases/modify/[id]/page.tsx +106 -106
  234. package/templates/default/src/app/(base)/test-cases/page.tsx +2 -2
  235. package/templates/default/src/app/(base)/test-cases/test-case-flow.tsx +82 -82
  236. package/templates/default/src/app/(base)/test-cases/test-case-form.tsx +395 -395
  237. package/templates/default/src/app/(base)/test-cases/test-case-table-columns.tsx +6 -71
  238. package/templates/default/src/app/(base)/test-cases/test-case-table.tsx +2 -2
  239. package/templates/default/src/app/(base)/test-runs/[id]/page.tsx +4 -1
  240. package/templates/default/src/app/(base)/test-runs/create/page.tsx +11 -9
  241. package/templates/default/src/app/(base)/test-runs/page.tsx +60 -60
  242. package/templates/default/src/app/(base)/test-runs/test-run-form.tsx +37 -44
  243. package/templates/default/src/app/(base)/test-runs/test-run-table-columns.tsx +229 -229
  244. package/templates/default/src/app/(base)/test-runs/test-run-table.tsx +127 -127
  245. package/templates/default/src/app/(base)/test-suites/create/page.tsx +3 -2
  246. package/templates/default/src/app/(base)/test-suites/modify/[id]/page.tsx +2 -1
  247. package/templates/default/src/app/(base)/test-suites/page.tsx +57 -21
  248. package/templates/default/src/app/(base)/test-suites/test-suite-form.tsx +16 -17
  249. package/templates/default/src/app/(base)/test-suites/test-suite-table-columns.tsx +2 -1
  250. package/templates/default/src/app/(base)/test-suites/test-suite-table.tsx +29 -29
  251. package/templates/default/src/app/(dashboard-components)/app-drawer.tsx +187 -187
  252. package/templates/default/src/app/(dashboard-components)/data-card-grid.tsx +12 -12
  253. package/templates/default/src/app/(dashboard-components)/data-card.tsx +26 -26
  254. package/templates/default/src/app/(dashboard-components)/execution-health-panel.tsx +56 -56
  255. package/templates/default/src/app/(dashboard-components)/ongoing-test-runs-card.tsx +87 -87
  256. package/templates/default/src/app/(dashboard-components)/quick-actions-drawer.tsx +44 -44
  257. package/templates/default/src/app/api/reports/steps/[stepId]/screenshot/route.ts +52 -0
  258. package/templates/default/src/app/api/test-runs/[runId]/download/route.ts +97 -34
  259. package/templates/default/src/app/api/test-runs/[runId]/logs/route.ts +4 -1
  260. package/templates/default/src/app/api/test-runs/[runId]/trace/[testCaseId]/route.ts +146 -147
  261. package/templates/default/src/app/globals.css +147 -147
  262. package/templates/default/src/app/layout.tsx +4 -0
  263. package/templates/default/src/app/page.tsx +2 -0
  264. package/templates/default/src/assets/icons/empty-tube.tsx +23 -23
  265. package/templates/default/src/assets/icons/tube-plus.tsx +29 -29
  266. package/templates/default/src/components/base-node.tsx +21 -21
  267. package/templates/default/src/components/chart/pie-chart.tsx +73 -73
  268. package/templates/default/src/components/data-extraction/locator-inspector.tsx +460 -460
  269. package/templates/default/src/components/data-state/empty-state.tsx +40 -40
  270. package/templates/default/src/components/data-visualization/info-card.tsx +70 -70
  271. package/templates/default/src/components/data-visualization/info-grid.tsx +22 -22
  272. package/templates/default/src/components/diagram/button-edge.tsx +54 -54
  273. package/templates/default/src/components/diagram/dynamic-parameters.tsx +474 -474
  274. package/templates/default/src/components/diagram/edit-header-option.tsx +36 -36
  275. package/templates/default/src/components/diagram/flow-diagram.tsx +470 -470
  276. package/templates/default/src/components/diagram/node-form.tsx +262 -262
  277. package/templates/default/src/components/diagram/options-header-node.tsx +57 -57
  278. package/templates/default/src/components/diagram/template-step-combobox.tsx +155 -155
  279. package/templates/default/src/components/form/error-message.tsx +7 -7
  280. package/templates/default/src/components/kokonutui/smooth-tab.tsx +453 -453
  281. package/templates/default/src/components/loading-skeleton/data-table/data-table-skeleton.tsx +30 -30
  282. package/templates/default/src/components/loading-skeleton/form/button-skeleton.tsx +8 -8
  283. package/templates/default/src/components/loading-skeleton/form/icon-button-skeleton.tsx +8 -8
  284. package/templates/default/src/components/loading-skeleton/form/text-input-skeleton.tsx +8 -8
  285. package/templates/default/src/components/loading-skeleton/visualization/table-skeleton.tsx +14 -14
  286. package/templates/default/src/components/logo.tsx +15 -15
  287. package/templates/default/src/components/navigation/command-badge.tsx +34 -34
  288. package/templates/default/src/components/navigation/command-chain-input.tsx +51 -51
  289. package/templates/default/src/components/navigation/entity-search-command.tsx +116 -116
  290. package/templates/default/src/components/navigation/nav-card.tsx +31 -31
  291. package/templates/default/src/components/navigation/nav-command.tsx +13 -0
  292. package/templates/default/src/components/navigation/nav-link.tsx +60 -60
  293. package/templates/default/src/components/navigation/nav-menu-card-deck.tsx +112 -112
  294. package/templates/default/src/components/node-header.tsx +159 -159
  295. package/templates/default/src/components/reports/test-case-logs-modal.tsx +310 -253
  296. package/templates/default/src/components/table/table-actions.tsx +172 -172
  297. package/templates/default/src/components/test-case/test-case-columns.tsx +76 -0
  298. package/templates/default/src/components/test-case/test-case-picker.tsx +244 -0
  299. package/templates/default/src/components/test-run/download-logs-button.tsx +92 -99
  300. package/templates/default/src/components/test-run/log-viewer.tsx +1 -14
  301. package/templates/default/src/components/test-run/test-run-details.tsx +15 -2
  302. package/templates/default/src/components/test-run/test-run-header.tsx +149 -149
  303. package/templates/default/src/components/test-run/view-report-button.tsx +102 -102
  304. package/templates/default/src/components/test-suite/test-suite-picker.tsx +444 -0
  305. package/templates/default/src/components/theme/mode-toggle.tsx +54 -54
  306. package/templates/default/src/components/theme/theme-provider.tsx +8 -8
  307. package/templates/default/src/components/typography/page-header-subtitle.tsx +7 -7
  308. package/templates/default/src/components/typography/page-header.tsx +7 -7
  309. package/templates/default/src/components/ui/alert-dialog.tsx +106 -106
  310. package/templates/default/src/components/ui/alert.tsx +43 -43
  311. package/templates/default/src/components/ui/avatar.tsx +40 -40
  312. package/templates/default/src/components/ui/badge.tsx +29 -29
  313. package/templates/default/src/components/ui/button.tsx +47 -47
  314. package/templates/default/src/components/ui/calendar.tsx +158 -158
  315. package/templates/default/src/components/ui/card.tsx +43 -43
  316. package/templates/default/src/components/ui/checkbox.tsx +28 -28
  317. package/templates/default/src/components/ui/command.tsx +135 -135
  318. package/templates/default/src/components/ui/data-table-column-header.tsx +61 -61
  319. package/templates/default/src/components/ui/data-table-pagination.tsx +87 -87
  320. package/templates/default/src/components/ui/data-table-view-options.tsx +50 -50
  321. package/templates/default/src/components/ui/data-table.tsx +261 -261
  322. package/templates/default/src/components/ui/dialog.tsx +97 -97
  323. package/templates/default/src/components/ui/dropdown-menu.tsx +182 -182
  324. package/templates/default/src/components/ui/input.tsx +22 -22
  325. package/templates/default/src/components/ui/kbd.tsx +28 -28
  326. package/templates/default/src/components/ui/label.tsx +19 -19
  327. package/templates/default/src/components/ui/loading.tsx +12 -12
  328. package/templates/default/src/components/ui/multi-select-with-preview.tsx +116 -116
  329. package/templates/default/src/components/ui/multi-select.tsx +142 -142
  330. package/templates/default/src/components/ui/navigation-menu.tsx +120 -120
  331. package/templates/default/src/components/ui/popover.tsx +33 -33
  332. package/templates/default/src/components/ui/progress.tsx +25 -25
  333. package/templates/default/src/components/ui/radio-group.tsx +44 -44
  334. package/templates/default/src/components/ui/scroll-area.tsx +40 -40
  335. package/templates/default/src/components/ui/select.tsx +151 -151
  336. package/templates/default/src/components/ui/separator.tsx +22 -22
  337. package/templates/default/src/components/ui/skeleton.tsx +7 -7
  338. package/templates/default/src/components/ui/table.tsx +76 -76
  339. package/templates/default/src/components/ui/tabs.tsx +55 -55
  340. package/templates/default/src/components/ui/textarea.tsx +21 -21
  341. package/templates/default/src/components/ui/toast.tsx +113 -113
  342. package/templates/default/src/components/ui/toaster.tsx +26 -26
  343. package/templates/default/src/components/user-prompt/delete-prompt.tsx +87 -87
  344. package/templates/default/src/config/db-config.ts +10 -10
  345. package/templates/default/src/constants/form-opts/diagram/node-form.ts +30 -30
  346. package/templates/default/src/constants/form-opts/environment-form-opts.ts +24 -24
  347. package/templates/default/src/constants/form-opts/locator-form-opts.ts +20 -20
  348. package/templates/default/src/constants/form-opts/locator-group-form-opts.ts +28 -28
  349. package/templates/default/src/constants/form-opts/module-form-opts.ts +21 -21
  350. package/templates/default/src/constants/form-opts/review-form-opts.ts +23 -23
  351. package/templates/default/src/constants/form-opts/tag-form-opts.ts +42 -42
  352. package/templates/default/src/constants/form-opts/template-selection-form-opts.ts +16 -16
  353. package/templates/default/src/constants/form-opts/template-step-group-form-opts.ts +24 -24
  354. package/templates/default/src/constants/form-opts/template-test-case-form-opts.ts +39 -39
  355. package/templates/default/src/constants/form-opts/template-test-step-form-opts.ts +36 -36
  356. package/templates/default/src/constants/form-opts/test-case-form-opts.ts +43 -43
  357. package/templates/default/src/constants/form-opts/test-run-form-opts.ts +5 -3
  358. package/templates/default/src/constants/form-opts/test-suite-form-opts.ts +24 -24
  359. package/templates/default/src/hooks/use-toast.ts +187 -187
  360. package/templates/default/src/lib/automation/paths.ts +42 -12
  361. package/templates/default/src/lib/automation/projection-service.ts +2 -1
  362. package/templates/default/src/lib/bidirectional-sync.ts +432 -432
  363. package/templates/default/src/lib/database-sync.ts +2 -7
  364. package/templates/default/src/lib/environment-file-utils.ts +184 -184
  365. package/templates/default/src/lib/executor/local-executor-adapter.ts +24 -25
  366. package/templates/default/src/lib/executor/types.ts +2 -2
  367. package/templates/default/src/lib/feature-file-generator.ts +5 -66
  368. package/templates/default/src/lib/gherkin-parser.ts +259 -259
  369. package/templates/default/src/lib/locator-group-file-utils.ts +307 -307
  370. package/templates/default/src/lib/locator-picker/session-manager.ts +452 -0
  371. package/templates/default/src/lib/locator-picker/suggestions.ts +124 -0
  372. package/templates/default/src/lib/metrics/metric-calculator.ts +5 -0
  373. package/templates/default/src/lib/module-hierarchy-builder.ts +205 -205
  374. package/templates/default/src/lib/path-helpers/module-path.ts +71 -71
  375. package/templates/default/src/lib/process/task-spawner.ts +39 -2
  376. package/templates/default/src/lib/sync/projected-feature-utils.ts +113 -0
  377. package/templates/default/src/lib/sync/sync-executor.ts +130 -0
  378. package/templates/default/src/lib/sync/sync-pending-counts.test.ts +239 -0
  379. package/templates/default/src/lib/sync/sync-pending-counts.ts +1358 -0
  380. package/templates/default/src/lib/sync/sync-registry.ts +149 -0
  381. package/templates/default/src/lib/tag-utils.ts +28 -0
  382. package/templates/default/src/lib/template-sync-utils.d.ts +6 -6
  383. package/templates/default/src/lib/template-sync-utils.js +46 -46
  384. package/templates/default/src/lib/template-sync-utils.ts +63 -63
  385. package/templates/default/src/lib/test-case-utils.ts +6 -6
  386. package/templates/default/src/lib/test-run/log-formatter.ts +83 -83
  387. package/templates/default/src/lib/test-run/matching.ts +117 -0
  388. package/templates/default/src/lib/test-run/process-manager.ts +2 -0
  389. package/templates/default/src/lib/test-run/report-parser.ts +352 -316
  390. package/templates/default/src/lib/test-run/test-run-executor.ts +13 -15
  391. package/templates/default/src/lib/test-run/winston-logger.ts +64 -66
  392. package/templates/default/src/lib/test-suite-identifier-service.ts +76 -0
  393. package/templates/default/src/lib/test-suite-utils.ts +6 -0
  394. package/templates/default/src/lib/transformers/gherkin-converter.ts +42 -42
  395. package/templates/default/src/lib/transformers/key-to-icon-transformer.tsx +95 -95
  396. package/templates/default/src/lib/transformers/template-test-case-converter.ts +160 -160
  397. package/templates/default/src/lib/utils/node-param-validation.ts +81 -81
  398. package/templates/default/src/lib/utils/template-step-file-generator.ts +104 -104
  399. package/templates/default/src/lib/utils/template-step-file-manager-intelligent.ts +0 -8
  400. package/templates/default/src/lib/utils/template-step-file-manager.ts +166 -166
  401. package/templates/default/src/lib/utils.ts +31 -31
  402. package/templates/default/src/types/diagram/diagram.ts +34 -34
  403. package/templates/default/src/types/diagram/template-step.ts +11 -11
  404. package/templates/default/src/types/executor/browser.type.ts +1 -1
  405. package/templates/default/src/types/form/actionHandler.ts +6 -6
  406. package/templates/default/src/types/locator/locator.type.ts +11 -11
  407. package/templates/default/src/types/locator-picker.ts +65 -0
  408. package/templates/default/src/types/step/step.type.ts +1 -1
  409. package/templates/default/src/types/table/data-table.ts +6 -6
  410. package/templates/default/src/types/test-case-picker.ts +6 -0
  411. package/templates/default/src/types/test-suite-picker.ts +18 -0
  412. package/templates/default/tailwind.config.ts +62 -62
  413. package/templates/default/tsconfig.json +4 -1
  414. package/templates/default/appraisejs.config.json +0 -1
@@ -1,253 +1,310 @@
1
- 'use client'
2
-
3
- import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle } from '@/components/ui/dialog'
4
- import { Badge } from '@/components/ui/badge'
5
- import { Separator } from '@/components/ui/separator'
6
- import { StepStatus, ReportScenario } from '@prisma/client'
7
- import { CheckCircle, XCircle, Clock, AlertCircle } from 'lucide-react'
8
- import { ScrollArea } from '../ui/scroll-area'
9
-
10
- /** Minimal shape so both full Prisma and report-table select types are accepted */
11
- type ReportScenarioWithDetails = ReportScenario & {
12
- tags: Array<{ tagName: string }>
13
- steps: Array<{
14
- id: string
15
- keyword: string
16
- name: string
17
- status: StepStatus
18
- duration: string
19
- errorMessage: string | null
20
- errorTrace: string | null
21
- order: number
22
- matchLocation?: string | null
23
- }>
24
- hooks: Array<{
25
- id: string
26
- keyword: string
27
- status: StepStatus
28
- duration: string
29
- errorMessage: string | null
30
- errorTrace: string | null
31
- }>
32
- }
33
-
34
- interface TestCaseLogsModalProps {
35
- open: boolean
36
- onOpenChange: (open: boolean) => void
37
- reportScenario: ReportScenarioWithDetails | null
38
- }
39
-
40
- const stepStatusToBadge = (status: StepStatus) => {
41
- switch (status) {
42
- case StepStatus.PASSED:
43
- return (
44
- <Badge
45
- variant="outline"
46
- className="flex items-center gap-1 rounded-xl border-green-700 bg-green-700/10 py-0.5 text-xs text-green-500"
47
- >
48
- <CheckCircle className="h-3 w-3" />
49
- PASSED
50
- </Badge>
51
- )
52
- case StepStatus.FAILED:
53
- return (
54
- <Badge
55
- variant="outline"
56
- className="flex items-center gap-1 rounded-xl border-red-700 bg-red-700/10 py-0.5 text-xs text-red-500"
57
- >
58
- <XCircle className="h-3 w-3" />
59
- FAILED
60
- </Badge>
61
- )
62
- case StepStatus.SKIPPED:
63
- return (
64
- <Badge
65
- variant="outline"
66
- className="flex items-center gap-1 rounded-xl border-gray-700 bg-gray-700/10 py-0.5 text-xs text-gray-500"
67
- >
68
- <Clock className="h-3 w-3" />
69
- SKIPPED
70
- </Badge>
71
- )
72
- default:
73
- return (
74
- <Badge
75
- variant="outline"
76
- className="flex items-center gap-1 rounded-xl border-gray-700 bg-gray-700/10 py-0.5 text-xs text-gray-500"
77
- >
78
- {status}
79
- </Badge>
80
- )
81
- }
82
- }
83
-
84
- const formatDuration = (duration: string) => {
85
- const durationNs = Number(duration)
86
- if (isNaN(durationNs)) return '-'
87
- const durationMs = Math.round(durationNs / 1000000)
88
- if (durationMs < 1000) {
89
- return `${durationMs}ms`
90
- }
91
- const seconds = Math.floor(durationMs / 1000)
92
- const milliseconds = durationMs % 1000
93
- return `${seconds}.${String(milliseconds).padStart(3, '0')}s`
94
- }
95
-
96
- const formatKeyword = (keyword: string) => {
97
- return keyword.charAt(0) + keyword.slice(1).toLowerCase()
98
- }
99
-
100
- export function TestCaseLogsModal({ open, onOpenChange, reportScenario }: TestCaseLogsModalProps) {
101
- if (!reportScenario) {
102
- return null
103
- }
104
-
105
- // Sort steps by order
106
- const sortedSteps = [...reportScenario.steps].sort((a, b) => a.order - b.order)
107
-
108
- return (
109
- <Dialog open={open} onOpenChange={onOpenChange}>
110
- <DialogContent className="flex max-h-[90vh] max-w-4xl flex-col p-0">
111
- <DialogHeader className="flex-shrink-0 px-6 pt-6">
112
- <DialogTitle className="text-xl font-semibold">{reportScenario.name}</DialogTitle>
113
- {reportScenario.description && (
114
- <DialogDescription className="text-sm text-muted-foreground">
115
- {reportScenario.description}
116
- </DialogDescription>
117
- )}
118
- </DialogHeader>
119
-
120
- <ScrollArea className="h-[calc(90vh-120px)] pr-4">
121
- <div className="px-6 pb-6">
122
- <div className="space-y-6">
123
- {/* Tags */}
124
- {reportScenario.tags.length > 0 && (
125
- <div>
126
- <h4 className="mb-2 text-sm font-medium">Tags</h4>
127
- <div className="flex flex-wrap gap-1">
128
- {reportScenario.tags.map((tag, _index) => (
129
- <Badge key={_index} variant="outline">
130
- {tag.tagName}
131
- </Badge>
132
- ))}
133
- </div>
134
- </div>
135
- )}
136
-
137
- {/* Steps */}
138
- <div>
139
- <h4 className="mb-3 text-sm font-medium">Steps</h4>
140
- <div className="space-y-3">
141
- {sortedSteps.length > 0 ? (
142
- sortedSteps.map((step, _index) => (
143
- <div key={step.id} className="space-y-2 rounded-lg border p-3">
144
- <div className="flex items-start justify-between gap-2">
145
- <div className="flex-1">
146
- <div className="mb-1 flex items-center gap-2">
147
- <span className="text-sm font-medium text-muted-foreground">
148
- {formatKeyword(step.keyword)}
149
- </span>
150
- <span className="text-sm">{step.name}</span>
151
- </div>
152
- {step.matchLocation && (
153
- <div className="mt-1 text-xs text-muted-foreground">{step.matchLocation}</div>
154
- )}
155
- </div>
156
- <div className="flex items-center gap-2">
157
- {stepStatusToBadge(step.status)}
158
- <span className="text-xs text-muted-foreground">{formatDuration(step.duration)}</span>
159
- </div>
160
- </div>
161
- {step.status === StepStatus.FAILED && (
162
- <div className="mt-2 space-y-2">
163
- {step.errorMessage && (
164
- <div className="rounded border border-red-800/50 bg-red-950/20 p-2">
165
- <div className="mb-1 flex items-center gap-2">
166
- <AlertCircle className="h-4 w-4 text-red-500" />
167
- <span className="text-sm font-medium text-red-400">Error Message</span>
168
- </div>
169
- <pre className="whitespace-pre-wrap break-words text-xs text-red-300">
170
- {step.errorMessage}
171
- </pre>
172
- </div>
173
- )}
174
- {step.errorTrace && (
175
- <div className="rounded border border-red-800/50 bg-red-950/20 p-2">
176
- <div className="mb-1 flex items-center gap-2">
177
- <AlertCircle className="h-4 w-4 text-red-500" />
178
- <span className="text-sm font-medium text-red-400">Error Trace</span>
179
- </div>
180
- <pre className="whitespace-pre-wrap break-words font-mono text-xs text-red-300">
181
- {step.errorTrace}
182
- </pre>
183
- </div>
184
- )}
185
- </div>
186
- )}
187
- </div>
188
- ))
189
- ) : (
190
- <div className="text-sm text-muted-foreground">No steps recorded</div>
191
- )}
192
- </div>
193
- </div>
194
-
195
- {/* Hooks */}
196
- {reportScenario.hooks.length > 0 && (
197
- <div>
198
- <Separator className="my-4" />
199
- <h4 className="mb-3 text-sm font-medium">Hooks</h4>
200
- <div className="space-y-3">
201
- {reportScenario.hooks.map((hook, _index) => (
202
- <div key={hook.id} className="space-y-2 rounded-lg border p-3">
203
- <div className="flex items-start justify-between gap-2">
204
- <div className="flex-1">
205
- <div className="mb-1 flex items-center gap-2">
206
- <span className="text-sm font-medium text-muted-foreground">
207
- {formatKeyword(hook.keyword)} Hook
208
- </span>
209
- </div>
210
- </div>
211
- <div className="flex items-center gap-2">
212
- {stepStatusToBadge(hook.status)}
213
- <span className="text-xs text-muted-foreground">{formatDuration(hook.duration)}</span>
214
- </div>
215
- </div>
216
- {hook.status === StepStatus.FAILED && (
217
- <div className="mt-2 space-y-2">
218
- {hook.errorMessage && (
219
- <div className="rounded border border-red-800/50 bg-red-950/20 p-2">
220
- <div className="mb-1 flex items-center gap-2">
221
- <AlertCircle className="h-4 w-4 text-red-500" />
222
- <span className="text-sm font-medium text-red-400">Error Message</span>
223
- </div>
224
- <pre className="whitespace-pre-wrap break-words text-xs text-red-300">
225
- {hook.errorMessage}
226
- </pre>
227
- </div>
228
- )}
229
- {hook.errorTrace && (
230
- <div className="rounded border border-red-800/50 bg-red-950/20 p-2">
231
- <div className="mb-1 flex items-center gap-2">
232
- <AlertCircle className="h-4 w-4 text-red-500" />
233
- <span className="text-sm font-medium text-red-400">Error Trace</span>
234
- </div>
235
- <pre className="whitespace-pre-wrap break-words font-mono text-xs text-red-300">
236
- {hook.errorTrace}
237
- </pre>
238
- </div>
239
- )}
240
- </div>
241
- )}
242
- </div>
243
- ))}
244
- </div>
245
- </div>
246
- )}
247
- </div>
248
- </div>
249
- </ScrollArea>
250
- </DialogContent>
251
- </Dialog>
252
- )
253
- }
1
+ 'use client'
2
+
3
+ import { useState } from 'react'
4
+ import Image from 'next/image'
5
+ import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle } from '@/components/ui/dialog'
6
+ import { Badge } from '@/components/ui/badge'
7
+ import { Separator } from '@/components/ui/separator'
8
+ import { StepStatus, ReportScenario } from '@prisma/client'
9
+ import { CheckCircle, XCircle, Clock, AlertCircle } from 'lucide-react'
10
+ import { ScrollArea } from '../ui/scroll-area'
11
+ import { Button } from '@/components/ui/button'
12
+
13
+ /** Minimal shape so both full Prisma and report-table select types are accepted */
14
+ type ReportScenarioWithDetails = ReportScenario & {
15
+ tags: Array<{ tagName: string }>
16
+ steps: Array<{
17
+ id: string
18
+ keyword: string
19
+ name: string
20
+ status: StepStatus
21
+ duration: string
22
+ errorMessage: string | null
23
+ errorTrace: string | null
24
+ screenshotPath?: string | null
25
+ order: number
26
+ matchLocation?: string | null
27
+ }>
28
+ hooks: Array<{
29
+ id: string
30
+ keyword: string
31
+ status: StepStatus
32
+ duration: string
33
+ errorMessage: string | null
34
+ errorTrace: string | null
35
+ }>
36
+ }
37
+
38
+ interface TestCaseLogsModalProps {
39
+ open: boolean
40
+ onOpenChange: (open: boolean) => void
41
+ reportScenario: ReportScenarioWithDetails | null
42
+ }
43
+
44
+ const stepStatusToBadge = (status: StepStatus) => {
45
+ switch (status) {
46
+ case StepStatus.PASSED:
47
+ return (
48
+ <Badge
49
+ variant="outline"
50
+ className="flex items-center gap-1 rounded-xl border-green-700 bg-green-700/10 py-0.5 text-xs text-green-500"
51
+ >
52
+ <CheckCircle className="h-3 w-3" />
53
+ PASSED
54
+ </Badge>
55
+ )
56
+ case StepStatus.FAILED:
57
+ return (
58
+ <Badge
59
+ variant="outline"
60
+ className="flex items-center gap-1 rounded-xl border-red-700 bg-red-700/10 py-0.5 text-xs text-red-500"
61
+ >
62
+ <XCircle className="h-3 w-3" />
63
+ FAILED
64
+ </Badge>
65
+ )
66
+ case StepStatus.SKIPPED:
67
+ return (
68
+ <Badge
69
+ variant="outline"
70
+ className="flex items-center gap-1 rounded-xl border-gray-700 bg-gray-700/10 py-0.5 text-xs text-gray-500"
71
+ >
72
+ <Clock className="h-3 w-3" />
73
+ SKIPPED
74
+ </Badge>
75
+ )
76
+ default:
77
+ return (
78
+ <Badge
79
+ variant="outline"
80
+ className="flex items-center gap-1 rounded-xl border-gray-700 bg-gray-700/10 py-0.5 text-xs text-gray-500"
81
+ >
82
+ {status}
83
+ </Badge>
84
+ )
85
+ }
86
+ }
87
+
88
+ const formatDuration = (duration: string) => {
89
+ const durationNs = Number(duration)
90
+ if (isNaN(durationNs)) return '-'
91
+ const durationMs = Math.round(durationNs / 1000000)
92
+ if (durationMs < 1000) {
93
+ return `${durationMs}ms`
94
+ }
95
+ const seconds = Math.floor(durationMs / 1000)
96
+ const milliseconds = durationMs % 1000
97
+ return `${seconds}.${String(milliseconds).padStart(3, '0')}s`
98
+ }
99
+
100
+ const formatKeyword = (keyword: string) => {
101
+ return keyword.charAt(0) + keyword.slice(1).toLowerCase()
102
+ }
103
+
104
+ export function TestCaseLogsModal({ open, onOpenChange, reportScenario }: TestCaseLogsModalProps) {
105
+ const [expandedScreenshot, setExpandedScreenshot] = useState<{ stepId: string; stepName: string } | null>(null)
106
+
107
+ if (!reportScenario) {
108
+ return null
109
+ }
110
+
111
+ // Sort steps by order
112
+ const sortedSteps = [...reportScenario.steps].sort((a, b) => a.order - b.order)
113
+
114
+ return (
115
+ <>
116
+ <Dialog open={open} onOpenChange={onOpenChange}>
117
+ <DialogContent className="flex max-h-[90vh] max-w-4xl flex-col p-0">
118
+ <DialogHeader className="flex-shrink-0 px-6 pt-6">
119
+ <DialogTitle className="text-xl font-semibold">{reportScenario.name}</DialogTitle>
120
+ {reportScenario.description && (
121
+ <DialogDescription className="text-sm text-muted-foreground">
122
+ {reportScenario.description}
123
+ </DialogDescription>
124
+ )}
125
+ </DialogHeader>
126
+
127
+ <ScrollArea className="h-[calc(90vh-120px)] pr-4">
128
+ <div className="px-6 pb-6">
129
+ <div className="space-y-6">
130
+ {/* Tags */}
131
+ {reportScenario.tags.length > 0 && (
132
+ <div>
133
+ <h4 className="mb-2 text-sm font-medium">Tags</h4>
134
+ <div className="flex flex-wrap gap-1">
135
+ {reportScenario.tags.map(tag => (
136
+ <Badge key={tag.tagName} variant="outline">
137
+ {tag.tagName}
138
+ </Badge>
139
+ ))}
140
+ </div>
141
+ </div>
142
+ )}
143
+
144
+ {/* Steps */}
145
+ <div>
146
+ <h4 className="mb-3 text-sm font-medium">Steps</h4>
147
+ <div className="space-y-3">
148
+ {sortedSteps.length > 0 ? (
149
+ sortedSteps.map(step => (
150
+ <div key={step.id} className="space-y-2 rounded-lg border p-3">
151
+ <div className="flex items-start justify-between gap-2">
152
+ <div className="flex-1">
153
+ <div className="mb-1 flex items-center gap-2">
154
+ <span className="text-sm font-medium text-muted-foreground">
155
+ {formatKeyword(step.keyword)}
156
+ </span>
157
+ <span className="text-sm">{step.name}</span>
158
+ </div>
159
+ {step.matchLocation && (
160
+ <div className="mt-1 text-xs text-muted-foreground">{step.matchLocation}</div>
161
+ )}
162
+ </div>
163
+ <div className="flex items-center gap-2">
164
+ {stepStatusToBadge(step.status)}
165
+ <span className="text-xs text-muted-foreground">{formatDuration(step.duration)}</span>
166
+ </div>
167
+ </div>
168
+ {step.status === StepStatus.FAILED && (
169
+ <div className="mt-2 space-y-2">
170
+ {step.errorMessage && (
171
+ <div className="rounded border border-red-800/50 bg-red-950/20 p-2">
172
+ <div className="mb-1 flex items-center gap-2">
173
+ <AlertCircle className="h-4 w-4 text-red-500" />
174
+ <span className="text-sm font-medium text-red-400">Error Message</span>
175
+ </div>
176
+ <pre className="whitespace-pre-wrap break-words text-xs text-red-300">
177
+ {step.errorMessage}
178
+ </pre>
179
+ </div>
180
+ )}
181
+ {step.errorTrace && (
182
+ <div className="rounded border border-red-800/50 bg-red-950/20 p-2">
183
+ <div className="mb-1 flex items-center gap-2">
184
+ <AlertCircle className="h-4 w-4 text-red-500" />
185
+ <span className="text-sm font-medium text-red-400">Error Trace</span>
186
+ </div>
187
+ <pre className="whitespace-pre-wrap break-words font-mono text-xs text-red-300">
188
+ {step.errorTrace}
189
+ </pre>
190
+ </div>
191
+ )}
192
+ {step.screenshotPath && (
193
+ <div className="rounded border border-red-800/50 bg-red-950/20 p-2">
194
+ <div className="mb-2 flex items-center justify-between gap-2">
195
+ <span className="text-sm font-medium text-red-400">Failure Screenshot</span>
196
+ <Button
197
+ type="button"
198
+ size="sm"
199
+ variant="secondary"
200
+ onClick={() => setExpandedScreenshot({ stepId: step.id, stepName: step.name })}
201
+ >
202
+ Expand
203
+ </Button>
204
+ </div>
205
+ <button
206
+ type="button"
207
+ className="block w-full overflow-hidden rounded-md border border-red-900/60"
208
+ onClick={() => setExpandedScreenshot({ stepId: step.id, stepName: step.name })}
209
+ >
210
+ <Image
211
+ src={`/api/reports/steps/${step.id}/screenshot`}
212
+ alt={`Failure screenshot for step ${step.name}`}
213
+ width={1280}
214
+ height={720}
215
+ unoptimized
216
+ className="max-h-64 w-full object-cover"
217
+ loading="lazy"
218
+ />
219
+ </button>
220
+ </div>
221
+ )}
222
+ </div>
223
+ )}
224
+ </div>
225
+ ))
226
+ ) : (
227
+ <div className="text-sm text-muted-foreground">No steps recorded</div>
228
+ )}
229
+ </div>
230
+ </div>
231
+
232
+ {/* Hooks */}
233
+ {reportScenario.hooks.length > 0 && (
234
+ <div>
235
+ <Separator className="my-4" />
236
+ <h4 className="mb-3 text-sm font-medium">Hooks</h4>
237
+ <div className="space-y-3">
238
+ {reportScenario.hooks.map(hook => (
239
+ <div key={hook.id} className="space-y-2 rounded-lg border p-3">
240
+ <div className="flex items-start justify-between gap-2">
241
+ <div className="flex-1">
242
+ <div className="mb-1 flex items-center gap-2">
243
+ <span className="text-sm font-medium text-muted-foreground">
244
+ {formatKeyword(hook.keyword)} Hook
245
+ </span>
246
+ </div>
247
+ </div>
248
+ <div className="flex items-center gap-2">
249
+ {stepStatusToBadge(hook.status)}
250
+ <span className="text-xs text-muted-foreground">{formatDuration(hook.duration)}</span>
251
+ </div>
252
+ </div>
253
+ {hook.status === StepStatus.FAILED && (
254
+ <div className="mt-2 space-y-2">
255
+ {hook.errorMessage && (
256
+ <div className="rounded border border-red-800/50 bg-red-950/20 p-2">
257
+ <div className="mb-1 flex items-center gap-2">
258
+ <AlertCircle className="h-4 w-4 text-red-500" />
259
+ <span className="text-sm font-medium text-red-400">Error Message</span>
260
+ </div>
261
+ <pre className="whitespace-pre-wrap break-words text-xs text-red-300">
262
+ {hook.errorMessage}
263
+ </pre>
264
+ </div>
265
+ )}
266
+ {hook.errorTrace && (
267
+ <div className="rounded border border-red-800/50 bg-red-950/20 p-2">
268
+ <div className="mb-1 flex items-center gap-2">
269
+ <AlertCircle className="h-4 w-4 text-red-500" />
270
+ <span className="text-sm font-medium text-red-400">Error Trace</span>
271
+ </div>
272
+ <pre className="whitespace-pre-wrap break-words font-mono text-xs text-red-300">
273
+ {hook.errorTrace}
274
+ </pre>
275
+ </div>
276
+ )}
277
+ </div>
278
+ )}
279
+ </div>
280
+ ))}
281
+ </div>
282
+ </div>
283
+ )}
284
+ </div>
285
+ </div>
286
+ </ScrollArea>
287
+ </DialogContent>
288
+ </Dialog>
289
+
290
+ <Dialog open={!!expandedScreenshot} onOpenChange={nextOpen => !nextOpen && setExpandedScreenshot(null)}>
291
+ <DialogContent className="max-w-5xl p-4">
292
+ <DialogHeader>
293
+ <DialogTitle>{expandedScreenshot?.stepName ?? 'Failure Screenshot'}</DialogTitle>
294
+ <DialogDescription>Captured from the failed scenario step.</DialogDescription>
295
+ </DialogHeader>
296
+ {expandedScreenshot && (
297
+ <Image
298
+ src={`/api/reports/steps/${expandedScreenshot.stepId}/screenshot`}
299
+ alt={`Failure screenshot for step ${expandedScreenshot.stepName}`}
300
+ width={1600}
301
+ height={900}
302
+ unoptimized
303
+ className="max-h-[75vh] w-full rounded-md border object-contain"
304
+ />
305
+ )}
306
+ </DialogContent>
307
+ </Dialog>
308
+ </>
309
+ )
310
+ }