Selenium WebDriver Tutorial (2026)

Selenium WebDriver automates browser actions for web testing. Learn how it works, how to set it up, and how to write tests.

Written by Sarthak Sharma Sarthak Sharma
Reviewed by Bhumika Babbar Bhumika Babbar
Last updated: 23 December 2025 25 min read

Key Takeaways

  • Selenium WebDriver automates real browsers through browser drivers, using Java commands to perform actions and verify results.
  • Use Maven, TestNG, and Selenium Manager to set up Selenium 4 without manually managing browser drivers.
  • Use stable locators, explicit waits, and driver.quit() from the start to avoid common Selenium failures.

Selenium WebDriver Tutorial (2026)

Testing a web application manually can get repetitive very quickly. You open a browser, go to a page, enter data, click buttons, check results, and repeat the same steps every time something changes.

Selenium WebDriver helps automate these browser actions. It lets you write code that opens a real browser, interacts with web elements, performs user actions, and verifies whether the application behaves as expected.

In this article, I’ll explain Selenium WebDriver using Java, starting from the basics. We’ll look at what WebDriver is, how it works, how to set it up, how to write your first test, and how to handle important parts of browser automation such as locators, waits, alerts, frames, windows, and common errors.

What is Selenium WebDriver?

Selenium WebDriver is a browser automation tool that lets you control a web browser through code. In Java, you can use WebDriver to open a browser, visit a URL, find elements on a web page, click buttons, type into fields, read text, and verify application behavior.

WebDriver is the main Selenium component used for automated web UI testing, while tools like TestNG or JUnit are usually added to manage test cases, assertions, and reports.

How Selenium WebDriver Works

Selenium WebDriver acts as a bridge between your test code and the browser. You write commands in Java, Selenium sends those commands to the browser driver, and the browser driver tells the browser what action to perform.

Here is the basic flow:

  1. Test script: You write Selenium commands in Java, such as opening a page, finding an element, clicking a button, or entering text.
  2. Selenium WebDriver API: The Java WebDriver library converts your code into browser automation commands.
  3. Browser driver: A browser-specific driver, such as ChromeDriver, GeckoDriver, or EdgeDriver, receives the command and passes it to the browser.
  4. Browser: The browser performs the action, such as loading a URL, clicking an element, typing into a field, or returning page information.
  5. Response: The browser sends the result back to the driver, and the driver sends it back to your Selenium script.

For example, when you write:

driver.get("https://example.com");

On executing this command, Selenium webdriver sends the navigation command to the browser driver. The WebDriver asks the browser to load the page, waits for the browser response, and then returns control to your test script.

The same flow applies when you click a button or type into an input field. Your test code gives the instruction, the browser driver executes it in the browser, and Selenium receives the result. In Selenium 4, this communication follows the W3C WebDriver standard, which helps keep browser automation more consistent across modern browsers.

Selenium WebDriver Architecture in Selenium 4

This architecture matters because your test code does not control the browser directly. WebDriver works through the browser driver, which is why browser version, driver compatibility, waits, and session handling can affect how reliably your tests run.

Older Selenium versions used the JSON Wire Protocol. Selenium 4 uses the W3C WebDriver protocol as the standard, which makes communication between Selenium, browser drivers, and modern browsers more consistent.

Selenium Grid 4 Architecture scaled

Prerequisites for Using Selenium WebDriver with Java

Before writing a Selenium WebDriver test in Java, you need a basic Java project setup and a browser where the test can run. Selenium 4 can manage browser drivers automatically in many common setups, but your local environment still needs the right tools installed.

You will need:

  • Java JDK: Install a supported Java Development Kit so you can compile and run Java test code.
  • Maven or Gradle: Use a build tool to manage Selenium and testing dependencies. Maven is commonly used in Java Selenium tutorials, so we will use Maven in this article.
  • IDE: Use an IDE such as IntelliJ IDEA, Eclipse, or VS Code to write and run the test.
  • Browser: Install the browser you want to automate, such as Chrome, Firefox, Edge, or Safari.
  • Selenium Java dependency: Add Selenium WebDriver to your project through Maven instead of downloading JAR files manually.
  • Test framework: Use TestNG or JUnit to structure tests, add assertions, manage setup and cleanup, and run test suites. For a basic script, Java’s main() method can work, but real projects should use a test framework.

