├── .gitignore ├── LICENSE ├── README.md ├── bump_includes.sh ├── external └── bash │ └── ccurl.sh ├── pom.profiles.xml ├── pom.xml ├── screenshots ├── capture-multi-zoom.png ├── capture_csp_blocking.png ├── capture_csp_bypassed.png ├── chromium_headless_in_chromum_gui.png ├── filtering-off_capture.jpg ├── filtering-on_capture.jpg ├── xhr_logged_capture.png └── xhr_test_capture.png └── src ├── main └── java │ └── com │ └── github │ └── sergueik │ └── selenium │ └── Utils.java └── test ├── java └── com │ └── github │ └── sergueik │ └── selenium │ ├── AlertDevToolsLocalTest.java │ ├── AlertDevToolsTest.java │ ├── AuthHeadersCdpTest.java │ ├── AuthHeadersDevToolsTest.java │ ├── AuthHeadersFailingCdpTest.java │ ├── BaseCdpTest.java │ ├── BaseDevToolsTest.java │ ├── BrowserCommandLineCDPTest.java │ ├── BrowserCommandLineDevToolsTest.java │ ├── BrowserDownloadCdpTest.java │ ├── BrowserDownloadDevToolsTest.java │ ├── BrowserHistogramCDPTest.java │ ├── BrowserHistogramDevToolsTest.java │ ├── BrowserVersionCdpTest.java │ ├── BrowserVersionDevToolsTest.java │ ├── BrowsingContextTraverseHistoryCdpTest.java │ ├── BypassCSPCdpTest.java │ ├── BypassCSPDevToolsTest.java │ ├── ChromeDevToolsInjectedScriptTest.java │ ├── ChromeDevToolsTest.java │ ├── ChromiumCdpInjectedScriptTest.java │ ├── ChromiumCdpTest.java │ ├── ComputedStyleCDPTest.java │ ├── ComputedStyleDevToolsTest.java │ ├── ConsoleMessagesDevToolsTest.java │ ├── CustomHeadersCdpTest.java │ ├── CustomHeadersDevToolsTest.java │ ├── DOMElementClickCdpTest.java │ ├── DOMElementClickDevToolsTest.java │ ├── DOMElementFocusCDPTest.java │ ├── DOMElementFocusDevToolsTest.java │ ├── DOMElementScrollCDPTest.java │ ├── DOMElementScrollDevToolsTest.java │ ├── DOMNodeAttributesCdpTest.java │ ├── DOMNodeAttributesDevToolsTest.java │ ├── DOMPerformSearchCdpTest.java │ ├── DOMPerformSearchDevToolsTest.java │ ├── DOMSnapshotCdpTest.java │ ├── DOMSnapshotDevToolsTest.java │ ├── DescribeNodeCdpTest.java │ ├── DescribeNodeDevToolsTest.java │ ├── DeviceMetricsOverrideCdpTest.java │ ├── DeviceMetricsOverrideDevToolsTest.java │ ├── DisplayFeatureCdpTest.java │ ├── DomainJavascriptDevToolsTest.java │ ├── ElementScreenshotCdpTest.java │ ├── ElementScreenshotDevToolsTest.java │ ├── EventSubscriptionCommonTest.java │ ├── ExceptionListenerDevToolsTest.java │ ├── FetcFailRequestDevToolsTest.java │ ├── FetchAuthRequiredDevToolsTest.java │ ├── FileChooserDialogInterceptDevToolsTest.java │ ├── FileUploadNetworkDevToolsTest.java │ ├── FilterUrlCdpTest.java │ ├── FilterUrlDevToolsTest.java │ ├── FrameDevToolsTest.java │ ├── FramesCdpTest.java │ ├── FramesDevToolsTest.java │ ├── GeolocationOverrideCdpTest.java │ ├── GeolocationOverrideDevToolsTest.java │ ├── HasAuthenticationTest.java │ ├── IgnoreCertificateErrorsCdpTest.java │ ├── IgnoreCertificateErrorsDevToolsTest.java │ ├── IndirectGeolocationOverrideCdpTest.java │ ├── IndirectGeolocationOverrideDevToolsTest.java │ ├── InputCdpTest.java │ ├── InputDevToolsTest.java │ ├── LegacyLoggingDevToolsTest.java │ ├── LocaleOverrideTest.java │ ├── LoggingDevToolsTest.java │ ├── MeasureEagerStrategyTest.java │ ├── NetworkConditionsCdpTest.java │ ├── NetworkConditionsDevToolsTest.java │ ├── NetworkDevToolsTest.java │ ├── NetworkInterceptorLegacyTest.java │ ├── NetworkResponseBodyTest.java │ ├── OverlayHighlightCDPTest.java │ ├── OverlayHighlightDevToolsTest.java │ ├── PageDownloadCdpTest.java │ ├── PageDownloadDevToolsTest.java │ ├── PageNavigationHistoryCDPTest.java │ ├── PageNavigationHistoryDevToolsTest.java │ ├── PageScaleFactorCdpTest.java │ ├── PageScaleFactorDevToolsTest.java │ ├── PageSourceCdpTest.java │ ├── PageSourceDevToolsTest.java │ ├── PerformanceMetricDevToolsTest.java │ ├── PerformanceMetricsCdpTest.java │ ├── PierceCdpTest.java │ ├── PierceDevToolsTest.java │ ├── PrintToPDFCDPTest.java │ ├── PrintToPDFDevToolsTest.java │ ├── RelativeLocatorTest.java │ ├── RuntimeCdpTest.java │ ├── RuntimeDevToolsTest.java │ ├── RuntimeLoggingDevToolsTest.java │ ├── ScreenCastFramesDevToolsTest.java │ ├── ScreenShotCdpTest.java │ ├── ScreenShotDevToolsTest.java │ ├── ShadowDomCDPTest.java │ ├── ShadowRootCdpTest.java │ ├── ShadowRootDevToolsTest.java │ ├── StorageDevToolsTest.java │ ├── SystemInfoCdpTest.java │ ├── SystemInfoDevToolsTest.java │ ├── TimeZoneCdpTest.java │ ├── TimeZoneDevToolsTest.java │ ├── UserAgentOverrideCdpTest.java │ ├── UserAgentOverrideDevToolsTest.java │ ├── WebpCdpTest.java │ ├── WebpDevToolsTest.java │ ├── WheelInputTest.java │ ├── WindowSizeCdpTest.java │ ├── WindowSizeDevToolsTest.java │ ├── WindowsTabsCdpTest.java │ ├── WindowsTabsDevToolsTest.java │ ├── WindowsTabsTest.java │ ├── XHRFetchDevToolsTest.java │ ├── ZoomCdpTest.java │ └── ZoomDevToolsTest.java └── resources ├── angular.js ├── call_ajax.html ├── fixed_size_page.html ├── getStyle.js ├── iframe_example.html ├── image_page.html ├── inner_html_example.html ├── ng_basic.htm ├── sizes.jpg ├── test1.html ├── test2.html ├── tryit1.html └── tryjsref_prompt.html /.gitignore: -------------------------------------------------------------------------------- 1 | **/bin/** 2 | **/.settings 3 | **/.classpath 4 | **/.project 5 | **/.gitignore 6 | **/work/** 7 | **/target/** 8 | **/.*.sw? 9 | **/*.jpg 10 | **/*.log 11 | **/*.png 12 | **/src/**/*.jar 13 | **/build/** 14 | **/test-output/** 15 | /pom.xml.releaseBackup 16 | /release.properties 17 | /settings.xml 18 | *.unc-backup~ 19 | *.uncrustify 20 | /target/ 21 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014,2017 Serguei Kouzmine 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /bump_includes.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # NOTE: after editing on Windows, fix the line endings to prevent 3 | # /bin/sh^M: bad interpreter: No such file or directory error 4 | 5 | VERSION=${1:-106} 6 | NEW_VERSION=$2 7 | CURRENT_VERSION=$(printf "v%s" ${VERSION}) 8 | if [ -z "$NEW_VERSION" ] ; then 9 | NEW_VERSION=$(printf "v%s" $(expr 1 + ${VERSION} )) 10 | else 11 | NEW_VERSION=$(printf "v%s" ${NEW_VERSION}) 12 | fi 13 | grep -ilr "$CURRENT_VERSION" src/* --include '*java' | xargs -IX sed -i "s|\.$CURRENT_VERSION|.$NEW_VERSION|g" X 14 | grep -ilr "${NEW_VERSION}" src/* --include '*java' |xargs -IX git add X 15 | -------------------------------------------------------------------------------- /external/bash/ccurl.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # origin: https://github.com/fipso/ccurl.sh/blob/main/ccurl.sh 4 | 5 | # Check if at least two arguments were provided 6 | if [ "$#" -lt 2 ]; then 7 | echo "Usage: $0 [Tab URL Prefix] [cURL command ...]" 8 | exit 1 9 | fi 10 | 11 | # Use cURL to get the JSON information on the openTab using your local Chrome instance's debug feature 12 | DEBUG_URL=$(curl "http://127.0.0.1:9222/json" -s | jq -r ".[] | select(.url | startswith(\"$1\")) | .webSocketDebuggerUrl") 13 | 14 | # If debug URL cannot be found, prompt the user and exit 15 | if ! [[ "$DEBUG_URL" =~ ^ws.* ]]; then 16 | echo "Could not find tab starting with '$1'. Is chrome running ?" 17 | exit 1 18 | fi 19 | 20 | # Count the number of URLs with that pattern 21 | URL_COUNT=$(echo "$DEBUG_URL" | tr -cd '\n' | wc -c) 22 | 23 | # If there is more than one URL with the specified pattern, prompt the user and exit 24 | if [[ "$URL_COUNT" -gt 1 ]]; then 25 | echo "Pattern '$1' is not precise enough. Multiple tabs/workers where found" 26 | exit 1 27 | fi 28 | 29 | # Use websocat to access the Chrome debug port and retrieve the cookies information 30 | COOKIES=$(echo '{ "id":2, "method":"Network.getCookies", "params":{} }' | websocat -t - $DEBUG_URL | jq -r '.result.cookies[] | "\(.name)=\(.value)"' | tr '\n' ';' | sed 's/\;$/\n/') 31 | 32 | # Append the cookies to the specified URL using curl 33 | curl -H "Cookie: $COOKIES" "${@:2}" 34 | -------------------------------------------------------------------------------- /screenshots/capture-multi-zoom.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sergueik/selenium_cdp/4944544674e62f6efd3584b7976f666a495fc137/screenshots/capture-multi-zoom.png -------------------------------------------------------------------------------- /screenshots/capture_csp_blocking.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sergueik/selenium_cdp/4944544674e62f6efd3584b7976f666a495fc137/screenshots/capture_csp_blocking.png -------------------------------------------------------------------------------- /screenshots/capture_csp_bypassed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sergueik/selenium_cdp/4944544674e62f6efd3584b7976f666a495fc137/screenshots/capture_csp_bypassed.png -------------------------------------------------------------------------------- /screenshots/chromium_headless_in_chromum_gui.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sergueik/selenium_cdp/4944544674e62f6efd3584b7976f666a495fc137/screenshots/chromium_headless_in_chromum_gui.png -------------------------------------------------------------------------------- /screenshots/filtering-off_capture.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sergueik/selenium_cdp/4944544674e62f6efd3584b7976f666a495fc137/screenshots/filtering-off_capture.jpg -------------------------------------------------------------------------------- /screenshots/filtering-on_capture.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sergueik/selenium_cdp/4944544674e62f6efd3584b7976f666a495fc137/screenshots/filtering-on_capture.jpg -------------------------------------------------------------------------------- /screenshots/xhr_logged_capture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sergueik/selenium_cdp/4944544674e62f6efd3584b7976f666a495fc137/screenshots/xhr_logged_capture.png -------------------------------------------------------------------------------- /screenshots/xhr_test_capture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sergueik/selenium_cdp/4944544674e62f6efd3584b7976f666a495fc137/screenshots/xhr_test_capture.png -------------------------------------------------------------------------------- /src/test/java/com/github/sergueik/selenium/AuthHeadersCdpTest.java: -------------------------------------------------------------------------------- 1 | package com.github.sergueik.selenium; 2 | 3 | /** 4 | * Copyright 2023,2024 Serguei Kouzmine 5 | */ 6 | 7 | import static org.hamcrest.CoreMatchers.containsString; 8 | import static org.hamcrest.MatcherAssert.assertThat; 9 | import static org.hamcrest.core.IsNot.not; 10 | 11 | import java.io.UnsupportedEncodingException; 12 | import java.util.HashMap; 13 | import java.util.Map; 14 | 15 | import org.apache.commons.codec.binary.Base64; 16 | import org.junit.After; 17 | import org.junit.AfterClass; 18 | import org.junit.Before; 19 | import org.junit.BeforeClass; 20 | import org.junit.Ignore; 21 | import org.junit.Test; 22 | import org.openqa.selenium.InvalidArgumentException; 23 | 24 | /** 25 | * Selected test scenarios for Selenium 4 Chrome Developer Tools bridge 26 | * https://chromedevtools.github.io/devtools-protocol/tot/Network/#method-setExtraHTTPHeaders 27 | * https://chromedevtools.github.io/devtools-protocol/tot/Network#method-enable 28 | * see also: https://stackoverflow.com/questions/50834002/chrome-headless-browser-with-corporate-proxy-authetication-not-working/67321556#67321556 29 | * @author: Serguei Kouzmine (kouzmine_serguei@yahoo.com) 30 | */ 31 | 32 | // see also: 33 | // https://github.com/shsarkar08/PythonSeleniumCDP_APIs/blob/master/selenium_py_cdp_basic_auth.py 34 | // 35 | public class AuthHeadersCdpTest extends BaseCdpTest { 36 | 37 | private static String baseURL = "https://jigsaw.w3.org/HTTP/"; 38 | private static String url = "https://jigsaw.w3.org/HTTP/Basic/"; 39 | 40 | private final String username = "guest"; 41 | private final String password = "guest"; 42 | // NOTE: cannot initialize here: 43 | // Default constructor cannot handle exception type 44 | // UnsupportedEncodingException thrown by implicit super constructor. Must 45 | // define an explicit constructor 46 | // private byte[] input = String.format("%s:%s", username, 47 | // password).getBytes("UTF-8"); 48 | private static String authString = null; 49 | 50 | private static Map headers = new HashMap<>(); 51 | 52 | private static String command = null; 53 | 54 | private static Map params = new HashMap<>(); 55 | 56 | @After 57 | public void afterTest() { 58 | command = "Network.disable"; 59 | driver.executeCdpCommand(command, new HashMap<>()); 60 | driver.get("about:blank"); 61 | } 62 | 63 | @AfterClass 64 | public static void tearDown() { 65 | if (driver != null) { 66 | driver.quit(); 67 | } 68 | } 69 | 70 | @BeforeClass 71 | public static void beforeClass() throws Exception { 72 | // NOTE: NPE without calling the superclass @BeforeClass method 73 | BaseCdpTest.beforeClass(); 74 | // Cannot use super in a static context 75 | // super.beforeClass(); 76 | driver.get(baseURL); 77 | } 78 | 79 | @Before 80 | public void beforeTest() throws UnsupportedEncodingException { 81 | // NOT passing any parameters 82 | command = "Network.enable"; 83 | driver.executeCdpCommand(command, new HashMap<>()); 84 | byte[] input = String.format("%s:%s", username, password).getBytes("UTF-8"); 85 | authString = new String(Base64.encodeBase64(input)); 86 | 87 | driver.get(baseURL); 88 | } 89 | 90 | @Test(expected = InvalidArgumentException.class) 91 | public void test3() throws UnsupportedEncodingException { 92 | params = new HashMap<>(); 93 | params.put("authorization", "Basic " + authString); 94 | command = "Network.setExtraHTTPHeaders"; 95 | // NOTE: org.openqa.selenium.InvalidArgumentException: 96 | // invalid argument: Invalid parameters 97 | driver.executeCdpCommand(command, params); 98 | } 99 | // 100 | 101 | @Test 102 | public void test1() throws UnsupportedEncodingException { 103 | headers = new HashMap<>(); 104 | params = new HashMap<>(); 105 | headers.put("authorization", "Basic " + authString); 106 | params.put("headers", headers); 107 | 108 | command = "Network.setExtraHTTPHeaders"; 109 | driver.executeCdpCommand(command, params); 110 | 111 | driver.get(url); 112 | assertThat(driver.getPageSource(), containsString("Your browser made it!")); 113 | System.err.println(driver.getPageSource()); 114 | } 115 | 116 | // NOTE: need to send extra HTTP Headers with blank value to fail to 117 | // authenticate ? 118 | @Ignore("failing to clear extra HTTP Headers") 119 | @Test 120 | public void test2() { 121 | params = new HashMap<>(); 122 | params.put("headers", new HashMap<>()); 123 | command = "Network.setExtraHTTPHeaders"; 124 | driver.executeCdpCommand(command, params); 125 | 126 | driver.get(url); 127 | assertThat(driver.getPageSource(), 128 | not(containsString("Your browser made it!"))); 129 | System.err.println(driver.getPageSource()); 130 | } 131 | 132 | } 133 | -------------------------------------------------------------------------------- /src/test/java/com/github/sergueik/selenium/AuthHeadersFailingCdpTest.java: -------------------------------------------------------------------------------- 1 | package com.github.sergueik.selenium; 2 | /** 3 | * Copyright 2023,2024 Serguei Kouzmine 4 | */ 5 | 6 | import static org.hamcrest.CoreMatchers.is; 7 | import static org.hamcrest.CoreMatchers.notNullValue; 8 | import static org.hamcrest.MatcherAssert.assertThat; 9 | 10 | import java.io.UnsupportedEncodingException; 11 | import java.util.HashMap; 12 | import java.util.Map; 13 | 14 | import org.apache.commons.codec.binary.Base64; 15 | import org.junit.After; 16 | import org.junit.AfterClass; 17 | import org.junit.Before; 18 | import org.junit.BeforeClass; 19 | import org.junit.Test; 20 | import org.openqa.selenium.By; 21 | import org.openqa.selenium.WebElement; 22 | 23 | /** 24 | * Selected test scenarios for Selenium 4 Chrome Developer Tools bridge 25 | * https://chromedevtools.github.io/devtools-protocol/tot/Network/#method-setExtraHTTPHeaders 26 | * https://chromedevtools.github.io/devtools-protocol/tot/Network#method-enable 27 | * see also: https://stackoverflow.com/questions/50834002/chrome-headless-browser-with-corporate-proxy-authetication-not-working/67321556#67321556 28 | * @author: Serguei Kouzmine (kouzmine_serguei@yahoo.com) 29 | */ 30 | 31 | // see also: 32 | // https://github.com/shsarkar08/PythonSeleniumCDP_APIs/blob/master/selenium_py_cdp_basic_auth.py 33 | // 34 | public class AuthHeadersFailingCdpTest extends BaseCdpTest { 35 | 36 | private static String baseURL = "https://jigsaw.w3.org/HTTP/"; 37 | private static String url = "https://jigsaw.w3.org/HTTP/Basic/"; 38 | 39 | private final String username = "guest"; 40 | private final String password = "wrong password"; 41 | // NOTE: cannot initialize authString here: 42 | // Default constructor cannot handle exception type 43 | // UnsupportedEncodingException thrown by implicit super constructor. Must 44 | // define an explicit constructor 45 | // private byte[] input = String.format("%s:%s", username, 46 | // password).getBytes("UTF-8"); 47 | private static String authString = null; 48 | private static WebElement element; 49 | 50 | private static Map headers = new HashMap<>(); 51 | 52 | private static String command = null; 53 | 54 | private static Map params = new HashMap<>(); 55 | 56 | @After 57 | public void afterTest() { 58 | command = "Network.disable"; 59 | driver.executeCdpCommand(command, new HashMap<>()); 60 | driver.get("about:blank"); 61 | } 62 | 63 | @AfterClass 64 | public static void tearDown() { 65 | if (driver != null) { 66 | driver.quit(); 67 | } 68 | } 69 | 70 | @BeforeClass 71 | public static void beforeClass() throws Exception { 72 | // NOTE: NPE without calling the superclass @BeforeClass method 73 | BaseCdpTest.beforeClass(); 74 | // Cannot use super in a static context 75 | // super.beforeClass(); 76 | driver.get(baseURL); 77 | } 78 | 79 | @Before 80 | public void beforeTest() throws UnsupportedEncodingException { 81 | // NOT passing any parameters 82 | command = "Network.enable"; 83 | driver.executeCdpCommand(command, new HashMap<>()); 84 | authString = new String(Base64.encodeBase64( 85 | String.format("%s:%s", username, password).getBytes("UTF-8"))); 86 | driver.get(baseURL); 87 | } 88 | 89 | @Test 90 | public void test1() throws UnsupportedEncodingException { 91 | if (runHeadless) 92 | return; 93 | headers = new HashMap<>(); 94 | params = new HashMap<>(); 95 | headers.put("authorization", "Basic " + authString); 96 | params.put("headers", headers); 97 | 98 | command = "Network.setExtraHTTPHeaders"; 99 | driver.executeCdpCommand(command, params); 100 | 101 | driver.get(url); 102 | 103 | element = driver.findElement(By.xpath("//body")); 104 | assertThat(element, notNullValue()); 105 | assertThat(element.getText(), is("")); 106 | } 107 | 108 | // NOTE: occasionally in headless test, the body is 109 | // "Unauthorized access\nYou are denied access to this resource." 110 | @Test 111 | public void test2() { 112 | if (!runHeadless) 113 | return; 114 | command = "Network.setExtraHTTPHeaders"; 115 | headers = new HashMap<>(); 116 | params = new HashMap<>(); 117 | headers.put("authorization", "Basic " + authString); 118 | params.put("headers", headers); 119 | driver.executeCdpCommand(command, params); 120 | 121 | driver.get(url); 122 | element = driver.findElement(By.xpath("//body")); 123 | assertThat(element, notNullValue()); 124 | assertThat(element.getText(), is("")); 125 | // assertThat(driver.getTitle(), is("Unauthorized access")); 126 | System.err.println(driver.getPageSource()); 127 | } 128 | 129 | } 130 | -------------------------------------------------------------------------------- /src/test/java/com/github/sergueik/selenium/BrowserCommandLineCDPTest.java: -------------------------------------------------------------------------------- 1 | package com.github.sergueik.selenium; 2 | 3 | /** 4 | * Copyright 2023,2024 Serguei Kouzmine 5 | */ 6 | 7 | import static org.hamcrest.CoreMatchers.is; 8 | 9 | /** 10 | * Copyright 2022,2023 Serguei Kouzmine 11 | */ 12 | 13 | import static org.hamcrest.CoreMatchers.notNullValue; 14 | import static org.hamcrest.MatcherAssert.assertThat; 15 | import static org.hamcrest.Matchers.greaterThan; 16 | 17 | import java.util.HashMap; 18 | import java.util.List; 19 | import java.util.Map; 20 | 21 | import org.junit.Test; 22 | 23 | /** 24 | * Selected test scenarios for Selenium 4 Chrome Developer Tools bridge inspired 25 | * https://chromedevtools.github.io/devtools-protocol/tot/Browser/#method-getBrowserCommandLine 26 | * 27 | * @author: Serguei Kouzmine (kouzmine_serguei@yahoo.com) 28 | */ 29 | 30 | public class BrowserCommandLineCDPTest extends BaseCdpTest { 31 | 32 | private static String command = "Browser.getBrowserCommandLine"; 33 | private static Map result = new HashMap<>(); 34 | private static List results; 35 | 36 | @SuppressWarnings("unchecked") 37 | @Test 38 | public void test() { 39 | // Act 40 | result = driver.executeCdpCommand(command, new HashMap<>()); 41 | // Assert 42 | assertThat(result, notNullValue()); 43 | 44 | assertThat(result instanceof Map, is(true)); 45 | assertThat(result.containsKey("arguments"), is(true)); 46 | assertThat(result.get("arguments") instanceof List, is(true)); 47 | results = (List) result.get("arguments"); 48 | assertThat(results.size(), greaterThan(1)); 49 | System.err.println(String.join("\n", results)); 50 | } 51 | 52 | } 53 | -------------------------------------------------------------------------------- /src/test/java/com/github/sergueik/selenium/BrowserCommandLineDevToolsTest.java: -------------------------------------------------------------------------------- 1 | package com.github.sergueik.selenium; 2 | 3 | /** 4 | * Copyright 2022-2024 Serguei Kouzmine 5 | */ 6 | 7 | import static org.hamcrest.CoreMatchers.notNullValue; 8 | import static org.hamcrest.MatcherAssert.assertThat; 9 | import static org.hamcrest.Matchers.greaterThan; 10 | 11 | import java.util.List; 12 | 13 | import org.junit.Test; 14 | import org.openqa.selenium.devtools.v127.browser.Browser; 15 | 16 | /** 17 | * 18 | * Selected test scenarios for Selenium 4 Chrome Developer Tools bridge 19 | * https://chromedevtools.github.io/devtools-protocol/tot/Browser/#method-getBrowserCommandLine 20 | * 21 | * @author: Serguei Kouzmine (kouzmine_serguei@yahoo.com) 22 | */ 23 | 24 | public class BrowserCommandLineDevToolsTest extends BaseDevToolsTest { 25 | 26 | private static List results; 27 | 28 | @Test 29 | public void test() { 30 | // Act 31 | results = chromeDevTools.send(Browser.getBrowserCommandLine()); 32 | // Assert 33 | assertThat(results, notNullValue()); 34 | assertThat(results.size(), greaterThan(0)); 35 | results.stream().forEach(o -> System.err.println(o)); 36 | 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /src/test/java/com/github/sergueik/selenium/BrowserHistogramCDPTest.java: -------------------------------------------------------------------------------- 1 | package com.github.sergueik.selenium; 2 | 3 | /** 4 | * Copyright 2023,2024 Serguei Kouzmine 5 | */ 6 | 7 | import static org.hamcrest.CoreMatchers.is; 8 | 9 | /** 10 | * Copyright 2022 Serguei Kouzmine 11 | */ 12 | 13 | import static org.hamcrest.CoreMatchers.notNullValue; 14 | import static org.hamcrest.MatcherAssert.assertThat; 15 | import static org.hamcrest.Matchers.greaterThan; 16 | 17 | import java.util.HashMap; 18 | import java.util.List; 19 | import java.util.Map; 20 | 21 | import org.junit.Test; 22 | 23 | /** 24 | * Selected test scenarios for Selenium 4 Chrome Developer Tools bridge 25 | * https://chromedevtools.github.io/devtools-protocol/tot/Browser/#method-getHistograms 26 | * https://chromedevtools.github.io/devtools-protocol/tot/Browser/#method-getHistogram 27 | * @author: Serguei Kouzmine (kouzmine_serguei@yahoo.com) 28 | */ 29 | 30 | public class BrowserHistogramCDPTest extends BaseCdpTest { 31 | 32 | private final static String url = "https://en.wikipedia.org/wiki/Main_Page"; 33 | 34 | private static String command = null; 35 | private static Map result = new HashMap<>(); 36 | private static Map params = new HashMap<>(); 37 | 38 | @Test 39 | public void test1() { 40 | // Arrange 41 | driver.get(url); 42 | // Act 43 | command = "Browser.getHistograms"; 44 | params = new HashMap<>(); 45 | params.put("query", ""); 46 | params.put("delta", false); 47 | result = driver.executeCdpCommand(command, params); 48 | // Assert 49 | assertThat(result, notNullValue()); 50 | assertThat(result instanceof Map, is(true)); 51 | assertThat(result.containsKey("histograms"), is(true)); 52 | // histograms 53 | assertThat(result.get("histograms") instanceof List, is(true)); 54 | assertThat(((List) result.get("histograms")).size(), 55 | greaterThan(1)); 56 | Object result2 = ((List) result.get("histograms")); 57 | assertThat(result2 instanceof List, is(true)); 58 | // System.err.println(result2); 59 | // ... 60 | // {buckets=[{count=9, high=2, low=1}], count=9, 61 | // name=API.StorageAccess.AllowedRequests2, sum=9} 62 | Object result3 = ((List) result2).get(0); 63 | assertThat(result3 instanceof Map, is(true)); 64 | assertThat(((Map) result3).containsKey("buckets"), is(true)); 65 | Object result4 = ((Map) result3).get("buckets"); 66 | // System.err.println(result4); 67 | assertThat(result4 instanceof List, is(true)); 68 | Object result5 = ((List) result4).get(0); 69 | assertThat(result5 instanceof Map, is(true)); 70 | assertThat(((Map) result3).containsKey("name"), is(true)); 71 | 72 | String name = (String) ((Map) result3).get("name"); 73 | 74 | // Act 75 | command = "Browser.getHistogram"; 76 | params = new HashMap<>(); 77 | params.put("name", name); 78 | params.put("delta", false); 79 | result = driver.executeCdpCommand(command, params); 80 | // Assert 81 | assertThat(result, notNullValue()); 82 | assertThat(result instanceof Map, is(true)); 83 | assertThat(((Map) result).containsKey("histogram"), is(true)); 84 | // System.err.println(result); 85 | // { 86 | // histogram={ 87 | // buckets=[ 88 | // { 89 | // count=12, 90 | // high=2, 91 | // low=1 92 | // }], 93 | // count=12, 94 | // name=API.StorageAccess.AllowedRequests2, 95 | // sum=12 96 | // } 97 | // } 98 | 99 | result2 = result.get("histogram"); 100 | assertThat(result2 instanceof Map, is(true)); 101 | assertThat(((Map) result2).containsKey("buckets"), is(true)); 102 | result3 = ((Map) result2).get("buckets"); 103 | // System.err.println(result3); 104 | assertThat(result3 instanceof List, is(true)); 105 | result4 = ((List) result3).get(0); 106 | assertThat(result4 instanceof Map, is(true)); 107 | assertThat(((Map) result2).containsKey("name"), is(true)); 108 | 109 | } 110 | 111 | } 112 | -------------------------------------------------------------------------------- /src/test/java/com/github/sergueik/selenium/BrowserVersionCdpTest.java: -------------------------------------------------------------------------------- 1 | package com.github.sergueik.selenium; 2 | 3 | /** 4 | * Copyright 2022,2024 Serguei Kouzmine 5 | */ 6 | 7 | import static org.hamcrest.CoreMatchers.notNullValue; 8 | import static org.hamcrest.MatcherAssert.assertThat; 9 | import static org.hamcrest.Matchers.hasKey; 10 | 11 | import java.util.ArrayList; 12 | import java.util.Arrays; 13 | import java.util.HashMap; 14 | import java.util.Map; 15 | 16 | import org.junit.Test; 17 | 18 | import org.openqa.selenium.WebDriverException; 19 | 20 | /** 21 | * Selected test scenarios for Selenium 4 Chrome Developer Tools bridge inspired 22 | * https://chromedevtools.github.io/devtools-protocol/tot/Browser/#method-getVersion 23 | * 24 | * @author: Serguei Kouzmine (kouzmine_serguei@yahoo.com) 25 | */ 26 | public class BrowserVersionCdpTest extends BaseCdpTest { 27 | 28 | private static String command = "Browser.getVersion"; 29 | private static Map result = new HashMap<>(); 30 | 31 | @Test 32 | public void test1() { 33 | 34 | try { 35 | // Act 36 | result = driver.executeCdpCommand(command, new HashMap<>()); 37 | System.err.println(command + " result: " + new ArrayList(result.keySet())); 38 | assertThat(result, notNullValue()); 39 | for (String field : Arrays.asList("jsVersion", "product", "protocolVersion", "revision", "userAgent")) { 40 | assertThat(result, hasKey(field)); 41 | System.err.print(field + ": " + result.get(field) + "\t"); 42 | } 43 | } catch (WebDriverException e) { 44 | System.err.println("Web Driver exception in " + command + " (ignored): " 45 | + Utils.processExceptionMessage(e.getMessage())); 46 | } catch (Exception e) { 47 | System.err.println("Exception in " + command + " " + e.toString()); 48 | throw (new RuntimeException(e)); 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/test/java/com/github/sergueik/selenium/BrowserVersionDevToolsTest.java: -------------------------------------------------------------------------------- 1 | package com.github.sergueik.selenium; 2 | 3 | /** 4 | * Copyright 2022,2024 Serguei Kouzmine 5 | */ 6 | 7 | import static org.hamcrest.CoreMatchers.notNullValue; 8 | import static org.hamcrest.MatcherAssert.assertThat; 9 | 10 | import org.junit.Ignore; 11 | import org.junit.Test; 12 | import org.openqa.selenium.WebDriverException; 13 | import org.openqa.selenium.devtools.Command; 14 | import org.openqa.selenium.devtools.ConverterFunctions; 15 | import org.openqa.selenium.devtools.v127.browser.Browser; 16 | import org.openqa.selenium.devtools.v127.browser.Browser.GetVersionResponse; 17 | import org.openqa.selenium.json.Json; 18 | import org.openqa.selenium.json.JsonInput; 19 | 20 | import com.google.common.collect.ImmutableMap; 21 | 22 | /** 23 | * Selected test scenarios for Selenium Chrome Developer Tools Selenium 4 bridge 24 | * see: https://chromedevtools.github.io/devtools-protocol/tot/Browser/#method-getVersion 25 | * 26 | * @author: Serguei Kouzmine (kouzmine_serguei@yahoo.com) 27 | */ 28 | 29 | public class BrowserVersionDevToolsTest extends BaseDevToolsTest { 30 | 31 | private GetVersionResponse response = null; 32 | 33 | @Test 34 | public void test1() { 35 | // Act 36 | GetVersionResponse response = chromeDevTools.send(Browser.getVersion()); 37 | assertThat(response, notNullValue()); 38 | response.getUserAgent(); 39 | System.err.println("Browser Version : " + response.getProduct() + "\t" 40 | + "Browser User Agent : " + response.getUserAgent() + "\t" 41 | + "Browser Protocol Version : " + response.getProtocolVersion() + "\t" 42 | + "Browser JS Version : " + response.getJsVersion()); 43 | } 44 | 45 | // based on: https://github.com/rookieInTraining/selenium-cdp-examples 46 | @Test 47 | public void test2() { 48 | // Act 49 | response = chromeDevTools 50 | .send(new Command("Browser.getVersion", 51 | ImmutableMap.of(), o -> o.read(GetVersionResponse.class))); 52 | 53 | assertThat(response, notNullValue()); 54 | System.err.println("Browser Version : " + response.getProduct() + "\t" 55 | + "Browser User Agent : " + response.getUserAgent() + "\t" 56 | + "Browser Protocol Version : " + response.getProtocolVersion() + "\t" 57 | + "Browser JS Version : " + response.getJsVersion()); 58 | } 59 | 60 | @Test 61 | public void test3() { 62 | // Act 63 | try { 64 | response = chromeDevTools.send(new Command( 65 | "Browser.getVersion", ImmutableMap.of(), o -> { 66 | System.err 67 | .println("in callback: " + new Json().toJson((JsonInput) o)); 68 | // difficult to parse, not attempted 69 | return ((GetVersionResponse) o.read(GetVersionResponse.class)); 70 | })); 71 | 72 | assertThat(response, notNullValue()); 73 | System.err.println("Browser Version : " + response.getProduct() + "\t" 74 | + "Browser User Agent : " + response.getUserAgent() + "\t" 75 | + "Browser Protocol Version : " + response.getProtocolVersion() + "\t" 76 | + "Browser JS Version : " + response.getJsVersion()); 77 | } catch (WebDriverException e) { 78 | System.err.println("Web Driver exception (ignored): " 79 | + Utils.processExceptionMessage(e.getMessage())); 80 | } catch (Exception e) { 81 | System.err.println("Exception: " + e.toString()); 82 | throw (new RuntimeException(e)); 83 | } 84 | } 85 | 86 | @Ignore 87 | @Test 88 | public void test4() { 89 | 90 | // Act 91 | response = chromeDevTools.send(new Command( 92 | "Browser.getVersion", ImmutableMap.of(), ConverterFunctions 93 | .map("getVersionResponse", GetVersionResponse.class))); 94 | assertThat(response, notNullValue()); 95 | assertThat(response.getProduct(), notNullValue()); 96 | assertThat(response.getRevision(), notNullValue()); 97 | assertThat(response.getProtocolVersion(), notNullValue()); 98 | assertThat(response.getUserAgent(), notNullValue()); 99 | assertThat(response.getJsVersion(), notNullValue()); 100 | 101 | } 102 | 103 | @Test 104 | public void test5() { 105 | // Act 106 | response = chromeDevTools.send(Browser.getVersion()); 107 | 108 | assertThat(response, notNullValue()); 109 | System.err.println("Browser Version : " + response.getProduct() + "\t" 110 | + "Browser User Agent : " + response.getUserAgent() + "\t" 111 | + "Browser Protocol Version : " + response.getProtocolVersion() + "\t" 112 | + "Browser JS Version : " + response.getJsVersion()); 113 | } 114 | 115 | } 116 | -------------------------------------------------------------------------------- /src/test/java/com/github/sergueik/selenium/BrowsingContextTraverseHistoryCdpTest.java: -------------------------------------------------------------------------------- 1 | package com.github.sergueik.selenium; 2 | 3 | /** 4 | * Copyright 2023,2024 Serguei Kouzmine 5 | */ 6 | 7 | import static org.hamcrest.CoreMatchers.notNullValue; 8 | import static org.hamcrest.MatcherAssert.assertThat; 9 | 10 | import java.io.UnsupportedEncodingException; 11 | import java.util.ArrayList; 12 | import java.util.Arrays; 13 | import java.util.Collections; 14 | import java.util.HashMap; 15 | import java.util.List; 16 | import java.util.Map; 17 | 18 | import org.junit.Before; 19 | import org.junit.Ignore; 20 | import org.junit.Test; 21 | import org.openqa.selenium.UnsupportedCommandException; 22 | 23 | import com.google.gson.Gson; 24 | 25 | /** 26 | * Selected test scenarios for Selenium 4 Chrome Developer Tools bridge inspired 27 | * 28 | * https://github.com/SeleniumHQ/selenium/commit/edbebe0f63c9a4facdc467a99dcc999fd77645dc 29 | * @author: Serguei Kouzmine (kouzmine_serguei@yahoo.com) 30 | */ 31 | public class BrowsingContextTraverseHistoryCdpTest extends BaseCdpTest { 32 | private static Gson gson = new Gson(); 33 | 34 | private static String command = null; 35 | private static Map result = new HashMap<>(); 36 | private static Map params = new HashMap<>(); 37 | private List urls = new ArrayList<>(); 38 | 39 | @Before 40 | public void beforeTest() throws UnsupportedEncodingException { 41 | 42 | command = "Page.resetNavigationHistory"; 43 | driver.executeCdpCommand(command, new HashMap()); 44 | urls.addAll(Arrays.asList(new String[] { "https://fr.wikipedia.org/wiki", 45 | "https://de.wikipedia.org/wiki", "https://es.wikipedia.org/wiki", 46 | "https://it.wikipedia.org/wiki", "https://ar.wikipedia.org/wiki", 47 | "https://en.wikipedia.org/wiki", "https://fi.wikipedia.org/wiki", 48 | "https://hu.wikipedia.org/wiki", "https://da.wikipedia.org/wiki", 49 | "https://pt.wikipedia.org/wiki" })); 50 | Collections.shuffle(urls); 51 | urls.forEach(url -> driver.get(url)); 52 | Utils.sleep(100); 53 | } 54 | 55 | @Test(expected = UnsupportedCommandException.class) 56 | public void test1() { 57 | command = "BrowsingContext.traverseHistory"; 58 | params.clear(); 59 | params.put("delta", 5); 60 | result = driver.executeCdpCommand(command, params); 61 | System.err.println( 62 | command + " result: " + new ArrayList(result.keySet())); 63 | assertThat(result, notNullValue()); 64 | } 65 | 66 | } 67 | -------------------------------------------------------------------------------- /src/test/java/com/github/sergueik/selenium/BypassCSPCdpTest.java: -------------------------------------------------------------------------------- 1 | package com.github.sergueik.selenium; 2 | 3 | /** 4 | * Copyright 2023,2024 Serguei Kouzmine 5 | */ 6 | 7 | import static org.hamcrest.CoreMatchers.is; 8 | import static org.hamcrest.CoreMatchers.notNullValue; 9 | import static org.hamcrest.MatcherAssert.assertThat; 10 | 11 | import java.util.HashMap; 12 | import java.util.Map; 13 | 14 | import org.junit.After; 15 | import org.junit.Test; 16 | import org.openqa.selenium.By; 17 | import org.openqa.selenium.WebElement; 18 | import org.openqa.selenium.interactions.Actions; 19 | import org.openqa.selenium.support.ui.ExpectedConditions; 20 | 21 | /** 22 | * Selected test scenarios for Selenium Chrome Developer Tools Selenium 4 bridge 23 | * see: 24 | * https://chromedevtools.github.io/devtools-protocol/tot/Page/#method-setBypassCSP 25 | */ 26 | 27 | public class BypassCSPCdpTest extends BaseCdpTest { 28 | private WebElement element; 29 | private static String command = null; 30 | private static Map params = new HashMap<>(); 31 | private static String page = null; 32 | private static int delay = 3000; 33 | 34 | @After 35 | public void afterTest() { 36 | command = "Page.setBypassCSP"; 37 | params.clear(); 38 | params.put("enabled", false); 39 | driver.get("about:blank"); 40 | } 41 | 42 | // @Ignore 43 | @Test 44 | public void test1() { 45 | page = "test1.html"; 46 | driver.get(Utils.getPageContent(page)); 47 | element = wait.until( 48 | ExpectedConditions.visibilityOfElementLocated(By.cssSelector("img"))); 49 | assertThat(element, notNullValue()); 50 | assertThat(element.isDisplayed(), is(true)); 51 | // to take screen shot uncommend pause 52 | // Utils.sleep(delay); 53 | assertThat(element.getRect().getWidth(), is(16)); 54 | // broken image size is different 55 | } 56 | 57 | // @Ignore 58 | @Test 59 | public void test2() { 60 | page = "test2.html"; 61 | driver.get(Utils.getPageContent(page)); 62 | element = wait.until( 63 | ExpectedConditions.visibilityOfElementLocated(By.cssSelector("img"))); 64 | assertThat(element, notNullValue()); 65 | assertThat(element.isDisplayed(), is(true)); 66 | assertThat(element.getRect().getWidth(), is(100)); 67 | } 68 | 69 | @Test 70 | public void test3() { 71 | command = "Page.setBypassCSP"; 72 | params.clear(); 73 | params.put("enabled", true); 74 | driver.executeCdpCommand(command, params); 75 | page = "test1.html"; 76 | driver.get(Utils.getPageContent(page)); 77 | element = wait.until( 78 | ExpectedConditions.visibilityOfElementLocated(By.cssSelector("img"))); 79 | assertThat(element, notNullValue()); 80 | assertThat(element.isDisplayed(), is(true)); 81 | // to take screen shot uncommend pause 82 | // Utils.sleep(delay); 83 | assertThat(element.getRect().getWidth(), is(100)); 84 | 85 | } 86 | 87 | } 88 | -------------------------------------------------------------------------------- /src/test/java/com/github/sergueik/selenium/BypassCSPDevToolsTest.java: -------------------------------------------------------------------------------- 1 | package com.github.sergueik.selenium; 2 | 3 | /** 4 | * Copyright 2023,2024 Serguei Kouzmine 5 | */ 6 | 7 | import static org.hamcrest.CoreMatchers.is; 8 | 9 | import static org.hamcrest.CoreMatchers.notNullValue; 10 | import static org.hamcrest.MatcherAssert.assertThat; 11 | 12 | import java.time.Duration; 13 | 14 | import org.junit.After; 15 | import org.junit.Before; 16 | import org.junit.Test; 17 | import org.openqa.selenium.By; 18 | import org.openqa.selenium.WebElement; 19 | import org.openqa.selenium.support.ui.ExpectedConditions; 20 | import org.openqa.selenium.support.ui.WebDriverWait; 21 | import org.openqa.selenium.devtools.v127.page.Page; 22 | 23 | /** 24 | * Selected test scenarios for Selenium Chrome Developer Tools Selenium 4 bridge 25 | * see: 26 | * https://chromedevtools.github.io/devtools-protocol/tot/Page/#method-setBypassCSP 27 | */ 28 | 29 | public class BypassCSPDevToolsTest extends BaseDevToolsTest { 30 | private WebElement element; 31 | private static String page = null; 32 | private static int delay = 3000; 33 | protected static WebDriverWait wait; 34 | public final static int flexibleWait = 10; // NOTE: 60 is quite long 35 | public final static Duration duration = Duration.ofSeconds(flexibleWait); 36 | public final static int implicitWait = 1; 37 | public final static int pollingInterval = 500; 38 | 39 | @Before 40 | public void before() throws Exception { 41 | chromeDevTools.send(Page.enable()); 42 | wait = new WebDriverWait(driver, duration); 43 | wait.pollingEvery(Duration.ofMillis(pollingInterval)); 44 | 45 | } 46 | 47 | @After 48 | public void afterTest() { 49 | chromeDevTools.send(Page.setBypassCSP(false)); 50 | chromeDevTools.clearListeners(); 51 | driver.get("about:blank"); 52 | } 53 | 54 | // @Ignore 55 | @Test 56 | public void test1() { 57 | page = "test1.html"; 58 | driver.get(Utils.getPageContent(page)); 59 | element = wait.until( 60 | ExpectedConditions.visibilityOfElementLocated(By.cssSelector("img"))); 61 | assertThat(element, notNullValue()); 62 | assertThat(element.isDisplayed(), is(true)); 63 | // to take screen shot uncommend pause 64 | // Utils.sleep(delay); 65 | assertThat(element.getRect().getWidth(), is(16)); 66 | // broken image size is different 67 | } 68 | 69 | // @Ignore 70 | @Test 71 | public void test2() { 72 | page = "test2.html"; 73 | driver.get(Utils.getPageContent(page)); 74 | element = wait.until( 75 | ExpectedConditions.visibilityOfElementLocated(By.cssSelector("img"))); 76 | assertThat(element, notNullValue()); 77 | assertThat(element.isDisplayed(), is(true)); 78 | assertThat(element.getRect().getWidth(), is(100)); 79 | } 80 | 81 | @Test 82 | public void test3() { 83 | chromeDevTools.send(Page.setBypassCSP(true)); 84 | page = "test1.html"; 85 | driver.get(Utils.getPageContent(page)); 86 | element = wait.until( 87 | ExpectedConditions.visibilityOfElementLocated(By.cssSelector("img"))); 88 | assertThat(element, notNullValue()); 89 | assertThat(element.isDisplayed(), is(true)); 90 | // to take screen shot uncommend pause 91 | // Utils.sleep(delay); 92 | assertThat(element.getRect().getWidth(), is(100)); 93 | } 94 | 95 | } 96 | -------------------------------------------------------------------------------- /src/test/java/com/github/sergueik/selenium/ComputedStyleDevToolsTest.java: -------------------------------------------------------------------------------- 1 | package com.github.sergueik.selenium; 2 | 3 | /** 4 | * Copyright 2023,2024 Serguei Kouzmine 5 | */ 6 | 7 | import static org.hamcrest.CoreMatchers.notNullValue; 8 | import static org.hamcrest.MatcherAssert.assertThat; 9 | import static org.hamcrest.Matchers.greaterThan; 10 | 11 | import java.util.ArrayList; 12 | import java.util.Arrays; 13 | import java.util.List; 14 | import java.util.Optional; 15 | 16 | import org.junit.After; 17 | import org.junit.Before; 18 | import org.junit.Test; 19 | import org.openqa.selenium.By; 20 | import org.openqa.selenium.WebElement; 21 | import org.openqa.selenium.devtools.DevToolsException; 22 | import org.openqa.selenium.devtools.v127.css.CSS; 23 | import org.openqa.selenium.devtools.v127.css.model.CSSComputedStyleProperty; 24 | import org.openqa.selenium.devtools.v127.dom.DOM; 25 | import org.openqa.selenium.devtools.v127.dom.DOM.EnableIncludeWhitespace; 26 | import org.openqa.selenium.devtools.v127.dom.model.Node; 27 | import org.openqa.selenium.devtools.v127.dom.model.NodeId; 28 | 29 | /** 30 | * Selected test scenarios for Selenium 4 Chrome Developer Tools bridge 31 | * https://chromedevtools.github.io/devtools-protocol/tot/DOM/#method-getDocument 32 | * https://chromedevtools.github.io/devtools-protocol/tot/DOM/#method-getOuterHTML 33 | * https://chromedevtools.github.io/devtools-protocol/tot/DOM/#method-getAttributes 34 | * https://chromedevtools.github.io/devtools-protocol/tot/DOM/#type-Node 35 | * https://chromedevtools.github.io/devtools-protocol/tot/DOM/#method-getContainerForNode 36 | * https://chromedevtools.github.io/devtools-protocol/tot/CSS/#method-setEffectivePropertyValueForNode 37 | * 38 | * @author: Serguei Kouzmine (kouzmine_serguei@yahoo.com) 39 | */ 40 | public class ComputedStyleDevToolsTest extends BaseDevToolsTest { 41 | 42 | private static String baseURL = "https://getbootstrap.com/docs/4.0/components/buttons/"; 43 | private final ArrayList classes = new ArrayList( 44 | Arrays.asList("btn-primary", "btn-secondary", "btn-success", "btn-danger", 45 | "btn-warning", "btn-info", "btn-light", "btn-dark", "btn-link")); 46 | 47 | private static String selector = null; 48 | private WebElement element; 49 | private static Node result; 50 | 51 | private static NodeId nodeId = null; 52 | private static NodeId rootNodeId = null; 53 | private static final String propertyName = "background-color"; 54 | private static final String value = "rgb(10,10,10)"; 55 | 56 | private static boolean debug = false; 57 | 58 | @After 59 | public void afterTest() { 60 | chromeDevTools.send(DOM.disable()); 61 | chromeDevTools.send(CSS.disable()); 62 | driver.get("about:blank"); 63 | } 64 | 65 | @Before 66 | public void beforeTest() { 67 | EnableIncludeWhitespace enableIncludeWhitespace = EnableIncludeWhitespace.ALL; 68 | driver.get(baseURL); 69 | chromeDevTools.send(DOM.enable(Optional.of(enableIncludeWhitespace))); 70 | chromeDevTools.send(CSS.enable()); 71 | } 72 | 73 | @Test 74 | public void test1() { 75 | driver.get(baseURL); 76 | for (String data : classes) { 77 | selector = String.format("div.bd-example button.%s", data); 78 | element = driver.findElement(By.cssSelector(selector)); 79 | assertThat(element, notNullValue()); 80 | String value = styleOfElement(element, propertyName); 81 | 82 | System.err.println(element.getText() + " computed style: " + propertyName 83 | + ": " + value); 84 | } 85 | try { 86 | result = chromeDevTools 87 | .send(DOM.getDocument(Optional.of(1), Optional.of(true))); 88 | rootNodeId = result.getNodeId(); 89 | for (String data : classes) { 90 | selector = String.format("div.bd-example button.%s", data); 91 | 92 | nodeId = chromeDevTools.send(DOM.querySelector(rootNodeId, selector)); 93 | 94 | List properties = chromeDevTools 95 | .send(CSS.getComputedStyleForNode(nodeId)); 96 | assertThat(properties.size(), greaterThan(2)); 97 | 98 | properties.stream().forEach((CSSComputedStyleProperty property) -> { 99 | if (debug) 100 | System.err 101 | .println(String.format("element: %s", property.getName())); 102 | if (property.getName().contains(propertyName)) { 103 | 104 | System.err.println( 105 | String.format("computed style: %s", property.getValue())); 106 | 107 | } 108 | }); 109 | chromeDevTools.send( 110 | CSS.setEffectivePropertyValueForNode(nodeId, propertyName, value)); 111 | Utils.sleep(1000); 112 | System.err 113 | .println(chromeDevTools.send(DOM.getOuterHTML(Optional.of(nodeId), 114 | Optional.empty(), Optional.empty()))); 115 | } 116 | } catch (DevToolsException e) { 117 | System.err.println("Exception (rethrown) " + e.getMessage()); 118 | throw e; 119 | } 120 | } 121 | 122 | protected String styleOfElement(WebElement element, Object... arguments) { 123 | return (String) Utils.executeScript(Utils.getScriptContent("getStyle.js"), 124 | element, arguments); 125 | } 126 | 127 | } 128 | -------------------------------------------------------------------------------- /src/test/java/com/github/sergueik/selenium/ConsoleMessagesDevToolsTest.java: -------------------------------------------------------------------------------- 1 | package com.github.sergueik.selenium; 2 | 3 | /** 4 | * Copyright 2023,2024 Serguei Kouzmine 5 | */ 6 | 7 | 8 | import java.time.Duration; 9 | 10 | /** 11 | * Copyright 2024 Serguei Kouzmine 12 | */ 13 | 14 | import org.junit.After; 15 | import org.junit.Before; 16 | import org.junit.Test; 17 | import org.openqa.selenium.By; 18 | import org.openqa.selenium.WebElement; 19 | import org.openqa.selenium.devtools.v127.console.Console; 20 | import org.openqa.selenium.devtools.v127.console.model.ConsoleMessage; 21 | import org.openqa.selenium.support.ui.ExpectedConditions; 22 | import org.openqa.selenium.support.ui.WebDriverWait; 23 | 24 | /** 25 | * Selected test scenarios for Selenium Chrome Developer Tools Selenium 4 bridge 26 | * NOTE: the Console domain is deprecated - using Runtime or Log instead is advised 27 | * https://chromedevtools.github.io/devtools-protocol/tot/Console/#method-disable 28 | * https://chromedevtools.github.io/devtools-protocol/tot/Console/#method-enable 29 | * https://chromedevtools.github.io/devtools-protocol/tot/Console/#event-messageAdded 30 | * https://chromedevtools.github.io/devtools-protocol/tot/Console/#type-ConsoleMessage 31 | * 32 | * @author: Serguei Kouzmine (kouzmine_serguei@yahoo.com) 33 | */ 34 | 35 | @SuppressWarnings("deprecation") 36 | public class ConsoleMessagesDevToolsTest extends BaseDevToolsTest { 37 | 38 | private final static String baseURL = "https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html"; 39 | private WebElement element; 40 | protected static WebDriverWait wait; 41 | public final static int flexibleWait = 10; 42 | public final static Duration duration = Duration.ofSeconds(flexibleWait); 43 | public final static int implicitWait = 1; 44 | public final static int pollingInterval = 50; 45 | 46 | @Before 47 | public void beforeTest() throws Exception { 48 | wait = new WebDriverWait(driver, duration); 49 | wait.pollingEvery(Duration.ofMillis(pollingInterval)); 50 | 51 | chromeDevTools.send(Console.enable()); 52 | chromeDevTools.addListener(Console.messageAdded(), 53 | (ConsoleMessage message) -> System.err.println(String.format( 54 | "level: %s" + "\n" + "source: %s" + "\n" + "line number: %s" + "\n" 55 | + "column number: %s" + "\n" + "url: \"%s\" text: %s", 56 | message.getLevel(), message.getSource(), 57 | (message.getLine().isPresent() ? message.getLine().get() : ""), 58 | (message.getColumn().isPresent() ? message.getColumn().get() : ""), 59 | (message.getUrl().isPresent() ? message.getUrl().get() : ""), 60 | message.getText()))); 61 | driver.get(baseURL); 62 | } 63 | 64 | // see also: 65 | // https://github.com/SaraMohamed2022/Selenium4_CDPPracticing/blob/main/src/test/java/selenium4_SelfPracticing/GetJavaScriptLogs.java 66 | @Test 67 | public void test1() { 68 | element = wait.until( 69 | ExpectedConditions.visibilityOfElementLocated(By.id("consoleLog"))); 70 | element.click(); 71 | Utils.highlight(element); 72 | } 73 | 74 | // NOTE: nothing will be logged 75 | @Test 76 | public void test2() { 77 | element = wait.until(ExpectedConditions 78 | .visibilityOfElementLocated(By.id("logWithStacktrace"))); 79 | element.click(); 80 | Utils.highlight(element); 81 | } 82 | 83 | @After 84 | public void afterTest() throws Exception { 85 | chromeDevTools.clearListeners(); 86 | chromeDevTools.send(Console.disable()); 87 | } 88 | 89 | } 90 | -------------------------------------------------------------------------------- /src/test/java/com/github/sergueik/selenium/CustomHeadersCdpTest.java: -------------------------------------------------------------------------------- 1 | package com.github.sergueik.selenium; 2 | 3 | /** 4 | * Copyright 2023,2024 Serguei Kouzmine 5 | */ 6 | 7 | import static org.hamcrest.CoreMatchers.containsString; 8 | import static org.hamcrest.MatcherAssert.assertThat; 9 | 10 | import java.io.UnsupportedEncodingException; 11 | import java.util.Date; 12 | import java.util.HashMap; 13 | import java.util.Map; 14 | import java.util.Random; 15 | 16 | import org.junit.After; 17 | import org.junit.Before; 18 | import org.junit.Test; 19 | import org.openqa.selenium.By; 20 | import org.openqa.selenium.WebElement; 21 | import org.openqa.selenium.support.ui.ExpectedConditions; 22 | 23 | /** 24 | * Selected test scenarios for Selenium 4 Chrome Developer Tools bridge 25 | * https://chromedevtools.github.io/devtools-protocol/tot/Network/#method-setExtraHTTPHeaders 26 | * https://chromedevtools.github.io/devtools-protocol/tot/Network#method-enable 27 | * see also: https://github.com/SeleniumHQ/selenium/issues/12162 28 | * https://stackoverflow.com/questions/71668952/how-to-set-user-agent-client-hint-sec-ch-ua-in-selenium-python 29 | * @author: Serguei Kouzmine (kouzmine_serguei@yahoo.com) 30 | */ 31 | 32 | public class CustomHeadersCdpTest extends BaseCdpTest { 33 | 34 | private static String baseURL = "https://manytools.org/http-html-text/http-request-headers/"; 35 | private static String text = null; 36 | private static Map headers = new HashMap<>(); 37 | private static String command = null; 38 | private static Map params = new HashMap<>(); 39 | 40 | @After 41 | public void afterTest() { 42 | command = "Network.disable"; 43 | driver.executeCdpCommand(command, new HashMap<>()); 44 | driver.get("about:blank"); 45 | } 46 | 47 | @Before 48 | public void beforeTest() throws UnsupportedEncodingException { 49 | command = "Network.enable"; 50 | driver.executeCdpCommand(command, new HashMap<>()); 51 | } 52 | 53 | @Test 54 | public void test1() { 55 | headers = new HashMap<>(); 56 | params = new HashMap<>(); 57 | 58 | headers.put("Sec-Ch-Ua", 59 | "\"Not_A Brand\";v=\"42\", \"Google Chrome\";v=\"109\", \"Chromium\";v=\"109\""); 60 | headers.put("Sec-Ch-Ua-Arch", "x86"); 61 | headers.put("Sec-Ch-Ua-Platform", "Windows"); 62 | String[] headerNames = new String[headers.keySet().size()]; 63 | headers.keySet().toArray(headerNames); 64 | String customHeaderName = headerNames[new Random((new Date()).getTime()) 65 | .nextInt(headers.keySet().size())]; 66 | 67 | params.put("headers", headers); 68 | 69 | command = "Network.setExtraHTTPHeaders"; 70 | driver.executeCdpCommand(command, params); 71 | 72 | driver.get(baseURL); 73 | WebElement element = wait.until(ExpectedConditions.visibilityOf(driver 74 | .findElement(By.cssSelector("#maincontent > div.middlecol > table")))); 75 | text = element.getText(); 76 | assertThat(text, containsString(customHeaderName)); 77 | // System.err.println(text); 78 | System.err.println("Verified: " + customHeaderName); 79 | 80 | } 81 | 82 | } 83 | -------------------------------------------------------------------------------- /src/test/java/com/github/sergueik/selenium/CustomHeadersDevToolsTest.java: -------------------------------------------------------------------------------- 1 | package com.github.sergueik.selenium; 2 | 3 | /** 4 | * Copyright 2022-2024 Serguei Kouzmine 5 | */ 6 | 7 | import static org.hamcrest.CoreMatchers.containsString; 8 | import static org.hamcrest.MatcherAssert.assertThat; 9 | 10 | import java.io.UnsupportedEncodingException; 11 | import java.time.Duration; 12 | import java.util.Date; 13 | import java.util.HashMap; 14 | import java.util.Map; 15 | import java.util.Optional; 16 | import java.util.Random; 17 | 18 | import org.junit.After; 19 | import org.junit.Before; 20 | import org.junit.Test; 21 | import org.openqa.selenium.By; 22 | import org.openqa.selenium.WebElement; 23 | import org.openqa.selenium.devtools.v127.network.Network; 24 | import org.openqa.selenium.devtools.v127.network.model.Headers; 25 | import org.openqa.selenium.support.ui.ExpectedConditions; 26 | import org.openqa.selenium.support.ui.WebDriverWait; 27 | 28 | /** 29 | * Selected test scenarios for Selenium 4 Chrome Developer Tools bridge 30 | * https://chromedevtools.github.io/devtools-protocol/tot/Network/#method-setExtraHTTPHeaders 31 | * https://chromedevtools.github.io/devtools-protocol/tot/Network#method-enable 32 | * see also: https://github.com/SeleniumHQ/selenium/issues/12162 33 | * https://stackoverflow.com/questions/71668952/how-to-set-user-agent-client-hint-sec-ch-ua-in-selenium-python 34 | * @author: Serguei Kouzmine (kouzmine_serguei@yahoo.com) 35 | */ 36 | 37 | public class CustomHeadersDevToolsTest extends BaseDevToolsTest { 38 | 39 | private static String baseURL = "https://manytools.org/http-html-text/http-request-headers/"; 40 | private static Map headers = new HashMap<>(); 41 | private static String text = null; 42 | private static WebDriverWait wait; 43 | private static int flexibleWait = 60; 44 | private static int pollingInterval = 500; 45 | 46 | @After 47 | public void after() { 48 | chromeDevTools.clearListeners(); 49 | chromeDevTools.send(Network.disable()); 50 | } 51 | 52 | @Before 53 | public void before() throws UnsupportedEncodingException { 54 | wait = new WebDriverWait(driver, Duration.ofSeconds(flexibleWait)); 55 | wait.pollingEvery(Duration.ofMillis(pollingInterval)); 56 | chromeDevTools.send(Network.enable(Optional.of(100000000), Optional.empty(), 57 | Optional.empty())); 58 | 59 | // add event listener to log custom headers requests are sending with 60 | chromeDevTools.addListener(Network.requestWillBeSent(), o -> { 61 | headers.keySet().stream() 62 | .forEach(h -> System.err.println( 63 | String.format("request will be sent with extra header %s=%s", h, 64 | o.getRequest().getHeaders().get(h)))); 65 | 66 | }); 67 | } 68 | 69 | @Test 70 | public void test1() { 71 | 72 | headers = new HashMap<>(); 73 | headers.put("Sec-Ch-Ua", 74 | "\"Not_A Brand\";v=\"42\", \"Google Chrome\";v=\"109\", \"Chromium\";v=\"109\""); 75 | headers.put("Sec-Ch-Ua-Arch", "x86"); 76 | headers.put("Sec-Ch-Ua-Platform", "Windows"); 77 | String[] headerNames = new String[headers.keySet().size()]; 78 | headers.keySet().toArray(headerNames); 79 | String customHeaderName = headerNames[new Random((new Date()).getTime()) 80 | .nextInt(headers.keySet().size())]; 81 | chromeDevTools.send(Network.setExtraHTTPHeaders(new Headers(headers))); 82 | 83 | driver.get(baseURL); 84 | WebElement element = wait.until(ExpectedConditions.visibilityOf(driver 85 | .findElement(By.cssSelector("#maincontent > div.middlecol > table")))); 86 | text = element.getText(); 87 | assertThat(text, containsString(customHeaderName)); 88 | System.err.println("Verified: " + customHeaderName); 89 | 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /src/test/java/com/github/sergueik/selenium/DOMElementFocusCDPTest.java: -------------------------------------------------------------------------------- 1 | package com.github.sergueik.selenium; 2 | /** 3 | * Copyright 2023,2024 Serguei Kouzmine 4 | */ 5 | 6 | import static org.hamcrest.CoreMatchers.is; 7 | import static org.hamcrest.CoreMatchers.notNullValue; 8 | import static org.hamcrest.MatcherAssert.assertThat; 9 | import static org.hamcrest.Matchers.hasKey; 10 | import static org.hamcrest.core.IsNot.not; 11 | 12 | import java.util.HashMap; 13 | import java.util.List; 14 | import java.util.Map; 15 | 16 | import org.junit.After; 17 | import org.junit.Before; 18 | import org.junit.Test; 19 | import org.openqa.selenium.WebDriverException; 20 | 21 | /** 22 | * Selected test scenarios for Selenium Chrome Developer Tools Selenium 4 bridge 23 | * https://chromedevtools.github.io/devtools-protocol/tot/Overlay/#method-enable 24 | * https://chromedevtools.github.io/devtools-protocol/tot/Overlay/#method-disable 25 | * https://chromedevtools.github.io/devtools-protocol/tot/DOM/#method-enable 26 | * https://chromedevtools.github.io/devtools-protocol/tot/DOM/#method-disable 27 | * https://chromedevtools.github.io/devtools-protocol/tot/DOM/#method-focus 28 | * @author: Serguei Kouzmine (kouzmine_serguei@yahoo.com) 29 | */ 30 | 31 | public class DOMElementFocusCDPTest extends BaseDevToolsTest { 32 | private static String url = "https://formy-project.herokuapp.com/form"; 33 | private static final String selector = "input"; 34 | 35 | private static String command = null; 36 | private static Map result = new HashMap<>(); 37 | private static Map params = new HashMap<>(); 38 | private static Map data = new HashMap<>(); 39 | private static String dataString = null; 40 | public static Long nodeId = -1l; 41 | public static String isolationId = null; 42 | 43 | @Before 44 | public void before() { 45 | command = "DOM.enable"; 46 | params.clear(); 47 | params.put("includeWhitespace", "all"); 48 | driver.executeCdpCommand(command, params); 49 | command = "Overlay.enable"; 50 | driver.executeCdpCommand(command, new HashMap<>()); 51 | driver.get(url); 52 | } 53 | 54 | @After 55 | public void after() { 56 | command = "Overlay.disable"; 57 | driver.executeCdpCommand(command, new HashMap<>()); 58 | command = "DOM.disable"; 59 | driver.executeCdpCommand(command, new HashMap<>()); 60 | } 61 | 62 | @SuppressWarnings("unchecked") 63 | @Test 64 | public void test() { 65 | 66 | String command = "DOM.getDocument"; 67 | params = new HashMap<>(); 68 | params.put("pierce", false); 69 | params.put("depth", 0); 70 | try { 71 | // Act 72 | result = driver.executeCdpCommand(command, params); 73 | nodeId = Long.parseLong( 74 | ((Map) result.get("root")).get("nodeId").toString()); 75 | command = "DOM.querySelectorAll"; 76 | params.clear(); 77 | params.put("nodeId", nodeId); 78 | params.put("selector", selector); 79 | 80 | result = driver.executeCdpCommand(command, params); 81 | assertThat(result, hasKey("nodeIds")); 82 | List results = (List) result.get("nodeIds"); 83 | results.stream().forEach((Long nodeId) -> { 84 | assertThat(nodeId, is(not(0))); 85 | System.err.println("nodeId: " + nodeId); 86 | 87 | params.clear(); 88 | params.put("nodeId", nodeId); 89 | driver.executeCdpCommand("DOM.focus", params); 90 | result = driver.executeCdpCommand("DOM.getOuterHTML", params); 91 | assertThat(result, notNullValue()); 92 | assertThat(result, hasKey("outerHTML")); 93 | dataString = (String) result.get("outerHTML"); 94 | assertThat(dataString, notNullValue()); 95 | System.err.println("Highlighted outerHTML: " + dataString); 96 | 97 | Utils.sleep(500); 98 | driver.executeCdpCommand("DOM.hideHighlight", new HashMap<>()); 99 | }); 100 | } catch (WebDriverException e) { 101 | System.err.println("Web Driver exception in " + command + " (ignored): " 102 | + Utils.processExceptionMessage(e.getMessage())); 103 | } catch (UnsupportedOperationException e) { 104 | System.err.println("UnsupportedOperation exception in " + command 105 | + " (ignored): " + e.getMessage()); 106 | } catch (Exception e) { 107 | System.err.println("Exception in " + command + " " + e.toString()); 108 | throw (new RuntimeException(e)); 109 | } 110 | } 111 | 112 | } 113 | -------------------------------------------------------------------------------- /src/test/java/com/github/sergueik/selenium/DOMElementFocusDevToolsTest.java: -------------------------------------------------------------------------------- 1 | package com.github.sergueik.selenium; 2 | /** 3 | * Copyright 2023,2024 Serguei Kouzmine 4 | */ 5 | 6 | import java.util.List; 7 | import java.util.Optional; 8 | 9 | import org.junit.After; 10 | import org.junit.Before; 11 | import org.junit.Test; 12 | import org.openqa.selenium.devtools.v127.dom.DOM; 13 | import org.openqa.selenium.devtools.v127.dom.model.Node; 14 | import org.openqa.selenium.devtools.v127.dom.model.NodeId; 15 | import org.openqa.selenium.devtools.v127.dom.model.RGBA; 16 | import org.openqa.selenium.devtools.v127.overlay.Overlay; 17 | import org.openqa.selenium.devtools.v127.overlay.model.HighlightConfig; 18 | 19 | /** 20 | * Selected test scenarios for Selenium Chrome Developer Tools Selenium 4 bridge 21 | * https://chromedevtools.github.io/devtools-protocol/tot/Overlay/#method-enable 22 | * https://chromedevtools.github.io/devtools-protocol/tot/Overlay/#method-disable 23 | * https://chromedevtools.github.io/devtools-protocol/tot/DOM/#method-enable 24 | * https://chromedevtools.github.io/devtools-protocol/tot/DOM/#method-disable 25 | * https://chromedevtools.github.io/devtools-protocol/tot/DOM/#method-focus 26 | * @author: Serguei Kouzmine (kouzmine_serguei@yahoo.com) 27 | */ 28 | 29 | // see also: 30 | // https://github.com/rkeeves/selenium-tricks/blob/main/src/test/java/io/github/rkeeves/interoperability/CDPHighlightByNodeIdTest.java 31 | public class DOMElementFocusDevToolsTest extends BaseDevToolsTest { 32 | private static String url = "https://formy-project.herokuapp.com/form"; 33 | private static final String selector = "input"; 34 | 35 | @Before 36 | public void before() { 37 | chromeDevTools 38 | .send(DOM.enable(Optional.of(DOM.EnableIncludeWhitespace.ALL))); 39 | chromeDevTools.send(Overlay.enable()); 40 | driver.get(url); 41 | } 42 | 43 | @After 44 | public void after() { 45 | chromeDevTools.send(Overlay.disable()); 46 | chromeDevTools.send(DOM.disable()); 47 | } 48 | 49 | @Test 50 | public void test() { 51 | Node result = chromeDevTools 52 | .send(DOM.getDocument(Optional.of(1), Optional.of(true))); 53 | 54 | List results = chromeDevTools 55 | .send(DOM.querySelectorAll(result.getNodeId(), selector)); 56 | results.forEach((NodeId nodeId) -> { 57 | chromeDevTools.send( 58 | DOM.focus(Optional.of(nodeId), Optional.empty(), Optional.empty())); 59 | Utils.sleep(500); 60 | }); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/test/java/com/github/sergueik/selenium/DOMElementScrollCDPTest.java: -------------------------------------------------------------------------------- 1 | package com.github.sergueik.selenium; 2 | /** 3 | * Copyright 2024 Serguei Kouzmine 4 | */ 5 | 6 | import static org.hamcrest.CoreMatchers.is; 7 | import static org.hamcrest.CoreMatchers.notNullValue; 8 | import static org.hamcrest.MatcherAssert.assertThat; 9 | import static org.hamcrest.Matchers.hasKey; 10 | import static org.hamcrest.core.IsNot.not; 11 | 12 | import java.util.HashMap; 13 | import java.util.List; 14 | import java.util.Map; 15 | 16 | import org.junit.After; 17 | import org.junit.Before; 18 | import org.junit.Test; 19 | import org.openqa.selenium.WebDriverException; 20 | 21 | /** 22 | * Selected test scenarios for Selenium Chrome Developer Tools Selenium 4 bridge 23 | * https://chromedevtools.github.io/devtools-protocol/tot/DOM/#method-enable 24 | * https://chromedevtools.github.io/devtools-protocol/tot/DOM/#method-disable 25 | * https://chromedevtools.github.io/devtools-protocol/tot/DOM/#method-scrollIntoViewIfNeeded 26 | * https://chromedevtools.github.io/devtools-protocol/tot/DOM/#method-getContentQuads 27 | * https://chromedevtools.github.io/devtools-protocol/tot/DOM/#method-performSearch 28 | * @author: Serguei Kouzmine (kouzmine_serguei@yahoo.com) 29 | */ 30 | 31 | public class DOMElementScrollCDPTest extends BaseDevToolsTest { 32 | private static String url = "https://formy-project.herokuapp.com/form"; 33 | private static final String selector = "input"; 34 | 35 | private static String command = null; 36 | private static Map result = new HashMap<>(); 37 | private static Map params = new HashMap<>(); 38 | private static Map data = new HashMap<>(); 39 | private static String dataString = null; 40 | public static Long nodeId = -1l; 41 | public static String isolationId = null; 42 | 43 | @Before 44 | public void before() { 45 | command = "DOM.enable"; 46 | params.clear(); 47 | params.put("includeWhitespace", "all"); 48 | driver.executeCdpCommand(command, params); 49 | driver.get(url); 50 | } 51 | 52 | @After 53 | public void after() { 54 | command = "DOM.disable"; 55 | driver.executeCdpCommand(command, new HashMap<>()); 56 | } 57 | 58 | @SuppressWarnings("unchecked") 59 | @Test 60 | public void test() { 61 | 62 | String command = "DOM.getDocument"; 63 | params = new HashMap<>(); 64 | params.put("pierce", false); 65 | params.put("depth", 0); 66 | try { 67 | // Act 68 | result = driver.executeCdpCommand(command, params); 69 | nodeId = Long.parseLong( 70 | ((Map) result.get("root")).get("nodeId").toString()); 71 | command = "DOM.querySelectorAll"; 72 | params.clear(); 73 | params.put("nodeId", nodeId); 74 | params.put("selector", selector); 75 | 76 | result = driver.executeCdpCommand(command, params); 77 | assertThat(result, hasKey("nodeIds")); 78 | List results = (List) result.get("nodeIds"); 79 | results.stream().forEach((Long nodeId) -> { 80 | assertThat(nodeId, is(not(0))); 81 | System.err.println("nodeId: " + nodeId); 82 | 83 | params.clear(); 84 | params.put("nodeId", nodeId); 85 | driver.executeCdpCommand("DOM.scrollIntoViewIfNeeded", params); 86 | result = driver.executeCdpCommand("DOM.scrollIntoViewIfNeeded", params); 87 | assertThat(result, notNullValue()); 88 | System.err.println("Element scroll result: " + result); 89 | 90 | Utils.sleep(500); 91 | }); 92 | } catch (WebDriverException e) { 93 | System.err.println("Web Driver exception in " + command + " (ignored): " 94 | + Utils.processExceptionMessage(e.getMessage())); 95 | } catch (UnsupportedOperationException e) { 96 | System.err.println("UnsupportedOperation exception in " + command 97 | + " (ignored): " + e.getMessage()); 98 | } catch (Exception e) { 99 | System.err.println("Exception in " + command + " " + e.toString()); 100 | throw (new RuntimeException(e)); 101 | } 102 | } 103 | 104 | } 105 | -------------------------------------------------------------------------------- /src/test/java/com/github/sergueik/selenium/DOMElementScrollDevToolsTest.java: -------------------------------------------------------------------------------- 1 | package com.github.sergueik.selenium; 2 | /** 3 | * Copyright 2024 Serguei Kouzmine 4 | */ 5 | 6 | import java.util.List; 7 | import java.util.Optional; 8 | 9 | import org.junit.After; 10 | import org.junit.Before; 11 | import org.junit.Test; 12 | import org.openqa.selenium.devtools.v127.dom.DOM; 13 | import org.openqa.selenium.devtools.v127.dom.model.Node; 14 | import org.openqa.selenium.devtools.v127.dom.model.NodeId; 15 | 16 | /** 17 | * Selected test scenarios for Selenium Chrome Developer Tools Selenium 4 bridge 18 | * https://chromedevtools.github.io/devtools-protocol/tot/DOM/#method-enable 19 | * https://chromedevtools.github.io/devtools-protocol/tot/DOM/#method-disable 20 | * https://chromedevtools.github.io/devtools-protocol/tot/DOM/#method-focus 21 | * https://chromedevtools.github.io/devtools-protocol/tot/DOM/#method-scrollIntoViewIfNeeded 22 | * https://chromedevtools.github.io/devtools-protocol/tot/DOM/#method-getContentQuads 23 | * https://chromedevtools.github.io/devtools-protocol/tot/DOM/#method-performSearch 24 | * @author: Serguei Kouzmine (kouzmine_serguei@yahoo.com) 25 | */ 26 | 27 | // see also: 28 | // https://github.com/rkeeves/selenium-tricks/blob/main/src/test/java/io/github/rkeeves/interoperability/CDPHighlightByNodeIdTest.java 29 | public class DOMElementScrollDevToolsTest extends BaseDevToolsTest { 30 | private static String url = "https://formy-project.herokuapp.com/form"; 31 | private static final String selector = "input"; 32 | 33 | @Before 34 | public void before() { 35 | chromeDevTools 36 | .send(DOM.enable(Optional.of(DOM.EnableIncludeWhitespace.ALL))); 37 | driver.get(url); 38 | } 39 | 40 | @After 41 | public void after() { 42 | chromeDevTools.send(DOM.disable()); 43 | } 44 | 45 | @Test 46 | public void test() { 47 | Node result = chromeDevTools 48 | .send(DOM.getDocument(Optional.of(1), Optional.of(true))); 49 | 50 | List results = chromeDevTools 51 | .send(DOM.querySelectorAll(result.getNodeId(), selector)); 52 | results.forEach((NodeId nodeId) -> { 53 | // @formatter:off 54 | chromeDevTools.send(DOM.scrollIntoViewIfNeeded( 55 | Optional.of(nodeId), // 56 | Optional.empty(), // backendNodeId 57 | Optional.empty(), // objectId 58 | Optional.empty() //rect 59 | )); 60 | // @formatter:on 61 | Utils.sleep(500); 62 | }); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/test/java/com/github/sergueik/selenium/DOMNodeAttributesDevToolsTest.java: -------------------------------------------------------------------------------- 1 | package com.github.sergueik.selenium; 2 | 3 | /** 4 | * Copyright 2023,2024 Serguei Kouzmine 5 | */ 6 | 7 | 8 | import static org.hamcrest.MatcherAssert.assertThat; 9 | import static org.hamcrest.Matchers.greaterThan; 10 | import static org.hamcrest.Matchers.hasKey; 11 | 12 | import java.util.ArrayList; 13 | import java.util.HashMap; 14 | import java.util.List; 15 | import java.util.Map; 16 | import java.util.Optional; 17 | 18 | import org.junit.After; 19 | import org.junit.Before; 20 | import org.junit.Test; 21 | import org.openqa.selenium.devtools.DevToolsException; 22 | import org.openqa.selenium.devtools.v127.dom.DOM; 23 | import org.openqa.selenium.devtools.v127.dom.DOM.EnableIncludeWhitespace; 24 | import org.openqa.selenium.devtools.v127.dom.model.Node; 25 | import org.openqa.selenium.devtools.v127.dom.model.NodeId; 26 | 27 | /** 28 | * Selected test scenarios for Selenium 4 Chrome Developer Tools bridge 29 | * https://chromedevtools.github.io/devtools-protocol/tot/DOM/#method-getDocument 30 | * https://chromedevtools.github.io/devtools-protocol/tot/DOM/#method-getOuterHTML 31 | * https://chromedevtools.github.io/devtools-protocol/tot/DOM/#method-getAttributes 32 | * https://chromedevtools.github.io/devtools-protocol/tot/DOM/#type-Node 33 | * https://chromedevtools.github.io/devtools-protocol/tot/DOM/#method-getContainerForNode 34 | * @author: Serguei Kouzmine (kouzmine_serguei@yahoo.com) 35 | */ 36 | 37 | public class DOMNodeAttributesDevToolsTest extends BaseDevToolsTest { 38 | 39 | private static String baseURL = "https://www.wikipedia.org"; 40 | private final String selector = "div.central-featured-lang[lang='ru']"; 41 | 42 | private static Node result; 43 | private static Map results = new HashMap<>(); 44 | private static NodeId nodeId = null; 45 | private static List attributes = new ArrayList<>(); 46 | 47 | @After 48 | public void afterTest() { 49 | chromeDevTools.send(DOM.disable()); 50 | driver.get("about:blank"); 51 | } 52 | 53 | @Before 54 | public void beforeTest() { 55 | EnableIncludeWhitespace enableIncludeWhitespace = EnableIncludeWhitespace.ALL; 56 | driver.get(baseURL); 57 | chromeDevTools.send(DOM.enable(Optional.of(enableIncludeWhitespace))); 58 | } 59 | 60 | @Test 61 | public void test1() { 62 | try { 63 | result = chromeDevTools 64 | .send(DOM.getDocument(Optional.of(1), Optional.of(true))); 65 | 66 | nodeId = chromeDevTools 67 | .send(DOM.querySelector(result.getNodeId(), selector)); 68 | 69 | attributes = chromeDevTools.send(DOM.getAttributes(nodeId)); 70 | assertThat(attributes.size(), greaterThan(2)); 71 | results = listToMap(attributes); 72 | assertThat(results, hasKey("lang")); 73 | String lang = (String) results.get("lang"); 74 | System.err.println(String.format("lang: %s", lang)); 75 | 76 | System.err.println(String.format("Id: %s", nodeId.toString())); 77 | System.err 78 | .println(chromeDevTools.send(DOM.getOuterHTML(Optional.of(nodeId), 79 | Optional.empty(), Optional.empty()))); 80 | } catch (DevToolsException e) { 81 | System.err.println("Exception (rethrown) " + e.getMessage()); 82 | throw e; 83 | } 84 | } 85 | 86 | // origin: 87 | // http://www.java2s.com/example/java/java.util/convert-array-to-map.html 88 | // 89 | @SuppressWarnings({ "unchecked", "rawtypes" }) 90 | public static Map listToMap(List objects) { 91 | HashMap map = new HashMap(); 92 | Object key = null; 93 | for (final String object : objects) { 94 | // System.err.println("processing " + object.toString()); 95 | if (key == null) { 96 | key = object; 97 | } else { 98 | map.put(key, object); 99 | key = null; 100 | } 101 | } 102 | return map; 103 | } 104 | 105 | } 106 | -------------------------------------------------------------------------------- /src/test/java/com/github/sergueik/selenium/DOMPerformSearchDevToolsTest.java: -------------------------------------------------------------------------------- 1 | package com.github.sergueik.selenium; 2 | 3 | /** 4 | * Copyright 2023,2024 Serguei Kouzmine 5 | */ 6 | 7 | 8 | import java.util.List; 9 | import java.util.Optional; 10 | 11 | import org.junit.After; 12 | import org.junit.Before; 13 | import org.junit.Test; 14 | import org.openqa.selenium.devtools.DevToolsException; 15 | import org.openqa.selenium.devtools.v127.dom.DOM; 16 | import org.openqa.selenium.devtools.v127.dom.DOM.EnableIncludeWhitespace; 17 | import org.openqa.selenium.devtools.v127.dom.DOM.PerformSearchResponse; 18 | import org.openqa.selenium.devtools.v127.dom.model.Node; 19 | import org.openqa.selenium.devtools.v127.dom.model.NodeId; 20 | 21 | /** 22 | * Selected test scenarios for Selenium 4 Chrome Developer Tools bridge 23 | * https://chromedevtools.github.io/devtools-protocol/tot/DOM/#method-getDocument 24 | * https://chromedevtools.github.io/devtools-protocol/tot/DOM/#method-querySelectorAll 25 | * https://chromedevtools.github.io/devtools-protocol/tot/DOM/#method-performSearch 26 | * https://chromedevtools.github.io/devtools-protocol/tot/DOM/#type-Node 27 | * https://chromedevtools.github.io/devtools-protocol/1-3/DOM/#event-setChildNodes 28 | * @author: Serguei Kouzmine (kouzmine_serguei@yahoo.com) 29 | */ 30 | 31 | public class DOMPerformSearchDevToolsTest extends BaseDevToolsTest { 32 | 33 | private static String baseURL = "https://www.wikipedia.org"; 34 | private final String selector = "a.other-project-link"; 35 | 36 | @After 37 | public void afterTest() { 38 | chromeDevTools.send(DOM.disable()); 39 | driver.get("about:blank"); 40 | } 41 | 42 | @Before 43 | public void beforeTest() { 44 | EnableIncludeWhitespace enableIncludeWhitespace = EnableIncludeWhitespace.ALL; 45 | driver.get(baseURL); 46 | chromeDevTools.send(DOM.enable(Optional.of(enableIncludeWhitespace))); 47 | } 48 | 49 | @Test 50 | public void test1() { 51 | try { 52 | Node result = chromeDevTools 53 | .send(DOM.getDocument(Optional.of(1), Optional.of(true))); 54 | 55 | List results = chromeDevTools.send( 56 | DOM.querySelectorAll(result.getNodeId(), "a.other-project-link")); 57 | System.err.println(String.format("Found %d Node Ids:", results.size())); 58 | results.forEach(nodeId -> System.err 59 | .println(String.format("Id: %s\nHTML: %s", nodeId.toString(), 60 | chromeDevTools.send(DOM.getOuterHTML(Optional.of(nodeId), 61 | Optional.empty(), Optional.empty()))))); 62 | } catch (DevToolsException e) { 63 | System.err.println("Exception (rethrown) " + e.getMessage()); 64 | throw e; 65 | } 66 | } 67 | 68 | // NOTE: "DOM.getSearchResults" is returning array of zero NodeIds 69 | @Test 70 | public void test2() { 71 | try { 72 | PerformSearchResponse searchResponse = chromeDevTools 73 | .send(DOM.performSearch(selector, Optional.of(true))); 74 | Utils.sleep(1000); // no effect 75 | System.err.println( 76 | String.format("returned %d nodes", searchResponse.getResultCount())); 77 | List results = chromeDevTools.send(DOM.getSearchResults( 78 | searchResponse.getSearchId(), 0, searchResponse.getResultCount())); 79 | System.err.println(String.format("Node Ids: %s", results.toString())); 80 | } catch (DevToolsException e) { 81 | System.err.println("Exception (rethrown) " + e.getMessage()); 82 | throw e; 83 | } 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /src/test/java/com/github/sergueik/selenium/DOMSnapshotDevToolsTest.java: -------------------------------------------------------------------------------- 1 | package com.github.sergueik.selenium; 2 | 3 | /** 4 | * Copyright 2022,2024 Serguei Kouzmine 5 | */ 6 | 7 | 8 | import java.util.ArrayList; 9 | import java.util.List; 10 | import java.util.Optional; 11 | 12 | import org.junit.After; 13 | import org.junit.Before; 14 | import org.junit.Test; 15 | import org.openqa.selenium.devtools.DevToolsException; 16 | import org.openqa.selenium.devtools.v127.domsnapshot.DOMSnapshot; 17 | import org.openqa.selenium.devtools.v127.domsnapshot.model.DocumentSnapshot; 18 | import org.openqa.selenium.devtools.v127.domsnapshot.model.StringIndex; 19 | 20 | /** 21 | * Selected test scenarios for Selenium 4 Chrome Developer Tools bridge 22 | * https://chromedevtools.github.io/devtools-protocol/tot/DOMSnapshot/#method-disable 23 | * https://chromedevtools.github.io/devtools-protocol/tot/DOMSnapshot/#method-enable 24 | * https://chromedevtools.github.io/devtools-protocol/tot/DOMSnapshot/#method-captureSnapshot 25 | * https://chromedevtools.github.io/devtools-protocol/tot/DOMSnapshot/#type-DocumentSnapshot 26 | * https://chromedevtools.github.io/devtools-protocol/tot/DOMSnapshot/#type-NodeTreeSnapshot 27 | * https://chromedevtools.github.io/devtools-protocol/tot/DOMSnapshot/#type-LayoutTreeSnapshot 28 | * see also: 29 | * https://stackoverflow.com/questions/58099695/is-there-a-way-in-hamcrest-to-test-for-a-value-to-be-a-number 30 | * 31 | * @author: Serguei Kouzmine (kouzmine_serguei@yahoo.com) 32 | */ 33 | // https://www.logicalincrements.com/articles/resolution 34 | 35 | public class DOMSnapshotDevToolsTest extends BaseDevToolsTest { 36 | 37 | private final static String baseURL = "http://www.java2s.com"; // "https://www.wikipedia.org"; 38 | 39 | @After 40 | public void afterTest() { 41 | chromeDevTools.send(DOMSnapshot.disable()); 42 | driver.get("about:blank"); 43 | } 44 | 45 | @Before 46 | public void beforeTest() { 47 | chromeDevTools.send(DOMSnapshot.enable()); 48 | driver.get(baseURL); 49 | } 50 | 51 | // @Ignore("Unable to create instance of class 52 | // org.openqa.selenium.devtools.v127.domsnapshot.DOMSnapshot$CaptureSnapshotResponse") 53 | // NOTE: pom.xml 54 | // org.openqa.selenium.devtools.DevToolsException: Unable to create instance 55 | // of 56 | // class 57 | // org.openqa.selenium.devtools.v127.domsnapshot.DOMSnapshot$CaptureSnapshotResponse 58 | // Exception in thread "CDP Connection" 59 | // org.openqa.selenium.devtools.DevToolsException: 60 | // Expected to read a NAME but instead have: START_COLLECTION. Last 128 61 | // characters read: 62 | // 0,1341,1342,1343,1344,1345,1346,1347,1348,1349,1350,1351,1352,1353,1354,1355,1356,1357, 63 | // 1358,94,1359,1360,1361], 64 | // "attributes":[[], 65 | 66 | // NOTE: on Ubuntu 18.04 the version 106 is not yet available. 67 | // This illustrates the error this leads to: 68 | // You are using a no-op implementation of the CDP. The most likely reason for 69 | // this is that Selenium was unable to find an implementation of the CDP 70 | // protocol that matches your browser. Please be sure to include an 71 | // implementation on the classpath, possibly by adding a new (maven) 72 | // dependency 73 | // of `org.seleniumhq.selenium:selenium-devtools-vNN:4.5.0` where `NN` matches 74 | // the major version of the browser you're using.(..) 75 | 76 | @Test(expected = DevToolsException.class) 77 | public void test() { 78 | try { 79 | DOMSnapshot.CaptureSnapshotResponse results = chromeDevTools 80 | .send(DOMSnapshot.captureSnapshot(new ArrayList(), 81 | Optional.of(false), Optional.of(false), Optional.of(false), 82 | Optional.of(false))); 83 | List documentSnapshots = results.getDocuments(); 84 | DocumentSnapshot documentSnapshot = documentSnapshots.get(0); 85 | StringIndex index = documentSnapshot.getTitle(); 86 | List strings = results.getStrings(); 87 | String title = strings.get((int) Long.parseLong(index.toString())); 88 | System.err.println("Page Title index: " + index + " value: " + title); 89 | } catch (DevToolsException e) { 90 | 91 | // the full exception is too long 92 | System.err.println("Exception (rethrown) " + e.getMessage()); 93 | throw e; 94 | } 95 | } 96 | 97 | } 98 | -------------------------------------------------------------------------------- /src/test/java/com/github/sergueik/selenium/DescribeNodeDevToolsTest.java: -------------------------------------------------------------------------------- 1 | package com.github.sergueik.selenium; 2 | 3 | /** 4 | * Copyright 2023,2024 Serguei Kouzmine 5 | */ 6 | 7 | 8 | import static org.hamcrest.CoreMatchers.notNullValue; 9 | import static org.hamcrest.MatcherAssert.assertThat; 10 | import static org.hamcrest.Matchers.greaterThan; 11 | import static org.hamcrest.Matchers.hasKey; 12 | 13 | import java.util.ArrayList; 14 | import java.util.HashMap; 15 | import java.util.List; 16 | import java.util.Map; 17 | import java.util.Optional; 18 | 19 | import org.junit.After; 20 | import org.junit.Before; 21 | import org.junit.Test; 22 | import org.openqa.selenium.devtools.DevToolsException; 23 | import org.openqa.selenium.devtools.v127.dom.DOM; 24 | import org.openqa.selenium.devtools.v127.dom.DOM.EnableIncludeWhitespace; 25 | import org.openqa.selenium.devtools.v127.dom.model.Node; 26 | import org.openqa.selenium.devtools.v127.dom.model.NodeId; 27 | 28 | import com.google.gson.Gson; 29 | 30 | /** 31 | * Selected test scenarios for Selenium 4 Chrome Developer Tools bridge 32 | * https://chromedevtools.github.io/devtools-protocol/tot/DOM/#method-getDocument 33 | * https://chromedevtools.github.io/devtools-protocol/tot/DOM/#method-querySelectorAll 34 | * https://chromedevtools.github.io/devtools-protocol/tot/DOM/#type-Node 35 | * https://chromedevtools.github.io/devtools-protocol/tot/DOM/#method-describeNode 36 | * @author: Serguei Kouzmine (kouzmine_serguei@yahoo.com) 37 | */ 38 | public class DescribeNodeDevToolsTest extends BaseDevToolsTest { 39 | 40 | private static String baseURL = "https://www.wikipedia.org"; 41 | private final String selector = "div.central-featured-lang[lang='ru']"; 42 | 43 | private static Node result; 44 | private static Map results = new HashMap<>(); 45 | private NodeId nodeId = null; 46 | private static List nodeIds = new ArrayList<>(); 47 | 48 | private static List attributes = new ArrayList<>(); 49 | 50 | @After 51 | public void afterTest() { 52 | chromeDevTools.send(DOM.disable()); 53 | driver.get("about:blank"); 54 | } 55 | 56 | @Before 57 | public void beforeTest() { 58 | driver.get(baseURL); 59 | chromeDevTools.send(DOM.enable(Optional.of(EnableIncludeWhitespace.ALL))); 60 | } 61 | 62 | @Test 63 | public void test1() { 64 | try { 65 | result = chromeDevTools 66 | .send(DOM.getDocument(Optional.of(-1), Optional.of(true))); 67 | nodeId = result.getNodeId(); 68 | result = chromeDevTools 69 | .send(DOM.describeNode(Optional.of(nodeId), Optional.empty(), 70 | Optional.empty(), Optional.of(-1), Optional.of(true))); 71 | assertThat(result.getDocumentURL(), notNullValue()); 72 | System.err 73 | .println("document node: " + new Gson().toJson(result, Node.class)); 74 | 75 | nodeIds = chromeDevTools.send(DOM.querySelectorAll(nodeId, selector)); 76 | for (NodeId nodeId : nodeIds) { 77 | attributes = chromeDevTools.send(DOM.getAttributes(nodeId)); 78 | assertThat(attributes.size(), greaterThan(2)); 79 | results = listToMap(attributes); 80 | assertThat(results, hasKey("lang")); 81 | String lang = (String) results.get("lang"); 82 | System.err.println(String.format("lang: %s", lang)); 83 | 84 | System.err.println(String.format("Id: %s", nodeId.toString())); 85 | System.err.println(chromeDevTools.send(DOM.getOuterHTML(Optional.of(nodeId), 86 | Optional.empty(), Optional.empty()))); 87 | 88 | result = chromeDevTools 89 | .send(DOM.describeNode(Optional.of(nodeId), Optional.empty(), 90 | Optional.empty(), Optional.of(1), Optional.of(false))); 91 | 92 | System.err.println( 93 | "nodeId: " + nodeId + ": " + new Gson().toJson(result, Node.class)); 94 | 95 | } 96 | } catch (DevToolsException e) { 97 | System.err.println("Exception (rethrown) " + e.getMessage()); 98 | throw e; 99 | } 100 | } 101 | 102 | // origin: 103 | // http://www.java2s.com/example/java/java.util/convert-array-to-map.html 104 | // 105 | @SuppressWarnings({ "unchecked", "rawtypes" }) 106 | public static Map listToMap(List objects) { 107 | HashMap map = new HashMap(); 108 | Object key = null; 109 | for (final String object : objects) { 110 | // System.err.println("processing " + object.toString()); 111 | if (key == null) { 112 | key = object; 113 | } else { 114 | map.put(key, object); 115 | key = null; 116 | } 117 | } 118 | return map; 119 | } 120 | 121 | } 122 | -------------------------------------------------------------------------------- /src/test/java/com/github/sergueik/selenium/DeviceMetricsOverrideCdpTest.java: -------------------------------------------------------------------------------- 1 | package com.github.sergueik.selenium; 2 | 3 | /* Copyright 2023,2024 Serguei Kouzmine */ 4 | 5 | import static org.hamcrest.CoreMatchers.containsString; 6 | import static org.hamcrest.CoreMatchers.notNullValue; 7 | import static org.hamcrest.MatcherAssert.assertThat; 8 | 9 | import java.util.HashMap; 10 | import java.util.Map; 11 | 12 | import org.junit.After; 13 | import org.junit.Before; 14 | import org.junit.Test; 15 | import org.openqa.selenium.By; 16 | import org.openqa.selenium.WebElement; 17 | import org.openqa.selenium.interactions.Actions; 18 | 19 | /** 20 | * Selected test scenarios for Selenium 4 Chrome Developer Tools bridge 21 | * https://chromedevtools.github.io/devtools-protocol/tot/Page/#method-getLayoutMetrics 22 | * https://chromedevtools.github.io/devtools-protocol/tot/Emulation/#method-setDeviceMetricsOverride 23 | * https://chromedevtools.github.io/devtools-protocol/tot/Emulation/#method-clearDeviceMetricsOverride 24 | * 25 | */ 26 | 27 | public class DeviceMetricsOverrideCdpTest extends BaseCdpTest { 28 | 29 | private static int delay = 300; 30 | 31 | private static String command = null; 32 | private static Map result = new HashMap<>(); 33 | private static Map params = new HashMap<>(); 34 | 35 | public static Long nodeId = (long) -1; 36 | 37 | private static String baseURL = "https://www.whatismybrowser.com/detect/what-http-headers-is-my-browser-sending"; 38 | private Actions actions; 39 | private WebElement element; 40 | 41 | private static Map widths = new HashMap<>(); 42 | static { 43 | widths.put(600, 480); 44 | widths.put(480, 384); 45 | widths.put(250, 200); 46 | } 47 | private static Integer height = 640; 48 | 49 | @Before 50 | public void beforeTest() throws Exception { 51 | driver.get("about:blank"); 52 | } 53 | 54 | @After 55 | public void clearDeviceMetricsOverride() { 56 | command = "Emulation.clearDeviceMetricsOverride"; 57 | driver.executeCdpCommand(command, new HashMap()); 58 | // Assert 59 | } 60 | 61 | @SuppressWarnings("unchecked") 62 | @Test 63 | public void test() { 64 | // Assert 65 | params = new HashMap<>(); 66 | 67 | for (Integer device_width : widths.keySet()) { 68 | Integer viewport_width = widths.get(device_width); 69 | command = "Emulation.setDeviceMetricsOverride"; 70 | // Arrange 71 | params.clear(); 72 | params.put("deviceScaleFactor", 0); 73 | params.put("width", device_width); 74 | params.put("height", height); 75 | params.put("mobile", true); 76 | System.err.println(String.format("Set device metrics to %02d %02d", 77 | viewport_width, height)); 78 | params.put("scale", 1); 79 | driver.executeCdpCommand(command, params); 80 | // Act 81 | driver.get(baseURL); 82 | command = "Page.getLayoutMetrics"; 83 | result = driver.executeCdpCommand(command, new HashMap<>()); 84 | System.err.println("Page.getLayoutMetrics: " + result.get("contentSize")); 85 | Map rect = (Map) result.get("contentSize"); 86 | element = driver.findElement(By.xpath( 87 | "//*[@id=\"content-base\"]//table//th[contains(text(),\"VIEWPORT-WIDTH\")]/../td")); 88 | assertThat(element, notNullValue()); 89 | assertThat(element.getText(), 90 | containsString(String.format("%d", viewport_width))); 91 | actions = new Actions(driver); 92 | actions.moveToElement(element).build().perform(); 93 | 94 | Utils.highlight(element); 95 | Utils.sleep(delay); 96 | } 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /src/test/java/com/github/sergueik/selenium/DeviceMetricsOverrideDevToolsTest.java: -------------------------------------------------------------------------------- 1 | package com.github.sergueik.selenium; 2 | 3 | /* Copyright 2023,2024 Serguei Kouzmine */ 4 | 5 | import static org.hamcrest.CoreMatchers.containsString; 6 | import static org.hamcrest.CoreMatchers.notNullValue; 7 | import static org.hamcrest.MatcherAssert.assertThat; 8 | 9 | import java.util.HashMap; 10 | import java.util.Map; 11 | import java.util.Optional; 12 | 13 | import org.junit.After; 14 | import org.junit.Before; 15 | import org.junit.Test; 16 | import org.openqa.selenium.By; 17 | import org.openqa.selenium.WebElement; 18 | import org.openqa.selenium.devtools.v127.dom.model.Rect; 19 | import org.openqa.selenium.devtools.v127.emulation.Emulation; 20 | import org.openqa.selenium.devtools.v127.page.Page; 21 | import org.openqa.selenium.interactions.Actions; 22 | 23 | /** 24 | * Selected test scenarios for Selenium Chrome Developer Tools Selenium 4 bridge 25 | * see also: 26 | * https://chromedevtools.github.io/devtools-protocol/tot/Page/#method-getLayoutMetrics 27 | * https://chromedevtools.github.io/devtools-protocol/tot/Emulation/#method-setDeviceMetricsOverride 28 | * https://chromedevtools.github.io/devtools-protocol/tot/Page#method-captureScreenshot 29 | * https://chromedevtools.github.io/devtools-protocol/tot/Emulation/#method-clearDeviceMetricsOverride 30 | * 31 | * @author: Serguei Kouzmine (kouzmine_serguei@yahoo.com) 32 | */ 33 | 34 | public class DeviceMetricsOverrideDevToolsTest extends BaseDevToolsTest { 35 | private static Page.GetLayoutMetricsResponse result; 36 | private static Rect rect; 37 | private static int delay = 300; 38 | 39 | private static String baseURL = "https://www.whatismybrowser.com/detect/what-http-headers-is-my-browser-sending"; 40 | private Actions actions; 41 | private WebElement element; 42 | 43 | private static Map widths = new HashMap<>(); 44 | static { 45 | widths.put(600, 480); 46 | widths.put(480, 384); 47 | widths.put(250, 200); 48 | } 49 | private static Integer height = 640; 50 | 51 | @Before 52 | public void before() throws Exception { 53 | } 54 | 55 | @After 56 | public void clearPage() { 57 | chromeDevTools.send(Emulation.clearDeviceMetricsOverride()); 58 | } 59 | 60 | @Test 61 | public void test1() { 62 | for (Integer device_width : widths.keySet()) { 63 | Integer viewport_width = widths.get(device_width); 64 | 65 | chromeDevTools.send( 66 | // @formatter:off 67 | Emulation.setDeviceMetricsOverride( 68 | device_width, 69 | height, 70 | 0, // deviceScaleFactor 71 | true, // mobile 72 | Optional.empty(), // scale 73 | Optional.empty(), // screenWidth 74 | Optional.empty(), // screenHeight 75 | Optional.empty(), // positionX 76 | Optional.empty(), // positionY 77 | Optional.empty(), // dontSetVisibleSize 78 | Optional.empty(), // screenOrientation 79 | Optional.empty(), // viewport 80 | Optional.empty(), // displayFeature 81 | Optional.empty() // devicePosture 82 | ) 83 | // @formatter:on 84 | ); 85 | driver.get(baseURL); 86 | result = chromeDevTools.send(Page.getLayoutMetrics()); 87 | rect = result.getContentSize(); 88 | System.err.println("Page.getLayoutMetrics: " + rect); 89 | 90 | element = driver.findElement(By.xpath( 91 | "//*[@id=\"content-base\"]//table//th[contains(text(),\"VIEWPORT-WIDTH\")]/../td")); 92 | assertThat(element, notNullValue()); 93 | assertThat(element.getText(), 94 | containsString(String.format("%d", viewport_width))); 95 | actions = new Actions(driver); 96 | actions.moveToElement(element).build().perform(); 97 | 98 | Utils.highlight(element); 99 | Utils.sleep(delay); 100 | 101 | } 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /src/test/java/com/github/sergueik/selenium/DisplayFeatureCdpTest.java: -------------------------------------------------------------------------------- 1 | package com.github.sergueik.selenium; 2 | 3 | /** 4 | * Copyright 2023,2024 Serguei Kouzmine 5 | */ 6 | 7 | 8 | import java.io.UnsupportedEncodingException; 9 | import java.util.Arrays; 10 | import java.util.HashMap; 11 | import java.util.Map; 12 | 13 | import org.junit.Test; 14 | import org.openqa.selenium.UnsupportedCommandException; 15 | 16 | /** 17 | * Selected test scenarios for Selenium 4 Chrome Developer Tools bridge 18 | * https://chromedevtools.github.io/devtools-protocol/tot/Emulation/#type-DisplayFeature 19 | * https://chromedevtools.github.io/devtools-protocol/tot/Emulation/#type-ScreenOrientation 20 | * NOTE: both are unsupported 21 | * @author: Serguei Kouzmine (kouzmine_serguei@yahoo.com) 22 | */ 23 | public class DisplayFeatureCdpTest extends BaseCdpTest { 24 | private static String baseURL = "https://www.wikipedia.org"; 25 | private static String command = null; 26 | private static Map params = new HashMap<>(); 27 | 28 | @Test(expected = UnsupportedCommandException.class) 29 | public void test1() throws UnsupportedEncodingException { 30 | // Arrange 31 | params = new HashMap<>(); 32 | params.put("orientation", Arrays.asList("horizontal")); 33 | command = "Emulation.DisplayFeature"; 34 | driver.executeCdpCommand(command, params); 35 | // Act 36 | driver.get(baseURL); 37 | } 38 | 39 | @Test(expected = UnsupportedCommandException.class) 40 | public void test2() throws UnsupportedEncodingException { 41 | // Arrange 42 | params = new HashMap<>(); 43 | params.put("orientation", Arrays.asList("landscapePrimary")); 44 | command = "Emulation.ScreenOrientation"; 45 | driver.executeCdpCommand(command, params); 46 | // Act 47 | driver.get(baseURL); 48 | } 49 | 50 | } 51 | -------------------------------------------------------------------------------- /src/test/java/com/github/sergueik/selenium/DomainJavascriptDevToolsTest.java: -------------------------------------------------------------------------------- 1 | package com.github.sergueik.selenium; 2 | /** 3 | * Copyright 2023,2024 Serguei Kouzmine 4 | */ 5 | 6 | import org.junit.Before; 7 | import org.junit.Test; 8 | import org.openqa.selenium.JavascriptException; 9 | 10 | /** 11 | * Selected test scenarios for Selenium Chrome Developer Tools Selenium 4 bridge 12 | * @author: Serguei Kouzmine (kouzmine_serguei@yahoo.com) 13 | */ 14 | 15 | // based on: 16 | // https://github.com/Shivshive/Selenium_CDP/blob/master/src/test/java/example/selenium_cdp/MainPageTest.java 17 | // Domains 18 | // see also: 19 | // https://github.com/SeleniumHQ/selenium/issues/11573 20 | // https://www.lambdatest.com/automation-testing-advisor/selenium/methods/org.openqa.selenium.devtools.idealized.Javascript.addJsBinding 21 | public class DomainJavascriptDevToolsTest extends BaseDevToolsTest { 22 | private static String url = "https://www.wikipedia.org"; 23 | 24 | @Before 25 | public void before() { 26 | driver.get(url); 27 | String script = "function showAlert(msg){ alert(msg); }"; 28 | String alias = "example"; 29 | chromeDevTools.getDomains().javascript().pin(alias, script); 30 | } 31 | 32 | @Test(expected = JavascriptException.class) 33 | public void test() { 34 | String msg = "test"; 35 | Utils.executeScript("showAlert(arguments[0])", msg); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/test/java/com/github/sergueik/selenium/EventSubscriptionCommonTest.java: -------------------------------------------------------------------------------- 1 | package com.github.sergueik.selenium; 2 | 3 | /** 4 | * Copyright 2022,2024 Serguei Kouzmine 5 | */ 6 | 7 | 8 | import static org.hamcrest.CoreMatchers.notNullValue; 9 | import static org.hamcrest.MatcherAssert.assertThat; 10 | 11 | import java.nio.file.Paths; 12 | import java.time.Duration; 13 | import java.util.List; 14 | 15 | import org.junit.After; 16 | import org.junit.AfterClass; 17 | import org.junit.Before; 18 | import org.junit.BeforeClass; 19 | import org.openqa.selenium.Alert; 20 | import org.openqa.selenium.By; 21 | import org.openqa.selenium.JavascriptExecutor; 22 | import org.openqa.selenium.WebDriver; 23 | import org.openqa.selenium.WebElement; 24 | import org.openqa.selenium.chrome.ChromeDriver; 25 | import org.openqa.selenium.chrome.ChromeOptions; 26 | import org.openqa.selenium.chromium.ChromiumDriver; 27 | import org.openqa.selenium.devtools.DevTools; 28 | import org.openqa.selenium.devtools.HasDevTools; 29 | import org.openqa.selenium.support.ui.ExpectedConditions; 30 | import org.openqa.selenium.support.ui.WebDriverWait; 31 | 32 | /** 33 | * Selected test scenarios for Selenium Chrome Developer Tools Selenium 4 bridge 34 | * https://chromedevtools.github.io/devtools-protocol/1-3/Runtime/#method-evaluate 35 | * 36 | * @author: Serguei Kouzmine (kouzmine_serguei@yahoo.com) 37 | */ 38 | 39 | public class EventSubscriptionCommonTest extends BaseDevToolsTest { 40 | 41 | protected static WebDriverWait wait; 42 | public final static int flexibleWait = 10; // NOTE: 60 is quite long 43 | public final static Duration duration = Duration.ofSeconds(flexibleWait); 44 | public final static int implicitWait = 1; 45 | public final static int pollingInterval = 500; 46 | protected Alert alert = null; 47 | protected static String name = null; 48 | protected static WebElement element; 49 | protected static List elements; 50 | protected static boolean debug = true; 51 | 52 | // NOTE: fragile w.r. org.openqa.selenium.NoAlertPresentException and slowly 53 | // loading 54 | @Before 55 | public void before() { 56 | wait = new WebDriverWait(driver, duration); 57 | wait.pollingEvery(Duration.ofMillis(pollingInterval)); 58 | } 59 | 60 | @After 61 | public void after() { 62 | driver.switchTo().defaultContent(); 63 | chromeDevTools.clearListeners(); 64 | driver.get("about:blank"); 65 | } 66 | 67 | @AfterClass 68 | public static void tearDown() { 69 | if (driver != null) { 70 | driver.quit(); 71 | } 72 | } 73 | 74 | protected static WebElement findButton() { 75 | 76 | elements = driver.findElements(By.tagName("iframe")); 77 | if (debug) { 78 | // System.err.println("page: " + driver.getPageSource()); 79 | } 80 | for (WebElement element : elements) { 81 | // TODO: org.openqa.selenium.StaleElementReferenceException 82 | // probably not navigating across frames 83 | if (!element.getAttribute("style").matches(".*display: none;.*")) { 84 | name = element.getAttribute("name"); 85 | if (debug) 86 | System.err 87 | .println(String.format("Selenium found visible iframe : %s\n%s\n", 88 | name, element.getAttribute("outerHTML"))); 89 | } 90 | } 91 | assertThat(name, notNullValue()); 92 | WebElement frame = wait.until(ExpectedConditions.visibilityOfElementLocated( 93 | By.cssSelector(String.format("iframe[name='%s']", name)))); 94 | assertThat(frame, notNullValue()); 95 | 96 | // Act 97 | WebDriver iframe = driver.switchTo().frame(frame); 98 | 99 | Utils.sleep(1000); 100 | WebElement element = iframe.findElement(By.tagName("button")); 101 | assertThat(element, notNullValue()); 102 | if (debug) 103 | System.err.println(String.format("Selenium found button: %s\n", 104 | element.getAttribute("outerHTML"))); 105 | Utils.highlight(element, 1000); 106 | return element; 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /src/test/java/com/github/sergueik/selenium/FetcFailRequestDevToolsTest.java: -------------------------------------------------------------------------------- 1 | package com.github.sergueik.selenium; 2 | /** 3 | * Copyright 2023,2024 Serguei Kouzmine 4 | */ 5 | 6 | import static org.hamcrest.CoreMatchers.is; 7 | import static org.hamcrest.MatcherAssert.assertThat; 8 | 9 | import java.time.Duration; 10 | import java.util.ArrayList; 11 | import java.util.List; 12 | import java.util.Optional; 13 | // import java.util.concurrent.TimeoutException; 14 | 15 | import org.junit.After; 16 | import org.junit.Before; 17 | import org.junit.Test; 18 | import org.openqa.selenium.By; 19 | import org.openqa.selenium.TimeoutException; 20 | import org.openqa.selenium.WebElement; 21 | import org.openqa.selenium.devtools.v127.fetch.Fetch; 22 | import org.openqa.selenium.devtools.v127.fetch.model.RequestId; 23 | import org.openqa.selenium.devtools.v127.fetch.model.RequestPattern; 24 | import org.openqa.selenium.devtools.v127.fetch.model.RequestPaused; 25 | import org.openqa.selenium.devtools.v127.network.Network; 26 | import org.openqa.selenium.devtools.v127.network.model.ErrorReason; 27 | import org.openqa.selenium.devtools.v127.network.model.Request; 28 | import org.openqa.selenium.support.ui.WebDriverWait; 29 | 30 | /** 31 | * Selected test scenarios for Selenium Chrome Developer Tools Selenium 4 bridge 32 | * https://chromedevtools.github.io/devtools-protocol/tot/Fetch/ 33 | * https://chromedevtools.github.io/devtools-protocol/tot/Fetch/#method-failRequest 34 | * https://chromedevtools.github.io/devtools-protocol/tot/Fetch/#method-fulfillRequest 35 | * https://chromedevtools.github.io/devtools-protocol/tot/Fetch/#method-continueRequest 36 | * https://chromedevtools.github.io/devtools-protocol/tot/Network/#type-Request 37 | * @author: Serguei Kouzmine (kouzmine_serguei@yahoo.com) 38 | */ 39 | // see also: 40 | // https://github.com/Sushmada/Selenium_CDP/blob/master/src/ChromeDevToolsSeleniumIntegration/FailNetworkRequest.java 41 | public class FetcFailRequestDevToolsTest extends BaseDevToolsTest { 42 | private static String url = "https://www.wikipedia.org"; 43 | private static WebDriverWait wait; 44 | private static int flexibleWait = 10; 45 | private static int pollingInterval = 500; 46 | private static WebElement element = null; 47 | 48 | @Before 49 | public void before() throws TimeoutException { 50 | String urlPattern = "*assets*"; 51 | 52 | RequestPattern requestPattern = new RequestPattern(Optional.of(urlPattern), 53 | Optional.empty(), Optional.empty()); 54 | List arg = new ArrayList<>(); 55 | arg.add(requestPattern); 56 | chromeDevTools.send(Fetch.enable(Optional.of(arg) /* Optional.empty()*/, 57 | Optional.of(false))); 58 | chromeDevTools.send(Network.clearBrowserCache()); 59 | chromeDevTools.send(Network.setCacheDisabled(true)); 60 | 61 | chromeDevTools.addListener(Fetch.requestPaused(), (RequestPaused event) -> { 62 | Request request = event.getRequest(); 63 | RequestId requestId = event.getRequestId(); 64 | System.err.println("About to handle the request: " + request.getUrl()); 65 | if (request.getUrl().matches(".*\\.(?:png|jpg|jpeg)$")) { 66 | System.err.println("About to abort the request to " + request.getUrl()); 67 | ErrorReason errorReason = ErrorReason.FAILED; 68 | Fetch.failRequest(requestId, errorReason); 69 | } else { 70 | // NOTE: setting HTTP response code by hand 71 | Fetch.continueRequest(requestId, Optional.of(request.getUrl()), 72 | Optional.of(request.getMethod()), request.getPostData(), 73 | /* Optional.of(request.getHeaders()) */ Optional.empty(), 74 | Optional.of(false)); 75 | } 76 | }); 77 | 78 | } 79 | 80 | @Test 81 | public void test2() { 82 | try { 83 | driver.navigate().to(url); 84 | } catch (TimeoutException e) { 85 | System.err.println("continue"); 86 | } 87 | wait = new WebDriverWait(driver, Duration.ofSeconds(flexibleWait)); 88 | 89 | wait.pollingEvery(Duration.ofMillis(pollingInterval)); 90 | // Visibility or presence would time out 91 | // element = wait.until(ExpectedConditions.visibilityOfElementLocated( 92 | // By.cssSelector("img.central-featured-logo"))); 93 | // element = wait.until(ExpectedConditions 94 | element = driver.findElement(By.cssSelector("img.central-featured-logo")); 95 | // .presenceOfElementLocated(By.cssSelector("img.central-featured-logo"))); 96 | Long naturalWidth = (Long) driver 97 | .executeScript("return arguments[0].naturalWidth", element); 98 | Long naturalHeight = (Long) driver 99 | .executeScript("return arguments[0].naturalHeight", element); 100 | assertThat(naturalWidth, is(0L)); 101 | assertThat(naturalHeight, is(0L)); 102 | } 103 | 104 | @After 105 | public void after() { 106 | 107 | chromeDevTools.send(Fetch.disable()); 108 | chromeDevTools.clearListeners(); 109 | } 110 | 111 | } 112 | 113 | -------------------------------------------------------------------------------- /src/test/java/com/github/sergueik/selenium/FileChooserDialogInterceptDevToolsTest.java: -------------------------------------------------------------------------------- 1 | package com.github.sergueik.selenium; 2 | 3 | /** 4 | * Copyright 2021,2024 Serguei Kouzmine 5 | */ 6 | 7 | 8 | import static org.hamcrest.CoreMatchers.notNullValue; 9 | import static org.hamcrest.MatcherAssert.assertThat; 10 | 11 | import org.junit.After; 12 | import org.junit.Before; 13 | import org.junit.Test; 14 | import org.openqa.selenium.By; 15 | import org.openqa.selenium.WebElement; 16 | import org.openqa.selenium.devtools.v127.page.Page; 17 | import org.openqa.selenium.devtools.v127.page.model.FileChooserOpened; 18 | import org.openqa.selenium.devtools.v127.page.model.FrameId; 19 | import org.openqa.selenium.interactions.Actions; 20 | 21 | /** 22 | * Selected test scenarios for Selenium Chrome Developer Tools Selenium 4 bridge 23 | * MOTE: does not work as documented: 24 | * Intercept file chooser requests and transfer control to protocol clients. 25 | * When file chooser interception is enabled, native file chooser dialog is not shown. 26 | * Instead, a protocol event Page.fileChooserOpened is emitted 27 | * https://chromedevtools.github.io/devtools-protocol/tot/Page/#method-setInterceptFileChooserDialog 28 | * https://chromedevtools.github.io/devtools-protocol/tot/Page/#event-fileChooserOpened 29 | * @author: Serguei Kouzmine (kouzmine_serguei@yahoo.com) 30 | */ 31 | 32 | public class FileChooserDialogInterceptDevToolsTest extends BaseDevToolsTest { 33 | 34 | public String baseURL = "http://www.dev2qa.com/demo/upload/uploadFileTest.html"; 35 | 36 | @Before 37 | public void before() throws Exception { 38 | driver.get(baseURL); 39 | chromeDevTools.send(Page.setInterceptFileChooserDialog(true)); 40 | // listen file chooser dialog events 41 | chromeDevTools.addListener(Page.fileChooserOpened(), 42 | (FileChooserOpened event) -> { 43 | FrameId frameId = event.getFrameId(); 44 | System.err.println("Event from frame: " + frameId.toJson()); 45 | }); 46 | } 47 | 48 | @After 49 | public void after() { 50 | 51 | chromeDevTools.send(Page.setInterceptFileChooserDialog(false)); 52 | chromeDevTools.clearListeners(); 53 | } 54 | 55 | @Test 56 | public void test() { 57 | // Arrange 58 | WebElement element = driver 59 | .findElement(By.cssSelector("input[name='uploadFileInputBox']")); 60 | assertThat(element, notNullValue()); 61 | Utils.highlight(element, 1000); 62 | Utils.sleep(1000); 63 | Actions actions = new Actions(driver); 64 | actions.moveToElement(element).click(element).build().perform(); 65 | // org.openqa.selenium.InvalidArgumentException: invalid argument 66 | // element.click(); 67 | // org.openqa.selenium.InvalidArgumentException: invalid argument 68 | // element.sendKeys(Keys.ENTER); 69 | // Input the uploaded file's absolute file path to the upload file web 70 | // element as string use sendKeys() method. 71 | Utils.sleep(1000); 72 | } 73 | 74 | } 75 | -------------------------------------------------------------------------------- /src/test/java/com/github/sergueik/selenium/FrameDevToolsTest.java: -------------------------------------------------------------------------------- 1 | package com.github.sergueik.selenium; 2 | /** 3 | * Copyright 2021,2023,2024 Serguei Kouzmine 4 | */ 5 | 6 | import java.util.Optional; 7 | 8 | import org.junit.After; 9 | import org.junit.Before; 10 | import org.junit.Test; 11 | import org.openqa.selenium.By; 12 | import org.openqa.selenium.WebElement; 13 | import org.openqa.selenium.devtools.v127.page.Page; 14 | import org.openqa.selenium.devtools.v127.page.model.FrameAttached; 15 | import org.openqa.selenium.devtools.v127.page.model.FrameNavigated; 16 | import org.openqa.selenium.devtools.v127.network.model.LoaderId; 17 | 18 | /** 19 | * Selected test scenarios for Selenium Chrome Developer Tools Selenium 4 bridge 20 | * https://chromedevtools.github.io/devtools-protocol/1-2/Page/#event-frameAttached 21 | * https://chromedevtools.github.io/devtools-protocol/1-2/Page/#event-frameNavigated 22 | * https://chromedevtools.github.io/devtools-protocol/tot/Page/#method-*reload 23 | * 24 | * @author: Serguei Kouzmine (kouzmine_serguei@yahoo.com) 25 | */ 26 | 27 | 28 | public class FrameDevToolsTest extends BaseDevToolsTest { 29 | private static int cnt = 0; 30 | private static WebElement element; 31 | private final static int maxcnt = 10; 32 | private final static String baseURL = "https://www.w3schools.com/html/tryit.asp?filename=tryhtml_iframe_target"; 33 | 34 | @Before 35 | public void before() throws Exception { 36 | chromeDevTools.createSession(); 37 | chromeDevTools.send(Page.enable()); 38 | 39 | // register to frame events 40 | chromeDevTools.addListener(Page.frameAttached(), (FrameAttached event) -> { 41 | if (cnt++ < maxcnt) 42 | System.err.println( 43 | String.format("Page has frame %s attached: ", event.getFrameId())); 44 | }); 45 | chromeDevTools.addListener(Page.frameNavigated(), 46 | (FrameNavigated event) -> System.err.println(String.format( 47 | "Page has frame %s navigated: ", event.getFrame().getId()))); 48 | driver.get(baseURL); 49 | } 50 | 51 | @After 52 | public void afterTest() throws Exception { 53 | chromeDevTools.clearListeners(); 54 | chromeDevTools.send(Page.disable()); 55 | } 56 | 57 | 58 | // @Ignore 59 | @Test 60 | public void Test() { 61 | element = driver.findElement(By.tagName("iframe")); 62 | driver.switchTo().frame(element); 63 | driver.switchTo().defaultContent(); 64 | chromeDevTools.send(Page.reload(Optional.of(true), Optional.empty(), Optional.empty())); 65 | } 66 | 67 | } 68 | -------------------------------------------------------------------------------- /src/test/java/com/github/sergueik/selenium/IgnoreCertificateErrorsCdpTest.java: -------------------------------------------------------------------------------- 1 | package com.github.sergueik.selenium; 2 | 3 | /** 4 | * Copyright 2023,2024 Serguei Kouzmine 5 | */ 6 | 7 | import static org.hamcrest.CoreMatchers.containsString; 8 | import static org.hamcrest.CoreMatchers.notNullValue; 9 | import static org.hamcrest.MatcherAssert.assertThat; 10 | import static org.hamcrest.Matchers.hasKey; 11 | import static org.junit.Assert.assertTrue; 12 | 13 | import java.util.HashMap; 14 | import java.util.Map; 15 | 16 | import org.junit.After; 17 | import org.junit.Before; 18 | import org.junit.Ignore; 19 | import org.junit.Test; 20 | import org.openqa.selenium.By; 21 | import org.openqa.selenium.WebDriverException; 22 | import org.openqa.selenium.WebElement; 23 | import org.openqa.selenium.support.ui.ExpectedConditions; 24 | 25 | import com.google.gson.JsonSyntaxException; 26 | 27 | /** 28 | * Selected test scenarios for Selenium 4 Chrome Developer Tools bridge 29 | * https://chromedevtools.github.io/devtools-protocol/tot/Security/#method-setIgnoreCertificateErrors 30 | * https://chromedevtools.github.io/devtools-protocol/tot/DOM/#method-getOuterHTML 31 | * @author: Serguei Kouzmine (kouzmine_serguei@yahoo.com) 32 | */ 33 | 34 | // based on: 35 | // https://github.com/shsarkar08/PythonSeleniumCDP_APIs/blob/master/sel_py_cdp_ignore_cert_errors.py 36 | public class IgnoreCertificateErrorsCdpTest extends BaseCdpTest { 37 | 38 | private static String baseURL = "https://untrusted-root.badssl.com/"; 39 | private final String selector = "#footer"; 40 | 41 | private static String command = "Security.setIgnoreCertificateErrors"; 42 | 43 | private static Map params = new HashMap<>(); 44 | private static Map result = new HashMap<>(); 45 | public static Long nodeId = (long) -1; 46 | private static WebElement element = null; 47 | 48 | @After 49 | public void afterTest() { 50 | command = "Security.setIgnoreCertificateErrors"; 51 | driver.get("about:blank"); 52 | params.clear(); 53 | params.put("ignore", false); 54 | result = driver.executeCdpCommand(command, params); 55 | } 56 | 57 | @Before 58 | public void beforeTest() { 59 | command = "Security.setIgnoreCertificateErrors"; 60 | params.clear(); 61 | params.put("ignore", true); 62 | result = driver.executeCdpCommand(command, params); 63 | driver.get(baseURL); 64 | } 65 | 66 | @Ignore 67 | @Test 68 | public void test1() { 69 | element = wait.until(ExpectedConditions 70 | .visibilityOfElementLocated(By.cssSelector(selector))); 71 | String data = element.getText(); 72 | assertThat(data, containsString( 73 | "The certificate for this site is signed using an untrusted root.")); 74 | System.err.println(data); 75 | 76 | } 77 | 78 | // @Ignore("appears broken in DOM navigation") 79 | @SuppressWarnings("unchecked") 80 | @Test 81 | public void test2() { 82 | 83 | try { 84 | command = "DOM.getDocument"; 85 | params = new HashMap<>(); 86 | params.put("pierce", false); 87 | params.put("depth", 1); 88 | // Act 89 | result = driver.executeCdpCommand(command, params); 90 | nodeId = Long.parseLong( 91 | ((Map) result.get("root")).get("nodeId").toString()); 92 | System.err.println(String.format("nodeid: %d", nodeId)); 93 | command = "DOM.querySelector"; 94 | params.clear(); 95 | 96 | params.put("nodeId", nodeId); 97 | params.put("selector", selector); 98 | 99 | result = driver.executeCdpCommand(command, params); 100 | 101 | assertThat(result, hasKey("nodeId")); 102 | nodeId = (Long) result.get("nodeId"); 103 | System.err.println(String.format("nodeid: %d", nodeId)); 104 | command = "DOM.getOuterHTML"; 105 | params.clear(); 106 | params.put("nodeId", nodeId); 107 | result = driver.executeCdpCommand(command, params); 108 | assertThat(result, notNullValue()); 109 | assertTrue(result.containsKey("outerHTML")); 110 | String data = result.get("outerHTML").toString(); 111 | assertThat(data, containsString( 112 | "The certificate for this site is signed using an untrusted root.")); 113 | System.err.println(data); 114 | } catch (JsonSyntaxException e) { 115 | System.err.println("JSON Syntax exception in " + command + " (ignored): " 116 | + e.toString()); 117 | } catch (WebDriverException e) { 118 | System.err.println("Web Driver exception in " + command + " (ignored): " 119 | + Utils.processExceptionMessage(e.getMessage())); 120 | } catch (Exception e) { 121 | System.err.println("Exception in " + command + " " + e.toString()); 122 | e.printStackTrace(); 123 | throw (new RuntimeException(e)); 124 | } 125 | } 126 | } 127 | -------------------------------------------------------------------------------- /src/test/java/com/github/sergueik/selenium/IgnoreCertificateErrorsDevToolsTest.java: -------------------------------------------------------------------------------- 1 | package com.github.sergueik.selenium; 2 | 3 | /** 4 | * Copyright 2023,2024 Serguei Kouzmine 5 | */ 6 | 7 | 8 | import static org.hamcrest.CoreMatchers.containsString; 9 | import static org.hamcrest.MatcherAssert.assertThat; 10 | 11 | import java.time.Duration; 12 | import java.util.Optional; 13 | 14 | import org.junit.After; 15 | import org.junit.Before; 16 | import org.junit.Test; 17 | import org.openqa.selenium.By; 18 | import org.openqa.selenium.WebElement; 19 | import org.openqa.selenium.devtools.DevToolsException; 20 | import org.openqa.selenium.devtools.v127.dom.DOM; 21 | import org.openqa.selenium.devtools.v127.dom.DOM.EnableIncludeWhitespace; 22 | import org.openqa.selenium.devtools.v127.dom.model.Node; 23 | import org.openqa.selenium.devtools.v127.dom.model.NodeId; 24 | import org.openqa.selenium.devtools.v127.security.Security; 25 | import org.openqa.selenium.support.ui.ExpectedConditions; 26 | import org.openqa.selenium.support.ui.WebDriverWait; 27 | 28 | /** 29 | * Selected test scenarios for Selenium 4 Chrome Developer Tools bridge 30 | * https://chromedevtools.github.io/devtools-protocol/tot/Security/#method-setIgnoreCertificateErrors 31 | * https://chromedevtools.github.io/devtools-protocol/tot/Security/#event-certificateError 32 | * @author: Serguei Kouzmine (kouzmine_serguei@yahoo.com) 33 | */ 34 | 35 | // based on: 36 | // https://github.com/shsarkar08/PythonSeleniumCDP_APIs/blob/master/sel_py_cdp_ignore_cert_errors.py 37 | 38 | public class IgnoreCertificateErrorsDevToolsTest extends BaseDevToolsTest { 39 | 40 | private static String baseURL = "https://untrusted-root.badssl.com/"; 41 | private final String selector = "#footer"; 42 | 43 | private static Node result; 44 | private static NodeId nodeId = null; 45 | private static WebDriverWait wait; 46 | private static int flexibleWait = 10; 47 | private static int pollingInterval = 500; 48 | 49 | private static WebElement element = null; 50 | 51 | @After 52 | public void afterTest() { 53 | chromeDevTools.send(Security.setIgnoreCertificateErrors(false)); 54 | chromeDevTools.send(DOM.disable()); 55 | driver.get("about:blank"); 56 | } 57 | 58 | @Before 59 | public void beforeTest() { 60 | chromeDevTools.send(Security.setIgnoreCertificateErrors(true)); 61 | driver.get(baseURL); 62 | EnableIncludeWhitespace enableIncludeWhitespace = EnableIncludeWhitespace.ALL; 63 | 64 | chromeDevTools.send(DOM.enable(Optional.of(enableIncludeWhitespace))); 65 | } 66 | 67 | @Test 68 | public void test1() { 69 | wait = new WebDriverWait(driver, Duration.ofSeconds(flexibleWait)); 70 | 71 | wait.pollingEvery(Duration.ofMillis(pollingInterval)); 72 | element = wait.until(ExpectedConditions 73 | .visibilityOfElementLocated(By.cssSelector(selector))); 74 | String data = element.getText(); 75 | assertThat(data, containsString( 76 | "The certificate for this site is signed using an untrusted root.")); 77 | System.err.println(data); 78 | } 79 | 80 | @Test 81 | public void test2() { 82 | try { 83 | result = chromeDevTools 84 | .send(DOM.getDocument(Optional.of(1), Optional.of(true))); 85 | 86 | nodeId = chromeDevTools 87 | .send(DOM.querySelector(result.getNodeId(), selector)); 88 | String data = chromeDevTools.send(DOM.getOuterHTML(Optional.of(nodeId), 89 | Optional.empty(), Optional.empty())); 90 | assertThat(data, containsString( 91 | "The certificate for this site is signed using an untrusted root.")); 92 | 93 | System.err.println(data); 94 | 95 | } catch (DevToolsException e) { 96 | System.err.println("Exception (rethrown) " + e.getMessage()); 97 | throw e; 98 | } 99 | } 100 | 101 | } 102 | -------------------------------------------------------------------------------- /src/test/java/com/github/sergueik/selenium/InputCdpTest.java: -------------------------------------------------------------------------------- 1 | package com.github.sergueik.selenium; 2 | /** 3 | * Copyright 2022,2024 Serguei Kouzmine 4 | */ 5 | 6 | import java.util.HashMap; 7 | import java.util.Map; 8 | 9 | import org.junit.Before; 10 | import org.junit.Test; 11 | 12 | /** 13 | * Selected test scenarios for Selenium 4 Chrome Developer Tools bridge 14 | * https://chromedevtools.github.io/devtools-protocol/tot/Input/#method-dispatchKeyEvent 15 | * @author: Serguei Kouzmine (kouzmine_serguei@yahoo.com) 16 | */ 17 | 18 | public class InputCdpTest extends BaseCdpTest { 19 | 20 | private final static String baseURL = "https://www.google.com"; 21 | private static String command; 22 | private static Map params = new HashMap<>(); 23 | 24 | @Before 25 | public void beforeTest() throws Exception { 26 | driver.get(baseURL); 27 | } 28 | 29 | @Test 30 | public void test1() { 31 | 32 | try { 33 | // Act 34 | command = "Input.dispatchKeyEvent"; 35 | params.put("type", "keyDown"); 36 | params.put("modifiers", 2); 37 | params.put("text", "a"); 38 | params.put("isKeypad", true); 39 | 40 | driver.executeCdpCommand(command, params); 41 | Utils.sleep(4000); 42 | } catch (Exception e) { 43 | System.err.println("Exception in " + command + " " + e.toString()); 44 | throw (new RuntimeException(e)); 45 | } 46 | } 47 | 48 | @Test 49 | public void test3() { 50 | 51 | try { 52 | // Act 53 | command = "Input.dispatchKeyEvent"; 54 | params.put("type", "keyDown"); 55 | params.put("commands", new String[] { "selectAll" }); 56 | driver.executeCdpCommand(command, params); 57 | Utils.sleep(4000); 58 | } catch (Exception e) { 59 | System.err.println("Exception in " + command + " " + e.toString()); 60 | throw (new RuntimeException(e)); 61 | } 62 | } 63 | 64 | @Test 65 | public void test2() { 66 | 67 | try { 68 | // Act 69 | command = "Input.insertText"; 70 | params.put("text", "^_^"); 71 | 72 | driver.executeCdpCommand(command, params); 73 | Utils.sleep(4000); 74 | } catch (Exception e) { 75 | System.err.println("Exception in " + command + " " + e.toString()); 76 | throw (new RuntimeException(e)); 77 | } 78 | } 79 | 80 | } 81 | -------------------------------------------------------------------------------- /src/test/java/com/github/sergueik/selenium/LegacyLoggingDevToolsTest.java: -------------------------------------------------------------------------------- 1 | package com.github.sergueik.selenium; 2 | /** 3 | * Copyright 2024 Serguei Kouzmine 4 | */ 5 | 6 | import org.junit.Test; 7 | import org.openqa.selenium.By; 8 | import org.openqa.selenium.WebElement; 9 | import org.openqa.selenium.logging.LogEntries; 10 | import org.openqa.selenium.logging.LogEntry; 11 | import org.openqa.selenium.logging.LogType; 12 | 13 | /** 14 | * Selected test scenarios for Selenium Chrome Developer Tools Selenium 4 bridge 15 | * 16 | * @author: Serguei Kouzmine (kouzmine_serguei@yahoo.com) 17 | */ 18 | 19 | @SuppressWarnings("deprecation") 20 | public class LegacyLoggingDevToolsTest extends BaseDevToolsTest { 21 | 22 | private final static String baseURL = "https://rahulshettyacademy.com/angularAppdemo/"; 23 | private WebElement element; 24 | 25 | // based on: 26 | // https://github.com/SaraMohamed2022/Selenium4_CDPPracticing/blob/main/src/test/java/selenium4_SelfPracticing/GetJavaScriptLogs.java 27 | @Test 28 | public void test1() { 29 | driver.get(baseURL); 30 | element = driver.findElement(By.linkText("Browse Products")); 31 | element.click(); 32 | element = driver.findElement(By.partialLinkText("Selenium")); 33 | element.click(); 34 | element = driver.findElement(By.cssSelector(".add-to-cart")); 35 | element.click(); 36 | element = driver.findElement(By.linkText("Cart")); 37 | element.click(); 38 | element = driver.findElement(By.id("exampleInputEmail1")); 39 | element.clear(); 40 | element.sendKeys("2"); 41 | 42 | LogEntries entries = driver.manage().logs().get(LogType.BROWSER); 43 | for (LogEntry e : entries) 44 | System.out.println(e.getMessage()); 45 | } 46 | 47 | } 48 | -------------------------------------------------------------------------------- /src/test/java/com/github/sergueik/selenium/LocaleOverrideTest.java: -------------------------------------------------------------------------------- 1 | package com.github.sergueik.selenium; 2 | 3 | /** 4 | * Copyright 2021,2024 Serguei Kouzmine 5 | */ 6 | 7 | 8 | import java.util.HashMap; 9 | import java.util.Map; 10 | import org.junit.Test; 11 | 12 | /** 13 | * Selected test scenarios for Selenium 4 Chrome Developer Tools bridge inspired 14 | * 15 | * @author: Serguei Kouzmine (kouzmine_serguei@yahoo.com) 16 | */ 17 | public class LocaleOverrideTest extends BaseCdpTest { 18 | 19 | private static String command = null; 20 | private static Map result = null; 21 | private static Map data = null; 22 | private static Map params = new HashMap<>(); 23 | private static final String baseURL = "https://www.wikipedia.org"; 24 | 25 | @SuppressWarnings("unchecked") 26 | @Test 27 | // https://phrase.com/blog/posts/detecting-a-users-locale/ 28 | public void test3() { 29 | // Arrange 30 | command = "Emulation.setLocaleOverride"; 31 | // Act 32 | params = new HashMap<>(); 33 | params.put("locale", "ru-RU"); 34 | driver.executeCdpCommand(command, params); 35 | driver.executeCdpCommand("Runtime.enable", new HashMap<>()); 36 | 37 | driver.get(baseURL); 38 | command = "Runtime.evaluate"; 39 | params = new HashMap<>(); 40 | params.put("expression", 41 | "function example(){ return navigator.userLanguage || (navigator.languages && navigator.languages.length && navigator.languages[0]) || navigator.language || navigator.browserLanguage || navigator.systemLanguage || 'en';} example();"); 42 | result = driver.executeCdpCommand(command, params); 43 | System.err.println("Response to " + command + ": " + result); 44 | command = "Runtime.evaluate"; 45 | params = new HashMap<>(); 46 | params.put("expression", 47 | "function example(){ return navigator.languages;} example();"); 48 | result = driver.executeCdpCommand(command, params); 49 | System.err.println("Response to " + command + ": " + result); 50 | command = "Runtime.getProperties"; 51 | params = new HashMap<>(); 52 | data = (Map) result.get("result"); 53 | params.put("objectId", data.get("objectId").toString()); 54 | result = driver.executeCdpCommand(command, params); 55 | System.err.println("Response to " + command + ": " + result); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/test/java/com/github/sergueik/selenium/LoggingDevToolsTest.java: -------------------------------------------------------------------------------- 1 | package com.github.sergueik.selenium; 2 | 3 | /** 4 | * Copyright 2020,2021,2024 Serguei Kouzmine 5 | */ 6 | 7 | import static org.hamcrest.CoreMatchers.containsString; 8 | import static org.hamcrest.CoreMatchers.notNullValue; 9 | import static org.junit.Assert.assertThat; 10 | 11 | import java.text.DateFormat; 12 | import java.text.SimpleDateFormat; 13 | import java.util.Date; 14 | import java.util.Optional; 15 | import java.util.TimeZone; 16 | 17 | import org.junit.After; 18 | import org.junit.Before; 19 | import org.junit.Test; 20 | import org.openqa.selenium.devtools.v127.log.Log; 21 | import org.openqa.selenium.devtools.v127.log.model.LogEntry; 22 | import org.openqa.selenium.devtools.v127.runtime.model.Timestamp; 23 | import org.openqa.selenium.devtools.v127.page.Page; 24 | 25 | /** 26 | * Selected test scenarios for Selenium Chrome Developer Tools Selenium 4 bridge 27 | * 28 | * https://chromedevtools.github.io/devtools-protocol/tot/Log#method-enable 29 | * https://chromedevtools.github.io/devtools-protocol/tot/Log/#event-entryAdded 30 | * https://chromedevtools.github.io/devtools-protocol/1-3/Page/#method-navigate 31 | * 32 | * @author: Serguei Kouzmine (kouzmine_serguei@yahoo.com) 33 | */ 34 | 35 | @SuppressWarnings("deprecation") 36 | public class LoggingDevToolsTest extends BaseDevToolsTest { 37 | 38 | private final static String baseURL = "https://www.google.com"; 39 | 40 | @Before 41 | public void beforeTest() throws Exception { 42 | chromeDevTools.send(Log.enable()); 43 | chromeDevTools.addListener(Log.entryAdded(), 44 | 45 | (LogEntry event) -> System.err.println(String.format( 46 | "time stamp: %s line number: %s url: \"%s\" text: %s", formatTimestamp(event.getTimestamp()), 47 | (event.getLineNumber().isPresent() ? event.getLineNumber().get() : ""), 48 | (event.getUrl().isPresent() ? event.getUrl().get() : ""), event.getText()))); 49 | } 50 | 51 | @Test 52 | public void test1() { 53 | // add event listener to show in host console the browser console message 54 | chromeDevTools.addListener(Log.entryAdded(), (LogEntry event) -> { 55 | assertThat(event.getText(), notNullValue()); 56 | assertThat(event.getLineNumber(), notNullValue()); 57 | assertThat(event.getTimestamp(), notNullValue()); 58 | assertThat(event.getSource(), notNullValue()); 59 | 60 | }); 61 | 62 | // chromeDevTools.addListener(Log.eventAdded(), System.err::println); 63 | // what it would print will not be too useful: 64 | // org.openqa.selenium.devtools.v127.log.model.LogEntry@5e77d702 65 | 66 | driver.get(baseURL); 67 | chromeDevTools 68 | .send(Page.navigate(baseURL, Optional.empty(), Optional.empty(), Optional.empty(), Optional.empty())); 69 | } 70 | 71 | @Test 72 | public void test2() { 73 | final String consoleMessage = "Lorem ipsum"; 74 | chromeDevTools.addListener(Log.entryAdded(), 75 | (LogEntry event) -> assertThat(event.getText(), containsString(consoleMessage))); 76 | driver.executeScript("console.log(arguments[0]);", consoleMessage); 77 | } 78 | 79 | // origin: 80 | // https://github.com/SaraMohamed2022/Selenium4_CDPPracticing/blob/main/src/test/java/selenium4_SelfPracticing/CDPLogs.java 81 | @Test 82 | public void test3() { 83 | chromeDevTools.addListener(Log.entryAdded(), logEntry -> { 84 | System.err.println( 85 | String.format("-----------" + "\n" + "Level: %s" + "\n" + "Text: %s" + "\n" + "Broken URL: %s", 86 | logEntry.getLevel(), logEntry.getText(), logEntry.getUrl())); 87 | }); 88 | String url = "https://the-internet.herokuapp.com/broken_images"; 89 | driver.get(url); 90 | } 91 | 92 | @After 93 | public void afterTest() throws Exception { 94 | chromeDevTools.clearListeners(); 95 | chromeDevTools.send(Log.disable()); 96 | } 97 | 98 | private String formatTimestamp(Timestamp timestamp) { 99 | final DateFormat gmtFormat = new SimpleDateFormat("E, dd-MMM-yyyy hh:mm:ss"); 100 | final TimeZone timeZone = TimeZone.getDefault(); 101 | gmtFormat.setTimeZone(timeZone); 102 | long time = Double.valueOf(timestamp.toString()).longValue(); 103 | return gmtFormat.format(new Date(time)) + " " + timeZone.getDisplayName(false, TimeZone.SHORT); 104 | 105 | } 106 | 107 | } 108 | -------------------------------------------------------------------------------- /src/test/java/com/github/sergueik/selenium/NetworkConditionsCdpTest.java: -------------------------------------------------------------------------------- 1 | package com.github.sergueik.selenium; 2 | 3 | /** 4 | * Copyright 2022-2024 Serguei Kouzmine 5 | */ 6 | 7 | 8 | import static org.hamcrest.CoreMatchers.containsString; 9 | import static org.hamcrest.MatcherAssert.assertThat; 10 | 11 | import java.io.IOException; 12 | import java.util.HashMap; 13 | import java.util.Map; 14 | 15 | import org.junit.After; 16 | import org.junit.Before; 17 | import org.junit.Rule; 18 | import org.junit.Test; 19 | import org.junit.rules.ExpectedException; 20 | import org.openqa.selenium.WebDriverException; 21 | 22 | /** 23 | * Selected test scenarios for Selenium Chrome Developer Tools Selenium 4 bridge 24 | * see also: 25 | * https://chromedevtools.github.io/devtools-protocol/tot/Network/#method-emulateNetworkConditions 26 | * https://chromedevtools.github.io/devtools-protocol/tot/Network/#type-ConnectionType 27 | * 28 | * @author: Serguei Kouzmine (kouzmine_serguei@yahoo.com) 29 | */ 30 | @SuppressWarnings("deprecation") 31 | public class NetworkConditionsCdpTest extends BaseCdpTest { 32 | 33 | private static String baseURL = "https://www.wikipedia.org"; 34 | private static String command = "Network.emulateNetworkConditions"; 35 | private static Map params = new HashMap<>(); 36 | @Rule 37 | public ExpectedException exceptionRule = ExpectedException.none(); 38 | 39 | 40 | @Before 41 | public void beforeTest() { 42 | params = new HashMap<>(); 43 | params.put("offline", false); 44 | params.put("latency", 100L); 45 | params.put("downloadThroughput", -1L); 46 | params.put("uploadThroughput", -1L); 47 | } 48 | 49 | @After 50 | public void afterTest() { 51 | params.put("offline", false); 52 | driver.executeCdpCommand(command, params); 53 | driver.get("about:blank"); 54 | } 55 | 56 | // https://www.baeldung.com/junit-assert-exception 57 | @Test(expected = WebDriverException.class) 58 | public void test1() throws IOException { 59 | params.put("offline", true); 60 | driver.executeCdpCommand(command, params); 61 | try { 62 | driver.get(baseURL); 63 | } catch (WebDriverException e) { 64 | assertThat(e.getMessage(), containsString("ERR_INTERNET_DISCONNECTED")); 65 | System.err.println("Exception (ignored): " + e.getMessage()); 66 | // e.printStackTrace(System.err); 67 | throw (e); 68 | } finally { 69 | params.put("offline", false); 70 | driver.executeCdpCommand(command, params); 71 | } 72 | } 73 | 74 | @Test 75 | public void test2() { 76 | exceptionRule.expect(WebDriverException.class); 77 | exceptionRule.expectMessage(containsString("ERR_INTERNET_DISCONNECTED")); 78 | params.put("offline", true); 79 | driver.executeCdpCommand(command, params); 80 | driver.get(baseURL); 81 | 82 | } 83 | 84 | } 85 | 86 | -------------------------------------------------------------------------------- /src/test/java/com/github/sergueik/selenium/NetworkConditionsDevToolsTest.java: -------------------------------------------------------------------------------- 1 | package com.github.sergueik.selenium; 2 | 3 | /** 4 | * Copyright 2022-2024 Serguei Kouzmine 5 | */ 6 | 7 | 8 | import static org.hamcrest.CoreMatchers.containsString; 9 | import static org.hamcrest.MatcherAssert.assertThat; 10 | 11 | import java.io.IOException; 12 | import java.util.Optional; 13 | 14 | import org.junit.After; 15 | import org.junit.Test; 16 | import org.openqa.selenium.WebDriver; 17 | import org.openqa.selenium.WebDriverException; 18 | import org.openqa.selenium.chromium.ChromiumNetworkConditions; 19 | import org.openqa.selenium.chromium.HasNetworkConditions; 20 | import org.openqa.selenium.devtools.v127.network.Network; 21 | import org.openqa.selenium.devtools.v127.network.model.ConnectionType; 22 | import org.openqa.selenium.remote.Augmenter; 23 | 24 | /** 25 | * Selected test scenarios for Selenium Chrome Developer Tools Selenium 4 bridge 26 | * see also: 27 | * https://chromedevtools.github.io/devtools-protocol/tot/Network/#method-emulateNetworkConditions 28 | * https://chromedevtools.github.io/devtools-protocol/tot/Network/#type-ConnectionType 29 | * 30 | * @author: Serguei Kouzmine (kouzmine_serguei@yahoo.com) 31 | */ 32 | 33 | public class NetworkConditionsDevToolsTest extends BaseDevToolsTest { 34 | 35 | private static String baseURL = "https://www.wikipedia.org"; 36 | 37 | private Boolean offline; 38 | 39 | @After 40 | public void afterTest() { 41 | offline = false; 42 | chromeDevTools 43 | .send(Network.emulateNetworkConditions(offline, new Long(100L), 44 | new Long(-1), new Long(-1), Optional.of(ConnectionType.ETHERNET), Optional.of(0.0), Optional.of(0), Optional.empty())); 45 | 46 | driver.get("about:blank"); 47 | } 48 | 49 | @SuppressWarnings("deprecation") 50 | @Test(expected = WebDriverException.class) 51 | public void test1() throws IOException { 52 | offline = true; 53 | chromeDevTools 54 | .send(Network.emulateNetworkConditions(offline, new Long(100L), 55 | new Long(-1), new Long(-1), Optional.of(ConnectionType.ETHERNET), Optional.of(0.0), Optional.of(0), Optional.empty())); 56 | try { 57 | driver.get(baseURL); 58 | } catch (WebDriverException e) { 59 | assertThat(e.getMessage(), containsString("ERR_INTERNET_DISCONNECTED")); 60 | System.err.println("Exception (ignored): " + e.getMessage()); 61 | // e.printStackTrace(System.err); 62 | throw (e); 63 | } finally { 64 | offline = false; 65 | chromeDevTools 66 | .send(Network.emulateNetworkConditions(offline, new Long(100L), 67 | new Long(-1), new Long(-1), Optional.of(ConnectionType.NONE), Optional.of(0.0), Optional.of(0), Optional.empty())); 68 | 69 | } 70 | } 71 | 72 | // based on: 73 | // https://github.com/Bhakti-satalkar/junit-selenium-offline-web-cdp-se4/blob/master/src/test/java/com/lambdatest/toggleNetworkOffline.java 74 | @Test(expected = WebDriverException.class) 75 | public void test2() throws IOException { 76 | WebDriver augmentedDriver = new Augmenter().augment(driver); 77 | ChromiumNetworkConditions networkConditions = new ChromiumNetworkConditions(); 78 | networkConditions.setOffline(true); 79 | ((HasNetworkConditions) augmentedDriver) 80 | .setNetworkConditions(networkConditions); 81 | try { 82 | driver.get(baseURL); 83 | } catch (WebDriverException e) { 84 | assertThat(e.getMessage(), containsString("ERR_INTERNET_DISCONNECTED")); 85 | System.err.println("Exception (ignored): " + e.getMessage()); 86 | // e.printStackTrace(System.err); 87 | throw (e); 88 | } finally { 89 | ((HasNetworkConditions) augmentedDriver) 90 | .setNetworkConditions(new ChromiumNetworkConditions()); 91 | } 92 | 93 | } 94 | 95 | } 96 | 97 | -------------------------------------------------------------------------------- /src/test/java/com/github/sergueik/selenium/NetworkResponseBodyTest.java: -------------------------------------------------------------------------------- 1 | package com.github.sergueik.selenium; 2 | 3 | /** 4 | * Copyright 2023,2024 Serguei Kouzmine 5 | */ 6 | 7 | 8 | import static org.hamcrest.CoreMatchers.notNullValue; 9 | import static org.hamcrest.MatcherAssert.assertThat; 10 | 11 | /** 12 | * Copyright 2023 Serguei Kouzmine 13 | */ 14 | 15 | import java.io.UnsupportedEncodingException; 16 | import java.util.Arrays; 17 | import java.util.HashMap; 18 | import java.util.List; 19 | import java.util.Map; 20 | import java.util.Optional; 21 | 22 | import org.apache.commons.codec.binary.Base64; 23 | import org.junit.After; 24 | import org.junit.Before; 25 | import org.junit.Test; 26 | import org.openqa.selenium.By; 27 | import org.openqa.selenium.WebDriverException; 28 | import org.openqa.selenium.WebElement; 29 | import org.openqa.selenium.devtools.v127.network.Network; 30 | import org.openqa.selenium.devtools.v127.network.model.ResourceType; 31 | import org.openqa.selenium.devtools.v127.network.model.ResponseReceived; 32 | import org.openqa.selenium.interactions.Actions; 33 | 34 | import com.google.gson.Gson; 35 | 36 | /** 37 | * Selected test scenarios for Selenium Chrome Developer Tools Selenium 4 bridge 38 | * see: 39 | * https://chromedevtools.github.io/devtools-protocol/tot/Network/#method-getResponseBody 40 | * https://chromedevtools.github.io/devtools-protocol/tot/Network#method-enable 41 | * https://chromedevtools.github.io/devtools-protocol/tot/Network/#event-responseReceived 42 | * 43 | * @author: Serguei Kouzmine (kouzmine_serguei@yahoo.com) 44 | */ 45 | // see: 46 | // https://github.com/Vipinvwarrier/selenium_cdp_profiler/blob/main/selenium_cdp_profiler/cdp/network_profiler.py 47 | 48 | public class NetworkResponseBodyTest extends BaseDevToolsTest { 49 | 50 | public Actions actions; 51 | private final static String url = "https://en.wikipedia.org/wiki/XMLHttpRequest"; 52 | private final int count = 5; 53 | 54 | @Before 55 | public void beforeTest() throws Exception { 56 | 57 | chromeDevTools.send(Network.enable(Optional.of(100000000), Optional.empty(), 58 | Optional.empty())); 59 | chromeDevTools.send(Network.clearBrowserCache()); 60 | chromeDevTools.send(Network.setCacheDisabled(true)); 61 | 62 | } 63 | 64 | @After 65 | public void afterTest() throws Exception { 66 | chromeDevTools.clearListeners(); 67 | chromeDevTools.send(Network.disable()); 68 | } 69 | 70 | @SuppressWarnings("unchecked") 71 | @Test 72 | public void test() { 73 | // Arrange 74 | final Gson gson = new Gson(); 75 | try { 76 | chromeDevTools.addListener(Network.responseReceived(), 77 | (ResponseReceived event) -> { 78 | ResourceType resourceType = event.getType(); 79 | String body = null; 80 | Map data = new HashMap<>(); 81 | System.err.println("Response type: " + resourceType.name()); 82 | 83 | Network.GetResponseBodyResponse responseBody = chromeDevTools 84 | .send(Network.getResponseBody(event.getRequestId())); 85 | if (responseBody.getBase64Encoded()) { 86 | try { 87 | body = new String(Base64 88 | .decodeBase64(responseBody.getBody().getBytes("UTF8"))); 89 | } catch (UnsupportedEncodingException e) { 90 | System.err.println("Exception (ignored): " + e.toString()); 91 | } 92 | } else { 93 | body = responseBody.getBody(); 94 | } 95 | if (resourceType.name().equalsIgnoreCase("FETCH")) { 96 | data = (Map) new Gson().fromJson(body, Map.class); 97 | assertThat(data, notNullValue()); 98 | System.err.println("FETCH request response JSON keys: " 99 | + Arrays.asList(data.keySet())); 100 | } 101 | if (resourceType.name().equalsIgnoreCase("SCRIPT")) { 102 | if (body.length() > 100) { 103 | System.err.println( 104 | "SCRIPT request response: " + body.substring(0, 100) 105 | + "... " + "(" + body.length() + " chars)"); 106 | } else { 107 | System.err.println("SCRIPT request response: " + body); 108 | } 109 | } 110 | }); 111 | 112 | // Act 113 | // hover the links in the main wikipedia document 114 | driver.get(url); 115 | Utils.sleep(1000); 116 | List elements = driver.findElement(By.id("mw-content-text")) 117 | .findElements(By.tagName("a")); 118 | actions = new Actions(driver); 119 | elements.stream().limit(count).forEach((WebElement element) -> { 120 | actions.moveToElement(element).build().perform(); 121 | Utils.sleep(1000); 122 | }); 123 | } catch (WebDriverException e) { 124 | System.err.println("Web Driver exception (ignored): " 125 | + Utils.processExceptionMessage(e.getMessage())); 126 | } catch (Exception e) { 127 | System.err.println("Exception: " + e.toString()); 128 | throw (new RuntimeException(e)); 129 | } 130 | } 131 | 132 | } 133 | -------------------------------------------------------------------------------- /src/test/java/com/github/sergueik/selenium/OverlayHighlightDevToolsTest.java: -------------------------------------------------------------------------------- 1 | package com.github.sergueik.selenium; 2 | /** 3 | * Copyright 2023,2024 Serguei Kouzmine 4 | */ 5 | 6 | import java.util.List; 7 | import java.util.Optional; 8 | 9 | import org.junit.After; 10 | import org.junit.Before; 11 | import org.junit.Test; 12 | import org.openqa.selenium.devtools.v127.dom.DOM; 13 | import org.openqa.selenium.devtools.v127.dom.model.Node; 14 | import org.openqa.selenium.devtools.v127.dom.model.NodeId; 15 | import org.openqa.selenium.devtools.v127.dom.model.RGBA; 16 | import org.openqa.selenium.devtools.v127.overlay.Overlay; 17 | import org.openqa.selenium.devtools.v127.overlay.model.HighlightConfig; 18 | 19 | /** 20 | * Selected test scenarios for Selenium Chrome Developer Tools Selenium 4 bridge 21 | * https://chromedevtools.github.io/devtools-protocol/tot/Overlay/#method-enable 22 | * https://chromedevtools.github.io/devtools-protocol/tot/DOM/#method-enable 23 | * https://chromedevtools.github.io/devtools-protocol/tot/DOM/#method-disable 24 | * https://chromedevtools.github.io/devtools-protocol/tot/DOM/#type-RGBA 25 | * https://chromedevtools.github.io/devtools-protocol/tot/Overlay/#method-highlightNode 26 | * https://chromedevtools.github.io/devtools-protocol/tot/Overlay/#type-HighlightConfig 27 | * https://chromedevtools.github.io/devtools-protocol/tot/Overlay/#method-hideHighlight 28 | * @author: Serguei Kouzmine (kouzmine_serguei@yahoo.com) 29 | */ 30 | 31 | // see also: 32 | // https://github.com/rkeeves/selenium-tricks/blob/main/src/test/java/io/github/rkeeves/interoperability/CDPHighlightByNodeIdTest.java 33 | public class OverlayHighlightDevToolsTest extends BaseDevToolsTest { 34 | private static String url = "https://www.wikipedia.org"; 35 | private static final String selector = "*[id^='js-link-box'] > strong"; 36 | 37 | @Before 38 | public void before() { 39 | chromeDevTools 40 | .send(DOM.enable(Optional.of(DOM.EnableIncludeWhitespace.ALL))); 41 | chromeDevTools.send(Overlay.enable()); 42 | driver.get(url); 43 | } 44 | 45 | @After 46 | public void after() { 47 | chromeDevTools.send(Overlay.disable()); 48 | chromeDevTools.send(DOM.disable()); 49 | } 50 | 51 | @Test 52 | public void test() { 53 | Node result = chromeDevTools 54 | .send(DOM.getDocument(Optional.of(1), Optional.of(true))); 55 | 56 | List results = chromeDevTools 57 | .send(DOM.querySelectorAll(result.getNodeId(), selector)); 58 | 59 | // based on: 60 | // https://github.com/rkeeves/selenium-tricks/blob/main/src/test/java/io/github/rkeeves/interoperability/CDPHighlightByNodeIdTest.java 61 | // https://youtu.be/OrOYvVf6tIM?t=328 62 | results.forEach((NodeId nodeId) -> { 63 | float alpha = (float) 0.5; 64 | RGBA contentColor = new RGBA(68, 255, 152, Optional.of(alpha)); 65 | boolean showInfo = true; 66 | boolean showRulers = true; 67 | boolean showAccessibilityInfo = false; 68 | boolean showExtensionLines = true; 69 | boolean showStyles = false; 70 | HighlightConfig highlightConfig = new HighlightConfig( 71 | Optional.of(showInfo), Optional.of(showStyles), 72 | Optional.of(showRulers), Optional.of(showAccessibilityInfo), 73 | Optional.of(showExtensionLines), Optional.of(contentColor), 74 | Optional.empty(), Optional.empty(), Optional.empty(), 75 | Optional.empty(), Optional.empty(), Optional.empty(), 76 | Optional.empty(), Optional.empty(), Optional.empty(), 77 | Optional.empty(), Optional.empty(), Optional.empty(), 78 | Optional.empty()); 79 | 80 | chromeDevTools 81 | .send(Overlay.highlightNode(highlightConfig, Optional.of(nodeId), 82 | Optional.empty(), Optional.empty(), Optional.empty())); 83 | Utils.sleep(500); 84 | }); 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /src/test/java/com/github/sergueik/selenium/PageDownloadCdpTest.java: -------------------------------------------------------------------------------- 1 | package com.github.sergueik.selenium; 2 | 3 | import static org.hamcrest.CoreMatchers.is; 4 | import static org.hamcrest.CoreMatchers.notNullValue; 5 | import static org.hamcrest.MatcherAssert.assertThat; 6 | 7 | import java.io.File; 8 | import java.io.IOException; 9 | import java.nio.file.FileSystems; 10 | import java.nio.file.Files; 11 | import java.nio.file.Path; 12 | import java.nio.file.Paths; 13 | import java.util.HashMap; 14 | import java.util.Map; 15 | 16 | import org.junit.After; 17 | import org.junit.Test; 18 | import org.openqa.selenium.WebDriverException; 19 | 20 | import com.google.gson.Gson; 21 | 22 | /** 23 | * Selected test scenarios for Selenium 4 Chrome Developer Tools bridge inspired 24 | * https://chromedevtools.github.io/devtools-protocol/tot/Page/#method-setDownloadBehavior 25 | * 26 | * @author: Serguei Kouzmine (kouzmine_serguei@yahoo.com) 27 | */ 28 | public class PageDownloadCdpTest extends BaseCdpTest { 29 | 30 | // NOTE: not using "http://www.africau.edu/images/default/sample.pdf" 31 | // because of the already provided 32 | // "browser.helperApps.neverAsk.saveToDisk" argument 33 | // including "application/pdf" 34 | private final static String url = "https://scholar.harvard.edu/files/torman_personal/files/samplepptx.pptx"; 35 | private final static String filename = url.replaceAll("^.*/", ""); 36 | private static String downloadPath = null; 37 | 38 | private static String command = "Page.setDownloadBehavior"; 39 | private static Map result = new HashMap<>(); 40 | private static Map params = new HashMap<>(); 41 | private static Gson gson = new Gson(); 42 | 43 | @After 44 | public void after() { 45 | // Arrange 46 | params = new HashMap<>(); 47 | params.put("behavior", "default"); 48 | result = driver.executeCdpCommand(command, params); 49 | assertThat(result, notNullValue()); 50 | driver.get("about:blank"); 51 | } 52 | 53 | @Test 54 | public void test() { 55 | downloadPath = createTempDownloadDir(); 56 | // Arrange 57 | params = new HashMap<>(); 58 | params.put("behavior", "allow"); 59 | // NOTE: the "allowAndName" is not available in Page domain 60 | params.put("downloadPath", downloadPath); 61 | System.err.println(String.format("Sent command: %s with params %s", 62 | command, gson.toJson(params))); 63 | result = driver.executeCdpCommand(command, params); 64 | 65 | assertThat(result, notNullValue()); 66 | try { 67 | // Act 68 | driver.get(url); 69 | Utils.sleep(3000); 70 | assertThat(new File( 71 | Paths.get(downloadPath).resolve(filename).toAbsolutePath().toString()) 72 | .exists(), 73 | is(true)); 74 | System.err.println(String.format("Verified downloaded file: %s in %s", 75 | filename, downloadPath)); 76 | // remove the file 77 | new File( 78 | Paths.get(downloadPath).resolve(filename).toAbsolutePath().toString()) 79 | .delete(); 80 | } catch (WebDriverException e) { 81 | System.err.println("Web Driver exception in " + command + " (ignored): " 82 | + Utils.processExceptionMessage(e.getMessage())); 83 | } catch (Exception e) { 84 | System.err.println("Exception in " + command + " " + e.toString()); 85 | throw (new RuntimeException(e)); 86 | } 87 | } 88 | 89 | // http://www.java2s.com/example/java-utility-method/temp-directory-get/gettempdir-466ee.html 90 | public static String getTempDownloadDir() { 91 | String tmpdir = System.getProperty("java.io.tmpdir"); 92 | return (tmpdir != null && new File(tmpdir).exists()) ? tmpdir 93 | : Paths.get(System.getProperty("user.home")).resolve("Downloads") 94 | .toAbsolutePath().toString(); 95 | } 96 | 97 | // http://www.java2s.com/Code/Java/JDK-7/Createtempfileanddirectory.htm 98 | public static String createTempDownloadDir() { 99 | 100 | String tempDownloadDirPath = null; 101 | 102 | try { 103 | Path tempDirectory = Files.createTempDirectory( 104 | FileSystems.getDefault().getPath(getTempDownloadDir()), ""); 105 | System.err.println("Temporary Download directory created"); 106 | tempDownloadDirPath = tempDirectory.toString(); 107 | } catch (IOException e) { 108 | throw new RuntimeException(e); 109 | } 110 | return tempDownloadDirPath; 111 | 112 | } 113 | 114 | } 115 | -------------------------------------------------------------------------------- /src/test/java/com/github/sergueik/selenium/PageNavigationHistoryCDPTest.java: -------------------------------------------------------------------------------- 1 | package com.github.sergueik.selenium; 2 | /** 3 | * Copyright 2022-2024 Serguei Kouzmine 4 | */ 5 | 6 | import static org.hamcrest.CoreMatchers.is; 7 | import static org.hamcrest.CoreMatchers.notNullValue; 8 | import static org.hamcrest.MatcherAssert.assertThat; 9 | import static org.hamcrest.Matchers.greaterThan; 10 | 11 | import java.util.ArrayList; 12 | import java.util.Arrays; 13 | import java.util.Collections; 14 | import java.util.HashMap; 15 | import java.util.List; 16 | import java.util.Map; 17 | 18 | import org.junit.After; 19 | import org.junit.Before; 20 | import org.junit.Test; 21 | import org.openqa.selenium.By; 22 | import org.openqa.selenium.WebElement; 23 | import org.openqa.selenium.support.ui.ExpectedConditions; 24 | 25 | import com.google.gson.Gson; 26 | 27 | /** 28 | * Selected test scenarios for Selenium 4 Chrome Developer Tools bridge 29 | * https://chromedevtools.github.io/devtools-protocol/tot/Page/#method-getNavigationHistory 30 | * https://chromedevtools.github.io/devtools-protocol/tot/Page/#method-resetNavigationHistory 31 | * https://chromedevtools.github.io/devtools-protocol/tot/Page/#method-navigateToHistoryEntry 32 | * @author: Serguei Kouzmine (kouzmine_serguei@yahoo.com) 33 | */ 34 | @SuppressWarnings("unchecked") 35 | public class PageNavigationHistoryCDPTest extends BaseCdpTest { 36 | 37 | private static String command = null; 38 | private static Map result = new HashMap<>(); 39 | private static Map params = new HashMap<>(); 40 | private List urls = new ArrayList<>(); 41 | private static Gson gson = new Gson(); 42 | private final String cssSelector = "#ca-nstab-main > a"; 43 | private WebElement element; 44 | 45 | @Before 46 | public void before() { 47 | // Arrange 48 | urls.addAll(Arrays.asList(new String[] { "https://fr.wikipedia.org/wiki", 49 | "https://de.wikipedia.org/wiki", "https://es.wikipedia.org/wiki", 50 | "https://it.wikipedia.org/wiki", "https://ar.wikipedia.org/wiki", 51 | "https://en.wikipedia.org/wiki", "https://fi.wikipedia.org/wiki", 52 | "https://hu.wikipedia.org/wiki", "https://da.wikipedia.org/wiki", 53 | "https://pt.wikipedia.org/wiki" })); 54 | Collections.shuffle(urls); 55 | urls.forEach(url -> driver.get(url)); 56 | 57 | } 58 | 59 | @After 60 | public void after() { 61 | // Arrange 62 | command = "Page.resetNavigationHistory"; 63 | driver.executeCdpCommand(command, new HashMap<>()); 64 | driver.get("about:blank"); 65 | } 66 | 67 | @Test 68 | public void test1() { 69 | // Act 70 | command = "Page.getNavigationHistory"; 71 | result = driver.executeCdpCommand(command, new HashMap<>()); 72 | // Assert 73 | assertThat(result, notNullValue()); 74 | System.err.println( 75 | command + " result keys: " + new ArrayList(result.keySet())); 76 | for (String key : Arrays.asList("currentIndex", "entries")) { 77 | assertThat(result.containsKey(key), is(true)); 78 | } 79 | assertThat(result.get("entries") instanceof List, is(true)); 80 | final int size = ((List) result.get("entries")).size(); 81 | assertThat(size, greaterThan(1)); 82 | System.err.println("History entries size: " + size); 83 | // NOTE: index 0 will be special: 84 | // History entry : 85 | // {"id":2,"url":"data:,","userTypedURL":"data:,","title":"","transitionType":"AUTO_TOPLEVEL"} 86 | 87 | Object result2 = ((List) result.get("entries")).get(1); 88 | assertThat(result2 instanceof Map, is(true)); 89 | for (String key : Arrays.asList("id", "url", "title", "userTypedURL", 90 | "transitionType")) { 91 | assertThat(((Map) result2).containsKey(key), is(true)); 92 | } 93 | System.err.println("History entry : " + gson.toJson(result2)); 94 | } 95 | 96 | @Test 97 | public void test2() { 98 | // Act 99 | command = "Page.getNavigationHistory"; 100 | result = driver.executeCdpCommand(command, new HashMap<>()); 101 | // Assert 102 | ((List) result.get("entries")).stream().forEach(o -> { 103 | Map entry = (Map) o; 104 | if (entry.get("url").toString().indexOf("https://en.wikipedia.org/wiki", 105 | 0) == 0) { 106 | // https://stackoverflow.com/questions/4355303/how-can-i-convert-a-long-to-int-in-java 107 | final int entryId = Math 108 | .toIntExact(Long.parseLong(entry.get("id").toString())); 109 | command = "Page.navigateToHistoryEntry"; 110 | params.clear(); 111 | params.put("entryId", entryId); 112 | result = driver.executeCdpCommand(command, params); 113 | 114 | } 115 | }); 116 | 117 | element = wait.until(ExpectedConditions 118 | .visibilityOfElementLocated(By.cssSelector(cssSelector))); 119 | assertThat(element.getText(), is("Main Page")); 120 | Utils.highlight(element); 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /src/test/java/com/github/sergueik/selenium/PageNavigationHistoryDevToolsTest.java: -------------------------------------------------------------------------------- 1 | package com.github.sergueik.selenium; 2 | /** 3 | * Copyright 2022-2024 Serguei Kouzmine 4 | */ 5 | 6 | import static org.hamcrest.CoreMatchers.is; 7 | import static org.hamcrest.CoreMatchers.notNullValue; 8 | import static org.hamcrest.MatcherAssert.assertThat; 9 | import static org.hamcrest.Matchers.greaterThan; 10 | 11 | import java.time.Duration; 12 | import java.util.ArrayList; 13 | import java.util.Arrays; 14 | import java.util.Collections; 15 | import java.util.List; 16 | 17 | import org.junit.After; 18 | import org.junit.Before; 19 | import org.junit.Test; 20 | import org.openqa.selenium.By; 21 | import org.openqa.selenium.TimeoutException; 22 | import org.openqa.selenium.WebElement; 23 | import org.openqa.selenium.devtools.v127.page.Page; 24 | import org.openqa.selenium.devtools.v127.page.model.NavigationEntry; 25 | import org.openqa.selenium.devtools.v127.page.model.TransitionType; 26 | import org.openqa.selenium.support.ui.ExpectedConditions; 27 | import org.openqa.selenium.support.ui.WebDriverWait; 28 | 29 | import com.google.gson.Gson; 30 | 31 | /** 32 | * Selected test scenarios for Selenium 4 Chrome Developer Tools bridge 33 | * https://chromedevtools.github.io/devtools-protocol/tot/Page/#method-getNavigationHistory 34 | * https://chromedevtools.github.io/devtools-protocol/tot/Page/#method-resetNavigationHistory 35 | * https://chromedevtools.github.io/devtools-protocol/tot/Page/#method-navigateToHistoryEntry 36 | * @author: Serguei Kouzmine (kouzmine_serguei@yahoo.com) 37 | */ 38 | public class PageNavigationHistoryDevToolsTest extends BaseDevToolsTest { 39 | 40 | private List urls = new ArrayList<>(); 41 | private static Gson gson = new Gson(); 42 | private static WebDriverWait wait; 43 | private static int flexibleWait = 60; 44 | private static int pollingInterval = 500; 45 | private final String cssSelector = "#ca-nstab-main > a"; 46 | private WebElement element; 47 | 48 | @Before 49 | public void before() { 50 | // Arrange 51 | urls.addAll(Arrays.asList(new String[] { "https://fr.wikipedia.org/wiki", 52 | "https://de.wikipedia.org/wiki", "https://es.wikipedia.org/wiki", 53 | "https://it.wikipedia.org/wiki", "https://ar.wikipedia.org/wiki", 54 | "https://en.wikipedia.org/wiki", "https://fi.wikipedia.org/wiki", 55 | "https://hu.wikipedia.org/wiki", "https://da.wikipedia.org/wiki", 56 | "https://pt.wikipedia.org/wiki" })); 57 | Collections.shuffle(urls); 58 | urls.forEach(url -> driver.get(url)); 59 | 60 | } 61 | 62 | @After 63 | public void after() { 64 | chromeDevTools.send(Page.resetNavigationHistory()); 65 | } 66 | 67 | @Test 68 | public void test1() { 69 | // Act 70 | Page.GetNavigationHistoryResponse result = chromeDevTools 71 | .send(Page.getNavigationHistory()); 72 | // Assert 73 | assertThat(result, notNullValue()); 74 | assertThat(result.getCurrentIndex(), greaterThan(0)); 75 | System.err.println(String.format("currend index: %d, url: %s", 76 | result.getCurrentIndex(), driver.getCurrentUrl())); 77 | assertThat(result.getEntries() instanceof List, is(true)); 78 | List navigationEntries = result.getEntries(); 79 | System.err.println("History entries size: " + navigationEntries.size()); 80 | // NOTE: index 0 will be special: 81 | // History entry : 82 | // {"id":2,"url":"data:,","userTypedURL":"data:,","title":"","transitionType":"AUTO_TOPLEVEL"} 83 | NavigationEntry navigationEntry = navigationEntries.get(1); 84 | 85 | // Assert 86 | assertThat(navigationEntry.getId(), notNullValue()); 87 | assertThat(navigationEntry.getUrl(), notNullValue()); 88 | assertThat(navigationEntry.getUserTypedURL(), notNullValue()); 89 | assertThat(navigationEntry.getTitle(), notNullValue()); 90 | assertThat(navigationEntry.getTransitionType() instanceof TransitionType, 91 | is(true)); 92 | System.err.print("History entry : " + gson.toJson(navigationEntry)); 93 | } 94 | 95 | @Test 96 | public void test2() { 97 | // Act 98 | Page.GetNavigationHistoryResponse result = chromeDevTools 99 | .send(Page.getNavigationHistory()); 100 | List navigationEntries = result.getEntries(); 101 | 102 | // Act 103 | navigationEntries.stream().forEach((NavigationEntry o) -> { 104 | if (o.getUrl().indexOf("https://en.wikipedia.org/wiki", 0) == 0) { 105 | final int entryId = o.getId(); 106 | System.err.println( 107 | String.format("Navigate to id: %d url: %s", entryId, o.getUrl())); 108 | try { 109 | chromeDevTools.send(Page.navigateToHistoryEntry(entryId)); 110 | Utils.sleep(250); 111 | } catch (TimeoutException e) { 112 | System.err.println("Exception (ignored): " + e.toString()); 113 | } 114 | } 115 | }); 116 | 117 | wait = new WebDriverWait(driver, Duration.ofSeconds(flexibleWait)); 118 | wait.pollingEvery(Duration.ofMillis(pollingInterval)); 119 | element = wait.until(ExpectedConditions 120 | .visibilityOfElementLocated(By.cssSelector(cssSelector))); 121 | assertThat(element.getText(), is("Main Page")); 122 | Utils.highlight(element); 123 | 124 | } 125 | } 126 | -------------------------------------------------------------------------------- /src/test/java/com/github/sergueik/selenium/PageScaleFactorCdpTest.java: -------------------------------------------------------------------------------- 1 | package com.github.sergueik.selenium; 2 | 3 | /** 4 | * Copyright 2022,2024 Serguei Kouzmine 5 | */ 6 | 7 | 8 | import static java.lang.System.err; 9 | 10 | import java.util.Arrays; 11 | import java.util.HashMap; 12 | import java.util.Map; 13 | 14 | import org.junit.After; 15 | import org.junit.Test; 16 | import org.openqa.selenium.WebDriverException; 17 | 18 | /** 19 | * Selected test scenarios for Selenium 4 Chrome Developer Tools bridge 20 | * https://chromedevtools.github.io/devtools-protocol/tot/Emulation/#method-resetPageScaleFactor 21 | * https://chromedevtools.github.io/devtools-protocol/tot/Emulation/#method-setPageScaleFactor 22 | * 23 | * @author: Serguei Kouzmine (kouzmine_serguei@yahoo.com) 24 | */ 25 | 26 | public class PageScaleFactorCdpTest extends BaseCdpTest { 27 | 28 | private static String command = "Browser.setDownloadBehavior"; 29 | private static Map params = new HashMap<>(); 30 | 31 | @Test 32 | // based on: 33 | // see also: 34 | // https://github.com/sahajamit/chrome-devtools-webdriver-integration/blob/master/src/test/java/com/sahajamit/DemoTests.java 35 | // https://github.com/sahajamit/chrome-devtools-webdriver-integration/blob/master/src/main/java/com/sahajamit/messaging/MessageBuilder.java 36 | public void test() { 37 | 38 | // Arrange 39 | baseURL = "https://www.wikipedia.org"; 40 | driver.get(baseURL); 41 | 42 | command = "Emulation.resetPageScaleFactor"; 43 | 44 | try { 45 | // Act 46 | driver.executeCdpCommand(command, new HashMap<>()); 47 | // returns empty JSON 48 | Utils.sleep(1000); 49 | 50 | command = "Emulation.setPageScaleFactor"; 51 | // Act 52 | params.clear(); 53 | for (float scale : Arrays 54 | .asList(new Float[] { (float) 1.25, (float) 1.5, (float) 2 })) { 55 | 56 | params.put("pageScaleFactor", scale); 57 | driver.executeCdpCommand(command, params); 58 | Utils.sleep(1000); 59 | } 60 | 61 | // Act 62 | params.clear(); 63 | params.put("pageScaleFactor", 1); 64 | driver.executeCdpCommand(command, params); 65 | Utils.sleep(1000); 66 | } catch (WebDriverException e) { 67 | err.println("Exception in command " + command + " (ignored): " 68 | + Utils.processExceptionMessage(e.getMessage())); 69 | } catch (Exception e) { 70 | err.println("Exception: in " + command + " " + e.toString()); 71 | throw (new RuntimeException(e)); 72 | } 73 | } 74 | 75 | @After 76 | public void after() { 77 | command = "Emulation.resetPageScaleFactor"; 78 | try { 79 | // Act 80 | driver.executeCdpCommand(command, new HashMap<>()); 81 | // returns empty JSON 82 | } catch (Exception e) { 83 | err.println("Exception: in " + command + " (ignored): " + e.toString()); 84 | } 85 | } 86 | 87 | } 88 | -------------------------------------------------------------------------------- /src/test/java/com/github/sergueik/selenium/PageScaleFactorDevToolsTest.java: -------------------------------------------------------------------------------- 1 | package com.github.sergueik.selenium; 2 | 3 | import java.util.Arrays; 4 | 5 | import org.junit.After; 6 | import org.junit.Before; 7 | import org.junit.Test; 8 | import org.openqa.selenium.devtools.v127.emulation.Emulation; 9 | 10 | /** 11 | * Selected test scenarios for Selenium 4 Chrome Developer Tools bridge 12 | * 13 | * https://chromedevtools.github.io/devtools-protocol/tot/Emulation/#method-resetPageScaleFactor 14 | * https://chromedevtools.github.io/devtools-protocol/tot/Emulation/#method-setPageScaleFactor 15 | * @author: Serguei Kouzmine (kouzmine_serguei@yahoo.com) 16 | */ 17 | // https://www.logicalincrements.com/articles/resolution 18 | 19 | public class PageScaleFactorDevToolsTest extends BaseDevToolsTest { 20 | 21 | private final static String baseURL = "http://www.wikipedia.org"; 22 | 23 | @After 24 | public void afterTest() { 25 | chromeDevTools.send(Emulation.resetPageScaleFactor()); 26 | } 27 | 28 | @Before 29 | public void beforeTest() { 30 | driver.get(baseURL); 31 | } 32 | 33 | @Test 34 | public void test() { 35 | for (float scale : Arrays 36 | .asList(new Float[] { (float) 1.25, (float) 1.5, (float) 2 })) { 37 | chromeDevTools.send(Emulation.setPageScaleFactor(scale)); 38 | Utils.sleep(1000); 39 | } 40 | 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /src/test/java/com/github/sergueik/selenium/PageSourceCdpTest.java: -------------------------------------------------------------------------------- 1 | package com.github.sergueik.selenium; 2 | 3 | /** 4 | * Copyright 2022,2024 Serguei Kouzmine 5 | */ 6 | 7 | 8 | import static java.lang.System.err; 9 | 10 | import java.util.Arrays; 11 | import java.util.HashMap; 12 | import java.util.Map; 13 | 14 | import org.junit.After; 15 | import org.junit.Before; 16 | import org.junit.Test; 17 | import org.openqa.selenium.WebDriverException; 18 | 19 | /** 20 | * Selected test scenarios for Selenium 4 Chrome Developer Tools bridge 21 | * https://chromedevtools.github.io/devtools-protocol/tot/DOM/#method-enable 22 | * https://chromedevtools.github.io/devtools-protocol/tot/DOM/#method-getDocument 23 | * https://chromedevtools.github.io/devtools-protocol/tot/DOM/#method-getOuterHTML 24 | * https://chromedevtools.github.io/devtools-protocol/tot/DOM/#method-disable 25 | * @author: Serguei Kouzmine (kouzmine_serguei@yahoo.com) 26 | */ 27 | 28 | // https://github.com/estromenko/driverless-selenium/blob/init-project/driverless_selenium/webdriver.py#L183 29 | @SuppressWarnings("unchecked") 30 | public class PageSourceCdpTest extends BaseCdpTest { 31 | 32 | private static String command = "Browser.setDownloadBehavior"; 33 | private static Map result = new HashMap<>(); 34 | private static Map params = new HashMap<>(); 35 | 36 | @Before 37 | public void before() { 38 | command = "DOM.enable"; 39 | driver.executeCdpCommand(command, new HashMap<>()); 40 | } 41 | 42 | 43 | @Test 44 | public void test1() { 45 | 46 | // Arrange 47 | String url = "http://www.wikipedia.org"; 48 | driver.get(url); 49 | command = "DOM.getDocument"; 50 | params = new HashMap<>(); 51 | params.put("pierce", false); 52 | params.put("depth", 1); 53 | result = driver.executeCdpCommand(command, params); 54 | Long nodeId = Long.parseLong( 55 | ((Map) result.get("root")).get("nodeId").toString()); 56 | command = "DOM.getOuterHTML"; 57 | params.clear(); 58 | params.put("nodeId", nodeId); 59 | // Act 60 | result = driver.executeCdpCommand(command, params); 61 | String pageSource = (String) result.get("outerHTML"); 62 | System.err.println("page source: " + pageSource); 63 | } 64 | 65 | @Test 66 | public void test2() { 67 | 68 | // Arrange 69 | String page = "call_ajax.html"; 70 | driver.get(Utils.getPageContent(page)); 71 | command = "DOM.getDocument"; 72 | params = new HashMap<>(); 73 | params.put("pierce", false); 74 | params.put("depth", 1); 75 | result = driver.executeCdpCommand(command, params); 76 | Long nodeId = Long.parseLong( 77 | ((Map) result.get("root")).get("nodeId").toString()); 78 | command = "DOM.getOuterHTML"; 79 | params.clear(); 80 | params.put("nodeId", nodeId); 81 | // Act 82 | result = driver.executeCdpCommand(command, params); 83 | String pageSource = (String) result.get("outerHTML"); 84 | System.err.println("page source: " + pageSource); 85 | } 86 | 87 | @After 88 | public void after() { 89 | command = "DOM.disable"; 90 | try { 91 | // Act 92 | driver.executeCdpCommand(command, new HashMap<>()); 93 | } catch (Exception e) { 94 | err.println("Exception: in " + command + " (ignored): " + e.toString()); 95 | } 96 | } 97 | 98 | } 99 | -------------------------------------------------------------------------------- /src/test/java/com/github/sergueik/selenium/PageSourceDevToolsTest.java: -------------------------------------------------------------------------------- 1 | package com.github.sergueik.selenium; 2 | 3 | /** 4 | * Copyright 2022,2024 Serguei Kouzmine 5 | */ 6 | 7 | 8 | import java.util.Arrays; 9 | import java.util.Optional; 10 | 11 | import org.junit.After; 12 | import org.junit.Before; 13 | import org.junit.Test; 14 | import org.openqa.selenium.devtools.v127.dom.DOM; 15 | import org.openqa.selenium.devtools.v127.dom.model.Node; 16 | 17 | /** 18 | * Selected test scenarios for Selenium 4 Chrome Developer Tools bridge 19 | * https://chromedevtools.github.io/devtools-protocol/tot/DOM/#method-enable 20 | * https://chromedevtools.github.io/devtools-protocol/tot/DOM/#method-getDocument 21 | * https://chromedevtools.github.io/devtools-protocol/tot/DOM/#method-getOuterHTML 22 | * https://chromedevtools.github.io/devtools-protocol/tot/DOM/#method-disable 23 | * @author: Serguei Kouzmine (kouzmine_serguei@yahoo.com) 24 | */ 25 | 26 | // https://github.com/estromenko/driverless-selenium/blob/init-project/driverless_selenium/webdriver.py#L183 27 | // see also: https://codepedia.info/angularjs-call-ajax-function-on-page-load 28 | // https://angular.io/tutorial/tour-of-heroes/toh-pt6 29 | 30 | public class PageSourceDevToolsTest extends BaseDevToolsTest { 31 | 32 | private String url = null; 33 | 34 | @Before 35 | public void before() { 36 | chromeDevTools 37 | .send(DOM.enable(Optional.of(DOM.EnableIncludeWhitespace.ALL))); 38 | 39 | } 40 | 41 | @After 42 | public void after() { 43 | chromeDevTools.send(DOM.disable()); 44 | } 45 | 46 | @Test 47 | public void test1() { 48 | url = "http://www.wikipedia.org"; 49 | driver.get(url); 50 | Node result = chromeDevTools 51 | .send(DOM.getDocument(Optional.of(1), Optional.of(false))); 52 | String pageSource = chromeDevTools.send(DOM.getOuterHTML( 53 | Optional.of(result.getNodeId()), Optional.empty(), Optional.empty())); 54 | System.err.println("page source: " + pageSource); 55 | } 56 | 57 | @Test 58 | public void test2() { 59 | // Arrange 60 | String page = "call_ajax.html"; 61 | driver.get(Utils.getPageContent(page)); 62 | Node result = chromeDevTools 63 | .send(DOM.getDocument(Optional.of(1), Optional.of(false))); 64 | String pageSource = chromeDevTools.send(DOM.getOuterHTML( 65 | Optional.of(result.getNodeId()), Optional.empty(), Optional.empty())); 66 | System.err.println("page source: " + pageSource); 67 | } 68 | 69 | } 70 | -------------------------------------------------------------------------------- /src/test/java/com/github/sergueik/selenium/PerformanceMetricDevToolsTest.java: -------------------------------------------------------------------------------- 1 | package com.github.sergueik.selenium; 2 | 3 | /** 4 | * Copyright 2023,2024 Serguei Kouzmine 5 | */ 6 | 7 | 8 | import static org.hamcrest.CoreMatchers.is; 9 | import static org.hamcrest.CoreMatchers.notNullValue; 10 | import static org.hamcrest.MatcherAssert.assertThat; 11 | import static org.hamcrest.Matchers.containsInAnyOrder; 12 | import static org.hamcrest.Matchers.greaterThan; 13 | 14 | import java.util.Arrays; 15 | import java.util.HashSet; 16 | import java.util.List; 17 | import java.util.Optional; 18 | import java.util.stream.Collectors; 19 | 20 | import org.apache.commons.collections4.CollectionUtils; 21 | import org.junit.After; 22 | import org.junit.Before; 23 | import org.junit.Test; 24 | import org.openqa.selenium.devtools.v127.performance.Performance; 25 | import org.openqa.selenium.devtools.v127.performance.model.Metric; 26 | 27 | 28 | /** 29 | * Selected test scenarios for Selenium Chrome Developer Tools Selenium 4 bridge 30 | * see: 31 | * https://developer.mozilla.org/en-US/docs/Web/API/PerformanceNavigationTiming 32 | * @author: Serguei Kouzmine (kouzmine_serguei@yahoo.com) 33 | */ 34 | 35 | public class PerformanceMetricDevToolsTest extends BaseDevToolsTest { 36 | 37 | private static List metrics; 38 | private static HashSet metricKeys = new HashSet<>(); 39 | private static String[] standardKeys = { "AdSubframes", "ArrayBufferContents", 40 | "AudioHandlers", "ContextLifecycleStateObservers", "DetachedScriptStates", 41 | "DevToolsCommandDuration", "Documents", "DomContentLoaded", 42 | "FirstMeaningfulPaint", "Frames", "JSEventListeners", "JSHeapTotalSize", 43 | "JSHeapUsedSize", "LayoutCount", "LayoutDuration", "LayoutObjects", 44 | "MediaKeySessions", "MediaKeys", "NavigationStart", "Nodes", 45 | "ProcessTime", "RTCPeerConnections", "RecalcStyleCount", 46 | "RecalcStyleDuration", "ResourceFetchers", "Resources", "ScriptDuration", 47 | "TaskDuration", "TaskOtherDuration", "ThreadTime", "Timestamp", 48 | "UACSSResources", "V8CompileDuration", "V8PerContextDatas", 49 | "WorkerGlobalScopes" }; 50 | private static String baseURL = "https://developer.mozilla.org/en-US/docs/Web/API/PerformanceNavigationTiming"; 51 | 52 | @Before 53 | public void before() throws Exception { 54 | // Arrange 55 | chromeDevTools.send(Performance.enable(Optional.empty())); 56 | } 57 | 58 | @Test 59 | public void test1() { 60 | // Arrange 61 | driver.get(baseURL); 62 | 63 | // Act 64 | metrics = chromeDevTools.send(Performance.getMetrics()); 65 | // Assert 66 | assertThat(metrics, notNullValue()); 67 | assertThat(metrics.size(), greaterThan(0)); 68 | metrics.stream().map((Metric metric) -> String.format("%s: %s", 69 | metric.getName(), metric.getValue())).forEach(System.err::println); 70 | metrics 71 | .forEach((Metric metric) -> metricKeys.add((Object) metric.getName())); 72 | assertThat("Checking performance metrics", metricKeys, 73 | containsInAnyOrder((Object[]) standardKeys)); 74 | 75 | } 76 | 77 | // slightly alternative key set validation 78 | // origin: 79 | // https://github.com/fugazi/carbonfour-selenium-4/blob/main/src/test/java/Selenium_4_Tests/TestDevToolsPerformance.java 80 | @Test 81 | public void test2() { 82 | // Arrange 83 | driver.get(baseURL); 84 | 85 | metrics = chromeDevTools.send(Performance.getMetrics()); 86 | // Assert 87 | assertThat(metrics, notNullValue()); 88 | // Act 89 | List metricNames = metrics.stream().map(Metric::getName) 90 | .collect(Collectors.toList()); 91 | System.err.println("MetricNames: " + metricNames); 92 | List keyMetrics = Arrays.asList("Timestamp", "Documents", "Frames", 93 | "JSEventListeners", "Nodes", "LayoutCount", "RecalcStyleCount", 94 | "RecalcStyleDuration", "LayoutDuration", "MediaKeySessions", 95 | "Resources", "DomContentLoaded", "NavigationStart", "TaskDuration", 96 | "JSHeapUsedSize", "JSHeapTotalSize", "ScriptDuration"); 97 | keyMetrics.forEach(metric -> System.err.println("Metric: " + metric + "\n" 98 | + metrics.get(metricNames.indexOf(metric)).getValue())); 99 | // NOTE: hamcrest does not have "containsAll" 100 | String[] keyMetricsArray = new String[keyMetrics.size()]; 101 | keyMetrics.toArray(keyMetricsArray); 102 | assertThat(CollectionUtils.containsAny(metricNames, keyMetrics), is(true)); 103 | // does not validate in the "correct" order - commented 104 | // assertThat("Checking key performance metrics", metricNames, 105 | // containsInAnyOrder(keyMetricsArray)); 106 | 107 | } 108 | 109 | // TODO: 110 | // https://github.com/fugazi/carbonfour-selenium-4/blob/main/src/test/java/Selenium_4_Tests/TestLoginRelativeLocators.java 111 | @After 112 | // Disables performance tracking 113 | public void afterTest() throws Exception { 114 | chromeDevTools.send(Performance.disable()); 115 | } 116 | 117 | } 118 | -------------------------------------------------------------------------------- /src/test/java/com/github/sergueik/selenium/PerformanceMetricsCdpTest.java: -------------------------------------------------------------------------------- 1 | package com.github.sergueik.selenium; 2 | 3 | /** 4 | * Copyright 2023,2024 Serguei Kouzmine 5 | */ 6 | 7 | 8 | import static java.lang.System.err; 9 | import static org.hamcrest.CoreMatchers.notNullValue; 10 | import static org.hamcrest.MatcherAssert.assertThat; 11 | import static org.hamcrest.Matchers.containsInAnyOrder; 12 | import static org.hamcrest.Matchers.greaterThan; 13 | import static org.hamcrest.Matchers.hasKey; 14 | 15 | import java.util.ArrayList; 16 | import java.util.HashMap; 17 | import java.util.HashSet; 18 | import java.util.List; 19 | import java.util.Map; 20 | 21 | import org.junit.Test; 22 | import org.openqa.selenium.WebDriverException; 23 | 24 | /** 25 | * Selected test scenarios for Selenium 4 Chrome Developer Tools bridge 26 | * https://chromedevtools.github.io/devtools-protocol/tot/Performance#method-setTimeDomain 27 | * https://chromedevtools.github.io/devtools-protocol/tot/Performance#method-enable 28 | * https://chromedevtools.github.io/devtools-protocol/tot/Performance#method-getMetrics 29 | * https://chromedevtools.github.io/devtools-protocol/tot/Performance/#type-Metric 30 | * 31 | * @author: Serguei Kouzmine (kouzmine_serguei@yahoo.com) 32 | */ 33 | 34 | public class PerformanceMetricsCdpTest extends BaseCdpTest { 35 | 36 | private static String command = null; 37 | private static Map result = new HashMap<>(); 38 | private static Map params = new HashMap<>(); 39 | private static List metrics = new ArrayList<>(); 40 | private static HashSet metricKeys = new HashSet<>(); 41 | 42 | private static String[] standardKeys = { "AdSubframes", "ArrayBufferContents", 43 | "AudioHandlers", "ContextLifecycleStateObservers", "DetachedScriptStates", 44 | "DevToolsCommandDuration", "Documents", "DomContentLoaded", 45 | "FirstMeaningfulPaint", "Frames", "JSEventListeners", "JSHeapTotalSize", 46 | "JSHeapUsedSize", "LayoutCount", "LayoutDuration", "LayoutObjects", 47 | "MediaKeySessions", "MediaKeys", "NavigationStart", "Nodes", 48 | "ProcessTime", "RTCPeerConnections", "RecalcStyleCount", 49 | "RecalcStyleDuration", "ResourceFetchers", "Resources", "ScriptDuration", 50 | "TaskDuration", "TaskOtherDuration", "ThreadTime", "Timestamp", 51 | "UACSSResources", "V8CompileDuration", "V8PerContextDatas", 52 | "WorkerGlobalScopes" }; 53 | 54 | @SuppressWarnings("unchecked") 55 | @Test 56 | // based on: 57 | // https://github.com/SrinivasanTarget/selenium4CDPsamples/blob/master/src/test/java/DevToolsTest.java 58 | // see also: 59 | // https://github.com/ShamaUgale/Selenium4Examples/blob/master/src/main/java/com/devtools/GetMetrics.java 60 | public void getPerformanceMetricsTest() { 61 | command = "Performance.setTimeDomain"; 62 | params.put("timeDomain", "timeTicks"); 63 | try { 64 | driver.executeCdpCommand(command, params); 65 | // Act 66 | command = "Performance.enable"; 67 | driver.executeCdpCommand(command, new HashMap<>()); 68 | baseURL = "https://developer.mozilla.org/en-US/docs/Web/API/PerformancePaintTiming"; 69 | driver.get(baseURL); 70 | // Act 71 | command = "Performance.getMetrics"; 72 | result = driver.executeCdpCommand(command, new HashMap<>()); 73 | // Assert 74 | assertThat(result, notNullValue()); 75 | assertThat(result, hasKey("metrics")); 76 | metrics = (List) result.get("metrics"); 77 | assertThat(metrics, notNullValue()); 78 | assertThat(metrics.size(), greaterThan(0)); 79 | System.err.println("Metric dimension: " + metrics.size()); 80 | for (int cnt = 0; cnt != metrics.size(); cnt++) { 81 | Object metricEntry = metrics.get(cnt); 82 | assertThat(metricEntry, notNullValue()); 83 | Map metricData = (Map) metricEntry; 84 | assertThat(metricData, hasKey("name")); 85 | assertThat(metricData, hasKey("value")); 86 | System.err.println(String.format("%s: %s", metricData.get("name"), 87 | metricData.get("value"))); 88 | metricKeys.add((Object) metricData.get("name")); 89 | } 90 | assertThat("Checking performance metrics", metricKeys, 91 | containsInAnyOrder((Object[]) standardKeys)); 92 | 93 | // Act 94 | command = "Performance.disable"; 95 | driver.executeCdpCommand(command, new HashMap<>()); 96 | } catch (WebDriverException e) { 97 | err.println("Exception in command " + command + " (ignored): " 98 | + Utils.processExceptionMessage(e.getMessage())); 99 | } catch (Exception e) { 100 | err.println("Exception: in " + command + " " + e.toString()); 101 | throw (new RuntimeException(e)); 102 | } 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /src/test/java/com/github/sergueik/selenium/PierceCdpTest.java: -------------------------------------------------------------------------------- 1 | package com.github.sergueik.selenium; 2 | 3 | /** 4 | * Copyright 2023,2024 Serguei Kouzmine 5 | */ 6 | 7 | 8 | import static org.hamcrest.MatcherAssert.assertThat; 9 | import static org.hamcrest.Matchers.hasKey; 10 | 11 | import java.io.File; 12 | import java.io.FileOutputStream; 13 | import java.io.OutputStreamWriter; 14 | import java.io.Writer; 15 | import java.util.HashMap; 16 | import java.util.Map; 17 | 18 | import org.junit.After; 19 | import org.junit.Before; 20 | import org.junit.Test; 21 | import org.openqa.selenium.WebDriverException; 22 | 23 | import com.google.gson.Gson; 24 | import com.google.gson.JsonSyntaxException; 25 | 26 | /** 27 | * Selected test scenarios for Selenium 4 Chrome Developer Tools bridge 28 | * https://chromedevtools.github.io/devtools-protocol/tot/DOM/#method-getDocument 29 | * https://chromedevtools.github.io/devtools-protocol/tot/DOM/#method-querySelectorAll 30 | * https://chromedevtools.github.io/devtools-protocol/tot/DOM/#method-describeNode 31 | * https://chromedevtools.github.io/devtools-protocol/tot/DOM/#type-Node 32 | * @author: Serguei Kouzmine (kouzmine_serguei@yahoo.com) 33 | */ 34 | 35 | public class PierceCdpTest extends BaseCdpTest { 36 | 37 | private static final String page = "iframe_example.html"; 38 | 39 | private static String command = null; 40 | private static String baseURL = "https://demoqa.com/frames"; 41 | 42 | private static Map params = new HashMap<>(); 43 | private static Map result = new HashMap<>(); 44 | private static Map result2 = new HashMap<>(); 45 | public static Long nodeId = (long) -1; 46 | 47 | @After 48 | public void afterTest() { 49 | command = "DOM.disable"; 50 | result = driver.executeCdpCommand(command, new HashMap()); 51 | driver.get("about:blank"); 52 | } 53 | 54 | @Before 55 | public void beforeTest() { 56 | command = "DOM.enable"; 57 | params = new HashMap(); 58 | params.put("includeWhitespace", "all"); 59 | result = driver.executeCdpCommand(command, params); 60 | // driver.get(Utils.getPageContent(page)); 61 | driver.get(baseURL); 62 | 63 | } 64 | 65 | @SuppressWarnings("unchecked") 66 | @Test 67 | public void test1() { 68 | 69 | try { 70 | command = "DOM.getDocument"; 71 | params = new HashMap<>(); 72 | params.put("pierce", true); 73 | params.put("depth", -1); 74 | // Act 75 | result = driver.executeCdpCommand(command, params); 76 | assertThat(result, hasKey("root")); 77 | result2 = (Map) result.get("root"); 78 | String resultFilepath = System.getProperty("user.dir") + System.getProperty("file.separator") + "target" + System.getProperty("file.separator") + "test1.json"; 79 | Writer out = new OutputStreamWriter(new FileOutputStream(new File(resultFilepath)), "UTF-8"); 80 | 81 | try { 82 | out.write(new Gson().toJson(result2, Map.class)); 83 | } finally { 84 | out.close(); 85 | } 86 | } catch (JsonSyntaxException e) { 87 | System.err.println("JSON Syntax exception in " + command + " (ignored): " 88 | + e.toString()); 89 | } catch (WebDriverException e) { 90 | System.err.println("Web Driver exception in " + command + " (ignored): " 91 | + Utils.processExceptionMessage(e.getMessage())); 92 | } catch (Exception e) { 93 | System.err.println("Exception in " + command + " " + e.toString()); 94 | e.printStackTrace(); 95 | throw (new RuntimeException(e)); 96 | } 97 | } 98 | 99 | @SuppressWarnings("unchecked") 100 | @Test 101 | public void test2() { 102 | 103 | try { 104 | command = "DOM.getDocument"; 105 | params = new HashMap<>(); 106 | params.put("pierce", false); 107 | params.put("depth", -1); 108 | // Act 109 | result = driver.executeCdpCommand(command, params); 110 | assertThat(result, hasKey("root")); 111 | result2 = (Map) result.get("root"); 112 | String resultFilepath = System.getProperty("user.dir") + System.getProperty("file.separator") + "target" + System.getProperty("file.separator") + "test2.json"; 113 | Writer out = new OutputStreamWriter(new FileOutputStream(new File(resultFilepath)), "UTF-8"); 114 | try { 115 | out.write(new Gson().toJson(result2, Map.class)); 116 | } finally { 117 | out.close(); 118 | } 119 | } catch (JsonSyntaxException e) { 120 | System.err.println("JSON Syntax exception in " + command + " (ignored): " 121 | + e.toString()); 122 | } catch (WebDriverException e) { 123 | System.err.println("Web Driver exception in " + command + " (ignored): " 124 | + Utils.processExceptionMessage(e.getMessage())); 125 | } catch (Exception e) { 126 | System.err.println("Exception in " + command + " " + e.toString()); 127 | e.printStackTrace(); 128 | throw (new RuntimeException(e)); 129 | } 130 | } 131 | } 132 | -------------------------------------------------------------------------------- /src/test/java/com/github/sergueik/selenium/PierceDevToolsTest.java: -------------------------------------------------------------------------------- 1 | package com.github.sergueik.selenium; 2 | 3 | /** 4 | * Copyright 2023,2024 Serguei Kouzmine 5 | */ 6 | 7 | 8 | import java.io.File; 9 | import java.io.FileOutputStream; 10 | import java.io.IOException; 11 | import java.io.OutputStreamWriter; 12 | import java.io.Writer; 13 | import java.util.Optional; 14 | 15 | import org.junit.After; 16 | import org.junit.Before; 17 | import org.junit.Test; 18 | import org.openqa.selenium.devtools.DevToolsException; 19 | import org.openqa.selenium.devtools.v127.dom.DOM; 20 | import org.openqa.selenium.devtools.v127.dom.DOM.EnableIncludeWhitespace; 21 | import org.openqa.selenium.devtools.v127.dom.model.Node; 22 | import org.openqa.selenium.devtools.v127.dom.model.NodeId; 23 | 24 | import com.google.gson.Gson; 25 | 26 | /** 27 | * Selected test scenarios for Selenium 4 Chrome Developer Tools bridge 28 | * https://chromedevtools.github.io/devtools-protocol/tot/DOM/#method-getDocument 29 | * https://chromedevtools.github.io/devtools-protocol/tot/DOM/#method-querySelectorAll 30 | * https://chromedevtools.github.io/devtools-protocol/tot/DOM/#method-describeNode 31 | * https://chromedevtools.github.io/devtools-protocol/tot/DOM/#type-Node 32 | * @author: Serguei Kouzmine (kouzmine_serguei@yahoo.com) 33 | */ 34 | public class PierceDevToolsTest extends BaseDevToolsTest { 35 | 36 | private static final String page = "iframe_example.html"; 37 | private static String baseURL = "https://demoqa.com/frames"; 38 | 39 | private static Node result; 40 | private NodeId nodeId = null; 41 | 42 | @After 43 | public void afterTest() { 44 | chromeDevTools.send(DOM.disable()); 45 | driver.get("about:blank"); 46 | } 47 | 48 | @Before 49 | public void beforeTest() { 50 | chromeDevTools.send(DOM.enable(Optional.of(EnableIncludeWhitespace.ALL))); 51 | // driver.get(Utils.getPageContent(page)); 52 | driver.get(baseURL); 53 | 54 | } 55 | 56 | @Test 57 | public void test3() throws IOException { 58 | try { 59 | result = chromeDevTools 60 | .send(DOM.getDocument(Optional.of(-1), Optional.of(true))); 61 | 62 | String resultFilepath = System.getProperty("user.dir") + System.getProperty("file.separator") + "target" + System.getProperty("file.separator") + "test3.json"; 63 | Writer out = new OutputStreamWriter(new FileOutputStream(new File(resultFilepath)), "UTF-8"); 64 | try { 65 | out.write(new Gson().toJson(result, Node.class)); 66 | } finally { 67 | out.close(); 68 | } 69 | 70 | } catch (DevToolsException e) { 71 | System.err.println("Exception (rethrown) " + e.getMessage()); 72 | throw e; 73 | } 74 | } 75 | 76 | @Test 77 | public void test4() throws IOException { 78 | try { 79 | result = chromeDevTools 80 | .send(DOM.getDocument(Optional.of(-1), Optional.of(false))); 81 | String resultFilepath = System.getProperty("user.dir") + System.getProperty("file.separator") + "target" + System.getProperty("file.separator") + "test3.json"; 82 | Writer out = new OutputStreamWriter(new FileOutputStream(new File(resultFilepath)), "UTF-8"); 83 | try { 84 | out.write(new Gson().toJson(result, Node.class)); 85 | } finally { 86 | out.close(); 87 | } 88 | 89 | } catch (DevToolsException e) { 90 | System.err.println("Exception (rethrown) " + e.getMessage()); 91 | throw e; 92 | } 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /src/test/java/com/github/sergueik/selenium/ShadowDomCDPTest.java: -------------------------------------------------------------------------------- 1 | package com.github.sergueik.selenium; 2 | 3 | /** 4 | * Copyright 2023,2024 Serguei Kouzmine 5 | */ 6 | 7 | 8 | import static java.lang.System.err; 9 | import static org.hamcrest.CoreMatchers.is; 10 | 11 | /** 12 | * Copyright 2023 Serguei Kouzmine 13 | */ 14 | 15 | import static org.hamcrest.CoreMatchers.notNullValue; 16 | import static org.hamcrest.MatcherAssert.assertThat; 17 | 18 | import java.util.HashMap; 19 | 20 | import org.junit.After; 21 | import org.junit.Before; 22 | import org.junit.Test; 23 | import org.openqa.selenium.By; 24 | import org.openqa.selenium.SearchContext; 25 | import org.openqa.selenium.WebElement; 26 | 27 | /** 28 | * Selected test scenarios for Selenium 4 Chrome Developer Tools bridge 29 | * @author: Serguei Kouzmine (kouzmine_serguei@yahoo.com) 30 | */ 31 | 32 | // based on: 33 | // https://github.com/diemol/selenium-4-demo/blob/master/src/test/java/com/saucelabs/demo/ShadowDomTest.java#L3 34 | 35 | public class ShadowDomCDPTest extends BaseCdpTest { 36 | 37 | private WebElement element1; 38 | private WebElement element2; 39 | private WebElement element3; 40 | private SearchContext shadowRoot; 41 | private static String page = "inner_html_example.html"; 42 | 43 | @Before 44 | public void beforeTest() throws Exception { 45 | driver.get(Utils.getPageContent(page)); 46 | driver.executeCdpCommand("Runtime.enable", new HashMap()); 47 | } 48 | 49 | @After 50 | public void clearPage() { 51 | driver.executeCdpCommand("Runtime.disable", new HashMap()); 52 | driver.get("about:blank"); 53 | } 54 | 55 | @Test 56 | public void test1() { 57 | // Act 58 | element1 = driver.findElement(By.cssSelector("body > div")); 59 | element2 = element1.findElement(By.tagName("h3")); 60 | assertThat(element2, notNullValue()); 61 | err.println("Page outerHTML: " + element2.getAttribute("outerHTML")); 62 | // Assert 63 | assertThat(element2.getText(), is("")); 64 | err.println(String.format("Page text: \"%s\"", element2.getText())); 65 | // Act 66 | shadowRoot = element1.getShadowRoot(); 67 | 68 | element3 = shadowRoot.findElement(By.cssSelector("h3")); 69 | 70 | assertThat(element3, notNullValue()); 71 | err.println("Shadow DOM outerHTML: " + element3.getAttribute("outerHTML")); 72 | // Assert 73 | assertThat(element3.getText(), is("Shadow DOM")); 74 | err.println(String.format("Shadow DOM text: \"%s\"", element3.getText())); 75 | 76 | } 77 | 78 | } 79 | -------------------------------------------------------------------------------- /src/test/java/com/github/sergueik/selenium/StorageDevToolsTest.java: -------------------------------------------------------------------------------- 1 | package com.github.sergueik.selenium; 2 | /** 3 | * Copyright 2023,2024 Serguei Kouzmine 4 | */ 5 | 6 | import org.junit.After; 7 | import org.junit.Before; 8 | // import org.junit.Ignore; 9 | import org.junit.Test; 10 | import org.openqa.selenium.devtools.DevToolsException; 11 | import org.openqa.selenium.devtools.v127.network.model.TimeSinceEpoch; 12 | import org.openqa.selenium.devtools.v127.storage.Storage; 13 | import org.openqa.selenium.devtools.v127.storage.model.SharedStorageMetadata; 14 | import org.openqa.selenium.json.JsonException; 15 | 16 | /** 17 | * Selected test scenarios for Selenium Chrome Developer Tools Selenium 4 bridge 18 | * https://chromedevtools.github.io/devtools-protocol/tot/Storage/#method-getSharedStorageEntries 19 | * https://chromedevtools.github.io/devtools-protocol/tot/Storage/ 20 | * https://developer.chrome.com/en/docs/privacy-sandbox/use-shared-storage/ 21 | * based on: https://github.com/GoogleChromeLabs/shared-storage-demo 22 | * see also: https://github.com/aslushnikov/getting-started-with-cdp (NOTE: js) 23 | * https://dev.to/grouparoo/testing-sessionstorage-and-localstorage-with-selenium-node-2336 (NOTE: js) 24 | * @author: Serguei Kouzmine (kouzmine_serguei@yahoo.com) 25 | */ 26 | 27 | public class StorageDevToolsTest extends BaseDevToolsTest { 28 | 29 | private final static String baseURL = "https://www.google.com"; 30 | 31 | @Before 32 | public void before() throws Exception { 33 | driver.get(baseURL); 34 | } 35 | 36 | @After 37 | public void clearPage() { 38 | try { 39 | driver.get("about:blank"); 40 | } catch (Exception e) { 41 | 42 | } 43 | } 44 | 45 | // Tests in error: 46 | // { 47 | // "id":5,"error":{"code":-32000, 48 | // "message":"Origin not found."}, 49 | // "sessionId":"9B2C2FC875140BF76750D29883144F10" 50 | // }(..) 51 | @Test(expected = DevToolsException.class) 52 | public void test1() { 53 | try { 54 | String ownerOrigin = "https://www.google.com"; 55 | SharedStorageMetadata response = chromeDevTools 56 | .send(Storage.getSharedStorageMetadata(ownerOrigin)); 57 | Integer length = response.getLength(); 58 | TimeSinceEpoch creationTime = response.getCreationTime(); 59 | // assertThat(result, notNullValue()); 60 | System.err.println( 61 | String.format("Shared Storage Metadata length: %d creation time: %s", 62 | length, creationTime.toString())); 63 | } catch (JsonException e) { 64 | System.err.println( 65 | "Exception in test 1 reading result (ignored): " + e.toString()); 66 | } 67 | 68 | } 69 | 70 | // Tests in error: 71 | // { 72 | // "id":6,"error":{ 73 | // "code":-32602, 74 | // "message":"Invalid owner origin."}, 75 | // "sessionId":"9B2C2FC875140BF76750D29883144F10" 76 | // }(..) 77 | @Test(expected = DevToolsException.class) 78 | public void test2() { 79 | try { 80 | String ownerOrigin = "www.google.com"; 81 | SharedStorageMetadata response = chromeDevTools 82 | .send(Storage.getSharedStorageMetadata(ownerOrigin)); 83 | Integer length = response.getLength(); 84 | TimeSinceEpoch creationTime = response.getCreationTime(); 85 | // assertThat(result, notNullValue()); 86 | System.err.println( 87 | String.format("Shared Storage Metadata length: %d creation time: %s", 88 | length, creationTime.toString())); 89 | } catch (JsonException e) { 90 | System.err.println( 91 | "Exception in test 1 reading result (ignored): " + e.toString()); 92 | } 93 | 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /src/test/java/com/github/sergueik/selenium/SystemInfoCdpTest.java: -------------------------------------------------------------------------------- 1 | package com.github.sergueik.selenium; 2 | /** 3 | * Copyright 2022,2024 Serguei Kouzmine 4 | */ 5 | 6 | import static org.hamcrest.CoreMatchers.notNullValue; 7 | import static org.hamcrest.MatcherAssert.assertThat; 8 | import static org.hamcrest.Matchers.hasKey; 9 | 10 | import java.util.ArrayList; 11 | import java.util.Arrays; 12 | import java.util.HashMap; 13 | import java.util.List; 14 | import java.util.Map; 15 | 16 | import org.junit.Test; 17 | import org.openqa.selenium.WebDriverException; 18 | 19 | /** 20 | * Selected test scenarios for Selenium 4 Chrome Developer Tools bridge inspired 21 | * by https://toster.ru/q/653249?e=7897302#comment_1962398 22 | * https://chromedevtools.github.io/devtools-protocol/tot/SystemInfo/#method-getProcessInfo 23 | * https://chromedevtools.github.io/devtools-protocol/tot/SystemInfo/#method-getInfo 24 | * @author: Serguei Kouzmine (kouzmine_serguei@yahoo.com) 25 | */ 26 | 27 | public class SystemInfoCdpTest extends BaseCdpTest { 28 | 29 | private static String command; 30 | private static Map result = new HashMap<>(); 31 | 32 | @Test(expected = WebDriverException.class) 33 | public void test1() { 34 | 35 | try { 36 | // Act 37 | command = "SystemInfo.getInfo"; 38 | assertThat(result, notNullValue()); 39 | result = driver.executeCdpCommand(command, new HashMap<>()); 40 | System.err.println( 41 | command + " result: " + new ArrayList(result.keySet())); 42 | for (String field : Arrays.asList("gpu", "modelName", "modelVersion", 43 | "commandLine")) { 44 | assertThat(result, hasKey(field)); 45 | System.err.print(field + ": " + result.get(field) + "\t"); 46 | } 47 | } catch (WebDriverException e) { 48 | System.err 49 | .println("Web Driver exception in " + command + ": " + e.toString()); 50 | throw e; 51 | } catch (Exception e) { 52 | System.err.println("Exception in " + command + " " + e.toString()); 53 | throw (new RuntimeException(e)); 54 | } 55 | } 56 | 57 | @Test(expected = WebDriverException.class) 58 | public void test2() { 59 | 60 | try { 61 | // Act 62 | command = "SystemInfo.getProcessInfo"; 63 | result = driver.executeCdpCommand(command, new HashMap<>()); 64 | System.err.println(command + " result: " + result.keySet()); 65 | assertThat(result, notNullValue()); 66 | 67 | } catch (WebDriverException e) { 68 | System.err 69 | .println("Web Driver exception in " + command + ": " + e.toString()); 70 | // Ubuntu host: 71 | // Web Driver exception in SystemInfo.getProcessInfo: 72 | // org.openqa.selenium.UnsupportedCommandException: unknown command: 73 | // 'SystemInfo.getProcessInfo' wasn't found 74 | // Windows host: 75 | // Web Driver exception: org.openqa.selenium.devtools.DevToolsException: 76 | // {"id":5,"error":{"code":-32601,"message":"'SystemInfo.getInfo' wasn't 77 | // found"},"sessionId": "AF6B2ECF976CFDAEC1C7EB1534259EB7"} 78 | throw e; 79 | } catch (Exception e) { 80 | System.err.println("Exception in " + command + " " + e.toString()); 81 | throw (new RuntimeException(e)); 82 | } 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /src/test/java/com/github/sergueik/selenium/SystemInfoDevToolsTest.java: -------------------------------------------------------------------------------- 1 | package com.github.sergueik.selenium; 2 | /** 3 | * Copyright 2022,2024 Serguei Kouzmine 4 | */ 5 | 6 | import static org.hamcrest.CoreMatchers.notNullValue; 7 | import static org.junit.Assert.assertThat; 8 | 9 | import java.util.List; 10 | 11 | import org.junit.Test; 12 | import org.openqa.selenium.WebDriverException; 13 | import org.openqa.selenium.devtools.v127.systeminfo.SystemInfo; 14 | import org.openqa.selenium.devtools.v127.systeminfo.model.ProcessInfo; 15 | 16 | /** 17 | * Selected test scenarios for Selenium Chrome Developer Tools Selenium 4 bridge 18 | 19 | * https://chromedevtools.github.io/devtools-protocol/tot/Log#method-enable 20 | * https://chromedevtools.github.io/devtools-protocol/tot/Log/#event-entryAdded 21 | * https://chromedevtools.github.io/devtools-protocol/1-3/Page/#method-navigate 22 | * https://chromedevtools.github.io/devtools-protocol/tot/SystemInfo/#method-getProcessInfo 23 | * https://chromedevtools.github.io/devtools-protocol/tot/SystemInfo/#method-getInfo 24 | * 25 | * @author: Serguei Kouzmine (kouzmine_serguei@yahoo.com) 26 | */ 27 | @SuppressWarnings("deprecation") 28 | public class SystemInfoDevToolsTest extends BaseDevToolsTest { 29 | 30 | @Test(expected = WebDriverException.class) 31 | public void test1() { 32 | try { 33 | SystemInfo.GetInfoResponse response = chromeDevTools 34 | .send(SystemInfo.getInfo()); 35 | 36 | assertThat(response, notNullValue()); 37 | response.getCommandLine(); 38 | } catch (WebDriverException e) { 39 | System.err.println("Web Driver exception: " + e.toString()); 40 | throw e; 41 | } 42 | } 43 | 44 | @Test(expected = WebDriverException.class) 45 | public void test2() { 46 | try { 47 | List response = chromeDevTools 48 | .send(SystemInfo.getProcessInfo()); 49 | assertThat(response, notNullValue()); 50 | response.get(0); 51 | } catch (WebDriverException e) { 52 | System.err.println("Web Driver exception: " + e.toString()); 53 | throw e; 54 | } 55 | } 56 | 57 | } -------------------------------------------------------------------------------- /src/test/java/com/github/sergueik/selenium/TimeZoneCdpTest.java: -------------------------------------------------------------------------------- 1 | package com.github.sergueik.selenium; 2 | 3 | /** 4 | * Copyright 2023,2024 Serguei Kouzmine 5 | */ 6 | 7 | import static org.hamcrest.CoreMatchers.containsString; 8 | import static org.hamcrest.MatcherAssert.assertThat; 9 | 10 | import java.util.Calendar; 11 | import java.util.HashMap; 12 | import java.util.Map; 13 | import java.util.TimeZone; 14 | 15 | import org.junit.After; 16 | import org.junit.Test; 17 | 18 | import org.openqa.selenium.By; 19 | import org.openqa.selenium.WebDriverException; 20 | import org.openqa.selenium.WebElement; 21 | 22 | /** 23 | * Selected test scenarios for Selenium 4 Chrome Developer Tools bridge inspired 24 | * https://chromedevtools.github.io/devtools-protocol/tot/Emulation/#method-setTimezoneOverride 25 | * 26 | * @author: Serguei Kouzmine (kouzmine_serguei@yahoo.com) 27 | */ 28 | public class TimeZoneCdpTest extends BaseCdpTest { 29 | 30 | private static String command = "Emulation.setTimezoneOverride"; 31 | private static Map params = new HashMap<>(); 32 | 33 | private static final String timezoneId = "America/Lima"; 34 | private static final String timezoneDescription = "Peru Standard Time"; 35 | // https://docs.oracle.com/middleware/12211/wcs/tag-ref/MISC/TimeZones.html 36 | 37 | static { 38 | { 39 | params.put("timezoneId", timezoneId); 40 | } 41 | }; 42 | private static String baseURL = "https://webbrowsertools.com/timezone/"; 43 | 44 | // see also: 45 | // https://github.com/SrinivasanTarget/selenium4CDPsamples/blob/master/src/test/java/DevToolsTest.java#L169 46 | @Test 47 | public void test1() { 48 | // Arrange 49 | driver.executeCdpCommand(command, params); 50 | // Act 51 | driver.get(baseURL); 52 | WebElement element = driver.findElement(By.xpath( 53 | "//table[@id=\"timezone\"]/tbody/tr/td[contains(text(),\"Time on Local Machine\")]/../td[@id=\"toString\"]")); 54 | Utils.highlight(element); 55 | Utils.sleep(100); 56 | // Assert 57 | assertThat(element.getAttribute("innerText"), 58 | containsString(timezoneDescription)); 59 | System.err 60 | .println("Time on Local Machine: " + element.getAttribute("innerText")); 61 | 62 | } 63 | 64 | @Test(expected = WebDriverException.class) 65 | public void test2() { 66 | try { 67 | // Arrange 68 | driver.executeCdpCommand(command, new HashMap<>()); 69 | // Assert 70 | } catch (WebDriverException e) { 71 | System.err.println("Web Driver exception in " + command + " (expected): " 72 | + Utils.processExceptionMessage(e.getMessage())); 73 | throw e; 74 | } 75 | } 76 | 77 | @After 78 | public void after() { 79 | 80 | TimeZone timeZone = Calendar.getInstance().getTimeZone(); 81 | System.err.println(String.format("Current TimeZone is: %s (%s) ", 82 | timeZone.getID(), timeZone.getDisplayName())); 83 | params.put("timezoneId", timeZone.getID()); 84 | driver.executeCdpCommand(command, params); 85 | driver.get("about:blank"); 86 | } 87 | 88 | } 89 | 90 | -------------------------------------------------------------------------------- /src/test/java/com/github/sergueik/selenium/TimeZoneDevToolsTest.java: -------------------------------------------------------------------------------- 1 | package com.github.sergueik.selenium; 2 | 3 | /** 4 | * Copyright 2023,2024 Serguei Kouzmine 5 | */ 6 | 7 | import static org.hamcrest.CoreMatchers.containsString; 8 | import static org.hamcrest.MatcherAssert.assertThat; 9 | 10 | import java.util.Calendar; 11 | import java.util.TimeZone; 12 | 13 | import org.junit.After; 14 | import org.junit.Test; 15 | import org.openqa.selenium.By; 16 | import org.openqa.selenium.WebElement; 17 | import org.openqa.selenium.devtools.v127.emulation.Emulation; 18 | 19 | /** 20 | * Selected test scenarios for Selenium Chrome Developer Tools Selenium 4 bridge 21 | * https://chromedevtools.github.io/devtools-protocol/tot/Network/#method-setUserAgentOverride 22 | * @author: Serguei Kouzmine (kouzmine_serguei@yahoo.com) 23 | */ 24 | 25 | public class TimeZoneDevToolsTest extends BaseDevToolsTest { 26 | 27 | private static final String timezoneId = "America/Lima"; 28 | private static final String timezoneDescription = "Peru Standard Time"; 29 | 30 | private static String baseURL = "https://webbrowsertools.com/timezone/"; 31 | 32 | @Test 33 | public void test1() { 34 | // does not work: 35 | // Assume.assumeTrue(pingHost("webbrowsertools.com", 443, 3)); 36 | // NOTE: nc -z webbrowsertools.com 443 37 | // echo $? 38 | // 0 39 | 40 | // Arrange 41 | chromeDevTools.send(Emulation.setTimezoneOverride(timezoneId)); 42 | // Act 43 | driver.get(baseURL); 44 | WebElement element = driver.findElement(By.xpath( 45 | "//table[@id=\"timezone\"]/tbody/tr/td[contains(text(),\"Time on Local Machine\")]/../td[@id=\"toString\"]")); 46 | Utils.highlight(element); 47 | Utils.sleep(100); 48 | // Assert 49 | assertThat(element.getAttribute("innerText"), 50 | containsString(timezoneDescription)); 51 | System.err 52 | .println("Time on Local Machine: " + element.getAttribute("innerText")); 53 | 54 | } 55 | 56 | @Test(expected = NullPointerException.class) 57 | // "If The timezone identifier is empty, disables the override and 58 | // restores default host system timezone." 59 | // NOTE: sending null leads to NPE 60 | public void test2() { 61 | // Arrange 62 | try { 63 | chromeDevTools.send(Emulation.setTimezoneOverride(null)); 64 | } catch (NullPointerException e) { 65 | System.err.println("Null Pointer exception (expected): " 66 | + Utils.processExceptionMessage(e.getMessage())); 67 | throw e; 68 | } 69 | } 70 | 71 | @After 72 | public void after() { 73 | 74 | TimeZone timeZone = Calendar.getInstance().getTimeZone(); 75 | System.err.println(String.format("Current TimeZone is: %s (%s) ", 76 | timeZone.getID(), timeZone.getDisplayName())); 77 | 78 | chromeDevTools.send(Emulation.setTimezoneOverride(timeZone.getID())); 79 | driver.get("about:blank"); 80 | } 81 | 82 | } 83 | -------------------------------------------------------------------------------- /src/test/java/com/github/sergueik/selenium/WebpCdpTest.java: -------------------------------------------------------------------------------- 1 | package com.github.sergueik.selenium; 2 | 3 | /** 4 | * Copyright 2023,2024 Serguei Kouzmine 5 | */ 6 | 7 | import static org.hamcrest.CoreMatchers.is; 8 | import static org.hamcrest.CoreMatchers.notNullValue; 9 | import static org.hamcrest.MatcherAssert.assertThat; 10 | import static org.hamcrest.Matchers.greaterThan; 11 | 12 | import java.io.UnsupportedEncodingException; 13 | import java.util.Arrays; 14 | import java.util.HashMap; 15 | import java.util.Map; 16 | 17 | import org.junit.Test; 18 | 19 | import org.openqa.selenium.By; 20 | import org.openqa.selenium.WebElement; 21 | import org.openqa.selenium.interactions.Actions; 22 | 23 | /** 24 | * Selected test scenarios for Selenium 4 Chrome Developer Tools bridge 25 | * https://chromedevtools.github.io/devtools-protocol/tot/Emulation/#method-setDisabledImageTypes 26 | * https://chromedevtools.github.io/devtools-protocol/tot/Emulation/#type-DisabledImageType 27 | * see also: 28 | * https://www.lambdatest.com/blog/find-broken-images-using-selenium-webdriver/ 29 | * @author: Serguei Kouzmine (kouzmine_serguei@yahoo.com) 30 | */ 31 | 32 | public class WebpCdpTest extends BaseCdpTest { 33 | private static String baseURL = "https://developers.google.com/speed/webp/gallery1"; 34 | private Actions actions; 35 | private WebElement element; 36 | private static String command = null; 37 | private static Map params = new HashMap<>(); 38 | private static int delay = 3000; 39 | 40 | @Test 41 | public void test1() throws UnsupportedEncodingException { 42 | // Arrange 43 | params = new HashMap<>(); 44 | params.put("imageTypes", Arrays.asList("webp")); 45 | command = "Emulation.setDisabledImageTypes"; 46 | driver.executeCdpCommand(command, params); 47 | // Act 48 | driver.get(baseURL); 49 | element = driver.findElement(By.xpath("//img[@alt='WebP Image']")); 50 | assertThat(element, notNullValue()); 51 | 52 | assertThat(element.isDisplayed(), is(true)); 53 | actions = new Actions(driver); 54 | actions.moveToElement(element).build().perform(); 55 | 56 | Utils.highlight(element); 57 | Utils.sleep(delay); 58 | // identify as Broken Image 59 | assertThat(element.getAttribute("naturalWidth"), is("0")); 60 | assertThat(element.getSize().width, greaterThan(0)); // 95 61 | assertThat( 62 | (int) Math.ceil( 63 | Float.parseFloat(element.getCssValue("width").replace("px", ""))), 64 | greaterThan(0)); // "94.75px" 65 | } 66 | 67 | } 68 | -------------------------------------------------------------------------------- /src/test/java/com/github/sergueik/selenium/WebpDevToolsTest.java: -------------------------------------------------------------------------------- 1 | package com.github.sergueik.selenium; 2 | 3 | /** 4 | * Copyright 2023,2024 Serguei Kouzmine 5 | */ 6 | 7 | import static org.hamcrest.CoreMatchers.is; 8 | import static org.hamcrest.CoreMatchers.notNullValue; 9 | import static org.hamcrest.MatcherAssert.assertThat; 10 | import static org.hamcrest.Matchers.greaterThan; 11 | 12 | import java.io.UnsupportedEncodingException; 13 | import java.util.Arrays; 14 | 15 | import org.junit.Test; 16 | import org.openqa.selenium.By; 17 | import org.openqa.selenium.WebElement; 18 | import org.openqa.selenium.devtools.v127.emulation.Emulation; 19 | import org.openqa.selenium.devtools.v127.emulation.model.DisabledImageType; 20 | import org.openqa.selenium.interactions.Actions; 21 | 22 | /** 23 | * Selected test scenarios for Selenium 4 Chrome Developer Tools bridge 24 | * https://chromedevtools.github.io/devtools-protocol/tot/Emulation/#method-setDisabledImageTypes 25 | * https://chromedevtools.github.io/devtools-protocol/tot/Emulation/#type-DisabledImageType 26 | * see also: 27 | * https://www.lambdatest.com/blog/find-broken-images-using-selenium-webdriver/ 28 | * @author: Serguei Kouzmine (kouzmine_serguei@yahoo.com) 29 | */ 30 | 31 | public class WebpDevToolsTest extends BaseDevToolsTest { 32 | private static String baseURL = "https://developers.google.com/speed/webp/gallery1"; 33 | private Actions actions; 34 | private WebElement element; 35 | private static int delay = 3000; 36 | 37 | @Test 38 | public void test1() throws UnsupportedEncodingException { 39 | // Arrange 40 | DisabledImageType type = DisabledImageType.WEBP; 41 | // @formatter:off 42 | chromeDevTools.send( 43 | Emulation.setDisabledImageTypes( 44 | Arrays.asList(type)) // imageTypes 45 | ); 46 | // @formatter:on 47 | // Act 48 | driver.get(baseURL); 49 | element = driver.findElement(By.xpath("//img[@alt='WebP Image']")); 50 | assertThat(element, notNullValue()); 51 | 52 | assertThat(element.isDisplayed(), is(true)); 53 | actions = new Actions(driver); 54 | actions.moveToElement(element).build().perform(); 55 | 56 | Utils.highlight(element); 57 | Utils.sleep(delay); 58 | // identify as Broken Image 59 | assertThat(element.getAttribute("naturalWidth"), is("0")); 60 | assertThat(element.getSize().width, greaterThan(0)); // 95 61 | assertThat( 62 | (int) Math.ceil( 63 | Float.parseFloat(element.getCssValue("width").replace("px", ""))), 64 | greaterThan(0)); // "94.75px" 65 | } 66 | 67 | } 68 | -------------------------------------------------------------------------------- /src/test/java/com/github/sergueik/selenium/WheelInputTest.java: -------------------------------------------------------------------------------- 1 | package com.github.sergueik.selenium; 2 | 3 | import org.junit.Before; 4 | import org.junit.Test; 5 | 6 | import org.openqa.selenium.By; 7 | import org.openqa.selenium.interactions.Actions; 8 | import org.openqa.selenium.interactions.WheelInput; 9 | 10 | //based on: https://github.com/fugazi/carbonfour-selenium-4/blob/main/src/test/java/Selenium_4_Tests/TestWheelScrolling.java 11 | //see also: 12 | 13 | public class WheelInputTest extends BaseCdpTest { 14 | 15 | private Actions actions; 16 | private static String baseURL = "https://www.wikipedia.org"; 17 | 18 | @Before 19 | public void setUp() { 20 | driver.get(baseURL); 21 | actions = new Actions(driver); 22 | // driver.manage().window().maximize(); 23 | } 24 | 25 | @Test 26 | public void testWheelScrolling() { 27 | 28 | actions 29 | .scrollToElement( 30 | driver.findElement(By.cssSelector("div.central-textlogo"))) 31 | .perform(); 32 | 33 | actions.scrollByAmount(0, 500).perform(); 34 | actions.scrollByAmount(0, -500).perform(); 35 | 36 | actions.scrollFromOrigin( 37 | WheelInput.ScrollOrigin.fromElement(driver.findElement(By.cssSelector( 38 | "div.footer > div.other-projects span[ data-jsl10n='metawiki.name']"))), 39 | 0, 500).perform(); 40 | actions.scrollFromOrigin(WheelInput.ScrollOrigin.fromViewport(), 0, 500) 41 | .perform(); 42 | actions 43 | .scrollFromOrigin(WheelInput.ScrollOrigin.fromViewport(35, 35), 0, 500) 44 | .perform(); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/test/java/com/github/sergueik/selenium/WindowsTabsCdpTest.java: -------------------------------------------------------------------------------- 1 | package com.github.sergueik.selenium; 2 | 3 | /** 4 | * Copyright 2023,2024 Serguei Kouzmine 5 | */ 6 | 7 | import static org.hamcrest.CoreMatchers.is; 8 | import static org.hamcrest.CoreMatchers.notNullValue; 9 | import static org.hamcrest.MatcherAssert.assertThat; 10 | import static org.hamcrest.Matchers.greaterThan; 11 | import static org.hamcrest.CoreMatchers.is; 12 | import static org.hamcrest.CoreMatchers.notNullValue; 13 | import static org.hamcrest.MatcherAssert.assertThat; 14 | import static org.hamcrest.Matchers.greaterThan; 15 | import static org.hamcrest.Matchers.hasKey; 16 | 17 | import java.io.UnsupportedEncodingException; 18 | import java.util.Arrays; 19 | import java.util.HashMap; 20 | import java.util.Map; 21 | import java.util.Optional; 22 | 23 | import org.junit.Ignore; 24 | import org.junit.Test; 25 | 26 | import org.openqa.selenium.By; 27 | import org.openqa.selenium.WebElement; 28 | import org.openqa.selenium.interactions.Actions; 29 | 30 | /** 31 | * Selected test scenarios for Selenium Chrome Developer Tools Selenium 4 bridge 32 | * see: 33 | * https://chromedevtools.github.io/devtools-protocol/tot/Target/#method-createTarget 34 | * https://chromedevtools.github.io/devtools-protocol/tot/Target/#method-getTargets 35 | * https://chromedevtools.github.io/devtools-protocol/tot/Target/#method-attachToTarget 36 | * https://chromedevtools.github.io/devtools-protocol/tot/Target/#method-getTargetInfo 37 | * https://chromedevtools.github.io/devtools-protocol/tot/Target/#type-TargetInfo 38 | * https://chromedevtools.github.io/devtools-protocol/tot/Target/#type-SessionID 39 | * https://chromedevtools.github.io/devtools-protocol/tot/Target/#method-attachToBrowserTarget 40 | */ 41 | 42 | public class WindowsTabsCdpTest extends BaseCdpTest { 43 | private static String baseURL = "https://developers.google.com/speed/webp/gallery1"; 44 | private Actions actions; 45 | private WebElement element; 46 | private static String command = null; 47 | private static Map params = new HashMap<>(); 48 | private Map bounds = new HashMap(); 49 | private static Map result = new HashMap<>(); 50 | private static Map data = new HashMap<>(); 51 | private static boolean headless = true; 52 | private static String targetId = null; 53 | private static int delay = 3000; 54 | 55 | @SuppressWarnings("unchecked") 56 | @Test 57 | public void test1() throws UnsupportedEncodingException { 58 | // Arrange 59 | baseURL = "https://en.wikipedia.org/wiki/Main_Page"; 60 | // Act 61 | params = new HashMap<>(); 62 | params.put("url", baseURL); 63 | command = "Target.createTarget"; 64 | result = driver.executeCdpCommand(command, params); 65 | assertThat(result, notNullValue()); 66 | assertThat(result, hasKey("targetId")); 67 | 68 | targetId = (String) result.get("targetId"); 69 | assertThat(targetId, notNullValue()); 70 | System.err.println("TargetID: " + targetId); 71 | // Act 72 | params = new HashMap<>(); 73 | params.put("targetId", targetId); 74 | command = "Target.getTargetInfo"; 75 | // Act 76 | result = driver.executeCdpCommand(command, params); 77 | assertThat(result, notNullValue()); 78 | assertThat(result, hasKey("targetInfo")); 79 | data = (Map) result.get("targetInfo"); 80 | assertThat(data, notNullValue()); 81 | // NOTE: optional fields will not be guaranteed to be present in the data 82 | for (String field : Arrays.asList(new String[] { "targetId", "attached", 83 | "type", "url", "title", "browserContextId", "canAccessOpener" })) { 84 | assertThat(data, hasKey(field)); 85 | } 86 | 87 | System.err.println("TargetInfo: " + "\n" + "TargetId: " 88 | + data.get("targetId") + "\n" + "Title: " + data.get("title") + "\n" 89 | + "Type: " + data.get("type") + "\n" + "Url: " + data.get("url") + "\n" 90 | + "Attached: " + data.get("attached")); 91 | 92 | } 93 | 94 | @Ignore 95 | // NOTE: occasionally timing out under CDP 96 | @Test 97 | public void test2() throws UnsupportedEncodingException { 98 | // Arrange 99 | baseURL = "https://en.wikipedia.org/wiki/Main_Page"; 100 | params = new HashMap<>(); 101 | params.put("url", baseURL); 102 | command = "Target.createTarget"; 103 | result = driver.executeCdpCommand(command, params); 104 | assertThat(result, notNullValue()); 105 | assertThat(result, hasKey("targetId")); 106 | 107 | targetId = (String) result.get("targetId"); 108 | assertThat(targetId, notNullValue()); 109 | params = new HashMap<>(); 110 | params.put("targetId", targetId); 111 | command = "Target.attachToTarget"; 112 | result = driver.executeCdpCommand(command, params); 113 | assertThat(result, notNullValue()); 114 | assertThat(result, hasKey("sessionId")); 115 | 116 | String sessionId = (String) result.get("sessionId"); 117 | assertThat(sessionId, notNullValue()); 118 | System.err.println("SessionId: " + sessionId); 119 | } 120 | } 121 | -------------------------------------------------------------------------------- /src/test/java/com/github/sergueik/selenium/ZoomDevToolsTest.java: -------------------------------------------------------------------------------- 1 | package com.github.sergueik.selenium; 2 | 3 | /** 4 | * Copyright 2023,2024 Serguei Kouzmine 5 | */ 6 | 7 | import java.nio.file.Paths; 8 | import java.util.Optional; 9 | 10 | import org.junit.After; 11 | import org.junit.AfterClass; 12 | import org.junit.Before; 13 | import org.junit.BeforeClass; 14 | // import org.junit.Ignore; 15 | import org.junit.Test; 16 | // https://github.com/SeleniumHQ/selenium/tree/cdp_codegen/java/client/src/org/openqa/selenium/devtools 17 | 18 | import org.openqa.selenium.chrome.ChromeDriver; 19 | import org.openqa.selenium.chrome.ChromeOptions; 20 | import org.openqa.selenium.devtools.DevTools; 21 | import org.openqa.selenium.devtools.HasDevTools; 22 | import org.openqa.selenium.devtools.v127.input.Input; 23 | import org.openqa.selenium.devtools.v127.input.Input.DispatchKeyEventType; 24 | 25 | /** 26 | * Selected test scenarios for Selenium Chrome Developer Tools Selenium 4 bridge 27 | * https://chromedevtools.github.io/devtools-protocol/tot/Input/#method-dispatchKeyEvent * @author: Serguei Kouzmine (kouzmine_serguei@yahoo.com) 28 | * see also: 29 | * https://github.com/ChromeDevTools/devtools-protocol/issues/74 30 | * https://github.com/puppeteer/puppeteer/blob/main/src/common/Input.ts#L118 31 | */ 32 | 33 | public class ZoomDevToolsTest extends BaseDevToolsTest { 34 | 35 | private final static int delay = 1000; 36 | private static final int modifiers = 2; 37 | // Bit field representing pressed modifier keys. Alt=1, Ctrl=2, 38 | // Meta/Command=4, Shift=8 (default: 0) 39 | // NOTE: 2 has no effect 40 | private static String baseURL = "https://www.wikipedia.org"; 41 | 42 | @Before 43 | // https://chromedevtools.github.io/devtools-protocol/tot/Console#method-enable 44 | // https://chromedevtools.github.io/devtools-protocol/tot/Log#method-enable 45 | public void before() throws Exception { 46 | driver.get(baseURL); 47 | } 48 | 49 | @After 50 | public void after() { 51 | if (driver != null) { 52 | driver.quit(); 53 | } 54 | } 55 | 56 | @Test 57 | public void test() { 58 | // Act 59 | for (int cnt = 0; cnt != 5; cnt++) { 60 | 61 | chromeDevTools.send(Input.dispatchKeyEvent(DispatchKeyEventType.KEYDOWN, 62 | Optional.of(modifiers), Optional.empty(), Optional.of("-"), 63 | Optional.empty(), Optional.empty(), Optional.empty(), 64 | Optional.empty(), Optional.empty(), Optional.empty(), 65 | Optional.empty(), Optional.empty(), Optional.empty(), 66 | Optional.empty(), Optional.empty())); 67 | 68 | chromeDevTools.send(Input.dispatchKeyEvent(DispatchKeyEventType.KEYUP, 69 | Optional.of(modifiers), Optional.empty(), Optional.empty(), 70 | Optional. empty(), Optional.empty(), Optional.empty(), 71 | Optional.empty(), Optional.empty(), Optional.empty(), 72 | Optional.empty(), Optional.empty(), Optional.empty(), 73 | Optional.empty(), Optional.empty())); 74 | 75 | Utils.sleep(delay); 76 | } 77 | } 78 | } 79 | 80 | -------------------------------------------------------------------------------- /src/test/resources/call_ajax.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 |

