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 inpytest.ini:
--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:- Turbo tracks file changes since last test run
- Each product defines inputs in
package.json: - Only products with changed inputs are tested
- 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.parametrizefor 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