How to Set Up Selenium WebDriver in Java

The easiest way to set up Selenium WebDriver in Java is to use Maven. Maven downloads Selenium, TestNG, and other required libraries through the pom.xml file, so you do not need to add JAR files manually.

Step 1: Create a Maven project

Open your IDE and create a new Maven project. Keep your Selenium test classes under src/test/java because these are test files, not application source files.

Project Setup

Step 2: Add Selenium and TestNG dependencies

Open pom.xml and add Selenium Java and TestNG. Selenium controls the browser, while TestNG helps you structure tests, add assertions, and manage setup and cleanup.

<dependencies>

   <dependency>

       <groupId>org.seleniumhq.selenium</groupId>

       <artifactId>selenium-java</artifactId>

       <version>4.x.x</version>

   </dependency>



   <dependency>

       <groupId>org.testng</groupId>

       <artifactId>testng</artifactId>

       <version>7.x.x</version>

       <scope>test</scope>

   </dependency>

</dependencies>

Use the latest stable Selenium 4 and TestNG versions available in Maven Central.

Step 3: Install a browser

Install the browser you want to automate, such as Chrome, Firefox, Edge, or Safari.

Step 4: Let Selenium Manager handle drivers

In Selenium 4, Selenium Manager can handle browser driver setup for many common local runs. This means you usually do not need to download ChromeDriver, GeckoDriver, or EdgeDriver manually before running a basic test.

Step 5: Create a test class

Create a Java test class under src/test/java. You can start with a simple main() method to understand WebDriver basics, but real test suites should use TestNG or JUnit for assertions, setup, teardown, grouping, and reports.

How to Run Your First Selenium WebDriver Test

Once the setup is ready, you can write a simple Selenium WebDriver script that opens a browser, loads a page, enters text, submits a form, and verifies the result.

Here is a basic Java example:

import java.time.Duration;



import org.openqa.selenium.By;

import org.openqa.selenium.WebDriver;

import org.openqa.selenium.WebElement;

import org.openqa.selenium.chrome.ChromeDriver;

import org.openqa.selenium.support.ui.ExpectedConditions;

import org.openqa.selenium.support.ui.WebDriverWait;



public class FirstSeleniumTest {

   public static void main(String[] args) {

       WebDriver driver = new ChromeDriver();



       try {

           driver.get("https://www.selenium.dev/selenium/web/web-form.html");



           WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(10));



           WebElement textBox = wait.until(

               ExpectedConditions.visibilityOfElementLocated(By.name("my-text"))

           );

           textBox.sendKeys("Selenium WebDriver");



           WebElement submitButton = driver.findElement(By.cssSelector("button"));

           submitButton.click();



           WebElement message = wait.until(

               ExpectedConditions.visibilityOfElementLocated(By.name("my-text"))

        );

        textBox.sendKeys("Selenium WebDriver");



        WebElement submitButton = driver.findElement(By.cssSelector("button"));

        submitButton.click();
 

        WebElement message = wait.until(

               ExpectedConditions.visibilityOfElementLocated(By.id("message"))

        );
 

        if (!message.getText().equals("Received!")) {

            throw new AssertionError("Expected confirmation message was not displayed.");

        }

 
        System.out.println("Test passed.");


    } finally {

        driver.quit();

    }

   }

}

FirstSeleniumTest Terminal

FirstSeleniumTest website

FirstSeleniumTest websiteThis test does five things:

  • Starts the browser: new ChromeDriver() creates a new Chrome browser session.
  • Opens the test page: driver.get() loads the web page that needs to be tested.
  • Finds and interacts with elements: findElement() and sendKeys() locate the input field and enter text.
  • Submits the form: click() performs a user-like click on the submit button.
  • Verifies the result: The script checks whether the confirmation message says Received!.

