wavexis 2.3.0__tar.gz → 2.3.1__tar.gz

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 (214) hide show
  1. {wavexis-2.3.0 → wavexis-2.3.1}/CHANGELOG.md +7 -0
  2. {wavexis-2.3.0 → wavexis-2.3.1}/PKG-INFO +1 -1
  3. {wavexis-2.3.0 → wavexis-2.3.1}/pyproject.toml +1 -1
  4. {wavexis-2.3.0 → wavexis-2.3.1}/tests/unit/test_auto_wait.py +29 -0
  5. {wavexis-2.3.0 → wavexis-2.3.1}/wavexis/__init__.py +1 -1
  6. {wavexis-2.3.0 → wavexis-2.3.1}/wavexis/backend/base.py +9 -3
  7. {wavexis-2.3.0 → wavexis-2.3.1}/wavexis/backend/bidi.py +36 -9
  8. {wavexis-2.3.0 → wavexis-2.3.1}/wavexis/backend/cdp.py +18 -6
  9. {wavexis-2.3.0 → wavexis-2.3.1}/.dockerignore +0 -0
  10. {wavexis-2.3.0 → wavexis-2.3.1}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
  11. {wavexis-2.3.0 → wavexis-2.3.1}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
  12. {wavexis-2.3.0 → wavexis-2.3.1}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
  13. {wavexis-2.3.0 → wavexis-2.3.1}/.github/workflows/ci.yml +0 -0
  14. {wavexis-2.3.0 → wavexis-2.3.1}/.github/workflows/docs.yml +0 -0
  15. {wavexis-2.3.0 → wavexis-2.3.1}/.github/workflows/release.yml +0 -0
  16. {wavexis-2.3.0 → wavexis-2.3.1}/.gitignore +0 -0
  17. {wavexis-2.3.0 → wavexis-2.3.1}/CODE_OF_CONDUCT.md +0 -0
  18. {wavexis-2.3.0 → wavexis-2.3.1}/CONTRIBUTING.md +0 -0
  19. {wavexis-2.3.0 → wavexis-2.3.1}/Dockerfile +0 -0
  20. {wavexis-2.3.0 → wavexis-2.3.1}/LICENSE +0 -0
  21. {wavexis-2.3.0 → wavexis-2.3.1}/README.md +0 -0
  22. {wavexis-2.3.0 → wavexis-2.3.1}/SECURITY.md +0 -0
  23. {wavexis-2.3.0 → wavexis-2.3.1}/docs/api/actions.md +0 -0
  24. {wavexis-2.3.0 → wavexis-2.3.1}/docs/api/backends.md +0 -0
  25. {wavexis-2.3.0 → wavexis-2.3.1}/docs/api/cli.md +0 -0
  26. {wavexis-2.3.0 → wavexis-2.3.1}/docs/api/config.md +0 -0
  27. {wavexis-2.3.0 → wavexis-2.3.1}/docs/api/exceptions.md +0 -0
  28. {wavexis-2.3.0 → wavexis-2.3.1}/docs/api/multi.md +0 -0
  29. {wavexis-2.3.0 → wavexis-2.3.1}/docs/api/plugins.md +0 -0
  30. {wavexis-2.3.0 → wavexis-2.3.1}/docs/api/serve.md +0 -0
  31. {wavexis-2.3.0 → wavexis-2.3.1}/docs/cookbook/auth.md +0 -0
  32. {wavexis-2.3.0 → wavexis-2.3.1}/docs/cookbook/ci-cd.md +0 -0
  33. {wavexis-2.3.0 → wavexis-2.3.1}/docs/cookbook/css.md +0 -0
  34. {wavexis-2.3.0 → wavexis-2.3.1}/docs/cookbook/debug.md +0 -0
  35. {wavexis-2.3.0 → wavexis-2.3.1}/docs/cookbook/record-replay.md +0 -0
  36. {wavexis-2.3.0 → wavexis-2.3.1}/docs/cookbook/scraping.md +0 -0
  37. {wavexis-2.3.0 → wavexis-2.3.1}/docs/cookbook/screenshots.md +0 -0
  38. {wavexis-2.3.0 → wavexis-2.3.1}/docs/cookbook/serve-mode.md +0 -0
  39. {wavexis-2.3.0 → wavexis-2.3.1}/docs/guide/assert.md +0 -0
  40. {wavexis-2.3.0 → wavexis-2.3.1}/docs/guide/backends.md +0 -0
  41. {wavexis-2.3.0 → wavexis-2.3.1}/docs/guide/commands.md +0 -0
  42. {wavexis-2.3.0 → wavexis-2.3.1}/docs/guide/init.md +0 -0
  43. {wavexis-2.3.0 → wavexis-2.3.1}/docs/guide/installation.md +0 -0
  44. {wavexis-2.3.0 → wavexis-2.3.1}/docs/guide/multi.md +0 -0
  45. {wavexis-2.3.0 → wavexis-2.3.1}/docs/guide/perf.md +0 -0
  46. {wavexis-2.3.0 → wavexis-2.3.1}/docs/guide/plugins.md +0 -0
  47. {wavexis-2.3.0 → wavexis-2.3.1}/docs/guide/quickstart.md +0 -0
  48. {wavexis-2.3.0 → wavexis-2.3.1}/docs/guide/raw.md +0 -0
  49. {wavexis-2.3.0 → wavexis-2.3.1}/docs/guide/repl.md +0 -0
  50. {wavexis-2.3.0 → wavexis-2.3.1}/docs/guide/troubleshooting.md +0 -0
  51. {wavexis-2.3.0 → wavexis-2.3.1}/docs/index.md +0 -0
  52. {wavexis-2.3.0 → wavexis-2.3.1}/mkdocs.yml +0 -0
  53. {wavexis-2.3.0 → wavexis-2.3.1}/stubs/bidiwave/__init__.pyi +0 -0
  54. {wavexis-2.3.0 → wavexis-2.3.1}/stubs/cdpwave/__init__.pyi +0 -0
  55. {wavexis-2.3.0 → wavexis-2.3.1}/tests/__init__.py +0 -0
  56. {wavexis-2.3.0 → wavexis-2.3.1}/tests/conftest.py +0 -0
  57. {wavexis-2.3.0 → wavexis-2.3.1}/tests/integration/__init__.py +0 -0
  58. {wavexis-2.3.0 → wavexis-2.3.1}/tests/integration/test_a11y.py +0 -0
  59. {wavexis-2.3.0 → wavexis-2.3.1}/tests/integration/test_animation.py +0 -0
  60. {wavexis-2.3.0 → wavexis-2.3.1}/tests/integration/test_backend_selection.py +0 -0
  61. {wavexis-2.3.0 → wavexis-2.3.1}/tests/integration/test_browser.py +0 -0
  62. {wavexis-2.3.0 → wavexis-2.3.1}/tests/integration/test_console.py +0 -0
  63. {wavexis-2.3.0 → wavexis-2.3.1}/tests/integration/test_css.py +0 -0
  64. {wavexis-2.3.0 → wavexis-2.3.1}/tests/integration/test_debug.py +0 -0
  65. {wavexis-2.3.0 → wavexis-2.3.1}/tests/integration/test_dialog.py +0 -0
  66. {wavexis-2.3.0 → wavexis-2.3.1}/tests/integration/test_dom.py +0 -0
  67. {wavexis-2.3.0 → wavexis-2.3.1}/tests/integration/test_dom_snapshot.py +0 -0
  68. {wavexis-2.3.0 → wavexis-2.3.1}/tests/integration/test_emulation.py +0 -0
  69. {wavexis-2.3.0 → wavexis-2.3.1}/tests/integration/test_emulation_advanced.py +0 -0
  70. {wavexis-2.3.0 → wavexis-2.3.1}/tests/integration/test_eval.py +0 -0
  71. {wavexis-2.3.0 → wavexis-2.3.1}/tests/integration/test_har.py +0 -0
  72. {wavexis-2.3.0 → wavexis-2.3.1}/tests/integration/test_input.py +0 -0
  73. {wavexis-2.3.0 → wavexis-2.3.1}/tests/integration/test_media.py +0 -0
  74. {wavexis-2.3.0 → wavexis-2.3.1}/tests/integration/test_multi.py +0 -0
  75. {wavexis-2.3.0 → wavexis-2.3.1}/tests/integration/test_navigate.py +0 -0
  76. {wavexis-2.3.0 → wavexis-2.3.1}/tests/integration/test_network.py +0 -0
  77. {wavexis-2.3.0 → wavexis-2.3.1}/tests/integration/test_network_advanced.py +0 -0
  78. {wavexis-2.3.0 → wavexis-2.3.1}/tests/integration/test_overlay.py +0 -0
  79. {wavexis-2.3.0 → wavexis-2.3.1}/tests/integration/test_pdf.py +0 -0
  80. {wavexis-2.3.0 → wavexis-2.3.1}/tests/integration/test_perf.py +0 -0
  81. {wavexis-2.3.0 → wavexis-2.3.1}/tests/integration/test_permissions.py +0 -0
  82. {wavexis-2.3.0 → wavexis-2.3.1}/tests/integration/test_raw.py +0 -0
  83. {wavexis-2.3.0 → wavexis-2.3.1}/tests/integration/test_record.py +0 -0
  84. {wavexis-2.3.0 → wavexis-2.3.1}/tests/integration/test_scrape.py +0 -0
  85. {wavexis-2.3.0 → wavexis-2.3.1}/tests/integration/test_screenshot.py +0 -0
  86. {wavexis-2.3.0 → wavexis-2.3.1}/tests/integration/test_security.py +0 -0
  87. {wavexis-2.3.0 → wavexis-2.3.1}/tests/integration/test_serve.py +0 -0
  88. {wavexis-2.3.0 → wavexis-2.3.1}/tests/integration/test_service_worker.py +0 -0
  89. {wavexis-2.3.0 → wavexis-2.3.1}/tests/integration/test_storage.py +0 -0
  90. {wavexis-2.3.0 → wavexis-2.3.1}/tests/integration/test_tabs.py +0 -0
  91. {wavexis-2.3.0 → wavexis-2.3.1}/tests/integration/test_webaudio.py +0 -0
  92. {wavexis-2.3.0 → wavexis-2.3.1}/tests/integration/test_webauthn.py +0 -0
  93. {wavexis-2.3.0 → wavexis-2.3.1}/tests/unit/__init__.py +0 -0
  94. {wavexis-2.3.0 → wavexis-2.3.1}/tests/unit/test_abstract_backend_phase5.py +0 -0
  95. {wavexis-2.3.0 → wavexis-2.3.1}/tests/unit/test_actions.py +0 -0
  96. {wavexis-2.3.0 → wavexis-2.3.1}/tests/unit/test_actions_phase5.py +0 -0
  97. {wavexis-2.3.0 → wavexis-2.3.1}/tests/unit/test_animation_action.py +0 -0
  98. {wavexis-2.3.0 → wavexis-2.3.1}/tests/unit/test_assert_multi.py +0 -0
  99. {wavexis-2.3.0 → wavexis-2.3.1}/tests/unit/test_auth.py +0 -0
  100. {wavexis-2.3.0 → wavexis-2.3.1}/tests/unit/test_backend_manager.py +0 -0
  101. {wavexis-2.3.0 → wavexis-2.3.1}/tests/unit/test_bidi_backend.py +0 -0
  102. {wavexis-2.3.0 → wavexis-2.3.1}/tests/unit/test_bidi_phase5.py +0 -0
  103. {wavexis-2.3.0 → wavexis-2.3.1}/tests/unit/test_bluetooth_action.py +0 -0
  104. {wavexis-2.3.0 → wavexis-2.3.1}/tests/unit/test_cast_action.py +0 -0
  105. {wavexis-2.3.0 → wavexis-2.3.1}/tests/unit/test_cleanup.py +0 -0
  106. {wavexis-2.3.0 → wavexis-2.3.1}/tests/unit/test_cli_phase5.py +0 -0
  107. {wavexis-2.3.0 → wavexis-2.3.1}/tests/unit/test_config.py +0 -0
  108. {wavexis-2.3.0 → wavexis-2.3.1}/tests/unit/test_config_phase5.py +0 -0
  109. {wavexis-2.3.0 → wavexis-2.3.1}/tests/unit/test_cookies_headers_actions.py +0 -0
  110. {wavexis-2.3.0 → wavexis-2.3.1}/tests/unit/test_css_action.py +0 -0
  111. {wavexis-2.3.0 → wavexis-2.3.1}/tests/unit/test_debug_action.py +0 -0
  112. {wavexis-2.3.0 → wavexis-2.3.1}/tests/unit/test_dom_snapshot_action.py +0 -0
  113. {wavexis-2.3.0 → wavexis-2.3.1}/tests/unit/test_download_screencast.py +0 -0
  114. {wavexis-2.3.0 → wavexis-2.3.1}/tests/unit/test_emulation_action.py +0 -0
  115. {wavexis-2.3.0 → wavexis-2.3.1}/tests/unit/test_error_handling.py +0 -0
  116. {wavexis-2.3.0 → wavexis-2.3.1}/tests/unit/test_exceptions.py +0 -0
  117. {wavexis-2.3.0 → wavexis-2.3.1}/tests/unit/test_format_record.py +0 -0
  118. {wavexis-2.3.0 → wavexis-2.3.1}/tests/unit/test_global_options.py +0 -0
  119. {wavexis-2.3.0 → wavexis-2.3.1}/tests/unit/test_init.py +0 -0
  120. {wavexis-2.3.0 → wavexis-2.3.1}/tests/unit/test_input_action.py +0 -0
  121. {wavexis-2.3.0 → wavexis-2.3.1}/tests/unit/test_interactions_crawl.py +0 -0
  122. {wavexis-2.3.0 → wavexis-2.3.1}/tests/unit/test_manager.py +0 -0
  123. {wavexis-2.3.0 → wavexis-2.3.1}/tests/unit/test_media_action.py +0 -0
  124. {wavexis-2.3.0 → wavexis-2.3.1}/tests/unit/test_multi.py +0 -0
  125. {wavexis-2.3.0 → wavexis-2.3.1}/tests/unit/test_multi_improvements.py +0 -0
  126. {wavexis-2.3.0 → wavexis-2.3.1}/tests/unit/test_new_features.py +0 -0
  127. {wavexis-2.3.0 → wavexis-2.3.1}/tests/unit/test_output.py +0 -0
  128. {wavexis-2.3.0 → wavexis-2.3.1}/tests/unit/test_overlay_action.py +0 -0
  129. {wavexis-2.3.0 → wavexis-2.3.1}/tests/unit/test_perf_action.py +0 -0
  130. {wavexis-2.3.0 → wavexis-2.3.1}/tests/unit/test_perf_console.py +0 -0
  131. {wavexis-2.3.0 → wavexis-2.3.1}/tests/unit/test_plugins.py +0 -0
  132. {wavexis-2.3.0 → wavexis-2.3.1}/tests/unit/test_raw.py +0 -0
  133. {wavexis-2.3.0 → wavexis-2.3.1}/tests/unit/test_record.py +0 -0
  134. {wavexis-2.3.0 → wavexis-2.3.1}/tests/unit/test_repl.py +0 -0
  135. {wavexis-2.3.0 → wavexis-2.3.1}/tests/unit/test_serve.py +0 -0
  136. {wavexis-2.3.0 → wavexis-2.3.1}/tests/unit/test_service_worker_action.py +0 -0
  137. {wavexis-2.3.0 → wavexis-2.3.1}/tests/unit/test_storage_action.py +0 -0
  138. {wavexis-2.3.0 → wavexis-2.3.1}/tests/unit/test_webaudio_action.py +0 -0
  139. {wavexis-2.3.0 → wavexis-2.3.1}/tests/unit/test_webauthn_action.py +0 -0
  140. {wavexis-2.3.0 → wavexis-2.3.1}/wavexis/__main__.py +0 -0
  141. {wavexis-2.3.0 → wavexis-2.3.1}/wavexis/actions/__init__.py +0 -0
  142. {wavexis-2.3.0 → wavexis-2.3.1}/wavexis/actions/accessibility.py +0 -0
  143. {wavexis-2.3.0 → wavexis-2.3.1}/wavexis/actions/animation.py +0 -0
  144. {wavexis-2.3.0 → wavexis-2.3.1}/wavexis/actions/base.py +0 -0
  145. {wavexis-2.3.0 → wavexis-2.3.1}/wavexis/actions/bluetooth.py +0 -0
  146. {wavexis-2.3.0 → wavexis-2.3.1}/wavexis/actions/browser.py +0 -0
  147. {wavexis-2.3.0 → wavexis-2.3.1}/wavexis/actions/cast.py +0 -0
  148. {wavexis-2.3.0 → wavexis-2.3.1}/wavexis/actions/console.py +0 -0
  149. {wavexis-2.3.0 → wavexis-2.3.1}/wavexis/actions/cookies.py +0 -0
  150. {wavexis-2.3.0 → wavexis-2.3.1}/wavexis/actions/crawl.py +0 -0
  151. {wavexis-2.3.0 → wavexis-2.3.1}/wavexis/actions/css.py +0 -0
  152. {wavexis-2.3.0 → wavexis-2.3.1}/wavexis/actions/debug.py +0 -0
  153. {wavexis-2.3.0 → wavexis-2.3.1}/wavexis/actions/dialog.py +0 -0
  154. {wavexis-2.3.0 → wavexis-2.3.1}/wavexis/actions/dom.py +0 -0
  155. {wavexis-2.3.0 → wavexis-2.3.1}/wavexis/actions/dom_snapshot.py +0 -0
  156. {wavexis-2.3.0 → wavexis-2.3.1}/wavexis/actions/download.py +0 -0
  157. {wavexis-2.3.0 → wavexis-2.3.1}/wavexis/actions/emulation.py +0 -0
  158. {wavexis-2.3.0 → wavexis-2.3.1}/wavexis/actions/eval.py +0 -0
  159. {wavexis-2.3.0 → wavexis-2.3.1}/wavexis/actions/extract.py +0 -0
  160. {wavexis-2.3.0 → wavexis-2.3.1}/wavexis/actions/form.py +0 -0
  161. {wavexis-2.3.0 → wavexis-2.3.1}/wavexis/actions/har.py +0 -0
  162. {wavexis-2.3.0 → wavexis-2.3.1}/wavexis/actions/headers.py +0 -0
  163. {wavexis-2.3.0 → wavexis-2.3.1}/wavexis/actions/input.py +0 -0
  164. {wavexis-2.3.0 → wavexis-2.3.1}/wavexis/actions/lighthouse.py +0 -0
  165. {wavexis-2.3.0 → wavexis-2.3.1}/wavexis/actions/media.py +0 -0
  166. {wavexis-2.3.0 → wavexis-2.3.1}/wavexis/actions/multi.py +0 -0
  167. {wavexis-2.3.0 → wavexis-2.3.1}/wavexis/actions/navigate.py +0 -0
  168. {wavexis-2.3.0 → wavexis-2.3.1}/wavexis/actions/network.py +0 -0
  169. {wavexis-2.3.0 → wavexis-2.3.1}/wavexis/actions/overlay.py +0 -0
  170. {wavexis-2.3.0 → wavexis-2.3.1}/wavexis/actions/pdf.py +0 -0
  171. {wavexis-2.3.0 → wavexis-2.3.1}/wavexis/actions/performance.py +0 -0
  172. {wavexis-2.3.0 → wavexis-2.3.1}/wavexis/actions/permissions.py +0 -0
  173. {wavexis-2.3.0 → wavexis-2.3.1}/wavexis/actions/record.py +0 -0
  174. {wavexis-2.3.0 → wavexis-2.3.1}/wavexis/actions/scrape.py +0 -0
  175. {wavexis-2.3.0 → wavexis-2.3.1}/wavexis/actions/screencast.py +0 -0
  176. {wavexis-2.3.0 → wavexis-2.3.1}/wavexis/actions/screenshot.py +0 -0
  177. {wavexis-2.3.0 → wavexis-2.3.1}/wavexis/actions/security.py +0 -0
  178. {wavexis-2.3.0 → wavexis-2.3.1}/wavexis/actions/service_worker.py +0 -0
  179. {wavexis-2.3.0 → wavexis-2.3.1}/wavexis/actions/session.py +0 -0
  180. {wavexis-2.3.0 → wavexis-2.3.1}/wavexis/actions/storage.py +0 -0
  181. {wavexis-2.3.0 → wavexis-2.3.1}/wavexis/actions/tabs.py +0 -0
  182. {wavexis-2.3.0 → wavexis-2.3.1}/wavexis/actions/wait.py +0 -0
  183. {wavexis-2.3.0 → wavexis-2.3.1}/wavexis/actions/webaudio.py +0 -0
  184. {wavexis-2.3.0 → wavexis-2.3.1}/wavexis/actions/webauthn.py +0 -0
  185. {wavexis-2.3.0 → wavexis-2.3.1}/wavexis/actions/websocket.py +0 -0
  186. {wavexis-2.3.0 → wavexis-2.3.1}/wavexis/auth.py +0 -0
  187. {wavexis-2.3.0 → wavexis-2.3.1}/wavexis/backend/__init__.py +0 -0
  188. {wavexis-2.3.0 → wavexis-2.3.1}/wavexis/backend/manager.py +0 -0
  189. {wavexis-2.3.0 → wavexis-2.3.1}/wavexis/cleanup.py +0 -0
  190. {wavexis-2.3.0 → wavexis-2.3.1}/wavexis/cli/__init__.py +0 -0
  191. {wavexis-2.3.0 → wavexis-2.3.1}/wavexis/cli/_advanced.py +0 -0
  192. {wavexis-2.3.0 → wavexis-2.3.1}/wavexis/cli/_capture.py +0 -0
  193. {wavexis-2.3.0 → wavexis-2.3.1}/wavexis/cli/_config.py +0 -0
  194. {wavexis-2.3.0 → wavexis-2.3.1}/wavexis/cli/_debug.py +0 -0
  195. {wavexis-2.3.0 → wavexis-2.3.1}/wavexis/cli/_emulation.py +0 -0
  196. {wavexis-2.3.0 → wavexis-2.3.1}/wavexis/cli/_experimental.py +0 -0
  197. {wavexis-2.3.0 → wavexis-2.3.1}/wavexis/cli/_input.py +0 -0
  198. {wavexis-2.3.0 → wavexis-2.3.1}/wavexis/cli/_navigation.py +0 -0
  199. {wavexis-2.3.0 → wavexis-2.3.1}/wavexis/cli/_network.py +0 -0
  200. {wavexis-2.3.0 → wavexis-2.3.1}/wavexis/cli/_perf.py +0 -0
  201. {wavexis-2.3.0 → wavexis-2.3.1}/wavexis/cli/_serve.py +0 -0
  202. {wavexis-2.3.0 → wavexis-2.3.1}/wavexis/cli/_session.py +0 -0
  203. {wavexis-2.3.0 → wavexis-2.3.1}/wavexis/cli/_shared.py +0 -0
  204. {wavexis-2.3.0 → wavexis-2.3.1}/wavexis/cli/_workflow.py +0 -0
  205. {wavexis-2.3.0 → wavexis-2.3.1}/wavexis/cli/app.py +0 -0
  206. {wavexis-2.3.0 → wavexis-2.3.1}/wavexis/config.py +0 -0
  207. {wavexis-2.3.0 → wavexis-2.3.1}/wavexis/exceptions.py +0 -0
  208. {wavexis-2.3.0 → wavexis-2.3.1}/wavexis/init.py +0 -0
  209. {wavexis-2.3.0 → wavexis-2.3.1}/wavexis/multi.py +0 -0
  210. {wavexis-2.3.0 → wavexis-2.3.1}/wavexis/output.py +0 -0
  211. {wavexis-2.3.0 → wavexis-2.3.1}/wavexis/plugins.py +0 -0
  212. {wavexis-2.3.0 → wavexis-2.3.1}/wavexis/record.py +0 -0
  213. {wavexis-2.3.0 → wavexis-2.3.1}/wavexis/repl.py +0 -0
  214. {wavexis-2.3.0 → wavexis-2.3.1}/wavexis/serve.py +0 -0
