Chrome DevTools Logging Features

Logging features using CDP.

While Selenium 4 provides direct access to the Chrome DevTools Protocol, these methods will eventually be removed when WebDriver BiDi implemented.

Console Logs

    ((HasLogEvents) driver).onLogEvent(consoleEvent(e -> messages.add(e.getMessages().get(0))));
Show full example
package dev.selenium.bidi.cdp;

import static org.openqa.selenium.devtools.events.CdpEventTypes.consoleEvent;

import dev.selenium.BaseTest;

import java.time.Duration;
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 LoggingTest extends BaseTest {

  @BeforeEach
  public void createSession() {
    driver = new ChromeDriver();
    wait = new WebDriverWait(driver, Duration.ofSeconds(10));
  }

  @Test
  public void consoleLogs() {
    driver.get("https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html");
    CopyOnWriteArrayList<String> messages = new CopyOnWriteArrayList<>();

    ((HasLogEvents) driver).onLogEvent(consoleEvent(e -> messages.add(e.getMessages().get(0))));

    driver.findElement(By.id("consoleLog")).click();
    driver.findElement(By.id("consoleError")).click();

    wait.until(_d -> messages.size() > 1);
    Assertions.assertTrue(messages.contains("Hello, world!"));
    Assertions.assertTrue(messages.contains("I am console error"));
  }
}
    async with driver.bidi_connection() as session:
        async with Log(driver, session).add_listener(Console.ALL) as messages:
Show full example
import pytest
from selenium.webdriver.common.bidi.console import Console
from selenium.webdriver.common.by import By
from selenium.webdriver.common.log import Log


@pytest.mark.trio
async def test_console_log(driver):
    driver.get('https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html')

    async with driver.bidi_connection() as session:
        async with Log(driver, session).add_listener(Console.ALL) as messages:
            driver.find_element(by=By.ID, value='consoleLog').click()

        assert messages["message"] == "Hello, world!"


@pytest.mark.trio
async def test_js_error(driver):
    driver.get('https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html')

    async with driver.bidi_connection() as session:
        async with Log(driver, session).add_js_error_listener() as messages:
            driver.find_element(by=By.ID, value='jsException').click()

        assert "Error: Not working" in messages.exception_details.exception.description
            using IJavaScriptEngine monitor = new JavaScriptEngine(driver);
            var messages = new List<string>();
            monitor.JavaScriptConsoleApiCalled += (_, e) =>
            {
                messages.Add(e.MessageContent);
            };
            await monitor.StartEventMonitoring();
Show full example
using System;
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 LoggingTest : BaseChromeTest
    {
        [TestMethod]
        public async Task ConsoleLogs()
        {
            driver.Url = "https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html";

            using IJavaScriptEngine monitor = new JavaScriptEngine(driver);
            var messages = new List<string>();
            monitor.JavaScriptConsoleApiCalled += (_, e) =>
            {
                messages.Add(e.MessageContent);
            };
            await monitor.StartEventMonitoring();

            driver.FindElement(By.Id("consoleLog")).Click();
            driver.FindElement(By.Id("consoleError")).Click();
            new WebDriverWait(driver, TimeSpan.FromSeconds(5)).Until(_ => messages.Count > 1);
            monitor.StopEventMonitoring();

            Assert.IsTrue(messages.Contains("Hello, world!"));
            Assert.IsTrue(messages.Contains("I am console error"));
        }
        
        [TestMethod]
        public async Task JsErrors()
        {
            driver.Url = "https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html";

            using IJavaScriptEngine monitor = new JavaScriptEngine(driver);
            var messages = new List<string>();
            monitor.JavaScriptExceptionThrown += (_, e) =>
            {
                messages.Add(e.Message);
            };
            await monitor.StartEventMonitoring();

            driver.FindElement(By.Id("jsException")).Click();
            new WebDriverWait(driver, TimeSpan.FromSeconds(5)).Until(_ => !messages.IsNullOrEmpty());
            monitor.StopEventMonitoring();

            Assert.IsTrue(messages.Contains("Uncaught"));
        }
    }
}
    driver.on_log_event(:console) { |log| logs << log.args.first }
Show full example
# frozen_string_literal: true

require 'spec_helper'

