Selenium Test passes locally but fails in jenkins
The Symptom

✅ Local:   47/47 passed
❌ Jenkins: 41/47 passed — 6 failed

  NoSuchElementException: Unable to locate element: {"method":"css","selector":"#submit"}
  TimeoutException: Expected condition failed: waiting for visibility of element

Same code. Same branch. Different result. This is the single most common CI complaint in test automation — and it's almost never random.


The Root Cause, In One Line

Something differs between the environments.

CI runs headless, fast, parallel, and resource-limited. Your machine runs interactive, slower, full-browser, with your data. Your test isn't flaky — it's environment-dependent, and it only looks flaky because you've never run it in CI's conditions.

Advertisement

The 5 Real Differences

1. Headless vs headed ⭐

  Local Jenkins
Browser Full UI Headless
Window size Your monitor Default 800×600
Rendering GPU Often software

The killer: headless defaults to a small viewport. Elements that sit comfortably on your 1920px monitor are below the fold or hidden in an 800px window — and Selenium can't interact with what isn't visible.

2. Timing & resources ⭐

CI machines are virtual, CPU-limited, and run tests in parallel. Elements load quicker or slower, animations behave differently, timeouts behave differently.

Any wait you tuned to your machine's speed is a coin flip in CI. This is why Thread.sleep(2000) "works" locally and fails in CI — you tuned it to a machine that no longer exists.

3. Test data ⭐

Locally you use your account, your test data, your cookies, cache, and history. CI starts clean — no cookies, no logged-in session, no leftover records from your last run.

The classic: your test "creates a user" that you already created three days ago locally, so the duplicate-check never fires. In CI it fires every time.

4. Browser & driver versions

Your Chrome auto-updates. The CI agent's may be pinned, older, or newer — and driver mismatches produce SessionNotCreatedException.

5. Timezone, locale, network

CI agents often run UTC while you're in IST. Date assertions break. Network policies may block third-party resources your local machine loads fine.


The Fixes

1. Set an explicit window size ⭐

The single highest-value fix. Do this first.

java
ChromeOptions options = new ChromeOptions();
options.addArguments("--headless=new");
options.addArguments("--window-size=1920,1080");   // ⭐ don't inherit 800x600
options.addArguments("--disable-gpu");
options.addArguments("--no-sandbox");             // needed in Docker/CI
options.addArguments("--disable-dev-shm-usage");  // prevents crashes in containers
WebDriver driver = new ChromeDriver(options);

2. Reproduce CI locally ⭐

Stop debugging blind. Run headless on your own machine:

bash
mvn test -Dheadless=true

If it fails locally in headless, you've reproduced it in seconds instead of pushing 14 commits to watch Jenkins.

3. Make waits condition-based

java
// ❌ Tuned to your machine's speed
Thread.sleep(2000);

// ✅ Works at any speed
wait.until(ExpectedConditions.elementToBeClickable(By.id("submit"))).click();

Never use hardcoded sleeps tuned to your machine. CI is a different machine.

4. Seed and isolate test data

  • Create the data the test needs inside the test — don't rely on it existing.
  • Use unique values: "user_" + System.currentTimeMillis() + "@test.com"
  • Clean up after — or use data that doesn't collide.
  • Never depend on your local cookies or a pre-logged-in session.

5. Capture evidence on CI failure ⭐

You can't watch a headless browser, so make it tell you what happened:

 
java
@AfterMethod
public void captureOnFailure(ITestResult result) {
    if (result.getStatus() == ITestResult.FAILURE) {
        // screenshot
        File src = ((TakesScreenshot) driver).getScreenshotAs(OutputType.FILE);
        // page source is often MORE useful than the screenshot
        String html = driver.getPageSource();
        // save both, attach to the report
    }
}

Then archive them in Jenkins so they survive the build. Debugging CI without screenshots is guessing.

6. Pin browser and driver versions

Use WebDriverManager or a Docker image with a fixed Chrome version, so local and CI agree.


Diagnosis by Error

Error in CI only Almost certainly
NoSuchElementException Viewport — element below the fold in 800×600
TimeoutException Timing — CI is slower/faster than your tuned wait
ElementNotInteractable Viewport or element not scrolled into view
SessionNotCreatedException Driver/browser version mismatch
Login failures Test data — CI has no session/cookies
Date/time assertions Timezone — CI is UTC
Passes alone, fails in suite Parallel execution — shared state or no ThreadLocal driver

The Parallel Trap

If it fails only when the full suite runs, it's not CI — it's thread safety:

java
// ❌ Shared across threads — tests hijack each other's browser
public static WebDriver driver;

// ✅ One driver per thread
private static ThreadLocal<WebDriver> driver = new ThreadLocal<>();

CI runs parallel; your local run often doesn't. That's why CI "found" the bug.


The Interview Answer

"When a test passes locally but fails in Jenkins, it's an environment difference — CI runs headless, faster, parallel, and resource-limited, with clean test data. The most common causes are viewport size in headless mode, waits tuned to my local machine's speed, and test data that exists locally but not in CI. I debug it by reproducing headless locally, capturing screenshots and page source on CI failure, setting an explicit window size, and making all waits condition-based instead of hardcoded sleeps."


Frequently Asked Questions

1. Why do Selenium tests pass locally but fail in Jenkins?

Because Jenkins runs in a different environment with headless browsers, different timing, clean test data, limited resources, and sometimes different browser versions.


2. What should I check first?

Verify the browser window size.

Headless browsers often default to a small viewport, causing elements to be outside the visible area.


3. How can I debug a headless failure?

Run the tests locally in headless mode and capture screenshots together with the HTML page source whenever a failure occurs.


4. Why do tests fail only when the complete suite runs?

This usually indicates parallel execution problems, such as sharing a single WebDriver instance across multiple threads.

Using ThreadLocal<WebDriver> resolves this issue.


5. Can increasing timeouts solve CI failures?

Increasing timeouts may reduce failures temporarily, but it does not address the underlying cause.

Explicit waits based on application state provide a much more reliable solution.