Chapter 6: End-to-End Testing
This chapter focuses on how to perform end-to-end (E2E) testing using tools like Selenium (Java-based) and Cypress (JavaScript-based). It includes practical examples, best practices, a hands-on lab, and a quiz to reinforce learning.
Objective
By the end of this chapter, you will:
- Understand the purpose and importance of end-to-end (E2E) testing in software development.
- Learn how to use Selenium and Cypress to automate browser-based tests.
- Write E2E tests to simulate user interactions and verify application workflows.
- Handle asynchronous behavior and validate UI states effectively.
- Apply best practices for creating reliable E2E tests.
6.1 Introduction to End-to-End Testing
End-to-end testing ensures an application works as a whole, from the user’s perspective.
- Definition: E2E testing verifies the complete flow of an application, simulating real user scenarios across all integrated components (frontend, backend, database, etc.).
- Purpose:
- Validate that the entire system meets requirements and delivers the expected user experience.
- Catch issues missed by unit or integration tests (e.g., UI glitches, workflow failures).
- Ensure the application behaves correctly in a production-like environment.
- Key Characteristics:
- Broad Scope: Tests the full stack, not just isolated parts.
- User-Centric: Mimics how a real user interacts with the application.
- Slower Execution: More comprehensive and resource-intensive than unit or integration tests.
Think of E2E testing as taking a car for a test drive—you’re checking the whole journey, not just the engine or tires.
6.2 Tools for End-to-End Testing
We’ll explore two popular tools: Selenium and Cypress, each with unique strengths.
- Selenium:
- A Java-based automation framework for testing web applications across multiple browsers (e.g., Chrome, Firefox).
- Uses WebDriver to interact with browser elements.
- Ideal for cross-browser testing and integration with Java ecosystems like Spring Boot.
- Cypress:
- A JavaScript-based testing framework designed for modern web applications.
- Runs directly in the browser, offering faster execution and real-time debugging.
- Best for JavaScript-heavy projects (e.g., React, Vue) and single-browser testing.
Both tools automate browser interactions, but their approaches differ—Selenium is broader, while Cypress is more developer-friendly for JavaScript apps.
6.3 Writing E2E Tests with Selenium
Selenium uses Java to automate browser actions, making it a good fit for Spring Boot projects.
6.3.1 Example Scenario
Test a login page that redirects to a dashboard:
- URL:
http://localhost:8080/login
- Fields: Username, Password
- Button: “Login”
- Success: Redirects to
http://localhost:8080/dashboard
6.3.2 Writing a Selenium Test
Dependencies (Maven):
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-java</artifactId>
<version>4.11.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>5.10.0</version>
<scope>test</scope>
</dependency>
Test Code:
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import static org.junit.jupiter.api.Assertions.assertEquals;
public class LoginE2ETest {
private WebDriver driver;
@BeforeEach
public void setup() {
// Set path to ChromeDriver executable (download from selenium.dev)
System.setProperty("webdriver.chrome.driver", "/path/to/chromedriver");
driver = new ChromeDriver();
}
@Test
public void testSuccessfulLogin() {
// Arrange
driver.get("http://localhost:8080/login");
// Act
driver.findElement(By.id("username")).sendKeys("testuser");
driver.findElement(By.id("password")).sendKeys("password123");
driver.findElement(By.id("login-btn")).click();
// Assert
assertEquals("http://localhost:8080/dashboard", driver.getCurrentUrl());
}
@AfterEach
public void teardown() {
driver.quit();
}
}
Explanation:
- WebDriver: Controls the browser (e.g., Chrome).
- findElement: Locates elements by ID, class, or other selectors.
- sendKeys: Simulates typing into fields.
- click: Triggers button actions.
- assertEquals: Verifies the redirect URL.
6.4 Writing E2E Tests with Cypress
Cypress offers a simpler, JavaScript-based approach for modern web apps.
6.4.1 Example Scenario
Test the same login page as above.
6.4.2 Setting Up Cypress
Install Cypress in a Node.js project:
npm install cypress --save-dev
Add to package.json
:
"scripts": {
"cypress:open": "cypress open"
}
Run npx cypress open
to launch the Cypress Test Runner.
6.4.3 Writing a Cypress Test
Create cypress/e2e/login.cy.js
:
describe("Login Page", () => {
it("should redirect to dashboard on successful login", () => {
// Arrange
cy.visit("http://localhost:8080/login");
// Act
cy.get("#username").type("testuser");
cy.get("#password").type("password123");
cy.get("#login-btn").click();
// Assert
cy.url().should("eq", "http://localhost:8080/dashboard");
});
});
Explanation:
- cy.visit: Navigates to the login page.
- cy.get: Selects elements by CSS selectors (e.g.,
#username
). - type: Enters text into fields.
- click: Simulates a button click.
- should: Asserts the URL matches the expected value.
6.5 Handling Asynchronous Behavior
Web applications often involve asynchronous operations (e.g., API calls). Both tools handle this differently:
-
Selenium:
- Use explicit waits to handle delays:
WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(10)); wait.until(ExpectedConditions.urlToBe("http://localhost:8080/dashboard"));
- Ensures the test waits for the redirect before asserting.
- Use explicit waits to handle delays:
-
Cypress:
- Automatically retries commands (e.g.,
cy.get
) until the element is available or a timeout occurs. - Use
cy.wait
for explicit delays if needed:cy.wait(1000); // Wait 1 second
- Automatically retries commands (e.g.,
6.6 Best Practices for E2E Testing
To ensure reliable E2E tests:
- Simulate Real User Flows: Test complete workflows (e.g., login to checkout).
- Use Stable Selectors: Prefer IDs or data attributes over fragile CSS classes.
- Minimize Flakiness: Handle asynchronous behavior and avoid hard-coded waits when possible.
- Run in CI/CD: Integrate with tools like Jenkins or GitHub Actions for consistent execution.
- Limit Scope: Focus on critical user journeys, not every edge case (leave those to unit/integration tests).
6.7 Lab: Hands-On End-to-End Testing
Apply your knowledge in this practical lab.
Lab Objective
Write E2E tests for a provided web application using Selenium or Cypress.
Lab Setup
- Provided: A simple web app with a login page and dashboard (e.g., a Spring Boot app or static HTML/JS).
- Tools: Selenium (Java) or Cypress (JavaScript).
Lab Tasks
-
Test Successful Login:
- Navigate to the login page.
- Enter valid credentials and submit.
- Verify redirection to the dashboard.
-
Test Failed Login:
- Enter invalid credentials.
- Check for an error message on the login page.
-
Handle Asynchrony:
- Add waits to ensure the test accounts for page loading or redirects.
Lab Deliverables
- Submit your test file(s) (e.g.,
LoginE2ETest.java
orlogin.cy.js
). - Include comments explaining each test step.
6.8 Quiz: Reinforcing Key Concepts
Test your understanding with this quiz:
-
What is the main goal of E2E testing?
- a) To test individual functions
- b) To verify the full application workflow
- c) To check code performance
- d) To validate database connections
-
Which tool uses WebDriver to automate browsers?
- a) Cypress
- b) Selenium
- c) Jest
- d) Rest Assured
-
In Cypress, how do you select an element by ID?
- a) driver.findElement(By.id())
- b) cy.get(’#id')
- c) expect(’#id')
- d) document.getElementById()
-
True or False: E2E tests are typically faster than unit tests.
- a) True
- b) False
-
What does WebDriverWait do in Selenium?
- a) Simulates a button click
- b) Waits for a condition before proceeding
- c) Mocks an API
- d) Runs assertions
Answers:
- b
- b
- b
- b (E2E tests are slower)
- b
6.9 Summary
In this chapter, you’ve learned:
- The critical role of E2E testing in validating complete application workflows.
- How to use Selenium and Cypress to automate browser-based tests.
- Techniques for simulating user interactions and handling asynchronous behavior.
- Best practices for creating reliable and maintainable E2E tests.
These skills enable you to ensure your application delivers a seamless user experience from start to finish.
This chapter equips you with the tools and knowledge to perform E2E testing effectively, ensuring your applications work as intended for end users!
By Wahid Hamdi