Chrome DevTools Script Features

Script features using CDP.

Page being translated from English to Japanese. Do you speak Japanese? 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