Skip to main content

playwright_rs/protocol/
web_storage.rs

1//! WebStorage: per-origin `localStorage` / `sessionStorage` access.
2//!
3//! Obtained via [`Page::local_storage`](crate::protocol::Page::local_storage) /
4//! [`Page::session_storage`](crate::protocol::Page::session_storage). Reads and
5//! writes the current origin's storage directly through the Page channel (not via
6//! `page.evaluate`), matching playwright-python's `WebStorage`.
7//!
8//! ```no_run
9//! # use playwright_rs::Playwright;
10//! # async fn ex() -> playwright_rs::Result<()> {
11//! # let pw = Playwright::launch().await?;
12//! # let browser = pw.chromium().launch().await?;
13//! # let page = browser.new_page().await?;
14//! page.goto("https://example.com", None).await?;
15//! let storage = page.local_storage();
16//! storage.set_item("token", "abc123").await?;
17//! assert_eq!(storage.get_item("token").await?, Some("abc123".to_string()));
18//! # Ok(())
19//! # }
20//! ```
21//!
22//! See: <https://playwright.dev/docs/api/class-webstorage>
23
24use crate::error::Result;
25use crate::server::channel::Channel;
26use serde_json::json;
27
28/// Which storage area a [`WebStorage`] handle targets.
29#[derive(Debug, Clone, Copy, PartialEq, Eq)]
30pub enum WebStorageKind {
31    /// `window.localStorage` — persists across sessions for the origin.
32    Local,
33    /// `window.sessionStorage` — cleared when the tab/context closes.
34    Session,
35}
36
37impl WebStorageKind {
38    pub(crate) fn as_str(self) -> &'static str {
39        match self {
40            WebStorageKind::Local => "local",
41            WebStorageKind::Session => "session",
42        }
43    }
44}
45
46/// Read/write access to a page's `localStorage` or `sessionStorage` for the
47/// current origin.
48///
49/// Obtained from [`Page::local_storage`](crate::protocol::Page::local_storage)
50/// and [`Page::session_storage`](crate::protocol::Page::session_storage).
51///
52/// See: <https://playwright.dev/docs/api/class-webstorage>
53#[derive(Clone)]
54pub struct WebStorage {
55    channel: Channel,
56    kind: WebStorageKind,
57}
58
59impl std::fmt::Debug for WebStorage {
60    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
61        f.debug_struct("WebStorage")
62            .field("kind", &self.kind)
63            .finish_non_exhaustive()
64    }
65}
66
67impl WebStorage {
68    pub(crate) fn new(channel: Channel, kind: WebStorageKind) -> Self {
69        Self { channel, kind }
70    }
71
72    /// Returns the value for `name`, or `None` if the key is not set.
73    ///
74    /// # Errors
75    ///
76    /// Returns error if:
77    /// - The page has been closed
78    /// - Communication with the browser process fails
79    ///
80    /// See: <https://playwright.dev/docs/api/class-webstorage#web-storage-get-item>
81    pub async fn get_item(&self, name: &str) -> Result<Option<String>> {
82        #[derive(serde::Deserialize)]
83        struct R {
84            #[serde(default)]
85            value: Option<String>,
86        }
87        let r: R = self
88            .channel
89            .send(
90                "webStorageGetItem",
91                json!({ "kind": self.kind.as_str(), "name": name }),
92            )
93            .await?;
94        Ok(r.value)
95    }
96
97    /// Sets `name` to `value`.
98    ///
99    /// # Errors
100    ///
101    /// Returns error if:
102    /// - The page has been closed
103    /// - Communication with the browser process fails
104    ///
105    /// See: <https://playwright.dev/docs/api/class-webstorage#web-storage-set-item>
106    pub async fn set_item(&self, name: &str, value: &str) -> Result<()> {
107        self.channel
108            .send_no_result(
109                "webStorageSetItem",
110                json!({ "kind": self.kind.as_str(), "name": name, "value": value }),
111            )
112            .await
113    }
114
115    /// Removes `name` from storage (no-op if absent).
116    ///
117    /// # Errors
118    ///
119    /// Returns error if:
120    /// - The page has been closed
121    /// - Communication with the browser process fails
122    ///
123    /// See: <https://playwright.dev/docs/api/class-webstorage#web-storage-remove-item>
124    pub async fn remove_item(&self, name: &str) -> Result<()> {
125        self.channel
126            .send_no_result(
127                "webStorageRemoveItem",
128                json!({ "kind": self.kind.as_str(), "name": name }),
129            )
130            .await
131    }
132
133    /// Removes all entries from this storage area.
134    ///
135    /// # Errors
136    ///
137    /// Returns error if:
138    /// - The page has been closed
139    /// - Communication with the browser process fails
140    ///
141    /// See: <https://playwright.dev/docs/api/class-webstorage#web-storage-clear>
142    pub async fn clear(&self) -> Result<()> {
143        self.channel
144            .send_no_result("webStorageClear", json!({ "kind": self.kind.as_str() }))
145            .await
146    }
147
148    /// Returns all `(name, value)` entries currently in this storage area.
149    ///
150    /// # Errors
151    ///
152    /// Returns error if:
153    /// - The page has been closed
154    /// - Communication with the browser process fails
155    ///
156    /// See: <https://playwright.dev/docs/api/class-webstorage#web-storage-items>
157    pub async fn items(&self) -> Result<Vec<(String, String)>> {
158        #[derive(serde::Deserialize)]
159        struct Item {
160            name: String,
161            value: String,
162        }
163        #[derive(serde::Deserialize)]
164        struct R {
165            items: Vec<Item>,
166        }
167        let r: R = self
168            .channel
169            .send("webStorageItems", json!({ "kind": self.kind.as_str() }))
170            .await?;
171        Ok(r.items.into_iter().map(|i| (i.name, i.value)).collect())
172    }
173}
174
175#[cfg(test)]
176mod tests {
177    use super::WebStorageKind;
178
179    #[test]
180    fn kind_as_str_maps_each_variant() {
181        assert_eq!(WebStorageKind::Local.as_str(), "local");
182        assert_eq!(WebStorageKind::Session.as_str(), "session");
183    }
184}