integratedhub/tests/E2E_TEST_GUIDE.md
2026-02-14 02:20:19 +00:00

629 lines
14 KiB
Markdown

# E2E Testing Guide
This guide covers running, debugging, and maintaining the End-to-End (E2E) test
suite for the Cyber Hybrid Hub application.
## Table of Contents
- [Overview](#overview)
- [Prerequisites](#prerequisites)
- [Running Tests](#running-tests)
- [Test Structure](#test-structure)
- [Writing Tests](#writing-tests)
- [Debugging Tests](#debugging-tests)
- [CI/CD Integration](#cicd-integration)
- [Troubleshooting](#troubleshooting)
## Overview
The E2E test suite uses **Playwright** to test the application through the
browser, simulating real user interactions. Tests are organized by feature and
role (landlord, tenant, admin).
### Test Categories
1. **Authentication** (`tests/e2e/auth/`)
- Login/logout flows
- Role-based access control (RBAC)
- Session management
2. **Landlord Features** (`tests/e2e/landlord/`)
- Dashboard
- Property management
- Applications
- Leases
- Maintenance requests
- Payments
3. **Tenant Features** (`tests/e2e/tenant/`)
- Dashboard
- Applications
- Leases
- Maintenance requests
- Payments
4. **Error Handling** (`tests/e2e/error-handling/`)
- Form validation
- Network errors
- Unauthorized access
- Session expiration
- Edge cases
## Prerequisites
### Required Software
- **Deno** v2.x: Runtime for the application
- **Node.js** v20+: For Playwright CLI
- **Playwright**: Browser automation framework
### Installation
```bash
# Install Deno (if not already installed)
curl -fsSL https://deno.land/install.sh | sh
# Install Playwright and browsers
cd .playwright-mcp
npm install
npx playwright install --with-deps chromium
```
### Environment Setup
Set these environment variables (optional, defaults provided):
```bash
# Application configuration
export PORT=8080 # Port for dev server
export E2E_BASE_URL=http://127.0.0.1:8080 # Base URL for tests
export E2E_TEST=true # Enable E2E test mode
export HOSTNAME_DENO=127.0.0.1 # Deno server hostname
```
## Running Tests
### Run All Tests
```bash
# From project root
npx playwright test
# Or from .playwright-mcp directory
cd .playwright-mcp
npx playwright test
```
### Run Specific Test Files
```bash
# Run authentication tests
npx playwright test tests/e2e/auth/
# Run specific test file
npx playwright test tests/e2e/auth/login.spec.ts
# Run tests matching a pattern
npx playwright test --grep "login"
```
### Run Tests in Different Modes
```bash
# Run in headed mode (show browser)
npx playwright test --headed
# Run with debug UI
npx playwright test --debug
# Run specific test file with UI
npx playwright test --ui tests/e2e/auth/login.spec.ts
# Run with trace on failure
npx playwright test --trace on
# Run tests in parallel
npx playwright test --workers=4
```
### Run Tests on Specific Browser
```bash
# Chromium (default)
npx playwright test --project=chromium
# Note: Currently only Chromium is configured
# Add more browsers in playwright.config.ts if needed
```
### View Test Reports
```bash
# Open HTML report
npx playwright show-report
# Report is generated in playwright-report/index.html
```
## Test Structure
### Directory Layout
```
tests/e2e/
├── helpers/
│ └── test-utils.ts # Shared test utilities
├── auth/
│ ├── login.spec.ts # Authentication flow tests
│ ├── logout.spec.ts # Logout and session cleanup
│ └── rbac.spec.ts # Role-based access control
├── landlord/
│ ├── dashboard.spec.ts # Landlord dashboard
│ ├── properties.spec.ts # Property management
│ ├── applications.spec.ts # Rental applications
│ ├── leases.spec.ts # Lease management
│ ├── maintenance.spec.ts # Maintenance requests
│ └── payments.spec.ts # Financial data
├── tenant/
│ ├── applications.spec.ts # Tenant applications
│ ├── leases.spec.ts # Tenant leases
│ ├── maintenance.spec.ts # Maintenance requests
│ └── payments.spec.ts # Payment management
└── error-handling/
└── validation.spec.ts # Error scenarios and edge cases
```
### Test File Structure
```typescript
import { expect, test } from "../../helpers/test-utils.ts";
test.describe("Feature Name", () => {
test.beforeEach(async ({ page }) => {
// Set E2E mode for each test
await page.addInitScript(() => {
globalThis.localStorage.setItem("E2E_TEST", "true");
});
});
test("should do something specific", async ({ page }) => {
// Navigate with E2E user header
await page.goto("/some-route", {
headers: {
"x-e2e-user": "landlord", // or "tenant", "admin"
},
});
// Wait for page to load
await page.waitForTimeout(1000);
// Perform actions and assertions
await expect(page.locator("h1")).toContainText("Expected Text");
});
test.describe("Sub-feature", () => {
test("should test sub-feature", async ({ page }) => {
// Test implementation
});
});
});
```
## Writing Tests
### Best Practices
1. **Use Descriptive Test Names**
```typescript
test("should allow landlord to create property", async ({ page }) => {
// Good: Clear and specific
});
test("create property", async ({ page }) => {
// Bad: Too vague
});
```
2. **Track Console Errors**
```typescript
const errors: string[] = [];
page.on("console", (msg) => {
if (msg.type() === "error") {
errors.push(msg.text());
}
});
// After test actions
const filteredErrors = errors.filter(
(err) => !err.includes("net::ERR_BLOCKED_BY_CLIENT"),
);
expect(filteredErrors.length).toBe(0);
```
3. **Use Conditional Assertions for Missing Features**
```typescript
const element = page.locator("#some-feature");
if (await element.isVisible({ timeout: 3000 })) {
await expect(element).toBeVisible();
// Additional assertions
}
```
4. **Group Related Tests with `test.describe`**
```typescript
test.describe("Property Creation", () => {
test("should show form", async ({ page }) => {});
test("should validate inputs", async ({ page }) => {});
test("should save property", async ({ page }) => {});
});
```
5. **Use E2E Test Fixtures**
```typescript
// E2E mode is required to bypass OAuth
await page.addInitScript(() => {
globalThis.localStorage.setItem("E2E_TEST", "true");
});
// Use E2E user headers for authentication
await page.goto("/protected-route", {
headers: {
"x-e2e-user": "landlord",
},
});
```
### E2E User Fixtures
The application provides E2E test fixtures for deterministic testing:
- **`landlord`**: Alex Landlord (owns properties e2e-prop-1, e2e-prop-2)
- **`tenant`**: Sam Tenant (has lease e2e-lease-1)
- **`admin`**: Admin user (full system access)
### Common Test Patterns
#### Navigation with Authentication
```typescript
await page.goto("/landlord/dashboard", {
headers: {
"x-e2e-user": "landlord",
},
});
await page.waitForTimeout(1000); // Allow for redirects/load
```
#### Form Interaction
```typescript
// Fill form fields
await page.locator('input[name="title"]').fill("Test Property");
await page.locator('textarea[name="description"]').fill("Description");
// Submit form
await page.locator('button[type="submit"]').click();
// Wait for response
await page.waitForTimeout(1000);
```
#### API Testing
```typescript
const response = await page.request.get("/api/properties", {
headers: {
"x-e2e-user": "landlord",
},
});
expect([200, 404].includes(response.status())).toBe(true);
```
#### Data Verification
```typescript
// Verify page content
const content = await page.content();
expect(content.includes("Expected Text")).toBe(true);
// Or use locators
await expect(page.locator("text=Expected Text")).toBeVisible();
```
## Debugging Tests
### Debug Mode
Run tests with the Playwright Inspector:
```bash
npx playwright test --debug
```
This opens:
1. A browser window
2. The Playwright Inspector for stepping through tests
3. Time-travel debugging capabilities
### UI Mode
Run tests with the Playwright UI:
```bash
npx playwright test --ui
```
Features:
- Visual test explorer
- Watch mode
- Trace viewer
- Time-travel debugging
### Headed Mode
See the browser running the test:
```bash
npx playwright test --headed
```
### Slow Motion
Run tests in slow motion to see what's happening:
```bash
npx playwright test --headed --slow-mo=1000
```
### Screenshots on Failure
Screenshots are automatically captured on failures. Find them in:
```
test-results/
├── test-name/
│ ├── screenshot.png
│ ├── trace.zip
│ └── video.webm
```
### Traces
Traces capture everything that happened during the test:
```bash
# Enable tracing for all tests
npx playwright test --trace on
# View a trace
npx playwright show-trace test-results/trace.zip
```
### Console Logging
Add debugging statements:
```typescript
test("should do something", async ({ page }) => {
console.log("Current URL:", page.url());
const content = await page.content();
console.log("Page content preview:", content.substring(0, 200));
// Or use page.evaluate
const result = await page.evaluate(() => {
console.log("Browser console log");
return document.body.innerText;
});
});
```
### Common Issues and Solutions
#### Issue: "Element not found"
**Solution**: Increase timeout or use conditional checks
```typescript
// Instead of:
await expect(page.locator("#element")).toBeVisible();
// Use:
if (await page.locator("#element").isVisible({ timeout: 5000 })) {
await expect(page.locator("#element")).toBeVisible();
}
```
#### Issue: "Test is too slow"
**Solution**: Adjust timeouts in `playwright.config.ts`
```typescript
export default defineConfig({
timeout: 60_000, // Overall test timeout
expect: {
timeout: 10_000, // Assertion timeout
},
});
```
#### Issue: "Tests fail in CI but pass locally"
**Solutions**:
1. Check CI environment variables
2. Increase retries in `playwright.config.ts`
3. Use `fullyParallel: false` in CI
4. Check for timing issues
```typescript
export default defineConfig({
retries: process.env.CI ? 2 : 0,
fullyParallel: !process.env.CI,
});
```
#### Issue: "Database connection errors"
**Solution**: Ensure database is running and accessible
```bash
# Check database status
psql -h localhost -U postgres -d cyberhybridhub -c "SELECT 1;"
# Or use docker-compose
docker-compose up -d postgres
```
## CI/CD Integration
### GitHub Actions
The project includes a GitHub Actions workflow
(`.github/workflows/e2e-tests.yml`) that:
1. Runs E2E tests on every push and PR
2. Runs tests on a schedule (daily at 2 AM UTC)
3. Shards tests across 4 workers for parallel execution
4. Uploads test results, screenshots, videos, and traces
5. Publishes test results as PR comments
### Workflow Features
- **Parallel Execution**: Tests run across 4 shards
- **Retry on Failure**: Tests retry up to 2 times in CI
- **Artifact Retention**: Results kept for 14 days
- **Failure Artifacts**: Screenshots, videos, and traces kept for 7 days
- **Test Summary**: JUnit XML results published to PR
### Manual Workflow Trigger
Trigger tests manually from GitHub Actions:
1. Go to Actions tab in GitHub
2. Select "E2E Tests" workflow
3. Click "Run workflow"
4. Select branch and click "Run workflow"
### Local CI Testing
Test CI workflow locally using [act](https://github.com/nektos/act):
```bash
# Install act
brew install act # macOS
# or
curl https://raw.githubusercontent.com/nektos/act/master/install.sh | sudo bash
# Run workflow
act push --job e2e-tests
```
## Troubleshooting
### Port Already in Use
```bash
# Kill process using port 8080
lsof -ti:8080 | xargs kill -9
# Or use a different port
PORT=8081 npx playwright test
```
### Browser Installation Issues
```bash
# Reinstall Playwright browsers
npx playwright install --force --with-deps chromium
# Or install all browsers
npx playwright install --with-deps
```
### Deno Installation Issues
```bash
# Reinstall Deno
rm -rf ~/.deno
curl -fsSL https://deno.land/install.sh | sh
```
### Cache Issues
```bash
# Clear Deno cache
deno cache --reload tests/e2e/**/*.spec.ts
# Clear Node cache
rm -rf node_modules package-lock.json
npm install
```
### Test Isolation Issues
If tests interfere with each other:
1. **Use unique test data** (add timestamps)
```typescript
const timestamp = Date.now();
await page.locator('input[name="title"]').fill(`Test ${timestamp}`);
```
2. **Clean up after tests**
```typescript
test.afterEach(async ({ page }) => {
// Delete test data
await page.request.delete("/api/test-data", {
headers: { "x-e2e-user": "admin" },
});
});
```
3. **Disable parallel execution**
```typescript
// In playwright.config.ts
fullyParallel: false,
workers: 1,
```
### Database Issues
```bash
# Reset test database
psql -h localhost -U postgres -c "DROP DATABASE IF EXISTS cyberhybridhub_test;"
psql -h localhost -U postgres -c "CREATE DATABASE cyberhybridhub_test;"
# Run migrations
deno task db:push
```
## Performance Tips
1. **Use parallel execution** for faster test runs
2. **Reuse browser context** when possible
3. **Avoid unnecessary waits** - use `waitForSelector` instead of
`waitForTimeout`
4. **Group tests** by feature to reduce setup overhead
5. **Use API tests** for data validation (faster than UI)
## Additional Resources
- [Playwright Documentation](https://playwright.dev)
- [Playwright Best Practices](https://playwright.dev/docs/best-practices)
- [Project CLAUDE.md](../CLAUDE.md) - Project-specific guidelines
- [Test Examples](./e2e/) - Reference implementations
## Support
For issues or questions:
1. Check this guide's troubleshooting section
2. Review Playwright documentation
3. Check existing test files for examples
4. Consult project documentation in `CLAUDE.md`