playwright_rs/protocol/
element_handle.rs1use crate::error::Result;
7use crate::protocol::locator::BoundingBox;
8use crate::server::channel_owner::{ChannelOwner, ChannelOwnerImpl, ParentOrConnection};
9use base64::Engine;
10use serde::Deserialize;
11use serde_json::Value;
12use std::any::Any;
13use std::sync::Arc;
14
15#[derive(Clone)]
22pub struct ElementHandle {
23 base: ChannelOwnerImpl,
24}
25
26impl ElementHandle {
27 pub fn new(
32 parent: Arc<dyn ChannelOwner>,
33 type_name: String,
34 guid: Arc<str>,
35 initializer: Value,
36 ) -> Result<Self> {
37 let base = ChannelOwnerImpl::new(
38 ParentOrConnection::Parent(parent),
39 type_name,
40 guid,
41 initializer,
42 );
43
44 Ok(Self { base })
45 }
46
47 pub async fn screenshot(
70 &self,
71 options: Option<crate::protocol::ScreenshotOptions>,
72 ) -> Result<Vec<u8>> {
73 let params = if let Some(opts) = options {
74 opts.to_json()
75 } else {
76 serde_json::json!({
78 "type": "png",
79 "timeout": crate::DEFAULT_TIMEOUT_MS
80 })
81 };
82
83 #[derive(Deserialize)]
84 struct ScreenshotResponse {
85 binary: String,
86 }
87
88 let response: ScreenshotResponse = self.base.channel().send("screenshot", params).await?;
89
90 let bytes = base64::prelude::BASE64_STANDARD
92 .decode(&response.binary)
93 .map_err(|e| {
94 crate::error::Error::ProtocolError(format!(
95 "Failed to decode element screenshot: {}",
96 e
97 ))
98 })?;
99
100 Ok(bytes)
101 }
102
103 pub async fn bounding_box(&self) -> Result<Option<BoundingBox>> {
109 #[derive(Deserialize)]
110 struct BoundingBoxResponse {
111 value: Option<BoundingBox>,
112 }
113
114 let response: BoundingBoxResponse = self
115 .base
116 .channel()
117 .send(
118 "boundingBox",
119 serde_json::json!({
120 "timeout": crate::DEFAULT_TIMEOUT_MS
121 }),
122 )
123 .await?;
124
125 Ok(response.value)
126 }
127
128 pub async fn scroll_into_view_if_needed(&self) -> Result<()> {
132 self.base
133 .channel()
134 .send_no_result(
135 "scrollIntoViewIfNeeded",
136 serde_json::json!({
137 "timeout": crate::DEFAULT_TIMEOUT_MS
138 }),
139 )
140 .await
141 }
142}
143
144impl ChannelOwner for ElementHandle {
145 fn guid(&self) -> &str {
146 self.base.guid()
147 }
148
149 fn type_name(&self) -> &str {
150 self.base.type_name()
151 }
152
153 fn parent(&self) -> Option<Arc<dyn ChannelOwner>> {
154 self.base.parent()
155 }
156
157 fn connection(&self) -> Arc<dyn crate::server::connection::ConnectionLike> {
158 self.base.connection()
159 }
160
161 fn initializer(&self) -> &Value {
162 self.base.initializer()
163 }
164
165 fn channel(&self) -> &crate::server::channel::Channel {
166 self.base.channel()
167 }
168
169 fn dispose(&self, reason: crate::server::channel_owner::DisposeReason) {
170 self.base.dispose(reason)
171 }
172
173 fn adopt(&self, child: Arc<dyn ChannelOwner>) {
174 self.base.adopt(child)
175 }
176
177 fn add_child(&self, guid: Arc<str>, child: Arc<dyn ChannelOwner>) {
178 self.base.add_child(guid, child)
179 }
180
181 fn remove_child(&self, guid: &str) {
182 self.base.remove_child(guid)
183 }
184
185 fn on_event(&self, _method: &str, _params: Value) {
186 }
188
189 fn was_collected(&self) -> bool {
190 self.base.was_collected()
191 }
192
193 fn as_any(&self) -> &dyn Any {
194 self
195 }
196}
197
198impl std::fmt::Debug for ElementHandle {
199 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
200 f.debug_struct("ElementHandle")
201 .field("guid", &self.guid())
202 .finish()
203 }
204}