browsix 1.0.0__py3-none-any.whl

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 (57) hide show
  1. browsix/__init__.py +3 -0
  2. browsix/__main__.py +6 -0
  3. browsix/actions/__init__.py +1 -0
  4. browsix/actions/accessibility.py +53 -0
  5. browsix/actions/animation.py +59 -0
  6. browsix/actions/base.py +26 -0
  7. browsix/actions/bluetooth.py +68 -0
  8. browsix/actions/browser.py +39 -0
  9. browsix/actions/cast.py +67 -0
  10. browsix/actions/console.py +57 -0
  11. browsix/actions/css.py +96 -0
  12. browsix/actions/debug.py +134 -0
  13. browsix/actions/dialog.py +50 -0
  14. browsix/actions/dom.py +70 -0
  15. browsix/actions/dom_snapshot.py +45 -0
  16. browsix/actions/download.py +38 -0
  17. browsix/actions/emulation.py +45 -0
  18. browsix/actions/eval.py +36 -0
  19. browsix/actions/har.py +27 -0
  20. browsix/actions/input.py +62 -0
  21. browsix/actions/media.py +62 -0
  22. browsix/actions/multi.py +29 -0
  23. browsix/actions/navigate.py +98 -0
  24. browsix/actions/network.py +70 -0
  25. browsix/actions/overlay.py +61 -0
  26. browsix/actions/pdf.py +32 -0
  27. browsix/actions/performance.py +69 -0
  28. browsix/actions/permissions.py +50 -0
  29. browsix/actions/scrape.py +50 -0
  30. browsix/actions/screencast.py +44 -0
  31. browsix/actions/screenshot.py +37 -0
  32. browsix/actions/security.py +50 -0
  33. browsix/actions/service_worker.py +69 -0
  34. browsix/actions/storage.py +92 -0
  35. browsix/actions/tabs.py +53 -0
  36. browsix/actions/webaudio.py +62 -0
  37. browsix/actions/webauthn.py +96 -0
  38. browsix/auth.py +86 -0
  39. browsix/backend/__init__.py +1 -0
  40. browsix/backend/base.py +829 -0
  41. browsix/backend/bidi.py +953 -0
  42. browsix/backend/cdp.py +2339 -0
  43. browsix/backend/manager.py +114 -0
  44. browsix/cli/__init__.py +8 -0
  45. browsix/cli/app.py +2409 -0
  46. browsix/config.py +589 -0
  47. browsix/exceptions.py +61 -0
  48. browsix/multi.py +156 -0
  49. browsix/output.py +142 -0
  50. browsix/plugins.py +101 -0
  51. browsix/record.py +105 -0
  52. browsix/serve.py +343 -0
  53. browsix-1.0.0.dist-info/METADATA +128 -0
  54. browsix-1.0.0.dist-info/RECORD +57 -0
  55. browsix-1.0.0.dist-info/WHEEL +4 -0
  56. browsix-1.0.0.dist-info/entry_points.txt +2 -0
  57. browsix-1.0.0.dist-info/licenses/LICENSE +21 -0
