End-to-End Testing
This guide covers how to run and write end-to-end (E2E) tests for TestPlanIt using Playwright.
Prerequisites
- Node.js 24+ and pnpm installed
- Docker, to run the E2E services
- TestPlanIt development environment set up
Setup
1. Start the E2E Services
E2E tests run against separate services from your development stack:
PostgreSQL, Valkey, Elasticsearch and S3-compatible file storage
(RustFS). From the testplanit/ directory,
start them with Docker:
cd testplanit
docker compose -f docker-compose.e2e.yml up -d
The ports (Postgres 5433, Valkey 6377, Elasticsearch 9221, storage 9100) don't
clash with docker-compose.dev.yml, so both stacks can run at once.
2. Configure Environment
Copy the example environment file. Its defaults match the services above:
cp .env.e2e.example .env.e2e
To use your own services instead, point DATABASE_URL, VALKEY_URL,
ELASTICSEARCH_NODE and the AWS_* storage settings at them. The database is
wiped on every run, so never point it at a database you want to keep.
Setup stops with an error if the storage bucket is not writable with the configured credentials. With the local storage service it also creates the bucket and sets its public-read and CORS rules.
Optional: Email Server Configuration
Some E2E tests (particularly signup tests) send verification emails. To prevent undeliverable email alerts, you can configure a test email server:
# Add to .env.e2e or create .env.test.local (gitignored)
EMAIL_SERVER_HOST=your-smtp-server.com
EMAIL_SERVER_PORT=587
EMAIL_SERVER_USER=your-username
EMAIL_SERVER_PASSWORD=your-password
TEST_EMAIL_DOMAIN=your-test-domain.com
Alternatives for email testing:
- Ethereal Email: Free fake SMTP service at ethereal.email - catches emails without actually sending them
- MailHog: Local SMTP test server (
docker run -p 1025:1025 -p 8025:8025 mailhog/mailhog) - Your own test server: Configure
TEST_EMAIL_DOMAINto match your test email domain
If not configured, tests will use @example.com addresses (which will fail delivery).
3. Install Playwright Browsers
cd testplanit
pnpm exec playwright install
4. Setup the E2E Database
Run migrations and seed the E2E database with test data:
pnpm test:e2e:setup-db
Running Tests
All E2E test commands are run from the testplanit/ directory.
Run All Tests
pnpm test:e2e
This will:
- Load the
.env.e2eenvironment - Start a development server on port 3002 (if not already running)
- Run all Playwright tests
Run with Production Build (Recommended)
For faster and more stable tests, use a production build:
pnpm test:e2e:prod
This builds the application first, then runs tests against the production build with more parallel workers.
Complete Setup + Run
To set up the database and run tests in one command:
pnpm test:e2e:run
Interactive UI Mode
Debug and explore tests visually:
pnpm test:e2e:ui
Headed Mode
Watch the browser as tests execute:
pnpm test:e2e:headed
Debug Mode
Step through tests with Playwright Inspector:
pnpm test:e2e:debug
View Test Report
After running tests, view the HTML report:
pnpm test:e2e:report
Test Configuration
The Playwright configuration is in testplanit/e2e/playwright.config.ts.
Key Settings
| Setting | Value | Description |
|---|---|---|
| Port | 3002 | E2E tests run on port 3002 to avoid conflicts with dev server |
| Timeout | 60s | Global test timeout |
| Retries | 2 (CI only) | Tests retry on CI, not locally |
| Workers | 1 (dev) / 6 (prod) | More workers with production build |
| Browser | Chromium | Currently testing on Chrome only |
Environment Variables
| Variable | Description |
|---|---|
E2E_PORT | Override the default port (3002) |
E2E_BASE_URL | Override the base URL for tests |
E2E_VIDEO | Set to on to always record video |
E2E_PROD | Set to on to run against production build |
TEST_EMAIL_DOMAIN | Email domain for test users (default: example.com). Configure with your test email server domain to receive verification emails during signup tests. |
Project Structure
testplanit/e2e/
├── playwright.config.ts # Playwright configuration
├── global-setup.ts # Authentication setup (runs once)
├── setup-db.ts # Database seeding script
├── fixtures/
│ ├── index.ts # Test fixtures
│ └── api.fixture.ts # API helper for test data
├── page-objects/
│ ├── base.page.ts # Base page object
│ ├── signin.page.ts # Sign-in page
│ └── repository/
│ └── repository.page.ts
├── tests/
│ ├── auth/ # Authentication tests
│ └── repository/ # Repository feature tests
├── .auth/ # Stored auth state (gitignored)
├── playwright-report/ # HTML reports (gitignored)
└── test-results/ # Test artifacts (gitignored)
Writing Tests
Adding New Test Files
Place new test files in the tests/ directory, organized by feature:
tests/
├── auth/ # Authentication-related tests
│ └── auth.spec.ts
├── repository/ # Repository feature tests
│ └── Test Repository Management/
│ ├── folder-creation.spec.ts
│ ├── test-case-management.spec.ts
│ └── ...
└── <new-feature>/ # Add new feature directories as needed
└── <test-name>.spec.ts
Test files must use the .spec.ts extension to be picked up by Playwright.
Using Page Objects
import { test, expect } from "../../fixtures";
import { RepositoryPage } from "../../page-objects/repository/repository.page";
test("should create a folder", async ({ page }) => {
const repositoryPage = new RepositoryPage(page);
await repositoryPage.goto(1); // Project ID
await repositoryPage.createFolder("My New Folder");
await repositoryPage.verifyFolderExists("My New Folder");
});
Using the API Fixture
Create test data via API for faster, more reliable tests:
test("should display test cases", async ({ api, page }) => {
// Create test data via API
const folderId = await api.createFolder(1, "Test Folder");
await api.createTestCase(1, folderId, "Test Case 1");
// Navigate and verify
const repositoryPage = new RepositoryPage(page);
await repositoryPage.goto(1);
await repositoryPage.selectFolder(folderId);
await repositoryPage.verifyTestCaseExists("Test Case 1");
// Cleanup is automatic via the api fixture
});
Best Practices
- Use API for test data: Create data via API instead of UI for speed and reliability
- Page Object Pattern: Encapsulate page interactions in page objects
- Automatic cleanup: The API fixture automatically cleans up created data after each test
- Isolated database: Tests run against a separate database to avoid affecting development data
Troubleshooting
Authentication Issues
If tests fail with authentication errors:
rm -rf testplanit/e2e/.auth/
pnpm test:e2e
Database Connection Issues
- Ensure PostgreSQL is running
- Verify
.env.e2ehas correct credentials - Re-run database setup:
pnpm test:e2e:setup-db
Port Conflicts
If port 3002 is in use:
E2E_PORT=3003 pnpm test:e2e
Slow Tests
- Use
E2E_PROD=onto run against production build - Use API fixture to create test data instead of UI
- Use
test.only()to run a single test during development
Flaky Tests
- Check for timing issues and add proper waits
- Use
await expect(locator).toBeVisible()instead of fixed delays - Increase timeouts for slow operations