@@ -2,6 +2,13 @@
2
2
 
3
3
  All notable changes to wavexis are documented in this file.
4
4
 
5
+ ## v2.3.1 — 2026-07-07
6
+
7
+ ### Added
8
+
9
+ - `auto_wait: bool = True` parameter in `click`, `fill`, `hover` (both backends)
10
+ - Pass `auto_wait=False` to skip element visibility polling for instant execution
11
+
5
12
  ## v2.3.0 — 2026-07-07
6
13
 
7
14
  ### Added
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: wavexis
3
- Version: 2.3.0
3
+ Version: 2.3.1
4
4
  Summary: Browser automation CLI — wraps cdpwave and bidiwave, no Node.js, no Chromium download
5
5
  Project-URL: Homepage, https://github.com/MathiasPaulenko/wavexis
6
6
  Project-URL: Repository, https://github.com/MathiasPaulenko/wavexis
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "wavexis"
7
- version = "2.3.0"
7
+ version = "2.3.1"
8
8
  description = "Browser automation CLI — wraps cdpwave and bidiwave, no Node.js, no Chromium download"
9
9
  readme = "README.md"
10
10
  license = { text = "MIT" }
@@ -68,6 +68,35 @@ class TestAutoWait:
68
68
  asyncio.run(backend.click("#btn"))
