E2E и тестовый клиент Django

Тестовый Client Django вызывает view напрямую: нет браузера, JavaScript и настоящего HTTP (основы тестов Django, настройка pytest-django). Это быстро и достаточно для большинства проверок. E2E-тест использует настоящий браузер, поэтому заодно доказывает, что маршрут, шаблон, CSRF-токен, сессия, статика и JavaScript работают вместе.

Тестовый клиентE2E с Playwright
Запускаетview внутри процессаChromium + Django по HTTP
JavaScript, HTMXнетда
Скоростьмиллисекундысекунды
Для чегологика, права, редиректыкритичные пути: вход, заказ, оплата

💡 Один E2E-тест на критичный сценарий, детали оставьте тестовому клиенту. Помечайте браузерные тесты @pytest.mark.e2e, чтобы ежедневный запуск мог их пропускать.

Установка

pytest-django даёт фикстуру live_server, а pytest-playwright фикстуры page, context и browser:

text
pip install pytest-django pytest-playwright
playwright install chromium

# pyproject.toml
[tool.pytest.ini_options]
DJANGO_SETTINGS_MODULE = "config.settings.test"
markers = ["e2e: slow browser tests"]

# run only the browser tests, with a visible browser
pytest -m e2e --headed

playwright install chromium скачивает браузер один раз. По умолчанию режим headless; --headed показывает окно, что помогает, когда вы пишете тест впервые.

live_server и первый тест

live_server запускает Django в отдельном потоке на свободном порту и даёт live_server.url. Поток теста управляет Playwright, Playwright обращается к Django по HTTP, и обе стороны используют одну тестовую базу.

live_server: один процесс, два потока
live_server: один процесс, два потока
python
import re

import pytest
from playwright.sync_api import Page, expect

pytestmark = pytest.mark.e2e

def test_login_shows_dashboard(live_server, page: Page, user):
    page.goto(f"{live_server.url}/accounts/login/")
    page.get_by_label("Username").fill("ann")
    page.get_by_label("Password").fill("secret123")
    page.get_by_role("button", name="Sign in").click()

    expect(page).to_have_url(re.compile(r"/dashboard/$"))
    expect(page.get_by_role("heading", name="Dashboard")).to_be_visible()

Три привычки делают тест стабильным: