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,166 @@
1
+ import prisma from '@/config/db-config'
2
+ import { writeTemplateStepFile, deleteTemplateStepFile, generateFileContent } from './template-step-file-generator'
3
+ import { TemplateStepGroupType } from '@prisma/client'
4
+
5
+ // TemplateStepGroupType helper - will be available from @prisma/client after migration
6
+ type TemplateStepGroupTypeLocal = 'ACTION' | 'VALIDATION'
7
+
8
+ // Type helper to safely extract type from Prisma templateStepGroup records
9
+ type TemplateStepGroupWithType = {
10
+ id: string
11
+ name: string
12
+ description: string | null
13
+ type?: TemplateStepGroupTypeLocal
14
+ createdAt: Date
15
+ updatedAt: Date
16
+ }
17
+
18
+ function getGroupType(group: unknown): TemplateStepGroupTypeLocal {
19
+ const groupWithType = group as TemplateStepGroupWithType
20
+ const type = groupWithType.type
21
+ if (type === 'VALIDATION' || type === 'ACTION') {
22
+ return type
23
+ }
24
+ return 'ACTION' // default
25
+ }
26
+
27
+ /**
28
+ * Regenerates the file for a specific template step group
29
+ * This function is called whenever template steps in a group change
30
+ */
31
+ export async function regenerateTemplateStepGroupFile(groupId: string): Promise<void> {
32
+ try {
33
+ // Get the template step group with all its template steps
34
+ const group = await prisma.templateStepGroup.findUnique({
35
+ where: { id: groupId },
36
+ include: {
37
+ templateSteps: {
38
+ orderBy: {
39
+ // Order by creation time or any other field you prefer
40
+ createdAt: 'asc',
41
+ },
42
+ },
43
+ },
44
+ })
45
+
46
+ if (!group) {
47
+ throw new Error(`Template step group with ID ${groupId} not found`)
48
+ }
49
+
50
+ // Generate file content from template steps
51
+ const content = generateFileContent(group.templateSteps)
52
+
53
+ // Write the file
54
+ const type = getGroupType(group)
55
+ await writeTemplateStepFile(group.name, content, type)
56
+
57
+ console.log(`File regenerated for template step group: ${group.name}`)
58
+ } catch (error) {
59
+ console.error(`Failed to regenerate file for template step group ${groupId}:`, error)
60
+ throw new Error(`File regeneration failed: ${error}`)
61
+ }
62
+ }
63
+
64
+ /**
65
+ * Creates a placeholder file for a new template step group
66
+ * Called when a new group is created
67
+ * @deprecated Use createTemplateStepGroupFile from template-step-file-manager-intelligent.ts instead
68
+ */
69
+ export async function createTemplateStepGroupFile(
70
+ groupName: string,
71
+ type: TemplateStepGroupType | string = 'ACTION',
72
+ ): Promise<void> {
73
+ try {
74
+ // Create empty placeholder content with required imports
75
+ const placeholderContent =
76
+ '// This file is generated automatically. Add template steps to this group to generate content.'
77
+
78
+ // Write the placeholder file
79
+ await writeTemplateStepFile(groupName, placeholderContent, type)
80
+
81
+ console.log(`Placeholder file created for template step group: ${groupName}`)
82
+ } catch (error) {
83
+ console.error(`Failed to create placeholder file for group "${groupName}":`, error)
84
+ throw new Error(`File creation failed: ${error}`)
85
+ }
86
+ }
87
+
88
+ /**
89
+ * Deletes the file for a template step group
90
+ * Called when a group is deleted
91
+ * @deprecated Use removeTemplateStepGroupFile from template-step-file-manager-intelligent.ts instead
92
+ */
93
+ export async function removeTemplateStepGroupFile(
94
+ groupName: string,
95
+ type: TemplateStepGroupType | string = 'ACTION',
96
+ ): Promise<void> {
97
+ try {
98
+ await deleteTemplateStepFile(groupName, type)
99
+
100
+ console.log(`File deleted for template step group: ${groupName}`)
101
+ } catch (error) {
102
+ console.error(`Failed to delete file for group "${groupName}":`, error)
103
+ throw new Error(`File deletion failed: ${error}`)
104
+ }
105
+ }
106
+
107
+ /**
108
+ * Handles file regeneration when a template step is created, updated, or deleted
109
+ * This function determines which groups need file regeneration
110
+ */
111
+ export async function handleTemplateStepChange(
112
+ templateStepId: string,
113
+ operation: 'create' | 'update' | 'delete',
114
+ ): Promise<void> {
115
+ try {
116
+ let groupId: string | null = null
117
+
118
+ if (operation === 'delete') {
119
+ // For delete operations, we need to get the group ID before deletion
120
+ const step = await prisma.templateStep.findUnique({
121
+ where: { id: templateStepId },
122
+ select: { templateStepGroupId: true },
123
+ })
124
+ groupId = step?.templateStepGroupId || null
125
+ } else {
126
+ // For create/update operations, get the current group ID
127
+ const step = await prisma.templateStep.findUnique({
128
+ where: { id: templateStepId },
129
+ select: { templateStepGroupId: true },
130
+ })
131
+ groupId = step?.templateStepGroupId || null
132
+ }
133
+
134
+ if (groupId) {
135
+ // Regenerate the file for the affected group
136
+ await regenerateTemplateStepGroupFile(groupId)
137
+ }
138
+ } catch (error) {
139
+ console.error(`Failed to handle template step change for step ${templateStepId}:`, error)
140
+ throw new Error(`File update failed: ${error}`)
141
+ }
142
+ }
143
+
144
+ /**
145
+ * Handles file regeneration when a template step is moved between groups
146
+ * This is a special case that requires regenerating files for both groups
147
+ */
148
+ export async function handleTemplateStepGroupChange(
149
+ oldGroupId: string | null,
150
+ newGroupId: string | null,
151
+ ): Promise<void> {
152
+ try {
153
+ // Regenerate file for the old group (if it exists)
154
+ if (oldGroupId) {
155
+ await regenerateTemplateStepGroupFile(oldGroupId)
156
+ }
157
+
158
+ // Regenerate file for the new group (if it exists)
159
+ if (newGroupId) {
160
+ await regenerateTemplateStepGroupFile(newGroupId)
161
+ }
162
+ } catch (error) {
163
+ console.error(`Failed to handle template step group change:`, error)
164
+ throw new Error(`File update failed: ${error}`)
165
+ }
166
+ }
@@ -0,0 +1,31 @@
1
+ import { clsx, type ClassValue } from 'clsx'
2
+ import { twMerge } from 'tailwind-merge'
3
+ export function cn(...inputs: ClassValue[]) {
4
+ return twMerge(clsx(inputs))
5
+ }
6
+
7
+ export function calculateCompletionPercentage(total: number, completed: number) {
8
+ return Math.round((completed / total) * 100)
9
+ }
10
+
11
+ /**
12
+ * Formats a date to show only date and time (without seconds/milliseconds)
13
+ * @param date - Date string or Date object
14
+ * @returns Formatted date string in format: "MM/DD/YYYY, HH:MM AM/PM"
15
+ */
16
+ export function formatDateTime(date: string | Date | null | undefined): string {
17
+ if (!date) return '-'
18
+
19
+ const dateObj = typeof date === 'string' ? new Date(date) : date
20
+
21
+ if (isNaN(dateObj.getTime())) return '-'
22
+
23
+ return dateObj.toLocaleString('en-US', {
24
+ year: 'numeric',
25
+ month: '2-digit',
26
+ day: '2-digit',
27
+ hour: '2-digit',
28
+ minute: '2-digit',
29
+ hour12: true,
30
+ })
31
+ }
@@ -0,0 +1,14 @@
1
+ {
2
+ "demoqa": {
3
+ "baseUrl": "https://demoqa.com/",
4
+ "apiBaseUrl": "",
5
+ "email": "",
6
+ "password": ""
7
+ },
8
+ "demo_test_site": {
9
+ "baseUrl": "https://demo-test-site-beta.vercel.app/login",
10
+ "apiBaseUrl": "",
11
+ "email": "demo@example.com",
12
+ "password": ""
13
+ }
14
+ }
@@ -0,0 +1,41 @@
1
+ import { World, IWorldOptions, setWorldConstructor, setDefaultTimeout } from '@cucumber/cucumber'
2
+ import * as chai from 'chai'
3
+ import chaiAsPromised from 'chai-as-promised'
4
+ import { BrowserContext, Page } from 'playwright'
5
+
6
+ setDefaultTimeout(120 * 1000)
7
+
8
+ export interface ScenarioData {
9
+ token?: string
10
+ vars: Record<string, unknown>
11
+ }
12
+ export class CustomWorld extends World {
13
+ context!: BrowserContext
14
+ page!: Page
15
+ data: ScenarioData = {
16
+ vars: {},
17
+ }
18
+ constructor(options: IWorldOptions) {
19
+ super(options)
20
+ }
21
+
22
+ setVar(key: string, value: unknown): void {
23
+ this.data.vars[key] = value
24
+ }
25
+
26
+ getVar<T = unknown>(key: string): T {
27
+ if (!(key in this.data.vars)) {
28
+ throw new Error(`Variable ${key} not found`)
29
+ }
30
+ return this.data.vars[key] as T
31
+ }
32
+
33
+ clearVars(): void {
34
+ this.data.vars = {}
35
+ }
36
+ }
37
+
38
+ setWorldConstructor(CustomWorld)
39
+
40
+ chai.use(chaiAsPromised)
41
+ export const expect = chai.expect
@@ -0,0 +1,80 @@
1
+ import { BrowserName } from '@/types/executor/browser.type'
2
+ import { CliOptions, startCli } from '@/tests/utils/cli.util.js'
3
+ import { spawnTask, waitForTask } from '@/tests/utils/spawner.util.js'
4
+ import { config } from 'dotenv'
5
+
6
+ function setEnvironmentVariables(environment: string, headless: boolean, browser: BrowserName) {
7
+ process.env.ENVIRONMENT = environment
8
+ process.env.HEADLESS = headless.toString()
9
+ process.env.BROWSER = browser
10
+ }
11
+
12
+ /**
13
+ * Main entry point for the CLI application
14
+ * Handles CLI parsing, error handling, and application lifecycle
15
+ */
16
+ async function bootstrap(): Promise<void> {
17
+ // Load environment variables
18
+ config()
19
+
20
+ try {
21
+ // Parse CLI arguments and get options
22
+ const { environment, tags, parallel, browser, headless }: CliOptions = startCli()
23
+
24
+ // Log parsed options with better formatting
25
+ console.log(
26
+ `Running tests in the following configuration\nEnvironment: ${environment}\nTags: ${tags}\nParallel: ${parallel}\nBrowser: ${browser}\nHeadless: ${headless}`,
27
+ )
28
+
29
+ setEnvironmentVariables(environment, headless as unknown as boolean, browser as unknown as BrowserName)
30
+
31
+ // Build the cucumber command with appropriate flags
32
+ const cucumberArgs: string[] = []
33
+
34
+ if (tags) {
35
+ cucumberArgs.push('-t', tags)
36
+ }
37
+
38
+ if (parallel > 1) {
39
+ cucumberArgs.push('--parallel', parallel.toString())
40
+ }
41
+
42
+ // Spawn the cucumber test process
43
+ console.log('🚀 Starting cucumber test process...')
44
+ await spawnTask('npm', ['run', 'test', ...cucumberArgs], {
45
+ streamLogs: true,
46
+ prefixLogs: true,
47
+ logPrefix: 'cucumber-test',
48
+ captureOutput: true,
49
+ })
50
+
51
+ // Wait for the test process to complete
52
+ const exitCode = await waitForTask('cucumber-test')
53
+
54
+ if (exitCode === 0) {
55
+ console.log('✅ Tests completed successfully')
56
+ } else {
57
+ console.log(`❌ Tests failed with exit code: ${exitCode}`)
58
+ }
59
+
60
+ process.exit(exitCode || 0)
61
+ } catch (error) {
62
+ console.error('❌ Application failed with error:')
63
+ console.error(error instanceof Error ? error.message : 'Unknown error occurred')
64
+ process.exit(1)
65
+ }
66
+ }
67
+
68
+ // Handle uncaught exceptions and unhandled rejections
69
+ process.on('uncaughtException', error => {
70
+ console.error('❌ Uncaught Exception:', error.message)
71
+ process.exit(1)
72
+ })
73
+
74
+ process.on('unhandledRejection', reason => {
75
+ console.error('❌ Unhandled Rejection:', reason)
76
+ process.exit(1)
77
+ })
78
+
79
+ // Start the application
80
+ bootstrap()
@@ -0,0 +1,99 @@
1
+ import { After, AfterAll, AfterStep, Before, BeforeAll, setDefaultTimeout } from '@cucumber/cucumber'
2
+ import { CustomWorld } from '../config/executor/world.js'
3
+ import { BrowserName } from '@/types/executor/browser.type'
4
+ import { config } from 'dotenv'
5
+ import { chromium, ChromiumBrowser, firefox, FirefoxBrowser, webkit, WebKitBrowser } from 'playwright'
6
+
7
+ // Load environment variables
8
+ config()
9
+
10
+ // Initialize browser
11
+ let browser: ChromiumBrowser | FirefoxBrowser | WebKitBrowser
12
+
13
+ // Track scenario status
14
+ let currentScenarioStatus: string = 'unknown'
15
+
16
+ BeforeAll(async function () {
17
+ setDefaultTimeout(60000)
18
+ const browserName = (process.env.BROWSER as BrowserName) || 'chromium'
19
+ switch (browserName) {
20
+ case 'chromium':
21
+ browser = await chromium.launch({
22
+ headless: process.env.HEADLESS === 'true',
23
+ })
24
+ break
25
+ case 'firefox':
26
+ browser = await firefox.launch({
27
+ headless: process.env.HEADLESS === 'true',
28
+ })
29
+ break
30
+ case 'webkit':
31
+ browser = await webkit.launch({
32
+ headless: process.env.HEADLESS === 'true',
33
+ })
34
+ break
35
+ default:
36
+ throw new Error(`Invalid browser name: ${browserName}`)
37
+ }
38
+ })
39
+
40
+ Before(async function (this: CustomWorld) {
41
+ this.clearVars()
42
+ this.context = await browser.newContext()
43
+ await this.context.tracing.start({
44
+ screenshots: true,
45
+ snapshots: true,
46
+ sources: true,
47
+ })
48
+ this.page = await this.context.newPage()
49
+ })
50
+
51
+ AfterStep(async function (this: CustomWorld, result) {
52
+ // Track the worst status encountered (failed > skipped > passed)
53
+ const status = result.result?.status
54
+ if (status === 'FAILED') {
55
+ currentScenarioStatus = 'failed'
56
+ } else if (status === 'SKIPPED' && currentScenarioStatus !== 'failed') {
57
+ currentScenarioStatus = 'skipped'
58
+ } else if (status === 'PASSED' && currentScenarioStatus === 'unknown') {
59
+ currentScenarioStatus = 'passed'
60
+ }
61
+ })
62
+
63
+ After(async function (this: CustomWorld, scenario) {
64
+ // Emit scenario end event as JSON to stdout
65
+ // ProcessManager will parse this and re-emit it as an event
66
+ let tracePath: string | undefined
67
+ if (scenario.result?.status === 'FAILED') {
68
+ tracePath = `${process.cwd()}/src/tests/reports/traces/${crypto.randomUUID()}.zip`
69
+ await this.context.tracing.stop({
70
+ path: tracePath,
71
+ })
72
+ }
73
+
74
+ const eventData = {
75
+ event: 'scenario::end',
76
+ data: {
77
+ scenarioName: scenario.pickle.name,
78
+ status: currentScenarioStatus,
79
+ tracePath: tracePath,
80
+ },
81
+ }
82
+
83
+ // Write to stdout in a parseable JSON format
84
+ // Use process.stdout.write to ensure it's captured by TaskSpawner
85
+ const eventJson = JSON.stringify(eventData)
86
+ console.log(eventJson)
87
+ // Also write directly to stdout to ensure it's captured
88
+ process.stdout.write(eventJson + '\n')
89
+
90
+ // Reset status for next scenario
91
+ currentScenarioStatus = 'unknown'
92
+
93
+ await this.page.close()
94
+ await this.context.close()
95
+ })
96
+
97
+ AfterAll(async function () {
98
+ await browser.close()
99
+ })
@@ -0,0 +1,62 @@
1
+ /**
2
+ * @name click
3
+ * @description Template step for handling element click
4
+ * @type ACTION
5
+ */
6
+ import { When } from '@cucumber/cucumber'
7
+ import { CustomWorld } from '../../config/executor/world.js'
8
+ import { SelectorName } from '@/types/locator/locator.type'
9
+ import { resolveLocator } from '../../utils/locator.util.js'
10
+
11
+ // This file is generated automatically. Add template steps to this group to generate content.
12
+
13
+ /**
14
+ * @name click
15
+ * @description Template step for clicking on an element
16
+ * @icon MOUSE
17
+ */
18
+ When('the user clicks on the {string} element', async function (this: CustomWorld, elementName: SelectorName) {
19
+ const selector = await resolveLocator(this.page, elementName)
20
+ if (!selector) {
21
+ throw new Error(`Selector ${elementName} not found. Current url: ${this.page.url()}`)
22
+ }
23
+ try {
24
+ await this.page.locator(selector).click()
25
+ } catch (error) {
26
+ throw new Error(`Failed to click on the ${elementName} element: ${error}`)
27
+ }
28
+ })
29
+
30
+ /**
31
+ * @name double click
32
+ * @description Template step for double clicking on an element
33
+ * @icon MOUSE
34
+ */
35
+ When('the user double clicks on the {string} element', async function (this: CustomWorld, elementName: SelectorName) {
36
+ const selector = await resolveLocator(this.page, elementName)
37
+ if (!selector) {
38
+ throw new Error(`Selector ${elementName} not found. Current url: ${this.page.url()}`)
39
+ }
40
+ try {
41
+ await this.page.locator(selector).dblclick()
42
+ } catch (error) {
43
+ throw new Error(`Failed to double click on the ${elementName} element: ${error}`)
44
+ }
45
+ })
46
+
47
+ /**
48
+ * @name right click
49
+ * @description Template step for right clicking on an element
50
+ * @icon MOUSE
51
+ */
52
+ When('the user right clicks on the {string} element', async function (this: CustomWorld, elementName: SelectorName) {
53
+ const selector = await resolveLocator(this.page, elementName)
54
+ if (!selector) {
55
+ throw new Error(`Selector ${elementName} not found. Current url: ${this.page.url()}`)
56
+ }
57
+ try {
58
+ await this.page.locator(selector).click({ button: 'right' })
59
+ } catch (error) {
60
+ throw new Error(`Failed to right click on the ${elementName} element: ${error}`)
61
+ }
62
+ })
@@ -0,0 +1,31 @@
1
+ /**
2
+ * @name hover
3
+ * @description Template steps that handles hover actions
4
+ * @type ACTION
5
+ */
6
+ import { When } from '@cucumber/cucumber';
7
+ import { CustomWorld } from '../../config/executor/world.js';
8
+ import { SelectorName } from '../../../types/locator/locator.type';
9
+ import { resolveLocator } from '../../utils/locator.util.js';
10
+
11
+ // This file is generated automatically. Add template steps to this group to generate content.
12
+
13
+ /**
14
+ * @name hover
15
+ * @description Template step for hovering over an element
16
+ * @icon MOUSE
17
+ */
18
+ When(
19
+ 'the user hovers the cursor over the {string} element',
20
+ async function (this: CustomWorld, elementName: SelectorName) {
21
+ try {
22
+ const selector = await resolveLocator(this.page, elementName);
23
+ if (!selector) {
24
+ throw new Error(`Selector ${elementName} not found`);
25
+ }
26
+ await this.page.locator(selector).hover();
27
+ } catch (error) {
28
+ throw new Error(`Failed to hover over the ${elementName} element: ${error}`);
29
+ }
30
+ }
31
+ );
@@ -0,0 +1,149 @@
1
+ /**
2
+ * @name input
3
+ * @description Template steps that deal with inputs
4
+ * @type ACTION
5
+ */
6
+ import { When } from '@cucumber/cucumber';
7
+ import { CustomWorld } from '../../config/executor/world.js';
8
+ import { SelectorName } from '@/types/locator/locator.type';
9
+ import { resolveLocator } from '../../utils/locator.util.js';
10
+
11
+ // This file is generated automatically. Add template steps to this group to generate content.
12
+
13
+ /**
14
+ * @name fill
15
+ * @description Template step for filling up an input field with a provided value
16
+ * @icon INPUT
17
+ */
18
+ When(
19
+ 'the user fills in the {string} input field with value {string}',
20
+ async function (this: CustomWorld, elementName: SelectorName, value: string) {
21
+ const selector = await resolveLocator(this.page, elementName);
22
+ if (!selector) {
23
+ throw new Error(`Selector ${elementName} not found`);
24
+ }
25
+ try {
26
+ await this.page.locator(selector).fill(value);
27
+ } catch (error) {
28
+ throw new Error(
29
+ `Failed to fill in the ${elementName} input field with value ${value}: ${error}`
30
+ );
31
+ }
32
+ }
33
+ );
34
+
35
+ /**
36
+ * @name clear
37
+ * @description Template step for clearing an input field
38
+ * @icon INPUT
39
+ */
40
+ When(
41
+ 'the user clears the {string} field',
42
+ async function (this: CustomWorld, elementName: SelectorName) {
43
+ const selector = await resolveLocator(this.page, elementName);
44
+ if (!selector) {
45
+ throw new Error(`Selector ${elementName} not found`);
46
+ }
47
+ try {
48
+ await this.page.locator(selector).clear();
49
+ } catch (error) {
50
+ throw new Error(`Failed to clear the ${elementName} field: ${error}`);
51
+ }
52
+ }
53
+ );
54
+
55
+ /**
56
+ * @name select dropdown option
57
+ * @description Template step for selecting a particular option inside a dropdown element
58
+ * @icon INPUT
59
+ */
60
+ When(
61
+ 'the user selects the {string} option of the {string} dropdown',
62
+ async function (
63
+ this: CustomWorld,
64
+ optionName: string,
65
+ elementName: SelectorName
66
+ ) {
67
+ const selector = await resolveLocator(this.page, elementName);
68
+ if (!selector) {
69
+ throw new Error(`Selector ${elementName} not found`);
70
+ }
71
+ try {
72
+ await this.page.locator(selector).selectOption(optionName);
73
+ } catch (error) {
74
+ throw new Error(
75
+ `Failed to select the ${optionName} option of the ${elementName} dropdown: ${error}`
76
+ );
77
+ }
78
+ }
79
+ );
80
+
81
+ /**
82
+ * @name check
83
+ * @description Template step for checking a checkbox
84
+ * @icon INPUT
85
+ */
86
+ When(
87
+ 'the user checks the {string} checkbox',
88
+ async function (this: CustomWorld, elementName: SelectorName) {
89
+ const selector = await resolveLocator(this.page, elementName);
90
+ if (!selector) {
91
+ throw new Error(`Selector ${elementName} not found`);
92
+ }
93
+ try {
94
+ await this.page.locator(selector).check();
95
+ } catch (error) {
96
+ throw new Error(`Failed to check the ${elementName} checkbox: ${error}`);
97
+ }
98
+ }
99
+ );
100
+
101
+ /**
102
+ * @name uncheck
103
+ * @description Template step for unchecking a checkbox
104
+ * @icon INPUT
105
+ */
106
+ When(
107
+ 'the user unchecks the {string} checkbox',
108
+ async function (this: CustomWorld, elementName: SelectorName) {
109
+ const selector = await resolveLocator(this.page, elementName);
110
+ if (!selector) {
111
+ throw new Error(`Selector ${elementName} not found`);
112
+ }
113
+ try {
114
+ await this.page.locator(selector).uncheck();
115
+ } catch (error) {
116
+ throw new Error(
117
+ `Failed to uncheck the ${elementName} checkbox: ${error}`
118
+ );
119
+ }
120
+ }
121
+ );
122
+
123
+ /**
124
+ * @name fill input with stored value
125
+ * @description Template step for filling an input field with data from a stored variable
126
+ * @icon INPUT
127
+ */
128
+ When(
129
+ 'the user fills in the {string} input with data from the stored variable {string}',
130
+ async function (
131
+ this: CustomWorld,
132
+ fieldName: SelectorName,
133
+ variableName: string
134
+ ) {
135
+ const value = this.getVar<string>(variableName);
136
+ if (!value) {
137
+ throw new Error(`Variable ${variableName} not found`);
138
+ }
139
+ const selector = await resolveLocator(this.page, fieldName);
140
+ if (!selector) {
141
+ throw new Error(`Selector ${fieldName} not found`);
142
+ }
143
+ try {
144
+ await this.page.locator(selector).fill(value);
145
+ } catch (error) {
146
+ throw new Error(`Failed to fill in the ${fieldName} input field with data from the stored variable ${variableName}: ${error}`);
147
+ }
148
+ }
149
+ );