create-appraise 0.1.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 (330) hide show
  1. package/README.md +52 -0
  2. package/package.json +63 -0
  3. package/templates/default/.env.example +2 -0
  4. package/templates/default/README.md +51 -0
  5. package/templates/default/appraise.config.json +4 -0
  6. package/templates/default/components.json +24 -0
  7. package/templates/default/eslint.config.mjs +15 -0
  8. package/templates/default/next-env.d.ts +6 -0
  9. package/templates/default/next.config.ts +7 -0
  10. package/templates/default/package-lock.json +14321 -0
  11. package/templates/default/package.json +124 -0
  12. package/templates/default/postcss.config.mjs +8 -0
  13. package/templates/default/prisma/migrations/20251026202316_migrate_back_to_sqlite/migration.sql +257 -0
  14. package/templates/default/prisma/migrations/20251104113456_add_type_for_template_step_groups/migration.sql +16 -0
  15. package/templates/default/prisma/migrations/20251104170946_add_tags_to_test_suite_and_test_case/migration.sql +27 -0
  16. package/templates/default/prisma/migrations/20251112190024_add_cascade_delete_to_test_run_test_case/migration.sql +17 -0
  17. package/templates/default/prisma/migrations/20251113181100_add_test_run_log/migration.sql +12 -0
  18. package/templates/default/prisma/migrations/20251119191838_add_tag_type/migration.sql +28 -0
  19. package/templates/default/prisma/migrations/20251121164059_add_conflict_resolution/migration.sql +12 -0
  20. package/templates/default/prisma/migrations/20251130190737_add_trace_path_to_test_run_test_case/migration.sql +2 -0
  21. package/templates/default/prisma/migrations/20251213074835_add_log_path_to_test_run/migration.sql +2 -0
  22. package/templates/default/prisma/migrations/20251213183952_add_name_property_for_the_test_run_entities/migration.sql +30 -0
  23. package/templates/default/prisma/migrations/20251223183400_add_report_model_to_db_schema/migration.sql +10 -0
  24. package/templates/default/prisma/migrations/20251223183637_add_report_test_case_entity_for_storing_test_results_for_individual_test_cases/migration.sql +10 -0
  25. package/templates/default/prisma/migrations/20251224083549_add_comprehensive_report_storage/migration.sql +108 -0
  26. package/templates/default/prisma/migrations/20251229194422_migrate_duration_to_string/migration.sql +55 -0
  27. package/templates/default/prisma/migrations/20251230124637_add_unique_constraint_to_test_run_name/migration.sql +27 -0
  28. package/templates/default/prisma/migrations/20260115094436_add_dashboard_metrics/migration.sql +59 -0
  29. package/templates/default/prisma/migrations/20260127172022_add_cascade_delete_to_step_parameters/migration.sql +34 -0
  30. package/templates/default/prisma/migrations/migration_lock.toml +3 -0
  31. package/templates/default/prisma/schema.prisma +554 -0
  32. package/templates/default/public/favicon.ico +0 -0
  33. package/templates/default/public/file.svg +1 -0
  34. package/templates/default/public/globe.svg +1 -0
  35. package/templates/default/public/next.svg +1 -0
  36. package/templates/default/public/vercel.svg +1 -0
  37. package/templates/default/public/window.svg +1 -0
  38. package/templates/default/scripts/regenerate-features.ts +94 -0
  39. package/templates/default/scripts/setup-env.ts +19 -0
  40. package/templates/default/scripts/sync-all.ts +341 -0
  41. package/templates/default/scripts/sync-environments.ts +323 -0
  42. package/templates/default/scripts/sync-locator-groups.ts +413 -0
  43. package/templates/default/scripts/sync-locators.ts +402 -0
  44. package/templates/default/scripts/sync-modules.ts +349 -0
  45. package/templates/default/scripts/sync-tags.ts +292 -0
  46. package/templates/default/scripts/sync-template-step-groups.ts +399 -0
  47. package/templates/default/scripts/sync-template-steps.ts +806 -0
  48. package/templates/default/scripts/sync-test-cases.ts +905 -0
  49. package/templates/default/scripts/sync-test-suites.ts +411 -0
  50. package/templates/default/src/actions/conflict/conflict.action.ts +33 -0
  51. package/templates/default/src/actions/dashboard/dashboard-actions.ts +241 -0
  52. package/templates/default/src/actions/environments/environment-actions.ts +205 -0
  53. package/templates/default/src/actions/locator/locator-actions.ts +547 -0
  54. package/templates/default/src/actions/locator-groups/locator-group-actions.ts +344 -0
  55. package/templates/default/src/actions/modules/module-actions.ts +133 -0
  56. package/templates/default/src/actions/reports/report-actions.ts +614 -0
  57. package/templates/default/src/actions/review/review-actions.ts +147 -0
  58. package/templates/default/src/actions/tags/tag-actions.ts +104 -0
  59. package/templates/default/src/actions/template-step/template-step-actions.ts +332 -0
  60. package/templates/default/src/actions/template-step-group/template-step-group-actions.ts +278 -0
  61. package/templates/default/src/actions/template-test-case/template-test-case-actions.ts +238 -0
  62. package/templates/default/src/actions/test-case/test-case-actions.ts +419 -0
  63. package/templates/default/src/actions/test-run/test-run-actions.ts +1185 -0
  64. package/templates/default/src/actions/test-suite/test-suite-actions.ts +253 -0
  65. package/templates/default/src/actions/user/user-actions.ts +13 -0
  66. package/templates/default/src/app/(base)/environments/create/page.tsx +28 -0
  67. package/templates/default/src/app/(base)/environments/environment-form.tsx +219 -0
  68. package/templates/default/src/app/(base)/environments/environment-table-columns.tsx +96 -0
  69. package/templates/default/src/app/(base)/environments/environment-table.tsx +24 -0
  70. package/templates/default/src/app/(base)/environments/modify/[id]/page.tsx +46 -0
  71. package/templates/default/src/app/(base)/environments/page.tsx +59 -0
  72. package/templates/default/src/app/(base)/layout.tsx +10 -0
  73. package/templates/default/src/app/(base)/locator-groups/create/page.tsx +44 -0
  74. package/templates/default/src/app/(base)/locator-groups/locator-group-form.tsx +215 -0
  75. package/templates/default/src/app/(base)/locator-groups/locator-group-table-columns.tsx +77 -0
  76. package/templates/default/src/app/(base)/locator-groups/locator-group-table.tsx +28 -0
  77. package/templates/default/src/app/(base)/locator-groups/modify/[id]/page.tsx +46 -0
  78. package/templates/default/src/app/(base)/locator-groups/page.tsx +61 -0
  79. package/templates/default/src/app/(base)/locators/create/page.tsx +38 -0
  80. package/templates/default/src/app/(base)/locators/locator-form.tsx +163 -0
  81. package/templates/default/src/app/(base)/locators/locator-table-columns.tsx +90 -0
  82. package/templates/default/src/app/(base)/locators/locator-table.tsx +28 -0
  83. package/templates/default/src/app/(base)/locators/modify/[id]/page.tsx +45 -0
  84. package/templates/default/src/app/(base)/locators/page.tsx +65 -0
  85. package/templates/default/src/app/(base)/locators/sync-locators-button.tsx +66 -0
  86. package/templates/default/src/app/(base)/modules/create/page.tsx +34 -0
  87. package/templates/default/src/app/(base)/modules/modify/[id]/page.tsx +46 -0
  88. package/templates/default/src/app/(base)/modules/module-form.tsx +126 -0
  89. package/templates/default/src/app/(base)/modules/module-table-columns.tsx +85 -0
  90. package/templates/default/src/app/(base)/modules/module-table.tsx +24 -0
  91. package/templates/default/src/app/(base)/modules/page.tsx +59 -0
  92. package/templates/default/src/app/(base)/reports/[id]/page.tsx +517 -0
  93. package/templates/default/src/app/(base)/reports/duration-chart.tsx +33 -0
  94. package/templates/default/src/app/(base)/reports/feature-chart.tsx +78 -0
  95. package/templates/default/src/app/(base)/reports/overview-chart.tsx +46 -0
  96. package/templates/default/src/app/(base)/reports/page.tsx +98 -0
  97. package/templates/default/src/app/(base)/reports/report-metric-card.tsx +16 -0
  98. package/templates/default/src/app/(base)/reports/report-table-columns.tsx +189 -0
  99. package/templates/default/src/app/(base)/reports/report-table.tsx +72 -0
  100. package/templates/default/src/app/(base)/reports/report-view-table-columns.tsx +131 -0
  101. package/templates/default/src/app/(base)/reports/report-view-table.tsx +82 -0
  102. package/templates/default/src/app/(base)/reports/test-cases/page.tsx +42 -0
  103. package/templates/default/src/app/(base)/reports/test-cases/test-cases-metric-table-columns.tsx +115 -0
  104. package/templates/default/src/app/(base)/reports/test-cases/test-cases-metric-table.tsx +27 -0
  105. package/templates/default/src/app/(base)/reports/test-suites/page.tsx +42 -0
  106. package/templates/default/src/app/(base)/reports/test-suites/test-suites-metric-table-columns.tsx +79 -0
  107. package/templates/default/src/app/(base)/reports/test-suites/test-suites-metric-table.tsx +27 -0
  108. package/templates/default/src/app/(base)/reports/view-logs-button.tsx +60 -0
  109. package/templates/default/src/app/(base)/reviews/create/page.tsx +26 -0
  110. package/templates/default/src/app/(base)/reviews/created-reviews-table.tsx +15 -0
  111. package/templates/default/src/app/(base)/reviews/modify/[id]/page.tsx +26 -0
  112. package/templates/default/src/app/(base)/reviews/page.tsx +26 -0
  113. package/templates/default/src/app/(base)/reviews/review/[id]/page.tsx +26 -0
  114. package/templates/default/src/app/(base)/reviews/review-form.tsx +11 -0
  115. package/templates/default/src/app/(base)/reviews/review-table-by-creator-columns.tsx +9 -0
  116. package/templates/default/src/app/(base)/reviews/review-table-by-reviewer-columns.tsx +9 -0
  117. package/templates/default/src/app/(base)/reviews/reviewer-reviews-table.tsx +15 -0
  118. package/templates/default/src/app/(base)/tags/create/page.tsx +39 -0
  119. package/templates/default/src/app/(base)/tags/modify/[id]/page.tsx +50 -0
  120. package/templates/default/src/app/(base)/tags/page.tsx +58 -0
  121. package/templates/default/src/app/(base)/tags/tag-form.tsx +147 -0
  122. package/templates/default/src/app/(base)/tags/tag-table-columns.tsx +63 -0
  123. package/templates/default/src/app/(base)/tags/tag-table.tsx +29 -0
  124. package/templates/default/src/app/(base)/template-step-groups/create/page.tsx +28 -0
  125. package/templates/default/src/app/(base)/template-step-groups/modify/[id]/page.tsx +45 -0
  126. package/templates/default/src/app/(base)/template-step-groups/page.tsx +60 -0
  127. package/templates/default/src/app/(base)/template-step-groups/template-step-group-form.tsx +167 -0
  128. package/templates/default/src/app/(base)/template-step-groups/template-step-group-table-columns.tsx +89 -0
  129. package/templates/default/src/app/(base)/template-step-groups/template-step-group-table.tsx +32 -0
  130. package/templates/default/src/app/(base)/template-steps/create/page.tsx +37 -0
  131. package/templates/default/src/app/(base)/template-steps/modify/[id]/page.tsx +49 -0
  132. package/templates/default/src/app/(base)/template-steps/page.tsx +59 -0
  133. package/templates/default/src/app/(base)/template-steps/paramChip.tsx +213 -0
  134. package/templates/default/src/app/(base)/template-steps/template-step-form.tsx +384 -0
  135. package/templates/default/src/app/(base)/template-steps/template-step-table-columns.tsx +158 -0
  136. package/templates/default/src/app/(base)/template-steps/template-step-table.tsx +24 -0
  137. package/templates/default/src/app/(base)/template-test-cases/create/page.tsx +56 -0
  138. package/templates/default/src/app/(base)/template-test-cases/modify/[id]/page.tsx +89 -0
  139. package/templates/default/src/app/(base)/template-test-cases/page.tsx +58 -0
  140. package/templates/default/src/app/(base)/template-test-cases/template-test-case-flow.tsx +84 -0
  141. package/templates/default/src/app/(base)/template-test-cases/template-test-case-form.tsx +262 -0
  142. package/templates/default/src/app/(base)/template-test-cases/template-test-case-table-columns.tsx +76 -0
  143. package/templates/default/src/app/(base)/template-test-cases/template-test-case-table.tsx +32 -0
  144. package/templates/default/src/app/(base)/test-cases/create/page.tsx +76 -0
  145. package/templates/default/src/app/(base)/test-cases/create-from-template/generate/[id]/page.tsx +96 -0
  146. package/templates/default/src/app/(base)/test-cases/create-from-template/page.tsx +38 -0
  147. package/templates/default/src/app/(base)/test-cases/create-from-template/template-selection-form.tsx +73 -0
  148. package/templates/default/src/app/(base)/test-cases/modify/[id]/page.tsx +106 -0
  149. package/templates/default/src/app/(base)/test-cases/page.tsx +60 -0
  150. package/templates/default/src/app/(base)/test-cases/test-case-flow.tsx +82 -0
  151. package/templates/default/src/app/(base)/test-cases/test-case-form.tsx +395 -0
  152. package/templates/default/src/app/(base)/test-cases/test-case-table-columns.tsx +90 -0
  153. package/templates/default/src/app/(base)/test-cases/test-case-table.tsx +35 -0
  154. package/templates/default/src/app/(base)/test-runs/[id]/page.tsx +56 -0
  155. package/templates/default/src/app/(base)/test-runs/create/page.tsx +47 -0
  156. package/templates/default/src/app/(base)/test-runs/page.tsx +60 -0
  157. package/templates/default/src/app/(base)/test-runs/test-run-form.tsx +512 -0
  158. package/templates/default/src/app/(base)/test-runs/test-run-table-columns.tsx +229 -0
  159. package/templates/default/src/app/(base)/test-runs/test-run-table.tsx +127 -0
  160. package/templates/default/src/app/(base)/test-suites/create/page.tsx +45 -0
  161. package/templates/default/src/app/(base)/test-suites/modify/[id]/page.tsx +55 -0
  162. package/templates/default/src/app/(base)/test-suites/page.tsx +82 -0
  163. package/templates/default/src/app/(base)/test-suites/test-suite-form.tsx +269 -0
  164. package/templates/default/src/app/(base)/test-suites/test-suite-table-columns.tsx +97 -0
  165. package/templates/default/src/app/(base)/test-suites/test-suite-table.tsx +29 -0
  166. package/templates/default/src/app/(dashboard-components)/app-drawer.tsx +187 -0
  167. package/templates/default/src/app/(dashboard-components)/data-card-grid.tsx +13 -0
  168. package/templates/default/src/app/(dashboard-components)/data-card.tsx +27 -0
  169. package/templates/default/src/app/(dashboard-components)/execution-health-panel.tsx +57 -0
  170. package/templates/default/src/app/(dashboard-components)/ongoing-test-runs-card.tsx +87 -0
  171. package/templates/default/src/app/(dashboard-components)/quick-actions-drawer.tsx +45 -0
  172. package/templates/default/src/app/api/test-runs/[runId]/download/route.ts +133 -0
  173. package/templates/default/src/app/api/test-runs/[runId]/logs/route.ts +420 -0
  174. package/templates/default/src/app/api/test-runs/[runId]/trace/[testCaseId]/route.ts +146 -0
  175. package/templates/default/src/app/favicon.ico +0 -0
  176. package/templates/default/src/app/globals.css +147 -0
  177. package/templates/default/src/app/layout.tsx +171 -0
  178. package/templates/default/src/app/page.tsx +64 -0
  179. package/templates/default/src/assets/icons/empty-tube.tsx +23 -0
  180. package/templates/default/src/assets/icons/tube-plus.tsx +29 -0
  181. package/templates/default/src/components/base-node.tsx +21 -0
  182. package/templates/default/src/components/chart/pie-chart.tsx +73 -0
  183. package/templates/default/src/components/data-extraction/locator-inspector.tsx +460 -0
  184. package/templates/default/src/components/data-state/empty-state.tsx +40 -0
  185. package/templates/default/src/components/data-visualization/info-card.tsx +70 -0
  186. package/templates/default/src/components/data-visualization/info-grid.tsx +22 -0
  187. package/templates/default/src/components/devtools/providers.tsx +13 -0
  188. package/templates/default/src/components/diagram/button-edge.tsx +54 -0
  189. package/templates/default/src/components/diagram/dynamic-parameters.tsx +438 -0
  190. package/templates/default/src/components/diagram/edit-header-option.tsx +36 -0
  191. package/templates/default/src/components/diagram/flow-diagram.tsx +470 -0
  192. package/templates/default/src/components/diagram/node-form.tsx +262 -0
  193. package/templates/default/src/components/diagram/options-header-node.tsx +57 -0
  194. package/templates/default/src/components/diagram/template-step-combobox.tsx +155 -0
  195. package/templates/default/src/components/form/error-message.tsx +7 -0
  196. package/templates/default/src/components/kokonutui/smooth-tab.tsx +453 -0
  197. package/templates/default/src/components/loading-skeleton/data-table/data-table-skeleton.tsx +30 -0
  198. package/templates/default/src/components/loading-skeleton/form/button-skeleton.tsx +8 -0
  199. package/templates/default/src/components/loading-skeleton/form/icon-button-skeleton.tsx +8 -0
  200. package/templates/default/src/components/loading-skeleton/form/text-input-skeleton.tsx +8 -0
  201. package/templates/default/src/components/loading-skeleton/visualization/table-skeleton.tsx +14 -0
  202. package/templates/default/src/components/logo.tsx +15 -0
  203. package/templates/default/src/components/navigation/command-badge.tsx +34 -0
  204. package/templates/default/src/components/navigation/command-chain-input.tsx +51 -0
  205. package/templates/default/src/components/navigation/entity-search-command.tsx +116 -0
  206. package/templates/default/src/components/navigation/nav-card.tsx +31 -0
  207. package/templates/default/src/components/navigation/nav-command.tsx +508 -0
  208. package/templates/default/src/components/navigation/nav-link.tsx +60 -0
  209. package/templates/default/src/components/navigation/nav-menu-card-deck.tsx +112 -0
  210. package/templates/default/src/components/node-header.tsx +159 -0
  211. package/templates/default/src/components/reports/test-case-logs-modal.tsx +253 -0
  212. package/templates/default/src/components/table/table-actions.tsx +172 -0
  213. package/templates/default/src/components/test-run/download-logs-button.tsx +99 -0
  214. package/templates/default/src/components/test-run/log-viewer.tsx +445 -0
  215. package/templates/default/src/components/test-run/test-run-details.tsx +611 -0
  216. package/templates/default/src/components/test-run/test-run-header.tsx +149 -0
  217. package/templates/default/src/components/test-run/view-report-button.tsx +102 -0
  218. package/templates/default/src/components/theme/mode-toggle.tsx +54 -0
  219. package/templates/default/src/components/theme/theme-provider.tsx +8 -0
  220. package/templates/default/src/components/typography/page-header-subtitle.tsx +7 -0
  221. package/templates/default/src/components/typography/page-header.tsx +7 -0
  222. package/templates/default/src/components/ui/alert-dialog.tsx +106 -0
  223. package/templates/default/src/components/ui/alert.tsx +43 -0
  224. package/templates/default/src/components/ui/avatar.tsx +40 -0
  225. package/templates/default/src/components/ui/badge.tsx +29 -0
  226. package/templates/default/src/components/ui/button.tsx +47 -0
  227. package/templates/default/src/components/ui/calendar.tsx +158 -0
  228. package/templates/default/src/components/ui/card.tsx +43 -0
  229. package/templates/default/src/components/ui/chart.tsx +369 -0
  230. package/templates/default/src/components/ui/checkbox.tsx +28 -0
  231. package/templates/default/src/components/ui/command.tsx +135 -0
  232. package/templates/default/src/components/ui/data-table-column-header.tsx +61 -0
  233. package/templates/default/src/components/ui/data-table-pagination.tsx +87 -0
  234. package/templates/default/src/components/ui/data-table-view-options.tsx +50 -0
  235. package/templates/default/src/components/ui/data-table.tsx +267 -0
  236. package/templates/default/src/components/ui/dialog.tsx +97 -0
  237. package/templates/default/src/components/ui/dropdown-menu.tsx +182 -0
  238. package/templates/default/src/components/ui/empty.tsx +104 -0
  239. package/templates/default/src/components/ui/input.tsx +22 -0
  240. package/templates/default/src/components/ui/kbd.tsx +28 -0
  241. package/templates/default/src/components/ui/label.tsx +19 -0
  242. package/templates/default/src/components/ui/loading.tsx +12 -0
  243. package/templates/default/src/components/ui/multi-select-with-preview.tsx +116 -0
  244. package/templates/default/src/components/ui/multi-select.tsx +142 -0
  245. package/templates/default/src/components/ui/navigation-menu.tsx +120 -0
  246. package/templates/default/src/components/ui/popover.tsx +33 -0
  247. package/templates/default/src/components/ui/progress.tsx +25 -0
  248. package/templates/default/src/components/ui/radio-group.tsx +44 -0
  249. package/templates/default/src/components/ui/scroll-area.tsx +40 -0
  250. package/templates/default/src/components/ui/select.tsx +144 -0
  251. package/templates/default/src/components/ui/separator.tsx +22 -0
  252. package/templates/default/src/components/ui/skeleton.tsx +7 -0
  253. package/templates/default/src/components/ui/table.tsx +76 -0
  254. package/templates/default/src/components/ui/tabs.tsx +55 -0
  255. package/templates/default/src/components/ui/textarea.tsx +21 -0
  256. package/templates/default/src/components/ui/toast.tsx +113 -0
  257. package/templates/default/src/components/ui/toaster.tsx +26 -0
  258. package/templates/default/src/components/ui/tooltip.tsx +32 -0
  259. package/templates/default/src/components/user-prompt/delete-prompt.tsx +87 -0
  260. package/templates/default/src/config/db-config.ts +10 -0
  261. package/templates/default/src/constants/form-opts/diagram/node-form.ts +30 -0
  262. package/templates/default/src/constants/form-opts/environment-form-opts.ts +24 -0
  263. package/templates/default/src/constants/form-opts/locator-form-opts.ts +20 -0
  264. package/templates/default/src/constants/form-opts/locator-group-form-opts.ts +28 -0
  265. package/templates/default/src/constants/form-opts/module-form-opts.ts +21 -0
  266. package/templates/default/src/constants/form-opts/review-form-opts.ts +23 -0
  267. package/templates/default/src/constants/form-opts/tag-form-opts.ts +42 -0
  268. package/templates/default/src/constants/form-opts/template-selection-form-opts.ts +16 -0
  269. package/templates/default/src/constants/form-opts/template-step-group-form-opts.ts +24 -0
  270. package/templates/default/src/constants/form-opts/template-test-case-form-opts.ts +39 -0
  271. package/templates/default/src/constants/form-opts/template-test-step-form-opts.ts +36 -0
  272. package/templates/default/src/constants/form-opts/test-case-form-opts.ts +43 -0
  273. package/templates/default/src/constants/form-opts/test-run-form-opts.ts +31 -0
  274. package/templates/default/src/constants/form-opts/test-suite-form-opts.ts +24 -0
  275. package/templates/default/src/hooks/use-toast.ts +187 -0
  276. package/templates/default/src/lib/bidirectional-sync.ts +432 -0
  277. package/templates/default/src/lib/database-sync.ts +531 -0
  278. package/templates/default/src/lib/environment-file-utils.ts +221 -0
  279. package/templates/default/src/lib/feature-file-generator.ts +411 -0
  280. package/templates/default/src/lib/gherkin-parser.ts +259 -0
  281. package/templates/default/src/lib/locator-group-file-utils.ts +370 -0
  282. package/templates/default/src/lib/metrics/metric-calculator.ts +613 -0
  283. package/templates/default/src/lib/module-hierarchy-builder.ts +205 -0
  284. package/templates/default/src/lib/path-helpers/module-path.ts +71 -0
  285. package/templates/default/src/lib/test-case-utils.ts +6 -0
  286. package/templates/default/src/lib/test-run/log-formatter.ts +83 -0
  287. package/templates/default/src/lib/test-run/process-manager.ts +191 -0
  288. package/templates/default/src/lib/test-run/report-parser.ts +316 -0
  289. package/templates/default/src/lib/test-run/test-run-executor.ts +144 -0
  290. package/templates/default/src/lib/test-run/winston-logger.ts +95 -0
  291. package/templates/default/src/lib/transformers/gherkin-converter.ts +42 -0
  292. package/templates/default/src/lib/transformers/key-to-icon-transformer.tsx +95 -0
  293. package/templates/default/src/lib/transformers/template-test-case-converter.ts +160 -0
  294. package/templates/default/src/lib/utils/node-param-validation.ts +81 -0
  295. package/templates/default/src/lib/utils/template-step-file-generator.ts +167 -0
  296. package/templates/default/src/lib/utils/template-step-file-manager-intelligent.ts +723 -0
  297. package/templates/default/src/lib/utils/template-step-file-manager.ts +166 -0
  298. package/templates/default/src/lib/utils.ts +31 -0
  299. package/templates/default/src/tests/config/environments/environments.json +14 -0
  300. package/templates/default/src/tests/config/executor/world.ts +41 -0
  301. package/templates/default/src/tests/executor.ts +80 -0
  302. package/templates/default/src/tests/hooks/hooks.ts +99 -0
  303. package/templates/default/src/tests/mapping/locator-map.json +1 -0
  304. package/templates/default/src/tests/steps/actions/click.step.ts +62 -0
  305. package/templates/default/src/tests/steps/actions/hover.step.ts +31 -0
  306. package/templates/default/src/tests/steps/actions/input.step.ts +149 -0
  307. package/templates/default/src/tests/steps/actions/navigation.step.ts +72 -0
  308. package/templates/default/src/tests/steps/actions/random_data.step.ts +146 -0
  309. package/templates/default/src/tests/steps/actions/store.step.ts +90 -0
  310. package/templates/default/src/tests/steps/actions/wait.step.ts +107 -0
  311. package/templates/default/src/tests/steps/validations/active_state_assertion.step.ts +34 -0
  312. package/templates/default/src/tests/steps/validations/navigation_assertion.step.ts +23 -0
  313. package/templates/default/src/tests/steps/validations/text_assertion.step.ts +111 -0
  314. package/templates/default/src/tests/steps/validations/visibility_assertion.step.ts +30 -0
  315. package/templates/default/src/tests/support/parameter-types.ts +12 -0
  316. package/templates/default/src/tests/utils/cache.util.ts +260 -0
  317. package/templates/default/src/tests/utils/cli.util.ts +177 -0
  318. package/templates/default/src/tests/utils/environment.util.ts +65 -0
  319. package/templates/default/src/tests/utils/locator.util.ts +248 -0
  320. package/templates/default/src/tests/utils/random-data.util.ts +45 -0
  321. package/templates/default/src/tests/utils/spawner.util.ts +617 -0
  322. package/templates/default/src/types/diagram/diagram.ts +34 -0
  323. package/templates/default/src/types/diagram/template-step.ts +11 -0
  324. package/templates/default/src/types/executor/browser.type.ts +1 -0
  325. package/templates/default/src/types/form/actionHandler.ts +6 -0
  326. package/templates/default/src/types/locator/locator.type.ts +11 -0
  327. package/templates/default/src/types/step/step.type.ts +1 -0
  328. package/templates/default/src/types/table/data-table.ts +6 -0
  329. package/templates/default/tailwind.config.ts +62 -0
  330. package/templates/default/tsconfig.json +28 -0