RSpec.describe 'Logging' do
  let(:driver) { start_session }

  it 'listens for console logs' do
    driver.get('https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html')

    logs = []
    driver.on_log_event(:console) { |log| logs << log.args.first }

    driver.find_element(id: 'consoleLog').click
    driver.find_element(id: 'consoleError').click

    Selenium::WebDriver::Wait.new.until { logs.size > 1 }
    expect(logs).to include 'Hello, world!'
    expect(logs).to include 'I am console error'
  end

  it 'listens for js exception' do
    driver.get('https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html')

    exceptions = []
    driver.on_log_event(:exception) { |exception| exceptions << exception }

    driver.find_element(id: 'jsException').click

    Selenium::WebDriver::Wait.new.until { exceptions.any? }
    expect(exceptions.first&.description).to include 'Error: Not working'
  end
end

JavaScript Exceptions

    async with driver.bidi_connection() as session:
        async with Log(driver, session).add_js_error_listener() as messages:
Show full example
import pytest
from selenium.webdriver.common.bidi.console import Console
from selenium.webdriver.common.by import By
from selenium.webdriver.common.log import Log


@pytest.mark.trio
async def test_console_log(driver):
    driver.get('https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html')

    async with driver.bidi_connection() as session:
        async with Log(driver, session).add_listener(Console.ALL) as messages:
            driver.find_element(by=By.ID, value='consoleLog').click()

        assert messages["message"] == "Hello, world!"


@pytest.mark.trio
async def test_js_error(driver):
    driver.get('https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html')

    async with driver.bidi_connection() as session:
        async with Log(driver, session).add_js_error_listener() as messages:
            driver.find_element(by=By.ID, value='jsException').click()

        assert "Error: Not working" in messages.exception_details.exception.description
            using IJavaScriptEngine monitor = new JavaScriptEngine(driver);
            var messages = new List<string>();
            monitor.JavaScriptExceptionThrown += (_, e) =>
            {
                messages.Add(e.Message);
            };
            await monitor.StartEventMonitoring();
Show full example
using System;
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 LoggingTest : BaseChromeTest
    {
        [TestMethod]
        public async Task ConsoleLogs()
        {
            driver.Url = "https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html";

            using IJavaScriptEngine monitor = new JavaScriptEngine(driver);
            var messages = new List<string>();
            monitor.JavaScriptConsoleApiCalled += (_, e) =>
            {
                messages.Add(e.MessageContent);
            };
            await monitor.StartEventMonitoring();

            driver.FindElement(By.Id("consoleLog")).Click();
            driver.FindElement(By.Id("consoleError")).Click();
            new WebDriverWait(driver, TimeSpan.FromSeconds(5)).Until(_ => messages.Count > 1);
            monitor.StopEventMonitoring();

            Assert.IsTrue(messages.Contains("Hello, world!"));
            Assert.IsTrue(messages.Contains("I am console error"));
        }
        
        [TestMethod]
        public async Task JsErrors()
        {
            driver.Url = "https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html";

            using IJavaScriptEngine monitor = new JavaScriptEngine(driver);
            var messages = new List<string>();
            monitor.JavaScriptExceptionThrown += (_, e) =>
            {
                messages.Add(e.Message);
            };
            await monitor.StartEventMonitoring();

            driver.FindElement(By.Id("jsException")).Click();
            new WebDriverWait(driver, TimeSpan.FromSeconds(5)).Until(_ => !messages.IsNullOrEmpty());
            monitor.StopEventMonitoring();

            Assert.IsTrue(messages.Contains("Uncaught"));
        }
    }
}
    driver.on_log_event(:exception) { |exception| exceptions << exception }
Show full example
# frozen_string_literal: true

require 'spec_helper'

RSpec.describe 'Logging' do
  let(:driver) { start_session }

  it 'listens for console logs' do
    driver.get('https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html')

    logs = []
    driver.on_log_event(:console) { |log| logs << log.args.first }

    driver.find_element(id: 'consoleLog').click
    driver.find_element(id: 'consoleError').click

    Selenium::WebDriver::Wait.new.until { logs.size > 1 }
    expect(logs).to include 'Hello, world!'
    expect(logs).to include 'I am console error'
  end

  it 'listens for js exception' do
    driver.get('https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html')

    exceptions = []
    driver.on_log_event(:exception) { |exception| exceptions << exception }

    driver.find_element(id: 'jsException').click

    Selenium::WebDriver::Wait.new.until { exceptions.any? }
    expect(exceptions.first&.description).to include 'Error: Not working'
  end
end
Last modified July 10, 2024: Release 4.22 Updates (#1765) (fa7b1165ed)