Chrome DevTools Script Features
Script features using CDP.
Page being translated from English to Chinese. Do you speak Chinese? Help us to translate it by sending us pull requests!
While Selenium 4 provides direct access to the Chrome DevTools Protocol, these methods will eventually be removed when WebDriver BiDi implemented.
Script Pinning
ScriptKey key = ((JavascriptExecutor) driver).pin("return arguments;");
List<Object> arguments =
(List<Object>) ((JavascriptExecutor) driver).executeScript(key, 1, true, element);
Show full example
package dev.selenium.bidi.cdp;
import static org.openqa.selenium.devtools.events.CdpEventTypes.domMutation;
import dev.selenium.BaseTest;
import java.time.Duration;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.openqa.selenium.*;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.logging.HasLogEvents;
import org.openqa.selenium.support.ui.WebDriverWait;
public class ScriptTest extends BaseTest {
@BeforeEach
public void createSession() {
driver = new ChromeDriver();
wait = new WebDriverWait(driver, Duration.ofSeconds(10));
}
@Test
public void pinScript() {
driver.get("https://www.selenium.dev/selenium/web/xhtmlTest.html");
WebElement element = driver.findElement(By.id("id1"));
ScriptKey key = ((JavascriptExecutor) driver).pin("return arguments;");
List<Object> arguments =
(List<Object>) ((JavascriptExecutor) driver).executeScript(key, 1, true, element);
Assertions.assertEquals(List.of(1L, true, element), arguments);
}
@Test
public void mutatedElements() {
driver.get("https://www.selenium.dev/selenium/web/dynamic.html");
CopyOnWriteArrayList<WebElement> mutations = new CopyOnWriteArrayList<>();
((HasLogEvents) driver).onLogEvent(domMutation(e -> mutations.add(e.getElement())));
driver.findElement(By.id("reveal")).click();
wait.until(_d -> !mutations.isEmpty());
Assertions.assertEquals(mutations.get(0), driver.findElement(By.id("revealed")));
}
}
var key = await new JavaScriptEngine(driver).PinScript("return arguments;");
var arguments = ((WebDriver)driver).ExecuteScript(key, 1, true, element);
Show full example
using System;
using System.Collections;
using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.IdentityModel.Tokens;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using OpenQA.Selenium;
using OpenQA.Selenium.Support.UI;
namespace SeleniumDocs.BiDi.CDP
{
[TestClass]
public class ScriptTest : BaseChromeTest
{
[TestMethod]
public async Task PinScript()
{
driver.Url = "https://www.selenium.dev/selenium/web/xhtmlTest.html";
var element = driver.FindElement(By.Id("id1"));
var key = await new JavaScriptEngine(driver).PinScript("return arguments;");
var arguments = ((WebDriver)driver).ExecuteScript(key, 1, true, element);
var expected = new List<object>
{
1L,
true,
element
};
CollectionAssert.AreEqual(expected, (ICollection)arguments);
}
[TestMethod]
public async Task MutatedElements()
{
driver.Url = "https://www.selenium.dev/selenium/web/dynamic.html";
var mutations = new List<IWebElement>();
using IJavaScriptEngine monitor = new JavaScriptEngine(driver);
monitor.DomMutated += (_, e) =>
{
var locator = By.CssSelector($"*[data-__webdriver_id='{e.AttributeData.TargetId}']");
mutations.Add(driver.FindElement(locator));
};
await monitor.StartEventMonitoring();
await monitor.EnableDomMutationMonitoring();
driver.FindElement(By.Id("reveal")).Click();
new WebDriverWait(driver, TimeSpan.FromSeconds(5)).Until(_ => !mutations.IsNullOrEmpty());
await monitor.DisableDomMutationMonitoring();
monitor.StopEventMonitoring();
var revealed = driver.FindElement(By.Id("revealed"));
Assert.AreEqual(revealed, mutations[0]);
}
}
}
key = driver.pin_script('return arguments;')
arguments = driver.execute_script(key, 1, true, element)
Show full example
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe 'Script' do
let(:driver) { start_session }
it 'pins script' do
driver.get('https://www.selenium.dev/selenium/web/xhtmlTest.html')
element = driver.find_element(id: 'id1')
key = driver.pin_script('return arguments;')
arguments = driver.execute_script(key, 1, true, element)
expect(arguments).to eq([1, true, element])
end
it 'gets mutated elements' do
driver.get 'https://www.selenium.dev/selenium/web/dynamic.html'
mutations = []
driver.on_log_event(:mutation) { |mutation| mutations << mutation.element }
driver.find_element(id: 'reveal').click
Selenium::WebDriver::Wait.new(timeout: 30).until { mutations.any? }
expect(mutations).to include(driver.find_element(id: 'revealed'))
end
end
DOM Mutation Handlers
Show full example
package dev.selenium.bidi.cdp;
import com.google.common.net.MediaType;
import dev.selenium.BaseTest;
import java.net.*;
import java.time.Duration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Predicate;
import java.util.function.Supplier;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.openqa.selenium.*;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.devtools.DevTools;
import org.openqa.selenium.devtools.HasDevTools;
import org.openqa.selenium.devtools.NetworkInterceptor;
import org.openqa.selenium.devtools.v134.browser.Browser;
import org.openqa.selenium.devtools.v134.network.Network;
import org.openqa.selenium.devtools.v134.performance.Performance;
import org.openqa.selenium.devtools.v134.performance.model.Metric;
import org.openqa.selenium.remote.http.*;
import org.openqa.selenium.support.ui.WebDriverWait;
public class NetworkTest extends BaseTest {
@BeforeEach
public void createSession() {
driver = new ChromeDriver();
wait = new WebDriverWait(driver, Duration.ofSeconds(10));
}
@Test
public void basicAuthentication() {
Predicate<URI> uriPredicate = uri -> uri.toString().contains("herokuapp.com");
Supplier<Credentials> authentication = UsernameAndPassword.of("admin", "admin");
((HasAuthentication) driver).register(uriPredicate, authentication);
driver.get("https://the-internet.herokuapp.com/basic_auth");
String successMessage = "Congratulations! You must have the proper credentials.";
WebElement elementMessage = driver.findElement(By.tagName("p"));
Assertions.assertEquals(successMessage, elementMessage.getText());
}
@Test
public void recordResponse() {
CopyOnWriteArrayList<String> contentType = new CopyOnWriteArrayList<>();
try (NetworkInterceptor ignored =
new NetworkInterceptor(
driver,
(Filter)
next ->
req -> {
HttpResponse res = next.execute(req);
contentType.add(res.getHeader("Content-Type"));
return res;
})) {
driver.get("https://www.selenium.dev/selenium/web/blank.html");
wait.until(_d -> contentType.size() > 1);
}
Assertions.assertEquals("text/html; charset=utf-8", contentType.get(0));
}
@Test
public void transformResponses() {
try (NetworkInterceptor ignored =
new NetworkInterceptor(
driver,
Route.matching(req -> true)
.to(
() ->
req ->
new HttpResponse()
.setStatus(200)
.addHeader("Content-Type", MediaType.HTML_UTF_8.toString())
.setContent(Contents.utf8String("Creamy, delicious cheese!"))))) {
driver.get("https://www.selenium.dev/selenium/web/blank.html");
}
WebElement body = driver.findElement(By.tagName("body"));
Assertions.assertEquals("Creamy, delicious cheese!", body.getText());
}
@Test
public void interceptRequests() {
AtomicBoolean completed = new AtomicBoolean(false);
try (NetworkInterceptor ignored =
new NetworkInterceptor(
driver,
(Filter)
next ->
req -> {
if (req.getUri().contains("one.js")) {
req =
new HttpRequest(
HttpMethod.GET, req.getUri().replace("one.js", "two.js"));
}
completed.set(true);
return next.execute(req);
})) {
driver.get("https://www.selenium.dev/selenium/web/devToolsRequestInterceptionTest.html");
driver.findElement(By.tagName("button")).click();
}
Assertions.assertEquals("two", driver.findElement(By.id("result")).getText());
}
@Test
public void performanceMetrics() {
driver.get("https://www.selenium.dev/selenium/web/frameset.html");
DevTools devTools = ((HasDevTools) driver).getDevTools();
devTools.createSession();
devTools.send(Performance.enable(Optional.empty()));
List<Metric> metricList = devTools.send(Performance.getMetrics());
Map<String, Number> metrics = new HashMap<>();
for (Metric metric : metricList) {
metrics.put(metric.getName(), metric.getValue());
}
Assertions.assertTrue(metrics.get("DevToolsCommandDuration").doubleValue() > 0);
Assertions.assertEquals(12, metrics.get("Frames").intValue());
}
@Test
public void setCookie() {
DevTools devTools = ((HasDevTools) driver).getDevTools();
devTools.createSession();
devTools.send(
Network.setCookie(
"cheese",
"gouda",
Optional.empty(),
Optional.of("www.selenium.dev"),
Optional.empty(),
Optional.of(true),
Optional.empty(),
Optional.empty(),
Optional.empty(),
Optional.empty(),
Optional.empty(),
Optional.empty(),
Optional.empty(),
Optional.empty()));
driver.get("https://www.selenium.dev");
Cookie cheese = driver.manage().getCookieNamed("cheese");
Assertions.assertEquals("gouda", cheese.getValue());
}
@Test
public void waitForDownload() {
driver.get("https://www.selenium.dev/selenium/web/downloads/download.html");
DevTools devTools = ((HasDevTools) driver).getDevTools();
devTools.createSession();
devTools.send(
Browser.setDownloadBehavior(
Browser.SetDownloadBehaviorBehavior.ALLOWANDNAME,
Optional.empty(),
Optional.of(""),
Optional.of(true)));
AtomicBoolean completed = new AtomicBoolean(false);
devTools.addListener(
Browser.downloadProgress(),
e -> completed.set(Objects.equals(e.getState().toString(), "completed")));
driver.findElement(By.id("file-2")).click();
Assertions.assertDoesNotThrow(() -> wait.until(_d -> completed));
}
}
async with driver.bidi_connection() as session:
async with Log(driver, session).mutation_events() as event:
Show full example
import pytest
import trio
from selenium.webdriver.common.by import By
from selenium.webdriver.common.log import Log
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
@pytest.mark.trio
async def test_mutation(driver):
async with driver.bidi_connection() as session:
async with Log(driver, session).mutation_events() as event:
await trio.to_thread.run_sync(lambda: driver.get('https://www.selenium.dev/selenium/web/dynamic.html'))
await trio.to_thread.run_sync(lambda: WebDriverWait(driver, 10).until(EC.element_to_be_clickable((By.ID, "reveal"))))
await trio.to_thread.run_sync(lambda: driver.find_element(By.ID, "reveal").click())
assert event["element"] == driver.find_element(By.ID, "revealed")
using IJavaScriptEngine monitor = new JavaScriptEngine(driver);
monitor.DomMutated += (_, e) =>
{
var locator = By.CssSelector($"*[data-__webdriver_id='{e.AttributeData.TargetId}']");
mutations.Add(driver.FindElement(locator));
};
await monitor.StartEventMonitoring();
await monitor.EnableDomMutationMonitoring();
Show full example
using System;
using System.Collections;
using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.IdentityModel.Tokens;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using OpenQA.Selenium;
using OpenQA.Selenium.Support.UI;
namespace SeleniumDocs.BiDi.CDP
{
[TestClass]
public class ScriptTest : BaseChromeTest
{
[TestMethod]
public async Task PinScript()
{
driver.Url = "https://www.selenium.dev/selenium/web/xhtmlTest.html";
var element = driver.FindElement(By.Id("id1"));
var key = await new JavaScriptEngine(driver).PinScript("return arguments;");
var arguments = ((WebDriver)driver).ExecuteScript(key, 1, true, element);
var expected = new List<object>
{
1L,
true,
element
};
CollectionAssert.AreEqual(expected, (ICollection)arguments);
}
[TestMethod]
public async Task MutatedElements()
{
driver.Url = "https://www.selenium.dev/selenium/web/dynamic.html";
var mutations = new List<IWebElement>();
using IJavaScriptEngine monitor = new JavaScriptEngine(driver);
monitor.DomMutated += (_, e) =>
{
var locator = By.CssSelector($"*[data-__webdriver_id='{e.AttributeData.TargetId}']");
mutations.Add(driver.FindElement(locator));
};
await monitor.StartEventMonitoring();
await monitor.EnableDomMutationMonitoring();
driver.FindElement(By.Id("reveal")).Click();
new WebDriverWait(driver, TimeSpan.FromSeconds(5)).Until(_ => !mutations.IsNullOrEmpty());
await monitor.DisableDomMutationMonitoring();
monitor.StopEventMonitoring();
var revealed = driver.FindElement(By.Id("revealed"));
Assert.AreEqual(revealed, mutations[0]);
}
}
}
driver.on_log_event(:mutation) { |mutation| mutations << mutation.element }
Show full example
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe 'Script' do
let(:driver) { start_session }
it 'pins script' do
driver.get('https://www.selenium.dev/selenium/web/xhtmlTest.html')
element = driver.find_element(id: 'id1')
key = driver.pin_script('return arguments;')
arguments = driver.execute_script(key, 1, true, element)
expect(arguments).to eq([1, true, element])
end
it 'gets mutated elements' do
driver.get 'https://www.selenium.dev/selenium/web/dynamic.html'
mutations = []
driver.on_log_event(:mutation) { |mutation| mutations << mutation.element }
driver.find_element(id: 'reveal').click
Selenium::WebDriver::Wait.new(timeout: 30).until { mutations.any? }
expect(mutations).to include(driver.find_element(id: 'revealed'))
end
end