create-appraisejs 0.2.0 → 0.3.0-alpha.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (485) hide show
  1. package/README.md +12 -1
  2. package/package.json +1 -1
  3. package/templates/default/.appraise-template-meta.json +2 -2
  4. package/templates/default/.env.example +2 -2
  5. package/templates/default/README.md +57 -53
  6. package/templates/default/automation/steps/actions/click.step.ts +58 -58
  7. package/templates/default/automation/steps/actions/hover.step.ts +27 -27
  8. package/templates/default/automation/steps/actions/navigation.step.ts +70 -70
  9. package/templates/default/automation/steps/actions/random_data.step.ts +142 -142
  10. package/templates/default/automation/steps/actions/store.step.ts +86 -86
  11. package/templates/default/automation/steps/actions/wait.step.ts +110 -90
  12. package/templates/default/automation/steps/validations/active_state_assertion.step.ts +30 -30
  13. package/templates/default/automation/steps/validations/navigation_assertion.step.ts +22 -22
  14. package/templates/default/automation/steps/validations/text_assertion.step.ts +107 -107
  15. package/templates/default/automation/steps/validations/visibility_assertion.step.ts +26 -26
  16. package/templates/default/components.json +24 -24
  17. package/templates/default/cucumber.mjs +16 -16
  18. package/templates/default/eslint.config.mjs +20 -16
  19. package/templates/default/next-env.d.ts +6 -6
  20. package/templates/default/next.config.ts +20 -11
  21. package/templates/default/package-lock.json +1775 -74
  22. package/templates/default/package.json +8 -1
  23. package/templates/default/packages/cucumber-runtime/package.json +13 -13
  24. package/templates/default/packages/cucumber-runtime/src/cache.util.ts +93 -93
  25. package/templates/default/packages/cucumber-runtime/src/cli.ts +68 -68
  26. package/templates/default/packages/cucumber-runtime/src/environment.util.ts +21 -21
  27. package/templates/default/packages/cucumber-runtime/src/executor.ts +32 -32
  28. package/templates/default/packages/cucumber-runtime/src/index.ts +17 -17
  29. package/templates/default/packages/cucumber-runtime/src/locator.util.ts +234 -234
  30. package/templates/default/packages/cucumber-runtime/src/parameter-types.ts +7 -7
  31. package/templates/default/packages/cucumber-runtime/src/random-data.util.ts +35 -35
  32. package/templates/default/packages/cucumber-runtime/src/types.ts +13 -13
  33. package/templates/default/packages/cucumber-runtime/src/world.ts +44 -44
  34. package/templates/default/packages/cucumber-runtime/tsconfig.json +11 -11
  35. package/templates/default/postcss.config.mjs +8 -8
  36. package/templates/default/prisma/dev.db +0 -0
  37. package/templates/default/prisma/migrations/20251104113456_add_type_for_template_step_groups/migration.sql +16 -16
  38. package/templates/default/prisma/migrations/20251104170946_add_tags_to_test_suite_and_test_case/migration.sql +27 -27
  39. package/templates/default/prisma/migrations/20251112190024_add_cascade_delete_to_test_run_test_case/migration.sql +17 -17
  40. package/templates/default/prisma/migrations/20251113181100_add_test_run_log/migration.sql +12 -12
  41. package/templates/default/prisma/migrations/20251119191838_add_tag_type/migration.sql +28 -28
  42. package/templates/default/prisma/migrations/20251121164059_add_conflict_resolution/migration.sql +12 -12
  43. package/templates/default/prisma/migrations/20251223183400_add_report_model_to_db_schema/migration.sql +10 -10
  44. package/templates/default/prisma/migrations/20251223183637_add_report_test_case_entity_for_storing_test_results_for_individual_test_cases/migration.sql +10 -10
  45. package/templates/default/prisma/migrations/20251224083549_add_comprehensive_report_storage/migration.sql +108 -108
  46. package/templates/default/prisma/migrations/20251229194422_migrate_duration_to_string/migration.sql +55 -55
  47. package/templates/default/prisma/migrations/20251230124637_add_unique_constraint_to_test_run_name/migration.sql +27 -27
  48. package/templates/default/prisma/migrations/20260115094436_add_dashboard_metrics/migration.sql +59 -59
  49. package/templates/default/prisma/migrations/20260127172022_add_cascade_delete_to_step_parameters/migration.sql +34 -34
  50. package/templates/default/prisma/migrations/20260313093000_add_report_step_screenshot_path/migration.sql +1 -1
  51. package/templates/default/scripts/build-step-registry.ts +33 -0
  52. package/templates/default/scripts/install-playwright.ts +17 -8
  53. package/templates/default/scripts/install-template-step.ts +128 -0
  54. package/templates/default/scripts/lib/filename-utils.test.ts +24 -0
  55. package/templates/default/scripts/lib/filename-utils.ts +24 -0
  56. package/templates/default/scripts/lib/jsdoc-parser.test.ts +63 -0
  57. package/templates/default/scripts/lib/jsdoc-parser.ts +88 -0
  58. package/templates/default/scripts/lib/step-file-parser.test.ts +71 -0
  59. package/templates/default/scripts/lib/step-file-parser.ts +315 -0
  60. package/templates/default/scripts/lib/step-matcher.test.ts +86 -0
  61. package/templates/default/scripts/lib/step-matcher.ts +120 -0
  62. package/templates/default/scripts/lib/sync-script-runner.ts +23 -0
  63. package/templates/default/scripts/lib/sync-summary.ts +29 -0
  64. package/templates/default/scripts/lib/tag-parsing.test.ts +20 -0
  65. package/templates/default/scripts/lib/tag-parsing.ts +10 -0
  66. package/templates/default/scripts/lib/template-step-installer.test.ts +225 -0
  67. package/templates/default/scripts/lib/template-step-installer.ts +404 -0
  68. package/templates/default/scripts/lib/template-step-registry.test.ts +118 -0
  69. package/templates/default/scripts/lib/template-step-registry.ts +137 -0
  70. package/templates/default/scripts/protect-seeded-files.ts +51 -38
  71. package/templates/default/scripts/regenerate-features.ts +98 -94
  72. package/templates/default/scripts/run-vitest.ts +59 -0
  73. package/templates/default/scripts/setup-env.ts +26 -19
  74. package/templates/default/scripts/sync-all.ts +44 -54
  75. package/templates/default/scripts/sync-appraise-base-template.ts +44 -16
  76. package/templates/default/scripts/sync-environments.ts +22 -66
  77. package/templates/default/scripts/sync-locator-groups.ts +358 -410
  78. package/templates/default/scripts/sync-locators.ts +348 -398
  79. package/templates/default/scripts/sync-modules.ts +302 -341
  80. package/templates/default/scripts/sync-tags.ts +29 -65
  81. package/templates/default/scripts/sync-template-step-groups.ts +24 -182
  82. package/templates/default/scripts/sync-template-steps.ts +36 -493
  83. package/templates/default/scripts/sync-test-cases.ts +296 -539
  84. package/templates/default/scripts/sync-test-suites.ts +32 -79
  85. package/templates/default/src/actions/dashboard/dashboard-actions.ts +70 -241
  86. package/templates/default/src/actions/environments/environment-actions.ts +102 -188
  87. package/templates/default/src/actions/locator/locator-actions.ts +77 -490
  88. package/templates/default/src/actions/locator-groups/locator-group-actions.ts +34 -212
  89. package/templates/default/src/actions/locator-picker/locator-picker-actions.test.ts +81 -0
  90. package/templates/default/src/actions/locator-picker/locator-picker-actions.ts +20 -161
  91. package/templates/default/src/actions/modules/module-actions.ts +99 -135
  92. package/templates/default/src/actions/reports/report-actions.ts +28 -565
  93. package/templates/default/src/actions/settings/sync-actions.test.ts +58 -0
  94. package/templates/default/src/actions/tags/tag-actions.ts +99 -107
  95. package/templates/default/src/actions/template-step/template-step-actions.ts +33 -194
  96. package/templates/default/src/actions/template-step-group/template-step-group-actions.ts +35 -92
  97. package/templates/default/src/actions/template-test-case/template-test-case-actions.ts +98 -238
  98. package/templates/default/src/actions/test-case/test-case-actions.ts +108 -356
  99. package/templates/default/src/actions/test-run/test-run-actions.ts +74 -1081
  100. package/templates/default/src/actions/test-suite/test-suite-actions.ts +35 -202
  101. package/templates/default/src/app/(base)/environments/create/page.tsx +28 -28
  102. package/templates/default/src/app/(base)/environments/environment-form.test.tsx +92 -0
  103. package/templates/default/src/app/(base)/environments/environment-form.tsx +228 -219
  104. package/templates/default/src/app/(base)/environments/environment-helpers.ts +58 -0
  105. package/templates/default/src/app/(base)/environments/environment-table-columns.tsx +96 -96
  106. package/templates/default/src/app/(base)/environments/environment-table.tsx +25 -24
  107. package/templates/default/src/app/(base)/environments/modify/[id]/page.tsx +49 -46
  108. package/templates/default/src/app/(base)/environments/page.tsx +59 -59
  109. package/templates/default/src/app/(base)/layout.tsx +10 -10
  110. package/templates/default/src/app/(base)/locator-groups/create/page.tsx +44 -44
  111. package/templates/default/src/app/(base)/locator-groups/locator-group-form.tsx +215 -215
  112. package/templates/default/src/app/(base)/locator-groups/locator-group-table-columns.tsx +77 -77
  113. package/templates/default/src/app/(base)/locator-groups/locator-group-table.tsx +28 -28
  114. package/templates/default/src/app/(base)/locator-groups/modify/[id]/page.tsx +46 -46
  115. package/templates/default/src/app/(base)/locators/create/create-locator-workspace-helpers.test.ts +71 -0
  116. package/templates/default/src/app/(base)/locators/create/create-locator-workspace-helpers.ts +333 -0
  117. package/templates/default/src/app/(base)/locators/create/create-locator-workspace.test.tsx +125 -0
  118. package/templates/default/src/app/(base)/locators/create/create-locator-workspace.tsx +56 -274
  119. package/templates/default/src/app/(base)/locators/create/page.tsx +8 -4
  120. package/templates/default/src/app/(base)/locators/create/use-locator-workspace.ts +183 -0
  121. package/templates/default/src/app/(base)/locators/locator-helpers.test.ts +28 -0
  122. package/templates/default/src/app/(base)/locators/locator-helpers.ts +59 -0
  123. package/templates/default/src/app/(base)/locators/locator-table-columns.tsx +74 -73
  124. package/templates/default/src/app/(base)/locators/locator-table.tsx +30 -28
  125. package/templates/default/src/app/(base)/locators/modify/[id]/page.tsx +20 -8
  126. package/templates/default/src/app/(base)/locators/page.tsx +3 -6
  127. package/templates/default/src/app/(base)/locators/sync-locators-button.tsx +67 -66
  128. package/templates/default/src/app/(base)/modules/create/page.tsx +33 -34
  129. package/templates/default/src/app/(base)/modules/modify/[id]/page.tsx +43 -46
  130. package/templates/default/src/app/(base)/modules/module-form.test.tsx +84 -0
  131. package/templates/default/src/app/(base)/modules/module-form.tsx +159 -126
  132. package/templates/default/src/app/(base)/modules/module-helpers.ts +64 -0
  133. package/templates/default/src/app/(base)/modules/module-table-columns.tsx +81 -85
  134. package/templates/default/src/app/(base)/modules/module-table.tsx +25 -24
  135. package/templates/default/src/app/(base)/modules/page.tsx +59 -59
  136. package/templates/default/src/app/(base)/reports/[id]/page.tsx +20 -260
  137. package/templates/default/src/app/(base)/reports/duration-chart.tsx +33 -33
  138. package/templates/default/src/app/(base)/reports/feature-chart.tsx +79 -78
  139. package/templates/default/src/app/(base)/reports/overview-chart.tsx +49 -49
  140. package/templates/default/src/app/(base)/reports/page.tsx +98 -98
  141. package/templates/default/src/app/(base)/reports/report-detail-helpers.test.ts +109 -0
  142. package/templates/default/src/app/(base)/reports/report-detail-helpers.ts +247 -0
  143. package/templates/default/src/app/(base)/reports/report-metric-card.tsx +78 -78
  144. package/templates/default/src/app/(base)/reports/report-table-columns.tsx +189 -189
  145. package/templates/default/src/app/(base)/reports/report-table.tsx +72 -72
  146. package/templates/default/src/app/(base)/reports/test-cases/page.tsx +40 -40
  147. package/templates/default/src/app/(base)/reports/test-cases/test-cases-metric-table-columns.tsx +115 -115
  148. package/templates/default/src/app/(base)/reports/test-cases/test-cases-metric-table.tsx +27 -27
  149. package/templates/default/src/app/(base)/reports/test-suites/page.tsx +42 -42
  150. package/templates/default/src/app/(base)/reports/test-suites/test-suites-metric-table-columns.tsx +79 -79
  151. package/templates/default/src/app/(base)/reports/test-suites/test-suites-metric-table.tsx +27 -27
  152. package/templates/default/src/app/(base)/reports/view-logs-button.tsx +58 -58
  153. package/templates/default/src/app/(base)/settings/settings-sync-panel-helpers.test.tsx +40 -0
  154. package/templates/default/src/app/(base)/settings/settings-sync-panel-helpers.tsx +110 -0
  155. package/templates/default/src/app/(base)/settings/settings-sync-panel.test.tsx +127 -0
  156. package/templates/default/src/app/(base)/settings/settings-sync-panel.tsx +19 -134
  157. package/templates/default/src/app/(base)/settings/use-settings-sync.ts +66 -0
  158. package/templates/default/src/app/(base)/tags/create/page.tsx +39 -39
  159. package/templates/default/src/app/(base)/tags/modify/[id]/page.tsx +50 -50
  160. package/templates/default/src/app/(base)/tags/page.tsx +58 -58
  161. package/templates/default/src/app/(base)/tags/tag-form-helpers.ts +13 -0
  162. package/templates/default/src/app/(base)/tags/tag-form.test.tsx +83 -0
  163. package/templates/default/src/app/(base)/tags/tag-form.tsx +143 -147
  164. package/templates/default/src/app/(base)/tags/tag-table-columns.tsx +63 -63
  165. package/templates/default/src/app/(base)/tags/tag-table.tsx +29 -29
  166. package/templates/default/src/app/(base)/template-step-groups/create/page.tsx +28 -28
  167. package/templates/default/src/app/(base)/template-step-groups/modify/[id]/page.tsx +43 -45
  168. package/templates/default/src/app/(base)/template-step-groups/page.tsx +60 -60
  169. package/templates/default/src/app/(base)/template-step-groups/template-step-group-form.test.tsx +82 -0
  170. package/templates/default/src/app/(base)/template-step-groups/template-step-group-form.tsx +181 -167
  171. package/templates/default/src/app/(base)/template-step-groups/template-step-group-helpers.ts +54 -0
  172. package/templates/default/src/app/(base)/template-step-groups/template-step-group-table-columns.tsx +89 -89
  173. package/templates/default/src/app/(base)/template-step-groups/template-step-group-table.tsx +34 -32
  174. package/templates/default/src/app/(base)/template-steps/create/page.tsx +40 -37
  175. package/templates/default/src/app/(base)/template-steps/modify/[id]/page.tsx +54 -49
  176. package/templates/default/src/app/(base)/template-steps/page.tsx +59 -58
  177. package/templates/default/src/app/(base)/template-steps/paramChip.tsx +233 -213
  178. package/templates/default/src/app/(base)/template-steps/template-step-form.test.tsx +132 -0
  179. package/templates/default/src/app/(base)/template-steps/template-step-form.tsx +342 -384
  180. package/templates/default/src/app/(base)/template-steps/template-step-helpers.test.ts +99 -0
  181. package/templates/default/src/app/(base)/template-steps/template-step-helpers.ts +176 -0
  182. package/templates/default/src/app/(base)/template-steps/template-step-table-columns.tsx +153 -158
  183. package/templates/default/src/app/(base)/template-steps/template-step-table.tsx +26 -24
  184. package/templates/default/src/app/(base)/template-test-cases/create/page.tsx +56 -56
  185. package/templates/default/src/app/(base)/template-test-cases/modify/[id]/page.tsx +89 -89
  186. package/templates/default/src/app/(base)/template-test-cases/page.tsx +58 -58
  187. package/templates/default/src/app/(base)/template-test-cases/template-test-case-flow.test.tsx +109 -0
  188. package/templates/default/src/app/(base)/template-test-cases/template-test-case-flow.tsx +45 -84
  189. package/templates/default/src/app/(base)/template-test-cases/template-test-case-form.test.tsx +140 -0
  190. package/templates/default/src/app/(base)/template-test-cases/template-test-case-form.tsx +154 -262
  191. package/templates/default/src/app/(base)/template-test-cases/template-test-case-table-columns.tsx +76 -76
  192. package/templates/default/src/app/(base)/template-test-cases/template-test-case-table.tsx +32 -32
  193. package/templates/default/src/app/(base)/test-cases/create/page.tsx +90 -76
  194. package/templates/default/src/app/(base)/test-cases/create-from-template/create-from-template-helpers.test.ts +94 -0
  195. package/templates/default/src/app/(base)/test-cases/create-from-template/create-from-template-helpers.ts +171 -0
  196. package/templates/default/src/app/(base)/test-cases/create-from-template/generate/[id]/page.tsx +105 -96
  197. package/templates/default/src/app/(base)/test-cases/create-from-template/page.tsx +40 -38
  198. package/templates/default/src/app/(base)/test-cases/create-from-template/template-selection-form.test.tsx +87 -0
  199. package/templates/default/src/app/(base)/test-cases/create-from-template/template-selection-form.tsx +83 -73
  200. package/templates/default/src/app/(base)/test-cases/modify/[id]/page.tsx +106 -106
  201. package/templates/default/src/app/(base)/test-cases/page.tsx +3 -2
  202. package/templates/default/src/app/(base)/test-cases/test-case-flow.test.tsx +108 -0
  203. package/templates/default/src/app/(base)/test-cases/test-case-flow.tsx +43 -82
  204. package/templates/default/src/app/(base)/test-cases/test-case-form.test.tsx +202 -0
  205. package/templates/default/src/app/(base)/test-cases/test-case-form.tsx +263 -395
  206. package/templates/default/src/app/(base)/test-cases/test-case-route-helpers.test.ts +95 -0
  207. package/templates/default/src/app/(base)/test-cases/test-case-route-helpers.ts +147 -0
  208. package/templates/default/src/app/(base)/test-cases/test-case-table.tsx +4 -2
  209. package/templates/default/src/app/(base)/test-runs/[id]/page.tsx +11 -10
  210. package/templates/default/src/app/(base)/test-runs/create/page.tsx +4 -5
  211. package/templates/default/src/app/(base)/test-runs/page.tsx +60 -60
  212. package/templates/default/src/app/(base)/test-runs/test-run-form-helpers.test.ts +50 -0
  213. package/templates/default/src/app/(base)/test-runs/test-run-form-helpers.ts +168 -0
  214. package/templates/default/src/app/(base)/test-runs/test-run-form.test.tsx +138 -0
  215. package/templates/default/src/app/(base)/test-runs/test-run-form.tsx +111 -256
  216. package/templates/default/src/app/(base)/test-runs/test-run-table-columns.tsx +229 -229
  217. package/templates/default/src/app/(base)/test-runs/test-run-table.tsx +127 -127
  218. package/templates/default/src/app/(base)/test-runs/use-test-run-name-validation.ts +74 -0
  219. package/templates/default/src/app/(base)/test-suites/create/page.tsx +17 -12
  220. package/templates/default/src/app/(base)/test-suites/modify/[id]/page.tsx +22 -19
  221. package/templates/default/src/app/(base)/test-suites/page.tsx +14 -56
  222. package/templates/default/src/app/(base)/test-suites/test-suite-form.test.tsx +127 -0
  223. package/templates/default/src/app/(base)/test-suites/test-suite-form.tsx +45 -64
  224. package/templates/default/src/app/(base)/test-suites/test-suite-helpers.test.ts +67 -0
  225. package/templates/default/src/app/(base)/test-suites/test-suite-helpers.ts +215 -0
  226. package/templates/default/src/app/(base)/test-suites/test-suite-table.tsx +32 -29
  227. package/templates/default/src/app/(dashboard-components)/app-drawer.tsx +187 -187
  228. package/templates/default/src/app/(dashboard-components)/data-card-grid.tsx +12 -12
  229. package/templates/default/src/app/(dashboard-components)/data-card.tsx +26 -26
  230. package/templates/default/src/app/(dashboard-components)/execution-health-panel.tsx +56 -56
  231. package/templates/default/src/app/(dashboard-components)/ongoing-test-runs-card.tsx +87 -87
  232. package/templates/default/src/app/(dashboard-components)/quick-actions-drawer.tsx +44 -44
  233. package/templates/default/src/app/api/reports/steps/[stepId]/screenshot/route.test.ts +83 -0
  234. package/templates/default/src/app/api/reports/steps/[stepId]/screenshot/route.ts +52 -52
  235. package/templates/default/src/app/api/test-runs/[runId]/download/route.test.ts +169 -0
  236. package/templates/default/src/app/api/test-runs/[runId]/download/route.ts +1 -1
  237. package/templates/default/src/app/api/test-runs/[runId]/trace/[testCaseId]/route.test.ts +135 -0
  238. package/templates/default/src/app/api/test-runs/[runId]/trace/[testCaseId]/route.ts +146 -146
  239. package/templates/default/src/app/globals.css +147 -147
  240. package/templates/default/src/app/page.tsx +1 -1
  241. package/templates/default/src/assets/icons/empty-tube.tsx +23 -23
  242. package/templates/default/src/assets/icons/tube-plus.tsx +29 -29
  243. package/templates/default/src/components/base-node.tsx +21 -21
  244. package/templates/default/src/components/chart/pie-chart.tsx +73 -73
  245. package/templates/default/src/components/data-extraction/locator-inspector-helpers.test.ts +32 -0
  246. package/templates/default/src/components/data-extraction/locator-inspector-helpers.ts +183 -0
  247. package/templates/default/src/components/data-extraction/locator-inspector.tsx +349 -460
  248. package/templates/default/src/components/data-state/empty-state.tsx +40 -40
  249. package/templates/default/src/components/data-visualization/info-card.tsx +70 -70
  250. package/templates/default/src/components/data-visualization/info-grid.tsx +22 -22
  251. package/templates/default/src/components/diagram/button-edge.tsx +54 -54
  252. package/templates/default/src/components/diagram/dynamic-parameters-helpers.test.ts +83 -0
  253. package/templates/default/src/components/diagram/dynamic-parameters-helpers.ts +158 -0
  254. package/templates/default/src/components/diagram/dynamic-parameters.tsx +350 -474
  255. package/templates/default/src/components/diagram/edit-header-option.tsx +36 -36
  256. package/templates/default/src/components/diagram/flow-diagram-helpers.test.ts +117 -0
  257. package/templates/default/src/components/diagram/flow-diagram-helpers.ts +251 -0
  258. package/templates/default/src/components/diagram/flow-diagram.tsx +247 -470
  259. package/templates/default/src/components/diagram/flow-host-helpers.test.ts +74 -0
  260. package/templates/default/src/components/diagram/flow-host-helpers.ts +51 -0
  261. package/templates/default/src/components/diagram/node-form-helpers.test.ts +92 -0
  262. package/templates/default/src/components/diagram/node-form-helpers.ts +100 -0
  263. package/templates/default/src/components/diagram/node-form.test.tsx +168 -0
  264. package/templates/default/src/components/diagram/node-form.tsx +199 -262
  265. package/templates/default/src/components/diagram/options-header-node.tsx +57 -57
  266. package/templates/default/src/components/diagram/template-step-combobox.tsx +155 -155
  267. package/templates/default/src/components/diagram/use-flow-node-order.ts +49 -0
  268. package/templates/default/src/components/form/error-message.tsx +7 -7
  269. package/templates/default/src/components/kokonutui/smooth-tab.tsx +453 -453
  270. package/templates/default/src/components/loading-skeleton/data-table/data-table-skeleton.tsx +30 -30
  271. package/templates/default/src/components/loading-skeleton/form/button-skeleton.tsx +8 -8
  272. package/templates/default/src/components/loading-skeleton/form/icon-button-skeleton.tsx +8 -8
  273. package/templates/default/src/components/loading-skeleton/form/text-input-skeleton.tsx +8 -8
  274. package/templates/default/src/components/loading-skeleton/visualization/table-skeleton.tsx +14 -14
  275. package/templates/default/src/components/navigation/command-badge.tsx +34 -34
  276. package/templates/default/src/components/navigation/command-chain-input.tsx +51 -51
  277. package/templates/default/src/components/navigation/entity-search-command.tsx +118 -116
  278. package/templates/default/src/components/navigation/nav-card.tsx +31 -31
  279. package/templates/default/src/components/navigation/nav-command-helpers.ts +122 -0
  280. package/templates/default/src/components/navigation/nav-command-search.tsx +125 -0
  281. package/templates/default/src/components/navigation/nav-command.test.tsx +106 -0
  282. package/templates/default/src/components/navigation/nav-command.tsx +49 -472
  283. package/templates/default/src/components/navigation/nav-link.tsx +60 -60
  284. package/templates/default/src/components/navigation/nav-menu-card-deck.tsx +112 -112
  285. package/templates/default/src/components/navigation/use-nav-command.ts +58 -0
  286. package/templates/default/src/components/node-header.tsx +159 -159
  287. package/templates/default/src/components/reports/test-case-logs-modal.tsx +310 -310
  288. package/templates/default/src/components/table/table-actions.tsx +174 -172
  289. package/templates/default/src/components/test-case/test-case-form-helpers.test.ts +100 -0
  290. package/templates/default/src/components/test-case/test-case-form-helpers.ts +140 -0
  291. package/templates/default/src/components/test-case/test-case-picker-helpers.test.ts +40 -0
  292. package/templates/default/src/components/test-case/test-case-picker-helpers.ts +41 -0
  293. package/templates/default/src/components/test-case/test-case-picker.test.tsx +44 -0
  294. package/templates/default/src/components/test-case/test-case-picker.tsx +16 -35
  295. package/templates/default/src/components/test-case/test-scenario-preview.tsx +34 -0
  296. package/templates/default/src/components/test-run/download-logs-button.tsx +92 -92
  297. package/templates/default/src/components/test-run/log-viewer-helpers.test.ts +37 -0
  298. package/templates/default/src/components/test-run/log-viewer-helpers.ts +80 -0
  299. package/templates/default/src/components/test-run/log-viewer.test.tsx +118 -0
  300. package/templates/default/src/components/test-run/log-viewer.tsx +51 -350
  301. package/templates/default/src/components/test-run/test-run-details-helpers.test.ts +31 -0
  302. package/templates/default/src/components/test-run/test-run-details-helpers.ts +208 -0
  303. package/templates/default/src/components/test-run/test-run-details.test.tsx +174 -0
  304. package/templates/default/src/components/test-run/test-run-details.tsx +155 -457
  305. package/templates/default/src/components/test-run/test-run-header-helpers.test.ts +31 -0
  306. package/templates/default/src/components/test-run/test-run-header-helpers.ts +23 -0
  307. package/templates/default/src/components/test-run/test-run-header.test.tsx +103 -0
  308. package/templates/default/src/components/test-run/test-run-header.tsx +27 -149
  309. package/templates/default/src/components/test-run/use-log-viewer.ts +213 -0
  310. package/templates/default/src/components/test-run/use-test-run-details.ts +184 -0
  311. package/templates/default/src/components/test-run/use-test-run-header.ts +89 -0
  312. package/templates/default/src/components/test-run/view-report-button.tsx +102 -102
  313. package/templates/default/src/components/test-suite/test-suite-picker-helpers.test.ts +68 -0
  314. package/templates/default/src/components/test-suite/test-suite-picker-helpers.ts +76 -0
  315. package/templates/default/src/components/test-suite/test-suite-picker.test.tsx +65 -0
  316. package/templates/default/src/components/test-suite/test-suite-picker.tsx +4 -72
  317. package/templates/default/src/components/theme/mode-toggle.tsx +54 -54
  318. package/templates/default/src/components/theme/theme-provider.tsx +8 -8
  319. package/templates/default/src/components/typography/page-header-subtitle.tsx +7 -7
  320. package/templates/default/src/components/typography/page-header.tsx +7 -7
  321. package/templates/default/src/components/ui/alert-dialog.tsx +106 -106
  322. package/templates/default/src/components/ui/alert.tsx +43 -43
  323. package/templates/default/src/components/ui/avatar.tsx +40 -40
  324. package/templates/default/src/components/ui/badge.tsx +29 -29
  325. package/templates/default/src/components/ui/button.tsx +47 -47
  326. package/templates/default/src/components/ui/calendar.tsx +158 -158
  327. package/templates/default/src/components/ui/card.tsx +43 -43
  328. package/templates/default/src/components/ui/checkbox.tsx +28 -28
  329. package/templates/default/src/components/ui/command.tsx +135 -135
  330. package/templates/default/src/components/ui/data-table-column-header.tsx +61 -61
  331. package/templates/default/src/components/ui/data-table-pagination.tsx +87 -87
  332. package/templates/default/src/components/ui/data-table-view-options.tsx +50 -50
  333. package/templates/default/src/components/ui/data-table.test.tsx +122 -0
  334. package/templates/default/src/components/ui/data-table.tsx +298 -261
  335. package/templates/default/src/components/ui/dialog.tsx +97 -97
  336. package/templates/default/src/components/ui/dropdown-menu.tsx +182 -182
  337. package/templates/default/src/components/ui/input.tsx +22 -22
  338. package/templates/default/src/components/ui/kbd.tsx +28 -28
  339. package/templates/default/src/components/ui/label.tsx +19 -19
  340. package/templates/default/src/components/ui/loading.tsx +12 -12
  341. package/templates/default/src/components/ui/multi-select-with-preview.tsx +116 -116
  342. package/templates/default/src/components/ui/multi-select.test.tsx +45 -0
  343. package/templates/default/src/components/ui/multi-select.tsx +158 -142
  344. package/templates/default/src/components/ui/navigation-menu.tsx +120 -120
  345. package/templates/default/src/components/ui/popover.tsx +33 -33
  346. package/templates/default/src/components/ui/progress.tsx +25 -25
  347. package/templates/default/src/components/ui/radio-group.tsx +44 -44
  348. package/templates/default/src/components/ui/scroll-area.tsx +40 -40
  349. package/templates/default/src/components/ui/select.tsx +151 -151
  350. package/templates/default/src/components/ui/separator.tsx +22 -22
  351. package/templates/default/src/components/ui/skeleton.tsx +7 -7
  352. package/templates/default/src/components/ui/table.tsx +76 -76
  353. package/templates/default/src/components/ui/tabs.tsx +55 -55
  354. package/templates/default/src/components/ui/textarea.tsx +21 -21
  355. package/templates/default/src/components/ui/toast.tsx +113 -113
  356. package/templates/default/src/components/ui/toaster.tsx +26 -26
  357. package/templates/default/src/components/user-prompt/delete-prompt.test.tsx +60 -0
  358. package/templates/default/src/components/user-prompt/delete-prompt.tsx +118 -87
  359. package/templates/default/src/constants/form-opts/diagram/node-form.ts +30 -30
  360. package/templates/default/src/constants/form-opts/environment-form-opts.ts +24 -24
  361. package/templates/default/src/constants/form-opts/locator-group-form-opts.ts +28 -28
  362. package/templates/default/src/constants/form-opts/module-form-opts.ts +21 -21
  363. package/templates/default/src/constants/form-opts/tag-form-opts.ts +42 -42
  364. package/templates/default/src/constants/form-opts/template-selection-form-opts.ts +16 -16
  365. package/templates/default/src/constants/form-opts/template-step-group-form-opts.ts +24 -24
  366. package/templates/default/src/constants/form-opts/template-test-case-form-opts.ts +39 -39
  367. package/templates/default/src/constants/form-opts/template-test-step-form-opts.ts +36 -36
  368. package/templates/default/src/constants/form-opts/test-case-form-opts.ts +43 -43
  369. package/templates/default/src/constants/form-opts/test-suite-form-opts.ts +24 -24
  370. package/templates/default/src/hooks/use-toast.ts +187 -187
  371. package/templates/default/src/lib/automation/automation-path-roots.ts +95 -0
  372. package/templates/default/src/lib/automation/automation-workspace.ts +147 -0
  373. package/templates/default/src/lib/automation/paths.ts +6 -211
  374. package/templates/default/src/lib/bidirectional-sync.ts +432 -432
  375. package/templates/default/src/lib/environment-file-utils.ts +2 -1
  376. package/templates/default/src/lib/executor/local-executor-adapter.ts +2 -5
  377. package/templates/default/src/lib/feature-file-generator.ts +2 -1
  378. package/templates/default/src/lib/gherkin-parser.ts +0 -2
  379. package/templates/default/src/lib/locator-group-file-utils.ts +304 -307
  380. package/templates/default/src/lib/locator-picker/session-manager.ts +0 -21
  381. package/templates/default/src/lib/locator-picker/suggestions.ts +4 -2
  382. package/templates/default/src/lib/metrics/metric-calculator.ts +2 -6
  383. package/templates/default/src/lib/module-hierarchy-builder.ts +205 -205
  384. package/templates/default/src/lib/path-helpers/module-path.ts +71 -71
  385. package/templates/default/src/lib/sync/sync-executor.test.ts +76 -0
  386. package/templates/default/src/lib/sync/sync-pending-counts.test.ts +227 -226
  387. package/templates/default/src/lib/sync/sync-pending-counts.ts +2 -5
  388. package/templates/default/src/lib/template-sync-utils.d.ts +6 -6
  389. package/templates/default/src/lib/template-sync-utils.js +46 -46
  390. package/templates/default/src/lib/template-sync-utils.ts +63 -63
  391. package/templates/default/src/lib/test-case-utils.ts +6 -6
  392. package/templates/default/src/lib/test-run/log-formatter.ts +83 -83
  393. package/templates/default/src/lib/test-run/report-parser.ts +352 -352
  394. package/templates/default/src/lib/test-run/test-run-executor.ts +13 -13
  395. package/templates/default/src/lib/test-run/winston-logger.ts +65 -64
  396. package/templates/default/src/lib/transformers/gherkin-converter.ts +42 -42
  397. package/templates/default/src/lib/transformers/key-to-icon-transformer.tsx +95 -95
  398. package/templates/default/src/lib/transformers/template-test-case-converter.ts +160 -160
  399. package/templates/default/src/lib/utils/node-param-validation.ts +81 -81
  400. package/templates/default/src/lib/utils/template-step-file-generator.ts +2 -2
  401. package/templates/default/src/lib/utils/template-step-file-manager.ts +166 -166
  402. package/templates/default/src/lib/utils.ts +31 -31
  403. package/templates/default/src/services/dashboard/dashboard-service.test.ts +106 -0
  404. package/templates/default/src/services/dashboard/dashboard-service.ts +173 -0
  405. package/templates/default/src/services/environment/environment-service.test.ts +137 -0
  406. package/templates/default/src/services/environment/environment-service.ts +96 -0
  407. package/templates/default/src/services/locator/locator-path-utils.test.ts +14 -0
  408. package/templates/default/src/services/locator/locator-path-utils.ts +14 -0
  409. package/templates/default/src/services/locator/locator-service.test.ts +63 -0
  410. package/templates/default/src/services/locator/locator-service.ts +479 -0
  411. package/templates/default/src/services/locator/locator-sync-utils.test.ts +19 -0
  412. package/templates/default/src/services/locator/locator-sync-utils.ts +21 -0
  413. package/templates/default/src/services/locator-group/locator-group-service.test.ts +123 -0
  414. package/templates/default/src/services/locator-group/locator-group-service.ts +180 -0
  415. package/templates/default/src/services/module/module-service.test.ts +89 -0
  416. package/templates/default/src/services/module/module-service.ts +66 -0
  417. package/templates/default/src/services/report/report-service.test.ts +244 -0
  418. package/templates/default/src/services/report/report-service.ts +438 -0
  419. package/templates/default/src/services/shared/constants.ts +2 -0
  420. package/templates/default/src/services/shared/errors.test.ts +38 -0
  421. package/templates/default/src/services/shared/errors.ts +44 -0
  422. package/templates/default/src/services/shared/index.ts +7 -0
  423. package/templates/default/src/services/tag/tag-service.test.ts +22 -0
  424. package/templates/default/src/services/tag/tag-service.ts +41 -0
  425. package/templates/default/src/services/template-step/template-step-service.test.ts +22 -0
  426. package/templates/default/src/services/template-step/template-step-service.ts +171 -0
  427. package/templates/default/src/services/template-step-group/template-step-group-service.test.ts +22 -0
  428. package/templates/default/src/services/template-step-group/template-step-group-service.ts +81 -0
  429. package/templates/default/src/services/template-test-case/template-test-case-service.test.ts +22 -0
  430. package/templates/default/src/services/template-test-case/template-test-case-service.ts +128 -0
  431. package/templates/default/src/services/test-case/test-case-service.test.ts +175 -0
  432. package/templates/default/src/services/test-case/test-case-service.ts +298 -0
  433. package/templates/default/src/services/test-run/test-run-helpers.ts +61 -0
  434. package/templates/default/src/services/test-run/test-run-service.test.ts +647 -0
  435. package/templates/default/src/services/test-run/test-run-service.ts +917 -0
  436. package/templates/default/src/services/test-suite/test-suite-service.test.ts +127 -0
  437. package/templates/default/src/services/test-suite/test-suite-service.ts +197 -0
  438. package/templates/default/src/types/diagram/diagram.ts +34 -34
  439. package/templates/default/src/types/diagram/template-step.ts +11 -11
  440. package/templates/default/src/types/executor/browser.type.ts +1 -1
  441. package/templates/default/src/types/form/actionHandler.ts +19 -6
  442. package/templates/default/src/types/locator/locator.type.ts +11 -11
  443. package/templates/default/src/types/step/step.type.ts +1 -1
  444. package/templates/default/src/types/table/data-table.ts +6 -6
  445. package/templates/default/tailwind.config.ts +62 -62
  446. package/templates/default/tsconfig.json +1 -1
  447. package/dist/cli.e2e.test.d.ts +0 -2
  448. package/dist/cli.e2e.test.d.ts.map +0 -1
  449. package/dist/cli.e2e.test.js +0 -73
  450. package/dist/cli.e2e.test.js.map +0 -1
  451. package/dist/config.test.d.ts +0 -2
  452. package/dist/config.test.d.ts.map +0 -1
  453. package/dist/config.test.js +0 -65
  454. package/dist/config.test.js.map +0 -1
  455. package/dist/copy-template.test.d.ts +0 -2
  456. package/dist/copy-template.test.d.ts.map +0 -1
  457. package/dist/copy-template.test.js +0 -71
  458. package/dist/copy-template.test.js.map +0 -1
  459. package/dist/download-repo.test.d.ts +0 -2
  460. package/dist/download-repo.test.d.ts.map +0 -1
  461. package/dist/download-repo.test.js +0 -14
  462. package/dist/download-repo.test.js.map +0 -1
  463. package/dist/install.test.d.ts +0 -2
  464. package/dist/install.test.d.ts.map +0 -1
  465. package/dist/install.test.js +0 -119
  466. package/dist/install.test.js.map +0 -1
  467. package/dist/prompts.test.d.ts +0 -2
  468. package/dist/prompts.test.d.ts.map +0 -1
  469. package/dist/prompts.test.js +0 -58
  470. package/dist/prompts.test.js.map +0 -1
  471. package/templates/default/src/actions/conflict/conflict.action.ts +0 -33
  472. package/templates/default/src/actions/review/review-actions.ts +0 -147
  473. package/templates/default/src/actions/user/user-actions.ts +0 -13
  474. package/templates/default/src/app/(base)/locators/locator-form.tsx +0 -163
  475. package/templates/default/src/app/(base)/reviews/create/page.tsx +0 -26
  476. package/templates/default/src/app/(base)/reviews/created-reviews-table.tsx +0 -15
  477. package/templates/default/src/app/(base)/reviews/modify/[id]/page.tsx +0 -26
  478. package/templates/default/src/app/(base)/reviews/page.tsx +0 -26
  479. package/templates/default/src/app/(base)/reviews/review/[id]/page.tsx +0 -26
  480. package/templates/default/src/app/(base)/reviews/review-form.tsx +0 -11
  481. package/templates/default/src/app/(base)/reviews/review-table-by-creator-columns.tsx +0 -9
  482. package/templates/default/src/app/(base)/reviews/review-table-by-reviewer-columns.tsx +0 -9
  483. package/templates/default/src/app/(base)/reviews/reviewer-reviews-table.tsx +0 -15
  484. package/templates/default/src/constants/form-opts/locator-form-opts.ts +0 -20
  485. package/templates/default/src/constants/form-opts/review-form-opts.ts +0 -23
