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.18.0.tar.gz (10.6 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.18.0-py3-none-any.whl (15.9 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: plain_pytest-0.18.0.tar.gz
  • Upload date:
  • Size: 10.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.11.8 {"installer":{"name":"uv","version":"0.11.8","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.18.0.tar.gz
Algorithm Hash digest
SHA256 e307ada2450ff2e962d8aa0e71d780bb028176e3ba392dae5649754cff558af4
MD5 a806fef969489be2ebb04f3f5ecf4a5e
BLAKE2b-256 a3eb8905eee2556ef64ca6db5b7c2ecdb3262641b9fe9c1089b49eb489a13327

See more details on using hashes here.

File details

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

File metadata

  • Download URL: plain_pytest-0.18.0-py3-none-any.whl
  • Upload date:
  • Size: 15.9 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.11.8 {"installer":{"name":"uv","version":"0.11.8","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.18.0-py3-none-any.whl
Algorithm Hash digest
SHA256 35ba8996cd5c89030a9ba5c5a8389f3924e4fb2ef659183acea27c131dcb1974
MD5 14c174df940ef26a860beaea4f4badaf
BLAKE2b-256 7299395c0015b487f1f1565a6f8076478de942872f0a8d39d118cad75cfd6b92

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