End-to-end testing with Selenium, Gradle, JUnit
I wanted to test a web page using JVM, but there are scattered tutorials everywhere. I decided to create a barebones project to illustrate how.
Our goal will be to test the end-to-end flow of adding a Kindle to the cart on Amazon.com.

1. New project
Follow the steps at:
2. Selenium
Add Selenium to the dependencies:
implementation("org.seleniumhq.selenium:selenium-java:4.+")
To be able to control a browser, Selenium needs a proper driver. There are multiple ways to achieve that but the quickest is to let WebDriverManager manage that for you:
implementation("io.github.bonigarcia:webdrivermanager:5.+")
Now, edit TestAmazonCart
and paste the following basic test that visits Amazon:
This assumes you have Chrome, but you can replace chromedriver()
with other.
3. Page object model
The test will quickly get filled with details like CSS selectors and waits, so we’ll resort to the Page Object Model pattern, which abstracts the page details. It’s a way to follow the SLA principle.
Let’s create the following files:
Some people like to put all the selectors in the beginning, but I avoid that due to simplicity and because they're used only once.
4. Reports
How about a beautiful report? Just add the Allure report dependency to build.gradle.kts
’s plugins
section:
id("io.qameta.allure") version "2.9.6"
id("io.qameta.allure-report") version "2.9.6"
Run the tests. Then, to view its report, run:
./gradlew allureServe

How about adding screenshots to the report when a test fails? Create the following utility:
Now, you just need to inject it into the test:
@RegisterExtension
private val screenshotOnError = ScreenshotOnError(driver as RemoteWebDriver)
This is enough to add the screenshot to the Allure report.
5. Headless
If you need to integrate this into your CI/CD system, you need to use a headless browser (browser runs without UI). For that, you can change the setup to:
init {
WebDriverManager.chromedriver().setup()
}
private val driver = ChromeDriver(ChromeOptions().addArguments("--headless"))
@RegisterExtension
private val screenshotOnError = ScreenshotOnError(driver)
Be aware that the addArguments
part needs to depend on an environment variable so that you can run on headless only on CI/CD and not on local testing.