The finally block is important because it closes the browser even if the test fails. Without driver.quit(), browser processes can remain open in the background and cause issues when you run more tests later.

How the Same Test Looks in TestNG

The earlier example uses a main() method to keep the first script simple. In a real automation project, you should use a test framework like TestNG so the test has proper setup, assertion, and cleanup methods.

import java.time.Duration;



import org.openqa.selenium.By;

import org.openqa.selenium.WebDriver;

import org.openqa.selenium.WebElement;

import org.openqa.selenium.chrome.ChromeDriver;

import org.openqa.selenium.support.ui.ExpectedConditions;

import org.openqa.selenium.support.ui.WebDriverWait;

import org.testng.Assert;

import org.testng.annotations.AfterMethod;

import org.testng.annotations.BeforeMethod;

import org.testng.annotations.Test;



public class FirstSeleniumTestNGTest {

   WebDriver driver;

   WebDriverWait wait;



   @BeforeMethod

   public void setUp() {

       driver = new ChromeDriver();

       wait = new WebDriverWait(driver, Duration.ofSeconds(10));

   }



   @Test

   public void submitWebForm() {

       driver.get("https://www.selenium.dev/selenium/web/web-form.html");



       WebElement textBox = wait.until(

           ExpectedConditions.visibilityOfElementLocated(By.name("my-text"))

       );

       textBox.sendKeys("Selenium WebDriver");



       WebElement submitButton = driver.findElement(By.cssSelector("button"));

       submitButton.click();



       WebElement message = wait.until(

           ExpectedConditions.visibilityOfElementLocated(By.id("message"))

       );



       Assert.assertEquals(message.getText(), "Received!");

   }



   @AfterMethod

   public void tearDown() {

       if (driver != null) {

           driver.quit();

       }

   }

}

FirstSeleniumTestNGTest Terminal

TestNG Report Screenshot

This version is closer to how Selenium tests are written in real projects. @BeforeMethod starts the browser before each test, @Test contains the actual test steps, and @AfterMethod closes the browser after the test finishes. This keeps the test clean and prevents leftover browser sessions from affecting later runs.

Common Selenium WebDriver Commands

Most Selenium WebDriver tests are built from a small set of commands. These commands usually fall into four groups: opening pages, finding elements, performing actions, and reading browser or element state.

