This is the multi-page printable view of this section.
Click here to print.
Return to the regular view of this page.
BiDirectional Functionality
Page being translated from
English to Portuguese. Do you speak Portuguese? Help us to translate
it by sending us pull requests!
Selenium is working with browser vendors to create the
WebDriver BiDirectional Protocol
as a means to provide a stable, cross-browser API that uses the bidirectional
functionality useful for both browser automation generally and testing specifically.
Before now, users seeking this functionality have had to rely on
with all of its frustrations and limitations.
The traditional WebDriver model of strict request/response commands will be supplemented
with the ability to stream events from the user agent to the controlling software via WebSockets,
better matching the evented nature of the browser DOM.
As it is not a good idea to tie your tests to a specific version of any browser, the
Selenium project recommends using WebDriver BiDi wherever possible.
However, until the specification is complete there are many useful things that
CDP (Chrome DevTools Protocol) offers. To help keep your tests independent
and portable, Selenium offers some useful helper classes as well. At the
moment, they use the CDP, but soon it could be done using WebDriver BiDi.
1 - RemoteWebDriver BiDirectional API (CDP implementation)
Page being translated from
English to Portuguese. Do you speak Portuguese? Help us to translate
it by sending us pull requests!
The following examples demonstrate how to leverage BiDi APIs with Remote WebDriver.
Register Basic Auth
Some applications make use of browser authentication to secure pages.
With Selenium, you can automate the input of basic auth credentials whenever they arise.
AtomicReference<DevTools> devToolsAtomicReference = new AtomicReference<>();
driver = new Augmenter()
.addDriverAugmentation("chrome",
HasAuthentication.class,
(caps, exec) -> (whenThisMatches, useTheseCredentials) -> {
devToolsAtomicReference.get()
.createSessionIfThereIsNotOne();
devToolsAtomicReference.get().getDomains()
.network()
.addAuthHandler(whenThisMatches,
useTheseCredentials);
}).augment(driver);
DevTools devTools = ((HasDevTools) driver).getDevTools();
devTools.createSession();
devToolsAtomicReference.set(devTools);
((HasAuthentication) driver).
register(UsernameAndPassword.of("admin", "admin"));
Mutation Observation
Mutation Observation is the ability to capture events via
WebDriver BiDi when there are DOM mutations on a specific
element in the DOM.
AtomicReference<DomMutationEvent> seen = new AtomicReference<>();
AtomicReference<WebDriver> augmentedDriver = new AtomicReference<>();
CountDownLatch latch = new CountDownLatch(1);
driver = new Augmenter()
.addDriverAugmentation("chrome",
HasLogEvents.class,
(caps, exec) -> new HasLogEvents() {
@Override
public <X> void onLogEvent(EventType<X> kind) {
kind.initializeListener(augmentedDriver.get());
}
}).augment(driver);
DevTools devTools = ((HasDevTools) driver).getDevTools();
devTools.createSession();
augmentedDriver.set(driver);
((HasLogEvents) driver).onLogEvent(domMutation(mutation -> {
if ("cheese".equals(mutation.getAttributeName())) {
seen.set(mutation);
latch.countDown();
}
}));
Listen to console.log
events
Listen to the console.log
events and register callbacks to process the event.
CountDownLatch latch = new CountDownLatch(4);
driver = new Augmenter().augment(driver);
DevTools devTools = ((HasDevTools) driver).getDevTools();
devTools.createSession();
devTools.send(org.openqa.selenium.devtools.v85.runtime.Runtime.enable());
devTools.send(Log.enable());
devTools.addListener(Log.entryAdded(),
logEntry -> {
System.out.println("log: " + logEntry.getText());
System.out.println("level: " + logEntry.getLevel());
latch.countDown();
});
devTools.addListener(org.openqa.selenium.devtools.v85.runtime.Runtime.consoleAPICalled(),
consoleLog -> System.out.println("Type: " + consoleLog.getType()));
Actions causing JS exceptions
driver = new Augmenter().augment(driver);
DevTools devTools = ((HasDevTools) driver).getDevTools();
devTools.createSession();
List<JavascriptException> jsExceptionsList = new ArrayList<>();
devTools.getDomains().events().addJavascriptExceptionListener(jsExceptionsList::add);
CompletableFuture<JavascriptException> futureJsExc = new CompletableFuture<>();
devTools.getDomains().events().addJavascriptExceptionListener(futureJsExc::complete);
Network Interception
If you want to capture network events coming into the browser and you want manipulate them you are able to do
it with the following examples.
driver = new Augmenter().augment(driver);
DevTools devTools = ((HasDevTools) driver).getDevTools();
devTools.createSession();
try (NetworkInterceptor interceptor = new NetworkInterceptor(
driver,
Route.matching(req -> req.getUri().contains("google"))
.to(() -> req -> new HttpResponse()
.setStatus(200)
.addHeader("Content-Type", MediaType.HTML_UTF_8.toString())
.setContent(utf8String("Creamy, delicious cheese!"))))) {
2 - Chrome DevTools
Apesar do Selenium 4 providenciar acesso direto ao Protocolo Chrome DevTools (CDP), é altamente recomendável que você use o WebDriver Bidi APIs ao invés do acesso direto.
Muitos navegadores fornecem o “DevTools”, um conjunto de ferramentas integradas ao navegador, que
desenvolvedores podem usar para depurar web apps analisar o desempenho de suas páginas. O DevTools do Google Chrome faz o uso de um protocolo chamado Protocolo Chrome DevTools (abreviado como “CDP”).
Como o nome sugere, ele não foi projetado para testes, ou tem uma API estável, portanto, sua funcionalidade depende muito da versão do navegador de internet.
WebDriver Bidi é a próxima geração do protocolo W3C WebDriver e visa fornecer uma API estável
implementado por todos os navegadores, mas ele ainda não está completo. Até que seja, o Selenium fornece acesso ao
CDP para os navegadores que o implementam (como Google Chrome ou Microsoft Edge e
Firefox), permitindo que você aprimore seus testes de maneiras interessantes. Alguns exemplos do que você pode
fazer com ele são dadas abaixo.
Emular Geo Localização
Alguns aplicativos têm recursos e funcionalidades diferentes em diferentes
locations. Automatizar esses tipos de aplicativos é complicado porque é difícil emular
as geolocalizações no navegador usando o Selenium. Mas com a ajuda do Devtools,
podemos facilmente as emular. O trecho do código abaixo demonstra isso.
ChromeDriver driver = new ChromeDriver();
DevTools devTools = driver.getDevTools();
devTools.createSession();
devTools.send(Emulation.setGeolocationOverride(Optional.of(52.5043),
Optional.of(13.4501),
Optional.of(1)));
driver.get("https://my-location.org/");
driver.quit();
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
def geoLocationTest():
driver = webdriver.Chrome()
Map_coordinates = dict({
"latitude": 41.8781,
"longitude": -87.6298,
"accuracy": 100
})
driver.execute_cdp_cmd("Emulation.setGeolocationOverride", Map_coordinates)
driver.get("<your site url>")
using System.Threading.Tasks;
using OpenQA.Selenium.Chrome;
using OpenQA.Selenium.DevTools;
// Replace the version to match the Chrome version
using OpenQA.Selenium.DevTools.V87.Emulation;
namespace dotnet_test {
class Program {
public static void Main(string[] args) {
GeoLocation().GetAwaiter().GetResult();
}
public static async Task GeoLocation() {
ChromeDriver driver = new ChromeDriver();
DevToolsSession devToolsSession = driver.CreateDevToolsSession();
var geoLocationOverrideCommandSettings = new SetGeolocationOverrideCommandSettings();
geoLocationOverrideCommandSettings.Latitude = 51.507351;
geoLocationOverrideCommandSettings.Longitude = -0.127758;
geoLocationOverrideCommandSettings.Accuracy = 1;
await devToolsSession
.GetVersionSpecificDomains<OpenQA.Selenium.DevTools.V87.DevToolsSessionDomains>()
.Emulation
.SetGeolocationOverride(geoLocationOverrideCommandSettings);
driver.Url = "<your site url>";
}
}
}
require 'selenium-webdriver'
driver = Selenium::WebDriver.for :chrome
begin
# Latitude e longitude de Tóquio, Japão
coordinates = { latitude: 35.689487,
longitude: 139.691706,
accuracy: 100 }
driver.execute_cdp('Emulation.setGeolocationOverride', coordinates)
driver.get 'https://www.google.com/search?q=selenium'
ensure
driver.quit
end
const { By, Key, Browser} = require('selenium-webdriver');
const { suite } = require('selenium-webdriver/testing');
const assert = require("assert");
suite(function(env) {
describe('Emulate geolocation', function() {
let driver;
before(async function() {
driver = await env.builder().build();
});
after(() => driver.quit());
it('Emulate coordinates of Tokyo', async function() {
const cdpConnection = await driver.createCDPConnection('page');
// Latitude and longitude of Tokyo, Japan
const coordinates = {
latitude: 35.689487,
longitude: 139.691706,
accuracy: 100,
};
await cdpConnection.execute(
"Emulation.setGeolocationOverride",
coordinates
);
await driver.get("https://kawasaki-india.com/dealer-locator/");
});
});
},{ browsers: [Browser.CHROME, Browser.FIREFOX]});
import org.openqa.selenium.chrome.ChromeDriver
import org.openqa.selenium.devtools.DevTools
fun main() {
val driver = ChromeDriver()
val coordinates : HashMap<String, Any> = HashMap<String, Any> ()
coordinates.put("latitude", 50.2334)
coordinates.put("longitude", 0.2334)
coordinates.put("accuracy", 1)
driver.executeCdpCommand("Emulation.setGeolocationOverride", coordinates)
driver.get("https://www.google.com")
}
ChromeOptions chromeOptions = new ChromeOptions();
WebDriver driver = new RemoteWebDriver(new URL("<grid-url>"), chromeOptions);
driver = new Augmenter().augment(driver);
DevTools devTools = ((HasDevTools) driver).getDevTools();
devTools.createSession();
devTools.send(Emulation.setGeolocationOverride(Optional.of(52.5043),
Optional.of(13.4501),
Optional.of(1)));
driver.get("https://my-location.org/");
driver.quit();
from selenium import webdriver
#Replace the version to match the Chrome version
import selenium.webdriver.common.devtools.v93 as devtools
async def geoLocationTest():
chrome_options = webdriver.ChromeOptions()
driver = webdriver.Remote(
command_executor='<grid-url>',
options=chrome_options
)
async with driver.bidi_connection() as session:
cdpSession = session.session
await cdpSession.execute(devtools.emulation.set_geolocation_override(latitude=41.8781,longitude=-87.6298,accuracy=100))
driver.get("https://my-location.org/")
driver.quit()
using System.Threading.Tasks;
using OpenQA.Selenium.Chrome;
using OpenQA.Selenium.DevTools;
// Replace the version to match the Chrome version
using OpenQA.Selenium.DevTools.V87.Emulation;
namespace dotnet_test {
class Program {
public static void Main(string[] args) {
GeoLocation().GetAwaiter().GetResult();
}
public static async Task GeoLocation() {
ChromeOptions chromeOptions = new ChromeOptions();
RemoteWebDriver driver = new RemoteWebDriver(new Uri("<grid-url>"), chromeOptions);
DevToolsSession devToolsSession = driver.CreateDevToolsSession();
var geoLocationOverrideCommandSettings = new SetGeolocationOverrideCommandSettings();
geoLocationOverrideCommandSettings.Latitude = 51.507351;
geoLocationOverrideCommandSettings.Longitude = -0.127758;
geoLocationOverrideCommandSettings.Accuracy = 1;
await devToolsSession
.GetVersionSpecificDomains<OpenQA.Selenium.DevTools.V87.DevToolsSessionDomains>()
.Emulation
.SetGeolocationOverride(geoLocationOverrideCommandSettings);
driver.Url = "https://my-location.org/";
}
}
}
driver = Selenium::WebDriver.for(
:remote,
:url => "<grid-url>",
:capabilities => :chrome)
begin
# Latitude e longitude de Tóquio, Japão
coordinates = { latitude: 35.689487,
longitude: 139.691706,
accuracy: 100 }
devToolsSession = driver.devtools
devToolsSession.send_cmd('Emulation.setGeolocationOverride', coordinates)
driver.get 'https://my-location.org/'
puts res
ensure
driver.quit
end
const webdriver = require('selenium-webdriver');
const BROWSER_NAME = webdriver.Browser.CHROME;
async function getDriver() {
return new webdriver.Builder()
.usingServer('<grid-url>')
.forBrowser(BROWSER_NAME)
.build();
}
async function executeCDPCommands () {
let driver = await getDriver();
await driver.get("<your site url>");
const cdpConnection = await driver.createCDPConnection('page');
//Latitude and longitude of Tokyo, Japan
const coordinates = {
latitude: 35.689487,
longitude: 139.691706,
accuracy: 100,
};
await cdpConnection.execute(
"Emulation.setGeolocationOverride",
coordinates
);
await driver.quit();
}
executeCDPCommands();
import org.openqa.selenium.WebDriver
import org.openqa.selenium.chrome.ChromeOptions
import org.openqa.selenium.devtools.HasDevTools
// Replace the version to match the Chrome version
import org.openqa.selenium.devtools.v91.emulation.Emulation
import org.openqa.selenium.remote.Augmenter
import org.openqa.selenium.remote.RemoteWebDriver
import java.net.URL
import java.util.Optional
fun main() {
val chromeOptions = ChromeOptions()
var driver: WebDriver = RemoteWebDriver(URL("<grid-url>"), chromeOptions)
driver = Augmenter().augment(driver)
val devTools = (driver as HasDevTools).devTools
devTools.createSession()
devTools.send(
Emulation.setGeolocationOverride(
Optional.of(52.5043),
Optional.of(13.4501),
Optional.of(1)
)
)
driver["https://my-location.org/"]
driver.quit()
}
Modo de Dispositivo Override
Usando a integração do Selenium com o CDP, pode-se substituir o modo do dispositivo atual e simular um novo modo. Width(largura), Height(altura), mobile(mobilidade) e deviceScaleFactor são parâmetros obrigatórios. Parâmetros opcionais incluem scale(escala), screenWidth(largura da tela),
screenHeight(altura da tela), positionX, positionY, dontSetVisible(não setar como visível), screenOrientation(orientação da tela), viewport e displayFeature.
ChromeDriver driver = new ChromeDriver();
DevTools devTools = driver.getDevTools();
devTools.createSession();
// iPhone 11 Pro dimensions
devTools.send(Emulation.setDeviceMetricsOverride(375,
812,
50,
true,
Optional.empty(),
Optional.empty(),
Optional.empty(),
Optional.empty(),
Optional.empty(),
Optional.empty(),
Optional.empty(),
Optional.empty(),
Optional.empty()));
driver.get("https://selenium.dev/");
driver.quit();
from selenium import webdriver
driver = webdriver.Chrome()
// iPhone 11 Pro dimensions
set_device_metrics_override = dict({
"width": 375,
"height": 812,
"deviceScaleFactor": 50,
"mobile": True
})
driver.execute_cdp_cmd('Emulation.setDeviceMetricsOverride', set_device_metrics_override)
driver.get("<your site url>")
using OpenQA.Selenium;
using OpenQA.Selenium.Chrome;
using OpenQA.Selenium.DevTools;
using System.Threading.Tasks;
using OpenQA.Selenium.DevTools.V91.Emulation;
using WebDriverManager;
using WebDriverManager.DriverConfigs.Impl;
using DevToolsSessionDomains = OpenQA.Selenium.DevTools.V91.DevToolsSessionDomains;
namespace Selenium4Sample {
public class ExampleDevice {
protected IDevToolsSession session;
protected IWebDriver driver;
protected DevToolsSessionDomains devToolsSession;
public async Task DeviceModeTest() {
new DriverManager().SetUpDriver(new ChromeConfig());
ChromeOptions chromeOptions = new ChromeOptions();
//Set ChromeDriver
driver = new ChromeDriver();
//Get DevTools
IDevTools devTools = driver as IDevTools;
//DevTools Session
session = devTools.GetDevToolsSession();
var deviceModeSetting = new SetDeviceMetricsOverrideCommandSettings();
deviceModeSetting.Width = 600;
deviceModeSetting.Height = 1000;
deviceModeSetting.Mobile = true;
deviceModeSetting.DeviceScaleFactor = 50;
await session
.GetVersionSpecificDomains < OpenQA.Selenium.DevTools.V91.DevToolsSessionDomains > ()
.Emulation
.SetDeviceMetricsOverride(deviceModeSetting);
driver.Url = "<your site url>";
}
}
}
require 'selenium-webdriver'
driver = Selenium::WebDriver.for :chrome
begin
metrics = { width: 300,
height: 200,
mobile: true,
deviceScaleFactor: 50 }
driver.execute_cdp('Emulation.setDeviceMetricsOverride', metrics)
driver.get 'https://www.google.com'
ensure
driver.quit
end
const {Builder} = require('selenium-webdriver');
const firefox = require('selenium-webdriver/firefox');
const options = new firefox.Options();
// enable debugger for CDP
options.enableDebugger();
(async function example() {
try {
let driver = await new Builder().forBrowser('firefox').setFirefoxOptions(options).build();
const pageCdpConnection = await driver.createCDPConnection('page');
const metrics = {
width: 300,
height: 200,
deviceScaleFactor: 50,
mobile: true,
};
await pageCdpConnection.execute(
"Emulation.setDeviceMetricsOverride",
metrics
);
await driver.get("https://www.google.com");
await driver.quit();
} catch (e) {
console.log(e);
}
})();
fun kotlinOverridDeviceMode() {
val driver = ChromeDriver()
val deviceMetrics: Map<String, Any> = object : HashMap<String, Any>() {
init {
put("width", 600)
put("height", 1000)
put("mobile", true)
put("deviceScaleFactor", 50)
}
}
driver.executeCdpCommand("Emulation.setDeviceMetricsOverride", deviceMetrics)
driver.get("https://www.google.com")
driver.quit()
}
Coletando Métricas de Desempenho
Colete várias métricas de desempenho enquanto navega no aplicativo.
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.devtools.DevTools;
public void performanceMetricsExample() {
ChromeDriver driver = new ChromeDriver();
DevTools devTools = driver.getDevTools();
devTools.createSession();
devTools.send(Performance.enable(Optional.empty()));
List<Metric> metricList = devTools.send(Performance.getMetrics());
driver.get("https://google.com");
driver.quit();
for(Metric m : metricList) {
System.out.println(m.getName() + " = " + m.getValue());
}
}
from selenium import webdriver
driver = webdriver.Chrome()
driver.get('https://www.duckduckgo.com')
driver.execute_cdp_cmd('Performance.enable', {})
t = driver.execute_cdp_cmd('Performance.getMetrics', {})
print(t)
driver.quit()
// File must contain the following using statements
using OpenQA.Selenium;
using OpenQA.Selenium.Chrome;
using OpenQA.Selenium.DevTools;
// We must use a version-specific set of domains
using OpenQA.Selenium.DevTools.V94.Performance;
public async Task PerformanceMetricsExample()
{
IWebDriver driver = new ChromeDriver();
IDevTools devTools = driver as IDevTools;
DevToolsSession session = devTools.GetDevToolsSession();
await session.SendCommand<EnableCommandSettings>(new EnableCommandSettings());
var metricsResponse =
await session.SendCommand<GetMetricsCommandSettings, GetMetricsCommandResponse>(
new GetMetricsCommandSettings());
driver.Navigate().GoToUrl("http://www.google.com");
driver.Quit();
var metrics = metricsResponse.Metrics;
foreach (Metric metric in metrics)
{
Console.WriteLine("{0} = {1}", metric.Name, metric.Value);
}
}
require 'selenium-webdriver'
driver = Selenium::WebDriver.for :chrome
begin
driver.get 'https://www.duckduckgo.com'
driver.execute_cdp('Performance.enable', {})
metrics = driver.execute_cdp('Performance.getMetrics', {})
puts metrics
ensure
driver.quit
end
await driver.get("https://www.duckduckgo.com");
await driver.sendAndGetDevToolsCommand('Performance.enable')
let result = await driver.sendAndGetDevToolsCommand('Performance.getMetrics')
console.log(result)
await driver.quit();
val driver = ChromeDriver()
val devTools = driver.devTools
devTools.createSession()
devTools.send(Performance.enable(Optional.empty()))
val metricList: List<Metric> = devTools.send(Performance.getMetrics())
driver["https://google.com"]
driver.quit()
for (m in metricList) {
println(m.name.toString() + " = " + m.value)
}
3 - API BiDirecional (CDP implementation)
A seguinte lista de APIs crescerá à medida que o projeto Selenium se prepara
para suportar casos de uso do mundo real. Se houver funcionalidades adicionais que você gostaria de ver, por favor, levante uma solicitação de recurso.
Registrar autenticação básica
Alguns aplicativos fazem o uso da autenticação do navegador para proteger suas páginas. Com o Selenium, você pode automatizar a entrada de credenciais básicas de autenticação sempre que for necessário.
Predicate<URI> uriPredicate = uri -> uri.getHost().contains("your-domain.com");
((HasAuthentication) driver).register(uriPredicate, UsernameAndPassword.of("admin", "password"));
driver.get("https://your-domain.com/login");
NetworkAuthenticationHandler handler = new NetworkAuthenticationHandler()
{
UriMatcher = (d) => d.Host.Contains("your-domain.com"),
Credentials = new PasswordCredentials("admin", "password")
};
INetwork networkInterceptor = driver.Manage().Network;
networkInterceptor.AddAuthenticationHandler(handler);
await networkInterceptor.StartMonitoring();
require 'selenium-webdriver'
driver = Selenium::WebDriver.for :chrome
begin
driver.devtools.new
driver.register(username: 'username', password: 'password')
driver.get '<your site url>'
ensure
driver.quit
end
const {Builder} = require('selenium-webdriver');
(async function example() {
try {
let driver = await new Builder()
.forBrowser('chrome')
.build();
const pageCdpConnection = await driver.createCDPConnection('page');
await driver.register('username', 'password', pageCdpConnection);
await driver.get('https://the-internet.herokuapp.com/basic_auth');
await driver.quit();
}catch (e){
console.log(e)
}
}())
val uriPredicate = Predicate { uri: URI ->
uri.host.contains("your-domain.com")
}
(driver as HasAuthentication).register(uriPredicate, UsernameAndPassword.of("admin", "password"))
driver.get("https://your-domain.com/login")
Mutation Observation
Mutation Observation(Observação de Mutação) é a capacidade de capturar eventos via WebDriver BiDi quando há mutações DOM em um elemento específico no DOM.
ChromeDriver driver = new ChromeDriver();
AtomicReference<DomMutationEvent> seen = new AtomicReference<>();
CountDownLatch latch = new CountDownLatch(1);
((HasLogEvents) driver).onLogEvent(domMutation(mutation -> {
seen.set(mutation);
latch.countDown();
}));
driver.get("https://www.google.com");
WebElement span = driver.findElement(By.cssSelector("span"));
((JavascriptExecutor) driver).executeScript("arguments[0].setAttribute('cheese', 'gouda');", span);
assertThat(latch.await(10, SECONDS), is(true));
assertThat(seen.get().getAttributeName(), is("cheese"));
assertThat(seen.get().getCurrentValue(), is("gouda"));
driver.quit();
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.wait import WebDriverWait
driver = webdriver.Chrome()
async with driver.log.mutation_events() as event:
pages.load("dynamic.html")
driver.find_element(By.ID, "reveal").click()
WebDriverWait(driver, 5)\
.until(EC.visibility_of(driver.find_element(By.ID, "revealed")))
assert event["attribute_name"] == "style"
assert event["current_value"] == ""
assert event["old_value"] == "display:none;"
List<DomMutationData> attributeValueChanges = new List<DomMutationData>();
DefaultWait<List<DomMutationData>> wait = new DefaultWait<List<DomMutationData>>(attributeValueChanges);
wait.Timeout = TimeSpan.FromSeconds(3);
IJavaScriptEngine monitor = new JavaScriptEngine(driver);
monitor.DomMutated += (sender, e) =>
{
attributeValueChanges.Add(e.AttributeData);
};
await monitor.StartEventMonitoring();
driver.Navigate().GoToUrl("http://www.google.com");
IWebElement span = driver.FindElement(By.CssSelector("span"));
await monitor.EnableDomMutationMonitoring();
((IJavaScriptExecutor) driver).ExecuteScript("arguments[0].setAttribute('cheese', 'gouda');", span);
wait.Until((list) => list.Count > 0);
Console.WriteLine("Found {0} DOM mutation events", attributeValueChanges.Count);
foreach(var record in attributeValueChanges)
{
Console.WriteLine("Attribute name: {0}", record.AttributeName);
Console.WriteLine("Attribute value: {0}", record.AttributeValue);
}
await monitor.DisableDomMutationMonitoring();
require 'selenium-webdriver'
driver = Selenium::WebDriver.for :firefox
begin
driver.on_log_event(:mutation) { |mutation| mutations.push(mutation) }
driver.navigate.to url_for('dynamic.html')
driver.find_element(id: 'reveal').click
wait.until { mutations.any? }
mutation = mutations.first
expect(mutation.element).to eq(driver.find_element(id: 'revealed'))
expect(mutation.attribute_name).to eq('style')
expect(mutation.current_value).to eq('')
expect(mutation.old_value).to eq('display:none;')
ensure
driver.quit
end
const {Builder, until} = require('selenium-webdriver');
const assert = require("assert");
(async function example() {
try {
let driver = await new Builder()
.forBrowser('chrome')
.build();
const cdpConnection = await driver.createCDPConnection('page');
await driver.logMutationEvents(cdpConnection, event => {
assert.deepStrictEqual(event['attribute_name'], 'style');
assert.deepStrictEqual(event['current_value'], "");
assert.deepStrictEqual(event['old_value'], "display:none;");
});
await driver.get('dynamic.html');
await driver.findElement({id: 'reveal'}).click();
let revealed = driver.findElement({id: 'revealed'});
await driver.wait(until.elementIsVisible(revealed), 5000);
await driver.quit();
}catch (e){
console.log(e)
}
}())
Vigie eventos console.log
Vigie os eventos console.log
e registre os callbacks(retornos de chamada) para processar o evento.
ChromeDriver driver = new ChromeDriver();
DevTools devTools = driver.getDevTools();
devTools.createSession();
devTools.send(Log.enable());
devTools.addListener(Log.entryAdded(),
logEntry -> {
System.out.println("log: "+logEntry.getText());
System.out.println("level: "+logEntry.getLevel());
});
driver.get("http://the-internet.herokuapp.com/broken_images");
// Check the terminal output for the browser console messages.
driver.quit();
import trio
from selenium import webdriver
from selenium.webdriver.common.log import Log
async def printConsoleLogs():
chrome_options = webdriver.ChromeOptions()
driver = webdriver.Chrome()
driver.get("http://www.google.com")
async with driver.bidi_connection() as session:
log = Log(driver, session)
from selenium.webdriver.common.bidi.console import Console
async with log.add_listener(Console.ALL) as messages:
driver.execute_script("console.log('I love cheese')")
print(messages["message"])
driver.quit()
trio.run(printConsoleLogs)
IJavaScriptEngine monitor = new JavaScriptEngine(driver);
List<string> consoleMessages = new List<string>();
monitor.JavaScriptConsoleApiCalled += (sender, e) =>
{
Console.WriteLine("Log: {0}", e.MessageContent);
};
await monitor.StartEventMonitoring();
require 'selenium-webdriver'
driver = Selenium::WebDriver.for :chrome
begin
driver.get 'http://www.google.com'
logs = []
driver.on_log_event(:console) do |event|
logs.push(event)
puts logs.length
end
driver.execute_script('console.log("here")')
ensure
driver.quit
end
const {Builder} = require('selenium-webdriver');
(async () => {
try {
let driver = new Builder()
.forBrowser('chrome')
.build();
const cdpConnection = await driver.createCDPConnection('page');
await driver.onLogEvent(cdpConnection, function (event) {
console.log(event['args'][0]['value']);
});
await driver.executeScript('console.log("here")');
await driver.quit();
}catch (e){
console.log(e);
}
})()
fun kotlinConsoleLogExample() {
val driver = ChromeDriver()
val devTools = driver.devTools
devTools.createSession()
val logConsole = { c: ConsoleEvent -> print("Console log message is: " + c.messages)}
devTools.domains.events().addConsoleListener(logConsole)
driver.get("https://www.google.com")
val executor = driver as JavascriptExecutor
executor.executeScript("console.log('Hello World')")
val input = driver.findElement(By.name("q"))
input.sendKeys("Selenium 4")
input.sendKeys(Keys.RETURN)
driver.quit()
}
Vigie exceções JS
Vigie as exceções JS
e registre callbacks(retornos de chamada) para processar os detalhes da exceção.
import org.openqa.selenium.*;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.devtools.DevTools;
public void jsExceptionsExample() {
ChromeDriver driver = new ChromeDriver();
DevTools devTools = driver.getDevTools();
devTools.createSession();
List<JavascriptException> jsExceptionsList = new ArrayList<>();
Consumer<JavascriptException> addEntry = jsExceptionsList::add;
devTools.getDomains().events().addJavascriptExceptionListener(addEntry);
driver.get("<your site url>");
WebElement link2click = driver.findElement(By.linkText("<your link text>"));
((JavascriptExecutor) driver).executeScript("arguments[0].setAttribute(arguments[1], arguments[2]);",
link2click, "onclick", "throw new Error('Hello, world!')");
link2click.click();
for (JavascriptException jsException : jsExceptionsList) {
System.out.println("JS exception message: " + jsException.getMessage());
System.out.println("JS exception system information: " + jsException.getSystemInformation());
jsException.printStackTrace();
}
}
async def catchJSException():
chrome_options = webdriver.ChromeOptions()
driver = webdriver.Chrome()
async with driver.bidi_connection() as session:
driver.get("<your site url>")
log = Log(driver, session)
async with log.add_js_error_listener() as messages:
# Operation on the website that throws an JS error
print(messages)
driver.quit()
List<string> exceptionMessages = new List<string>();
IJavaScriptEngine monitor = new JavaScriptEngine(driver);
monitor.JavaScriptExceptionThrown += (sender, e) =>
{
exceptionMessages.Add(e.Message);
};
await monitor.StartEventMonitoring();
driver.Navigate.GoToUrl("<your site url>");
IWebElement link2click = driver.FindElement(By.LinkText("<your link text>"));
((IJavaScriptExecutor) driver).ExecuteScript("arguments[0].setAttribute(arguments[1], arguments[2]);",
link2click, "onclick", "throw new Error('Hello, world!')");
link2click.Click();
foreach (string message in exceptionMessages)
{
Console.WriteLine("JS exception message: {0}", message);
}
require 'selenium-webdriver'
driver = Selenium::WebDriver.for :chrome
begin
driver.get '<your-site-url>'
exceptions = []
driver.on_log_event(:exception) do |event|
exceptions.push(event)
puts exceptions.length
end
#Ações que causam exceções JS
ensure
driver.quit
end
const {Builder, By} = require('selenium-webdriver');
(async () => {
try {
let driver = new Builder()
.forBrowser('chrome')
.build();
const cdpConnection = await driver.createCDPConnection('page')
await driver.onLogException(cdpConnection, function (event) {
console.log(event['exceptionDetails']);
})
await driver.get('https://the-internet.herokuapp.com');
const link = await driver.findElement(By.linkText('Checkboxes'));
await driver.executeScript("arguments[0].setAttribute(arguments[1], arguments[2]);", link, "onclick","throw new Error('Hello, world!')");
await link.click();
await driver.quit();
}catch (e){
console.log(e);
}
})()
fun kotlinJsErrorListener() {
val driver = ChromeDriver()
val devTools = driver.devTools
devTools.createSession()
val logJsError = { j: JavascriptException -> print("Javascript error: '" + j.localizedMessage + "'.") }
devTools.domains.events().addJavascriptExceptionListener(logJsError)
driver.get("https://www.google.com")
val link2click = driver.findElement(By.name("q"))
(driver as JavascriptExecutor).executeScript(
"arguments[0].setAttribute(arguments[1], arguments[2]);",
link2click, "onclick", "throw new Error('Hello, world!')"
)
link2click.click()
driver.quit()
}
Interceptação de Rede
Se você quer capturar eventos de rede que chegam ao navegador e deseja manipulá-los, você pode fazer
com os exemplos a seguir.
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.devtools.HasDevTools;
import org.openqa.selenium.devtools.NetworkInterceptor;
import org.openqa.selenium.remote.http.Contents;
import org.openqa.selenium.remote.http.Filter;
import org.openqa.selenium.remote.http.HttpResponse;
import org.openqa.selenium.remote.http.Route;
NetworkInterceptor interceptor = new NetworkInterceptor(
driver,
Route.matching(req -> true)
.to(() -> req -> new HttpResponse()
.setStatus(200)
.addHeader("Content-Type", MediaType.HTML_UTF_8.toString())
.setContent(utf8String("Creamy, delicious cheese!"))));
driver.get("https://example-sausages-site.com");
String source = driver.getPageSource();
assertThat(source).contains("delicious cheese!");
Currently unavailable in python due the inability to mix certain async and sync commands
require 'selenium-webdriver'
driver = Selenium::WebDriver.for :chrome
driver.intercept do |request, &continue|
uri = URI(request.url)
if uri.path.end_with?('one.js')
uri.path = '/devtools_request_interception_test/two.js'
request.url = uri.to_s
end
continue.call(request)
end
driver.navigate.to url_for('devToolsRequestInterceptionTest.html')
driver.find_element(tag_name: 'button').click
expect(driver.find_element(id: 'result').text).to eq('two')
const connection = await driver.createCDPConnection('page')
let url = fileServer.whereIs("/cheese")
let httpResponse = new HttpResponse(url)
httpResponse.addHeaders("Content-Type", "UTF-8")
httpResponse.body = "sausages"
await driver.onIntercept(connection, httpResponse, async function () {
let body = await driver.getPageSource()
assert.strictEqual(body.includes("sausages"), true, `Body contains: ${body}`)
})
driver.get(url)
val driver = ChromeDriver()
val interceptor = new NetworkInterceptor(
driver,
Route.matching(req -> true)
.to(() -> req -> new HttpResponse()
.setStatus(200)
.addHeader("Content-Type", MediaType.HTML_UTF_8.toString())
.setContent(utf8String("Creamy, delicious cheese!"))))
driver.get(appServer.whereIs("/cheese"))
String source = driver.getPageSource()
4 - BiDirectional API (W3C compliant)
Page being translated from
English to Portuguese. Do you speak Portuguese? Help us to translate
it by sending us pull requests!
The following list of APIs will be growing as the WebDriver BiDirectional Protocol grows
and browser vendors implement the same.
Additionally, Selenium will try to support real-world use cases that internally use a combination of W3C BiDi protocol APIs.
If there is additional functionality you’d like to see, please raise a
feature request.
4.1 - Browsing Context
Page being translated from
English to Portuguese. Do you speak Portuguese? Help us to translate
it by sending us pull requests!
This section contains the APIs related to browsing context commands.
Open a new window
Creates a new browsing context in a new window.
BrowsingContext browsingContext = new BrowsingContext(driver, WindowType.WINDOW);
Open a new tab
Creates a new browsing context in a new tab.
BrowsingContext browsingContext = new BrowsingContext(driver, WindowType.TAB);
Use existing window handle
Creates a browsing context for the existing tab/window to run commands.
String id = driver.getWindowHandle();
BrowsingContext browsingContext = new BrowsingContext(driver, id);
Open a window with a reference browsing context
A reference browsing context is a top-level browsing context.
The API allows to pass the reference browsing context, which is used to create a new window. The implementation is operating system specific.
BrowsingContext
browsingContext =
new BrowsingContext(driver, WindowType.WINDOW, driver.getWindowHandle());
Open a tab with a reference browsing context
A reference browsing context is a top-level browsing context.
The API allows to pass the reference browsing context, which is used to create a new tab. The implementation is operating system specific.
BrowsingContext
browsingContext =
new BrowsingContext(driver, WindowType.TAB, driver.getWindowHandle());
Navigate to a URL
BrowsingContext browsingContext = new BrowsingContext(driver, WindowType.TAB);
NavigationResult info = browsingContext.navigate("https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html");
Assertions.assertNotNull(browsingContext.getId());
Assertions.assertNull(info.getNavigationId());
Assertions.assertTrue(info.getUrl().contains("/bidi/logEntryAdded.html"));
Navigate to a URL with readiness state
BrowsingContext browsingContext = new BrowsingContext(driver, WindowType.TAB);
NavigationResult info = browsingContext.navigate("https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html",
ReadinessState.COMPLETE);
Assertions.assertNotNull(browsingContext.getId());
Assertions.assertNull(info.getNavigationId());
Assertions.assertTrue(info.getUrl().contains("/bidi/logEntryAdded.html"));
Get browsing context tree
Provides a tree of all browsing contexts descending from the parent browsing context, including the parent browsing context.
String referenceContextId = driver.getWindowHandle();
BrowsingContext parentWindow = new BrowsingContext(driver, referenceContextId);
parentWindow.navigate("https://www.selenium.dev/selenium/web/iframes.html", ReadinessState.COMPLETE);
List<BrowsingContextInfo> contextInfoList = parentWindow.getTree();
Assertions.assertEquals(1, contextInfoList.size());
BrowsingContextInfo info = contextInfoList.get(0);
Assertions.assertEquals(1, info.getChildren().size());
Assertions.assertEquals(referenceContextId, info.getId());
Assertions.assertTrue(info.getChildren().get(0).getUrl().contains("formPage.html"));
Get browsing context tree with depth
Provides a tree of all browsing contexts descending from the parent browsing context, including the parent browsing context upto the depth value passed.
String referenceContextId = driver.getWindowHandle();
BrowsingContext parentWindow = new BrowsingContext(driver, referenceContextId);
parentWindow.navigate("https://www.selenium.dev/selenium/web/iframes.html", ReadinessState.COMPLETE);
List<BrowsingContextInfo> contextInfoList = parentWindow.getTree(0);
Assertions.assertEquals(1, contextInfoList.size());
BrowsingContextInfo info = contextInfoList.get(0);
Assertions.assertNull(info.getChildren()); // since depth is 0
Assertions.assertEquals(referenceContextId, info.getId());
Get All Top level browsing contexts
BrowsingContext window1 = new BrowsingContext(driver, driver.getWindowHandle());
BrowsingContext window2 = new BrowsingContext(driver, WindowType.WINDOW);
List<BrowsingContextInfo> contextInfoList = window1.getTopLevelContexts();
Assertions.assertEquals(2, contextInfoList.size());
Close a tab/window
BrowsingContext window1 = new BrowsingContext(driver, WindowType.WINDOW);
BrowsingContext window2 = new BrowsingContext(driver, WindowType.WINDOW);
window2.close();
Assertions.assertThrows(BiDiException.class, window2::getTree);
4.2 - BiDirectional API (W3C compliant)
Page being translated from
English to Portuguese. Do you speak Portuguese? Help us to translate
it by sending us pull requests!
This section contains the APIs related to logging.
Listen to console.log
events
Listen to the console.log
events and register callbacks to process the event.
try (LogInspector logInspector = new LogInspector(driver)) {
CompletableFuture<ConsoleLogEntry> future = new CompletableFuture<>();
logInspector.onConsoleLog(future::complete);
driver.get("https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html");
driver.findElement(By.id("consoleLog")).click();
ConsoleLogEntry logEntry = future.get(5, TimeUnit.SECONDS);
Assertions.assertEquals("Hello, world!", logEntry.getText());
Assertions.assertNull(logEntry.getRealm());
Assertions.assertEquals(1, logEntry.getArgs().size());
Assertions.assertEquals("console", logEntry.getType());
Assertions.assertEquals("log", logEntry.getMethod());
Assertions.assertNull(logEntry.getStackTrace());
}
const inspector = await LogInspector(driver)
await inspector.onConsoleEntry(function (log) {
logEntry = log
})
await driver.get('https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html')
await driver.findElement({ id: 'consoleLog' }).click()
assert.equal(logEntry.text, 'Hello, world!')
assert.equal(logEntry.realm, null)
assert.equal(logEntry.type, 'console')
assert.equal(logEntry.level, 'info')
assert.equal(logEntry.method, 'log')
assert.equal(logEntry.stackTrace, null)
assert.equal(logEntry.args.length, 1)
Listen to JS Exceptions
Listen to the JS Exceptions
and register callbacks to process the exception details.
try (LogInspector logInspector = new LogInspector(driver)) {
CompletableFuture<JavascriptLogEntry> future = new CompletableFuture<>();
logInspector.onJavaScriptException(future::complete);
driver.get("https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html");
driver.findElement(By.id("jsException")).click();
JavascriptLogEntry logEntry = future.get(5, TimeUnit.SECONDS);
Assertions.assertEquals("Error: Not working", logEntry.getText());
Assertions.assertEquals("javascript", logEntry.getType());
}
const inspector = await LogInspector(driver)
await inspector.onJavascriptException(function (log) {
logEntry = log
})
await driver.get('https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html')
await driver.findElement({ id: 'jsException' }).click()
assert.equal(logEntry.text, 'Error: Not working')
assert.equal(logEntry.type, 'javascript')
assert.equal(logEntry.level, 'error')
Listen to JS Logs
Listen to all JS logs at all levels and register callbacks to process the log.
try (LogInspector logInspector = new LogInspector(driver)) {
CompletableFuture<JavascriptLogEntry> future = new CompletableFuture<>();
logInspector.onJavaScriptLog(future::complete);
driver.get("https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html");
driver.findElement(By.id("jsException")).click();
JavascriptLogEntry logEntry = future.get(5, TimeUnit.SECONDS);
Assertions.assertEquals("Error: Not working", logEntry.getText());
Assertions.assertEquals("javascript", logEntry.getType());
Assertions.assertEquals(LogLevel.ERROR, logEntry.getLevel());
}