Run Vibium Tests in Jenkins
Run Vibium tests in Jenkins: write a Jenkinsfile, install Chrome libraries, run headless, and archive screenshots and traces as build artifacts on failure.
To run Vibium tests in Jenkins, add a Jenkinsfile that checks out your repo, installs Chrome's shared libraries, installs vibium with pip or npm, and runs your suite headless with HEADLESS=true. Vibium ships as a single Go binary that auto-downloads Chrome for Testing on first run, so a Jenkins agent has no driver to install and no browser version to align — historically the biggest source of red pipelines. On a Linux agent you install Chrome's system libraries (libnss3, libgbm1, libasound2), install Vibium, flip a headless environment variable, and run your tests. Because Vibium's find() auto-waits for actionability, the suite that passes on your laptop passes on a slower shared agent without sprinkled sleep() calls. Add a post block that archives failure screenshots — or a Vibium trace — and publishes JUnit results, and you get a fast, debuggable pipeline that runs on every commit and pull request. This guide shows declarative and scripted pipelines, Docker agents, parallel stages, and artifact debugging.
How a Vibium build runs in Jenkins
Why is Vibium a clean fit for Jenkins?
Vibium removes the three things that most often break browser jobs on a CI server: driver drift, headless quirks, and timing flakiness. Jenkins agents are long-lived and shared, which means anything you install globally tends to rot — a chromedriver pinned last quarter silently stops matching the Chrome that a base image upgraded. Vibium sidesteps this entirely because it bundles its WebDriver BiDi engine into one Go binary and downloads a known-good Chrome for Testing itself.
That leaves your Jenkinsfile short and boring, which is exactly what you want from CI. There is no Selenium Grid to stand up, no webdriver-manager step, and no PATH surgery on the agent. New to the tool itself? Start with what is Vibium and install Vibium, then come back to wire it into a pipeline.
Here is how Vibium compares to a classic Selenium-on-Jenkins setup for the parts that actually cause build failures.
| Concern | Selenium on Jenkins | Vibium on Jenkins |
|---|---|---|
| Browser driver | Install + version-match chromedriver | None — bundled Go binary |
| Browser install | Full Chrome package or Grid node | Auto-downloaded Chrome for Testing |
| Headless on agent | Often needs Xvfb historically | Native headless, no X server |
| Waiting for elements | Explicit WebDriverWait everywhere | find() auto-waits by default |
| Agent setup | Java + Grid + drivers | Chrome shared libraries only |
| Failure debugging | Screenshot plugin wiring | screenshot() returns PNG bytes |
What is the minimal declarative Jenkinsfile?
A declarative Jenkinsfile at the repo root is the clearest starting point for most teams. It reads top to bottom: pick an agent, set the headless flag once, then install and run in ordered stages. This example targets a Linux agent that has Python available.
pipeline {
agent any
environment {
HEADLESS = 'true'
}
stages {
stage('Checkout') {
steps {
checkout scm
}
}
stage('Install Chrome libraries') {
steps {
sh '''
sudo apt-get update
sudo apt-get install -y \
libnss3 libatk-bridge2.0-0 libgbm1 libasound2 \
libxkbcommon0 libxcomposite1 libxdamage1 libxfixes3 \
libxrandr2 libdrm2 libpango-1.0-0 libcairo2
'''
}
}
stage('Install Vibium') {
steps {
sh '''
python3 -m venv .venv
. .venv/bin/activate
pip install vibium pytest
vibium install # pre-download Chrome for Testing
'''
}
}
stage('Run tests') {
steps {
sh '''
. .venv/bin/activate
pytest -v --junitxml=results.xml
'''
}
}
}
post {
always {
junit 'results.xml'
}
}
}The HEADLESS = 'true' line is the single switch that makes Chrome run without a display. vibium install pre-fetches Chrome for Testing during the build so your first test does not pay the download cost. The post { always { junit ... } } block renders your test results in the Jenkins UI regardless of whether the build passed or failed.
Why is there no driver or browser to install on the agent?
Vibium bundles its WebDriver BiDi engine into one Go binary and downloads a known-good Chrome for Testing itself, so there is nothing on the agent to version-match. In older Jenkins setups, browser jobs broke constantly because a base-image Chrome upgrade drifted out of sync with the pinned chromedriver. Vibium removes that whole class of failure.
The only host setup is Chrome's shared libraries, which you install once per agent (or bake into a Docker image). Modern headless Chrome renders with no X display, so you do not need Xvfb or a virtual framebuffer — a common source of confusing "works locally, hangs in CI" tickets. For the architecture behind this, see how Vibium works.
How does my code know to run headless in Jenkins?
Read headless mode from an environment variable in your launch code so the identical suite runs headed locally and headless on the agent. This is the one switch the Jenkinsfile flips, and it means there is no separate CI code path to drift out of sync.
import os
from vibium import browser_sync as browser
headless = os.getenv("HEADLESS", "false") == "true"
vibe = browser.launch(headless=headless)The JavaScript client follows the same shape — read the flag, pass it to launch():
const { browser } = require('vibium/sync')
const headless = process.env.HEADLESS === 'true'
const bro = browser.launch({ headless })
const page = bro.page()With this pattern you debug headed on your laptop, push, and the same code runs invisibly on the agent. Centralizing it in a fixture or setup file (see structuring a Vibium suite) keeps every test consistent instead of repeating the check.
How do I archive screenshots and traces on failure?
Since Jenkins builds are headless and remote, a failure screenshot is the fastest way to see what the page actually showed when a test broke. Save a PNG when a test fails, then archive it in a post block so it attaches to the build. Vibium's screenshot() returns PNG bytes, so writing it to disk is one line.
For pytest, capture in a fixture that checks the test outcome after yield:
# conftest.py
import os
import pytest
from vibium import browser_sync as browser
@pytest.fixture
def vibe(request):
headless = os.getenv("HEADLESS", "false") == "true"
instance = browser.launch(headless=headless)
page = instance.page()
yield page
if getattr(request.node, "rep_call", None) and request.node.rep_call.failed:
png = page.screenshot(full_page=True)
with open(f"fail-{request.node.name}.png", "wb") as f:
f.write(png)
instance.close()Then archive the screenshots and publish results in the pipeline's post block:
post {
always {
junit 'results.xml'
}
failure {
archiveArtifacts artifacts: 'fail-*.png', allowEmptyArchive: true
}
}For richer debugging, record a Vibium trace with screenshots and DOM snapshots, archive the resulting trace.zip the same way, and open it in the Vibium Trace viewer to scrub the timeline frame by frame. See taking a full-page screenshot for the capture options and find element for how find() locates the node you are about to shoot.
How do I run Vibium in a Docker agent?
Pin a clean, reproducible environment by running the build inside a container image instead of relying on whatever a shared agent happens to have installed. Declarative pipelines support a Docker agent directly, so you get a fresh Python or Node environment every build. Because Vibium fetches its own Chrome, the image stays small — you only add Chrome's shared libraries.
pipeline {
agent {
docker {
image 'python:3.12-slim'
args '-u root'
}
}
environment {
HEADLESS = 'true'
}
stages {
stage('Install') {
steps {
sh '''
apt-get update
apt-get install -y \
libnss3 libatk-bridge2.0-0 libgbm1 libasound2 \
libxkbcommon0 libxcomposite1 libxdamage1 libxfixes3 \
libxrandr2 libdrm2 libpango-1.0-0 libcairo2
pip install vibium pytest
vibium install
'''
}
}
stage('Test') {
steps {
sh 'pytest -v --junitxml=results.xml'
}
}
}
post {
always { junit 'results.xml' }
failure { archiveArtifacts artifacts: 'fail-*.png', allowEmptyArchive: true }
}
}The -u root argument lets apt-get install packages inside the container. If you prefer, bake the libraries and pip install vibium into a custom base image so each build skips the install step and starts near-instantly. Caching Vibium's downloaded Chrome directory in that image trims the vibium install step to a no-op.
How do I run Vibium tests in parallel stages?
Fan your suite across parallel stages to cut wall-clock time on large test counts. Jenkins declarative pipelines run parallel branches concurrently, which pairs naturally with a test runner that shards. Give each branch its own slice of tests and its own results file so nothing collides.
stage('Test') {
parallel {
stage('Smoke') {
steps {
sh 'pytest tests/smoke -v --junitxml=smoke.xml'
}
}
stage('Regression') {
steps {
sh 'pytest tests/regression -v --junitxml=regression.xml'
}
}
}
}Then collect every results file at once with a glob: junit '*.xml'. Vibium is safe to run concurrently because each test can take a fresh, isolated browser context — a separate cookie jar and storage sandbox — so logins and state never leak between parallel runs. For patterns that scale further (per-worker browsers, sharding strategy), see parallelizing Vibium tests.
How do I pass test credentials without leaking them?
Store login credentials and API keys in the Jenkins Credentials store and inject them as masked environment variables, never as plaintext in the Jenkinsfile. Browser tests almost always need to log in, and hard-coding a password in source control is both a security problem and an audit failure. Jenkins solves this with the credentials() helper, which pulls a secret by ID and masks it in build logs.
pipeline {
agent any
environment {
HEADLESS = 'true'
TEST_USER = credentials('vibium-test-user') // "username:password" pair
APP_TOKEN = credentials('vibium-app-token') // secret text
}
stages {
stage('Test') {
steps {
sh '. .venv/bin/activate && pytest -v --junitxml=results.xml'
}
}
}
}A usernamePassword credential bound with credentials() exposes TEST_USER_USR and TEST_USER_PSW automatically, which your test reads with os.getenv. Because these arrive as environment variables, the exact same login automation code runs locally with a .env file and in Jenkins with injected secrets — no branching.
import os
from vibium import browser_sync as browser
vibe = browser.launch(headless=os.getenv("HEADLESS") == "true")
vibe.go("https://staging.example.com/login")
vibe.find("#username").type(os.getenv("TEST_USER_USR"))
vibe.find("#password").type(os.getenv("TEST_USER_PSW"))
vibe.find("button[type=submit]").click()Jenkins masks any value that matches a bound credential in the console output, so even a stray print() will not spill the password. Keep the secret IDs stable and rotate the underlying values in the Credentials UI without touching the pipeline.
How do I point tests at a staging or preview URL per build?
Parameterize the target URL so one pipeline can test staging, production smoke, or a per-branch preview deployment without code changes. Hard-coding the base URL in tests forces a code edit every time the environment moves; reading it from a build parameter or environment variable makes the same suite portable across every deploy target.
pipeline {
agent any
parameters {
string(name: 'BASE_URL', defaultValue: 'https://staging.example.com',
description: 'App URL to run Vibium tests against')
}
environment {
HEADLESS = 'true'
BASE_URL = "${params.BASE_URL}"
}
stages {
stage('Test') {
steps {
sh '. .venv/bin/activate && pytest -v --junitxml=results.xml'
}
}
}
}Your tests read BASE_URL and build every navigation from it, so a build that deploys a preview environment can pass its ephemeral URL straight into the same job.
import os
from vibium import browser_sync as browser
BASE = os.getenv("BASE_URL", "http://localhost:3000")
vibe = browser.launch(headless=os.getenv("HEADLESS") == "true")
vibe.go(f"{BASE}/checkout")
assert vibe.find("h1").text() == "Checkout"This is the pattern that makes Vibium useful as a deployment gate: a CD stage spins up a preview, hands its URL to a downstream Vibium job via build job:, and the pipeline blocks promotion until the browser suite passes. Centralize the base URL in your page object model so no individual test hard-codes a host.
When should I use a scripted pipeline instead?
Reach for a scripted Jenkinsfile when your logic needs real Groovy — loops over a matrix of browsers or shards, conditional stages, or shared library calls that declarative syntax makes awkward. Declarative pipelines cover the vast majority of Vibium jobs and are easier to read, so start there. But scripted pipelines give you the full programming model when you need it, for example generating parallel branches dynamically from a list.
node {
def shards = ['smoke', 'auth', 'checkout', 'search']
stage('Checkout') { checkout scm }
stage('Setup') {
sh '''
python3 -m venv .venv && . .venv/bin/activate
pip install vibium pytest && vibium install
'''
}
stage('Test') {
def branches = [:]
for (s in shards) {
def name = s // capture per-iteration value
branches[name] = {
withEnv(["HEADLESS=true"]) {
sh ". .venv/bin/activate && pytest tests/${name} --junitxml=${name}.xml"
}
}
}
parallel branches
}
stage('Report') { junit '*.xml' }
}This generates one parallel branch per shard from a plain list — trivial in scripted Groovy, verbose in declarative. Note the def name = s line: it captures the loop value so each closure runs the right shard rather than all closures sharing the final value, a classic Groovy closure pitfall worth remembering. For the trade-offs on splitting work this way, see parallelizing Vibium tests.
Can I get AI to write and debug my Jenkins Vibium tests?
Yes — Vibium ships a built-in MCP server, so an AI coding agent like Claude Code can drive a real browser to explore your app and generate the Vibium test that your Jenkinsfile then runs. This closes a useful loop for CI: you describe a flow in plain English, the agent navigates the live app through Vibium's MCP, and it writes the find() / click() / assertion code that becomes a committed test. Set it up with Vibium MCP in Claude Code.
The two roles are distinct and complementary. In your editor, the MCP server lets an agent see the page and author or repair tests interactively. In Jenkins, the plain Vibium client runs those same tests headless and deterministically on every push — no MCP or AI in the pipeline itself, just fast, reproducible browser checks. When a build goes red, you archive the failure screenshot, hand it and the trace back to the agent locally, and let it propose the fix. It is a practical division of labor: AI for authoring and triage, deterministic Vibium runs for the gate.
What does a JavaScript / Jest pipeline look like?
If your suite is JavaScript or TypeScript, the pipeline is nearly identical — swap the language runtime and package manager, keep the same headless flag and artifact steps. Use a Node agent, install with npm, and emit JUnit XML with a reporter so Jenkins can render results.
pipeline {
agent { docker { image 'node:20-slim'; args '-u root' } }
environment {
HEADLESS = 'true'
JEST_JUNIT_OUTPUT = 'results.xml'
}
stages {
stage('Install') {
steps {
sh '''
apt-get update && apt-get install -y \
libnss3 libatk-bridge2.0-0 libgbm1 libasound2 \
libxkbcommon0 libxcomposite1 libxdamage1 libxfixes3 \
libxrandr2 libdrm2 libpango-1.0-0 libcairo2
npm ci
'''
}
}
stage('Test') {
steps {
sh 'npx jest --reporters=default --reporters=jest-junit'
}
}
}
post {
always { junit 'results.xml' }
failure { archiveArtifacts artifacts: 'fail-*.png', allowEmptyArchive: true }
}
}Your Jest tests read the HEADLESS flag exactly like the Python ones and drive the page with page.go(), page.find(), and page.screenshot({ fullPage: true }). For a full walkthrough of the runner glue — setup, teardown, and screenshot-on-failure hooks — see using Vibium with Jest. The wider CI mechanics also carry over from running Vibium in GitHub Actions; only the pipeline syntax differs.
How do I trigger builds automatically on every push?
Point Jenkins at your repository and let a webhook fire the pipeline on each commit and pull request. With a multibranch pipeline job, Jenkins discovers every branch that contains a Jenkinsfile and builds it automatically, so feature branches get the same Vibium checks as main. Configure the SCM webhook (GitHub, GitLab, or Bitbucket) to notify Jenkins, and each push queues a build.
This closes the loop: a developer pushes, Jenkins spins up a fresh agent or container, installs Vibium, runs the suite headless, and reports back with results and — on failure — screenshots. Because the whole environment is described in the Jenkinsfile and Vibium needs no external browser infrastructure, the pipeline is reproducible from a clean agent every time. Pair it with a page object model so your growing suite stays maintainable as the branch count climbs.
Common Jenkins gotchas with Vibium
A few environment-specific snags trip up first-time setups, and all of them are quick fixes. Most trace back to the agent lacking Chrome's shared libraries or the workspace not carrying state between stages.
| Symptom | Cause | Fix |
|---|---|---|
| Chrome fails to start on agent | Missing shared libraries | Install libnss3, libgbm1, libasound2, etc. |
| Build hangs waiting for a display | Expecting an X server | Nothing to do — headless Chrome needs none; ensure HEADLESS=true |
vibium: command not found in later stage | venv not re-activated | Re-run . .venv/bin/activate in each sh block |
| No screenshots on failed build | Artifacts not archived | Add archiveArtifacts in the post { failure } block |
| Results not shown in UI | JUnit not published | Emit XML (--junitxml / jest-junit) and call junit |
| Slow first test every build | Chrome re-downloaded | Run vibium install; cache the browser dir in your image |
Each sh step runs in a fresh shell, so environment activation does not persist across stages — re-source your virtualenv (or prefix commands) in every block that needs it. Once the libraries are present and the headless flag is set, Vibium behaves the same on the agent as on your machine.
Next steps
Frequently asked questions
How do I run Vibium tests in Jenkins?
Add a Jenkinsfile with stages that check out your repo, install Chrome's shared libraries, install vibium with pip or npm, and run your suite with HEADLESS=true. Vibium auto-downloads Chrome for Testing, so the agent needs no browser or driver install, only Chrome's system libraries.
Do I need to install Chrome or a driver on the Jenkins agent?
No driver, and no full browser package. Vibium is a single Go binary that downloads its own Chrome for Testing on first run. On a Linux agent you install Chrome's shared libraries like libnss3 and libgbm1; there is no chromedriver to version-match against the browser.
How do I run Vibium headless on a Jenkins agent with no display?
Read headless mode from an environment variable and set it in the Jenkinsfile environment block, for example HEADLESS = 'true'. Modern headless Chrome renders with no X server, so you do not need Xvfb. The same suite runs headed on your laptop and headless on the agent.
How do I see screenshots from a failed Vibium build in Jenkins?
Capture a PNG on failure, write it to the workspace, then use archiveArtifacts in a post block to attach it to the build. Vibium's screenshot() returns PNG bytes, so saving it is one line. You can also archive a Vibium trace.zip and open it at trace.vibium.dev.
Can I run Vibium tests in a Docker agent in Jenkins?
Yes. Use a python:3.12 or node:20 image, install Chrome's shared libraries in the container, then pip install vibium or npm install vibium. Because Vibium fetches its own Chrome, the image stays small and you avoid pinning a chromedriver version to a browser build.
How do I publish Vibium test results in Jenkins?
Have your runner emit JUnit XML — pytest with --junitxml, or a Jest JUnit reporter — then call junit in a post block to render the results in the Jenkins UI. Combine it with archiveArtifacts for failure screenshots so every red build links straight to visual evidence.
Vibium is created by Jason Huggins. This is an independent tutorial — see the official Vibium site and GitHub repo for canonical docs.
Related guides
Vibium Best Practices: The Complete Guide
Vibium best practices for reliable browser automation: semantic locators, actionability waits, page objects, isolation, CI, and AI checks.
13 min read→Best PracticesA Complete Vibium CI/CD Pipeline
Build a complete Vibium CI/CD pipeline: install, headless run, parallel shards, artifact capture, and quality gates that block bad merges on every push.
12 min read→Best PracticesData-Driven Testing with Vibium
Data-driven testing with Vibium: feed one browser test many rows from arrays, CSV, or JSON, loop over cases, and keep the automation logic in one place.
15 min read→Best PracticesRun Vibium with Docker Compose
Run Vibium with Docker Compose: orchestrate a headless test service, an app-under-test, mounted artifact volumes, healthchecks, and parallel workers.
15 min read→