playwright/api/playwright.rs
1pub use crate::imp::playwright::DeviceDescriptor;
2use crate::{
3 api::{browser_type::BrowserType, selectors::Selectors},
4 imp::{core::*, playwright::Playwright as Impl, prelude::*},
5 Error,
6};
7use std::{io, process::Command};
8
9/// Entry point
10pub struct Playwright {
11 driver: Driver,
12 _conn: Connection,
13 inner: Weak<Impl>,
14}
15
16fn run(driver: &Driver, args: &'static [&'static str]) -> io::Result<()> {
17 // For Playwright 1.50+, we run: node package/cli.js <args>
18 let cli_script = driver.cli_script();
19 let status = Command::new(driver.executable())
20 .arg(&cli_script)
21 .args(args)
22 .status()?;
23 if !status.success() {
24 return Err(io::Error::new(
25 io::ErrorKind::Other,
26 format!("Exit with {}", status),
27 ));
28 }
29 Ok(())
30}
31
32impl Playwright {
33 /// Installs the Playwright driver and initializes a new Playwright instance.
34 ///
35 /// This is the main entry point for using Playwright. It downloads and installs
36 /// the Playwright driver to the system's cache directory
37 /// (`$CACHE_DIR/.ms-playwright/playwright-rust/driver`) and establishes a connection
38 /// to the driver process.
39 ///
40 /// # Returns
41 ///
42 /// Returns a new `Playwright` instance if the driver installation and connection succeed,
43 /// or an `Error` if installation or connection fails.
44 ///
45 /// # Errors
46 ///
47 /// This function will return an error if:
48 /// - The driver installation fails (network issues, disk space, etc.)
49 /// - The connection to the driver process cannot be established
50 ///
51 /// # Examples
52 ///
53 /// Initialize Playwright and use it to launch a browser:
54 ///
55 /// ```
56 /// # async fn example() -> Result<(), Box<dyn std::error::Error>> {
57 /// use playwright::Playwright;
58 ///
59 /// let playwright = Playwright::initialize().await?;
60 /// let chromium = playwright.chromium();
61 /// # Ok(())
62 /// # }
63 /// ```
64 pub async fn initialize() -> Result<Playwright, Error> {
65 let driver = Driver::install()?;
66 Self::with_driver(driver).await
67 }
68
69 /// Constructs a new `Playwright` instance from an already-installed driver.
70 ///
71 /// Use this method when you have a custom `Driver` instance or want to use
72 /// an existing driver installation. This establishes a connection to the driver
73 /// process and initializes the Playwright object.
74 ///
75 /// # Arguments
76 ///
77 /// * `driver` - An installed Playwright driver instance
78 ///
79 /// # Returns
80 ///
81 /// Returns a new `Playwright` instance connected to the given driver, or an `Error`
82 /// if the connection cannot be established.
83 ///
84 /// # Errors
85 ///
86 /// This function will return an error if the connection to the driver process fails.
87 ///
88 /// # Examples
89 ///
90 /// ```
91 /// # async fn example() -> Result<(), playwright::Error> {
92 /// use playwright::{Playwright, Driver};
93 ///
94 /// let driver = Driver::install()?;
95 /// let playwright = Playwright::with_driver(driver).await?;
96 /// # Ok(())
97 /// # }
98 /// ```
99 pub async fn with_driver(driver: Driver) -> Result<Playwright, Error> {
100 let conn = Connection::run(&driver)?;
101 let p = Impl::wait_initial_object(&conn).await?;
102 Ok(Self {
103 driver,
104 _conn: conn,
105 inner: p,
106 })
107 }
108
109 /// Installs all Playwright browsers (Chromium, Firefox, and WebKit).
110 ///
111 /// This runs the equivalent of `playwright install` and downloads all supported
112 /// browser engines. It may take several minutes depending on your internet connection.
113 /// If you only need specific browsers, consider using [`install_chromium`](Self::install_chromium),
114 /// [`install_firefox`](Self::install_firefox), or [`install_webkit`](Self::install_webkit) instead.
115 ///
116 /// # Returns
117 ///
118 /// Returns `Ok(())` if installation succeeds, or an `io::Error` if it fails.
119 ///
120 /// # Examples
121 ///
122 /// ```
123 /// # async fn example() -> Result<(), Box<dyn std::error::Error>> {
124 /// # use playwright::Playwright;
125 /// # let playwright = Playwright::initialize().await?;
126 /// playwright.prepare()?;
127 /// # Ok(())
128 /// # }
129 /// ```
130 pub fn prepare(&self) -> io::Result<()> {
131 run(&self.driver, &["install"])
132 }
133
134 /// Installs the Chromium browser engine.
135 ///
136 /// This runs the equivalent of `playwright install chromium` and downloads
137 /// the Chromium browser engine. If you only need Chromium, use this instead
138 /// of [`prepare`](Self::prepare) to save disk space and download time.
139 ///
140 /// # Returns
141 ///
142 /// Returns `Ok(())` if installation succeeds, or an `io::Error` if it fails.
143 ///
144 /// # Examples
145 ///
146 /// ```
147 /// # async fn example() -> Result<(), Box<dyn std::error::Error>> {
148 /// # use playwright::Playwright;
149 /// # let playwright = Playwright::initialize().await?;
150 /// playwright.install_chromium()?;
151 /// # Ok(())
152 /// # }
153 /// ```
154 pub fn install_chromium(&self) -> io::Result<()> {
155 run(&self.driver, &["install", "chromium"])
156 }
157
158 /// Installs the Firefox browser engine.
159 ///
160 /// This runs the equivalent of `playwright install firefox` and downloads
161 /// the Firefox browser engine. If you only need Firefox, use this instead
162 /// of [`prepare`](Self::prepare) to save disk space and download time.
163 ///
164 /// # Returns
165 ///
166 /// Returns `Ok(())` if installation succeeds, or an `io::Error` if it fails.
167 ///
168 /// # Examples
169 ///
170 /// ```
171 /// # async fn example() -> Result<(), Box<dyn std::error::Error>> {
172 /// # use playwright::Playwright;
173 /// # let playwright = Playwright::initialize().await?;
174 /// playwright.install_firefox()?;
175 /// # Ok(())
176 /// # }
177 /// ```
178 pub fn install_firefox(&self) -> io::Result<()> {
179 run(&self.driver, &["install", "firefox"])
180 }
181
182 /// Installs the WebKit browser engine.
183 ///
184 /// This runs the equivalent of `playwright install webkit` and downloads
185 /// the WebKit browser engine. If you only need WebKit, use this instead
186 /// of [`prepare`](Self::prepare) to save disk space and download time.
187 ///
188 /// # Returns
189 ///
190 /// Returns `Ok(())` if installation succeeds, or an `io::Error` if it fails.
191 ///
192 /// # Examples
193 ///
194 /// ```
195 /// # async fn example() -> Result<(), Box<dyn std::error::Error>> {
196 /// # use playwright::Playwright;
197 /// # let playwright = Playwright::initialize().await?;
198 /// playwright.install_webkit()?;
199 /// # Ok(())
200 /// # }
201 /// ```
202 pub fn install_webkit(&self) -> io::Result<()> {
203 run(&self.driver, &["install", "webkit"])
204 }
205
206 /// Returns a launcher for the Chromium browser engine.
207 ///
208 /// # Returns
209 ///
210 /// A `BrowserType` instance that can be used to launch Chromium browsers.
211 ///
212 /// # Examples
213 ///
214 /// ```
215 /// # async fn example() -> Result<(), Box<dyn std::error::Error>> {
216 /// # use playwright::Playwright;
217 /// # let playwright = Playwright::initialize().await?;
218 /// let chromium = playwright.chromium();
219 /// # Ok(())
220 /// # }
221 /// ```
222 pub fn chromium(&self) -> BrowserType {
223 match self.inner.upgrade() {
224 Some(playwright_impl) => {
225 let chromium_weak = playwright_impl.chromium();
226 BrowserType::new(chromium_weak)
227 }
228 None => BrowserType::new(Weak::new()),
229 }
230 }
231
232 /// Returns a launcher for the Firefox browser engine.
233 ///
234 /// # Returns
235 ///
236 /// A `BrowserType` instance that can be used to launch Firefox browsers.
237 ///
238 /// # Examples
239 ///
240 /// ```
241 /// # async fn example() -> Result<(), Box<dyn std::error::Error>> {
242 /// # use playwright::Playwright;
243 /// # let playwright = Playwright::initialize().await?;
244 /// let firefox = playwright.firefox();
245 /// # Ok(())
246 /// # }
247 /// ```
248 pub fn firefox(&self) -> BrowserType {
249 let inner = weak_and_then(&self.inner, |rc| rc.firefox());
250 BrowserType::new(inner)
251 }
252
253 /// Returns a launcher for the WebKit browser engine.
254 ///
255 /// # Returns
256 ///
257 /// A `BrowserType` instance that can be used to launch WebKit browsers.
258 ///
259 /// # Examples
260 ///
261 /// ```
262 /// # async fn example() -> Result<(), Box<dyn std::error::Error>> {
263 /// # use playwright::Playwright;
264 /// # let playwright = Playwright::initialize().await?;
265 /// let webkit = playwright.webkit();
266 /// # Ok(())
267 /// # }
268 /// ```
269 pub fn webkit(&self) -> BrowserType {
270 let inner = weak_and_then(&self.inner, |rc| rc.webkit());
271 BrowserType::new(inner)
272 }
273
274 /// Returns a mutable reference to the underlying `Driver`.
275 ///
276 /// This allows you to access driver-specific operations or configuration.
277 ///
278 /// # Returns
279 ///
280 /// A mutable reference to the `Driver` instance.
281 ///
282 /// # Examples
283 ///
284 /// ```
285 /// # async fn example() -> Result<(), Box<dyn std::error::Error>> {
286 /// # use playwright::Playwright;
287 /// # let mut playwright = Playwright::initialize().await?;
288 /// let driver = playwright.driver();
289 /// # Ok(())
290 /// # }
291 /// ```
292 pub fn driver(&mut self) -> &mut Driver {
293 &mut self.driver
294 }
295
296 /// Returns a Selectors object for registering custom selector engines, if available.
297 ///
298 /// Note: Selectors are not available in Playwright 1.50+ as a separate object.
299 /// This method returns `None` if selectors are not available in the current
300 /// driver version.
301 ///
302 /// # Returns
303 ///
304 /// Some(`Selectors`) if available, or `None` if not supported by the driver.
305 ///
306 /// # Examples
307 ///
308 /// ```
309 /// # async fn example() -> Result<(), Box<dyn std::error::Error>> {
310 /// # use playwright::Playwright;
311 /// # let playwright = Playwright::initialize().await?;
312 /// if let Some(_selectors) = playwright.selectors() {
313 /// // Register custom selector engines
314 /// }
315 /// # Ok(())
316 /// # }
317 /// ```
318 pub fn selectors(&self) -> Option<Selectors> {
319 let inner = self.inner.upgrade()?;
320 let selectors_weak = inner.selectors()?;
321 Some(Selectors::new(selectors_weak))
322 }
323
324 /// Returns a dictionary of all available device descriptors.
325 ///
326 /// Device descriptors contain pre-configured settings for various devices
327 /// (phones, tablets, etc.) that can be used with [`Browser::newContext`]
328 /// or [`Browser::newPage`] to simulate real device behavior.
329 ///
330 /// # Returns
331 ///
332 /// A vector of `DeviceDescriptor` objects, or an empty vector if no devices
333 /// are available.
334 ///
335 /// # Examples
336 ///
337 /// ```
338 /// # async fn example() -> Result<(), Box<dyn std::error::Error>> {
339 /// # use playwright::Playwright;
340 /// # let playwright = Playwright::initialize().await?;
341 /// let devices = playwright.devices();
342 /// println!("Available devices: {}", devices.len());
343 /// # Ok(())
344 /// # }
345 /// ```
346 pub fn devices(&self) -> Vec<DeviceDescriptor> {
347 upgrade(&self.inner)
348 .map(|x| x.devices().to_vec())
349 .unwrap_or_default()
350 }
351
352 /// Returns a device descriptor by name, if available.
353 ///
354 /// Device descriptors contain pre-configured settings for various devices
355 /// (phones, tablets, etc.) that can be used with [`Browser::newContext`]
356 /// or [`Browser::newPage`] to simulate real device behavior.
357 ///
358 /// # Arguments
359 ///
360 /// * `name` - The name of the device (e.g., "iPhone 12", "Pixel 5")
361 ///
362 /// # Returns
363 ///
364 /// Some(`DeviceDescriptor`) if a device with the given name exists,
365 /// or `None` if no such device is found.
366 ///
367 /// # Examples
368 ///
369 /// ```
370 /// # async fn example() -> Result<(), Box<dyn std::error::Error>> {
371 /// # use playwright::Playwright;
372 /// # let playwright = Playwright::initialize().await?;
373 /// if let Some(_device) = playwright.device("iPhone 12") {
374 /// println!("Found iPhone 12");
375 /// }
376 /// # Ok(())
377 /// # }
378 /// ```
379 pub fn device(&self, name: &str) -> Option<DeviceDescriptor> {
380 let inner = self.inner.upgrade()?;
381 let device = inner.device(name)?;
382 Some(device.to_owned())
383 }
384}
385
386#[cfg(test)]
387mod tests {
388 use super::*;
389
390 crate::runtime_test!(failure_status_code, {
391 let mut p = Playwright::initialize().await.unwrap();
392 let err = run(p.driver(), &["nonExistentArg"]);
393 assert!(err.is_err());
394 if let Some(e) = err.err() {
395 assert_eq!(e.kind(), io::ErrorKind::Other);
396 }
397 });
398}