Run Vibium Tests in Azure DevOps
Run Vibium tests in Azure DevOps Pipelines: install on a Microsoft-hosted agent, run headless, publish screenshots and traces, and cache Chrome.
To run Vibium tests in Azure DevOps, add an azure-pipelines.yml that installs Chrome's system libraries, runs pip install vibium (or npm install vibium), sets HEADLESS=true, and executes your test command — then publish screenshots and JUnit results as pipeline artifacts. Vibium ships as a single Go binary that auto-downloads Chrome for Testing on first run, so the hosted agent has no driver to install and no browser version to align — the classic cause of red CI in older stacks. On the ubuntu-latest Microsoft-hosted agent you apt-get a handful of shared libraries (libnss3, libgbm1, libasound2), install Vibium, flip the headless flag through a variable, and run pytest or your Node runner. Because Vibium's find() auto-waits for actionability, the suite that passes on your laptop passes on a slower agent without sprinkled sleep() calls. Add a failure-artifact step and a JUnit publish task, and you get a fast, debuggable pipeline on every push and pull request.
What does a Vibium Azure DevOps pipeline look like end to end?
The path from a commit to a green Azure DevOps run is short and linear, because Vibium removes the browser-provisioning stage that dominates most CI setups. Each stage below maps to a section of this guide: install the OS libraries Chrome needs, install Vibium (which fetches its own Chrome), run the suite headless, then publish the results and any failure evidence back to the run.
This is the whole pipeline. There is no "download browser" or "match driver version" box in that diagram, and that omission is the point — it is the single biggest reason Vibium pipelines stay green while driver-based ones drift out of sync. If you are new to the tool, skim what is Vibium first for the mental model, then come back for the Azure DevOps specifics.
What is the minimal azure-pipelines.yml for Vibium?
The smallest working pipeline checks out your code, installs Chrome's libraries and Vibium, and runs the suite headless on the Microsoft-hosted Ubuntu agent. Drop this file at the root of your repository as azure-pipelines.yml and Azure DevOps picks it up automatically.
trigger:
- main
pr:
- main
pool:
vmImage: ubuntu-latest
variables:
HEADLESS: "true"
steps:
- task: UsePythonVersion@0
inputs:
versionSpec: "3.12"
- script: |
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
displayName: "Install Chrome system libraries"
- script: |
pip install vibium pytest
vibium install # pre-download Chrome for Testing
displayName: "Install Vibium"
- script: pytest -v
displayName: "Run Vibium tests"The trigger and pr blocks run the pipeline on pushes and pull requests targeting main. The HEADLESS: "true" variable is surfaced to your test code as an environment variable so Chrome launches without a display. vibium install pre-fetches Chrome during the job, so the first test does not pay the download cost mid-run.
Why is there no driver or browser install step?
Vibium bundles its WebDriver BiDi engine into one Go binary and downloads a known-good Chrome for Testing itself, so there is nothing to version-match on the agent. In older stacks, Azure DevOps builds broke constantly because the agent's pre-installed browser drifted out of sync with a separately pinned driver — a chromedriver that was correct last week now throws session not created after the image updated Chrome overnight.
Vibium deletes that entire failure class. The only host setup is Chrome's shared system libraries, which you apt-get once, and modern headless Chrome renders with no X server, so you do not need Xvfb or a virtual display. The Microsoft-hosted image already carries most of these libraries; installing them explicitly just makes the pipeline reproducible across image updates. For the architecture behind the single binary, see install Vibium.
How does my code know to run headless in the pipeline?
Read headless mode from an environment variable in your launch code, so the identical suite runs headed on your laptop and headless on the agent. This is the one switch the pipeline flips, and it means there is no separate "CI version" of your tests to fall out of sync.
import os
from vibium import browser_sync as browser
headless = os.getenv("HEADLESS", "false") == "true"
vibe = browser.launch(headless=headless)
vibe.go("https://example.com")
print(vibe.find("h1").text())
vibe.quit()The JavaScript client uses the same trick — process.env.HEADLESS gates the launch option:
const { browser } = require('vibium/sync')
const bro = browser.launch({ headless: process.env.HEADLESS === 'true' })
const page = bro.page()
page.go('https://example.com')
console.log(page.find('h1').text())
bro.close()You debug headed on your machine, push, and the same code runs invisibly on the agent. Centralizing this in a fixture — the pattern in structuring a Vibium suite — keeps every test consistent instead of repeating the getenv dance in each file.
How do I publish test results to the Azure DevOps Tests tab?
Emit a JUnit XML report from your runner and publish it with the PublishTestResults task, and Azure DevOps renders pass/fail trends, durations, and flaky-test history in the Tests tab of every run. This is the single most valuable reporting step, because it turns a wall of console output into a structured, clickable result.
For pytest, add --junitxml and publish the file:
- script: pytest -v --junitxml=test-results.xml
displayName: "Run Vibium tests"
- task: PublishTestResults@2
condition: succeededOrFailed()
inputs:
testResultsFormat: "JUnit"
testResultsFiles: "test-results.xml"
testRunTitle: "Vibium browser tests"The condition: succeededOrFailed() is essential — without it, the publish step is skipped when tests fail, which is exactly when you most need the report. For a Node runner, wire up a JUnit reporter (jest-junit for Jest, or the equivalent for Vitest) so the reporter writes the same XML shape, then point testResultsFiles at it. The result: a failing assertion shows up as a named, timed test case rather than a stack trace buried in logs.
How do I capture screenshots and traces on failure?
Because pipeline runs are headless and remote, a failure screenshot is the fastest way to see what the page actually showed. Save a PNG when a test fails and let a publish task upload it. Vibium's screenshot() returns PNG bytes, so writing it to disk is one line, and full_page=True captures the whole scroll height, not just the viewport.
import os
import pytest
from vibium import browser_sync as browser
@pytest.fixture
def vibe(request):
instance = browser.launch(headless=os.getenv("HEADLESS") == "true")
yield instance
if request.node.rep_call.failed:
png = instance.screenshot(full_page=True)
with open(f"fail-{request.node.name}.png", "wb") as f:
f.write(png)
instance.quit()Then publish the images as a pipeline artifact, gated on failed() so successful runs stay lean:
- task: PublishPipelineArtifact@1
condition: failed()
inputs:
targetPath: "$(System.DefaultWorkingDirectory)"
artifact: "vibium-failure-screenshots"For richer debugging, record a Vibium trace with screenshots and DOM snapshots, publish 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 flake-free tests for why a captured artifact beats guessing at a re-run.
How do I cache Chrome to speed up Azure DevOps runs?
Vibium downloads Chrome for Testing once and reuses it, so caching that download trims the vibium install step down to a near-instant restore on later runs. Add the Cache@2 task keyed on your Vibium version, pointing at the directory where Vibium stores its browser, and every subsequent build starts from a warm binary.
- task: Cache@2
inputs:
key: 'vibium-chrome | "$(Agent.OS)" | requirements.txt'
path: "$(HOME)/.cache/vibium"
displayName: "Cache Vibium Chrome"
- script: |
pip install vibium pytest
vibium install
displayName: "Install Vibium (warm cache)"Key the cache on something that changes when you bump Vibium — a lockfile such as requirements.txt or package-lock.json — so a version upgrade correctly invalidates the stale Chrome and re-downloads. This matters most on busy repositories where the pipeline fires on every commit; a warm cache shaves the download off each of those runs. Pair it with parallelizing Vibium tests to keep total pipeline time low as the suite grows.
How do I run Vibium tests in parallel across agents?
Fan a single job across shards with a matrix strategy, and give each test its own browser context so parallel workers never corrupt one another's state. Azure DevOps spins up a fresh agent per matrix leg, each installs Vibium and runs one slice of the suite, and the Tests tab aggregates the results.
strategy:
matrix:
shard_1:
SHARD: "1/3"
shard_2:
SHARD: "2/3"
shard_3:
SHARD: "3/3"
maxParallel: 3
steps:
- script: pytest -v --junitxml=results-$(System.JobName).xml --shard=$(SHARD)
displayName: "Run shard $(SHARD)"The isolation rule is what keeps this safe: launch one browser per agent, then open a new Context per test — an isolated cookie jar and storage — so tests share a single Chrome launch without sharing cookies. Vibium's auto-waiting find() is doubly valuable under parallel load, because a shared agent under CPU pressure is exactly where hard-coded sleeps become flaky. Publish each shard's JUnit file with a unique name and Azure DevOps merges them into one result view.
Which Azure DevOps agent should I use for Vibium?
Pick the Microsoft-hosted ubuntu-latest agent by default; reach for Windows or self-hosted only when a specific requirement forces it. The table below maps the common situations to the right pool.
| Agent | Best for | Vibium notes |
|---|---|---|
ubuntu-latest (hosted) | Most headless runs; cheapest, fastest | apt-get Chrome libs, pip install vibium, done |
windows-latest (hosted) | Verifying Windows-specific behavior | Vibium auto-downloads Chrome; no apt step needed |
macOS-latest (hosted) | Rare; Safari-adjacent or macOS-only checks | Heaviest and slowest hosted option |
| Self-hosted (Linux) | Private network, fixed image, warm Chrome cache | Pre-install Chrome libs once in the image |
For nearly every browser suite, ubuntu-latest is the correct answer: it is the least expensive hosted option, boots quickly, and headless Chrome has no reason to prefer another OS. Choose windows-latest only when you are testing behavior that genuinely differs on Windows. Move to a self-hosted agent when you need access to a private staging environment, want a pinned OS image that will not shift under you, or want to bake Chrome's libraries into the image so no run ever pays for the apt-get.
How do I handle secrets and logins for authenticated tests?
Store credentials in an Azure DevOps variable group (or Key Vault-linked group) and read them from environment variables in your test — never hard-code a password into the repo. Most real suites need to log in, and the agent has no browser session to inherit, so the login runs fresh on every job.
Mark the variable as secret in the pipeline UI or link a variable group, then map it into the step's environment:
- script: pytest -v --junitxml=test-results.xml
displayName: "Run authenticated tests"
env:
HEADLESS: "true"
TEST_USER: "$(TEST_USER)"
TEST_PASSWORD: "$(TEST_PASSWORD)"Then consume them in the test rather than embedding literals:
import os
from vibium import browser_sync as browser
vibe = browser.launch(headless=os.getenv("HEADLESS") == "true")
vibe.go("https://example.com/login")
vibe.find("#email").type(os.getenv("TEST_USER"))
vibe.find("#password").type(os.getenv("TEST_PASSWORD"))
vibe.find("button[type=submit]").click()
# find() auto-waits for the dashboard element to be actionable
assert vibe.find("[data-testid=welcome]").text()
vibe.quit()Two rules keep this safe. Mark secrets as secret variables so Azure DevOps masks them in logs — a masked value shows as *** even if a test prints it. And prefer a dedicated test account over a real user's credentials, so a leaked value in a log has limited blast radius. For a complete, resilient login flow with semantic selectors, follow automate login with Vibium.
How does Vibium in Azure DevOps compare to Selenium and Playwright?
All three run in Azure DevOps, but they differ sharply in how much agent setup and browser provisioning each demands. This decision table is honest about the trade-offs rather than stacking the deck for Vibium.
| Consideration | Vibium | Selenium (WebDriver) | Playwright |
|---|---|---|---|
| Browser provisioning in CI | Auto-downloads its own Chrome | Match browser + chromedriver versions | npx playwright install step |
| Agent setup weight | Chrome libs + install vibium | Grid/driver + browser management | Install + browsers download |
| Driver version drift risk | None — single binary | High; a top CI failure cause | Low; versions bundled |
| Auto-wait in CI | Built in | Manual/explicit waits | Built in |
| Headless in CI | One launch flag | Flag, plus display quirks historically | One launch flag |
AI-native check() / do() | Yes | No | No |
| Maturity / ecosystem | Newer (currently 26.2) | Most mature, huge install base | Very mature |
When to choose Vibium in Azure DevOps: you want the thinnest possible pipeline — no driver to match, no browser download step to maintain — plus built-in auto-wait and optional AI assertions, especially if you also drive the browser from an agent via Vibium's MCP server. When Selenium fits: you already run a Selenium Grid or need its unmatched browser and language breadth. When Playwright fits: you want its very mature ecosystem, built-in test runner, and trace viewer today.
Be fair to the alternatives: Selenium and Playwright are more established, and Vibium is the newer entrant. Vibium's differentiator here is operational — it collapses the browser-provisioning stage that makes so many Azure DevOps pipelines fragile — not raw ecosystem size. For side-by-side detail, read Vibium vs Playwright and Vibium vs Selenium.
How do I migrate an existing Selenium pipeline to Vibium?
The migration is mostly a subtraction: delete the driver-management and browser-version steps, then swap the test command. If your current azure-pipelines.yml has tasks that download chromedriver, pin a Chrome version, or start a Selenium Grid, those all disappear.
A typical before-and-after on the install portion:
# Before (Selenium): pin Chrome, download matching chromedriver, start display
- script: |
CHROME_VERSION=$(google-chrome --version | grep -oP '\d+\.\d+\.\d+')
wget "https://chromedriver.storage.googleapis.com/$CHROME_VERSION/chromedriver_linux64.zip"
unzip chromedriver_linux64.zip
export DISPLAY=:99
Xvfb :99 &
displayName: "Provision Selenium browser + driver"
# After (Vibium): install libs, install Vibium, that is all
- script: |
sudo apt-get update
sudo apt-get install -y libnss3 libgbm1 libasound2
pip install vibium
vibium install
displayName: "Install Vibium"Watch for two gotchas. First, remove any DISPLAY/Xvfb setup — headless Chrome under Vibium needs no virtual display, and a leftover Xvfb just wastes agent time. Second, replace explicit WebDriverWait calls in your tests with Vibium's implicit actionability waits; find() already blocks until the element is ready, so hard waits become dead code. For the code-level translation, follow migrate from Selenium to Vibium and lean on the Page Object Model to keep the ported suite maintainable.
Why is Vibium a clean fit for Azure DevOps?
Three design choices make Vibium pipelines low-maintenance on Azure DevOps. First, the single Go binary plus auto-downloaded Chrome means zero driver management — the session not created version-mismatch error that plagues driver-based builds simply cannot occur. Second, headless is a launch flag driven by one variable, not a separate code path, so the suite you debug locally is byte-for-byte the suite the agent runs. Third, auto-waiting find() keeps tests stable on shared, sometimes-throttled hosted agents without manual sleeps.
Together they remove the three things that most often turn an Azure DevOps run red — driver drift, headless quirks, and timing flakiness — leaving a pipeline whose job step is just pytest or npm test. Layer in the JUnit publish for reporting, failure-screenshot artifacts for debugging, and Chrome caching for speed, and you have a pipeline that scales from a handful of tests to a full suite without the browser-provisioning maintenance tax.
How does this pair with AI agents and MCP?
Deterministic Azure DevOps pipelines and Vibium's MCP server are complementary. Your pipeline runs compiler-checked, repeatable flows for the journeys you know, while an LLM can drive the same engine for exploratory checks — both hit identical find/click/fill/check code paths under the hood.
Vibium ships a built-in MCP server, so an agent in a client like Claude Code can call the very same commands your pipeline executes. That means a page.do('accept the cookie banner') in a scripted test and an agent-issued action are the same operation, not two parallel implementations. To wire an agent to the engine, see Vibium MCP in Claude Code. The practical pattern: keep stable, high-value journeys as page objects in the pipeline for reliability, and reserve AI checks for the parts that change often — all in one repository, one engine.
Next steps
- What is Vibium — the mental model behind the tool.
- Install Vibium — the single binary and what lands on disk.
- Structure a Vibium test suite — the fixture that flips headless.
- Parallelize Vibium tests — fan out across agents safely.
- Flake-free tests — why auto-wait keeps CI green.
- Screenshot command — capture options for failure artifacts.
- Vibium MCP in Claude Code — let an agent drive the same engine.
- Course and Roadmap — go from basics to a production pipeline.
Frequently asked questions
How do I run Vibium tests in Azure DevOps Pipelines?
Add an azure-pipelines.yml that installs Chrome's shared libraries, runs pip install vibium (or npm install vibium), sets HEADLESS=true, and executes your test command. Vibium auto-downloads Chrome for Testing on first run, so the agent needs no separate browser or driver install.
Do I need to install Chrome on the Azure DevOps agent for Vibium?
No browser download step is required. Vibium is a single Go binary that fetches its own Chrome for Testing. On the ubuntu-latest hosted agent you only apt-get Chrome's system libraries such as libnss3 and libgbm1; there is no chromedriver to version-match against the browser.
Which Azure DevOps agent should I use for Vibium?
The Microsoft-hosted ubuntu-latest agent is the simplest and cheapest choice for headless Vibium runs. Use windows-latest only if you must test Windows-specific behavior, and a self-hosted agent when you need a fixed OS image, private network access, or a warm Chrome cache.
How do I publish Vibium screenshots and traces in Azure DevOps?
Save a PNG on failure with page.screenshot(full_page=True), then add a PublishBuildArtifacts or PublishPipelineArtifact task that runs on failed() to upload the images. Record a Vibium trace the same way and publish trace.zip so you can scrub the failure frame by frame.
How do I show Vibium test results in the Azure DevOps Tests tab?
Emit a JUnit XML report from your runner — pytest --junitxml=results.xml or a Jest JUnit reporter — then add the PublishTestResults task with testResultsFormat set to JUnit. Azure DevOps parses the file and renders pass/fail trends in the Tests tab of each run.
Can I run Vibium tests in parallel in Azure DevOps?
Yes. Use a matrix or parallel strategy to fan a job across shards, and give each test its own browser context so state never leaks. Combine that with caching Vibium's Chrome download so every parallel agent starts from a warm binary instead of re-downloading.
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→