playwright_rs/protocol/dialog.rs
1// Copyright 2026 Paul Adamson
2// Licensed under the Apache License, Version 2.0
3//
4// Dialog protocol object
5//
6// Represents a browser dialog (alert, confirm, prompt, or beforeunload)
7// dispatched via page.on('dialog') events.
8
9use crate::error::Result;
10use crate::server::channel_owner::{ChannelOwner, ChannelOwnerImpl, ParentOrConnection};
11use crate::server::connection::downcast_parent;
12use serde_json::{Value, json};
13use std::any::Any;
14use std::sync::Arc;
15
16/// Dialog represents a browser dialog (alert, confirm, prompt, or beforeunload).
17///
18/// Dialogs are dispatched via the page.on('dialog') event. Dialogs must be
19/// explicitly accepted or dismissed, otherwise the page will freeze waiting
20/// for the dialog to be handled.
21///
22/// See module-level documentation for usage examples.
23///
24/// See: <https://playwright.dev/docs/api/class-dialog>
25#[derive(Clone)]
26pub struct Dialog {
27 base: ChannelOwnerImpl,
28}
29
30impl Dialog {
31 /// Creates a new Dialog from protocol initialization
32 ///
33 /// This is called by the object factory when the server sends a `__create__` message
34 /// for a Dialog object.
35 pub fn new(
36 parent: Arc<dyn ChannelOwner>,
37 type_name: String,
38 guid: Arc<str>,
39 initializer: Value,
40 ) -> Result<Self> {
41 let base = ChannelOwnerImpl::new(
42 ParentOrConnection::Parent(parent),
43 type_name,
44 guid,
45 initializer,
46 );
47
48 Ok(Self { base })
49 }
50
51 /// Returns the dialog's type.
52 ///
53 /// Returns one of:
54 /// - "alert" - Simple notification dialog
55 /// - "confirm" - Yes/No confirmation dialog
56 /// - "prompt" - Text input dialog
57 /// - "beforeunload" - Page unload confirmation dialog
58 ///
59 /// See: <https://playwright.dev/docs/api/class-dialog#dialog-type>
60 pub fn type_(&self) -> &str {
61 self.initializer()
62 .get("type")
63 .and_then(|v| v.as_str())
64 .unwrap_or("")
65 }
66
67 /// Returns the message displayed in the dialog.
68 ///
69 /// See: <https://playwright.dev/docs/api/class-dialog#dialog-message>
70 pub fn message(&self) -> &str {
71 self.initializer()
72 .get("message")
73 .and_then(|v| v.as_str())
74 .unwrap_or("")
75 }
76
77 /// Returns the default value for prompt dialogs.
78 ///
79 /// For prompt dialogs, returns the default input value.
80 /// For other dialog types (alert, confirm, beforeunload), returns an empty string.
81 ///
82 /// See: <https://playwright.dev/docs/api/class-dialog#dialog-default-value>
83 pub fn default_value(&self) -> &str {
84 self.initializer()
85 .get("defaultValue")
86 .and_then(|v| v.as_str())
87 .unwrap_or("")
88 }
89
90 /// Returns the [`Page`](crate::protocol::Page) that owns this dialog.
91 ///
92 /// The dialog's parent in the protocol object hierarchy is the Page.
93 ///
94 /// See: <https://playwright.dev/docs/api/class-dialog#dialog-page>
95 pub fn page(&self) -> Option<crate::protocol::Page> {
96 downcast_parent::<crate::protocol::Page>(self)
97 }
98
99 /// Accepts the dialog.
100 ///
101 /// For prompt dialogs, optionally provides text input.
102 /// For other dialog types, the promptText parameter is ignored.
103 ///
104 /// # Arguments
105 ///
106 /// * `prompt_text` - Optional text to enter in a prompt dialog
107 ///
108 /// # Errors
109 ///
110 /// Returns error if:
111 /// - Dialog has already been accepted or dismissed
112 /// - Communication with browser process fails
113 ///
114 /// See: <https://playwright.dev/docs/api/class-dialog#dialog-accept>
115 pub async fn accept(&self, prompt_text: Option<&str>) -> Result<()> {
116 let params = if let Some(text) = prompt_text {
117 json!({ "promptText": text })
118 } else {
119 json!({})
120 };
121
122 self.channel().send_no_result("accept", params).await?;
123
124 Ok(())
125 }
126
127 /// Dismisses the dialog.
128 ///
129 /// For confirm dialogs, this is equivalent to clicking "Cancel".
130 /// For prompt dialogs, this is equivalent to clicking "Cancel".
131 ///
132 /// # Errors
133 ///
134 /// Returns error if:
135 /// - Dialog has already been accepted or dismissed
136 /// - Communication with browser process fails
137 ///
138 /// See: <https://playwright.dev/docs/api/class-dialog#dialog-dismiss>
139 pub async fn dismiss(&self) -> Result<()> {
140 self.channel().send_no_result("dismiss", json!({})).await?;
141
142 Ok(())
143 }
144}
145
146impl ChannelOwner for Dialog {
147 fn guid(&self) -> &str {
148 self.base.guid()
149 }
150
151 fn type_name(&self) -> &str {
152 self.base.type_name()
153 }
154
155 fn parent(&self) -> Option<Arc<dyn ChannelOwner>> {
156 self.base.parent()
157 }
158
159 fn connection(&self) -> Arc<dyn crate::server::connection::ConnectionLike> {
160 self.base.connection()
161 }
162
163 fn initializer(&self) -> &Value {
164 self.base.initializer()
165 }
166
167 fn channel(&self) -> &crate::server::channel::Channel {
168 self.base.channel()
169 }
170
171 fn dispose(&self, reason: crate::server::channel_owner::DisposeReason) {
172 self.base.dispose(reason)
173 }
174
175 fn adopt(&self, child: Arc<dyn ChannelOwner>) {
176 self.base.adopt(child)
177 }
178
179 fn add_child(&self, guid: Arc<str>, child: Arc<dyn ChannelOwner>) {
180 self.base.add_child(guid, child)
181 }
182
183 fn remove_child(&self, guid: &str) {
184 self.base.remove_child(guid)
185 }
186
187 fn on_event(&self, _method: &str, _params: Value) {
188 // Dialog doesn't emit events
189 }
190
191 fn was_collected(&self) -> bool {
192 self.base.was_collected()
193 }
194
195 fn as_any(&self) -> &dyn Any {
196 self
197 }
198}
199
200impl std::fmt::Debug for Dialog {
201 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
202 f.debug_struct("Dialog")
203 .field("guid", &self.guid())
204 .field("type", &self.type_())
205 .field("message", &self.message())
206 .field("default_value", &self.default_value())
207 .finish()
208 }
209}