Automated Testing with Selenium

Selenium has been, for more than two decades, one of the most widely used tools for test automation of web applications. It controls the browser like a real user, which makes it possible to validate complete end-to-end flows. With Selenium 4, the tool gained a standardized protocol, automatic driver management, and new features that make writing tests simpler and more stable.
This guide is practical and technical. We will go from the environment to the first test with JUnit 5, covering waits, locators, the Page Object Model (POM) architecture, integration with Cucumber, and a look at the future with Vibium. The examples use Selenium 4 and Java.
What is Selenium?
Selenium is not a single tool, but a suite. Its three main components are WebDriver, which controls the browser via code; Selenium IDE, an extension to quickly record and play back tests; and Selenium Grid, which distributes execution in parallel across several machines and browsers. In serious automation, WebDriver is the protagonist.
What changed in Selenium 4
If you learned Selenium years ago, it is worth knowing what changed, because some of the old content on the internet has become outdated:
- W3C WebDriver protocol: communication with the browser now follows the W3C standard, which made tests more stable across browsers.
- Selenium Manager: Selenium downloads and configures the browser driver automatically. You no longer need to download chromedriver manually or use external libraries for that.
- Relative locators: new locators that find elements by their position relative to others (above, below, to the left, to the right, or near).
- New window and tab API: opening a tab or window became straightforward, with driver.switchTo().newWindow().
- WebDriver BiDi: a bidirectional protocol that paves the way for intercepting network traffic, capturing console logs, and more advanced scenarios.
Preparing the environment
Here is the first piece of good news: you do not need to download a specific IDE or the browser driver manually. Any modern editor works, and Selenium Manager takes care of the driver. In a Java project with Maven, you just add the Selenium and JUnit 5 dependencies:
<!-- pom.xml -->
<dependencies>
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-java</artifactId>
<version>4.27.0</version>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>5.11.3</version>
<scope>test</scope>
</dependency>
</dependencies>Always use the latest available version. With that, the environment is ready for the first test.
First test with Selenium 4 and JUnit 5
The example below automates a login and validates the redirect. Note the use of @BeforeEach and @AfterEach to open and close the browser for each test, keeping isolation:
import org.junit.jupiter.api.*;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import static org.junit.jupiter.api.Assertions.assertTrue;
class LoginTest {
WebDriver driver;
@BeforeEach
void setUp() {
// Selenium Manager downloads and configures the driver automatically
driver = new ChromeDriver();
driver.manage().window().maximize();
}
@Test
void shouldAuthenticateWithValidCredentials() {
driver.get("https://example.com/login");
driver.findElement(By.id("email")).sendKeys("user@example.com");
driver.findElement(By.id("password")).sendKeys("password123");
driver.findElement(By.cssSelector("button[type=submit]")).click();
assertTrue(driver.getCurrentUrl().contains("/dashboard"));
}
@AfterEach
void tearDown() {
driver.quit();
}
}Waits: the secret against flaky tests
The biggest cause of flaky tests is interacting with an element before it is ready. Avoid Thread.sleep with a fixed time and prefer explicit waits, which wait for a specific condition:
import java.time.Duration;
import org.openqa.selenium.support.ui.WebDriverWait;
import org.openqa.selenium.support.ui.ExpectedConditions;
WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(10));
wait.until(ExpectedConditions.elementToBeClickable(By.id("submit"))).click();Locators and the new relative locators
Besides the classic locators (By.id, By.cssSelector, By.xpath), Selenium 4 brings relative locators, which find elements by their position relative to others. They are useful when the HTML structure is unstable but the visual layout is predictable:
import static org.openqa.selenium.support.locators.RelativeLocator.with;
// Finds the password field located right below the email field
WebElement password = driver.findElement(
with(By.tagName("input")).below(By.id("email")));Organizing tests with the Page Object Model (POM)
Writing locators scattered across tests becomes a maintenance nightmare. The Page Object Model solves this by representing each page as a class that concentrates its elements and actions. When the interface changes, the adjustment happens in a single place. It is one of the most important practices for a sustainable suite, a topic we explore further in the article on automation frameworks.
First, the login page as a Page Object:
public class LoginPage {
private final WebDriver driver;
private final By email = By.id("email");
private final By password = By.id("password");
private final By submit = By.cssSelector("button[type=submit]");
public LoginPage(WebDriver driver) {
this.driver = driver;
}
public DashboardPage authenticate(String user, String pass) {
driver.findElement(email).sendKeys(user);
driver.findElement(password).sendKeys(pass);
driver.findElement(submit).click();
return new DashboardPage(driver);
}
}Now the test is clean, readable, and focused on behavior, with no locator details:
@Test
void validLoginLeadsToDashboard() {
driver.get("https://example.com/login");
DashboardPage dashboard = new LoginPage(driver)
.authenticate("user@example.com", "password123");
assertTrue(dashboard.isVisible());
}Selenium with Cucumber (BDD)
A strong point of Selenium is its flexibility: it fits both with test frameworks like JUnit 5 and with BDD approaches like Cucumber. In BDD, the scenario is described in near-natural language, in the Given-When-Then format, bringing the technical team and the business closer together. See the same login described in a feature file:
# login.feature
Feature: Login
Scenario: Login with valid credentials
Given I am on the login page
When I enter a valid username and password
Then I should be redirected to the dashboardThe steps link each phrase to the Selenium code. Notice that the same Page Object is reused, showing how POM, Selenium, and Cucumber work well together:
import io.cucumber.java.en.*;
import static org.junit.jupiter.api.Assertions.assertTrue;
public class LoginSteps {
WebDriver driver = new ChromeDriver();
LoginPage login = new LoginPage(driver);
@Given("I am on the login page")
public void openLogin() {
driver.get("https://example.com/login");
}
@When("I enter a valid username and password")
public void enterCredentials() {
login.authenticate("user@example.com", "password123");
}
@Then("I should be redirected to the dashboard")
public void validateDashboard() {
assertTrue(driver.getCurrentUrl().contains("/dashboard"));
}
}Best practices with Selenium
- Adopt the Page Object Model from the start to isolate the interface from the test logic.
- Use explicit waits and avoid fixed wait times.
- Keep test data isolated and prioritize scenarios by risk, as in regression testing.
- Integrate the suite into the CI/CD pipeline to run on every delivery.
- Scale execution in parallel with Selenium Grid when the suite grows.
- Watch out for practices that sabotage results, as we detail in automation best practices.
The future: from Selenium to Vibium
It is worth keeping an eye on what is coming. Jason Huggins, the creator of Selenium, is developing Vibium, presented as a successor designed for the AI era. The idea is born from a direct question: if we were to rebuild Selenium so that it stopped being flaky, what would we change? The answer involves communication via WebSocket and WebDriver BiDi, along with features such as describing tests in natural language and self-healing of broken selectors.
Vibium is still in an early stage, but it signals where automation is heading. Knowing Selenium well today is the best foundation for following this evolution without surprises.
Conclusion
Selenium 4 is simpler and more stable than the versions that made the tool popular. With Selenium Manager, relative locators, and the W3C protocol, writing tests became more straightforward, and, combined with good practices like the Page Object Model, JUnit 5, and Cucumber, it serves everyone from technical teams to BDD scenarios. To choose the right tool for your context, it is worth comparing the options in our guide on test automation frameworks.
It is worth noting that Proton, Atomic's automation platform, supports Selenium. This makes it possible to integrate and orchestrate the automations built with this technology in a single place, adding the power of Selenium to the platform's centralized management.
Do you want to implement test automation with the confidence of a company with 10 years in the market and expertise in Quality Assurance? Talk to Atomic Solutions and speed up your deliveries without giving up quality.
Keep reading

Test automation: what it is, how it works, why to do it, and how the right platform can optimize your business model
Understand what test automation is, when to invest in this strategy, and how it helps companies reduce failures, speed up deliveries, and scale software quality more efficiently.

SESI/SENAI SP Success Story: Quality Assurance for System Structuring and a Test Center of Excellence
Between August and October 2025, Atomic Solutions structured a Test Center of Excellence (TCoE) for SESI/SENAI SP, standardizing QA practices, reducing rework, and establishing quality as a strategic pillar in the development of the institution's internal systems.

Understand why your automation framework may be holding back your QA evolution
Understand how a poorly structured automation framework can limit your QA evolution, create rework, and make it harder to scale automated testing.