Selenium test fails with element visibility error in headless mode on CI server but works locally with GUI browser

Issue with automated tests on CI pipeline

I’m having trouble with my automated test suite when it runs on our continuous integration server. The tests work perfectly fine when I run them locally using a regular Chrome browser, but they keep failing when executed in headless mode on the CI environment.

The specific error I’m getting is org.openqa.selenium.ElementNotVisibleException indicating that certain elements cannot be found or interacted with.

What I’ve already tried:

  1. Double checked that the target elements actually exist on the webpage
  2. Added explicit waits and Thread.sleep() calls to give the page more time to load completely
  3. Verified the test logic works correctly in local environment

The main difference between my local setup and the CI server is that locally I use Chrome with GUI while the CI runs in headless mode on a Windows agent.

Has anyone encountered similar issues with headless browser testing? What could be causing elements to be invisible only in headless execution?

Check if your headless Chrome version matches your local one - version mismatches cause weird rendering issues. Also try adding --disable-dev-shm-usage and --no-sandbox flags to Chrome options since CI environments are finicky with those. Sometimes elements load but get covered by invisible overlays or modals that don’t show in headless. Use executeScript to scroll elements into view before interacting.

Hit this same issue six months back and wasted hours debugging it. The problem? Viewport size differences between headless and regular browser modes. Headless defaults to a tiny viewport that pushes elements outside the visible area or triggers responsive breakpoints that hide stuff. Fixed it by setting explicit window size in headless mode - use ChromeOptions with --window-size=1920,1080 or match whatever dimensions you’re testing with locally. Also check for CSS media queries hiding elements on smaller screens. One more thing - verify JS animations and transitions actually finish in headless mode since timing-dependent UI stuff acts weird without GPU acceleration.

Had this same issue about a year ago with our Jenkins pipeline. Turns out CSS animations and transitions were still running when Selenium tried clicking elements. Headless Chrome handles animations differently - elements show up in the DOM but aren’t ready for clicks yet. Here’s what fixed it: kill all CSS animations in headless mode by injecting CSS that sets animation-duration and transition-duration to zero. Then ditch implicit waits for explicit ones using WebDriverWait with ExpectedConditions.elementToBeClickable() instead of just checking if it exists. The element might be there but still animating or blocked by something else transitioning. Also check if your CI has different fonts installed - missing fonts mess up layouts and elements end up in weird spots.