I want to use Selenium-Jupiter in my Spring Boot Project but my requirement is to switch the WebDriver implementation at runtime - based on the execution environment - using one common base class for all tests.
I already checked this post and this one, but I couldn't get it to work.
Stacktrace:
2020-09-17 23:17:47.196 INFO 14092 --- [ Test worker] d[....path....].SignupPageTest : Started SignupPageTest in 26.133 seconds (JVM running for 29.179)
2020-09-17 23:17:47.498 WARN 14092 --- [ Test worker] i.g.bonigarcia.seljup.SeleniumExtension : Driver handler for context id [engine:junit-jupiter]/[class:de,[....path....].SignupPageTest]/[method:verifyLogInPage(org.openqa.selenium.WebDriver)] not found
Failed to resolve parameter [org.openqa.selenium.WebDriver genDriver] in method [public void de.[....path....].SignupPageTest.verifyLogInPage(org.openqa.selenium.WebDriver) throws java.lang.Exception]: org/glassfish/hk2/api/MultiException
org.junit.jupiter.api.extension.ParameterResolutionException: Failed to resolve parameter [org.openqa.selenium.WebDriver genDriver] in method [public void de.[....path....].SignupPageTest.verifyLogInPage(org.openqa.selenium.WebDriver) throws java.lang.Exception]: org/glassfish/hk2/api/MultiException
at org.junit.jupiter.engine.execution.ExecutableInvoker.resolveParameter(ExecutableInvoker.java:239)
at org.junit.jupiter.engine.execution.ExecutableInvoker.resolveParameters(ExecutableInvoker.java:183)
at org.junit.jupiter.engine.execution.ExecutableInvoker.resolveParameters(ExecutableInvoker.java:144)
at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:96)
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeTestMethod$6(TestMethodTestDescriptor.java:212)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeTestMethod(TestMethodTestDescriptor.java:208)
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:137)
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:71)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:135)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:125)
at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:135)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:123)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:122)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:80)
at java.base/java.util.ArrayList.forEach(ArrayList.java:1511)
at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:38)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:139)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:125)
at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:135)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:123)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:122)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:80)
at java.base/java.util.ArrayList.forEach(ArrayList.java:1511)
at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:38)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:139)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:125)
at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:135)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:123)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:122)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:80)
at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:32)
at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:57)
at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:51)
at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:248)
at org.junit.platform.launcher.core.DefaultLauncher.lambda$execute$5(DefaultLauncher.java:211)
at org.junit.platform.launcher.core.DefaultLauncher.withInterceptedStreams(DefaultLauncher.java:226)
at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:199)
at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:132)
at org.gradle.api.internal.tasks.testing.junitplatform.JUnitPlatformTestClassProcessor$CollectAllTestClassesExecutor.processAllTestClasses(JUnitPlatformTestClassProcessor.java:99)
at org.gradle.api.internal.tasks.testing.junitplatform.JUnitPlatformTestClassProcessor$CollectAllTestClassesExecutor.access$000(JUnitPlatformTestClassProcessor.java:79)
at org.gradle.api.internal.tasks.testing.junitplatform.JUnitPlatformTestClassProcessor.stop(JUnitPlatformTestClassProcessor.java:75)
at org.gradle.api.internal.tasks.testing.SuiteTestClassProcessor.stop(SuiteTestClassProcessor.java:61)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:564)
at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:36)
at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
at org.gradle.internal.dispatch.ContextClassLoaderDispatch.dispatch(ContextClassLoaderDispatch.java:33)
at org.gradle.internal.dispatch.ProxyDispatchAdapter$DispatchingInvocationHandler.invoke(ProxyDispatchAdapter.java:94)
at com.sun.proxy.$Proxy5.stop(Unknown Source)
at org.gradle.api.internal.tasks.testing.worker.TestWorker.stop(TestWorker.java:133)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:564)
at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:36)
at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
at org.gradle.internal.remote.internal.hub.MessageHubBackedObjectConnection$DispatchWrapper.dispatch(MessageHubBackedObjectConnection.java:182)
at org.gradle.internal.remote.internal.hub.MessageHubBackedObjectConnection$DispatchWrapper.dispatch(MessageHubBackedObjectConnection.java:164)
at org.gradle.internal.remote.internal.hub.MessageHub$Handler.run(MessageHub.java:414)
at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:64)
at org.gradle.internal.concurrent.ManagedExecutorImpl$1.run(ManagedExecutorImpl.java:48)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1130)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:630)
at org.gradle.internal.concurrent.ThreadFactoryImpl$ManagedThreadRunnable.run(ThreadFactoryImpl.java:56)
at java.base/java.lang.Thread.run(Thread.java:832)
Caused by: java.lang.NoClassDefFoundError: org/glassfish/hk2/api/MultiException
at io.github.bonigarcia.seljup.DockerService.<init>(DockerService.java:79)
at io.github.bonigarcia.seljup.SeleniumExtension.initHandlerForDocker(SeleniumExtension.java:381)
at io.github.bonigarcia.seljup.SeleniumExtension.getDriverHandler(SeleniumExtension.java:242)
at io.github.bonigarcia.seljup.SeleniumExtension.resolveParameter(SeleniumExtension.java:220)
at org.junit.jupiter.engine.execution.ExecutableInvoker.resolveParameter(ExecutableInvoker.java:216)
... 73 more
Caused by: java.lang.ClassNotFoundException: org.glassfish.hk2.api.MultiException
at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:602)
at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:178)
at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:522)
... 78 more
de.[....path....].SignupPageTest > verifyLogInPage(WebDriver) FAILED
org.junit.jupiter.api.extension.ParameterResolutionException at ExecutableInvoker.java:239
Caused by: java.lang.NoClassDefFoundError at DockerService.java:79
Caused by: java.lang.ClassNotFoundException at BuiltinClassLoader.java:602
Just in advance with chrome-driver everything works fine, but not with the generic webdriver.
I use Java14 and created an additional source set for the selenium tests called "endToEndTest"
Here is everything related from the gradle.build:
sourceCompatibility = 14
sourceSets {
endToEndTest {
java.srcDir('src/end-to-end-test/java')
resources.srcDir file('src/end-to-end-tests/resources')
compileClasspath += sourceSets.main.output + configurations.testRuntime
runtimeClasspath += output + compileClasspath
}
}
configurations {
endToEndTestImplementation.extendsFrom testImplementation
endToEndTestRuntimeOnly.extendsFrom testRuntimeOnly
}
task endToEndTest(type: Test) {
testClassesDirs = sourceSets.endToEndTest.output.classesDirs
classpath = sourceSets.endToEndTest.runtimeClasspath
useJUnitPlatform ()
}
endToEndTestImplementation('io.github.bonigarcia:selenium-jupiter:3.3.5')
I have a base class from which every other test class is supposed to extend. It takes care of starting the web environment etc.
Baseclass
@ExtendWith({SpringExtension.class})
@SpringBootTest(classes = Application.class, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class SeleniumBaseTestEnvironment {
@RegisterExtension
static SeleniumExtension seleniumJupiter = new SeleniumExtension();
@LocalServerPort
protected int serverPort;
@BeforeAll
public static void beforeAll() {
//both seems to have no impact
seleniumJupiter.getConfig().setDefaultBrowser("chrome");
seleniumJupiter.addBrowsers(BrowserBuilder.chrome().build());
}
protected String getUrl(String address) {
return "http://localhost:" + serverPort + address;
}
}
Testclass It works just fine if I replace WebDriver with ChromeDriver. But I need the generic driver.
public class SignupPageTest extends SeleniumBaseTestEnvironment {
@Test
public void verifyLogInPage(WebDriver genDriver) throws Exception {
genDriver.get(getUrl("/"));
List<WebElement> cardTitleList = genDriver.findElements(By.className("card-title"));
List<WebElement> navbar = genDriver.findElements(By.className("navbar-toggler collapsed"));
assertEquals(cardTitleList.get(0).getText(), "Login");
assertTrue(navbar.isEmpty());
}
}
It seems like my settings regarding the default browser are not applied. Other setting like the ones for screenshots work just fine.
As per my research adding browsers to Selenium Extension works only for the Test Templates feature in the Selenium Jupiter.
So using Test Templates following code should work:
@ExtendWith({SpringExtension.class})
@SpringBootTest(classes = Application.class, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class SeleniumBaseTestEnvironment {
@RegisterExtension
static SeleniumExtension seleniumJupiter = new SeleniumExtension();
@LocalServerPort
protected int serverPort;
@BeforeAll
public static void beforeAll() {
String browsersList = System.getProperty("prop.browsers.list");
List<String> browsers = Arrays.asList(browsersList.split(","));
if (browsers.contains("chrome")) {
seleniumJupiter.addBrowsers(BrowserBuilder.chrome().build());
}
if (browsers.contains("firefox")) {
seleniumJupiter.addBrowsers(BrowserBuilder.firefox().build());
}
//----// All browsers you need
}
protected String getUrl(String address) {
return "http://localhost:" + serverPort + address;
}
public class SignupPageTest extends SeleniumBaseTestEnvironment {
@TestTemplate
public void verifyLogInPage(WebDriver genDriver) throws Exception {
genDriver.get(getUrl("/"));
List<WebElement> cardTitleList = genDriver.findElements(By.className("card-title"));
List<WebElement> navbar = genDriver.findElements(By.className("navbar-toggler collapsed"));
assertEquals(cardTitleList.get(0).getText(), "Login");
assertTrue(navbar.isEmpty());
}
}
Please note:
-Dprop.browsers.list=chrome,firefox
in order to provide multiple browsers into the test.@TestTemplate
should be placed for each method of all subclasses of SeleniumBaseTestEnvironment.(You can create your own class level annotation to work around it).Webdriver
implementation you can setup a spring configuration for each environment that will provide an appropriate list of drivers.