CommandWhat it doesExample
get()Opens a URL in the current browser windowdriver.get(“https://example.com”);
getTitle()Returns the page titledriver.getTitle();
getCurrentUrl()Returns the current browser URLdriver.getCurrentUrl();
findElement()Finds the first matching element on the pagedriver.findElement(By.id(“email”));
findElements()Finds all matching elements and returns a listdriver.findElements(By.cssSelector(“.item”));
click()Clicks a button, link, checkbox, or another clickable elementsubmitButton.click();
sendKeys()Types text into an input fieldemailField.sendKeys(“test@example.com”);
getText()Reads visible text from an elementmessage.getText();
getAttribute()Reads an attribute value from an elementinput.getAttribute(“value”);
isDisplayed()Checks whether an element is visiblebanner.isDisplayed();
isEnabled()Checks whether an element is enabledbutton.isEnabled();
isSelected()Checks whether a checkbox or radio button is selectedcheckbox.isSelected();
quit()Closes all browser windows and ends the WebDriver sessiondriver.quit();

Here is a simple example using a few of these commands together:

driver.get("https://www.selenium.dev/selenium/web/web-form.html");



WebElement textBox = driver.findElement(By.name("my-text"));

textBox.sendKeys("Selenium");



WebElement submitButton = driver.findElement(By.cssSelector("button"));

submitButton.click();



System.out.println(driver.getTitle());



driver.quit();

A common mistake I see is treating findElement() as if it will always find the element immediately. It will not. If the page loads slowly or the element appears after JavaScript runs, the command can fail. That is why locators and waits are the next important part of writing stable Selenium tests.

Selenium WebDriver Locators and Waits

Locators and waits decide whether a Selenium test is stable or flaky. A locator tells WebDriver which element to interact with, while a wait tells WebDriver when the element is ready for that interaction. If either one is weak, the test may fail even when the application is working correctly.

Selenium WebDriver Locators

A locator is used to find an element on a web page. Selenium supports different locator strategies, but not all of them are equally stable.

LocatorExampleBest used when
By.id()By.id(“email”)The element has a unique and stable id
By.name()By.name(“username”)Form fields have reliable name attributes
By.cssSelector()By.cssSelector(“button[type=’submit’]”)You need flexible and readable element targeting
By.xpath()By.xpath(“//button[text()=’Login’]”)You need to locate elements by text, hierarchy, or complex conditions
By.className()By.className(“submit-button”)The class is unique enough to identify the element
By.linkText()By.linkText(“Forgot password?”)You need to locate a link by its exact visible text
By.partialLinkText()By.partialLinkText(“Forgot”)The link text may be long but has a stable part
By.tagName()By.tagName(“input”)You need to find elements by HTML tag, usually as part of a broader check

A good locator should be stable, readable, and specific enough to find only the intended element.

Use this order of preference in most cases:

  • Stable ID or test attribute: Prefer id, data-testid, data-test, or similar attributes when they are available and controlled by the team.
  • CSS selector: Use CSS selectors when you need a clean and flexible locator for attributes, classes, parent-child relationships, or element states.
  • XPath: Use XPath when CSS cannot express what you need, such as locating an element by exact text or moving from a label to a related input.
  • Avoid brittle paths: Do not rely on long absolute XPath values such as /html/body/div[2]/div[1]/form/input[3]. These break easily when the page layout changes.

Example of better locators:

By emailInput = By.id("email");

By submitButton = By.cssSelector("button[type='submit']");

By errorMessage = By.cssSelector("[data-testid='login-error']");

Example of a brittle locator:

By badLocator = By.xpath("/html/body/div[2]/div[1]/form/div[3]/button");

The brittle locator depends on the exact page structure. If one extra div is added, the test may fail even though the button still exists.

Selenium WebDriver Waits

Modern web pages do not always load everything at once. Elements may appear after an API call, become clickable after an animation, or update after JavaScript finishes running. Waits help Selenium pause until the page reaches the expected state.

There are three main types of waits in Selenium:

Wait typeWhat it doesWhen to use
Implicit waitTells WebDriver to wait for a short time when finding elementsRarely, and only for simple projects
Explicit waitWaits for a specific condition before continuingBest choice for most Selenium tests
Fluent waitWaits for a condition with custom polling and ignored exceptionsUseful for highly dynamic elements

In real projects, explicit waits are usually the safest option because they wait for a clear condition.

WAIT Flow Diagram

Example:

WebDriverWait wait = new WebDriverWait(driver,

                  Duration.ofSeconds(10));



WebElement submitButton = wait.until(ExpectedConditions.

                       elementToBeClickable(

                          By.cssSelector("button")));


submitButton.click();

This code waits until the login button is clickable before clicking it. That is better than using Thread.sleep() because the test continues as soon as the condition is met. It does not wait for a fixed delay every time.

Selenium WebDriver Waits

Avoid this:

Thread.sleep(5000);

driver.findElement(By.id("submit-button")).click();

This slows down the suite and still does not guarantee that the element is ready after five seconds.

Use this instead:

WebElement submitButton = wait.until(ExpectedConditions.

                       elementToBeClickable(

                          By.cssSelector("button")));

 

submitButton.click();

A useful rule is to wait for the state you actually need:

  • Before typing: Wait for the element to be visible or clickable.
  • Before clicking: Wait for the element to be clickable.
  • Before reading text: Wait for the element to be visible or wait until the text is present.
  • Before checking page changes: Wait for the expected URL, title, element, or message.

For example:

wait.until(ExpectedConditions.visibilityOfElementLocated(By.id("message")));



wait.until(ExpectedConditions.textToBePresentInElementLocated(

   By.id("message"),

   "Received!"

));

Confirmation message

Also avoid mixing implicit and explicit waits in the same test suite unless there is a clear reason. It can make timeout behavior harder to understand because both waits may affect how long Selenium keeps trying to find an element.

For stable Selenium tests, the practical formula is simple:

Stable locator + explicit wait + clear assertion = more reliable test

Handling Common Selenium WebDriver Scenarios

After the first test works, the next challenge is handling browser behavior that appears in real applications. Selenium WebDriver provides APIs for common UI scenarios such as dropdowns, alerts, frames, windows, screenshots, and file uploads.

The examples below assume that driver is already initialized and that common Selenium classes such as WebElement, By, WebDriverWait, and ExpectedConditions are already imported. Some examples need additional imports, such as Select, Alert, TakesScreenshot, OutputType, File, Files, Paths, and StandardCopyOption.

1. Handling Dropdowns

Use Selenium’s Select class only when the dropdown is built with the HTML <select> tag.

import org.openqa.selenium.support.ui.Select;



WebElement countryDropdown = driver.findElement(By.id("country"));

Select select = new Select(countryDropdown);



select.selectByVisibleText("India");

select.selectByValue("IN");

select.selectByIndex(1);

For custom dropdowns built with div, span, or JavaScript components, do not use Select. Click the dropdown first, then click the required option.

driver.findElement(By.id("country-dropdown")).click();

driver.findElement(By.xpath("//div[text()='India']")).click();

2. Handling Alerts

JavaScript alerts, confirms, and prompts are handled by switching WebDriver’s focus to the alert.

Alert alert = driver.switchTo().alert();



String alertText = alert.getText();

alert.accept();

For a prompt, enter text before accepting it.

Alert prompt = driver.switchTo().alert();



prompt.sendKeys("Test input");

prompt.accept();

Handling Alerts

Use an explicit wait when the alert may not appear immediately.

WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(10));



Alert alert = wait.until(ExpectedConditions.alertIsPresent());

alert.accept();

3. Handling Frames and Iframes

If an element is inside a frame or iframe, WebDriver cannot interact with it until you switch into that frame.

WebElement frame = driver.findElement(By.cssSelector("iframe[name='payment-frame']"));

driver.switchTo().frame(frame);



driver.findElement(By.id("card-number")).sendKeys("4111111111111111");



driver.switchTo().defaultContent();

The important part is switching back to the main page after the frame interaction. If you forget defaultContent(), Selenium will keep searching for elements inside the frame.

4. Handling Multiple Windows and Tabs

When a click opens a new tab or window, store the original window handle first. Then switch to the new handle.

package org.example;



import org.openqa.selenium.By;

import org.openqa.selenium.WebDriver;

import org.openqa.selenium.chrome.ChromeDriver;

 

public class WindowHandlingExample {

public static void main(String[] args) throws InterruptedException {

     WebDriver driver = new ChromeDriver();

     {

            driver.manage().window().maximize();

         driver.get(

                    "https://www.selenium.dev/selenium/web/window_switching_tests/page_with_frame.html"

         );

         // Store parent window

         String originalWindow = driver.getWindowHandle();

         System.out.println(

                 "Parent Window Title: " + driver.getTitle()

         );

         // Click link that opens a new window

            driver.findElement(By.linkText("Open new window")).click();

         // Wait for second window

         while (driver.getWindowHandles().size() < 2) {

             Thread.sleep(500);

         }

         // Switch to child window

         for (String windowHandle : driver.getWindowHandles()) {

             if (!windowHandle.equals(originalWindow)) {

                    driver.switchTo().window(windowHandle);

                 break;

             }

         }

         System.out.println(

                 "Child Window Title: " + driver.getTitle()

         );

         Thread.sleep(3000);

         // Switch back to parent window

            driver.switchTo().window(originalWindow);

         System.out.println(

                 "Back to Parent Window: " + driver.getTitle()

         );

         Thread.sleep(3000);

     }

}

}

WindowHandlingExample Terminal

Parent_Window

Child Window

This pattern is useful for payment redirects, OAuth login flows, help pages, and third-party windows.

5. Handling File Uploads

For file uploads, locate the <input type=”file”> element and send the file path using sendKeys().

WebElement uploadInput = driver.findElement(By.cssSelector("input[type='file']"));


uploadInput.sendKeys("C:\\Users\\user\\Downloads\\sample.pdf");

This works when the file input is available in the DOM. Selenium does not directly automate native operating system file picker windows. If the app hides the file input behind a custom button, locate the actual file input instead of trying to control the OS dialog.

Handling File Uploads

6. Taking Screenshots

Screenshots are useful when debugging failed tests because they show the browser state at the time of failure.

File screenshot = ((TakesScreenshot) driver).getScreenshotAs(OutputType.FILE);


Files.copy(

   screenshot.toPath(),

   Paths.get("screenshots/test-failure.png"),

   StandardCopyOption.REPLACE_EXISTING

);

In real test suites, screenshots are usually captured inside failure hooks or listeners so every failed test produces visual evidence automatically.

Common Selenium WebDriver Exceptions and Fixes

Selenium WebDriver exceptions usually happen when the browser state and the test script are not aligned. The page may still be loading, the element may have changed after a JavaScript update, or the locator may no longer match the current DOM.

The goal is not to hide these errors with longer waits. The goal is to understand what the exception means and fix the real cause.

ExceptionWhat it usually meansCommon fix
NoSuchElementExceptionSelenium could not find the element using the given locatorCheck the locator, wait for the element, or switch to the correct frame/window
TimeoutExceptionThe expected condition was not met within the wait timeWait for the correct condition, not just a longer duration
StaleElementReferenceExceptionThe element was found earlier, but the DOM changed and the reference is no longer validFind the element again after the page update
ElementClickInterceptedExceptionAnother element is blocking the clickWait until overlays, loaders, or animations disappear
ElementNotInteractableExceptionThe element exists in the DOM but cannot be interacted withWait for visibility/clickability or target the correct visible element
InvalidSelectorExceptionThe CSS selector or XPath syntax is invalidFix the locator syntax
NoSuchFrameExceptionSelenium tried to switch to a frame that was not availableWait for the frame and switch before interacting
NoSuchWindowExceptionSelenium tried to use a window or tab that is no longer openStore and validate window handles before switching

1. NoSuchElementException

NoSuchElementException means Selenium could not find an element that matches the locator.

This can happen for a few reasons:

  • Wrong locator: The locator does not match the actual HTML.
  • Element loads later: The element appears only after JavaScript or an API response.
  • Wrong frame: The element is inside an iframe, but Selenium is still looking at the main page.
  • Wrong window: The element is in a new tab or window, but Selenium has not switched to it.

Avoid this:

WebElement submitButton = driver.findElement(By.id("submit-button"));

Use this when the element may load after the page opens:

WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(10));
 

