Chrome DevTools Script Features
Script features using CDP.
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);
/examples/java/src/test/java/dev/selenium/bidi/cdp/ScriptTest.java
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);
/examples/dotnet/SeleniumDocs/BiDi/CDP/ScriptTest.cs
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)
/examples/ruby/spec/bidi/cdp/script_spec.rb
# 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
/examples/java/src/test/java/dev/selenium/bidi/cdp/NetworkTest.java
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.v137.browser.Browser; import org.openqa.selenium.devtools.v137.network.Network; import org.openqa.selenium.devtools.v137.performance.Performance; import org.openqa.selenium.devtools.v137.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:
/examples/python/tests/bidi/cdp/test_script.py
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();
/examples/dotnet/SeleniumDocs/BiDi/CDP/ScriptTest.cs
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 }
/examples/ruby/spec/bidi/cdp/script_spec.rb
# 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
Last modified November 5, 2024: Add examples for Drivers HTTP Client in Java and Python (#2041) (2ce6752bfc8)