browsix/__init__.py ADDED
@@ -0,0 +1,3 @@
1
+ """browsix — CLI de automatización de navegador."""
2
+
3
+ __version__ = "1.0.0"
browsix/__main__.py ADDED
@@ -0,0 +1,6 @@
1
+ """Allow `python -m browsix` execution."""
2
+
3
+ from browsix.cli import main
4
+
5
+ if __name__ == "__main__":
6
+ main()
@@ -0,0 +1 @@
1
+ """Actions layer for browsix."""
@@ -0,0 +1,53 @@
1
+ """Accessibility action for retrieving a11y tree, node, and ancestors."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import Any
6
+
7
+ from browsix.actions.base import BaseAction
8
+ from browsix.backend.base import AbstractBackend
9
+ from browsix.config import WaitStrategy
10
+
11
+
12
+ class AccessibilityAction(BaseAction[Any, Any]):
13
+ """Action for accessibility tree operations."""
14
+
15
+ def __init__(
16
+ self,
17
+ params: Any,
18
+ action: str = "tree",
19
+ node_id: str = "",
20
+ url: str = "",
21
+ wait: WaitStrategy | None = None,
22
+ ) -> None:
23
+ self.params = params
24
+ self._action = action
25
+ self._node_id = node_id
26
+ self._url = url
27
+ self._wait = wait or WaitStrategy(strategy="load")
28
+
29
+ async def execute(self, backend: AbstractBackend) -> Any:
30
+ """Execute the accessibility action on the backend.
31
+
32
+ Args:
33
+ backend: The browser backend to use.
34
+
35
+ Returns:
36
+ Accessibility tree dict, node dict, or list of ancestor dicts.
37
+ """
38
+ from browsix.config import BrowserOptions
39
+
40
+ await backend.launch(BrowserOptions())
41
+ try:
42
+ if self._url:
43
+ await backend.navigate(self._url, self._wait)
44
+ if self._action == "tree":
45
+ return await backend.a11y_tree()
46
+ elif self._action == "node":
47
+ return await backend.a11y_node(self._node_id)
48
+ elif self._action == "ancestors":
49
+ return await backend.a11y_ancestors(self._node_id)
50
+ else:
51
+ raise ValueError(f"Unknown a11y action: {self._action}")
52
+ finally:
53
+ await backend.close()
@@ -0,0 +1,59 @@
1
+ """Animation action for listing, pausing, playing, and seeking animations."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import Any
6
+
7
+ from browsix.actions.base import BaseAction
8
+ from browsix.backend.base import AbstractBackend
9
+ from browsix.config import AnimationParams
10
+
11
+
12
+ class AnimationAction(BaseAction[AnimationParams, Any]):
13
+ """Action for animation operations."""
14
+
15
+ async def execute(self, backend: AbstractBackend) -> Any:
16
+ """Execute the animation action on the backend.
17
+
18
+ Args:
19
+ backend: An AbstractBackend instance.
20
+
21
+ Returns:
22
+ Result of the animation operation.
23
+ """
24
+ try:
25
+ await backend.launch(self.params.browser)
26
+ if self.params.url:
27
+ await backend.navigate(self.params.url, self.params.wait)
28
+
29
+ action = self.params.action
30
+
31
+ if action == "list":
32
+ return await backend.animation_list()
33
+
34
+ if action == "pause":
35
+ if not self.params.animation_id:
36
+ raise ValueError("animation_id is required for pause action")
37
+ await backend.animation_pause(self.params.animation_id)
38
+ return None
39
+
40
+ if action == "play":
41
+ if not self.params.animation_id:
42
+ raise ValueError("animation_id is required for play action")
43
+ await backend.animation_play(self.params.animation_id)
44
+ return None
45
+
46
+ if action == "seek":
47
+ if not self.params.animation_id or self.params.time_ms is None:
48
+ raise ValueError(
49
+ "animation_id and time_ms are required for seek action"
50
+ )
51
+ await backend.animation_seek(
52
+ self.params.animation_id, self.params.time_ms
53
+ )
54
+ return None
55
+
56
+ raise ValueError(f"Unknown animation action: {action}")
57
+
58
+ finally:
59
+ await backend.close()
@@ -0,0 +1,26 @@
1
+ """Base action class for browsix actions."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from abc import ABC, abstractmethod
6
+ from typing import Generic, TypeVar
7
+
8
+ from browsix.backend.base import AbstractBackend
9
+
10
+ P = TypeVar("P")
11
+ R = TypeVar("R")
12
+
13
+
14
+ class BaseAction(ABC, Generic[P, R]):
15
+ """Abstract base class for all browsix actions.
16
+
17
+ An action encapsulates a single operation (e.g. screenshot, eval, pdf)
18
+ that is executed against a backend.
19
+ """
20
+
21
+ def __init__(self, params: P) -> None:
22
+ self.params = params
23
+
24
+ @abstractmethod
25
+ async def execute(self, backend: AbstractBackend) -> R:
26
+ """Execute the action against the given backend."""
@@ -0,0 +1,68 @@
1
+ """Bluetooth action for BLE emulation (experimental)."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from dataclasses import dataclass, field
6
+ from typing import Any
7
+
8
+ from browsix.actions.base import BaseAction
9
+ from browsix.backend.base import AbstractBackend
10
+ from browsix.config import BrowserOptions, WaitStrategy
11
+
12
+
13
+ @dataclass
14
+ class BluetoothParams:
15
+ """Parameters for Bluetooth emulation operations.
16
+
17
+ Attributes:
18
+ url: URL to navigate to before Bluetooth operations.
19
+ action: Bluetooth action — "emulate", "stop".
20
+ name: Device name for "emulate" action.
21
+ address: Device MAC address for "emulate" action.
22
+ wait: Wait strategy after navigation.
23
+ browser: Browser launch options.
24
+ """
25
+
26
+ url: str = ""
27
+ action: str = "emulate"
28
+ name: str | None = None
29
+ address: str = "00:00:00:00:00:01"
30
+ wait: WaitStrategy = field(default_factory=WaitStrategy)
31
+ browser: BrowserOptions = field(default_factory=BrowserOptions)
32
+
33
+
34
+ class BluetoothAction(BaseAction[BluetoothParams, Any]):
35
+ """Action for Bluetooth emulation operations (experimental)."""
36
+
37
+ async def execute(self, backend: AbstractBackend) -> Any:
38
+ """Execute the Bluetooth action on the backend.
39
+
40
+ Args:
41
+ backend: An AbstractBackend instance.
42
+
43
+ Returns:
44
+ Result of the Bluetooth operation.
45
+ """
46
+ try:
47
+ await backend.launch(self.params.browser)
48
+ if self.params.url:
49
+ await backend.navigate(self.params.url, self.params.wait)
50
+
51
+ action = self.params.action
52
+
53
+ if action == "emulate":
54
+ if not self.params.name:
55
+ raise ValueError("name is required for emulate action")
56
+ await backend.bluetooth_emulate(
57
+ self.params.name, self.params.address
58
+ )
59
+ return None
60
+
61
+ if action == "stop":
62
+ await backend.bluetooth_stop()
63
+ return None
64
+
65
+ raise ValueError(f"Unknown Bluetooth action: {action}")
66
+
67
+ finally:
68
+ await backend.close()
@@ -0,0 +1,39 @@
1
+ """Browser action for context and window management."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import Any
6
+
7
+ from browsix.actions.base import BaseAction
8
+ from browsix.backend.base import AbstractBackend
9
+
10
+
11
+ class BrowserAction(BaseAction[str, Any]):
12
+ """Action for browser management operations.
13
+
14
+ Supports contexts (new/list/close), window bounds (get/set), and version.
15
+ The params string specifies the action: "new_context", "list_contexts",
16
+ "close_context", "get_window", "set_window", or "version".
17
+ """
18
+
19
+ async def execute(self, backend: AbstractBackend) -> Any:
20
+ """Execute the browser action.
21
+
22
+ Args:
23
+ backend: The browser backend to use.
24
+
25
+ Returns:
26
+ Action-dependent result (str, list, dict, or None).
27
+ """
28
+ action = self.params
29
+
30
+ if action == "version":
31
+ return await backend.browser_version()
32
+
33
+ if action == "new_context":
34
+ return await backend.new_context()
35
+
36
+ if action == "list_contexts":
37
+ return await backend.list_contexts()
38
+
39
+ return None
@@ -0,0 +1,67 @@
1
+ """Cast action for listing sinks and controlling tab mirroring (experimental)."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from dataclasses import dataclass, field
6
+ from typing import Any
7
+
8
+ from browsix.actions.base import BaseAction
9
+ from browsix.backend.base import AbstractBackend
10
+ from browsix.config import BrowserOptions, WaitStrategy
11
+
12
+
13
+ @dataclass
14
+ class CastParams:
15
+ """Parameters for Cast operations.
16
+
17
+ Attributes:
18
+ url: URL to navigate to before Cast operations.
19
+ action: Cast action — "list", "start-tab", "stop".
20
+ sink_name: Cast sink name for "start-tab" action.
21
+ wait: Wait strategy after navigation.
22
+ browser: Browser launch options.
23
+ """
24
+
25
+ url: str = ""
26
+ action: str = "list"
27
+ sink_name: str | None = None
28
+ wait: WaitStrategy = field(default_factory=WaitStrategy)
29
+ browser: BrowserOptions = field(default_factory=BrowserOptions)
30
+
31
+
32
+ class CastAction(BaseAction[CastParams, Any]):
33
+ """Action for Cast operations (experimental)."""
34
+
35
+ async def execute(self, backend: AbstractBackend) -> Any:
36
+ """Execute the Cast action on the backend.
37
+
38
+ Args:
39
+ backend: An AbstractBackend instance.
40
+
41
+ Returns:
42
+ Result of the Cast operation.
43
+ """
44
+ try:
45
+ await backend.launch(self.params.browser)
46
+ if self.params.url:
47
+ await backend.navigate(self.params.url, self.params.wait)
48
+
49
+ action = self.params.action
50
+
51
+ if action == "list":
52
+ return await backend.cast_list()
53
+
54
+ if action == "start-tab":
55
+ if not self.params.sink_name:
56
+ raise ValueError("sink_name is required for start-tab action")
57
+ await backend.cast_start_tab(self.params.sink_name)
58
+ return None
59
+
60
+ if action == "stop":
61
+ await backend.cast_stop()
62
+ return None
63
+
64
+ raise ValueError(f"Unknown Cast action: {action}")
65
+
66
+ finally:
67
+ await backend.close()
@@ -0,0 +1,57 @@
1
+ """Console action for capturing console messages and browser logs."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from dataclasses import dataclass
6
+ from typing import Any
7
+
8
+ from browsix.actions.base import BaseAction
9
+ from browsix.backend.base import AbstractBackend
10
+ from browsix.config import WaitStrategy
11
+
12
+
13
+ @dataclass
14
+ class ConsoleParams:
15
+ """Parameters for console capture.
16
+
17
+ Attributes:
18
+ url: URL to navigate to before capturing.
19
+ level: Minimum log level — "all", "error", "warning", "info".
20
+ wait: Wait strategy after navigation.
21
+ capture: What to capture — "console", "logs", or "both".
22
+ """
23
+
24
+ url: str = ""
25
+ level: str = "all"
26
+ wait: WaitStrategy | None = None
27
+ capture: str = "console"
28
+
29
+
30
+ class ConsoleAction(BaseAction[ConsoleParams, dict[str, Any]]):
31
+ """Action for capturing console messages and browser logs.
32
+
33
+ Navigates to the URL, then captures console messages and/or log entries.
34
+ """
35
+
36
+ async def execute(self, backend: AbstractBackend) -> dict[str, Any]:
37
+ """Execute the console action.
38
+
39
+ Args:
40
+ backend: The browser backend to use.
41
+
42
+ Returns:
43
+ Dict with "console" and/or "logs" keys containing entry lists.
44
+ """
45
+ params = self.params
46
+ if params.url:
47
+ await backend.navigate(params.url, params.wait)
48
+
49
+ result: dict[str, Any] = {}
50
+
51
+ if params.capture in ("console", "both"):
52
+ result["console"] = await backend.capture_console(level=params.level)
53
+
54
+ if params.capture in ("logs", "both"):
55
+ result["logs"] = await backend.capture_logs()
56
+
57
+ return result
browsix/actions/css.py ADDED
@@ -0,0 +1,96 @@
1
+ """CSS action for inspecting styles, stylesheets, rules, and computed styles."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from dataclasses import dataclass, field
6
+ from typing import Any
7
+
8
+ from browsix.actions.base import BaseAction
9
+ from browsix.backend.base import AbstractBackend
10
+ from browsix.config import BrowserOptions, CSSParams, WaitStrategy
11
+
12
+
13
+ @dataclass
14
+ class CSSActionParams:
15
+ """Parameters for CSS inspection operations.
16
+
17
+ Attributes:
18
+ url: URL to navigate to before CSS inspection.
19
+ selector: CSS selector for the target element.
20
+ stylesheet_id: Stylesheet ID for rules action.
21
+ action: CSS action — "styles", "stylesheets", "rules", "computed".
22
+ wait: Wait strategy after navigation.
23
+ browser: Browser launch options.
24
+ """
25
+
26
+ url: str = ""
27
+ selector: str | None = None
28
+ stylesheet_id: str | None = None
29
+ action: str = "styles"
30
+ wait: WaitStrategy = field(default_factory=WaitStrategy)
31
+ browser: BrowserOptions = field(default_factory=BrowserOptions)
32
+
33
+
34
+ class CSSAction(BaseAction[CSSActionParams, dict[str, Any] | list[dict[str, Any]]]):
35
+ """Action for CSS inspection operations."""
36
+
37
+ async def execute(
38
+ self, backend: AbstractBackend
39
+ ) -> dict[str, Any] | list[dict[str, Any]]:
40
+ """Execute the CSS action on the backend.
41
+
42
+ Args:
43
+ backend: The browser backend to use.
44
+
45
+ Returns:
46
+ Dict or list of dicts containing CSS data.
47
+
48
+ Raises:
49
+ ValueError: If the action is not recognized or required params missing.
50
+ """
51
+ await backend.launch(self.params.browser)
52
+ try:
53
+ await backend.navigate(self.params.url, self.params.wait)
54
+ return await self._run_action(backend)
55
+ finally:
56
+ await backend.close()
57
+
58
+ async def _run_action(
59
+ self, backend: AbstractBackend
60
+ ) -> dict[str, Any] | list[dict[str, Any]]:
61
+ action = self.params.action
62
+ if action == "styles":
63
+ if not self.params.selector:
64
+ raise ValueError("selector is required for styles action")
65
+ return await backend.css_get_styles(self.params.selector)
66
+ if action == "stylesheets":
67
+ return await backend.css_get_stylesheets()
68
+ if action == "rules":
69
+ if not self.params.stylesheet_id:
70
+ raise ValueError("stylesheet_id is required for rules action")
71
+ return await backend.css_get_rules(self.params.stylesheet_id)
72
+ if action == "computed":
73
+ if not self.params.selector:
74
+ raise ValueError("selector is required for computed action")
75
+ return await backend.css_get_computed(self.params.selector)
76
+ raise ValueError(f"Unknown CSS action: {action}")
77
+
78
+
79
+ def css_action_from_config(params: CSSParams) -> CSSAction:
80
+ """Create a CSSAction from CSSParams config dataclass.
81
+
82
+ Args:
83
+ params: CSSParams from browsix.config.
84
+
85
+ Returns:
86
+ CSSAction instance with mapped parameters.
87
+ """
88
+ action_params = CSSActionParams(
89
+ url=params.url,
90
+ selector=params.selector,
91
+ stylesheet_id=params.stylesheet_id,
92
+ action=params.action,
93
+ wait=params.wait,
94
+ browser=params.browser,
95
+ )
96
+ return CSSAction(action_params)
@@ -0,0 +1,134 @@
1
+ """Debug action for breakpoints, stepping, pause/resume, and listeners."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from dataclasses import dataclass, field
6
+ from typing import Any
7
+
8
+ from browsix.actions.base import BaseAction
9
+ from browsix.backend.base import AbstractBackend
10
+ from browsix.config import BrowserOptions, DebugParams, WaitStrategy
11
+
12
+
13
+ @dataclass
14
+ class DebugActionParams:
15
+ """Parameters for debugging operations.
16
+
17
+ Attributes:
18
+ url: URL to navigate to before debugging (optional for step/pause/resume).
19
+ line: Line number for breakpoint (0-based).
20
+ function_name: Function name for function breakpoint.
21
+ condition: Optional condition expression for breakpoint.
22
+ action: Debug action — "breakpoint", "function_breakpoint",
23
+ "remove_breakpoint", "step_over", "step_into", "step_out",
24
+ "pause", "resume", "listeners".
25
+ breakpoint_id: Breakpoint ID for remove_breakpoint.
26
+ selector: CSS selector for listeners action.
27
+ script_url: URL of the script for breakpoint (distinct from page url).
28
+ wait: Wait strategy after navigation.
29
+ browser: Browser launch options.
30
+ """
31
+
32
+ url: str | None = None
33
+ line: int | None = None
34
+ function_name: str | None = None
35
+ condition: str | None = None
36
+ action: str = "breakpoint"
37
+ breakpoint_id: str | None = None
38
+ selector: str | None = None
39
+ script_url: str | None = None
40
+ wait: WaitStrategy = field(default_factory=WaitStrategy)
41
+ browser: BrowserOptions = field(default_factory=BrowserOptions)
42
+
43
+
44
+ class DebugAction(BaseAction[DebugActionParams, Any]):
45
+ """Action for debugging operations."""
46
+
47
+ async def execute(self, backend: AbstractBackend) -> Any:
48
+ """Execute the debug action on the backend.
49
+
50
+ Args:
51
+ backend: The browser backend to use.
52
+
53
+ Returns:
54
+ Result of the debug action (breakpoint ID, listener list, or None).
55
+
56
+ Raises:
57
+ ValueError: If the action is not recognized or required params missing.
58
+ """
59
+ await backend.launch(self.params.browser)
60
+ try:
61
+ if self.params.url:
62
+ await backend.navigate(self.params.url, self.params.wait)
63
+ return await self._run_action(backend)
64
+ finally:
65
+ await backend.close()
66
+
67
+ async def _run_action(self, backend: AbstractBackend) -> Any:
68
+ action = self.params.action
69
+ if action == "breakpoint":
70
+ if self.params.script_url is None or self.params.line is None:
71
+ raise ValueError(
72
+ "script_url and line are required for breakpoint action"
73
+ )
74
+ return await backend.debug_set_breakpoint(
75
+ self.params.script_url, self.params.line, self.params.condition
76
+ )
77
+ if action == "function_breakpoint":
78
+ if not self.params.function_name:
79
+ raise ValueError(
80
+ "function_name is required for function_breakpoint action"
81
+ )
82
+ return await backend.debug_set_breakpoint_function(
83
+ self.params.function_name
84
+ )
85
+ if action == "remove_breakpoint":
86
+ if not self.params.breakpoint_id:
87
+ raise ValueError(
88
+ "breakpoint_id is required for remove_breakpoint action"
89
+ )
90
+ await backend.debug_remove_breakpoint(self.params.breakpoint_id)
91
+ return None
92
+ if action == "step_over":
93
+ await backend.debug_step_over()
94
+ return None
95
+ if action == "step_into":
96
+ await backend.debug_step_into()
97
+ return None
98
+ if action == "step_out":
99
+ await backend.debug_step_out()
100
+ return None
101
+ if action == "pause":
102
+ await backend.debug_pause()
103
+ return None
104
+ if action == "resume":
105
+ await backend.debug_resume()
106
+ return None
107
+ if action == "listeners":
108
+ if not self.params.selector:
109
+ raise ValueError("selector is required for listeners action")
110
+ return await backend.debug_get_listeners(self.params.selector)
111
+ raise ValueError(f"Unknown debug action: {action}")
112
+
113
+
114
+ def debug_action_from_config(params: DebugParams) -> DebugAction:
115
+ """Create a DebugAction from DebugParams config dataclass.
116
+
117
+ Args:
118
+ params: DebugParams from browsix.config.
119
+
120
+ Returns:
121
+ DebugAction instance with mapped parameters.
122
+ """
123
+ action_params = DebugActionParams(
124
+ url=params.url,
125
+ line=params.line,
126
+ function_name=params.function_name,
127
+ condition=params.condition,
128
+ action=params.action,
129
+ breakpoint_id=params.breakpoint_id,
130
+ selector=params.selector,
131
+ wait=params.wait,
132
+ browser=params.browser,
133
+ )
134
+ return DebugAction(action_params)
@@ -0,0 +1,50 @@
1
+ """Dialog action for accepting or dismissing JavaScript dialogs."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import Any
6
+
7
+ from browsix.actions.base import BaseAction
8
+ from browsix.backend.base import AbstractBackend
9
+ from browsix.config import BrowserOptions, WaitStrategy
10
+
11
+
12
+ class DialogAction(BaseAction[str, None]):
13
+ """Action for handling JavaScript dialogs (alert, confirm, prompt)."""
14
+
15
+ def __init__(
16
+ self,
17
+ params: str,
18
+ action: str = "accept",
19
+ prompt_text: str | None = None,
20
+ url: str = "",
21
+ wait: WaitStrategy | None = None,
22
+ ) -> None:
23
+ self.params = params
24
+ self._action = action
25
+ self._prompt_text = prompt_text
26
+ self._url = url
27
+ self._wait = wait or WaitStrategy(strategy="load")
28
+
29
+ async def execute(self, backend: AbstractBackend) -> Any:
30
+ """Execute the dialog action on the backend.
31
+
32
+ Args:
33
+ backend: The browser backend to use.
34
+
35
+ Returns:
36
+ None.
37
+ """
38
+ await backend.launch(BrowserOptions())
39
+ try:
40
+ if self._url:
41
+ await backend.navigate(self._url, self._wait)
42
+ if self._action == "accept":
43
+ await backend.dialog_accept(self._prompt_text)
44
+ elif self._action == "dismiss":
45
+ await backend.dialog_dismiss()
46
+ else:
47
+ raise ValueError(f"Unknown dialog action: {self._action}")
48
+ finally:
49
+ await backend.close()
50
+ return None