Testing Guide
Comprehensive guide to testing LDAP Manager with backend unit tests and frontend E2E tests.
Test Coverage Overview
LDAP Manager has 199 total tests with comprehensive coverage across backend and frontend.
Test Statistics
- Backend Tests: 104 tests (97% pass rate, >80% code coverage target)
- Frontend E2E Tests: 95 tests (100% pass rate)
- Total: 199 tests
- Browsers: Chrome, Firefox, Safari (E2E)
- Coverage: Security, LDAP operations, API endpoints, UI workflows
Backend Testing
Running Backend Tests
cd backend
# Install test dependencies
pip install -r requirements-test.txt
# Run all tests with coverage
pytest --cov=app --cov-report=html --cov-report=term-missing
# Run specific test file
pytest tests/test_password_cache.py -v
# Run with verbose output
pytest -v
# View HTML coverage report
open htmlcov/index.html
Backend Test Suite (104 tests)
Password Cache Tests (24 tests)
- Fernet encryption key generation and storage
- Password encryption and decryption
- TTL expiration and automatic cleanup
- Cache file permissions (0600)
- Multi-cluster password isolation
Node Selector Tests (19 tests)
- READ operations use last→second→first node order
- WRITE operations always use first node
- Automatic failover on node failure
- Socket connectivity checks
- Single-node cluster handling
LDAP Client Tests (20 tests)
- Connection and authentication
- Search operations with pagination
- Add, modify, delete operations
- Group membership management
- Error handling and timeouts
API Endpoints Tests (25 tests)
- LDAP injection protection
- Authentication and authorization
- Entry CRUD operations
- Group membership endpoints
- Read-only cluster enforcement
Connection Pool Tests (15 tests)
- Connection reuse and TTL
- Stale connection cleanup
- Thread safety
- Pool statistics
Configuration Validation Tests (25+ tests)
- Pydantic schema validation
- Port range validation
- Host/nodes XOR constraint
- Duplicate cluster name detection
Security Testing
Dedicated tests for security features:
- ✅ Password never stored in plaintext
- ✅ LDAP injection attempts blocked
- ✅ Invalid credentials handled properly
- ✅ TTL expiration enforced
- ✅ File permissions verified
Frontend E2E Testing
Running E2E Tests
cd frontend
# Install dependencies
npm install
# Run E2E tests (all browsers)
npx playwright test
# Run in headed mode (watch tests run)
npx playwright test --headed
# Run specific test file
npx playwright test tests/e2e/dashboard.spec.ts
# Run in specific browser
npx playwright test --project=chromium
Frontend Test Categories (95 tests)
Dashboard Tests (5 tests)
- Cluster listing display
- Navigation to cluster details
- Health status indicators
- Cluster information display
Cluster Details Tests (8 tests)
- View switching (Users, Groups, OUs, All)
- Search functionality
- Pagination controls
- Entry display
User Creation Tests (7 tests)
- Form validation
- Custom fields display
- Dropdown options
- Auto-fill fields
- Required field validation
Column Settings Tests (4 tests)
- Show/hide columns
- localStorage persistence
- Default visibility
- Settings dialog
User Lifecycle Tests (3 tests)
- Create user
- Verify user exists
- Delete user
User Edit Tests (11 tests)
- Field updates
- Validation
- Disabled fields (uid, uidNumber)
- Save changes
Password Change Tests (11 tests)
- Policy validation
- Confirmation matching
- shadowLastChange update
- Error handling
Complete Lifecycle Tests (5 tests)
- Create → Edit → Password Change → Delete
- Full user workflow
Setup
Prerequisites
- Node.js 20+
- LDAP Manager running locally
- Test LDAP server configured
Install Playwright
cd frontend
npm install
npx playwright install
This installs Playwright and downloads browser binaries (Chrome, Firefox, Safari).
Running Tests
Run All Tests
npx playwright test
Run Specific Browser
# Chrome only
npx playwright test --project=chromium
# Firefox only
npx playwright test --project=firefox
# Safari only
npx playwright test --project=webkit
Run Specific Test File
npx playwright test user-lifecycle.spec.ts
Run with UI (Interactive Mode)
npx playwright test --ui
Opens Playwright UI for interactive test running and debugging.
Run in Headed Mode (See Browser)
npx playwright test --headed
View HTML Report
npx playwright show-report
Test Organization
frontend/tests/e2e/
├── dashboard.spec.ts # Dashboard tests (5)
├── cluster-details.spec.ts # Cluster view tests (8)
├── user-creation.spec.ts # Form UI tests (7)
├── user-creation-simple.spec.ts # Form validation (3)
├── column-settings.spec.ts # Column preferences (4)
├── user-lifecycle.spec.ts # Full E2E lifecycle (3)
├── user-edit.spec.ts # Edit functionality (11)
├── password-change.spec.ts # Password change (11)
└── user-lifecycle-complete.spec.ts # Complete workflow (5)
Writing Tests
Example Test
import { test, expect } from '@playwright/test';
test('should display cluster list', async ({ page }) => {
await page.goto('http://localhost:5173');
// Check if clusters are displayed
await expect(page.locator('.cluster-card')).toBeVisible();
// Verify cluster name
await expect(page.locator('text=Production LDAP')).toBeVisible();
});
Test Structure
test.describe('Feature Name', () => {
test.beforeEach(async ({ page }) => {
// Setup before each test
await page.goto('http://localhost:5173');
});
test('should do something', async ({ page }) => {
// Test implementation
});
test.afterEach(async ({ page }) => {
// Cleanup after each test
});
});
Test Configuration
playwright.config.ts
import { defineConfig, devices } from '@playwright/test';
export default defineConfig({
testDir: './tests/e2e',
fullyParallel: true,
forbidOnly: !!process.env.CI,
retries: process.env.CI ? 2 : 0,
workers: process.env.CI ? 1 : undefined,
reporter: 'html',
use: {
baseURL: 'http://localhost:5173',
trace: 'on-first-retry',
},
projects: [
{
name: 'chromium',
use: { ...devices['Desktop Chrome'] },
},
{
name: 'firefox',
use: { ...devices['Desktop Firefox'] },
},
{
name: 'webkit',
use: { ...devices['Desktop Safari'] },
},
],
});
Debugging Tests
Debug Mode
npx playwright test --debug
Opens Playwright Inspector for step-by-step debugging.
Pause Test
test('debug test', async ({ page }) => {
await page.goto('http://localhost:5173');
await page.pause(); // Pauses execution
// Continue debugging in browser
});
Screenshots on Failure
use: {
screenshot: 'only-on-failure',
video: 'retain-on-failure',
}
CI/CD Integration
GitHub Actions Example
name: Playwright Tests
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: 20
- name: Install dependencies
run: cd frontend && npm ci
- name: Install Playwright
run: cd frontend && npx playwright install --with-deps
- name: Run tests
run: cd frontend && npx playwright test
- uses: actions/upload-artifact@v3
if: always()
with:
name: playwright-report
path: frontend/playwright-report/
Best Practices
Test Writing
- Use descriptive test names
- Keep tests independent
- Clean up test data
- Use page object pattern for complex pages
- Avoid hard-coded waits
Selectors
- Prefer data-testid attributes
- Use role-based selectors
- Avoid CSS selectors that may change
- Use text content for stable elements
Example: Good Selectors
// Good - data-testid
await page.locator('[data-testid="create-user-button"]').click();
// Good - role
await page.getByRole('button', { name: 'Create User' }).click();
// Good - text
await page.locator('text=Create User').click();
// Bad - CSS class (may change)
await page.locator('.btn-primary').click();
Test Data Management
Test User Creation
const testUser = {
uid: `testuser_${Date.now()}`,
cn: 'Test User',
mail: 'test@example.com',
password: 'Test123!@#'
};
// Create user
await createUser(page, testUser);
// Verify user
await expect(page.locator(`text=${testUser.uid}`)).toBeVisible();
// Cleanup
await deleteUser(page, testUser.uid);
Performance Testing
Measure Page Load
test('page load performance', async ({ page }) => {
const start = Date.now();
await page.goto('http://localhost:5173');
const loadTime = Date.now() - start;
expect(loadTime).toBeLessThan(3000); // 3 seconds
});
Accessibility Testing
Install axe-playwright
npm install --save-dev @axe-core/playwright
Run Accessibility Tests
import { test, expect } from '@playwright/test';
import { injectAxe, checkA11y } from '@axe-core/playwright';
test('should not have accessibility violations', async ({ page }) => {
await page.goto('http://localhost:5173');
await injectAxe(page);
await checkA11y(page);
});
Troubleshooting
Tests Failing Locally
- Ensure LDAP Manager is running
- Check LDAP server is accessible
- Verify config.yml is correct
- Clear browser cache
- Update Playwright browsers
Flaky Tests
- Add proper waits for elements
- Use
waitForLoadState - Increase timeout for slow operations
- Check for race conditions
Update Browsers
npx playwright install