I want to migrate existing Selenium-Tests based on JUnit 4 to JUnit 5. For this purpose, I want to make use of Selenium-Jupiter.
One requirement, that the tests must fulfill is, to be able to switch the WebDriver implementation at runtime - based on the execution environment - using one common base class for all tests:
- When executed on a developer machine (Windows 10), a FirefoxDriver should be used, launching a locally installed Firefox.
- In the CI-environment (CentOS 7), a RemoteWebDriver should be used, delegating test execution to a Selenium Grid
I already tried to configure a "Generic WebDriver" according to documentation, but I don't know how to achieve this for a RemoteWebDriver ("Example 2" should make things clearer).
With regards to content this stackoverflow-posting is quite related, but does not yield a satisfying answer.
UPDATE: I solved the problem by myself. See "Example 3"...
Hey Boni, maybe you want to update the Selenium Jupiter documentation a bit. At least I had some problems, figuring it out... oh, and thanks a lot for the awesome work you have done with Selenium Jupiter (and the underlying WebDriverManger).
Example 1: What works, but is not elegant
@ExtendWith(SeleniumExtension.class)
class MyTest {
@EnabledIfSystemProperty(named = "os.name", matches = "Windows 10")
@Test
void test_executed_with_local_firefox(FirefoxDriver ffDriver) {
executeTestCaseWith(ffDriver);
}
@EnabledIfSystemProperty(named = "os.name", matches = "Linux")
@Test
void test_executed_with_firefox_from_selenium_grid(@DriverUrl("http://...") RemoteWebDriver remoteDriver) {
executeTestCaseWith(remoteDriver);
}
void executeTestCaseWith(WebDriver webDriver) {
webDriver.get(...)
Assert(...)
}
}
The problems I see hee, are:
- Pretty verbose (tho' this might by handable with custom annotations)
- Each test class needs two @Test-methods for one logical/semantical test case
- The concrete WebDriver implementation is exposed, thus, allowing test authors to rely on WebDriver implementation detail (for example, Firefox profiles)
Example 2: What I would like to do, but doesn't work, yet
Base class, that does WebDriver configuration:
abstract class UiTest {
@RegisterExtension
static SeleniumExtension seleniumExtension = new SeleniumExtension();
@BeforeAll
static void setUpOnce() {
// This check is not the problem discussed here
boolean isRunningInCiEnvironment = ...
Browser firefox;
if( ! isRunningInCiEnvironment ) {
// This works
firefox = BrowserBuilder.firefox().build();
} else {
// this does not exist yet!
//firefox = BrowserBuilder.remoteWebDriver().url("http://...").build();
// This executes, but does not behave as expected
// The URL is pretty much ignored.
firefox = BrowserBuilder.firefox().url("http://...").build();
}
seleniumExtension.addBrowsers(firefox);
}
}
In the test I would then only need to do sth. like this.
class MyTest extends UiTest {
@Test
void my_one_logic_test_case(WebDriver webDriver) {
webDriver.get(...)
Assert(...)
}
}
Note, how the type of the parameter is only WebDriver!
Example 3: My current solution
abstract class UiTest {
@RegisterExtension
static SeleniumExtension seleniumExtension = new SeleniumExtension();
@BeforeAll
static void setUpOnce() {
// This check is not the problem discussed here
boolean isRunningInCiEnvironment = ...
if( isRunningInCiEnvironment ) {
// This is doing the trick!
seleniumExtension.getConfig().setSeleniumServerUrl("http://...");
}
seleniumExtension.addBrowsers( BrowserBuilder.firefox().build() );
}
}
The concrete test can now be implemented as depicted in "Example 2".