Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

When a CodeceptJS test says an element is not visible on Jenkins but passes locally, start by proving which browser mode, display environment, executable, viewport and page state the job actually uses. Keep the run headless on a display-less agent unless the test genuinely requires a headed window. If headed mode is required, provide a virtual display such as Xvfb. Then wait for the UI state you intend to test, distinguish DOM presence from rendered visibility, and preserve logs and screenshots from the failing build.

1. Identify the failure you are actually seeing

“Not visible” is not one diagnosis. A Jenkins run can fail because Chrome cannot launch, because the page has not reached the state your test expects, because the selector matches a hidden node, or because Jenkins is using a different browser binary or viewport. Record the failing step, selector, current URL, browser mode, viewport and a screenshot before changing timeouts.

  • Launch/display failure: Chrome reports a display error or never starts.
  • Timing failure: the page is still navigating, rendering a modal or loading data.
  • Visibility-versus-presence mismatch: the node is in the DOM but hidden by CSS, an overlay, an animation or responsive layout.
  • Environment drift: Jenkins resolves a different Chrome/Chromium executable, launch mode or window size than your workstation.

The documentation does not establish one Jenkins-wide root cause. Treat the following as a ranked diagnostic process for your agent and application.

2. Make the headless or headed choice explicit

Use headless mode on a display-less worker

CodeceptJS runs headless by default and documents a CI-conditional configuration:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
const { setHeadlessWhen } = require('@codeceptjs/configure');
setHeadlessWhen(process.env.CI);

exports.config = {
  helpers: {
    Puppeteer: {
      url: 'https://your-app.example',
      show: false
    }
  }
};

Inspect the codecept.conf.js that Jenkins loads, including any CI-specific file or environment override. Do not infer its values from your local run. For a one-off check, the browser plugin can force headless mode:

npx codeceptjs run -p browser:hide

This is usually the simplest fix when the test does not depend on seeing a browser window.

Use a virtual display when headed behavior is required

If the test must run with show: true, a Linux worker needs a display service. Puppeteer’s CI troubleshooting guidance calls for launching Xvfb for non-headless Chrome for Testing. A typical Jenkins shell step is:

Xvfb :99 -screen 0 1280x1024x24 &
export DISPLAY=:99
npx codeceptjs run

Adapt process supervision and cleanup to your agent image. If the test has no headed-browser requirement, remove this dependency instead of adding a display server.

Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

3. Wait for the state, not an arbitrary number of seconds

Wait for asynchronous UI changes

Automatic waiting covers many interactions, but a modal, toast or data-driven component may need an explicit state check. Wait for the element that proves the transition completed:

Scenario('opens the confirmation dialog', async ({ I }) => {
  I.click('[data-test="delete"]');
  I.waitForVisible('.modal', 10);
  I.seeElement('.modal');
});

Use the smallest selector that represents the user-visible state. A long blanket sleep can hide a race and make the whole suite slower. If the application is consistently slower in CI, CodeceptJS’s Puppeteer helper exposes waitForAction; its documented default is 100 milliseconds. Increase it only after confirming that the action itself, rather than navigation or a missing state wait, is the bottleneck.

Choose a navigation condition that matches the application

The Puppeteer helper documents domcontentloaded as its default navigation strategy and allows networkidle0, which can suit a single-page application that becomes usable only after requests finish:

exports.config = {
  helpers: {
    Puppeteer: {
      waitForNavigation: 'networkidle0'
    }
  }
};

Do not use network-idle blindly: an app with polling, analytics or long-lived connections may never become idle. Prefer a product-specific readiness signal, such as a visible heading or loaded table, after navigation.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

4. Separate DOM presence from user-visible rendering

CodeceptJS treats these as different assertions:

  • I.seeElement(selector) checks that an element exists and is visible.
  • I.seeElementInDOM(selector) checks DOM presence even when the matching element may be invisible.

Use seeElementInDOM only when presence is the requirement—for example, verifying that a template inserted a hidden panel. Keep seeElement when the acceptance criterion is that a user can see and interact with the control. For a visibility failure, inspect the captured page for display:none, visibility:hidden, zero dimensions, an off-screen responsive layout, a covering overlay or an animation that has not completed. These are diagnostic possibilities, not assumptions about your application.

5. Align Jenkins with the local browser setup

Confirm the executable

A normal Puppeteer installation downloads a matching Chromium. If your job uses an existing Chrome installation, configure its path explicitly:

exports.config = {
  helpers: {
    Puppeteer: {
      chrome: {
        executablePath: process.env.CHROME_BIN
      }
    }
  }
};

The exact configuration shape depends on your CodeceptJS version; the important check is the resolved path in the Jenkins log. With puppeteer-core, you must provide the browser executable yourself. Compare the Jenkins install output, browser version and launch flags with the machine where the test passes.

