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