playwright_cdp/browser_type.rs
1//! `BrowserType` — a browser engine entry point (Playwright-shaped).
2//!
3//! Unlike upstream Playwright, this crate drives Chromium directly over CDP
4//! and does **not** spawn a Node.js driver. `BrowserType` is therefore a thin
5//! handle whose only real engine is Chromium; `firefox()`/`webkit()` exist for
6//! API shape parity and resolve to Chromium (with a warning).
7
8use crate::browser::Browser;
9use crate::browser_context::BrowserContext;
10use crate::browser_process;
11use crate::error::Result;
12use crate::options::{ConnectOverCdpOptions, LaunchOptions};
13use std::path::PathBuf;
14
15/// Which browser engine a [`BrowserType`] represents.
16#[derive(Debug, Clone, Copy, PartialEq, Eq)]
17pub enum Engine {
18 Chromium,
19 Firefox,
20 Webkit,
21}
22
23/// A browser engine. Created from a [`Playwright`](crate::Playwright) handle.
24#[derive(Debug, Clone, Copy)]
25pub struct BrowserType {
26 engine: Engine,
27}
28
29impl BrowserType {
30 pub(crate) fn new(engine: Engine) -> Self {
31 Self { engine }
32 }
33
34 /// Chromium engine (the only fully-supported engine here).
35 pub fn chromium() -> Self {
36 Self::new(Engine::Chromium)
37 }
38
39 /// Engine name: `"chromium"`, `"firefox"`, or `"webkit"`.
40 pub fn name(&self) -> &'static str {
41 match self.engine {
42 Engine::Chromium => "chromium",
43 Engine::Firefox => "firefox",
44 Engine::Webkit => "webkit",
45 }
46 }
47
48 /// Best-effort discovery of the executable path for this engine.
49 pub fn executable_path(&self) -> Option<PathBuf> {
50 browser_process::discover_executable(&LaunchOptions::default()).ok()
51 }
52
53 /// Launch a browser with default options.
54 pub async fn launch(&self) -> Result<Browser> {
55 self.launch_with_options(LaunchOptions::default()).await
56 }
57
58 /// Launch a browser with the given options.
59 ///
60 /// Only Chromium is driven here; `firefox`/`webkit` log a warning and fall
61 /// back to launching Chromium (kept for porting compatibility).
62 pub async fn launch_with_options(&self, opts: LaunchOptions) -> Result<Browser> {
63 if !matches!(self.engine, Engine::Chromium) {
64 tracing::warn!(
65 engine = self.name(),
66 "playwright-cdp only drives Chromium via CDP; launching Chromium instead"
67 );
68 }
69 Browser::launch(opts).await
70 }
71
72 /// Launch a browser with a persistent user-data-dir and return its default
73 /// [`BrowserContext`]. Cookies / localStorage persist to `user_data_dir`
74 /// across runs. Mirrors Playwright's `browserType.launchPersistentContext`.
75 ///
76 /// `user_data_dir` accepts any path-like value (`impl AsRef<Path>`), so you
77 /// can pass a `&str`, `&Path`, `&PathBuf`, or an owned `PathBuf` directly.
78 pub async fn launch_persistent_context(
79 &self,
80 user_data_dir: impl AsRef<std::path::Path>,
81 ) -> Result<BrowserContext> {
82 self.launch_persistent_context_with_options(user_data_dir, LaunchOptions::default())
83 .await
84 }
85
86 /// Like [`launch_persistent_context`](Self::launch_persistent_context) but with
87 /// custom launch options. The `user_data_dir` passed here overrides any
88 /// `user_data_dir` set on `opts`.
89 ///
90 /// `user_data_dir` accepts any path-like value (`impl AsRef<Path>`), so you
91 /// can pass a `&str`, `&Path`, `&PathBuf`, or an owned `PathBuf` directly.
92 pub async fn launch_persistent_context_with_options(
93 &self,
94 user_data_dir: impl AsRef<std::path::Path>,
95 mut opts: LaunchOptions,
96 ) -> Result<BrowserContext> {
97 if !matches!(self.engine, Engine::Chromium) {
98 tracing::warn!(
99 engine = self.name(),
100 "playwright-cdp only drives Chromium via CDP; launching Chromium instead"
101 );
102 }
103 opts.user_data_dir = Some(PathBuf::from(user_data_dir.as_ref()));
104 let browser = Browser::launch(opts).await?;
105 // The persistent context is the browser's default (non-isolated) context:
106 // browser_context_id == None, backed by the on-disk user-data-dir.
107 let ctx = BrowserContext::default_for(browser);
108 // Owning context: close() must tear the whole browser down, matching
109 // Playwright's persistent-context semantics.
110 ctx.mark_persistent();
111 Ok(ctx)
112 }
113
114 /// Attach to an already-running browser over CDP.
115 pub async fn connect_over_cdp(
116 &self,
117 endpoint: &str,
118 opts: Option<ConnectOverCdpOptions>,
119 ) -> Result<Browser> {
120 Browser::connect_over_cdp(endpoint, opts).await
121 }
122}