GitHub JSON Data


8 |

{{myData}}

9 | 10 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /src/test/resources/fixed_size_page.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 22 | 23 | 24 | 25 |

  26 |
1366x768px
27 |
28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /src/test/resources/getStyle.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Returns computed style of the element or some of its properties 3 | * 4 | * arguments[0] {Element} The event target. 5 | * arguments[1] {String} The name of the property (e.g. 'width'). 6 | */ 7 | 8 | // http://www.htmlgoodies.com/html5/css/referencing-css3-properties-using-javascript.html#fbid=88eQV8NzD6Q 9 | // https://developer.mozilla.org/en-US/docs/Web/API/Window/getComputedStyle 10 | getStyle = function(element, property) { 11 | var result = ''; 12 | if (window.getComputedStyle) { 13 | var styleObj = window.getComputedStyle(element, null); 14 | // var styleObj = document.defaultView.getComputedStyle(element, null); 15 | if (undefined != property ) { 16 | result = styleObj.getPropertyValue(property); 17 | } else { 18 | var len = styleObj.length; 19 | for (var i = 0; i < len; i++) { 20 | var style = styleObj[i]; 21 | result += ' ' + style + ':' + styleObj.getPropertyValue(style) + '\n'; 22 | } 23 | } 24 | } 25 | // IE lacks getComputedStyle but has currentStyle 26 | else if (element.currentStyle) { 27 | try { 28 | result = element.currentStyle[property]; 29 | } catch (e) {} 30 | } 31 | return result; 32 | } 33 | 34 | var element = arguments[0]; 35 | var property = arguments[1]; 36 | return getStyle(element, property); -------------------------------------------------------------------------------- /src/test/resources/iframe_example.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | Frames 4 | 5 | 6 | 7 | 8 |
9 | 11 |
12 |
13 | 15 |
16 | 17 | 18 | -------------------------------------------------------------------------------- /src/test/resources/image_page.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | typical screen sizes 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /src/test/resources/inner_html_example.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 |

Light DOM

8 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /src/test/resources/ng_basic.htm: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 8 | 10 | 11 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 |
{{item.a}}{{item.b}}{{item.c}}
45 | 46 | -------------------------------------------------------------------------------- /src/test/resources/sizes.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sergueik/selenium_cdp/4944544674e62f6efd3584b7976f666a495fc137/src/test/resources/sizes.jpg -------------------------------------------------------------------------------- /src/test/resources/test1.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /src/test/resources/test2.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | not displayed 8 | 9 | 10 | -------------------------------------------------------------------------------- /src/test/resources/tryit1.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 |

The Window Object

6 |

The prompt() Method

7 | 8 |

Click the button to demonstrate the prompt box.

9 | 10 | 11 | 12 |

13 | 14 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /src/test/resources/tryjsref_prompt.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 |

The Window Object

6 |

The prompt() Method

7 | 8 |

Click the button to demonstrate the prompt box.

9 | 10 | 11 | 12 |

13 | 14 | 23 | 24 | 25 | 26 | --------------------------------------------------------------------------------