playwright/api/
js_handle.rs

1use crate::imp::{core::*, js_handle::JsHandle as Impl, prelude::*};
2use std::fmt;
3
4/// JsHandle represents an in-page JavaScript object. JsHandles can be created with the [`method: Page.evaluateHandle`]
5/// method.
6///
7/// ```js
8/// const windowHandle = await page.evaluateHandle(() => window);
9///// ...
10/// ```
11/// 
12/// JsHandle prevents the referenced JavaScript object being garbage collected unless the handle is exposed with
13/// [`method: JsHandle.dispose`]. JsHandles are auto-disposed when their origin frame gets navigated or the parent context
14/// gets destroyed.
15///
16/// JsHandle instances can be used as an argument in [`method: Page.evalOnSelector`], [`method: Page.evaluate`] and
17/// [`method: Page.evaluateHandle`] methods.
18pub struct JsHandle {
19    inner: Weak<Impl>
20}
21
22impl PartialEq for JsHandle {
23    fn eq(&self, other: &Self) -> bool {
24        let a = self.inner.upgrade();
25        let b = other.inner.upgrade();
26        a.and_then(|a| b.map(|b| (a, b)))
27            .map(|(a, b)| a.guid() == b.guid())
28            .unwrap_or_default()
29    }
30}
31
32impl JsHandle {
33    pub(crate) fn new(inner: Weak<Impl>) -> Self { Self { inner } }
34
35    pub(crate) fn guid(&self) -> Result<Str<Guid>, Error> {
36        Ok(upgrade(&self.inner)?.guid().to_owned())
37    }
38
39    /// Fetches a single property from the referenced object.
40    pub async fn get_property(&mut self, name: &str) -> ArcResult<JsHandle> {
41        upgrade(&self.inner)?
42            .get_property(name)
43            .await
44            .map(JsHandle::new)
45    }
46
47    /// The method returns a map with **own property names** as keys and JsHandle instances for the property values.
48    ///
49    /// ```js
50    /// const handle = await page.evaluateHandle(() => ({window, document}));
51    /// const properties = await handle.getProperties();
52    /// const windowHandle = properties.get('window');
53    /// const documentHandle = properties.get('document');
54    /// await handle.dispose();
55    /// ```
56    pub async fn get_properties(&mut self) -> ArcResult<HashMap<String, JsHandle>> {
57        let m = upgrade(&self.inner)?.get_properties().await?;
58        Ok(m.into_iter().map(|(k, v)| (k, JsHandle::new(v))).collect())
59    }
60
61    pub async fn dispose(&mut self) -> ArcResult<()> { upgrade(&self.inner)?.dispose().await }
62
63    /// Returns a JSON representation of the object. If the object has a `toJSON` function, it **will not be called**.
64    ///
65    /// > NOTE: The method will return an empty JSON object if the referenced object is not stringifiable. It will throw an
66    /// error if the object has circular references.
67    pub async fn json_value<U>(&mut self) -> ArcResult<U>
68    where
69        U: DeserializeOwned
70    {
71        upgrade(&self.inner)?.json_value().await
72    }
73
74    // evaluate
75}
76
77impl fmt::Display for JsHandle {
78    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
79        if let Some(inner) = self.inner.upgrade() {
80            inner.fmt(f)
81        } else {
82            write!(f, "")
83        }
84    }
85}
86
87mod ser {
88    use super::*;
89    use serde::{ser, ser::SerializeStruct};
90
91    impl Serialize for JsHandle {
92        fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
93        where
94            S: ser::Serializer
95        {
96            let mut s = serializer.serialize_struct("4a9c3811-6f00-49e5-8a81-939f932d9061", 1)?;
97            let guid = &self.guid().map_err(<S::Error as ser::Error>::custom)?;
98            s.serialize_field("guid", &guid)?;
99            s.end()
100        }
101    }
102}