Skip to main content
PostHog uses a comprehensive testing strategy combining Python pytest, JavaScript Jest, and end-to-end Playwright tests.

Test Types

Backend Tests

pytest for Django and business logic

Frontend Tests

Jest for React components and Kea logic

E2E Tests

Playwright for full user flows

Backend Testing (pytest)

Running Tests

Test Configuration

Tests are configured in pytest.ini:
Key options:
  • --reuse-db: Reuse database between test runs (faster)
  • -p no:warnings: Suppress warnings
  • --ignore: Skip certain directories

Writing Backend Tests

1

Test Structure

Organize tests in tests/ directories within products:
2

Basic Test Example

3

Using Fixtures

Parameterized Tests

Use @pytest.mark.parametrize for testing multiple inputs:
Prefer parameterized tests over multiple assertions in a single test. This makes test failures clearer and exercises the system more thoroughly.

API Tests

Test Django REST Framework views:

Testing with ClickHouse

Tests that query ClickHouse:

Frontend Testing (Jest)

Running Frontend Tests

Writing Frontend Tests

1

Component Tests

2

Kea Logic Tests

Jest Best Practices

Prefer a single top-level describe block per file. Organize tests with nested describe blocks only when it significantly improves clarity.

End-to-End Testing (Playwright)

Running E2E Tests

Writing E2E Tests

Selective Testing with Turbo

PostHog uses Turborepo for selective test execution based on changed files:
How it works:
  1. Turbo tracks file changes since last test run
  2. Each product defines inputs in package.json:
  3. Only products with changed inputs are tested
  4. Contract files (facades) determine downstream dependencies
When you change a product’s facade contracts, downstream products that depend on it will also be retested.

Testing Best Practices

General Principles

  • No doc comments in Python tests - Test names should be self-explanatory
  • Prefer parameterized tests - Use @pytest.mark.parametrize for multiple cases
  • One assertion per concept - But use parameterized tests instead of multiple tests
  • Test behavior, not implementation - Focus on what, not how
  • Keep tests isolated - No shared state between tests

Code Examples

Security Testing

Always test team isolation:

Continuous Integration

Tests run automatically on every pull request:
  • Backend tests: pytest across all changed products
  • Frontend tests: Jest for changed components
  • E2E tests: Playwright for critical user flows
  • Type checking: TypeScript and mypy (baseline only)
  • Linting: Ruff (Python) and oxlint (TypeScript)
Do not run mypy for type checks locally - it takes too long. Rely on the baseline and LSP for type hints.

Next Steps

Contributing

Learn how to contribute to PostHog

Architecture

Understand the system architecture