keepcalculator

06 Numbers and Powers

Selenium 4 Java End-to-End Tests: Step-by-Step

Card No. 06·49048 · Updated · Standard formula, shown below

This guide walks you through writing end-to-end (E2E) tests using Selenium 4 with Java. You’ll learn how to set up a project, write a test that interacts with a real browser, and run it reliably. By the end, you’ll have a reusable test structure you can extend to cover your own user journeys.

What You’ll Need

  • Java JDK 8 or later (Selenium 4 requires Java 8+; Java 11 or 17 is recommended)
  • Maven or Gradle for dependency management (examples use Maven)
  • An IDE like IntelliJ IDEA, Eclipse, or VS Code with Java support
  • A modern browser – Chrome, Firefox, Edge, or Safari
  • WebDriver binaries – Selenium 4 can manage these automatically using Selenium Manager (bundled), but you can also download them manually if you prefer.
  • Basic Java knowledge – classes, methods, and annotations.

Step-by-Step

  1. Create a new Maven project

    In your IDE, create a new Maven project (or a Gradle one). If you’re using the command line, run:

    mvn archetype:generate -DgroupId=com.example -DartifactId=e2e-tests -DarchetypeArtifactId=maven-archetype-quickstart

    This gives you a standard project structure with a pom.xml.

  2. Add Selenium 4 dependencies

    Open pom.xml and add the Selenium Java dependency. As of Selenium 4.6+, Selenium Manager automatically handles driver binaries, so you don’t need to add separate driver dependencies.

    <dependency>
        <groupId>org.seleniumhq.selenium</groupId>
        <artifactId>selenium-java</artifactId>
        <version>4.21.0</version>
        <scope>test</scope>
    </dependency>

    Also add JUnit 5 (or TestNG) for writing test cases:

    <dependency>
        <groupId>org.junit.jupiter</groupId>
        <artifactId>junit-jupiter</artifactId>
        <version>5.10.2</version>
        <scope>test</scope>
    </dependency>
  3. Set up a WebDriver instance

    Create a class that initializes the WebDriver. Using Selenium 4, you can simply do:

    import org.openqa.selenium.WebDriver;
    import org.openqa.selenium.chrome.ChromeDriver;
    
    public class DriverFactory {
        public static WebDriver createDriver() {
            return new ChromeDriver();
        }
    }

    Selenium Manager will automatically download the matching ChromeDriver if it’s not present. For Firefox, use FirefoxDriver(), and for Edge, EdgeDriver().

  4. Write your first E2E test

    Create a test class (e.g., LoginTest.java) in src/test/java. Use JUnit 5 annotations:

    import org.junit.jupiter.api.*;
    import org.openqa.selenium.By;
    import org.openqa.selenium.WebDriver;
    import org.openqa.selenium.WebElement;
    import static org.junit.jupiter.api.Assertions.*;
    
    public class LoginTest {
        private WebDriver driver;
    
        @BeforeEach
        void setUp() {
            driver = DriverFactory.createDriver();
        }
    
        @AfterEach
        void tearDown() {
            driver.quit();
        }
    
        @Test
        void testLogin() {
            driver.get("https://example.com/login");
            driver.findElement(By.id("username")).sendKeys("testuser");
            driver.findElement(By.id("password")).sendKeys("password123");
            driver.findElement(By.cssSelector("button[type='submit']")).click();
            WebElement welcome = driver.findElement(By.cssSelector(".welcome"));
            assertTrue(welcome.isDisplayed());
            assertEquals("Welcome, testuser!", welcome.getText());
        }
    }

    Replace the selectors and URL with your own application’s elements.

  5. Run the test

    From the command line, run mvn test (or run the test from your IDE). The test will open a browser, perform the steps, and report pass/fail.

  6. Use explicit waits for dynamic content

    Modern web apps load content asynchronously. Replace implicit waits (or sleeps) with explicit waits:

    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.visibilityOfElementLocated(By.id("result")));

    This waits up to 10 seconds for the element to appear, reducing flakiness.

  7. Organize tests with Page Object Model

    For maintainability, create a page class for each page. For example:

    public class LoginPage {
        private WebDriver driver;
        private By usernameField = By.id("username");
        private By passwordField = By.id("password");
        private By submitButton = By.cssSelector("button[type='submit']");
    
        public LoginPage(WebDriver driver) {
            this.driver = driver;
        }
    
        public void login(String user, String pass) {
            driver.findElement(usernameField).sendKeys(user);
            driver.findElement(passwordField).sendKeys(pass);
            driver.findElement(submitButton).click();
        }
    }

    Then use it in your test: new LoginPage(driver).login("user", "pass");

  8. Run tests in CI/CD

    To run tests in a headless environment (like a build server), configure the driver to run headless:

    ChromeOptions options = new ChromeOptions();
    options.addArguments("--headless");
    WebDriver driver = new ChromeDriver(options);

    This lets you run tests without a visible browser window.

