这是本节的多页打印视图。
点击此处打印 .
返回本页常规视图 .
双向协议 Selenium正在与浏览器供应商合作创建
WebDriver双向协议 ,
作为一种提供稳定的跨浏览器API的方法,
该API使用双向协议处理
各种浏览器的通用自动化以及特定测试的需求.
在此之前, 寻求此功能的用户
必须忍受当前实现的全部问题和局限.
严格限制请求响应命令的传统WebDriver模型,
将从user agent转变为基于WebSockets的软件控制,
通过这样完善流事件的能力,
以便更好地匹配浏览器DOM的事件性质.
While the specification is in works, the browser vendors are parallely implementing
the WebDriver BiDirectional Protocol .
Refer web-platform-tests dashboard
to see how far along the browser vendors are.
Selenium is trying to keep up with the browser vendors and has started implementing W3C BiDi APIs.
The goal is to ensure APIs are W3C compliant and uniform among the different language bindings.
However, until the specification and corresponding Selenium implementation is complete there are many useful things that
CDP offers. Selenium offers some useful helper classes that use CDP.
1 - Chrome DevTools Many browsers provide “DevTools” – a set of tools that are integrated with the browser that
developers can use to debug web apps and explore the performance of their pages. Google Chrome’s
DevTools make use of a protocol called the Chrome DevTools Protocol (or “CDP” for short).
As the name suggests, this is not designed for testing, nor to have a stable API, so functionality
is highly dependent on the version of the browser.
The WebDriver BiDirectional Protocol is the next generation of the
W3C WebDriver protocol and aims to provide a stable API implemented by all browsers, but it’s not yet complete.
Until it is, Selenium provides access to
the CDP for those browsers that implement it (such as Google Chrome, or Microsoft Edge, and
Firefox), allowing you to enhance your tests in interesting ways. Some examples of what you can
do with it are given below.
There are three different ways to access Chrome DevTools in Selenium. If you look for other examples online,
you will likely see each of these mixed and matched.
The CDP Endpoint was the first option available to users.
It only works for the most simple things (setting state, getting basic information), and you
have to know the “magic strings” for the domain and methods and key value pairs.
For basic requirements, this might be simpler than the other options. These methods are only temporarily supported. The CDP API is an improvement on just using the endpoint because you can set
do things asynchronously. Instead of a String and a Map, you can access the supported classes,
methods and parameters in the code. These methods are also only temporarily supported. The BiDi API option should be used whenever possible because it
abstracts away the implementation details entirely and will work with either CDP or WebDriver-BiDi
when Selenium moves away from CDP. Examples With Limited Value There are a number of commonly cited examples for using CDP that are of limited practical value.
Geo Location — almost all sites use the IP address to determine physical location,
so setting an emulated geolocation rarely has the desired effect.Overriding Device Metrics — Chrome provides a great API for setting Mobile Emulation
in the Options classes, which is generally superior to attempting to do this with CDP.Check out the examples in these documents for ways to do additional useful things:
1.1 - Chrome DevTools Protocol Endpoint Google provides a /cdp/execute
endpoint that can be accessed directly. Each Selenium binding provides a method that allows you to pass the CDP domain as a String, and the required parameters as a simple Map.
These methods will eventually be removed. It is recommended to use the WebDriver-BiDi or WebDriver Bidi APIs
methods where possible to ensure future compatibility.
Usage Generally you should prefer the use of the CDP API over this approach,
but sometimes the syntax is cleaner or significantly more simple.
Limitations include:
It only works for use cases that are limited to setting or getting information;
any actual asynchronous interactions require another implementation You have to know the exactly correct “magic strings” for domains and keys It is possible that an update to Chrome will change the required parameters Examples Set Cookie An alternate implementation can be found at CDP API Set Cookie
Java
Python
CSharp
Ruby
JavaScript
Kotlin Map < String , Object > cookie = new HashMap <>();
cookie . put ( "name" , "cheese" );
cookie . put ( "value" , "gouda" );
cookie . put ( "domain" , "www.selenium.dev" );
cookie . put ( "secure" , true );
(( HasCdp ) driver ). executeCdpCommand ( "Network.setCookie" , cookie );
cookie = { 'name' : 'cheese' ,
'value' : 'gouda' ,
'domain' : 'www.selenium.dev' ,
'secure' : True }
driver . execute_cdp_cmd ( 'Network.setCookie' , cookie )
var cookie = new Dictionary < string , object >
{
{ "name" , "cheese" },
{ "value" , "gouda" },
{ "domain" , "www.selenium.dev" },
{ "secure" , true }
};
(( ChromeDriver ) driver ). ExecuteCdpCommand ( "Network.setCookie" , cookie );
The CDP API Set Cookie implementation should be preferred
cookie = { name : 'cheese' ,
value : 'gouda' ,
domain : 'www.selenium.dev' ,
secure : true }
driver . execute_cdp ( 'Network.setCookie' , ** cookie )
An alternate implementation can be found at CDP API Performance Metrics
Java
Python
CSharp
Ruby
JavaScript
Kotlin The CDP API Performance Metrics implementation should be preferred
(( HasCdp ) driver ). executeCdpCommand ( "Performance.enable" , new HashMap <>());
Map < String , Object > response =
(( HasCdp ) driver ). executeCdpCommand ( "Performance.getMetrics" , new HashMap <>());
driver . execute_cdp_cmd ( 'Performance.enable' , {})
metric_list = driver . execute_cdp_cmd ( 'Performance.getMetrics' , {})[ "metrics" ]
(( ChromeDriver ) driver ). ExecuteCdpCommand ( "Performance.enable" , emptyDictionary );
Dictionary < string , object > response = ( Dictionary < string , object >)(( ChromeDriver ) driver )
. ExecuteCdpCommand ( "Performance.getMetrics" , emptyDictionary );
The CDP API Performance Metrics implementation should be preferred
driver . execute_cdp ( 'Performance.enable' )
metric_list = driver . execute_cdp ( 'Performance.getMetrics' ) [ 'metrics' ]
Basic authentication Alternate implementations can be found at CDP API Basic Authentication
and BiDi API Basic Authentication
Java
Python
CSharp
Ruby
JavaScript
Kotlin The BiDi API Basic Authentication implementation should be preferred
(( HasCdp ) driver ). executeCdpCommand ( "Network.enable" , new HashMap <>());
String encodedAuth = Base64 . getEncoder (). encodeToString ( "admin:admin" . getBytes ());
Map < String , Object > headers =
ImmutableMap . of ( "headers" , ImmutableMap . of ( "authorization" , "Basic " + encodedAuth ));
(( HasCdp ) driver ). executeCdpCommand ( "Network.setExtraHTTPHeaders" , headers );
driver . execute_cdp_cmd ( "Network.enable" , {})
credentials = base64 . b64encode ( "admin:admin" . encode ()) . decode ()
headers = { 'headers' : { 'authorization' : 'Basic ' + credentials }}
driver . execute_cdp_cmd ( 'Network.setExtraHTTPHeaders' , headers )
(( ChromeDriver ) driver ). ExecuteCdpCommand ( "Network.enable" , emptyDictionary );
string encodedAuth = Convert . ToBase64String ( Encoding . Default . GetBytes ( "admin:admin" ));
var headers = new Dictionary < string , object >
{
{ "headers" , new Dictionary < string , string > { { "authorization" , "Basic " + encodedAuth } } }
};
(( ChromeDriver ) driver ). ExecuteCdpCommand ( "Network.setExtraHTTPHeaders" , headers );
The BiDi API Basic Authentication implementation should be preferred
driver . execute_cdp ( 'Network.enable' )
credentials = Base64 . strict_encode64 ( 'admin:admin' )
headers = { authorization : "Basic #{ credentials } " }
driver . execute_cdp ( 'Network.setExtraHTTPHeaders' , headers : headers )
1.2 - Chrome DevTools Protocol API Each of the Selenium bindings dynamically generates classes and methods for the various CDP domains and features; these are tied to specific versions of Chrome.
While Selenium 4 provides direct access to the Chrome DevTools Protocol (CDP), these
methods will eventually be removed. It is recommended to use the WebDriver Bidi APIs
methods where possible to ensure future compatibility.
Usage If your use case has been implemented by WebDriver Bidi or
the BiDi API , you should use those implementations instead of this one.
Generally you should prefer this approach over executing with the CDP Endpoint ,
especially in Ruby.
Examples Set Cookie An alternate implementation can be found at CDP Endpoint Set Cookie
Java
Python
CSharp
Ruby
JavaScript
Kotlin Because Java requires using all the parameters example, the Map approach used in
CDP Endpoint Set Cookie might be more simple.
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 ()));
Because Python requires using async methods for this example, the synchronous approach found in
CDP Endpoint Set Cookie might be easier.
async with driver . bidi_connection () as connection :
execution = connection . devtools . network . set_cookie (
name = "cheese" ,
value = "gouda" ,
domain = "www.selenium.dev" ,
secure = True
)
await connection . session . execute ( execution )
Due to the added complexity in .NET of obtaining the domains and executing with awaits, the
CDP Endpoint Set Cookie might be easier.
var session = (( IDevTools ) driver ). GetDevToolsSession ();
var domains = session . GetVersionSpecificDomains < OpenQA . Selenium . DevTools . V118 . DevToolsSessionDomains >();
await domains . Network . Enable ( new OpenQA . Selenium . DevTools . V118 . Network . EnableCommandSettings ());
var cookieCommandSettings = new SetCookieCommandSettings
{
Name = "cheese" ,
Value = "gouda" ,
Domain = "www.selenium.dev" ,
Secure = true
};
await domains . Network . SetCookie ( cookieCommandSettings );
driver . devtools . network . set_cookie ( name : 'cheese' ,
value : 'gouda' ,
domain : 'www.selenium.dev' ,
secure : true )
An alternate implementation can be found at CDP Endpoint Performance Metrics
Java
Python
CSharp
Ruby
JavaScript
Kotlin devTools = (( HasDevTools ) driver ). getDevTools ();
devTools . createSession ();
devTools . send ( Performance . enable ( Optional . empty ()));
List < Metric > metricList = devTools . send ( Performance . getMetrics ());
Because Python requires using async methods for this example, the synchronous approach found in
CDP Endpoint Performance Metrics might be easier.
async with driver . bidi_connection () as connection :
await connection . session . execute ( connection . devtools . performance . enable ())
metric_list = await connection . session . execute ( connection . devtools . performance . get_metrics ())
Due to the added complexity in .NET of obtaining the domains and executing with awaits, the
CDP Endpoint Performance Metrics might be easier.
var session = (( IDevTools ) driver ). GetDevToolsSession ();
var domains = session . GetVersionSpecificDomains < OpenQA . Selenium . DevTools . V118 . DevToolsSessionDomains >();
await domains . Performance . Enable ( new OpenQA . Selenium . DevTools . V118 . Performance . EnableCommandSettings ());
var metricsResponse =
await session . SendCommand < GetMetricsCommandSettings , GetMetricsCommandResponse >(
new GetMetricsCommandSettings ()
);
driver . devtools . performance . enable
metric_list = driver . devtools . performance . get_metrics . dig ( 'result' , 'metrics' )
Basic authentication Alternate implementations can be found at
CDP Endpoint Basic Authentication
and BiDi API Basic Authentication
Java
Python
CSharp
Ruby
JavaScript
Kotlin The BiDi API Basic Authentication implementation should be preferred
devTools = (( HasDevTools ) driver ). getDevTools ();
devTools . createSession ();
devTools . send ( Network . enable ( Optional . of ( 100000 ), Optional . of ( 100000 ), Optional . of ( 100000 )));
String encodedAuth = Base64 . getEncoder (). encodeToString ( "admin:admin" . getBytes ());
Map < String , Object > headers = ImmutableMap . of ( "Authorization" , "Basic " + encodedAuth );
devTools . send ( Network . setExtraHTTPHeaders ( new Headers ( headers )));
Because Python requires using async methods for this example, the synchronous approach found in
CDP Endpoint Basic Authentication might be easier.
async with driver . bidi_connection () as connection :
await connection . session . execute ( connection . devtools . network . enable ())
credentials = base64 . b64encode ( "admin:admin" . encode ()) . decode ()
auth = { 'authorization' : 'Basic ' + credentials }
await connection . session . execute ( connection . devtools . network . set_extra_http_headers ( Headers ( auth )))
Due to the added complexity in .NET of obtaining the domains and executing with awaits, the
CDP Endpoint Basic Authentication might be easier.
var session = (( IDevTools ) driver ). GetDevToolsSession ();
var domains = session . GetVersionSpecificDomains < OpenQA . Selenium . DevTools . V118 . DevToolsSessionDomains >();
await domains . Network . Enable ( new OpenQA . Selenium . DevTools . V118 . Network . EnableCommandSettings ());
var encodedAuth = Convert . ToBase64String ( Encoding . Default . GetBytes ( "admin:admin" ));
var headerSettings = new SetExtraHTTPHeadersCommandSettings
{
Headers = new Headers ()
{
{ "authorization" , "Basic " + encodedAuth }
}
};
await domains . Network . SetExtraHTTPHeaders ( headerSettings );
The BiDi API Basic Authentication implementation should be preferred
driver . devtools . network . enable
credentials = Base64 . strict_encode64 ( 'admin:admin' )
driver . devtools . network . set_extra_http_headers ( headers : { authorization : "Basic #{ credentials } " })
Console logs Because reading console logs requires setting an event listener,
this cannot be done with a CDP Endpoint implementation
Alternate implementations can be found at
BiDi API Console logs and errors
and WebDriver BiDi Console logs
Java
Python
CSharp
Ruby
JavaScript
Kotlin Use the WebDriver BiDi Console logs implementation
DevTools devTools = (( HasDevTools ) driver ). getDevTools ();
devTools . createSession ();
devTools . send ( Runtime . enable ());
CopyOnWriteArrayList < String > logs = new CopyOnWriteArrayList <>();
devTools . addListener (
Runtime . consoleAPICalled (),
event -> logs . add (( String ) event . getArgs (). get ( 0 ). getValue (). orElse ( "" )));
The BiDi API Console logs and errors implementation should be preferred
driver . devtools . runtime . enable
logs = []
driver . devtools . runtime . on ( :console_api_called ) do | params |
logs << params [ 'args' ]. first [ 'value' ]
end
JavaScript exceptions Similar to console logs, but this listens for actual javascript exceptions not just logged errors
Alternate implementations can be found at
BiDi API JavaScript exceptions
and WebDriver BiDi JavaScript exceptions
Java
Python
CSharp
Ruby
JavaScript
Kotlin Use the WebDriver BiDi JavaScript exceptions implementation
DevTools devTools = (( HasDevTools ) driver ). getDevTools ();
devTools . createSession ();
devTools . send ( Runtime . enable ());
CopyOnWriteArrayList < JavascriptException > errors = new CopyOnWriteArrayList <>();
devTools . getDomains (). events (). addJavascriptExceptionListener ( errors :: add );
Download complete Wait for a download to finish before continuing.
Because getting download status requires setting a listener, this cannot be done with a CDP Endpoint implementation.
Java
Python
CSharp
Ruby
JavaScript
Kotlin 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 . devtools . browser . set_download_behavior ( behavior : 'allow' ,
download_path : '' ,
events_enabled : true )
driver . devtools . browser . on ( :download_progress ) do | progress |
@completed = progress [ 'state' ] == 'completed'
end
1.3 - Chrome Devtools Protocol with BiDi API These examples are currently implemented with CDP, but the same code should work when the functionality is re-implemented with WebDriver-BiDi.
Usage The following list of APIs will be growing as the Selenium
project works through supporting real world use cases. If there
is additional functionality you’d like to see, please raise a
feature request .
As these examples are re-implemented with the WebDriver-Bidi protocol, they will
be moved to the WebDriver Bidi pages.
Examples Basic authentication Some applications make use of browser authentication to secure pages.
It used to be common to handle them in the URL, but browser stopped supporting this.
With BiDi, you can now provide the credentials when necessary
Alternate implementations can be found at
CDP Endpoint Basic Authentication
and CDP API Basic Authentication
Java
Python
CSharp
Ruby
JavaScript
Kotlin Predicate < URI > uriPredicate = uri -> uri . toString (). contains ( "herokuapp.com" );
Supplier < Credentials > authentication = UsernameAndPassword . of ( "admin" , "admin" );
(( HasAuthentication ) driver ). register ( uriPredicate , authentication );
var handler = new NetworkAuthenticationHandler ()
{
UriMatcher = uri => uri . AbsoluteUri . Contains ( "herokuapp" ),
Credentials = new PasswordCredentials ( "admin" , "admin" )
};
var networkInterceptor = driver . Manage (). Network ;
networkInterceptor . AddAuthenticationHandler ( handler );
await networkInterceptor . StartMonitoring ();
driver . register ( username : 'admin' ,
password : 'admin' ,
uri : /herokuapp/ )
Move Code
const { Builder } = require ( 'selenium-webdriver' );
( async function example () {
try {
let driver = await new Builder ()
. forBrowser ( 'chrome' )
. build ();
const pageCdpConnection = await driver . createCDPConnection ( 'page' );
await driver . register ( 'username' , 'password' , pageCdpConnection );
await driver . get ( 'https://the-internet.herokuapp.com/basic_auth' );
await driver . quit ();
} catch ( e ){
console . log ( e )
}
}())
Move Code
val uriPredicate = Predicate { uri : URI ->
uri . host . contains ( "your-domain.com" )
}
( driver as HasAuthentication ). register ( uriPredicate , UsernameAndPassword . of ( "admin" , "password" ))
driver . get ( "https://your-domain.com/login" )
Pin scripts This can be especially useful when executing on a remote server. For example,
whenever you check the visibility of an element, or whenever you use
the classic get attribute method, Selenium is sending the contents of a js file
to the script execution endpoint. These files are each about 50kB, which adds up.
Java
Python
CSharp
Ruby
JavaScript
Kotlin var key = await new JavaScriptEngine ( driver ). PinScript ( "return arguments;" );
var arguments = (( WebDriver ) driver ). ExecuteScript ( key , 1 , true , element );
key = driver . pin_script ( 'return arguments;' )
arguments = driver . execute_script ( key , 1 , true , element )
Mutation observation Mutation Observation is the ability to capture events via
WebDriver BiDi when there are DOM mutations on a specific
element in the DOM.
Java
Python
CSharp
Ruby
JavaScript
Kotlin CopyOnWriteArrayList < WebElement > mutations = new CopyOnWriteArrayList <>();
(( HasLogEvents ) driver ). onLogEvent ( domMutation ( e -> mutations . add ( e . getElement ())));
async with driver . bidi_connection () as session :
log = Log ( driver , session )
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 ();
mutations = []
driver . on_log_event ( :mutation ) { | mutation | mutations << mutation . element }
Move Code
const { Builder , until } = require ( 'selenium-webdriver' );
const assert = require ( "assert" );
( async function example () {
try {
let driver = await new Builder ()
. forBrowser ( 'chrome' )
. build ();
const cdpConnection = await driver . createCDPConnection ( 'page' );
await driver . logMutationEvents ( cdpConnection , event => {
assert . deepStrictEqual ( event [ 'attribute_name' ], 'style' );
assert . deepStrictEqual ( event [ 'current_value' ], "" );
assert . deepStrictEqual ( event [ 'old_value' ], "display:none;" );
});
await driver . get ( 'dynamic.html' );
await driver . findElement ({ id : 'reveal' }). click ();
let revealed = driver . findElement ({ id : 'revealed' });
await driver . wait ( until . elementIsVisible ( revealed ), 5000 );
await driver . quit ();
} catch ( e ){
console . log ( e )
}
}())
Console logs and errors Listen to the console.log
events and register callbacks to process the event.
CDP API Console logs
and WebDriver BiDi Console logs
Java
Python
CSharp
Ruby
JavaScript
Kotlin Use the WebDriver BiDi Console logs implementation. HasLogEvents
will likely end up deprecated because it does not implement Closeable
.
CopyOnWriteArrayList < String > messages = new CopyOnWriteArrayList <>();
(( HasLogEvents ) driver ). onLogEvent ( consoleEvent ( e -> messages . add ( e . getMessages (). get ( 0 ))));
async with driver . bidi_connection () as session :
log = Log ( driver , session )
async with log . add_listener ( Console . ALL ) as messages :
using IJavaScriptEngine monitor = new JavaScriptEngine ( driver );
var messages = new List < string >();
monitor . JavaScriptConsoleApiCalled += ( _ , e ) =>
{
messages . Add ( e . MessageContent );
};
await monitor . StartEventMonitoring ();
logs = []
driver . on_log_event ( :console ) { | log | logs << log . args . first }
Move Code
const { Builder } = require ( 'selenium-webdriver' );
( async () => {
try {
let driver = new Builder ()
. forBrowser ( 'chrome' )
. build ();
const cdpConnection = await driver . createCDPConnection ( 'page' );
await driver . onLogEvent ( cdpConnection , function ( event ) {
console . log ( event [ 'args' ][ 0 ][ 'value' ]);
});
await driver . executeScript ( 'console.log("here")' );
await driver . quit ();
} catch ( e ){
console . log ( e );
}
})()
Move Code
fun kotlinConsoleLogExample () {
val driver = ChromeDriver ()
val devTools = driver . devTools
devTools . createSession ()
val logConsole = { c : ConsoleEvent -> print ( "Console log message is: " + c . messages )}
devTools . domains . events (). addConsoleListener ( logConsole )
driver . get ( "https://www.google.com" )
val executor = driver as JavascriptExecutor
executor . executeScript ( "console.log('Hello World')" )
val input = driver . findElement ( By . name ( "q" ))
input . sendKeys ( "Selenium 4" )
input . sendKeys ( Keys . RETURN )
driver . quit ()
}
JavaScript exceptions Listen to the JS Exceptions
and register callbacks to process the exception details.
Java
Python
CSharp
Ruby
JavaScript
Kotlin async with driver . bidi_connection () as session :
log = Log ( driver , session )
async with log . add_js_error_listener () as messages :
using IJavaScriptEngine monitor = new JavaScriptEngine ( driver );
var messages = new List < string >();
monitor . JavaScriptExceptionThrown += ( _ , e ) =>
{
messages . Add ( e . Message );
};
await monitor . StartEventMonitoring ();
exceptions = []
driver . on_log_event ( :exception ) { | exception | exceptions << exception }
Network Interception Both requests and responses can be recorded or transformed.
Java
Python
CSharp
Ruby
JavaScript
Kotlin 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 ;
})) {
var contentType = new List < string >();
INetwork networkInterceptor = driver . Manage (). Network ;
networkInterceptor . NetworkResponseReceived += ( _ , e ) =>
{
contentType . Add ( e . ResponseHeaders [ "content-type" ]);
};
await networkInterceptor . StartMonitoring ();
content_type = []
driver . intercept do | request , & continue |
continue . call ( request ) do | response |
content_type << response . headers [ 'content-type' ]
end
end
Java
Python
CSharp
Ruby
JavaScript
Kotlin 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!" ))))) {
var handler = new NetworkResponseHandler ()
{
ResponseMatcher = _ => true ,
ResponseTransformer = _ => new HttpResponseData
{
StatusCode = 200 ,
Body = "Creamy, delicious cheese!"
}
};
INetwork networkInterceptor = driver . Manage (). Network ;
networkInterceptor . AddResponseHandler ( handler );
await networkInterceptor . StartMonitoring ();
driver . intercept do | request , & continue |
continue . call ( request ) do | response |
response . body = 'Creamy, delicious cheese!' if request . url . include? ( 'blank' )
end
end
Move Code
const connection = await driver . createCDPConnection ( 'page' )
let url = fileServer . whereIs ( "/cheese" )
let httpResponse = new HttpResponse ( url )
httpResponse . addHeaders ( "Content-Type" , "UTF-8" )
httpResponse . body = "sausages"
await driver . onIntercept ( connection , httpResponse , async function () {
let body = await driver . getPageSource ()
assert . strictEqual ( body . includes ( "sausages" ), true , `Body contains: ${ body } ` )
})
driver . get ( url )
Move Code
val driver = ChromeDriver ()
val interceptor = new NetworkInterceptor (
driver ,
Route . matching ( req -> true )
. to (() -> req -> new HttpResponse ()
. setStatus ( 200 )
. addHeader ( "Content-Type" , MediaType . HTML_UTF_8 . toString ())
. setContent ( utf8String ( "Creamy, delicious cheese!" ))))
driver . get ( appServer . whereIs ( "/cheese" ))
String source = driver . getPageSource ()
Request interception
Java
Python
CSharp
Ruby
JavaScript
Kotlin var handler = new NetworkRequestHandler
{
RequestMatcher = request => request . Url . Contains ( "one.js" ),
RequestTransformer = request =>
{
request . Url = request . Url . Replace ( "one" , "two" );
return request ;
}
};
INetwork networkInterceptor = driver . Manage (). Network ;
networkInterceptor . AddRequestHandler ( handler );
await networkInterceptor . StartMonitoring ();
driver . intercept do | request , & continue |
uri = URI ( request . url )
request . url = uri . to_s . gsub ( 'one' , 'two' ) if uri . path &. end_with? ( 'one.js' )
continue . call ( request )
end
2 - BiDirectional API (W3C compliant) The following list of APIs will be growing as the WebDriver BiDirectional Protocol grows
and browser vendors implement the same.
Additionally, Selenium will try to support real-world use cases that internally use a combination of W3C BiDi protocol APIs.
If there is additional functionality you’d like to see, please raise a
feature request .
2.1 - Browsing Context
Page being translated from
English to Chinese. Do you speak Chinese? Help us to translate
it by sending us pull requests!
This section contains the APIs related to browsing context commands.
Open a new window Creates a new browsing context in a new window.
Java
Ruby
JavaScript
Kotlin Selenium v4.8
BrowsingContext browsingContext = new BrowsingContext ( driver , WindowType . WINDOW );
Open a new tab Creates a new browsing context in a new tab.
Java
Ruby
JavaScript
Kotlin Selenium v4.8
BrowsingContext browsingContext = new BrowsingContext ( driver , WindowType . TAB );
Use existing window handle Creates a browsing context for the existing tab/window to run commands.
Java
Ruby
JavaScript
Kotlin Selenium v4.8
String id = driver . getWindowHandle ();
BrowsingContext browsingContext = new BrowsingContext ( driver , id );
Open a window with a reference browsing context A reference browsing context is a top-level browsing context .
The API allows to pass the reference browsing context, which is used to create a new window. The implementation is operating system specific.
Java
Ruby
JavaScript
Kotlin Selenium v4.8
BrowsingContext
browsingContext =
new BrowsingContext ( driver , WindowType . WINDOW , driver . getWindowHandle ());
Open a tab with a reference browsing context A reference browsing context is a top-level browsing context .
The API allows to pass the reference browsing context, which is used to create a new tab. The implementation is operating system specific.
Java
Ruby
JavaScript
Kotlin Selenium v4.8
BrowsingContext
browsingContext =
new BrowsingContext ( driver , WindowType . TAB , driver . getWindowHandle ());
Navigate to a URL
Java
Ruby
JavaScript
Kotlin Selenium v4.8
BrowsingContext browsingContext = new BrowsingContext ( driver , WindowType . TAB );
NavigationResult info = browsingContext . navigate ( "https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html" );
Navigate to a URL with readiness state
Java
Ruby
JavaScript
Kotlin Selenium v4.8
BrowsingContext browsingContext = new BrowsingContext ( driver , WindowType . TAB );
NavigationResult info = browsingContext . navigate ( "https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html" ,
ReadinessState . COMPLETE );
Get browsing context tree Provides a tree of all browsing contexts descending from the parent browsing context, including the parent browsing context.
Java
Ruby
JavaScript
Kotlin Selenium v4.8
String referenceContextId = driver . getWindowHandle ();
BrowsingContext parentWindow = new BrowsingContext ( driver , referenceContextId );
parentWindow . navigate ( "https://www.selenium.dev/selenium/web/iframes.html" , ReadinessState . COMPLETE );
List < BrowsingContextInfo > contextInfoList = parentWindow . getTree ();
Get browsing context tree with depth Provides a tree of all browsing contexts descending from the parent browsing context, including the parent browsing context upto the depth value passed.
Java
Ruby
JavaScript
Kotlin Selenium v4.8
String referenceContextId = driver . getWindowHandle ();
BrowsingContext parentWindow = new BrowsingContext ( driver , referenceContextId );
parentWindow . navigate ( "https://www.selenium.dev/selenium/web/iframes.html" , ReadinessState . COMPLETE );
Get All Top level browsing contexts
Java
Ruby
JavaScript
Kotlin Selenium v4.8
BrowsingContext window1 = new BrowsingContext ( driver , driver . getWindowHandle ());
BrowsingContext window2 = new BrowsingContext ( driver , WindowType . WINDOW );
List < BrowsingContextInfo > contextInfoList = window1 . getTopLevelContexts ();
Close a tab/window
Java
Ruby
JavaScript
Kotlin Selenium v4.8
BrowsingContext window1 = new BrowsingContext ( driver , WindowType . WINDOW );
BrowsingContext window2 = new BrowsingContext ( driver , WindowType . WINDOW );
window2 . close ();
2.2 - BiDirectional API (W3C compliant)
Page being translated from
English to Chinese. Do you speak Chinese? Help us to translate
it by sending us pull requests!
This section contains the APIs related to logging.
Console logs Listen to the console.log
events and register callbacks to process the event.
Java
Ruby
JavaScript
Kotlin public void jsErrors () {
CopyOnWriteArrayList < ConsoleLogEntry > logs = new CopyOnWriteArrayList <>();
try ( LogInspector logInspector = new LogInspector ( driver )) {
logInspector . onConsoleEntry ( logs :: add );
}
driver . get ( "https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html" );
Selenium v4.8
const inspector = await LogInspector ( driver )
await inspector . onConsoleEntry ( function ( log ) {
logEntry = log
})
await driver . get ( 'https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html' )
await driver . findElement ({ id : 'consoleLog' }). click ()
assert . equal ( logEntry . text , 'Hello, world!' )
assert . equal ( logEntry . realm , null )
assert . equal ( logEntry . type , 'console' )
assert . equal ( logEntry . level , 'info' )
assert . equal ( logEntry . method , 'log' )
assert . equal ( logEntry . stackTrace , null )
assert . equal ( logEntry . args . length , 1 )
JavaScript exceptions Listen to the JS Exceptions
and register callbacks to process the exception details.
Java
Ruby
JavaScript
Kotlin logInspector . onJavaScriptLog ( future :: complete );
driver . get ( "https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html" );
driver . findElement ( By . id ( "jsException" )). click ();
JavascriptLogEntry logEntry = future . get ( 5 , TimeUnit . SECONDS );
Assertions . assertEquals ( "Error: Not working" , logEntry . getText ());
Selenium v4.8
const inspector = await LogInspector ( driver )
await inspector . onJavascriptException ( function ( log ) {
logEntry = log
})
await driver . get ( 'https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html' )
await driver . findElement ({ id : 'jsException' }). click ()
assert . equal ( logEntry . text , 'Error: Not working' )
assert . equal ( logEntry . type , 'javascript' )
assert . equal ( logEntry . level , 'error' )
Listen to JS Logs Listen to all JS logs at all levels and register callbacks to process the log.
Java
Ruby
JavaScript
Kotlin driver . findElement ( By . id ( "consoleLog" )). click ();
ConsoleLogEntry logEntry = future . get ( 5 , TimeUnit . SECONDS );
Assertions . assertEquals ( "Hello, world!" , logEntry . getText ());
Assertions . assertNull ( logEntry . getRealm ());
Assertions . assertEquals ( 1 , logEntry . getArgs (). size ());
Assertions . assertEquals ( "console" , logEntry . getType ());