WebDriver Lifecycle Management
What Is WebDriver Lifecycle Management?
WebDriver lifecycle management is the process of creating, configuring, using, and closing Selenium WebDriver instances during test execution. In a Cucumber framework, it defines when the browser opens, how it is configured, how it is shared with Page Objects, and when it is safely destroyed after a scenario finishes.
Without lifecycle control, browsers may remain open, memory usage may grow, tests may interfere with each other, and parallel execution may become unreliable. Good lifecycle design gives every scenario a predictable browser session and releases resources after execution.
Why Lifecycle Management Matters
Imagine a suite with hundreds of scenarios. If each scenario opens a browser but never closes it, the machine eventually runs out of memory and browser processes. If multiple scenarios reuse the same browser without careful cleanup, cookies, local storage, sessions, and page state can leak from one scenario to another. These issues create false failures and unstable automation.
Lifecycle management is therefore not just a coding style. It is a reliability requirement for professional Selenium-Cucumber frameworks.
Typical WebDriver Lifecycle
Create WebDriver
-> Configure Browser
-> Open Application
-> Execute Test Steps
-> Capture Result Evidence
-> Take Screenshot if Needed
-> Quit Browser
-> Destroy WebDriver Reference
Each part has a specific purpose. Creation starts the browser session. Configuration prepares the browser. Execution performs the scenario. Cleanup closes windows and releases operating system resources.
Lifecycle in Cucumber
Cucumber hooks are the natural place to manage browser lifecycle. A @Before hook can create the WebDriver before every scenario. An @After hook can capture failure evidence and quit the WebDriver after the scenario.
@Before
public void setup() {
DriverFactory.initializeDriver();
}
@After
public void tearDown() {
DriverFactory.quitDriver();
}
This keeps lifecycle code out of feature files, step definitions, and Page Objects. All scenarios follow the same setup and teardown pattern.
Browser Creation
Browser creation happens before scenario execution. The framework may choose Chrome, Firefox, Edge, or a remote grid browser based on configuration.
public static void initializeDriver() {
driver = new ChromeDriver();
driver.manage().window().maximize();
}
At this point, Selenium creates a browser session and communicates with the browser driver. Browser options such as headless mode, download preferences, window size, and certificate handling can be applied during this stage.
Browser Configuration
After creation, the framework may maximize the browser, set timeouts, configure cookies, define download folders, or apply browser-specific capabilities. Configuration should be centralized because inconsistent browser setup is a common source of flaky tests.
Many teams prefer explicit waits for interaction readiness and use implicit waits sparingly or not at all. Whatever approach is chosen, it should be consistent across the framework.
Browser Usage During Scenario Execution
During execution, feature files trigger step definitions, step definitions call Page Objects, and Page Objects use WebDriver to interact with the browser. The driver remains active until the scenario ends.
Feature File
-> Step Definition
-> Page Object
-> WebDriver
-> Browser
Page Objects should obtain the driver from a central Driver Factory. They should not create new driver instances on their own.
Browser Cleanup
Cleanup usually uses driver.quit(). This closes all browser windows, ends the WebDriver session, terminates the driver process, and releases resources.
public static void quitDriver() {
if (driver != null) {
driver.quit();
driver = null;
}
}
Setting the reference to null helps avoid accidental reuse of a closed session.
close() vs quit()
driver.close() closes only the current browser window. The browser session may continue if other windows are open. driver.quit() closes all windows and ends the session completely. Enterprise frameworks generally use quit() in teardown because it is the cleaner lifecycle boundary.
Use close() only when the test intentionally manages multiple windows and wants to close one window while continuing with the session.
Lifecycle Per Scenario
The recommended approach is one browser per scenario. Scenario one creates a browser, executes, and quits. Scenario two creates a fresh browser, executes, and quits. This keeps scenarios independent and reduces state leakage.
The tradeoff is execution time. Starting browsers repeatedly is slower than reusing one browser. However, independence is usually more important than raw speed for reliable acceptance tests.
Lifecycle Per Feature or Suite
Some teams reuse one browser across a feature or an entire suite for speed. This can work for carefully controlled smoke checks, but it increases the risk of state leakage. Cookies, storage, page navigation, and failed scenarios can affect later scenarios.
If browser reuse is chosen, the framework must intentionally reset application state between scenarios. Otherwise the suite becomes order-dependent.
Driver Factory Pattern
A Driver Factory centralizes browser management. It hides browser creation details from step definitions and Page Objects.
public class DriverFactory {
private static WebDriver driver;
public static WebDriver getDriver() {
return driver;
}
public static void initializeDriver() {
driver = new ChromeDriver();
}
public static void quitDriver() {
if (driver != null) {
driver.quit();
driver = null;
}
}
}
This structure makes it easier to add browser selection, remote execution, headless mode, and common options later.
Parallel Execution and ThreadLocal
A static WebDriver field is unsafe in parallel execution because multiple threads can share and overwrite the same driver. A safer pattern is ThreadLocal<WebDriver>, where each thread has its own browser instance.
private static ThreadLocal<WebDriver> driver = new ThreadLocal<>();
public static WebDriver getDriver() {
return driver.get();
}
ThreadLocal solves driver isolation, but the rest of the framework must also be thread-safe. Scenario context, reports, screenshots, and test data cannot be shared carelessly.
Screenshot Timing
Failure screenshots must be captured before the driver is quit. If the browser session is already closed, screenshot capture will fail. A good teardown hook checks scenario status, attaches evidence, and then quits the driver.
This order is important in real projects because screenshots often provide the fastest clue about why a UI scenario failed.
Common Mistakes
Common mistakes include creating drivers inside step definitions, not closing drivers, using a static driver in parallel runs, creating multiple browsers unintentionally in one scenario, and quitting the driver before taking screenshots. Another mistake is letting Page Objects own driver lifecycle. Page Objects should use the driver, not decide when the browser starts or stops.
Best Practices
Create the browser in a @Before hook and quit it in an @After hook. Prefer one browser per scenario for independence. Use Driver Factory to centralize creation and cleanup. Use quit() instead of close() for teardown. Capture screenshots before quitting. Use ThreadLocal for parallel execution. Choose browser and environment through configuration instead of hardcoding values.
Interview-Ready Summary
WebDriver lifecycle management controls when Selenium browser sessions are created, configured, used, and destroyed. In Cucumber frameworks, hooks usually manage this lifecycle, Driver Factory centralizes driver access, and driver.quit() releases resources after each scenario. Parallel execution requires thread-safe driver management, commonly implemented with ThreadLocal.