From b604d131967d51f63bacafc4c4d508ee7fafa5f2 Mon Sep 17 00:00:00 2001 From: "n.rusak" Date: Tue, 31 Oct 2023 18:11:25 +0000 Subject: [PATCH 1/9] Removed webDriverManager (redundant for new Selenium version) --- pom.xml | 2 +- .../java/aquality/selenium/browser/LocalBrowserFactory.java | 6 ------ 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/pom.xml b/pom.xml index 6547771..22c0765 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ com.github.aquality-automation aquality-selenium - 4.0.0 + 4.0.1 jar Aquality Selenium Library around Selenium WebDriver diff --git a/src/main/java/aquality/selenium/browser/LocalBrowserFactory.java b/src/main/java/aquality/selenium/browser/LocalBrowserFactory.java index 555600f..516d712 100644 --- a/src/main/java/aquality/selenium/browser/LocalBrowserFactory.java +++ b/src/main/java/aquality/selenium/browser/LocalBrowserFactory.java @@ -39,15 +39,9 @@ protected RemoteWebDriver getDriver() { switch (browserName) { case CHROME: case YANDEX: - WebDriverManager.chromedriver().driverVersion(webDriverVersion).setup(); - driver = new ChromeDriver((ChromeOptions) driverSettings.getDriverOptions()); - break; - case OPERA: - WebDriverManager.operadriver().driverVersion(webDriverVersion).setup(); driver = new ChromeDriver((ChromeOptions) driverSettings.getDriverOptions()); break; case FIREFOX: - WebDriverManager.firefoxdriver().driverVersion(webDriverVersion).setup(); driver = new FirefoxDriver((FirefoxOptions) driverSettings.getDriverOptions()); break; case IEXPLORER: From e1fbce378e1de9995885850c9e4b460fdf197076 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alaksiej=20Miale=C5=A1ka?= Date: Sat, 20 Jan 2024 03:40:40 +0100 Subject: [PATCH 2/9] Remove WebDriverManager dependency and update to Selenium 4.13 +semver: feature (#130) * Remove WebDriverManager dependency and update to Selenium 4.13 - As now built-in Selenium Manager allows to download driver, we don't need to maintain webDriverManager dependency. - updated core library to use Selenium 4.13 (latest supported for Java 8) - removed jackson-databind dependency - update testng to 7.5.1 (latest supported for Java 8) - added commons-lang dependency - add workflow to automatically deploy to maven central after PR merge * Update tests * Update the-internet URL in tests to use https --- .github/workflows/release-maven-central.yml | 61 +++++++++++++++++++ LICENSE | 2 +- pom.xml | 31 ++++++---- .../aquality/selenium/browser/Browser.java | 15 ++--- .../aquality/selenium/browser/JavaScript.java | 27 ++++++-- .../selenium/browser/LocalBrowserFactory.java | 10 +-- .../browser/devtools/DevToolsHandling.java | 3 +- .../browser/devtools/JavaScriptHandling.java | 5 +- .../configuration/BrowserProfile.java | 5 +- .../driversettings/DriverSettings.java | 17 ------ .../driversettings/IDriverSettings.java | 13 ---- .../driversettings/IExplorerSettings.java | 2 +- .../driversettings/OperaSettings.java | 27 -------- .../driversettings/SafariSettings.java | 2 +- src/main/resources/settings.json | 21 ------- src/test/java/forms/MyLocationForm.java | 11 +++- .../java/manytools/RequestHeadersForm.java | 3 +- .../tests/usecases/BrowserFactoryTests.java | 2 - .../devtools/DeviceEmulationTest.java | 4 +- .../devtools/NetworkInterceptionTests.java | 5 +- .../devtools/NetworkSpeedEmulationTest.java | 2 +- .../devtools/OverrideUserAgentTest.java | 2 +- .../java/theinternet/TheInternetPage.java | 2 +- .../theinternet/forms/JQueryMenuForm.java | 2 +- .../theinternet/forms/TheInternetForm.java | 2 +- src/test/resources/settings.incorrect.json | 4 -- src/test/resources/settings.json | 21 ------- src/test/resources/settings.local.json | 4 -- 28 files changed, 136 insertions(+), 169 deletions(-) create mode 100644 .github/workflows/release-maven-central.yml delete mode 100644 src/main/java/aquality/selenium/configuration/driversettings/OperaSettings.java diff --git a/.github/workflows/release-maven-central.yml b/.github/workflows/release-maven-central.yml new file mode 100644 index 0000000..75fd3f3 --- /dev/null +++ b/.github/workflows/release-maven-central.yml @@ -0,0 +1,61 @@ +name: Publish package to Maven Central +on: + pull_request: + branches: + - master + types: [closed] + +jobs: + publish: + if: github.event.pull_request.merged == true + runs-on: ubuntu-latest + steps: + - name: Step 1 - Checkout code + uses: actions/checkout@v3 + with: + fetch-depth: 0 + + - name: Step 2 - Set up Maven Central Repository + uses: actions/setup-java@v3 + with: + java-version: "8" + distribution: "adopt" + server-id: ossrh + server-username: MVN_CENTRAL_USERNAME + server-password: MVN_CENTRAL_PASSWORD + gpg-private-key: ${{ secrets.GPG_SECRET_KEY }} + gpg-passphrase: MVN_GPG_PASSPHRASE + + - name: Step 3 - Install GitVersion + uses: gittools/actions/gitversion/setup@v0 + with: + versionSpec: '5.x' + + - name: Step 4 - Determine Version + id: gitversion + uses: gittools/actions/gitversion/execute@v0 + with: + useConfigFile: true + + - name: Step 5 - Create Release + id: create_release + uses: actions/create-release@latest + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + TITLE: ${{ github.event.pull_request.title }} + BODY: ${{ github.event.pull_request.body }} + VERSION: "v${{ steps.gitversion.outputs.semVer }}" + with: + tag_name: ${{ env.VERSION }} + release_name: ${{ env.VERSION }} ${{ env.TITLE }} + body: ${{ env.BODY }} + draft: false + prerelease: false + + - name: Step 6 - Publish package + run: | + mvn -Dmaven.test.skip=true -P release -Drevision=${{ steps.gitversion.outputs.semVer }} deploy + env: + MVN_CENTRAL_USERNAME: ${{ secrets.OSSRH_USERNAME }} + MVN_CENTRAL_PASSWORD: ${{ secrets.OSSRH_TOKEN }} + MVN_GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }} diff --git a/LICENSE b/LICENSE index a6ceff9..ecef83a 100644 --- a/LICENSE +++ b/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright 2023 Aquality Automation + Copyright 2024 Aquality Automation Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pom.xml b/pom.xml index 22c0765..e23c67a 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ com.github.aquality-automation aquality-selenium - 4.0.1 + ${revision} jar Aquality Selenium Library around Selenium WebDriver @@ -15,6 +15,7 @@ UTF-8 UTF-8 + 4.0.0-SNAPSHOT @@ -81,25 +82,22 @@ com.github.aquality-automation aquality-selenium-core - 3.0.0 + 3.1.0 - - io.github.bonigarcia - webdrivermanager - 5.3.2 + org.apache.commons + commons-lang3 + 3.13.0 - - com.fasterxml.jackson.core - jackson-databind - 2.14.2 + org.slf4j + slf4j-simple + 2.0.10 - org.testng testng - 7.5 + 7.5.1 test @@ -187,6 +185,9 @@ org.apache.maven.plugins maven-javadoc-plugin + + 8 + attach-javadocs @@ -207,6 +208,12 @@ sign + + + --pinentry-mode + loopback + + diff --git a/src/main/java/aquality/selenium/browser/Browser.java b/src/main/java/aquality/selenium/browser/Browser.java index 8b6a998..e10ec5f 100644 --- a/src/main/java/aquality/selenium/browser/Browser.java +++ b/src/main/java/aquality/selenium/browser/Browser.java @@ -9,8 +9,6 @@ import aquality.selenium.core.localization.ILocalizationManager; import aquality.selenium.core.localization.ILocalizedLogger; import aquality.selenium.core.waitings.IConditionalWait; -import org.apache.commons.io.IOUtils; -import org.apache.commons.lang3.NotImplementedException; import org.openqa.selenium.*; import org.openqa.selenium.WebDriver.Navigation; import org.openqa.selenium.devtools.HasDevTools; @@ -21,7 +19,6 @@ import java.io.File; import java.io.IOException; -import java.nio.charset.StandardCharsets; import java.time.Duration; import java.util.function.Supplier; @@ -147,7 +144,8 @@ public IBrowserTabNavigation tabs() { } /** - * Sets page load timeout (Will be ignored for Safari https://github.com/SeleniumHQ/selenium-google-code-issue-archive/issues/687) + * Sets page load timeout (Will be ignored for Safari + * ...) * * @param timeout seconds to wait */ @@ -248,10 +246,9 @@ public Object executeAsyncScript(JavaScript scriptName, Object... args) { * @param file Java Script file * @param arguments Arguments for the script (web elements, values etc. * @return Result object of script execution - * @throws IOException in case of problems with the File */ - public Object executeAsyncScript(final File file, Object... arguments) throws IOException { - return executeAsyncScript(IOUtils.toString(file.toURI(), StandardCharsets.UTF_8.name()), arguments); + public Object executeAsyncScript(final File file, Object... arguments) { + return executeAsyncScript(JavaScript.readScript(file), arguments); } /** @@ -303,7 +300,7 @@ public Object executeScript(JavaScript scriptName, Object... args) { * @throws IOException in case of problems with the File */ public Object executeScript(final File file, Object... arguments) throws IOException { - return executeScript(IOUtils.toString(file.toURI(), StandardCharsets.UTF_8.name()), arguments); + return executeScript(JavaScript.readScript(file), arguments); } /** @@ -400,7 +397,7 @@ public DevToolsHandling devTools() { return devTools; } else { - throw new NotImplementedException("DevTools protocol is not supported for current browser."); + throw new UnsupportedOperationException("DevTools protocol is not supported for current browser."); } } diff --git a/src/main/java/aquality/selenium/browser/JavaScript.java b/src/main/java/aquality/selenium/browser/JavaScript.java index b9a4c19..967b769 100644 --- a/src/main/java/aquality/selenium/browser/JavaScript.java +++ b/src/main/java/aquality/selenium/browser/JavaScript.java @@ -1,12 +1,12 @@ package aquality.selenium.browser; import aquality.selenium.core.logging.Logger; -import org.apache.commons.io.IOUtils; +import org.apache.logging.log4j.core.util.IOUtils; -import java.io.IOException; -import java.io.InputStream; +import java.io.*; import java.net.URL; import java.nio.charset.StandardCharsets; +import java.nio.file.Files; import static java.lang.String.format; @@ -59,11 +59,28 @@ public String getScript() { URL scriptFile = getClass().getResource("/js/" + filename); if (scriptFile != null) { try (InputStream stream = scriptFile.openStream()) { - return IOUtils.toString(stream, StandardCharsets.UTF_8.name()); + return readScript(stream); } catch (IOException e) { - Logger.getInstance().fatal(format("Couldn't find the script \"%s\"", filename), e); + logScriptAbsence(filename, e); } } return ""; } + + static String readScript(final File file) { + try (InputStream stream = Files.newInputStream(file.toPath())) { + return readScript(stream); + } catch (IOException e) { + logScriptAbsence(file.getName(), e); + return ""; + } + } + + private static void logScriptAbsence(String filename, IOException e) { + Logger.getInstance().fatal(format("Couldn't find the script \"%s\"", filename), e); + } + + private static String readScript(InputStream stream) throws IOException { + return IOUtils.toString(new BufferedReader(new InputStreamReader(stream, StandardCharsets.UTF_8))); + } } diff --git a/src/main/java/aquality/selenium/browser/LocalBrowserFactory.java b/src/main/java/aquality/selenium/browser/LocalBrowserFactory.java index 516d712..c53963b 100644 --- a/src/main/java/aquality/selenium/browser/LocalBrowserFactory.java +++ b/src/main/java/aquality/selenium/browser/LocalBrowserFactory.java @@ -4,9 +4,6 @@ import aquality.selenium.configuration.driversettings.IDriverSettings; import aquality.selenium.core.localization.ILocalizedLogger; import aquality.selenium.core.utilities.IActionRetrier; -import io.github.bonigarcia.wdm.WebDriverManager; -import io.github.bonigarcia.wdm.config.Architecture; -import org.openqa.selenium.Capabilities; import org.openqa.selenium.chrome.ChromeDriver; import org.openqa.selenium.chrome.ChromeOptions; import org.openqa.selenium.edge.EdgeDriver; @@ -15,7 +12,6 @@ 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.RemoteWebDriver; import org.openqa.selenium.safari.SafariDriver; import org.openqa.selenium.safari.SafariOptions; @@ -34,8 +30,6 @@ protected RemoteWebDriver getDriver() { BrowserName browserName = browserProfile.getBrowserName(); RemoteWebDriver driver; IDriverSettings driverSettings = browserProfile.getDriverSettings(); - String webDriverVersion = driverSettings.getWebDriverVersion(); - Architecture systemArchitecture = driverSettings.getSystemArchitecture(); switch (browserName) { case CHROME: case YANDEX: @@ -45,18 +39,16 @@ protected RemoteWebDriver getDriver() { driver = new FirefoxDriver((FirefoxOptions) driverSettings.getDriverOptions()); break; case IEXPLORER: - WebDriverManager.iedriver().architecture(systemArchitecture).driverVersion(webDriverVersion).setup(); driver = new InternetExplorerDriver((InternetExplorerOptions) driverSettings.getDriverOptions()); break; case EDGE: - WebDriverManager.edgedriver().driverVersion(webDriverVersion).setup(); driver = new EdgeDriver((EdgeOptions) driverSettings.getDriverOptions()); break; case SAFARI: driver = new SafariDriver((SafariOptions) driverSettings.getDriverOptions()); break; default: - throw new IllegalArgumentException(String.format("Browser [%s] is not supported.", browserName)); + throw new UnsupportedOperationException(String.format("Browser [%s] is not supported.", browserName)); } return driver; } diff --git a/src/main/java/aquality/selenium/browser/devtools/DevToolsHandling.java b/src/main/java/aquality/selenium/browser/devtools/DevToolsHandling.java index 387eb9c..6187ec5 100644 --- a/src/main/java/aquality/selenium/browser/devtools/DevToolsHandling.java +++ b/src/main/java/aquality/selenium/browser/devtools/DevToolsHandling.java @@ -2,7 +2,6 @@ import aquality.selenium.browser.AqualityServices; import aquality.selenium.core.localization.ILocalizedLogger; -import org.apache.commons.lang3.NotImplementedException; import org.openqa.selenium.chromium.ChromiumDriver; import org.openqa.selenium.devtools.Command; import org.openqa.selenium.devtools.DevTools; @@ -132,7 +131,7 @@ public Map executeCdpCommand(String commandName, Map getPinnedScripts() { logger.info("loc.browser.javascript.snippets.get"); @@ -227,7 +226,7 @@ public void onLogEvent(EventType kind) { } }).augment(driver); if (!(driver instanceof HasLogEvents)) { - throw new NotImplementedException( + throw new UnsupportedOperationException( String.format("Driver for the current browser [%s] doesn't implement HasLogEvents", browserName)); } } diff --git a/src/main/java/aquality/selenium/configuration/BrowserProfile.java b/src/main/java/aquality/selenium/configuration/BrowserProfile.java index 0dc583a..55206fe 100644 --- a/src/main/java/aquality/selenium/configuration/BrowserProfile.java +++ b/src/main/java/aquality/selenium/configuration/BrowserProfile.java @@ -49,9 +49,6 @@ public IDriverSettings getDriverSettings() { case IEXPLORER: driverSettings = new IExplorerSettings(settingsFile); break; - case OPERA: - driverSettings = new OperaSettings(settingsFile); - break; case SAFARI: driverSettings = new SafariSettings(settingsFile); break; @@ -59,7 +56,7 @@ public IDriverSettings getDriverSettings() { driverSettings = new YandexSettings(settingsFile); break; default: - throw new IllegalArgumentException("There are no assigned behaviour for retrieving driver driversettings for browser " + getBrowserName()); + throw new UnsupportedOperationException("There are no assigned behaviour for retrieving driver driversettings for browser " + getBrowserName()); } return driverSettings; } diff --git a/src/main/java/aquality/selenium/configuration/driversettings/DriverSettings.java b/src/main/java/aquality/selenium/configuration/driversettings/DriverSettings.java index 96092b4..5c804fd 100644 --- a/src/main/java/aquality/selenium/configuration/driversettings/DriverSettings.java +++ b/src/main/java/aquality/selenium/configuration/driversettings/DriverSettings.java @@ -4,7 +4,6 @@ import aquality.selenium.core.localization.ILocalizationManager; import aquality.selenium.core.logging.Logger; import aquality.selenium.core.utilities.ISettingsFile; -import io.github.bonigarcia.wdm.config.Architecture; import org.apache.commons.lang3.StringUtils; import org.openqa.selenium.MutableCapabilities; import org.openqa.selenium.PageLoadStrategy; @@ -101,22 +100,6 @@ private final void logCollection(String messageKey, final T... elements) { } } - @Override - public String getWebDriverVersion() { - return String.valueOf(getSettingsFile().getValueOrDefault( - getDriverSettingsPath("webDriverVersion"), "Latest")); - } - - @Override - public Architecture getSystemArchitecture() { - String strValue = String.valueOf(getSettingsFile().getValueOrDefault( - getDriverSettingsPath("systemArchitecture"), "Auto")); - return Arrays.stream(Architecture.values()) - .filter(value -> value.name().equals(strValue)) - .findFirst() - .orElse(Architecture.X32); - } - @Override public PageLoadStrategy getPageLoadStrategy() { String value = (String) getSettingsFile().getValueOrDefault(getDriverSettingsPath("pageLoadStrategy"), "normal"); diff --git a/src/main/java/aquality/selenium/configuration/driversettings/IDriverSettings.java b/src/main/java/aquality/selenium/configuration/driversettings/IDriverSettings.java index 912d4b8..43fd1d4 100644 --- a/src/main/java/aquality/selenium/configuration/driversettings/IDriverSettings.java +++ b/src/main/java/aquality/selenium/configuration/driversettings/IDriverSettings.java @@ -1,7 +1,6 @@ package aquality.selenium.configuration.driversettings; import aquality.selenium.browser.BrowserName; -import io.github.bonigarcia.wdm.config.Architecture; import org.openqa.selenium.Capabilities; import org.openqa.selenium.PageLoadStrategy; import org.openqa.selenium.remote.AbstractDriverOptions; @@ -23,18 +22,6 @@ public interface IDriverSettings { */ PageLoadStrategy getPageLoadStrategy(); - /** - * Gets version of web driver for WebDriverManager. - * @return Version of web driver. - */ - String getWebDriverVersion(); - - /** - * Gets target system architecture for WebDriverManager. - * @return initialized {@link Architecture}. - */ - Architecture getSystemArchitecture(); - /** * Gets download directory for web driver. * @return Path to download directory. diff --git a/src/main/java/aquality/selenium/configuration/driversettings/IExplorerSettings.java b/src/main/java/aquality/selenium/configuration/driversettings/IExplorerSettings.java index 9269c80..b2ae379 100644 --- a/src/main/java/aquality/selenium/configuration/driversettings/IExplorerSettings.java +++ b/src/main/java/aquality/selenium/configuration/driversettings/IExplorerSettings.java @@ -22,7 +22,7 @@ public AbstractDriverOptions getDriverOptions() { @Override public String getDownloadDirCapabilityKey() { - throw new IllegalArgumentException("Download directory for Internet Explorer profiles is not supported"); + throw new UnsupportedOperationException("Download directory for Internet Explorer profiles is not supported"); } @Override diff --git a/src/main/java/aquality/selenium/configuration/driversettings/OperaSettings.java b/src/main/java/aquality/selenium/configuration/driversettings/OperaSettings.java deleted file mode 100644 index 30ca499..0000000 --- a/src/main/java/aquality/selenium/configuration/driversettings/OperaSettings.java +++ /dev/null @@ -1,27 +0,0 @@ -package aquality.selenium.configuration.driversettings; - -import aquality.selenium.browser.BrowserName; -import aquality.selenium.core.utilities.ISettingsFile; -import org.openqa.selenium.chrome.ChromeOptions; -import org.openqa.selenium.remote.AbstractDriverOptions; - -public class OperaSettings extends ChromeSettings { - private static final String DEFAULT_BINARY_LOCATION = "%USERPROFILE%\\AppData\\Local\\Programs\\Opera\\launcher.exe"; - - public OperaSettings(ISettingsFile settingsFile) { - super(settingsFile); - } - - @Override - public BrowserName getBrowserName() { - return BrowserName.OPERA; - } - - @Override - public AbstractDriverOptions getDriverOptions() { - ChromeOptions options = (ChromeOptions) super.getDriverOptions(); - options.setExperimentalOption("w3c", true); - options.setBinary(getBinaryLocation(DEFAULT_BINARY_LOCATION)); - return options; - } -} diff --git a/src/main/java/aquality/selenium/configuration/driversettings/SafariSettings.java b/src/main/java/aquality/selenium/configuration/driversettings/SafariSettings.java index 3acd382..14d716d 100644 --- a/src/main/java/aquality/selenium/configuration/driversettings/SafariSettings.java +++ b/src/main/java/aquality/selenium/configuration/driversettings/SafariSettings.java @@ -20,7 +20,7 @@ public AbstractDriverOptions getDriverOptions() { @Override public String getDownloadDirCapabilityKey() { - throw new IllegalArgumentException("Download directory for Safari profiles is not supported in capabilities. Please, use separate 'downloadDir' property"); + throw new UnsupportedOperationException("Download directory for Safari profiles is not supported in capabilities. Please, use separate 'downloadDir' property"); } @Override diff --git a/src/main/resources/settings.json b/src/main/resources/settings.json index 57f0c68..b25b7b0 100644 --- a/src/main/resources/settings.json +++ b/src/main/resources/settings.json @@ -6,7 +6,6 @@ "driverSettings": { "chrome": { - "webDriverVersion": "latest", "capabilities": { }, "options": { @@ -24,7 +23,6 @@ "startArguments": [] }, "edge": { - "webDriverVersion": "latest", "capabilities": { }, "options": { @@ -41,7 +39,6 @@ "startArguments": [] }, "firefox": { - "webDriverVersion": "latest", "capabilities": { }, "options": { @@ -62,32 +59,14 @@ "startArguments": [] }, "iexplorer": { - "webDriverVersion": "latest", - "systemArchitecture": "X32", "capabilities": { "ignoreProtectedModeSettings": true } }, - "opera": { - "webDriverVersion": "latest", - "binaryLocation": "%USERPROFILE%\\AppData\\Local\\Programs\\Opera\\launcher.exe", - "capabilities": { - }, - "options": { - "intl.accept_languages": "en", - "safebrowsing.enabled": "true", - "profile.default_content_settings.popups": "0", - "disable-popup-blocking": "true", - "download.prompt_for_download": "false", - "download.default_directory": "./downloads" - }, - "startArguments": ["--remote-debugging-port=9222", "--no-sandbox", "--disable-dev-shm-usage"] - }, "safari": { "downloadDir": "/Users/username/Downloads" }, "yandex": { - "webDriverVersion": "102.0.5005.61", "binaryLocation": "%USERPROFILE%\\AppData\\Local\\Yandex\\YandexBrowser\\Application\\browser.exe", "capabilities": { }, diff --git a/src/test/java/forms/MyLocationForm.java b/src/test/java/forms/MyLocationForm.java index 39f7007..2d94aed 100644 --- a/src/test/java/forms/MyLocationForm.java +++ b/src/test/java/forms/MyLocationForm.java @@ -1,5 +1,6 @@ package forms; +import aquality.selenium.elements.interfaces.IButton; import aquality.selenium.elements.interfaces.ILabel; import aquality.selenium.forms.Form; import org.openqa.selenium.By; @@ -8,13 +9,21 @@ public class MyLocationForm extends Form { private final ILabel lblLatitude = getElementFactory().getLabel(By.id("latitude"), "Latitude"); private final ILabel lblLongitude = getElementFactory().getLabel(By.id("longitude"), "Longitude"); + private final IButton btnConsent = getElementFactory().getButton(By.xpath("//button[@aria-label='Consent']"), "Consent"); public MyLocationForm() { super(By.xpath("//h1[contains(text(),'My Location')]"), "My Location"); } public double getLatitude() { - return Double.parseDouble(lblLatitude.getText()); + if (!lblLatitude.state().isDisplayed() && btnConsent.state().isDisplayed()) { + clickConsent(); + } + return Double.parseDouble(lblLatitude.getText()); + } + + public void clickConsent() { + btnConsent.click(); } public double getLongitude() { diff --git a/src/test/java/manytools/RequestHeadersForm.java b/src/test/java/manytools/RequestHeadersForm.java index 5cfa3b8..96a5ba6 100644 --- a/src/test/java/manytools/RequestHeadersForm.java +++ b/src/test/java/manytools/RequestHeadersForm.java @@ -1,7 +1,6 @@ package manytools; import aquality.selenium.elements.interfaces.ILabel; -import org.apache.commons.lang3.NotImplementedException; import org.openqa.selenium.By; import java.util.function.Function; @@ -20,7 +19,7 @@ protected String getUrlPart() { @Override public String getValue() { - throw new NotImplementedException("Please call the method getNullableValue with parameter instead"); + throw new UnsupportedOperationException("Please call the method getNullableValue with parameter instead"); } public String getNullableValue(String headerName) { diff --git a/src/test/java/tests/usecases/BrowserFactoryTests.java b/src/test/java/tests/usecases/BrowserFactoryTests.java index 80f46d2..8e4980d 100644 --- a/src/test/java/tests/usecases/BrowserFactoryTests.java +++ b/src/test/java/tests/usecases/BrowserFactoryTests.java @@ -9,7 +9,6 @@ import aquality.selenium.core.utilities.IActionRetrier; import aquality.selenium.core.utilities.ISettingsFile; import com.google.inject.Provider; -import io.github.bonigarcia.wdm.WebDriverManager; import org.openqa.selenium.SessionNotCreatedException; import org.openqa.selenium.TimeoutException; import org.openqa.selenium.WebDriverException; @@ -53,7 +52,6 @@ public void testShouldBePossibleToSetFactory() { private IBrowserFactory getCustomFactory() { return () -> { FirefoxSettings firefoxSettings = new FirefoxSettings(AqualityServices.get(ISettingsFile.class)); - WebDriverManager.firefoxdriver().setup(); FirefoxOptions options = ((FirefoxOptions) firefoxSettings.getDriverOptions()).addArguments("--headless"); final List> handledExceptions = Arrays.asList( SessionNotCreatedException.class, diff --git a/src/test/java/tests/usecases/devtools/DeviceEmulationTest.java b/src/test/java/tests/usecases/devtools/DeviceEmulationTest.java index 346d7eb..c9a6c16 100644 --- a/src/test/java/tests/usecases/devtools/DeviceEmulationTest.java +++ b/src/test/java/tests/usecases/devtools/DeviceEmulationTest.java @@ -3,8 +3,8 @@ import aquality.selenium.browser.AqualityServices; import aquality.selenium.browser.devtools.EmulationHandling; import com.google.common.collect.ImmutableMap; -import org.openqa.selenium.devtools.v110.emulation.Emulation; -import org.openqa.selenium.devtools.v110.emulation.model.DisplayFeature; +import org.openqa.selenium.devtools.v117.emulation.Emulation; +import org.openqa.selenium.devtools.v117.emulation.model.DisplayFeature; import org.testng.Assert; import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; diff --git a/src/test/java/tests/usecases/devtools/NetworkInterceptionTests.java b/src/test/java/tests/usecases/devtools/NetworkInterceptionTests.java index e8bada1..81134ee 100644 --- a/src/test/java/tests/usecases/devtools/NetworkInterceptionTests.java +++ b/src/test/java/tests/usecases/devtools/NetworkInterceptionTests.java @@ -4,7 +4,6 @@ import aquality.selenium.browser.devtools.NetworkHandling; import com.google.common.net.MediaType; import manytools.RequestHeadersForm; -import org.apache.hc.core5.http.HttpStatus; import org.openqa.selenium.devtools.NetworkInterceptor; import org.openqa.selenium.remote.http.HttpHandler; import org.openqa.selenium.remote.http.HttpRequest; @@ -40,7 +39,7 @@ public void testAllRequestsInterception() { WelcomeForm welcomeForm = new WelcomeForm(); NetworkInterceptor interceptor = network().interceptAllRequests(new HttpResponse() - .setStatus(HttpStatus.SC_OK) + .setStatus(200) .addHeader("Content-Type", MediaType.HTML_UTF_8.toString()) .setContent(utf8String(SOME_PHRASE))); Assert.assertNotNull(interceptor, "Network interceptor must not be null"); @@ -56,7 +55,7 @@ public void testAllRequestsInterception() { public void testRequestsInterception() { WelcomeForm welcomeForm = new WelcomeForm(); NetworkInterceptor interceptor = network().startNetworkInterceptor((HttpHandler) request -> new HttpResponse() - .setStatus(HttpStatus.SC_OK) + .setStatus(200) .addHeader("Content-Type", MediaType.HTML_UTF_8.toString()) .setContent(utf8String(SOME_PHRASE))); Assert.assertNotNull(interceptor, "Network interceptor must not be null"); diff --git a/src/test/java/tests/usecases/devtools/NetworkSpeedEmulationTest.java b/src/test/java/tests/usecases/devtools/NetworkSpeedEmulationTest.java index ead1a18..bfbc8ca 100644 --- a/src/test/java/tests/usecases/devtools/NetworkSpeedEmulationTest.java +++ b/src/test/java/tests/usecases/devtools/NetworkSpeedEmulationTest.java @@ -2,7 +2,7 @@ import aquality.selenium.browser.AqualityServices; import org.openqa.selenium.TimeoutException; -import org.openqa.selenium.devtools.v110.network.model.ConnectionType; +import org.openqa.selenium.devtools.v117.network.model.ConnectionType; import org.testng.Assert; import org.testng.annotations.Test; import tests.BaseTest; diff --git a/src/test/java/tests/usecases/devtools/OverrideUserAgentTest.java b/src/test/java/tests/usecases/devtools/OverrideUserAgentTest.java index 1a4386f..d8d0c06 100644 --- a/src/test/java/tests/usecases/devtools/OverrideUserAgentTest.java +++ b/src/test/java/tests/usecases/devtools/OverrideUserAgentTest.java @@ -5,7 +5,7 @@ import manytools.BrowserLanguageForm; import manytools.UserAgentForm; import org.openqa.selenium.devtools.idealized.Network; -import org.openqa.selenium.devtools.v110.emulation.Emulation; +import org.openqa.selenium.devtools.v117.emulation.Emulation; import org.testng.Assert; import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; diff --git a/src/test/java/theinternet/TheInternetPage.java b/src/test/java/theinternet/TheInternetPage.java index 80c1938..c987500 100644 --- a/src/test/java/theinternet/TheInternetPage.java +++ b/src/test/java/theinternet/TheInternetPage.java @@ -13,7 +13,7 @@ public enum TheInternetPage { TABLES, CHALLENGING_DOM; - private static final String BASE_URL = "http://the-internet.herokuapp.com/"; + private static final String BASE_URL = "https://the-internet.herokuapp.com/"; private final String postfix; diff --git a/src/test/java/theinternet/forms/JQueryMenuForm.java b/src/test/java/theinternet/forms/JQueryMenuForm.java index 1b911be..fcbb9b0 100644 --- a/src/test/java/theinternet/forms/JQueryMenuForm.java +++ b/src/test/java/theinternet/forms/JQueryMenuForm.java @@ -5,7 +5,7 @@ import org.openqa.selenium.By; public class JQueryMenuForm extends TheInternetForm { - private final IButton btnEnabled = getElementFactory().getButton(By.id("ui-id-2"), "Enabled"); + private final IButton btnEnabled = getElementFactory().getButton(By.id("ui-id-3"), "Enabled"); public JQueryMenuForm(){ super(By.id("menu"), "JQueryUI menu"); diff --git a/src/test/java/theinternet/forms/TheInternetForm.java b/src/test/java/theinternet/forms/TheInternetForm.java index 67b8603..67bb737 100644 --- a/src/test/java/theinternet/forms/TheInternetForm.java +++ b/src/test/java/theinternet/forms/TheInternetForm.java @@ -10,7 +10,7 @@ public abstract class TheInternetForm extends Form { super(locator, name); } - private static final String THE_INTERNET_FORM_URL = "http://the-internet.herokuapp.com"; + private static final String THE_INTERNET_FORM_URL = "https://the-internet.herokuapp.com"; private final ILink elementalSeleniumLink = getElementFactory().getLink(By.xpath("//a[contains(@href,'elementalselenium')]"), "Elemental Selenium"); public String getUrl() { diff --git a/src/test/resources/settings.incorrect.json b/src/test/resources/settings.incorrect.json index 0e5c550..cf95279 100644 --- a/src/test/resources/settings.incorrect.json +++ b/src/test/resources/settings.incorrect.json @@ -6,7 +6,6 @@ "driverSettings": { "chrome": { - "webDriverVersion": "latest", "capabilities": { }, "options": { @@ -20,7 +19,6 @@ "startArguments": [] }, "firefox": { - "webDriverVersion": "latest", "capabilities": { }, "options": { @@ -41,8 +39,6 @@ "startArguments": [] }, "iexplorer": { - "webDriverVersion": "latest", - "systemArchitecture": "X32", "capabilities": { "ignoreProtectedModeSettings": true } diff --git a/src/test/resources/settings.json b/src/test/resources/settings.json index a20c520..db5aad0 100644 --- a/src/test/resources/settings.json +++ b/src/test/resources/settings.json @@ -6,7 +6,6 @@ "driverSettings": { "chrome": { - "webDriverVersion": "latest", "capabilities": { }, "options": { @@ -23,7 +22,6 @@ "startArguments": [] }, "edge": { - "webDriverVersion": "latest", "capabilities": { }, "options": { @@ -40,7 +38,6 @@ "startArguments": [] }, "firefox": { - "webDriverVersion": "latest", "capabilities": { }, "options": { @@ -61,32 +58,14 @@ "startArguments": [] }, "iexplorer": { - "webDriverVersion": "latest", - "systemArchitecture": "X32", "capabilities": { "ignoreProtectedModeSettings": true } }, - "opera": { - "webDriverVersion": "latest", - "binaryLocation": "%USERPROFILE%\\AppData\\Local\\Programs\\Opera\\launcher.exe", - "capabilities": { - }, - "options": { - "intl.accept_languages": "en", - "safebrowsing.enabled": "true", - "profile.default_content_settings.popups": "0", - "disable-popup-blocking": "true", - "download.prompt_for_download": "false", - "download.default_directory": "./downloads" - }, - "startArguments": ["--remote-debugging-port=9222", "--no-sandbox", "--disable-dev-shm-usage"] - }, "safari": { "downloadDir": "/Users/username/Downloads" }, "yandex": { - "webDriverVersion": "102.0.5005.61", "binaryLocation": "%USERPROFILE%\\AppData\\Local\\Yandex\\YandexBrowser\\Application\\browser.exe", "capabilities": { }, diff --git a/src/test/resources/settings.local.json b/src/test/resources/settings.local.json index 1f82288..cddfee0 100644 --- a/src/test/resources/settings.local.json +++ b/src/test/resources/settings.local.json @@ -6,7 +6,6 @@ "driverSettings": { "chrome": { - "webDriverVersion": "latest", "capabilities": { }, "options": { @@ -23,8 +22,6 @@ "startArguments": [] }, "firefox": { - "webDriverVersion": "latest", - "systemArchitecture": "X32", "capabilities": { }, "options": { @@ -45,7 +42,6 @@ "startArguments": [] }, "iexplorer": { - "webDriverVersion": "latest", "capabilities": { "ignoreProtectedModeSettings": true } From eda9bb427e16217c6b644bbc839fadeea63849e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alaksiej=20Miale=C5=A1ka?= Date: Sat, 20 Jan 2024 04:24:32 +0100 Subject: [PATCH 3/9] Add GitVersion.yml for publishing --- GitVersion.yml | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 GitVersion.yml diff --git a/GitVersion.yml b/GitVersion.yml new file mode 100644 index 0000000..3396b04 --- /dev/null +++ b/GitVersion.yml @@ -0,0 +1,5 @@ +mode: Mainline +increment: Inherit +branches: {} +ignore: + sha: [] \ No newline at end of file From 15dfe95090774dfef4aa67765169ca092d8b65a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alaksiej=20Miale=C5=A1ka?= Date: Sat, 20 Jan 2024 04:32:33 +0100 Subject: [PATCH 4/9] Remove WebDriverManager dependency and update to Selenium 4.13 (#131) - As now built-in Selenium Manager allows to download driver, we don't need to maintain webDriverManager dependency. - updated core library to use Selenium 4.13 (latest compatible with Java 8) - removed jackson-databind dependency - update testng to 7.5.1 (latest compatible with Java 8) - added commons-lang dependency - add workflow to automatically deploy to maven central after PR merge --- GitVersion.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/GitVersion.yml b/GitVersion.yml index 3396b04..d1f11e4 100644 --- a/GitVersion.yml +++ b/GitVersion.yml @@ -2,4 +2,5 @@ mode: Mainline increment: Inherit branches: {} ignore: - sha: [] \ No newline at end of file + sha: [] + From dee591444031a35d03506e27c58d32ecaf6f44cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alaksiej=20Miale=C5=A1ka?= Date: Sat, 20 Jan 2024 04:51:32 +0100 Subject: [PATCH 5/9] Remove WebDriverManager dependency and update to Selenium 4.13.0 (#132) - As now built-in Selenium Manager allows to download driver, we don't need to maintain webDriverManager dependency. - updated core library to use Selenium 4.13.0 (latest compatible with Java 8) - removed jackson-databind dependency - update testng to 7.5.1 (latest compatible with Java 8) - added commons-lang dependency - add workflow to automatically deploy to maven central after PR merge --- pom.xml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pom.xml b/pom.xml index e23c67a..e2a4cb9 100644 --- a/pom.xml +++ b/pom.xml @@ -21,11 +21,11 @@ ossrh - https://oss.sonatype.org/content/repositories/snapshots + https://s01.oss.sonatype.org/content/repositories/snapshots ossrh - https://oss.sonatype.org/service/local/staging/deploy/maven2/ + https://s01.oss.sonatype.org/service/local/staging/deploy/maven2/ @@ -224,7 +224,7 @@ true ossrh - https://oss.sonatype.org/ + https://s01.oss.sonatype.org/ true From ca87db9867a3a979fdac5103f84433637ba24e0a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alaksiej=20Miale=C5=A1ka?= Date: Sat, 20 Jan 2024 20:34:15 +0100 Subject: [PATCH 6/9] Update dependencies and restore jackson databind dependency (#133) aquality.selenium.core dependency was updated to 3.1.1 Updates in the core library: - log4j to 2.22.1 - testng to 7.5.1 - jackson-databind to 2.16.1 - guice to 6.0.0, guava exclusion removed Also scope for slf4j-simple was set to test. --- pom.xml | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index e2a4cb9..a8d9318 100644 --- a/pom.xml +++ b/pom.xml @@ -82,17 +82,23 @@ com.github.aquality-automation aquality-selenium-core - 3.1.0 + 3.1.1 org.apache.commons commons-lang3 3.13.0 + + com.fasterxml.jackson.core + jackson-databind + 2.16.1 + org.slf4j slf4j-simple 2.0.10 + test org.testng From 165e135f3ce859f4a5c758a6179abf464ad40476 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alaksiej=20Miale=C5=A1ka?= Date: Wed, 24 Jan 2024 18:02:46 +0100 Subject: [PATCH 7/9] Support Opera and Yandex browsers (#134) - Add section to settings.json for Opera browser - Add specific OperaSettings with w3c workaround and binary location - Update LocalBrowserFactory to separate Opera and Yandex cases from Chrome. For them, use ChromeDriverService with disabled build check --- .../selenium/browser/LocalBrowserFactory.java | 7 ++++- .../configuration/BrowserProfile.java | 3 +++ .../driversettings/OperaSettings.java | 26 +++++++++++++++++++ src/main/resources/settings.json | 15 +++++++++++ src/test/resources/settings.json | 15 +++++++++++ 5 files changed, 65 insertions(+), 1 deletion(-) create mode 100644 src/main/java/aquality/selenium/configuration/driversettings/OperaSettings.java diff --git a/src/main/java/aquality/selenium/browser/LocalBrowserFactory.java b/src/main/java/aquality/selenium/browser/LocalBrowserFactory.java index c53963b..f2c5056 100644 --- a/src/main/java/aquality/selenium/browser/LocalBrowserFactory.java +++ b/src/main/java/aquality/selenium/browser/LocalBrowserFactory.java @@ -5,6 +5,7 @@ import aquality.selenium.core.localization.ILocalizedLogger; import aquality.selenium.core.utilities.IActionRetrier; import org.openqa.selenium.chrome.ChromeDriver; +import org.openqa.selenium.chrome.ChromeDriverService; import org.openqa.selenium.chrome.ChromeOptions; import org.openqa.selenium.edge.EdgeDriver; import org.openqa.selenium.edge.EdgeOptions; @@ -32,9 +33,13 @@ protected RemoteWebDriver getDriver() { IDriverSettings driverSettings = browserProfile.getDriverSettings(); switch (browserName) { case CHROME: - case YANDEX: driver = new ChromeDriver((ChromeOptions) driverSettings.getDriverOptions()); break; + case YANDEX: + case OPERA: + driver = new ChromeDriver(new ChromeDriverService.Builder().withBuildCheckDisabled(true).build(), + (ChromeOptions) driverSettings.getDriverOptions()); + break; case FIREFOX: driver = new FirefoxDriver((FirefoxOptions) driverSettings.getDriverOptions()); break; diff --git a/src/main/java/aquality/selenium/configuration/BrowserProfile.java b/src/main/java/aquality/selenium/configuration/BrowserProfile.java index 55206fe..404feef 100644 --- a/src/main/java/aquality/selenium/configuration/BrowserProfile.java +++ b/src/main/java/aquality/selenium/configuration/BrowserProfile.java @@ -52,6 +52,9 @@ public IDriverSettings getDriverSettings() { case SAFARI: driverSettings = new SafariSettings(settingsFile); break; + case OPERA: + driverSettings = new OperaSettings(settingsFile); + break; case YANDEX: driverSettings = new YandexSettings(settingsFile); break; diff --git a/src/main/java/aquality/selenium/configuration/driversettings/OperaSettings.java b/src/main/java/aquality/selenium/configuration/driversettings/OperaSettings.java new file mode 100644 index 0000000..e494428 --- /dev/null +++ b/src/main/java/aquality/selenium/configuration/driversettings/OperaSettings.java @@ -0,0 +1,26 @@ +package aquality.selenium.configuration.driversettings; + +import aquality.selenium.browser.BrowserName; +import aquality.selenium.core.utilities.ISettingsFile; +import org.openqa.selenium.chrome.ChromeOptions; +import org.openqa.selenium.remote.AbstractDriverOptions; + +public class OperaSettings extends ChromeSettings { + private static final String DEFAULT_BINARY_LOCATION = "%USERPROFILE%\\AppData\\Local\\Programs\\Opera\\launcher.exe"; + public OperaSettings(ISettingsFile settingsFile) { + super(settingsFile); + } + + @Override + public AbstractDriverOptions getDriverOptions() { + ChromeOptions options = (ChromeOptions) super.getDriverOptions(); + options.setExperimentalOption("w3c", true); + options.setBinary(getBinaryLocation(DEFAULT_BINARY_LOCATION)); + return options; + } + + @Override + public BrowserName getBrowserName() { + return BrowserName.OPERA; + } +} diff --git a/src/main/resources/settings.json b/src/main/resources/settings.json index b25b7b0..7e13b26 100644 --- a/src/main/resources/settings.json +++ b/src/main/resources/settings.json @@ -66,6 +66,21 @@ "safari": { "downloadDir": "/Users/username/Downloads" }, + "opera": { + "binaryLocation": "%USERPROFILE%\\AppData\\Local\\Programs\\Opera\\launcher.exe", + "capabilities": { + "unhandledPromptBehavior": "ignore" + }, + "options": { + "intl.accept_languages": "en", + "safebrowsing.enabled": "true", + "profile.default_content_settings.popups": "0", + "disable-popup-blocking": "true", + "download.prompt_for_download": "false", + "download.default_directory": "./downloads" + }, + "startArguments": [ "--remote-debugging-port=9222", "--no-sandbox", "--disable-dev-shm-usage" ] + }, "yandex": { "binaryLocation": "%USERPROFILE%\\AppData\\Local\\Yandex\\YandexBrowser\\Application\\browser.exe", "capabilities": { diff --git a/src/test/resources/settings.json b/src/test/resources/settings.json index db5aad0..cf0ac09 100644 --- a/src/test/resources/settings.json +++ b/src/test/resources/settings.json @@ -65,6 +65,21 @@ "safari": { "downloadDir": "/Users/username/Downloads" }, + "opera": { + "binaryLocation": "%USERPROFILE%\\AppData\\Local\\Programs\\Opera\\launcher.exe", + "capabilities": { + "unhandledPromptBehavior": "ignore" + }, + "options": { + "intl.accept_languages": "en", + "safebrowsing.enabled": "true", + "profile.default_content_settings.popups": "0", + "disable-popup-blocking": "true", + "download.prompt_for_download": "false", + "download.default_directory": "./downloads" + }, + "startArguments": [ "--remote-debugging-port=9222", "--no-sandbox", "--disable-dev-shm-usage" ] + }, "yandex": { "binaryLocation": "%USERPROFILE%\\AppData\\Local\\Yandex\\YandexBrowser\\Application\\browser.exe", "capabilities": { From 888ec158f35b226fbddede19e95eaca8731bfb59 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alaksiej=20Miale=C5=A1ka?= Date: Thu, 25 Jan 2024 18:59:23 +0100 Subject: [PATCH 8/9] Support Finding of Multiple elements from ShadowRoot (#125) * Support Finding of Multiple elements from ShadowRoot - add JavaScript to generate CSS selector from element - try to generate CSS selector if XPath generation fails - necessary for ShadowRoot elements since XPath doesn't work for them Related to https://github.com/aquality-automation/aquality-selenium-dotnet/issues/235 * Update ElementFactory to use generate CSS locator logic in generateLocator method instead of generateXPathLocator --- pom.xml | 2 +- .../aquality/selenium/browser/JavaScript.java | 1 + .../selenium/elements/ElementFactory.java | 37 ++++++++++++++--- .../resources/js/getElementCssSelector.js | 40 +++++++++++++++++++ src/test/java/forms/ChromeDownloadsForm.java | 26 +++++++++++- .../java/tests/usecases/ShadowRootTests.java | 21 ++++++++++ 6 files changed, 118 insertions(+), 9 deletions(-) create mode 100644 src/main/resources/js/getElementCssSelector.js diff --git a/pom.xml b/pom.xml index a8d9318..ac2724c 100644 --- a/pom.xml +++ b/pom.xml @@ -82,7 +82,7 @@ com.github.aquality-automation aquality-selenium-core - 3.1.1 + 3.1.2 org.apache.commons diff --git a/src/main/java/aquality/selenium/browser/JavaScript.java b/src/main/java/aquality/selenium/browser/JavaScript.java index 967b769..b079794 100644 --- a/src/main/java/aquality/selenium/browser/JavaScript.java +++ b/src/main/java/aquality/selenium/browser/JavaScript.java @@ -22,6 +22,7 @@ public enum JavaScript { GET_COMBOBOX_SELECTED_TEXT("getCmbText.js"), GET_COMBOBOX_TEXTS("getCmbValues.js"), GET_ELEMENT_BY_XPATH("getElementByXpath.js"), + GET_ELEMENT_CSS_SELECTOR("getElementCssSelector.js"), GET_ELEMENT_XPATH("getElementXPath.js"), GET_ELEMENT_TEXT("getElementText.js"), GET_TEXT_FIRST_CHILD("getTextFirstChild.js"), diff --git a/src/main/java/aquality/selenium/elements/ElementFactory.java b/src/main/java/aquality/selenium/elements/ElementFactory.java index f63d5ec..ed99699 100644 --- a/src/main/java/aquality/selenium/elements/ElementFactory.java +++ b/src/main/java/aquality/selenium/elements/ElementFactory.java @@ -1,6 +1,5 @@ package aquality.selenium.elements; -import aquality.selenium.browser.AqualityServices; import aquality.selenium.browser.JavaScript; import aquality.selenium.core.elements.interfaces.IElementFinder; import aquality.selenium.core.elements.interfaces.IElementSupplier; @@ -8,23 +7,26 @@ import aquality.selenium.core.waitings.IConditionalWait; import aquality.selenium.elements.interfaces.*; import com.google.inject.Inject; -import org.openqa.selenium.By; +import org.openqa.selenium.*; import org.openqa.selenium.By.ByClassName; import org.openqa.selenium.By.ById; import org.openqa.selenium.By.ByName; -import org.openqa.selenium.WebElement; +import org.openqa.selenium.remote.RemoteWebDriver; import org.openqa.selenium.support.ByIdOrName; import java.util.HashMap; import java.util.Map; +import java.util.Objects; public class ElementFactory extends aquality.selenium.core.elements.ElementFactory implements IElementFactory { + private final IConditionalWait conditionalWait; private final IElementFinder elementFinder; @Inject public ElementFactory(IConditionalWait conditionalWait, IElementFinder elementFinder, ILocalizationManager localizationManager) { super(conditionalWait, elementFinder, localizationManager); + this.conditionalWait = conditionalWait; this.elementFinder = elementFinder; } @@ -50,6 +52,24 @@ protected Map ((RemoteWebDriver) Objects.requireNonNull(driver)) + .executeScript(JavaScript.GET_ELEMENT_CSS_SELECTOR.getScript(), webElement), ex.getMessage() + ". CSS selector generation failed too.")); + } + } + /** * Generates xpath locator for target element. * @@ -60,9 +80,14 @@ protected Map ((RemoteWebDriver) Objects.requireNonNull(driver)) + .executeScript(JavaScript.GET_ELEMENT_XPATH.getScript(), webElement), "XPath generation failed")); } /** diff --git a/src/main/resources/js/getElementCssSelector.js b/src/main/resources/js/getElementCssSelector.js new file mode 100644 index 0000000..b1d2120 --- /dev/null +++ b/src/main/resources/js/getElementCssSelector.js @@ -0,0 +1,40 @@ +function previousElementSibling (element) { + if (element.previousElementSibling !== 'undefined') { + return element.previousElementSibling; + } else { + // Loop through ignoring anything not an element + while (element = element.previousSibling) { + if (element.nodeType === 1) { + return element; + } + } + } +} +function getCssPath (element) { + // Empty on non-elements + if (!(element instanceof HTMLElement)) { return ''; } + let path = []; + while (element.nodeType === Node.ELEMENT_NODE) { + let selector = element.nodeName; + if (element.id) { selector += ('#' + element.id); } + else { + // Walk backwards until there is no previous sibling + let sibling = element; + // Will hold nodeName to join for adjacent selection + let siblingSelectors = []; + while (sibling !== null && sibling.nodeType === Node.ELEMENT_NODE) { + siblingSelectors.unshift(sibling.nodeName); + sibling = previousElementSibling(sibling); + } + // :first-child does not apply to HTML + if (siblingSelectors[0] !== 'HTML') { + siblingSelectors[0] = siblingSelectors[0] + ':first-child'; + } + selector = siblingSelectors.join(' + '); + } + path.unshift(selector); + element = element.parentNode; + } + return path.join(' > '); +} +return getCssPath(arguments[0]); diff --git a/src/test/java/forms/ChromeDownloadsForm.java b/src/test/java/forms/ChromeDownloadsForm.java index 28ff07e..8ff19ac 100644 --- a/src/test/java/forms/ChromeDownloadsForm.java +++ b/src/test/java/forms/ChromeDownloadsForm.java @@ -6,9 +6,15 @@ import org.openqa.selenium.By; import org.openqa.selenium.SearchContext; +import java.util.List; + public class ChromeDownloadsForm extends Form { private static final String ADDRESS = "chrome://downloads/"; public static final By NESTED_SHADOW_ROOT_LOCATOR = By.id("moreActionsMenu"); + public static final By DIV_ELEMENTS_LOCATOR = By.cssSelector("div"); + + private final ILabel lblDownloadsToolbar = getFormLabel().findElementInShadowRoot(By.cssSelector("downloads-toolbar"), "Downloads toolbar", ILabel.class); + private final ILabel lblMainContainer = getFormLabel().findElementInShadowRoot(By.id("mainContainer"), "Main container", ILabel.class); private final ILabel lblDownloadsToolbarFromJs = getFormLabel().getJsActions().findElementInShadowRoot(By.cssSelector("downloads-toolbar"), "Downloads toolbar", ILabel.class); private final ILabel lblMainContainerFromJs = getFormLabel().getJsActions().findElementInShadowRoot(By.id("mainContainer"), "Main container", ILabel.class); @@ -31,11 +37,11 @@ public SearchContext expandShadowRootViaJs() { } public ILabel getDownloadsToolbarLabel() { - return getFormLabel().findElementInShadowRoot(By.cssSelector("downloads-toolbar"), "Downloads toolbar", ILabel.class); + return lblDownloadsToolbar; } public ILabel getMainContainerLabel() { - return getFormLabel().findElementInShadowRoot(By.id("mainContainer"), "main container", ILabel.class); + return lblMainContainer; } public ILabel getDownloadsToolbarLabelFromJs() { @@ -45,4 +51,20 @@ public ILabel getDownloadsToolbarLabelFromJs() { public ILabel getMainContainerLabelFromJs() { return lblMainContainerFromJs; } + + public List getDivElementLabels() { + return getFormLabel().findElementsInShadowRoot(DIV_ELEMENTS_LOCATOR, "div", ILabel.class); + } + + public List getDivElementLabelsFromJs() { + return getFormLabel().getJsActions().findElementsInShadowRoot(DIV_ELEMENTS_LOCATOR, "div", ILabel.class); + } + + public List getMainContainerLabels() { + return getFormLabel().findElementsInShadowRoot(lblMainContainer.getLocator(), lblMainContainer.getName(), ILabel.class); + } + + public List getMainContainerLabelsFromJs() { + return getFormLabel().getJsActions().findElementsInShadowRoot(lblMainContainer.getLocator(), lblMainContainer.getName(), ILabel.class); + } } diff --git a/src/test/java/tests/usecases/ShadowRootTests.java b/src/test/java/tests/usecases/ShadowRootTests.java index 3422ced..cd257b9 100644 --- a/src/test/java/tests/usecases/ShadowRootTests.java +++ b/src/test/java/tests/usecases/ShadowRootTests.java @@ -2,11 +2,14 @@ import aquality.selenium.elements.interfaces.ILabel; import forms.ChromeDownloadsForm; +import org.openqa.selenium.By; import org.testng.Assert; import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; import tests.BaseTest; +import java.util.List; + public class ShadowRootTests extends BaseTest { private static final ChromeDownloadsForm form = new ChromeDownloadsForm(); @@ -19,16 +22,34 @@ public void beforeMethod() { @Test public void testExpandShadowRoot() { Assert.assertNotNull(form.expandShadowRoot(), "Should be possible to expand shadow root and get Selenium native ShadowRoot object"); + } + + @Test + public void testFindElementInShadowRoot() { Assert.assertNotNull(form.getDownloadsToolbarLabel().getElement(), "Should be possible do get the element hidden under the shadow"); Assert.assertNotNull(form.getDownloadsToolbarLabel().findElementInShadowRoot(ChromeDownloadsForm.NESTED_SHADOW_ROOT_LOCATOR, "More actions menu", ILabel.class).getElement(), "Should be possible to expand the nested shadow root and get the element from it"); Assert.assertTrue(form.getMainContainerLabel().state().isDisplayed(), "Should be possible to check that element under the shadow is displayed"); } + @Test + public void testFindElementsInShadowRoot() { + List elementLabels = form.getDivElementLabels(); + Assert.assertTrue(elementLabels.size() > 1, "Should be possible to find multiple elements hidden under the shadow"); + Assert.assertTrue(elementLabels.get(0).getLocator() instanceof By.ByCssSelector, "Unique locator of correct type should be generated"); + Assert.assertEquals(elementLabels.get(0).getElement().getTagName(), "div", "Should be possible to work with one of found elements"); + Assert.assertEquals(form.getMainContainerLabels().get(0).getElement().getTagName(), "div", "Should be possible to work with one of found elements found by id"); + } + @Test public void testExpandShadowRootViaJs() { Assert.assertNotNull(form.expandShadowRootViaJs(), "Should be possible to expand shadow root and get Selenium native ShadowRoot object"); Assert.assertNotNull(form.getDownloadsToolbarLabelFromJs().getElement(), "Should be possible do get the element hidden under the shadow"); + List elementLabels = form.getDivElementLabelsFromJs(); + Assert.assertTrue(elementLabels.size() > 1, "Should be possible to find multiple elements hidden under the shadow"); + Assert.assertTrue(elementLabels.get(0).getLocator() instanceof By.ByCssSelector, "Unique locator of correct type should be generated"); + Assert.assertEquals(elementLabels.get(0).getElement().getTagName(), "div", "Should be possible to work with one of found elements"); + Assert.assertEquals(form.getMainContainerLabelsFromJs().get(0).getElement().getTagName(), "div", "Should be possible to work with one of found elements found by id"); Assert.assertNotNull(form.getDownloadsToolbarLabelFromJs().findElementInShadowRoot(ChromeDownloadsForm.NESTED_SHADOW_ROOT_LOCATOR, "More actions menu", ILabel.class).getElement(), "Should be possible to expand the nested shadow root and get the element from it"); Assert.assertTrue(form.getMainContainerLabelFromJs().state().isDisplayed(), "Should be possible to check that element under the shadow is displayed"); From 9445843f5fdb452f40389ffc9c79cab1252b3221 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alaksiej=20Miale=C5=A1ka?= Date: Sat, 27 Jan 2024 00:33:34 +0100 Subject: [PATCH 9/9] [Feature] DevTools command logging options (#135) +semver: feature Add optional parameter for DevTools Command/Result logging options to SendCommand and ExecuteCdpCommand methods --- .../browser/devtools/DevToolsHandling.java | 61 +++++++++++++++---- .../DevToolsCommandLoggingOptions.java | 39 ++++++++++++ .../devtools/OverrideUserAgentTest.java | 8 ++- 3 files changed, 95 insertions(+), 13 deletions(-) create mode 100644 src/main/java/aquality/selenium/logging/DevToolsCommandLoggingOptions.java diff --git a/src/main/java/aquality/selenium/browser/devtools/DevToolsHandling.java b/src/main/java/aquality/selenium/browser/devtools/DevToolsHandling.java index 6187ec5..b9de2d8 100644 --- a/src/main/java/aquality/selenium/browser/devtools/DevToolsHandling.java +++ b/src/main/java/aquality/selenium/browser/devtools/DevToolsHandling.java @@ -2,6 +2,8 @@ import aquality.selenium.browser.AqualityServices; import aquality.selenium.core.localization.ILocalizedLogger; +import aquality.selenium.logging.DevToolsCommandLoggingOptions; +import aquality.selenium.logging.LoggingParameters; import org.openqa.selenium.chromium.ChromiumDriver; import org.openqa.selenium.devtools.Command; import org.openqa.selenium.devtools.DevTools; @@ -16,6 +18,8 @@ import java.util.function.Consumer; import java.util.stream.Collectors; +import static aquality.selenium.logging.LocalizedLoggerUtility.logByLevel; + /** * Wrapper for Selenium {@link DevTools} functionality. */ @@ -53,21 +57,30 @@ private DevTools getDevTools(String handleToLog) { return session; } - private void logCommand(String commandName, Map commandParameters) { + private void logCommand(String commandName, Map commandParameters, + DevToolsCommandLoggingOptions loggingOptions) { + LoggingParameters logging = (loggingOptions == null ? new DevToolsCommandLoggingOptions() : loggingOptions) + .getCommand(); + if (!logging.isEnabled()) + { + return; + } if (!commandParameters.isEmpty()) { - logger.info("loc.browser.devtools.command.execute.withparams", commandName, commandParameters); + logByLevel(logging.getLogLevel(), "loc.browser.devtools.command.execute.withparams", commandName, commandParameters); } else { - logger.info("loc.browser.devtools.command.execute", commandName); + logByLevel(logging.getLogLevel(), "loc.browser.devtools.command.execute", commandName); } } - private void logCommandResult(Object result) { - if (result != null) { + private void logCommandResult(Object result, DevToolsCommandLoggingOptions loggingOptions) { + LoggingParameters logging = (loggingOptions == null ? new DevToolsCommandLoggingOptions() : loggingOptions) + .getCommand(); + if (result != null && logging.isEnabled()) { if (result instanceof Map && ((Map) result).isEmpty()) { return; } - logger.info("loc.browser.devtools.command.execute.result", result); + logByLevel(logging.getLogLevel(), "loc.browser.devtools.command.execute.result", result); } } @@ -123,11 +136,24 @@ public void closeDevToolsSession() { * @return An object representing the result of the command, if applicable. */ public Map executeCdpCommand(String commandName, Map commandParameters) { + return executeCdpCommand(commandName, commandParameters, null); + } + + /** + * Executes a custom Chromium Dev Tools Protocol Command. + * Note: works only if current driver is instance of {@link ChromiumDriver}. + * @param commandName Name of the command to execute. + * @param commandParameters Parameters of the command to execute. + * @param loggingOptions Logging preferences. + * @return An object representing the result of the command, if applicable. + */ + public Map executeCdpCommand(String commandName, Map commandParameters, + DevToolsCommandLoggingOptions loggingOptions) { if (devToolsProvider instanceof ChromiumDriver) { - logCommand(commandName, commandParameters); + logCommand(commandName, commandParameters, loggingOptions); ChromiumDriver driver = (ChromiumDriver) devToolsProvider; Map result = driver.executeCdpCommand(commandName, commandParameters); - logCommandResult(result); + logCommandResult(result, loggingOptions); return result; } else { @@ -142,9 +168,20 @@ public Map executeCdpCommand(String commandName, Map X sendCommand(Command command) { - logCommand(command.getMethod(), command.getParams()); + return sendCommand(command, null); + } + + /** + * Sends the specified command and returns the associated command response. + * @param command An instance of the {@link Command} to send. + * @param The type of the command's result. For most commands it's {@link Void} + * @param loggingOptions Logging preferences. + * @return the result of the command, if applicable + */ + public X sendCommand(Command command, DevToolsCommandLoggingOptions loggingOptions) { + logCommand(command.getMethod(), command.getParams(), loggingOptions); X result = getDevToolsSession().send(command); - logCommandResult(result); + logCommandResult(result, loggingOptions); return result; } @@ -229,10 +266,10 @@ public void enablePerformanceMonitoring() { */ public Map getPerformanceMetrics() { Command> command = Performance.getMetrics(); - logCommand(command.getMethod(), command.getParams()); + logCommand(command.getMethod(), command.getParams(), null); List metrics = getDevToolsSession().send(command); Map result = metrics.stream().collect(Collectors.toMap(Metric::getName, Metric::getValue)); - logCommandResult(result.isEmpty() ? "empty" : result); + logCommandResult(result.isEmpty() ? "empty" : result, null); return result; } } diff --git a/src/main/java/aquality/selenium/logging/DevToolsCommandLoggingOptions.java b/src/main/java/aquality/selenium/logging/DevToolsCommandLoggingOptions.java new file mode 100644 index 0000000..765ba0e --- /dev/null +++ b/src/main/java/aquality/selenium/logging/DevToolsCommandLoggingOptions.java @@ -0,0 +1,39 @@ +package aquality.selenium.logging; + +/** + * DevTools Command/Result logging options. + */ +public class DevToolsCommandLoggingOptions { + private LoggingParameters command = new LoggingParameters(true, LogLevel.INFO); + private LoggingParameters result = new LoggingParameters(true, LogLevel.INFO); + + /** + * Gets logging parameters for command info: name and parameters (if any). + * @return command info logging parameters. + */ + public LoggingParameters getCommand() { + return command; + } + + /** + * Sets logging parameters for command info: name and parameters (if any). + */ + public void setCommand(LoggingParameters command) { + this.command = command; + } + + /** + * Gets logging parameters for command result (when it's present). + * @return logging parameters of command result. + */ + public LoggingParameters getResult() { + return result; + } + + /** + * Sets logging parameters for command result (when it's present). + */ + public void setResult(LoggingParameters result) { + this.result = result; + } +} diff --git a/src/test/java/tests/usecases/devtools/OverrideUserAgentTest.java b/src/test/java/tests/usecases/devtools/OverrideUserAgentTest.java index d8d0c06..19be87a 100644 --- a/src/test/java/tests/usecases/devtools/OverrideUserAgentTest.java +++ b/src/test/java/tests/usecases/devtools/OverrideUserAgentTest.java @@ -2,6 +2,9 @@ import aquality.selenium.browser.AqualityServices; import aquality.selenium.browser.devtools.EmulationHandling; +import aquality.selenium.logging.DevToolsCommandLoggingOptions; +import aquality.selenium.logging.LogLevel; +import aquality.selenium.logging.LoggingParameters; import manytools.BrowserLanguageForm; import manytools.UserAgentForm; import org.openqa.selenium.devtools.idealized.Network; @@ -60,9 +63,12 @@ public void overrideUserAgentByParametersMapTest() { @Test public void overrideUserAgentByVersionSpecificCommandTest() { + DevToolsCommandLoggingOptions loggingOptions = new DevToolsCommandLoggingOptions(); + loggingOptions.setCommand(new LoggingParameters(false, LogLevel.DEBUG)); + loggingOptions.setResult(new LoggingParameters(false, LogLevel.DEBUG)); AqualityServices.getBrowser().devTools().sendCommand(Emulation.setUserAgentOverride(CUSTOM_USER_AGENT, Optional.of(CUSTOM_ACCEPT_LANGUAGE), Optional.empty(), - Optional.empty())); + Optional.empty()), loggingOptions); Assert.assertEquals(new UserAgentForm().open().getValue(), CUSTOM_USER_AGENT, "User agent should match to value set"); }