donobu 2.15.0 → 2.16.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 (402) hide show
  1. package/dist/apis/FlowsFilesApi.d.ts.map +1 -1
  2. package/dist/apis/FlowsFilesApi.js +5 -2
  3. package/dist/apis/FlowsFilesApi.js.map +1 -1
  4. package/dist/assets/control-panel.js +30 -3
  5. package/dist/assets/generated/parameter-schemas.json +118 -17
  6. package/dist/assets/generated/version +1 -1
  7. package/dist/assets/interactive-elements-tracker.js +351 -0
  8. package/dist/assets/page-interactions-tracker.js +39 -20
  9. package/dist/assets/smart-selector-generator.js +38 -15
  10. package/dist/bindings/FocusPage.d.ts +6 -1
  11. package/dist/bindings/FocusPage.d.ts.map +1 -1
  12. package/dist/bindings/FocusPage.js +2 -8
  13. package/dist/bindings/FocusPage.js.map +1 -1
  14. package/dist/bindings/PageInteractionTracker.d.ts +9 -2
  15. package/dist/bindings/PageInteractionTracker.d.ts.map +1 -1
  16. package/dist/bindings/PageInteractionTracker.js +29 -5
  17. package/dist/bindings/PageInteractionTracker.js.map +1 -1
  18. package/dist/bindings/ProposeToolCall.d.ts +20 -0
  19. package/dist/bindings/ProposeToolCall.d.ts.map +1 -0
  20. package/dist/bindings/ProposeToolCall.js +29 -0
  21. package/dist/bindings/ProposeToolCall.js.map +1 -0
  22. package/dist/bindings/ToggleDonobuAnnotations.d.ts +5 -2
  23. package/dist/bindings/ToggleDonobuAnnotations.d.ts.map +1 -1
  24. package/dist/bindings/ToggleDonobuAnnotations.js +12 -6
  25. package/dist/bindings/ToggleDonobuAnnotations.js.map +1 -1
  26. package/dist/clients/AnthropicAwsBedrockGptClient.d.ts +1 -20
  27. package/dist/clients/AnthropicAwsBedrockGptClient.d.ts.map +1 -1
  28. package/dist/clients/AnthropicAwsBedrockGptClient.js +12 -329
  29. package/dist/clients/AnthropicAwsBedrockGptClient.js.map +1 -1
  30. package/dist/clients/AnthropicGptClient.d.ts +0 -8
  31. package/dist/clients/AnthropicGptClient.d.ts.map +1 -1
  32. package/dist/clients/AnthropicGptClient.js +8 -22
  33. package/dist/clients/AnthropicGptClient.js.map +1 -1
  34. package/dist/clients/GoogleGptClient.d.ts +4 -20
  35. package/dist/clients/GoogleGptClient.d.ts.map +1 -1
  36. package/dist/clients/GoogleGptClient.js +23 -299
  37. package/dist/clients/GoogleGptClient.js.map +1 -1
  38. package/dist/clients/OpenAiGptClient.d.ts +0 -6
  39. package/dist/clients/OpenAiGptClient.d.ts.map +1 -1
  40. package/dist/clients/OpenAiGptClient.js +4 -8
  41. package/dist/clients/OpenAiGptClient.js.map +1 -1
  42. package/dist/clients/VercelAiGptClient.d.ts +3 -1
  43. package/dist/clients/VercelAiGptClient.d.ts.map +1 -1
  44. package/dist/clients/VercelAiGptClient.js +18 -14
  45. package/dist/clients/VercelAiGptClient.js.map +1 -1
  46. package/dist/esm/apis/FlowsFilesApi.d.ts.map +1 -1
  47. package/dist/esm/apis/FlowsFilesApi.js +5 -2
  48. package/dist/esm/apis/FlowsFilesApi.js.map +1 -1
  49. package/dist/esm/assets/control-panel.js +30 -3
  50. package/dist/esm/assets/generated/parameter-schemas.json +118 -17
  51. package/dist/esm/assets/generated/version +1 -1
  52. package/dist/esm/assets/interactive-elements-tracker.js +351 -0
  53. package/dist/esm/assets/page-interactions-tracker.js +39 -20
  54. package/dist/esm/assets/smart-selector-generator.js +38 -15
  55. package/dist/esm/bindings/FocusPage.d.ts +6 -1
  56. package/dist/esm/bindings/FocusPage.d.ts.map +1 -1
  57. package/dist/esm/bindings/FocusPage.js +2 -8
  58. package/dist/esm/bindings/FocusPage.js.map +1 -1
  59. package/dist/esm/bindings/PageInteractionTracker.d.ts +9 -2
  60. package/dist/esm/bindings/PageInteractionTracker.d.ts.map +1 -1
  61. package/dist/esm/bindings/PageInteractionTracker.js +29 -5
  62. package/dist/esm/bindings/PageInteractionTracker.js.map +1 -1
  63. package/dist/esm/bindings/ProposeToolCall.d.ts +20 -0
  64. package/dist/esm/bindings/ProposeToolCall.d.ts.map +1 -0
  65. package/dist/esm/bindings/ProposeToolCall.js +29 -0
  66. package/dist/esm/bindings/ProposeToolCall.js.map +1 -0
  67. package/dist/esm/bindings/ToggleDonobuAnnotations.d.ts +5 -2
  68. package/dist/esm/bindings/ToggleDonobuAnnotations.d.ts.map +1 -1
  69. package/dist/esm/bindings/ToggleDonobuAnnotations.js +12 -6
  70. package/dist/esm/bindings/ToggleDonobuAnnotations.js.map +1 -1
  71. package/dist/esm/clients/AnthropicAwsBedrockGptClient.d.ts +1 -20
  72. package/dist/esm/clients/AnthropicAwsBedrockGptClient.d.ts.map +1 -1
  73. package/dist/esm/clients/AnthropicAwsBedrockGptClient.js +12 -329
  74. package/dist/esm/clients/AnthropicAwsBedrockGptClient.js.map +1 -1
  75. package/dist/esm/clients/AnthropicGptClient.d.ts +0 -8
  76. package/dist/esm/clients/AnthropicGptClient.d.ts.map +1 -1
  77. package/dist/esm/clients/AnthropicGptClient.js +8 -22
  78. package/dist/esm/clients/AnthropicGptClient.js.map +1 -1
  79. package/dist/esm/clients/GoogleGptClient.d.ts +4 -20
  80. package/dist/esm/clients/GoogleGptClient.d.ts.map +1 -1
  81. package/dist/esm/clients/GoogleGptClient.js +23 -299
  82. package/dist/esm/clients/GoogleGptClient.js.map +1 -1
  83. package/dist/esm/clients/OpenAiGptClient.d.ts +0 -6
  84. package/dist/esm/clients/OpenAiGptClient.d.ts.map +1 -1
  85. package/dist/esm/clients/OpenAiGptClient.js +4 -8
  86. package/dist/esm/clients/OpenAiGptClient.js.map +1 -1
  87. package/dist/esm/clients/VercelAiGptClient.d.ts +3 -1
  88. package/dist/esm/clients/VercelAiGptClient.d.ts.map +1 -1
  89. package/dist/esm/clients/VercelAiGptClient.js +18 -14
  90. package/dist/esm/clients/VercelAiGptClient.js.map +1 -1
  91. package/dist/esm/managers/CodeGenerator.d.ts.map +1 -1
  92. package/dist/esm/managers/CodeGenerator.js +2 -1
  93. package/dist/esm/managers/CodeGenerator.js.map +1 -1
  94. package/dist/esm/managers/ControlPanel.d.ts +124 -0
  95. package/dist/esm/managers/ControlPanel.d.ts.map +1 -0
  96. package/dist/esm/managers/ControlPanel.js +282 -0
  97. package/dist/esm/managers/ControlPanel.js.map +1 -0
  98. package/dist/esm/managers/DonobuFlow.d.ts +9 -13
  99. package/dist/esm/managers/DonobuFlow.d.ts.map +1 -1
  100. package/dist/esm/managers/DonobuFlow.js +123 -172
  101. package/dist/esm/managers/DonobuFlow.js.map +1 -1
  102. package/dist/esm/managers/InteractionVisualizer.d.ts +9 -15
  103. package/dist/esm/managers/InteractionVisualizer.d.ts.map +1 -1
  104. package/dist/esm/managers/InteractionVisualizer.js +44 -44
  105. package/dist/esm/managers/InteractionVisualizer.js.map +1 -1
  106. package/dist/esm/managers/PageInspector.d.ts +242 -0
  107. package/dist/esm/managers/PageInspector.d.ts.map +1 -0
  108. package/dist/esm/managers/PageInspector.js +783 -0
  109. package/dist/esm/managers/PageInspector.js.map +1 -0
  110. package/dist/esm/managers/ToolManager.d.ts.map +1 -1
  111. package/dist/esm/managers/ToolManager.js +4 -6
  112. package/dist/esm/managers/ToolManager.js.map +1 -1
  113. package/dist/esm/models/GptMessage.d.ts +3 -3
  114. package/dist/esm/models/GptMessage.d.ts.map +1 -1
  115. package/dist/esm/models/InteractableElement.d.ts +2 -2
  116. package/dist/esm/models/ToolCallContext.d.ts +6 -2
  117. package/dist/esm/models/ToolCallContext.d.ts.map +1 -1
  118. package/dist/esm/persistence/FlowsPersistence.d.ts +4 -4
  119. package/dist/esm/persistence/FlowsPersistence.d.ts.map +1 -1
  120. package/dist/esm/persistence/FlowsPersistenceAwsS3.d.ts +2 -3
  121. package/dist/esm/persistence/FlowsPersistenceAwsS3.d.ts.map +1 -1
  122. package/dist/esm/persistence/FlowsPersistenceAwsS3.js +8 -6
  123. package/dist/esm/persistence/FlowsPersistenceAwsS3.js.map +1 -1
  124. package/dist/esm/persistence/FlowsPersistenceFilesystem.d.ts +2 -3
  125. package/dist/esm/persistence/FlowsPersistenceFilesystem.d.ts.map +1 -1
  126. package/dist/esm/persistence/FlowsPersistenceFilesystem.js +5 -4
  127. package/dist/esm/persistence/FlowsPersistenceFilesystem.js.map +1 -1
  128. package/dist/esm/persistence/FlowsPersistenceGoogleCloudStorage.d.ts +2 -3
  129. package/dist/esm/persistence/FlowsPersistenceGoogleCloudStorage.d.ts.map +1 -1
  130. package/dist/esm/persistence/FlowsPersistenceGoogleCloudStorage.js +7 -5
  131. package/dist/esm/persistence/FlowsPersistenceGoogleCloudStorage.js.map +1 -1
  132. package/dist/esm/persistence/FlowsPersistenceSqlite.d.ts +2 -3
  133. package/dist/esm/persistence/FlowsPersistenceSqlite.d.ts.map +1 -1
  134. package/dist/esm/persistence/FlowsPersistenceSqlite.js +8 -6
  135. package/dist/esm/persistence/FlowsPersistenceSqlite.js.map +1 -1
  136. package/dist/esm/persistence/FlowsPersistenceSupabase.d.ts +2 -2
  137. package/dist/esm/persistence/FlowsPersistenceSupabase.d.ts.map +1 -1
  138. package/dist/esm/persistence/FlowsPersistenceSupabase.js +5 -3
  139. package/dist/esm/persistence/FlowsPersistenceSupabase.js.map +1 -1
  140. package/dist/esm/persistence/FlowsPersistenceVolatile.d.ts +2 -2
  141. package/dist/esm/persistence/FlowsPersistenceVolatile.d.ts.map +1 -1
  142. package/dist/esm/persistence/FlowsPersistenceVolatile.js +5 -3
  143. package/dist/esm/persistence/FlowsPersistenceVolatile.js.map +1 -1
  144. package/dist/esm/playwrightTestExtensions.d.ts +5 -0
  145. package/dist/esm/playwrightTestExtensions.d.ts.map +1 -1
  146. package/dist/esm/playwrightTestExtensions.js +56 -17
  147. package/dist/esm/playwrightTestExtensions.js.map +1 -1
  148. package/dist/esm/tools/AnalyzePageTextTool.js +1 -1
  149. package/dist/esm/tools/AnalyzePageTextTool.js.map +1 -1
  150. package/dist/esm/tools/AssertPageTextTool.js +1 -1
  151. package/dist/esm/tools/AssertPageTextTool.js.map +1 -1
  152. package/dist/esm/tools/AssertTool.d.ts.map +1 -1
  153. package/dist/esm/tools/AssertTool.js +5 -5
  154. package/dist/esm/tools/AssertTool.js.map +1 -1
  155. package/dist/esm/tools/ChangeWebBrowserTabTool.d.ts.map +1 -1
  156. package/dist/esm/tools/ChangeWebBrowserTabTool.js +8 -7
  157. package/dist/esm/tools/ChangeWebBrowserTabTool.js.map +1 -1
  158. package/dist/esm/tools/ClickTool.js +1 -1
  159. package/dist/esm/tools/ClickTool.js.map +1 -1
  160. package/dist/esm/tools/CreateBrowserCookieReportTool.js +1 -1
  161. package/dist/esm/tools/CreateBrowserCookieReportTool.js.map +1 -1
  162. package/dist/esm/tools/CustomToolRunnerTool.d.ts.map +1 -1
  163. package/dist/esm/tools/CustomToolRunnerTool.js +1 -1
  164. package/dist/esm/tools/CustomToolRunnerTool.js.map +1 -1
  165. package/dist/esm/tools/DetectBrokenLinksTool.d.ts.map +1 -1
  166. package/dist/esm/tools/DetectBrokenLinksTool.js +5 -3
  167. package/dist/esm/tools/DetectBrokenLinksTool.js.map +1 -1
  168. package/dist/esm/tools/ExtractGoogleStreetviewEntityDataTool.js +4 -4
  169. package/dist/esm/tools/ExtractGoogleStreetviewEntityDataTool.js.map +1 -1
  170. package/dist/esm/tools/ExtractPaymentProviderKeyTool.js +1 -1
  171. package/dist/esm/tools/ExtractPaymentProviderKeyTool.js.map +1 -1
  172. package/dist/esm/tools/ExtractPublicFacebookEntityDataTool.js +1 -1
  173. package/dist/esm/tools/ExtractPublicFacebookEntityDataTool.js.map +1 -1
  174. package/dist/esm/tools/GoForwardOrBackTool.js +1 -1
  175. package/dist/esm/tools/GoForwardOrBackTool.js.map +1 -1
  176. package/dist/esm/tools/GoToGoogleMapsStreetViewTool.js +1 -1
  177. package/dist/esm/tools/GoToGoogleMapsStreetViewTool.js.map +1 -1
  178. package/dist/esm/tools/GoToWebpageTool.js +1 -1
  179. package/dist/esm/tools/GoToWebpageTool.js.map +1 -1
  180. package/dist/esm/tools/HoverOverElementTool.d.ts.map +1 -1
  181. package/dist/esm/tools/HoverOverElementTool.js +1 -1
  182. package/dist/esm/tools/HoverOverElementTool.js.map +1 -1
  183. package/dist/esm/tools/NavigateWithinStreetView.js +1 -1
  184. package/dist/esm/tools/NavigateWithinStreetView.js.map +1 -1
  185. package/dist/esm/tools/PressKeyTool.js +1 -1
  186. package/dist/esm/tools/PressKeyTool.js.map +1 -1
  187. package/dist/esm/tools/ReloadPageTool.js +1 -1
  188. package/dist/esm/tools/ReloadPageTool.js.map +1 -1
  189. package/dist/esm/tools/ReplayableInteraction.d.ts +16 -1
  190. package/dist/esm/tools/ReplayableInteraction.d.ts.map +1 -1
  191. package/dist/esm/tools/ReplayableInteraction.js +169 -16
  192. package/dist/esm/tools/ReplayableInteraction.js.map +1 -1
  193. package/dist/esm/tools/RunAccessibilityTestTool.d.ts +8 -0
  194. package/dist/esm/tools/RunAccessibilityTestTool.d.ts.map +1 -1
  195. package/dist/esm/tools/RunAccessibilityTestTool.js +15 -2
  196. package/dist/esm/tools/RunAccessibilityTestTool.js.map +1 -1
  197. package/dist/esm/tools/RunInlineJavaScriptCodeTool.d.ts.map +1 -1
  198. package/dist/esm/tools/RunInlineJavaScriptCodeTool.js +1 -1
  199. package/dist/esm/tools/RunInlineJavaScriptCodeTool.js.map +1 -1
  200. package/dist/esm/tools/SaveWebpageAsPdfTool.js +1 -1
  201. package/dist/esm/tools/SaveWebpageAsPdfTool.js.map +1 -1
  202. package/dist/esm/tools/ScrollPageTool.d.ts +1 -1
  203. package/dist/esm/tools/ScrollPageTool.d.ts.map +1 -1
  204. package/dist/esm/tools/ScrollPageTool.js +47 -4
  205. package/dist/esm/tools/ScrollPageTool.js.map +1 -1
  206. package/dist/esm/tools/WaitTool.js +1 -1
  207. package/dist/esm/tools/WaitTool.js.map +1 -1
  208. package/dist/esm/utils/MiscUtils.d.ts +10 -13
  209. package/dist/esm/utils/MiscUtils.d.ts.map +1 -1
  210. package/dist/esm/utils/MiscUtils.js +92 -56
  211. package/dist/esm/utils/MiscUtils.js.map +1 -1
  212. package/dist/esm/utils/PlaywrightUtils.d.ts +32 -130
  213. package/dist/esm/utils/PlaywrightUtils.d.ts.map +1 -1
  214. package/dist/esm/utils/PlaywrightUtils.js +140 -938
  215. package/dist/esm/utils/PlaywrightUtils.js.map +1 -1
  216. package/dist/managers/CodeGenerator.d.ts.map +1 -1
  217. package/dist/managers/CodeGenerator.js +2 -1
  218. package/dist/managers/CodeGenerator.js.map +1 -1
  219. package/dist/managers/ControlPanel.d.ts +124 -0
  220. package/dist/managers/ControlPanel.d.ts.map +1 -0
  221. package/dist/managers/ControlPanel.js +282 -0
  222. package/dist/managers/ControlPanel.js.map +1 -0
  223. package/dist/managers/DonobuFlow.d.ts +9 -13
  224. package/dist/managers/DonobuFlow.d.ts.map +1 -1
  225. package/dist/managers/DonobuFlow.js +123 -172
  226. package/dist/managers/DonobuFlow.js.map +1 -1
  227. package/dist/managers/InteractionVisualizer.d.ts +9 -15
  228. package/dist/managers/InteractionVisualizer.d.ts.map +1 -1
  229. package/dist/managers/InteractionVisualizer.js +44 -44
  230. package/dist/managers/InteractionVisualizer.js.map +1 -1
  231. package/dist/managers/PageInspector.d.ts +242 -0
  232. package/dist/managers/PageInspector.d.ts.map +1 -0
  233. package/dist/managers/PageInspector.js +783 -0
  234. package/dist/managers/PageInspector.js.map +1 -0
  235. package/dist/managers/ToolManager.d.ts.map +1 -1
  236. package/dist/managers/ToolManager.js +4 -6
  237. package/dist/managers/ToolManager.js.map +1 -1
  238. package/dist/models/GptMessage.d.ts +3 -3
  239. package/dist/models/GptMessage.d.ts.map +1 -1
  240. package/dist/models/InteractableElement.d.ts +2 -2
  241. package/dist/models/ToolCallContext.d.ts +6 -2
  242. package/dist/models/ToolCallContext.d.ts.map +1 -1
  243. package/dist/persistence/FlowsPersistence.d.ts +4 -4
  244. package/dist/persistence/FlowsPersistence.d.ts.map +1 -1
  245. package/dist/persistence/FlowsPersistenceAwsS3.d.ts +2 -3
  246. package/dist/persistence/FlowsPersistenceAwsS3.d.ts.map +1 -1
  247. package/dist/persistence/FlowsPersistenceAwsS3.js +8 -6
  248. package/dist/persistence/FlowsPersistenceAwsS3.js.map +1 -1
  249. package/dist/persistence/FlowsPersistenceFilesystem.d.ts +2 -3
  250. package/dist/persistence/FlowsPersistenceFilesystem.d.ts.map +1 -1
  251. package/dist/persistence/FlowsPersistenceFilesystem.js +5 -4
  252. package/dist/persistence/FlowsPersistenceFilesystem.js.map +1 -1
  253. package/dist/persistence/FlowsPersistenceGoogleCloudStorage.d.ts +2 -3
  254. package/dist/persistence/FlowsPersistenceGoogleCloudStorage.d.ts.map +1 -1
  255. package/dist/persistence/FlowsPersistenceGoogleCloudStorage.js +7 -5
  256. package/dist/persistence/FlowsPersistenceGoogleCloudStorage.js.map +1 -1
  257. package/dist/persistence/FlowsPersistenceSqlite.d.ts +2 -3
  258. package/dist/persistence/FlowsPersistenceSqlite.d.ts.map +1 -1
  259. package/dist/persistence/FlowsPersistenceSqlite.js +8 -6
  260. package/dist/persistence/FlowsPersistenceSqlite.js.map +1 -1
  261. package/dist/persistence/FlowsPersistenceSupabase.d.ts +2 -2
  262. package/dist/persistence/FlowsPersistenceSupabase.d.ts.map +1 -1
  263. package/dist/persistence/FlowsPersistenceSupabase.js +5 -3
  264. package/dist/persistence/FlowsPersistenceSupabase.js.map +1 -1
  265. package/dist/persistence/FlowsPersistenceVolatile.d.ts +2 -2
  266. package/dist/persistence/FlowsPersistenceVolatile.d.ts.map +1 -1
  267. package/dist/persistence/FlowsPersistenceVolatile.js +5 -3
  268. package/dist/persistence/FlowsPersistenceVolatile.js.map +1 -1
  269. package/dist/playwrightTestExtensions.d.ts +5 -0
  270. package/dist/playwrightTestExtensions.d.ts.map +1 -1
  271. package/dist/playwrightTestExtensions.js +56 -17
  272. package/dist/playwrightTestExtensions.js.map +1 -1
  273. package/dist/tools/AnalyzePageTextTool.js +1 -1
  274. package/dist/tools/AnalyzePageTextTool.js.map +1 -1
  275. package/dist/tools/AssertPageTextTool.js +1 -1
  276. package/dist/tools/AssertPageTextTool.js.map +1 -1
  277. package/dist/tools/AssertTool.d.ts.map +1 -1
  278. package/dist/tools/AssertTool.js +5 -5
  279. package/dist/tools/AssertTool.js.map +1 -1
  280. package/dist/tools/ChangeWebBrowserTabTool.d.ts.map +1 -1
  281. package/dist/tools/ChangeWebBrowserTabTool.js +8 -7
  282. package/dist/tools/ChangeWebBrowserTabTool.js.map +1 -1
  283. package/dist/tools/ClickTool.js +1 -1
  284. package/dist/tools/ClickTool.js.map +1 -1
  285. package/dist/tools/CreateBrowserCookieReportTool.js +1 -1
  286. package/dist/tools/CreateBrowserCookieReportTool.js.map +1 -1
  287. package/dist/tools/CustomToolRunnerTool.d.ts.map +1 -1
  288. package/dist/tools/CustomToolRunnerTool.js +1 -1
  289. package/dist/tools/CustomToolRunnerTool.js.map +1 -1
  290. package/dist/tools/DetectBrokenLinksTool.d.ts.map +1 -1
  291. package/dist/tools/DetectBrokenLinksTool.js +5 -3
  292. package/dist/tools/DetectBrokenLinksTool.js.map +1 -1
  293. package/dist/tools/ExtractGoogleStreetviewEntityDataTool.js +4 -4
  294. package/dist/tools/ExtractGoogleStreetviewEntityDataTool.js.map +1 -1
  295. package/dist/tools/ExtractPaymentProviderKeyTool.js +1 -1
  296. package/dist/tools/ExtractPaymentProviderKeyTool.js.map +1 -1
  297. package/dist/tools/ExtractPublicFacebookEntityDataTool.js +1 -1
  298. package/dist/tools/ExtractPublicFacebookEntityDataTool.js.map +1 -1
  299. package/dist/tools/GoForwardOrBackTool.js +1 -1
  300. package/dist/tools/GoForwardOrBackTool.js.map +1 -1
  301. package/dist/tools/GoToGoogleMapsStreetViewTool.js +1 -1
  302. package/dist/tools/GoToGoogleMapsStreetViewTool.js.map +1 -1
  303. package/dist/tools/GoToWebpageTool.js +1 -1
  304. package/dist/tools/GoToWebpageTool.js.map +1 -1
  305. package/dist/tools/HoverOverElementTool.d.ts.map +1 -1
  306. package/dist/tools/HoverOverElementTool.js +1 -1
  307. package/dist/tools/HoverOverElementTool.js.map +1 -1
  308. package/dist/tools/NavigateWithinStreetView.js +1 -1
  309. package/dist/tools/NavigateWithinStreetView.js.map +1 -1
  310. package/dist/tools/PressKeyTool.js +1 -1
  311. package/dist/tools/PressKeyTool.js.map +1 -1
  312. package/dist/tools/ReloadPageTool.js +1 -1
  313. package/dist/tools/ReloadPageTool.js.map +1 -1
  314. package/dist/tools/ReplayableInteraction.d.ts +16 -1
  315. package/dist/tools/ReplayableInteraction.d.ts.map +1 -1
  316. package/dist/tools/ReplayableInteraction.js +169 -16
  317. package/dist/tools/ReplayableInteraction.js.map +1 -1
  318. package/dist/tools/RunAccessibilityTestTool.d.ts +8 -0
  319. package/dist/tools/RunAccessibilityTestTool.d.ts.map +1 -1
  320. package/dist/tools/RunAccessibilityTestTool.js +15 -2
  321. package/dist/tools/RunAccessibilityTestTool.js.map +1 -1
  322. package/dist/tools/RunInlineJavaScriptCodeTool.d.ts.map +1 -1
  323. package/dist/tools/RunInlineJavaScriptCodeTool.js +1 -1
  324. package/dist/tools/RunInlineJavaScriptCodeTool.js.map +1 -1
  325. package/dist/tools/SaveWebpageAsPdfTool.js +1 -1
  326. package/dist/tools/SaveWebpageAsPdfTool.js.map +1 -1
  327. package/dist/tools/ScrollPageTool.d.ts +1 -1
  328. package/dist/tools/ScrollPageTool.d.ts.map +1 -1
  329. package/dist/tools/ScrollPageTool.js +47 -4
  330. package/dist/tools/ScrollPageTool.js.map +1 -1
  331. package/dist/tools/WaitTool.js +1 -1
  332. package/dist/tools/WaitTool.js.map +1 -1
  333. package/dist/utils/MiscUtils.d.ts +10 -13
  334. package/dist/utils/MiscUtils.d.ts.map +1 -1
  335. package/dist/utils/MiscUtils.js +92 -56
  336. package/dist/utils/MiscUtils.js.map +1 -1
  337. package/dist/utils/PlaywrightUtils.d.ts +32 -130
  338. package/dist/utils/PlaywrightUtils.d.ts.map +1 -1
  339. package/dist/utils/PlaywrightUtils.js +140 -938
  340. package/dist/utils/PlaywrightUtils.js.map +1 -1
  341. package/package.json +4 -2
  342. package/dist/assets/clickable-elements-tracker.js +0 -63
  343. package/dist/assets/zaru-eyes.html +0 -141
  344. package/dist/esm/assets/clickable-elements-tracker.js +0 -63
  345. package/dist/esm/assets/zaru-eyes.html +0 -141
  346. package/dist/esm/managers/TemplateInterpolator.d.ts +0 -19
  347. package/dist/esm/managers/TemplateInterpolator.d.ts.map +0 -1
  348. package/dist/esm/managers/TemplateInterpolator.js +0 -86
  349. package/dist/esm/managers/TemplateInterpolator.js.map +0 -1
  350. package/dist/esm/managers/ToolTipper.d.ts +0 -32
  351. package/dist/esm/managers/ToolTipper.d.ts.map +0 -1
  352. package/dist/esm/managers/ToolTipper.js +0 -229
  353. package/dist/esm/managers/ToolTipper.js.map +0 -1
  354. package/dist/esm/models/BrowserState.d.ts +0 -26
  355. package/dist/esm/models/BrowserState.d.ts.map +0 -1
  356. package/dist/esm/models/BrowserState.js +0 -3
  357. package/dist/esm/models/BrowserState.js.map +0 -1
  358. package/dist/esm/models/ResolverContext.d.ts +0 -7
  359. package/dist/esm/models/ResolverContext.d.ts.map +0 -1
  360. package/dist/esm/models/ResolverContext.js +0 -3
  361. package/dist/esm/models/ResolverContext.js.map +0 -1
  362. package/dist/esm/models/ToolTemplateDataSource.d.ts +0 -36
  363. package/dist/esm/models/ToolTemplateDataSource.d.ts.map +0 -1
  364. package/dist/esm/models/ToolTemplateDataSource.js +0 -3
  365. package/dist/esm/models/ToolTemplateDataSource.js.map +0 -1
  366. package/dist/esm/test.d.ts +0 -78
  367. package/dist/esm/test.d.ts.map +0 -1
  368. package/dist/esm/test.js +0 -423
  369. package/dist/esm/test.js.map +0 -1
  370. package/dist/esm/utils/TemplateInterpolator.d.ts +0 -29
  371. package/dist/esm/utils/TemplateInterpolator.d.ts.map +0 -1
  372. package/dist/esm/utils/TemplateInterpolator.js +0 -206
  373. package/dist/esm/utils/TemplateInterpolator.js.map +0 -1
  374. package/dist/managers/TemplateInterpolator.d.ts +0 -19
  375. package/dist/managers/TemplateInterpolator.d.ts.map +0 -1
  376. package/dist/managers/TemplateInterpolator.js +0 -86
  377. package/dist/managers/TemplateInterpolator.js.map +0 -1
  378. package/dist/managers/ToolTipper.d.ts +0 -32
  379. package/dist/managers/ToolTipper.d.ts.map +0 -1
  380. package/dist/managers/ToolTipper.js +0 -229
  381. package/dist/managers/ToolTipper.js.map +0 -1
  382. package/dist/models/BrowserState.d.ts +0 -26
  383. package/dist/models/BrowserState.d.ts.map +0 -1
  384. package/dist/models/BrowserState.js +0 -3
  385. package/dist/models/BrowserState.js.map +0 -1
  386. package/dist/models/ResolverContext.d.ts +0 -7
  387. package/dist/models/ResolverContext.d.ts.map +0 -1
  388. package/dist/models/ResolverContext.js +0 -3
  389. package/dist/models/ResolverContext.js.map +0 -1
  390. package/dist/models/ToolTemplateDataSource.d.ts +0 -36
  391. package/dist/models/ToolTemplateDataSource.d.ts.map +0 -1
  392. package/dist/models/ToolTemplateDataSource.js +0 -3
  393. package/dist/models/ToolTemplateDataSource.js.map +0 -1
  394. package/dist/test.d.ts +0 -78
  395. package/dist/test.d.ts.map +0 -1
  396. package/dist/test.js +0 -423
  397. package/dist/test.js.map +0 -1
  398. package/dist/tsconfig.esm.tsbuildinfo +0 -1
  399. package/dist/utils/TemplateInterpolator.d.ts +0 -29
  400. package/dist/utils/TemplateInterpolator.d.ts.map +0 -1
  401. package/dist/utils/TemplateInterpolator.js +0 -211
  402. package/dist/utils/TemplateInterpolator.js.map +0 -1
