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,470 @@
1
+ 'use client'
2
+
3
+ import {
4
+ addEdge,
5
+ Background,
6
+ ConnectionMode,
7
+ Controls,
8
+ Edge,
9
+ Node,
10
+ NodeProps,
11
+ OnConnect,
12
+ ReactFlow,
13
+ useEdgesState,
14
+ useNodesState,
15
+ Connection,
16
+ } from '@xyflow/react'
17
+ import '@xyflow/react/dist/style.css'
18
+ import { useCallback, useState, useEffect, useMemo, memo, useRef } from 'react'
19
+ import { Button } from '@/components/ui/button'
20
+ import ButtonEdge from './button-edge'
21
+ import { Plus } from 'lucide-react'
22
+ import OptionsHeaderNode from './options-header-node'
23
+ import NodeForm from './node-form'
24
+ import { NodeData } from '@/constants/form-opts/diagram/node-form'
25
+ import { NodeOrderMap, TemplateTestCaseNodeData, TemplateTestCaseNodeOrderMap } from '@/types/diagram/diagram'
26
+ import { Locator, TemplateStep, TemplateStepParameter, StepParameterType, LocatorGroup } from '@prisma/client'
27
+ import { checkMissingMandatoryParams } from '@/lib/utils/node-param-validation'
28
+
29
+ const edgeTypes = {
30
+ buttonEdge: ButtonEdge,
31
+ }
32
+
33
+ const FlowDiagram = ({
34
+ nodeOrder,
35
+ templateStepParams,
36
+ templateSteps,
37
+ locators,
38
+ locatorGroups,
39
+ onNodeOrderChange,
40
+ defaultValueInput = false,
41
+ }: {
42
+ nodeOrder: NodeOrderMap | TemplateTestCaseNodeOrderMap
43
+ templateStepParams: TemplateStepParameter[]
44
+ templateSteps: TemplateStep[]
45
+ locators: Locator[]
46
+ locatorGroups: LocatorGroup[]
47
+ defaultValueInput?: boolean
48
+ onNodeOrderChange: (nodeOrder: NodeOrderMap | TemplateTestCaseNodeOrderMap) => void
49
+ }) => {
50
+ const handleEditNodeRef = useRef<(nodeId: string) => void>(() => {})
51
+
52
+ const generateInitialNodesAndEdges = useCallback(
53
+ (nodeOrder: NodeOrderMap | TemplateTestCaseNodeOrderMap) => {
54
+ const nodes: Node[] = []
55
+ const edges: Edge[] = []
56
+
57
+ // Sort entries by order value
58
+ const sortedEntries = Object.entries(nodeOrder).sort(
59
+ ([, nodeDataA], [, nodeDataB]) => nodeDataA.order - nodeDataB.order,
60
+ )
61
+
62
+ // Create nodes
63
+ sortedEntries.forEach(([id, nodeData], index) => {
64
+ const baseNodeData = {
65
+ label: nodeData.label,
66
+ gherkinStep: nodeData.gherkinStep ?? '',
67
+ isFirstNode: nodeData.isFirstNode ?? false,
68
+ icon: nodeData.icon ?? '',
69
+ parameters: (nodeData.parameters ?? []).map(
70
+ (p: NodeData['parameters'][number] | TemplateTestCaseNodeData['parameters'][number]) => ({
71
+ name: p.name,
72
+ value: 'value' in p ? p.value : p.defaultValue,
73
+ type: p.type ?? StepParameterType.STRING,
74
+ order: p.order,
75
+ }),
76
+ ),
77
+ templateStepId: nodeData.templateStepId ?? '',
78
+ }
79
+
80
+ // Check for missing mandatory parameters (only when defaultValueInput is false)
81
+ const isMissingParams = checkMissingMandatoryParams(
82
+ {
83
+ parameters: baseNodeData.parameters,
84
+ templateStepId: baseNodeData.templateStepId,
85
+ },
86
+ templateStepParams,
87
+ defaultValueInput,
88
+ )
89
+
90
+ const nodeDataWithValidation = {
91
+ ...baseNodeData,
92
+ ...(isMissingParams ? { isMissingParams: true } : {}),
93
+ }
94
+
95
+ // Skip isolated nodes (order === -1)
96
+ if (nodeData.order === -1) {
97
+ nodes.push({
98
+ id,
99
+ data: nodeDataWithValidation,
100
+ position: { x: 0, y: index * 100 }, // Stack isolated nodes vertically
101
+ type: 'optionsHeaderNode',
102
+ })
103
+ return
104
+ }
105
+
106
+ nodes.push({
107
+ id,
108
+ data: nodeDataWithValidation,
109
+ position: { x: nodeData.order * 500, y: 0 }, // Space nodes horizontally based on order
110
+ type: 'optionsHeaderNode',
111
+ })
112
+
113
+ // Create edges between consecutive nodes
114
+ if (index < sortedEntries.length - 1) {
115
+ const nextEntry = sortedEntries[index + 1]
116
+ // Only create edge if both nodes have valid orders (not -1)
117
+ if (nodeData.order !== -1 && nextEntry[1].order !== -1 && nodeData.order === nextEntry[1].order - 1) {
118
+ edges.push({
119
+ id: `${id}-${nextEntry[0]}`,
120
+ source: id,
121
+ target: nextEntry[0],
122
+ type: 'buttonEdge',
123
+ })
124
+ }
125
+ }
126
+ })
127
+
128
+ return { nodes, edges }
129
+ },
130
+ [templateStepParams, defaultValueInput],
131
+ )
132
+
133
+ const { nodes: initialNodes, edges: initialEdges } = useMemo(
134
+ () => generateInitialNodesAndEdges(nodeOrder),
135
+ [nodeOrder, generateInitialNodesAndEdges],
136
+ )
137
+
138
+ const [nodes, setNodes, onNodesChange] = useNodesState(initialNodes)
139
+ const [edges, setEdges, onEdgesChange] = useEdgesState(initialEdges)
140
+ const [showAddNodeDialog, setShowAddNodeDialog] = useState(false)
141
+ const [showEditNodeDialog, setShowEditNodeDialog] = useState(false)
142
+ const [editNodeId, setEditNodeId] = useState<string | null>(null)
143
+ const [editNodeData, setEditNodeData] = useState<NodeData | null>(null)
144
+
145
+ const handleEditNode = useCallback(
146
+ (nodeId: string) => {
147
+ const node = nodes.find(node => node.id === nodeId)
148
+ setEditNodeData({
149
+ ...(node?.data as NodeData),
150
+ gherkinStep: (node?.data as NodeData)?.gherkinStep ?? '',
151
+ parameters: ((node?.data as NodeData)?.parameters ?? []).map(p => ({
152
+ name: p.name,
153
+ value: p.value,
154
+ type: p.type ?? StepParameterType.STRING,
155
+ order: p.order,
156
+ })),
157
+ templateStepId: (node?.data as NodeData)?.templateStepId ?? '',
158
+ })
159
+ setEditNodeId(nodeId)
160
+ setShowEditNodeDialog(true)
161
+ },
162
+ [nodes],
163
+ )
164
+
165
+ // Update the ref whenever handleEditNode changes
166
+ useEffect(() => {
167
+ handleEditNodeRef.current = handleEditNode
168
+ }, [handleEditNode])
169
+
170
+ const addNode = useCallback(
171
+ (formData: NodeData) => {
172
+ // Lookup the icon from the template step
173
+ const templateStep = templateSteps.find(ts => ts.id === formData.templateStepId)
174
+ const icon = templateStep?.icon ?? 'MOUSE'
175
+
176
+ // Check for missing mandatory parameters (only when defaultValueInput is false)
177
+ const isMissingParams = checkMissingMandatoryParams(
178
+ {
179
+ parameters: formData.parameters,
180
+ templateStepId: formData.templateStepId,
181
+ },
182
+ templateStepParams,
183
+ defaultValueInput,
184
+ )
185
+
186
+ const newNode: Node = {
187
+ id: crypto.randomUUID(),
188
+ data: {
189
+ ...formData,
190
+ icon, // Add icon here
191
+ isFirstNode: nodes.length === 0,
192
+ ...(isMissingParams ? { isMissingParams: true } : {}),
193
+ },
194
+ position: { x: 0, y: 0 },
195
+ type: 'optionsHeaderNode',
196
+ }
197
+ setNodes(nds => nds.concat(newNode))
198
+ setShowAddNodeDialog(false)
199
+ },
200
+ [setNodes, setShowAddNodeDialog, nodes, templateSteps, templateStepParams, defaultValueInput],
201
+ )
202
+
203
+ const handleEditNodeSubmit = useCallback(
204
+ (formData: NodeData) => {
205
+ if (!editNodeId) return
206
+ const templateStep = templateSteps.find(ts => ts.id === formData.templateStepId)
207
+ const icon = templateStep?.icon ?? 'MOUSE'
208
+
209
+ // Check for missing mandatory parameters (only when defaultValueInput is false)
210
+ const isMissingParams = checkMissingMandatoryParams(
211
+ {
212
+ parameters: formData.parameters,
213
+ templateStepId: formData.templateStepId,
214
+ },
215
+ templateStepParams,
216
+ defaultValueInput,
217
+ )
218
+
219
+ setNodes(nds =>
220
+ nds.map(node =>
221
+ node.id === editNodeId
222
+ ? {
223
+ ...node,
224
+ data: {
225
+ ...node.data,
226
+ ...formData,
227
+ icon, // Update icon here
228
+ // Remove isMissingParams if all params are present, add it if missing
229
+ ...(isMissingParams ? { isMissingParams: true } : { isMissingParams: false }),
230
+ },
231
+ }
232
+ : node,
233
+ ),
234
+ )
235
+ setShowEditNodeDialog(false)
236
+ },
237
+ [editNodeId, setNodes, setShowEditNodeDialog, templateSteps, templateStepParams, defaultValueInput],
238
+ )
239
+
240
+ const determineNodeOrders = useCallback((nodes: Node[], edges: Edge[]) => {
241
+ // Create adjacency list
242
+ const graph: Record<string, string[]> = {}
243
+ const inDegree: Record<string, number> = {}
244
+ const hasConnections: Record<string, boolean> = {}
245
+ const nodeIds = new Set(nodes.map(node => node.id))
246
+
247
+ // Initialize graph, inDegree, and hasConnections
248
+ nodes.forEach(node => {
249
+ graph[node.id] = []
250
+ inDegree[node.id] = 0
251
+ hasConnections[node.id] = false
252
+ })
253
+
254
+ // Build graph - only include edges where both source and target nodes exist
255
+ edges.forEach(edge => {
256
+ if (edge.source && edge.target && nodeIds.has(edge.source) && nodeIds.has(edge.target)) {
257
+ graph[edge.source].push(edge.target)
258
+ inDegree[edge.target] = (inDegree[edge.target] || 0) + 1
259
+ hasConnections[edge.source] = true
260
+ hasConnections[edge.target] = true
261
+ }
262
+ })
263
+
264
+ // Find nodes with no incoming edges
265
+ const queue = nodes.map(node => node.id).filter(id => inDegree[id] === 0 && hasConnections[id])
266
+
267
+ const orders: NodeOrderMap = {}
268
+ let orderNum = 1
269
+
270
+ // First mark all isolated nodes with -1
271
+ nodes.forEach(node => {
272
+ if (!hasConnections[node.id]) {
273
+ orders[node.id] = {
274
+ order: -1,
275
+ label: node.data.label as string,
276
+ gherkinStep: (node.data.gherkinStep as string) ?? '',
277
+ isFirstNode: (node.data.isFirstNode as boolean) ?? false,
278
+ icon: (node.data.icon as string) ?? '',
279
+ parameters: ((node.data.parameters as NodeData['parameters']) ?? []).map(p => ({
280
+ name: p.name,
281
+ value: p.value,
282
+ type: p.type ?? StepParameterType.STRING,
283
+ order: p.order,
284
+ })),
285
+ templateStepId: (node.data.templateStepId as string) ?? '',
286
+ }
287
+ }
288
+ })
289
+
290
+ // Process queue
291
+ while (queue.length > 0) {
292
+ const currentId = queue.shift()!
293
+ const currentNode = nodes.find(node => node.id === currentId)!
294
+ orders[currentId] = {
295
+ order: orderNum++,
296
+ label: currentNode.data.label as string,
297
+ gherkinStep: (currentNode.data.gherkinStep as string) ?? '',
298
+ isFirstNode: (currentNode.data.isFirstNode as boolean) ?? false,
299
+ icon: (currentNode.data.icon as string) ?? '',
300
+ parameters: ((currentNode.data.parameters as NodeData['parameters']) ?? []).map(p => ({
301
+ name: p.name,
302
+ value: p.value,
303
+ type: p.type ?? StepParameterType.STRING,
304
+ order: p.order,
305
+ })),
306
+ templateStepId: (currentNode.data.templateStepId as string) ?? '',
307
+ }
308
+
309
+ // Process neighbors
310
+ graph[currentId].forEach(neighborId => {
311
+ inDegree[neighborId]--
312
+ if (inDegree[neighborId] === 0) {
313
+ queue.push(neighborId)
314
+ }
315
+ })
316
+ }
317
+
318
+ // Handle any remaining nodes (cycles)
319
+ nodes.forEach(node => {
320
+ if (!orders[node.id]) {
321
+ orders[node.id] = {
322
+ order: orderNum++,
323
+ label: node.data.label as string,
324
+ gherkinStep: (node.data.gherkinStep as string) ?? '',
325
+ isFirstNode: (node.data.isFirstNode as boolean) ?? false,
326
+ icon: (node.data.icon as string) ?? '',
327
+ parameters: ((node.data.parameters as NodeData['parameters']) ?? []).map(p => ({
328
+ name: p.name,
329
+ value: p.value,
330
+ type: p.type ?? StepParameterType.STRING,
331
+ order: p.order,
332
+ })),
333
+ templateStepId: (node.data.templateStepId as string) ?? '',
334
+ }
335
+ }
336
+ })
337
+
338
+ return orders
339
+ }, [])
340
+
341
+ useEffect(() => {
342
+ const orders = determineNodeOrders(nodes, edges)
343
+ onNodeOrderChange(orders)
344
+ }, [nodes, edges, determineNodeOrders, onNodeOrderChange])
345
+
346
+ // Clean up orphaned edges when nodes are deleted
347
+ useEffect(() => {
348
+ const nodeIds = new Set(nodes.map(node => node.id))
349
+ const orphanedEdges = edges.filter(edge => !nodeIds.has(edge.source) || !nodeIds.has(edge.target))
350
+
351
+ if (orphanedEdges.length > 0) {
352
+ setEdges(prevEdges => prevEdges.filter(edge => nodeIds.has(edge.source) && nodeIds.has(edge.target)))
353
+ }
354
+ }, [nodes, edges, setEdges])
355
+
356
+ const isValidConnection = useCallback(
357
+ (connection: Connection | Edge) => {
358
+ // Check if source node already has an outgoing connection
359
+ const hasSourceConnection = edges.some(edge => edge.source === connection.source)
360
+
361
+ // Check if target node already has an incoming connection
362
+ const hasTargetConnection = edges.some(edge => edge.target === connection.target)
363
+
364
+ // Allow reconnection if we're connecting the same nodes
365
+ const isReconnecting = edges.some(edge => edge.source === connection.source && edge.target === connection.target)
366
+
367
+ return isReconnecting || (!hasSourceConnection && !hasTargetConnection)
368
+ },
369
+ [edges],
370
+ )
371
+
372
+ const onConnect: OnConnect = useCallback(
373
+ params => {
374
+ if (isValidConnection(params)) {
375
+ setEdges(eds => addEdge(params, eds))
376
+ }
377
+ },
378
+ [setEdges, isValidConnection],
379
+ )
380
+
381
+ const memoizedTemplateSteps = useMemo(() => templateSteps, [templateSteps])
382
+ const memoizedTemplateStepParams = useMemo(() => templateStepParams, [templateStepParams])
383
+ const memoizedLocators = useMemo(() => locators, [locators])
384
+
385
+ // Memoize nodeTypes to prevent recreation
386
+ const nodeTypes = useMemo(
387
+ () => ({
388
+ optionsHeaderNode: (props: NodeProps) => (
389
+ <OptionsHeaderNode {...props} onEdit={nodeId => handleEditNodeRef.current(nodeId)} />
390
+ ),
391
+ }),
392
+ [], // Empty dependency array - now stable since we use ref
393
+ )
394
+
395
+ return (
396
+ <>
397
+ <div className="h-[400px] w-full">
398
+ <div className="mb-8">
399
+ <Button onClick={() => setShowAddNodeDialog(true)}>
400
+ <span className="flex items-center">
401
+ <Plus className="mr-2 h-4 w-4" />
402
+ Add Node
403
+ </span>
404
+ </Button>
405
+ </div>
406
+ <ReactFlow
407
+ nodes={nodes}
408
+ onNodesChange={onNodesChange}
409
+ edges={edges}
410
+ onEdgesChange={onEdgesChange}
411
+ onConnect={onConnect}
412
+ fitView
413
+ colorMode="dark"
414
+ connectionMode={ConnectionMode.Loose}
415
+ edgeTypes={edgeTypes}
416
+ nodeTypes={nodeTypes}
417
+ defaultEdgeOptions={{
418
+ type: 'buttonEdge',
419
+ }}
420
+ connectOnClick={false}
421
+ isValidConnection={isValidConnection}
422
+ proOptions={{ hideAttribution: true }}
423
+ >
424
+ <Background />
425
+ <Controls />
426
+ </ReactFlow>
427
+ </div>
428
+
429
+ {showAddNodeDialog && (
430
+ <NodeForm
431
+ onSubmitAction={addNode}
432
+ initialValues={{
433
+ label: '',
434
+ gherkinStep: '',
435
+ templateStepId: '',
436
+ parameters: [],
437
+ }}
438
+ templateSteps={memoizedTemplateSteps}
439
+ templateStepParams={memoizedTemplateStepParams}
440
+ showAddNodeDialog={showAddNodeDialog}
441
+ setShowAddNodeDialog={setShowAddNodeDialog}
442
+ locators={memoizedLocators}
443
+ defaultValueInput={defaultValueInput}
444
+ locatorGroups={locatorGroups}
445
+ />
446
+ )}
447
+
448
+ {showEditNodeDialog && (
449
+ <NodeForm
450
+ onSubmitAction={handleEditNodeSubmit}
451
+ initialValues={{
452
+ label: editNodeData?.label ?? '',
453
+ gherkinStep: editNodeData?.gherkinStep ?? '',
454
+ templateStepId: editNodeData?.templateStepId ?? '',
455
+ parameters: editNodeData?.parameters ?? [],
456
+ }}
457
+ templateSteps={memoizedTemplateSteps}
458
+ templateStepParams={memoizedTemplateStepParams}
459
+ showAddNodeDialog={showEditNodeDialog}
460
+ setShowAddNodeDialog={setShowEditNodeDialog}
461
+ locators={memoizedLocators}
462
+ defaultValueInput={defaultValueInput}
463
+ locatorGroups={locatorGroups}
464
+ />
465
+ )}
466
+ </>
467
+ )
468
+ }
469
+
470
+ export default memo(FlowDiagram)