WebElement textBox = wait.until(ExpectedConditions.

                  visibilityOfElementLocated(By.name("my-text"))

         );



textBox.sendKeys("Selenium WebDriver");


WebElement submitButton = driver.findElement(By.cssSelector("button"));


submitButton.click();

NoSuchElementException

2. TimeoutException

TimeoutException happens when Selenium waits for a condition, but that condition is not met within the given time.

A common mistake is increasing the wait time without checking whether the condition is correct. For example, waiting for visibility will not help if the element exists but is hidden behind a loader, disabled, or inside an iframe.

Better checks:

  • For buttons: Wait for elementToBeClickable().
  • For messages: Wait for visibilityOfElementLocated() or textToBePresentInElementLocated().
  • For page navigation: Wait for urlContains() or titleContains().
  • For loaders: Wait for invisibilityOfElementLocated().

Example:

wait.until(ExpectedConditions.invisibilityOfElementLocated(By.id("loading-spinner")));



WebElement submitButton = wait.until(

   ExpectedConditions.elementToBeClickable(By.id("submit"))

);



submitButton.click();

3. StaleElementReferenceException

StaleElementReferenceException means the element reference is no longer valid. This usually happens when the page updates after Selenium has already found the element.

For example, this can fail if the DOM refreshes after the element is stored:

