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,205 @@
1
+ import prisma from '@/config/db-config'
2
+
3
+ /**
4
+ * Represents a module path structure
5
+ */
6
+ export interface ModulePath {
7
+ path: string
8
+ name: string
9
+ parentPath?: string
10
+ }
11
+
12
+ /**
13
+ * Creates or finds a module by its path
14
+ * @param modulePath - The module path (e.g., "/module1/submodule")
15
+ * @param moduleName - The name of the module
16
+ * @param parentId - Optional parent module ID
17
+ * @returns Promise<string> - The ID of the created or found module
18
+ */
19
+ export async function createOrFindModule(modulePath: string, moduleName: string, parentId?: string): Promise<string> {
20
+ try {
21
+ // First, try to find existing module by name and parent
22
+ const existingModule = await prisma.module.findFirst({
23
+ where: {
24
+ name: moduleName,
25
+ parentId: parentId || null,
26
+ },
27
+ })
28
+
29
+ if (existingModule) {
30
+ return existingModule.id
31
+ }
32
+
33
+ // Create new module
34
+ const newModule = await prisma.module.create({
35
+ data: {
36
+ name: moduleName,
37
+ parentId: parentId || null,
38
+ // Add description only if it's required by the schema
39
+ // For now, we'll leave it empty since it's optional
40
+ },
41
+ })
42
+
43
+ console.log(`Created module: ${moduleName} (${modulePath})`)
44
+ return newModule.id
45
+ } catch (error) {
46
+ console.error(`Error creating module ${moduleName}:`, error)
47
+ throw error
48
+ }
49
+ }
50
+
51
+ /**
52
+ * Builds the complete module hierarchy from a module path
53
+ * @param modulePath - The module path (e.g., "/module1/submodule")
54
+ * @returns Promise<string> - The ID of the leaf module
55
+ */
56
+ export async function buildModuleHierarchy(modulePath: string): Promise<string> {
57
+ try {
58
+ // Parse the module path
59
+ const pathParts = modulePath.split('/').filter(part => part && part !== '')
60
+
61
+ // Handle empty path (root level) - create/find a default root module
62
+ if (pathParts.length === 0) {
63
+ const rootModule = await prisma.module.findFirst({
64
+ where: {
65
+ name: 'root',
66
+ parentId: null,
67
+ },
68
+ })
69
+
70
+ if (rootModule) {
71
+ return rootModule.id
72
+ }
73
+
74
+ // Create default root module
75
+ const newRootModule = await prisma.module.create({
76
+ data: {
77
+ name: 'root',
78
+ parentId: null,
79
+ },
80
+ })
81
+
82
+ console.log(`Created root module for features without module path`)
83
+ return newRootModule.id
84
+ }
85
+
86
+ let currentParentId: string | undefined
87
+ let currentPath = ''
88
+
89
+ // Create or find each module in the hierarchy
90
+ for (let i = 0; i < pathParts.length; i++) {
91
+ const moduleName = pathParts[i]
92
+ currentPath += `/${moduleName}`
93
+
94
+ const moduleId = await createOrFindModule(currentPath, moduleName, currentParentId)
95
+
96
+ currentParentId = moduleId
97
+ }
98
+
99
+ return currentParentId!
100
+ } catch (error) {
101
+ console.error(`Error building module hierarchy for path ${modulePath}:`, error)
102
+ throw error
103
+ }
104
+ }
105
+
106
+ /**
107
+ * Gets all existing modules as a flat list with their paths
108
+ * @returns Promise<Array<{id: string, name: string, path: string, parentId: string | null}>>
109
+ */
110
+ export async function getAllModulesWithPaths(): Promise<
111
+ Array<{
112
+ id: string
113
+ name: string
114
+ path: string
115
+ parentId: string | null
116
+ }>
117
+ > {
118
+ try {
119
+ const modules = await prisma.module.findMany({
120
+ orderBy: [{ parentId: 'asc' }, { name: 'asc' }],
121
+ })
122
+
123
+ // Build paths for each module
124
+ const modulesWithPaths = modules.map(module => {
125
+ const path = buildModulePath(modules, module)
126
+ return {
127
+ id: module.id,
128
+ name: module.name,
129
+ path,
130
+ parentId: module.parentId,
131
+ }
132
+ })
133
+
134
+ return modulesWithPaths
135
+ } catch (error) {
136
+ console.error('Error fetching modules with paths:', error)
137
+ throw error
138
+ }
139
+ }
140
+
141
+ /**
142
+ * Builds the full path for a module based on its hierarchy
143
+ * @param allModules - All modules from the database
144
+ * @param targetModule - The module to build the path for
145
+ * @returns string - The full module path
146
+ */
147
+ function buildModulePath(
148
+ allModules: Array<{ id: string; name: string; parentId: string | null }>,
149
+ targetModule: { id: string; name: string; parentId: string | null },
150
+ ): string {
151
+ const pathParts: string[] = []
152
+ let currentModule = targetModule
153
+
154
+ // Traverse up the hierarchy
155
+ while (currentModule) {
156
+ pathParts.unshift(currentModule.name)
157
+
158
+ if (currentModule.parentId) {
159
+ currentModule = allModules.find(m => m.id === currentModule.parentId)!
160
+ if (!currentModule) break
161
+ } else {
162
+ break
163
+ }
164
+ }
165
+
166
+ return '/' + pathParts.join('/')
167
+ }
168
+
169
+ /**
170
+ * Finds a module by its path
171
+ * @param modulePath - The module path to find
172
+ * @returns Promise<string | null> - The module ID or null if not found
173
+ */
174
+ export async function findModuleByPath(modulePath: string): Promise<string | null> {
175
+ try {
176
+ const modules = await prisma.module.findMany()
177
+ const pathParts = modulePath.split('/').filter(part => part && part !== '')
178
+
179
+ if (pathParts.length === 0) {
180
+ return null
181
+ }
182
+
183
+ // Find the root module
184
+ let currentModule = modules.find(m => m.name === pathParts[0] && !m.parentId)
185
+ if (!currentModule) {
186
+ return null
187
+ }
188
+
189
+ // Traverse down the hierarchy
190
+ for (let i = 1; i < pathParts.length; i++) {
191
+ const childModule = modules.find(m => m.name === pathParts[i] && m.parentId === currentModule!.id)
192
+
193
+ if (!childModule) {
194
+ return null
195
+ }
196
+
197
+ currentModule = childModule
198
+ }
199
+
200
+ return currentModule.id
201
+ } catch (error) {
202
+ console.error(`Error finding module by path ${modulePath}:`, error)
203
+ return null
204
+ }
205
+ }
@@ -0,0 +1,71 @@
1
+ import { Module } from '@prisma/client'
2
+
3
+ /**
4
+ * Builds the hierarchical path for a module based on its parent modules
5
+ * @param modules - Array of all modules
6
+ * @param selectedModule - The module to get the path for
7
+ * @returns The hierarchical path as a string (e.g., "/user/user profile")
8
+ */
9
+ export function buildModulePath(modules: Module[], selectedModule: Module): string {
10
+ const path: string[] = []
11
+ let currentModule: Module | null = selectedModule
12
+
13
+ // Build path from current module up to root
14
+ while (currentModule) {
15
+ path.unshift(currentModule.name)
16
+ currentModule = modules.find(m => m.id === currentModule?.parentId) || null
17
+ }
18
+
19
+ // Return path with leading slash
20
+ return `/${path.join('/')}`
21
+ }
22
+
23
+ /**
24
+ * Alternative implementation that can handle modules with parent relationships
25
+ * This version works with the current data structure where we have parent info
26
+ */
27
+ export function buildModulePathFromParent(
28
+ modules: (Module & { parent: { name: string } })[],
29
+ selectedModule: Module & { parent: { name: string } },
30
+ ): string {
31
+ const path: string[] = []
32
+ let currentModule: (Module & { parent: { name: string } }) | null = selectedModule
33
+
34
+ // Build path from current module up to root
35
+ while (currentModule) {
36
+ path.unshift(currentModule.name)
37
+
38
+ if (currentModule.parent?.name) {
39
+ // Find the parent module in the modules array
40
+ const parentModule = modules.find(m => m.name === currentModule?.parent?.name)
41
+ currentModule = parentModule || null
42
+ } else {
43
+ // No parent, we've reached the root
44
+ currentModule = null
45
+ }
46
+ }
47
+
48
+ // Return path with leading slash
49
+ return `/${path.join('/')}`
50
+ }
51
+
52
+ /**
53
+ * Builds paths for all modules in a single pass for better performance
54
+ * @param modules - Array of all modules with parent info
55
+ * @returns Map of module ID to path string
56
+ */
57
+ export function buildAllModulePaths(modules: (Module & { parent: { name: string } })[]): Map<string, string> {
58
+ const pathMap = new Map<string, string>()
59
+
60
+ // First pass: create a map for quick lookup
61
+ const moduleMap = new Map<string, Module & { parent: { name: string } }>()
62
+ modules.forEach(module => moduleMap.set(module.id, module))
63
+
64
+ // Second pass: build paths for each module
65
+ modules.forEach(module => {
66
+ const path = buildModulePathFromParent(modules, module)
67
+ pathMap.set(module.id, path)
68
+ })
69
+
70
+ return pathMap
71
+ }
@@ -0,0 +1,6 @@
1
+ import crypto from 'crypto'
2
+
3
+ export function generateUniqueTestCaseIdentifier(): string {
4
+ const id = crypto.randomBytes(8).toString('hex')
5
+ return `tc_${id}`
6
+ }
@@ -0,0 +1,83 @@
1
+ /**
2
+ * Log formatting utilities for storing and retrieving test run logs
3
+ */
4
+
5
+ export interface LogEntry {
6
+ type: 'stdout' | 'stderr' | 'status'
7
+ message: string
8
+ timestamp: Date
9
+ }
10
+
11
+ /**
12
+ * Formats log entries into a single text string for storage in the database
13
+ * Format: [timestamp] [TYPE] message
14
+ *
15
+ * @param logs - Array of log entries to format
16
+ * @returns Formatted log string
17
+ */
18
+ export function formatLogsForStorage(logs: LogEntry[]): string {
19
+ return logs
20
+ .map(log => {
21
+ const timestamp = log.timestamp.toISOString()
22
+ const type = log.type.toUpperCase()
23
+ // Escape newlines in message to preserve them in the formatted string
24
+ const escapedMessage = log.message.replace(/\n/g, '\\n')
25
+ return `[${timestamp}] [${type}] ${escapedMessage}`
26
+ })
27
+ .join('\n')
28
+ }
29
+
30
+ /**
31
+ * Parses formatted log text back into an array of LogEntry objects
32
+ *
33
+ * @param formattedLogs - Formatted log string from database
34
+ * @returns Array of log entries
35
+ */
36
+ export function parseLogsFromStorage(formattedLogs: string): LogEntry[] {
37
+ if (!formattedLogs || formattedLogs.trim() === '') {
38
+ return []
39
+ }
40
+
41
+ const lines = formattedLogs.split('\n')
42
+ const parsedLogs: LogEntry[] = []
43
+
44
+ for (const line of lines) {
45
+ if (!line.trim()) continue
46
+
47
+ try {
48
+ // Match format: [timestamp] [TYPE] message
49
+ const match = line.match(/^\[([^\]]+)\] \[([^\]]+)\] (.+)$/)
50
+
51
+ if (match) {
52
+ const [, timestampStr, typeStr, message] = match
53
+ const timestamp = new Date(timestampStr)
54
+ const type = typeStr.toLowerCase() as 'stdout' | 'stderr' | 'status'
55
+
56
+ // Unescape newlines in message
57
+ const unescapedMessage = message.replace(/\\n/g, '\n')
58
+
59
+ // Validate type
60
+ if (type === 'stdout' || type === 'stderr' || type === 'status') {
61
+ parsedLogs.push({
62
+ type,
63
+ message: unescapedMessage,
64
+ timestamp: isNaN(timestamp.getTime()) ? new Date() : timestamp,
65
+ })
66
+ }
67
+ } else {
68
+ // Fallback: treat as stdout if format doesn't match
69
+ parsedLogs.push({
70
+ type: 'stdout',
71
+ message: line,
72
+ timestamp: new Date(),
73
+ })
74
+ }
75
+ } catch (error) {
76
+ // Skip malformed lines
77
+ console.error('[LogFormatter] Error parsing log line:', line, error)
78
+ }
79
+ }
80
+
81
+ return parsedLogs
82
+ }
83
+
@@ -0,0 +1,191 @@
1
+ import type { SpawnedProcess } from '@/tests/utils/spawner.util'
2
+ import { EventEmitter } from 'events'
3
+ import { taskSpawner } from '@/tests/utils/spawner.util'
4
+
5
+ /**
6
+ * Process Manager - Singleton to track running test processes by test run ID
7
+ *
8
+ * This manager maintains a registry of active test processes, allowing
9
+ * the SSE route handler to look up processes and stream their logs.
10
+ *
11
+ * Uses global variable pattern (like Prisma) to persist across Next.js runtime contexts
12
+ *
13
+ * Security: Currently stores processes by testRunId only.
14
+ * TODO: When user authentication is implemented, consider adding user isolation:
15
+ * - Option 1: Use composite keys like `${userId}:${testRunId}`
16
+ * - Option 2: Store userId in process metadata and filter by userId in get() method
17
+ * - Option 3: Create separate ProcessManager instances per user (more complex)
18
+ */
19
+ class ProcessManager extends EventEmitter {
20
+ private processes: Map<string, SpawnedProcess> = new Map()
21
+ // Track event listeners for cleanup
22
+ private eventListeners: Map<string, Map<string, () => void>> = new Map()
23
+
24
+ private constructor() {
25
+ super()
26
+ // Private constructor for singleton pattern
27
+ }
28
+
29
+ /**
30
+ * Get the singleton instance of ProcessManager
31
+ * Uses global variable to persist across Next.js runtime contexts
32
+ */
33
+ static getInstance(): ProcessManager {
34
+ const globalForProcessManager = global as unknown as {
35
+ processManager: ProcessManager | undefined
36
+ }
37
+
38
+ if (!globalForProcessManager.processManager) {
39
+ globalForProcessManager.processManager = new ProcessManager()
40
+ }
41
+
42
+ return globalForProcessManager.processManager
43
+ }
44
+
45
+ /**
46
+ * Register a process for a test run
47
+ * Sets up event listeners to parse custom events from stdout/stderr
48
+ * @param testRunId - The test run ID
49
+ * @param process - The spawned process instance
50
+ */
51
+ register(testRunId: string, process: SpawnedProcess): void {
52
+ this.processes.set(testRunId, process)
53
+
54
+ // Set up listeners to parse custom events from stdout/stderr
55
+ const listeners = new Map<string, () => void>()
56
+
57
+ // Handler for stdout events - parse for custom events
58
+ const onStdout = ({ processName, data }: { processName: string; data: string }) => {
59
+ if (processName === process.name) {
60
+ this.parseAndEmitCustomEvents(testRunId, data)
61
+ }
62
+ }
63
+
64
+ // Handler for stderr events - parse for custom events
65
+ const onStderr = ({ processName, data }: { processName: string; data: string }) => {
66
+ if (processName === process.name) {
67
+ this.parseAndEmitCustomEvents(testRunId, data)
68
+ }
69
+ }
70
+
71
+ // Store cleanup functions
72
+ listeners.set('stdout', () => taskSpawner.removeListener('stdout', onStdout))
73
+ listeners.set('stderr', () => taskSpawner.removeListener('stderr', onStderr))
74
+
75
+ // Register listeners
76
+ taskSpawner.on('stdout', onStdout)
77
+ taskSpawner.on('stderr', onStderr)
78
+
79
+ this.eventListeners.set(testRunId, listeners)
80
+ }
81
+
82
+ /**
83
+ * Parse stdout/stderr output for custom event markers and emit them
84
+ * Expects events in JSON format: {"event":"scenario::end","data":{...}}
85
+ */
86
+ private parseAndEmitCustomEvents(testRunId: string, output: string): void {
87
+ // Split by newlines to handle multi-line output
88
+ const lines = output.split('\n')
89
+
90
+ for (const line of lines) {
91
+ if (!line.trim()) continue
92
+
93
+ try {
94
+ // Look for JSON objects in the line that contain an "event" field
95
+ // Matches: {"event":"scenario::end","data":{...}}
96
+ const jsonMatch = line.match(/\{[\s\S]*"event"[\s\S]*\}/)
97
+ if (jsonMatch) {
98
+ const eventData = JSON.parse(jsonMatch[0])
99
+ if (eventData.event === 'scenario::end') {
100
+ console.log(`[ProcessManager] Parsed scenario::end event for testRunId: ${testRunId}`, eventData)
101
+ this.emit('scenario::end', {
102
+ testRunId,
103
+ scenarioName: eventData.data?.scenarioName,
104
+ status: eventData.data?.status,
105
+ tracePath: eventData.data?.tracePath,
106
+ ...eventData.data,
107
+ })
108
+ console.log(`[ProcessManager] Emitted scenario::end event for testRunId: ${testRunId}`)
109
+ }
110
+ }
111
+ } catch (error) {
112
+ // Not a custom event, continue parsing other lines
113
+ // This is expected for regular log output
114
+ // Only log if it looks like it might be a JSON parse error
115
+ if (line.trim().startsWith('{')) {
116
+ console.warn(`[ProcessManager] Failed to parse potential event JSON: ${line.substring(0, 100)}`, error)
117
+ }
118
+ }
119
+ }
120
+ }
121
+
122
+ /**
123
+ * Get a process by test run ID
124
+ * @param testRunId - The test run ID
125
+ * @returns The spawned process or undefined if not found
126
+ */
127
+ get(testRunId: string): SpawnedProcess | undefined {
128
+ return this.processes.get(testRunId)
129
+ }
130
+
131
+ /**
132
+ * Unregister a process for a test run
133
+ * Cleans up event listeners
134
+ * @param testRunId - The test run ID
135
+ * @returns True if the process was found and removed, false otherwise
136
+ */
137
+ unregister(testRunId: string): boolean {
138
+ // Clean up event listeners
139
+ const listeners = this.eventListeners.get(testRunId)
140
+ if (listeners) {
141
+ listeners.forEach(cleanup => cleanup())
142
+ this.eventListeners.delete(testRunId)
143
+ }
144
+
145
+ const deleted = this.processes.delete(testRunId)
146
+ console.log(
147
+ `[ProcessManager] Unregistering process for testRunId: ${testRunId}, deleted: ${deleted}, remaining processes: ${this.processes.size}`,
148
+ )
149
+ return deleted
150
+ }
151
+
152
+ /**
153
+ * Check if a process exists for a test run
154
+ * @param testRunId - The test run ID
155
+ * @returns True if a process exists, false otherwise
156
+ */
157
+ has(testRunId: string): boolean {
158
+ return this.processes.has(testRunId)
159
+ }
160
+
161
+ /**
162
+ * Get all registered test run IDs (for debugging)
163
+ * @returns Array of test run IDs
164
+ */
165
+ getAllTestRunIds(): string[] {
166
+ return Array.from(this.processes.keys())
167
+ }
168
+
169
+ /**
170
+ * Clear all registered processes (useful for cleanup)
171
+ */
172
+ clear(): void {
173
+ // Clean up all event listeners
174
+ this.eventListeners.forEach(listeners => {
175
+ listeners.forEach(cleanup => cleanup())
176
+ })
177
+ this.eventListeners.clear()
178
+ this.processes.clear()
179
+ }
180
+
181
+ /**
182
+ * Get the number of active processes
183
+ * @returns The number of registered processes
184
+ */
185
+ size(): number {
186
+ return this.processes.size
187
+ }
188
+ }
189
+
190
+ // Export singleton instance
191
+ export const processManager = ProcessManager.getInstance()