mirror of
https://github.com/keycloak/keycloak.git
synced 2025-12-20 14:00:09 -06:00
Fix Chrome and Firefox in new test framework on GitHub Actions (#44804)
Closes #44776 Signed-off-by: stianst <stianst@gmail.com>
This commit is contained in:
2
.github/workflows/ci.yml
vendored
2
.github/workflows/ci.yml
vendored
@@ -914,7 +914,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Run new Forms IT
|
- name: Run new Forms IT
|
||||||
run: |
|
run: |
|
||||||
./mvnw package -f tests/pom.xml -Dkc.test.browser=${{ matrix.browser }} -Dtest=FormsTestSuite
|
./mvnw package -f tests/pom.xml -Dkc.test.browser=${{ matrix.browser }}-headless -Dtest=FormsTestSuite
|
||||||
|
|
||||||
- uses: ./.github/actions/upload-flaky-tests
|
- uses: ./.github/actions/upload-flaky-tests
|
||||||
name: Upload flaky tests
|
name: Upload flaky tests
|
||||||
|
|||||||
@@ -174,6 +174,16 @@ Valid values:
|
|||||||
| firefox | Firefox WebDriver |
|
| firefox | Firefox WebDriver |
|
||||||
| firefox-headless | Firefox WebDriver without UI |
|
| firefox-headless | Firefox WebDriver without UI |
|
||||||
|
|
||||||
|
Resolving the web driver is done either automatically by Selenium, or the binary can be specified directly either
|
||||||
|
through using `CHROMEWEBDRIVER` and `GECKOWEBDRIVER` environment variables (these environment variables are already
|
||||||
|
configured on GitHub Actions), or it can be configured using standard test framework configuration options.
|
||||||
|
|
||||||
|
Configuration:
|
||||||
|
|
||||||
|
| Value | Description |
|
||||||
|
|-----------------------------------------------------|--------------------|
|
||||||
|
| `kc.test.browser.driver` / `KC_TEST_BROWSER_DRIVER` | Path to the driver |
|
||||||
|
|
||||||
### Supplier configuration
|
### Supplier configuration
|
||||||
|
|
||||||
#### Set the supplier
|
#### Set the supplier
|
||||||
|
|||||||
@@ -32,8 +32,8 @@
|
|||||||
<description>UI extension for Keycloak Test Framework</description>
|
<description>UI extension for Keycloak Test Framework</description>
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
<selenium.version>4.25.0</selenium.version>
|
<selenium.version>4.39.0</selenium.version>
|
||||||
<selenium.html.unit.version>4.25.0</selenium.html.unit.version>
|
<selenium.html.unit.version>4.39.0</selenium.html.unit.version>
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
package org.keycloak.testframework.ui.webdriver;
|
package org.keycloak.testframework.ui.webdriver;
|
||||||
|
|
||||||
import java.time.Duration;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
import org.keycloak.testframework.injection.InstanceContext;
|
import org.keycloak.testframework.injection.InstanceContext;
|
||||||
import org.keycloak.testframework.injection.LifeCycle;
|
import org.keycloak.testframework.injection.LifeCycle;
|
||||||
@@ -9,10 +7,7 @@ import org.keycloak.testframework.injection.RequestedInstance;
|
|||||||
import org.keycloak.testframework.injection.Supplier;
|
import org.keycloak.testframework.injection.Supplier;
|
||||||
import org.keycloak.testframework.ui.annotations.InjectWebDriver;
|
import org.keycloak.testframework.ui.annotations.InjectWebDriver;
|
||||||
|
|
||||||
import org.openqa.selenium.MutableCapabilities;
|
|
||||||
import org.openqa.selenium.PageLoadStrategy;
|
|
||||||
import org.openqa.selenium.WebDriver;
|
import org.openqa.selenium.WebDriver;
|
||||||
import org.openqa.selenium.remote.CapabilityType;
|
|
||||||
|
|
||||||
public abstract class AbstractWebDriverSupplier implements Supplier<ManagedWebDriver, InjectWebDriver> {
|
public abstract class AbstractWebDriverSupplier implements Supplier<ManagedWebDriver, InjectWebDriver> {
|
||||||
|
|
||||||
@@ -38,9 +33,4 @@ public abstract class AbstractWebDriverSupplier implements Supplier<ManagedWebDr
|
|||||||
|
|
||||||
public abstract WebDriver getWebDriver();
|
public abstract WebDriver getWebDriver();
|
||||||
|
|
||||||
public void setCommonCapabilities(MutableCapabilities capabilities) {
|
|
||||||
capabilities.setCapability(CapabilityType.PAGE_LOAD_STRATEGY, PageLoadStrategy.NORMAL.toString());
|
|
||||||
capabilities.setCapability("timeouts", Map.of("implicit", Duration.ofSeconds(5).toMillis()));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,6 @@
|
|||||||
package org.keycloak.testframework.ui.webdriver;
|
package org.keycloak.testframework.ui.webdriver;
|
||||||
|
|
||||||
import org.openqa.selenium.WebDriver;
|
import org.openqa.selenium.WebDriver;
|
||||||
import org.openqa.selenium.chrome.ChromeDriver;
|
|
||||||
import org.openqa.selenium.chrome.ChromeOptions;
|
|
||||||
|
|
||||||
public class ChromeHeadlessWebDriverSupplier extends AbstractWebDriverSupplier {
|
public class ChromeHeadlessWebDriverSupplier extends AbstractWebDriverSupplier {
|
||||||
|
|
||||||
@@ -13,15 +11,6 @@ public class ChromeHeadlessWebDriverSupplier extends AbstractWebDriverSupplier {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public WebDriver getWebDriver() {
|
public WebDriver getWebDriver() {
|
||||||
ChromeOptions options = new ChromeOptions();
|
return DriverUtils.createChromeDriver(true);
|
||||||
setCommonCapabilities(options);
|
|
||||||
options.addArguments(
|
|
||||||
"--headless",
|
|
||||||
"--disable-gpu",
|
|
||||||
"--window-size=1920,1200",
|
|
||||||
"--ignore-certificate-errors",
|
|
||||||
"--disable-dev-shm-usage"
|
|
||||||
);
|
|
||||||
return new ChromeDriver(options);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,6 @@
|
|||||||
package org.keycloak.testframework.ui.webdriver;
|
package org.keycloak.testframework.ui.webdriver;
|
||||||
|
|
||||||
import org.openqa.selenium.WebDriver;
|
import org.openqa.selenium.WebDriver;
|
||||||
import org.openqa.selenium.chrome.ChromeDriver;
|
|
||||||
import org.openqa.selenium.chrome.ChromeOptions;
|
|
||||||
|
|
||||||
public class ChromeWebDriverSupplier extends AbstractWebDriverSupplier {
|
public class ChromeWebDriverSupplier extends AbstractWebDriverSupplier {
|
||||||
|
|
||||||
@@ -13,8 +11,6 @@ public class ChromeWebDriverSupplier extends AbstractWebDriverSupplier {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public WebDriver getWebDriver() {
|
public WebDriver getWebDriver() {
|
||||||
ChromeOptions options = new ChromeOptions();
|
return DriverUtils.createChromeDriver(false);
|
||||||
setCommonCapabilities(options);
|
|
||||||
return new ChromeDriver(options);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,66 @@
|
|||||||
|
package org.keycloak.testframework.ui.webdriver;
|
||||||
|
|
||||||
|
import java.time.Duration;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.openqa.selenium.MutableCapabilities;
|
||||||
|
import org.openqa.selenium.PageLoadStrategy;
|
||||||
|
import org.openqa.selenium.chrome.ChromeOptions;
|
||||||
|
import org.openqa.selenium.firefox.FirefoxOptions;
|
||||||
|
import org.openqa.selenium.htmlunit.HtmlUnitDriver;
|
||||||
|
import org.openqa.selenium.remote.CapabilityType;
|
||||||
|
import org.openqa.selenium.remote.DesiredCapabilities;
|
||||||
|
|
||||||
|
class DriverOptions {
|
||||||
|
|
||||||
|
static ChromeOptions createChromeOptions(boolean headless) {
|
||||||
|
ChromeOptions options = new ChromeOptions();
|
||||||
|
setCommonCapabilities(options);
|
||||||
|
|
||||||
|
if (headless) {
|
||||||
|
options.addArguments(
|
||||||
|
"--headless=new",
|
||||||
|
"--disable-gpu",
|
||||||
|
"--window-size=1920,1200",
|
||||||
|
"--ignore-certificate-errors",
|
||||||
|
"--disable-dev-shm-usage",
|
||||||
|
"--remote-allow-origins=*",
|
||||||
|
"--no-sandbox"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return options;
|
||||||
|
}
|
||||||
|
|
||||||
|
static FirefoxOptions createFirefoxOptions(boolean headless) {
|
||||||
|
FirefoxOptions options = new FirefoxOptions();
|
||||||
|
setCommonCapabilities(options);
|
||||||
|
|
||||||
|
if (headless) {
|
||||||
|
options.addArguments("-headless");
|
||||||
|
}
|
||||||
|
|
||||||
|
options.addPreference("extensions.update.enabled", "false");
|
||||||
|
options.addPreference("app.update.enabled", "false");
|
||||||
|
options.addPreference("app.update.auto", "false");
|
||||||
|
|
||||||
|
return options;
|
||||||
|
}
|
||||||
|
|
||||||
|
static DesiredCapabilities createHtmlUnitOptions() {
|
||||||
|
DesiredCapabilities capabilities = new DesiredCapabilities();
|
||||||
|
setCommonCapabilities(capabilities);
|
||||||
|
|
||||||
|
capabilities.setBrowserName("htmlunit");
|
||||||
|
capabilities.setCapability(HtmlUnitDriver.DOWNLOAD_IMAGES_CAPABILITY, false);
|
||||||
|
capabilities.setCapability(HtmlUnitDriver.JAVASCRIPT_ENABLED, true);
|
||||||
|
|
||||||
|
return capabilities;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void setCommonCapabilities(MutableCapabilities capabilities) {
|
||||||
|
capabilities.setCapability(CapabilityType.PAGE_LOAD_STRATEGY, PageLoadStrategy.NORMAL.toString());
|
||||||
|
capabilities.setCapability("timeouts", Map.of("implicit", Duration.ofSeconds(5).toMillis()));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,70 @@
|
|||||||
|
package org.keycloak.testframework.ui.webdriver;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
|
||||||
|
import org.keycloak.testframework.config.Config;
|
||||||
|
|
||||||
|
import org.openqa.selenium.chrome.ChromeDriver;
|
||||||
|
import org.openqa.selenium.chrome.ChromeDriverService;
|
||||||
|
import org.openqa.selenium.firefox.FirefoxDriver;
|
||||||
|
import org.openqa.selenium.firefox.FirefoxDriverService;
|
||||||
|
import org.openqa.selenium.firefox.GeckoDriverService;
|
||||||
|
import org.openqa.selenium.htmlunit.HtmlUnitDriver;
|
||||||
|
|
||||||
|
class DriverUtils {
|
||||||
|
|
||||||
|
static ChromeDriver createChromeDriver(boolean headless) {
|
||||||
|
ChromeDriverService.Builder builder = new ChromeDriverService.Builder();
|
||||||
|
|
||||||
|
File driver = resolveDriver("CHROMEWEBDRIVER", "chromedriver");
|
||||||
|
if (driver != null) {
|
||||||
|
builder.usingDriverExecutable(driver);
|
||||||
|
}
|
||||||
|
|
||||||
|
ChromeDriverService driverService = builder.build();
|
||||||
|
return new ChromeDriver(driverService, DriverOptions.createChromeOptions(headless));
|
||||||
|
}
|
||||||
|
|
||||||
|
static FirefoxDriver createFirefoxDriver(boolean headless) {
|
||||||
|
GeckoDriverService.Builder builder = new GeckoDriverService.Builder();
|
||||||
|
|
||||||
|
File driver = resolveDriver("GECKOWEBDRIVER", "geckodriver");
|
||||||
|
if (driver != null) {
|
||||||
|
builder.usingDriverExecutable(driver);
|
||||||
|
}
|
||||||
|
|
||||||
|
FirefoxDriverService driverService = builder.build();
|
||||||
|
return new FirefoxDriver(driverService, DriverOptions.createFirefoxOptions(headless));
|
||||||
|
}
|
||||||
|
|
||||||
|
static HtmlUnitDriver createHtmlUnitDriver() {
|
||||||
|
HtmlUnitDriver driver = new HtmlUnitDriver(DriverOptions.createHtmlUnitOptions());
|
||||||
|
driver.getWebClient().getOptions().setCssEnabled(false);
|
||||||
|
return driver;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static File resolveDriver(String envName, String driverName) {
|
||||||
|
File driver = Config.getValueTypeConfig(ManagedWebDriver.class, "driver", null, File.class);
|
||||||
|
if (driver != null) {
|
||||||
|
return driver;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Environment variable can point to directory where the driver is located, or the driver directly
|
||||||
|
String driverPathFromEnv = System.getenv(envName);
|
||||||
|
if (driverPathFromEnv != null) {
|
||||||
|
driver = new File(driverPathFromEnv);
|
||||||
|
if (driver.isFile()) {
|
||||||
|
return driver;
|
||||||
|
} else {
|
||||||
|
return new File(driver, driverName + (isWindows() ? ".exe" : ""));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean isWindows() {
|
||||||
|
return System.getProperty("os.name").toLowerCase().contains("win");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,8 +1,6 @@
|
|||||||
package org.keycloak.testframework.ui.webdriver;
|
package org.keycloak.testframework.ui.webdriver;
|
||||||
|
|
||||||
import org.openqa.selenium.WebDriver;
|
import org.openqa.selenium.WebDriver;
|
||||||
import org.openqa.selenium.firefox.FirefoxDriver;
|
|
||||||
import org.openqa.selenium.firefox.FirefoxOptions;
|
|
||||||
|
|
||||||
public class FirefoxHeadlessWebDriverSupplier extends AbstractWebDriverSupplier {
|
public class FirefoxHeadlessWebDriverSupplier extends AbstractWebDriverSupplier {
|
||||||
|
|
||||||
@@ -13,9 +11,6 @@ public class FirefoxHeadlessWebDriverSupplier extends AbstractWebDriverSupplier
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public WebDriver getWebDriver() {
|
public WebDriver getWebDriver() {
|
||||||
FirefoxOptions options = new FirefoxOptions();
|
return DriverUtils.createFirefoxDriver(true);
|
||||||
setCommonCapabilities(options);
|
|
||||||
options.addArguments("-headless");
|
|
||||||
return new FirefoxDriver(options);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,6 @@
|
|||||||
package org.keycloak.testframework.ui.webdriver;
|
package org.keycloak.testframework.ui.webdriver;
|
||||||
|
|
||||||
import org.openqa.selenium.WebDriver;
|
import org.openqa.selenium.WebDriver;
|
||||||
import org.openqa.selenium.firefox.FirefoxDriver;
|
|
||||||
import org.openqa.selenium.firefox.FirefoxOptions;
|
|
||||||
|
|
||||||
public class FirefoxWebDriverSupplier extends AbstractWebDriverSupplier {
|
public class FirefoxWebDriverSupplier extends AbstractWebDriverSupplier {
|
||||||
|
|
||||||
@@ -13,8 +11,6 @@ public class FirefoxWebDriverSupplier extends AbstractWebDriverSupplier {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public WebDriver getWebDriver() {
|
public WebDriver getWebDriver() {
|
||||||
FirefoxOptions options = new FirefoxOptions();
|
return DriverUtils.createFirefoxDriver(false);
|
||||||
setCommonCapabilities(options);
|
|
||||||
return new FirefoxDriver(options);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,6 @@
|
|||||||
package org.keycloak.testframework.ui.webdriver;
|
package org.keycloak.testframework.ui.webdriver;
|
||||||
|
|
||||||
import org.openqa.selenium.WebDriver;
|
import org.openqa.selenium.WebDriver;
|
||||||
import org.openqa.selenium.htmlunit.HtmlUnitDriver;
|
|
||||||
import org.openqa.selenium.remote.DesiredCapabilities;
|
|
||||||
|
|
||||||
public class HtmlUnitWebDriverSupplier extends AbstractWebDriverSupplier {
|
public class HtmlUnitWebDriverSupplier extends AbstractWebDriverSupplier {
|
||||||
|
|
||||||
@@ -13,15 +11,6 @@ public class HtmlUnitWebDriverSupplier extends AbstractWebDriverSupplier {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public WebDriver getWebDriver() {
|
public WebDriver getWebDriver() {
|
||||||
DesiredCapabilities capabilities = new DesiredCapabilities();
|
return DriverUtils.createHtmlUnitDriver();
|
||||||
setCommonCapabilities(capabilities);
|
|
||||||
|
|
||||||
capabilities.setBrowserName("htmlunit");
|
|
||||||
capabilities.setCapability(HtmlUnitDriver.DOWNLOAD_IMAGES_CAPABILITY, false);
|
|
||||||
capabilities.setCapability(HtmlUnitDriver.JAVASCRIPT_ENABLED, true);
|
|
||||||
|
|
||||||
HtmlUnitDriver driver = new HtmlUnitDriver(capabilities);
|
|
||||||
driver.getWebClient().getOptions().setCssEnabled(false);
|
|
||||||
return driver;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import java.util.function.Function;
|
|||||||
import org.keycloak.testframework.ui.page.AbstractPage;
|
import org.keycloak.testframework.ui.page.AbstractPage;
|
||||||
|
|
||||||
import org.junit.jupiter.api.Assertions;
|
import org.junit.jupiter.api.Assertions;
|
||||||
|
import org.openqa.selenium.StaleElementReferenceException;
|
||||||
import org.openqa.selenium.TimeoutException;
|
import org.openqa.selenium.TimeoutException;
|
||||||
import org.openqa.selenium.WebDriver;
|
import org.openqa.selenium.WebDriver;
|
||||||
import org.openqa.selenium.support.ui.WebDriverWait;
|
import org.openqa.selenium.support.ui.WebDriverWait;
|
||||||
@@ -21,7 +22,7 @@ public class WaitUtils {
|
|||||||
public WaitUtils waitForPage(AbstractPage page) {
|
public WaitUtils waitForPage(AbstractPage page) {
|
||||||
String expectedPageId = page.getExpectedPageId();
|
String expectedPageId = page.getExpectedPageId();
|
||||||
try {
|
try {
|
||||||
createDefaultWait().until(d -> expectedPageId.equals(managed.page().getCurrentPageId()));
|
createDefaultWait().ignoring(StaleElementReferenceException.class).until(d -> expectedPageId.equals(managed.page().getCurrentPageId()));
|
||||||
} catch (TimeoutException e) {
|
} catch (TimeoutException e) {
|
||||||
Assertions.fail("Expected page '" + expectedPageId + "' to be loaded, but currently on page '" + managed.page().getCurrentPageId() + "' after timeout");
|
Assertions.fail("Expected page '" + expectedPageId + "' to be loaded, but currently on page '" + managed.page().getCurrentPageId() + "' after timeout");
|
||||||
}
|
}
|
||||||
@@ -47,7 +48,7 @@ public class WaitUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private WebDriverWait createDefaultWait() {
|
private WebDriverWait createDefaultWait() {
|
||||||
return new WebDriverWait(managed.driver(), Duration.ofSeconds(5), Duration.ofMillis(50));
|
return new WebDriverWait(managed.driver(), Duration.ofSeconds(10), Duration.ofMillis(50));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,12 +1,14 @@
|
|||||||
package org.keycloak.tests.suites;
|
package org.keycloak.tests.suites;
|
||||||
|
|
||||||
import org.keycloak.tests.admin.AdminHeadersTest;
|
import org.keycloak.tests.i18n.LoginPageTest;
|
||||||
|
|
||||||
import org.junit.platform.suite.api.SelectClasses;
|
import org.junit.platform.suite.api.SelectClasses;
|
||||||
import org.junit.platform.suite.api.Suite;
|
import org.junit.platform.suite.api.Suite;
|
||||||
|
|
||||||
@Suite
|
@Suite
|
||||||
// TODO: Select relevant test classes or packages once they have been migrated
|
// TODO: Select relevant test classes or packages once they have been migrated
|
||||||
@SelectClasses({AdminHeadersTest.class})
|
@SelectClasses({
|
||||||
|
LoginPageTest.class
|
||||||
|
})
|
||||||
public class FormsTestSuite {
|
public class FormsTestSuite {
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user