1use crate::element_handle::ElementHandle;
4use crate::error::{Error, Result};
5use crate::options::{GotoOptions, WaitUntil};
6use crate::page::Page;
7use crate::response::Response;
8use crate::types::AriaRole;
9use serde_json::Value;
10
11#[derive(Clone)]
13pub struct Frame {
14 page: Page,
15 frame_id: String,
16}
17
18impl Frame {
19 pub(crate) fn new(page: Page, frame_id: String) -> Self {
20 Self { page, frame_id }
21 }
22
23 pub(crate) fn main(page: Page) -> Self {
24 let frame_id = page.main_frame_id().unwrap_or_default();
25 Self { page, frame_id }
26 }
27
28 pub fn page(&self) -> Page {
30 self.page.clone()
31 }
32
33 pub fn frame_id(&self) -> &str {
35 &self.frame_id
36 }
37
38 pub fn name(&self) -> String {
39 self.page
40 .frame_data(&self.frame_id)
41 .map(|d| d.name)
42 .unwrap_or_default()
43 }
44
45 pub fn url(&self) -> String {
46 self.page
47 .frame_data(&self.frame_id)
48 .map(|d| d.url)
49 .unwrap_or_default()
50 }
51
52 pub fn parent_frame(&self) -> Option<Frame> {
53 let parent = self.page.frame_data(&self.frame_id)?.parent_id.clone()?;
54 Some(Frame::new(self.page.clone(), parent))
55 }
56
57 pub fn child_frames(&self) -> Vec<Frame> {
58 self.page
59 .frame_ids_with_parent(&self.frame_id)
60 .into_iter()
61 .map(|id| Frame::new(self.page.clone(), id))
62 .collect()
63 }
64
65 pub fn is_detached(&self) -> bool {
66 self.page
67 .frame_data(&self.frame_id)
68 .map(|d| d.detached)
69 .unwrap_or(false)
70 }
71
72 pub async fn evaluate<R: serde::de::DeserializeOwned>(&self, expression: &str) -> Result<R> {
74 self.page.evaluate::<R>(expression).await
75 }
76
77 pub async fn goto(
79 &self,
80 url: &str,
81 opts: Option<GotoOptions>,
82 ) -> Result<Option<Response>> {
83 if self.frame_id != self.page.main_frame_id().unwrap_or_default() {
84 return Err(Error::InvalidArgument(
85 "Frame::goto on non-main frames is not supported".into(),
86 ));
87 }
88 self.page.goto(url, opts).await
89 }
90
91 pub async fn wait_for_load_state(&self, state: Option<WaitUntil>) -> Result<()> {
92 self.page.wait_for_load_state(state).await
93 }
94
95 pub async fn wait_for_function<R: serde::de::DeserializeOwned>(
98 &self,
99 expression: &str,
100 arg: Option<serde_json::Value>,
101 options: Option<crate::options::WaitForFunctionOptions>,
102 ) -> Result<R> {
103 self.page.wait_for_function(expression, arg, options).await
104 }
105
106 pub async fn content(&self) -> Result<String> {
107 self.page.content().await
108 }
109
110 pub async fn set_content(&self, html: &str) -> Result<()> {
111 self.page.set_content(html).await
112 }
113
114 pub async fn title(&self) -> Result<String> {
115 self.page.title().await
116 }
117
118 pub fn locator(&self, selector: impl Into<String>) -> crate::locator::Locator {
119 crate::locator::Locator::new(self.page.clone(), selector.into(), true, None)
120 }
121
122 pub fn get_by_text(&self, text: &str, exact: bool) -> crate::locator::Locator {
123 self.page.get_by_text(text, exact)
124 }
125
126 pub fn get_by_label(&self, text: &str) -> crate::locator::Locator {
127 self.page.get_by_label(text)
128 }
129
130 pub fn get_by_role(
131 &self,
132 role: AriaRole,
133 opts: Option<crate::options::GetByRoleOptions>,
134 ) -> crate::locator::Locator {
135 self.page.get_by_role(role, opts)
136 }
137
138 pub async fn query_selector(&self, selector: &str) -> Result<Option<ElementHandle>> {
140 self.page.query_selector(selector).await
141 }
142
143 pub async fn query_selector_all(&self, selector: &str) -> Result<Vec<ElementHandle>> {
145 self.page.query_selector_all(selector).await
146 }
147
148 #[allow(dead_code)]
150 fn _json_marker(&self) -> Value {
151 serde_json::json!({})
152 }
153}