# Async::WebDriver

Provides a client implementation of the W3C WebDriver specification with support for Chrome and Firefox.

[![Development Status](https://github.com/socketry/async-webdriver/workflows/Test/badge.svg)](https://github.com/socketry/async-webdriver/actions?workflow=Test)

## Motivation

In the past, I've used [selenium-webdriver](https://github.com/SeleniumHQ/selenium) for testing web applications. However, I found it to be slow. I wanted to improve the performance of my tests, so I decided to write a new implementation from scratch. The W3C WebDriver specification is quite simple, so it wasn't too difficult to implement, and I was able to get a significant performance improvement, between 2x-10x depending on the usage. Specifically, most test suites can take advantage of pre-warmed sessions, which can minimise the overhead of each test running in a new session. Additionally, I'd like to explore reusing sessions between tests, which could provide even more performance improvements.

In addition, building on top of [async](https://github.com/socketry/async) allows us to take advantage of [async-http](https://github.com/socketry/async-http) and run the web server in the same reactor as the test itself, which can provide a performance improvement over [capybara](https://github.com/teamcapybara/capybara) which usually needs to start a separate server process. This also makes it possible to share a single database transaction between the client and server, which can significantly reduce the overhead of "cleaning" the database after each test, and improve the opportunity for parallelisation.

## Usage

Please see the [project documentation](https://socketry.github.io/async-webdriver/) for more details.

  - [Getting Started](https://socketry.github.io/async-webdriver/guides/getting-started/index) - This guide explains how to use `async-webdriver` for controlling a browser.

  - [Debugging](https://socketry.github.io/async-webdriver/guides/debugging/index) - This guide explains how to debug WebDriver issues by capturing HTML source and screenshots when tests fail.

  - [Navigation Timing](https://socketry.github.io/async-webdriver/guides/navigation-timing/index) - This guide explains how to avoid race conditions when triggering navigation operations while browser navigation is already in progress.

  - [GitHub Actions Integrations](https://socketry.github.io/async-webdriver/guides/github-actions-integration/index) - This guide explains how to use `async-webdriver` with GitHub Actions.

  - [Sus Integration](https://socketry.github.io/async-webdriver/guides/sus-integration/index) - This guide will show you how to integrate `async-webdriver` with the sus test framework.

## Releases

Please see the [project releases](https://socketry.github.io/async-webdriver/releases/index) for all releases.

### v0.12.2

  - **Fixed** `Installer.cache_path` usage.

### v0.12.0

  - Add `Async::WebDriver::Installer::Chrome` for automatic Chrome for Testing installation and management. `Installer::Chrome.install(version)` resolves the version via the Chrome for Testing JSON API, caches binaries in `~/.local/state/async-webdriver/` (XDG `$XDG_STATE_HOME`), and returns an `Installation` with paths to both the Chrome and ChromeDriver binaries.
  - Add `Bridge::Chrome.for(version)` as a convenience shorthand: installs the requested version if needed, then returns a fully configured `Chrome` bridge. Versions can be a channel symbol (`:stable`, `:beta`, `:dev`, `:canary`), a major version string (`"148"`), or an exact version string (`"148.0.7778.56"`).
  - Add `bake async:webdriver:chrome:install` task for installing Chrome for Testing from the command line, e.g. in CI setup steps.
  - Fix `Bridge::Chrome#start`, `Bridge::Firefox#start`, and `Bridge::Safari#start` not forwarding the bridge's own options (including `:driver_path`) to the driver process.
  - Rename `path:` to `driver_path:` on `Bridge::Chrome`, `Bridge::Firefox`, and `Bridge::Safari` for consistency. Add `browser_path:` to `Bridge::Chrome` (mapped to `goog:chromeOptions.binary`) in place of the former `binary:` option, consistent with `Installer::Chrome::Installation#browser_path` and `#driver_path`.

### v0.11.0

  - Add `Scope::Window` with `#window_rect`, `#resize_window`, `#set_window_rect`, `#maximize_window`, `#minimize_window`, and `#fullscreen_window`.
  - Expand `Scope::Printing#print` with full W3C WebDriver parameters: `orientation`, `scale`, `background`, `page`, `margin`, `page_ranges`, and `shrink_to_fit`.

### v0.10.0

  - Introduce `Scope#wait_for_navigation` to properly wait for page navigations to complete.

### v0.9.0

  - Fix `Scope#screenshot` to use the correct HTTP method (`GET` instead of `POST`).

### v0.8.0

  - Fix `fill_in` `<select>` on Safari.
  - `Element#tag_name` now normalizes the tag name to lowercase (Safari returns uppercase while other browsers return lowercase).

## See Also

  - [sus-fixtures-async-webdriver](https://github.com/socketry/sus-fixtures-async-webdriver) - Standard fixtures for testing web applications with `async-webdriver`.

## Contributing

We welcome contributions to this project.

1.  Fork it.
2.  Create your feature branch (`git checkout -b my-new-feature`).
3.  Commit your changes (`git commit -am 'Add some feature'`).
4.  Push to the branch (`git push origin my-new-feature`).
5.  Create new Pull Request.

### Running Tests

To run the test suite:

``` shell
bundle exec sus
```

### Making Releases

To make a new release:

``` shell
bundle exec bake gem:release:patch # or minor or major
```

### Developer Certificate of Origin

In order to protect users of this project, we require all contributors to comply with the [Developer Certificate of Origin](https://developercertificate.org/). This ensures that all contributions are properly licensed and attributed.

### Community Guidelines

This project is best served by a collaborative and respectful environment. Treat each other professionally, respect differing viewpoints, and engage constructively. Harassment, discrimination, or harmful behavior is not tolerated. Communicate clearly, listen actively, and support one another. If any issues arise, please inform the project maintainers.
