Network interception and mocking
You want to assert that the page called an API, fail a request to see how the application copes, block the analytics beacon that slows every test down, or supply credentials to a basic authentication challenge. Plain WebDriver only sees the DOM; it has no view of the traffic behind it.
Recommended approach
Use the network module of WebDriver BiDi. It is part of the W3C standard, it works in every browser that implements BiDi, and it is the Selenium project’s supported route for anything that needs to observe or change network traffic.
The module has two halves. Events (beforeRequestSent, responseStarted,
responseCompleted, authRequired) let you subscribe to traffic and record or assert on it.
Intercepts pause requests at a chosen phase so your handler can continue them, fail them,
or, at the authRequired phase, continue them with a username and password. Enable BiDi in
the browser options when starting the session; the reference page shows the capability for
each binding.
Keep interception narrow. Match the URL patterns you care about, remove the intercept when the test is done, and prefer failing or stubbing an external dependency over letting the test talk to a live third-party service.
The Chrome DevTools Protocol integration that Selenium offered before BiDi existed is Chromium-only, tied to specific browser versions, and being phased out. Do not start new work on it.
Subscribe to requests as they are sent:
try (Network network = new Network(driver)) {
CompletableFuture<BeforeRequestSent> future = new CompletableFuture<>();
network.onBeforeRequestSent(future::complete);
driver.get("https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html");
BeforeRequestSent requestSent = future.get(5, TimeUnit.SECONDS);/examples/java/src/test/java/dev/selenium/bidirectional/webdriver_bidi/NetworkEventsTest.java
package dev.selenium.bidirectional.webdriver_bidi;
import dev.selenium.BaseTest;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.openqa.selenium.Cookie;
import org.openqa.selenium.bidi.module.Network;
import org.openqa.selenium.bidi.network.BeforeRequestSent;
import org.openqa.selenium.bidi.network.ResponseDetails;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.firefox.FirefoxOptions;
class NetworkEventsTest extends BaseTest {
@BeforeEach
public void setup() {
FirefoxOptions options = new FirefoxOptions();
options.setCapability("webSocketUrl", true);
driver = new FirefoxDriver(options);
}
@Test
void canListenToBeforeRequestSentEvent()
throws ExecutionException, InterruptedException, TimeoutException {
try (Network network = new Network(driver)) {
CompletableFuture<BeforeRequestSent> future = new CompletableFuture<>();
network.onBeforeRequestSent(future::complete);
driver.get("https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html");
BeforeRequestSent requestSent = future.get(5, TimeUnit.SECONDS);
String windowHandle = driver.getWindowHandle();
Assertions.assertEquals(windowHandle, requestSent.getBrowsingContextId());
Assertions.assertEquals("get", requestSent.getRequest().getMethod().toLowerCase());
}
}
@Test
void canListenToResponseStartedEvent()
throws ExecutionException, InterruptedException, TimeoutException {
try (Network network = new Network(driver)) {
CompletableFuture<ResponseDetails> future = new CompletableFuture<>();
network.onResponseStarted(future::complete);
driver.get("https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html");
ResponseDetails response = future.get(5, TimeUnit.SECONDS);
String windowHandle = driver.getWindowHandle();
Assertions.assertEquals(windowHandle, response.getBrowsingContextId());
Assertions.assertEquals("get", response.getRequest().getMethod().toLowerCase());
Assertions.assertEquals(200L, response.getResponseData().getStatus());
}
}
@Test
void canListenToResponseCompletedEvent()
throws ExecutionException, InterruptedException, TimeoutException {
try (Network network = new Network(driver)) {
CompletableFuture<ResponseDetails> future = new CompletableFuture<>();
network.onResponseCompleted(future::complete);
driver.get("https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html");
ResponseDetails response = future.get(5, TimeUnit.SECONDS);
String windowHandle = driver.getWindowHandle();
Assertions.assertEquals(windowHandle, response.getBrowsingContextId());
Assertions.assertEquals("get", response.getRequest().getMethod().toLowerCase());
Assertions.assertEquals(200L, response.getResponseData().getStatus());
}
}
@Test
void canListenToResponseCompletedEventWithCookie()
throws ExecutionException, InterruptedException, TimeoutException {
try (Network network = new Network(driver)) {
CompletableFuture<BeforeRequestSent> future = new CompletableFuture<>();
driver.get("https://www.selenium.dev/selenium/web/blankPage");
driver.manage().addCookie(new Cookie("foo", "bar"));
network.onBeforeRequestSent(future::complete);
driver.navigate().refresh();
BeforeRequestSent requestSent = future.get(5, TimeUnit.SECONDS);
String windowHandle = driver.getWindowHandle();
Assertions.assertEquals(windowHandle, requestSent.getBrowsingContextId());
Assertions.assertEquals("get", requestSent.getRequest().getMethod().toLowerCase());
Assertions.assertEquals("foo", requestSent.getRequest().getCookies().get(0).getName());
Assertions.assertEquals("bar", requestSent.getRequest().getCookies().get(0).getValue().getValue());
}
}
@Test
void canListenToOnAuthRequiredEvent()
throws ExecutionException, InterruptedException, TimeoutException {
try (Network network = new Network(driver)) {
CompletableFuture<ResponseDetails> future = new CompletableFuture<>();
network.onAuthRequired(future::complete);
driver.get("https://the-internet.herokuapp.com/basic_auth");
ResponseDetails response = future.get(5, TimeUnit.SECONDS);
String windowHandle = driver.getWindowHandle();
Assertions.assertEquals(windowHandle, response.getBrowsingContextId());
Assertions.assertEquals("get", response.getRequest().getMethod().toLowerCase());
Assertions.assertEquals(401L, response.getResponseData().getStatus());
}
}
}
requests.append(request)
callback_id = driver.network.add_request_handler("before_request", callback)
assert callback_id is not None/examples/python/tests/bidi/test_network_commands.py
# Licensed to the Software Freedom Conservancy (SFC) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The SFC licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
import pytest
from selenium.common.exceptions import WebDriverException
@pytest.mark.driver_type("bidi")
def test_add_intercept(driver):
# _add_intercept is currently the available Python API for BiDi network intercepts.
# This will be updated when a public API is stabilized.
intercept = driver.network._add_intercept()
assert intercept is not None
driver.network._remove_intercept(intercept["intercept"])
@pytest.mark.driver_type("bidi")
def test_remove_intercept(driver):
# _add_intercept/_remove_intercept are currently the available Python APIs.
# These will be updated when a public API is stabilized.
intercept = driver.network._add_intercept()
driver.network._remove_intercept(intercept["intercept"])
assert driver.network.intercepts == []
@pytest.mark.driver_type("bidi")
def test_fail_request(driver):
from selenium.webdriver.common.bidi.browsing_context import ReadinessState
from selenium.webdriver.common.bidi.network import Request
def block_request(request: Request):
request.fail()
driver.network.add_request_handler(["**/blank.html"], block_request)
try:
with pytest.raises(WebDriverException):
driver.browsing_context.navigate(
context=driver.current_window_handle,
url="https://www.selenium.dev/selenium/web/blank.html",
wait=ReadinessState.COMPLETE,
)
finally:
driver.network.clear_request_handlers()
@pytest.mark.driver_type("bidi")
def test_add_and_remove_request_handler(driver):
from selenium.webdriver.common.bidi.network import Request
requests = []
def callback(request: Request):
requests.append(request)
callback_id = driver.network.add_request_handler("before_request", callback)
assert callback_id is not None
driver.network.remove_request_handler("before_request", callback_id)
driver.get("https://www.selenium.dev/selenium/web/blank.html")
assert not requests
const network = await Network(driver)
await network.beforeRequestSent(function (event) {
beforeRequestEvent.push(event)
})/examples/javascript/test/bidirectional/network_events.spec.js
const assert = require("assert");
const firefox = require('selenium-webdriver/firefox');
const { Network } = require("selenium-webdriver/bidi/network");
const {until, Builder} = require("selenium-webdriver");
describe('Network events', function () {
let driver
beforeEach(async function () {
driver = new Builder()
.forBrowser('firefox')
.setFirefoxOptions(new firefox.Options().enableBidi())
.build()
})
afterEach(async function () {
await driver.quit()
})
it('can listen to event before request is sent', async function () {
let beforeRequestEvent = []
const network = await Network(driver)
await network.beforeRequestSent(function (event) {
beforeRequestEvent.push(event)
})
await driver.get('https://www.selenium.dev/selenium/web/blank.html')
const currentUrl = await driver.getCurrentUrl()
const currentUrlFound = beforeRequestEvent.some(event => event.request.url.includes(currentUrl))
assert(currentUrlFound, `${currentUrl} was not requested`)
})
it('can request cookies', async function () {
const network = await Network(driver)
let beforeRequestEvent = null
await network.beforeRequestSent(function (event) {
beforeRequestEvent = event
})
await driver.get('https://www.selenium.dev/selenium/web/blank.html')
await driver.manage().addCookie({
name: 'north',
value: 'biryani',
})
await driver.navigate().refresh()
assert.equal(beforeRequestEvent.request.method, 'GET')
assert.equal(beforeRequestEvent.request.cookies[0].name, 'north')
assert.equal(beforeRequestEvent.request.cookies[0].value.value, 'biryani')
await driver.manage().addCookie({
name: 'south',
value: 'dosa',
})
await driver.navigate().refresh()
assert.equal(beforeRequestEvent.request.cookies[1].name, 'south')
assert.equal(beforeRequestEvent.request.cookies[1].value.value, 'dosa')
})
it('can redirect http equiv', async function () {
let beforeRequestEvent = []
const network = await Network(driver)
await network.beforeRequestSent(function (event) {
beforeRequestEvent.push(event)
})
await driver.get('https://www.selenium.dev/selenium/web/bidi/redirected_http_equiv.html')
await driver.wait(until.urlContains('redirected.html'), 1000)
assert.equal(beforeRequestEvent[0].request.method, 'GET')
let redirectedFound = beforeRequestEvent.some(event => event.request.url.includes('redirected.html'))
assert(redirectedFound, 'redirected.html was not requested')
redirectedFound = beforeRequestEvent.some(event => event.request.url.includes('redirected_http_equiv.html'))
assert(redirectedFound, 'redirected_http_equiv.html was not requested')
})
it('can subscribe to response started', async function () {
let onResponseStarted = []
const network = await Network(driver)
await network.responseStarted(function (event) {
onResponseStarted.push(event)
})
await driver.get('https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html')
assert.equal(onResponseStarted[0].request.method, 'GET')
assert.equal(onResponseStarted[0].request.url, await driver.getCurrentUrl())
assert.equal(onResponseStarted[0].response.url, await driver.getCurrentUrl())
})
it('can subscribe to response completed', async function () {
let onResponseCompleted = []
const network = await Network(driver)
await network.responseCompleted(function (event) {
onResponseCompleted.push(event)
})
await driver.get('https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html')
assert.equal(onResponseCompleted[0].request.method, 'GET')
assert.equal(onResponseCompleted[0].request.url, await driver.getCurrentUrl())
assert.equal(onResponseCompleted[0].response.fromCache, false)
assert.equal(onResponseCompleted[0].response.status, 200)
})
})
Intercept a request and fail it:
network.addIntercept(new AddInterceptParameters(InterceptPhase.BEFORE_REQUEST_SENT));
network.onBeforeRequestSent(
responseDetails -> network.failRequest(responseDetails.getRequest().getRequestId()));/examples/java/src/test/java/dev/selenium/bidirectional/webdriver_bidi/NetworkCommandsTest.java
package dev.selenium.bidirectional.webdriver_bidi;
import dev.selenium.BaseTest;
import java.time.Duration;
import java.time.temporal.ChronoUnit;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.openqa.selenium.Alert;
import org.openqa.selenium.By;
import org.openqa.selenium.TimeoutException;
import org.openqa.selenium.UsernameAndPassword;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.bidi.module.Network;
import org.openqa.selenium.bidi.network.AddInterceptParameters;
import org.openqa.selenium.bidi.network.InterceptPhase;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.firefox.FirefoxOptions;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;
class NetworkCommandsTest extends BaseTest {
@BeforeEach
public void setup() {
FirefoxOptions options = new FirefoxOptions();
options.setCapability("webSocketUrl", true);
driver = new FirefoxDriver(options);
wait = new WebDriverWait(driver, Duration.ofSeconds(10));
}
@Test
void canAddIntercept() {
try (Network network = new Network(driver)) {
String intercept =
network.addIntercept(new AddInterceptParameters(InterceptPhase.BEFORE_REQUEST_SENT));
Assertions.assertNotNull(intercept);
}
}
@Test
void canRemoveIntercept() {
try (Network network = new Network(driver)) {
String intercept =
network.addIntercept(new AddInterceptParameters(InterceptPhase.BEFORE_REQUEST_SENT));
Assertions.assertNotNull(intercept);
network.removeIntercept(intercept);
}
}
@Test
void canContinueWithAuthCredentials() {
try (Network network = new Network(driver)) {
network.addIntercept(new AddInterceptParameters(InterceptPhase.AUTH_REQUIRED));
network.onAuthRequired(
responseDetails ->
network.continueWithAuth(
responseDetails.getRequest().getRequestId(),
new UsernameAndPassword("admin", "admin")));
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
void canContinueWithoutAuthCredentials() {
try (Network network = new Network(driver)) {
network.addIntercept(new AddInterceptParameters(InterceptPhase.AUTH_REQUIRED));
network.onAuthRequired(
responseDetails ->
// Does not handle the alert
network.continueWithAuthNoCredentials(responseDetails.getRequest().getRequestId()));
driver.get("https://the-internet.herokuapp.com/basic_auth");
Alert alert = wait.until(ExpectedConditions.alertIsPresent());
alert.dismiss();
Assertions.assertTrue(driver.getPageSource().contains("Not authorized"));
}
}
@Test
void canCancelAuth() {
try (Network network = new Network(driver)) {
network.addIntercept(new AddInterceptParameters(InterceptPhase.AUTH_REQUIRED));
network.onAuthRequired(
responseDetails ->
// Does not handle the alert
network.cancelAuth(responseDetails.getRequest().getRequestId()));
driver.get("https://the-internet.herokuapp.com/basic_auth");
Assertions.assertTrue(driver.getPageSource().contains("Not authorized"));
}
}
@Test
void canFailRequest() {
try (Network network = new Network(driver)) {
network.addIntercept(new AddInterceptParameters(InterceptPhase.BEFORE_REQUEST_SENT));
network.onBeforeRequestSent(
responseDetails -> network.failRequest(responseDetails.getRequest().getRequestId()));
driver.manage().timeouts().pageLoadTimeout(Duration.of(5, ChronoUnit.SECONDS));
Assertions.assertThrows(TimeoutException.class, () -> driver.get("https://the-internet.herokuapp.com/basic_auth"));
}
}
}
request.fail()
driver.network.add_request_handler(["**/blank.html"], block_request)
/examples/python/tests/bidi/test_network_commands.py
# Licensed to the Software Freedom Conservancy (SFC) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The SFC licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
import pytest
from selenium.common.exceptions import WebDriverException
@pytest.mark.driver_type("bidi")
def test_add_intercept(driver):
# _add_intercept is currently the available Python API for BiDi network intercepts.
# This will be updated when a public API is stabilized.
intercept = driver.network._add_intercept()
assert intercept is not None
driver.network._remove_intercept(intercept["intercept"])
@pytest.mark.driver_type("bidi")
def test_remove_intercept(driver):
# _add_intercept/_remove_intercept are currently the available Python APIs.
# These will be updated when a public API is stabilized.
intercept = driver.network._add_intercept()
driver.network._remove_intercept(intercept["intercept"])
assert driver.network.intercepts == []
@pytest.mark.driver_type("bidi")
def test_fail_request(driver):
from selenium.webdriver.common.bidi.browsing_context import ReadinessState
from selenium.webdriver.common.bidi.network import Request
def block_request(request: Request):
request.fail()
driver.network.add_request_handler(["**/blank.html"], block_request)
try:
with pytest.raises(WebDriverException):
driver.browsing_context.navigate(
context=driver.current_window_handle,
url="https://www.selenium.dev/selenium/web/blank.html",
wait=ReadinessState.COMPLETE,
)
finally:
driver.network.clear_request_handlers()
@pytest.mark.driver_type("bidi")
def test_add_and_remove_request_handler(driver):
from selenium.webdriver.common.bidi.network import Request
requests = []
def callback(request: Request):
requests.append(request)
callback_id = driver.network.add_request_handler("before_request", callback)
assert callback_id is not None
driver.network.remove_request_handler("before_request", callback_id)
driver.get("https://www.selenium.dev/selenium/web/blank.html")
assert not requests
Answer a basic authentication challenge:
network.addIntercept(new AddInterceptParameters(InterceptPhase.AUTH_REQUIRED));
network.onAuthRequired(
responseDetails ->
network.continueWithAuth(
responseDetails.getRequest().getRequestId(),
new UsernameAndPassword("admin", "admin")));/examples/java/src/test/java/dev/selenium/bidirectional/webdriver_bidi/NetworkCommandsTest.java
package dev.selenium.bidirectional.webdriver_bidi;
import dev.selenium.BaseTest;
import java.time.Duration;
import java.time.temporal.ChronoUnit;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.openqa.selenium.Alert;
import org.openqa.selenium.By;
import org.openqa.selenium.TimeoutException;
import org.openqa.selenium.UsernameAndPassword;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.bidi.module.Network;
import org.openqa.selenium.bidi.network.AddInterceptParameters;
import org.openqa.selenium.bidi.network.InterceptPhase;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.firefox.FirefoxOptions;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;
class NetworkCommandsTest extends BaseTest {
@BeforeEach
public void setup() {
FirefoxOptions options = new FirefoxOptions();
options.setCapability("webSocketUrl", true);
driver = new FirefoxDriver(options);
wait = new WebDriverWait(driver, Duration.ofSeconds(10));
}
@Test
void canAddIntercept() {
try (Network network = new Network(driver)) {
String intercept =
network.addIntercept(new AddInterceptParameters(InterceptPhase.BEFORE_REQUEST_SENT));
Assertions.assertNotNull(intercept);
}
}
@Test
void canRemoveIntercept() {
try (Network network = new Network(driver)) {
String intercept =
network.addIntercept(new AddInterceptParameters(InterceptPhase.BEFORE_REQUEST_SENT));
Assertions.assertNotNull(intercept);
network.removeIntercept(intercept);
}
}
@Test
void canContinueWithAuthCredentials() {
try (Network network = new Network(driver)) {
network.addIntercept(new AddInterceptParameters(InterceptPhase.AUTH_REQUIRED));
network.onAuthRequired(
responseDetails ->
network.continueWithAuth(
responseDetails.getRequest().getRequestId(),
new UsernameAndPassword("admin", "admin")));
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
void canContinueWithoutAuthCredentials() {
try (Network network = new Network(driver)) {
network.addIntercept(new AddInterceptParameters(InterceptPhase.AUTH_REQUIRED));
network.onAuthRequired(
responseDetails ->
// Does not handle the alert
network.continueWithAuthNoCredentials(responseDetails.getRequest().getRequestId()));
driver.get("https://the-internet.herokuapp.com/basic_auth");
Alert alert = wait.until(ExpectedConditions.alertIsPresent());
alert.dismiss();
Assertions.assertTrue(driver.getPageSource().contains("Not authorized"));
}
}
@Test
void canCancelAuth() {
try (Network network = new Network(driver)) {
network.addIntercept(new AddInterceptParameters(InterceptPhase.AUTH_REQUIRED));
network.onAuthRequired(
responseDetails ->
// Does not handle the alert
network.cancelAuth(responseDetails.getRequest().getRequestId()));
driver.get("https://the-internet.herokuapp.com/basic_auth");
Assertions.assertTrue(driver.getPageSource().contains("Not authorized"));
}
}
@Test
void canFailRequest() {
try (Network network = new Network(driver)) {
network.addIntercept(new AddInterceptParameters(InterceptPhase.BEFORE_REQUEST_SENT));
network.onBeforeRequestSent(
responseDetails -> network.failRequest(responseDetails.getRequest().getRequestId()));
driver.manage().timeouts().pageLoadTimeout(Duration.of(5, ChronoUnit.SECONDS));
Assertions.assertThrows(TimeoutException.class, () -> driver.get("https://the-internet.herokuapp.com/basic_auth"));
}
}
}
/examples/python/tests/bidi/test_network_commands.py
# Licensed to the Software Freedom Conservancy (SFC) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The SFC licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
import pytest
from selenium.common.exceptions import WebDriverException
@pytest.mark.driver_type("bidi")
def test_add_intercept(driver):
# _add_intercept is currently the available Python API for BiDi network intercepts.
# This will be updated when a public API is stabilized.
intercept = driver.network._add_intercept()
assert intercept is not None
driver.network._remove_intercept(intercept["intercept"])
@pytest.mark.driver_type("bidi")
def test_remove_intercept(driver):
# _add_intercept/_remove_intercept are currently the available Python APIs.
# These will be updated when a public API is stabilized.
intercept = driver.network._add_intercept()
driver.network._remove_intercept(intercept["intercept"])
assert driver.network.intercepts == []
@pytest.mark.driver_type("bidi")
def test_fail_request(driver):
from selenium.webdriver.common.bidi.browsing_context import ReadinessState
from selenium.webdriver.common.bidi.network import Request
def block_request(request: Request):
request.fail()
driver.network.add_request_handler(["**/blank.html"], block_request)
try:
with pytest.raises(WebDriverException):
driver.browsing_context.navigate(
context=driver.current_window_handle,
url="https://www.selenium.dev/selenium/web/blank.html",
wait=ReadinessState.COMPLETE,
)
finally:
driver.network.clear_request_handlers()
@pytest.mark.driver_type("bidi")
def test_add_and_remove_request_handler(driver):
from selenium.webdriver.common.bidi.network import Request
requests = []
def callback(request: Request):
requests.append(request)
callback_id = driver.network.add_request_handler("before_request", callback)
assert callback_id is not None
driver.network.remove_request_handler("before_request", callback_id)
driver.get("https://www.selenium.dev/selenium/web/blank.html")
assert not requests
await network.authRequired(async (event) => {
await network.continueWithAuth(event.request.request, 'admin','admin')
})/examples/javascript/test/bidirectional/network_commands.spec.js
const assert = require("assert")
const firefox = require('selenium-webdriver/firefox')
const { Network } = require('selenium-webdriver/bidi/network')
const {until, By, Builder} = require('selenium-webdriver')
const {AddInterceptParameters} = require("selenium-webdriver/bidi/addInterceptParameters");
const {InterceptPhase} = require("selenium-webdriver/bidi/interceptPhase");
describe('Network commands', function () {
let driver
let network
beforeEach(async function () {
driver = new Builder()
.forBrowser('firefox')
.setFirefoxOptions(new firefox.Options().enableBidi())
.build()
network = await Network(driver)
})
afterEach(async function () {
await network.close()
await driver.quit()
})
it('can add intercept', async function () {
const intercept = await network.addIntercept(new AddInterceptParameters(InterceptPhase.BEFORE_REQUEST_SENT))
assert.notEqual(intercept, null)
})
it('can remove intercept', async function () {
const network = await Network(driver)
const intercept = await network.addIntercept(new AddInterceptParameters(InterceptPhase.BEFORE_REQUEST_SENT))
assert.notEqual(intercept, null)
await network.removeIntercept(intercept)
})
it('can continue with auth credentials ', async function () {
await network.addIntercept(new AddInterceptParameters(InterceptPhase.AUTH_REQUIRED))
await network.authRequired(async (event) => {
await network.continueWithAuth(event.request.request, 'admin','admin')
})
await driver.get('https://the-internet.herokuapp.com/basic_auth')
const successMessage = 'Congratulations! You must have the proper credentials.'
let elementMessage = await driver.findElement(By.tagName('p')).getText()
assert.equal(elementMessage, successMessage)
})
it('can continue without auth credentials ', async function () {
await network.addIntercept(new AddInterceptParameters(InterceptPhase.AUTH_REQUIRED))
await network.authRequired(async (event) => {
await network.continueWithAuthNoCredentials(event.request.request)
})
await driver.get('https://the-internet.herokuapp.com/basic_auth')
const alert = await driver.wait(until.alertIsPresent())
await alert.dismiss()
let source = await driver.getPageSource()
assert.equal(source.includes('Not authorized'), true)
})
it('can cancel auth ', async function () {
await network.addIntercept(new AddInterceptParameters(InterceptPhase.AUTH_REQUIRED))
await network.authRequired(async (event) => {
await network.cancelAuth(event.request.request)
})
await driver.get('https://the-internet.herokuapp.com/basic_auth')
let source = await driver.getPageSource()
assert.equal(source.includes('Not authorized'), true)
})
})
Common errors
- TimeoutException: an intercepted request was never continued or failed, so navigation hung until the page load timeout. Every intercepted request needs a handler that resolves it.
- UnsupportedCommandException: BiDi was not enabled for the session, or the browser does not implement the command yet.
Reference
- BiDi network: all commands and events
- Enabling BiDi
- Mock external services
- HTTP response codes: why WebDriver does not expose them directly



