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}