@@ -1,5 +1,4 @@
1
1
  "use strict";
2
- // PlaywrightUtils.ts
3
2
  var __importDefault = (this && this.__importDefault) || function (mod) {
4
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
5
4
  };
@@ -10,23 +9,29 @@ const MiscUtils_1 = require("./MiscUtils");
10
9
  const path_1 = __importDefault(require("path"));
11
10
  const PageClosedException_1 = require("../exceptions/PageClosedException");
12
11
  const child_process_1 = require("child_process");
12
+ const ControlPanel_1 = require("../managers/ControlPanel");
13
+ const PageInspector_1 = require("../managers/PageInspector");
14
+ const RunAccessibilityTestTool_1 = require("../tools/RunAccessibilityTestTool");
13
15
  /**
14
16
  * Miscellaneous utility functions for working with the Playwright SDK. If you are looking to
15
17
  * instantiate a Playwright instance, see PlaywrightSetup instead.
16
18
  */
17
19
  class PlaywrightUtils {
18
20
  /**
19
- * Attempts to take a screenshot of the given page in PNG format, returning
20
- * the raw byte array. If the operation fails, an empty array is returned.
21
+ * Attempts to take a screenshot of the given page, returning the raw byte
22
+ * array.
23
+ *
24
+ * If the operation fails, an empty array is returned.
25
+ *
21
26
  * Note that if the Donobu control panel is present in the page, it will be
22
27
  * excluded from the screenshot.
23
28
  */
24
- static async takePngScreenshot(page) {
29
+ static async takeScreenshot(page, type = 'jpeg') {
25
30
  try {
26
- const style = `#${PlaywrightUtils.DONOBU_CONTROL_PANEL_ELEMENT_ID} { display: none !important; }`;
31
+ const style = `#${ControlPanel_1.ControlPanel.DONOBU_CONTROL_PANEL_ELEMENT_ID} { display: none !important; }`;
27
32
  return await page.screenshot({
28
33
  style,
29
- type: 'png',
34
+ type: type,
30
35
  });
31
36
  }
32
37
  catch (error) {
@@ -47,56 +52,9 @@ class PlaywrightUtils {
47
52
  */
48
53
  static async generateSelectors(element) {
49
54
  return element.evaluate((elem) => {
50
- return window.donobuGenerateSmartSelectors(elem);
55
+ return window.__donobu.generateSmartSelectors(elem);
51
56
  });
52
57
  }
53
- /**
54
- * Returns a JavaScript code snippet intended to run as an initialization
55
- * script for `DonobuFlow` flows. This script helps other scripts to know
56
- * which elements have mouse-click related event listeners attached to them
57
- * via inspecting the {@code window.donobuGetClickableElements} element array.
58
- */
59
- static clickableElementsTrackerInitScript() {
60
- return PlaywrightUtils.CLICKABLE_ELEMENTS_TRACKER_INIT_SCRIPT;
61
- }
62
- /**
63
- * Returns a JavaScript code snippet intended to run as an initialization
64
- * script for `DonobuFlow` flows. This script helps flows handle/track
65
- * prompts/confirmations. This is done specially since these browser actions
66
- * pause the Javascript main thread and also cause issues with running various
67
- * Playwright actions. See `DonobuFlow.onDialog(Dialog)` for details.
68
- */
69
- static dialogPromptTrackerInitScript() {
70
- return PlaywrightUtils.DIALOG_PROMPT_TRACKER_INIT_SCRIPT;
71
- }
72
- /**
73
- * Returns a JavaScript code snippet intended to run as an initialization
74
- * script for `DonobuFlow` flows. This is an in-page version of the
75
- * `SelectorGenerator` class so that smart selectors can be generated in
76
- * the web client. This is done so the
77
- * {@link PlaywrightUtils.pageInteractionsTrackerInitScript()} can generate
78
- * smart selectors on the fly and pass them to the `PageInteractionTracker`
79
- * so the page interactions can be converted to synthetic `ToolCallResult`s.
80
- */
81
- static smartSelectorGeneratorInitScript() {
82
- return PlaywrightUtils.SMART_SELECTOR_GENERATOR_INIT_SCRIPT;
83
- }
84
- /**
85
- * This script is used by the `RunAccessibilityTestTool` to test the
86
- * accessibility of a webpage. This script is injected on page load, rather
87
- * than when running the `RunAccessibilityTestTool` because we need to bypass
88
- * webpage Content Security Policy (CSP); this is done by injecting the
89
- * script via `BrowserContext#addInitScript`.
90
- */
91
- static accessibilityTestInitScript() {
92
- return PlaywrightUtils.ACCESSIBILITY_TEST_INIT_SCRIPT;
93
- }
94
- static pageInteractionsTrackerInitScript() {
95
- return PlaywrightUtils.PAGE_INTERACTIONS_TRACKER_INIT_SCRIPT;
96
- }
97
- static donobuControlPanelInitScript() {
98
- return PlaywrightUtils.DONOBU_CONTROL_PANEL_INIT_SCRIPT;
99
- }
100
58
  /**
101
59
  * Sets up the given browser context so that it can be minimally used by the
102
60
  * rest of Donobu. This involves registering virtual routes for serving up
@@ -104,614 +62,10 @@ class PlaywrightUtils {
104
62
  * scripts.
105
63
  */
106
64
  static async setupBasicBrowserContext(browserContext) {
107
- // Add Donobu CSS and SVG routes to the browser so that are not violating
108
- // the CSP of any of the pages we attempt to render our custom stuff on.
109
- await browserContext.route('**/donobu-virtual-mouse.svg', async (route) => {
110
- await route.fulfill({
111
- status: 200,
112
- contentType: 'image/svg+xml',
113
- body: MiscUtils_1.MiscUtils.getResourceFileAsString('donobu-virtual-mouse.svg'),
114
- });
115
- });
116
- await browserContext.route('**/donobu.css', async (route) => {
117
- await route.fulfill({
118
- status: 200,
119
- contentType: 'text/css',
120
- body: MiscUtils_1.MiscUtils.getResourceFileAsString('donobu.css'),
121
- });
122
- });
123
- await browserContext.addInitScript(PlaywrightUtils.accessibilityTestInitScript());
124
- await browserContext.addInitScript(PlaywrightUtils.clickableElementsTrackerInitScript());
125
- await browserContext.addInitScript(PlaywrightUtils.dialogPromptTrackerInitScript());
126
- await browserContext.addInitScript(PlaywrightUtils.smartSelectorGeneratorInitScript());
127
- }
128
- /**
129
- * Returns the given locator or its label, if it has one and is associated with a labelable element.
130
- * Labelable elements include: button, input (except hidden), meter, output, progress, select, and textarea.
131
- */
132
- static async getLocatorOrItsLabel(element) {
133
- const timeoutMilliseconds = 5000;
134
- try {
135
- // First check if the element itself is visible
136
- try {
137
- await element.waitFor({
138
- state: 'visible',
139
- timeout: timeoutMilliseconds,
140
- });
141
- }
142
- catch (error) {
143
- // If the element itself isn't visible, just return it without looking for labels
144
- if (PlaywrightUtils.isPageClosedError(error)) {
145
- throw new PageClosedException_1.PageClosedException();
146
- }
147
- return element;
148
- }
149
- // Check if the element is a labelable element
150
- // See https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/label
151
- const isLabelable = await element.evaluate((elem) => {
152
- const tagName = elem.tagName.toLowerCase();
153
- if (tagName === 'button' ||
154
- tagName === 'meter' ||
155
- tagName === 'output' ||
156
- tagName === 'progress' ||
157
- tagName === 'select' ||
158
- tagName === 'textarea') {
159
- return true;
160
- }
161
- if (tagName === 'input') {
162
- // Input is labelable except when type="hidden"
163
- const type = elem.getAttribute('type')?.toLowerCase() || 'text';
164
- return type !== 'hidden';
165
- }
166
- return false;
167
- });
168
- // If the element is not labelable, return the original locator
169
- if (!isLabelable) {
170
- return element;
171
- }
172
- // Try to get the ID attribute
173
- const id = await element
174
- .getAttribute('id', {
175
- timeout: timeoutMilliseconds,
176
- })
177
- .catch(() => null);
178
- if (id) {
179
- try {
180
- // Get the underlying ElementHandle first
181
- const handle = await element.elementHandle({
182
- timeout: timeoutMilliseconds,
183
- });
184
- if (handle) {
185
- // From the handle, retrieve the frame that owns this element
186
- const frame = await handle.ownerFrame();
187
- if (frame) {
188
- // Look for label with matching 'for' attribute
189
- const labelByFor = frame.locator(`label[for="${id}"]`);
190
- // Check if the label exists and is visible
191
- if ((await labelByFor.count()) > 0) {
192
- try {
193
- await labelByFor.waitFor({
194
- state: 'visible',
195
- timeout: timeoutMilliseconds,
196
- });
197
- return labelByFor;
198
- }
199
- catch (visibilityError) {
200
- // If label exists but isn't visible, continue to other checks
201
- if (PlaywrightUtils.isPageClosedError(visibilityError)) {
202
- throw new PageClosedException_1.PageClosedException();
203
- }
204
- }
205
- }
206
- }
207
- }
208
- }
209
- catch (error) {
210
- // Handle errors in the ElementHandle/frame retrieval, but continue to other checks
211
- if (PlaywrightUtils.isPageClosedError(error)) {
212
- throw new PageClosedException_1.PageClosedException();
213
- }
214
- }
215
- }
216
- // Fallback: look for a directly wrapping label (immediate ancestor)
217
- // Using 'xpath=parent::label' to only get direct parent if it's a label
218
- const directParentLabel = element.locator('xpath=parent::label');
219
- if ((await directParentLabel.count()) > 0) {
220
- try {
221
- await directParentLabel.waitFor({
222
- state: 'visible',
223
- timeout: timeoutMilliseconds,
224
- });
225
- return directParentLabel;
226
- }
227
- catch (visibilityError) {
228
- if (PlaywrightUtils.isPageClosedError(visibilityError)) {
229
- throw new PageClosedException_1.PageClosedException();
230
- }
231
- }
232
- }
233
- // If direct parent isn't a label, check any ancestor label
234
- const wrappingLabel = element.locator('xpath=ancestor::label[1]'); // Get closest ancestor label
235
- if ((await wrappingLabel.count()) > 0) {
236
- try {
237
- await wrappingLabel.waitFor({
238
- state: 'visible',
239
- timeout: timeoutMilliseconds,
240
- });
241
- return wrappingLabel;
242
- }
243
- catch (visibilityError) {
244
- if (PlaywrightUtils.isPageClosedError(visibilityError)) {
245
- throw new PageClosedException_1.PageClosedException();
246
- }
247
- }
248
- }
249
- // Neither "for" nor wrapping label found or visible
250
- return element;
251
- }
252
- catch (error) {
253
- if (PlaywrightUtils.isPageClosedError(error)) {
254
- throw new PageClosedException_1.PageClosedException();
255
- }
256
- throw error;
257
- }
258
- }
259
- /**
260
- * Reads and clears the desired next state as directed by the in-flow control
261
- * panel. Note that the control panel does not have carte blanche control, as
262
- * we only support the control panel signaling an intent to pause and resume a
263
- * flow.
264
- */
265
- static async popControlPanelNextDesiredState(page) {
266
- try {
267
- const desiredNextState = await page.evaluate(() => {
268
- const tmpState = window.donobuNextState;
269
- window.donobuNextState = null;
270
- return tmpState;
271
- });
272
- if (desiredNextState) {
273
- return desiredNextState;
274
- }
275
- }
276
- catch (error) {
277
- if (PlaywrightUtils.isPageClosedError(error)) {
278
- throw new PageClosedException_1.PageClosedException();
279
- }
280
- else {
281
- throw error;
282
- }
283
- }
284
- return null;
285
- }
286
- /**
287
- * Hides the control panel by setting its display to 'none'. This ensures the
288
- * panel is not visible and does not intercept mouse events.
289
- */
290
- static async hideControlPanel(focusedPage, flowMetadata) {
291
- if (!flowMetadata.isControlPanelEnabled) {
292
- return;
293
- }
294
- for (const page of focusedPage.context().pages()) {
295
- try {
296
- await page.evaluate((panelId) => {
297
- const element = document.querySelector(`#${panelId}`);
298
- if (element) {
299
- element.style.display = 'none';
300
- }
301
- }, PlaywrightUtils.DONOBU_CONTROL_PANEL_ELEMENT_ID);
302
- }
303
- catch (error) {
304
- if (PlaywrightUtils.isPageClosedError(error)) {
305
- // Pass; this can happen normally.
306
- }
307
- else {
308
- Logger_1.appLogger.error(`Unexpected exception while attempting to show control panel for flow '${flowMetadata.id}'`, error);
309
- }
310
- }
311
- }
312
- }
313
- /**
314
- * Shows the control panel by resetting its display property. Assumes the
315
- * original display was 'block'.
316
- */
317
- static async showControlPanel(focusedPage, flowMetadata) {
318
- if (!flowMetadata.isControlPanelEnabled) {
319
- return;
320
- }
321
- for (const page of focusedPage.context().pages()) {
322
- try {
323
- await page.evaluate((panelId) => {
324
- const element = document.querySelector(`#${panelId}`);
325
- if (element) {
326
- element.style.display = 'block';
327
- }
328
- }, PlaywrightUtils.DONOBU_CONTROL_PANEL_ELEMENT_ID);
329
- }
330
- catch (error) {
331
- if (PlaywrightUtils.isPageClosedError(error)) {
332
- // Pass; this can happen normally.
333
- }
334
- else {
335
- Logger_1.appLogger.error(`Unexpected exception while attempting to show control panel for flow '${flowMetadata.id}'`, error);
336
- }
337
- }
338
- }
339
- }
340
- /**
341
- * Updates all control panels in the given browser context. If the provided
342
- * headline is non-null, the headline in the control panel will be updated.
343
- */
344
- static async updateControlPanel(focusedPage, flowMetadata, headline) {
345
- const controlPanelQuerySelector = `#${PlaywrightUtils.DONOBU_CONTROL_PANEL_ELEMENT_ID}`;
346
- const controlPanelHeadlineQuerySelector = `#${PlaywrightUtils.DONOBU_CONTROL_PANEL_HEADLINE_ELEMENT_ID}`;
347
- for (const page of focusedPage.context().pages()) {
348
- try {
349
- const controlPanel = page.locator(controlPanelQuerySelector).first();
350
- if ((await controlPanel.count()) === 1) {
351
- await controlPanel.evaluate((element, state) => {
352
- element.donobuFlowState = state;
353
- }, flowMetadata.state.toString());
354
- if (headline) {
355
- const controlPanelHeadline = page
356
- .locator(controlPanelHeadlineQuerySelector)
357
- .first();
358
- if ((await controlPanelHeadline.count()) === 1) {
359
- const escapedMessage = headline.replace(/[\\"']/g, '\\$&');
360
- await controlPanelHeadline.evaluate((element, message) => {
361
- element.textContent = message;
362
- }, escapedMessage);
363
- }
364
- }
365
- }
366
- }
367
- catch (error) {
368
- if (PlaywrightUtils.isPageClosedError(error)) {
369
- // Pass; this can happen normally.
370
- }
371
- else {
372
- Logger_1.appLogger.error(`Unexpected exception while attempting to show control panel for flow '${flowMetadata.id}'`, error);
373
- }
374
- }
375
- }
376
- }
377
- /**
378
- * Returns all elements that have the
379
- * {@link PlaywrightUtils.DONOBU_INTERACTABLE_ATTRIBUTE} HTML attribute.
380
- **/
381
- static async getAttributedInteractableElements(page) {
382
- try {
383
- const interactableElements = [];
384
- const frames = page
385
- .frames()
386
- .filter((frame) => PlaywrightUtils.frameFilter(frame));
387
- for (const frame of frames) {
388
- const attributeMap = await frame.evaluate((interactableAttribute) => {
389
- const getOuterHTMLWithoutChildrenExceptForSelectElements = (element) => {
390
- if (element.tagName.toLowerCase() === 'select') {
391
- return element.outerHTML;
392
- }
393
- else {
394
- const tempElement = document.createElement('div');
395
- tempElement.appendChild(element.cloneNode(false));
396
- return tempElement.innerHTML;
397
- }
398
- };
399
- const attributeToHtmlMap = {};
400
- const elements = document.querySelectorAll(`[${interactableAttribute}]`);
401
- elements.forEach((element) => {
402
- const attributeValue = element.getAttribute(interactableAttribute);
403
- const outerHtml = getOuterHTMLWithoutChildrenExceptForSelectElements(element);
404
- if (attributeValue) {
405
- attributeToHtmlMap[attributeValue] = outerHtml;
406
- }
407
- });
408
- return attributeToHtmlMap;
409
- }, PlaywrightUtils.DONOBU_INTERACTABLE_ATTRIBUTE);
410
- Object.entries(attributeMap).forEach(([donobuAttributeValue, htmlSnippet]) => {
411
- interactableElements.push({
412
- donobuAttributeValue,
413
- htmlSnippet,
414
- });
415
- });
416
- }
417
- return interactableElements;
418
- }
419
- catch (error) {
420
- if (PlaywrightUtils.isPageClosedError(error)) {
421
- throw new PageClosedException_1.PageClosedException();
422
- }
423
- else {
424
- throw error;
425
- }
426
- }
427
- }
428
- /**
429
- * Assigns a globally unique {@link PlaywrightUtils.DONOBU_INTERACTABLE_ATTRIBUTE}
430
- * attribute value to each visible, interactable, element in the given page.
431
- * Any pre-existing {@link PlaywrightUtils.DONOBU_INTERACTABLE_ATTRIBUTE}
432
- * attributes will be removed.
433
- */
434
- static async attributeInteractableElements(page) {
435
- try {
436
- // Remove any preexisting attributes
437
- await this.deattributeVisibleInteractableElements(page);
438
- // Get viewport dimensions and scroll position properly
439
- const viewportInfo = await page.evaluate(() => {
440
- return {
441
- viewportWidth: window.innerWidth,
442
- viewportHeight: window.innerHeight,
443
- scrollX: window.scrollX || window.pageXOffset,
444
- scrollY: window.scrollY || window.pageYOffset,
445
- };
446
- });
447
- // 1) Attribute elements in the main page
448
- let annotationOffset = await page.evaluate(this.attributeElementsInContext, [0, PlaywrightUtils.DONOBU_INTERACTABLE_ATTRIBUTE]);
449
- // 2) Check child frames, attributing elements if the frame is (partially) in view
450
- const frames = page
451
- .frames()
452
- .filter((frame) => PlaywrightUtils.frameFilter(frame) && frame !== page.mainFrame());
453
- for (const frame of frames) {
454
- const elementHandle = await frame.frameElement();
455
- if (!elementHandle) {
456
- continue;
457
- }
458
- const boundingBox = await elementHandle.boundingBox();
459
- if (!boundingBox) {
460
- continue;
461
- }
462
- // boundingBox coordinates are already in viewport space, so we need to account for scroll
463
- const isInViewport = boundingBox.x + boundingBox.width > 0 &&
464
- boundingBox.x < viewportInfo.viewportWidth &&
465
- boundingBox.y + boundingBox.height > 0 &&
466
- boundingBox.y < viewportInfo.viewportHeight;
467
- if (isInViewport) {
468
- annotationOffset = await frame.evaluate(this.attributeElementsInContext, [
469
- annotationOffset,
470
- PlaywrightUtils.DONOBU_INTERACTABLE_ATTRIBUTE,
471
- ]);
472
- }
473
- }
474
- }
475
- catch (error) {
476
- if (PlaywrightUtils.isPageClosedError(error)) {
477
- throw new PageClosedException_1.PageClosedException();
478
- }
479
- else {
480
- throw error;
481
- }
482
- }
483
- }
484
- /**
485
- * Annotate all elements in the given page that have a
486
- * {@link PlaywrightUtils.DONOBU_INTERACTABLE_ATTRIBUTE} HTML attribute.
487
- *
488
- * The annotations are placed in a shadow root to avoid site-specific CSS,
489
- * each having a {@link PlaywrightUtils.DONOBU_ANNOTATION_ATTRIBUTE} attribute.
490
- */
491
- static async annotateInteractableElements(page) {
492
- try {
493
- // Filter frames as needed
494
- const frames = page
495
- .frames()
496
- .filter((frame) => PlaywrightUtils.frameFilter(frame));
497
- for (const frame of frames) {
498
- await frame.evaluate(([interactableAttr, annotationAttr]) => {
499
- // 1) Ensure we have a shadow container in the main document
500
- let container = document.getElementById('annotation-shadow-container');
501
- if (!container) {
502
- container = document.createElement('div');
503
- container.id = 'annotation-shadow-container';
504
- // Position container so child elements can be absolutely placed
505
- Object.assign(container.style, {
506
- position: 'fixed', // anchor to viewport
507
- inset: '0', // stretch across it
508
- pointerEvents: 'none', // Let clicks pass through
509
- zIndex: '2147483647', // win every z-index fight
510
- });
511
- // Check if document.body exists before trying to append.
512
- if (document.body) {
513
- document.body.appendChild(container);
514
- }
515
- else if (document.documentElement) {
516
- // Fall back to document.documentElement if body does not exist.
517
- document.documentElement.appendChild(container);
518
- }
519
- else {
520
- // If neither exists, we can't proceed with annotations in this frame.
521
- console.warn(`Cannot create annotation container for ${window.location.href} since the document structure is incomplete`);
522
- return;
523
- }
524
- // Attach a shadow root
525
- const shadowRoot = container.attachShadow({ mode: 'open' });
526
- // Add a <style> element inside the shadow root to reset and define annotation styles
527
- const style = document.createElement('style');
528
- style.textContent = `
529
- :host {
530
- all: initial; /* Reset styles in shadow root */
531
- }
532
- .annotation {
533
- position: absolute;
534
- z-index: 2147483647;
535
- background-color: black;
536
- color: white;
537
- width: 40px;
538
- height: 40px;
539
- border-radius: 50%;
540
- display: flex;
541
- align-items: center;
542
- justify-content: center;
543
- font-size: 14px;
544
- font-weight: bold;
545
- line-height: 20px;
546
- text-align: center;
547
- box-shadow: 0px 2px 4px rgba(0,0,0,0.2);
548
- border: 4px solid #FF4136;
549
- pointer-events: none;
550
- }
551
- `;
552
- shadowRoot.appendChild(style);
553
- }
554
- // Retrieve the shadow root to place annotation elements
555
- const containerEl = document.getElementById('annotation-shadow-container');
556
- if (!containerEl?.shadowRoot) {
557
- return;
558
- }
559
- const shadowRoot = containerEl.shadowRoot;
560
- // 2) Factory to create a new annotation inside the shadow root
561
- const createAnnotation = (value) => {
562
- const annotation = document.createElement('div');
563
- annotation.classList.add('annotation');
564
- annotation.dataset[annotationAttr] = '1';
565
- annotation.textContent = value;
566
- return annotation;
567
- };
568
- // 3) Position annotation relative to an element
569
- const positionAnnotation = (annotation, element) => {
570
- const rect = element.getBoundingClientRect();
571
- // Center the annotation on the element, adjusting for its size
572
- const x = rect.left + rect.width / 2 - 20 + window.scrollX;
573
- const y = rect.top + rect.height / 2 - 20 + window.scrollY;
574
- annotation.style.left = `${x}px`;
575
- annotation.style.top = `${y}px`;
576
- };
577
- // 4) Traverse DOM (including any nested shadow roots) to find interactable elements
578
- const processNode = (root) => {
579
- // Find elements with the interactable attribute
580
- const elements = root.querySelectorAll(`[${interactableAttr}]`);
581
- elements.forEach((element) => {
582
- const value = element.getAttribute(interactableAttr);
583
- if (value) {
584
- const annotation = createAnnotation(value);
585
- shadowRoot.appendChild(annotation);
586
- positionAnnotation(annotation, element);
587
- }
588
- });
589
- // Recursively process any child shadow roots
590
- root.querySelectorAll('*').forEach((el) => {
591
- if (el.shadowRoot) {
592
- processNode(el.shadowRoot);
593
- }
594
- });
595
- };
596
- // Start processing from the (frame) document root
597
- processNode(document);
598
- }, [
599
- PlaywrightUtils.DONOBU_INTERACTABLE_ATTRIBUTE,
600
- PlaywrightUtils.convertToJsAttribute(PlaywrightUtils.DONOBU_ANNOTATION_ATTRIBUTE),
601
- ]);
602
- }
603
- }
604
- catch (error) {
605
- if (PlaywrightUtils.isPageClosedError(error)) {
606
- throw new PageClosedException_1.PageClosedException();
607
- }
608
- else {
609
- throw error;
610
- }
611
- }
612
- }
613
- /**
614
- * Removes all annotations with a {@link PlaywrightUtils.DONOBU_ANNOTATION_ATTRIBUTE}
615
- * HTML attribute in the given page, including any containers in shadow DOM.
616
- */
617
- static async removeDonobuAnnotations(page) {
618
- try {
619
- const frames = page
620
- .frames()
621
- .filter((frame) => PlaywrightUtils.frameFilter(frame));
622
- for (const frame of frames) {
623
- await frame.evaluate(() => {
624
- const containerId = 'annotation-shadow-container';
625
- const container = document.getElementById(containerId);
626
- if (container) {
627
- container.remove();
628
- }
629
- });
630
- }
631
- }
632
- catch (error) {
633
- if (PlaywrightUtils.isPageClosedError(error)) {
634
- throw new PageClosedException_1.PageClosedException();
635
- }
636
- throw error;
637
- }
638
- }
639
- /**
640
- * Removes the {@link PlaywrightUtils.DONOBU_INTERACTABLE_ATTRIBUTE} HTML
641
- * attribute for all elements in the given page. This attribute is normally
642
- * added by the {@link PlaywrightUtils.attributeInteractableElements(Page)}
643
- * function.
644
- */
645
- static async deattributeVisibleInteractableElements(page) {
646
- try {
647
- const frames = page
648
- .frames()
649
- .filter((frame) => PlaywrightUtils.frameFilter(frame));
650
- for (const frame of frames) {
651
- await frame.evaluate((attr) => {
652
- document.querySelectorAll(`[${attr}]`).forEach((element) => {
653
- element.removeAttribute(attr);
654
- });
655
- }, PlaywrightUtils.DONOBU_INTERACTABLE_ATTRIBUTE);
656
- }
657
- }
658
- catch (error) {
659
- if (PlaywrightUtils.isPageClosedError(error)) {
660
- throw new PageClosedException_1.PageClosedException();
661
- }
662
- else {
663
- throw error;
664
- }
665
- }
666
- }
667
- static async parseUnambiguousSelector(elementHandle) {
668
- try {
669
- return await elementHandle.evaluate((element) => {
670
- const escapeCssIdentifier = (ident) => {
671
- return ident.replace(/([!"#$%&'()*+,./:;<=>?@[\\]^{|}~])/g, '\\$1');
672
- };
673
- const getPath = (el) => {
674
- if (el.id)
675
- return '#' + escapeCssIdentifier(el.id);
676
- if (!el.parentNode || el.parentNode.nodeType === Node.DOCUMENT_NODE)
677
- return '';
678
- const siblings = Array.from(el.parentNode.children).filter((e) => e.tagName === el.tagName);
679
- const index = siblings.indexOf(el) + 1;
680
- const tag = el.tagName.toLowerCase();
681
- const parentPath = getPath(el.parentNode);
682
- return (parentPath +
683
- (parentPath ? ' > ' : '') +
684
- tag +
685
- (siblings.length > 1 ? ':nth-child(' + index + ')' : ''));
686
- };
687
- return getPath(element);
688
- });
689
- }
690
- catch (error) {
691
- if (PlaywrightUtils.isPageClosedError(error)) {
692
- throw new PageClosedException_1.PageClosedException();
693
- }
694
- else {
695
- throw error;
696
- }
697
- }
698
- }
699
- /**
700
- * Converts an HTML attribute to a JavaScript attribute. For example,
701
- * "data-foo-bar" is turned into "fooBar". Notice the dropping of the "data-"
702
- * prefix, and the conversion from kebab-case to camelCase.
703
- */
704
- static convertToJsAttribute(htmlAttribute) {
705
- if (htmlAttribute.startsWith('data-')) {
706
- htmlAttribute = htmlAttribute.substring(5);
707
- }
708
- const parts = htmlAttribute.split('-');
709
- const jsAttribute = parts[0] +
710
- parts
711
- .slice(1)
712
- .map((part) => part.charAt(0).toUpperCase() + part.slice(1).toLowerCase())
713
- .join('');
714
- return jsAttribute;
65
+ await browserContext.addInitScript(RunAccessibilityTestTool_1.RunAccessibilityTestTool.INIT_SCRIPT);
66
+ await browserContext.addInitScript(PageInspector_1.PageInspector.INIT_SCRIPT);
67
+ await browserContext.addInitScript(PlaywrightUtils.DIALOG_PROMPT_TRACKER_INIT_SCRIPT);
68
+ await browserContext.addInitScript(PlaywrightUtils.SMART_SELECTOR_GENERATOR_INIT_SCRIPT);
715
69
  }
716
70
  /**
717
71
  * Returned true IFF the given error is a Playwright error regarding page closing,
@@ -802,294 +156,142 @@ class PlaywrightUtils {
802
156
  }
803
157
  }
804
158
  }
805
- static frameFilter(frame) {
806
- return (!frame.isDetached() &&
807
- !frame.url().startsWith('about:') &&
808
- !frame.url().startsWith('chrome:') &&
809
- !frame.url().startsWith('edge:'));
810
- }
811
159
  /**
812
- * This function is injected into the page (or frame) context. It finds
813
- * "interactable" elements, checks visibility, and sets a unique attribute.
814
- * It returns the updated offset after labeling.
160
+ * Takes a screenshot of the webpage as if it were scrolled down by one viewport.
161
+ * If the page cannot be scrolled as a whole, tries to find and scroll individual
162
+ * scrollable elements on the page. After taking the screenshot, it reverts to
163
+ * the original scroll position.
164
+ *
165
+ * @param page The Playwright Page to take a screenshot of
166
+ * @returns An image buffer of the scrolled down view, or undefined if scrolling isn't possible
815
167
  */
816
- static attributeElementsInContext(arg) {
817
- let offset = arg[0];
818
- const interactableAttribute = arg[1];
819
- // --- Utility Functions ---
820
- function isElementVisible(rect, style) {
821
- return (rect.width > 0 &&
822
- rect.height > 0 &&
823
- style.display !== 'none' &&
824
- style.visibility !== 'hidden');
825
- }
826
- function isElementMoreThanHalfInViewport(rect) {
827
- const viewportWidth = window.innerWidth || document.documentElement.clientWidth;
828
- const viewportHeight = window.innerHeight || document.documentElement.clientHeight;
829
- const visibleWidth = Math.min(rect.right, viewportWidth) - Math.max(rect.left, 0);
830
- const visibleHeight = Math.min(rect.bottom, viewportHeight) - Math.max(rect.top, 0);
831
- const visibleArea = Math.max(0, visibleWidth) * Math.max(0, visibleHeight);
832
- const elementArea = rect.width * rect.height;
833
- return visibleArea >= elementArea / 2;
834
- }
835
- function isElementEnabled(element, style) {
836
- // Check standard disabled attribute (for form controls like button, input, etc.)
837
- if (element.hasAttribute('disabled')) {
838
- return false;
839
- }
840
- // Check for ARIA attributes that indicate non-interactivity
841
- if (element.getAttribute('aria-disabled') === 'true' ||
842
- element.getAttribute('aria-hidden') === 'true') {
843
- return false;
844
- }
845
- // Check for pointer-events: none which prevents interactions
846
- if (style.pointerEvents === 'none') {
847
- return false;
848
- }
849
- // Check for ARIA attributes indicating disabled state
850
- if (element.getAttribute('aria-disabled') === 'true') {
851
- return false;
852
- }
853
- // Check for inert attribute which makes elements non-interactive
854
- if (element.hasAttribute('inert')) {
855
- return false;
856
- }
857
- // If the element is in a form and the fieldset is disabled, it might be disabled as well
858
- let parent = element.parentElement;
859
- while (parent) {
860
- if (parent.tagName.toLowerCase() === 'fieldset' &&
861
- parent.hasAttribute('disabled') &&
862
- element.tagName.toLowerCase() !== 'legend') {
863
- return false;
864
- }
865
- parent = parent.parentElement;
866
- }
867
- return true;
868
- }
869
- /**
870
- * Generate a few test points on the element's bounding box. We only need
871
- * a small offset (1px) from each corner, plus the center.
872
- */
873
- function getPointsToCheck(rect) {
874
- const cornerOffset = 1;
875
- return [
876
- { x: rect.left + cornerOffset, y: rect.top + cornerOffset },
877
- { x: rect.right - cornerOffset, y: rect.top + cornerOffset },
878
- { x: rect.left + cornerOffset, y: rect.bottom - cornerOffset },
879
- { x: rect.right - cornerOffset, y: rect.bottom - cornerOffset },
880
- { x: rect.left + rect.width / 2, y: rect.top + rect.height / 2 },
881
- ];
882
- }
883
- /**
884
- * Like `elementFromPoint` but continues walking shadow roots if found.
885
- */
886
- function getDeepElementFromPoint(x, y) {
887
- let el = document.elementFromPoint(x, y);
888
- while (el && el.shadowRoot) {
889
- const shadowEl = el.shadowRoot.elementFromPoint(x, y);
890
- if (!shadowEl || shadowEl === el)
891
- break;
892
- el = shadowEl;
893
- }
894
- return el;
895
- }
896
- function getAllInteractableElements(root) {
897
- const selector = [
898
- // ----- STANDARD HTML INTERACTIVE ELEMENTS -----
899
- // Basic form controls and interactive elements
900
- 'button',
901
- 'button svg', // SVG inside buttons are also clickable
902
- 'input',
903
- 'textarea',
904
- 'a',
905
- 'select',
906
- 'summary', // Disclosure (details/summary) elements
907
- 'details',
908
- 'audio[controls]', // Media controls
909
- 'video[controls]',
910
- // ----- ARIA ROLE-BASED INTERACTIVE ELEMENTS -----
911
- // Elements with explicit interactive ARIA roles
912
- '[role="button"]',
913
- '[role="option"]',
914
- '[role="link"]',
915
- '[role="checkbox"]',
916
- '[role="radio"]',
917
- '[role="tab"]',
918
- '[role="menuitem"]',
919
- '[role="menuitemcheckbox"]',
920
- '[role="menuitemradio"]',
921
- '[role="combobox"]',
922
- '[role="listbox"]',
923
- '[role="searchbox"]',
924
- '[role="spinbutton"]',
925
- '[role="slider"]',
926
- '[role="switch"]',
927
- '[role="menu"]',
928
- '[role="menubar"]',
929
- '[role="treeitem"]',
930
- // ----- INTERACTIVE ARIA ATTRIBUTES -----
931
- // Elements with popup behavior
932
- '[aria-haspopup]',
933
- '[aria-controls]',
934
- '[aria-expanded]', // Elements that can expand/collapse
935
- '[aria-pressed]', // Toggle buttons
936
- '[aria-selected]', // Selectable items
937
- // ----- EDITABLE AND FOCUSABLE ELEMENTS -----
938
- // Elements that can receive input
939
- '[contenteditable="true"]',
940
- // Elements that can be dragged
941
- '[draggable="true"]',
942
- // Elements with explicit focus capability
943
- '[tabindex]:not([tabindex="-1"])',
944
- // ----- CSS FRAMEWORK-SPECIFIC CLASSES -----
945
- // Bootstrap & similar frameworks
946
- '.btn', // Standard button class
947
- '.dropdown-toggle', // Dropdown triggers
948
- '.nav-link', // Navigation links
949
- '.page-link', // Pagination links
950
- '.card-header[data-toggle="collapse"]', // Collapsible headers
951
- '.accordion-button', // Accordion toggles
952
- '.close', // Close buttons
953
- '.modal-close', // Modal close buttons
954
- // Material Design & Angular Material
955
- '.mdc-button',
956
- '.mat-button',
957
- '.mat-icon-button',
958
- '.mat-fab',
959
- '.mat-mini-fab',
960
- '.mat-menu-item',
961
- '.mat-tab-label',
962
- // Foundation
963
- '.button',
964
- '.menu-item',
965
- '.accordion-title',
966
- // Tailwind UI & Headless UI components
967
- '.tw-button',
968
- '[x-on\\:click]', // Alpine.js click handlers
969
- // Vue-based frameworks
970
- '.v-btn', // Vuetify
971
- '.el-button', // Element UI
972
- // React-based frameworks
973
- '.ant-btn', // Ant Design
974
- '.chakra-button', // Chakra UI
975
- '.mui-button', // Material-UI
976
- // ----- CUSTOM INTERACTIVE PATTERNS -----
977
- // Common custom interactive classes
978
- '.clickable',
979
- '.selectable',
980
- '.interactive',
981
- '.toggle',
982
- '.expandable',
983
- '.switch',
984
- '.slider',
985
- // Common dropdown/select libraries
986
- '.select2-selection',
987
- '.chosen-single',
988
- '.vs__dropdown-toggle', // Vue Select
989
- // Tabs and accordion components
990
- '.tab',
991
- '.tab-header',
992
- '.tab-title',
993
- '.accordion-header',
994
- // Mobile-friendly interactive elements
995
- '.swipe-item',
996
- '.touch-target',
997
- // ----- COMMON COMPONENT PATTERNS -----
998
- // Cards and tiles that are often clickable
999
- '.card[onclick]',
1000
- '.tile[onclick]',
1001
- '.card a', // Links inside cards
1002
- // Social media & e-commerce patterns
1003
- '.share-button',
1004
- '.like-button',
1005
- '.add-to-cart',
1006
- '.product-card',
1007
- // Notification and alert controls
1008
- '.alert .close',
1009
- '.toast .close',
1010
- '.notification-action',
1011
- ].join(', ');
1012
- let elements = Array.from(root.querySelectorAll(selector));
1013
- // Dive into shadow roots
1014
- root.querySelectorAll('*').forEach((el) => {
1015
- if (el.shadowRoot) {
1016
- // Recurse
1017
- elements = elements.concat(getAllInteractableElements(el.shadowRoot));
1018
- }
168
+ static async getScrolledDownScreenShot(page) {
169
+ try {
170
+ // Get the current scroll position and viewport height
171
+ const { scrollX, scrollY, viewportHeight } = await page.evaluate(() => {
172
+ return {
173
+ scrollX: window.scrollX,
174
+ scrollY: window.scrollY,
175
+ viewportHeight: window.innerHeight,
176
+ };
1019
177
  });
1020
- // Remove duplicates
1021
- return Array.from(new Set(elements));
1022
- }
1023
- // 1) Gather candidate elements (including any custom "clickable" from donobuGetClickableElements)
1024
- let interactableElements = getAllInteractableElements(document);
1025
- if (window.donobuGetClickableElements) {
1026
- interactableElements = interactableElements.concat(window
1027
- .donobuGetClickableElements()
1028
- // Exclude elements with a "donobu-" prefixed ID.
1029
- .filter((el) => !el.id || !el.id.startsWith('donobu-')));
1030
- }
1031
- // Use a Set to avoid duplicates
1032
- const uniqueElements = new Set(interactableElements);
1033
- // 2) Check each element for visibility + actual "interactability"
1034
- uniqueElements.forEach((element) => {
1035
- if (typeof element.getBoundingClientRect !== 'function') {
1036
- // Should be rare, but just in case
1037
- return;
1038
- }
1039
- const rect = element.getBoundingClientRect();
1040
- const style = window.getComputedStyle(element);
1041
- const visible = isElementVisible(rect, style) && isElementMoreThanHalfInViewport(rect);
1042
- // Check if the element is actually enabled/interactive
1043
- const enabled = isElementEnabled(element, style);
1044
- if (!visible || !enabled) {
1045
- return;
1046
- }
1047
- let annotated = false;
1048
- // 3) Test small set of points on the element to confirm it's truly topmost
1049
- for (const pt of getPointsToCheck(rect)) {
1050
- let elToCheck = getDeepElementFromPoint(pt.x, pt.y);
1051
- // Walk up the DOM tree from that point
1052
- while (elToCheck) {
1053
- if (elToCheck === element) {
1054
- // Found the actual element
1055
- element.setAttribute(interactableAttribute, offset.toString());
1056
- offset++;
1057
- annotated = true;
1058
- break;
1059
- }
1060
- else if (elToCheck.tagName?.toLowerCase() === 'label' &&
1061
- elToCheck.htmlFor) {
1062
- // If we found a label referencing an element, also mark that
1063
- const forId = elToCheck.htmlFor;
1064
- const associatedInput = document.getElementById(forId);
1065
- if (associatedInput) {
1066
- associatedInput.setAttribute(interactableAttribute, offset.toString());
1067
- offset++;
178
+ // Step 1: Try to scroll the window down by one viewport
179
+ await page.evaluate((viewportHeight) => {
180
+ window.scrollBy(0, viewportHeight);
181
+ }, viewportHeight);
182
+ // Check if the page actually scrolled
183
+ const newScrollY = await page.evaluate(() => window.scrollY);
184
+ // If the window scrolled successfully, take the screenshot and return
185
+ if (newScrollY > scrollY) {
186
+ // Take the screenshot
187
+ const screenshot = await PlaywrightUtils.takeScreenshot(page);
188
+ // Scroll back to the original position
189
+ await page.evaluate(([x, y]) => {
190
+ window.scrollTo(x, y);
191
+ }, [scrollX, scrollY]);
192
+ return screenshot;
193
+ }
194
+ // Step 2: If window didn't scroll, try to find scrollable elements
195
+ const didScrollElement = await page.evaluate(() => {
196
+ // Find all potentially scrollable elements
197
+ function findScrollableElements() {
198
+ const allElements = document.querySelectorAll('*');
199
+ const scrollableElements = [];
200
+ allElements.forEach((el) => {
201
+ const style = window.getComputedStyle(el);
202
+ const overflowY = style.getPropertyValue('overflow-y');
203
+ const overflowX = style.getPropertyValue('overflow-x');
204
+ const overflow = style.getPropertyValue('overflow');
205
+ // Check if the element has scrollable properties
206
+ if (overflowY === 'auto' ||
207
+ overflowY === 'scroll' ||
208
+ overflowX === 'auto' ||
209
+ overflowX === 'scroll' ||
210
+ overflow === 'auto' ||
211
+ overflow === 'scroll') {
212
+ // Additional check to see if the element actually has content to scroll
213
+ const scrollHeight = el.scrollHeight;
214
+ const clientHeight = el.clientHeight;
215
+ if (scrollHeight > clientHeight) {
216
+ scrollableElements.push({
217
+ element: el,
218
+ area: el.clientWidth * el.clientHeight, // Calculate area for sorting
219
+ scrollTop: el.scrollTop, // Save original scroll position
220
+ });
221
+ }
1068
222
  }
1069
- annotated = true;
223
+ });
224
+ return scrollableElements;
225
+ }
226
+ // Find and sort scrollable elements by size (largest first)
227
+ const scrollableElements = findScrollableElements().sort((a, b) => b.area - a.area);
228
+ let didScroll = false;
229
+ // Try to scroll each element until one successfully scrolls
230
+ for (const { element } of scrollableElements) {
231
+ const originalScrollTop = element.scrollTop;
232
+ // Try to scroll down by the element's client height
233
+ element.scrollTop += element.clientHeight;
234
+ // Check if scrolling was successful
235
+ if (element.scrollTop > originalScrollTop) {
236
+ didScroll = true;
237
+ // Save the element in the window object so we can access it later
238
+ // @ts-ignore
239
+ window.__lastScrolledElement = element;
240
+ // @ts-ignore
241
+ window.__lastScrolledElementOriginalPosition = originalScrollTop;
1070
242
  break;
1071
243
  }
1072
- elToCheck = elToCheck.parentElement;
1073
244
  }
1074
- if (annotated) {
1075
- break;
245
+ return didScroll;
246
+ });
247
+ // If no element could be scrolled, return undefined
248
+ if (!didScrollElement) {
249
+ return undefined;
250
+ }
251
+ // Take a screenshot after scrolling the element
252
+ const screenshot = await PlaywrightUtils.takeScreenshot(page);
253
+ // Restore the original scroll position of the element
254
+ await page.evaluate(() => {
255
+ if (
256
+ // @ts-ignore
257
+ window.__lastScrolledElement &&
258
+ // @ts-ignore
259
+ window.__lastScrolledElementOriginalPosition !== undefined) {
260
+ // @ts-ignore
261
+ window.__lastScrolledElement.scrollTop = window.__lastScrolledElementOriginalPosition;
262
+ // Clean up
263
+ // @ts-ignore
264
+ delete window.__lastScrolledElement;
265
+ // @ts-ignore
266
+ delete window.__lastScrolledElementOriginalPosition;
1076
267
  }
268
+ });
269
+ return screenshot;
270
+ }
271
+ catch (error) {
272
+ if (PlaywrightUtils.isPageClosedError(error)) {
273
+ throw new PageClosedException_1.PageClosedException();
1077
274
  }
1078
- });
1079
- return offset;
275
+ else {
276
+ throw error;
277
+ }
278
+ }
1080
279
  }
1081
280
  }
1082
281
  exports.PlaywrightUtils = PlaywrightUtils;
1083
- PlaywrightUtils.ACCESSIBILITY_TEST_INIT_SCRIPT = MiscUtils_1.MiscUtils.getResourceFileAsString(path_1.default.join('axe.js'));
1084
- PlaywrightUtils.CLICKABLE_ELEMENTS_TRACKER_INIT_SCRIPT = MiscUtils_1.MiscUtils.getResourceFileAsString(path_1.default.join('clickable-elements-tracker.js'));
282
+ /**
283
+ * A JavaScript code snippet intended to run as an initialization
284
+ * script for `DonobuFlow` flows. This script helps flows handle/track
285
+ * prompts/confirmations. This is done specially since these browser actions
286
+ * pause the Javascript main thread and also cause issues with running various
287
+ * Playwright actions. See `DonobuFlow.onDialog(Dialog)` for details.
288
+ */
1085
289
  PlaywrightUtils.DIALOG_PROMPT_TRACKER_INIT_SCRIPT = MiscUtils_1.MiscUtils.getResourceFileAsString(path_1.default.join('dialog-prompt-tracker.js'));
290
+ /**
291
+ * Returns a JavaScript code snippet intended to run as an initialization
292
+ * script for `DonobuFlow` flows. This enables the {@link ReplayableInteraction}
293
+ * and {@link PageInteractionTracker.INIT_SCRIPT} to generate
294
+ * smart selectors.
295
+ */
1086
296
  PlaywrightUtils.SMART_SELECTOR_GENERATOR_INIT_SCRIPT = MiscUtils_1.MiscUtils.getResourceFileAsString(path_1.default.join('smart-selector-generator.js'));
1087
- PlaywrightUtils.PAGE_INTERACTIONS_TRACKER_INIT_SCRIPT = MiscUtils_1.MiscUtils.getResourceFileAsString(path_1.default.join('page-interactions-tracker.js'));
1088
- PlaywrightUtils.DONOBU_CONTROL_PANEL_INIT_SCRIPT = MiscUtils_1.MiscUtils.getResourceFileAsString(path_1.default.join('control-panel.js'));
1089
- // WARNING: If the control panel ID is changed here, you must also change the
1090
- // control-panel.js control panel ID value.
1091
- PlaywrightUtils.DONOBU_CONTROL_PANEL_ELEMENT_ID = 'donobu-control-panel';
1092
- PlaywrightUtils.DONOBU_CONTROL_PANEL_HEADLINE_ELEMENT_ID = 'donobu-control-panel-title-text';
1093
- PlaywrightUtils.DONOBU_INTERACTABLE_ATTRIBUTE = 'data-donobu-interactable';
1094
- PlaywrightUtils.DONOBU_ANNOTATION_ATTRIBUTE = 'data-donobu-annotation';
1095
297
  //# sourceMappingURL=PlaywrightUtils.js.map