@empiricalrun/playwright-utils 0.22.7 → 0.23.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 (274) hide show
  1. package/CHANGELOG.md +11 -0
  2. package/bundled/test-gen/actions/assert.d.ts +4 -0
  3. package/bundled/test-gen/actions/assert.d.ts.map +1 -0
  4. package/bundled/test-gen/actions/assert.js +50 -0
  5. package/bundled/test-gen/actions/click.d.ts +4 -0
  6. package/bundled/test-gen/actions/click.d.ts.map +1 -0
  7. package/bundled/test-gen/actions/click.js +51 -0
  8. package/bundled/test-gen/actions/constants/index.d.ts +2 -0
  9. package/bundled/test-gen/actions/constants/index.d.ts.map +1 -0
  10. package/bundled/test-gen/actions/constants/index.js +4 -0
  11. package/bundled/test-gen/actions/done.d.ts +4 -0
  12. package/bundled/test-gen/actions/done.d.ts.map +1 -0
  13. package/bundled/test-gen/actions/done.js +30 -0
  14. package/bundled/test-gen/actions/fill.d.ts +4 -0
  15. package/bundled/test-gen/actions/fill.d.ts.map +1 -0
  16. package/bundled/test-gen/actions/fill.js +82 -0
  17. package/bundled/test-gen/actions/goto.d.ts +4 -0
  18. package/bundled/test-gen/actions/goto.d.ts.map +1 -0
  19. package/bundled/test-gen/actions/goto.js +47 -0
  20. package/bundled/test-gen/actions/hover.d.ts +4 -0
  21. package/bundled/test-gen/actions/hover.d.ts.map +1 -0
  22. package/bundled/test-gen/actions/hover.js +51 -0
  23. package/bundled/test-gen/actions/index.d.ts +30 -0
  24. package/bundled/test-gen/actions/index.d.ts.map +1 -0
  25. package/bundled/test-gen/actions/index.js +159 -0
  26. package/bundled/test-gen/actions/next-task.d.ts +53 -0
  27. package/bundled/test-gen/actions/next-task.d.ts.map +1 -0
  28. package/bundled/test-gen/actions/next-task.js +58 -0
  29. package/bundled/test-gen/actions/press.d.ts +4 -0
  30. package/bundled/test-gen/actions/press.d.ts.map +1 -0
  31. package/bundled/test-gen/actions/press.js +56 -0
  32. package/bundled/test-gen/actions/skill.d.ts +21 -0
  33. package/bundled/test-gen/actions/skill.d.ts.map +1 -0
  34. package/bundled/test-gen/actions/skill.js +127 -0
  35. package/bundled/test-gen/actions/text-content.d.ts +4 -0
  36. package/bundled/test-gen/actions/text-content.d.ts.map +1 -0
  37. package/bundled/test-gen/actions/text-content.js +58 -0
  38. package/bundled/test-gen/actions/utils/index.d.ts +10 -0
  39. package/bundled/test-gen/actions/utils/index.d.ts.map +1 -0
  40. package/bundled/test-gen/actions/utils/index.js +109 -0
  41. package/bundled/test-gen/agent/browsing/index.d.ts +15 -0
  42. package/bundled/test-gen/agent/browsing/index.d.ts.map +1 -0
  43. package/bundled/test-gen/agent/browsing/index.js +68 -0
  44. package/bundled/test-gen/agent/browsing/run.d.ts +19 -0
  45. package/bundled/test-gen/agent/browsing/run.d.ts.map +1 -0
  46. package/bundled/test-gen/agent/browsing/run.js +88 -0
  47. package/bundled/test-gen/agent/browsing/utils.d.ts +41 -0
  48. package/bundled/test-gen/agent/browsing/utils.d.ts.map +1 -0
  49. package/bundled/test-gen/agent/browsing/utils.js +406 -0
  50. package/bundled/test-gen/agent/codegen/create-test-block.d.ts +9 -0
  51. package/bundled/test-gen/agent/codegen/create-test-block.d.ts.map +1 -0
  52. package/bundled/test-gen/agent/codegen/create-test-block.js +63 -0
  53. package/bundled/test-gen/agent/codegen/fix-ts-errors.d.ts +13 -0
  54. package/bundled/test-gen/agent/codegen/fix-ts-errors.d.ts.map +1 -0
  55. package/bundled/test-gen/agent/codegen/fix-ts-errors.js +80 -0
  56. package/bundled/test-gen/agent/codegen/generate-code-apply-changes.d.ts +13 -0
  57. package/bundled/test-gen/agent/codegen/generate-code-apply-changes.d.ts.map +1 -0
  58. package/bundled/test-gen/agent/codegen/generate-code-apply-changes.js +381 -0
  59. package/bundled/test-gen/agent/codegen/lexical-scoped-vars.d.ts +9 -0
  60. package/bundled/test-gen/agent/codegen/lexical-scoped-vars.d.ts.map +1 -0
  61. package/bundled/test-gen/agent/codegen/lexical-scoped-vars.js +56 -0
  62. package/bundled/test-gen/agent/codegen/repo-edit.d.ts +23 -0
  63. package/bundled/test-gen/agent/codegen/repo-edit.d.ts.map +1 -0
  64. package/bundled/test-gen/agent/codegen/repo-edit.js +86 -0
  65. package/bundled/test-gen/agent/codegen/run.d.ts +16 -0
  66. package/bundled/test-gen/agent/codegen/run.d.ts.map +1 -0
  67. package/bundled/test-gen/agent/codegen/run.js +119 -0
  68. package/bundled/test-gen/agent/codegen/skills-retriever.d.ts +26 -0
  69. package/bundled/test-gen/agent/codegen/skills-retriever.d.ts.map +1 -0
  70. package/bundled/test-gen/agent/codegen/skills-retriever.js +93 -0
  71. package/bundled/test-gen/agent/codegen/test-update-feedback.d.ts +12 -0
  72. package/bundled/test-gen/agent/codegen/test-update-feedback.d.ts.map +1 -0
  73. package/bundled/test-gen/agent/codegen/test-update-feedback.js +50 -0
  74. package/bundled/test-gen/agent/codegen/types.d.ts +25 -0
  75. package/bundled/test-gen/agent/codegen/types.d.ts.map +1 -0
  76. package/bundled/test-gen/agent/codegen/types.js +8 -0
  77. package/bundled/test-gen/agent/codegen/update-flow.d.ts +34 -0
  78. package/bundled/test-gen/agent/codegen/update-flow.d.ts.map +1 -0
  79. package/bundled/test-gen/agent/codegen/update-flow.js +300 -0
  80. package/bundled/test-gen/agent/codegen/use-skill.d.ts +11 -0
  81. package/bundled/test-gen/agent/codegen/use-skill.d.ts.map +1 -0
  82. package/bundled/test-gen/agent/codegen/use-skill.js +54 -0
  83. package/bundled/test-gen/agent/codegen/utils.d.ts +126 -0
  84. package/bundled/test-gen/agent/codegen/utils.d.ts.map +1 -0
  85. package/bundled/test-gen/agent/codegen/utils.js +416 -0
  86. package/bundled/test-gen/agent/diagnosis-agent/index.d.ts +18 -0
  87. package/bundled/test-gen/agent/diagnosis-agent/index.d.ts.map +1 -0
  88. package/bundled/test-gen/agent/diagnosis-agent/index.js +105 -0
  89. package/bundled/test-gen/agent/diagnosis-agent/strict-mode-violation.d.ts +9 -0
  90. package/bundled/test-gen/agent/diagnosis-agent/strict-mode-violation.d.ts.map +1 -0
  91. package/bundled/test-gen/agent/diagnosis-agent/strict-mode-violation.js +31 -0
  92. package/bundled/test-gen/agent/enrich-prompt/index.d.ts +12 -0
  93. package/bundled/test-gen/agent/enrich-prompt/index.d.ts.map +1 -0
  94. package/bundled/test-gen/agent/enrich-prompt/index.js +81 -0
  95. package/bundled/test-gen/agent/enrich-prompt/utils.d.ts +6 -0
  96. package/bundled/test-gen/agent/enrich-prompt/utils.d.ts.map +1 -0
  97. package/bundled/test-gen/agent/enrich-prompt/utils.js +12 -0
  98. package/bundled/test-gen/agent/infer-agent/index.d.ts +10 -0
  99. package/bundled/test-gen/agent/infer-agent/index.d.ts.map +1 -0
  100. package/bundled/test-gen/agent/infer-agent/index.js +70 -0
  101. package/bundled/test-gen/agent/master/action-tool-calls.d.ts +42 -0
  102. package/bundled/test-gen/agent/master/action-tool-calls.d.ts.map +1 -0
  103. package/bundled/test-gen/agent/master/action-tool-calls.js +87 -0
  104. package/bundled/test-gen/agent/master/browser-tests/fixtures.d.ts +9 -0
  105. package/bundled/test-gen/agent/master/browser-tests/fixtures.d.ts.map +1 -0
  106. package/bundled/test-gen/agent/master/browser-tests/fixtures.js +33 -0
  107. package/bundled/test-gen/agent/master/browser-tests/index.spec.d.ts +2 -0
  108. package/bundled/test-gen/agent/master/browser-tests/index.spec.d.ts.map +1 -0
  109. package/bundled/test-gen/agent/master/browser-tests/index.spec.js +113 -0
  110. package/bundled/test-gen/agent/master/browser-tests/skills.spec.d.ts +2 -0
  111. package/bundled/test-gen/agent/master/browser-tests/skills.spec.d.ts.map +1 -0
  112. package/bundled/test-gen/agent/master/browser-tests/skills.spec.js +109 -0
  113. package/bundled/test-gen/agent/master/element-annotation.d.ts +30 -0
  114. package/bundled/test-gen/agent/master/element-annotation.d.ts.map +1 -0
  115. package/bundled/test-gen/agent/master/element-annotation.js +195 -0
  116. package/bundled/test-gen/agent/master/execute-browser-action.d.ts +24 -0
  117. package/bundled/test-gen/agent/master/execute-browser-action.d.ts.map +1 -0
  118. package/bundled/test-gen/agent/master/execute-browser-action.js +124 -0
  119. package/bundled/test-gen/agent/master/execute-skill-action.d.ts +11 -0
  120. package/bundled/test-gen/agent/master/execute-skill-action.d.ts.map +1 -0
  121. package/bundled/test-gen/agent/master/execute-skill-action.js +25 -0
  122. package/bundled/test-gen/agent/master/icon-descriptor/index.d.ts +22 -0
  123. package/bundled/test-gen/agent/master/icon-descriptor/index.d.ts.map +1 -0
  124. package/bundled/test-gen/agent/master/icon-descriptor/index.js +250 -0
  125. package/bundled/test-gen/agent/master/icon-descriptor/normalize-svg.d.ts +2 -0
  126. package/bundled/test-gen/agent/master/icon-descriptor/normalize-svg.d.ts.map +1 -0
  127. package/bundled/test-gen/agent/master/icon-descriptor/normalize-svg.js +248 -0
  128. package/bundled/test-gen/agent/master/next-action.d.ts +22 -0
  129. package/bundled/test-gen/agent/master/next-action.d.ts.map +1 -0
  130. package/bundled/test-gen/agent/master/next-action.js +104 -0
  131. package/bundled/test-gen/agent/master/planner.d.ts +15 -0
  132. package/bundled/test-gen/agent/master/planner.d.ts.map +1 -0
  133. package/bundled/test-gen/agent/master/planner.js +144 -0
  134. package/bundled/test-gen/agent/master/run.d.ts +15 -0
  135. package/bundled/test-gen/agent/master/run.d.ts.map +1 -0
  136. package/bundled/test-gen/agent/master/run.js +274 -0
  137. package/bundled/test-gen/agent/master/scroller.d.ts +15 -0
  138. package/bundled/test-gen/agent/master/scroller.d.ts.map +1 -0
  139. package/bundled/test-gen/agent/master/scroller.js +375 -0
  140. package/bundled/test-gen/agent/master/with-hints.d.ts +17 -0
  141. package/bundled/test-gen/agent/master/with-hints.d.ts.map +1 -0
  142. package/bundled/test-gen/agent/master/with-hints.js +102 -0
  143. package/bundled/test-gen/agent/planner/run-time-planner.d.ts +15 -0
  144. package/bundled/test-gen/agent/planner/run-time-planner.d.ts.map +1 -0
  145. package/bundled/test-gen/agent/planner/run-time-planner.js +100 -0
  146. package/bundled/test-gen/agent/planner/run.d.ts +7 -0
  147. package/bundled/test-gen/agent/planner/run.d.ts.map +1 -0
  148. package/bundled/test-gen/agent/planner/run.js +127 -0
  149. package/bundled/test-gen/agent/utils.d.ts +2 -0
  150. package/bundled/test-gen/agent/utils.d.ts.map +1 -0
  151. package/bundled/test-gen/agent/utils.js +12 -0
  152. package/bundled/test-gen/bin/index.d.ts +3 -0
  153. package/bundled/test-gen/bin/index.d.ts.map +1 -0
  154. package/bundled/test-gen/bin/index.js +212 -0
  155. package/bundled/test-gen/bin/logger/index.d.ts +14 -0
  156. package/bundled/test-gen/bin/logger/index.d.ts.map +1 -0
  157. package/bundled/test-gen/bin/logger/index.js +57 -0
  158. package/bundled/test-gen/bin/utils/context.d.ts +13 -0
  159. package/bundled/test-gen/bin/utils/context.d.ts.map +1 -0
  160. package/bundled/test-gen/bin/utils/context.js +67 -0
  161. package/bundled/test-gen/bin/utils/fs/index.d.ts +6 -0
  162. package/bundled/test-gen/bin/utils/fs/index.d.ts.map +1 -0
  163. package/bundled/test-gen/bin/utils/fs/index.js +63 -0
  164. package/bundled/test-gen/bin/utils/index.d.ts +9 -0
  165. package/bundled/test-gen/bin/utils/index.d.ts.map +1 -0
  166. package/bundled/test-gen/bin/utils/index.js +64 -0
  167. package/bundled/test-gen/bin/utils/platform/web/index.d.ts +78 -0
  168. package/bundled/test-gen/bin/utils/platform/web/index.d.ts.map +1 -0
  169. package/bundled/test-gen/bin/utils/platform/web/index.js +544 -0
  170. package/bundled/test-gen/bin/utils/platform/web/test-files/ts-path-import-validate.d.ts +2 -0
  171. package/bundled/test-gen/bin/utils/platform/web/test-files/ts-path-import-validate.d.ts.map +1 -0
  172. package/bundled/test-gen/bin/utils/platform/web/test-files/ts-path-import-validate.js +7 -0
  173. package/bundled/test-gen/bin/utils/scenarios/index.d.ts +6 -0
  174. package/bundled/test-gen/bin/utils/scenarios/index.d.ts.map +1 -0
  175. package/bundled/test-gen/bin/utils/scenarios/index.js +57 -0
  176. package/bundled/test-gen/browser-injected-scripts/annotate-elements.js +615 -0
  177. package/bundled/test-gen/browser-injected-scripts/annotate-elements.spec.d.ts +2 -0
  178. package/bundled/test-gen/browser-injected-scripts/annotate-elements.spec.d.ts.map +1 -0
  179. package/bundled/test-gen/browser-injected-scripts/annotate-elements.spec.js +207 -0
  180. package/bundled/test-gen/browser-injected-scripts/annotate-elements.spec.ts +332 -0
  181. package/bundled/test-gen/constants/index.d.ts +7 -0
  182. package/bundled/test-gen/constants/index.d.ts.map +1 -0
  183. package/bundled/test-gen/constants/index.js +18 -0
  184. package/bundled/test-gen/errors/index.d.ts +5 -0
  185. package/bundled/test-gen/errors/index.d.ts.map +1 -0
  186. package/bundled/test-gen/errors/index.js +9 -0
  187. package/bundled/test-gen/evals/add-scenario-agent.evals.d.ts +4 -0
  188. package/bundled/test-gen/evals/add-scenario-agent.evals.d.ts.map +1 -0
  189. package/bundled/test-gen/evals/add-scenario-agent.evals.js +44 -0
  190. package/bundled/test-gen/evals/append-create-test-agent.evals.d.ts +4 -0
  191. package/bundled/test-gen/evals/append-create-test-agent.evals.d.ts.map +1 -0
  192. package/bundled/test-gen/evals/append-create-test-agent.evals.js +117 -0
  193. package/bundled/test-gen/evals/fetch-pom-skills-agent.evals.d.ts +4 -0
  194. package/bundled/test-gen/evals/fetch-pom-skills-agent.evals.d.ts.map +1 -0
  195. package/bundled/test-gen/evals/fetch-pom-skills-agent.evals.js +36 -0
  196. package/bundled/test-gen/evals/infer-master-or-code-agent.evals.d.ts +4 -0
  197. package/bundled/test-gen/evals/infer-master-or-code-agent.evals.d.ts.map +1 -0
  198. package/bundled/test-gen/evals/infer-master-or-code-agent.evals.js +22 -0
  199. package/bundled/test-gen/evals/master-agent.evals.d.ts +4 -0
  200. package/bundled/test-gen/evals/master-agent.evals.d.ts.map +1 -0
  201. package/bundled/test-gen/evals/master-agent.evals.js +35 -0
  202. package/bundled/test-gen/evals/type.d.ts +12 -0
  203. package/bundled/test-gen/evals/type.d.ts.map +1 -0
  204. package/bundled/test-gen/evals/type.js +2 -0
  205. package/bundled/test-gen/evals/update-scenario-agent.evals.d.ts +4 -0
  206. package/bundled/test-gen/evals/update-scenario-agent.evals.d.ts.map +1 -0
  207. package/bundled/test-gen/evals/update-scenario-agent.evals.js +47 -0
  208. package/bundled/test-gen/file/client.d.ts +14 -0
  209. package/bundled/test-gen/file/client.d.ts.map +1 -0
  210. package/bundled/test-gen/file/client.js +48 -0
  211. package/bundled/test-gen/file/server.d.ts +13 -0
  212. package/bundled/test-gen/file/server.d.ts.map +1 -0
  213. package/bundled/test-gen/file/server.js +52 -0
  214. package/bundled/test-gen/human-in-the-loop/cli.d.ts +2 -0
  215. package/bundled/test-gen/human-in-the-loop/cli.d.ts.map +1 -0
  216. package/bundled/test-gen/human-in-the-loop/cli.js +24 -0
  217. package/bundled/test-gen/human-in-the-loop/index.d.ts +12 -0
  218. package/bundled/test-gen/human-in-the-loop/index.d.ts.map +1 -0
  219. package/bundled/test-gen/human-in-the-loop/index.js +30 -0
  220. package/bundled/test-gen/human-in-the-loop/ipc.d.ts +4 -0
  221. package/bundled/test-gen/human-in-the-loop/ipc.d.ts.map +1 -0
  222. package/bundled/test-gen/human-in-the-loop/ipc.js +47 -0
  223. package/bundled/test-gen/index.d.ts +4 -0
  224. package/bundled/test-gen/index.d.ts.map +1 -0
  225. package/bundled/test-gen/index.js +55 -0
  226. package/bundled/test-gen/package.json +106 -0
  227. package/bundled/test-gen/page/index.d.ts +11 -0
  228. package/bundled/test-gen/page/index.d.ts.map +1 -0
  229. package/bundled/test-gen/page/index.js +16 -0
  230. package/bundled/test-gen/prompts/lib/ts-transformer.d.ts +4 -0
  231. package/bundled/test-gen/prompts/lib/ts-transformer.d.ts.map +1 -0
  232. package/bundled/test-gen/prompts/lib/ts-transformer.js +92 -0
  233. package/bundled/test-gen/reporter/index.d.ts +33 -0
  234. package/bundled/test-gen/reporter/index.d.ts.map +1 -0
  235. package/bundled/test-gen/reporter/index.js +161 -0
  236. package/bundled/test-gen/session/index.d.ts +20 -0
  237. package/bundled/test-gen/session/index.d.ts.map +1 -0
  238. package/bundled/test-gen/session/index.js +105 -0
  239. package/bundled/test-gen/test-build/index.d.ts +10 -0
  240. package/bundled/test-gen/test-build/index.d.ts.map +1 -0
  241. package/bundled/test-gen/test-build/index.js +30 -0
  242. package/bundled/test-gen/types/index.d.ts +69 -0
  243. package/bundled/test-gen/types/index.d.ts.map +1 -0
  244. package/bundled/test-gen/types/index.js +2 -0
  245. package/bundled/test-gen/uploader/index.d.ts +26 -0
  246. package/bundled/test-gen/uploader/index.d.ts.map +1 -0
  247. package/bundled/test-gen/uploader/index.js +102 -0
  248. package/bundled/test-gen/utils/env.d.ts +2 -0
  249. package/bundled/test-gen/utils/env.d.ts.map +1 -0
  250. package/bundled/test-gen/utils/env.js +9 -0
  251. package/bundled/test-gen/utils/exec.d.ts +4 -0
  252. package/bundled/test-gen/utils/exec.d.ts.map +1 -0
  253. package/bundled/test-gen/utils/exec.js +45 -0
  254. package/bundled/test-gen/utils/file.d.ts +2 -0
  255. package/bundled/test-gen/utils/file.d.ts.map +1 -0
  256. package/bundled/test-gen/utils/file.js +25 -0
  257. package/bundled/test-gen/utils/html.d.ts +4 -0
  258. package/bundled/test-gen/utils/html.d.ts.map +1 -0
  259. package/bundled/test-gen/utils/html.js +46 -0
  260. package/bundled/test-gen/utils/index.d.ts +2 -0
  261. package/bundled/test-gen/utils/index.d.ts.map +1 -0
  262. package/bundled/test-gen/utils/index.js +5 -0
  263. package/bundled/test-gen/utils/pw-test.d.ts +3 -0
  264. package/bundled/test-gen/utils/pw-test.d.ts.map +1 -0
  265. package/bundled/test-gen/utils/pw-test.js +26 -0
  266. package/bundled/test-gen/utils/slug.d.ts +2 -0
  267. package/bundled/test-gen/utils/slug.d.ts.map +1 -0
  268. package/bundled/test-gen/utils/slug.js +18 -0
  269. package/bundled/test-gen/utils/string.d.ts +2 -0
  270. package/bundled/test-gen/utils/string.d.ts.map +1 -0
  271. package/bundled/test-gen/utils/string.js +9 -0
  272. package/dist/overlay-tests/click.spec.js +1 -1
  273. package/package.json +3 -3
  274. package/scripts/prepare-publish.js +42 -0