69
69
  assert call_order == ["wait", "scroll", "box"]
70
70
 
71
+ def test_cdp_click_auto_wait_false_skips_wait(self) -> None:
72
+ """Test that click with auto_wait=False skips _wait_for_element."""
73
+ from wavexis.backend.cdp import CDPBackend
74
+
75
+ backend = CDPBackend()
76
+ backend._session = MagicMock()
77
+ backend._session.input = MagicMock()
78
+ backend._session.input.dispatch_mouse_event = AsyncMock()
79
+
80
+ call_order: list[str] = []
81
+
82
+ async def _mock_wait(selector: str, timeout_ms: int = 30000) -> None:
83
+ call_order.append("wait")
84
+
85
+ async def _mock_scroll(selector: str) -> None:
86
+ call_order.append("scroll")
87
+
88
+ async def _mock_box(selector: str) -> tuple[float, float]:
89
+ call_order.append("box")
90
+ return 50.0, 25.0
91
+
92
+ backend._wait_for_element = _mock_wait # type: ignore[assignment]
93
+ backend._scroll_into_view_if_needed = _mock_scroll # type: ignore[assignment]
94
+ backend._get_box_center = _mock_box # type: ignore[assignment]
95
+
96
+ asyncio.run(backend.click("#btn", auto_wait=False))
97
+ assert "wait" not in call_order
98
+ assert call_order == ["scroll", "box"]
99
+
71
100
  def test_bidi_wait_for_element_found(self) -> None:
72
101
  """Test BiDi _wait_for_element returns when element is visible."""
73
102
  from wavexis.backend.bidi import BiDiBackend
@@ -1,3 +1,3 @@
1
1
  """wavexis — CLI de automatización de navegador."""
2
2
 
3
- __version__ = "2.3.0"
3
+ __version__ = "2.3.1"
@@ -237,7 +237,11 @@ class AbstractBackend(ABC):
237
237
 
238
238
  @abstractmethod
239
239
  async def click(
240
- self, selector: str, button: str = "left", click_count: int = 1
240
+ self,
241
+ selector: str,
242
+ button: str = "left",
243
+ click_count: int = 1,
244
+ auto_wait: bool = True,
241
245
  ) -> None:
242
246
  """Click an element matching a CSS selector."""
243
247
 
@@ -246,7 +250,9 @@ class AbstractBackend(ABC):
246
250
  """Type text into an element, optionally with delay between keystrokes."""
247
251
 
248
252
  @abstractmethod
249
- async def fill(self, selector: str, value: str) -> None:
253
+ async def fill(
254
+ self, selector: str, value: str, auto_wait: bool = True
255
+ ) -> None:
250
256
  """Fill an input element with a value (replaces existing content)."""
251
257
 
252
258
  @abstractmethod
@@ -254,7 +260,7 @@ class AbstractBackend(ABC):
254
260
  """Select an option in a <select> element by value."""
255
261
 
256
262
  @abstractmethod
257
- async def hover(self, selector: str) -> None:
263
+ async def hover(self, selector: str, auto_wait: bool = True) -> None:
258
264
  """Hover over an element matching a CSS selector."""
259
265
 
260
266
  @abstractmethod
@@ -853,11 +853,23 @@ class BiDiBackend(AbstractBackend):
853
853
  await client.script.evaluate(self._context, js)
854
854
 
855
855
  async def click(
856
- self, selector: str, button: str = "left", click_count: int = 1
856
+ self,
857
+ selector: str,
858
+ button: str = "left",
859
+ click_count: int = 1,
860
+ auto_wait: bool = True,
857
861
  ) -> None:
858
- """Click an element via BiDi script.evaluate."""
862
+ """Click an element via BiDi script.evaluate.
863
+
864
+ Args:
865
+ selector: CSS selector for the target element.
866
+ button: Mouse button (unused in BiDi, for API compatibility).
867
+ click_count: Number of clicks to dispatch.
868
+ auto_wait: If True, wait for element to be visible before clicking.
869
+ """
859
870
  client = self._require_client()
860
- await self._wait_for_element(selector)
871
+ if auto_wait:
872
+ await self._wait_for_element(selector)
861
873
  await self._scroll_into_view_if_needed(selector)
