Files
customerTicket/tests/e2e
..
2026-09-10 11:34:19 +03:30
2026-09-10 11:34:19 +03:30
2026-09-10 11:34:19 +03:30
2026-09-10 11:34:19 +03:30
2026-09-10 11:34:19 +03:30
2026-09-10 11:34:19 +03:30
2026-09-10 11:34:19 +03:30
2026-09-10 11:34:19 +03:30
2026-09-10 11:34:19 +03:30

End-to-end browser tests

The E2E suite uses Python Playwright, Chromium, pytest-django, and Django's transactional live_server. It is intentionally separate from fast unit and view tests.

Structure

tests/e2e/
├── config.py             # environment-driven browser settings
├── conftest.py           # browser lifecycle, isolated contexts, failure artifacts
├── pages/                # reusable Page Objects and stable UI actions
│   ├── base.py
│   ├── auth.py
│   └── tickets.py
├── test_chat_coach.py    # user-visible workflow examples
└── test_pwa_versioning.py

Keep business setup in the test/database layer and browser interactions in Page Objects. Tests should describe user outcomes, not repeat selectors or login steps.

Installation

.\.venv\Scripts\python.exe -m pip install -r requirements-dev.txt
.\.venv\Scripts\python.exe -m playwright install chromium

Running tests

# All browser tests
.\.venv\Scripts\python.exe -m pytest tests\e2e -m e2e -q

# One scenario
.\.venv\Scripts\python.exe -m pytest tests\e2e\test_chat_coach.py::test_customer_sees_chat_guidance_after_two_rapid_messages -q

# Only service-worker/PWA scenarios
.\.venv\Scripts\python.exe -m pytest tests\e2e -m pwa -q

# Visible browser with slowed interactions for debugging
$env:E2E_HEADLESS="false"
$env:E2E_SLOW_MO="250"
.\.venv\Scripts\python.exe -m pytest tests\e2e -m e2e -s

Supported settings are E2E_HEADLESS, E2E_SLOW_MO, E2E_ACTION_TIMEOUT_MS, E2E_NAVIGATION_TIMEOUT_MS, E2E_VIEWPORT_WIDTH, E2E_VIEWPORT_HEIGHT, and E2E_ARTIFACT_DIR.

QA / staging / live smoke checks

The destructive workflow suite always uses Django's isolated live_server. A separate, read-only smoke layer can target a deployed environment without modifying real tickets:

$env:E2E_BASE_URL="https://qa.example.com"
$env:E2E_ENVIRONMENT="qa"
$env:E2E_CUSTOMER_MOBILE="0912..."
$env:E2E_CUSTOMER_PASSWORD="..."
$env:E2E_STAFF_USERNAME="qa-staff"
$env:E2E_STAFF_PASSWORD="..."
.\.venv\Scripts\python.exe -m pytest tests\e2e\test_external_environment_smoke.py -m external_e2e -q

BASE_URL is accepted as an alias for E2E_BASE_URL. Missing URLs or credentials are reported as skipped tests, never as a successful external run. Use only controlled accounts.

Failure diagnostics

Every test receives a fresh Chromium process and BrowserContext. This keeps Django's synchronous database lifecycle isolated from Playwright's event loop and prevents cross-test browser state. On failure, the fixture automatically saves these files under test-results/e2e/<test-name>/:

  • failure.png: full-page screenshot at failure time;
  • trace.zip: DOM snapshots, screenshots, network timing and browser actions.

Open a trace with:

.\.venv\Scripts\python.exe -m playwright show-trace test-results\e2e\<test-name>\trace.zip

JavaScript page errors also fail the test and produce the same artifacts. Ordinary UI tests block service workers. A PWA test must use browser_page(service_workers="allow") and the pwa marker.

Adding a scenario

  1. Mark the module with e2e and django_db(transaction=True).
  2. Create only the minimum database state required by the scenario.
  3. Open an isolated page using with browser_page() as page:.
  4. Use an existing Page Object; add reusable selectors/actions there if needed.
  5. Assert a user-visible outcome with Playwright's auto-waiting expect API.
  6. Avoid sleep; wait on URLs, elements, responses, or application state.

Minimal pattern:

pytestmark = [pytest.mark.e2e, pytest.mark.django_db(transaction=True)]

def test_example(live_server, browser_page, customer):
    with browser_page() as page:
        AuthenticationPage(page, live_server.url).login_customer(customer, PASSWORD)
        tickets = TicketConversationPage(page, live_server.url)
        tickets.goto("/tickets/")
        expect(page.get_by_role("heading", name="درخواست‌های من")).to_be_visible()

The fixture prefers Playwright's bundled Chromium and falls back to installed Google Chrome.