org.openqa.selenium.chromium.ChromiumDriver Maven / Gradle / Ivy
// Licensed to the Software Freedom Conservancy (SFC) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The SFC licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
package org.openqa.selenium.chromium;
import static org.openqa.selenium.remote.Browser.CHROME;
import static org.openqa.selenium.remote.Browser.EDGE;
import static org.openqa.selenium.remote.Browser.OPERA;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.function.Predicate;
import java.util.function.Supplier;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.openqa.selenium.BuildInfo;
import org.openqa.selenium.Capabilities;
import org.openqa.selenium.Credentials;
import org.openqa.selenium.HasAuthentication;
import org.openqa.selenium.ImmutableCapabilities;
import org.openqa.selenium.PersistentCapabilities;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebDriverException;
import org.openqa.selenium.bidi.BiDi;
import org.openqa.selenium.bidi.BiDiException;
import org.openqa.selenium.bidi.HasBiDi;
import org.openqa.selenium.devtools.CdpEndpointFinder;
import org.openqa.selenium.devtools.CdpInfo;
import org.openqa.selenium.devtools.CdpVersionFinder;
import org.openqa.selenium.devtools.Connection;
import org.openqa.selenium.devtools.DevTools;
import org.openqa.selenium.devtools.HasDevTools;
import org.openqa.selenium.devtools.noop.NoOpCdpInfo;
import org.openqa.selenium.html5.LocalStorage;
import org.openqa.selenium.html5.Location;
import org.openqa.selenium.html5.LocationContext;
import org.openqa.selenium.html5.SessionStorage;
import org.openqa.selenium.html5.WebStorage;
import org.openqa.selenium.internal.Require;
import org.openqa.selenium.logging.EventType;
import org.openqa.selenium.logging.HasLogEvents;
import org.openqa.selenium.mobile.NetworkConnection;
import org.openqa.selenium.remote.CommandExecutor;
import org.openqa.selenium.remote.FileDetector;
import org.openqa.selenium.remote.RemoteWebDriver;
import org.openqa.selenium.remote.html5.RemoteLocationContext;
import org.openqa.selenium.remote.html5.RemoteWebStorage;
import org.openqa.selenium.remote.http.ClientConfig;
import org.openqa.selenium.remote.http.ConnectionFailedException;
import org.openqa.selenium.remote.http.HttpClient;
import org.openqa.selenium.remote.mobile.RemoteNetworkConnection;
/**
* A {@link WebDriver} implementation that controls a Chromium browser running on the local machine.
* It is used as the base class for Chromium-based browser drivers (Chrome, Edge).
*/
public class ChromiumDriver extends RemoteWebDriver
implements HasAuthentication,
HasBiDi,
HasCasting,
HasCdp,
HasDevTools,
HasLaunchApp,
HasLogEvents,
HasNetworkConditions,
HasPermissions,
LocationContext,
NetworkConnection,
WebStorage {
public static final Predicate IS_CHROMIUM_BROWSER =
name -> CHROME.is(name) || EDGE.is(name) || OPERA.is(name);
private static final Logger LOG = Logger.getLogger(ChromiumDriver.class.getName());
private final Capabilities capabilities;
private final RemoteLocationContext locationContext;
private final RemoteWebStorage webStorage;
private final RemoteNetworkConnection networkConnection;
private final HasNetworkConditions networkConditions;
private final HasPermissions permissions;
private final HasLaunchApp launch;
private Optional connection;
private final Optional devTools;
private final Optional biDiUri;
private final Optional biDi;
protected HasCasting casting;
protected HasCdp cdp;
protected ChromiumDriver(
CommandExecutor commandExecutor, Capabilities capabilities, String capabilityKey) {
super(commandExecutor, capabilities);
locationContext = new RemoteLocationContext(getExecuteMethod());
webStorage = new RemoteWebStorage(getExecuteMethod());
permissions = new AddHasPermissions().getImplementation(getCapabilities(), getExecuteMethod());
networkConnection = new RemoteNetworkConnection(getExecuteMethod());
networkConditions =
new AddHasNetworkConditions().getImplementation(getCapabilities(), getExecuteMethod());
launch = new AddHasLaunchApp().getImplementation(getCapabilities(), getExecuteMethod());
HttpClient.Factory factory = HttpClient.Factory.createDefault();
Capabilities originalCapabilities = super.getCapabilities();
Optional webSocketUrl =
Optional.ofNullable((String) originalCapabilities.getCapability("webSocketUrl"));
this.biDiUri =
webSocketUrl.map(
uri -> {
try {
return new URI(uri);
} catch (URISyntaxException e) {
LOG.warning(e.getMessage());
}
return null;
});
this.biDi = createBiDi(biDiUri);
Optional reportedUri =
CdpEndpointFinder.getReportedUri(capabilityKey, originalCapabilities);
Optional client =
reportedUri.map(uri -> CdpEndpointFinder.getHttpClient(factory, uri));
Optional cdpUri;
try {
try {
cdpUri = client.flatMap(httpClient -> CdpEndpointFinder.getCdpEndPoint(httpClient));
} catch (Exception e) {
try {
client.ifPresent(HttpClient::close);
} catch (Exception ex) {
e.addSuppressed(ex);
}
throw e;
}
connection = cdpUri.map(uri -> new Connection(client.get(), uri.toString()));
} catch (ConnectionFailedException e) {
cdpUri = Optional.empty();
LOG.log(Level.WARNING, "Unable to establish websocket connection to " + reportedUri.get(), e);
connection = Optional.empty();
}
CdpInfo cdpInfo =
new CdpVersionFinder()
.match(originalCapabilities.getBrowserVersion())
.orElseGet(
() -> {
LOG.warning(
String.format(
"Unable to find version of CDP to use for %s. You may need to include a"
+ " dependency on a specific version of the CDP using something"
+ " similar to `org.seleniumhq.selenium:selenium-devtools-v86:%s`"
+ " where the version (\"v86\") matches the version of the"
+ " chromium-based browser you're using and the version number of the"
+ " artifact is the same as Selenium's.",
originalCapabilities.getBrowserVersion(),
new BuildInfo().getReleaseLabel()));
return new NoOpCdpInfo();
});
devTools = connection.map(conn -> new DevTools(cdpInfo::getDomains, conn));
this.capabilities =
cdpUri
.map(
uri ->
new ImmutableCapabilities(
new PersistentCapabilities(originalCapabilities)
.setCapability("se:cdp", uri.toString())
.setCapability(
"se:cdpVersion", originalCapabilities.getBrowserVersion())))
.orElse(new ImmutableCapabilities(originalCapabilities));
}
@Override
public Capabilities getCapabilities() {
return capabilities;
}
@Override
public void setFileDetector(FileDetector detector) {
throw new WebDriverException(
"Setting the file detector only works on remote webdriver instances obtained "
+ "via RemoteWebDriver");
}
@Override
public void onLogEvent(EventType kind) {
Require.nonNull("Event type", kind);
kind.initializeListener(this);
}
@Override
public void register(Predicate whenThisMatches, Supplier useTheseCredentials) {
Require.nonNull("Check to use to see how we should authenticate", whenThisMatches);
Require.nonNull("Credentials to use when authenticating", useTheseCredentials);
getDevTools().createSessionIfThereIsNotOne(getWindowHandle());
getDevTools().getDomains().network().addAuthHandler(whenThisMatches, useTheseCredentials);
}
@Override
public LocalStorage getLocalStorage() {
return webStorage.getLocalStorage();
}
@Override
public SessionStorage getSessionStorage() {
return webStorage.getSessionStorage();
}
@Override
public Location location() {
return locationContext.location();
}
@Override
public void setLocation(Location location) {
Require.nonNull("Location", location);
locationContext.setLocation(location);
}
@Override
public ConnectionType getNetworkConnection() {
return networkConnection.getNetworkConnection();
}
@Override
public ConnectionType setNetworkConnection(ConnectionType type) {
Require.nonNull("Network Connection Type", type);
return networkConnection.setNetworkConnection(type);
}
@Override
public void launchApp(String id) {
Require.nonNull("Launch App ID", id);
launch.launchApp(id);
}
@Override
public Map executeCdpCommand(String commandName, Map parameters) {
Require.nonNull("Command Name", commandName);
return cdp.executeCdpCommand(commandName, parameters);
}
@Override
public Optional maybeGetDevTools() {
return devTools;
}
private Optional createBiDi(Optional biDiUri) {
if (!biDiUri.isPresent()) {
return Optional.empty();
}
URI wsUri =
biDiUri.orElseThrow(
() -> new BiDiException("This version of Chromium driver does not support BiDi"));
HttpClient.Factory clientFactory = HttpClient.Factory.createDefault();
ClientConfig wsConfig = ClientConfig.defaultConfig().baseUri(wsUri);
HttpClient wsClient = clientFactory.createClient(wsConfig);
org.openqa.selenium.bidi.Connection biDiConnection =
new org.openqa.selenium.bidi.Connection(wsClient, wsUri.toString());
return Optional.of(new BiDi(biDiConnection));
}
@Override
public Optional maybeGetBiDi() {
return biDi;
}
@Override
public List © 2015 - 2025 Weber Informatics LLC | Privacy Policy