@@ -0,0 +1,615 @@
1
+ /* eslint-disable autofix/no-unused-vars */
2
+
3
+ /**
4
+ * Annotates all clickable elements on the page with unique hint markers.
5
+ * Returns an object containing annotations and methods to enable/disable them.
6
+ *
7
+ * @param {Object} options - Configuration options for hint markers.
8
+ * @param {string} options.hintCharacterSet - Characters to use for generating hint identifiers.
9
+ * @param {number} options.maxHints - Maximum number of hints to generate.
10
+ * @param {string} options.markerClass - CSS class to apply to hint markers.
11
+ * @returns {Object} An object containing annotations map and enable/disable methods.
12
+ */
13
+ function annotateElementsWithPreference({
14
+ options = {},
15
+ preference = {},
16
+ } = {}) {
17
+ const {
18
+ hintCharacterSet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ", // Default set of characters for hints
19
+ maxHints = 1000, // Maximum number of hints to generate
20
+ markerClass = "hint-marker", // CSS class for markers
21
+ } = options;
22
+
23
+ const MAX_Z_INDEX_FOR_DOM = 10000;
24
+ const Z_INDEX_FOR_MARKERS = 99999;
25
+ const originalZIndices = new Map(); // Store original z-indices
26
+
27
+ const document = window.document;
28
+ const annotationsMap = {};
29
+ const usedHints = new Set();
30
+ let annotationsContainer = null;
31
+
32
+ // Check if the element is not blocked and visible for clicking
33
+ function isElementClickNotBlocked(element, windowToAnnotate) {
34
+ const rect = element.getBoundingClientRect();
35
+ const originalScrollX = windowToAnnotate.scrollX;
36
+ const originalScrollY = windowToAnnotate.scrollY;
37
+
38
+ // Calculate the center point of the element
39
+ const centerX = rect.left + rect.width / 2;
40
+ const centerY = rect.top + rect.height / 2;
41
+
42
+ // check if element is within the viewport
43
+ if (
44
+ centerX < 0 ||
45
+ centerY < 0 ||
46
+ centerX >
47
+ (windowToAnnotate.innerWidth || document.documentElement.clientWidth) ||
48
+ centerY >
49
+ (windowToAnnotate.innerHeight || document.documentElement.clientHeight)
50
+ ) {
51
+ return false;
52
+ }
53
+
54
+ const topElement = windowToAnnotate.document.elementFromPoint(
55
+ centerX,
56
+ centerY,
57
+ );
58
+
59
+ // Check if the topmost element is the target element or one of its descendants
60
+ return element.contains(topElement);
61
+ }
62
+
63
+ function generateHintStrings(charset, max) {
64
+ const hints = [];
65
+ let length = 1;
66
+
67
+ while (hints.length < max) {
68
+ const combos = cartesianProduct(Array(length).fill(charset.split("")));
69
+ for (const combo of combos) {
70
+ const hint = combo.join("");
71
+ if (!usedHints.has(hint)) {
72
+ hints.push(hint);
73
+ usedHints.add(hint);
74
+ }
75
+ if (hints.length >= max) break;
76
+ }
77
+ length++;
78
+ }
79
+
80
+ return hints;
81
+ }
82
+
83
+ function cartesianProduct(arrays) {
84
+ return arrays.reduce(
85
+ (acc, curr) =>
86
+ acc
87
+ .map((a) => curr.map((b) => a.concat([b])))
88
+ .reduce((a, b) => a.concat(b), []),
89
+ [[]],
90
+ );
91
+ }
92
+
93
+ // Check if an element is clickable
94
+ function isElementClickable(element, windowToAnnotate) {
95
+ if (!(element instanceof windowToAnnotate.Element)) return false;
96
+
97
+ const tagName = element.tagName.toLowerCase();
98
+ let isClickable = false;
99
+
100
+ // Check for aria-disabled
101
+ const ariaDisabled = element.getAttribute("aria-disabled");
102
+ if (ariaDisabled && ["", "true"].includes(ariaDisabled.toLowerCase())) {
103
+ return false; // Element should not be clickable if aria-disabled is true
104
+ }
105
+
106
+ // Check for visibility
107
+ const style = window.getComputedStyle(element);
108
+ if (
109
+ style.display === "none" ||
110
+ style.visibility === "hidden" ||
111
+ // This is done for cases where opacity is undefined
112
+ // parseFloat(style.opacity) === 0
113
+ style.pointerEvents === "none"
114
+ ) {
115
+ return false;
116
+ }
117
+
118
+ // Check if element is disabled (for applicable elements)
119
+ if (element.disabled) return false;
120
+
121
+ // Check for AngularJS click handlers
122
+ if (!isElementClickable._checkForAngularJs) {
123
+ isElementClickable._checkForAngularJs = (function () {
124
+ const angularElements = document.getElementsByClassName("ng-scope");
125
+ if (angularElements.length === 0) {
126
+ return () => false;
127
+ } else {
128
+ const ngAttributes = [];
129
+ for (const prefix of ["", "data-", "x-"]) {
130
+ for (const separator of ["-", ":", "_"]) {
131
+ ngAttributes.push(`${prefix}ng${separator}click`);
132
+ }
133
+ }
134
+ return function (el) {
135
+ for (const attribute of ngAttributes) {
136
+ if (el.hasAttribute(attribute)) return true;
137
+ }
138
+ return false;
139
+ };
140
+ }
141
+ })();
142
+ }
143
+
144
+ if (!isClickable && isElementClickable._checkForAngularJs(element)) {
145
+ isClickable = true;
146
+ }
147
+
148
+ // Tag-specific clickability
149
+ const focusableTags = [
150
+ "a",
151
+ "button",
152
+ "input",
153
+ "select",
154
+ "textarea",
155
+ "object",
156
+ "embed",
157
+ "label",
158
+ "details",
159
+ ];
160
+
161
+ // Check for onclick attribute or listener
162
+ if (
163
+ (element.hasAttribute("onclick") ||
164
+ typeof element.onclick === "function") &&
165
+ // check for parent element having same on click
166
+ element.parentNode.onclick !== element.onclick &&
167
+ // parent element should not be a focusable tag like button
168
+ focusableTags.indexOf(element.parentNode.tagName.toLowerCase()) === -1
169
+ ) {
170
+ isClickable = true;
171
+ }
172
+
173
+ // Check for jsaction attribute (commonly used in frameworks like Google's)
174
+ if (!isClickable && element.hasAttribute("jsaction")) {
175
+ const jsactionRules = element.getAttribute("jsaction").split(";");
176
+ for (const jsactionRule of jsactionRules) {
177
+ const ruleSplit = jsactionRule.trim().split(":");
178
+ if (ruleSplit.length >= 1 && ruleSplit.length <= 2) {
179
+ const [eventType] = ruleSplit[0].trim().split(".");
180
+ if (eventType === "click") {
181
+ isClickable = true;
182
+ break;
183
+ }
184
+ }
185
+ }
186
+ }
187
+
188
+ // Check for role attributes that imply clickability
189
+ if (!isClickable) {
190
+ const role = element.getAttribute("role");
191
+ const clickableRoles = [
192
+ "button",
193
+ "tab",
194
+ "link",
195
+ "checkbox",
196
+ "menuitem",
197
+ "menuitemcheckbox",
198
+ "menuitemradio",
199
+ "radio",
200
+ "switch",
201
+ ];
202
+ if (role && clickableRoles.includes(role.toLowerCase())) {
203
+ isClickable = true;
204
+ }
205
+ }
206
+
207
+ // Check for contentEditable
208
+ if (!isClickable) {
209
+ const contentEditable = element.getAttribute("contentEditable");
210
+ if (
211
+ contentEditable != null &&
212
+ ["", "contenteditable", "true"].includes(contentEditable.toLowerCase())
213
+ ) {
214
+ isClickable = true;
215
+ }
216
+ }
217
+
218
+ if (focusableTags.includes(tagName)) {
219
+ switch (tagName) {
220
+ case "a":
221
+ // Ensure it's not just a named anchor without href
222
+ if (element.hasAttribute("href")) {
223
+ isClickable = true;
224
+ }
225
+ break;
226
+ case "input": {
227
+ const type = (element.getAttribute("type") || "").toLowerCase();
228
+ if (
229
+ type !== "hidden" &&
230
+ !element.disabled &&
231
+ !(element.readOnly && isInputSelectable(element))
232
+ ) {
233
+ isClickable = true;
234
+ }
235
+ break;
236
+ }
237
+ case "textarea":
238
+ if (!element.disabled && !element.readOnly) {
239
+ isClickable = true;
240
+ }
241
+ break;
242
+ case "button":
243
+ case "select":
244
+ if (!element.disabled) {
245
+ isClickable = true;
246
+ }
247
+ break;
248
+ case "object":
249
+ case "embed":
250
+ isClickable = true;
251
+ break;
252
+ case "label":
253
+ if (element.control && !element.control.disabled) {
254
+ isClickable = true;
255
+ }
256
+ break;
257
+ case "details":
258
+ isClickable = true;
259
+ break;
260
+ default:
261
+ break;
262
+ }
263
+ }
264
+
265
+ // Some special handling for Tailwind CSS and Vue
266
+ if (!isClickable) {
267
+ if (element.classList.contains("cursor-pointer")) {
268
+ isClickable = true;
269
+ } else if (element.classList.contains("v-list-item--link")) {
270
+ // vue specific click handling
271
+ isClickable = true;
272
+ } else if (element.style.cursor === "pointer") {
273
+ isClickable = true;
274
+ }
275
+ }
276
+
277
+ // Check for tabindex
278
+ if (!isClickable) {
279
+ const tabIndexValue = element.getAttribute("tabindex");
280
+ const tabIndex = tabIndexValue ? parseInt(tabIndexValue) : -1;
281
+ if (tabIndex >= 0 && !isNaN(tabIndex)) {
282
+ isClickable = true;
283
+ }
284
+ }
285
+
286
+ return isClickable;
287
+ }
288
+
289
+ function isInputSelectable(input) {
290
+ const selectableTypes = [
291
+ "text",
292
+ "search",
293
+ "password",
294
+ "url",
295
+ "email",
296
+ "number",
297
+ "tel",
298
+ ];
299
+ const type = (input.getAttribute("type") || "").toLowerCase();
300
+ return selectableTypes.includes(type);
301
+ }
302
+
303
+ var parentElements = [];
304
+
305
+ // Create a hint marker
306
+ function createHintMarker(
307
+ el,
308
+ hint,
309
+ parentElement,
310
+ windowToAnnotate,
311
+ baseColor,
312
+ ) {
313
+ const rect = el.getBoundingClientRect();
314
+
315
+ // Create the marker element
316
+ const marker = document.createElement("div");
317
+ marker.textContent = hint;
318
+ marker.className = markerClass;
319
+ // Style the marker
320
+ Object.assign(marker.style, {
321
+ position: "absolute",
322
+ background: baseColor,
323
+ padding: "1px 3px 0px",
324
+ borderRadius: "3px",
325
+ border: `1px solid ${baseColor}`,
326
+ fontSize: "11px",
327
+ pointerEvents: "none",
328
+ zIndex: `${Z_INDEX_FOR_MARKERS}`,
329
+ whiteSpace: "nowrap",
330
+ overflow: "hidden",
331
+ letterSpacing: 0,
332
+ minHeight: 0,
333
+ lineHeight: "100%",
334
+ color: "white",
335
+ fontFamily: "Helvetica, Arial, sans-serif",
336
+ fontWeight: "bold",
337
+ visibility: "hidden", // Setting the visibility to hidden initially, to get the height and width of marker
338
+ });
339
+
340
+ parentElement.appendChild(marker);
341
+ let markerRect = marker.getBoundingClientRect();
342
+ let top = rect.top + windowToAnnotate.scrollY;
343
+ let left = rect.left + windowToAnnotate.scrollX;
344
+
345
+ // If the target element is smaller, we annotate outside the container
346
+ if (markerRect.height > rect.height - markerRect.height) {
347
+ top = top - markerRect.height;
348
+ }
349
+
350
+ if (markerRect.width > rect.width - markerRect.width) {
351
+ left = left - markerRect.width / 2;
352
+ }
353
+
354
+ // Applying the position and setting visibility
355
+ marker.style.top = `${top}px`;
356
+ marker.style.left = `${left}px`;
357
+ marker.style.visibility = "visible";
358
+
359
+ // Attach the marker to the specified parent element
360
+ parentElements.push(parentElement);
361
+ return marker;
362
+ }
363
+
364
+ // Clear existing annotations
365
+ //TODO: Handle clearing annotations
366
+ function clearAnnotations() {
367
+ parentElements.forEach((parentElement) => {
368
+ const markers = parentElement.querySelectorAll(`.${markerClass}`);
369
+ markers.forEach((marker) => marker.remove());
370
+ });
371
+ parentElements = [];
372
+ }
373
+
374
+ function isInputElement(el) {
375
+ // Check if it's an input with a text-like type
376
+ if (el instanceof HTMLInputElement) {
377
+ const textTypes = [
378
+ "text",
379
+ "email",
380
+ "number",
381
+ "password",
382
+ "search",
383
+ "tel",
384
+ "url",
385
+ "checkbox",
386
+ ];
387
+ return textTypes.includes(el.type.toLowerCase());
388
+ }
389
+
390
+ // Check if it's a textarea
391
+ if (el instanceof HTMLTextAreaElement) {
392
+ return true;
393
+ }
394
+
395
+ // Check if it's contentEditable
396
+ return el.isContentEditable;
397
+ }
398
+
399
+ function isRequiredTextPresent(el, assertionText) {
400
+ assertionText = assertionText?.trim().toLowerCase();
401
+ if (assertionText) {
402
+ let elementText = el.innerText?.trim().toLowerCase();
403
+ let placeHolderText = el.placeholder?.trim().toLowerCase();
404
+ if (elementText === assertionText || placeHolderText === assertionText) {
405
+ //Check if the text for parent and child is same or not, if its same don't annotate again
406
+ if (el.parentNode.innerText?.toLowerCase() !== elementText) {
407
+ return true;
408
+ }
409
+ }
410
+ return false;
411
+ }
412
+ return true;
413
+ }
414
+
415
+ // This checks if the element is scrollable or not
416
+ function isElementScrollable(elem) {
417
+ function getComputedStyle(elem) {
418
+ return window.getComputedStyle(elem, null);
419
+ }
420
+
421
+ function getActualCss(elem, style) {
422
+ return getComputedStyle(elem)[style];
423
+ }
424
+
425
+ function isYScrollable(elem) {
426
+ return (
427
+ elem.offsetHeight < elem.scrollHeight &&
428
+ autoOrScroll(getActualCss(elem, "overflow-y"))
429
+ );
430
+ }
431
+
432
+ function autoOrScroll(text) {
433
+ return text == "scroll" || text == "auto";
434
+ }
435
+
436
+ // This doesn't annotate the elements with horizontal scroll
437
+ return isYScrollable(elem);
438
+ }
439
+
440
+ // Initialize annotations for a given window (including iframes)
441
+ function initializeAnnotations(windowToAnnotate, parentHints, depth) {
442
+ const container =
443
+ parentHints?.nodeName === "IFRAME"
444
+ ? parentHints.contentWindow.document.body
445
+ : annotationsContainer;
446
+
447
+ // Ensure the container exists
448
+ if (!container) return;
449
+
450
+ // Filter for clickable elements
451
+ const elementsToAnnotate = Array.from(
452
+ windowToAnnotate.document.querySelectorAll("*"),
453
+ ).filter((el) => {
454
+ // Here based on the action type we filter the elements
455
+ // and annotate only those elements
456
+ switch (preference.actionType) {
457
+ case "fill":
458
+ return isInputElement(el);
459
+
460
+ case "assert_text":
461
+ return isRequiredTextPresent(el, preference.assertionText);
462
+
463
+ case "scroll":
464
+ return isElementScrollable(el);
465
+
466
+ default:
467
+ return (
468
+ isElementClickable(el, windowToAnnotate) &&
469
+ isElementClickNotBlocked(el, windowToAnnotate)
470
+ );
471
+ }
472
+ });
473
+ // Generate hint strings for the clickable elements
474
+ const hints = generateHintStrings(
475
+ hintCharacterSet,
476
+ Math.min(maxHints, elementsToAnnotate.length),
477
+ );
478
+
479
+ // Create markers for the elements
480
+ elementsToAnnotate.slice(0, maxHints).forEach((el, index) => {
481
+ const hint = hints[index];
482
+ const rect = el.getBoundingClientRect();
483
+
484
+ const colors = [
485
+ "#FF0000", // Red
486
+ "#006400", // Dark Green
487
+ "#0000FF", // Blue
488
+ "#FFA500", // Orange
489
+ "#800080", // Purple
490
+ "#008080", // Teal
491
+ "#FF69B4", // Hot Pink
492
+ "#4B0082", // Indigo
493
+ "#FF4500", // Orange Red
494
+ "#2E8B57", // Sea Green
495
+ "#DC143C", // Crimson
496
+ "#4682B4", // Steel Blue
497
+ ];
498
+ const colorIndex = index % colors.length;
499
+ const baseColor = colors[colorIndex];
500
+
501
+ // Use createHintMarker with the specified container
502
+ createHintMarker(el, hint, container, windowToAnnotate, baseColor);
503
+
504
+ el.style.boxShadow = `inset 0 0 0px 1px ${baseColor}`;
505
+
506
+ // Add element details to the annotations map
507
+ annotationsMap[hint] = {
508
+ node: el,
509
+ rect: {
510
+ top: rect.top + windowToAnnotate.scrollY,
511
+ left: rect.left + windowToAnnotate.scrollX,
512
+ width: rect.width,
513
+ height: rect.height,
514
+ },
515
+ depth: [...depth],
516
+ };
517
+ });
518
+
519
+ // Process iframes recursively
520
+ Array.from(windowToAnnotate.document.querySelectorAll("iframe")).forEach(
521
+ (iframe) => {
522
+ try {
523
+ const frameWindow = iframe.contentWindow;
524
+ if (
525
+ frameWindow &&
526
+ iframe.offsetWidth > 0 &&
527
+ iframe.offsetHeight > 0
528
+ ) {
529
+ initializeAnnotations(frameWindow, iframe, [...depth, iframe]);
530
+ }
531
+ } catch (e) {
532
+ console.warn("Cannot access iframe:", e);
533
+ }
534
+ },
535
+ );
536
+ }
537
+
538
+ // Initialize and enable annotations
539
+ function enable() {
540
+ scaleAllZIndices(MAX_Z_INDEX_FOR_DOM);
541
+ clearAnnotations();
542
+ if (!annotationsContainer) {
543
+ annotationsContainer = document.createElement("div");
544
+ annotationsContainer.className = "annotations";
545
+ Object.assign(annotationsContainer.style, {
546
+ position: "absolute",
547
+ top: "0",
548
+ left: "0",
549
+ width: "100%",
550
+ height: "100%",
551
+ pointerEvents: "none",
552
+ zIndex: `${Z_INDEX_FOR_MARKERS}`,
553
+ });
554
+ document.body.appendChild(annotationsContainer);
555
+ initializeAnnotations(window, null, []);
556
+ } else {
557
+ annotationsContainer.style.display = "block";
558
+ }
559
+ }
560
+
561
+ // Destroy annotations
562
+ function destroy() {
563
+ if (annotationsContainer) {
564
+ clearAnnotations();
565
+ Object.values(annotationsMap).forEach((annotation) => {
566
+ annotation.node.style.boxShadow = "none";
567
+ });
568
+
569
+ // Restore original z-indices
570
+ originalZIndices.forEach((originalZ, element) => {
571
+ element.style.zIndex = originalZ;
572
+ });
573
+ originalZIndices.clear();
574
+
575
+ annotationsContainer.parentNode.removeChild(annotationsContainer);
576
+ annotationsContainer = null;
577
+ }
578
+ }
579
+
580
+ function scaleAllZIndices(maxValue) {
581
+ const allElements = document.querySelectorAll("*");
582
+ let zIndexes = [];
583
+ allElements.forEach((el) => {
584
+ const z = window.getComputedStyle(el).getPropertyValue("z-index");
585
+ if (z !== "auto" && !isNaN(parseInt(z, 10))) {
586
+ zIndexes.push(parseInt(z, 10));
587
+ // Store original z-index
588
+ originalZIndices.set(el, z);
589
+ }
590
+ });
591
+ if (zIndexes.length === 0) {
592
+ console.log("No elements with a numeric z-index were found.");
593
+ } else {
594
+ const currentMax = Math.max(...zIndexes);
595
+ const scalingFactor = maxValue / currentMax;
596
+ allElements.forEach((el) => {
597
+ const computedZ = window
598
+ .getComputedStyle(el)
599
+ .getPropertyValue("z-index");
600
+ if (computedZ !== "auto" && !isNaN(parseInt(computedZ, 10))) {
601
+ const originalZ = parseInt(computedZ, 10);
602
+ const newZ = Math.floor(originalZ * scalingFactor);
603
+ el.style.zIndex = newZ;
604
+ }
605
+ });
606
+ }
607
+ }
608
+
609
+ enable();
610
+
611
+ return {
612
+ annotations: annotationsMap,
613
+ destroy,
614
+ };
615
+ }
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=annotate-elements.spec.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"annotate-elements.spec.d.ts","sourceRoot":"","sources":["../../src/browser-injected-scripts/annotate-elements.spec.ts"],"names":[],"mappings":""}