862
874
  escaped = selector.replace("'", "\\'")
863
875
  js = (
@@ -887,10 +899,19 @@ class BiDiBackend(AbstractBackend):
887
899
  if delay > 0:
888
900
  await _asyncio.sleep(delay / 1000)
889
901
 
890
- async def fill(self, selector: str, value: str) -> None:
891
- """Fill an input element with a value via BiDi."""
902
+ async def fill(
903
+ self, selector: str, value: str, auto_wait: bool = True
904
+ ) -> None:
905
+ """Fill an input element with a value via BiDi.
906
+
907
+ Args:
908
+ selector: CSS selector for the target element.
909
+ value: Value to set in the input field.
910
+ auto_wait: If True, wait for element to be visible before filling.
911
+ """
892
912
  client = self._require_client()
893
- await self._wait_for_element(selector)
913
+ if auto_wait:
914
+ await self._wait_for_element(selector)
894
915
  await self._scroll_into_view_if_needed(selector)
895
916
  escaped = selector.replace("'", "\\'")
896
917
  escaped_val = value.replace("\\", "\\\\").replace("'", "\\'")
@@ -906,10 +927,16 @@ class BiDiBackend(AbstractBackend):
906
927
  js = f"document.querySelector('{escaped}').value = '{escaped_val}'"
907
928
  await self._client.script.evaluate(self._context, js)
908
929
 
909
- async def hover(self, selector: str) -> None:
910
- """Hover over an element via BiDi script.evaluate."""
930
+ async def hover(self, selector: str, auto_wait: bool = True) -> None:
931
+ """Hover over an element via BiDi script.evaluate.
932
+
933
+ Args:
934
+ selector: CSS selector for the target element.
935
+ auto_wait: If True, wait for element to be visible before hovering.
936
+ """
911
937
  client = self._require_client()
912
- await self._wait_for_element(selector)
938
+ if auto_wait:
939
+ await self._wait_for_element(selector)
913
940
  await self._scroll_into_view_if_needed(selector)
914
941
  escaped = selector.replace("'", "\\'")
915
942
  js = (
@@ -1072,7 +1072,11 @@ class CDPBackend(AbstractBackend):
1072
1072
  await session.runtime.evaluate(js)
1073
1073
 
1074
1074
  async def click(
1075
- self, selector: str, button: str = "left", click_count: int = 1
1075
+ self,
1076
+ selector: str,
1077
+ button: str = "left",
1078
+ click_count: int = 1,
1079
+ auto_wait: bool = True,
1076
1080
  ) -> None:
1077
1081
  """Click an element matching a CSS selector.
1078
1082
 
@@ -1080,9 +1084,11 @@ class CDPBackend(AbstractBackend):
1080
1084
  selector: CSS selector for the target element.
1081
1085
  button: Mouse button — "left", "right", or "middle".
1082
1086
  click_count: Number of clicks to dispatch.
1087
+ auto_wait: If True, wait for element to be visible before clicking.
1083
1088
  """
1084
1089
  session = self._require_session()
1085
- await self._wait_for_element(selector)
1090
+ if auto_wait:
1091
+ await self._wait_for_element(selector)
1086
1092
  await self._scroll_into_view_if_needed(selector)
1087
1093
  x, y = await self._get_box_center(selector)
1088
1094
  btn_map = {"left": "left", "right": "right", "middle": "middle"}
@@ -1113,15 +1119,19 @@ class CDPBackend(AbstractBackend):
1113
1119
  if delay > 0:
1114
1120
  await asyncio.sleep(delay / 1000)
1115
1121
 
1116
- async def fill(self, selector: str, value: str) -> None:
1122
+ async def fill(
1123
+ self, selector: str, value: str, auto_wait: bool = True
1124
+ ) -> None:
1117
1125
  """Fill an input element with a value (replaces existing content).
1118
1126
 
1119
1127
  Args:
1120
1128
  selector: CSS selector for the target element.
1121
1129
  value: Value to set in the input field.
1130
+ auto_wait: If True, wait for element to be visible before filling.
1122
1131
  """
1123
1132
  session = self._require_session()
1124
- await self._wait_for_element(selector)
1133
+ if auto_wait:
1134
+ await self._wait_for_element(selector)
1125
1135
  await self._scroll_into_view_if_needed(selector)
1126
1136
  escaped = selector.replace("'", "\\'")
1127
1137
  js = (
@@ -1155,14 +1165,16 @@ class CDPBackend(AbstractBackend):
1155
1165
  if not result.get("result", {}).get("value"):
1156
1166
  raise ElementNotFoundError(selector)
1157
1167
 
1158
- async def hover(self, selector: str) -> None:
1168
+ async def hover(self, selector: str, auto_wait: bool = True) -> None:
1159
1169
  """Hover over an element matching a CSS selector.
1160
1170
 
1161
1171
  Args:
1162
1172
  selector: CSS selector for the target element.
1173
+ auto_wait: If True, wait for element to be visible before hovering.
1163
1174
  """
1164
1175
  session = self._require_session()
1165
- await self._wait_for_element(selector)
1176
+ if auto_wait:
1177
+ await self._wait_for_element(selector)
1166
1178
  await self._scroll_into_view_if_needed(selector)
1167
1179
  x, y = await self._get_box_center(selector)
1168
1180
  await session.input.dispatch_mouse_event(
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes