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.1.tar.gz (10.7 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.1-py3-none-any.whl (16.0 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: plain_pytest-0.18.1.tar.gz
  • Upload date:
  • Size: 10.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.11.10 {"installer":{"name":"uv","version":"0.11.10","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.1.tar.gz
Algorithm Hash digest
SHA256 0cec25c8a8c3342a9dbb169f04cc18b7f36322de45862b34c107cd9140d8545c
MD5 faac99b99c7ddae1613264b31059014e
BLAKE2b-256 d85b2def73e0f88ed48f7d2664b8ab145c6085fc967c4f6c96166fda61046831

See more details on using hashes here.

File details

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

File metadata

  • Download URL: plain_pytest-0.18.1-py3-none-any.whl
  • Upload date:
  • Size: 16.0 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.11.10 {"installer":{"name":"uv","version":"0.11.10","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.1-py3-none-any.whl
Algorithm Hash digest
SHA256 64e0eedbb2e2d3e1c546be138a0db0849a05da17d452144ff8c39672f12d7f81
MD5 45947254a2392e9c1f9b2a194d4d046e
BLAKE2b-256 36986688b1193eaf0701c201b145a89014433f28a0baa6ad315f8c75679ac02d

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