chrome-for-testing-manager 0.10.0

Programmatic management of chrome-for-testing installations.
Documentation
# chrome-for-testing-manager

Drive a real Chrome browser from your Rust tests without ever installing Chrome yourself.

`chrome-for-testing-manager` is a thin orchestration layer over Google's
[Chrome for Testing](https://googlechromelabs.github.io/chrome-for-testing/) release index. It picks the right
`chrome` + `chromedriver` pair for your platform, downloads them into a local cache the first time you ask, spawns
`chromedriver` on a port of your choosing (or one the OS picks), and hands you a managed
[`thirtyfour`](https://docs.rs/thirtyfour) `WebDriver` session. When your test finishes, panics, or is canceled, the
spawned process is terminated and the session closed for you.

It exists so that browser tests in CI and on developer machines don't depend on whatever Chrome happens to be installed,
and so that bumping the Chrome version under test is one simple change.

## Why use it

- **No global Chrome dependency.** Tests don't care what Chrome happens to be installed on the host. Every developer
  and CI runner runs against the browser this library brings along. No more "works on my machine."
- **Deterministic upgrades.** Pin to a specific `Version`, follow a `Channel` (Stable / Beta / Dev / Canary), or always
  grab the latest. Switching is a one-line change.
- **Port and lifecycle managed for you.** Bind to a fixed port for debugging or let the OS pick one for parallel test
  isolation. The `chromedriver` process is terminated on drop, even on panics, which are very common in tests.
- **Ergonomic `thirtyfour` integration.** Run a test inside `with_session(|session| ...)` and the WebDriver session is
  created, scoped, and torn down automatically. The library needs a session-driver to be useful - `thirtyfour` is the
  default; disable the feature only if you wire in another one.
- **Observable.** Attach a `DriverOutputListener` to stream `chromedriver` stdout/stderr lines into your own logging
  or fixtures.

## Installation

```toml
[dependencies]
chrome-for-testing-manager = "0.10"
rootcause = "0.12"
thirtyfour = "0.37"

# Additional dependencies for the example below.
assertr = "0.6"
tokio = { version = "1", features = ["full"] }
```

## Example

```rust
use assertr::prelude::*;
use chrome_for_testing_manager::Chromedriver;
use rootcause::Report;
use std::time::Duration;
use thirtyfour::prelude::*;

// This library requires being used in a multithreaded runtime.
// If you want to run a test, use: `#[tokio::test(flavor = "multi_thread")]`.
#[tokio::main]
async fn main() -> Result<(), Report> {
    Chromedriver::run_default()
        .await?
        .with_session(async |session| {
            session.goto("https://wikipedia.org").await?;

            let search_form = session.find(By::Id("search-form")).await?;
            let search_input = search_form.find(By::Id("searchInput")).await?;
            search_input.send_keys("selenium").await?;

            let submit_btn = search_form.find(By::Css("button[type='submit']")).await?;
            submit_btn.click().await?;

            // Look for header to implicitly wait for the page to load.
            let _heading = session
                .query(By::Id("firstHeading"))
                .wait(Duration::from_secs(2), Duration::from_millis(100))
                .exists()
                .await?;
            assert_that!(session.title().await?).is_equal_to("Selenium – Wikipedia");

            Ok(())
        }).await
}
```

## Configuration

Anything beyond defaults goes through `ChromedriverRunConfig::builder()`. The `version` setter accepts a `Channel`,
a specific `Version`, or a `VersionRequest`; `port` accepts a `u16`, a `Port`, or a `PortRequest`.

```rust,no_run
use chrome_for_testing_manager::{
    Channel, Chromedriver, ChromedriverRunConfig, DriverOutputListener, GracefulShutdown,
};
use std::time::Duration;

async fn run() -> Result<(), rootcause::Report<chrome_for_testing_manager::ChromeForTestingManagerError>> {
    let config = ChromedriverRunConfig::builder()
        .version(Channel::Beta)
        .port(3000u16)
        .output_listener(DriverOutputListener::new(|line| println!("{line:?}")))
        .graceful_shutdown(
            GracefulShutdown::builder()
                .unix_sigterm(Duration::from_secs(5))
                .windows_ctrl_break(Duration::from_secs(5))
                .build(),
        )
        .build();
    Chromedriver::run(config).await?;
    Ok(())
}
```

`GracefulShutdown` (re-exported from `tokio-process-tools`) mirrors the platform's actual graceful-shutdown model:

- on Unix, it carries one or more phases (`SIGTERM` and/or `SIGINT`).
- on Windows, it carries a single `CTRL_BREAK_EVENT` budget.

## Managed sessions opt-out

The `with_session` function providing a `thirtyfour` session, called in the example, is only available because
`chrome-for-testing-manager` enables its `thirtyfour` feature by default.

If you only want its chrome/chromedriver version resolution, download, and launch orchestration, declare the dependency
as

```toml
chrome-for-testing-manager = { version = "0.10", default-features = false }
```

instead.

## Going lower-level

For most users `Chromedriver` is the right entry point. If you need finer control, pre-warming the cache without
spawning chromedriver, running multiple chromedriver instances off a single download, pinning a custom cache directory
in CI, or driving sessions through a non-`thirtyfour` WebDriver client, reach for `ChromeForTestingManager` directly.
It exposes `resolve_version`, `download`, `launch_chromedriver`, and `prepare_caps` as separate steps.

## MSRV

- Starting from version `0.8.0`, the minimum supported rust version is `1.89.0`
- Starting from version `0.7.0`, the minimum supported rust version is `1.85.1`
- Starting from version `0.5.0`, the minimum supported rust version is `1.85.0`
- Starting from version `0.1.0`, the minimum supported rust version is `1.81.0`