WebElement saveButton = driver.findElement(By.id("save"));



driver.navigate().refresh();



saveButton.click();

The fix is to locate the element again after the update:

driver.navigate().refresh();



WebElement saveButton = wait.until(

   ExpectedConditions.elementToBeClickable(By.id("save"))

);



saveButton.click();

A useful rule: do not store WebElement references too early if the page is dynamic. Store locators, then find the element when you need to interact with it.

4. ElementClickInterceptedException

ElementClickInterceptedException means Selenium found the element, but the click could not reach it. Another element is usually covering it, such as a loader, cookie banner, modal, sticky header, or animation.

Fix it by waiting for the blocking element to disappear:

wait.until(ExpectedConditions.invisibilityOfElementLocated(By.cssSelector(".modal-backdrop")));


WebElement continueButton = wait.until(

   ExpectedConditions.elementToBeClickable(By.id("continue"))

);


continueButton.click();

Do not immediately use JavaScript click as the default fix. A JavaScript click can bypass real user behavior and hide actual UI problems. Use it only when you have confirmed that the application intentionally requires it.

5. ElementNotInteractableException

ElementNotInteractableException means the element is present in the DOM, but Selenium cannot interact with it. The element may be hidden, disabled, outside the visible area, or not the actual interactive control.

Common fixes:

  • Wait for visibility: Use visibilityOfElementLocated() before typing or reading visible text.
  • Wait for clickability: Use elementToBeClickable() before clicking.
  • Check duplicate elements: The locator may match a hidden element instead of the visible one.
  • Scroll only when needed: If the element is below the fold, scroll it into view before interacting.