Match the viewport and device scale

Responsive CSS can hide or relocate a target at a different width. Set a known window size, then reproduce that size locally:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
npx codeceptjs run -p browser:windowSize=1024x768

You can also set the viewport in the browser helper configuration. Keep headless/headed mode, viewport, timezone and relevant cookies consistent while isolating the failure; otherwise you may be debugging two different page states.

6. Capture evidence from the failing build

Run the smallest failing scenario with CodeceptJS diagnostics and retain the output as Jenkins artifacts:

npx codeceptjs run --debug
npx codeceptjs run --verbose
DEBUG=codeceptjs:* npx codeceptjs run

Enable the screenshot/reporting options used by your project and archive the resulting files. At the assertion, capture or log:

Rank #4
The Web Testing Handbook
  • Used Book in Good Condition
  • the current URL and page title;
  • the selector and number of matching nodes;
  • whether the node has non-zero dimensions and computed visibility;
  • the viewport size and user agent;
  • the browser executable path and launch mode.

Compare the Jenkins screenshot with a local run using the same mode and viewport. A screenshot showing a login page, consent dialog or error page points to application state or environment setup; a matching page with a hidden target points to selector, CSS or timing logic.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

7. A practical decision table

Observation First check Next action
Chrome reports display errors Is headed mode enabled on a worker without a display? Force headless with -p browser:hide, or launch Xvfb for an intentionally headed run.
The selector exists but visibility fails Does the requirement concern presence or visibility? Use seeElementInDOM for presence; otherwise inspect CSS, overlays, animation and the screenshot, then wait explicitly.
Failures occur around navigation or modals Is the test waiting for the actual completion state? Add waitForVisible/waitForText for that state and select a suitable navigation condition.
Local passes, Jenkins fails Are executable, mode and viewport identical? Log the resolved Chrome path, set the same mode and window size, and rerun.
The report has no useful context Are debug logs and screenshots retained? Use CodeceptJS debug flags and archive the artifacts in Jenkins.

8. Common fixes that make failures worse

  • Adding a global sleep: it slows every test and still may miss a delayed state. Wait on the state you need.
  • Forcing headed mode to “see” the problem: without Xvfb, this creates a display failure unrelated to the selector.
  • Changing the assertion to presence without checking the requirement: the test may pass while a real user still cannot see the control.
  • Assuming local Chrome is used: Jenkins may resolve downloaded Chromium or a system binary with different defaults.
  • Choosing networkidle0 for every page: polling applications may never satisfy it; use a concrete readiness element instead.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Or skip the browser setup

For repeatable evidence outside the Jenkins browser process, ScreenshotNeo provides a website screenshot API and MCP server. It accepts consent banners before capture and removes more than 60 known consent platforms, newsletter popups and chat widgets; each step can be disabled. Bot checks, CAPTCHAs, blank pages, timeouts, failed loads and cache hits are not billed, and response headers identify the page verdict and billing status. Its MCP server exposes take_screenshot, get_page_info and capture_pdf for Claude, Cursor and other MCP clients.

One GET request returns PNG, JPEG, WebP or PDF. See the ScreenshotNeo documentation for all options, including selectors, waits, custom headers, cookies, JavaScript, resource blocking, device presets and signed webhooks.

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
import requests
r = requests.get("https://api.screenshotneo.com/v1/shot", params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"}, timeout=90)
open("shot.webp", "wb").write(r.content)
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);

The Free plan includes 1,000 screenshots per month with no card. Paid plans start at $5 for 3,000 shots; every feature is available on every plan. Create a free ScreenshotNeo account.

FAQ

Should every Jenkins run use headless mode?

No. Use headless unless the test genuinely requires headed browser behavior; headed Linux runs need a display such as Xvfb.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Is a longer timeout always the fix?

No. First verify that the selector and readiness condition represent the state the test needs. Then adjust the relevant wait or action timing.

What if the element is in the DOM but hidden?

Use a presence assertion only if that is the requirement. Otherwise inspect the rendered state and wait for visibility after the application removes the hiding condition.

Frequently Asked Questions

Should every Jenkins run use headless mode?

No. Use headless unless the test genuinely requires headed browser behavior; headed Linux runs need a display such as Xvfb.

Is a longer timeout always the fix?

No. First verify that the selector and readiness condition represent the state the test needs. Then adjust the relevant wait or action timing.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

What if the element is in the DOM but hidden?

Use a presence assertion only if that is the requirement. Otherwise inspect the rendered state and wait for visibility after the application removes the hiding condition.

The Bottom Line

Make Jenkins’ browser mode, display, executable and viewport explicit; wait for the application state you intend to assert; and preserve screenshots and debug logs. That sequence distinguishes infrastructure failures from genuine visibility defects without hiding races behind arbitrary sleeps.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.