From f4301810c6a3605676e672c30f40cf123266715d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Gro=C3=9Fmann?= Date: Mon, 28 Nov 2022 17:53:26 +0100 Subject: [PATCH 01/64] Migrated to Selenium 4 for RemoteDriver --- build.gradle | 2 +- .../tic/testframework/constants/Browsers.java | 1 - driver-ui-desktop/build.gradle | 9 -- .../DesktopWebDriverFactory.java | 87 +++-------- .../webdrivermanager/HttpClientFactory.java | 141 +++++++++--------- .../utils/DefaultCapabilityUtils.java | 11 +- .../AbstractWebDriverRequest.java | 11 +- integration-tests/build.gradle | 2 +- .../testframework/AbstractTestSitesTest.java | 10 +- .../testframework/AbstractWebDriverTest.java | 21 +-- .../server/{Server.java => StaticServer.java} | 26 ++-- .../playground/DriverAndGuiElementTest.java | 19 +-- .../testframework/test/utils/ServerTest.java | 21 +-- .../src/test/resources/test.properties | 4 +- 14 files changed, 154 insertions(+), 211 deletions(-) rename integration-tests/src/main/java/eu/tsystems/mms/tic/testframework/core/server/{Server.java => StaticServer.java} (77%) diff --git a/build.gradle b/build.gradle index 572abf8448..19a4b5aea9 100644 --- a/build.gradle +++ b/build.gradle @@ -20,7 +20,7 @@ ext { core = project(':core') report = project(':report-ng') - seleniumVersion = '3.141.59' + seleniumVersion = '4.6.0' guavaVersion = "28.1-jre" moduleVersion = '2-SNAPSHOT' diff --git a/core/src/main/java/eu/tsystems/mms/tic/testframework/constants/Browsers.java b/core/src/main/java/eu/tsystems/mms/tic/testframework/constants/Browsers.java index 4725e13fa1..3dc218b1d9 100644 --- a/core/src/main/java/eu/tsystems/mms/tic/testframework/constants/Browsers.java +++ b/core/src/main/java/eu/tsystems/mms/tic/testframework/constants/Browsers.java @@ -28,7 +28,6 @@ public class Browsers { public static final String ie = "ie"; public static final String edge = "edge"; public static final String safari = "safari"; - public static final String phantomjs = "phantomjs"; public static final String htmlunit = "htmlunit"; public static final String chromeHeadless = "chromeHeadless"; } diff --git a/driver-ui-desktop/build.gradle b/driver-ui-desktop/build.gradle index f44580d227..79a856343c 100644 --- a/driver-ui-desktop/build.gradle +++ b/driver-ui-desktop/build.gradle @@ -1,14 +1,5 @@ dependencies { api driver_ui - - // - implementation 'net.anthavio:phanbedder-2.1.1:1.0.0' - implementation ('com.codeborne:phantomjsdriver:1.4.4') { - // @see https://stackoverflow.com/questions/43859075/using-latest-selenium-ver-with-java-8-is-giving-logginghandler-error - exclude group: 'org.seleniumhq.selenium', module: 'selenium-api' - exclude group: 'org.seleniumhq.selenium', module: 'selenium-remote-driver' - } - // } test { diff --git a/driver-ui-desktop/src/main/java/eu/tsystems/mms/tic/testframework/webdrivermanager/DesktopWebDriverFactory.java b/driver-ui-desktop/src/main/java/eu/tsystems/mms/tic/testframework/webdrivermanager/DesktopWebDriverFactory.java index 644c40a23d..9ae802856c 100644 --- a/driver-ui-desktop/src/main/java/eu/tsystems/mms/tic/testframework/webdrivermanager/DesktopWebDriverFactory.java +++ b/driver-ui-desktop/src/main/java/eu/tsystems/mms/tic/testframework/webdrivermanager/DesktopWebDriverFactory.java @@ -37,21 +37,9 @@ import eu.tsystems.mms.tic.testframework.report.utils.ExecutionContextUtils; import eu.tsystems.mms.tic.testframework.testing.TestControllerProvider; import eu.tsystems.mms.tic.testframework.testing.WebDriverManagerProvider; -import eu.tsystems.mms.tic.testframework.utils.DefaultCapabilityUtils; -import eu.tsystems.mms.tic.testframework.utils.FileUtils; import eu.tsystems.mms.tic.testframework.utils.Sleepy; import eu.tsystems.mms.tic.testframework.utils.TimerUtils; import eu.tsystems.mms.tic.testframework.webdriver.WebDriverFactory; -import eu.tsystems.mms.tic.testframework.webdrivermanager.desktop.WebDriverMode; -import java.io.File; -import java.lang.reflect.Constructor; -import java.net.URL; -import java.util.Arrays; -import java.util.Date; -import java.util.HashMap; -import java.util.List; -import java.util.concurrent.TimeUnit; -import net.anthavio.phanbedder.Phanbedder; import org.openqa.selenium.Capabilities; import org.openqa.selenium.Dimension; import org.openqa.selenium.Point; @@ -64,9 +52,6 @@ import org.openqa.selenium.firefox.FirefoxOptions; import org.openqa.selenium.ie.InternetExplorerDriver; import org.openqa.selenium.ie.InternetExplorerOptions; -import org.openqa.selenium.phantomjs.PhantomJSDriver; -import org.openqa.selenium.phantomjs.PhantomJSDriverService; -import org.openqa.selenium.remote.BrowserType; import org.openqa.selenium.remote.CapabilityType; import org.openqa.selenium.remote.DesiredCapabilities; import org.openqa.selenium.remote.HttpCommandExecutor; @@ -76,20 +61,25 @@ import org.openqa.selenium.safari.SafariOptions; import org.openqa.selenium.support.events.EventFiringWebDriver; +import java.lang.reflect.Constructor; +import java.net.URL; +import java.util.Arrays; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.concurrent.TimeUnit; + public class DesktopWebDriverFactory implements WebDriverFactory, Loggable, WebDriverManagerProvider, TestControllerProvider, - Sleepy -{ + Sleepy { //public static final TimingInfosCollector STARTUP_TIME_COLLECTOR = new TimingInfosCollector(); - private static File phantomjsFile = null; - @Override public WebDriver createWebDriver(WebDriverRequest request, SessionContext sessionContext) { - return startSession((DesktopWebDriverRequest)request, sessionContext); + return startSession((DesktopWebDriverRequest) request, sessionContext); } private WebDriver startSession(DesktopWebDriverRequest desktopWebDriverRequest, SessionContext sessionContext) { @@ -171,19 +161,6 @@ public WebDriverRequest prepareWebDriverRequest(WebDriverRequest webDriverReques } userAgentCapabilities = chromeOptions; break; - case Browsers.phantomjs: - File phantomjsFile = getPhantomJSBinary(); - DesiredCapabilities phantomJsOptions = new DesiredCapabilities(); - phantomJsOptions.setCapability(PhantomJSDriverService.PHANTOMJS_EXECUTABLE_PATH_PROPERTY, phantomjsFile.getAbsolutePath()); - phantomJsOptions.setBrowserName(BrowserType.PHANTOMJS); - phantomJsOptions.setJavascriptEnabled(true); - - String[] args = { - "--ssl-protocol=any" - }; - phantomJsOptions.setCapability(PhantomJSDriverService.PHANTOMJS_CLI_ARGS, args); - userAgentCapabilities = phantomJsOptions; - break; case Browsers.safari: SafariOptions safariOptions = new SafariOptions(); WEB_DRIVER_MANAGER.getUserAgentConfig(browser).ifPresent(userAgentConfig -> { @@ -214,7 +191,7 @@ public WebDriverRequest prepareWebDriverRequest(WebDriverRequest webDriverReques @Override public void setupNewWebDriverSession(EventFiringWebDriver eventFiringWebDriver, SessionContext sessionContext) { - DesktopWebDriverRequest desktopWebDriverRequest = (DesktopWebDriverRequest)sessionContext.getWebDriverRequest(); + DesktopWebDriverRequest desktopWebDriverRequest = (DesktopWebDriverRequest) sessionContext.getWebDriverRequest(); final String browser = desktopWebDriverRequest.getBrowser(); // add event listeners @@ -333,7 +310,7 @@ private WebDriver newWebDriver(DesktopWebDriverRequest desktopWebDriverRequest, try { newDriver = startNewWebDriverSession(desktopWebDriverRequest, sessionContext); } catch (final SetupException e) { - int ms = Testerra.Properties.WEBDRIVER_TIMEOUT_SECONDS_RETRY.asLong().intValue()*1000; + int ms = Testerra.Properties.WEBDRIVER_TIMEOUT_SECONDS_RETRY.asLong().intValue() * 1000; log().error(String.format("Error starting WebDriver. Trying again in %d seconds", (ms / 1000)), e); TimerUtils.sleep(ms); newDriver = startNewWebDriverSession(desktopWebDriverRequest, sessionContext); @@ -361,9 +338,6 @@ private WebDriver startNewWebDriverSession(DesktopWebDriverRequest request, Sess case Browsers.chromeHeadless: driverClass = ChromeDriver.class; break; - case Browsers.phantomjs: - driverClass = PhantomJSDriver.class; - break; case Browsers.safari: driverClass = SafariDriver.class; break; @@ -380,8 +354,10 @@ private WebDriver startNewWebDriverSession(DesktopWebDriverRequest request, Sess try { if (request.getServerUrl().isPresent()) { final URL seleniumUrl = request.getServerUrl().get(); - final HttpCommandExecutor httpCommandExecutor = new HttpCommandExecutor(new HashMap<>(), seleniumUrl, new HttpClientFactory()); - webDriver = new RemoteWebDriver(httpCommandExecutor, requestCapabilities); + // TODO: Reduced timeouts of Selenium 3, needed in Selenium 4? +// final HttpCommandExecutor httpCommandExecutor = new HttpCommandExecutor(new HashMap<>(), seleniumUrl, new HttpClientFactory()); +// final HttpCommandExecutor httpCommandExecutor = new HttpCommandExecutor(new HashMap<>(), seleniumUrl); + webDriver = new RemoteWebDriver(seleniumUrl, requestCapabilities); webDriver.setFileDetector(new LocalFileDetector()); sessionContext.setNodeUrl(seleniumUrl); } else { @@ -397,34 +373,15 @@ private WebDriver startNewWebDriverSession(DesktopWebDriverRequest request, Sess return webDriver; } - private File getPhantomJSBinary() { - if (phantomjsFile == null) { - log().info("Unpacking phantomJS..."); - try { - phantomjsFile = Phanbedder.unpack(); //Phanbedder to the rescue! - } catch (Exception e) { - if (e.getMessage() != null && e.getMessage().toLowerCase().contains("failed to make target directory")) { - File tmp = new File(FileUtils.getTempDirectory(), "phantomjs" + System.currentTimeMillis()); - phantomjsFile = Phanbedder.unpack(tmp); - } else { - throw e; - } - } - log().info("Unpacked phantomJS to: " + phantomjsFile); - } - return phantomjsFile; - } - @Override public List getSupportedBrowsers() { return Arrays.asList( - Browsers.safari, - Browsers.ie, - Browsers.chrome, - Browsers.chromeHeadless, - Browsers.edge, - Browsers.firefox, - Browsers.phantomjs + Browsers.safari, + Browsers.ie, + Browsers.chrome, + Browsers.chromeHeadless, + Browsers.edge, + Browsers.firefox ); } diff --git a/driver-ui-desktop/src/main/java/eu/tsystems/mms/tic/testframework/webdrivermanager/HttpClientFactory.java b/driver-ui-desktop/src/main/java/eu/tsystems/mms/tic/testframework/webdrivermanager/HttpClientFactory.java index 436ca23131..6688d5ed65 100644 --- a/driver-ui-desktop/src/main/java/eu/tsystems/mms/tic/testframework/webdrivermanager/HttpClientFactory.java +++ b/driver-ui-desktop/src/main/java/eu/tsystems/mms/tic/testframework/webdrivermanager/HttpClientFactory.java @@ -23,17 +23,10 @@ * */ -import com.google.common.base.Strings; -import eu.tsystems.mms.tic.testframework.common.PropertyManager; -import eu.tsystems.mms.tic.testframework.constants.TesterraProperties; -import java.net.URL; -import java.time.Duration; -import okhttp3.ConnectionPool; -import okhttp3.Credentials; -import okhttp3.Request; -import okhttp3.Response; +import org.openqa.selenium.remote.http.ClientConfig; import org.openqa.selenium.remote.http.HttpClient; -import static java.util.concurrent.TimeUnit.MILLISECONDS; + +import java.time.Duration; /** * This Client Factory allows us to reduces timeouts of 3 HOURS to our custom timeouts. @@ -45,71 +38,79 @@ * @author Eric Kubenka */ class HttpClientFactory implements HttpClient.Factory { + private final Duration factoryConnectionTimeout = Duration.ofSeconds(120); // Kill, when connect does not succeed in this timeout private final Duration factoryReadTimeout = factoryConnectionTimeout; // Kill hanging / stuck selenium commands after this timeout. - private final ConnectionPool pool = new ConnectionPool(); - - @Override - public HttpClient.Builder builder() { - - // this code is copied from OkHttpClient.Factory .. and modified in timeout configuration. - return new HttpClient.Builder() { - - @Override - public HttpClient createClient(URL url) { - - connectionTimeout = factoryConnectionTimeout; - readTimeout = factoryReadTimeout; - - okhttp3.OkHttpClient.Builder client = new okhttp3.OkHttpClient.Builder() - .connectionPool(pool) - .followRedirects(true) - .followSslRedirects(true) - .proxy(proxy) - .readTimeout(readTimeout.toMillis(), MILLISECONDS) - .connectTimeout(connectionTimeout.toMillis(), MILLISECONDS); - String info = url.getUserInfo(); - if (!Strings.isNullOrEmpty(info)) { - String[] parts = info.split(":", 2); - String user = parts[0]; - String pass = parts.length > 1 ? parts[1] : null; - - String credentials = Credentials.basic(user, pass); - - client.authenticator((route, response) -> { - if (response.request().header("Authorization") != null) { - return null; // Give up, we've already attempted to authenticate. - } - - return response.request().newBuilder() - .header("Authorization", credentials) - .build(); - }); - } - - client.addNetworkInterceptor(chain -> { - Request request = chain.request(); - Response response = chain.proceed(request); - return response.code() == 408 - ? response.newBuilder().code(500).message("Server-Side Timeout").build() - : response; - }); - - return new org.openqa.selenium.remote.internal.OkHttpClient(client.build(), url); - } - }; - } +// private final ConnectionPool pool = new ConnectionPool(); + // TODO: Just a placeholder @Override - public HttpClient createClient(URL url) { - - return builder().createClient(url); + public HttpClient createClient(ClientConfig config) { + return null; } - @Override - public void cleanupIdleClients() { - - pool.evictAll(); - } +// @Override +// public HttpClient.Builder builder() { +// +// // this code is copied from OkHttpClient.Factory .. and modified in timeout configuration. +// return new HttpClient.Builder() { +// +// @Override +// public HttpClient createClient(URL url) { +// +// connectionTimeout = factoryConnectionTimeout; +// readTimeout = factoryReadTimeout; +// +// okhttp3.OkHttpClient.Builder client = new okhttp3.OkHttpClient.Builder() +// .connectionPool(pool) +// .followRedirects(true) +// .followSslRedirects(true) +// .proxy(proxy) +// .readTimeout(readTimeout.toMillis(), MILLISECONDS) +// .connectTimeout(connectionTimeout.toMillis(), MILLISECONDS); +// +// String info = url.getUserInfo(); +// if (!Strings.isNullOrEmpty(info)) { +// String[] parts = info.split(":", 2); +// String user = parts[0]; +// String pass = parts.length > 1 ? parts[1] : null; +// +// String credentials = Credentials.basic(user, pass); +// +// client.authenticator((route, response) -> { +// if (response.request().header("Authorization") != null) { +// return null; // Give up, we've already attempted to authenticate. +// } +// +// return response.request().newBuilder() +// .header("Authorization", credentials) +// .build(); +// }); +// } +// +// client.addNetworkInterceptor(chain -> { +// Request request = chain.request(); +// Response response = chain.proceed(request); +// return response.code() == 408 +// ? response.newBuilder().code(500).message("Server-Side Timeout").build() +// : response; +// }); +// +// return new org.openqa.selenium.remote.internal.OkHttpClient(client.build(), url); +// } +// }; +// } +// +// @Override +// public HttpClient createClient(URL url) { +// +// return builder().createClient(url); +// } +// +// @Override +// public void cleanupIdleClients() { +// +// pool.evictAll(); +// } } diff --git a/driver-ui/src/main/java/eu/tsystems/mms/tic/testframework/utils/DefaultCapabilityUtils.java b/driver-ui/src/main/java/eu/tsystems/mms/tic/testframework/utils/DefaultCapabilityUtils.java index 7f372703eb..699759171e 100644 --- a/driver-ui/src/main/java/eu/tsystems/mms/tic/testframework/utils/DefaultCapabilityUtils.java +++ b/driver-ui/src/main/java/eu/tsystems/mms/tic/testframework/utils/DefaultCapabilityUtils.java @@ -77,12 +77,19 @@ private Map shortChromeExtensionStrings(Map capa if (chromeOptionsObject != null) { final Map chromeOptions = (Map) chromeOptionsObject; if (chromeOptions.containsKey("extensions")) { - chromeOptions.put("extensions", shortAllStringsInLists(chromeOptions.get("extensions"))); +// chromeOptions.put("extensions", shortAllStringsInLists(chromeOptions.get("extensions"))); + List extensions = shortAllStringsInLists(chromeOptions.get("extensions")); + if (extensions.size() > 0) { + chromeOptions.put("extensions", extensions); + } } } if (extensionsObject != null) { - capabilityMap.put("extensions", shortAllStringsInLists(extensionsObject)); + List extensions = shortAllStringsInLists(extensionsObject); + if (extensions.size() > 0) { + capabilityMap.put("extensions", shortAllStringsInLists(extensionsObject)); + } } return capabilityMap; diff --git a/driver-ui/src/main/java/eu/tsystems/mms/tic/testframework/webdrivermanager/AbstractWebDriverRequest.java b/driver-ui/src/main/java/eu/tsystems/mms/tic/testframework/webdrivermanager/AbstractWebDriverRequest.java index b2631028e7..da2121c3e1 100644 --- a/driver-ui/src/main/java/eu/tsystems/mms/tic/testframework/webdrivermanager/AbstractWebDriverRequest.java +++ b/driver-ui/src/main/java/eu/tsystems/mms/tic/testframework/webdrivermanager/AbstractWebDriverRequest.java @@ -22,12 +22,13 @@ import eu.tsystems.mms.tic.testframework.common.PropertyManager; import eu.tsystems.mms.tic.testframework.constants.TesterraProperties; +import org.apache.commons.lang3.StringUtils; +import org.openqa.selenium.remote.DesiredCapabilities; + import java.net.MalformedURLException; import java.net.URL; import java.util.Map; import java.util.Optional; -import org.apache.commons.lang3.StringUtils; -import org.openqa.selenium.remote.DesiredCapabilities; public class AbstractWebDriverRequest implements WebDriverRequest { @@ -59,11 +60,13 @@ public void setBrowser(String browser) { } public String getBrowserVersion() { - return getDesiredCapabilities().getVersion(); + return getDesiredCapabilities().getBrowserVersion(); } public void setBrowserVersion(String browserVersion) { - this.getDesiredCapabilities().setVersion(browserVersion); + if (StringUtils.isNotBlank(browserVersion)) { + this.getDesiredCapabilities().setVersion(browserVersion); + } } public String getSessionKey() { diff --git a/integration-tests/build.gradle b/integration-tests/build.gradle index b0a497a992..aefbb8a6f3 100644 --- a/integration-tests/build.gradle +++ b/integration-tests/build.gradle @@ -9,7 +9,7 @@ dependencies { // ResponsiveClassFinder tests implementation 'org.reflections:reflections:0.9.12' - api 'org.seleniumhq.selenium:selenium-server:' + seleniumVersion + api 'org.eclipse.jetty:jetty-server:9.4.3.v20170317' } // Deactivate JAR publishing diff --git a/integration-tests/src/main/java/eu/tsystems/mms/tic/testframework/AbstractTestSitesTest.java b/integration-tests/src/main/java/eu/tsystems/mms/tic/testframework/AbstractTestSitesTest.java index 296b55a9f9..13f0855cea 100644 --- a/integration-tests/src/main/java/eu/tsystems/mms/tic/testframework/AbstractTestSitesTest.java +++ b/integration-tests/src/main/java/eu/tsystems/mms/tic/testframework/AbstractTestSitesTest.java @@ -22,10 +22,9 @@ package eu.tsystems.mms.tic.testframework; -import eu.tsystems.mms.tic.testframework.core.server.Server; +import eu.tsystems.mms.tic.testframework.core.server.StaticServer; import eu.tsystems.mms.tic.testframework.core.testpage.TestPage; import eu.tsystems.mms.tic.testframework.logging.Loggable; -import eu.tsystems.mms.tic.testframework.pageobjects.UiElement; import eu.tsystems.mms.tic.testframework.utils.FileUtils; import java.net.BindException; import org.openqa.selenium.WebDriver; @@ -35,7 +34,8 @@ * Abstract test class for tests based on static test site resources */ public abstract class AbstractTestSitesTest extends AbstractWebDriverTest implements Loggable { - protected static Server server = new Server(FileUtils.getResourceFile("testsites")); + + protected static StaticServer staticServer = new StaticServer(FileUtils.getResourceFile("testsites")); protected TestPage getTestPage() { return TestPage.INPUT_TEST_PAGE; @@ -44,7 +44,7 @@ protected TestPage getTestPage() { @BeforeTest(alwaysRun = true) public void setUp() throws Exception { try { - server.start(80); + staticServer.start(80); } catch (BindException e) { log().warn("Use already running WebServer: " + e.getMessage()); } @@ -65,7 +65,7 @@ public WebDriver getWebDriver() { */ private void visitTestPage(WebDriver driver, TestPage testPage) { if (!driver.getCurrentUrl().contains(testPage.getPath())) { - String baseUrl = String.format("http://localhost:%d/%s", server.getPort(), testPage.getPath()); + String baseUrl = String.format("http://localhost:%d/%s", staticServer.getPort(), testPage.getPath()); driver.get(baseUrl); } } diff --git a/integration-tests/src/main/java/eu/tsystems/mms/tic/testframework/AbstractWebDriverTest.java b/integration-tests/src/main/java/eu/tsystems/mms/tic/testframework/AbstractWebDriverTest.java index be527906a5..ed68da3ce3 100644 --- a/integration-tests/src/main/java/eu/tsystems/mms/tic/testframework/AbstractWebDriverTest.java +++ b/integration-tests/src/main/java/eu/tsystems/mms/tic/testframework/AbstractWebDriverTest.java @@ -29,8 +29,6 @@ import eu.tsystems.mms.tic.testframework.useragents.ChromeConfig; import eu.tsystems.mms.tic.testframework.webdriver.WebDriverRetainer; import eu.tsystems.mms.tic.testframework.webdrivermanager.AbstractWebDriverRequest; -import eu.tsystems.mms.tic.testframework.webdrivermanager.WebDriverManager; -import java.lang.reflect.Method; import org.openqa.selenium.WebDriver; import org.openqa.selenium.WebDriverException; import org.openqa.selenium.chrome.ChromeOptions; @@ -38,12 +36,13 @@ import org.testng.annotations.AfterSuite; import org.testng.annotations.BeforeMethod; +import java.lang.reflect.Method; + /** * Abstract test class for tests using a WebDriver */ public abstract class AbstractWebDriverTest extends TesterraTest implements WebDriverRetainer, WebDriverManagerProvider, Loggable { - // static { // WebDriverManager.config().closeWindowsAfterTestMethod = false; // } @@ -57,7 +56,7 @@ public abstract class AbstractWebDriverTest extends TesterraTest implements WebD @AfterSuite(alwaysRun = true) private void closeBrowsers() { - WebDriverManager.forceShutdownAllThreads(); + WEB_DRIVER_MANAGER.shutdownAllSessions(); } /** @@ -75,22 +74,13 @@ public void configure(ChromeOptions options) { }); } - /** - * Sets the unsupportedBrowser=true flag for the @Fails annotation - */ - protected static void setUnsupportedBrowserFlag() { - if (Browsers.phantomjs.equals(WEB_DRIVER_MANAGER.getConfig().getBrowser())) { - System.setProperty("unsupportedBrowser", "true"); - } - } - protected AbstractWebDriverRequest getWebDriverRequest() { return null; } private WebDriver _getWebDriver() { WebDriver webDriver; - AbstractWebDriverRequest request = getWebDriverRequest(); + AbstractWebDriverRequest request = getWebDriverRequest(); if (request != null) { webDriver = WEB_DRIVER_MANAGER.getWebDriver(request); } else { @@ -126,7 +116,4 @@ public WebDriver getWebDriver() { return this._getWebDriver(); } - static { - setUnsupportedBrowserFlag(); - } } diff --git a/integration-tests/src/main/java/eu/tsystems/mms/tic/testframework/core/server/Server.java b/integration-tests/src/main/java/eu/tsystems/mms/tic/testframework/core/server/StaticServer.java similarity index 77% rename from integration-tests/src/main/java/eu/tsystems/mms/tic/testframework/core/server/Server.java rename to integration-tests/src/main/java/eu/tsystems/mms/tic/testframework/core/server/StaticServer.java index d193074657..07f7940a77 100644 --- a/integration-tests/src/main/java/eu/tsystems/mms/tic/testframework/core/server/Server.java +++ b/integration-tests/src/main/java/eu/tsystems/mms/tic/testframework/core/server/StaticServer.java @@ -22,21 +22,23 @@ package eu.tsystems.mms.tic.testframework.core.server; import eu.tsystems.mms.tic.testframework.utils.FileUtils; +import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.server.handler.ContextHandler; +import org.eclipse.jetty.server.handler.ResourceHandler; + import java.io.File; import java.net.ServerSocket; -import org.seleniumhq.jetty9.server.handler.ContextHandler; -import org.seleniumhq.jetty9.server.handler.ResourceHandler; -public class Server { - private org.seleniumhq.jetty9.server.Server server; +public class StaticServer { + private Server server; private File rootDir; private int port; - public Server() { + public StaticServer() { this(new File(System.getProperty("user.dir"))); } - public Server(File rootDir) { + public StaticServer(File rootDir) { this.rootDir = rootDir; } @@ -46,11 +48,11 @@ public int getPort() { public void start(int port) throws Exception { this.port = port; - server = new org.seleniumhq.jetty9.server.Server(port); + server = new Server(port); ResourceHandler resourceHandler = new ResourceHandler(); resourceHandler.setDirectoriesListed(true); resourceHandler.setResourceBase(rootDir.getAbsolutePath()); - ContextHandler contextHandler= new ContextHandler("/"); + ContextHandler contextHandler = new ContextHandler("/"); contextHandler.setHandler(resourceHandler); server.setHandler(contextHandler); @@ -61,7 +63,7 @@ public void start(int port) throws Exception { public void start() throws Exception { int port; try ( - ServerSocket socket = new ServerSocket(0); + ServerSocket socket = new ServerSocket(0); ) { port = socket.getLocalPort(); socket.close(); @@ -76,11 +78,11 @@ public void stop() throws Exception { } public static void main(String[] args) throws Exception { - Server server = new Server(FileUtils.getResourceFile("testsites")); - server.start(); + StaticServer staticServer = new StaticServer(FileUtils.getResourceFile("testsites")); + staticServer.start(); System.out.println("Hit ENTER to stop"); System.in.read(); - server.stop(); + staticServer.stop(); } } diff --git a/integration-tests/src/test/java/eu/tsystems/mms/tic/testframework/playground/DriverAndGuiElementTest.java b/integration-tests/src/test/java/eu/tsystems/mms/tic/testframework/playground/DriverAndGuiElementTest.java index ea1108a20b..55695fe55f 100644 --- a/integration-tests/src/test/java/eu/tsystems/mms/tic/testframework/playground/DriverAndGuiElementTest.java +++ b/integration-tests/src/test/java/eu/tsystems/mms/tic/testframework/playground/DriverAndGuiElementTest.java @@ -19,33 +19,28 @@ * under the License. * */ - package eu.tsystems.mms.tic.testframework.playground; +package eu.tsystems.mms.tic.testframework.playground; import eu.tsystems.mms.tic.testframework.AbstractTestSitesTest; import eu.tsystems.mms.tic.testframework.constants.Browsers; -import eu.tsystems.mms.tic.testframework.core.pageobjects.testdata.PageWithExistingElement; import eu.tsystems.mms.tic.testframework.pageobjects.UiElement; import eu.tsystems.mms.tic.testframework.pageobjects.UiElementFinder; -import eu.tsystems.mms.tic.testframework.pageobjects.factory.PageFactory; import eu.tsystems.mms.tic.testframework.report.model.context.SessionContext; -import eu.tsystems.mms.tic.testframework.testing.TesterraTest; import eu.tsystems.mms.tic.testframework.testing.UiElementFinderFactoryProvider; -import eu.tsystems.mms.tic.testframework.testing.WebDriverManagerProvider; import eu.tsystems.mms.tic.testframework.webdrivermanager.DesktopWebDriverRequest; import eu.tsystems.mms.tic.testframework.webdrivermanager.WebDriverSessionsManager; -import eu.tsystems.mms.tic.testframework.webdrivermanager.desktop.WebDriverMode; -import java.util.Map; - import org.openqa.selenium.By; import org.openqa.selenium.WebDriver; import org.openqa.selenium.remote.DesiredCapabilities; import org.testng.Assert; import org.testng.annotations.Test; +import java.util.Map; + public class DriverAndGuiElementTest extends AbstractTestSitesTest implements UiElementFinderFactoryProvider { @Test - public void testUiElement() throws Exception { + public void testUiElement() { WebDriver driver = getWebDriver(); UiElementFinder uiElementFinder = UI_ELEMENT_FINDER_FACTORY.create(driver); @@ -59,8 +54,7 @@ public void testUiElement() throws Exception { public void testTapCapabilities() throws Exception { DesktopWebDriverRequest request = new DesktopWebDriverRequest(); request.setBaseUrl("http://google.de"); - request.setWebDriverMode(WebDriverMode.local); - request.setBrowser(Browsers.phantomjs); + request.setBrowser(Browsers.chrome); /* create caps @@ -80,8 +74,7 @@ public void testTapCapabilities() throws Exception { public void testFailing() throws Exception { DesktopWebDriverRequest request = new DesktopWebDriverRequest(); request.setBaseUrl("http://google.de"); - request.setWebDriverMode(WebDriverMode.local); - request.setBrowser(Browsers.phantomjs); + request.setBrowser(Browsers.chrome); WEB_DRIVER_MANAGER.getWebDriver(request); Assert.assertTrue(false); diff --git a/integration-tests/src/test/java/eu/tsystems/mms/tic/testframework/test/utils/ServerTest.java b/integration-tests/src/test/java/eu/tsystems/mms/tic/testframework/test/utils/ServerTest.java index c8bb38fad3..3bd4d18436 100644 --- a/integration-tests/src/test/java/eu/tsystems/mms/tic/testframework/test/utils/ServerTest.java +++ b/integration-tests/src/test/java/eu/tsystems/mms/tic/testframework/test/utils/ServerTest.java @@ -21,35 +21,36 @@ */ package eu.tsystems.mms.tic.testframework.test.utils; -import eu.tsystems.mms.tic.testframework.core.server.Server; +import eu.tsystems.mms.tic.testframework.core.server.StaticServer; import java.net.BindException; + import org.testng.Assert; import org.testng.annotations.Test; public class ServerTest { - private Server server; + private StaticServer staticServer; @Test public void test_StartServer() throws Exception { - server = new Server(); - server.start(1234); + staticServer = new StaticServer(); + staticServer.start(1234); } @Test(dependsOnMethods = "test_StartServer") public void test_AlreadyStartedServer() throws Exception{ - Server newServer = new Server(); + StaticServer newStaticServer = new StaticServer(); try { - newServer.start(1234); + newStaticServer.start(1234); } catch (BindException e) { - Assert.assertEquals(newServer.getPort(), 1234); + Assert.assertEquals(newStaticServer.getPort(), 1234); } } @Test public void test_NewRandomPort() throws Exception { - Server newServer = new Server(); - newServer.start(); - Assert.assertTrue(newServer.getPort() > 0); + StaticServer newStaticServer = new StaticServer(); + newStaticServer.start(); + Assert.assertTrue(newStaticServer.getPort() > 0); } } diff --git a/integration-tests/src/test/resources/test.properties b/integration-tests/src/test/resources/test.properties index 5ef7033dbc..ac493f22b8 100644 --- a/integration-tests/src/test/resources/test.properties +++ b/integration-tests/src/test/resources/test.properties @@ -6,7 +6,9 @@ tt.browser.maximize=false #tt.browser.maximize.position=right tt.window.size=800x600 -#tt.selenium.server.host=localhost +#tt.browser.version=90 + +tt.selenium.server.host=localhost tt.element.timeout.seconds=2 tt.report.screencaster.active=false From e15554cd0642af43a9423607226546ec8ffd4ae7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Gro=C3=9Fmann?= Date: Mon, 28 Nov 2022 18:20:17 +0100 Subject: [PATCH 02/64] Added Selenium 4 support for local webdriver --- .../DesktopWebDriverFactory.java | 19 +++++++++++++++---- .../src/test/resources/test.properties | 8 +++----- 2 files changed, 18 insertions(+), 9 deletions(-) diff --git a/driver-ui-desktop/src/main/java/eu/tsystems/mms/tic/testframework/webdrivermanager/DesktopWebDriverFactory.java b/driver-ui-desktop/src/main/java/eu/tsystems/mms/tic/testframework/webdrivermanager/DesktopWebDriverFactory.java index 9ae802856c..b8cb66602c 100644 --- a/driver-ui-desktop/src/main/java/eu/tsystems/mms/tic/testframework/webdrivermanager/DesktopWebDriverFactory.java +++ b/driver-ui-desktop/src/main/java/eu/tsystems/mms/tic/testframework/webdrivermanager/DesktopWebDriverFactory.java @@ -52,9 +52,9 @@ import org.openqa.selenium.firefox.FirefoxOptions; import org.openqa.selenium.ie.InternetExplorerDriver; import org.openqa.selenium.ie.InternetExplorerOptions; +import org.openqa.selenium.remote.AbstractDriverOptions; import org.openqa.selenium.remote.CapabilityType; import org.openqa.selenium.remote.DesiredCapabilities; -import org.openqa.selenium.remote.HttpCommandExecutor; import org.openqa.selenium.remote.LocalFileDetector; import org.openqa.selenium.remote.RemoteWebDriver; import org.openqa.selenium.safari.SafariDriver; @@ -65,7 +65,6 @@ import java.net.URL; import java.util.Arrays; import java.util.Date; -import java.util.HashMap; import java.util.List; import java.util.concurrent.TimeUnit; @@ -325,24 +324,30 @@ private WebDriver newWebDriver(DesktopWebDriverRequest desktopWebDriverRequest, private WebDriver startNewWebDriverSession(DesktopWebDriverRequest request, SessionContext sessionContext) { final Class driverClass; + final Class optionClass; final String browser = request.getBrowser(); switch (browser) { case Browsers.firefox: driverClass = FirefoxDriver.class; + optionClass = FirefoxOptions.class; break; case Browsers.ie: driverClass = InternetExplorerDriver.class; + optionClass = InternetExplorerOptions.class; break; case Browsers.chrome: case Browsers.chromeHeadless: driverClass = ChromeDriver.class; + optionClass = ChromeOptions.class; break; case Browsers.safari: driverClass = SafariDriver.class; + optionClass = SafariOptions.class; break; case Browsers.edge: driverClass = EdgeDriver.class; + optionClass = EdgeOptions.class; break; default: throw new SystemException("Browser not supported: " + browser); @@ -362,8 +367,14 @@ private WebDriver startNewWebDriverSession(DesktopWebDriverRequest request, Sess sessionContext.setNodeUrl(seleniumUrl); } else { log().warn("Local WebDriver setups may cause side effects. It's highly recommended to use a remote Selenium configurations for all environments!"); - Constructor constructor = driverClass.getConstructor(Capabilities.class); - webDriver = constructor.newInstance(requestCapabilities); + + // Starting local webdriver needs caps as browser options + Constructor optionClassConstructor = optionClass.getConstructor(); + AbstractDriverOptions abstractDriverOptions = optionClassConstructor.newInstance(); + abstractDriverOptions.merge(requestCapabilities); + + Constructor constructor = driverClass.getConstructor(abstractDriverOptions.getClass()); + webDriver = constructor.newInstance(abstractDriverOptions); } } catch (Exception e) { WebDriverSessionsManager.SESSION_STARTUP_ERRORS.put(new Date(), e); diff --git a/integration-tests/src/test/resources/test.properties b/integration-tests/src/test/resources/test.properties index ac493f22b8..d58968ad8a 100644 --- a/integration-tests/src/test/resources/test.properties +++ b/integration-tests/src/test/resources/test.properties @@ -1,14 +1,12 @@ -tt.browser=chromeHeadless -#tt.browser=chrome +#tt.browser=chromeHeadless +tt.browser=chrome #tt.browser=firefox tt.browser.maximize=false #tt.browser.maximize=true #tt.browser.maximize.position=right tt.window.size=800x600 -#tt.browser.version=90 - -tt.selenium.server.host=localhost +#tt.selenium.server.host=localhost tt.element.timeout.seconds=2 tt.report.screencaster.active=false From 4656542ab8a7ce37f78d0344814cfc97275be7e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Gro=C3=9Fmann?= Date: Mon, 28 Nov 2022 18:32:11 +0100 Subject: [PATCH 03/64] Removed deprecated usage of timeout settings --- .../webdrivermanager/DesktopWebDriverFactory.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/driver-ui-desktop/src/main/java/eu/tsystems/mms/tic/testframework/webdrivermanager/DesktopWebDriverFactory.java b/driver-ui-desktop/src/main/java/eu/tsystems/mms/tic/testframework/webdrivermanager/DesktopWebDriverFactory.java index b8cb66602c..c9cea35164 100644 --- a/driver-ui-desktop/src/main/java/eu/tsystems/mms/tic/testframework/webdrivermanager/DesktopWebDriverFactory.java +++ b/driver-ui-desktop/src/main/java/eu/tsystems/mms/tic/testframework/webdrivermanager/DesktopWebDriverFactory.java @@ -63,10 +63,10 @@ import java.lang.reflect.Constructor; import java.net.URL; +import java.time.Duration; import java.util.Arrays; import java.util.Date; import java.util.List; -import java.util.concurrent.TimeUnit; public class DesktopWebDriverFactory implements WebDriverFactory, @@ -261,12 +261,12 @@ public void setupNewWebDriverSession(EventFiringWebDriver eventFiringWebDriver, int pageLoadTimeout = Testerra.Properties.WEBDRIVER_TIMEOUT_SECONDS_PAGELOAD.asLong().intValue(); int scriptTimeout = Testerra.Properties.WEBDRIVER_TIMEOUT_SECONDS_SCRIPT.asLong().intValue(); try { - eventFiringWebDriver.manage().timeouts().pageLoadTimeout(pageLoadTimeout, TimeUnit.SECONDS); + eventFiringWebDriver.manage().timeouts().pageLoadTimeout(Duration.ofSeconds(pageLoadTimeout)); } catch (Exception e) { log().error("Could not set Page Load Timeout", e); } try { - eventFiringWebDriver.manage().timeouts().setScriptTimeout(scriptTimeout, TimeUnit.SECONDS); + eventFiringWebDriver.manage().timeouts().scriptTimeout(Duration.ofSeconds(scriptTimeout)); } catch (Exception e) { log().error("Could not set Script Timeout", e); } From 2bc1762be194cc879ed100bde0ca9f75c64b9288 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Gro=C3=9Fmann?= Date: Tue, 29 Nov 2022 10:06:29 +0100 Subject: [PATCH 04/64] Fixed test.properties --- integration-tests/src/test/resources/test.properties | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/integration-tests/src/test/resources/test.properties b/integration-tests/src/test/resources/test.properties index d58968ad8a..5ef7033dbc 100644 --- a/integration-tests/src/test/resources/test.properties +++ b/integration-tests/src/test/resources/test.properties @@ -1,5 +1,5 @@ -#tt.browser=chromeHeadless -tt.browser=chrome +tt.browser=chromeHeadless +#tt.browser=chrome #tt.browser=firefox tt.browser.maximize=false #tt.browser.maximize=true From 162235b5a7dbd13b860859a42c6962c52fadf476 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Gro=C3=9Fmann?= Date: Tue, 29 Nov 2022 13:26:24 +0100 Subject: [PATCH 05/64] Added browser options as Capabilities to AbstractWebDriverRequest --- .../tic/testframework/constants/Browsers.java | 1 - .../DesktopWebDriverFactory.java | 28 ++++++++++------- .../AbstractWebDriverRequest.java | 13 +++++++- .../WebDriverSessionsManager.java | 1 + .../testframework/AbstractWebDriverTest.java | 9 ------ .../DesktopWebDriverFactoryTest.java | 31 +++++++------------ 6 files changed, 41 insertions(+), 42 deletions(-) diff --git a/core/src/main/java/eu/tsystems/mms/tic/testframework/constants/Browsers.java b/core/src/main/java/eu/tsystems/mms/tic/testframework/constants/Browsers.java index 3dc218b1d9..d56777e4c5 100644 --- a/core/src/main/java/eu/tsystems/mms/tic/testframework/constants/Browsers.java +++ b/core/src/main/java/eu/tsystems/mms/tic/testframework/constants/Browsers.java @@ -28,6 +28,5 @@ public class Browsers { public static final String ie = "ie"; public static final String edge = "edge"; public static final String safari = "safari"; - public static final String htmlunit = "htmlunit"; public static final String chromeHeadless = "chromeHeadless"; } diff --git a/driver-ui-desktop/src/main/java/eu/tsystems/mms/tic/testframework/webdrivermanager/DesktopWebDriverFactory.java b/driver-ui-desktop/src/main/java/eu/tsystems/mms/tic/testframework/webdrivermanager/DesktopWebDriverFactory.java index c9cea35164..01a153ee4e 100644 --- a/driver-ui-desktop/src/main/java/eu/tsystems/mms/tic/testframework/webdrivermanager/DesktopWebDriverFactory.java +++ b/driver-ui-desktop/src/main/java/eu/tsystems/mms/tic/testframework/webdrivermanager/DesktopWebDriverFactory.java @@ -177,13 +177,16 @@ public WebDriverRequest prepareWebDriverRequest(WebDriverRequest webDriverReques } DesiredCapabilities desiredCapabilities = finalRequest.getDesiredCapabilities(); - if (userAgentCapabilities != null) { - desiredCapabilities.merge(userAgentCapabilities); - } finalRequest.getPlatformName().ifPresent(s -> { desiredCapabilities.setCapability(CapabilityType.PLATFORM, s); desiredCapabilities.setCapability(CapabilityType.PLATFORM_NAME, s); }); + + if (userAgentCapabilities != null) { + finalRequest.setBrowserOptions(userAgentCapabilities); + userAgentCapabilities.merge(finalRequest.getDesiredCapabilities()); +// desiredCapabilities.merge(userAgentCapabilities); + } return finalRequest; } @@ -354,7 +357,7 @@ private WebDriver startNewWebDriverSession(DesktopWebDriverRequest request, Sess } // Finalize capabilities - final DesiredCapabilities requestCapabilities = request.getDesiredCapabilities(); +// final DesiredCapabilities requestCapabilities = request.getDesiredCapabilities(); RemoteWebDriver webDriver; try { if (request.getServerUrl().isPresent()) { @@ -362,19 +365,22 @@ private WebDriver startNewWebDriverSession(DesktopWebDriverRequest request, Sess // TODO: Reduced timeouts of Selenium 3, needed in Selenium 4? // final HttpCommandExecutor httpCommandExecutor = new HttpCommandExecutor(new HashMap<>(), seleniumUrl, new HttpClientFactory()); // final HttpCommandExecutor httpCommandExecutor = new HttpCommandExecutor(new HashMap<>(), seleniumUrl); - webDriver = new RemoteWebDriver(seleniumUrl, requestCapabilities); + webDriver = new RemoteWebDriver(seleniumUrl, request.getBrowserOptions()); webDriver.setFileDetector(new LocalFileDetector()); sessionContext.setNodeUrl(seleniumUrl); } else { log().warn("Local WebDriver setups may cause side effects. It's highly recommended to use a remote Selenium configurations for all environments!"); // Starting local webdriver needs caps as browser options - Constructor optionClassConstructor = optionClass.getConstructor(); - AbstractDriverOptions abstractDriverOptions = optionClassConstructor.newInstance(); - abstractDriverOptions.merge(requestCapabilities); - - Constructor constructor = driverClass.getConstructor(abstractDriverOptions.getClass()); - webDriver = constructor.newInstance(abstractDriverOptions); +// Constructor optionClassConstructor = optionClass.getConstructor(); +// AbstractDriverOptions abstractDriverOptions = optionClassConstructor.newInstance(); +// abstractDriverOptions.merge(requestCapabilities); + if (optionClass == request.getBrowserOptions().getClass()) { + Constructor constructor = driverClass.getConstructor(optionClass); + webDriver = constructor.newInstance(request.getBrowserOptions()); + } else { + throw new SystemException("Browser options cannot use for new session: \nRequired " + optionClass.getName() + ",\nProvided: " + request.getBrowserOptions().getClass().getName()); + } } } catch (Exception e) { WebDriverSessionsManager.SESSION_STARTUP_ERRORS.put(new Date(), e); diff --git a/driver-ui/src/main/java/eu/tsystems/mms/tic/testframework/webdrivermanager/AbstractWebDriverRequest.java b/driver-ui/src/main/java/eu/tsystems/mms/tic/testframework/webdrivermanager/AbstractWebDriverRequest.java index da2121c3e1..c527c2800d 100644 --- a/driver-ui/src/main/java/eu/tsystems/mms/tic/testframework/webdrivermanager/AbstractWebDriverRequest.java +++ b/driver-ui/src/main/java/eu/tsystems/mms/tic/testframework/webdrivermanager/AbstractWebDriverRequest.java @@ -23,6 +23,7 @@ import eu.tsystems.mms.tic.testframework.common.PropertyManager; import eu.tsystems.mms.tic.testframework.constants.TesterraProperties; import org.apache.commons.lang3.StringUtils; +import org.openqa.selenium.Capabilities; import org.openqa.selenium.remote.DesiredCapabilities; import java.net.MalformedURLException; @@ -35,6 +36,8 @@ public class AbstractWebDriverRequest implements WebDriverRequest { private String sessionKey = DEFAULT_SESSION_KEY; private URL serverUrl; private DesiredCapabilities desiredCapabilities; + + private Capabilities capabilities; private boolean shutdownAfterTest = false; private boolean shutdownAfterTestFailed = false; private boolean shutdownAfterExecution = true; @@ -129,7 +132,7 @@ public boolean getShutdownAfterExecution() { @Override public Map getCapabilities() { - return getDesiredCapabilities().asMap(); + return getBrowserOptions().asMap(); } public void setSessionKey(String sessionKey) { @@ -159,6 +162,14 @@ public AbstractWebDriverRequest clone() throws CloneNotSupportedException { return clone; } + public Capabilities getBrowserOptions() { + return capabilities; + } + + public void setBrowserOptions(Capabilities capabilities) { + this.capabilities = capabilities; + } + public void setPlatformName(String platformName) { if (StringUtils.isNotBlank(platformName)) { this.platformName = platformName; diff --git a/driver-ui/src/main/java/eu/tsystems/mms/tic/testframework/webdrivermanager/WebDriverSessionsManager.java b/driver-ui/src/main/java/eu/tsystems/mms/tic/testframework/webdrivermanager/WebDriverSessionsManager.java index 0c778313a6..77b4014d9e 100644 --- a/driver-ui/src/main/java/eu/tsystems/mms/tic/testframework/webdrivermanager/WebDriverSessionsManager.java +++ b/driver-ui/src/main/java/eu/tsystems/mms/tic/testframework/webdrivermanager/WebDriverSessionsManager.java @@ -466,6 +466,7 @@ public static EventFiringWebDriver getWebDriver(final WebDriverRequest webDriver } private static void logRequest(WebDriverRequest request, SessionContext sessionContext) { + Map cleanedCapsMap = new DefaultCapabilityUtils().clean(request.getCapabilities()); Gson gson = new GsonBuilder() .setPrettyPrinting() diff --git a/integration-tests/src/main/java/eu/tsystems/mms/tic/testframework/AbstractWebDriverTest.java b/integration-tests/src/main/java/eu/tsystems/mms/tic/testframework/AbstractWebDriverTest.java index ed68da3ce3..d31be9d86d 100644 --- a/integration-tests/src/main/java/eu/tsystems/mms/tic/testframework/AbstractWebDriverTest.java +++ b/integration-tests/src/main/java/eu/tsystems/mms/tic/testframework/AbstractWebDriverTest.java @@ -43,15 +43,6 @@ */ public abstract class AbstractWebDriverTest extends TesterraTest implements WebDriverRetainer, WebDriverManagerProvider, Loggable { - // static { - // WebDriverManager.config().closeWindowsAfterTestMethod = false; - // } - // - // @AfterTest(alwaysRun = true) - // public void resetWDCloseWindowsMode() { - // WebDriverManager.config().closeWindowsAfterTestMethod = true; - // } - private String exclusiveSessionId; @AfterSuite(alwaysRun = true) diff --git a/integration-tests/src/test/java/eu/tsystems/mms/tic/testframework/test/webdrivermanager/DesktopWebDriverFactoryTest.java b/integration-tests/src/test/java/eu/tsystems/mms/tic/testframework/test/webdrivermanager/DesktopWebDriverFactoryTest.java index e65800262f..9dd9d0bad7 100644 --- a/integration-tests/src/test/java/eu/tsystems/mms/tic/testframework/test/webdrivermanager/DesktopWebDriverFactoryTest.java +++ b/integration-tests/src/test/java/eu/tsystems/mms/tic/testframework/test/webdrivermanager/DesktopWebDriverFactoryTest.java @@ -21,38 +21,34 @@ package eu.tsystems.mms.tic.testframework.test.webdrivermanager; -import eu.tsystems.mms.tic.testframework.testing.TesterraTest; import eu.tsystems.mms.tic.testframework.report.model.context.SessionContext; +import eu.tsystems.mms.tic.testframework.testing.TesterraTest; +import eu.tsystems.mms.tic.testframework.testing.WebDriverManagerProvider; import eu.tsystems.mms.tic.testframework.webdrivermanager.DesktopWebDriverRequest; -import eu.tsystems.mms.tic.testframework.webdrivermanager.WebDriverManager; -import eu.tsystems.mms.tic.testframework.webdrivermanager.WebDriverSessionsManager; -import java.util.Map; import org.openqa.selenium.WebDriver; import org.openqa.selenium.remote.DesiredCapabilities; import org.testng.Assert; import org.testng.annotations.Test; -public class DesktopWebDriverFactoryTest extends TesterraTest { +import java.util.Map; + +public class DesktopWebDriverFactoryTest extends TesterraTest implements WebDriverManagerProvider { @Test public void testT01_BaseURL() throws Exception { DesktopWebDriverRequest request = new DesktopWebDriverRequest(); request.setBaseUrl("http://google.de"); - //request.webDriverMode = WebDriverMode.local; - //request.browser = Browsers.phantomjs; - WebDriver driver = WebDriverManager.getWebDriver(request); + WebDriver driver = WEB_DRIVER_MANAGER.getWebDriver(request); String currentUrl = driver.getCurrentUrl(); Assert.assertTrue(currentUrl.contains("google"), "Current URL contains google - actual: " + currentUrl); } @Test - public void testT02_BaseURL_NotSet() throws Exception { + public void testT02_BaseURL_NotSet() { DesktopWebDriverRequest request = new DesktopWebDriverRequest(); - //request.webDriverMode = WebDriverMode.local; - //request.browser = Browsers.phantomjs; - WebDriver driver = WebDriverManager.getWebDriver(request); + WebDriver driver = WEB_DRIVER_MANAGER.getWebDriver(request); String currentUrl = driver.getCurrentUrl(); // Empty baseUrl of Chrome Assert.assertTrue(currentUrl.contains("data"), "Current URL is invalid - actual: " + currentUrl); @@ -62,19 +58,14 @@ public void testT02_BaseURL_NotSet() throws Exception { public void testT03_EndPointCapabilities() throws Exception { DesktopWebDriverRequest request = new DesktopWebDriverRequest(); request.setBaseUrl("http://google.de"); - //request.webDriverMode = WebDriverMode.local; - //request.browser = Browsers.phantomjs; - /* - create caps - */ DesiredCapabilities caps = new DesiredCapabilities(); caps.setCapability("enableVideo", true); caps.setCapability("enableVNC", true); - // start session - WebDriver driver = WebDriverManager.getWebDriver(request); - SessionContext sessionContext = WebDriverSessionsManager.getSessionContext(driver).get(); + WebDriver driver = WEB_DRIVER_MANAGER.getWebDriver(request); + + SessionContext sessionContext = WEB_DRIVER_MANAGER.getSessionContext(driver).get(); Map sessionCapabilities = sessionContext.getWebDriverRequest().getCapabilities(); Assert.assertEquals(sessionCapabilities.get("tap:projectId"), caps.getCapability("tap:projectId"), "EndPoint Capability is set"); From 3462bde0c2af04a18c15e0d4f1a0aae5dde824c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Gro=C3=9Fmann?= Date: Tue, 29 Nov 2022 14:23:37 +0100 Subject: [PATCH 06/64] Added logging for debug --- .../mms/tic/testframework/adapters/ContextExporter.java | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/report-model/src/main/java/eu/tsystems/mms/tic/testframework/adapters/ContextExporter.java b/report-model/src/main/java/eu/tsystems/mms/tic/testframework/adapters/ContextExporter.java index 9b09f5d566..959878fee0 100644 --- a/report-model/src/main/java/eu/tsystems/mms/tic/testframework/adapters/ContextExporter.java +++ b/report-model/src/main/java/eu/tsystems/mms/tic/testframework/adapters/ContextExporter.java @@ -512,6 +512,15 @@ public SessionContext.Builder buildSessionContext(eu.tsystems.mms.tic.testframew sessionContext.getActualBrowserName().ifPresent(builder::setBrowserName); sessionContext.getActualBrowserVersion().ifPresent(builder::setBrowserVersion); + + try { + sessionContext.getWebDriverRequest().getCapabilities(); + } catch (Exception e) { + List collect = sessionContext.readMethodContexts().collect(Collectors.toList()); + log().info(e.getMessage()); + collect.forEach(context -> log().info(context.getName())); + } + builder.setCapabilities(jsonEncoder.toJson(sessionContext.getWebDriverRequest().getCapabilities())); sessionContext.getWebDriverRequest().getServerUrl().ifPresent(url -> builder.setServerUrl(url.toString())); sessionContext.getNodeInfo().ifPresent(nodeInfo -> builder.setNodeUrl(nodeInfo.toString())); From c77c9a461b49a40860a8592e4e432b8fb14136ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Gro=C3=9Fmann?= Date: Tue, 29 Nov 2022 14:48:53 +0100 Subject: [PATCH 07/64] Fixed NPE in getting capabilities --- .../AbstractWebDriverRequest.java | 6 +++- .../adapters/ContextExporter.java | 31 +++++++------------ 2 files changed, 16 insertions(+), 21 deletions(-) diff --git a/driver-ui/src/main/java/eu/tsystems/mms/tic/testframework/webdrivermanager/AbstractWebDriverRequest.java b/driver-ui/src/main/java/eu/tsystems/mms/tic/testframework/webdrivermanager/AbstractWebDriverRequest.java index c527c2800d..916554f500 100644 --- a/driver-ui/src/main/java/eu/tsystems/mms/tic/testframework/webdrivermanager/AbstractWebDriverRequest.java +++ b/driver-ui/src/main/java/eu/tsystems/mms/tic/testframework/webdrivermanager/AbstractWebDriverRequest.java @@ -132,7 +132,11 @@ public boolean getShutdownAfterExecution() { @Override public Map getCapabilities() { - return getBrowserOptions().asMap(); + if (getBrowserOptions() != null) { + return getBrowserOptions().asMap(); + } else { + return Map.of(); + } } public void setSessionKey(String sessionKey) { diff --git a/report-model/src/main/java/eu/tsystems/mms/tic/testframework/adapters/ContextExporter.java b/report-model/src/main/java/eu/tsystems/mms/tic/testframework/adapters/ContextExporter.java index 959878fee0..2c031429b1 100644 --- a/report-model/src/main/java/eu/tsystems/mms/tic/testframework/adapters/ContextExporter.java +++ b/report-model/src/main/java/eu/tsystems/mms/tic/testframework/adapters/ContextExporter.java @@ -27,13 +27,13 @@ import eu.tsystems.mms.tic.testframework.common.Testerra; import eu.tsystems.mms.tic.testframework.internal.IdGenerator; import eu.tsystems.mms.tic.testframework.logging.Loggable; +import eu.tsystems.mms.tic.testframework.report.FailureCorridor; import eu.tsystems.mms.tic.testframework.report.ITestStatusController; import eu.tsystems.mms.tic.testframework.report.Report; import eu.tsystems.mms.tic.testframework.report.Status; -import eu.tsystems.mms.tic.testframework.report.TestStatusController; import eu.tsystems.mms.tic.testframework.report.TesterraListener; import eu.tsystems.mms.tic.testframework.report.model.ClickPathEvent; -import eu.tsystems.mms.tic.testframework.report.FailureCorridor; + import eu.tsystems.mms.tic.testframework.report.model.BuildInformation; import eu.tsystems.mms.tic.testframework.report.model.ClassContext; import eu.tsystems.mms.tic.testframework.report.model.ContextValues; @@ -61,6 +61,9 @@ import eu.tsystems.mms.tic.testframework.report.model.context.Screenshot; import eu.tsystems.mms.tic.testframework.report.model.context.Video; import eu.tsystems.mms.tic.testframework.report.utils.ExecutionContextController; +import org.apache.commons.lang3.StringUtils; +import org.apache.logging.log4j.Level; + import java.util.Arrays; import java.util.Date; import java.util.LinkedHashMap; @@ -71,8 +74,6 @@ import java.util.function.Function; import java.util.stream.Collectors; import java.util.stream.Stream; -import org.apache.commons.lang3.StringUtils; -import org.apache.logging.log4j.Level; public class ContextExporter implements Loggable { private final Injector injector = Testerra.getInjector(); @@ -87,7 +88,6 @@ public MethodContext.Builder buildMethodContext(eu.tsystems.mms.tic.testframewor ContextValues.Builder contextValuesBuilder = buildContextValues(methodContext); - methodContext.getTestNgResult().ifPresent(iTestResult -> { String testName = methodContext.getName(); String methodName = iTestResult.getMethod().getMethodName(); @@ -288,20 +288,20 @@ public TestStepAction.Builder buildTestStepAction(eu.tsystems.mms.tic.testframew Optional optional = Optional.ofNullable(builders[0]); optional.ifPresent(file -> entryBuilder.setScreenshotId(file.getId())); } else if (entry instanceof eu.tsystems.mms.tic.testframework.report.model.context.LogMessage) { - eu.tsystems.mms.tic.testframework.report.model.context.LogMessage logEvent = (eu.tsystems.mms.tic.testframework.report.model.context.LogMessage)entry; + eu.tsystems.mms.tic.testframework.report.model.context.LogMessage logEvent = (eu.tsystems.mms.tic.testframework.report.model.context.LogMessage) entry; Optional optional = Optional.ofNullable(buildLogMessage(logEvent)); optional.ifPresent(entryBuilder::setLogMessage); } else if (entry instanceof eu.tsystems.mms.tic.testframework.report.model.context.ErrorContext) { - eu.tsystems.mms.tic.testframework.report.model.context.ErrorContext errorContext = (eu.tsystems.mms.tic.testframework.report.model.context.ErrorContext)entry; + eu.tsystems.mms.tic.testframework.report.model.context.ErrorContext errorContext = (eu.tsystems.mms.tic.testframework.report.model.context.ErrorContext) entry; Optional optional = Optional.ofNullable(buildErrorContext(errorContext)); optional.ifPresent(entryBuilder::setErrorContext); } if ( entryBuilder.hasErrorContext() - || entryBuilder.hasLogMessage() - || entryBuilder.hasClickPathEvent() - || StringUtils.isNotBlank(entryBuilder.getScreenshotId()) + || entryBuilder.hasLogMessage() + || entryBuilder.hasClickPathEvent() + || StringUtils.isNotBlank(entryBuilder.getScreenshotId()) ) { actionBuilder.addEntries(entryBuilder); } @@ -356,7 +356,7 @@ protected void apply(T value, Function function) { /** * Maps and applies a value if not null */ - protected void map(T value, Function map, Function function) { + protected void map(T value, Function map, Function function) { if (value != null) { M m = map.apply(value); function.apply(m); @@ -512,15 +512,6 @@ public SessionContext.Builder buildSessionContext(eu.tsystems.mms.tic.testframew sessionContext.getActualBrowserName().ifPresent(builder::setBrowserName); sessionContext.getActualBrowserVersion().ifPresent(builder::setBrowserVersion); - - try { - sessionContext.getWebDriverRequest().getCapabilities(); - } catch (Exception e) { - List collect = sessionContext.readMethodContexts().collect(Collectors.toList()); - log().info(e.getMessage()); - collect.forEach(context -> log().info(context.getName())); - } - builder.setCapabilities(jsonEncoder.toJson(sessionContext.getWebDriverRequest().getCapabilities())); sessionContext.getWebDriverRequest().getServerUrl().ifPresent(url -> builder.setServerUrl(url.toString())); sessionContext.getNodeInfo().ifPresent(nodeInfo -> builder.setNodeUrl(nodeInfo.toString())); From b2c775cbd2d6d1da31b7d5764f20aef31886a882 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Gro=C3=9Fmann?= Date: Wed, 30 Nov 2022 11:28:23 +0100 Subject: [PATCH 08/64] Fixed setting capabilities to browser options --- .../DesktopWebDriverFactory.java | 3 +- .../WebDriverCapabilities.java | 10 +++-- .../WebDriverSessionsManager.java | 5 +-- .../DesktopWebDriverFactoryTest.java | 41 +++++++++++++++++-- .../WebDriverManagerTest.java | 5 +-- 5 files changed, 50 insertions(+), 14 deletions(-) diff --git a/driver-ui-desktop/src/main/java/eu/tsystems/mms/tic/testframework/webdrivermanager/DesktopWebDriverFactory.java b/driver-ui-desktop/src/main/java/eu/tsystems/mms/tic/testframework/webdrivermanager/DesktopWebDriverFactory.java index 01a153ee4e..13805f4b5c 100644 --- a/driver-ui-desktop/src/main/java/eu/tsystems/mms/tic/testframework/webdrivermanager/DesktopWebDriverFactory.java +++ b/driver-ui-desktop/src/main/java/eu/tsystems/mms/tic/testframework/webdrivermanager/DesktopWebDriverFactory.java @@ -183,9 +183,8 @@ public WebDriverRequest prepareWebDriverRequest(WebDriverRequest webDriverReques }); if (userAgentCapabilities != null) { + userAgentCapabilities = userAgentCapabilities.merge(finalRequest.getDesiredCapabilities()); finalRequest.setBrowserOptions(userAgentCapabilities); - userAgentCapabilities.merge(finalRequest.getDesiredCapabilities()); -// desiredCapabilities.merge(userAgentCapabilities); } return finalRequest; } diff --git a/driver-ui/src/main/java/eu/tsystems/mms/tic/testframework/webdrivermanager/WebDriverCapabilities.java b/driver-ui/src/main/java/eu/tsystems/mms/tic/testframework/webdrivermanager/WebDriverCapabilities.java index 93fc376020..a5f4d0a536 100644 --- a/driver-ui/src/main/java/eu/tsystems/mms/tic/testframework/webdrivermanager/WebDriverCapabilities.java +++ b/driver-ui/src/main/java/eu/tsystems/mms/tic/testframework/webdrivermanager/WebDriverCapabilities.java @@ -23,6 +23,8 @@ import eu.tsystems.mms.tic.testframework.utils.CertUtils; import java.util.function.Consumer; + +import org.openqa.selenium.Capabilities; import org.openqa.selenium.remote.CapabilityType; import org.openqa.selenium.remote.DesiredCapabilities; import org.slf4j.Logger; @@ -93,13 +95,15 @@ static Map getGlobalExtraCapabilities() { @Override public void accept(WebDriverRequest webDriverRequest) { if (webDriverRequest instanceof AbstractWebDriverRequest) { - DesiredCapabilities desiredCapabilities = ((AbstractWebDriverRequest) webDriverRequest).getDesiredCapabilities(); - desiredCapabilities.merge(new DesiredCapabilities(GLOBALCAPABILITIES)); + Capabilities browserOptions = ((AbstractWebDriverRequest) webDriverRequest).getBrowserOptions(); + // 'merge' method of browser options always creates a new instance + Capabilities newOptions = browserOptions.merge(new DesiredCapabilities(GLOBALCAPABILITIES)); CertUtils certUtils = CertUtils.getInstance(); if (certUtils.isTrustAllHosts() || certUtils.getTrustedHosts().length > 0) { - desiredCapabilities.setAcceptInsecureCerts(true); + newOptions = newOptions.merge(new DesiredCapabilities(Map.of(CapabilityType.ACCEPT_INSECURE_CERTS,true))); } + ((AbstractWebDriverRequest) webDriverRequest).setBrowserOptions(newOptions); } } } diff --git a/driver-ui/src/main/java/eu/tsystems/mms/tic/testframework/webdrivermanager/WebDriverSessionsManager.java b/driver-ui/src/main/java/eu/tsystems/mms/tic/testframework/webdrivermanager/WebDriverSessionsManager.java index 77b4014d9e..9e9e90ad4a 100644 --- a/driver-ui/src/main/java/eu/tsystems/mms/tic/testframework/webdrivermanager/WebDriverSessionsManager.java +++ b/driver-ui/src/main/java/eu/tsystems/mms/tic/testframework/webdrivermanager/WebDriverSessionsManager.java @@ -400,12 +400,11 @@ public static EventFiringWebDriver getWebDriver(final WebDriverRequest webDriver if (WEB_DRIVER_FACTORIES.containsKey(browser)) { WebDriverFactory webDriverFactory = WEB_DRIVER_FACTORIES.get(browser); - /* - create session context and link to method context - */ + // Catch all existing browser caps and add them to specific browser options final WebDriverRequest finalWebDriverRequest = webDriverFactory.prepareWebDriverRequest(webDriverRequest); webDriverRequestConfigurators.forEach(handler -> handler.accept(finalWebDriverRequest)); + // Create session context and link to method context SessionContext sessionContext = new SessionContext(finalWebDriverRequest); executionContextController.getCurrentMethodContext().ifPresent(methodContext -> { methodContext.addSessionContext(sessionContext); diff --git a/integration-tests/src/test/java/eu/tsystems/mms/tic/testframework/test/webdrivermanager/DesktopWebDriverFactoryTest.java b/integration-tests/src/test/java/eu/tsystems/mms/tic/testframework/test/webdrivermanager/DesktopWebDriverFactoryTest.java index 9dd9d0bad7..a1827d052d 100644 --- a/integration-tests/src/test/java/eu/tsystems/mms/tic/testframework/test/webdrivermanager/DesktopWebDriverFactoryTest.java +++ b/integration-tests/src/test/java/eu/tsystems/mms/tic/testframework/test/webdrivermanager/DesktopWebDriverFactoryTest.java @@ -21,11 +21,14 @@ package eu.tsystems.mms.tic.testframework.test.webdrivermanager; +import eu.tsystems.mms.tic.testframework.constants.Browsers; import eu.tsystems.mms.tic.testframework.report.model.context.SessionContext; import eu.tsystems.mms.tic.testframework.testing.TesterraTest; import eu.tsystems.mms.tic.testframework.testing.WebDriverManagerProvider; +import eu.tsystems.mms.tic.testframework.useragents.ChromeConfig; import eu.tsystems.mms.tic.testframework.webdrivermanager.DesktopWebDriverRequest; import org.openqa.selenium.WebDriver; +import org.openqa.selenium.chrome.ChromeOptions; import org.openqa.selenium.remote.DesiredCapabilities; import org.testng.Assert; import org.testng.annotations.Test; @@ -55,11 +58,11 @@ public void testT02_BaseURL_NotSet() { } @Test - public void testT03_EndPointCapabilities() throws Exception { + public void testT03_EndPointCapabilities_WebDriverRequest() throws Exception { DesktopWebDriverRequest request = new DesktopWebDriverRequest(); request.setBaseUrl("http://google.de"); - DesiredCapabilities caps = new DesiredCapabilities(); + DesiredCapabilities caps = request.getDesiredCapabilities(); caps.setCapability("enableVideo", true); caps.setCapability("enableVNC", true); @@ -68,7 +71,39 @@ public void testT03_EndPointCapabilities() throws Exception { SessionContext sessionContext = WEB_DRIVER_MANAGER.getSessionContext(driver).get(); Map sessionCapabilities = sessionContext.getWebDriverRequest().getCapabilities(); - Assert.assertEquals(sessionCapabilities.get("tap:projectId"), caps.getCapability("tap:projectId"), "EndPoint Capability is set"); + Assert.assertEquals(sessionCapabilities.get("enableVideo"), caps.getCapability("enableVideo"), "EndPoint Capability via WebDriverRequest is set"); + Assert.assertEquals(sessionCapabilities.get("enableVNC"), caps.getCapability("enableVNC"), "EndPoint Capability via WebDriverRequest is set"); + } + + @Test + public void testT04_EndPointCapabilities_Global() { + WEB_DRIVER_MANAGER.setGlobalCapability("t04Global", "yes"); + + WebDriver driver = WEB_DRIVER_MANAGER.getWebDriver(); + + WEB_DRIVER_MANAGER.removeGlobalCapability("t04Global"); + + SessionContext sessionContext = WEB_DRIVER_MANAGER.getSessionContext(driver).get(); + Map sessionCapabilities = sessionContext.getWebDriverRequest().getCapabilities(); + + Assert.assertEquals(sessionCapabilities.get("t04Global"), "yes", "EndPoint Capability is set"); + } + + @Test + public void test05_EndPointCapabilities_UserAgent() { + WEB_DRIVER_MANAGER.setUserAgentConfig(Browsers.chromeHeadless, new ChromeConfig() { + @Override + public void configure(ChromeOptions options) { + options.setCapability("t05UserAgent", "yesyes"); + } + }); + + WebDriver driver = WEB_DRIVER_MANAGER.getWebDriver(); + + SessionContext sessionContext = WEB_DRIVER_MANAGER.getSessionContext(driver).get(); + Map sessionCapabilities = sessionContext.getWebDriverRequest().getCapabilities(); + + Assert.assertEquals(sessionCapabilities.get("t05UserAgent"), "yesyes", "EndPoint Capability is set"); } } diff --git a/integration-tests/src/test/java/eu/tsystems/mms/tic/testframework/test/webdrivermanager/WebDriverManagerTest.java b/integration-tests/src/test/java/eu/tsystems/mms/tic/testframework/test/webdrivermanager/WebDriverManagerTest.java index 97e43fc5d8..8a84ce8f4e 100644 --- a/integration-tests/src/test/java/eu/tsystems/mms/tic/testframework/test/webdrivermanager/WebDriverManagerTest.java +++ b/integration-tests/src/test/java/eu/tsystems/mms/tic/testframework/test/webdrivermanager/WebDriverManagerTest.java @@ -145,8 +145,7 @@ public void testT03b_SessionExclusiveCheckLinkedSession() { @Test public void testT04_ManageGlobalCapabilities() { - - WebDriverManager.setGlobalExtraCapability("foo", "bar"); + WEB_DRIVER_MANAGER.setGlobalCapability("foo", "bar"); Map globalExtraCapabilities = WebDriverManager.getGlobalExtraCapabilities(); Assert.assertTrue(globalExtraCapabilities.containsKey("foo")); @@ -154,7 +153,7 @@ public void testT04_ManageGlobalCapabilities() { WebDriver driver = WebDriverManager.getWebDriver(); - WebDriverManager.removeGlobalExtraCapability("foo"); + WEB_DRIVER_MANAGER.removeGlobalCapability("foo"); globalExtraCapabilities = WebDriverManager.getGlobalExtraCapabilities(); Assert.assertFalse(globalExtraCapabilities.containsKey("foo")); } From 62a97a5bd4cbc405fec98d5ff78fcf385632b0fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Gro=C3=9Fmann?= Date: Wed, 30 Nov 2022 12:16:06 +0100 Subject: [PATCH 09/64] Added null check for browser options --- .../webdrivermanager/DesktopWebDriverFactory.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/driver-ui-desktop/src/main/java/eu/tsystems/mms/tic/testframework/webdrivermanager/DesktopWebDriverFactory.java b/driver-ui-desktop/src/main/java/eu/tsystems/mms/tic/testframework/webdrivermanager/DesktopWebDriverFactory.java index 13805f4b5c..198ceb5616 100644 --- a/driver-ui-desktop/src/main/java/eu/tsystems/mms/tic/testframework/webdrivermanager/DesktopWebDriverFactory.java +++ b/driver-ui-desktop/src/main/java/eu/tsystems/mms/tic/testframework/webdrivermanager/DesktopWebDriverFactory.java @@ -364,7 +364,11 @@ private WebDriver startNewWebDriverSession(DesktopWebDriverRequest request, Sess // TODO: Reduced timeouts of Selenium 3, needed in Selenium 4? // final HttpCommandExecutor httpCommandExecutor = new HttpCommandExecutor(new HashMap<>(), seleniumUrl, new HttpClientFactory()); // final HttpCommandExecutor httpCommandExecutor = new HttpCommandExecutor(new HashMap<>(), seleniumUrl); - webDriver = new RemoteWebDriver(seleniumUrl, request.getBrowserOptions()); + Capabilities browserOptions = request.getBrowserOptions(); + if (browserOptions == null) { + throw new SystemException("Cannot start browser session with empty browser options"); + } + webDriver = new RemoteWebDriver(seleniumUrl, browserOptions); webDriver.setFileDetector(new LocalFileDetector()); sessionContext.setNodeUrl(seleniumUrl); } else { From 1a6fa24a55c7ef4ae18c78e3b0ebd6d9fe4ba1b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Gro=C3=9Fmann?= Date: Wed, 30 Nov 2022 12:17:49 +0100 Subject: [PATCH 10/64] Cleanup --- .../webdrivermanager/DesktopWebDriverFactory.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/driver-ui-desktop/src/main/java/eu/tsystems/mms/tic/testframework/webdrivermanager/DesktopWebDriverFactory.java b/driver-ui-desktop/src/main/java/eu/tsystems/mms/tic/testframework/webdrivermanager/DesktopWebDriverFactory.java index 198ceb5616..06d1b827a7 100644 --- a/driver-ui-desktop/src/main/java/eu/tsystems/mms/tic/testframework/webdrivermanager/DesktopWebDriverFactory.java +++ b/driver-ui-desktop/src/main/java/eu/tsystems/mms/tic/testframework/webdrivermanager/DesktopWebDriverFactory.java @@ -375,9 +375,6 @@ private WebDriver startNewWebDriverSession(DesktopWebDriverRequest request, Sess log().warn("Local WebDriver setups may cause side effects. It's highly recommended to use a remote Selenium configurations for all environments!"); // Starting local webdriver needs caps as browser options -// Constructor optionClassConstructor = optionClass.getConstructor(); -// AbstractDriverOptions abstractDriverOptions = optionClassConstructor.newInstance(); -// abstractDriverOptions.merge(requestCapabilities); if (optionClass == request.getBrowserOptions().getClass()) { Constructor constructor = driverClass.getConstructor(optionClass); webDriver = constructor.newInstance(request.getBrowserOptions()); From 14076d145b157532e3cd697be287771ebd3e19dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Gro=C3=9Fmann?= Date: Fri, 2 Dec 2022 10:49:50 +0100 Subject: [PATCH 11/64] Cleanup --- .../webdrivermanager/HttpClientFactory.java | 7 +++++++ .../tic/testframework/utils/DefaultCapabilityUtils.java | 1 - .../webdrivermanager/DesktopWebDriverFactoryTest.java | 9 ++------- 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/driver-ui-desktop/src/main/java/eu/tsystems/mms/tic/testframework/webdrivermanager/HttpClientFactory.java b/driver-ui-desktop/src/main/java/eu/tsystems/mms/tic/testframework/webdrivermanager/HttpClientFactory.java index 6688d5ed65..28d385aa06 100644 --- a/driver-ui-desktop/src/main/java/eu/tsystems/mms/tic/testframework/webdrivermanager/HttpClientFactory.java +++ b/driver-ui-desktop/src/main/java/eu/tsystems/mms/tic/testframework/webdrivermanager/HttpClientFactory.java @@ -39,6 +39,13 @@ */ class HttpClientFactory implements HttpClient.Factory { + /** TODO: Delete or re-implement + * This class was used to set a custom timeout for sending commands to browser sessions. Selenium 3 has a default of 120 minutes. This was reduced to 2 minutes. + * + * For using in Selenium 4 this class has to re-implement because Selenium 4 uses HttpClient of Java 11. + * + */ + private final Duration factoryConnectionTimeout = Duration.ofSeconds(120); // Kill, when connect does not succeed in this timeout private final Duration factoryReadTimeout = factoryConnectionTimeout; // Kill hanging / stuck selenium commands after this timeout. diff --git a/driver-ui/src/main/java/eu/tsystems/mms/tic/testframework/utils/DefaultCapabilityUtils.java b/driver-ui/src/main/java/eu/tsystems/mms/tic/testframework/utils/DefaultCapabilityUtils.java index 699759171e..9ad1406149 100644 --- a/driver-ui/src/main/java/eu/tsystems/mms/tic/testframework/utils/DefaultCapabilityUtils.java +++ b/driver-ui/src/main/java/eu/tsystems/mms/tic/testframework/utils/DefaultCapabilityUtils.java @@ -77,7 +77,6 @@ private Map shortChromeExtensionStrings(Map capa if (chromeOptionsObject != null) { final Map chromeOptions = (Map) chromeOptionsObject; if (chromeOptions.containsKey("extensions")) { -// chromeOptions.put("extensions", shortAllStringsInLists(chromeOptions.get("extensions"))); List extensions = shortAllStringsInLists(chromeOptions.get("extensions")); if (extensions.size() > 0) { chromeOptions.put("extensions", extensions); diff --git a/integration-tests/src/test/java/eu/tsystems/mms/tic/testframework/test/webdrivermanager/DesktopWebDriverFactoryTest.java b/integration-tests/src/test/java/eu/tsystems/mms/tic/testframework/test/webdrivermanager/DesktopWebDriverFactoryTest.java index a1827d052d..00cd314b01 100644 --- a/integration-tests/src/test/java/eu/tsystems/mms/tic/testframework/test/webdrivermanager/DesktopWebDriverFactoryTest.java +++ b/integration-tests/src/test/java/eu/tsystems/mms/tic/testframework/test/webdrivermanager/DesktopWebDriverFactoryTest.java @@ -28,7 +28,6 @@ import eu.tsystems.mms.tic.testframework.useragents.ChromeConfig; import eu.tsystems.mms.tic.testframework.webdrivermanager.DesktopWebDriverRequest; import org.openqa.selenium.WebDriver; -import org.openqa.selenium.chrome.ChromeOptions; import org.openqa.selenium.remote.DesiredCapabilities; import org.testng.Assert; import org.testng.annotations.Test; @@ -91,12 +90,8 @@ public void testT04_EndPointCapabilities_Global() { @Test public void test05_EndPointCapabilities_UserAgent() { - WEB_DRIVER_MANAGER.setUserAgentConfig(Browsers.chromeHeadless, new ChromeConfig() { - @Override - public void configure(ChromeOptions options) { - options.setCapability("t05UserAgent", "yesyes"); - } - }); + WEB_DRIVER_MANAGER.setUserAgentConfig(Browsers.chromeHeadless, + (ChromeConfig) options -> options.setCapability("t05UserAgent", "yesyes")); WebDriver driver = WEB_DRIVER_MANAGER.getWebDriver(); From a85393c3913692b8f5bcd30b99ba8a8a7253af67 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Gro=C3=9Fmann?= Date: Thu, 8 Dec 2022 20:48:38 +0100 Subject: [PATCH 12/64] Reverted to Selenium 4.5.0 --- build.gradle | 5 +++-- driver-ui/build.gradle | 9 +++------ 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/build.gradle b/build.gradle index 19a4b5aea9..13be0ef916 100644 --- a/build.gradle +++ b/build.gradle @@ -20,8 +20,9 @@ ext { core = project(':core') report = project(':report-ng') - seleniumVersion = '4.6.0' - guavaVersion = "28.1-jre" + seleniumVersion = '4.5.0' +// guavaVersion = "28.1-jre" + guavaVersion = "31.1-jre" moduleVersion = '2-SNAPSHOT' if (System.properties.containsKey('ttVersion')) { diff --git a/driver-ui/build.gradle b/driver-ui/build.gradle index 3e53ea64b4..045483da6c 100644 --- a/driver-ui/build.gradle +++ b/driver-ui/build.gradle @@ -22,20 +22,17 @@ dependencies { api 'org.sikuli:sikuli-api:1.2.0' // - // -// implementation 'org.glassfish.jersey.core:jersey-common:2.22.2' - // - -// implementation 'com.sun.jersey:jersey-client:1.19.3' -// implementation 'commons-codec:commons-codec:1.13' implementation 'commons-collections:commons-collections:3.2.2' implementation 'org.reflections:reflections:0.9.12' // //implementation 'nl.basjes.parse.useragent:yauaa:4.5' + // 1.5.3 implementation group: 'com.github.ua-parser', name: 'uap-java', version: '1.4.3' // + // Selenium 4.6 comes with 'io.netty:netty-transport-native-epoll:4.1.84.Final' + // -> Dependency error Could not find netty-transport-native-epoll-4.1.84.Final-linux-x86_64.jar (io.netty:netty-transport-native-epoll:4.1.84.Final). api 'org.seleniumhq.selenium:selenium-java:' + seleniumVersion } From 444ef530e4a4ec996e46437d37b26d52427a8180 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Gro=C3=9Fmann?= Date: Thu, 8 Dec 2022 20:48:38 +0100 Subject: [PATCH 13/64] Added hint --- build.gradle | 5 +++-- driver-ui/build.gradle | 9 +++------ 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/build.gradle b/build.gradle index 19a4b5aea9..cd9d42eeb6 100644 --- a/build.gradle +++ b/build.gradle @@ -20,8 +20,9 @@ ext { core = project(':core') report = project(':report-ng') - seleniumVersion = '4.6.0' - guavaVersion = "28.1-jre" + seleniumVersion = '4.5.0' + // Must be the same like in Selenium + guavaVersion = "31.1-jre" moduleVersion = '2-SNAPSHOT' if (System.properties.containsKey('ttVersion')) { diff --git a/driver-ui/build.gradle b/driver-ui/build.gradle index 3e53ea64b4..045483da6c 100644 --- a/driver-ui/build.gradle +++ b/driver-ui/build.gradle @@ -22,20 +22,17 @@ dependencies { api 'org.sikuli:sikuli-api:1.2.0' // - // -// implementation 'org.glassfish.jersey.core:jersey-common:2.22.2' - // - -// implementation 'com.sun.jersey:jersey-client:1.19.3' -// implementation 'commons-codec:commons-codec:1.13' implementation 'commons-collections:commons-collections:3.2.2' implementation 'org.reflections:reflections:0.9.12' // //implementation 'nl.basjes.parse.useragent:yauaa:4.5' + // 1.5.3 implementation group: 'com.github.ua-parser', name: 'uap-java', version: '1.4.3' // + // Selenium 4.6 comes with 'io.netty:netty-transport-native-epoll:4.1.84.Final' + // -> Dependency error Could not find netty-transport-native-epoll-4.1.84.Final-linux-x86_64.jar (io.netty:netty-transport-native-epoll:4.1.84.Final). api 'org.seleniumhq.selenium:selenium-java:' + seleniumVersion } From 4b104908542bcaf46355bd8cf505440d8893f547 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Gro=C3=9Fmann?= Date: Wed, 11 Jan 2023 18:04:45 +0100 Subject: [PATCH 14/64] Merged and updated --- .../webdrivermanager/DesktopWebDriverFactory.java | 3 +-- .../webdrivermanager/AbstractWebDriverRequest.java | 8 ++++++-- .../webdrivermanager/DesktopWebDriverRequest.java | 2 +- .../webdrivermanager/DesktopWebDriverFactoryTest.java | 2 +- 4 files changed, 9 insertions(+), 6 deletions(-) diff --git a/driver-ui-desktop/src/main/java/eu/tsystems/mms/tic/testframework/webdrivermanager/DesktopWebDriverFactory.java b/driver-ui-desktop/src/main/java/eu/tsystems/mms/tic/testframework/webdrivermanager/DesktopWebDriverFactory.java index db99acec62..dcd4006bdf 100644 --- a/driver-ui-desktop/src/main/java/eu/tsystems/mms/tic/testframework/webdrivermanager/DesktopWebDriverFactory.java +++ b/driver-ui-desktop/src/main/java/eu/tsystems/mms/tic/testframework/webdrivermanager/DesktopWebDriverFactory.java @@ -63,7 +63,6 @@ import java.lang.reflect.Constructor; import java.net.URL; import java.time.Duration; -import java.util.Arrays; import java.util.Date; import java.util.List; @@ -385,7 +384,7 @@ private WebDriver startNewWebDriverSession(DesktopWebDriverRequest request, Sess @Override public List getSupportedBrowsers() { - return Arrays.asList( + return List.of( Browsers.safari, Browsers.ie, Browsers.chrome, diff --git a/driver-ui/src/main/java/eu/tsystems/mms/tic/testframework/webdrivermanager/AbstractWebDriverRequest.java b/driver-ui/src/main/java/eu/tsystems/mms/tic/testframework/webdrivermanager/AbstractWebDriverRequest.java index 37175b4c55..19b783acae 100644 --- a/driver-ui/src/main/java/eu/tsystems/mms/tic/testframework/webdrivermanager/AbstractWebDriverRequest.java +++ b/driver-ui/src/main/java/eu/tsystems/mms/tic/testframework/webdrivermanager/AbstractWebDriverRequest.java @@ -22,8 +22,12 @@ import eu.tsystems.mms.tic.testframework.common.PropertyManager; import eu.tsystems.mms.tic.testframework.constants.TesterraProperties; +import eu.tsystems.mms.tic.testframework.logging.Loggable; import org.apache.commons.lang3.StringUtils; import org.openqa.selenium.Capabilities; +import org.openqa.selenium.Platform; +import org.openqa.selenium.WebDriverException; +import org.openqa.selenium.remote.CapabilityType; import org.openqa.selenium.remote.DesiredCapabilities; import java.net.MalformedURLException; @@ -185,8 +189,8 @@ public void setPlatformName(String platformName) { } public Optional getPlatformName() { - if (this.getDesiredCapabilities().getPlatform() != null) { - return Optional.ofNullable(this.getDesiredCapabilities().getPlatform().toString()); + if (this.getDesiredCapabilities().getPlatformName() != null) { + return Optional.ofNullable(this.getDesiredCapabilities().getPlatformName().toString()); } return Optional.empty(); } diff --git a/driver-ui/src/main/java/eu/tsystems/mms/tic/testframework/webdrivermanager/DesktopWebDriverRequest.java b/driver-ui/src/main/java/eu/tsystems/mms/tic/testframework/webdrivermanager/DesktopWebDriverRequest.java index e48b925826..3fa2b731c9 100644 --- a/driver-ui/src/main/java/eu/tsystems/mms/tic/testframework/webdrivermanager/DesktopWebDriverRequest.java +++ b/driver-ui/src/main/java/eu/tsystems/mms/tic/testframework/webdrivermanager/DesktopWebDriverRequest.java @@ -34,7 +34,7 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; -public class DesktopWebDriverRequest extends SeleniumWebDriverRequest implements Loggable, Serializable, PropertyManagerProvider { +public class DesktopWebDriverRequest extends SeleniumWebDriverRequest implements Serializable, PropertyManagerProvider { /* Default values for the size of a browser window. diff --git a/integration-tests/src/test/java/eu/tsystems/mms/tic/testframework/test/webdrivermanager/DesktopWebDriverFactoryTest.java b/integration-tests/src/test/java/eu/tsystems/mms/tic/testframework/test/webdrivermanager/DesktopWebDriverFactoryTest.java index 13ced970d1..3452ac4ef3 100644 --- a/integration-tests/src/test/java/eu/tsystems/mms/tic/testframework/test/webdrivermanager/DesktopWebDriverFactoryTest.java +++ b/integration-tests/src/test/java/eu/tsystems/mms/tic/testframework/test/webdrivermanager/DesktopWebDriverFactoryTest.java @@ -107,7 +107,7 @@ public void test05_EndPointCapabilities_UserAgent() { } @Test - public void testT04_PlatformCaps() { + public void testT06_PlatformCaps() { DesktopWebDriverRequest request = new DesktopWebDriverRequest(); request.setPlatformName(Platform.LINUX.toString()); WebDriver driver = WEB_DRIVER_MANAGER.getWebDriver(request); From ede674df9b8797afe1ea7f9e2327cb8159b5c379 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Gro=C3=9Fmann?= Date: Thu, 12 Jan 2023 09:28:46 +0100 Subject: [PATCH 15/64] Added selenium version comment --- build.gradle | 1 + 1 file changed, 1 insertion(+) diff --git a/build.gradle b/build.gradle index 848412752e..fb9c023869 100644 --- a/build.gradle +++ b/build.gradle @@ -20,6 +20,7 @@ ext { core = project(':core') report = project(':report-ng') +// seleniumVersion = '4.7.2' seleniumVersion = '4.6.0' // guavaVersion = "28.1-jre" guavaVersion = "31.1-jre" From b60c9080819c4e1fad38b53311796c5ce7d6550d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Gro=C3=9Fmann?= Date: Thu, 12 Jan 2023 17:45:48 +0100 Subject: [PATCH 16/64] Fixed merging stuff, updated to Selenium 4.7.2 --- build.gradle | 6 +++--- .../webdrivermanager/DesktopWebDriverFactory.java | 4 ++-- .../webdrivermanager/AbstractWebDriverRequest.java | 2 +- .../test/webdrivermanager/DesktopWebDriverFactoryTest.java | 7 ++----- 4 files changed, 8 insertions(+), 11 deletions(-) diff --git a/build.gradle b/build.gradle index fb9c023869..31c56d2898 100644 --- a/build.gradle +++ b/build.gradle @@ -20,9 +20,9 @@ ext { core = project(':core') report = project(':report-ng') -// seleniumVersion = '4.7.2' - seleniumVersion = '4.6.0' -// guavaVersion = "28.1-jre" + seleniumVersion = '4.7.2' +// seleniumVersion = '4.6.0' + // Must be the same like in Selenium 4 guavaVersion = "31.1-jre" moduleVersion = '2-SNAPSHOT' diff --git a/driver-ui-desktop/src/main/java/eu/tsystems/mms/tic/testframework/webdrivermanager/DesktopWebDriverFactory.java b/driver-ui-desktop/src/main/java/eu/tsystems/mms/tic/testframework/webdrivermanager/DesktopWebDriverFactory.java index dcd4006bdf..e8dc5c0f7e 100644 --- a/driver-ui-desktop/src/main/java/eu/tsystems/mms/tic/testframework/webdrivermanager/DesktopWebDriverFactory.java +++ b/driver-ui-desktop/src/main/java/eu/tsystems/mms/tic/testframework/webdrivermanager/DesktopWebDriverFactory.java @@ -174,9 +174,9 @@ public WebDriverRequest prepareWebDriverRequest(WebDriverRequest webDriverReques break; } - DesiredCapabilities desiredCapabilities = finalRequest.getDesiredCapabilities(); if (userAgentCapabilities != null) { - desiredCapabilities.merge(userAgentCapabilities); + userAgentCapabilities = userAgentCapabilities.merge(finalRequest.getDesiredCapabilities()); + finalRequest.setBrowserOptions(userAgentCapabilities); } return finalRequest; } diff --git a/driver-ui/src/main/java/eu/tsystems/mms/tic/testframework/webdrivermanager/AbstractWebDriverRequest.java b/driver-ui/src/main/java/eu/tsystems/mms/tic/testframework/webdrivermanager/AbstractWebDriverRequest.java index 19b783acae..a44668ca48 100644 --- a/driver-ui/src/main/java/eu/tsystems/mms/tic/testframework/webdrivermanager/AbstractWebDriverRequest.java +++ b/driver-ui/src/main/java/eu/tsystems/mms/tic/testframework/webdrivermanager/AbstractWebDriverRequest.java @@ -181,7 +181,7 @@ public void setPlatformName(String platformName) { try { if (StringUtils.isNotBlank(platformName)) { final Platform platform = Platform.fromString(platformName); - this.getDesiredCapabilities().setCapability(CapabilityType.PLATFORM_NAME, platform); + this.getDesiredCapabilities().setPlatform(platform); } } catch (WebDriverException e) { log().warn("Trying to set invalid platform '{}' was ignored.", platformName); diff --git a/integration-tests/src/test/java/eu/tsystems/mms/tic/testframework/test/webdrivermanager/DesktopWebDriverFactoryTest.java b/integration-tests/src/test/java/eu/tsystems/mms/tic/testframework/test/webdrivermanager/DesktopWebDriverFactoryTest.java index 3452ac4ef3..f3b3d39a81 100644 --- a/integration-tests/src/test/java/eu/tsystems/mms/tic/testframework/test/webdrivermanager/DesktopWebDriverFactoryTest.java +++ b/integration-tests/src/test/java/eu/tsystems/mms/tic/testframework/test/webdrivermanager/DesktopWebDriverFactoryTest.java @@ -25,8 +25,6 @@ import eu.tsystems.mms.tic.testframework.report.model.context.SessionContext; import eu.tsystems.mms.tic.testframework.testing.TesterraTest; import eu.tsystems.mms.tic.testframework.testing.WebDriverManagerProvider; -import eu.tsystems.mms.tic.testframework.testing.TesterraTest; -import eu.tsystems.mms.tic.testframework.testing.WebDriverManagerProvider; import eu.tsystems.mms.tic.testframework.useragents.ChromeConfig; import eu.tsystems.mms.tic.testframework.webdrivermanager.DesktopWebDriverRequest; import eu.tsystems.mms.tic.testframework.webdrivermanager.WebDriverRequest; @@ -109,12 +107,11 @@ public void test05_EndPointCapabilities_UserAgent() { @Test public void testT06_PlatformCaps() { DesktopWebDriverRequest request = new DesktopWebDriverRequest(); - request.setPlatformName(Platform.LINUX.toString()); + request.setPlatformName(Platform.ANY.toString()); WebDriver driver = WEB_DRIVER_MANAGER.getWebDriver(request); WebDriverRequest webDriverRequest = WEB_DRIVER_MANAGER.getSessionContext(driver).get().getWebDriverRequest(); - Assert.assertEquals(webDriverRequest.getCapabilities().get(CapabilityType.PLATFORM_NAME), Platform.LINUX); + Assert.assertEquals(webDriverRequest.getCapabilities().get(CapabilityType.PLATFORM_NAME), Platform.ANY); } - } From fc8e57387a960b271d1318f97a5edaf6d0a05831 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Gro=C3=9Fmann?= Date: Fri, 13 Jan 2023 14:41:22 +0100 Subject: [PATCH 17/64] Added test for capability priority --- .../DesktopWebDriverFactoryTest.java | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/integration-tests/src/test/java/eu/tsystems/mms/tic/testframework/test/webdrivermanager/DesktopWebDriverFactoryTest.java b/integration-tests/src/test/java/eu/tsystems/mms/tic/testframework/test/webdrivermanager/DesktopWebDriverFactoryTest.java index f3b3d39a81..c05f1ef443 100644 --- a/integration-tests/src/test/java/eu/tsystems/mms/tic/testframework/test/webdrivermanager/DesktopWebDriverFactoryTest.java +++ b/integration-tests/src/test/java/eu/tsystems/mms/tic/testframework/test/webdrivermanager/DesktopWebDriverFactoryTest.java @@ -29,6 +29,7 @@ import eu.tsystems.mms.tic.testframework.webdrivermanager.DesktopWebDriverRequest; import eu.tsystems.mms.tic.testframework.webdrivermanager.WebDriverRequest; import org.openqa.selenium.Platform; +import org.openqa.selenium.Proxy; import org.openqa.selenium.WebDriver; import org.openqa.selenium.remote.CapabilityType; import org.openqa.selenium.remote.DesiredCapabilities; @@ -114,4 +115,30 @@ public void testT06_PlatformCaps() { Assert.assertEquals(webDriverRequest.getCapabilities().get(CapabilityType.PLATFORM_NAME), Platform.ANY); } + + @Test + public void testT07_OverwriteCaps() { + Proxy agentProxy = new Proxy(); + agentProxy.setHttpProxy("my.agent.proxy:8080"); + Proxy requestProxy = new Proxy(); + requestProxy.setHttpProxy("my.request.proxy:8080"); + + WEB_DRIVER_MANAGER.setUserAgentConfig(Browsers.chromeHeadless, + (ChromeConfig) options -> { + options.setCapability("t07Overwrite", "agentCaps"); + options.setProxy(agentProxy); + }); + + DesktopWebDriverRequest request = new DesktopWebDriverRequest(); + request.getDesiredCapabilities().setCapability("t07Overwrite", "requestCaps"); + request.getDesiredCapabilities().setCapability(CapabilityType.PROXY, requestProxy); + + WebDriver driver = WEB_DRIVER_MANAGER.getWebDriver(request); + + SessionContext sessionContext = WEB_DRIVER_MANAGER.getSessionContext(driver).get(); + Map sessionCapabilities = sessionContext.getWebDriverRequest().getCapabilities(); + + Assert.assertEquals(sessionCapabilities.get("t07Overwrite"), "requestCaps", "Request capability is set"); + Assert.assertEquals(sessionCapabilities.get(CapabilityType.PROXY), requestProxy, "Request proxy is set"); + } } From 7f6aa9fe50569a78ccb8b69d4fe7c948de7924b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Gro=C3=9Fmann?= Date: Fri, 13 Jan 2023 15:01:43 +0100 Subject: [PATCH 18/64] Removed proxy settings from overwrite caps test --- .../test/webdrivermanager/DesktopWebDriverFactoryTest.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/integration-tests/src/test/java/eu/tsystems/mms/tic/testframework/test/webdrivermanager/DesktopWebDriverFactoryTest.java b/integration-tests/src/test/java/eu/tsystems/mms/tic/testframework/test/webdrivermanager/DesktopWebDriverFactoryTest.java index c05f1ef443..41cc29aca4 100644 --- a/integration-tests/src/test/java/eu/tsystems/mms/tic/testframework/test/webdrivermanager/DesktopWebDriverFactoryTest.java +++ b/integration-tests/src/test/java/eu/tsystems/mms/tic/testframework/test/webdrivermanager/DesktopWebDriverFactoryTest.java @@ -126,12 +126,12 @@ public void testT07_OverwriteCaps() { WEB_DRIVER_MANAGER.setUserAgentConfig(Browsers.chromeHeadless, (ChromeConfig) options -> { options.setCapability("t07Overwrite", "agentCaps"); - options.setProxy(agentProxy); +// options.setProxy(agentProxy); }); DesktopWebDriverRequest request = new DesktopWebDriverRequest(); request.getDesiredCapabilities().setCapability("t07Overwrite", "requestCaps"); - request.getDesiredCapabilities().setCapability(CapabilityType.PROXY, requestProxy); +// request.getDesiredCapabilities().setCapability(CapabilityType.PROXY, requestProxy); WebDriver driver = WEB_DRIVER_MANAGER.getWebDriver(request); @@ -139,6 +139,6 @@ public void testT07_OverwriteCaps() { Map sessionCapabilities = sessionContext.getWebDriverRequest().getCapabilities(); Assert.assertEquals(sessionCapabilities.get("t07Overwrite"), "requestCaps", "Request capability is set"); - Assert.assertEquals(sessionCapabilities.get(CapabilityType.PROXY), requestProxy, "Request proxy is set"); +// Assert.assertEquals(sessionCapabilities.get(CapabilityType.PROXY), requestProxy, "Request proxy is set"); } } From 18721b6070efd72476052b3d0fa3be826d43e5f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Gro=C3=9Fmann?= Date: Fri, 13 Jan 2023 15:37:31 +0100 Subject: [PATCH 19/64] Added playground tests for Chrome DevTools --- .../playground/ChromeDevToolsTests.java | 59 +++++++++++++++++++ 1 file changed, 59 insertions(+) create mode 100644 integration-tests/src/test/java/eu/tsystems/mms/tic/testframework/playground/ChromeDevToolsTests.java diff --git a/integration-tests/src/test/java/eu/tsystems/mms/tic/testframework/playground/ChromeDevToolsTests.java b/integration-tests/src/test/java/eu/tsystems/mms/tic/testframework/playground/ChromeDevToolsTests.java new file mode 100644 index 0000000000..217fc60246 --- /dev/null +++ b/integration-tests/src/test/java/eu/tsystems/mms/tic/testframework/playground/ChromeDevToolsTests.java @@ -0,0 +1,59 @@ +package eu.tsystems.mms.tic.testframework.playground; + +import eu.tsystems.mms.tic.testframework.AbstractWebDriverTest; +import eu.tsystems.mms.tic.testframework.constants.Browsers; +import eu.tsystems.mms.tic.testframework.webdrivermanager.DesktopWebDriverRequest; +import org.openqa.selenium.WebDriver; +import org.openqa.selenium.chrome.ChromeDriver; +import org.openqa.selenium.devtools.DevTools; +import org.openqa.selenium.devtools.HasDevTools; +import org.openqa.selenium.devtools.v106.emulation.Emulation; +import org.openqa.selenium.remote.Augmenter; +import org.openqa.selenium.support.events.EventFiringWebDriver; +import org.testng.annotations.Test; + +import java.util.Optional; + +/** + * Created on 2023-01-13 + * + * @author mgn + */ +public class ChromeDevToolsTests extends AbstractWebDriverTest { + + /** + * See here for examples: + * https://www.selenium.dev/documentation/webdriver/bidirectional/chrome_devtools/ + */ + + @Test + public void testT01_GeoLocation_localDriver() { + DesktopWebDriverRequest request = new DesktopWebDriverRequest(); + request.setBrowser(Browsers.chrome); + WebDriver webDriver = WEB_DRIVER_MANAGER.getWebDriver(request); + + ChromeDriver chromeDriver = WEB_DRIVER_MANAGER.unwrapWebDriver(webDriver, ChromeDriver.class).get(); + + DevTools devTools = chromeDriver.getDevTools(); + devTools.createSession(); + devTools.send(Emulation.setGeolocationOverride(Optional.of(52.5043), + Optional.of(13.4501), + Optional.of(1))); + webDriver.get("https://my-location.org/"); + } + + @Test + public void testT02_GeoLocation_remoteDriver() { + WebDriver webDriver = this.getWebDriver(); + webDriver = new Augmenter().augment(webDriver); + + DevTools devTools = ((HasDevTools) webDriver).getDevTools(); + devTools.createSession(); + + devTools.send(Emulation.setGeolocationOverride(Optional.of(52.5043), + Optional.of(13.4501), + Optional.of(1))); + + webDriver.get("https://my-location.org/"); + } +} From 4eda7db198fa412377255ce3a71e0842e194147a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Gro=C3=9Fmann?= Date: Fri, 13 Jan 2023 17:14:45 +0100 Subject: [PATCH 20/64] Updated ChromeDevTools tests --- .../playground/BrowserDevToolsTests.java | 112 ++++++++++++++++++ .../playground/ChromeDevToolsTests.java | 59 --------- 2 files changed, 112 insertions(+), 59 deletions(-) create mode 100644 integration-tests/src/test/java/eu/tsystems/mms/tic/testframework/playground/BrowserDevToolsTests.java delete mode 100644 integration-tests/src/test/java/eu/tsystems/mms/tic/testframework/playground/ChromeDevToolsTests.java diff --git a/integration-tests/src/test/java/eu/tsystems/mms/tic/testframework/playground/BrowserDevToolsTests.java b/integration-tests/src/test/java/eu/tsystems/mms/tic/testframework/playground/BrowserDevToolsTests.java new file mode 100644 index 0000000000..3cdfc1de9f --- /dev/null +++ b/integration-tests/src/test/java/eu/tsystems/mms/tic/testframework/playground/BrowserDevToolsTests.java @@ -0,0 +1,112 @@ +package eu.tsystems.mms.tic.testframework.playground; + +import eu.tsystems.mms.tic.testframework.AbstractWebDriverTest; +import eu.tsystems.mms.tic.testframework.constants.Browsers; +import eu.tsystems.mms.tic.testframework.webdrivermanager.DesktopWebDriverRequest; +import org.openqa.selenium.HasAuthentication; +import org.openqa.selenium.UsernameAndPassword; +import org.openqa.selenium.WebDriver; +import org.openqa.selenium.chrome.ChromeDriver; +import org.openqa.selenium.devtools.DevTools; +import org.openqa.selenium.devtools.HasDevTools; +import org.openqa.selenium.devtools.v106.emulation.Emulation; +import org.openqa.selenium.remote.Augmenter; +import org.openqa.selenium.remote.RemoteWebDriver; +import org.testng.annotations.Test; + +import java.util.Optional; +import java.util.concurrent.atomic.AtomicReference; + +/** + * Created on 2023-01-13 + * + * @author mgn + */ +public class BrowserDevToolsTests extends AbstractWebDriverTest { + + /** + * See here for examples: + * https://www.selenium.dev/documentation/webdriver/bidirectional/bidi_api_remotewebdriver/ + * https://www.selenium.dev/documentation/webdriver/bidirectional/chrome_devtools/ + *

+ *

+ * Important for local selenium server: + * - Use --host parameter, otherwise it could return a wrong IP address from another network interface (e.g. with active VPN) + *

+ * Example + * - java -Dwebdriver.chrome.driver=driver\chromedriver.exe -jar selenium4\selenium-server-4.7.2.jar standalone --port 4444 --host localhost + * + * + * Known issues: + * - Issue with Selenoid: https://github.com/aerokube/selenoid/issues/1063 + */ + + @Test + public void testT01_GeoLocation_localDriver() { + DesktopWebDriverRequest request = new DesktopWebDriverRequest(); + request.setBrowser(Browsers.chrome); + WebDriver webDriver = WEB_DRIVER_MANAGER.getWebDriver(request); + + ChromeDriver chromeDriver = WEB_DRIVER_MANAGER.unwrapWebDriver(webDriver, ChromeDriver.class).get(); + + DevTools devTools = chromeDriver.getDevTools(); + devTools.createSession(); + devTools.send(Emulation.setGeolocationOverride(Optional.of(52.5043), + Optional.of(13.4501), + Optional.of(1))); + webDriver.get("https://my-location.org/"); + } + + @Test + public void testT02_GeoLocation_remoteDriver() { + DesktopWebDriverRequest request = new DesktopWebDriverRequest(); + request.setBrowser(Browsers.chrome); +// request.setBrowser(Browsers.firefox); + WebDriver webDriver = WEB_DRIVER_MANAGER.getWebDriver(request); + RemoteWebDriver remoteWebDriver = WEB_DRIVER_MANAGER.unwrapWebDriver(webDriver, RemoteWebDriver.class).get(); + + webDriver = new Augmenter().augment(remoteWebDriver); + + DevTools devTools = ((HasDevTools) webDriver).getDevTools(); + devTools.createSession(); + + devTools.send(Emulation.setGeolocationOverride(Optional.of(52.5043), + Optional.of(13.4501), + Optional.of(1))); + + webDriver.get("https://my-location.org/"); + } + + @Test + public void testT04_BasicAuth_remoteDriver() { + DesktopWebDriverRequest request = new DesktopWebDriverRequest(); + request.setBrowser(Browsers.chrome); + request.setBrowserVersion("106"); +// request.getDesiredCapabilities().setCapability("se:cdp", "http://"); + WebDriver webDriver = WEB_DRIVER_MANAGER.getWebDriver(request); + WebDriver remoteWebDriver = WEB_DRIVER_MANAGER.unwrapWebDriver(webDriver, RemoteWebDriver.class).get(); + + AtomicReference devToolsAtomicReference = new AtomicReference<>(); + + remoteWebDriver = new Augmenter() + .addDriverAugmentation("chrome", + HasAuthentication.class, + (caps, exec) -> (whenThisMatches, useTheseCredentials) -> { + + devToolsAtomicReference.get() + .createSessionIfThereIsNotOne(); + devToolsAtomicReference.get().getDomains() + .network() + .addAuthHandler(whenThisMatches, useTheseCredentials); + + }) + .augment(remoteWebDriver); + + DevTools devTools = ((HasDevTools) remoteWebDriver).getDevTools(); + devTools.createSession(); + devToolsAtomicReference.set(devTools); + ((HasAuthentication) remoteWebDriver).register(UsernameAndPassword.of("admin", "admin")); + + remoteWebDriver.get("https://the-internet.herokuapp.com/basic_auth"); + } +} diff --git a/integration-tests/src/test/java/eu/tsystems/mms/tic/testframework/playground/ChromeDevToolsTests.java b/integration-tests/src/test/java/eu/tsystems/mms/tic/testframework/playground/ChromeDevToolsTests.java deleted file mode 100644 index 217fc60246..0000000000 --- a/integration-tests/src/test/java/eu/tsystems/mms/tic/testframework/playground/ChromeDevToolsTests.java +++ /dev/null @@ -1,59 +0,0 @@ -package eu.tsystems.mms.tic.testframework.playground; - -import eu.tsystems.mms.tic.testframework.AbstractWebDriverTest; -import eu.tsystems.mms.tic.testframework.constants.Browsers; -import eu.tsystems.mms.tic.testframework.webdrivermanager.DesktopWebDriverRequest; -import org.openqa.selenium.WebDriver; -import org.openqa.selenium.chrome.ChromeDriver; -import org.openqa.selenium.devtools.DevTools; -import org.openqa.selenium.devtools.HasDevTools; -import org.openqa.selenium.devtools.v106.emulation.Emulation; -import org.openqa.selenium.remote.Augmenter; -import org.openqa.selenium.support.events.EventFiringWebDriver; -import org.testng.annotations.Test; - -import java.util.Optional; - -/** - * Created on 2023-01-13 - * - * @author mgn - */ -public class ChromeDevToolsTests extends AbstractWebDriverTest { - - /** - * See here for examples: - * https://www.selenium.dev/documentation/webdriver/bidirectional/chrome_devtools/ - */ - - @Test - public void testT01_GeoLocation_localDriver() { - DesktopWebDriverRequest request = new DesktopWebDriverRequest(); - request.setBrowser(Browsers.chrome); - WebDriver webDriver = WEB_DRIVER_MANAGER.getWebDriver(request); - - ChromeDriver chromeDriver = WEB_DRIVER_MANAGER.unwrapWebDriver(webDriver, ChromeDriver.class).get(); - - DevTools devTools = chromeDriver.getDevTools(); - devTools.createSession(); - devTools.send(Emulation.setGeolocationOverride(Optional.of(52.5043), - Optional.of(13.4501), - Optional.of(1))); - webDriver.get("https://my-location.org/"); - } - - @Test - public void testT02_GeoLocation_remoteDriver() { - WebDriver webDriver = this.getWebDriver(); - webDriver = new Augmenter().augment(webDriver); - - DevTools devTools = ((HasDevTools) webDriver).getDevTools(); - devTools.createSession(); - - devTools.send(Emulation.setGeolocationOverride(Optional.of(52.5043), - Optional.of(13.4501), - Optional.of(1))); - - webDriver.get("https://my-location.org/"); - } -} From 01db43af1f61b171b1b93cee813484387378be6e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Gro=C3=9Fmann?= Date: Tue, 25 Apr 2023 16:04:08 +0200 Subject: [PATCH 21/64] Activated extensions test for chrome because of merge issue of capabilities (fixed with Selenium 4) --- .../mms/tic/testframework/test/utils/FileDownloaderTest.java | 2 +- .../test/webdrivermanager/DesktopWebDriverFactoryTest.java | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/integration-tests/src/test/java/eu/tsystems/mms/tic/testframework/test/utils/FileDownloaderTest.java b/integration-tests/src/test/java/eu/tsystems/mms/tic/testframework/test/utils/FileDownloaderTest.java index 0c0cfc3a23..ad2ebedad0 100644 --- a/integration-tests/src/test/java/eu/tsystems/mms/tic/testframework/test/utils/FileDownloaderTest.java +++ b/integration-tests/src/test/java/eu/tsystems/mms/tic/testframework/test/utils/FileDownloaderTest.java @@ -137,7 +137,7 @@ public void test04_readFileNameFromResponseHeader() throws IOException { @Test public void test05_readFileFromUrl() throws IOException { - final String baseUrl = String.format("http://localhost:%d/%s", server.getPort(), getTestPage().getPath()); + final String baseUrl = String.format("http://localhost:%d/%s", staticServer.getPort(), getTestPage().getPath()); final FileDownloader downloader = new FileDownloader(); final File file = downloader.download(baseUrl); diff --git a/integration-tests/src/test/java/eu/tsystems/mms/tic/testframework/test/webdrivermanager/DesktopWebDriverFactoryTest.java b/integration-tests/src/test/java/eu/tsystems/mms/tic/testframework/test/webdrivermanager/DesktopWebDriverFactoryTest.java index 6174568b19..d3aca64426 100644 --- a/integration-tests/src/test/java/eu/tsystems/mms/tic/testframework/test/webdrivermanager/DesktopWebDriverFactoryTest.java +++ b/integration-tests/src/test/java/eu/tsystems/mms/tic/testframework/test/webdrivermanager/DesktopWebDriverFactoryTest.java @@ -151,9 +151,8 @@ public void testT07_OverwriteCaps() { // Assert.assertEquals(sessionCapabilities.get(CapabilityType.PROXY), requestProxy, "Request proxy is set"); } - // TODO: Selenium 3 cannot merge correctly caps. Issue is fixed in Selenium 4 (https://github.com/telekom/testerra/issues/285) - @Test(enabled = false) - public void testT05_ChromeExtensions() throws MalformedURLException { + @Test + public void testT08_ChromeExtensions() throws MalformedURLException { File chromeExtensionFile = new File( Objects.requireNonNull(Thread.currentThread().getContextClassLoader().getResource("testfiles/Simple_Translate_2.8.1.0.crx")).getFile()); From 55ad3491d7970c73dad66d9bfe289161b358475e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Gro=C3=9Fmann?= Date: Thu, 27 Apr 2023 15:47:38 +0200 Subject: [PATCH 22/64] Added code comment --- .../testframework/webdrivermanager/WebDriverSessionsManager.java | 1 + 1 file changed, 1 insertion(+) diff --git a/driver-ui/src/main/java/eu/tsystems/mms/tic/testframework/webdrivermanager/WebDriverSessionsManager.java b/driver-ui/src/main/java/eu/tsystems/mms/tic/testframework/webdrivermanager/WebDriverSessionsManager.java index 9e9e90ad4a..2d1c4a443e 100644 --- a/driver-ui/src/main/java/eu/tsystems/mms/tic/testframework/webdrivermanager/WebDriverSessionsManager.java +++ b/driver-ui/src/main/java/eu/tsystems/mms/tic/testframework/webdrivermanager/WebDriverSessionsManager.java @@ -402,6 +402,7 @@ public static EventFiringWebDriver getWebDriver(final WebDriverRequest webDriver // Catch all existing browser caps and add them to specific browser options final WebDriverRequest finalWebDriverRequest = webDriverFactory.prepareWebDriverRequest(webDriverRequest); + // Update webDriverRequest with caps of external or global defined request configurators webDriverRequestConfigurators.forEach(handler -> handler.accept(finalWebDriverRequest)); // Create session context and link to method context From 2a41374910ee90437773f1eca0f509486a647b76 Mon Sep 17 00:00:00 2001 From: Wolfgang Lange Date: Tue, 23 May 2023 08:48:44 +0200 Subject: [PATCH 23/64] Adjusted selenium version to last stable - 4.9.0. --- build.gradle | 2 +- .../mms/tic/testframework/playground/BrowserDevToolsTests.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index 31c56d2898..464902e3ba 100644 --- a/build.gradle +++ b/build.gradle @@ -20,7 +20,7 @@ ext { core = project(':core') report = project(':report-ng') - seleniumVersion = '4.7.2' + seleniumVersion = '4.9.0' // seleniumVersion = '4.6.0' // Must be the same like in Selenium 4 guavaVersion = "31.1-jre" diff --git a/integration-tests/src/test/java/eu/tsystems/mms/tic/testframework/playground/BrowserDevToolsTests.java b/integration-tests/src/test/java/eu/tsystems/mms/tic/testframework/playground/BrowserDevToolsTests.java index 3cdfc1de9f..48e0070025 100644 --- a/integration-tests/src/test/java/eu/tsystems/mms/tic/testframework/playground/BrowserDevToolsTests.java +++ b/integration-tests/src/test/java/eu/tsystems/mms/tic/testframework/playground/BrowserDevToolsTests.java @@ -9,7 +9,7 @@ import org.openqa.selenium.chrome.ChromeDriver; import org.openqa.selenium.devtools.DevTools; import org.openqa.selenium.devtools.HasDevTools; -import org.openqa.selenium.devtools.v106.emulation.Emulation; +import org.openqa.selenium.devtools.v112.emulation.Emulation; import org.openqa.selenium.remote.Augmenter; import org.openqa.selenium.remote.RemoteWebDriver; import org.testng.annotations.Test; From ce13e9b8f20f2754b6d5b7e84531d714ba6bd622 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Gro=C3=9Fmann?= Date: Wed, 7 Jun 2023 08:24:57 +0200 Subject: [PATCH 24/64] Fixed merge conflict --- .../test/webdrivermanager/DesktopWebDriverFactoryTest.java | 1 + 1 file changed, 1 insertion(+) diff --git a/integration-tests/src/test/java/eu/tsystems/mms/tic/testframework/test/webdrivermanager/DesktopWebDriverFactoryTest.java b/integration-tests/src/test/java/eu/tsystems/mms/tic/testframework/test/webdrivermanager/DesktopWebDriverFactoryTest.java index 840e389e49..cde8892f6b 100644 --- a/integration-tests/src/test/java/eu/tsystems/mms/tic/testframework/test/webdrivermanager/DesktopWebDriverFactoryTest.java +++ b/integration-tests/src/test/java/eu/tsystems/mms/tic/testframework/test/webdrivermanager/DesktopWebDriverFactoryTest.java @@ -28,6 +28,7 @@ import eu.tsystems.mms.tic.testframework.testing.TesterraTest; import eu.tsystems.mms.tic.testframework.testing.UiElementFinderFactoryProvider; import eu.tsystems.mms.tic.testframework.testing.WebDriverManagerProvider; +import eu.tsystems.mms.tic.testframework.useragents.ChromeConfig; import eu.tsystems.mms.tic.testframework.webdrivermanager.DesktopWebDriverRequest; import eu.tsystems.mms.tic.testframework.webdrivermanager.WebDriverRequest; import org.openqa.selenium.By; From 497a99d0396012c93dc6d527d25e09b89d2dcf36 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Gro=C3=9Fmann?= Date: Wed, 7 Jun 2023 18:59:35 +0200 Subject: [PATCH 25/64] Fixed capability tests --- .../DesktopWebDriverFactory.java | 1 + .../DesktopWebDriverFactoryTest.java | 58 +++++++++++-------- 2 files changed, 34 insertions(+), 25 deletions(-) diff --git a/driver-ui-desktop/src/main/java/eu/tsystems/mms/tic/testframework/webdrivermanager/DesktopWebDriverFactory.java b/driver-ui-desktop/src/main/java/eu/tsystems/mms/tic/testframework/webdrivermanager/DesktopWebDriverFactory.java index e8dc5c0f7e..29992ba853 100644 --- a/driver-ui-desktop/src/main/java/eu/tsystems/mms/tic/testframework/webdrivermanager/DesktopWebDriverFactory.java +++ b/driver-ui-desktop/src/main/java/eu/tsystems/mms/tic/testframework/webdrivermanager/DesktopWebDriverFactory.java @@ -174,6 +174,7 @@ public WebDriverRequest prepareWebDriverRequest(WebDriverRequest webDriverReques break; } + // Any additional defined desired capabilities are merged into browser options if (userAgentCapabilities != null) { userAgentCapabilities = userAgentCapabilities.merge(finalRequest.getDesiredCapabilities()); finalRequest.setBrowserOptions(userAgentCapabilities); diff --git a/integration-tests/src/test/java/eu/tsystems/mms/tic/testframework/test/webdrivermanager/DesktopWebDriverFactoryTest.java b/integration-tests/src/test/java/eu/tsystems/mms/tic/testframework/test/webdrivermanager/DesktopWebDriverFactoryTest.java index cde8892f6b..2c4ed79e67 100644 --- a/integration-tests/src/test/java/eu/tsystems/mms/tic/testframework/test/webdrivermanager/DesktopWebDriverFactoryTest.java +++ b/integration-tests/src/test/java/eu/tsystems/mms/tic/testframework/test/webdrivermanager/DesktopWebDriverFactoryTest.java @@ -33,7 +33,6 @@ import eu.tsystems.mms.tic.testframework.webdrivermanager.WebDriverRequest; import org.openqa.selenium.By; import org.openqa.selenium.Platform; -import org.openqa.selenium.Proxy; import org.openqa.selenium.WebDriver; import org.openqa.selenium.chrome.ChromeOptions; import org.openqa.selenium.remote.CapabilityType; @@ -42,6 +41,7 @@ import org.testng.annotations.Test; import java.io.File; +import java.util.HashMap; import java.util.Map; import java.util.Objects; @@ -73,83 +73,91 @@ public void testT03_EndPointCapabilities_WebDriverRequest() throws Exception { request.setBaseUrl("http://google.de"); DesiredCapabilities caps = request.getDesiredCapabilities(); - caps.setCapability("enableVideo", true); - caps.setCapability("enableVNC", true); + Map selenoidCaps = new HashMap<>(); + selenoidCaps.put("enableVideo", true); + selenoidCaps.put("enableVNC", true); + caps.setCapability("selenoid:options", selenoidCaps); WebDriver driver = WEB_DRIVER_MANAGER.getWebDriver(request); SessionContext sessionContext = WEB_DRIVER_MANAGER.getSessionContext(driver).get(); - Map sessionCapabilities = sessionContext.getWebDriverRequest().getCapabilities(); + Map sessionCapabilities = (Map) sessionContext.getWebDriverRequest().getCapabilities().get("selenoid:options"); - Assert.assertEquals(sessionCapabilities.get("enableVideo"), caps.getCapability("enableVideo"), "EndPoint Capability via WebDriverRequest is set"); - Assert.assertEquals(sessionCapabilities.get("enableVNC"), caps.getCapability("enableVNC"), "EndPoint Capability via WebDriverRequest is set"); + Assert.assertEquals(sessionCapabilities.get("enableVideo"), selenoidCaps.get("enableVideo"), "EndPoint Capability via WebDriverRequest is set"); + Assert.assertEquals(sessionCapabilities.get("enableVNC"), selenoidCaps.get("enableVNC"), "EndPoint Capability via WebDriverRequest is set"); } + // TODO Global caps!! -> needs to be independent from other tests @Test public void testT04_EndPointCapabilities_Global() { - WEB_DRIVER_MANAGER.setGlobalCapability("t04Global", "yes"); + Map customCaps = new HashMap<>(); + customCaps.put("t04Global", "yes"); + WEB_DRIVER_MANAGER.setGlobalCapability("custom:caps", customCaps); WebDriver driver = WEB_DRIVER_MANAGER.getWebDriver(); - WEB_DRIVER_MANAGER.removeGlobalCapability("t04Global"); + WEB_DRIVER_MANAGER.removeGlobalCapability("custom:caps"); SessionContext sessionContext = WEB_DRIVER_MANAGER.getSessionContext(driver).get(); - Map sessionCapabilities = sessionContext.getWebDriverRequest().getCapabilities(); + Map sessionCapabilities = (Map) sessionContext.getWebDriverRequest().getCapabilities().get("custom:caps"); Assert.assertEquals(sessionCapabilities.get("t04Global"), "yes", "EndPoint Capability is set"); } + // TODO Global caps!! -> needs to be independent from other tests @Test public void test05_EndPointCapabilities_UserAgent() { + Map customCaps = new HashMap<>(); + customCaps.put("t05UserAgent", "yesyes"); WEB_DRIVER_MANAGER.setUserAgentConfig(Browsers.chromeHeadless, - (ChromeConfig) options -> options.setCapability("t05UserAgent", "yesyes")); + (ChromeConfig) options -> options.setCapability("custom:caps", customCaps)); WebDriver driver = WEB_DRIVER_MANAGER.getWebDriver(); SessionContext sessionContext = WEB_DRIVER_MANAGER.getSessionContext(driver).get(); - Map sessionCapabilities = sessionContext.getWebDriverRequest().getCapabilities(); + Map sessionCapabilities = (Map) sessionContext.getWebDriverRequest().getCapabilities().get("custom:caps"); Assert.assertEquals(sessionCapabilities.get("t05UserAgent"), "yesyes", "EndPoint Capability is set"); } - @Test + // TODO Can only run with Remote Selenium server + @Test(enabled = false) public void testT06_PlatformCaps() { DesktopWebDriverRequest request = new DesktopWebDriverRequest(); - request.setPlatformName(Platform.ANY.toString()); + request.setPlatformName(Platform.WINDOWS.toString()); WebDriver driver = WEB_DRIVER_MANAGER.getWebDriver(request); WebDriverRequest webDriverRequest = WEB_DRIVER_MANAGER.getSessionContext(driver).get().getWebDriverRequest(); - Assert.assertEquals(webDriverRequest.getCapabilities().get(CapabilityType.PLATFORM_NAME), Platform.ANY); + Assert.assertEquals(webDriverRequest.getCapabilities().get(CapabilityType.PLATFORM_NAME), Platform.WINDOWS); } + // TODO Global caps!! -> needs to be independent from other tests @Test public void testT07_OverwriteCaps() { - Proxy agentProxy = new Proxy(); - agentProxy.setHttpProxy("my.agent.proxy:8080"); - Proxy requestProxy = new Proxy(); - requestProxy.setHttpProxy("my.request.proxy:8080"); + Map customCaps = new HashMap<>(); + customCaps.put("t07Overwrite", "agentCaps"); WEB_DRIVER_MANAGER.setUserAgentConfig(Browsers.chromeHeadless, (ChromeConfig) options -> { - options.setCapability("t07Overwrite", "agentCaps"); -// options.setProxy(agentProxy); + options.setCapability("custom:caps", customCaps); }); DesktopWebDriverRequest request = new DesktopWebDriverRequest(); - request.getDesiredCapabilities().setCapability("t07Overwrite", "requestCaps"); -// request.getDesiredCapabilities().setCapability(CapabilityType.PROXY, requestProxy); + Map customCaps2 = new HashMap<>(); + customCaps2.put("t07Overwrite", "requestCaps"); + request.getDesiredCapabilities().setCapability("custom:caps", customCaps2); WebDriver driver = WEB_DRIVER_MANAGER.getWebDriver(request); SessionContext sessionContext = WEB_DRIVER_MANAGER.getSessionContext(driver).get(); - Map sessionCapabilities = sessionContext.getWebDriverRequest().getCapabilities(); + Map sessionCapabilities = (Map) sessionContext.getWebDriverRequest().getCapabilities().get("custom:caps"); Assert.assertEquals(sessionCapabilities.get("t07Overwrite"), "requestCaps", "Request capability is set"); -// Assert.assertEquals(sessionCapabilities.get(CapabilityType.PROXY), requestProxy, "Request proxy is set"); } - @Test + // TODO Does not work in Chrome Headless + @Test(enabled = false) public void testT08_ChromeExtensions() { File chromeExtensionFile = new File( From 3fe40cf6ae2a56dd175b41bd002e16eee4b8de82 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Gro=C3=9Fmann?= Date: Thu, 8 Jun 2023 08:12:32 +0200 Subject: [PATCH 26/64] Fixed static server --- .../java/io/testerra/report/test/AbstractReportTest.java | 8 ++++---- .../io/testerra/report/test/AbstractTestSitesTest.java | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/report-ng-tests/src/test/java/io/testerra/report/test/AbstractReportTest.java b/report-ng-tests/src/test/java/io/testerra/report/test/AbstractReportTest.java index f2ae80478d..7885b190b9 100644 --- a/report-ng-tests/src/test/java/io/testerra/report/test/AbstractReportTest.java +++ b/report-ng-tests/src/test/java/io/testerra/report/test/AbstractReportTest.java @@ -23,7 +23,7 @@ package io.testerra.report.test; import eu.tsystems.mms.tic.testframework.common.DefaultPropertyManager; -import eu.tsystems.mms.tic.testframework.core.server.Server; +import eu.tsystems.mms.tic.testframework.core.server.StaticServer; import eu.tsystems.mms.tic.testframework.core.testpage.TestPage; import eu.tsystems.mms.tic.testframework.report.Report; import eu.tsystems.mms.tic.testframework.utils.FileUtils; @@ -42,12 +42,12 @@ public abstract class AbstractReportTest extends AbstractTest { private final static File serverRootDir = FileUtils.getResourceFile("reports"); - private final static Server server = new Server(serverRootDir); + private final static StaticServer staticServer = new StaticServer(serverRootDir); @BeforeTest(alwaysRun = true) public void setUp() throws Exception { try { - server.start(8081); + staticServer.start(8081); } catch (BindException e) { log().warn("Use already running WebServer: " + e.getMessage()); } @@ -80,7 +80,7 @@ public synchronized T visitReportPage(final Class File reportDir = new File(serverRootDir, directory); Assert.assertTrue(reportDir.exists(), String.format("Report directory '%s' doesn't exists", reportDir)); - final String baseUrl = String.format("http://localhost:%d/%s", server.getPort(), directory); + final String baseUrl = String.format("http://localhost:%d/%s", staticServer.getPort(), directory); driver.get(baseUrl); return PAGE_FACTORY.createPage(reportPageClass, driver); diff --git a/report-ng-tests/src/test/java/io/testerra/report/test/AbstractTestSitesTest.java b/report-ng-tests/src/test/java/io/testerra/report/test/AbstractTestSitesTest.java index dd2b4e5073..e298ee4675 100644 --- a/report-ng-tests/src/test/java/io/testerra/report/test/AbstractTestSitesTest.java +++ b/report-ng-tests/src/test/java/io/testerra/report/test/AbstractTestSitesTest.java @@ -22,7 +22,7 @@ package io.testerra.report.test; -import eu.tsystems.mms.tic.testframework.core.server.Server; +import eu.tsystems.mms.tic.testframework.core.server.StaticServer; import eu.tsystems.mms.tic.testframework.logging.Loggable; import eu.tsystems.mms.tic.testframework.testing.AssertProvider; import eu.tsystems.mms.tic.testframework.testing.PageFactoryProvider; @@ -40,13 +40,13 @@ */ public abstract class AbstractTestSitesTest extends AbstractTest implements WebDriverManagerProvider, PageFactoryProvider, AssertProvider, Loggable { - protected static Server server = new Server(FileUtils.getResourceFile("testsites")); + protected static StaticServer staticServer = new StaticServer(FileUtils.getResourceFile("testsites")); private String exclusiveSessionId; @BeforeTest(alwaysRun = true) public void setUp() throws Exception { try { - server.start(80); + staticServer.start(80); } catch (BindException e) { log().warn("Use already running WebServer: " + e.getMessage()); } @@ -68,7 +68,7 @@ public void closeExclusiveWebDriverSession() { */ protected synchronized void visitTestPage(final WebDriver driver, final TestPage testPage) { if (!driver.getCurrentUrl().contains(testPage.getPath())) { - String baseUrl = String.format("http://localhost:%d/%s", server.getPort(), testPage.getPath()); + String baseUrl = String.format("http://localhost:%d/%s", staticServer.getPort(), testPage.getPath()); driver.get(baseUrl); } } From 2cfc23cbc9e8d474953b03ff28ca5adb87761c4b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Gro=C3=9Fmann?= Date: Thu, 8 Jun 2023 08:33:46 +0200 Subject: [PATCH 27/64] Updated integration test suite --- .../DesktopWebDriverFactoryTest.java | 14 ++++++------- integration-tests/src/test/resources/Core.xml | 1 + .../src/test/resources/Integration.xml | 3 ++- .../src/test/resources/SingleRuns.xml | 20 +++++++++++++++++++ 4 files changed, 30 insertions(+), 8 deletions(-) create mode 100644 integration-tests/src/test/resources/SingleRuns.xml diff --git a/integration-tests/src/test/java/eu/tsystems/mms/tic/testframework/test/webdrivermanager/DesktopWebDriverFactoryTest.java b/integration-tests/src/test/java/eu/tsystems/mms/tic/testframework/test/webdrivermanager/DesktopWebDriverFactoryTest.java index 2c4ed79e67..baa7838ad9 100644 --- a/integration-tests/src/test/java/eu/tsystems/mms/tic/testframework/test/webdrivermanager/DesktopWebDriverFactoryTest.java +++ b/integration-tests/src/test/java/eu/tsystems/mms/tic/testframework/test/webdrivermanager/DesktopWebDriverFactoryTest.java @@ -87,8 +87,8 @@ public void testT03_EndPointCapabilities_WebDriverRequest() throws Exception { Assert.assertEquals(sessionCapabilities.get("enableVNC"), selenoidCaps.get("enableVNC"), "EndPoint Capability via WebDriverRequest is set"); } - // TODO Global caps!! -> needs to be independent from other tests - @Test + // Global caps! -> needs to be independent of other tests + @Test(groups = "SEQUENTIAL_SINGLE") public void testT04_EndPointCapabilities_Global() { Map customCaps = new HashMap<>(); customCaps.put("t04Global", "yes"); @@ -104,8 +104,8 @@ public void testT04_EndPointCapabilities_Global() { Assert.assertEquals(sessionCapabilities.get("t04Global"), "yes", "EndPoint Capability is set"); } - // TODO Global caps!! -> needs to be independent from other tests - @Test + // Global caps! -> needs to be independent of other tests + @Test(groups = "SEQUENTIAL_SINGLE") public void test05_EndPointCapabilities_UserAgent() { Map customCaps = new HashMap<>(); customCaps.put("t05UserAgent", "yesyes"); @@ -132,8 +132,8 @@ public void testT06_PlatformCaps() { Assert.assertEquals(webDriverRequest.getCapabilities().get(CapabilityType.PLATFORM_NAME), Platform.WINDOWS); } - // TODO Global caps!! -> needs to be independent from other tests - @Test + // Global caps!! -> needs to be independent of other tests + @Test(groups = "SEQUENTIAL_SINGLE") public void testT07_OverwriteCaps() { Map customCaps = new HashMap<>(); customCaps.put("t07Overwrite", "agentCaps"); @@ -156,7 +156,7 @@ public void testT07_OverwriteCaps() { Assert.assertEquals(sessionCapabilities.get("t07Overwrite"), "requestCaps", "Request capability is set"); } - // TODO Does not work in Chrome Headless + // TODO Does not work in Chrome Headless @Test(enabled = false) public void testT08_ChromeExtensions() { diff --git a/integration-tests/src/test/resources/Core.xml b/integration-tests/src/test/resources/Core.xml index 64ec61e82d..e36d9adc94 100644 --- a/integration-tests/src/test/resources/Core.xml +++ b/integration-tests/src/test/resources/Core.xml @@ -5,6 +5,7 @@ + diff --git a/integration-tests/src/test/resources/Integration.xml b/integration-tests/src/test/resources/Integration.xml index 97e1f59f1e..62d05fcbd9 100644 --- a/integration-tests/src/test/resources/Integration.xml +++ b/integration-tests/src/test/resources/Integration.xml @@ -5,10 +5,11 @@ - + + diff --git a/integration-tests/src/test/resources/SingleRuns.xml b/integration-tests/src/test/resources/SingleRuns.xml new file mode 100644 index 0000000000..bb9ad6d463 --- /dev/null +++ b/integration-tests/src/test/resources/SingleRuns.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + From f35b3f2a074259cecb0e3ee9332fa7615929d25f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Gro=C3=9Fmann?= Date: Thu, 8 Jun 2023 09:48:26 +0200 Subject: [PATCH 28/64] Updated WebDriverManagerTests --- .../WebDriverManagerTest.java | 24 ++++++++++++------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/integration-tests/src/test/java/eu/tsystems/mms/tic/testframework/test/webdrivermanager/WebDriverManagerTest.java b/integration-tests/src/test/java/eu/tsystems/mms/tic/testframework/test/webdrivermanager/WebDriverManagerTest.java index 8a84ce8f4e..c91f042cd0 100644 --- a/integration-tests/src/test/java/eu/tsystems/mms/tic/testframework/test/webdrivermanager/WebDriverManagerTest.java +++ b/integration-tests/src/test/java/eu/tsystems/mms/tic/testframework/test/webdrivermanager/WebDriverManagerTest.java @@ -43,6 +43,7 @@ import org.testng.Assert; import org.testng.annotations.Test; +import java.util.HashMap; import java.util.Locale; import java.util.Map; import java.util.Optional; @@ -143,7 +144,9 @@ public void testT03b_SessionExclusiveCheckLinkedSession() { } } - @Test + // Testcase is replaced by DesktopWebDriverFactoryTest.testT04_EndPointCapabilities_Global + // Does not work with Selenium 4 (see custom caps) + @Test(enabled = false) public void testT04_ManageGlobalCapabilities() { WEB_DRIVER_MANAGER.setGlobalCapability("foo", "bar"); @@ -170,7 +173,7 @@ public void testT05_ManageThreadCapabilities() { // WebDriverManager.getThreadCapabilities().clear(); } - @Test + @Test(groups = "SEQUENTIAL_SINGLE") public void testT06_clonedWebDriverRequest() { final String sessionKey = "testT06"; final String capKey = "MyCap"; @@ -179,10 +182,12 @@ public void testT06_clonedWebDriverRequest() { DesktopWebDriverRequest request = new DesktopWebDriverRequest(); request.setSessionKey(sessionKey); DesiredCapabilities baseCaps = request.getDesiredCapabilities(); - baseCaps.setCapability(capKey, capVal); + Map customCaps = new HashMap<>(); + customCaps.put(capKey, capVal); + baseCaps.setCapability("custom:caps", customCaps); - WebDriver webDriver = WebDriverManager.getWebDriver(request); - SessionContext sessionContext = WebDriverSessionsManager.getSessionContext(webDriver).get(); + WebDriver webDriver = WEB_DRIVER_MANAGER.getWebDriver(request); + SessionContext sessionContext = WEB_DRIVER_MANAGER.getSessionContext(webDriver).get(); DesktopWebDriverRequest clonedRequest = (DesktopWebDriverRequest) sessionContext.getWebDriverRequest(); // Test for cloned primitives @@ -192,11 +197,12 @@ public void testT06_clonedWebDriverRequest() { // Test for not shallow copy of capabilities DesiredCapabilities clonedCaps = clonedRequest.getDesiredCapabilities(); - Assert.assertEquals(capVal, clonedCaps.getCapability(capKey)); - Assert.assertEquals(clonedCaps.getCapability(capKey), baseCaps.getCapability(capKey)); + Map clonedCustomCaps = (Map) clonedCaps.getCapability("custom:caps"); + Assert.assertEquals(capVal, clonedCustomCaps.get(capKey)); + Assert.assertEquals(clonedCustomCaps.get(capKey), customCaps.get(capKey)); - clonedCaps.setCapability(capKey, "newValue"); - Assert.assertNotEquals(clonedCaps.getCapability(capKey), baseCaps.getCapability(capKey)); + clonedCustomCaps.put(capKey, "newValue"); + Assert.assertNotEquals(clonedCustomCaps.get(capKey), customCaps.get(capKey)); } @Test From add4b2c7d1c828a6d6bc3e4db93eca0c0e9037b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Gro=C3=9Fmann?= Date: Thu, 8 Jun 2023 12:15:41 +0200 Subject: [PATCH 29/64] Updated clone method of AbstractWebDriverRequest --- .../report/model/context/SessionContext.java | 1 + .../webdrivermanager/AbstractWebDriverRequest.java | 10 ++++++---- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/core/src/main/java/eu/tsystems/mms/tic/testframework/report/model/context/SessionContext.java b/core/src/main/java/eu/tsystems/mms/tic/testframework/report/model/context/SessionContext.java index 3a35331290..07b7a08e22 100644 --- a/core/src/main/java/eu/tsystems/mms/tic/testframework/report/model/context/SessionContext.java +++ b/core/src/main/java/eu/tsystems/mms/tic/testframework/report/model/context/SessionContext.java @@ -41,6 +41,7 @@ public class SessionContext extends AbstractContext { public SessionContext(WebDriverRequest webDriverRequest) { try { + // Store a clone of current WebDriverRequest to prevent changes and keep the real request settings for every session setWebDriverRequest(webDriverRequest.clone()); } catch (CloneNotSupportedException e) { throw new RuntimeException(e); diff --git a/driver-ui/src/main/java/eu/tsystems/mms/tic/testframework/webdrivermanager/AbstractWebDriverRequest.java b/driver-ui/src/main/java/eu/tsystems/mms/tic/testframework/webdrivermanager/AbstractWebDriverRequest.java index a44668ca48..4932a7b30b 100644 --- a/driver-ui/src/main/java/eu/tsystems/mms/tic/testframework/webdrivermanager/AbstractWebDriverRequest.java +++ b/driver-ui/src/main/java/eu/tsystems/mms/tic/testframework/webdrivermanager/AbstractWebDriverRequest.java @@ -20,6 +20,7 @@ */ package eu.tsystems.mms.tic.testframework.webdrivermanager; +import com.google.gson.Gson; import eu.tsystems.mms.tic.testframework.common.PropertyManager; import eu.tsystems.mms.tic.testframework.constants.TesterraProperties; import eu.tsystems.mms.tic.testframework.logging.Loggable; @@ -27,7 +28,6 @@ import org.openqa.selenium.Capabilities; import org.openqa.selenium.Platform; import org.openqa.selenium.WebDriverException; -import org.openqa.selenium.remote.CapabilityType; import org.openqa.selenium.remote.DesiredCapabilities; import java.net.MalformedURLException; @@ -156,15 +156,17 @@ public DesiredCapabilities getDesiredCapabilities() { /** * Cloning of DesiredCapabilites with SerializationUtils occurs org.apache.commons.lang3.SerializationException: IOException while reading or closing cloned object data * -> We have to backup the current caps and clone WebDriverRequest without caps. After cloning the original caps are added again. - * -> Caps can cloned via merge() method. + * -> merge()-Method does not clone capability values like Maps (e.g. goog:chromeOptions) -> used Gson + *

+ * -> * * @return */ public AbstractWebDriverRequest clone() throws CloneNotSupportedException { AbstractWebDriverRequest clone = (AbstractWebDriverRequest) super.clone(); if (this.desiredCapabilities != null) { - clone.desiredCapabilities = new DesiredCapabilities(); - clone.desiredCapabilities.merge(this.desiredCapabilities); + Gson gson = new Gson(); + clone.desiredCapabilities = gson.fromJson(gson.toJson(this.desiredCapabilities), DesiredCapabilities.class); } return clone; } From 62871fa870fa1cfbd7a3faf16705cd79435d4d40 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Gro=C3=9Fmann?= Date: Thu, 8 Jun 2023 12:25:01 +0200 Subject: [PATCH 30/64] Updated clone method of AbstractWebDriverRequest --- .../webdrivermanager/AbstractWebDriverRequest.java | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/driver-ui/src/main/java/eu/tsystems/mms/tic/testframework/webdrivermanager/AbstractWebDriverRequest.java b/driver-ui/src/main/java/eu/tsystems/mms/tic/testframework/webdrivermanager/AbstractWebDriverRequest.java index 4932a7b30b..f43bef6aaa 100644 --- a/driver-ui/src/main/java/eu/tsystems/mms/tic/testframework/webdrivermanager/AbstractWebDriverRequest.java +++ b/driver-ui/src/main/java/eu/tsystems/mms/tic/testframework/webdrivermanager/AbstractWebDriverRequest.java @@ -20,10 +20,10 @@ */ package eu.tsystems.mms.tic.testframework.webdrivermanager; -import com.google.gson.Gson; import eu.tsystems.mms.tic.testframework.common.PropertyManager; import eu.tsystems.mms.tic.testframework.constants.TesterraProperties; import eu.tsystems.mms.tic.testframework.logging.Loggable; +import org.apache.commons.lang3.SerializationUtils; import org.apache.commons.lang3.StringUtils; import org.openqa.selenium.Capabilities; import org.openqa.selenium.Platform; @@ -156,17 +156,15 @@ public DesiredCapabilities getDesiredCapabilities() { /** * Cloning of DesiredCapabilites with SerializationUtils occurs org.apache.commons.lang3.SerializationException: IOException while reading or closing cloned object data * -> We have to backup the current caps and clone WebDriverRequest without caps. After cloning the original caps are added again. - * -> merge()-Method does not clone capability values like Maps (e.g. goog:chromeOptions) -> used Gson - *

- * -> - * - * @return + * -> merge()-Method does not clone capability values like Maps (e.g. goog:chromeOptions, no deep copy) -> used org.apache.commons.lang3.SerializationUtils */ public AbstractWebDriverRequest clone() throws CloneNotSupportedException { AbstractWebDriverRequest clone = (AbstractWebDriverRequest) super.clone(); if (this.desiredCapabilities != null) { - Gson gson = new Gson(); - clone.desiredCapabilities = gson.fromJson(gson.toJson(this.desiredCapabilities), DesiredCapabilities.class); + clone.desiredCapabilities = SerializationUtils.clone(this.desiredCapabilities); + } + if (this.capabilities != null) { + clone.setBrowserOptions(SerializationUtils.clone(this.capabilities)); } return clone; } From fb7fe9dfdffbbd2320a95bcc8e48d538fc7c0cf8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Gro=C3=9Fmann?= Date: Fri, 16 Jun 2023 11:31:38 +0200 Subject: [PATCH 31/64] Added note for browser versions and standalone Selenium 4 --- docs/src/docs/known-issues.adoc | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/docs/src/docs/known-issues.adoc b/docs/src/docs/known-issues.adoc index 64dc8891f8..5508784242 100644 --- a/docs/src/docs/known-issues.adoc +++ b/docs/src/docs/known-issues.adoc @@ -1,4 +1,5 @@ = Known issues +include::properties/property-attributes.adoc[] Because we depend on other frameworks and tools like TestNG and Selenium we may encounter issues that we want to fix, but are bound to releases and fixes in our dependencies. @@ -10,4 +11,8 @@ Every known issue in our dependencies that will lead to an error, an unexpected CAUTION: Never close WebDriver sessions calling `WebDriver.quit()`. This may encounter problems or some kind of unexpected issues, because the session is not marked as closed in `WebDriverManager` 's session store. +=== Selenium 4 and browser version + +Using a standalone Selenium 4 server (no grid) you must not set browser version via `{browser_setting}` or `{browser_version}`. Your local Selenium 4 server has no information about the versions of your installed browsers and cannot handle version information in your Webdriver request. + From 756edbc512417eae40938537d582239fc8c57266 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Gro=C3=9Fmann?= Date: Fri, 16 Jun 2023 13:01:13 +0200 Subject: [PATCH 32/64] Updated manual --- .../constants/TesterraProperties.java | 5 ++ docs/src/docs/browser-caps.adoc | 4 +- .../docs/browsercaps/common-browser-caps.adoc | 28 --------- .../browsercaps/setting-browser-caps.adoc | 9 ++- docs/src/docs/properties/webdriver-props.adoc | 2 - .../webdrivermanager-config.adoc | 60 +++++++------------ .../src/test/resources/test.properties | 4 +- 7 files changed, 38 insertions(+), 74 deletions(-) delete mode 100644 docs/src/docs/browsercaps/common-browser-caps.adoc diff --git a/core/src/main/java/eu/tsystems/mms/tic/testframework/constants/TesterraProperties.java b/core/src/main/java/eu/tsystems/mms/tic/testframework/constants/TesterraProperties.java index cdb7d4c8d1..8581136605 100644 --- a/core/src/main/java/eu/tsystems/mms/tic/testframework/constants/TesterraProperties.java +++ b/core/src/main/java/eu/tsystems/mms/tic/testframework/constants/TesterraProperties.java @@ -23,6 +23,8 @@ import eu.tsystems.mms.tic.testframework.common.Testerra.Properties; +import java.util.function.Predicate; + /** * Class holding keys of all properties. * @@ -49,7 +51,10 @@ private TesterraProperties() { /** * WDM: Timeout / Duration Setting for Window Switching + * + * @deprecated Use {@link IWebDriverManager#switchToWindow(Predicate)} and {@link CONTROL#waitFor(int, Predicate)} instead */ + @Deprecated public static final String WEBDRIVER_WINDOW_SWITCH_MAX_DURATION = "tt.wdm.timeouts.seconds.window.switch.duration"; /** diff --git a/docs/src/docs/browser-caps.adoc b/docs/src/docs/browser-caps.adoc index 63197ad8fc..287355c1bf 100644 --- a/docs/src/docs/browser-caps.adoc +++ b/docs/src/docs/browser-caps.adoc @@ -2,12 +2,10 @@ You can customize your WebDriver session by setting capabilities in the following ways: -- <> that affect every WebDriver session created +- Global capabilities that affect every WebDriver session created and can be set by <> - <> that affect only WebDrivers for a given request -- <> that affect only WebDrivers for a specified browser When creating a new WebDriver, these capabilities get merged together in this exact order. -include::browsercaps/common-browser-caps.adoc[leveloffset=+1] include::browsercaps/setting-browser-caps.adoc[leveloffset=+1] include::browsercaps/proxy-setup.adoc[leveloffset=+1] diff --git a/docs/src/docs/browsercaps/common-browser-caps.adoc b/docs/src/docs/browsercaps/common-browser-caps.adoc deleted file mode 100644 index a9c980e4b2..0000000000 --- a/docs/src/docs/browsercaps/common-browser-caps.adoc +++ /dev/null @@ -1,28 +0,0 @@ -= Common browser capabilities - -include::../properties/property-attributes.adoc[] - -The following table shows the most used browser capabilities and how they can set. - -[cols="1,1a,1a,1a"] -|=== -|Capability | Selenium type | test.properties | DesktopWebDriverRequest - -| Browser type -| `CapabilityType.BROWSER_NAME` -| `{browser_setting}`, `{browser}` -| `setBrowser(String)` - -| Browser version -| `CapabilityType.BROWSER_VERSION` -| `{browser_setting}`, `{browser_version}` -| `setBrowserVersion(String)` - -| Platform -| `CapabilityType.PLATFORM_NAME` * -| `{browser_setting}`, `{browser_platform}` -| `setPlatformName(String)` - -|=== - -{empty}* The capability `CapabilityType.PLATFORM` is deprecated and has to be set manually. diff --git a/docs/src/docs/browsercaps/setting-browser-caps.adoc b/docs/src/docs/browsercaps/setting-browser-caps.adoc index a934706bd0..e2d9e7cd32 100644 --- a/docs/src/docs/browsercaps/setting-browser-caps.adoc +++ b/docs/src/docs/browsercaps/setting-browser-caps.adoc @@ -2,17 +2,22 @@ The user agent configuration is most precise, because it provides explicit browser options based on the Selenium driver. +The setting applies to all created sessions for a browser type (_global_). + [source, java] ---- import eu.tsystems.mms.tic.testframework.useragents.FirefoxConfig; WEB_DRIVER_MANAGER.setUserAgentConfig(Browsers.firefox, (FirefoxConfig) options -> { options.addPreference("intl.accept_languages", "de-DE"); + options.setCapability("myKey", value); }); ---- NOTE: Have a look into <> for specific browser options. +NOTE: Since Selenium 4 the `DesiredCapabilties` are replaced by browser options (https://www.selenium.dev/documentation/webdriver/getting_started/upgrade_to_selenium_4). + = Request capabilities Some WebDriverRequests support setting capabilities, like the `DesktopWebDriverRequest`. It's used to specify a single WebDriver session. @@ -33,7 +38,9 @@ Have a look into <> for specific browser options. + Find some more details for `DesktopWebDriverRequest` at <<_request_configuration>>. ===== -= Global capabilities += Global capabilities with `WEB_DRIVER_MANAGER` (`@deprecated`) + +NOTE: This feature is deprecated, please use <> You can customize your browser session by setting capabilities for every browser type. diff --git a/docs/src/docs/properties/webdriver-props.adoc b/docs/src/docs/properties/webdriver-props.adoc index 2a2874ad9b..9bc4ccf4a7 100644 --- a/docs/src/docs/properties/webdriver-props.adoc +++ b/docs/src/docs/properties/webdriver-props.adoc @@ -15,8 +15,6 @@ The following types of browsers are supported: * ie * edge * safari -* phantomjs -* htmlunit * chromeHeadless | {browser} | na. diff --git a/docs/src/docs/webdrivermanager/webdrivermanager-config.adoc b/docs/src/docs/webdrivermanager/webdrivermanager-config.adoc index f2669c0dcb..7d8fb25392 100644 --- a/docs/src/docs/webdrivermanager/webdrivermanager-config.adoc +++ b/docs/src/docs/webdrivermanager/webdrivermanager-config.adoc @@ -2,20 +2,23 @@ include::../properties/property-attributes.adoc[] -An WebDriver can be configured in the following ways. - A global configuration applies to all new sessions created by WebDriverManager. You can set a global configuration by. * Setting defaults as <> * Configure the WebDriver <> -* at runtime by using the <> (`@deprecated`) == Property configuration -Like shown above all session properties can be set in `test.properties`. +The main configuration your WebDriver session is done in `test.properties`. + +The most important properties are: + +* `{browser_setting}` (or `{browser}`, `{browser_version}` and `{browser_platform}`) +* `{baseurl}` +* `{selenium_server_url}` (or `{selenium_server_host}` and `{selenium_server_port}`) -include::../properties/webdriver-props.adoc[leveloffset=+1] +The complete list of WebDriver properties can be found at <>. == Request configuration @@ -24,14 +27,19 @@ All defined attributes overrides the standard configuration. NOTE: If an attribute is not set, the global definition is used. -[source,java] +[source,java,subs="attributes"] ---- DesktopWebDriverRequest myRequest = new DesktopWebDriverRequest(); myRequest.setBaseUrl("http://example.org"); myRequest.setBrowser(Browsers.firefox); myRequest.setBrowserVersion("66"); myRequest.setSessionKey("mysession"); -myRequest.setWindowSize(new Dimension(2560,1440)); +myRequest.setWindowSize(new Dimension(2560,1440)); // {window_size} +myRequest.setShutdownAfterTest(false); // applies to all test method results + // {wdm_closewindows_aftertestmethods} +myRequest.setShutdownAfterTestFailed(false); // applies only to failed test methods + // {wdm_closewindows_onfailure} +myRequest.setMaximizeBrowser(true); // {browser_maximize} WebDriver driver = WEB_DRIVER_MANAGER.getWebDriver(myRequest); ---- @@ -42,40 +50,16 @@ Via the `SessionContext` you can get the current configuration of a WebDriver se ---- Optional sessionContext = WEB_DRIVER_MANAGER.getSessionContext(webDriver); // In case of a desktop browser you can cast to 'DesktopWebDriverRequest' -// Be careful if you are using Appium Connector! +// Be careful if you are using other session types like Appium sessions! DesktopWebDriverRequest webDriverRequest = (DesktopWebDriverRequest) sessionContext.get().getWebDriverRequest(); ---- -== Configure with WebDriverManagerConfig (`@deprecated`) - -Since this `WebDriverManagerConfig` is actually a `DesktopWebDriverRequest`, you should prefer using that when creating a new WebDriver. - -Some of the WebDriverManager settings you can change as follows - -[source,java] ----- -// tt.wdm.closewindows.aftertestmethods -WEB_DRIVER_MANAGER.getConfig().setShutdownSessionAfterTestMethod(true); +NOTE: With `DesktopWebDriverRequest` you can also define <>. -// tt.wdm.closewindows.onfailure -WEB_DRIVER_MANAGER.getConfig().setShutdownSessionOnFailure(false); - -// tt.browser.maximize -WEB_DRIVER_MANAGER.getConfig().setMaximizeViewport(true); ----- - -[NOTE] -====== -`setShutdownSessions()` controls closing of browser windows after every test method in general, -when its set to `false`, this also affects `shouldShutdownSessionOnFailure()` and `shouldShutdownSessionAfterTestMethod()`. - -Keep in mind, that after the complete test run a session shutdown is being forced. -====== - -You can reset the settings to the default values or defined in `test.properties` as follows +== Configure with WebDriverManagerConfig (`@deprecated`) -[source,java] ----- -WEB_DRIVER_MANAGER.getConfig().reset(); ----- +[IMPORTANT] +==== +Do not use anymore set methods of `WebDriverManagerConfig` or `WEB_DRIVER_MANAGER.getConfig()`. +==== diff --git a/integration-tests/src/test/resources/test.properties b/integration-tests/src/test/resources/test.properties index 6f7575b388..06b49da789 100644 --- a/integration-tests/src/test/resources/test.properties +++ b/integration-tests/src/test/resources/test.properties @@ -7,9 +7,9 @@ tt.browser.maximize=false tt.window.size=800x600 #tt.browser.version=106 -#tt.selenium.server.host=localhost +tt.selenium.server.host=localhost -tt.element.timeout.seconds=2 +#tt.element.timeout.seconds=2 tt.report.screencaster.active=false #tt.layoutcheck.takereference=true From b3f1189b147ecf7d9e17c6df5c202356d85d1bf8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Gro=C3=9Fmann?= Date: Fri, 16 Jun 2023 13:02:07 +0200 Subject: [PATCH 33/64] Fixed test.properties --- integration-tests/src/test/resources/test.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/integration-tests/src/test/resources/test.properties b/integration-tests/src/test/resources/test.properties index 06b49da789..00adb02420 100644 --- a/integration-tests/src/test/resources/test.properties +++ b/integration-tests/src/test/resources/test.properties @@ -9,7 +9,7 @@ tt.window.size=800x600 #tt.browser.version=106 tt.selenium.server.host=localhost -#tt.element.timeout.seconds=2 +tt.element.timeout.seconds=2 tt.report.screencaster.active=false #tt.layoutcheck.takereference=true From 547160cd8860e449f5e4c12050956f8e19b3f1b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Gro=C3=9Fmann?= Date: Fri, 16 Jun 2023 14:24:53 +0200 Subject: [PATCH 34/64] Updated docs --- docs/src/docs/browsercaps/proxy-setup.adoc | 10 +--------- .../docs/browsercaps/setting-browser-caps.adoc | 15 ++++++++++++++- 2 files changed, 15 insertions(+), 10 deletions(-) diff --git a/docs/src/docs/browsercaps/proxy-setup.adoc b/docs/src/docs/browsercaps/proxy-setup.adoc index 0f2af083ad..f26811116a 100644 --- a/docs/src/docs/browsercaps/proxy-setup.adoc +++ b/docs/src/docs/browsercaps/proxy-setup.adoc @@ -20,15 +20,7 @@ public abstract class AbstractTest extends TesterraTest { @BeforeSuite public void proxySetup() { WebDriverProxyUtils utils = new WebDriverProxyUtils(); - /** - * Global browser proxy configuration - */ - Proxy defaultProxy = utils.getDefaultHttpProxy(); - WEB_DRIVER_MANAGER.setGlobalCapability(CapabilityType.PROXY, defaultProxy); - - /** - * Browser specific proxy configuration - */ + Proxy otherProxy = utils.createHttpProxyFromUrl( new URL("http://proxyUser:secretPassword@my-proxy:3128") ); diff --git a/docs/src/docs/browsercaps/setting-browser-caps.adoc b/docs/src/docs/browsercaps/setting-browser-caps.adoc index e2d9e7cd32..884a00bd5a 100644 --- a/docs/src/docs/browsercaps/setting-browser-caps.adoc +++ b/docs/src/docs/browsercaps/setting-browser-caps.adoc @@ -10,7 +10,6 @@ import eu.tsystems.mms.tic.testframework.useragents.FirefoxConfig; WEB_DRIVER_MANAGER.setUserAgentConfig(Browsers.firefox, (FirefoxConfig) options -> { options.addPreference("intl.accept_languages", "de-DE"); - options.setCapability("myKey", value); }); ---- @@ -38,6 +37,20 @@ Have a look into <> for specific browser options. + Find some more details for `DesktopWebDriverRequest` at <<_request_configuration>>. ===== += Custom capabilties + +Non-standard capabilties need a vendor prefix and can be set as follows: + +[source,java] +---- +Map customCaps = new HashMap<>(); +customCaps.put("foo", "bar"); + +WEB_DRIVER_MANAGER.setUserAgentConfig(Browsers.firefox, (FirefoxConfig) options -> { + options.setCapability("custom:caps", customCaps); +}); +---- + = Global capabilities with `WEB_DRIVER_MANAGER` (`@deprecated`) NOTE: This feature is deprecated, please use <> From 586d71f0a29b0b75a3b9ac2d536dea54a80eef27 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Gro=C3=9Fmann?= Date: Fri, 16 Jun 2023 15:46:36 +0200 Subject: [PATCH 35/64] Updated DevTools examples --- .../testframework/AbstractWebDriverTest.java | 3 +- .../playground/BrowserDevToolsTests.java | 31 ++++++++++++++----- 2 files changed, 26 insertions(+), 8 deletions(-) diff --git a/integration-tests/src/main/java/eu/tsystems/mms/tic/testframework/AbstractWebDriverTest.java b/integration-tests/src/main/java/eu/tsystems/mms/tic/testframework/AbstractWebDriverTest.java index d31be9d86d..5527caff2a 100644 --- a/integration-tests/src/main/java/eu/tsystems/mms/tic/testframework/AbstractWebDriverTest.java +++ b/integration-tests/src/main/java/eu/tsystems/mms/tic/testframework/AbstractWebDriverTest.java @@ -25,6 +25,7 @@ import eu.tsystems.mms.tic.testframework.constants.Browsers; import eu.tsystems.mms.tic.testframework.logging.Loggable; import eu.tsystems.mms.tic.testframework.testing.TesterraTest; +import eu.tsystems.mms.tic.testframework.testing.UiElementFinderFactoryProvider; import eu.tsystems.mms.tic.testframework.testing.WebDriverManagerProvider; import eu.tsystems.mms.tic.testframework.useragents.ChromeConfig; import eu.tsystems.mms.tic.testframework.webdriver.WebDriverRetainer; @@ -41,7 +42,7 @@ /** * Abstract test class for tests using a WebDriver */ -public abstract class AbstractWebDriverTest extends TesterraTest implements WebDriverRetainer, WebDriverManagerProvider, Loggable { +public abstract class AbstractWebDriverTest extends TesterraTest implements WebDriverRetainer, WebDriverManagerProvider, Loggable, UiElementFinderFactoryProvider { private String exclusiveSessionId; diff --git a/integration-tests/src/test/java/eu/tsystems/mms/tic/testframework/playground/BrowserDevToolsTests.java b/integration-tests/src/test/java/eu/tsystems/mms/tic/testframework/playground/BrowserDevToolsTests.java index 48e0070025..8503131f96 100644 --- a/integration-tests/src/test/java/eu/tsystems/mms/tic/testframework/playground/BrowserDevToolsTests.java +++ b/integration-tests/src/test/java/eu/tsystems/mms/tic/testframework/playground/BrowserDevToolsTests.java @@ -2,7 +2,10 @@ import eu.tsystems.mms.tic.testframework.AbstractWebDriverTest; import eu.tsystems.mms.tic.testframework.constants.Browsers; +import eu.tsystems.mms.tic.testframework.pageobjects.UiElementFinder; +import eu.tsystems.mms.tic.testframework.testing.UiElementFinderFactoryProvider; import eu.tsystems.mms.tic.testframework.webdrivermanager.DesktopWebDriverRequest; +import org.openqa.selenium.By; import org.openqa.selenium.HasAuthentication; import org.openqa.selenium.UsernameAndPassword; import org.openqa.selenium.WebDriver; @@ -41,50 +44,62 @@ public class BrowserDevToolsTests extends AbstractWebDriverTest { * - Issue with Selenoid: https://github.com/aerokube/selenoid/issues/1063 */ + private Optional latitude = Optional.of(52.52084); + private Optional longitude = Optional.of(13.40943); + @Test public void testT01_GeoLocation_localDriver() { DesktopWebDriverRequest request = new DesktopWebDriverRequest(); request.setBrowser(Browsers.chrome); WebDriver webDriver = WEB_DRIVER_MANAGER.getWebDriver(request); + UiElementFinder uiElementFinder = UI_ELEMENT_FINDER_FACTORY.create(webDriver); ChromeDriver chromeDriver = WEB_DRIVER_MANAGER.unwrapWebDriver(webDriver, ChromeDriver.class).get(); DevTools devTools = chromeDriver.getDevTools(); devTools.createSession(); - devTools.send(Emulation.setGeolocationOverride(Optional.of(52.5043), - Optional.of(13.4501), + devTools.send(Emulation.setGeolocationOverride( + latitude, + longitude, Optional.of(1))); webDriver.get("https://my-location.org/"); + uiElementFinder.find(By.id("latitude")).assertThat().text().isContaining(latitude.get().toString()); + uiElementFinder.find(By.id("longitude")).assertThat().text().isContaining(longitude.get().toString()); + } @Test public void testT02_GeoLocation_remoteDriver() { DesktopWebDriverRequest request = new DesktopWebDriverRequest(); request.setBrowser(Browsers.chrome); -// request.setBrowser(Browsers.firefox); WebDriver webDriver = WEB_DRIVER_MANAGER.getWebDriver(request); - RemoteWebDriver remoteWebDriver = WEB_DRIVER_MANAGER.unwrapWebDriver(webDriver, RemoteWebDriver.class).get(); + UiElementFinder uiElementFinder = UI_ELEMENT_FINDER_FACTORY.create(webDriver); + RemoteWebDriver remoteWebDriver = WEB_DRIVER_MANAGER.unwrapWebDriver(webDriver, RemoteWebDriver.class).get(); webDriver = new Augmenter().augment(remoteWebDriver); DevTools devTools = ((HasDevTools) webDriver).getDevTools(); devTools.createSession(); - devTools.send(Emulation.setGeolocationOverride(Optional.of(52.5043), - Optional.of(13.4501), + devTools.send(Emulation.setGeolocationOverride( + latitude, + longitude, Optional.of(1))); webDriver.get("https://my-location.org/"); + uiElementFinder.find(By.id("latitude")).assertThat().text().isContaining(latitude.get().toString()); + uiElementFinder.find(By.id("longitude")).assertThat().text().isContaining(longitude.get().toString()); } @Test public void testT04_BasicAuth_remoteDriver() { DesktopWebDriverRequest request = new DesktopWebDriverRequest(); request.setBrowser(Browsers.chrome); - request.setBrowserVersion("106"); +// request.setBrowserVersion("106"); // request.getDesiredCapabilities().setCapability("se:cdp", "http://"); WebDriver webDriver = WEB_DRIVER_MANAGER.getWebDriver(request); WebDriver remoteWebDriver = WEB_DRIVER_MANAGER.unwrapWebDriver(webDriver, RemoteWebDriver.class).get(); + UiElementFinder uiElementFinder = UI_ELEMENT_FINDER_FACTORY.create(webDriver); AtomicReference devToolsAtomicReference = new AtomicReference<>(); @@ -108,5 +123,7 @@ public void testT04_BasicAuth_remoteDriver() { ((HasAuthentication) remoteWebDriver).register(UsernameAndPassword.of("admin", "admin")); remoteWebDriver.get("https://the-internet.herokuapp.com/basic_auth"); + uiElementFinder.find(By.tagName("p")).assertThat().text().isContaining("Congratulations"); + } } From efc141df2119b557aad343f560d1b2d2f176e67a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Gro=C3=9Fmann?= Date: Fri, 16 Jun 2023 16:11:28 +0200 Subject: [PATCH 36/64] Added example for emulate geo location --- docs/src/docs/best-practices.adoc | 1 + .../best-practices/chrome-dev-tools.adoc.adoc | 44 +++++++++++++++++++ 2 files changed, 45 insertions(+) create mode 100644 docs/src/docs/best-practices/chrome-dev-tools.adoc.adoc diff --git a/docs/src/docs/best-practices.adoc b/docs/src/docs/best-practices.adoc index 97f45f26cc..7fce00bbe9 100644 --- a/docs/src/docs/best-practices.adoc +++ b/docs/src/docs/best-practices.adoc @@ -9,3 +9,4 @@ include::best-practices/multiple-profiles.adoc[leveloffset=+1] include::best-practices/multiple-environments.adoc[leveloffset=+1] include::best-practices/project-setup.adoc[leveloffset=+1] include::best-practices/debugging.adoc[leveloffset=+1] +include::best-practices/chrome-dev-tools.adoc.adoc[leveloffset=+1] diff --git a/docs/src/docs/best-practices/chrome-dev-tools.adoc.adoc b/docs/src/docs/best-practices/chrome-dev-tools.adoc.adoc new file mode 100644 index 0000000000..f7fdc26914 --- /dev/null +++ b/docs/src/docs/best-practices/chrome-dev-tools.adoc.adoc @@ -0,0 +1,44 @@ += Access to Chrome dev tools + +NOTE: Only Chrome browser supports access to development tools. + +== Emulate geo location + +Examples are based on https://www.selenium.dev/documentation/webdriver/bidirectional/chrome_devtools/. + +.Local webdriver +[source,java] +---- +WebDriver webDriver = WEB_DRIVER_MANAGER.getWebDriver(); + +ChromeDriver chromeDriver = WEB_DRIVER_MANAGER + .unwrapWebDriver(webDriver, ChromeDriver.class).get(); + +DevTools devTools = chromeDriver.getDevTools(); +devTools.createSession(); +devTools.send(Emulation.setGeolocationOverride( + Optional.of(52.52084), + Optional.of(13.40943), + Optional.of(1))); +webDriver.get("https://my-location.org/"); +---- + +.Remote webdriver (e.g. of a grid) +[source,java] +---- +WebDriver webDriver = WEB_DRIVER_MANAGER.getWebDriver(); + +RemoteWebDriver remoteWebDriver = WEB_DRIVER_MANAGER + .unwrapWebDriver(webDriver, RemoteWebDriver.class).get(); +webDriver = new Augmenter().augment(remoteWebDriver); + +DevTools devTools = ((HasDevTools) webDriver).getDevTools(); +devTools.createSession(); + +devTools.send(Emulation.setGeolocationOverride( + Optional.of(52.52084), + Optional.of(13.40943), + Optional.of(1))); + +webDriver.get("https://my-location.org/"); +---- From 758460cca6208623e3b3489bfa1eeee4c4d02ab5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Gro=C3=9Fmann?= Date: Mon, 19 Jun 2023 09:55:21 +0200 Subject: [PATCH 37/64] Added example for basic authentication --- .../best-practices/chrome-dev-tools.adoc.adoc | 33 ++++++++++++++++++- .../browsercaps/setting-browser-caps.adoc | 2 +- .../playground/BrowserDevToolsTests.java | 17 ++++------ 3 files changed, 40 insertions(+), 12 deletions(-) diff --git a/docs/src/docs/best-practices/chrome-dev-tools.adoc.adoc b/docs/src/docs/best-practices/chrome-dev-tools.adoc.adoc index f7fdc26914..3aac864e03 100644 --- a/docs/src/docs/best-practices/chrome-dev-tools.adoc.adoc +++ b/docs/src/docs/best-practices/chrome-dev-tools.adoc.adoc @@ -20,7 +20,8 @@ devTools.send(Emulation.setGeolocationOverride( Optional.of(52.52084), Optional.of(13.40943), Optional.of(1))); -webDriver.get("https://my-location.org/"); + +webDriver.get("https://my-location.org/"); // page gets the new geo location information ---- .Remote webdriver (e.g. of a grid) @@ -42,3 +43,33 @@ devTools.send(Emulation.setGeolocationOverride( webDriver.get("https://my-location.org/"); ---- + +== Basic authentication + +[source,java] +---- +WebDriver webDriver = WEB_DRIVER_MANAGER.getWebDriver(); +WebDriver remoteWebDriver = WEB_DRIVER_MANAGER.unwrapWebDriver(webDriver, RemoteWebDriver.class).get(); + +AtomicReference devToolsAtomicReference = new AtomicReference<>(); + +remoteWebDriver = new Augmenter() + .addDriverAugmentation( + "chrome", + HasAuthentication.class, + (caps, exec) -> (whenThisMatches, useTheseCredentials) -> { + devToolsAtomicReference.get().createSessionIfThereIsNotOne(); + devToolsAtomicReference.get().getDomains() + .network() + .addAuthHandler(whenThisMatches, useTheseCredentials); + }) + .augment(remoteWebDriver); + +DevTools devTools = ((HasDevTools) remoteWebDriver).getDevTools(); +devTools.createSession(); +devToolsAtomicReference.set(devTools); + +// Set credentials and call the page with 'basic authentication' protection +((HasAuthentication) remoteWebDriver).register(UsernameAndPassword.of("admin", "admin")); +webDriver.get("https://the-internet.herokuapp.com/basic_auth"); +---- diff --git a/docs/src/docs/browsercaps/setting-browser-caps.adoc b/docs/src/docs/browsercaps/setting-browser-caps.adoc index 884a00bd5a..4e23e4b9c7 100644 --- a/docs/src/docs/browsercaps/setting-browser-caps.adoc +++ b/docs/src/docs/browsercaps/setting-browser-caps.adoc @@ -51,7 +51,7 @@ WEB_DRIVER_MANAGER.setUserAgentConfig(Browsers.firefox, (FirefoxConfig) options }); ---- -= Global capabilities with `WEB_DRIVER_MANAGER` (`@deprecated`) += Global capabilities with `WEB_DRIVER_MANAGER` (*@deprecated*) NOTE: This feature is deprecated, please use <> diff --git a/integration-tests/src/test/java/eu/tsystems/mms/tic/testframework/playground/BrowserDevToolsTests.java b/integration-tests/src/test/java/eu/tsystems/mms/tic/testframework/playground/BrowserDevToolsTests.java index 8503131f96..fb03275c83 100644 --- a/integration-tests/src/test/java/eu/tsystems/mms/tic/testframework/playground/BrowserDevToolsTests.java +++ b/integration-tests/src/test/java/eu/tsystems/mms/tic/testframework/playground/BrowserDevToolsTests.java @@ -3,7 +3,6 @@ import eu.tsystems.mms.tic.testframework.AbstractWebDriverTest; import eu.tsystems.mms.tic.testframework.constants.Browsers; import eu.tsystems.mms.tic.testframework.pageobjects.UiElementFinder; -import eu.tsystems.mms.tic.testframework.testing.UiElementFinderFactoryProvider; import eu.tsystems.mms.tic.testframework.webdrivermanager.DesktopWebDriverRequest; import org.openqa.selenium.By; import org.openqa.selenium.HasAuthentication; @@ -38,8 +37,8 @@ public class BrowserDevToolsTests extends AbstractWebDriverTest { *

* Example * - java -Dwebdriver.chrome.driver=driver\chromedriver.exe -jar selenium4\selenium-server-4.7.2.jar standalone --port 4444 --host localhost - * - * + *

+ *

* Known issues: * - Issue with Selenoid: https://github.com/aerokube/selenoid/issues/1063 */ @@ -96,24 +95,22 @@ public void testT04_BasicAuth_remoteDriver() { DesktopWebDriverRequest request = new DesktopWebDriverRequest(); request.setBrowser(Browsers.chrome); // request.setBrowserVersion("106"); -// request.getDesiredCapabilities().setCapability("se:cdp", "http://"); WebDriver webDriver = WEB_DRIVER_MANAGER.getWebDriver(request); + WebDriver remoteWebDriver = WEB_DRIVER_MANAGER.unwrapWebDriver(webDriver, RemoteWebDriver.class).get(); UiElementFinder uiElementFinder = UI_ELEMENT_FINDER_FACTORY.create(webDriver); AtomicReference devToolsAtomicReference = new AtomicReference<>(); remoteWebDriver = new Augmenter() - .addDriverAugmentation("chrome", + .addDriverAugmentation( + "chrome", HasAuthentication.class, (caps, exec) -> (whenThisMatches, useTheseCredentials) -> { - - devToolsAtomicReference.get() - .createSessionIfThereIsNotOne(); + devToolsAtomicReference.get().createSessionIfThereIsNotOne(); devToolsAtomicReference.get().getDomains() .network() .addAuthHandler(whenThisMatches, useTheseCredentials); - }) .augment(remoteWebDriver); @@ -122,7 +119,7 @@ public void testT04_BasicAuth_remoteDriver() { devToolsAtomicReference.set(devTools); ((HasAuthentication) remoteWebDriver).register(UsernameAndPassword.of("admin", "admin")); - remoteWebDriver.get("https://the-internet.herokuapp.com/basic_auth"); + webDriver.get("https://the-internet.herokuapp.com/basic_auth"); uiElementFinder.find(By.tagName("p")).assertThat().text().isContaining("Congratulations"); } From b012111565dd623f6b777cbdb125edeeae808805 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Gro=C3=9Fmann?= Date: Mon, 19 Jun 2023 18:36:15 +0200 Subject: [PATCH 38/64] Added first implementation of SeleniumDevTools --- .../best-practices/chrome-dev-tools.adoc.adoc | 6 +- .../tic/testframework/hooks/DriverUiHook.java | 3 + .../webdrivermanager/BrowserDevTools.java | 49 +++++++++++ .../webdrivermanager/IWebDriverManager.java | 9 +- .../webdrivermanager/SeleniumDevTools.java | 83 +++++++++++++++++++ .../playground/BrowserDevToolsTests.java | 19 +++++ 6 files changed, 167 insertions(+), 2 deletions(-) create mode 100644 driver-ui/src/main/java/eu/tsystems/mms/tic/testframework/webdrivermanager/BrowserDevTools.java create mode 100644 driver-ui/src/main/java/eu/tsystems/mms/tic/testframework/webdrivermanager/SeleniumDevTools.java diff --git a/docs/src/docs/best-practices/chrome-dev-tools.adoc.adoc b/docs/src/docs/best-practices/chrome-dev-tools.adoc.adoc index 3aac864e03..375bb0d7d9 100644 --- a/docs/src/docs/best-practices/chrome-dev-tools.adoc.adoc +++ b/docs/src/docs/best-practices/chrome-dev-tools.adoc.adoc @@ -1,6 +1,10 @@ = Access to Chrome dev tools -NOTE: Only Chrome browser supports access to development tools. +[NOTE] +==== +* The following examples are working with Selenium 4 server. If you are using another grid like Selenoid the usage could be different. +* Only Chrome browser supports access to development tools. +==== == Emulate geo location diff --git a/driver-ui/src/main/java/eu/tsystems/mms/tic/testframework/hooks/DriverUiHook.java b/driver-ui/src/main/java/eu/tsystems/mms/tic/testframework/hooks/DriverUiHook.java index 0912bc6329..e248f57ed5 100644 --- a/driver-ui/src/main/java/eu/tsystems/mms/tic/testframework/hooks/DriverUiHook.java +++ b/driver-ui/src/main/java/eu/tsystems/mms/tic/testframework/hooks/DriverUiHook.java @@ -53,8 +53,10 @@ import eu.tsystems.mms.tic.testframework.useragents.BrowserInformation; import eu.tsystems.mms.tic.testframework.useragents.UapBrowserInformation; import eu.tsystems.mms.tic.testframework.watchdog.WebDriverWatchDog; +import eu.tsystems.mms.tic.testframework.webdrivermanager.BrowserDevTools; import eu.tsystems.mms.tic.testframework.webdrivermanager.DefaultWebDriverManager; import eu.tsystems.mms.tic.testframework.webdrivermanager.IWebDriverManager; +import eu.tsystems.mms.tic.testframework.webdrivermanager.SeleniumDevTools; import eu.tsystems.mms.tic.testframework.webdrivermanager.WebDriverCapabilities; import eu.tsystems.mms.tic.testframework.webdrivermanager.WebDriverSessionsManager; @@ -75,6 +77,7 @@ protected void configure() { // Instances bind(BrowserInformation.class).to(UapBrowserInformation.class); + bind(BrowserDevTools.class).to(SeleniumDevTools.class); } @Override diff --git a/driver-ui/src/main/java/eu/tsystems/mms/tic/testframework/webdrivermanager/BrowserDevTools.java b/driver-ui/src/main/java/eu/tsystems/mms/tic/testframework/webdrivermanager/BrowserDevTools.java new file mode 100644 index 0000000000..1726b468ae --- /dev/null +++ b/driver-ui/src/main/java/eu/tsystems/mms/tic/testframework/webdrivermanager/BrowserDevTools.java @@ -0,0 +1,49 @@ +/* + * Testerra + * + * (C) 2023, Martin Großmann, Deutsche Telekom MMS GmbH, Deutsche Telekom AG + * + * Deutsche Telekom AG and all other contributors / + * copyright owners license this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this + * file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package eu.tsystems.mms.tic.testframework.webdrivermanager; + +import eu.tsystems.mms.tic.testframework.constants.Browsers; +import eu.tsystems.mms.tic.testframework.testing.WebDriverManagerProvider; +import org.openqa.selenium.WebDriver; +import org.openqa.selenium.devtools.DevTools; + +import java.util.Optional; + +/** + * Created on 2023-06-19 + * + * @author mgn + */ +public interface BrowserDevTools extends WebDriverManagerProvider { + + DevTools getRawDevTools(WebDriver driver); + + void setGeoLocation(WebDriver driver, double latitude, double longitude, int accuracy); + + default boolean isSupported(WebDriver driver) { + Optional requestedBrowser = WEB_DRIVER_MANAGER.getRequestedBrowser(driver); + return Optional.ofNullable(requestedBrowser) + .map(Optional::get) + .map(browser -> browser.toLowerCase().contains(Browsers.chrome)) + .orElse(false); + } + +} diff --git a/driver-ui/src/main/java/eu/tsystems/mms/tic/testframework/webdrivermanager/IWebDriverManager.java b/driver-ui/src/main/java/eu/tsystems/mms/tic/testframework/webdrivermanager/IWebDriverManager.java index 2a09af4a76..6b2cd16951 100644 --- a/driver-ui/src/main/java/eu/tsystems/mms/tic/testframework/webdrivermanager/IWebDriverManager.java +++ b/driver-ui/src/main/java/eu/tsystems/mms/tic/testframework/webdrivermanager/IWebDriverManager.java @@ -22,6 +22,7 @@ package eu.tsystems.mms.tic.testframework.webdrivermanager; import eu.tsystems.mms.tic.testframework.common.IProperties; +import eu.tsystems.mms.tic.testframework.common.Testerra; import eu.tsystems.mms.tic.testframework.logging.Loggable; import eu.tsystems.mms.tic.testframework.report.model.context.SessionContext; import eu.tsystems.mms.tic.testframework.useragents.UserAgentConfig; @@ -44,7 +45,9 @@ * Replacement for static {@link WebDriverManager} * @todo Rename to {@link WebDriverManager} */ -public interface IWebDriverManager extends WebDriverRetainer, Loggable { +public interface IWebDriverManager extends + WebDriverRetainer, + Loggable { enum Properties implements IProperties { BROWSER("tt.browser", ""), @@ -261,4 +264,8 @@ default boolean setSessionLocale(WebDriver webDriver, Locale locale) { default Optional getSessionLocale(WebDriver webDriver) { return WebDriverManager.getSessionLocale(webDriver); } + + default BrowserDevTools accessDevTools() { + return Testerra.getInjector().getInstance(BrowserDevTools.class); + } } diff --git a/driver-ui/src/main/java/eu/tsystems/mms/tic/testframework/webdrivermanager/SeleniumDevTools.java b/driver-ui/src/main/java/eu/tsystems/mms/tic/testframework/webdrivermanager/SeleniumDevTools.java new file mode 100644 index 0000000000..f7a254d094 --- /dev/null +++ b/driver-ui/src/main/java/eu/tsystems/mms/tic/testframework/webdrivermanager/SeleniumDevTools.java @@ -0,0 +1,83 @@ +/* + * Testerra + * + * (C) 2023, Martin Großmann, Deutsche Telekom MMS GmbH, Deutsche Telekom AG + * + * Deutsche Telekom AG and all other contributors / + * copyright owners license this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this + * file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package eu.tsystems.mms.tic.testframework.webdrivermanager; + +import eu.tsystems.mms.tic.testframework.logging.Loggable; +import org.openqa.selenium.WebDriver; +import org.openqa.selenium.chrome.ChromeDriver; +import org.openqa.selenium.devtools.DevTools; +import org.openqa.selenium.devtools.HasDevTools; +import org.openqa.selenium.devtools.v112.emulation.Emulation; +import org.openqa.selenium.remote.Augmenter; +import org.openqa.selenium.remote.RemoteWebDriver; + +import java.util.Optional; + +/** + * Created on 2023-06-19 + * + * @author mgn + */ +public class SeleniumDevTools implements BrowserDevTools, Loggable { + + /** + * Create a Chrome DevTools session + */ + @Override + public DevTools getRawDevTools(WebDriver webDriver) { + if (!isSupported(webDriver)) { + throw new RuntimeException("The current browser does not support DevTools"); + } + try { + WebDriverRequest webDriverRequest = WEB_DRIVER_MANAGER.getSessionContext(webDriver).get().getWebDriverRequest(); + DevTools devTools = null; + final String message = "Creating DevTools instance of "; + // Check if current session is a local or remote session + if (webDriverRequest.getServerUrl().isPresent()) { + log().info("{}remote driver session.", message); + RemoteWebDriver remoteWebDriver = WEB_DRIVER_MANAGER.unwrapWebDriver(webDriver, RemoteWebDriver.class).get(); + webDriver = new Augmenter().augment(remoteWebDriver); + devTools = ((HasDevTools) webDriver).getDevTools(); + } else { + log().info("{}local driver session.", message); + ChromeDriver chromeDriver = WEB_DRIVER_MANAGER.unwrapWebDriver(webDriver, ChromeDriver.class).get(); + devTools = chromeDriver.getDevTools(); + } + devTools.createSession(); + return devTools; + } catch (Exception e) { + throw new RuntimeException("Could not create DevTools", e); + } + } + + @Override + public void setGeoLocation(WebDriver webDriver, double latitude, double longitude, int accuracy) { + if (!isSupported(webDriver)) { + throw new RuntimeException("The current browser does not support DevTools"); + } + DevTools devTools = this.getRawDevTools(webDriver); + devTools.send(Emulation.setGeolocationOverride( + Optional.of(latitude), + Optional.of(longitude), + Optional.of(accuracy))); + } + +} diff --git a/integration-tests/src/test/java/eu/tsystems/mms/tic/testframework/playground/BrowserDevToolsTests.java b/integration-tests/src/test/java/eu/tsystems/mms/tic/testframework/playground/BrowserDevToolsTests.java index fb03275c83..944479b8e4 100644 --- a/integration-tests/src/test/java/eu/tsystems/mms/tic/testframework/playground/BrowserDevToolsTests.java +++ b/integration-tests/src/test/java/eu/tsystems/mms/tic/testframework/playground/BrowserDevToolsTests.java @@ -90,6 +90,25 @@ public void testT02_GeoLocation_remoteDriver() { uiElementFinder.find(By.id("longitude")).assertThat().text().isContaining(longitude.get().toString()); } + @Test + public void testT03_GeoLocation_generic() { + DesktopWebDriverRequest request = new DesktopWebDriverRequest(); + request.setBrowser(Browsers.chrome); + WebDriver webDriver = WEB_DRIVER_MANAGER.getWebDriver(request); + UiElementFinder uiElementFinder = UI_ELEMENT_FINDER_FACTORY.create(webDriver); + + DevTools devTools = WEB_DRIVER_MANAGER.accessDevTools().getRawDevTools(webDriver); + + devTools.send(Emulation.setGeolocationOverride( + latitude, + longitude, + Optional.of(1))); + + webDriver.get("https://my-location.org/"); + uiElementFinder.find(By.id("latitude")).assertThat().text().isContaining(latitude.get().toString()); + uiElementFinder.find(By.id("longitude")).assertThat().text().isContaining(longitude.get().toString()); + } + @Test public void testT04_BasicAuth_remoteDriver() { DesktopWebDriverRequest request = new DesktopWebDriverRequest(); From 7b98bab9ffca5876580dfb5177059b20087e6e05 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Gro=C3=9Fmann?= Date: Tue, 20 Jun 2023 13:22:50 +0200 Subject: [PATCH 39/64] Added basic authentication support --- .../tic/testframework/hooks/DriverUiHook.java | 2 +- .../testing/BrowserDevToolsProvider.java | 33 ++++++++++++++ .../SeleniumDevTools.java | 44 +++++++++++++++++-- .../webdrivermanager/BrowserDevTools.java | 13 +++++- .../webdrivermanager/IWebDriverManager.java | 23 ++++------ .../playground/BrowserDevToolsTests.java | 32 +++++++++++--- 6 files changed, 120 insertions(+), 27 deletions(-) create mode 100644 driver-ui/src/main/java/eu/tsystems/mms/tic/testframework/testing/BrowserDevToolsProvider.java rename driver-ui/src/main/java/eu/tsystems/mms/tic/testframework/{webdrivermanager => testing}/SeleniumDevTools.java (61%) diff --git a/driver-ui/src/main/java/eu/tsystems/mms/tic/testframework/hooks/DriverUiHook.java b/driver-ui/src/main/java/eu/tsystems/mms/tic/testframework/hooks/DriverUiHook.java index e248f57ed5..43c5f2e8a8 100644 --- a/driver-ui/src/main/java/eu/tsystems/mms/tic/testframework/hooks/DriverUiHook.java +++ b/driver-ui/src/main/java/eu/tsystems/mms/tic/testframework/hooks/DriverUiHook.java @@ -56,7 +56,7 @@ import eu.tsystems.mms.tic.testframework.webdrivermanager.BrowserDevTools; import eu.tsystems.mms.tic.testframework.webdrivermanager.DefaultWebDriverManager; import eu.tsystems.mms.tic.testframework.webdrivermanager.IWebDriverManager; -import eu.tsystems.mms.tic.testframework.webdrivermanager.SeleniumDevTools; +import eu.tsystems.mms.tic.testframework.testing.SeleniumDevTools; import eu.tsystems.mms.tic.testframework.webdrivermanager.WebDriverCapabilities; import eu.tsystems.mms.tic.testframework.webdrivermanager.WebDriverSessionsManager; diff --git a/driver-ui/src/main/java/eu/tsystems/mms/tic/testframework/testing/BrowserDevToolsProvider.java b/driver-ui/src/main/java/eu/tsystems/mms/tic/testframework/testing/BrowserDevToolsProvider.java new file mode 100644 index 0000000000..7d5645acfe --- /dev/null +++ b/driver-ui/src/main/java/eu/tsystems/mms/tic/testframework/testing/BrowserDevToolsProvider.java @@ -0,0 +1,33 @@ +/* + * Testerra + * + * (C) 2023, Martin Großmann, Deutsche Telekom MMS GmbH, Deutsche Telekom AG + * + * Deutsche Telekom AG and all other contributors / + * copyright owners license this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this + * file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package eu.tsystems.mms.tic.testframework.testing; + +import eu.tsystems.mms.tic.testframework.common.Testerra; +import eu.tsystems.mms.tic.testframework.webdrivermanager.BrowserDevTools; + +/** + * Provides a {@link BrowserDevTools} + * + * @author mgn + */ +public interface BrowserDevToolsProvider { + BrowserDevTools BROWSER_DEV_TOOLS = Testerra.getInjector().getInstance(BrowserDevTools.class); +} diff --git a/driver-ui/src/main/java/eu/tsystems/mms/tic/testframework/webdrivermanager/SeleniumDevTools.java b/driver-ui/src/main/java/eu/tsystems/mms/tic/testframework/testing/SeleniumDevTools.java similarity index 61% rename from driver-ui/src/main/java/eu/tsystems/mms/tic/testframework/webdrivermanager/SeleniumDevTools.java rename to driver-ui/src/main/java/eu/tsystems/mms/tic/testframework/testing/SeleniumDevTools.java index f7a254d094..d3ef236a91 100644 --- a/driver-ui/src/main/java/eu/tsystems/mms/tic/testframework/webdrivermanager/SeleniumDevTools.java +++ b/driver-ui/src/main/java/eu/tsystems/mms/tic/testframework/testing/SeleniumDevTools.java @@ -18,9 +18,14 @@ * specific language governing permissions and limitations * under the License. */ -package eu.tsystems.mms.tic.testframework.webdrivermanager; +package eu.tsystems.mms.tic.testframework.testing; import eu.tsystems.mms.tic.testframework.logging.Loggable; +import eu.tsystems.mms.tic.testframework.pageobjects.UiElementFinder; +import eu.tsystems.mms.tic.testframework.webdrivermanager.BrowserDevTools; +import org.openqa.selenium.Credentials; +import org.openqa.selenium.HasAuthentication; +import org.openqa.selenium.UsernameAndPassword; import org.openqa.selenium.WebDriver; import org.openqa.selenium.chrome.ChromeDriver; import org.openqa.selenium.devtools.DevTools; @@ -30,6 +35,8 @@ import org.openqa.selenium.remote.RemoteWebDriver; import java.util.Optional; +import java.util.concurrent.atomic.AtomicReference; +import java.util.function.Supplier; /** * Created on 2023-06-19 @@ -47,11 +54,10 @@ public DevTools getRawDevTools(WebDriver webDriver) { throw new RuntimeException("The current browser does not support DevTools"); } try { - WebDriverRequest webDriverRequest = WEB_DRIVER_MANAGER.getSessionContext(webDriver).get().getWebDriverRequest(); DevTools devTools = null; final String message = "Creating DevTools instance of "; // Check if current session is a local or remote session - if (webDriverRequest.getServerUrl().isPresent()) { + if (isRemoteDriver(webDriver)) { log().info("{}remote driver session.", message); RemoteWebDriver remoteWebDriver = WEB_DRIVER_MANAGER.unwrapWebDriver(webDriver, RemoteWebDriver.class).get(); webDriver = new Augmenter().augment(remoteWebDriver); @@ -80,4 +86,36 @@ public void setGeoLocation(WebDriver webDriver, double latitude, double longitud Optional.of(accuracy))); } + @Override + public void setBasicAuthentication(WebDriver webDriver, Supplier credentials) { + if (!isSupported(webDriver)) { + throw new RuntimeException("The current browser does not support DevTools"); + } + if (isRemoteDriver(webDriver)) { + WebDriver remoteWebDriver = WEB_DRIVER_MANAGER.unwrapWebDriver(webDriver, RemoteWebDriver.class).get(); + AtomicReference devToolsAtomicReference = new AtomicReference<>(); + remoteWebDriver = new Augmenter() + .addDriverAugmentation( + "chrome", + HasAuthentication.class, + (caps, exec) -> (whenThisMatches, useTheseCredentials) -> { + devToolsAtomicReference.get().createSessionIfThereIsNotOne(); + devToolsAtomicReference.get().getDomains() + .network() + .addAuthHandler(whenThisMatches, useTheseCredentials); + }) + .augment(remoteWebDriver); + DevTools devTools = ((HasDevTools) remoteWebDriver).getDevTools(); + devTools.createSession(); + devToolsAtomicReference.set(devTools); + ((HasAuthentication) remoteWebDriver).register(credentials); + } else { + // TODO Implement me + } + + + + } + + } diff --git a/driver-ui/src/main/java/eu/tsystems/mms/tic/testframework/webdrivermanager/BrowserDevTools.java b/driver-ui/src/main/java/eu/tsystems/mms/tic/testframework/webdrivermanager/BrowserDevTools.java index 1726b468ae..6e5f4ba352 100644 --- a/driver-ui/src/main/java/eu/tsystems/mms/tic/testframework/webdrivermanager/BrowserDevTools.java +++ b/driver-ui/src/main/java/eu/tsystems/mms/tic/testframework/webdrivermanager/BrowserDevTools.java @@ -22,10 +22,12 @@ import eu.tsystems.mms.tic.testframework.constants.Browsers; import eu.tsystems.mms.tic.testframework.testing.WebDriverManagerProvider; +import org.openqa.selenium.Credentials; import org.openqa.selenium.WebDriver; import org.openqa.selenium.devtools.DevTools; import java.util.Optional; +import java.util.function.Supplier; /** * Created on 2023-06-19 @@ -34,9 +36,11 @@ */ public interface BrowserDevTools extends WebDriverManagerProvider { - DevTools getRawDevTools(WebDriver driver); + DevTools getRawDevTools(WebDriver webDriver); - void setGeoLocation(WebDriver driver, double latitude, double longitude, int accuracy); + void setGeoLocation(WebDriver webDriver, double latitude, double longitude, int accuracy); + + void setBasicAuthentication(WebDriver webDriver, Supplier credentials); default boolean isSupported(WebDriver driver) { Optional requestedBrowser = WEB_DRIVER_MANAGER.getRequestedBrowser(driver); @@ -46,4 +50,9 @@ default boolean isSupported(WebDriver driver) { .orElse(false); } + default boolean isRemoteDriver(WebDriver webDriver) { + WebDriverRequest webDriverRequest = WEB_DRIVER_MANAGER.getSessionContext(webDriver).get().getWebDriverRequest(); + return webDriverRequest.getServerUrl().isPresent(); + } + } diff --git a/driver-ui/src/main/java/eu/tsystems/mms/tic/testframework/webdrivermanager/IWebDriverManager.java b/driver-ui/src/main/java/eu/tsystems/mms/tic/testframework/webdrivermanager/IWebDriverManager.java index 6b2cd16951..d83f3f55a3 100644 --- a/driver-ui/src/main/java/eu/tsystems/mms/tic/testframework/webdrivermanager/IWebDriverManager.java +++ b/driver-ui/src/main/java/eu/tsystems/mms/tic/testframework/webdrivermanager/IWebDriverManager.java @@ -22,27 +22,24 @@ package eu.tsystems.mms.tic.testframework.webdrivermanager; import eu.tsystems.mms.tic.testframework.common.IProperties; -import eu.tsystems.mms.tic.testframework.common.Testerra; import eu.tsystems.mms.tic.testframework.logging.Loggable; import eu.tsystems.mms.tic.testframework.report.model.context.SessionContext; import eu.tsystems.mms.tic.testframework.useragents.UserAgentConfig; import eu.tsystems.mms.tic.testframework.utils.WebDriverUtils; import eu.tsystems.mms.tic.testframework.webdriver.WebDriverFactory; import eu.tsystems.mms.tic.testframework.webdriver.WebDriverRetainer; +import org.openqa.selenium.WebDriver; +import org.openqa.selenium.support.events.EventFiringWebDriver; + import java.util.Locale; -import java.util.Map; import java.util.Optional; -import java.util.function.BiConsumer; import java.util.function.Consumer; -import java.util.function.Function; import java.util.function.Predicate; -import java.util.function.Supplier; import java.util.stream.Stream; -import org.openqa.selenium.WebDriver; -import org.openqa.selenium.support.events.EventFiringWebDriver; /** * Replacement for static {@link WebDriverManager} + * * @todo Rename to {@link WebDriverManager} */ public interface IWebDriverManager extends @@ -140,7 +137,7 @@ default Optional getWebDriver(SessionContext sessionContex return WebDriverSessionsManager.getWebDriver(sessionContext); } - default OptionalgetRequestedBrowser(WebDriver webDriver) { + default Optional getRequestedBrowser(WebDriver webDriver) { return WebDriverSessionsManager.getRequestedBrowser(webDriver); } @@ -165,7 +162,6 @@ default Stream readWebDrivers() { return WebDriverSessionsManager.readWebDrivers(); } - default IWebDriverManager setUserAgentConfig(String browser, UserAgentConfig configurator) { WebDriverManager.setUserAgentConfig(browser, configurator); return this; @@ -230,6 +226,7 @@ default void stopKeepingAlive(WebDriver webDriver) { default void setGlobalCapability(String key, Object value) { WebDriverManager.setGlobalExtraCapability(key, value); } + default void removeGlobalCapability(String key) { WebDriverManager.removeGlobalExtraCapability(key); } @@ -241,7 +238,7 @@ default void removeGlobalCapability(String key) { default Optional unwrapWebDriver(WebDriver webDriver, Class targetWebDriverClass) { WebDriver lowestWebDriver = WebDriverUtils.getLowestWebDriver(webDriver); if (targetWebDriverClass.isInstance(lowestWebDriver)) { - return Optional.of((WEBDRIVER)lowestWebDriver); + return Optional.of((WEBDRIVER) lowestWebDriver); } else { return Optional.empty(); } @@ -249,6 +246,7 @@ default Optional unwrapWebDriver(WebDriver webDriver, Cla /** * Sets the locale for a specified session + * * @param webDriver * @param locale * @return TRUE if locale has been set @@ -259,13 +257,10 @@ default boolean setSessionLocale(WebDriver webDriver, Locale locale) { /** * Returns the session locale + * * @param webDriver */ default Optional getSessionLocale(WebDriver webDriver) { return WebDriverManager.getSessionLocale(webDriver); } - - default BrowserDevTools accessDevTools() { - return Testerra.getInjector().getInstance(BrowserDevTools.class); - } } diff --git a/integration-tests/src/test/java/eu/tsystems/mms/tic/testframework/playground/BrowserDevToolsTests.java b/integration-tests/src/test/java/eu/tsystems/mms/tic/testframework/playground/BrowserDevToolsTests.java index 944479b8e4..e5429001d9 100644 --- a/integration-tests/src/test/java/eu/tsystems/mms/tic/testframework/playground/BrowserDevToolsTests.java +++ b/integration-tests/src/test/java/eu/tsystems/mms/tic/testframework/playground/BrowserDevToolsTests.java @@ -3,6 +3,7 @@ import eu.tsystems.mms.tic.testframework.AbstractWebDriverTest; import eu.tsystems.mms.tic.testframework.constants.Browsers; import eu.tsystems.mms.tic.testframework.pageobjects.UiElementFinder; +import eu.tsystems.mms.tic.testframework.testing.BrowserDevToolsProvider; import eu.tsystems.mms.tic.testframework.webdrivermanager.DesktopWebDriverRequest; import org.openqa.selenium.By; import org.openqa.selenium.HasAuthentication; @@ -24,7 +25,7 @@ * * @author mgn */ -public class BrowserDevToolsTests extends AbstractWebDriverTest { +public class BrowserDevToolsTests extends AbstractWebDriverTest implements BrowserDevToolsProvider { /** * See here for examples: @@ -97,12 +98,13 @@ public void testT03_GeoLocation_generic() { WebDriver webDriver = WEB_DRIVER_MANAGER.getWebDriver(request); UiElementFinder uiElementFinder = UI_ELEMENT_FINDER_FACTORY.create(webDriver); - DevTools devTools = WEB_DRIVER_MANAGER.accessDevTools().getRawDevTools(webDriver); - - devTools.send(Emulation.setGeolocationOverride( - latitude, - longitude, - Optional.of(1))); +// DevTools devTools = BROWSER_DEV_TOOLS.getRawDevTools(webDriver); +// +// devTools.send(Emulation.setGeolocationOverride( +// latitude, +// longitude, +// Optional.of(1))); + BROWSER_DEV_TOOLS.setGeoLocation(webDriver, latitude.get().doubleValue(), longitude.get().doubleValue(), 1); webDriver.get("https://my-location.org/"); uiElementFinder.find(By.id("latitude")).assertThat().text().isContaining(latitude.get().toString()); @@ -142,4 +144,20 @@ public void testT04_BasicAuth_remoteDriver() { uiElementFinder.find(By.tagName("p")).assertThat().text().isContaining("Congratulations"); } + + @Test + public void testT05_BasicAuth_DevTools() { + DesktopWebDriverRequest request = new DesktopWebDriverRequest(); + request.setBrowser(Browsers.chrome); +// request.setBrowserVersion("106"); + WebDriver webDriver = WEB_DRIVER_MANAGER.getWebDriver(request); + UiElementFinder uiElementFinder = UI_ELEMENT_FINDER_FACTORY.create(webDriver); + + BROWSER_DEV_TOOLS.setBasicAuthentication(webDriver, UsernameAndPassword.of("admin", "admin")); + + webDriver.get("https://the-internet.herokuapp.com/basic_auth"); + uiElementFinder.find(By.tagName("p")).assertThat().text().isContaining("Congratulations"); + + } + } From cbc690e1b92622fc4e1ed98dd89e07cad3a480a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Gro=C3=9Fmann?= Date: Tue, 20 Jun 2023 18:05:46 +0200 Subject: [PATCH 40/64] Fixed cloning of a WebDriverRequest --- .../utils/DefaultCapabilityUtils.java | 15 +++++-- .../AbstractWebDriverRequest.java | 40 +++++++++++-------- 2 files changed, 34 insertions(+), 21 deletions(-) diff --git a/driver-ui/src/main/java/eu/tsystems/mms/tic/testframework/utils/DefaultCapabilityUtils.java b/driver-ui/src/main/java/eu/tsystems/mms/tic/testframework/utils/DefaultCapabilityUtils.java index 539f0bc9c9..a146d9e45c 100644 --- a/driver-ui/src/main/java/eu/tsystems/mms/tic/testframework/utils/DefaultCapabilityUtils.java +++ b/driver-ui/src/main/java/eu/tsystems/mms/tic/testframework/utils/DefaultCapabilityUtils.java @@ -54,10 +54,7 @@ public Map clean(Capabilities capabilities) { public Map clean(Map capabilityMap) { // 1. clone and make map modifiable. - // For deep cloning it is needed convert it to JSON and back because Firefox options also contain some immutable map objects - Gson gson = new GsonBuilder().create(); - String json = gson.toJson(capabilityMap); - Map clonedMap = (Map) gson.fromJson(json, Map.class); + Map clonedMap = this.clone(capabilityMap); // 2. do all the operations shortMapValues(clonedMap); @@ -66,6 +63,16 @@ public Map clean(Map capabilityMap) { return Collections.unmodifiableMap(clonedMap); } + /** + * For deep cloning it is needed convert it to JSON and back because Firefox options also contain some immutable map objects + * Note: Complex objects are simplified to key-value pairs. This is acceptable because capabilities are always simplified to a kind of Map + */ + public Map clone(Map capabilityMap) { + Gson gson = new GsonBuilder().create(); + String json = gson.toJson(capabilityMap); + return (Map) gson.fromJson(json, Map.class); + } + /** * Some caps like Extensions strings are very long, so therefore we will cut them off */ diff --git a/driver-ui/src/main/java/eu/tsystems/mms/tic/testframework/webdrivermanager/AbstractWebDriverRequest.java b/driver-ui/src/main/java/eu/tsystems/mms/tic/testframework/webdrivermanager/AbstractWebDriverRequest.java index f43bef6aaa..debae44e58 100644 --- a/driver-ui/src/main/java/eu/tsystems/mms/tic/testframework/webdrivermanager/AbstractWebDriverRequest.java +++ b/driver-ui/src/main/java/eu/tsystems/mms/tic/testframework/webdrivermanager/AbstractWebDriverRequest.java @@ -23,9 +23,10 @@ import eu.tsystems.mms.tic.testframework.common.PropertyManager; import eu.tsystems.mms.tic.testframework.constants.TesterraProperties; import eu.tsystems.mms.tic.testframework.logging.Loggable; -import org.apache.commons.lang3.SerializationUtils; +import eu.tsystems.mms.tic.testframework.utils.DefaultCapabilityUtils; import org.apache.commons.lang3.StringUtils; import org.openqa.selenium.Capabilities; +import org.openqa.selenium.MutableCapabilities; import org.openqa.selenium.Platform; import org.openqa.selenium.WebDriverException; import org.openqa.selenium.remote.DesiredCapabilities; @@ -153,22 +154,6 @@ public DesiredCapabilities getDesiredCapabilities() { return desiredCapabilities; } - /** - * Cloning of DesiredCapabilites with SerializationUtils occurs org.apache.commons.lang3.SerializationException: IOException while reading or closing cloned object data - * -> We have to backup the current caps and clone WebDriverRequest without caps. After cloning the original caps are added again. - * -> merge()-Method does not clone capability values like Maps (e.g. goog:chromeOptions, no deep copy) -> used org.apache.commons.lang3.SerializationUtils - */ - public AbstractWebDriverRequest clone() throws CloneNotSupportedException { - AbstractWebDriverRequest clone = (AbstractWebDriverRequest) super.clone(); - if (this.desiredCapabilities != null) { - clone.desiredCapabilities = SerializationUtils.clone(this.desiredCapabilities); - } - if (this.capabilities != null) { - clone.setBrowserOptions(SerializationUtils.clone(this.capabilities)); - } - return clone; - } - public Capabilities getBrowserOptions() { return capabilities; } @@ -195,4 +180,25 @@ public Optional getPlatformName() { return Optional.empty(); } + /** + * Cloning of DesiredCapabilites with SerializationUtils occurs org.apache.commons.lang3.SerializationException: IOException while reading or closing cloned object data + * -> We have to backup the current caps and clone WebDriverRequest without caps. After cloning the original caps are added again. + * -> org.apache.commons.lang3.SerializationUtils cannot used because not all objects are serializable (e.g. Proxy) + * -> merge()-Method does not clone capability values like Maps (e.g. goog:chromeOptions, no deep copy) + * --> used Gson lib + */ + public AbstractWebDriverRequest clone() throws CloneNotSupportedException { + AbstractWebDriverRequest clone = (AbstractWebDriverRequest) super.clone(); + + DefaultCapabilityUtils capabilityUtils = new DefaultCapabilityUtils(); + if (this.desiredCapabilities != null) { + Map clonedCaps = capabilityUtils.clone(this.desiredCapabilities.asMap()); + clone.desiredCapabilities = new DesiredCapabilities(clonedCaps); + } + if (this.capabilities != null) { + Map clonedCaps = capabilityUtils.clone(this.capabilities.asMap()); + clone.setBrowserOptions(new MutableCapabilities(clonedCaps)); + } + return clone; + } } From 6c1f6b71b7660ae33c7bcc5f2410ebe520cb2ce5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Gro=C3=9Fmann?= Date: Thu, 22 Jun 2023 09:15:53 +0200 Subject: [PATCH 41/64] Added BiDiChrome example --- .../testing/SeleniumDevTools.java | 3 -- .../playground/BrowserDevToolsTests.java | 44 +++++++++++++++++++ 2 files changed, 44 insertions(+), 3 deletions(-) diff --git a/driver-ui/src/main/java/eu/tsystems/mms/tic/testframework/testing/SeleniumDevTools.java b/driver-ui/src/main/java/eu/tsystems/mms/tic/testframework/testing/SeleniumDevTools.java index d3ef236a91..39ce6b9c7b 100644 --- a/driver-ui/src/main/java/eu/tsystems/mms/tic/testframework/testing/SeleniumDevTools.java +++ b/driver-ui/src/main/java/eu/tsystems/mms/tic/testframework/testing/SeleniumDevTools.java @@ -21,11 +21,9 @@ package eu.tsystems.mms.tic.testframework.testing; import eu.tsystems.mms.tic.testframework.logging.Loggable; -import eu.tsystems.mms.tic.testframework.pageobjects.UiElementFinder; import eu.tsystems.mms.tic.testframework.webdrivermanager.BrowserDevTools; import org.openqa.selenium.Credentials; import org.openqa.selenium.HasAuthentication; -import org.openqa.selenium.UsernameAndPassword; import org.openqa.selenium.WebDriver; import org.openqa.selenium.chrome.ChromeDriver; import org.openqa.selenium.devtools.DevTools; @@ -114,7 +112,6 @@ public void setBasicAuthentication(WebDriver webDriver, Supplier cr } - } diff --git a/integration-tests/src/test/java/eu/tsystems/mms/tic/testframework/playground/BrowserDevToolsTests.java b/integration-tests/src/test/java/eu/tsystems/mms/tic/testframework/playground/BrowserDevToolsTests.java index e5429001d9..ff40397237 100644 --- a/integration-tests/src/test/java/eu/tsystems/mms/tic/testframework/playground/BrowserDevToolsTests.java +++ b/integration-tests/src/test/java/eu/tsystems/mms/tic/testframework/playground/BrowserDevToolsTests.java @@ -1,3 +1,23 @@ +/* + * Testerra + * + * (C) 2023, Martin Großmann, Deutsche Telekom MMS GmbH, Deutsche Telekom AG + * + * Deutsche Telekom AG and all other contributors / + * copyright owners license this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this + * file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ package eu.tsystems.mms.tic.testframework.playground; import eu.tsystems.mms.tic.testframework.AbstractWebDriverTest; @@ -10,6 +30,7 @@ import org.openqa.selenium.UsernameAndPassword; import org.openqa.selenium.WebDriver; import org.openqa.selenium.chrome.ChromeDriver; +import org.openqa.selenium.chrome.ChromeOptions; import org.openqa.selenium.devtools.DevTools; import org.openqa.selenium.devtools.HasDevTools; import org.openqa.selenium.devtools.v112.emulation.Emulation; @@ -17,8 +38,10 @@ import org.openqa.selenium.remote.RemoteWebDriver; import org.testng.annotations.Test; +import java.net.URI; import java.util.Optional; import java.util.concurrent.atomic.AtomicReference; +import java.util.function.Predicate; /** * Created on 2023-01-13 @@ -160,4 +183,25 @@ public void testT05_BasicAuth_DevTools() { } + /** + * The following example uses the BiDi implementation of Chrome to add basic authentication information + * + * Works only with local ChromeDriver, RemoteWebDriver is not supported + */ + @Test + public void testT06_BasicAuth_ChromeBiDiAPI() { + DesktopWebDriverRequest request = new DesktopWebDriverRequest(); + request.setBrowser(Browsers.chrome); +// request.setBrowserVersion("106"); + WebDriver webDriver = WEB_DRIVER_MANAGER.getWebDriver(request); + UiElementFinder uiElementFinder = UI_ELEMENT_FINDER_FACTORY.create(webDriver); + Predicate uriPredicate = uri -> uri.getHost().contains("the-internet.herokuapp.com"); + + ChromeDriver chromeDriver = WEB_DRIVER_MANAGER.unwrapWebDriver(webDriver, ChromeDriver.class).get(); + ((HasAuthentication) chromeDriver).register(uriPredicate, UsernameAndPassword.of("admin", "admin")); + + webDriver.get("https://the-internet.herokuapp.com/basic_auth"); + uiElementFinder.find(By.tagName("p")).assertThat().text().isContaining("Congratulations"); + } + } From 10cfc32d40256a319b7fe7a191a64339b092c6a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Gro=C3=9Fmann?= Date: Thu, 22 Jun 2023 09:57:03 +0200 Subject: [PATCH 42/64] Rename BrowserDevTools to ChromeDevTools --- build.gradle | 2 +- .../tic/testframework/hooks/DriverUiHook.java | 6 +++--- ...vider.java => ChromeDevToolsProvider.java} | 8 ++++---- ...Tools.java => SeleniumChromeDevTools.java} | 20 ++++++++++++++++--- ...owserDevTools.java => ChromeDevTools.java} | 2 +- ...olsTests.java => ChromeDevToolsTests.java} | 9 ++++----- 6 files changed, 30 insertions(+), 17 deletions(-) rename driver-ui/src/main/java/eu/tsystems/mms/tic/testframework/testing/{BrowserDevToolsProvider.java => ChromeDevToolsProvider.java} (77%) rename driver-ui/src/main/java/eu/tsystems/mms/tic/testframework/testing/{SeleniumDevTools.java => SeleniumChromeDevTools.java} (80%) rename driver-ui/src/main/java/eu/tsystems/mms/tic/testframework/webdrivermanager/{BrowserDevTools.java => ChromeDevTools.java} (96%) rename integration-tests/src/test/java/eu/tsystems/mms/tic/testframework/playground/{BrowserDevToolsTests.java => ChromeDevToolsTests.java} (95%) diff --git a/build.gradle b/build.gradle index 464902e3ba..d074ca7fda 100644 --- a/build.gradle +++ b/build.gradle @@ -20,7 +20,7 @@ ext { core = project(':core') report = project(':report-ng') - seleniumVersion = '4.9.0' + seleniumVersion = '4.10.0' // seleniumVersion = '4.6.0' // Must be the same like in Selenium 4 guavaVersion = "31.1-jre" diff --git a/driver-ui/src/main/java/eu/tsystems/mms/tic/testframework/hooks/DriverUiHook.java b/driver-ui/src/main/java/eu/tsystems/mms/tic/testframework/hooks/DriverUiHook.java index 43c5f2e8a8..a8905869fc 100644 --- a/driver-ui/src/main/java/eu/tsystems/mms/tic/testframework/hooks/DriverUiHook.java +++ b/driver-ui/src/main/java/eu/tsystems/mms/tic/testframework/hooks/DriverUiHook.java @@ -53,10 +53,10 @@ import eu.tsystems.mms.tic.testframework.useragents.BrowserInformation; import eu.tsystems.mms.tic.testframework.useragents.UapBrowserInformation; import eu.tsystems.mms.tic.testframework.watchdog.WebDriverWatchDog; -import eu.tsystems.mms.tic.testframework.webdrivermanager.BrowserDevTools; +import eu.tsystems.mms.tic.testframework.webdrivermanager.ChromeDevTools; import eu.tsystems.mms.tic.testframework.webdrivermanager.DefaultWebDriverManager; import eu.tsystems.mms.tic.testframework.webdrivermanager.IWebDriverManager; -import eu.tsystems.mms.tic.testframework.testing.SeleniumDevTools; +import eu.tsystems.mms.tic.testframework.testing.SeleniumChromeDevTools; import eu.tsystems.mms.tic.testframework.webdrivermanager.WebDriverCapabilities; import eu.tsystems.mms.tic.testframework.webdrivermanager.WebDriverSessionsManager; @@ -77,7 +77,7 @@ protected void configure() { // Instances bind(BrowserInformation.class).to(UapBrowserInformation.class); - bind(BrowserDevTools.class).to(SeleniumDevTools.class); + bind(ChromeDevTools.class).to(SeleniumChromeDevTools.class); } @Override diff --git a/driver-ui/src/main/java/eu/tsystems/mms/tic/testframework/testing/BrowserDevToolsProvider.java b/driver-ui/src/main/java/eu/tsystems/mms/tic/testframework/testing/ChromeDevToolsProvider.java similarity index 77% rename from driver-ui/src/main/java/eu/tsystems/mms/tic/testframework/testing/BrowserDevToolsProvider.java rename to driver-ui/src/main/java/eu/tsystems/mms/tic/testframework/testing/ChromeDevToolsProvider.java index 7d5645acfe..737fb3bad4 100644 --- a/driver-ui/src/main/java/eu/tsystems/mms/tic/testframework/testing/BrowserDevToolsProvider.java +++ b/driver-ui/src/main/java/eu/tsystems/mms/tic/testframework/testing/ChromeDevToolsProvider.java @@ -21,13 +21,13 @@ package eu.tsystems.mms.tic.testframework.testing; import eu.tsystems.mms.tic.testframework.common.Testerra; -import eu.tsystems.mms.tic.testframework.webdrivermanager.BrowserDevTools; +import eu.tsystems.mms.tic.testframework.webdrivermanager.ChromeDevTools; /** - * Provides a {@link BrowserDevTools} + * Provides a {@link ChromeDevTools} * * @author mgn */ -public interface BrowserDevToolsProvider { - BrowserDevTools BROWSER_DEV_TOOLS = Testerra.getInjector().getInstance(BrowserDevTools.class); +public interface ChromeDevToolsProvider { + ChromeDevTools CHROME_DEV_TOOLS = Testerra.getInjector().getInstance(ChromeDevTools.class); } diff --git a/driver-ui/src/main/java/eu/tsystems/mms/tic/testframework/testing/SeleniumDevTools.java b/driver-ui/src/main/java/eu/tsystems/mms/tic/testframework/testing/SeleniumChromeDevTools.java similarity index 80% rename from driver-ui/src/main/java/eu/tsystems/mms/tic/testframework/testing/SeleniumDevTools.java rename to driver-ui/src/main/java/eu/tsystems/mms/tic/testframework/testing/SeleniumChromeDevTools.java index 39ce6b9c7b..521c750394 100644 --- a/driver-ui/src/main/java/eu/tsystems/mms/tic/testframework/testing/SeleniumDevTools.java +++ b/driver-ui/src/main/java/eu/tsystems/mms/tic/testframework/testing/SeleniumChromeDevTools.java @@ -21,7 +21,9 @@ package eu.tsystems.mms.tic.testframework.testing; import eu.tsystems.mms.tic.testframework.logging.Loggable; -import eu.tsystems.mms.tic.testframework.webdrivermanager.BrowserDevTools; +import eu.tsystems.mms.tic.testframework.report.model.context.SessionContext; +import eu.tsystems.mms.tic.testframework.webdrivermanager.ChromeDevTools; +import eu.tsystems.mms.tic.testframework.webdrivermanager.DesktopWebDriverRequest; import org.openqa.selenium.Credentials; import org.openqa.selenium.HasAuthentication; import org.openqa.selenium.WebDriver; @@ -32,8 +34,11 @@ import org.openqa.selenium.remote.Augmenter; import org.openqa.selenium.remote.RemoteWebDriver; +import java.net.URI; +import java.net.URL; import java.util.Optional; import java.util.concurrent.atomic.AtomicReference; +import java.util.function.Predicate; import java.util.function.Supplier; /** @@ -41,7 +46,7 @@ * * @author mgn */ -public class SeleniumDevTools implements BrowserDevTools, Loggable { +public class SeleniumChromeDevTools implements ChromeDevTools, Loggable { /** * Create a Chrome DevTools session @@ -108,7 +113,16 @@ public void setBasicAuthentication(WebDriver webDriver, Supplier cr devToolsAtomicReference.set(devTools); ((HasAuthentication) remoteWebDriver).register(credentials); } else { - // TODO Implement me + DesktopWebDriverRequest webDriverRequest = (DesktopWebDriverRequest) WEB_DRIVER_MANAGER.getSessionContext(webDriver) + .map(SessionContext::getWebDriverRequest) + .orElse(null); + if (webDriverRequest == null) { + throw new RuntimeException("Cannot get WebdriverRequest from SessionContext"); + } + String baseUrlHost = webDriverRequest.getBaseUrl().map(URL::getHost).orElse(""); + Predicate uriPredicate = uri -> uri.getHost().contains(baseUrlHost); + ChromeDriver chromeDriver = WEB_DRIVER_MANAGER.unwrapWebDriver(webDriver, ChromeDriver.class).get(); + ((HasAuthentication) chromeDriver).register(uriPredicate, credentials); } diff --git a/driver-ui/src/main/java/eu/tsystems/mms/tic/testframework/webdrivermanager/BrowserDevTools.java b/driver-ui/src/main/java/eu/tsystems/mms/tic/testframework/webdrivermanager/ChromeDevTools.java similarity index 96% rename from driver-ui/src/main/java/eu/tsystems/mms/tic/testframework/webdrivermanager/BrowserDevTools.java rename to driver-ui/src/main/java/eu/tsystems/mms/tic/testframework/webdrivermanager/ChromeDevTools.java index 6e5f4ba352..6fa1f0c36c 100644 --- a/driver-ui/src/main/java/eu/tsystems/mms/tic/testframework/webdrivermanager/BrowserDevTools.java +++ b/driver-ui/src/main/java/eu/tsystems/mms/tic/testframework/webdrivermanager/ChromeDevTools.java @@ -34,7 +34,7 @@ * * @author mgn */ -public interface BrowserDevTools extends WebDriverManagerProvider { +public interface ChromeDevTools extends WebDriverManagerProvider { DevTools getRawDevTools(WebDriver webDriver); diff --git a/integration-tests/src/test/java/eu/tsystems/mms/tic/testframework/playground/BrowserDevToolsTests.java b/integration-tests/src/test/java/eu/tsystems/mms/tic/testframework/playground/ChromeDevToolsTests.java similarity index 95% rename from integration-tests/src/test/java/eu/tsystems/mms/tic/testframework/playground/BrowserDevToolsTests.java rename to integration-tests/src/test/java/eu/tsystems/mms/tic/testframework/playground/ChromeDevToolsTests.java index ff40397237..1b37c3325e 100644 --- a/integration-tests/src/test/java/eu/tsystems/mms/tic/testframework/playground/BrowserDevToolsTests.java +++ b/integration-tests/src/test/java/eu/tsystems/mms/tic/testframework/playground/ChromeDevToolsTests.java @@ -23,14 +23,13 @@ import eu.tsystems.mms.tic.testframework.AbstractWebDriverTest; import eu.tsystems.mms.tic.testframework.constants.Browsers; import eu.tsystems.mms.tic.testframework.pageobjects.UiElementFinder; -import eu.tsystems.mms.tic.testframework.testing.BrowserDevToolsProvider; +import eu.tsystems.mms.tic.testframework.testing.ChromeDevToolsProvider; import eu.tsystems.mms.tic.testframework.webdrivermanager.DesktopWebDriverRequest; import org.openqa.selenium.By; import org.openqa.selenium.HasAuthentication; import org.openqa.selenium.UsernameAndPassword; import org.openqa.selenium.WebDriver; import org.openqa.selenium.chrome.ChromeDriver; -import org.openqa.selenium.chrome.ChromeOptions; import org.openqa.selenium.devtools.DevTools; import org.openqa.selenium.devtools.HasDevTools; import org.openqa.selenium.devtools.v112.emulation.Emulation; @@ -48,7 +47,7 @@ * * @author mgn */ -public class BrowserDevToolsTests extends AbstractWebDriverTest implements BrowserDevToolsProvider { +public class ChromeDevToolsTests extends AbstractWebDriverTest implements ChromeDevToolsProvider { /** * See here for examples: @@ -127,7 +126,7 @@ public void testT03_GeoLocation_generic() { // latitude, // longitude, // Optional.of(1))); - BROWSER_DEV_TOOLS.setGeoLocation(webDriver, latitude.get().doubleValue(), longitude.get().doubleValue(), 1); + CHROME_DEV_TOOLS.setGeoLocation(webDriver, latitude.get().doubleValue(), longitude.get().doubleValue(), 1); webDriver.get("https://my-location.org/"); uiElementFinder.find(By.id("latitude")).assertThat().text().isContaining(latitude.get().toString()); @@ -176,7 +175,7 @@ public void testT05_BasicAuth_DevTools() { WebDriver webDriver = WEB_DRIVER_MANAGER.getWebDriver(request); UiElementFinder uiElementFinder = UI_ELEMENT_FINDER_FACTORY.create(webDriver); - BROWSER_DEV_TOOLS.setBasicAuthentication(webDriver, UsernameAndPassword.of("admin", "admin")); + CHROME_DEV_TOOLS.setBasicAuthentication(webDriver, UsernameAndPassword.of("admin", "admin")); webDriver.get("https://the-internet.herokuapp.com/basic_auth"); uiElementFinder.find(By.tagName("p")).assertThat().text().isContaining("Congratulations"); From 01a0c6326dbddb362b243e3c446aeeca7c4ba6a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Gro=C3=9Fmann?= Date: Fri, 23 Jun 2023 16:52:00 +0200 Subject: [PATCH 43/64] Updated test examples with CDP and BiDi API --- .../testframework/AbstractWebDriverTest.java | 8 +- .../playground/ChromeDevToolsTests.java | 57 ++++- .../playground/SeleniumBiDiApiTests.java | 218 ++++++++++++++++++ 3 files changed, 280 insertions(+), 3 deletions(-) create mode 100644 integration-tests/src/test/java/eu/tsystems/mms/tic/testframework/playground/SeleniumBiDiApiTests.java diff --git a/integration-tests/src/main/java/eu/tsystems/mms/tic/testframework/AbstractWebDriverTest.java b/integration-tests/src/main/java/eu/tsystems/mms/tic/testframework/AbstractWebDriverTest.java index 5527caff2a..c836628a43 100644 --- a/integration-tests/src/main/java/eu/tsystems/mms/tic/testframework/AbstractWebDriverTest.java +++ b/integration-tests/src/main/java/eu/tsystems/mms/tic/testframework/AbstractWebDriverTest.java @@ -24,6 +24,7 @@ import eu.tsystems.mms.tic.testframework.constants.Browsers; import eu.tsystems.mms.tic.testframework.logging.Loggable; +import eu.tsystems.mms.tic.testframework.testing.AssertProvider; import eu.tsystems.mms.tic.testframework.testing.TesterraTest; import eu.tsystems.mms.tic.testframework.testing.UiElementFinderFactoryProvider; import eu.tsystems.mms.tic.testframework.testing.WebDriverManagerProvider; @@ -42,7 +43,12 @@ /** * Abstract test class for tests using a WebDriver */ -public abstract class AbstractWebDriverTest extends TesterraTest implements WebDriverRetainer, WebDriverManagerProvider, Loggable, UiElementFinderFactoryProvider { +public abstract class AbstractWebDriverTest extends TesterraTest implements + WebDriverRetainer, + WebDriverManagerProvider, + Loggable, + UiElementFinderFactoryProvider, + AssertProvider { private String exclusiveSessionId; diff --git a/integration-tests/src/test/java/eu/tsystems/mms/tic/testframework/playground/ChromeDevToolsTests.java b/integration-tests/src/test/java/eu/tsystems/mms/tic/testframework/playground/ChromeDevToolsTests.java index 1b37c3325e..29f69fccb5 100644 --- a/integration-tests/src/test/java/eu/tsystems/mms/tic/testframework/playground/ChromeDevToolsTests.java +++ b/integration-tests/src/test/java/eu/tsystems/mms/tic/testframework/playground/ChromeDevToolsTests.java @@ -33,13 +33,21 @@ import org.openqa.selenium.devtools.DevTools; import org.openqa.selenium.devtools.HasDevTools; import org.openqa.selenium.devtools.v112.emulation.Emulation; +import org.openqa.selenium.devtools.v114.log.Log; +import org.openqa.selenium.devtools.v114.log.model.LogEntry; +import org.openqa.selenium.devtools.v85.runtime.Runtime; import org.openqa.selenium.remote.Augmenter; import org.openqa.selenium.remote.RemoteWebDriver; +import org.testng.Assert; import org.testng.annotations.Test; +import java.net.MalformedURLException; import java.net.URI; +import java.util.ArrayList; +import java.util.List; import java.util.Optional; import java.util.concurrent.atomic.AtomicReference; +import java.util.function.Consumer; import java.util.function.Predicate; /** @@ -184,7 +192,7 @@ public void testT05_BasicAuth_DevTools() { /** * The following example uses the BiDi implementation of Chrome to add basic authentication information - * + *

* Works only with local ChromeDriver, RemoteWebDriver is not supported */ @Test @@ -196,11 +204,56 @@ public void testT06_BasicAuth_ChromeBiDiAPI() { UiElementFinder uiElementFinder = UI_ELEMENT_FINDER_FACTORY.create(webDriver); Predicate uriPredicate = uri -> uri.getHost().contains("the-internet.herokuapp.com"); - ChromeDriver chromeDriver = WEB_DRIVER_MANAGER.unwrapWebDriver(webDriver, ChromeDriver.class).get(); + ChromeDriver chromeDriver = WEB_DRIVER_MANAGER.unwrapWebDriver(webDriver, ChromeDriver.class).get(); ((HasAuthentication) chromeDriver).register(uriPredicate, UsernameAndPassword.of("admin", "admin")); webDriver.get("https://the-internet.herokuapp.com/basic_auth"); uiElementFinder.find(By.tagName("p")).assertThat().text().isContaining("Congratulations"); } + @Test + public void testT07_LogListener() throws MalformedURLException { + DesktopWebDriverRequest request = new DesktopWebDriverRequest(); + request.setBaseUrl("https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html"); + WebDriver webDriver = WEB_DRIVER_MANAGER.getWebDriver(request); + DevTools rawDevTools = CHROME_DEV_TOOLS.getRawDevTools(webDriver); + + rawDevTools.send(Runtime.enable()); + rawDevTools.send(Log.enable()); + rawDevTools.addListener(Log.entryAdded(), + entry -> { + log().info("{} - {}: {}", entry.getTimestamp(), entry.getLevel().toString().toUpperCase(), entry.getText()); + System.out.println(entry.getText()); + }); + + UiElementFinder uiElementFinder = UI_ELEMENT_FINDER_FACTORY.create(webDriver); + uiElementFinder.find(By.id("consoleLog")).click(); + uiElementFinder.find(By.id("consoleError")).click(); + + } + + + @Test + public void testT08_LogListenerBrokenImages() throws MalformedURLException { + DesktopWebDriverRequest request = new DesktopWebDriverRequest(); +// request.setBaseUrl("https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html"); + WebDriver webDriver = WEB_DRIVER_MANAGER.getWebDriver(request); + DevTools devTools = CHROME_DEV_TOOLS.getRawDevTools(webDriver); + + devTools.send(Log.enable()); + + List logEntries = new ArrayList<>(); + Consumer addedLog = logEntries::add; + + // Consumer is running in another thread... Asserts do not have impact to main thread + devTools.addListener(Log.entryAdded(), addedLog); + webDriver.get("http://the-internet.herokuapp.com/broken_images"); + + for (LogEntry logEntry : logEntries) { + System.out.println(String.format("LOG_ENTRY: %s %s %s - %s (%s)", logEntry.getTimestamp(), logEntry.getLevel(), logEntry.getSource(), logEntry.getText(), logEntry.getUrl())); + log().info("LOG_ENTRY: {} {} {} - {} ({})", logEntry.getTimestamp(), logEntry.getLevel(), logEntry.getSource(), logEntry.getText(), logEntry.getUrl()); + ASSERT.assertFalse(logEntry.getText().contains("404")); + } + } + } diff --git a/integration-tests/src/test/java/eu/tsystems/mms/tic/testframework/playground/SeleniumBiDiApiTests.java b/integration-tests/src/test/java/eu/tsystems/mms/tic/testframework/playground/SeleniumBiDiApiTests.java new file mode 100644 index 0000000000..6eb4971fd7 --- /dev/null +++ b/integration-tests/src/test/java/eu/tsystems/mms/tic/testframework/playground/SeleniumBiDiApiTests.java @@ -0,0 +1,218 @@ +/* + * Testerra + * + * (C) 2023, Martin Großmann, Deutsche Telekom MMS GmbH, Deutsche Telekom AG + * + * Deutsche Telekom AG and all other contributors / + * copyright owners license this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this + * file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package eu.tsystems.mms.tic.testframework.playground; + +import eu.tsystems.mms.tic.testframework.AbstractWebDriverTest; +import eu.tsystems.mms.tic.testframework.constants.Browsers; +import eu.tsystems.mms.tic.testframework.pageobjects.UiElementFinder; +import eu.tsystems.mms.tic.testframework.report.model.steps.TestStep; +import eu.tsystems.mms.tic.testframework.useragents.ChromeConfig; +import eu.tsystems.mms.tic.testframework.useragents.FirefoxConfig; +import eu.tsystems.mms.tic.testframework.webdrivermanager.DesktopWebDriverRequest; +import org.openqa.selenium.By; +import org.openqa.selenium.WebDriver; +import org.openqa.selenium.bidi.LogInspector; +import org.openqa.selenium.bidi.log.ConsoleLogEntry; +import org.openqa.selenium.bidi.log.LogEntry; +import org.openqa.selenium.bidi.log.LogLevel; +import org.openqa.selenium.chrome.ChromeDriver; +import org.openqa.selenium.firefox.FirefoxDriver; +import org.openqa.selenium.remote.RemoteWebDriver; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Test; + +import java.net.MalformedURLException; +import java.rmi.Remote; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + +/** + * Created on 2023-06-22 + * + * @author mgn + */ +public class SeleniumBiDiApiTests extends AbstractWebDriverTest { + + @BeforeClass + public void initBrowser() { + WEB_DRIVER_MANAGER.setUserAgentConfig(Browsers.chrome, (ChromeConfig) options -> { + options.setCapability("webSocketUrl", true); + }); + + WEB_DRIVER_MANAGER.setUserAgentConfig(Browsers.firefox, (FirefoxConfig) options -> { + options.setCapability("webSocketUrl", true); + }); + } + + @Test + public void testT01_ListenToConsoleLogLocalWithException() throws MalformedURLException, ExecutionException, InterruptedException, TimeoutException { + DesktopWebDriverRequest request = new DesktopWebDriverRequest(); + request.setBrowser(Browsers.chrome); +// request.setBrowser(Browsers.firefox); + request.setBaseUrl("https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html"); + WebDriver webDriver = WEB_DRIVER_MANAGER.getWebDriver(request); + + UiElementFinder uiElementFinder = UI_ELEMENT_FINDER_FACTORY.create(webDriver); + + ChromeDriver chromeDriver = WEB_DRIVER_MANAGER.unwrapWebDriver(webDriver, ChromeDriver.class).get(); +// FirefoxDriver firefoxDriver = WEB_DRIVER_MANAGER.unwrapWebDriver(webDriver, FirefoxDriver.class).get(); + LogInspector logInspector = new LogInspector(chromeDriver); +// LogInspector logInspector = new LogInspector(firefoxDriver); + CompletableFuture future = new CompletableFuture<>(); + +// future.exceptionally(ex -> { +// log().error("Exception in future"); +// throw new RuntimeException(ex); +// }); + + logInspector.onConsoleEntry(entry -> { + try { + log().info("{} - {}: {}", entry.getTimestamp(), entry.getLevel().toString().toUpperCase(), entry.getText()); + ASSERT.assertNotEquals(entry.getLevel(), LogLevel.ERROR, "Console log type"); + } catch (AssertionError e) { + future.completeExceptionally(e); + } + }); +// logInspector.onConsoleEntry(entry -> { +// log().info("{} - {}: {}", entry.getTimestamp(), entry.getLevel().toString().toUpperCase(), entry.getText()); +// ASSERT.assertNotEquals(entry.getLevel(), LogLevel.ERROR, "Console log type"); +// Assert.fail("TestNG fail"); +// }); + TestStep.begin("clicks"); + log().info("Vor click"); + uiElementFinder.find(By.id("consoleLog")).click(); + log().info("Nach click"); + uiElementFinder.find(By.id("consoleError")).click(); + // Exception behandeln, ohne get() aufzurufen + + TestStep.begin("nach allem"); + log().info("Foo bar"); + +// ConsoleLogEntry logEntry = future.get(5, TimeUnit.SECONDS); +// log().info(logEntry.getText()); +// ASSERT.assertTrue(logEntry.getText().contains("Hello, world!")); + // Cause that exception are thrown to current main thread + CompletableFuture.allOf(future).join(); + } + + @Test + public void testT02_ListenToConsoleLogRemote() throws ExecutionException, InterruptedException, TimeoutException { + WebDriver webDriver = WEB_DRIVER_MANAGER.getWebDriver(); + RemoteWebDriver remoteWebDriver = WEB_DRIVER_MANAGER.unwrapWebDriver(webDriver, RemoteWebDriver.class).get(); + LogInspector logInspector = new LogInspector(remoteWebDriver); + CompletableFuture future = new CompletableFuture<>(); + logInspector.onConsoleEntry(future::complete); + + webDriver.get("https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html"); + webDriver.findElement(By.id("consoleLog")).click(); + + ConsoleLogEntry logEntry = future.get(5, TimeUnit.SECONDS); + log().info(logEntry.toString()); + } + + @Test + public void testT03_ListenToConsoleLogWithList_LOCAL() throws MalformedURLException { + DesktopWebDriverRequest request = new DesktopWebDriverRequest(); + request.setBrowser(Browsers.chrome); + request.setBaseUrl("https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html"); + WebDriver webDriver = WEB_DRIVER_MANAGER.getWebDriver(request); + + ChromeDriver chromeDriver = WEB_DRIVER_MANAGER.unwrapWebDriver(webDriver, ChromeDriver.class).get(); + UiElementFinder uiElementFinder = UI_ELEMENT_FINDER_FACTORY.create(webDriver); + + LogInspector logInspector = new LogInspector(chromeDriver); + List logEntryList = new ArrayList<>(); + logInspector.onConsoleEntry(logEntryList::add); + + uiElementFinder.find(By.id("consoleLog")).click(); // --> working + uiElementFinder.find(By.id("consoleError")).click(); // --> working + uiElementFinder.find(By.id("jsException")).click(); // --> not working + uiElementFinder.find(By.id("logWithStacktrace")).click(); // --> not working + + for (ConsoleLogEntry logEntry : logEntryList) { + System.out.println(String.format("LOG_ENTRY: %s %s %s - %s", logEntry.getTimestamp(), logEntry.getLevel(), logEntry.getMethod(), logEntry.getText())); + } + ASSERT.assertEquals(logEntryList.size(), 2, "LogEntry list"); + } + + @Test + public void testT04_ListenToConsoleLogWithAssert_LOCAL() throws MalformedURLException { + DesktopWebDriverRequest request = new DesktopWebDriverRequest(); + request.setBrowser(Browsers.chrome); + request.setBaseUrl("https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html"); + WebDriver webDriver = WEB_DRIVER_MANAGER.getWebDriver(request); + + ChromeDriver chromeDriver = WEB_DRIVER_MANAGER.unwrapWebDriver(webDriver, ChromeDriver.class).get(); + UiElementFinder uiElementFinder = UI_ELEMENT_FINDER_FACTORY.create(webDriver); + + LogInspector logInspector = new LogInspector(chromeDriver); + log().info("My main thread: {}", Thread.currentThread().getName()); + logInspector.onConsoleEntry(logEntry -> { + log().info("LOG_ENTRY: {} {} {} - {}", logEntry.getTimestamp(), logEntry.getLevel(), logEntry.getMethod(), logEntry.getText()); + log().info("My listener thread: {}", Thread.currentThread().getName()); + ASSERT.assertNotEquals(logEntry.getLevel(), LogLevel.ERROR, "Log entry level"); + }); + + uiElementFinder.find(By.id("consoleLog")).click(); // --> working + uiElementFinder.find(By.id("consoleError")).click(); // --> working + uiElementFinder.find(By.id("jsException")).click(); // --> not working + uiElementFinder.find(By.id("logWithStacktrace")).click(); // --> not working + } + + @Test + public void testT04_ListenToConsoleLogWithList_REMOTE() throws MalformedURLException, ExecutionException, InterruptedException, TimeoutException { +// DesktopWebDriverRequest request = new DesktopWebDriverRequest(); +// request.setBrowser(Browsers.chrome); +// request.setServerUrl("http://localhost:4444/wd/hub"); +// request.setBaseUrl("https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html"); +// WebDriver webDriver = WEB_DRIVER_MANAGER.getWebDriver(request); + WebDriver webDriver = WEB_DRIVER_MANAGER.getWebDriver(); + RemoteWebDriver remoteWebDriver = WEB_DRIVER_MANAGER.unwrapWebDriver(webDriver, RemoteWebDriver.class).get(); +// UiElementFinder uiElementFinder = UI_ELEMENT_FINDER_FACTORY.create(webDriver); + + LogInspector logInspector = new LogInspector(remoteWebDriver); + +// CompletableFuture future = new CompletableFuture<>(); + List logs = new ArrayList<>(); + logInspector.onConsoleEntry(logs::add); + + TestStep.begin("clicks"); + log().info("Vor click"); +// uiElementFinder.find(By.id("consoleLog")).click(); + log().info("Nach click"); +// uiElementFinder.find(By.id("consoleError")).click(); + // Exception behandeln, ohne get() aufzurufen + + TestStep.begin("nach allem"); + log().info("Foo bar"); + +// ConsoleLogEntry logEntry = future.get(5, TimeUnit.SECONDS); +// log().info(logEntry.getText()); +// ASSERT.assertTrue(logEntry.getText().contains("Hello, world!")); + // Cause that exception are thrown to current main thread +// CompletableFuture.allOf(future).join(); + } + +} From 56fbc06a1446d6c8f7c68194f428c9a5a0152500 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Gro=C3=9Fmann?= Date: Tue, 27 Jun 2023 13:02:31 +0200 Subject: [PATCH 44/64] Typo --- .../mms/tic/testframework/playground/ChromeDevToolsTests.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/integration-tests/src/test/java/eu/tsystems/mms/tic/testframework/playground/ChromeDevToolsTests.java b/integration-tests/src/test/java/eu/tsystems/mms/tic/testframework/playground/ChromeDevToolsTests.java index 29f69fccb5..1eea957426 100644 --- a/integration-tests/src/test/java/eu/tsystems/mms/tic/testframework/playground/ChromeDevToolsTests.java +++ b/integration-tests/src/test/java/eu/tsystems/mms/tic/testframework/playground/ChromeDevToolsTests.java @@ -245,7 +245,7 @@ public void testT08_LogListenerBrokenImages() throws MalformedURLException { List logEntries = new ArrayList<>(); Consumer addedLog = logEntries::add; - // Consumer is running in another thread... Asserts do not have impact to main thread + // Consumer is running in another thread... Asserts does not have impact to main thread devTools.addListener(Log.entryAdded(), addedLog); webDriver.get("http://the-internet.herokuapp.com/broken_images"); From a2bbac11d76ba790d00f28258db921ecb69eeaa7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Gro=C3=9Fmann?= Date: Wed, 28 Jun 2023 07:54:16 +0200 Subject: [PATCH 45/64] Added note for not executable test --- .../test/pagefactory/CheckPageTest.java | 20 +++++++------------ 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/integration-tests/src/test/java/eu/tsystems/mms/tic/testframework/test/pagefactory/CheckPageTest.java b/integration-tests/src/test/java/eu/tsystems/mms/tic/testframework/test/pagefactory/CheckPageTest.java index 78ae3f59b7..f090deefc5 100644 --- a/integration-tests/src/test/java/eu/tsystems/mms/tic/testframework/test/pagefactory/CheckPageTest.java +++ b/integration-tests/src/test/java/eu/tsystems/mms/tic/testframework/test/pagefactory/CheckPageTest.java @@ -22,14 +22,11 @@ package eu.tsystems.mms.tic.testframework.test.pagefactory; import eu.tsystems.mms.tic.testframework.AbstractTestSitesTest; -import eu.tsystems.mms.tic.testframework.annotations.Fails; -import eu.tsystems.mms.tic.testframework.common.Testerra; import eu.tsystems.mms.tic.testframework.core.pageobjects.testdata.PageWithCheckRuleIsDisplayed; import eu.tsystems.mms.tic.testframework.core.pageobjects.testdata.PageWithCheckRuleIsNotDisplayed; import eu.tsystems.mms.tic.testframework.core.pageobjects.testdata.PageWithCheckRuleIsNotPresent; import eu.tsystems.mms.tic.testframework.core.pageobjects.testdata.PageWithCheckRuleIsPresent; import eu.tsystems.mms.tic.testframework.core.pageobjects.testdata.PageWithCollectedAndOptionalElement; -import eu.tsystems.mms.tic.testframework.core.pageobjects.testdata.PageWithCollectedElement; import eu.tsystems.mms.tic.testframework.core.pageobjects.testdata.PageWithExistingElement; import eu.tsystems.mms.tic.testframework.core.pageobjects.testdata.PageWithExistingStaticElement; import eu.tsystems.mms.tic.testframework.core.pageobjects.testdata.PageWithNonCheckableCheck; @@ -37,19 +34,9 @@ import eu.tsystems.mms.tic.testframework.core.pageobjects.testdata.PageWithNullElement; import eu.tsystems.mms.tic.testframework.core.pageobjects.testdata.PageWithOptionalElement; import eu.tsystems.mms.tic.testframework.exceptions.PageFactoryException; -import eu.tsystems.mms.tic.testframework.report.model.context.ClassContext; -import eu.tsystems.mms.tic.testframework.report.model.context.ErrorContext; -import eu.tsystems.mms.tic.testframework.report.model.context.MethodContext; -import eu.tsystems.mms.tic.testframework.report.utils.IExecutionContextController; import eu.tsystems.mms.tic.testframework.testing.PageFactoryProvider; -import org.testng.Assert; import org.testng.annotations.Test; -import java.util.List; -import java.util.Optional; -import java.util.stream.Collectors; -import java.util.stream.Stream; - public class CheckPageTest extends AbstractTestSitesTest implements PageFactoryProvider { @Test @@ -102,6 +89,13 @@ public void testT10_checkOptionalElement_IsNotPresent() { PAGE_FACTORY.createPage(PageWithOptionalElement.class, getClassExclusiveWebDriver()); } + // Cannot checked with 'expectedException' because TestNG test result is changed by Testerra + // {@link eu.tsystems.mms.tic.testframework.execution.testng.worker.finish.MethodContextUpdateWorker} +// @Test(expectedExceptions = UiElementAssertionError.class) +// public void testT11_checkCollectedElement() { +// PAGE_FACTORY.createPage(PageWithCollectedElement.class, getClassExclusiveWebDriver()); +// } + @Test public void testT12_checkCollectedAndOptionalElements_IsNotPresent() { // The used page is bad practice, but possible: From b47703ab4af59d5531d19209e45d14e857b5cdae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Gro=C3=9Fmann?= Date: Tue, 4 Jul 2023 13:37:01 +0200 Subject: [PATCH 46/64] Updated playground tests --- .../playground/ChromeDevToolsTests.java | 97 ++++++++++++++----- 1 file changed, 73 insertions(+), 24 deletions(-) diff --git a/integration-tests/src/test/java/eu/tsystems/mms/tic/testframework/playground/ChromeDevToolsTests.java b/integration-tests/src/test/java/eu/tsystems/mms/tic/testframework/playground/ChromeDevToolsTests.java index 1eea957426..72223cc3c3 100644 --- a/integration-tests/src/test/java/eu/tsystems/mms/tic/testframework/playground/ChromeDevToolsTests.java +++ b/integration-tests/src/test/java/eu/tsystems/mms/tic/testframework/playground/ChromeDevToolsTests.java @@ -24,21 +24,23 @@ import eu.tsystems.mms.tic.testframework.constants.Browsers; import eu.tsystems.mms.tic.testframework.pageobjects.UiElementFinder; import eu.tsystems.mms.tic.testframework.testing.ChromeDevToolsProvider; +import eu.tsystems.mms.tic.testframework.utils.TimerUtils; import eu.tsystems.mms.tic.testframework.webdrivermanager.DesktopWebDriverRequest; import org.openqa.selenium.By; import org.openqa.selenium.HasAuthentication; +import org.openqa.selenium.JavascriptException; import org.openqa.selenium.UsernameAndPassword; import org.openqa.selenium.WebDriver; import org.openqa.selenium.chrome.ChromeDriver; import org.openqa.selenium.devtools.DevTools; import org.openqa.selenium.devtools.HasDevTools; +import org.openqa.selenium.devtools.events.ConsoleEvent; import org.openqa.selenium.devtools.v112.emulation.Emulation; import org.openqa.selenium.devtools.v114.log.Log; import org.openqa.selenium.devtools.v114.log.model.LogEntry; import org.openqa.selenium.devtools.v85.runtime.Runtime; import org.openqa.selenium.remote.Augmenter; import org.openqa.selenium.remote.RemoteWebDriver; -import org.testng.Assert; import org.testng.annotations.Test; import java.net.MalformedURLException; @@ -211,30 +213,33 @@ public void testT06_BasicAuth_ChromeBiDiAPI() { uiElementFinder.find(By.tagName("p")).assertThat().text().isContaining("Congratulations"); } - @Test - public void testT07_LogListener() throws MalformedURLException { - DesktopWebDriverRequest request = new DesktopWebDriverRequest(); - request.setBaseUrl("https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html"); - WebDriver webDriver = WEB_DRIVER_MANAGER.getWebDriver(request); - DevTools rawDevTools = CHROME_DEV_TOOLS.getRawDevTools(webDriver); - - rawDevTools.send(Runtime.enable()); - rawDevTools.send(Log.enable()); - rawDevTools.addListener(Log.entryAdded(), - entry -> { - log().info("{} - {}: {}", entry.getTimestamp(), entry.getLevel().toString().toUpperCase(), entry.getText()); - System.out.println(entry.getText()); - }); - - UiElementFinder uiElementFinder = UI_ELEMENT_FINDER_FACTORY.create(webDriver); - uiElementFinder.find(By.id("consoleLog")).click(); - uiElementFinder.find(By.id("consoleError")).click(); - - } +// @Test +// public void testT07_LogListener() throws MalformedURLException { +// DesktopWebDriverRequest request = new DesktopWebDriverRequest(); +// request.setBaseUrl("https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html"); +// WebDriver webDriver = WEB_DRIVER_MANAGER.getWebDriver(request); +// DevTools rawDevTools = CHROME_DEV_TOOLS.getRawDevTools(webDriver); +// +// rawDevTools.send(Runtime.enable()); +// rawDevTools.send(Log.enable()); +// rawDevTools.addListener(Log.entryAdded(), +// entry -> { +// log().info("{} - {}: {}", entry.getTimestamp(), entry.getLevel().toString().toUpperCase(), entry.getText()); +// System.out.println(entry.getText()); +// }); +// +// UiElementFinder uiElementFinder = UI_ELEMENT_FINDER_FACTORY.create(webDriver); +// uiElementFinder.find(By.id("consoleLog")).click(); +// uiElementFinder.find(By.id("consoleError")).click(); +// +// } + // + // The following tests demonstrate Browser console listener + // @Test - public void testT08_LogListenerBrokenImages() throws MalformedURLException { + public void testT08_LogListener_BrokenImages() throws MalformedURLException { DesktopWebDriverRequest request = new DesktopWebDriverRequest(); // request.setBaseUrl("https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html"); WebDriver webDriver = WEB_DRIVER_MANAGER.getWebDriver(request); @@ -248,12 +253,56 @@ public void testT08_LogListenerBrokenImages() throws MalformedURLException { // Consumer is running in another thread... Asserts does not have impact to main thread devTools.addListener(Log.entryAdded(), addedLog); webDriver.get("http://the-internet.herokuapp.com/broken_images"); - + TimerUtils.sleep(1000); // Short wait to get delayed logs for (LogEntry logEntry : logEntries) { - System.out.println(String.format("LOG_ENTRY: %s %s %s - %s (%s)", logEntry.getTimestamp(), logEntry.getLevel(), logEntry.getSource(), logEntry.getText(), logEntry.getUrl())); log().info("LOG_ENTRY: {} {} {} - {} ({})", logEntry.getTimestamp(), logEntry.getLevel(), logEntry.getSource(), logEntry.getText(), logEntry.getUrl()); ASSERT.assertFalse(logEntry.getText().contains("404")); } } + @Test + public void testT10_LogListener_JsLogs() throws MalformedURLException { + DesktopWebDriverRequest request = new DesktopWebDriverRequest(); + request.setBaseUrl("https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html"); + WebDriver webDriver = WEB_DRIVER_MANAGER.getWebDriver(request); + DevTools devTools = CHROME_DEV_TOOLS.getRawDevTools(webDriver); + + List consoleEvents = new ArrayList<>(); + Consumer addEntry = consoleEvents::add; + devTools.getDomains().events().addConsoleListener(addEntry); + + UiElementFinder uiElementFinder = UI_ELEMENT_FINDER_FACTORY.create(webDriver); + uiElementFinder.find(By.id("consoleLog")).click(); // --> working + uiElementFinder.find(By.id("consoleError")).click(); // --> working + uiElementFinder.find(By.id("jsException")).click(); // --> not working + uiElementFinder.find(By.id("logWithStacktrace")).click(); // --> not working + + for (ConsoleEvent event : consoleEvents) { + log().info("Console: {} {} - {}", event.getTimestamp(), event.getType(), event.getMessages().toString()); + } + } + + @Test + public void testT10_LogListener_JsExceptions() throws MalformedURLException { + DesktopWebDriverRequest request = new DesktopWebDriverRequest(); + request.setBaseUrl("https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html"); + WebDriver webDriver = WEB_DRIVER_MANAGER.getWebDriver(request); + DevTools devTools = CHROME_DEV_TOOLS.getRawDevTools(webDriver); + + List jsExceptionsList = new ArrayList<>(); + Consumer addEntry = jsExceptionsList::add; + devTools.getDomains().events().addJavascriptExceptionListener(addEntry); + + UiElementFinder uiElementFinder = UI_ELEMENT_FINDER_FACTORY.create(webDriver); + uiElementFinder.find(By.id("consoleLog")).click(); // --> not working + uiElementFinder.find(By.id("consoleError")).click(); // --> not working + uiElementFinder.find(By.id("jsException")).click(); // --> working + uiElementFinder.find(By.id("logWithStacktrace")).click(); // --> working + + for (JavascriptException jsException : jsExceptionsList) { + log().info("JS_EXCEPTION: {} {}", jsException.getMessage(), jsException.getSystemInformation()); + } + } + + } From 63256fff5b4fc78f57d14e11f1aae47316266d3a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Gro=C3=9Fmann?= Date: Tue, 4 Jul 2023 13:38:34 +0200 Subject: [PATCH 47/64] Updated playground tests --- .../tic/testframework/playground/ChromeDevToolsTests.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/integration-tests/src/test/java/eu/tsystems/mms/tic/testframework/playground/ChromeDevToolsTests.java b/integration-tests/src/test/java/eu/tsystems/mms/tic/testframework/playground/ChromeDevToolsTests.java index 72223cc3c3..78298dae41 100644 --- a/integration-tests/src/test/java/eu/tsystems/mms/tic/testframework/playground/ChromeDevToolsTests.java +++ b/integration-tests/src/test/java/eu/tsystems/mms/tic/testframework/playground/ChromeDevToolsTests.java @@ -239,7 +239,7 @@ public void testT06_BasicAuth_ChromeBiDiAPI() { // @Test - public void testT08_LogListener_BrokenImages() throws MalformedURLException { + public void testT10_LogListener_BrokenImages() throws MalformedURLException { DesktopWebDriverRequest request = new DesktopWebDriverRequest(); // request.setBaseUrl("https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html"); WebDriver webDriver = WEB_DRIVER_MANAGER.getWebDriver(request); @@ -261,7 +261,7 @@ public void testT08_LogListener_BrokenImages() throws MalformedURLException { } @Test - public void testT10_LogListener_JsLogs() throws MalformedURLException { + public void testT11_LogListener_JsLogs() throws MalformedURLException { DesktopWebDriverRequest request = new DesktopWebDriverRequest(); request.setBaseUrl("https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html"); WebDriver webDriver = WEB_DRIVER_MANAGER.getWebDriver(request); @@ -278,12 +278,12 @@ public void testT10_LogListener_JsLogs() throws MalformedURLException { uiElementFinder.find(By.id("logWithStacktrace")).click(); // --> not working for (ConsoleEvent event : consoleEvents) { - log().info("Console: {} {} - {}", event.getTimestamp(), event.getType(), event.getMessages().toString()); + log().info("JS_LOGS: {} {} - {}", event.getTimestamp(), event.getType(), event.getMessages().toString()); } } @Test - public void testT10_LogListener_JsExceptions() throws MalformedURLException { + public void testT12_LogListener_JsExceptions() throws MalformedURLException { DesktopWebDriverRequest request = new DesktopWebDriverRequest(); request.setBaseUrl("https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html"); WebDriver webDriver = WEB_DRIVER_MANAGER.getWebDriver(request); From a7b6eb0fec850d9d6e227e3846802ab1df5bf44f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Gro=C3=9Fmann?= Date: Tue, 11 Jul 2023 17:35:10 +0200 Subject: [PATCH 48/64] Changed basic authentication to Network API --- .../testing/SeleniumChromeDevTools.java | 60 ++++++++----------- .../playground/ChromeDevToolsTests.java | 28 ++++++++- 2 files changed, 49 insertions(+), 39 deletions(-) diff --git a/driver-ui/src/main/java/eu/tsystems/mms/tic/testframework/testing/SeleniumChromeDevTools.java b/driver-ui/src/main/java/eu/tsystems/mms/tic/testframework/testing/SeleniumChromeDevTools.java index 521c750394..9d233a9d01 100644 --- a/driver-ui/src/main/java/eu/tsystems/mms/tic/testframework/testing/SeleniumChromeDevTools.java +++ b/driver-ui/src/main/java/eu/tsystems/mms/tic/testframework/testing/SeleniumChromeDevTools.java @@ -21,24 +21,24 @@ package eu.tsystems.mms.tic.testframework.testing; import eu.tsystems.mms.tic.testframework.logging.Loggable; -import eu.tsystems.mms.tic.testframework.report.model.context.SessionContext; import eu.tsystems.mms.tic.testframework.webdrivermanager.ChromeDevTools; -import eu.tsystems.mms.tic.testframework.webdrivermanager.DesktopWebDriverRequest; import org.openqa.selenium.Credentials; -import org.openqa.selenium.HasAuthentication; +import org.openqa.selenium.UsernameAndPassword; import org.openqa.selenium.WebDriver; import org.openqa.selenium.chrome.ChromeDriver; import org.openqa.selenium.devtools.DevTools; import org.openqa.selenium.devtools.HasDevTools; import org.openqa.selenium.devtools.v112.emulation.Emulation; +import org.openqa.selenium.devtools.v112.network.Network; +import org.openqa.selenium.devtools.v112.network.model.Headers; import org.openqa.selenium.remote.Augmenter; import org.openqa.selenium.remote.RemoteWebDriver; -import java.net.URI; -import java.net.URL; +import java.io.UnsupportedEncodingException; +import java.util.Base64; +import java.util.HashMap; +import java.util.Map; import java.util.Optional; -import java.util.concurrent.atomic.AtomicReference; -import java.util.function.Predicate; import java.util.function.Supplier; /** @@ -94,37 +94,25 @@ public void setBasicAuthentication(WebDriver webDriver, Supplier cr if (!isSupported(webDriver)) { throw new RuntimeException("The current browser does not support DevTools"); } - if (isRemoteDriver(webDriver)) { - WebDriver remoteWebDriver = WEB_DRIVER_MANAGER.unwrapWebDriver(webDriver, RemoteWebDriver.class).get(); - AtomicReference devToolsAtomicReference = new AtomicReference<>(); - remoteWebDriver = new Augmenter() - .addDriverAugmentation( - "chrome", - HasAuthentication.class, - (caps, exec) -> (whenThisMatches, useTheseCredentials) -> { - devToolsAtomicReference.get().createSessionIfThereIsNotOne(); - devToolsAtomicReference.get().getDomains() - .network() - .addAuthHandler(whenThisMatches, useTheseCredentials); - }) - .augment(remoteWebDriver); - DevTools devTools = ((HasDevTools) remoteWebDriver).getDevTools(); - devTools.createSession(); - devToolsAtomicReference.set(devTools); - ((HasAuthentication) remoteWebDriver).register(credentials); - } else { - DesktopWebDriverRequest webDriverRequest = (DesktopWebDriverRequest) WEB_DRIVER_MANAGER.getSessionContext(webDriver) - .map(SessionContext::getWebDriverRequest) - .orElse(null); - if (webDriverRequest == null) { - throw new RuntimeException("Cannot get WebdriverRequest from SessionContext"); + DevTools devTools = this.getRawDevTools(webDriver); + + try { + Map headers = new HashMap<>(); + byte[] authByteArray = "".getBytes(); + + if (credentials.get() instanceof UsernameAndPassword) { + UsernameAndPassword usernameAndPassword = (UsernameAndPassword) credentials.get(); + authByteArray = String.format("%s:%s", usernameAndPassword.username(), usernameAndPassword.password()).getBytes("UTF-8"); + } else { + throw new RuntimeException("Unsupported type of Credentials"); } - String baseUrlHost = webDriverRequest.getBaseUrl().map(URL::getHost).orElse(""); - Predicate uriPredicate = uri -> uri.getHost().contains(baseUrlHost); - ChromeDriver chromeDriver = WEB_DRIVER_MANAGER.unwrapWebDriver(webDriver, ChromeDriver.class).get(); - ((HasAuthentication) chromeDriver).register(uriPredicate, credentials); - } + headers.put("authorization", "Basic " + Base64.getEncoder().encodeToString(authByteArray)); + devTools.send(Network.enable(Optional.empty(), Optional.empty(), Optional.empty())); + devTools.send(Network.setExtraHTTPHeaders(new Headers(headers))); + } catch (UnsupportedEncodingException e) { + throw new RuntimeException("Cannot set basic authentication", e); + } } diff --git a/integration-tests/src/test/java/eu/tsystems/mms/tic/testframework/playground/ChromeDevToolsTests.java b/integration-tests/src/test/java/eu/tsystems/mms/tic/testframework/playground/ChromeDevToolsTests.java index 78298dae41..7453aa056a 100644 --- a/integration-tests/src/test/java/eu/tsystems/mms/tic/testframework/playground/ChromeDevToolsTests.java +++ b/integration-tests/src/test/java/eu/tsystems/mms/tic/testframework/playground/ChromeDevToolsTests.java @@ -36,9 +36,11 @@ import org.openqa.selenium.devtools.HasDevTools; import org.openqa.selenium.devtools.events.ConsoleEvent; import org.openqa.selenium.devtools.v112.emulation.Emulation; +import org.openqa.selenium.devtools.v112.network.Network; +import org.openqa.selenium.devtools.v112.network.model.RequestWillBeSent; +import org.openqa.selenium.devtools.v112.network.model.ResponseReceived; import org.openqa.selenium.devtools.v114.log.Log; import org.openqa.selenium.devtools.v114.log.model.LogEntry; -import org.openqa.selenium.devtools.v85.runtime.Runtime; import org.openqa.selenium.remote.Augmenter; import org.openqa.selenium.remote.RemoteWebDriver; import org.testng.annotations.Test; @@ -181,7 +183,6 @@ public void testT04_BasicAuth_remoteDriver() { public void testT05_BasicAuth_DevTools() { DesktopWebDriverRequest request = new DesktopWebDriverRequest(); request.setBrowser(Browsers.chrome); -// request.setBrowserVersion("106"); WebDriver webDriver = WEB_DRIVER_MANAGER.getWebDriver(request); UiElementFinder uiElementFinder = UI_ELEMENT_FINDER_FACTORY.create(webDriver); @@ -189,7 +190,6 @@ public void testT05_BasicAuth_DevTools() { webDriver.get("https://the-internet.herokuapp.com/basic_auth"); uiElementFinder.find(By.tagName("p")).assertThat().text().isContaining("Congratulations"); - } /** @@ -304,5 +304,27 @@ public void testT12_LogListener_JsExceptions() throws MalformedURLException { } } + @Test + public void testT13_NetworkListener() { + WebDriver webDriver = WEB_DRIVER_MANAGER.getWebDriver(); + DevTools devTools = CHROME_DEV_TOOLS.getRawDevTools(webDriver); + + List responseReceivedList = new ArrayList<>(); + List requestList = new ArrayList<>(); + devTools.send(Network.enable(Optional.empty(), Optional.empty(), Optional.empty())); + + devTools.addListener(Network.responseReceived(), responseReceivedList::add); + devTools.addListener(Network.requestWillBeSent(), requestList::add); + + webDriver.get("https://the-internet.herokuapp.com/"); + + for (RequestWillBeSent request : requestList) { + log().info("Request: {} - {}", request.getRequestId().toString(), request.getRequest().getUrl()); + } + + for (ResponseReceived response : responseReceivedList) { + log().info("Response: {} - [{}] {}", response.getRequestId().toString(), response.getResponse().getStatus(), response.getResponse().getStatusText()); + } + } } From 9aeaab9609419aef06dc0632ecdd7e6a336fdf9d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Gro=C3=9Fmann?= Date: Tue, 11 Jul 2023 17:40:09 +0200 Subject: [PATCH 49/64] Updated comments --- .../playground/ChromeDevToolsTests.java | 25 +++---------------- 1 file changed, 4 insertions(+), 21 deletions(-) diff --git a/integration-tests/src/test/java/eu/tsystems/mms/tic/testframework/playground/ChromeDevToolsTests.java b/integration-tests/src/test/java/eu/tsystems/mms/tic/testframework/playground/ChromeDevToolsTests.java index 7453aa056a..33128bb02c 100644 --- a/integration-tests/src/test/java/eu/tsystems/mms/tic/testframework/playground/ChromeDevToolsTests.java +++ b/integration-tests/src/test/java/eu/tsystems/mms/tic/testframework/playground/ChromeDevToolsTests.java @@ -145,6 +145,10 @@ public void testT03_GeoLocation_generic() { uiElementFinder.find(By.id("longitude")).assertThat().text().isContaining(longitude.get().toString()); } + /** + * The following example set basic authentication via driver augumentation. This solution works only remote, not local. + * A more flexible solution is implemented in SeleniumChromeDevTools + */ @Test public void testT04_BasicAuth_remoteDriver() { DesktopWebDriverRequest request = new DesktopWebDriverRequest(); @@ -213,27 +217,6 @@ public void testT06_BasicAuth_ChromeBiDiAPI() { uiElementFinder.find(By.tagName("p")).assertThat().text().isContaining("Congratulations"); } -// @Test -// public void testT07_LogListener() throws MalformedURLException { -// DesktopWebDriverRequest request = new DesktopWebDriverRequest(); -// request.setBaseUrl("https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html"); -// WebDriver webDriver = WEB_DRIVER_MANAGER.getWebDriver(request); -// DevTools rawDevTools = CHROME_DEV_TOOLS.getRawDevTools(webDriver); -// -// rawDevTools.send(Runtime.enable()); -// rawDevTools.send(Log.enable()); -// rawDevTools.addListener(Log.entryAdded(), -// entry -> { -// log().info("{} - {}: {}", entry.getTimestamp(), entry.getLevel().toString().toUpperCase(), entry.getText()); -// System.out.println(entry.getText()); -// }); -// -// UiElementFinder uiElementFinder = UI_ELEMENT_FINDER_FACTORY.create(webDriver); -// uiElementFinder.find(By.id("consoleLog")).click(); -// uiElementFinder.find(By.id("consoleError")).click(); -// -// } - // // The following tests demonstrate Browser console listener // From 0917a56358329bc260952e869ccfe1ecc6e782ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Gro=C3=9Fmann?= Date: Wed, 12 Jul 2023 16:00:56 +0200 Subject: [PATCH 50/64] Added Selenium 4 docs --- docs/src/docs/index.adoc | 1 + docs/src/docs/selenium4.adoc | 5 ++ docs/src/docs/selenium4/selenium4-cdp.adoc | 1 + .../src/docs/selenium4/selenium4-changes.adoc | 20 +++++++ docs/src/docs/selenium4/selenium4-common.adoc | 5 ++ .../DesktopWebDriverFactory.java | 10 +--- .../AbstractWebDriverRequest.java | 6 ++ .../playground/Selenium4_vs_3_Tests.java | 59 +++++++++++++++++++ 8 files changed, 99 insertions(+), 8 deletions(-) create mode 100644 docs/src/docs/selenium4.adoc create mode 100644 docs/src/docs/selenium4/selenium4-cdp.adoc create mode 100644 docs/src/docs/selenium4/selenium4-changes.adoc create mode 100644 docs/src/docs/selenium4/selenium4-common.adoc create mode 100644 integration-tests/src/test/java/eu/tsystems/mms/tic/testframework/playground/Selenium4_vs_3_Tests.java diff --git a/docs/src/docs/index.adoc b/docs/src/docs/index.adoc index 0070172313..952f868bc8 100644 --- a/docs/src/docs/index.adoc +++ b/docs/src/docs/index.adoc @@ -31,6 +31,7 @@ include::execution.adoc[leveloffset=+1] include::reports.adoc[leveloffset=+1] include::modules.adoc[leveloffset=+1] include::utilities.adoc[leveloffset=+1] +include::selenium4.adoc[leveloffset=+1] ''' = Extending Testerra diff --git a/docs/src/docs/selenium4.adoc b/docs/src/docs/selenium4.adoc new file mode 100644 index 0000000000..e16b8256d8 --- /dev/null +++ b/docs/src/docs/selenium4.adoc @@ -0,0 +1,5 @@ += Selenium 4 + +include::selenium4/selenium4-common.adoc[leveloffset=+1] +include::selenium4/selenium4-changes.adoc[leveloffset=+1] +include::selenium4/selenium4-cdp.adoc[leveloffset=+1] diff --git a/docs/src/docs/selenium4/selenium4-cdp.adoc b/docs/src/docs/selenium4/selenium4-cdp.adoc new file mode 100644 index 0000000000..de671c1707 --- /dev/null +++ b/docs/src/docs/selenium4/selenium4-cdp.adoc @@ -0,0 +1 @@ += Support of Chrome developer toos (CDP) diff --git a/docs/src/docs/selenium4/selenium4-changes.adoc b/docs/src/docs/selenium4/selenium4-changes.adoc new file mode 100644 index 0000000000..3adb19ca62 --- /dev/null +++ b/docs/src/docs/selenium4/selenium4-changes.adoc @@ -0,0 +1,20 @@ += Important changes + +The Selenium devs provide a short https://www.selenium.dev/documentation/webdriver/getting_started/upgrade_to_selenium_4/[migration guide] for Selenium 4 (). + +The following subsections describes how the changes affect Testerra. + +== Custom capabilities + +Any capability that not in the standard of https://www.w3.org/TR/webdriver1/#capabilities[W3C] needs a vendor prefix. + + + +== Global capabilities + +== Browser version + +Be aware of using a browser version if you execute your test against a standalone Selenium 4 server. This is running as a local grid which knows nothing about any local browser versions. + +Your test will run into a timeout! + diff --git a/docs/src/docs/selenium4/selenium4-common.adoc b/docs/src/docs/selenium4/selenium4-common.adoc new file mode 100644 index 0000000000..124ad85039 --- /dev/null +++ b/docs/src/docs/selenium4/selenium4-common.adoc @@ -0,0 +1,5 @@ += Testerra and Selenium 4 + +Since version 2.4 Testerra includes Selenium 4. It brings some new features like support of Chrome developer tools, but also some breaking changes. + + diff --git a/driver-ui-desktop/src/main/java/eu/tsystems/mms/tic/testframework/webdrivermanager/DesktopWebDriverFactory.java b/driver-ui-desktop/src/main/java/eu/tsystems/mms/tic/testframework/webdrivermanager/DesktopWebDriverFactory.java index 29992ba853..adc4735031 100644 --- a/driver-ui-desktop/src/main/java/eu/tsystems/mms/tic/testframework/webdrivermanager/DesktopWebDriverFactory.java +++ b/driver-ui-desktop/src/main/java/eu/tsystems/mms/tic/testframework/webdrivermanager/DesktopWebDriverFactory.java @@ -42,6 +42,7 @@ import eu.tsystems.mms.tic.testframework.webdriver.WebDriverFactory; import org.openqa.selenium.Capabilities; import org.openqa.selenium.Dimension; +import org.openqa.selenium.MutableCapabilities; import org.openqa.selenium.Point; import org.openqa.selenium.WebDriver; import org.openqa.selenium.chrome.ChromeDriver; @@ -53,7 +54,6 @@ import org.openqa.selenium.ie.InternetExplorerDriver; import org.openqa.selenium.ie.InternetExplorerOptions; import org.openqa.selenium.remote.AbstractDriverOptions; -import org.openqa.selenium.remote.DesiredCapabilities; import org.openqa.selenium.remote.LocalFileDetector; import org.openqa.selenium.remote.RemoteWebDriver; import org.openqa.selenium.safari.SafariDriver; @@ -143,18 +143,12 @@ public WebDriverRequest prepareWebDriverRequest(WebDriverRequest webDriverReques case Browsers.chrome: case Browsers.chromeHeadless: ChromeOptions chromeOptions = new ChromeOptions(); -// if (capabilities.getCapabilityNames().contains(ChromeOptions.CAPABILITY)) { -// final TreeMap predefinedChromeOptions = (TreeMap) capabilities.getCapability(ChromeOptions.CAPABILITY); -// predefinedChromeOptions.forEach((s, o) -> chromeOptions.setCapability(s.toString(), o)); -// } - WEB_DRIVER_MANAGER.getUserAgentConfig(browser).ifPresent(userAgentConfig -> { userAgentConfig.configure(chromeOptions); }); - chromeOptions.addArguments("--no-sandbox"); if (browser.equals(Browsers.chromeHeadless)) { - chromeOptions.setHeadless(true); + chromeOptions.addArguments("--headless"); } userAgentCapabilities = chromeOptions; break; diff --git a/driver-ui/src/main/java/eu/tsystems/mms/tic/testframework/webdrivermanager/AbstractWebDriverRequest.java b/driver-ui/src/main/java/eu/tsystems/mms/tic/testframework/webdrivermanager/AbstractWebDriverRequest.java index debae44e58..5915fd7cf5 100644 --- a/driver-ui/src/main/java/eu/tsystems/mms/tic/testframework/webdrivermanager/AbstractWebDriverRequest.java +++ b/driver-ui/src/main/java/eu/tsystems/mms/tic/testframework/webdrivermanager/AbstractWebDriverRequest.java @@ -40,6 +40,7 @@ public class AbstractWebDriverRequest implements WebDriverRequest, Loggable { private String sessionKey = DEFAULT_SESSION_KEY; private URL serverUrl; + @Deprecated private DesiredCapabilities desiredCapabilities; private Capabilities capabilities; @@ -147,6 +148,11 @@ public void setSessionKey(String sessionKey) { this.sessionKey = sessionKey; } + /** + * + * @deprecated Use {@link #getMutableCapabilities()} instead + */ + @Deprecated public DesiredCapabilities getDesiredCapabilities() { if (this.desiredCapabilities == null) { this.desiredCapabilities = new DesiredCapabilities(); diff --git a/integration-tests/src/test/java/eu/tsystems/mms/tic/testframework/playground/Selenium4_vs_3_Tests.java b/integration-tests/src/test/java/eu/tsystems/mms/tic/testframework/playground/Selenium4_vs_3_Tests.java new file mode 100644 index 0000000000..660b3d3aed --- /dev/null +++ b/integration-tests/src/test/java/eu/tsystems/mms/tic/testframework/playground/Selenium4_vs_3_Tests.java @@ -0,0 +1,59 @@ +package eu.tsystems.mms.tic.testframework.playground; + +import eu.tsystems.mms.tic.testframework.AbstractWebDriverTest; +import eu.tsystems.mms.tic.testframework.constants.Browsers; +import eu.tsystems.mms.tic.testframework.webdrivermanager.DesktopWebDriverRequest; +import org.openqa.selenium.MutableCapabilities; +import org.openqa.selenium.WebDriver; +import org.openqa.selenium.remote.DesiredCapabilities; +import org.testng.annotations.Test; + +import java.net.MalformedURLException; +import java.util.HashMap; +import java.util.Map; + +/** + * Created on 2023-07-11 + * + * @author mgn + */ +public class Selenium4_vs_3_Tests extends AbstractWebDriverTest { + + /** + * This test will pass if a Selenium 3 standalone server is used. + * This test will fail (or go into a timeout) if a Selenium 4 standalone server is used. + * Cause: + * Selenium 4 standalone server knows nothing about any version of local browsers. + */ + @Test + public void testBrowserVersionAgainstSeleniumStandalone() throws MalformedURLException { + DesktopWebDriverRequest request = new DesktopWebDriverRequest(); + request.setBrowser(Browsers.chrome); + request.setBrowserVersion("110"); + request.setBaseUrl("https://the-internet.herokuapp.com/"); + + WebDriver webDriver = WEB_DRIVER_MANAGER.getWebDriver(request); + } + + @Test + public void testBrowserCustomCaps_Selenium3() { + DesktopWebDriverRequest request = new DesktopWebDriverRequest(); + DesiredCapabilities desiredCapabilities = request.getDesiredCapabilities(); + desiredCapabilities.setCapability("foo", "bar"); + + WEB_DRIVER_MANAGER.getWebDriver(request); + } + +// @Test +// public void testBrowserCustomCaps_Selenium4() { +// DesktopWebDriverRequest request = new DesktopWebDriverRequest(); +// MutableCapabilities caps = new MutableCapabilities(); +// caps.setCapability("foo", "bar"); +// +// request.getCapabilities() +// request.getBrowserOptions().merge(caps); +// +// WEB_DRIVER_MANAGER.getWebDriver(request); +// } + +} From 77170f684678f074fb52a85be183ff1fa6f7471a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Gro=C3=9Fmann?= Date: Wed, 12 Jul 2023 18:32:56 +0200 Subject: [PATCH 51/64] Set DesiredCapabilities as deprecated --- core/build.gradle | 8 ++-- .../webdrivermanager/WebDriverRequest.java | 6 ++- .../DesktopWebDriverFactory.java | 20 ++++---- driver-ui/build.gradle | 4 -- .../AbstractWebDriverRequest.java | 48 +++++++++++-------- .../SeleniumWebDriverRequest.java | 7 ++- .../WebDriverCapabilities.java | 21 ++++---- .../playground/DriverAndGuiElementTest.java | 2 +- .../playground/Selenium4_vs_3_Tests.java | 22 ++++----- .../DesktopWebDriverFactoryTest.java | 10 ++-- 10 files changed, 75 insertions(+), 73 deletions(-) diff --git a/core/build.gradle b/core/build.gradle index 7a23695045..abb03a8b65 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -29,10 +29,10 @@ dependencies { implementation 'com.opencsv:opencsv:3.9' // - // - // Comes already implicit from reflections - // implementation 'org.javassist:javassist:3.20.0-GA' - // + + // Selenium 4.6 comes with 'io.netty:netty-transport-native-epoll:4.1.84.Final' + // -> Dependency error Could not find netty-transport-native-epoll-4.1.84.Final-linux-x86_64.jar (io.netty:netty-transport-native-epoll:4.1.84.Final). + api 'org.seleniumhq.selenium:selenium-java:' + seleniumVersion api('org.testng:testng:7.6.1') // { diff --git a/core/src/main/java/eu/tsystems/mms/tic/testframework/webdrivermanager/WebDriverRequest.java b/core/src/main/java/eu/tsystems/mms/tic/testframework/webdrivermanager/WebDriverRequest.java index 4a4e974d41..c3ca84b0a3 100644 --- a/core/src/main/java/eu/tsystems/mms/tic/testframework/webdrivermanager/WebDriverRequest.java +++ b/core/src/main/java/eu/tsystems/mms/tic/testframework/webdrivermanager/WebDriverRequest.java @@ -1,5 +1,7 @@ package eu.tsystems.mms.tic.testframework.webdrivermanager; +import org.openqa.selenium.Capabilities; + import java.net.URL; import java.util.Map; import java.util.Optional; @@ -9,8 +11,8 @@ public interface WebDriverRequest extends Cloneable { String getSessionKey(); String getBrowser(); String getBrowserVersion(); - Optional getPlatformName(); - Map getCapabilities(); + String getPlatformName(); + Capabilities getCapabilities(); boolean getShutdownAfterTest(); boolean getShutdownAfterTestFailed(); diff --git a/driver-ui-desktop/src/main/java/eu/tsystems/mms/tic/testframework/webdrivermanager/DesktopWebDriverFactory.java b/driver-ui-desktop/src/main/java/eu/tsystems/mms/tic/testframework/webdrivermanager/DesktopWebDriverFactory.java index adc4735031..74d220c4f3 100644 --- a/driver-ui-desktop/src/main/java/eu/tsystems/mms/tic/testframework/webdrivermanager/DesktopWebDriverFactory.java +++ b/driver-ui-desktop/src/main/java/eu/tsystems/mms/tic/testframework/webdrivermanager/DesktopWebDriverFactory.java @@ -42,7 +42,6 @@ import eu.tsystems.mms.tic.testframework.webdriver.WebDriverFactory; import org.openqa.selenium.Capabilities; import org.openqa.selenium.Dimension; -import org.openqa.selenium.MutableCapabilities; import org.openqa.selenium.Point; import org.openqa.selenium.WebDriver; import org.openqa.selenium.chrome.ChromeDriver; @@ -123,10 +122,6 @@ public WebDriverRequest prepareWebDriverRequest(WebDriverRequest webDriverReques switch (browser) { case Browsers.firefox: FirefoxOptions firefoxOptions = new FirefoxOptions(); -// if (capabilities.getCapabilityNames().contains(FirefoxOptions.FIREFOX_OPTIONS)) { -// final TreeMap predefinedFirefoxOptions = (TreeMap) capabilities.getCapability(FirefoxOptions.FIREFOX_OPTIONS); -// predefinedFirefoxOptions.forEach((s, o) -> firefoxOptions.setCapability(s.toString(), o)); -// } WEB_DRIVER_MANAGER.getUserAgentConfig(browser).ifPresent(userAgentConfig -> { userAgentConfig.configure(firefoxOptions); }); @@ -171,7 +166,8 @@ public WebDriverRequest prepareWebDriverRequest(WebDriverRequest webDriverReques // Any additional defined desired capabilities are merged into browser options if (userAgentCapabilities != null) { userAgentCapabilities = userAgentCapabilities.merge(finalRequest.getDesiredCapabilities()); - finalRequest.setBrowserOptions(userAgentCapabilities); + userAgentCapabilities = userAgentCapabilities.merge(finalRequest.getMutableCapabilities()); + finalRequest.setCapabilities(userAgentCapabilities); } return finalRequest; } @@ -351,22 +347,22 @@ private WebDriver startNewWebDriverSession(DesktopWebDriverRequest request, Sess // TODO: Reduced timeouts of Selenium 3, needed in Selenium 4? // final HttpCommandExecutor httpCommandExecutor = new HttpCommandExecutor(new HashMap<>(), seleniumUrl, new HttpClientFactory()); // final HttpCommandExecutor httpCommandExecutor = new HttpCommandExecutor(new HashMap<>(), seleniumUrl); - Capabilities browserOptions = request.getBrowserOptions(); - if (browserOptions == null) { + Capabilities capabilities = request.getCapabilities(); + if (capabilities == null) { throw new SystemException("Cannot start browser session with empty browser options"); } - webDriver = new RemoteWebDriver(seleniumUrl, browserOptions); + webDriver = new RemoteWebDriver(seleniumUrl, capabilities); webDriver.setFileDetector(new LocalFileDetector()); sessionContext.setNodeUrl(seleniumUrl); } else { log().warn("Local WebDriver setups may cause side effects. It's highly recommended to use a remote Selenium configurations for all environments!"); // Starting local webdriver needs caps as browser options - if (optionClass == request.getBrowserOptions().getClass()) { + if (optionClass == request.getCapabilities().getClass()) { Constructor constructor = driverClass.getConstructor(optionClass); - webDriver = constructor.newInstance(request.getBrowserOptions()); + webDriver = constructor.newInstance(request.getCapabilities()); } else { - throw new SystemException("Browser options cannot use for new session: \nRequired " + optionClass.getName() + ",\nProvided: " + request.getBrowserOptions().getClass().getName()); + throw new SystemException("Browser options cannot use for new session: \nRequired " + optionClass.getName() + ",\nProvided: " + request.getCapabilities().getClass().getName()); } } } catch (Exception e) { diff --git a/driver-ui/build.gradle b/driver-ui/build.gradle index 045483da6c..8ff44fc3a6 100644 --- a/driver-ui/build.gradle +++ b/driver-ui/build.gradle @@ -30,10 +30,6 @@ dependencies { // 1.5.3 implementation group: 'com.github.ua-parser', name: 'uap-java', version: '1.4.3' // - - // Selenium 4.6 comes with 'io.netty:netty-transport-native-epoll:4.1.84.Final' - // -> Dependency error Could not find netty-transport-native-epoll-4.1.84.Final-linux-x86_64.jar (io.netty:netty-transport-native-epoll:4.1.84.Final). - api 'org.seleniumhq.selenium:selenium-java:' + seleniumVersion } test { diff --git a/driver-ui/src/main/java/eu/tsystems/mms/tic/testframework/webdrivermanager/AbstractWebDriverRequest.java b/driver-ui/src/main/java/eu/tsystems/mms/tic/testframework/webdrivermanager/AbstractWebDriverRequest.java index 5915fd7cf5..cb2fc80f8c 100644 --- a/driver-ui/src/main/java/eu/tsystems/mms/tic/testframework/webdrivermanager/AbstractWebDriverRequest.java +++ b/driver-ui/src/main/java/eu/tsystems/mms/tic/testframework/webdrivermanager/AbstractWebDriverRequest.java @@ -29,6 +29,7 @@ import org.openqa.selenium.MutableCapabilities; import org.openqa.selenium.Platform; import org.openqa.selenium.WebDriverException; +import org.openqa.selenium.remote.CapabilityType; import org.openqa.selenium.remote.DesiredCapabilities; import java.net.MalformedURLException; @@ -43,6 +44,8 @@ public class AbstractWebDriverRequest implements WebDriverRequest, Loggable { @Deprecated private DesiredCapabilities desiredCapabilities; + private MutableCapabilities mutableCapabilities; + private Capabilities capabilities; private boolean shutdownAfterTest = false; private boolean shutdownAfterTestFailed = false; @@ -68,12 +71,12 @@ public void setBrowser(String browser) { } public String getBrowserVersion() { - return getDesiredCapabilities().getBrowserVersion(); + return this.getMutableCapabilities().getBrowserVersion(); } public void setBrowserVersion(String browserVersion) { if (StringUtils.isNotBlank(browserVersion)) { - this.getDesiredCapabilities().setVersion(browserVersion); + this.getMutableCapabilities().setCapability(CapabilityType.BROWSER_VERSION, browserVersion); } } @@ -135,21 +138,27 @@ public boolean getShutdownAfterExecution() { return shutdownAfterExecution; } - @Override - public Map getCapabilities() { - if (getBrowserOptions() != null) { - return getBrowserOptions().asMap(); + public Capabilities getCapabilities() { + if (capabilities != null) { + return this.capabilities; } else { - return Map.of(); + return new MutableCapabilities(); } } + /** + * This method is needed to update the current capabilities with merged capabilities. + * Should use only internally. + */ + public void setCapabilities(Capabilities capabilities) { + this.capabilities = capabilities; + } + public void setSessionKey(String sessionKey) { this.sessionKey = sessionKey; } /** - * * @deprecated Use {@link #getMutableCapabilities()} instead */ @Deprecated @@ -160,30 +169,29 @@ public DesiredCapabilities getDesiredCapabilities() { return desiredCapabilities; } - public Capabilities getBrowserOptions() { - return capabilities; - } - - public void setBrowserOptions(Capabilities capabilities) { - this.capabilities = capabilities; + public MutableCapabilities getMutableCapabilities() { + if (this.mutableCapabilities == null) { + this.mutableCapabilities = new MutableCapabilities(); + } + return this.mutableCapabilities; } public void setPlatformName(String platformName) { try { if (StringUtils.isNotBlank(platformName)) { final Platform platform = Platform.fromString(platformName); - this.getDesiredCapabilities().setPlatform(platform); + this.getMutableCapabilities().setCapability(CapabilityType.PLATFORM_NAME, platform); } } catch (WebDriverException e) { log().warn("Trying to set invalid platform '{}' was ignored.", platformName); } } - public Optional getPlatformName() { - if (this.getDesiredCapabilities().getPlatformName() != null) { - return Optional.ofNullable(this.getDesiredCapabilities().getPlatformName().toString()); + public String getPlatformName() { + if (this.getMutableCapabilities().getPlatformName() != null) { + return this.getMutableCapabilities().getPlatformName().toString(); } - return Optional.empty(); + return null; } /** @@ -203,7 +211,7 @@ public AbstractWebDriverRequest clone() throws CloneNotSupportedException { } if (this.capabilities != null) { Map clonedCaps = capabilityUtils.clone(this.capabilities.asMap()); - clone.setBrowserOptions(new MutableCapabilities(clonedCaps)); + clone.capabilities = new MutableCapabilities(clonedCaps); } return clone; } diff --git a/driver-ui/src/main/java/eu/tsystems/mms/tic/testframework/webdrivermanager/SeleniumWebDriverRequest.java b/driver-ui/src/main/java/eu/tsystems/mms/tic/testframework/webdrivermanager/SeleniumWebDriverRequest.java index 0552eb1751..075b31162b 100644 --- a/driver-ui/src/main/java/eu/tsystems/mms/tic/testframework/webdrivermanager/SeleniumWebDriverRequest.java +++ b/driver-ui/src/main/java/eu/tsystems/mms/tic/testframework/webdrivermanager/SeleniumWebDriverRequest.java @@ -18,16 +18,15 @@ * specific language governing permissions and limitations * under the License. */ - package eu.tsystems.mms.tic.testframework.webdrivermanager; +package eu.tsystems.mms.tic.testframework.webdrivermanager; import eu.tsystems.mms.tic.testframework.common.Testerra; -import eu.tsystems.mms.tic.testframework.logging.Loggable; +import org.apache.commons.lang3.StringUtils; import java.io.Serializable; import java.net.MalformedURLException; import java.net.URL; import java.util.Optional; -import org.apache.commons.lang3.StringUtils; public class SeleniumWebDriverRequest extends AbstractWebDriverRequest implements Serializable { @@ -51,7 +50,7 @@ public SeleniumWebDriverRequest() { this.setBrowserVersion(IWebDriverManager.Properties.BROWSER_VERSION.asString()); } - if (!this.getPlatformName().isPresent()) { + if (StringUtils.isBlank(this.getPlatformName())) { this.setPlatformName(IWebDriverManager.Properties.BROWSER_PLATFORM.asString()); } diff --git a/driver-ui/src/main/java/eu/tsystems/mms/tic/testframework/webdrivermanager/WebDriverCapabilities.java b/driver-ui/src/main/java/eu/tsystems/mms/tic/testframework/webdrivermanager/WebDriverCapabilities.java index a5f4d0a536..6137fcc0bc 100644 --- a/driver-ui/src/main/java/eu/tsystems/mms/tic/testframework/webdrivermanager/WebDriverCapabilities.java +++ b/driver-ui/src/main/java/eu/tsystems/mms/tic/testframework/webdrivermanager/WebDriverCapabilities.java @@ -19,12 +19,11 @@ * under the License. * */ - package eu.tsystems.mms.tic.testframework.webdrivermanager; +package eu.tsystems.mms.tic.testframework.webdrivermanager; import eu.tsystems.mms.tic.testframework.utils.CertUtils; -import java.util.function.Consumer; - import org.openqa.selenium.Capabilities; +import org.openqa.selenium.MutableCapabilities; import org.openqa.selenium.remote.CapabilityType; import org.openqa.selenium.remote.DesiredCapabilities; import org.slf4j.Logger; @@ -32,6 +31,7 @@ import java.util.HashMap; import java.util.Map; +import java.util.function.Consumer; public class WebDriverCapabilities implements Consumer { @@ -44,7 +44,7 @@ public class WebDriverCapabilities implements Consumer { /** * Adds a capability. * - * @param key The key of the capability to set. + * @param key The key of the capability to set. * @param value The value of the capability to set. * @deprecated Configure capabilities on your {@link WebDriverRequest} */ @@ -68,6 +68,7 @@ static void removeGlobalExtraCapability(final String key) { /** * Clear capabilities. + * * @deprecated Configure capabilities on your {@link WebDriverRequest} */ static void clearGlobalCapabilities() { @@ -95,15 +96,17 @@ static Map getGlobalExtraCapabilities() { @Override public void accept(WebDriverRequest webDriverRequest) { if (webDriverRequest instanceof AbstractWebDriverRequest) { - Capabilities browserOptions = ((AbstractWebDriverRequest) webDriverRequest).getBrowserOptions(); - // 'merge' method of browser options always creates a new instance - Capabilities newOptions = browserOptions.merge(new DesiredCapabilities(GLOBALCAPABILITIES)); + Capabilities capabilities = webDriverRequest.getCapabilities(); + if (!GLOBALCAPABILITIES.isEmpty()) { + // 'merge' method of browser options always creates a new instance + capabilities = capabilities.merge(new MutableCapabilities(GLOBALCAPABILITIES)); + } CertUtils certUtils = CertUtils.getInstance(); if (certUtils.isTrustAllHosts() || certUtils.getTrustedHosts().length > 0) { - newOptions = newOptions.merge(new DesiredCapabilities(Map.of(CapabilityType.ACCEPT_INSECURE_CERTS,true))); + capabilities = capabilities.merge(new MutableCapabilities(Map.of(CapabilityType.ACCEPT_INSECURE_CERTS, true))); } - ((AbstractWebDriverRequest) webDriverRequest).setBrowserOptions(newOptions); + ((AbstractWebDriverRequest) webDriverRequest).setCapabilities(capabilities); } } } diff --git a/integration-tests/src/test/java/eu/tsystems/mms/tic/testframework/playground/DriverAndGuiElementTest.java b/integration-tests/src/test/java/eu/tsystems/mms/tic/testframework/playground/DriverAndGuiElementTest.java index c4348ea66c..2aaff4d6bf 100644 --- a/integration-tests/src/test/java/eu/tsystems/mms/tic/testframework/playground/DriverAndGuiElementTest.java +++ b/integration-tests/src/test/java/eu/tsystems/mms/tic/testframework/playground/DriverAndGuiElementTest.java @@ -76,7 +76,7 @@ public void testTapCapabilities() throws Exception { WebDriver driver = WEB_DRIVER_MANAGER.getWebDriver(request); SessionContext sessionContext = WebDriverSessionsManager.getSessionContext(driver).get(); - Map sessionCapabilities = sessionContext.getWebDriverRequest().getCapabilities(); + Map sessionCapabilities = sessionContext.getWebDriverRequest().getCapabilities().asMap(); Assert.assertEquals(sessionCapabilities.get("projectId"), caps.getCapability("projectId"), "EndPoint Capability is set"); } diff --git a/integration-tests/src/test/java/eu/tsystems/mms/tic/testframework/playground/Selenium4_vs_3_Tests.java b/integration-tests/src/test/java/eu/tsystems/mms/tic/testframework/playground/Selenium4_vs_3_Tests.java index 660b3d3aed..926b83794f 100644 --- a/integration-tests/src/test/java/eu/tsystems/mms/tic/testframework/playground/Selenium4_vs_3_Tests.java +++ b/integration-tests/src/test/java/eu/tsystems/mms/tic/testframework/playground/Selenium4_vs_3_Tests.java @@ -9,7 +9,6 @@ import org.testng.annotations.Test; import java.net.MalformedURLException; -import java.util.HashMap; import java.util.Map; /** @@ -44,16 +43,15 @@ public void testBrowserCustomCaps_Selenium3() { WEB_DRIVER_MANAGER.getWebDriver(request); } -// @Test -// public void testBrowserCustomCaps_Selenium4() { -// DesktopWebDriverRequest request = new DesktopWebDriverRequest(); -// MutableCapabilities caps = new MutableCapabilities(); -// caps.setCapability("foo", "bar"); -// -// request.getCapabilities() -// request.getBrowserOptions().merge(caps); -// -// WEB_DRIVER_MANAGER.getWebDriver(request); -// } + @Test + public void testBrowserCustomCaps_Selenium4() { + DesktopWebDriverRequest request = new DesktopWebDriverRequest(); + MutableCapabilities caps = request.getMutableCapabilities(); + + Map customCaps = Map.of("foo", "bar"); + caps.setCapability("custom:caps", customCaps); + + WEB_DRIVER_MANAGER.getWebDriver(request); + } } diff --git a/integration-tests/src/test/java/eu/tsystems/mms/tic/testframework/test/webdrivermanager/DesktopWebDriverFactoryTest.java b/integration-tests/src/test/java/eu/tsystems/mms/tic/testframework/test/webdrivermanager/DesktopWebDriverFactoryTest.java index baa7838ad9..9a5f1ba13c 100644 --- a/integration-tests/src/test/java/eu/tsystems/mms/tic/testframework/test/webdrivermanager/DesktopWebDriverFactoryTest.java +++ b/integration-tests/src/test/java/eu/tsystems/mms/tic/testframework/test/webdrivermanager/DesktopWebDriverFactoryTest.java @@ -81,7 +81,7 @@ public void testT03_EndPointCapabilities_WebDriverRequest() throws Exception { WebDriver driver = WEB_DRIVER_MANAGER.getWebDriver(request); SessionContext sessionContext = WEB_DRIVER_MANAGER.getSessionContext(driver).get(); - Map sessionCapabilities = (Map) sessionContext.getWebDriverRequest().getCapabilities().get("selenoid:options"); + Map sessionCapabilities = (Map) sessionContext.getWebDriverRequest().getCapabilities().getCapability("selenoid:options"); Assert.assertEquals(sessionCapabilities.get("enableVideo"), selenoidCaps.get("enableVideo"), "EndPoint Capability via WebDriverRequest is set"); Assert.assertEquals(sessionCapabilities.get("enableVNC"), selenoidCaps.get("enableVNC"), "EndPoint Capability via WebDriverRequest is set"); @@ -99,7 +99,7 @@ public void testT04_EndPointCapabilities_Global() { WEB_DRIVER_MANAGER.removeGlobalCapability("custom:caps"); SessionContext sessionContext = WEB_DRIVER_MANAGER.getSessionContext(driver).get(); - Map sessionCapabilities = (Map) sessionContext.getWebDriverRequest().getCapabilities().get("custom:caps"); + Map sessionCapabilities = (Map) sessionContext.getWebDriverRequest().getCapabilities().asMap().get("custom:caps"); Assert.assertEquals(sessionCapabilities.get("t04Global"), "yes", "EndPoint Capability is set"); } @@ -115,7 +115,7 @@ public void test05_EndPointCapabilities_UserAgent() { WebDriver driver = WEB_DRIVER_MANAGER.getWebDriver(); SessionContext sessionContext = WEB_DRIVER_MANAGER.getSessionContext(driver).get(); - Map sessionCapabilities = (Map) sessionContext.getWebDriverRequest().getCapabilities().get("custom:caps"); + Map sessionCapabilities = (Map) sessionContext.getWebDriverRequest().getCapabilities().asMap().get("custom:caps"); Assert.assertEquals(sessionCapabilities.get("t05UserAgent"), "yesyes", "EndPoint Capability is set"); } @@ -129,7 +129,7 @@ public void testT06_PlatformCaps() { WebDriverRequest webDriverRequest = WEB_DRIVER_MANAGER.getSessionContext(driver).get().getWebDriverRequest(); - Assert.assertEquals(webDriverRequest.getCapabilities().get(CapabilityType.PLATFORM_NAME), Platform.WINDOWS); + Assert.assertEquals(webDriverRequest.getCapabilities().asMap().get(CapabilityType.PLATFORM_NAME), Platform.WINDOWS); } // Global caps!! -> needs to be independent of other tests @@ -151,7 +151,7 @@ public void testT07_OverwriteCaps() { WebDriver driver = WEB_DRIVER_MANAGER.getWebDriver(request); SessionContext sessionContext = WEB_DRIVER_MANAGER.getSessionContext(driver).get(); - Map sessionCapabilities = (Map) sessionContext.getWebDriverRequest().getCapabilities().get("custom:caps"); + Map sessionCapabilities = (Map) sessionContext.getWebDriverRequest().getCapabilities().asMap().get("custom:caps"); Assert.assertEquals(sessionCapabilities.get("t07Overwrite"), "requestCaps", "Request capability is set"); } From 11c5c0402160534355e8461ddebe4df1924b9924 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Gro=C3=9Fmann?= Date: Thu, 13 Jul 2023 14:57:31 +0200 Subject: [PATCH 52/64] Removed comment --- .../testframework/webdrivermanager/DesktopWebDriverFactory.java | 1 - 1 file changed, 1 deletion(-) diff --git a/driver-ui-desktop/src/main/java/eu/tsystems/mms/tic/testframework/webdrivermanager/DesktopWebDriverFactory.java b/driver-ui-desktop/src/main/java/eu/tsystems/mms/tic/testframework/webdrivermanager/DesktopWebDriverFactory.java index 74d220c4f3..03a27a783e 100644 --- a/driver-ui-desktop/src/main/java/eu/tsystems/mms/tic/testframework/webdrivermanager/DesktopWebDriverFactory.java +++ b/driver-ui-desktop/src/main/java/eu/tsystems/mms/tic/testframework/webdrivermanager/DesktopWebDriverFactory.java @@ -339,7 +339,6 @@ private WebDriver startNewWebDriverSession(DesktopWebDriverRequest request, Sess } // Finalize capabilities -// final DesiredCapabilities requestCapabilities = request.getDesiredCapabilities(); RemoteWebDriver webDriver; try { if (request.getServerUrl().isPresent()) { From 4ace4e681942c89e0c46bdbd0eca1c1ce8153ef9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Gro=C3=9Fmann?= Date: Fri, 14 Jul 2023 16:11:34 +0200 Subject: [PATCH 53/64] Update custom caps for Selenium 4 --- docs/src/docs/selenium4/selenium4-changes.adoc | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/docs/src/docs/selenium4/selenium4-changes.adoc b/docs/src/docs/selenium4/selenium4-changes.adoc index 3adb19ca62..72115aca89 100644 --- a/docs/src/docs/selenium4/selenium4-changes.adoc +++ b/docs/src/docs/selenium4/selenium4-changes.adoc @@ -6,11 +6,23 @@ The following subsections describes how the changes affect Testerra. == Custom capabilities -Any capability that not in the standard of https://www.w3.org/TR/webdriver1/#capabilities[W3C] needs a vendor prefix. +Any capability that not in the standard of https://www.w3.org/TR/webdriver1/#capabilities[W3C] needs a vendor prefix. Otherwise, the session could not created and Selenium returns +* `WARNUNG: Support for Legacy Capabilities is deprecated; You are sending the following invalid capabilities: [foo]; Please update to W3C Syntax: https://www.selenium.dev/blog/2022/legacy-protocol-support/` +* `java.lang.IllegalArgumentException: Illegal key values seen in w3c capabilities: [foo]`. +.Example for custom capabilities compatible with Selenium 4 +[source, java] +---- +DesktopWebDriverRequest request = new DesktopWebDriverRequest(); +MutableCapabilities caps = request.getMutableCapabilities(); -== Global capabilities +// The custom caps have to packaged into an additional map and added to the request with a vendor prefix. +Map customCaps = Map.of("foo", "bar"); +caps.setCapability("custom:caps", customCaps); + +WebDriver driver = WEB_DRIVER_MANAGER.getWebDriver(request); +---- == Browser version From 7effeeeb4c3e3a71806787cb556099a5d5062f92 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Gro=C3=9Fmann?= Date: Fri, 14 Jul 2023 16:31:36 +0200 Subject: [PATCH 54/64] Added deprecated to setting global caps --- .../webdrivermanager/IWebDriverManager.java | 8 ++++++++ .../webdrivermanager/WebDriverManager.java | 20 +++++++------------ 2 files changed, 15 insertions(+), 13 deletions(-) diff --git a/driver-ui/src/main/java/eu/tsystems/mms/tic/testframework/webdrivermanager/IWebDriverManager.java b/driver-ui/src/main/java/eu/tsystems/mms/tic/testframework/webdrivermanager/IWebDriverManager.java index 1f777b9b13..6d05710459 100644 --- a/driver-ui/src/main/java/eu/tsystems/mms/tic/testframework/webdrivermanager/IWebDriverManager.java +++ b/driver-ui/src/main/java/eu/tsystems/mms/tic/testframework/webdrivermanager/IWebDriverManager.java @@ -223,10 +223,18 @@ default void stopKeepingAlive(WebDriver webDriver) { WebDriverUtils.removeKeepAliveForWebDriver(webDriver); } + /** + * @deprecated Use {@link #setUserAgentConfig(String, UserAgentConfig)} or {@link DesktopWebDriverRequest#getMutableCapabilities()} for custom capabilities instead + */ + @Deprecated default void setGlobalCapability(String key, Object value) { WebDriverManager.setGlobalExtraCapability(key, value); } + /** + * @deprecated Use {@link #setUserAgentConfig(String, UserAgentConfig)} or {@link DesktopWebDriverRequest#getMutableCapabilities()} instead. + */ + @Deprecated default void removeGlobalCapability(String key) { WebDriverManager.removeGlobalExtraCapability(key); } diff --git a/driver-ui/src/main/java/eu/tsystems/mms/tic/testframework/webdrivermanager/WebDriverManager.java b/driver-ui/src/main/java/eu/tsystems/mms/tic/testframework/webdrivermanager/WebDriverManager.java index 1daf2058d3..2de89485f5 100644 --- a/driver-ui/src/main/java/eu/tsystems/mms/tic/testframework/webdrivermanager/WebDriverManager.java +++ b/driver-ui/src/main/java/eu/tsystems/mms/tic/testframework/webdrivermanager/WebDriverManager.java @@ -84,6 +84,7 @@ public final class WebDriverManager { * @param value The value of the capability to set. * @deprecated Configure capabilities on your {@link WebDriverRequest} */ + @Deprecated public static void setGlobalExtraCapability(final String key, final Object value) { addGlobalCapability(key, value); } @@ -102,9 +103,9 @@ public static void setGlobalExtraCapabilities(final DesiredCapabilities desiredC /** * Get all set extra capabilities (not the DesiredCapabilities that are set automatically * - * @return * @deprecated Configure capabilities on your {@link WebDriverRequest} */ + @Deprecated public static Map getGlobalExtraCapabilities() { return WebDriverCapabilities.getGlobalExtraCapabilities(); } @@ -116,6 +117,7 @@ public static Map getGlobalExtraCapabilities() { * @param value The value of the capability to set. * @deprecated Configure capabilities on your {@link WebDriverRequest} */ + @Deprecated private static void addGlobalCapability(String key, Object value) { WebDriverCapabilities.addGlobalCapability(key, value); } @@ -124,7 +126,9 @@ private static void addGlobalCapability(String key, Object value) { * Remove extra capability from capabilities. * * @param key The key of the capability to remove. + * @deprecated Configure capabilities on your {@link WebDriverRequest} */ + @Deprecated public static void removeGlobalExtraCapability(final String key) { WebDriverCapabilities.removeGlobalExtraCapability(key); } @@ -197,6 +201,7 @@ public static void forceShutdown() { /** * @deprecated Use {@link IWebDriverManager#shutdownAllThreadSessions()} instead */ + @Deprecated public static void shutdown() { forceShutdown(); } @@ -272,18 +277,7 @@ public static boolean hasAnySessionActive() { public static boolean hasSessionsActiveInThisThread() { return WebDriverSessionsManager.hasSessionActiveInThisThread(); } - - /** - * Are you sure you want do that?? This action quits all browser sessions in all threads. - * Does not close windows when executeCloseWindows == false. - * - * @deprecated Use forceShotDownAllThreads, does the same thing, but sounds more dangerous. - */ -// @Deprecated -// public static void shutdownAllThreads() { -// pRealShutdownAllThreads(false); -// } - + /** * Are you sure you want do that?? This action quits all browser sessions in all threads. */ From 349ceede80ad5c77c245d645c36db700f552abf0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Gro=C3=9Fmann?= Date: Fri, 14 Jul 2023 16:38:34 +0200 Subject: [PATCH 55/64] Removed DEFAULT_SESSION_KEY from WebDriverManager class --- .../webdrivermanager/WebDriverManager.java | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/driver-ui/src/main/java/eu/tsystems/mms/tic/testframework/webdrivermanager/WebDriverManager.java b/driver-ui/src/main/java/eu/tsystems/mms/tic/testframework/webdrivermanager/WebDriverManager.java index 2de89485f5..fab4fa2901 100644 --- a/driver-ui/src/main/java/eu/tsystems/mms/tic/testframework/webdrivermanager/WebDriverManager.java +++ b/driver-ui/src/main/java/eu/tsystems/mms/tic/testframework/webdrivermanager/WebDriverManager.java @@ -57,11 +57,6 @@ public final class WebDriverManager { UITestUtils.initializePerfTest(); } - /** - * @deprecated Use {@link WebDriverRequest#DEFAULT_SESSION_KEY} instead - */ - public static final String DEFAULT_SESSION_KEY = WebDriverRequest.DEFAULT_SESSION_KEY; - /** * WebDriverManager configuration set. Modify by config() call! */ @@ -139,7 +134,7 @@ public static void removeGlobalExtraCapability(final String key) { * @return instance of WebDriver object. */ public static WebDriver getWebDriver() { - return getWebDriver(DEFAULT_SESSION_KEY); + return getWebDriver(WebDriverRequest.DEFAULT_SESSION_KEY); } /** @@ -164,7 +159,7 @@ public static EventFiringWebDriver getWebDriver(WebDriverRequest webDriverReques * @param driver . */ public static void introduceWebDriver(final WebDriver driver) { - introduceWebDriver(DEFAULT_SESSION_KEY, driver); + introduceWebDriver(WebDriverRequest.DEFAULT_SESSION_KEY, driver); } /** @@ -277,7 +272,7 @@ public static boolean hasAnySessionActive() { public static boolean hasSessionsActiveInThisThread() { return WebDriverSessionsManager.hasSessionActiveInThisThread(); } - + /** * Are you sure you want do that?? This action quits all browser sessions in all threads. */ From 168b667afa38581342476316778d48c2b0414b58 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Gro=C3=9Fmann?= Date: Fri, 14 Jul 2023 17:13:22 +0200 Subject: [PATCH 56/64] Updated Selenium 4 docu --- docs/build.gradle | 3 +- docs/src/docs/selenium4/selenium4-cdp.adoc | 42 +++++++++++++++++++ .../src/docs/selenium4/selenium4-changes.adoc | 16 +++++-- .../highlight/styles/atom-one-dark.min.css | 1 + 4 files changed, 57 insertions(+), 5 deletions(-) create mode 100644 docs/src/highlight/styles/atom-one-dark.min.css diff --git a/docs/build.gradle b/docs/build.gradle index 79fa544046..fc3f7df237 100644 --- a/docs/build.gradle +++ b/docs/build.gradle @@ -57,7 +57,8 @@ asciidoctor { revnumber: "${version}", nofooter: true, 'source-highlighter': 'highlightjs', - 'highlightjs-theme': 'atom-one-light', + 'highlightjs-theme': 'atom-one-dark', +// 'highlightjs-theme': 'atom-one-light', highlightjsdir: 'highlight', icons: 'font', imagesdir: 'images' diff --git a/docs/src/docs/selenium4/selenium4-cdp.adoc b/docs/src/docs/selenium4/selenium4-cdp.adoc index de671c1707..9cb55a51f8 100644 --- a/docs/src/docs/selenium4/selenium4-cdp.adoc +++ b/docs/src/docs/selenium4/selenium4-cdp.adoc @@ -1 +1,43 @@ = Support of Chrome developer toos (CDP) + +Selenium 4 supports the access to the Chrome developer tools. Testerra provides a simple API to interact with CDP. + +NOTE: As the name says, it only works in Chrome browser. :-) + +== Set basic authentication + +[source, java] +---- +... +import org.openqa.selenium.UsernameAndPassword +... + +public class ChromeDevToolsTests extends TesterraTest implements + ChromeDevToolsProvider, + WebDriverManagerProvider, + UiElementFinderFactoryProvider { + + @Test + public void test_BasicAuthentication_DevTools() { + WebDriver webDriver = WEB_DRIVER_MANAGER.getWebDriver(); + UiElementFinder uiElementFinder = UI_ELEMENT_FINDER_FACTORY.create(webDriver); + + CHROME_DEV_TOOLS + .setBasicAuthentication(webDriver, UsernameAndPassword.of("admin", "admin")); + + webDriver.get("https://the-internet.herokuapp.com/basic_auth"); + uiElementFinder.find(By.tagName("p")) + .assertThat().text().isContaining("Congratulations"); + } + +} + +---- + +== Change geolocation + + + +== Listen to Network logs + +== Listen to browser console diff --git a/docs/src/docs/selenium4/selenium4-changes.adoc b/docs/src/docs/selenium4/selenium4-changes.adoc index 72115aca89..210401b3ac 100644 --- a/docs/src/docs/selenium4/selenium4-changes.adoc +++ b/docs/src/docs/selenium4/selenium4-changes.adoc @@ -1,15 +1,23 @@ = Important changes -The Selenium devs provide a short https://www.selenium.dev/documentation/webdriver/getting_started/upgrade_to_selenium_4/[migration guide] for Selenium 4 (). +The Selenium devs provide a short https://www.selenium.dev/documentation/webdriver/getting_started/upgrade_to_selenium_4/[migration guide] for Selenium 4. The following subsections describes how the changes affect Testerra. == Custom capabilities -Any capability that not in the standard of https://www.w3.org/TR/webdriver1/#capabilities[W3C] needs a vendor prefix. Otherwise, the session could not created and Selenium returns +Any capability that not in the standard of https://www.w3.org/TR/webdriver1/#capabilities[W3C] needs a vendor prefix. -* `WARNUNG: Support for Legacy Capabilities is deprecated; You are sending the following invalid capabilities: [foo]; Please update to W3C Syntax: https://www.selenium.dev/blog/2022/legacy-protocol-support/` -* `java.lang.IllegalArgumentException: Illegal key values seen in w3c capabilities: [foo]`. +Otherwise, the session could not created and Selenium returns + +[source] +---- +... +WARNING: Support for Legacy Capabilities is deprecated; You are sending the following invalid capabilities: [foo]; Please update to W3C Syntax: https://www.selenium.dev/blog/2022/legacy-protocol-support/ +... +java.lang.IllegalArgumentException: Illegal key values seen in w3c capabilities: [foo] +... +---- .Example for custom capabilities compatible with Selenium 4 [source, java] diff --git a/docs/src/highlight/styles/atom-one-dark.min.css b/docs/src/highlight/styles/atom-one-dark.min.css new file mode 100644 index 0000000000..23609b4db2 --- /dev/null +++ b/docs/src/highlight/styles/atom-one-dark.min.css @@ -0,0 +1 @@ +pre code.hljs{display:block;overflow-x:auto;padding:1em}code.hljs{padding:3px 5px}.hljs{color:#abb2bf;background:#282c34}.hljs-comment,.hljs-quote{color:#5c6370;font-style:italic}.hljs-doctag,.hljs-formula,.hljs-keyword{color:#c678dd}.hljs-deletion,.hljs-name,.hljs-section,.hljs-selector-tag,.hljs-subst{color:#e06c75}.hljs-literal{color:#56b6c2}.hljs-addition,.hljs-attribute,.hljs-meta .hljs-string,.hljs-regexp,.hljs-string{color:#98c379}.hljs-attr,.hljs-number,.hljs-selector-attr,.hljs-selector-class,.hljs-selector-pseudo,.hljs-template-variable,.hljs-type,.hljs-variable{color:#d19a66}.hljs-bullet,.hljs-link,.hljs-meta,.hljs-selector-id,.hljs-symbol,.hljs-title{color:#61aeee}.hljs-built_in,.hljs-class .hljs-title,.hljs-title.class_{color:#e6c07b}.hljs-emphasis{font-style:italic}.hljs-strong{font-weight:700}.hljs-link{text-decoration:underline} From 27d97376ff22707fb1326b56a7d7948d9bfc13de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Gro=C3=9Fmann?= Date: Mon, 17 Jul 2023 15:26:29 +0200 Subject: [PATCH 57/64] Added log messages to CDP tools --- .../mms/tic/testframework/testing/SeleniumChromeDevTools.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/driver-ui/src/main/java/eu/tsystems/mms/tic/testframework/testing/SeleniumChromeDevTools.java b/driver-ui/src/main/java/eu/tsystems/mms/tic/testframework/testing/SeleniumChromeDevTools.java index 9d233a9d01..cdc3cba3fc 100644 --- a/driver-ui/src/main/java/eu/tsystems/mms/tic/testframework/testing/SeleniumChromeDevTools.java +++ b/driver-ui/src/main/java/eu/tsystems/mms/tic/testframework/testing/SeleniumChromeDevTools.java @@ -87,6 +87,7 @@ public void setGeoLocation(WebDriver webDriver, double latitude, double longitud Optional.of(latitude), Optional.of(longitude), Optional.of(accuracy))); + log().info("Changed geolocation information to lat={}, long={}", latitude, longitude); } @Override @@ -110,6 +111,7 @@ public void setBasicAuthentication(WebDriver webDriver, Supplier cr headers.put("authorization", "Basic " + Base64.getEncoder().encodeToString(authByteArray)); devTools.send(Network.enable(Optional.empty(), Optional.empty(), Optional.empty())); devTools.send(Network.setExtraHTTPHeaders(new Headers(headers))); + log().info("Set credentials for basic authentication"); } catch (UnsupportedEncodingException e) { throw new RuntimeException("Cannot set basic authentication", e); } From 93fdcab1ef3f095bcd3f063274eb9924efb451c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Gro=C3=9Fmann?= Date: Mon, 17 Jul 2023 16:32:24 +0200 Subject: [PATCH 58/64] Updated CDP examples --- docs/build.gradle | 4 +- docs/src/docs/selenium4/selenium4-cdp.adoc | 220 +++++++++++++++++- .../playground/ChromeDevToolsTests.java | 22 +- 3 files changed, 227 insertions(+), 19 deletions(-) diff --git a/docs/build.gradle b/docs/build.gradle index fc3f7df237..0c6ba990f2 100644 --- a/docs/build.gradle +++ b/docs/build.gradle @@ -57,8 +57,8 @@ asciidoctor { revnumber: "${version}", nofooter: true, 'source-highlighter': 'highlightjs', - 'highlightjs-theme': 'atom-one-dark', -// 'highlightjs-theme': 'atom-one-light', +// 'highlightjs-theme': 'atom-one-dark', + 'highlightjs-theme': 'atom-one-light', highlightjsdir: 'highlight', icons: 'font', imagesdir: 'images' diff --git a/docs/src/docs/selenium4/selenium4-cdp.adoc b/docs/src/docs/selenium4/selenium4-cdp.adoc index 9cb55a51f8..0d7c29d86b 100644 --- a/docs/src/docs/selenium4/selenium4-cdp.adoc +++ b/docs/src/docs/selenium4/selenium4-cdp.adoc @@ -2,14 +2,15 @@ Selenium 4 supports the access to the Chrome developer tools. Testerra provides a simple API to interact with CDP. +You can find some more examples at https://www.selenium.dev/documentation/webdriver/bidirectional/chrome_devtools/. + NOTE: As the name says, it only works in Chrome browser. :-) == Set basic authentication [source, java] ---- -... -import org.openqa.selenium.UsernameAndPassword +import org.openqa.selenium.UsernameAndPassword; ... public class ChromeDevToolsTests extends TesterraTest implements @@ -18,10 +19,11 @@ public class ChromeDevToolsTests extends TesterraTest implements UiElementFinderFactoryProvider { @Test - public void test_BasicAuthentication_DevTools() { + public void test_CDP_BasicAuthentication() { WebDriver webDriver = WEB_DRIVER_MANAGER.getWebDriver(); UiElementFinder uiElementFinder = UI_ELEMENT_FINDER_FACTORY.create(webDriver); + // Credentials are used for all further website calls in your webdriver session CHROME_DEV_TOOLS .setBasicAuthentication(webDriver, UsernameAndPassword.of("admin", "admin")); @@ -36,8 +38,218 @@ public class ChromeDevToolsTests extends TesterraTest implements == Change geolocation +[source, java] +---- +public class ChromeDevToolsTests extends TesterraTest implements + ChromeDevToolsProvider, + WebDriverManagerProvider, + UiElementFinderFactoryProvider { -== Listen to Network logs + @Test + public void test_CDP_GeoLocation() { + WebDriver webDriver = WEB_DRIVER_MANAGER.getWebDriver(); + UiElementFinder uiElementFinder = UI_ELEMENT_FINDER_FACTORY.create(webDriver); + + CHROME_DEV_TOOLS.setGeoLocation( + webDriver, + Optional.of(52.52084), // latitude + Optional.of(13.40943), // longitude + 1); // accuracy + + webDriver.get("https://my-location.org/"); + uiElementFinder.find(By.id("latitude")) + .assertThat().text().isContaining("52.52084"); + uiElementFinder.find(By.id("longitude")) + .assertThat().text().isContaining("13.40943"); + } + +} + +---- == Listen to browser console + +The browser console window shows different types of logging information. You have to know which kind of logs you need. + +IMPORTANT: The created consumer for all listeners will be executed in an additional thread. + +If you use an `Assert` this will be no impact to the main thread. + +.JavaScript logging information +[source, java] +---- + +import org.openqa.selenium.devtools.events.ConsoleEvent; +... + +public class ChromeDevToolsTests extends TesterraTest implements + ChromeDevToolsProvider, + Loggable, + WebDriverManagerProvider, + UiElementFinderFactoryProvider { + + @Test + public void test_CDP_LogListener_JsLogs() throws MalformedURLException { + DesktopWebDriverRequest request = new DesktopWebDriverRequest(); + request + .setBaseUrl("https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html"); + WebDriver webDriver = WEB_DRIVER_MANAGER.getWebDriver(request); + DevTools devTools = CHROME_DEV_TOOLS.getRawDevTools(webDriver); + + // Create a list for console events + List consoleEvents = new ArrayList<>(); + // Create a consumer and add them to a listener + Consumer addEntry = consoleEvents::add; + devTools.getDomains().events().addConsoleListener(addEntry); + + UiElementFinder uiElementFinder = UI_ELEMENT_FINDER_FACTORY.create(webDriver); + uiElementFinder.find(By.id("consoleLog")).click(); + uiElementFinder.find(By.id("consoleError")).click(); + + for (ConsoleEvent event : consoleEvents) { + log().info( + "JS_LOGS: {} {} - {}", + event.getTimestamp(), + event.getType(), + event.getMessages().toString() + ); + } + } +} +---- + +.JavaScript exception logs +[source, java] +---- +import org.openqa.selenium.JavascriptException; +... + +public class ChromeDevToolsTests extends TesterraTest implements + ChromeDevToolsProvider, + Loggable, + WebDriverManagerProvider, + UiElementFinderFactoryProvider { + + @Test + public void testT_CDP_LogListener_JsExceptions() throws MalformedURLException { + DesktopWebDriverRequest request = new DesktopWebDriverRequest(); + request + .setBaseUrl("https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html"); + WebDriver webDriver = WEB_DRIVER_MANAGER.getWebDriver(request); + DevTools devTools = CHROME_DEV_TOOLS.getRawDevTools(webDriver); + + // Create a list for JS exceptions + List jsExceptionsList = new ArrayList<>(); + Consumer addEntry = jsExceptionsList::add; + devTools.getDomains().events().addJavascriptExceptionListener(addEntry); + + UiElementFinder uiElementFinder = UI_ELEMENT_FINDER_FACTORY.create(webDriver); + uiElementFinder.find(By.id("jsException")).click(); + uiElementFinder.find(By.id("logWithStacktrace")).click(); + + for (JavascriptException jsException : jsExceptionsList) { + log().info( + "JS_EXCEPTION: {} {}", + jsException.getMessage(), + jsException.getSystemInformation() + ); + } + } + +} + +---- + +.'Broken' page resources +[source, java] +---- +import org.openqa.selenium.devtools.v114.log.model.LogEntry; +... + +public class ChromeDevToolsTests extends TesterraTest implements + ChromeDevToolsProvider, + Loggable, + WebDriverManagerProvider { + + @Test + public void test_CDP_LogListener_BrokenImages() { + WebDriver webDriver = WEB_DRIVER_MANAGER.getWebDriver(); + DevTools devTools = CHROME_DEV_TOOLS.getRawDevTools(webDriver); + devTools.send(Log.enable()); + + List logEntries = new ArrayList<>(); + Consumer addedLog = logEntries::add; + devTools.addListener(Log.entryAdded(), addedLog); + + webDriver.get("http://the-internet.herokuapp.com/broken_images"); + TimerUtils.sleep(1000); // Short wait to get delayed logs + + for (LogEntry logEntry : logEntries) { + log().info( + "LOG_ENTRY: {} {} {} - {} ({})", + logEntry.getTimestamp(), + logEntry.getLevel(), + logEntry.getSource(), + logEntry.getText(), + logEntry.getUrl() + ); + } + } + +} + +---- + +== Listen to Network logs + +[source, java] +---- +import org.openqa.selenium.devtools.v114.network.Network; +import org.openqa.selenium.devtools.v114.network.model.RequestWillBeSent; +import org.openqa.selenium.devtools.v114.network.model.ResponseReceived; +... + +public class ChromeDevToolsTests extends TesterraTest implements + ChromeDevToolsProvider, + Loggable, + WebDriverManagerProvider { + + @Test + public void test_CDP_NetworkListener() { + WebDriver webDriver = WEB_DRIVER_MANAGER.getWebDriver(); + DevTools devTools = CHROME_DEV_TOOLS.getRawDevTools(webDriver); + devTools.send(Network.enable(Optional.empty(), Optional.empty(), Optional.empty())); + + // Create lists for requests and responses + List responseReceivedList = new ArrayList<>(); + List requestList = new ArrayList<>(); + + devTools.addListener(Network.responseReceived(), responseReceivedList::add); + devTools.addListener(Network.requestWillBeSent(), requestList::add); + + webDriver.get("https://the-internet.herokuapp.com/broken_images"); + + for (RequestWillBeSent request : requestList) { + log().info( + "Request: {} {} - {}", + request.getRequestId().toString(), + request.getRequest().getMethod(), + request.getRequest().getUrl() + ); + } + + for (ResponseReceived response : responseReceivedList) { + log().info( + "Response: {} {} - {}", + response.getRequestId().toString(), + response.getResponse().getStatus(), + response.getResponse().getStatusText() + ); + } + } + +} + +---- + + diff --git a/integration-tests/src/test/java/eu/tsystems/mms/tic/testframework/playground/ChromeDevToolsTests.java b/integration-tests/src/test/java/eu/tsystems/mms/tic/testframework/playground/ChromeDevToolsTests.java index 33128bb02c..799698eee0 100644 --- a/integration-tests/src/test/java/eu/tsystems/mms/tic/testframework/playground/ChromeDevToolsTests.java +++ b/integration-tests/src/test/java/eu/tsystems/mms/tic/testframework/playground/ChromeDevToolsTests.java @@ -35,10 +35,10 @@ import org.openqa.selenium.devtools.DevTools; import org.openqa.selenium.devtools.HasDevTools; import org.openqa.selenium.devtools.events.ConsoleEvent; -import org.openqa.selenium.devtools.v112.emulation.Emulation; -import org.openqa.selenium.devtools.v112.network.Network; -import org.openqa.selenium.devtools.v112.network.model.RequestWillBeSent; -import org.openqa.selenium.devtools.v112.network.model.ResponseReceived; +import org.openqa.selenium.devtools.v114.emulation.Emulation; +import org.openqa.selenium.devtools.v114.network.Network; +import org.openqa.selenium.devtools.v114.network.model.RequestWillBeSent; +import org.openqa.selenium.devtools.v114.network.model.ResponseReceived; import org.openqa.selenium.devtools.v114.log.Log; import org.openqa.selenium.devtools.v114.log.model.LogEntry; import org.openqa.selenium.remote.Augmenter; @@ -222,19 +222,15 @@ public void testT06_BasicAuth_ChromeBiDiAPI() { // @Test - public void testT10_LogListener_BrokenImages() throws MalformedURLException { - DesktopWebDriverRequest request = new DesktopWebDriverRequest(); -// request.setBaseUrl("https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html"); - WebDriver webDriver = WEB_DRIVER_MANAGER.getWebDriver(request); + public void testT10_LogListener_BrokenImages() { + WebDriver webDriver = WEB_DRIVER_MANAGER.getWebDriver(); DevTools devTools = CHROME_DEV_TOOLS.getRawDevTools(webDriver); - devTools.send(Log.enable()); List logEntries = new ArrayList<>(); Consumer addedLog = logEntries::add; - - // Consumer is running in another thread... Asserts does not have impact to main thread devTools.addListener(Log.entryAdded(), addedLog); + webDriver.get("http://the-internet.herokuapp.com/broken_images"); TimerUtils.sleep(1000); // Short wait to get delayed logs for (LogEntry logEntry : logEntries) { @@ -299,10 +295,10 @@ public void testT13_NetworkListener() { devTools.addListener(Network.responseReceived(), responseReceivedList::add); devTools.addListener(Network.requestWillBeSent(), requestList::add); - webDriver.get("https://the-internet.herokuapp.com/"); + webDriver.get("https://the-internet.herokuapp.com/broken_images"); for (RequestWillBeSent request : requestList) { - log().info("Request: {} - {}", request.getRequestId().toString(), request.getRequest().getUrl()); + log().info("Request: {} {} - {}", request.getRequestId().toString(), request.getRequest().getMethod(), request.getRequest().getUrl()); } for (ResponseReceived response : responseReceivedList) { From a7f2b76033fed4049bd0712bbbc000c6ca72490a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Gro=C3=9Fmann?= Date: Tue, 18 Jul 2023 17:43:59 +0200 Subject: [PATCH 59/64] Updated docs --- docs/src/docs/browsercaps/proxy-setup.adoc | 1 - .../browsercaps/setting-browser-caps.adoc | 37 +++++++++---------- docs/src/docs/selenium4/selenium4-cdp.adoc | 7 +++- .../playground/Selenium4_vs_3_Tests.java | 17 +++++++++ 4 files changed, 41 insertions(+), 21 deletions(-) diff --git a/docs/src/docs/browsercaps/proxy-setup.adoc b/docs/src/docs/browsercaps/proxy-setup.adoc index f26811116a..75af2c83bc 100644 --- a/docs/src/docs/browsercaps/proxy-setup.adoc +++ b/docs/src/docs/browsercaps/proxy-setup.adoc @@ -10,7 +10,6 @@ The following code setups a proxy based on the <> for specific browser options. +Non-standard capabilities need a vendor prefix and can be set as follows: -NOTE: Since Selenium 4 the `DesiredCapabilties` are replaced by browser options (https://www.selenium.dev/documentation/webdriver/getting_started/upgrade_to_selenium_4). +[source,java] +---- +Map customCaps = new HashMap<>(); +customCaps.put("foo", "bar"); + +WEB_DRIVER_MANAGER.setUserAgentConfig(Browsers.firefox, (FirefoxConfig) options -> { + options.setCapability("custom:caps", customCaps); +}); +---- + +NOTE: Have a look into <> for specific browser options. = Request capabilities @@ -25,32 +35,21 @@ Some WebDriverRequests support setting capabilities, like the `DesktopWebDriverR [source,java] ---- DesktopWebDriverRequest request = new DesktopWebDriverRequest(); -DesiredCapabilities caps = request.getDesiredCapabilities(); +MutableCapabilities caps = request.getMutableCapabilities(); caps.setCapability(CapabilityType.ACCEPT_INSECURE_CERTS, true); + // Start your session with the DesktopWebDriverRequest object WebDriver webDriver = WEB_DRIVER_MANAGER.getWebDriver(request); ---- [NOTE] ===== -Have a look into <> for specific browser options. + -Find some more details for `DesktopWebDriverRequest` at <<_request_configuration>>. +* Have a look into <> for specific browser options. +* Find some more details for `DesktopWebDriverRequest` at <<_request_configuration>>. +* Since Selenium 4 browser options should use instead of `DesiredCapabilties` (https://www.selenium.dev/documentation/webdriver/getting_started/upgrade_to_selenium_4). + +Therefore `request.getDesiredCapabilities()` is deprecated. ===== -= Custom capabilties - -Non-standard capabilties need a vendor prefix and can be set as follows: - -[source,java] ----- -Map customCaps = new HashMap<>(); -customCaps.put("foo", "bar"); - -WEB_DRIVER_MANAGER.setUserAgentConfig(Browsers.firefox, (FirefoxConfig) options -> { - options.setCapability("custom:caps", customCaps); -}); ----- - = Global capabilities with `WEB_DRIVER_MANAGER` (*@deprecated*) NOTE: This feature is deprecated, please use <> diff --git a/docs/src/docs/selenium4/selenium4-cdp.adoc b/docs/src/docs/selenium4/selenium4-cdp.adoc index 0d7c29d86b..fb633c06a2 100644 --- a/docs/src/docs/selenium4/selenium4-cdp.adoc +++ b/docs/src/docs/selenium4/selenium4-cdp.adoc @@ -4,7 +4,12 @@ Selenium 4 supports the access to the Chrome developer tools. Testerra provides You can find some more examples at https://www.selenium.dev/documentation/webdriver/bidirectional/chrome_devtools/. -NOTE: As the name says, it only works in Chrome browser. :-) +[NOTE] +==== +* As the name says, it only works in Chrome browser. :-) +* If you're running your tests against a grid, check the CDP compatible Chrome versions in https://github.com/SeleniumHQ/selenium/blob/trunk/java/CHANGELOG[Selenium release notes] +==== + == Set basic authentication diff --git a/integration-tests/src/test/java/eu/tsystems/mms/tic/testframework/playground/Selenium4_vs_3_Tests.java b/integration-tests/src/test/java/eu/tsystems/mms/tic/testframework/playground/Selenium4_vs_3_Tests.java index 926b83794f..1c7495d377 100644 --- a/integration-tests/src/test/java/eu/tsystems/mms/tic/testframework/playground/Selenium4_vs_3_Tests.java +++ b/integration-tests/src/test/java/eu/tsystems/mms/tic/testframework/playground/Selenium4_vs_3_Tests.java @@ -5,6 +5,7 @@ import eu.tsystems.mms.tic.testframework.webdrivermanager.DesktopWebDriverRequest; import org.openqa.selenium.MutableCapabilities; import org.openqa.selenium.WebDriver; +import org.openqa.selenium.remote.CapabilityType; import org.openqa.selenium.remote.DesiredCapabilities; import org.testng.annotations.Test; @@ -34,6 +35,22 @@ public void testBrowserVersionAgainstSeleniumStandalone() throws MalformedURLExc WebDriver webDriver = WEB_DRIVER_MANAGER.getWebDriver(request); } + @Test + public void testBrowserCapsW3C_Selenium3() { + DesktopWebDriverRequest request = new DesktopWebDriverRequest(); + DesiredCapabilities caps = request.getDesiredCapabilities(); + caps.setCapability(CapabilityType.ACCEPT_INSECURE_CERTS, true); + WebDriver webDriver = WEB_DRIVER_MANAGER.getWebDriver(request); + } + + @Test + public void testBrowserCapsW3C_Selenium4() { + DesktopWebDriverRequest request = new DesktopWebDriverRequest(); + MutableCapabilities caps = request.getMutableCapabilities(); + caps.setCapability(CapabilityType.ACCEPT_INSECURE_CERTS, true); + WebDriver webDriver = WEB_DRIVER_MANAGER.getWebDriver(request); + } + @Test public void testBrowserCustomCaps_Selenium3() { DesktopWebDriverRequest request = new DesktopWebDriverRequest(); From b86da82c02033822ea141c32a7214585f2835ba1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Gro=C3=9Fmann?= Date: Thu, 27 Jul 2023 16:44:29 +0200 Subject: [PATCH 60/64] Added gradle wrapper to fix Gradle version --- .gitignore | 2 - gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 59821 bytes gradle/wrapper/gradle-wrapper.properties | 5 + gradlew | 234 +++++++++++++++++++++++ gradlew.bat | 89 +++++++++ 5 files changed, 328 insertions(+), 2 deletions(-) create mode 100644 gradle/wrapper/gradle-wrapper.jar create mode 100644 gradle/wrapper/gradle-wrapper.properties create mode 100644 gradlew create mode 100644 gradlew.bat diff --git a/.gitignore b/.gitignore index 9b061caa90..5b1b4adde5 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,6 @@ test-report **/report-testsundertest-* .gradle -gradle *.iml .idea target @@ -9,7 +8,6 @@ licenses *.zip out build -gradlew /bin/ /.classpath /.project diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..41d9927a4d4fb3f96a785543079b8df6723c946b GIT binary patch literal 59821 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 literal 0 HcmV?d00001 diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000000..070cb702f0 --- /dev/null +++ b/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,5 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-7.6-bin.zip +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew new file mode 100644 index 0000000000..1b6c787337 --- /dev/null +++ b/gradlew @@ -0,0 +1,234 @@ +#!/bin/sh + +# +# Copyright © 2015-2021 the original authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +############################################################################## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# +############################################################################## + +# Attempt to set APP_HOME + +# Resolve links: $0 may be a link +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac +done + +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit + +APP_NAME="Gradle" +APP_BASE_NAME=${0##*/} + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD=maximum + +warn () { + echo "$*" +} >&2 + +die () { + echo + echo "$*" + echo + exit 1 +} >&2 + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD=$JAVA_HOME/jre/sh/java + else + JAVACMD=$JAVA_HOME/bin/java + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD=java + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac +fi + +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +fi + +# Collect all arguments for the java command; +# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of +# shell script including quotes and variable substitutions, so put them in +# double quotes to make sure that they get re-expanded; and +# * put everything else in single quotes, so that it's not re-expanded. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + +exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat new file mode 100644 index 0000000000..107acd32c4 --- /dev/null +++ b/gradlew.bat @@ -0,0 +1,89 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto execute + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega From c7c1f1ad28fa83fd09f8a521e75e26a2b32dea76 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Gro=C3=9Fmann?= Date: Thu, 27 Jul 2023 17:16:46 +0200 Subject: [PATCH 61/64] Cleanup --- .../tic/testframework/webdrivermanager/WebDriverRequest.java | 2 +- integration-tests/src/test/resources/test.properties | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/core/src/main/java/eu/tsystems/mms/tic/testframework/webdrivermanager/WebDriverRequest.java b/core/src/main/java/eu/tsystems/mms/tic/testframework/webdrivermanager/WebDriverRequest.java index c3ca84b0a3..f6d6514bc4 100644 --- a/core/src/main/java/eu/tsystems/mms/tic/testframework/webdrivermanager/WebDriverRequest.java +++ b/core/src/main/java/eu/tsystems/mms/tic/testframework/webdrivermanager/WebDriverRequest.java @@ -3,7 +3,6 @@ import org.openqa.selenium.Capabilities; import java.net.URL; -import java.util.Map; import java.util.Optional; public interface WebDriverRequest extends Cloneable { @@ -22,5 +21,6 @@ public interface WebDriverRequest extends Cloneable { void setShutdownAfterExecution(boolean shutdownAfterExecution); Optional getServerUrl(); + WebDriverRequest clone() throws CloneNotSupportedException; } diff --git a/integration-tests/src/test/resources/test.properties b/integration-tests/src/test/resources/test.properties index 00adb02420..6f7575b388 100644 --- a/integration-tests/src/test/resources/test.properties +++ b/integration-tests/src/test/resources/test.properties @@ -7,7 +7,7 @@ tt.browser.maximize=false tt.window.size=800x600 #tt.browser.version=106 -tt.selenium.server.host=localhost +#tt.selenium.server.host=localhost tt.element.timeout.seconds=2 tt.report.screencaster.active=false From 41d90e4e987ca46472bd61f46254b2c3ae4f70b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Gro=C3=9Fmann?= Date: Thu, 27 Jul 2023 17:33:32 +0200 Subject: [PATCH 62/64] Updated comments --- .../webdrivermanager/DesktopWebDriverFactory.java | 4 ++-- .../tic/testframework/webdrivermanager/HttpClientFactory.java | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/driver-ui-desktop/src/main/java/eu/tsystems/mms/tic/testframework/webdrivermanager/DesktopWebDriverFactory.java b/driver-ui-desktop/src/main/java/eu/tsystems/mms/tic/testframework/webdrivermanager/DesktopWebDriverFactory.java index 03a27a783e..ca4de47f4a 100644 --- a/driver-ui-desktop/src/main/java/eu/tsystems/mms/tic/testframework/webdrivermanager/DesktopWebDriverFactory.java +++ b/driver-ui-desktop/src/main/java/eu/tsystems/mms/tic/testframework/webdrivermanager/DesktopWebDriverFactory.java @@ -343,9 +343,9 @@ private WebDriver startNewWebDriverSession(DesktopWebDriverRequest request, Sess try { if (request.getServerUrl().isPresent()) { final URL seleniumUrl = request.getServerUrl().get(); - // TODO: Reduced timeouts of Selenium 3, needed in Selenium 4? + // The old HttpClientFactory reduced timeouts of Selenium 3 because of very long timeouts + // Selenium 4 uses JDK 11 HttpClient: connectionTimeout=10sec, readTimeout=180 sec, seems to be ok // final HttpCommandExecutor httpCommandExecutor = new HttpCommandExecutor(new HashMap<>(), seleniumUrl, new HttpClientFactory()); -// final HttpCommandExecutor httpCommandExecutor = new HttpCommandExecutor(new HashMap<>(), seleniumUrl); Capabilities capabilities = request.getCapabilities(); if (capabilities == null) { throw new SystemException("Cannot start browser session with empty browser options"); diff --git a/driver-ui-desktop/src/main/java/eu/tsystems/mms/tic/testframework/webdrivermanager/HttpClientFactory.java b/driver-ui-desktop/src/main/java/eu/tsystems/mms/tic/testframework/webdrivermanager/HttpClientFactory.java index 28d385aa06..d348ca14c3 100644 --- a/driver-ui-desktop/src/main/java/eu/tsystems/mms/tic/testframework/webdrivermanager/HttpClientFactory.java +++ b/driver-ui-desktop/src/main/java/eu/tsystems/mms/tic/testframework/webdrivermanager/HttpClientFactory.java @@ -43,7 +43,7 @@ class HttpClientFactory implements HttpClient.Factory { * This class was used to set a custom timeout for sending commands to browser sessions. Selenium 3 has a default of 120 minutes. This was reduced to 2 minutes. * * For using in Selenium 4 this class has to re-implement because Selenium 4 uses HttpClient of Java 11. - * + * Selenium 4 has the following default timeouts: connectionTimeout=10sec, readTimeout=180 sec, seems to be ok */ private final Duration factoryConnectionTimeout = Duration.ofSeconds(120); // Kill, when connect does not succeed in this timeout From a1781fe50546e9433c7af793dde495de6f14ffd5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Gro=C3=9Fmann?= Date: Thu, 27 Jul 2023 17:35:29 +0200 Subject: [PATCH 63/64] Updated comment --- .../testframework/webdrivermanager/DesktopWebDriverFactory.java | 1 + 1 file changed, 1 insertion(+) diff --git a/driver-ui-desktop/src/main/java/eu/tsystems/mms/tic/testframework/webdrivermanager/DesktopWebDriverFactory.java b/driver-ui-desktop/src/main/java/eu/tsystems/mms/tic/testframework/webdrivermanager/DesktopWebDriverFactory.java index ca4de47f4a..15e824e3a2 100644 --- a/driver-ui-desktop/src/main/java/eu/tsystems/mms/tic/testframework/webdrivermanager/DesktopWebDriverFactory.java +++ b/driver-ui-desktop/src/main/java/eu/tsystems/mms/tic/testframework/webdrivermanager/DesktopWebDriverFactory.java @@ -345,6 +345,7 @@ private WebDriver startNewWebDriverSession(DesktopWebDriverRequest request, Sess final URL seleniumUrl = request.getServerUrl().get(); // The old HttpClientFactory reduced timeouts of Selenium 3 because of very long timeouts // Selenium 4 uses JDK 11 HttpClient: connectionTimeout=10sec, readTimeout=180 sec, seems to be ok + // see {@link org.openqa.selenium.remote.http.ClientConfig#defaultConfig()} // final HttpCommandExecutor httpCommandExecutor = new HttpCommandExecutor(new HashMap<>(), seleniumUrl, new HttpClientFactory()); Capabilities capabilities = request.getCapabilities(); if (capabilities == null) { From 634a3ed1c080b1b93f99e8049ea54e3a98256d76 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Gro=C3=9Fmann?= Date: Fri, 28 Jul 2023 10:59:11 +0200 Subject: [PATCH 64/64] Added W3C link with standard capabilities --- docs/src/docs/browsercaps/setting-browser-caps.adoc | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/docs/src/docs/browsercaps/setting-browser-caps.adoc b/docs/src/docs/browsercaps/setting-browser-caps.adoc index f11236ce94..da8e7f8fa9 100644 --- a/docs/src/docs/browsercaps/setting-browser-caps.adoc +++ b/docs/src/docs/browsercaps/setting-browser-caps.adoc @@ -25,7 +25,11 @@ WEB_DRIVER_MANAGER.setUserAgentConfig(Browsers.firefox, (FirefoxConfig) options }); ---- -NOTE: Have a look into <> for specific browser options. +[NOTE] +==== +* Have a look into <> for specific browser options. +* See https://www.w3.org/TR/webdriver1/#capabilities[here] a list of W3C conform capabilities. +==== = Request capabilities