chore: clean .gitignore cache
This commit is contained in:
@@ -1,251 +0,0 @@
|
||||
# DNS Provider E2E Test Triage Report
|
||||
|
||||
**Date**: 2026-01-15
|
||||
**Agent**: QA_Security
|
||||
**Phase**: Phase 4 — E2E Coverage + Regression Safety
|
||||
|
||||
## Executive Summary
|
||||
|
||||
Successfully triaged and fixed Playwright E2E tests for the DNS Provider feature. All tests now pass with 52 tests passing and 3 conditionally skipped (expected behavior).
|
||||
|
||||
## Test Results
|
||||
|
||||
### Before Fixes
|
||||
| Status | Count |
|
||||
|--------|-------|
|
||||
| ❌ Failed | 7 |
|
||||
| ✅ Passed | 45 |
|
||||
| ⏭️ Skipped | 3 |
|
||||
|
||||
### After Fixes
|
||||
| Status | Count |
|
||||
|--------|-------|
|
||||
| ❌ Failed | 0 |
|
||||
| ✅ Passed | 52 |
|
||||
| ⏭️ Skipped | 3 |
|
||||
|
||||
## Test Files Summary
|
||||
|
||||
### 1. `tests/auth.setup.ts`
|
||||
| Test | Status |
|
||||
|------|--------|
|
||||
| authenticate | ✅ Pass |
|
||||
|
||||
### 2. `tests/dns-provider-types.spec.ts`
|
||||
**API Tests:**
|
||||
| Test | Status |
|
||||
|------|--------|
|
||||
| GET /dns-providers/types returns all built-in and custom providers | ✅ Pass |
|
||||
| Each provider type has required fields | ✅ Pass |
|
||||
| Manual provider type has correct configuration | ✅ Pass |
|
||||
| Webhook provider type has URL field | ✅ Pass |
|
||||
| RFC2136 provider type has server and key fields | ✅ Pass |
|
||||
| Script provider type has command/path field | ✅ Pass |
|
||||
|
||||
**UI Tests:**
|
||||
| Test | Status |
|
||||
|------|--------|
|
||||
| Provider selector shows all provider types in dropdown | ✅ Pass |
|
||||
| Provider selector displays provider description | ✅ Pass |
|
||||
| Provider types keyboard navigation | ✅ Pass (Fixed) |
|
||||
| Manual type selection shows correct fields | ✅ Pass |
|
||||
| Webhook type selection shows URL field | ✅ Pass (Fixed) |
|
||||
| RFC2136 type selection shows server field | ✅ Pass (Fixed) |
|
||||
| Script type selection shows script path field | ✅ Pass |
|
||||
|
||||
### 3. `tests/dns-provider-crud.spec.ts`
|
||||
**Create Provider:**
|
||||
| Test | Status |
|
||||
|------|--------|
|
||||
| Create Manual DNS provider | ✅ Pass |
|
||||
| Create Webhook DNS provider | ✅ Pass |
|
||||
| Validation errors for missing required fields | ✅ Pass |
|
||||
| Validate webhook URL format | ✅ Pass |
|
||||
|
||||
**Provider List:**
|
||||
| Test | Status |
|
||||
|------|--------|
|
||||
| Display provider list or empty state | ✅ Pass |
|
||||
| Show Add Provider button | ✅ Pass |
|
||||
| Show provider details in list | ✅ Pass |
|
||||
|
||||
**Edit Provider:**
|
||||
| Test | Status |
|
||||
|------|--------|
|
||||
| Open edit dialog for existing provider | ⏭️ Skipped (conditional) |
|
||||
| Update provider name | ⏭️ Skipped (conditional) |
|
||||
|
||||
**Delete Provider:**
|
||||
| Test | Status |
|
||||
|------|--------|
|
||||
| Show delete confirmation dialog | ⏭️ Skipped (conditional) |
|
||||
|
||||
**API Operations:**
|
||||
| Test | Status |
|
||||
|------|--------|
|
||||
| List providers via API | ✅ Pass |
|
||||
| Create provider via API | ✅ Pass |
|
||||
| Reject invalid provider type via API | ✅ Pass |
|
||||
| Get single provider via API | ✅ Pass |
|
||||
|
||||
**Form Accessibility:**
|
||||
| Test | Status |
|
||||
|------|--------|
|
||||
| Form has accessible labels | ✅ Pass |
|
||||
| Keyboard navigation in form | ✅ Pass |
|
||||
| Errors announced to screen readers | ✅ Pass |
|
||||
|
||||
### 4. `tests/manual-dns-provider.spec.ts`
|
||||
**Provider Selection Flow:**
|
||||
| Test | Status |
|
||||
|------|--------|
|
||||
| Navigate to DNS Providers page | ✅ Pass |
|
||||
| Show Add Provider button on DNS Providers page | ✅ Pass (Fixed) |
|
||||
| Display Manual option in provider selection | ✅ Pass (Fixed) |
|
||||
|
||||
**Manual Challenge UI Display:**
|
||||
| Test | Status |
|
||||
|------|--------|
|
||||
| Display challenge panel with required elements | ✅ Pass |
|
||||
| Show record name and value fields | ✅ Pass |
|
||||
| Display progress bar with time remaining | ✅ Pass |
|
||||
| Display status indicator | ✅ Pass (Fixed) |
|
||||
|
||||
**Copy to Clipboard:**
|
||||
| Test | Status |
|
||||
|------|--------|
|
||||
| Have accessible copy buttons | ✅ Pass |
|
||||
| Show copied feedback on click | ✅ Pass |
|
||||
|
||||
**Verify Button Interactions:**
|
||||
| Test | Status |
|
||||
|------|--------|
|
||||
| Have Check DNS Now button | ✅ Pass |
|
||||
| Show loading state when checking DNS | ✅ Pass |
|
||||
| Have Verify button with description | ✅ Pass |
|
||||
|
||||
**Accessibility Checks:**
|
||||
| Test | Status |
|
||||
|------|--------|
|
||||
| Keyboard accessible interactive elements | ✅ Pass |
|
||||
| Proper ARIA labels on copy buttons | ✅ Pass |
|
||||
| Announce status changes to screen readers | ✅ Pass |
|
||||
| Accessible form labels | ✅ Pass (Fixed) |
|
||||
| Validate accessibility tree structure | ✅ Pass (Fixed) |
|
||||
|
||||
**Component Tests:**
|
||||
| Test | Status |
|
||||
|------|--------|
|
||||
| Render all required challenge information | ✅ Pass |
|
||||
| Handle expired challenge state | ✅ Pass |
|
||||
| Handle verified challenge state | ✅ Pass |
|
||||
|
||||
**Error Handling:**
|
||||
| Test | Status |
|
||||
|------|--------|
|
||||
| Display error message on verification failure | ✅ Pass |
|
||||
| Handle network errors gracefully | ✅ Pass |
|
||||
|
||||
## Issues Fixed
|
||||
|
||||
### 1. URL Path Mismatch
|
||||
**Issue**: `manual-dns-provider.spec.ts` used `/dns-providers` URL while the frontend uses `/dns/providers`.
|
||||
|
||||
**Fix**: Updated all occurrences to use `/dns/providers`.
|
||||
|
||||
**Files Changed**: `tests/manual-dns-provider.spec.ts`
|
||||
|
||||
### 2. Button Selector Too Strict
|
||||
**Issue**: Tests used `getByRole('button', { name: /add provider/i })` without `.first()` which failed when multiple buttons matched.
|
||||
|
||||
**Fix**: Added `.first()` to handle both header button and empty state button.
|
||||
|
||||
### 3. Dropdown Search Filter Test
|
||||
**Issue**: Test tried to fill text into a combobox that doesn't support text input.
|
||||
|
||||
**Fix**: Changed test to verify keyboard navigation works instead.
|
||||
|
||||
**File**: `tests/dns-provider-types.spec.ts`
|
||||
|
||||
### 4. Dynamic Field Locators
|
||||
**Issue**: Tests used `getByLabel(/url/i)` but credential fields are rendered dynamically without proper labels.
|
||||
|
||||
**Fix**: Changed to locate fields by label text followed by input structure.
|
||||
|
||||
**Files Changed**: `tests/dns-provider-types.spec.ts`
|
||||
|
||||
### 5. Conditional Status Icon Test
|
||||
**Issue**: Test expected SVG icon in status indicator but icon may not always be present.
|
||||
|
||||
**Fix**: Made icon check conditional.
|
||||
|
||||
**File**: `tests/manual-dns-provider.spec.ts`
|
||||
|
||||
## Skipped Tests (Expected)
|
||||
|
||||
The following tests are conditionally skipped when no providers with edit/delete capabilities exist:
|
||||
|
||||
1. `should open edit dialog for existing provider`
|
||||
2. `should update provider name`
|
||||
3. `should show delete confirmation dialog`
|
||||
|
||||
This is expected behavior — these tests only run when provider cards with edit/delete buttons are present.
|
||||
|
||||
## Test Fixtures Created
|
||||
|
||||
Created `tests/fixtures/dns-providers.ts` with:
|
||||
- Mock provider types (built-in and custom)
|
||||
- Mock provider data for different types
|
||||
- Mock API responses
|
||||
- Mock manual challenge data
|
||||
- Helper functions for test provider creation/cleanup
|
||||
|
||||
## Recommendations
|
||||
|
||||
### Next Steps
|
||||
|
||||
1. **Enable Edit/Delete Tests**: Add test data setup to ensure providers with edit buttons exist before running edit/delete tests.
|
||||
|
||||
2. **Add Plugin Provider Tests**: When external plugins are loaded, add tests for plugin-specific provider types (e.g., PowerDNS).
|
||||
|
||||
3. **Expand Accessibility Tests**: Add more accessibility tests for:
|
||||
- Focus trap in dialog
|
||||
- Screen reader announcements for success/error states
|
||||
- High contrast mode support
|
||||
|
||||
4. **Add Visual Regression Tests**: Consider adding visual regression tests for provider cards and forms.
|
||||
|
||||
### Known Limitations
|
||||
|
||||
1. **Dynamic Fields**: Credential fields are rendered dynamically from the API response. Tests rely on label text patterns rather than stable IDs.
|
||||
|
||||
2. **Mock Challenge Panel**: The manual challenge panel tests use conditional checks since the challenge UI requires an active certificate issuance.
|
||||
|
||||
3. **No Real Plugin Tests**: Tests for external plugin providers require actual `.so` files to be loaded.
|
||||
|
||||
## Verification Command
|
||||
|
||||
```bash
|
||||
# Run all DNS Provider E2E tests
|
||||
PLAYWRIGHT_BASE_URL=http://localhost:8080 npm run e2e
|
||||
|
||||
# Or with the E2E Docker environment
|
||||
docker compose -f .docker/compose/docker-compose.e2e.yml up -d
|
||||
PLAYWRIGHT_BASE_URL=http://localhost:8080 npm run e2e
|
||||
```
|
||||
|
||||
## Test Coverage Summary
|
||||
|
||||
| Category | Tests | Passing |
|
||||
|----------|-------|---------|
|
||||
| API Endpoints | 10 | 10 |
|
||||
| UI Navigation | 6 | 6 |
|
||||
| Provider CRUD | 8 | 5 (+3 conditional) |
|
||||
| Manual Challenge | 11 | 11 |
|
||||
| Accessibility | 9 | 9 |
|
||||
| Error Handling | 2 | 2 |
|
||||
| **Total** | **55** | **52 (+3 conditional)** |
|
||||
|
||||
---
|
||||
|
||||
**Status**: ✅ Phase 4 E2E Test Triage Complete
|
||||
@@ -1,143 +0,0 @@
|
||||
# Security Test Helpers
|
||||
|
||||
Helper utilities for managing security module state during E2E tests.
|
||||
|
||||
## Overview
|
||||
|
||||
The security helpers module (`tests/utils/security-helpers.ts`) provides utilities for:
|
||||
|
||||
- Capturing and restoring security module state
|
||||
- Toggling individual security modules (ACL, WAF, Rate Limiting, CrowdSec)
|
||||
- Ensuring test isolation without ACL deadlock
|
||||
|
||||
## Problem Solved
|
||||
|
||||
During E2E testing, if ACL is left enabled from a previous test run (e.g., due to test failure), it creates a **deadlock**:
|
||||
|
||||
1. ACL blocks API requests → returns 403 Forbidden
|
||||
2. Global cleanup can't run → API blocked
|
||||
3. Auth setup fails → tests skip
|
||||
4. Manual intervention required to reset volumes
|
||||
|
||||
The security helpers solve this by using Playwright's `test.afterAll()` fixture to guarantee cleanup even when tests fail.
|
||||
|
||||
## Usage
|
||||
|
||||
### Capture and Restore Pattern
|
||||
|
||||
```typescript
|
||||
import { captureSecurityState, restoreSecurityState } from '../utils/security-helpers';
|
||||
import { request } from '@playwright/test';
|
||||
|
||||
let originalState;
|
||||
|
||||
test.beforeAll(async ({ request: reqFixture }) => {
|
||||
originalState = await captureSecurityState(reqFixture);
|
||||
});
|
||||
|
||||
test.afterAll(async () => {
|
||||
const cleanup = await request.newContext({ baseURL: '...' });
|
||||
try {
|
||||
await restoreSecurityState(cleanup, originalState);
|
||||
} finally {
|
||||
await cleanup.dispose();
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
### Toggle Security Module
|
||||
|
||||
```typescript
|
||||
import { setSecurityModuleEnabled } from '../utils/security-helpers';
|
||||
|
||||
await setSecurityModuleEnabled(request, 'acl', true);
|
||||
await setSecurityModuleEnabled(request, 'waf', false);
|
||||
```
|
||||
|
||||
### With Guaranteed Cleanup
|
||||
|
||||
```typescript
|
||||
import { withSecurityEnabled } from '../utils/security-helpers';
|
||||
|
||||
test.describe('ACL Tests', () => {
|
||||
let cleanup: () => Promise<void>;
|
||||
|
||||
test.beforeAll(async ({ request }) => {
|
||||
cleanup = await withSecurityEnabled(request, { acl: true, cerberus: true });
|
||||
});
|
||||
|
||||
test.afterAll(async () => {
|
||||
await cleanup();
|
||||
});
|
||||
|
||||
test('should enforce ACL', async ({ page }) => {
|
||||
// ACL is now enabled, test enforcement
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
## Functions
|
||||
|
||||
| Function | Purpose |
|
||||
|----------|---------|
|
||||
| `getSecurityStatus` | Fetch current security module states |
|
||||
| `setSecurityModuleEnabled` | Toggle a specific module on/off |
|
||||
| `captureSecurityState` | Snapshot all module states |
|
||||
| `restoreSecurityState` | Restore to captured snapshot |
|
||||
| `withSecurityEnabled` | Enable modules with guaranteed cleanup |
|
||||
| `disableAllSecurityModules` | Emergency reset |
|
||||
|
||||
## API Endpoints Used
|
||||
|
||||
| Endpoint | Method | Purpose |
|
||||
|----------|--------|---------|
|
||||
| `/api/v1/security/status` | GET | Returns current state of all security modules |
|
||||
| `/api/v1/settings` | POST | Toggle settings with `{ key: "...", value: "true/false" }` |
|
||||
|
||||
## Settings Keys
|
||||
|
||||
| Key | Values | Description |
|
||||
|-----|--------|-------------|
|
||||
| `security.acl.enabled` | `"true"` / `"false"` | Toggle ACL enforcement |
|
||||
| `security.waf.enabled` | `"true"` / `"false"` | Toggle WAF enforcement |
|
||||
| `security.rate_limit.enabled` | `"true"` / `"false"` | Toggle Rate Limiting |
|
||||
| `security.crowdsec.enabled` | `"true"` / `"false"` | Toggle CrowdSec |
|
||||
| `feature.cerberus.enabled` | `"true"` / `"false"` | Master toggle for all security |
|
||||
|
||||
## Best Practices
|
||||
|
||||
1. **Always use `test.afterAll`** for cleanup - it runs even when tests fail
|
||||
2. **Capture state before modifying** - enables precise restoration
|
||||
3. **Enable Cerberus first** - it's the master toggle for all security modules
|
||||
4. **Don't toggle back in individual tests** - let `afterAll` handle cleanup
|
||||
5. **Use `withSecurityEnabled`** for the cleanest pattern
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### ACL Deadlock Recovery
|
||||
|
||||
If the test suite is stuck due to ACL deadlock:
|
||||
|
||||
```bash
|
||||
# Check current security status
|
||||
curl http://localhost:8080/api/v1/security/status
|
||||
|
||||
# Manually disable ACL (requires auth)
|
||||
curl -X POST http://localhost:8080/api/v1/settings \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"key": "security.acl.enabled", "value": "false"}'
|
||||
```
|
||||
|
||||
### Complete Reset
|
||||
|
||||
Use `disableAllSecurityModules` in global setup to ensure clean slate:
|
||||
|
||||
```typescript
|
||||
import { disableAllSecurityModules } from './utils/security-helpers';
|
||||
|
||||
async function globalSetup() {
|
||||
const context = await request.newContext({ baseURL: '...' });
|
||||
await disableAllSecurityModules(context);
|
||||
await context.dispose();
|
||||
}
|
||||
```
|
||||
Reference in New Issue
Block a user