firefox_webdriver/browser/tab/
core.rs

1//! Core Tab struct and accessors.
2
3use std::fmt;
4use std::sync::Arc;
5
6use crate::error::{Error, Result};
7use crate::identifiers::{FrameId, SessionId, TabId};
8use crate::protocol::{Command, Request, Response};
9
10use crate::browser::Window;
11
12// ============================================================================
13// Types
14// ============================================================================
15
16/// Information about a frame in the tab.
17#[derive(Debug, Clone)]
18pub struct FrameInfo {
19    /// Frame ID.
20    pub frame_id: FrameId,
21    /// Parent frame ID (None for main frame).
22    pub parent_frame_id: Option<FrameId>,
23    /// Frame URL.
24    pub url: String,
25}
26
27/// Internal shared state for a tab.
28pub(crate) struct TabInner {
29    /// Tab ID.
30    pub tab_id: TabId,
31    /// Current frame ID.
32    pub frame_id: FrameId,
33    /// Session ID.
34    pub session_id: SessionId,
35    /// Parent window (optional for standalone tab references).
36    pub window: Option<Window>,
37}
38
39// ============================================================================
40// Tab
41// ============================================================================
42
43/// A handle to a browser tab.
44///
45/// Tabs provide methods for navigation, scripting, and element interaction.
46#[derive(Clone)]
47pub struct Tab {
48    pub(crate) inner: Arc<TabInner>,
49}
50
51impl fmt::Debug for Tab {
52    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
53        f.debug_struct("Tab")
54            .field("tab_id", &self.inner.tab_id)
55            .field("frame_id", &self.inner.frame_id)
56            .field("session_id", &self.inner.session_id)
57            .finish_non_exhaustive()
58    }
59}
60
61impl Tab {
62    /// Creates a new tab handle.
63    pub(crate) fn new(
64        tab_id: TabId,
65        frame_id: FrameId,
66        session_id: SessionId,
67        window: Option<Window>,
68    ) -> Self {
69        Self {
70            inner: Arc::new(TabInner {
71                tab_id,
72                frame_id,
73                session_id,
74                window,
75            }),
76        }
77    }
78}
79
80// ============================================================================
81// Tab - Accessors
82// ============================================================================
83
84impl Tab {
85    /// Returns the tab ID.
86    #[inline]
87    #[must_use]
88    pub fn tab_id(&self) -> TabId {
89        self.inner.tab_id
90    }
91
92    /// Returns the current frame ID.
93    #[inline]
94    #[must_use]
95    pub fn frame_id(&self) -> FrameId {
96        self.inner.frame_id
97    }
98
99    /// Returns the session ID.
100    #[inline]
101    #[must_use]
102    pub fn session_id(&self) -> SessionId {
103        self.inner.session_id
104    }
105
106    /// Checks if currently in the main frame.
107    #[inline]
108    #[must_use]
109    pub fn is_main_frame(&self) -> bool {
110        self.inner.frame_id.is_main()
111    }
112}
113
114// ============================================================================
115// Tab - Internal
116// ============================================================================
117
118impl Tab {
119    /// Sends a command and returns the response.
120    pub(crate) async fn send_command(&self, command: Command) -> Result<Response> {
121        let window = self.get_window()?;
122        let request = Request::new(self.inner.tab_id, self.inner.frame_id, command);
123        window
124            .inner
125            .pool
126            .send(window.inner.session_id, request)
127            .await
128    }
129
130    /// Gets the window reference or returns an error.
131    pub(crate) fn get_window(&self) -> Result<&Window> {
132        self.inner
133            .window
134            .as_ref()
135            .ok_or_else(|| Error::protocol("Tab has no associated window"))
136    }
137}
138
139// ============================================================================
140// Tests
141// ============================================================================
142
143#[cfg(test)]
144mod tests {
145    use super::Tab;
146
147    #[test]
148    fn test_tab_is_clone() {
149        fn assert_clone<T: Clone>() {}
150        assert_clone::<Tab>();
151    }
152
153    #[test]
154    fn test_tab_is_debug() {
155        fn assert_debug<T: std::fmt::Debug>() {}
156        assert_debug::<Tab>();
157    }
158}