Example:

WebElement input = wait.until(

   ExpectedConditions.visibilityOfElementLocated(By.id("email"))

);


input.sendKeys("test@example.com");

The best way to reduce Selenium exceptions is to combine stable locators, explicit waits, correct frame/window handling, and clean test setup. Most failures become easier to debug when each test waits for the exact browser state it needs before taking the next action.

Selenium WebDriver Best Practices for 2026

A good Selenium WebDriver test should be easy to read, stable across runs, and simple to debug when it fails. Once the basic script works, follow these practices to make the test suite maintainable.

  • Use stable locators: Prefer id, data-testid, data-test, or clear CSS selectors. Avoid long absolute XPath values because they break when the page structure changes.
  • Use explicit waits: Wait for the exact state you need, such as visibility, clickability, text presence, or loader disappearance. Avoid using Thread.sleep() as a regular waiting strategy.
  • Keep tests focused: Each test should validate one clear flow or behavior. Long tests that cover too many actions are harder to debug and more likely to fail for unrelated reasons.
  • Use Page Object Model: Keep locators and page actions inside page classes instead of placing everything in the test method. This makes tests easier to read and update when the UI changes.
  • Close the browser session properly: Use driver.quit() after each test to end the full WebDriver session and avoid leftover browser processes.
  • Make tests independent: A test should not depend on another test running before it. Prepare the data, login state, and cleanup needed for each test.
  • Capture failure evidence: Save screenshots, page source, logs, and failed step details when tests fail, especially in CI where you cannot watch the browser run.
  • Run important flows across real browsers: Local testing is useful for fast feedback, but critical flows should also run across the browsers, operating systems, and viewports your users rely on.

Conclusion

Selenium WebDriver is one of the most widely used tools for automating web browser testing because it gives testers direct control over real browsers through code. With Java, you can use WebDriver to open pages, locate elements, perform actions, handle browser events, and verify application behavior.

A basic script is only the starting point. To build reliable Selenium tests, focus on stable locators, explicit waits, clean browser session handling, and clear test structure. As your test suite grows, practices like Page Object Model, independent tests, failure screenshots, and cross-browser execution become important for keeping automation useful and maintainable.

Tags
Automation Testing Selenium Selenium Webdriver
Sarthak Sharma
Sarthak Sharma

Senior SDE - Customer Engineering

Sarthak Sharma has spent 9+ years building and improving systems used in real customer environments. As a Senior SDE, he focuses on making solutions that can handle scale, complexity, and the kind of challenges that come up in production.

Writing Selenium WebDriver tests?
Run them across real browsers to catch cross-browser issues.