VLearnVibium

How to Structure a Vibium Test Suite

Structure a Vibium test suite with Python and pytest — organize page objects, fixtures, and config so your browser tests stay fast, isolated, and maintainable.

By Pramod Dutta··4 min read·Verified with Vibium 26.2
▶ Animated overview · made with Remotion

A well-structured Vibium suite separates three concerns: test files that assert behavior, page objects that own locators, and pytest fixtures that launch and tear down the browser. The conventional layout is a tests/ folder for the test functions, a pages/ package for page object classes, and a conftest.py holding a vibe fixture that calls browser.launch() and vibe.quit() around each test. This keeps every test isolated, every locator in one place, and every launch option centralized so you can flip headless mode for CI from a single spot. Because Vibium ships as a single Go binary that auto-downloads Chrome for Testing, there is no driver to manage and no version to pin against the browser — your requirements.txt just needs vibium and pytest. The result is a suite that reads cleanly, runs the same locally and in CI, and grows without turning into a tangle of duplicated setup code.

What does a good Vibium project layout look like?

Keep tests, pages, and fixtures in clearly separated folders so each file has a single job. A typical Python + pytest project looks like this:

my-vibium-suite/
├── conftest.py           # pytest fixtures: the browser/vibe fixture
├── pytest.ini            # pytest config, markers
├── requirements.txt      # vibium, pytest, pytest-xdist
├── pages/
   ├── __init__.py
   ├── login_page.py     # LoginPage class
   └── dashboard_page.py # DashboardPage class
└── tests/
    ├── test_login.py
    └── test_checkout.py

This structure scales: new screens become new files in pages/, new scenarios become new files in tests/, and the browser plumbing never gets copied. Everything that touches the DOM lives in pages/; everything that asserts lives in tests/.

How do I create a reusable browser fixture?

Put a pytest fixture in conftest.py that launches a Vibium browser before a test and quits it after. Reading headless from the environment lets the same suite run headed on your laptop and headless in CI.

# conftest.py
import os
import pytest
from vibium import browser_sync as browser
 
 
@pytest.fixture
def vibe():
    headless = os.getenv("HEADLESS", "true") == "true"
    instance = browser.launch(headless=headless)
    try:
        yield instance
    finally:
        instance.quit()

Every test that takes vibe as an argument now gets a fresh, auto-cleaned browser. The try/finally guarantees quit() runs even when an assertion fails, so a crashed test never leaks a Chrome process — the same discipline you would use running Vibium on a server.

How should tests use the fixture and page objects?

A test requests the vibe fixture, hands it to a page object, and asserts on a high-level result. No selectors and no launch code appear in the test itself.

# tests/test_login.py
from pages.login_page import LoginPage
 
 
def test_valid_login(vibe):
    dashboard = LoginPage(vibe).open().login("alice", "secret")
    assert "Welcome, Alice" in dashboard.welcome_text()
 
 
def test_invalid_login(vibe):
    login = LoginPage(vibe).open()
    login.login("alice", "wrong")
    assert login.error_message() == "Invalid credentials"

These tests are short and declarative because the page objects carry the locators and the fixture carries the browser lifecycle. That division is what keeps a large suite readable.

Should each test get its own browser or context?

For maximum isolation, give each test a fresh browser via the fixture above — simple and bulletproof, at the cost of launch time per test. For more speed, launch the browser once per session and create a fresh context per test, since each Vibium context has its own cookies and storage. A session-scoped browser with a function-scoped context gives you isolation without paying the launch cost every time.

@pytest.fixture(scope="session")
def shared_browser():
    instance = browser.launch(headless=True)
    yield instance
    instance.quit()
 
 
@pytest.fixture
def vibe(shared_browser):
    ctx = shared_browser.new_context()  # fresh cookies/storage per test
    page = ctx.new_page()
    yield page
    ctx.close()

The trade-off is clear: per-browser fixtures are the safest default, while per-context fixtures trade a little setup complexity for a faster suite — ideal once you have enough tests for launch time to matter.

How do I keep config out of test files?

Centralize every launch option — headless mode, viewport size, base URL — in fixtures and environment variables, never hard-coded in tests. This is what lets the identical suite run headed during debugging and headless in CI by setting one variable. Define a base_url fixture and build page URLs from it so the suite can point at staging or production without edits. With config centralized, switching environments is an env-var change, and your tests stay focused purely on behavior.

How does this structure prepare the suite for CI?

A suite split into fixtures, pages, and tests drops straight into CI because the only environment-specific knobs — headless mode and base URL — already come from environment variables. You install vibium and pytest, let Vibium auto-download Chrome, and run pytest. There is no driver to install and no browser version to align, which removes the most common source of CI breakage in older tools. From here, two articles take you the rest of the way: running Vibium in CI/CD with GitHub Actions and parallelizing your tests for faster feedback.

Next steps

Frequently asked questions

How should I structure a Vibium test suite?

Split the project into tests, page objects, and shared fixtures. Put test files under a tests/ folder, page classes under pages/, and a Vibium browser fixture in conftest.py so pytest launches and quits the browser around each test automatically and cleanly.

Should each Vibium test get its own browser or context?

For full isolation give each test a fresh browser via a fixture, or use one browser with a new context per test. Vibium contexts have separate cookies and storage, so a per-context fixture keeps tests independent while reusing a single browser process for speed.

Where do I configure Vibium settings like headless mode?

Centralize launch options in a single pytest fixture in conftest.py. Read headless mode and viewport from environment variables there, so the same suite runs headed locally and headless in CI without touching any individual test file.

Vibium is created by Jason Huggins. This is an independent tutorial — see the official Vibium site and GitHub repo for canonical docs.

Related guides