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,352 +1,352 @@
1
- import { readFile } from 'fs/promises'
2
- import { StepStatus, StepKeyword } from '@prisma/client'
3
-
4
- const SCREENSHOT_ATTACHMENT_MEDIA_TYPE = 'application/vnd.appraisejs.report-step-screenshot+json'
5
-
6
- /**
7
- * Parsed report structure matching cucumber.json format
8
- */
9
- export interface ParsedReport {
10
- features: Array<{
11
- name: string
12
- description: string
13
- uri: string
14
- line: number
15
- keyword: string
16
- tags: Array<{ name: string; line: number }>
17
- scenarios: Array<{
18
- name: string
19
- description: string
20
- line: number
21
- keyword: string
22
- type: string
23
- cucumberId: string
24
- tags: Array<{ name: string; line: number }>
25
- steps: Array<{
26
- keyword: string
27
- line: number | null
28
- name: string
29
- matchLocation?: string
30
- status: string
31
- duration: number
32
- errorMessage?: string
33
- errorTrace?: string
34
- screenshotPath?: string
35
- hidden: boolean
36
- order: number
37
- }>
38
- hooks: Array<{
39
- keyword: string
40
- status: string
41
- duration: number
42
- errorMessage?: string
43
- errorTrace?: string
44
- hidden: boolean
45
- }>
46
- }>
47
- }>
48
- }
49
-
50
- /**
51
- * Cucumber JSON report structure (as received from cucumber-js)
52
- */
53
- interface CucumberJsonFeature {
54
- description: string
55
- elements: Array<{
56
- description: string
57
- id: string
58
- keyword: string
59
- line: number
60
- name: string
61
- steps: Array<{
62
- keyword: string
63
- line?: number
64
- name?: string
65
- hidden?: boolean
66
- match?: {
67
- location: string
68
- }
69
- result?: {
70
- status: string
71
- duration?: number
72
- error_message?: string
73
- }
74
- embeddings?: Array<{
75
- data?: string
76
- mime_type?: string
77
- }>
78
- }>
79
- tags: Array<{
80
- name: string
81
- line: number
82
- }>
83
- type: string
84
- }>
85
- id: string
86
- line: number
87
- keyword: string
88
- name: string
89
- tags: Array<{
90
- name: string
91
- line: number
92
- }>
93
- uri: string
94
- }
95
-
96
- function extractScreenshotPath(
97
- embeddings: Array<{ data?: string; mime_type?: string }> | undefined,
98
- ): string | undefined {
99
- const screenshotAttachment = embeddings?.find(embedding => embedding.mime_type === SCREENSHOT_ATTACHMENT_MEDIA_TYPE)
100
-
101
- if (!screenshotAttachment?.data) {
102
- return undefined
103
- }
104
-
105
- const parsePayload = (payload: string): string | undefined => {
106
- try {
107
- const parsedPayload = JSON.parse(payload) as { screenshotPath?: unknown }
108
- return typeof parsedPayload.screenshotPath === 'string' ? parsedPayload.screenshotPath : undefined
109
- } catch {
110
- return undefined
111
- }
112
- }
113
-
114
- const directPayload = parsePayload(screenshotAttachment.data)
115
- if (directPayload) {
116
- return directPayload
117
- }
118
-
119
- const decodedPayload = Buffer.from(screenshotAttachment.data, 'base64').toString('utf8')
120
- return parsePayload(decodedPayload)
121
- }
122
-
123
- /**
124
- * Maps cucumber step status to Prisma StepStatus enum
125
- */
126
- function mapStepStatus(status: string): StepStatus {
127
- const upperStatus = status.toUpperCase()
128
- switch (upperStatus) {
129
- case 'PASSED':
130
- return StepStatus.PASSED
131
- case 'FAILED':
132
- return StepStatus.FAILED
133
- case 'SKIPPED':
134
- return StepStatus.SKIPPED
135
- case 'PENDING':
136
- return StepStatus.PENDING
137
- case 'UNDEFINED':
138
- return StepStatus.UNDEFINED
139
- default:
140
- return StepStatus.PENDING
141
- }
142
- }
143
-
144
- /**
145
- * Maps cucumber step keyword to Prisma StepKeyword enum
146
- */
147
- function mapStepKeyword(keyword: string): StepKeyword {
148
- const trimmedKeyword = keyword.trim()
149
- const upperKeyword = trimmedKeyword.toUpperCase()
150
- switch (upperKeyword) {
151
- case 'GIVEN':
152
- return StepKeyword.GIVEN
153
- case 'WHEN':
154
- return StepKeyword.WHEN
155
- case 'THEN':
156
- return StepKeyword.THEN
157
- case 'AND':
158
- return StepKeyword.AND
159
- case 'BUT':
160
- return StepKeyword.BUT
161
- case 'BEFORE':
162
- return StepKeyword.BEFORE
163
- case 'AFTER':
164
- return StepKeyword.AFTER
165
- default:
166
- // Default to GIVEN for unknown keywords
167
- return StepKeyword.GIVEN
168
- }
169
- }
170
-
171
- /**
172
- * Separates error message from stack trace
173
- * Cucumber's error_message typically contains both the error message and stack trace
174
- * The stack trace usually starts with "at" or contains file paths
175
- *
176
- * @param errorMessage - The full error message from Cucumber
177
- * @returns Object with separated message and trace
178
- */
179
- function separateErrorMessageAndTrace(errorMessage: string | undefined): {
180
- message: string | undefined
181
- trace: string | undefined
182
- } {
183
- if (!errorMessage) {
184
- return { message: undefined, trace: undefined }
185
- }
186
-
187
- // Look for common stack trace indicators
188
- // Stack traces typically start with "at", " at", or contain file paths with line numbers
189
- const stackTracePatterns = [
190
- /\n\s*at\s/, // "at" at the start of a line (with optional whitespace)
191
- /\n\s+at\s/, // "at" with leading whitespace
192
- /Error:\s*$/m, // Error: at end of line (message ends, trace starts)
193
- ]
194
-
195
- // Find the first occurrence of a stack trace pattern
196
- let splitIndex = -1
197
- for (const pattern of stackTracePatterns) {
198
- const match = errorMessage.match(pattern)
199
- if (match && match.index !== undefined) {
200
- // If we find "at" pattern, split before it (include the newline before "at")
201
- // If we find "Error:" pattern, split after it
202
- if (pattern.source.includes('Error:')) {
203
- splitIndex = match.index + match[0].length
204
- } else {
205
- splitIndex = match.index
206
- }
207
- break
208
- }
209
- }
210
-
211
- // If no stack trace pattern found, check if it looks like just a message (short, no file paths)
212
- if (splitIndex === -1) {
213
- // Check if it contains file paths (common in stack traces)
214
- const hasFilePath = /[\/\\][\w\-\.]+:\d+/.test(errorMessage)
215
- if (hasFilePath && errorMessage.length > 200) {
216
- // Likely contains a trace, try to find where message ends
217
- // Usually the first few lines are the message, rest is trace
218
- const lines = errorMessage.split('\n')
219
- // Look for the first line that starts with whitespace and "at" or contains a file path
220
- for (let i = 0; i < lines.length; i++) {
221
- if (/^\s*at\s/.test(lines[i]) || /[\/\\][\w\-\.]+:\d+/.test(lines[i])) {
222
- splitIndex = errorMessage.indexOf(lines[i])
223
- break
224
- }
225
- }
226
- }
227
- }
228
-
229
- if (splitIndex > 0) {
230
- const message = errorMessage.substring(0, splitIndex).trim()
231
- const trace = errorMessage.substring(splitIndex).trim()
232
- return {
233
- message: message || undefined,
234
- trace: trace || undefined,
235
- }
236
- }
237
-
238
- // If we can't separate them, treat the whole thing as the message
239
- // and leave trace as undefined (better than duplicating)
240
- return {
241
- message: errorMessage.trim() || undefined,
242
- trace: undefined,
243
- }
244
- }
245
-
246
- /**
247
- * Parses a cucumber.json report file into a structured ParsedReport object
248
- *
249
- * @param reportPath - Path to the cucumber.json file
250
- * @returns Parsed report structure
251
- * @throws Error if file cannot be read or parsed
252
- */
253
- export async function parseCucumberReport(reportPath: string): Promise<ParsedReport> {
254
- try {
255
- // Read the report file
256
- const fileContent = await readFile(reportPath, 'utf-8')
257
- const cucumberData: CucumberJsonFeature[] = JSON.parse(fileContent)
258
-
259
- // Parse features
260
- const features = cucumberData.map(feature => {
261
- // Separate steps into regular steps and hooks
262
- const scenarios = feature.elements.map(element => {
263
- const steps: ParsedReport['features'][0]['scenarios'][0]['steps'] = []
264
- const hooks: ParsedReport['features'][0]['scenarios'][0]['hooks'] = []
265
-
266
- element.steps.forEach((step, index) => {
267
- const isHook = step.keyword === 'Before' || step.keyword === 'After'
268
- const stepStatus = step.result?.status || 'pending'
269
- const duration = step.result?.duration || 0
270
-
271
- // Separate error message from stack trace
272
- const { message: errorMessage, trace: errorTrace } = separateErrorMessageAndTrace(step.result?.error_message)
273
- const screenshotPath = extractScreenshotPath(step.embeddings)
274
-
275
- if (isHook) {
276
- hooks.push({
277
- keyword: step.keyword,
278
- status: stepStatus,
279
- duration,
280
- errorMessage,
281
- errorTrace,
282
- hidden: step.hidden || false,
283
- })
284
- } else {
285
- steps.push({
286
- keyword: step.keyword.trim(),
287
- line: step.line || null,
288
- name: step.name || '',
289
- matchLocation: step.match?.location,
290
- status: stepStatus,
291
- duration,
292
- errorMessage,
293
- errorTrace,
294
- screenshotPath,
295
- hidden: step.hidden || false,
296
- order: index,
297
- })
298
- }
299
- })
300
-
301
- return {
302
- name: element.name,
303
- description: element.description || '',
304
- line: element.line,
305
- keyword: element.keyword,
306
- type: element.type,
307
- cucumberId: element.id,
308
- tags: element.tags.map(tag => ({
309
- name: tag.name,
310
- line: tag.line,
311
- })),
312
- steps,
313
- hooks,
314
- }
315
- })
316
-
317
- return {
318
- name: feature.name,
319
- description: feature.description || '',
320
- uri: feature.uri,
321
- line: feature.line,
322
- keyword: feature.keyword,
323
- tags: feature.tags.map(tag => ({
324
- name: tag.name,
325
- line: tag.line,
326
- })),
327
- scenarios,
328
- }
329
- })
330
-
331
- return { features }
332
- } catch (error) {
333
- if (error instanceof Error) {
334
- throw new Error(`Failed to parse cucumber report at ${reportPath}: ${error.message}`)
335
- }
336
- throw new Error(`Failed to parse cucumber report at ${reportPath}: Unknown error`)
337
- }
338
- }
339
-
340
- /**
341
- * Helper function to convert parsed step status to Prisma enum
342
- */
343
- export function getStepStatusEnum(status: string): StepStatus {
344
- return mapStepStatus(status)
345
- }
346
-
347
- /**
348
- * Helper function to convert parsed step keyword to Prisma enum
349
- */
350
- export function getStepKeywordEnum(keyword: string): StepKeyword {
351
- return mapStepKeyword(keyword)
352
- }
1
+ import { readFile } from 'fs/promises'
2
+ import { StepStatus, StepKeyword } from '@prisma/client'
3
+
4
+ const SCREENSHOT_ATTACHMENT_MEDIA_TYPE = 'application/vnd.appraisejs.report-step-screenshot+json'
5
+
6
+ /**
7
+ * Parsed report structure matching cucumber.json format
8
+ */
9
+ export interface ParsedReport {
10
+ features: Array<{
11
+ name: string
12
+ description: string
13
+ uri: string
14
+ line: number
15
+ keyword: string
16
+ tags: Array<{ name: string; line: number }>
17
+ scenarios: Array<{
18
+ name: string
19
+ description: string
20
+ line: number
21
+ keyword: string
22
+ type: string
23
+ cucumberId: string
24
+ tags: Array<{ name: string; line: number }>
25
+ steps: Array<{
26
+ keyword: string
27
+ line: number | null
28
+ name: string
29
+ matchLocation?: string
30
+ status: string
31
+ duration: number
32
+ errorMessage?: string
33
+ errorTrace?: string
34
+ screenshotPath?: string
35
+ hidden: boolean
36
+ order: number
37
+ }>
38
+ hooks: Array<{
39
+ keyword: string
40
+ status: string
41
+ duration: number
42
+ errorMessage?: string
43
+ errorTrace?: string
44
+ hidden: boolean
45
+ }>
46
+ }>
47
+ }>
48
+ }
49
+
50
+ /**
51
+ * Cucumber JSON report structure (as received from cucumber-js)
52
+ */
53
+ interface CucumberJsonFeature {
54
+ description: string
55
+ elements: Array<{
56
+ description: string
57
+ id: string
58
+ keyword: string
59
+ line: number
60
+ name: string
61
+ steps: Array<{
62
+ keyword: string
63
+ line?: number
64
+ name?: string
65
+ hidden?: boolean
66
+ match?: {
67
+ location: string
68
+ }
69
+ result?: {
70
+ status: string
71
+ duration?: number
72
+ error_message?: string
73
+ }
74
+ embeddings?: Array<{
75
+ data?: string
76
+ mime_type?: string
77
+ }>
78
+ }>
79
+ tags: Array<{
80
+ name: string
81
+ line: number
82
+ }>
83
+ type: string
84
+ }>
85
+ id: string
86
+ line: number
87
+ keyword: string
88
+ name: string
89
+ tags: Array<{
90
+ name: string
91
+ line: number
92
+ }>
93
+ uri: string
94
+ }
95
+
96
+ function extractScreenshotPath(
97
+ embeddings: Array<{ data?: string; mime_type?: string }> | undefined,
98
+ ): string | undefined {
99
+ const screenshotAttachment = embeddings?.find(embedding => embedding.mime_type === SCREENSHOT_ATTACHMENT_MEDIA_TYPE)
100
+
101
+ if (!screenshotAttachment?.data) {
102
+ return undefined
103
+ }
104
+
105
+ const parsePayload = (payload: string): string | undefined => {
106
+ try {
107
+ const parsedPayload = JSON.parse(payload) as { screenshotPath?: unknown }
108
+ return typeof parsedPayload.screenshotPath === 'string' ? parsedPayload.screenshotPath : undefined
109
+ } catch {
110
+ return undefined
111
+ }
112
+ }
113
+
114
+ const directPayload = parsePayload(screenshotAttachment.data)
115
+ if (directPayload) {
116
+ return directPayload
117
+ }
118
+
119
+ const decodedPayload = Buffer.from(screenshotAttachment.data, 'base64').toString('utf8')
120
+ return parsePayload(decodedPayload)
121
+ }
122
+
123
+ /**
124
+ * Maps cucumber step status to Prisma StepStatus enum
125
+ */
126
+ function mapStepStatus(status: string): StepStatus {
127
+ const upperStatus = status.toUpperCase()
128
+ switch (upperStatus) {
129
+ case 'PASSED':
130
+ return StepStatus.PASSED
131
+ case 'FAILED':
132
+ return StepStatus.FAILED
133
+ case 'SKIPPED':
134
+ return StepStatus.SKIPPED
135
+ case 'PENDING':
136
+ return StepStatus.PENDING
137
+ case 'UNDEFINED':
138
+ return StepStatus.UNDEFINED
139
+ default:
140
+ return StepStatus.PENDING
141
+ }
142
+ }
143
+
144
+ /**
145
+ * Maps cucumber step keyword to Prisma StepKeyword enum
146
+ */
147
+ function mapStepKeyword(keyword: string): StepKeyword {
148
+ const trimmedKeyword = keyword.trim()
149
+ const upperKeyword = trimmedKeyword.toUpperCase()
150
+ switch (upperKeyword) {
151
+ case 'GIVEN':
152
+ return StepKeyword.GIVEN
153
+ case 'WHEN':
154
+ return StepKeyword.WHEN
155
+ case 'THEN':
156
+ return StepKeyword.THEN
157
+ case 'AND':
158
+ return StepKeyword.AND
159
+ case 'BUT':
160
+ return StepKeyword.BUT
161
+ case 'BEFORE':
162
+ return StepKeyword.BEFORE
163
+ case 'AFTER':
164
+ return StepKeyword.AFTER
165
+ default:
166
+ // Default to GIVEN for unknown keywords
167
+ return StepKeyword.GIVEN
168
+ }
169
+ }
170
+
171
+ /**
172
+ * Separates error message from stack trace
173
+ * Cucumber's error_message typically contains both the error message and stack trace
174
+ * The stack trace usually starts with "at" or contains file paths
175
+ *
176
+ * @param errorMessage - The full error message from Cucumber
177
+ * @returns Object with separated message and trace
178
+ */
179
+ function separateErrorMessageAndTrace(errorMessage: string | undefined): {
180
+ message: string | undefined
181
+ trace: string | undefined
182
+ } {
183
+ if (!errorMessage) {
184
+ return { message: undefined, trace: undefined }
185
+ }
186
+
187
+ // Look for common stack trace indicators
188
+ // Stack traces typically start with "at", " at", or contain file paths with line numbers
189
+ const stackTracePatterns = [
190
+ /\n\s*at\s/, // "at" at the start of a line (with optional whitespace)
191
+ /\n\s+at\s/, // "at" with leading whitespace
192
+ /Error:\s*$/m, // Error: at end of line (message ends, trace starts)
193
+ ]
194
+
195
+ // Find the first occurrence of a stack trace pattern
196
+ let splitIndex = -1
197
+ for (const pattern of stackTracePatterns) {
198
+ const match = errorMessage.match(pattern)
199
+ if (match && match.index !== undefined) {
200
+ // If we find "at" pattern, split before it (include the newline before "at")
201
+ // If we find "Error:" pattern, split after it
202
+ if (pattern.source.includes('Error:')) {
203
+ splitIndex = match.index + match[0].length
204
+ } else {
205
+ splitIndex = match.index
206
+ }
207
+ break
208
+ }
209
+ }
210
+
211
+ // If no stack trace pattern found, check if it looks like just a message (short, no file paths)
212
+ if (splitIndex === -1) {
213
+ // Check if it contains file paths (common in stack traces)
214
+ const hasFilePath = /[\/\\][\w\-\.]+:\d+/.test(errorMessage)
215
+ if (hasFilePath && errorMessage.length > 200) {
216
+ // Likely contains a trace, try to find where message ends
217
+ // Usually the first few lines are the message, rest is trace
218
+ const lines = errorMessage.split('\n')
219
+ // Look for the first line that starts with whitespace and "at" or contains a file path
220
+ for (let i = 0; i < lines.length; i++) {
221
+ if (/^\s*at\s/.test(lines[i]) || /[\/\\][\w\-\.]+:\d+/.test(lines[i])) {
222
+ splitIndex = errorMessage.indexOf(lines[i])
223
+ break
224
+ }
225
+ }
226
+ }
227
+ }
228
+
229
+ if (splitIndex > 0) {
230
+ const message = errorMessage.substring(0, splitIndex).trim()
231
+ const trace = errorMessage.substring(splitIndex).trim()
232
+ return {
233
+ message: message || undefined,
234
+ trace: trace || undefined,
235
+ }
236
+ }
237
+
238
+ // If we can't separate them, treat the whole thing as the message
239
+ // and leave trace as undefined (better than duplicating)
240
+ return {
241
+ message: errorMessage.trim() || undefined,
242
+ trace: undefined,
243
+ }
244
+ }
245
+
246
+ /**
247
+ * Parses a cucumber.json report file into a structured ParsedReport object
248
+ *
249
+ * @param reportPath - Path to the cucumber.json file
250
+ * @returns Parsed report structure
251
+ * @throws Error if file cannot be read or parsed
252
+ */
253
+ export async function parseCucumberReport(reportPath: string): Promise<ParsedReport> {
254
+ try {
255
+ // Read the report file
256
+ const fileContent = await readFile(reportPath, 'utf-8')
257
+ const cucumberData: CucumberJsonFeature[] = JSON.parse(fileContent)
258
+
259
+ // Parse features
260
+ const features = cucumberData.map(feature => {
261
+ // Separate steps into regular steps and hooks
262
+ const scenarios = feature.elements.map(element => {
263
+ const steps: ParsedReport['features'][0]['scenarios'][0]['steps'] = []
264
+ const hooks: ParsedReport['features'][0]['scenarios'][0]['hooks'] = []
265
+
266
+ element.steps.forEach((step, index) => {
267
+ const isHook = step.keyword === 'Before' || step.keyword === 'After'
268
+ const stepStatus = step.result?.status || 'pending'
269
+ const duration = step.result?.duration || 0
270
+
271
+ // Separate error message from stack trace
272
+ const { message: errorMessage, trace: errorTrace } = separateErrorMessageAndTrace(step.result?.error_message)
273
+ const screenshotPath = extractScreenshotPath(step.embeddings)
274
+
275
+ if (isHook) {
276
+ hooks.push({
277
+ keyword: step.keyword,
278
+ status: stepStatus,
279
+ duration,
280
+ errorMessage,
281
+ errorTrace,
282
+ hidden: step.hidden || false,
283
+ })
284
+ } else {
285
+ steps.push({
286
+ keyword: step.keyword.trim(),
287
+ line: step.line || null,
288
+ name: step.name || '',
289
+ matchLocation: step.match?.location,
290
+ status: stepStatus,
291
+ duration,
292
+ errorMessage,
293
+ errorTrace,
294
+ screenshotPath,
295
+ hidden: step.hidden || false,
296
+ order: index,
297
+ })
298
+ }
299
+ })
300
+
301
+ return {
302
+ name: element.name,
303
+ description: element.description || '',
304
+ line: element.line,
305
+ keyword: element.keyword,
306
+ type: element.type,
307
+ cucumberId: element.id,
308
+ tags: element.tags.map(tag => ({
309
+ name: tag.name,
310
+ line: tag.line,
311
+ })),
312
+ steps,
313
+ hooks,
314
+ }
315
+ })
316
+
317
+ return {
318
+ name: feature.name,
319
+ description: feature.description || '',
320
+ uri: feature.uri,
321
+ line: feature.line,
322
+ keyword: feature.keyword,
323
+ tags: feature.tags.map(tag => ({
324
+ name: tag.name,
325
+ line: tag.line,
326
+ })),
327
+ scenarios,
328
+ }
329
+ })
330
+
331
+ return { features }
332
+ } catch (error) {
333
+ if (error instanceof Error) {
334
+ throw new Error(`Failed to parse cucumber report at ${reportPath}: ${error.message}`)
335
+ }
336
+ throw new Error(`Failed to parse cucumber report at ${reportPath}: Unknown error`)
337
+ }
338
+ }
339
+
340
+ /**
341
+ * Helper function to convert parsed step status to Prisma enum
342
+ */
343
+ export function getStepStatusEnum(status: string): StepStatus {
344
+ return mapStepStatus(status)
345
+ }
346
+
347
+ /**
348
+ * Helper function to convert parsed step keyword to Prisma enum
349
+ */
350
+ export function getStepKeywordEnum(keyword: string): StepKeyword {
351
+ return mapStepKeyword(keyword)
352
+ }