use crate::core::constants::CHROME_ARGS;
use crate::core::engine::EngineType;
use std::path::PathBuf;
#[derive(Debug, Clone)]
pub struct LaunchOptions {
pub engine: EngineType,
pub user_data_dir: Option<PathBuf>,
pub headless: bool,
pub slow_mo: u64,
pub verbose: bool,
pub args: Vec<String>,
}
impl Default for LaunchOptions {
fn default() -> Self {
Self {
engine: EngineType::Chromiumoxide,
user_data_dir: None,
headless: false,
slow_mo: 0,
verbose: false,
args: Vec::new(),
}
}
}
impl LaunchOptions {
pub fn chromiumoxide() -> Self {
Self {
engine: EngineType::Chromiumoxide,
..Default::default()
}
}
pub fn fantoccini() -> Self {
Self {
engine: EngineType::Fantoccini,
..Default::default()
}
}
pub fn headless(mut self, headless: bool) -> Self {
self.headless = headless;
self
}
pub fn user_data_dir(mut self, dir: impl Into<PathBuf>) -> Self {
self.user_data_dir = Some(dir.into());
self
}
pub fn slow_mo(mut self, ms: u64) -> Self {
self.slow_mo = ms;
self
}
pub fn verbose(mut self, verbose: bool) -> Self {
self.verbose = verbose;
self
}
pub fn with_args(mut self, args: Vec<String>) -> Self {
self.args = args;
self
}
pub fn all_chrome_args(&self) -> Vec<String> {
let mut all_args: Vec<String> = CHROME_ARGS.iter().map(|s| s.to_string()).collect();
all_args.extend(self.args.clone());
all_args
}
pub fn get_user_data_dir(&self) -> PathBuf {
if let Some(ref dir) = self.user_data_dir {
dir.clone()
} else {
let home = dirs::home_dir().unwrap_or_else(|| PathBuf::from("."));
home.join(".browser-commander")
.join(format!("{}-data", self.engine))
}
}
}
#[derive(Debug)]
pub struct Browser {
pub engine: EngineType,
pub user_data_dir: PathBuf,
pub headless: bool,
}
#[derive(Debug)]
pub struct LaunchResult {
pub browser: Browser,
}
pub async fn launch_browser(options: LaunchOptions) -> Result<LaunchResult, anyhow::Error> {
if options.verbose {
tracing::info!("Launching browser with {} engine...", options.engine);
}
let user_data_dir = options.get_user_data_dir();
std::fs::create_dir_all(&user_data_dir)?;
let browser = Browser {
engine: options.engine,
user_data_dir,
headless: options.headless,
};
if options.verbose {
tracing::info!("Browser launched with {} engine", options.engine);
}
Ok(LaunchResult { browser })
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn launch_options_default() {
let options = LaunchOptions::default();
assert_eq!(options.engine, EngineType::Chromiumoxide);
assert!(!options.headless);
assert_eq!(options.slow_mo, 0);
assert!(!options.verbose);
assert!(options.args.is_empty());
}
#[test]
fn launch_options_builder() {
let options = LaunchOptions::chromiumoxide()
.headless(true)
.slow_mo(100)
.verbose(true)
.with_args(vec!["--custom-arg".to_string()]);
assert_eq!(options.engine, EngineType::Chromiumoxide);
assert!(options.headless);
assert_eq!(options.slow_mo, 100);
assert!(options.verbose);
assert_eq!(options.args, vec!["--custom-arg"]);
}
#[test]
fn launch_options_fantoccini() {
let options = LaunchOptions::fantoccini();
assert_eq!(options.engine, EngineType::Fantoccini);
}
#[test]
fn all_chrome_args_includes_defaults() {
let options = LaunchOptions::default();
let args = options.all_chrome_args();
assert!(args.contains(&"--disable-infobars".to_string()));
assert!(args.contains(&"--no-first-run".to_string()));
}
#[test]
fn all_chrome_args_includes_custom() {
let options = LaunchOptions::default().with_args(vec!["--custom".to_string()]);
let args = options.all_chrome_args();
assert!(args.contains(&"--custom".to_string()));
}
#[test]
fn get_user_data_dir_uses_custom() {
let options = LaunchOptions::default().user_data_dir("/custom/path");
assert_eq!(options.get_user_data_dir(), PathBuf::from("/custom/path"));
}
#[test]
fn get_user_data_dir_creates_default() {
let options = LaunchOptions::default();
let dir = options.get_user_data_dir();
assert!(dir.to_string_lossy().contains("browser-commander"));
assert!(dir.to_string_lossy().contains("chromiumoxide-data"));
}
}