playwright/api/
browser_context.rs

1pub use crate::imp::browser_context::EventType;
2use crate::{
3    api::{Browser, Page},
4    imp::{
5        browser_context::{BrowserContext as Impl, Evt},
6        core::*,
7        prelude::*,
8        utils::{Cookie, Geolocation, StorageState}
9    },
10    Error
11};
12
13/// BrowserContexts provide a way to operate multiple independent browser sessions.
14///
15/// If a page opens another page, e.g. with a `window.open` call, the popup will belong to the parent page's browser
16/// context.
17///
18/// Playwright allows creation of "incognito" browser contexts with `browser.newContext()` method. "Incognito" browser
19/// contexts don't write any browsing data to disk.
20#[derive(Debug)]
21pub struct BrowserContext {
22    inner: Weak<Impl>
23}
24
25impl PartialEq for BrowserContext {
26    fn eq(&self, other: &Self) -> bool {
27        let a = self.inner.upgrade();
28        let b = other.inner.upgrade();
29        a.and_then(|a| b.map(|b| (a, b)))
30            .map(|(a, b)| a.guid() == b.guid())
31            .unwrap_or_default()
32    }
33}
34
35impl BrowserContext {
36    pub(crate) fn new(inner: Weak<Impl>) -> Self { Self { inner } }
37
38    /// Returns all open pages in the context.
39    pub fn pages(&self) -> Result<Vec<Page>, Error> {
40        Ok(upgrade(&self.inner)?
41            .pages()
42            .iter()
43            .cloned()
44            .map(Page::new)
45            .collect())
46    }
47
48    /// Returns the browser instance of the context. If it was launched as a persistent context None gets returned.
49    pub fn browser(&self) -> Result<Option<Browser>, Error> {
50        Ok(upgrade(&self.inner)?.browser().map(Browser::new))
51    }
52
53    /// Creates a new page in the browser context.
54    pub async fn new_page(&self) -> Result<Page, Arc<Error>> {
55        let inner = upgrade(&self.inner)?;
56        Ok(Page::new(inner.new_page().await?))
57    }
58
59    pub async fn set_default_navigation_timeout(&self, timeout: u32) -> ArcResult<()> {
60        upgrade(&self.inner)?
61            .set_default_navigation_timeout(timeout)
62            .await
63    }
64
65    pub async fn set_default_timeout(&self, timeout: u32) -> ArcResult<()> {
66        upgrade(&self.inner)?.set_default_timeout(timeout).await
67    }
68
69    /// If no URLs are specified, this method returns all cookies. If URLs are specified, only cookies that affect those URLs
70    /// are returned.
71    pub async fn cookies(&self, urls: &[String]) -> ArcResult<Vec<Cookie>> {
72        upgrade(&self.inner)?.cookies(urls).await
73    }
74
75    /// Adds cookies into this browser context. All pages within this context will have these cookies installed.
76    pub async fn add_cookies(&self, cookies: &[Cookie]) -> ArcResult<()> {
77        upgrade(&self.inner)?.add_cookies(cookies).await
78    }
79
80    /// Clears context cookies.
81    pub async fn clear_cookies(&self) -> ArcResult<()> {
82        upgrade(&self.inner)?.clear_cookies().await
83    }
84
85    /// Grants specified permissions to the browser context. Only grants corresponding permissions to the given origin if
86    /// specified.
87    ///
88    /// ```js
89    /// const context = await browser.newContext();
90    /// await context.grantPermissions(['clipboard-read']);
91    /// context.clearPermissions();
92    /// ```
93    /// # Args
94    /// ## permissions
95    /// A permission or an array of permissions to grant. Permissions can be one of the following values:
96    /// - `'geolocation'`
97    /// - `'midi'`
98    /// - `'midi-sysex'` (system-exclusive midi)
99    /// - `'notifications'`
100    /// - `'push'`
101    /// - `'camera'`
102    /// - `'microphone'`
103    /// - `'background-sync'`
104    /// - `'ambient-light-sensor'`
105    /// - `'accelerometer'`
106    /// - `'gyroscope'`
107    /// - `'magnetometer'`
108    /// - `'accessibility-events'`
109    /// - `'clipboard-read'`
110    /// - `'clipboard-write'`
111    /// - `'payment-handler'`
112    /// ## origin
113    /// The origin to grant permissions to, e.g. `"https://example.com"`.
114    pub async fn grant_permissions(
115        &self,
116        permissions: &[String],
117        origin: Option<&str>
118    ) -> ArcResult<()> {
119        upgrade(&self.inner)?
120            .grant_permissions(permissions, origin)
121            .await
122    }
123
124    /// Clears all permission overrides for the browser context.
125    pub async fn clear_permissions(&self) -> ArcResult<()> {
126        upgrade(&self.inner)?.clear_permissions().await
127    }
128
129    /// Sets the context's geolocation. Passing `null` or `undefined` emulates position unavailable.
130    ///
131    /// ```js
132    /// await browserContext.setGeolocation({latitude: 59.95, longitude: 30.31667});
133    /// ```
134    /// > NOTE: Consider using [`method: BrowserContext.grantPermissions`] to grant permissions for the browser context pages to
135    /// read its geolocation.
136    pub async fn set_geolocation(&self, geolocation: Option<&Geolocation>) -> ArcResult<()> {
137        upgrade(&self.inner)?.set_geolocation(geolocation).await
138    }
139
140    /// Sets whether to emulate network being offline for the browser context.
141    pub async fn set_offline(&self, offline: bool) -> ArcResult<()> {
142        upgrade(&self.inner)?.set_offline(offline).await
143    }
144
145    /// Adds a script which would be evaluated in one of the following scenarios:
146    /// - Whenever a page is created in the browser context or is navigated.
147    /// - Whenever a child frame is attached or navigated in any page in the browser context. In this case, the script is
148    ///  evaluated in the context of the newly attached frame.
149    ///
150    /// The script is evaluated after the document was created but before any of its scripts were run. This is useful to amend
151    /// the JavaScript environment, e.g. to seed `Math.random`.
152    ///
153    /// An example of overriding `Math.random` before the page loads:
154    ///
155    /// ```js browser
156    ///// preload.js
157    /// Math.random = () => 42;
158    /// ```
159    /// ```js
160    ///// In your playwright script, assuming the preload.js file is in same directory.
161    /// await browserContext.addInitScript({
162    ///  path: 'preload.js'
163    /// });
164    /// ```
165    /// > NOTE: The order of evaluation of multiple scripts installed via [`method: BrowserContext.addInitScript`] and
166    /// [`method: Page.addInitScript`] is not defined.
167    pub async fn add_init_script(&self, script: &str) -> ArcResult<()> {
168        // arg not supported
169        upgrade(&self.inner)?.add_init_script(script).await
170    }
171
172    /// The extra HTTP headers will be sent with every request initiated by any page in the context. These headers are merged
173    /// with page-specific extra HTTP headers set with [`method: Page.setExtraHTTPHeaders`]. If page overrides a particular
174    /// header, page-specific header value will be used instead of the browser context header value.
175    ///
176    /// > NOTE: [`method: BrowserContext.setExtraHTTPHeaders`] does not guarantee the order of headers in the outgoing requests.
177    pub async fn set_extra_http_headers<T>(&self, headers: T) -> ArcResult<()>
178    where
179        T: IntoIterator<Item = (String, String)>
180    {
181        upgrade(&self.inner)?.set_extra_http_headers(headers).await
182    }
183
184    // async fn expose_binding(&mut self) -> Result<(), Error> { unimplemented!() }
185
186    // async fn expose_function(&mut self) -> Result<(), Error> { unimplemented!() }
187
188    // async fn route(&mut self) -> Result<(), Error> { unimplemented!() }
189
190    // async fn unroute(&mut self) -> Result<(), Error> { unimplemented!() }
191
192    pub async fn expect_event(&self, evt: EventType) -> Result<Event, Error> {
193        let stream = upgrade(&self.inner)?.subscribe_event();
194        let timeout = upgrade(&self.inner)?.default_timeout();
195        expect_event(stream, evt, timeout).await.map(Event::from)
196    }
197
198    /// Returns storage state for this browser context, contains current cookies and local storage snapshot.
199    pub async fn storage_state(&self) -> ArcResult<StorageState> {
200        // path no supported
201        upgrade(&self.inner)?.storage_state().await
202    }
203
204    /// All temporary browsers will be closed when the connection is terminated, but
205    /// this struct has no Drop. it needs to be called explicitly to close it at any given time.
206    /// > NOTE: The default browser context cannot be closed.
207    pub async fn close(&self) -> ArcResult<()> {
208        let inner = match self.inner.upgrade() {
209            None => return Ok(()),
210            Some(inner) => inner
211        };
212        inner.close().await
213    }
214
215    subscribe_event! {}
216
217    // background_page for chromium
218    // new_cdp_session
219    // service_workers
220}
221
222#[derive(Debug, PartialEq)]
223pub enum Event {
224    // BackgroundPage for chromium persistent
225    // ServiceWorker
226    /// Emitted when Browser context gets closed. This might happen because of one of the following:
227    /// - Browser context is closed.
228    /// - Browser application is closed or crashed.
229    /// - The [`method: Browser.close`] method was called.
230    Close,
231    /// The event is emitted when a new Page is created in the BrowserContext. The page may still be loading. The event will
232    /// also fire for popup pages. See also [`event: Page.popup`] to receive events about popups relevant to a specific page.
233    ///
234    /// The earliest moment that page is available is when it has navigated to the initial url. For example, when opening a
235    /// popup with `window.open('http://example.com')`, this event will fire when the network request to <http://example.com> is
236    /// done and its response has started loading in the popup.
237    ///
238    /// ```js
239    /// const [newPage] = await Promise.all([
240    ///  context.waitForEvent('page'),
241    ///  page.click('a[target=_blank]'),
242    /// ]);
243    /// console.log(await newPage.evaluate('location.href'));
244    /// ```
245    Page(Page)
246}
247
248impl From<Evt> for Event {
249    fn from(e: Evt) -> Event {
250        match e {
251            Evt::Close => Event::Close,
252            Evt::Page(w) => Event::Page(Page::new(w))
253        }
254    }
255}