@@ -0,0 +1,55 @@
1
+ 'use client'
2
+
3
+ import * as React from 'react'
4
+ import * as TabsPrimitive from '@radix-ui/react-tabs'
5
+
6
+ import { cn } from '@/lib/utils'
7
+
8
+ const Tabs = TabsPrimitive.Root
9
+
10
+ const TabsList = React.forwardRef<
11
+ React.ElementRef<typeof TabsPrimitive.List>,
12
+ React.ComponentPropsWithoutRef<typeof TabsPrimitive.List>
13
+ >(({ className, ...props }, ref) => (
14
+ <TabsPrimitive.List
15
+ ref={ref}
16
+ className={cn(
17
+ 'inline-flex h-9 items-center justify-center rounded-lg bg-muted p-1 text-muted-foreground',
18
+ className,
19
+ )}
20
+ {...props}
21
+ />
22
+ ))
23
+ TabsList.displayName = TabsPrimitive.List.displayName
24
+
25
+ const TabsTrigger = React.forwardRef<
26
+ React.ElementRef<typeof TabsPrimitive.Trigger>,
27
+ React.ComponentPropsWithoutRef<typeof TabsPrimitive.Trigger>
28
+ >(({ className, ...props }, ref) => (
29
+ <TabsPrimitive.Trigger
30
+ ref={ref}
31
+ className={cn(
32
+ 'inline-flex items-center justify-center whitespace-nowrap rounded-md px-3 py-1 text-sm font-medium ring-offset-background transition-all focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 data-[state=active]:bg-background data-[state=active]:text-foreground data-[state=active]:shadow',
33
+ className,
34
+ )}
35
+ {...props}
36
+ />
37
+ ))
38
+ TabsTrigger.displayName = TabsPrimitive.Trigger.displayName
39
+
40
+ const TabsContent = React.forwardRef<
41
+ React.ElementRef<typeof TabsPrimitive.Content>,
42
+ React.ComponentPropsWithoutRef<typeof TabsPrimitive.Content>
43
+ >(({ className, ...props }, ref) => (
44
+ <TabsPrimitive.Content
45
+ ref={ref}
46
+ className={cn(
47
+ 'mt-2 ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2',
48
+ className,
49
+ )}
50
+ {...props}
51
+ />
52
+ ))
53
+ TabsContent.displayName = TabsPrimitive.Content.displayName
54
+
55
+ export { Tabs, TabsList, TabsTrigger, TabsContent }
@@ -0,0 +1,21 @@
1
+ import * as React from 'react'
2
+
3
+ import { cn } from '@/lib/utils'
4
+
5
+ const Textarea = React.forwardRef<HTMLTextAreaElement, React.ComponentProps<'textarea'>>(
6
+ ({ className, ...props }, ref) => {
7
+ return (
8
+ <textarea
9
+ className={cn(
10
+ 'flex min-h-[60px] w-full rounded-md border border-input bg-transparent px-3 py-2 text-base shadow-sm placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50 md:text-sm',
11
+ className,
12
+ )}
13
+ ref={ref}
14
+ {...props}
15
+ />
16
+ )
17
+ },
18
+ )
19
+ Textarea.displayName = 'Textarea'
20
+
21
+ export { Textarea }
@@ -0,0 +1,113 @@
1
+ 'use client'
2
+
3
+ import * as React from 'react'
4
+ import * as ToastPrimitives from '@radix-ui/react-toast'
5
+ import { cva, type VariantProps } from 'class-variance-authority'
6
+ import { X } from 'lucide-react'
7
+
8
+ import { cn } from '@/lib/utils'
9
+
10
+ const ToastProvider = ToastPrimitives.Provider
11
+
12
+ const ToastViewport = React.forwardRef<
13
+ React.ElementRef<typeof ToastPrimitives.Viewport>,
14
+ React.ComponentPropsWithoutRef<typeof ToastPrimitives.Viewport>
15
+ >(({ className, ...props }, ref) => (
16
+ <ToastPrimitives.Viewport
17
+ ref={ref}
18
+ className={cn(
19
+ 'fixed top-0 z-[100] flex max-h-screen w-full flex-col-reverse p-4 sm:bottom-0 sm:right-0 sm:top-auto sm:flex-col md:max-w-[420px]',
20
+ className,
21
+ )}
22
+ {...props}
23
+ />
24
+ ))
25
+ ToastViewport.displayName = ToastPrimitives.Viewport.displayName
26
+
27
+ const toastVariants = cva(
28
+ 'group pointer-events-auto relative flex w-full items-center justify-between space-x-2 overflow-hidden rounded-md border p-4 pr-6 shadow-lg transition-all data-[swipe=cancel]:translate-x-0 data-[swipe=end]:translate-x-[var(--radix-toast-swipe-end-x)] data-[swipe=move]:translate-x-[var(--radix-toast-swipe-move-x)] data-[swipe=move]:transition-none data-[state=open]:animate-in data-[state=closed]:animate-out data-[swipe=end]:animate-out data-[state=closed]:fade-out-80 data-[state=closed]:slide-out-to-right-full data-[state=open]:slide-in-from-top-full data-[state=open]:sm:slide-in-from-bottom-full',
29
+ {
30
+ variants: {
31
+ variant: {
32
+ default: 'border bg-background text-foreground',
33
+ destructive: 'destructive group border-destructive bg-destructive text-destructive-foreground',
34
+ },
35
+ },
36
+ defaultVariants: {
37
+ variant: 'default',
38
+ },
39
+ },
40
+ )
41
+
42
+ const Toast = React.forwardRef<
43
+ React.ElementRef<typeof ToastPrimitives.Root>,
44
+ React.ComponentPropsWithoutRef<typeof ToastPrimitives.Root> & VariantProps<typeof toastVariants>
45
+ >(({ className, variant, ...props }, ref) => {
46
+ return <ToastPrimitives.Root ref={ref} className={cn(toastVariants({ variant }), className)} {...props} />
47
+ })
48
+ Toast.displayName = ToastPrimitives.Root.displayName
49
+
50
+ const ToastAction = React.forwardRef<
51
+ React.ElementRef<typeof ToastPrimitives.Action>,
52
+ React.ComponentPropsWithoutRef<typeof ToastPrimitives.Action>
53
+ >(({ className, ...props }, ref) => (
54
+ <ToastPrimitives.Action
55
+ ref={ref}
56
+ className={cn(
57
+ 'inline-flex h-8 shrink-0 items-center justify-center rounded-md border bg-transparent px-3 text-sm font-medium transition-colors hover:bg-secondary focus:outline-none focus:ring-1 focus:ring-ring disabled:pointer-events-none disabled:opacity-50 group-[.destructive]:border-muted/40 group-[.destructive]:hover:border-destructive/30 group-[.destructive]:hover:bg-destructive group-[.destructive]:hover:text-destructive-foreground group-[.destructive]:focus:ring-destructive',
58
+ className,
59
+ )}
60
+ {...props}
61
+ />
62
+ ))
63
+ ToastAction.displayName = ToastPrimitives.Action.displayName
64
+
65
+ const ToastClose = React.forwardRef<
66
+ React.ElementRef<typeof ToastPrimitives.Close>,
67
+ React.ComponentPropsWithoutRef<typeof ToastPrimitives.Close>
68
+ >(({ className, ...props }, ref) => (
69
+ <ToastPrimitives.Close
70
+ ref={ref}
71
+ className={cn(
72
+ 'absolute right-1 top-1 rounded-md p-1 text-foreground/50 opacity-0 transition-opacity hover:text-foreground focus:opacity-100 focus:outline-none focus:ring-1 group-hover:opacity-100 group-[.destructive]:text-red-300 group-[.destructive]:hover:text-red-50 group-[.destructive]:focus:ring-red-400 group-[.destructive]:focus:ring-offset-red-600',
73
+ className,
74
+ )}
75
+ toast-close=""
76
+ {...props}
77
+ >
78
+ <X className="h-4 w-4" />
79
+ </ToastPrimitives.Close>
80
+ ))
81
+ ToastClose.displayName = ToastPrimitives.Close.displayName
82
+
83
+ const ToastTitle = React.forwardRef<
84
+ React.ElementRef<typeof ToastPrimitives.Title>,
85
+ React.ComponentPropsWithoutRef<typeof ToastPrimitives.Title>
86
+ >(({ className, ...props }, ref) => (
87
+ <ToastPrimitives.Title ref={ref} className={cn('text-sm font-semibold [&+div]:text-xs', className)} {...props} />
88
+ ))
89
+ ToastTitle.displayName = ToastPrimitives.Title.displayName
90
+
91
+ const ToastDescription = React.forwardRef<
92
+ React.ElementRef<typeof ToastPrimitives.Description>,
93
+ React.ComponentPropsWithoutRef<typeof ToastPrimitives.Description>
94
+ >(({ className, ...props }, ref) => (
95
+ <ToastPrimitives.Description ref={ref} className={cn('text-sm opacity-90', className)} {...props} />
96
+ ))
97
+ ToastDescription.displayName = ToastPrimitives.Description.displayName
98
+
99
+ type ToastProps = React.ComponentPropsWithoutRef<typeof Toast>
100
+
101
+ type ToastActionElement = React.ReactElement<typeof ToastAction>
102
+
103
+ export {
104
+ type ToastProps,
105
+ type ToastActionElement,
106
+ ToastProvider,
107
+ ToastViewport,
108
+ Toast,
109
+ ToastTitle,
110
+ ToastDescription,
111
+ ToastClose,
112
+ ToastAction,
113
+ }
@@ -0,0 +1,26 @@
1
+ 'use client'
2
+
3
+ import { useToast } from '@/hooks/use-toast'
4
+ import { Toast, ToastClose, ToastDescription, ToastProvider, ToastTitle, ToastViewport } from '@/components/ui/toast'
5
+
6
+ export function Toaster() {
7
+ const { toasts } = useToast()
8
+
9
+ return (
10
+ <ToastProvider>
11
+ {toasts.map(function ({ id, title, description, action, ...props }) {
12
+ return (
13
+ <Toast key={id} {...props}>
14
+ <div className="grid gap-1">
15
+ {title && <ToastTitle>{title}</ToastTitle>}
16
+ {description && <ToastDescription>{description}</ToastDescription>}
17
+ </div>
18
+ {action}
19
+ <ToastClose />
20
+ </Toast>
21
+ )
22
+ })}
23
+ <ToastViewport />
24
+ </ToastProvider>
25
+ )
26
+ }
@@ -0,0 +1,32 @@
1
+ "use client"
2
+
3
+ import * as React from "react"
4
+ import * as TooltipPrimitive from "@radix-ui/react-tooltip"
5
+
6
+ import { cn } from "@/lib/utils"
7
+
8
+ const TooltipProvider = TooltipPrimitive.Provider
9
+
10
+ const Tooltip = TooltipPrimitive.Root
11
+
12
+ const TooltipTrigger = TooltipPrimitive.Trigger
13
+
14
+ const TooltipContent = React.forwardRef<
15
+ React.ElementRef<typeof TooltipPrimitive.Content>,
16
+ React.ComponentPropsWithoutRef<typeof TooltipPrimitive.Content>
17
+ >(({ className, sideOffset = 4, ...props }, ref) => (
18
+ <TooltipPrimitive.Portal>
19
+ <TooltipPrimitive.Content
20
+ ref={ref}
21
+ sideOffset={sideOffset}
22
+ className={cn(
23
+ "z-50 overflow-hidden rounded-md bg-primary px-3 py-1.5 text-xs text-primary-foreground animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 origin-[--radix-tooltip-content-transform-origin]",
24
+ className
25
+ )}
26
+ {...props}
27
+ />
28
+ </TooltipPrimitive.Portal>
29
+ ))
30
+ TooltipContent.displayName = TooltipPrimitive.Content.displayName
31
+
32
+ export { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider }
@@ -0,0 +1,87 @@
1
+ 'use client'
2
+
3
+ import {
4
+ Dialog,
5
+ DialogContent,
6
+ DialogDescription,
7
+ DialogFooter,
8
+ DialogHeader,
9
+ DialogTitle,
10
+ DialogTrigger,
11
+ DialogClose,
12
+ } from '../ui/dialog'
13
+ import { Button } from '../ui/button'
14
+ import { AlertCircle, Trash, X } from 'lucide-react'
15
+ import { useState } from 'react'
16
+
17
+ export default function DeletePrompt({
18
+ isDisabled,
19
+ dialogTitle,
20
+ dialogDescription,
21
+ confirmationText,
22
+ deleteHandler,
23
+ open,
24
+ onOpenChange,
25
+ }: {
26
+ isDisabled?: boolean
27
+ dialogTitle: string
28
+ dialogDescription: string
29
+ confirmationText: string
30
+ deleteHandler: () => Promise<void>
31
+ open?: boolean
32
+ onOpenChange?: (open: boolean) => void
33
+ }) {
34
+ const [internalOpen, setInternalOpen] = useState(false)
35
+
36
+ // Use controlled state if provided, otherwise use internal state
37
+ const isOpen = open !== undefined ? open : internalOpen
38
+ const setIsOpen = onOpenChange || setInternalOpen
39
+
40
+ // Determine if we're in controlled mode (open prop provided)
41
+ const isControlled = open !== undefined
42
+
43
+ return (
44
+ <Dialog open={isOpen} onOpenChange={setIsOpen}>
45
+ {!isControlled && (
46
+ <DialogTrigger asChild disabled={isDisabled}>
47
+ <Button variant="outline" size="icon">
48
+ <Trash className="h-4 w-4" />
49
+ </Button>
50
+ </DialogTrigger>
51
+ )}
52
+ <DialogContent className="border-none">
53
+ <DialogHeader>
54
+ <DialogTitle className="flex items-end gap-2">
55
+ <AlertCircle className="h-5 w-5" />
56
+ {dialogTitle}
57
+ </DialogTitle>
58
+ <DialogDescription>{dialogDescription}</DialogDescription>
59
+ </DialogHeader>
60
+ <div className="mb-4 flex flex-col gap-2">
61
+ <h1 className="text-md">{confirmationText}</h1>
62
+ </div>
63
+ <DialogFooter>
64
+ <Button
65
+ variant="destructive"
66
+ className="bg-red-500 hover:bg-red-600"
67
+ onClick={async () => {
68
+ await deleteHandler()
69
+ setIsOpen(false)
70
+ }}
71
+ >
72
+ <span className="flex items-center gap-2 text-white">
73
+ <Trash className="h-4 w-4" />
74
+ Delete
75
+ </span>
76
+ </Button>
77
+ <DialogClose asChild className="bg-gray-700 text-white hover:bg-gray-800">
78
+ <Button variant="secondary">
79
+ <X className="h-4 w-4" />
80
+ Cancel
81
+ </Button>
82
+ </DialogClose>
83
+ </DialogFooter>
84
+ </DialogContent>
85
+ </Dialog>
86
+ )
87
+ }
@@ -0,0 +1,10 @@
1
+ import { PrismaClient } from '@prisma/client'
2
+
3
+ const globalForPrisma = global as unknown as {
4
+ prisma: PrismaClient | undefined
5
+ }
6
+ const prisma = globalForPrisma.prisma ?? new PrismaClient()
7
+
8
+ if (process.env.NODE_ENV !== 'production') globalForPrisma.prisma = prisma
9
+
10
+ export default prisma
@@ -0,0 +1,30 @@
1
+ import { StepParameterType } from '@prisma/client'
2
+ import { z } from 'zod'
3
+
4
+ export const nodeDataSchema = z.object({
5
+ label: z.string().min(3, { message: 'Label must be at least 3 characters' }),
6
+ gherkinStep: z.string(),
7
+ templateStepId: z.string().min(1, { message: 'Template step is required' }),
8
+ parameters: z.array(
9
+ z.object({
10
+ name: z.string(),
11
+ value: z.string(),
12
+ type: z.nativeEnum(StepParameterType),
13
+ order: z.number(),
14
+ }),
15
+ ),
16
+ })
17
+
18
+ export type NodeData = z.infer<typeof nodeDataSchema>
19
+
20
+ export const formOpts = {
21
+ defaultValues: {
22
+ label: '',
23
+ gherkinStep: '',
24
+ templateStepId: '',
25
+ parameters: [],
26
+ } as NodeData,
27
+ validators: {
28
+ onChange: nodeDataSchema,
29
+ },
30
+ }
@@ -0,0 +1,24 @@
1
+ import { z } from 'zod'
2
+
3
+ export const environmentSchema = z.object({
4
+ name: z.string().min(1, { message: 'Name is required' }),
5
+ baseUrl: z.string().url({ message: 'Base URL must be a valid URL' }),
6
+ apiBaseUrl: z.string().url({ message: 'API Base URL must be a valid URL' }).optional().or(z.literal('')),
7
+ username: z.string().optional().or(z.literal('')),
8
+ password: z.string().optional().or(z.literal('')),
9
+ })
10
+
11
+ export type Environment = z.infer<typeof environmentSchema>
12
+
13
+ export const formOpts = {
14
+ defaultValues: {
15
+ name: '',
16
+ baseUrl: '',
17
+ apiBaseUrl: '',
18
+ username: '',
19
+ password: '',
20
+ },
21
+ validators: {
22
+ onChange: environmentSchema,
23
+ },
24
+ }
@@ -0,0 +1,20 @@
1
+ import { z } from 'zod'
2
+
3
+ export const locatorSchema = z.object({
4
+ name: z.string().min(1, { message: 'Name is required' }),
5
+ value: z.string().min(1, { message: 'Value is required' }),
6
+ locatorGroupId: z.string().min(1, { message: 'Locator group is required' }),
7
+ })
8
+
9
+ export type Locator = z.infer<typeof locatorSchema>
10
+
11
+ export const formOpts = {
12
+ defaultValues: {
13
+ name: '',
14
+ value: '',
15
+ locatorGroupId: '',
16
+ },
17
+ validators: {
18
+ onChange: locatorSchema,
19
+ },
20
+ }
@@ -0,0 +1,28 @@
1
+ import { z } from 'zod'
2
+
3
+ export const locatorGroupSchema = z.object({
4
+ name: z.string().min(1, { message: 'Name is required' }),
5
+ moduleId: z.string().min(1, { message: 'Module is required' }),
6
+ locators: z.array(z.string()).optional(),
7
+ route: z.string().optional(),
8
+ })
9
+
10
+ // Schema for checking unique name (used in server actions)
11
+ export const locatorGroupUniqueNameSchema = z.object({
12
+ name: z.string().min(1, { message: 'Name is required' }),
13
+ id: z.string().optional(), // For updates, exclude current record
14
+ })
15
+
16
+ export type LocatorGroup = z.infer<typeof locatorGroupSchema>
17
+
18
+ export const formOpts = {
19
+ defaultValues: {
20
+ name: '',
21
+ moduleId: '',
22
+ locators: [],
23
+ route: '',
24
+ },
25
+ validators: {
26
+ onChange: locatorGroupSchema,
27
+ },
28
+ }
@@ -0,0 +1,21 @@
1
+ import { z } from 'zod'
2
+
3
+ // Special UUID to represent root (no parent) in the form
4
+ export const ROOT_MODULE_UUID = '00000000-0000-0000-0000-000000000000'
5
+
6
+ export const moduleSchema = z.object({
7
+ name: z.string().min(1, { message: 'Name is required' }),
8
+ parentId: z.string().optional().or(z.undefined()),
9
+ })
10
+
11
+ export type Module = z.infer<typeof moduleSchema>
12
+
13
+ export const formOpts = {
14
+ defaultValues: {
15
+ name: '',
16
+ parentId: ROOT_MODULE_UUID,
17
+ },
18
+ validators: {
19
+ onChange: moduleSchema,
20
+ },
21
+ }
@@ -0,0 +1,23 @@
1
+ import { ReviewStatus } from '@prisma/client'
2
+ import { z } from 'zod'
3
+
4
+ export const reviewSchema = z.object({
5
+ testCaseId: z.string().min(1, { message: 'Test case is required' }),
6
+ status: z.nativeEnum(ReviewStatus),
7
+ comments: z.string().optional(),
8
+ reviewerId: z.string().min(1, { message: 'Reviewer is required' }),
9
+ })
10
+
11
+ export type Review = z.infer<typeof reviewSchema>
12
+
13
+ export const formOpts = {
14
+ defaultValues: {
15
+ testCaseId: '',
16
+ status: 'PENDING',
17
+ comments: '',
18
+ reviewerId: '',
19
+ },
20
+ validators: {
21
+ onChange: reviewSchema,
22
+ },
23
+ }
@@ -0,0 +1,42 @@
1
+ import { z } from 'zod'
2
+
3
+ export const tagSchema = z.object({
4
+ name: z.string().min(1, { message: 'Name is required' }),
5
+ tagExpression: z
6
+ .string()
7
+ .min(1, { message: 'Tag expression is required' })
8
+ .refine(
9
+ value => {
10
+ // Check if the value follows Gherkin tag rules
11
+ // Only one tag allowed per entry - single word after @ symbol
12
+ const trimmedValue = value.trim()
13
+ if (!trimmedValue) return false
14
+
15
+ // Should not contain any spaces (only one tag allowed)
16
+ if (trimmedValue.includes(' ')) return false
17
+
18
+ // Tag should start with @
19
+ if (!trimmedValue.startsWith('@')) return false
20
+
21
+ // Tag should have at least one character after @
22
+ if (trimmedValue.length <= 1) return false
23
+
24
+ return true
25
+ },
26
+ {
27
+ message: 'Tag expression must be a single tag starting with @ and contain no spaces (e.g., "@smoke")',
28
+ },
29
+ ),
30
+ })
31
+
32
+ export type Tag = z.infer<typeof tagSchema>
33
+
34
+ export const formOpts = {
35
+ defaultValues: {
36
+ name: '',
37
+ tagExpression: '',
38
+ },
39
+ validators: {
40
+ onChange: tagSchema,
41
+ },
42
+ }
@@ -0,0 +1,16 @@
1
+ import { z } from 'zod'
2
+
3
+ export const templateSelectionSchema = z.object({
4
+ templateTestCaseId: z.string().min(1, { message: 'Template test case is required' }),
5
+ })
6
+
7
+ export type TemplateSelection = z.infer<typeof templateSelectionSchema>
8
+
9
+ export const formOpts = {
10
+ defaultValues: {
11
+ templateTestCaseId: '',
12
+ },
13
+ validators: {
14
+ onChange: templateSelectionSchema,
15
+ },
16
+ }
@@ -0,0 +1,24 @@
1
+ import { z } from 'zod'
2
+
3
+ // TemplateStepGroupType enum - will be available from @prisma/client after migration
4
+ const TemplateStepGroupTypeEnum = z.enum(['ACTION', 'VALIDATION'])
5
+ type TemplateStepGroupType = z.infer<typeof TemplateStepGroupTypeEnum>
6
+
7
+ export const templateStepGroupSchema = z.object({
8
+ name: z.string().min(3, { message: 'Name must be at least 3 characters' }),
9
+ description: z.string().optional(),
10
+ type: TemplateStepGroupTypeEnum,
11
+ })
12
+
13
+ export type TemplateStepGroup = z.infer<typeof templateStepGroupSchema>
14
+
15
+ export const formOpts = {
16
+ defaultValues: {
17
+ name: '',
18
+ description: '',
19
+ type: 'ACTION' as TemplateStepGroupType,
20
+ } as TemplateStepGroup,
21
+ validators: {
22
+ onChange: templateStepGroupSchema,
23
+ },
24
+ }
@@ -0,0 +1,39 @@
1
+ import { StepParameterType, TemplateStepIcon } from '@prisma/client'
2
+ import { z } from 'zod'
3
+
4
+ export const templateTestCaseSchema = z.object({
5
+ title: z.string().min(3, { message: 'Title must be at least 3 characters' }),
6
+ description: z.string().optional(),
7
+ steps: z
8
+ .array(
9
+ z.object({
10
+ gherkinStep: z.string(),
11
+ label: z.string(),
12
+ icon: z.nativeEnum(TemplateStepIcon),
13
+ parameters: z.array(
14
+ z.object({
15
+ name: z.string(),
16
+ value: z.string(),
17
+ type: z.nativeEnum(StepParameterType),
18
+ order: z.number(),
19
+ }),
20
+ ),
21
+ order: z.number(),
22
+ templateStepId: z.string(),
23
+ }),
24
+ )
25
+ .min(1, { message: 'Steps are required' }),
26
+ })
27
+
28
+ export type TemplateTestCase = z.infer<typeof templateTestCaseSchema>
29
+
30
+ export const formOpts = {
31
+ defaultValues: {
32
+ title: '',
33
+ description: '',
34
+ steps: [],
35
+ } as TemplateTestCase,
36
+ validators: {
37
+ onChange: templateTestCaseSchema,
38
+ },
39
+ }
@@ -0,0 +1,36 @@
1
+ import { z } from 'zod'
2
+
3
+ export const templateStepSchema = z.object({
4
+ name: z.string().min(3, { message: 'Name must be at least 3 characters' }),
5
+ description: z.string().optional(),
6
+ type: z.string(),
7
+ signature: z.string(),
8
+ functionDefinition: z.string().optional(),
9
+ params: z.array(
10
+ z.object({
11
+ name: z.string(),
12
+ type: z.string(),
13
+ order: z.number(),
14
+ }),
15
+ ),
16
+ icon: z.string(),
17
+ templateStepGroupId: z.string().min(1, { message: 'Template step group is required' }),
18
+ })
19
+
20
+ export type TemplateStep = z.infer<typeof templateStepSchema>
21
+
22
+ export const formOpts = {
23
+ defaultValues: {
24
+ name: '',
25
+ description: '',
26
+ type: 'ACTION',
27
+ signature: '',
28
+ functionDefinition: '',
29
+ params: [],
30
+ icon: 'MOUSE',
31
+ templateStepGroupId: '',
32
+ } as TemplateStep,
33
+ validators: {
34
+ onChange: templateStepSchema,
35
+ },
36
+ }