## 🚀 Feature Proposal

Add support for the WebAuthn Automation API, a standard WebDriver extension that allows developers to create virtual authenticators to test websites using WebAuthn.

https://w3c.github.io/webauthn/#sctn-automation

_note: the above link may not work until https://github.com/w3c/webauthn/pull/1340 is merged_

## Motivation

At the moment there is no practical way to write e2e tests for pages using WebAuthn. Since this is a standard WebDriver API, the cost of implementing a layer on java is low.

## Example

For a page like this

```html
<button id="signup">Sign up with webauthn</button>
<span id="result"></span>
```

```javascript
document.getElmentById("signup").addEventListener("click", () => {
  navigator.credentials.create({...}).then(credentials => {
    document.getElementById("result").innerText = "Success!";
  })
});
```

A test could be written like so:

```java
// HasVirtualAuthenticator is an interface that augments a RemoteWebDriver.
HasVirtualAuthenticator virtualAuthenticatorManager = ((HasVirtualAuthenticator) driver);
VirtualAuthenticatorOptions options = new VirtualAuthenticatorOptions();
VirtualAuthenticator authenticator =
    virtualAuthenticatorManager.addVirtualAuthenticator(options);
driver.findElement(By.id("signup")).click();
WebElement result = driver.findElement(By.id("result"));
new WebDriverWait(driver, 60, 1000).until(
    driver -> !result.getText().equals(""));
assertThat(result.getText()).isEqualTo("Success!");
```

## Implementation

We can implement the AddVirtualAuthenticator and RemoveVirtualAuthenticator methods first since they're the most useful and follow up with the others in subsequent PRs.
private void init(Capabilities capabilities) {
    capabilities = capabilities == null ? new ImmutableCapabilities() : capabilities;
    logger.addHandler(LoggingHandler.getInstance());
    converter = new JsonToWebElementConverter(this);
    executeMethod = new RemoteExecuteMethod(this);
    keyboard = new RemoteKeyboard(executeMethod);
    mouse = new RemoteMouse(executeMethod);
    ImmutableSet.Builder<String> builder = new ImmutableSet.Builder<>();
    boolean isProfilingEnabled = capabilities.is(CapabilityType.ENABLE_PROFILING_CAPABILITY);
    if (isProfilingEnabled) {
      builder.add(LogType.PROFILER);
    }
    LoggingPreferences mergedLoggingPrefs = new LoggingPreferences();
    mergedLoggingPrefs.addPreferences((LoggingPreferences) capabilities.getCapability(LOGGING_PREFS));
    if (!mergedLoggingPrefs.getEnabledLogTypes().contains(LogType.CLIENT) ||
        mergedLoggingPrefs.getLevel(LogType.CLIENT) != Level.OFF) {
      builder.add(LogType.CLIENT);
    }
    Set<String> logTypesToInclude = builder.build();
    LocalLogs performanceLogger = LocalLogs.getStoringLoggerInstance(logTypesToInclude);
    LocalLogs clientLogs = LocalLogs.getHandlerBasedLoggerInstance(LoggingHandler.getInstance(),
        logTypesToInclude);
    localLogs = LocalLogs.getCombinedLogsHolder(clientLogs, performanceLogger);
    remoteLogs = new RemoteLogs(executeMethod, localLogs);
  }
  /**
   * Set the file detector to be used when sending keyboard input. By default, this is set to a file
   * detector that does nothing.
   *
   * @param detector The detector to use. Must not be null.