@@ -1,460 +1,349 @@
1
- 'use client'
2
-
3
- import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'
4
- import { Button } from '@/components/ui/button'
5
- import { Input } from '@/components/ui/input'
6
- import { Label } from '@/components/ui/label'
7
- import { Separator } from '@/components/ui/separator'
8
- import { Badge } from '@/components/ui/badge'
9
- import { Textarea } from '@/components/ui/textarea'
10
- import { ScrollArea } from '@/components/ui/scroll-area'
11
- import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '@/components/ui/tooltip'
12
- import { Alert, AlertDescription } from '@/components/ui/alert'
13
- import { Copy, Target, MousePointer, Info } from 'lucide-react'
14
- import { useState, useEffect, useRef } from 'react'
15
-
16
- interface SelectedElementDetails {
17
- tag: string
18
- id?: string
19
- className?: string
20
- name?: string
21
- text?: string
22
- cssPath: string
23
- xpath: string
24
- html: string
25
- }
26
-
27
- interface LocatorInspectorProps {
28
- iframeUrl?: string
29
- }
30
-
31
- export default function LocatorInspector({ iframeUrl = '/sample-page' }: LocatorInspectorProps) {
32
- const [isSelectionMode, setIsSelectionMode] = useState(false)
33
- const [selectedElementDetails, setSelectedElementDetails] = useState<SelectedElementDetails | undefined>()
34
- const iframeRef = useRef<HTMLIFrameElement>(null)
35
-
36
- // Injection script - optimized and cleaned up
37
- const injectionScript = `
38
- (function() {
39
- if (window.locatorInspectorInjected) return;
40
- window.locatorInspectorInjected = true;
41
-
42
- let isSelectionMode = false;
43
- let hoveredElement = null;
44
-
45
- // Inject CSS for hover effects
46
- const style = document.createElement('style');
47
- style.textContent = \`
48
- .locator-inspector-hover {
49
- outline: 2px solid #3b82f6 !important;
50
- background-color: rgba(59, 130, 246, 0.1) !important;
51
- cursor: crosshair !important;
52
- }
53
- .locator-inspector-selection-mode * {
54
- cursor: crosshair !important;
55
- }
56
- \`;
57
- document.head.appendChild(style);
58
-
59
- function handleElementClick(event) {
60
- if (!isSelectionMode) return;
61
-
62
- event.preventDefault();
63
- event.stopPropagation();
64
-
65
- const target = event.target;
66
-
67
- // Send element data to parent
68
- window.parent.postMessage({
69
- type: 'ELEMENT_SELECTED',
70
- elementData: {
71
- tagName: target.tagName,
72
- id: target.id,
73
- className: target.className,
74
- name: target.name,
75
- textContent: target.textContent?.trim(),
76
- outerHTML: target.outerHTML,
77
- }
78
- }, '*');
79
-
80
- exitSelectionMode();
81
- }
82
-
83
- function handleElementHover(event) {
84
- if (!isSelectionMode) return;
85
-
86
- if (hoveredElement) {
87
- hoveredElement.classList.remove('locator-inspector-hover');
88
- }
89
-
90
- hoveredElement = event.target;
91
- hoveredElement.classList.add('locator-inspector-hover');
92
- }
93
-
94
- function handleElementLeave(event) {
95
- if (!isSelectionMode) return;
96
- event.target.classList.remove('locator-inspector-hover');
97
- }
98
-
99
- function enterSelectionMode() {
100
- isSelectionMode = true;
101
- document.body.classList.add('locator-inspector-selection-mode');
102
- document.addEventListener('click', handleElementClick, true);
103
- document.addEventListener('mouseover', handleElementHover, true);
104
- document.addEventListener('mouseout', handleElementLeave, true);
105
- }
106
-
107
- function exitSelectionMode() {
108
- isSelectionMode = false;
109
- document.body.classList.remove('locator-inspector-selection-mode');
110
- document.removeEventListener('click', handleElementClick, true);
111
- document.removeEventListener('mouseover', handleElementHover, true);
112
- document.removeEventListener('mouseout', handleElementLeave, true);
113
-
114
- // Clean up hover effects
115
- document.querySelectorAll('.locator-inspector-hover').forEach(el => {
116
- el.classList.remove('locator-inspector-hover');
117
- });
118
-
119
- hoveredElement = null;
120
-
121
- window.parent.postMessage({ type: 'SELECTION_MODE_OFF' }, '*');
122
- }
123
-
124
- // Listen for toggle messages
125
- window.addEventListener('message', function(event) {
126
- if (event.data.type === 'TOGGLE_SELECTION_MODE') {
127
- if (event.data.isSelectionMode) {
128
- enterSelectionMode();
129
- } else {
130
- exitSelectionMode();
131
- }
132
- }
133
- });
134
- })();
135
- `
136
-
137
- // Inject script when iframe loads
138
- const handleIframeLoad = () => {
139
- const iframe = iframeRef.current
140
- if (!iframe?.contentWindow) return
141
-
142
- try {
143
- const script = iframe.contentDocument?.createElement('script')
144
- if (script) {
145
- script.textContent = injectionScript
146
- iframe.contentDocument?.head.appendChild(script)
147
- }
148
- } catch (error) {
149
- console.warn('Could not inject script into iframe:', error)
150
- }
151
- }
152
-
153
- // Generate CSS selector
154
- const generateCSSPath = (element: { tagName: string; className?: string; id?: string }) => {
155
- if (element.id) return `#${element.id}`
156
-
157
- let path = element.tagName.toLowerCase()
158
- if (element.className) {
159
- const classes = element.className.split(' ').filter(Boolean)
160
- if (classes.length > 0) {
161
- path += '.' + classes.join('.')
162
- }
163
- }
164
- return path
165
- }
166
-
167
- // Generate XPath
168
- const generateXPath = (element: { tagName: string; className?: string; id?: string }) => {
169
- if (element.id) return `//*[@id="${element.id}"]`
170
-
171
- let path = `//${element.tagName.toLowerCase()}`
172
- if (element.className) {
173
- path += `[@class="${element.className}"]`
174
- }
175
- return path
176
- }
177
-
178
- // Listen for messages from iframe
179
- useEffect(() => {
180
- const handleMessage = (event: MessageEvent) => {
181
- if (event.data.type === 'SELECTION_MODE_OFF') {
182
- setIsSelectionMode(false)
183
- } else if (event.data.type === 'ELEMENT_SELECTED') {
184
- const { elementData } = event.data
185
- setSelectedElementDetails({
186
- tag: elementData.tagName.toLowerCase(),
187
- id: elementData.id || undefined,
188
- className: elementData.className || undefined,
189
- name: elementData.name || undefined,
190
- text: elementData.textContent || undefined,
191
- cssPath: generateCSSPath(elementData),
192
- xpath: generateXPath(elementData),
193
- html: elementData.outerHTML,
194
- })
195
- }
196
- }
197
-
198
- window.addEventListener('message', handleMessage)
199
- return () => window.removeEventListener('message', handleMessage)
200
- }, [])
201
-
202
- const copyToClipboard = (text: string) => {
203
- navigator.clipboard.writeText(text)
204
- }
205
-
206
- const toggleSelectionMode = () => {
207
- const newSelectionMode = !isSelectionMode
208
- setIsSelectionMode(newSelectionMode)
209
-
210
- const iframe = iframeRef.current
211
- if (iframe?.contentWindow) {
212
- iframe.contentWindow.postMessage(
213
- {
214
- type: 'TOGGLE_SELECTION_MODE',
215
- isSelectionMode: newSelectionMode,
216
- },
217
- '*',
218
- )
219
- }
220
- }
221
-
222
- // Render property field with copy button
223
- const renderPropertyField = (id: string, label: string, value: string, bgColor?: string, borderColor?: string) => (
224
- <div className="space-y-2">
225
- <Label htmlFor={id} className="text-sm font-medium">
226
- {label}
227
- </Label>
228
- <div className="flex">
229
- <Input
230
- id={id}
231
- value={value}
232
- readOnly
233
- className={`rounded-r-none border-r-0 font-mono text-sm ${bgColor || ''} ${borderColor || ''}`}
234
- />
235
- <Tooltip>
236
- <TooltipTrigger asChild>
237
- <Button
238
- size="sm"
239
- variant="outline"
240
- className="h-10 w-10 rounded-l-none border-l-0 p-0"
241
- onClick={() => copyToClipboard(value)}
242
- >
243
- <Copy className="h-3 w-3" />
244
- </Button>
245
- </TooltipTrigger>
246
- <TooltipContent>
247
- <p>Copy {label.toLowerCase()}</p>
248
- </TooltipContent>
249
- </Tooltip>
250
- </div>
251
- </div>
252
- )
253
-
254
- return (
255
- <TooltipProvider>
256
- <div className="min-h-screen bg-gray-50">
257
- {/* Header */}
258
- <header className="border-b bg-background shadow-sm">
259
- <div className="container mx-auto flex items-center justify-between px-6 py-4">
260
- <div className="space-y-1">
261
- <h1 className="text-2xl font-bold tracking-tight">Locator Explorer</h1>
262
- <p className="text-sm text-muted-foreground">Inspect and generate locators for test automation</p>
263
- </div>
264
- <div className="flex items-center gap-3">
265
- <Button
266
- onClick={toggleSelectionMode}
267
- variant={isSelectionMode ? 'default' : 'outline'}
268
- size="sm"
269
- className="flex items-center gap-2"
270
- >
271
- {isSelectionMode ? (
272
- <>
273
- <MousePointer className="h-4 w-4" />
274
- Exit Selection
275
- </>
276
- ) : (
277
- <>
278
- <Target className="h-4 w-4" />
279
- Select Element
280
- </>
281
- )}
282
- </Button>
283
- {isSelectionMode && (
284
- <Badge variant="secondary" className="flex items-center gap-2">
285
- <div className="h-2 w-2 animate-pulse rounded-full bg-blue-500"></div>
286
- Click an element to inspect
287
- </Badge>
288
- )}
289
- </div>
290
- </div>
291
- </header>
292
-
293
- {/* Main Content */}
294
- <div className="flex h-[calc(100vh-80px)]">
295
- {/* Left Column - Application Under Test */}
296
- <div className="flex-1 p-6">
297
- <Card className="h-full shadow-lg">
298
- <CardHeader className="pb-3">
299
- <CardTitle className="text-lg font-semibold text-gray-800">Application Under Test</CardTitle>
300
- </CardHeader>
301
- <CardContent className="p-0">
302
- <div className="h-[80vh] overflow-hidden rounded-b-lg bg-gray-100">
303
- <iframe
304
- ref={iframeRef}
305
- src={iframeUrl}
306
- className="h-full w-full border-0"
307
- title="Application Under Test"
308
- sandbox="allow-same-origin allow-scripts allow-forms"
309
- onLoad={handleIframeLoad}
310
- />
311
- </div>
312
- </CardContent>
313
- </Card>
314
- </div>
315
-
316
- {/* Right Column - Inspector Sidebar */}
317
- <div className="w-96 p-6 pl-0">
318
- <Card className="h-full shadow-lg">
319
- <CardHeader className="pb-3">
320
- <CardTitle className="flex items-center gap-2 text-lg font-semibold">
321
- <span className="truncate">Selected Element</span>
322
- {selectedElementDetails && (
323
- <Badge variant="outline" className="shrink-0 font-mono text-xs">
324
- {selectedElementDetails.tag.toUpperCase()}
325
- </Badge>
326
- )}
327
- </CardTitle>
328
- </CardHeader>
329
- <CardContent className="p-0">
330
- <ScrollArea className="h-[calc(80vh-60px)] p-6">
331
- {selectedElementDetails ? (
332
- <div className="space-y-6">
333
- {/* Element Properties */}
334
- <div className="space-y-4">
335
- <h3 className="text-sm font-medium uppercase tracking-wide text-muted-foreground">
336
- Properties
337
- </h3>
338
- <div className="space-y-3">
339
- {renderPropertyField(
340
- 'tag',
341
- 'Tag Name',
342
- selectedElementDetails.tag,
343
- 'bg-blue-50',
344
- 'border-blue-200',
345
- )}
346
- {selectedElementDetails.id && renderPropertyField('id', 'ID', selectedElementDetails.id)}
347
- {selectedElementDetails.className &&
348
- renderPropertyField('class', 'Class', selectedElementDetails.className)}
349
- {selectedElementDetails.name &&
350
- renderPropertyField('name', 'Name', selectedElementDetails.name)}
351
- {selectedElementDetails.text &&
352
- renderPropertyField('text', 'Text Content', selectedElementDetails.text)}
353
- </div>
354
- </div>
355
-
356
- <Separator />
357
-
358
- {/* Selectors */}
359
- <div className="space-y-4">
360
- <h3 className="text-sm font-medium uppercase tracking-wide text-muted-foreground">Locators</h3>
361
- <div className="space-y-3">
362
- <div className="space-y-2">
363
- <Label htmlFor="css" className="flex flex-wrap items-center gap-2 text-sm font-medium">
364
- <span>CSS Selector</span>
365
- <Badge variant="secondary" className="shrink-0 text-xs">
366
- Recommended
367
- </Badge>
368
- </Label>
369
- <div className="flex">
370
- <Input
371
- id="css"
372
- value={selectedElementDetails.cssPath}
373
- readOnly
374
- className="rounded-r-none border-r-0 border-green-200 bg-green-50 font-mono text-sm"
375
- />
376
- <Tooltip>
377
- <TooltipTrigger asChild>
378
- <Button
379
- size="sm"
380
- variant="outline"
381
- className="h-10 w-10 rounded-l-none border-l-0 p-0"
382
- onClick={() => copyToClipboard(selectedElementDetails.cssPath)}
383
- >
384
- <Copy className="h-3 w-3" />
385
- </Button>
386
- </TooltipTrigger>
387
- <TooltipContent>
388
- <p>Copy CSS selector</p>
389
- </TooltipContent>
390
- </Tooltip>
391
- </div>
392
- </div>
393
-
394
- {renderPropertyField(
395
- 'xpath',
396
- 'XPath',
397
- selectedElementDetails.xpath,
398
- 'bg-yellow-50',
399
- 'border-yellow-200',
400
- )}
401
- </div>
402
- </div>
403
-
404
- <Separator />
405
-
406
- {/* HTML Snippet */}
407
- <div className="space-y-3">
408
- <Label className="text-sm font-medium">HTML Snippet</Label>
409
- <div className="flex">
410
- <Textarea
411
- value={selectedElementDetails.html}
412
- readOnly
413
- className="min-h-[120px] flex-1 resize-none rounded-r-none border-r-0 font-mono text-xs"
414
- />
415
- <Tooltip>
416
- <TooltipTrigger asChild>
417
- <Button
418
- size="sm"
419
- variant="outline"
420
- className="w-10 self-start rounded-l-none border-l-0"
421
- style={{ height: '120px' }}
422
- onClick={() => copyToClipboard(selectedElementDetails.html)}
423
- >
424
- <Copy className="h-3 w-3" />
425
- </Button>
426
- </TooltipTrigger>
427
- <TooltipContent>
428
- <p>Copy HTML</p>
429
- </TooltipContent>
430
- </Tooltip>
431
- </div>
432
- </div>
433
- </div>
434
- ) : (
435
- <div className="flex h-full flex-col items-center justify-center p-8 text-center">
436
- <div className="mx-auto mb-4 flex h-16 w-16 items-center justify-center rounded-full bg-muted">
437
- <Target className="h-8 w-8 text-muted-foreground" />
438
- </div>
439
- <h3 className="mb-2 text-lg font-semibold">No Element Selected</h3>
440
- <p className="mb-4 max-w-sm break-words text-sm text-muted-foreground">
441
- Click the &quot;Select Element&quot; button above, then click on any element in the application
442
- to inspect its properties.
443
- </p>
444
- <Alert className="max-w-sm">
445
- <Info className="h-4 w-4" />
446
- <AlertDescription className="break-words">
447
- Use the element selector to generate reliable locators for your test automation scripts.
448
- </AlertDescription>
449
- </Alert>
450
- </div>
451
- )}
452
- </ScrollArea>
453
- </CardContent>
454
- </Card>
455
- </div>
456
- </div>
457
- </div>
458
- </TooltipProvider>
459
- )
460
- }
1
+ 'use client'
2
+
3
+ import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'
4
+ import { Button } from '@/components/ui/button'
5
+ import { Input } from '@/components/ui/input'
6
+ import { Label } from '@/components/ui/label'
7
+ import { Separator } from '@/components/ui/separator'
8
+ import { Badge } from '@/components/ui/badge'
9
+ import { Textarea } from '@/components/ui/textarea'
10
+ import { ScrollArea } from '@/components/ui/scroll-area'
11
+ import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '@/components/ui/tooltip'
12
+ import { Alert, AlertDescription } from '@/components/ui/alert'
13
+ import { Copy, Target, MousePointer, Info } from 'lucide-react'
14
+ import { useState, useEffect, useRef } from 'react'
15
+ import {
16
+ createLocatorInspectorInjectionScript,
17
+ generateCSSPath,
18
+ generateXPath,
19
+ getLocatorInspectorOrigin,
20
+ isLocatorInspectorMessage,
21
+ } from './locator-inspector-helpers'
22
+
23
+ interface SelectedElementDetails {
24
+ tag: string
25
+ id?: string
26
+ className?: string
27
+ name?: string
28
+ text?: string
29
+ cssPath: string
30
+ xpath: string
31
+ html: string
32
+ }
33
+
34
+ interface LocatorInspectorProps {
35
+ iframeUrl?: string
36
+ }
37
+
38
+ export default function LocatorInspector({ iframeUrl = '/sample-page' }: LocatorInspectorProps) {
39
+ const [isSelectionMode, setIsSelectionMode] = useState(false)
40
+ const [selectedElementDetails, setSelectedElementDetails] = useState<SelectedElementDetails | undefined>()
41
+ const iframeRef = useRef<HTMLIFrameElement>(null)
42
+
43
+ // Inject script when iframe loads
44
+ const handleIframeLoad = () => {
45
+ const iframe = iframeRef.current
46
+ if (!iframe?.contentWindow) return
47
+
48
+ try {
49
+ const script = iframe.contentDocument?.createElement('script')
50
+ if (script) {
51
+ script.textContent = createLocatorInspectorInjectionScript(window.location.origin)
52
+ iframe.contentDocument?.head.appendChild(script)
53
+ }
54
+ } catch (error) {
55
+ console.warn('Could not inject script into iframe:', error)
56
+ }
57
+ }
58
+
59
+ // Listen for messages from iframe
60
+ useEffect(() => {
61
+ const handleMessage = (event: MessageEvent) => {
62
+ const iframeWindow = iframeRef.current?.contentWindow
63
+ const iframeOrigin = getLocatorInspectorOrigin(iframeUrl, window.location.href)
64
+
65
+ if (event.source !== iframeWindow || event.origin !== iframeOrigin || !isLocatorInspectorMessage(event.data)) {
66
+ return
67
+ }
68
+
69
+ if (event.data.type === 'SELECTION_MODE_OFF') {
70
+ setIsSelectionMode(false)
71
+ } else if (event.data.type === 'ELEMENT_SELECTED') {
72
+ const { elementData } = event.data
73
+ setSelectedElementDetails({
74
+ tag: elementData.tagName.toLowerCase(),
75
+ id: elementData.id || undefined,
76
+ className: elementData.className || undefined,
77
+ name: elementData.name || undefined,
78
+ text: elementData.textContent || undefined,
79
+ cssPath: generateCSSPath(elementData),
80
+ xpath: generateXPath(elementData),
81
+ html: elementData.outerHTML,
82
+ })
83
+ }
84
+ }
85
+
86
+ window.addEventListener('message', handleMessage)
87
+ return () => window.removeEventListener('message', handleMessage)
88
+ }, [iframeUrl])
89
+
90
+ const copyToClipboard = (text: string) => {
91
+ navigator.clipboard.writeText(text)
92
+ }
93
+
94
+ const toggleSelectionMode = () => {
95
+ const newSelectionMode = !isSelectionMode
96
+ setIsSelectionMode(newSelectionMode)
97
+
98
+ const iframe = iframeRef.current
99
+ const iframeOrigin = getLocatorInspectorOrigin(iframeUrl, window.location.href)
100
+ if (iframe?.contentWindow) {
101
+ iframe.contentWindow.postMessage(
102
+ {
103
+ type: 'TOGGLE_SELECTION_MODE',
104
+ isSelectionMode: newSelectionMode,
105
+ },
106
+ iframeOrigin,
107
+ )
108
+ }
109
+ }
110
+
111
+ // Render property field with copy button
112
+ const renderPropertyField = (id: string, label: string, value: string, bgColor?: string, borderColor?: string) => (
113
+ <div className="space-y-2">
114
+ <Label htmlFor={id} className="text-sm font-medium">
115
+ {label}
116
+ </Label>
117
+ <div className="flex">
118
+ <Input
119
+ id={id}
120
+ value={value}
121
+ readOnly
122
+ className={`rounded-r-none border-r-0 font-mono text-sm ${bgColor || ''} ${borderColor || ''}`}
123
+ />
124
+ <Tooltip>
125
+ <TooltipTrigger asChild>
126
+ <Button
127
+ size="sm"
128
+ variant="outline"
129
+ className="h-10 w-10 rounded-l-none border-l-0 p-0"
130
+ onClick={() => copyToClipboard(value)}
131
+ >
132
+ <Copy className="h-3 w-3" />
133
+ </Button>
134
+ </TooltipTrigger>
135
+ <TooltipContent>
136
+ <p>Copy {label.toLowerCase()}</p>
137
+ </TooltipContent>
138
+ </Tooltip>
139
+ </div>
140
+ </div>
141
+ )
142
+
143
+ return (
144
+ <TooltipProvider>
145
+ <div className="min-h-screen bg-gray-50">
146
+ {/* Header */}
147
+ <header className="border-b bg-background shadow-sm">
148
+ <div className="container mx-auto flex items-center justify-between px-6 py-4">
149
+ <div className="space-y-1">
150
+ <h1 className="text-2xl font-bold tracking-tight">Locator Explorer</h1>
151
+ <p className="text-sm text-muted-foreground">Inspect and generate locators for test automation</p>
152
+ </div>
153
+ <div className="flex items-center gap-3">
154
+ <Button
155
+ onClick={toggleSelectionMode}
156
+ variant={isSelectionMode ? 'default' : 'outline'}
157
+ size="sm"
158
+ className="flex items-center gap-2"
159
+ >
160
+ {isSelectionMode ? (
161
+ <>
162
+ <MousePointer className="h-4 w-4" />
163
+ Exit Selection
164
+ </>
165
+ ) : (
166
+ <>
167
+ <Target className="h-4 w-4" />
168
+ Select Element
169
+ </>
170
+ )}
171
+ </Button>
172
+ {isSelectionMode && (
173
+ <Badge variant="secondary" className="flex items-center gap-2">
174
+ <div className="h-2 w-2 animate-pulse rounded-full bg-blue-500"></div>
175
+ Click an element to inspect
176
+ </Badge>
177
+ )}
178
+ </div>
179
+ </div>
180
+ </header>
181
+
182
+ {/* Main Content */}
183
+ <div className="flex h-[calc(100vh-80px)]">
184
+ {/* Left Column - Application Under Test */}
185
+ <div className="flex-1 p-6">
186
+ <Card className="h-full shadow-lg">
187
+ <CardHeader className="pb-3">
188
+ <CardTitle className="text-lg font-semibold text-gray-800">Application Under Test</CardTitle>
189
+ </CardHeader>
190
+ <CardContent className="p-0">
191
+ <div className="h-[80vh] overflow-hidden rounded-b-lg bg-gray-100">
192
+ <iframe
193
+ ref={iframeRef}
194
+ src={iframeUrl}
195
+ className="h-full w-full border-0"
196
+ title="Application Under Test"
197
+ sandbox="allow-same-origin allow-scripts allow-forms"
198
+ onLoad={handleIframeLoad}
199
+ />
200
+ </div>
201
+ </CardContent>
202
+ </Card>
203
+ </div>
204
+
205
+ {/* Right Column - Inspector Sidebar */}
206
+ <div className="w-96 p-6 pl-0">
207
+ <Card className="h-full shadow-lg">
208
+ <CardHeader className="pb-3">
209
+ <CardTitle className="flex items-center gap-2 text-lg font-semibold">
210
+ <span className="truncate">Selected Element</span>
211
+ {selectedElementDetails && (
212
+ <Badge variant="outline" className="shrink-0 font-mono text-xs">
213
+ {selectedElementDetails.tag.toUpperCase()}
214
+ </Badge>
215
+ )}
216
+ </CardTitle>
217
+ </CardHeader>
218
+ <CardContent className="p-0">
219
+ <ScrollArea className="h-[calc(80vh-60px)] p-6">
220
+ {selectedElementDetails ? (
221
+ <div className="space-y-6">
222
+ {/* Element Properties */}
223
+ <div className="space-y-4">
224
+ <h3 className="text-sm font-medium uppercase tracking-wide text-muted-foreground">
225
+ Properties
226
+ </h3>
227
+ <div className="space-y-3">
228
+ {renderPropertyField(
229
+ 'tag',
230
+ 'Tag Name',
231
+ selectedElementDetails.tag,
232
+ 'bg-blue-50',
233
+ 'border-blue-200',
234
+ )}
235
+ {selectedElementDetails.id && renderPropertyField('id', 'ID', selectedElementDetails.id)}
236
+ {selectedElementDetails.className &&
237
+ renderPropertyField('class', 'Class', selectedElementDetails.className)}
238
+ {selectedElementDetails.name &&
239
+ renderPropertyField('name', 'Name', selectedElementDetails.name)}
240
+ {selectedElementDetails.text &&
241
+ renderPropertyField('text', 'Text Content', selectedElementDetails.text)}
242
+ </div>
243
+ </div>
244
+
245
+ <Separator />
246
+
247
+ {/* Selectors */}
248
+ <div className="space-y-4">
249
+ <h3 className="text-sm font-medium uppercase tracking-wide text-muted-foreground">Locators</h3>
250
+ <div className="space-y-3">
251
+ <div className="space-y-2">
252
+ <Label htmlFor="css" className="flex flex-wrap items-center gap-2 text-sm font-medium">
253
+ <span>CSS Selector</span>
254
+ <Badge variant="secondary" className="shrink-0 text-xs">
255
+ Recommended
256
+ </Badge>
257
+ </Label>
258
+ <div className="flex">
259
+ <Input
260
+ id="css"
261
+ value={selectedElementDetails.cssPath}
262
+ readOnly
263
+ className="rounded-r-none border-r-0 border-green-200 bg-green-50 font-mono text-sm"
264
+ />
265
+ <Tooltip>
266
+ <TooltipTrigger asChild>
267
+ <Button
268
+ size="sm"
269
+ variant="outline"
270
+ className="h-10 w-10 rounded-l-none border-l-0 p-0"
271
+ onClick={() => copyToClipboard(selectedElementDetails.cssPath)}
272
+ >
273
+ <Copy className="h-3 w-3" />
274
+ </Button>
275
+ </TooltipTrigger>
276
+ <TooltipContent>
277
+ <p>Copy CSS selector</p>
278
+ </TooltipContent>
279
+ </Tooltip>
280
+ </div>
281
+ </div>
282
+
283
+ {renderPropertyField(
284
+ 'xpath',
285
+ 'XPath',
286
+ selectedElementDetails.xpath,
287
+ 'bg-yellow-50',
288
+ 'border-yellow-200',
289
+ )}
290
+ </div>
291
+ </div>
292
+
293
+ <Separator />
294
+
295
+ {/* HTML Snippet */}
296
+ <div className="space-y-3">
297
+ <Label className="text-sm font-medium">HTML Snippet</Label>
298
+ <div className="flex">
299
+ <Textarea
300
+ value={selectedElementDetails.html}
301
+ readOnly
302
+ className="min-h-[120px] flex-1 resize-none rounded-r-none border-r-0 font-mono text-xs"
303
+ />
304
+ <Tooltip>
305
+ <TooltipTrigger asChild>
306
+ <Button
307
+ size="sm"
308
+ variant="outline"
309
+ className="w-10 self-start rounded-l-none border-l-0"
310
+ style={{ height: '120px' }}
311
+ onClick={() => copyToClipboard(selectedElementDetails.html)}
312
+ >
313
+ <Copy className="h-3 w-3" />
314
+ </Button>
315
+ </TooltipTrigger>
316
+ <TooltipContent>
317
+ <p>Copy HTML</p>
318
+ </TooltipContent>
319
+ </Tooltip>
320
+ </div>
321
+ </div>
322
+ </div>
323
+ ) : (
324
+ <div className="flex h-full flex-col items-center justify-center p-8 text-center">
325
+ <div className="mx-auto mb-4 flex h-16 w-16 items-center justify-center rounded-full bg-muted">
326
+ <Target className="h-8 w-8 text-muted-foreground" />
327
+ </div>
328
+ <h3 className="mb-2 text-lg font-semibold">No Element Selected</h3>
329
+ <p className="mb-4 max-w-sm break-words text-sm text-muted-foreground">
330
+ Click the &quot;Select Element&quot; button above, then click on any element in the application
331
+ to inspect its properties.
332
+ </p>
333
+ <Alert className="max-w-sm">
334
+ <Info className="h-4 w-4" />
335
+ <AlertDescription className="break-words">
336
+ Use the element selector to generate reliable locators for your test automation scripts.
337
+ </AlertDescription>
338
+ </Alert>
339
+ </div>
340
+ )}
341
+ </ScrollArea>
342
+ </CardContent>
343
+ </Card>
344
+ </div>
345
+ </div>
346
+ </div>
347
+ </TooltipProvider>
348
+ )
349
+ }