Skip to main content

Test with pytest.

Project description

plain.pytest

Run tests with pytest and useful fixtures for Plain applications.

Overview

You can run tests using the plain test command, which wraps pytest and automatically loads environment variables from .env.test if it exists.

plain test

Any additional arguments are passed directly to pytest.

plain test -v --tb=short
plain test tests/test_views.py

A basic test looks like this:

from plain.test import Client


def test_homepage():
    client = Client()
    response = client.get("/")
    assert response.status_code == 200

The Client class comes from plain.test and lets you make requests to your app without starting a server.

Fixtures

settings

The settings fixture provides access to your Plain settings during tests. Any modifications you make are automatically restored when the test completes.

def test_debug_mode(settings):
    settings.DEBUG = True
    assert settings.DEBUG is True
    # After this test, DEBUG is restored to its original value

testbrowser

The testbrowser fixture gives you a TestBrowser instance that wraps Playwright and runs a real Plain server in the background. This is useful for end-to-end browser testing.

def test_login_page(testbrowser):
    page = testbrowser.new_page()
    page.goto("/login/")
    assert page.title() == "Login"

The browser connects to a test server running over HTTPS on a random available port. Self-signed certificates are generated automatically.

Authentication helpers

You can log in a user without going through the login form using force_login.

def test_dashboard(testbrowser, user):
    testbrowser.force_login(user)
    page = testbrowser.new_page()
    page.goto("/dashboard/")
    assert "Welcome" in page.content()

To log out, use logout, which clears all cookies.

def test_logout_clears_session(testbrowser, user):
    testbrowser.force_login(user)
    testbrowser.logout()
    page = testbrowser.new_page()
    page.goto("/dashboard/")
    assert "Login" in page.content()

URL discovery

The discover_urls method crawls your site starting from given URLs and returns all discovered internal links. This is useful for smoke testing.

def test_no_broken_links(testbrowser, user):
    testbrowser.force_login(user)
    urls = testbrowser.discover_urls(["/"])
    assert len(urls) > 0

Database isolation

If plain.postgres is installed, the testbrowser fixture automatically uses the isolated_db fixture and passes the database connection to the test server. This means your browser tests and your test code share the same database state.

otel_spans

The otel_spans fixture gives you the OpenTelemetry spans emitted during the test. It returns an InMemorySpanExporter — call .get_finished_spans() to read them.

from opentelemetry import trace


def test_homepage_span(otel_spans):
    Client().get("/")

    spans = otel_spans.get_finished_spans()
    server_span = next(s for s in spans if s.kind == trace.SpanKind.SERVER)
    assert server_span.name == "GET /"
    assert server_span.attributes["http.route"] == "/"
    assert server_span.attributes["http.response.status_code"] == 200

The fixture clears previously captured spans on entry, so each test sees only its own.

otel_metrics

The otel_metrics fixture gives you the OpenTelemetry metrics emitted during the test. It returns an InMemoryMetricReader — call .get_metrics_data() to read accumulated points, or .collect() to force collection of observable instruments.

def test_request_duration_metric(otel_metrics):
    Client().get("/")

    data = otel_metrics.get_metrics_data()
    metric_names = {
        m.name
        for rm in data.resource_metrics
        for sm in rm.scope_metrics
        for m in sm.metrics
    }
    assert "http.server.request.duration" in metric_names

The fixture drains any prior observations on entry. Both fixtures share the same global tracer/meter providers — fine to use them together in one test.

FAQs

Do I need Playwright installed?

The testbrowser fixture requires playwright and pytest-playwright to be installed, but they are not dependencies of this package. If you only use the settings fixture, you don't need Playwright.

uv add playwright pytest-playwright --dev
playwright install

How do I use a .env.test file?

Create a .env.test file in your project root with test-specific environment variables. The plain test command automatically loads it before running pytest.

# .env.test
DATABASE_URL=postgres://localhost/myapp_test
SECRET_KEY=test-secret-key

How do I run a specific test?

Pass the test path and any pytest options after plain test.

plain test tests/test_views.py::test_homepage -v

Installation

Install the plain.pytest package from PyPI:

uv add plain.pytest --dev

The settings and testbrowser fixtures are automatically available in all tests — no conftest.py import needed.

If you're using the testbrowser fixture, also install Playwright:

uv add playwright pytest-playwright --dev
playwright install chromium

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

plain_pytest-0.19.0.tar.gz (11.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

plain_pytest-0.19.0-py3-none-any.whl (16.7 kB view details)

Uploaded Python 3

File details

Details for the file plain_pytest-0.19.0.tar.gz.

File metadata

  • Download URL: plain_pytest-0.19.0.tar.gz
  • Upload date:
  • Size: 11.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.11.16 {"installer":{"name":"uv","version":"0.11.16","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for plain_pytest-0.19.0.tar.gz
Algorithm Hash digest
SHA256 b82c9d7ac7eb12a08288c121b8cc18162f63c2fb6bd137dfd33a445004528356
MD5 5d599ac6754a11e7eb5e01220ee1fc2c
BLAKE2b-256 62a4aa203daeec0453373a5096c00a61e1c672ea110f89ca714f68677b3e6661

See more details on using hashes here.

File details

Details for the file plain_pytest-0.19.0-py3-none-any.whl.

File metadata

  • Download URL: plain_pytest-0.19.0-py3-none-any.whl
  • Upload date:
  • Size: 16.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.11.16 {"installer":{"name":"uv","version":"0.11.16","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for plain_pytest-0.19.0-py3-none-any.whl
Algorithm Hash digest
SHA256 9c90f627cbf84575b85033b336be5e101f3cf1e5b6b21076918695c704a4dfff
MD5 626afa50127055ee2535a005743bfdb6
BLAKE2b-256 f78b1fc66353224ed0957a5e3ddc25f4f8482138f138df364630143eb2e44733

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page