Skip to main content

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    #[tracing::instrument(level = "debug", skip_all, fields(guid = %self.guid()))]
116    pub async fn accept(&self, prompt_text: Option<&str>) -> Result<()> {
117        let params = if let Some(text) = prompt_text {
118            json!({ "promptText": text })
119        } else {
120            json!({})
121        };
122
123        self.channel().send_no_result("accept", params).await?;
124
125        Ok(())
126    }
127
128    /// Dismisses the dialog.
129    ///
130    /// For confirm dialogs, this is equivalent to clicking "Cancel".
131    /// For prompt dialogs, this is equivalent to clicking "Cancel".
132    ///
133    /// # Errors
134    ///
135    /// Returns error if:
136    /// - Dialog has already been accepted or dismissed
137    /// - Communication with browser process fails
138    ///
139    /// See: <https://playwright.dev/docs/api/class-dialog#dialog-dismiss>
140    #[tracing::instrument(level = "debug", skip_all, fields(guid = %self.guid()))]
141    pub async fn dismiss(&self) -> Result<()> {
142        self.channel().send_no_result("dismiss", json!({})).await?;
143
144        Ok(())
145    }
146}
147
148impl ChannelOwner for Dialog {
149    fn guid(&self) -> &str {
150        self.base.guid()
151    }
152
153    fn type_name(&self) -> &str {
154        self.base.type_name()
155    }
156
157    fn parent(&self) -> Option<Arc<dyn ChannelOwner>> {
158        self.base.parent()
159    }
160
161    fn connection(&self) -> Arc<dyn crate::server::connection::ConnectionLike> {
162        self.base.connection()
163    }
164
165    fn initializer(&self) -> &Value {
166        self.base.initializer()
167    }
168
169    fn channel(&self) -> &crate::server::channel::Channel {
170        self.base.channel()
171    }
172
173    fn dispose(&self, reason: crate::server::channel_owner::DisposeReason) {
174        self.base.dispose(reason)
175    }
176
177    fn adopt(&self, child: Arc<dyn ChannelOwner>) {
178        self.base.adopt(child)
179    }
180
181    fn add_child(&self, guid: Arc<str>, child: Arc<dyn ChannelOwner>) {
182        self.base.add_child(guid, child)
183    }
184
185    fn remove_child(&self, guid: &str) {
186        self.base.remove_child(guid)
187    }
188
189    fn on_event(&self, _method: &str, _params: Value) {
190        // Dialog doesn't emit events
191    }
192
193    fn was_collected(&self) -> bool {
194        self.base.was_collected()
195    }
196
197    fn as_any(&self) -> &dyn Any {
198        self
199    }
200}
201
202impl std::fmt::Debug for Dialog {
203    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
204        f.debug_struct("Dialog")
205            .field("guid", &self.guid())
206            .field("type", &self.type_())
207            .field("message", &self.message())
208            .field("default_value", &self.default_value())
209            .finish()
210    }
211}