Common Mistakes

  • Using Thread.sleep() – Hard-coded sleeps are brittle; use explicit waits instead.
  • Not closing the driver – Always call driver.quit() in @AfterEach to release resources.
  • Ignoring element visibility – An element may exist in DOM but not be visible; use isDisplayed() checks.
  • Hard-coding URLs – Use configuration files or environment variables for different environments.
  • Testing only the happy path – Include negative tests (e.g., wrong password) to ensure error handling works.
  • Running tests in parallel without isolation – Each test should create its own driver instance.

Tips

  • Use relative locators – Selenium 4 introduced RelativeLocator (e.g., withTagName("button").below(By.id("email"))) for more robust element finding.
  • Leverage Selenium Manager – It automatically handles driver versions, so you don’t need to manually download drivers.
  • Take screenshots on failure – Use ((TakesScreenshot) driver).getScreenshotAs(...) in a @AfterEach hook to debug.
  • Use data-driven tests – Parameterize tests with different input sets using JUnit’s @ParameterizedTest.
  • Keep tests independent – Each test should be able to run alone; avoid dependencies on order.

Troubleshooting

  • Driver not found error – If Selenium Manager fails (e.g., no internet), download the driver manually and set webdriver.chrome.driver system property.
  • Element not found exception – Double-check the selector; use the browser’s DevTools to inspect. Also ensure you’re waiting for the element to be present.
  • Tests pass locally but fail in CI – Often due to different screen size or timing. Use explicit waits and set a viewport size in options.
  • Browser opens but test hangs – Check for JavaScript alerts or pop-ups; handle them with driver.switchTo().alert().accept().
  • Version mismatch – Ensure your browser is compatible with the WebDriver version. Selenium Manager usually picks the right one, but if you manually manage drivers, keep them updated.

Frequently Asked Questions

  1. Do I need to download WebDriver separately? – No, Selenium 4.6+ includes Selenium Manager, which automatically downloads the correct driver for your browser and version.
  2. Can I use Selenium 4 with Java 8? – Yes, Selenium 4 requires Java 8 or higher, but Java 11+ is recommended for better performance and features.
  3. How do I run tests in parallel? – Use JUnit 5’s parallel execution or integrate with TestNG. Set junit.jupiter.execution.parallel.enabled=true in junit-platform.properties.
  4. What is the difference between findElement and findElements? – findElement returns the first matching element or throws if none; findElements returns a list (empty if none). Use the latter when checking for existence.
  5. How do I handle pop-ups or new tabs? – Use driver.getWindowHandles() to switch between windows, or driver.switchTo().alert() for JavaScript alerts.
  6. Is Selenium 4 backward compatible with Selenium 3 code? – Most Selenium 3 code works, but some APIs were deprecated or changed (e.g., WebDriverWait now uses Duration). You’ll need to update imports and method signatures.

Related

Method: the standard formula for this calculation, rounded as each result states. See how the calculators work or report an error.

More cards in this drawer

The whole Numbers and Powers drawer →