E2e testing
E2E Testing with Playwright¶
This document describes how to run and maintain end-to-end (E2E) tests for the TrikuSec frontend using Playwright.
Overview¶
E2E tests verify the complete user experience by testing the frontend in a real browser environment. The tests cover:
- Ruleset CRUD operations (create, edit, delete)
- Rule CRUD operations (create, edit, delete)
- Device detail page interactions
- Sidebar state management and nested sidebar behavior
- AJAX form submissions
- Dialog confirmations
Running E2E Tests¶
Prerequisites¶
- Docker and Docker Compose installed
- TrikuSec service running (for E2E tests that need the live server)
Running All E2E Tests¶
Run all E2E tests in headless mode:
Running Specific Tests¶
Run a specific test file:
docker compose -f docker-compose.dev.yml --profile test run --rm test-e2e \
pytest frontend/tests_e2e.py -v
Run a specific test:
docker compose -f docker-compose.dev.yml --profile test run --rm test-e2e \
pytest frontend/tests_e2e.py::TestRulesetCRUD::test_create_ruleset_basic -v
Running Tests with HTML Report¶
Generate an HTML report:
docker compose -f docker-compose.dev.yml --profile test run --rm test-e2e \
pytest -v -m e2e --html=e2e-report.html --self-contained-html
The report will be saved in src/e2e-report.html.
Running Tests in Headed Mode (for Debugging)¶
To see the browser while tests run, you'll need to modify the test container to run in non-headless mode. This requires changes to the test configuration or running tests locally.
Test Structure¶
Test Files¶
src/frontend/tests_e2e.py: Main E2E test suitesrc/frontend/conftest_e2e.py: E2E-specific fixtures
Test Classes¶
TestRulesetCRUD: Tests for ruleset create, edit, delete operationsTestRuleCRUD: Tests for rule create, edit, delete operationsTestDeviceDetailInteractions: Tests for device detail page interactionsTestSidebarStateManagement: Tests for sidebar state and nested sidebar behavior
Fixtures¶
authenticated_browser: Provides a logged-in browser sessiontest_policy_data: Creates sample rules and rulesets for testingtest_device_with_rulesets: Creates a device with assigned rulesetslive_server_url: Provides the URL of the Django test server
Writing New E2E Tests¶
Basic Test Structure¶
@pytest.mark.e2e
def test_my_feature(authenticated_browser, live_server_url):
"""Test description."""
page = authenticated_browser
# Navigate to page
page.goto(f"{live_server_url}/policies/")
page.wait_for_load_state("networkidle")
# Interact with page
page.click('button:has-text("New Ruleset")')
# Assert results
assert page.locator('text=Expected Text').is_visible()
Best Practices¶
- Use descriptive test names: Test names should clearly describe what they test
- Wait for elements: Always wait for elements to be visible/ready before interacting
- Use data-testid attributes: When possible, use stable selectors (consider adding
data-testidto HTML) - Test user flows: Focus on complete user workflows, not implementation details
- Keep tests independent: Each test should be able to run in isolation
- Use fixtures: Leverage fixtures for common setup (authentication, test data)
Common Patterns¶
Waiting for Sidebars¶
Filling Forms¶
Handling Dialogs¶
Checking Visibility¶
assert page.locator('text=Expected Text').is_visible()
assert page.locator('text=Should Not Exist').is_hidden()
Debugging Failing Tests¶
View Test Output¶
E2E tests provide detailed output. Look for:
- Element not found errors
- Timeout errors
- Network errors
- JavaScript console errors
Common Issues¶
- Element not found: The selector might be incorrect or the element might not be loaded yet
-
Solution: Add explicit waits or check if the element exists before interacting
-
Timeout errors: The page might be loading slowly or an action might be taking too long
-
Solution: Increase timeout or add explicit waits
-
Dialog not handled: If a test expects a dialog but it doesn't appear
-
Solution: Check if the dialog handler is set up before clicking the button
-
Sidebar state issues: Sidebars might not be in the expected state
- Solution: Wait for sidebar animations to complete before interacting
Running Tests Locally (Advanced)¶
For advanced debugging, you can run tests locally:
-
Install dependencies:
-
Set up environment:
-
Run tests:
CI/CD Integration¶
E2E tests run automatically in GitHub Actions after integration tests pass. The workflow:
- Builds the test image with Playwright
- Starts the TrikuSec service
- Waits for the service to be ready
- Runs E2E tests
- Uploads HTML test report as an artifact
- Fails the build if tests fail
Maintenance Guidelines¶
When to Update Tests¶
- UI changes: If you change UI structure (HTML, CSS classes, IDs), update selectors
- New features: Add E2E tests for new user-facing features
- Bug fixes: Add regression tests for fixed bugs
Selector Strategy¶
- Prefer stable selectors: Use IDs, data attributes, or text content
- Avoid CSS classes: CSS classes may change for styling reasons
- Use semantic selectors: Prefer
button:has-text("Save")overbutton.btn-primary
Test Data¶
- Use fixtures to create test data
- Clean up test data in fixtures (Django's test database is reset between tests)
- Use descriptive names for test data (e.g., "Test Ruleset E2E")
Troubleshooting¶
Tests Fail Intermittently¶
- Timing issues: Add explicit waits for async operations
- Race conditions: Ensure proper sequencing of actions
- Browser state: Check if previous tests are affecting current test
Browser Not Found¶
If you see "Browser not found" errors:
Service Not Ready¶
If tests fail because the service isn't ready:
- Check service logs:
docker compose -f docker-compose.dev.yml logs trikusec - Increase wait timeout in CI/CD workflow
- Check health endpoint:
curl http://localhost:8000/health/