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}