# Moderation Queue Testing Guide

## Overview

Comprehensive testing strategy for the moderation queue component covering unit tests, integration tests, and end-to-end tests.

## Test Structure

```
tests/
├── unit/                    # Fast, isolated tests
│   └── sanitize.test.ts    # Input sanitization
├── integration/             # Database + API tests
│   └── moderation-security.test.ts
├── e2e/                     # Browser-based tests
│   └── moderation/
│       └── lock-management.spec.ts
├── fixtures/                # Shared test utilities
│   ├── auth.ts             # Authentication helpers
│   └── database.ts         # Database setup/teardown
└── setup/
    ├── global-setup.ts     # Runs before all tests
    └── global-teardown.ts  # Runs after all tests
```

## Unit Tests

### Sanitization Tests

**File:** `tests/unit/sanitize.test.ts`

Tests XSS protection utilities:
- URL validation (block `javascript:`, `data:` protocols)
- HTML entity escaping
- Plain text sanitization
- Suspicious content detection

**Run:**
```bash
npm run test:unit -- sanitize
```

### Hook Tests (Future)

Test custom hooks in isolation:
- `useModerationQueue`
- `useModerationActions`
- `useQueueQuery`

**Example:**
```typescript
import { renderHook } from '@testing-library/react';
import { useModerationQueue } from '@/hooks/useModerationQueue';

test('should claim submission', async () => {
  const { result } = renderHook(() => useModerationQueue());
  
  const success = await result.current.claimSubmission('test-id');
  expect(success).toBe(true);
  expect(result.current.currentLock).toBeTruthy();
});
```

## Integration Tests

### Moderation Security Tests

**File:** `tests/integration/moderation-security.test.ts`

Tests backend security enforcement:

1. **Role Validation**
   - Regular users cannot perform moderation actions
   - Only moderators/admins/superusers can validate actions

2. **Lock Enforcement**
   - Cannot modify submission locked by another moderator
   - Lock must be claimed before approve/reject
   - Expired locks are automatically released

3. **Audit Logging**
   - All actions logged in `moderation_audit_log`
   - Logs include metadata (notes, status changes)
   - Logs are immutable (cannot be modified)

4. **Rate Limiting**
   - Maximum 10 actions per minute per user
   - 11th action within minute fails with rate limit error

**Run:**
```bash
npm run test:integration -- moderation-security
```

### Test Data Management

**Setup:**
- Uses service role key to create test users and data
- All test data marked with `is_test_data: true`
- Isolated from production data

**Cleanup:**
- Global teardown removes all test data
- Query `moderation_audit_log` to verify cleanup
- Check `getTestDataStats()` for remaining records

**Example:**
```typescript
import { setupTestUser, cleanupTestData } from '../fixtures/database';

test.beforeAll(async () => {
  await cleanupTestData();
  await setupTestUser('test@example.com', 'password', 'moderator');
});

test.afterAll(async () => {
  await cleanupTestData();
});
```

## End-to-End Tests

### Lock Management E2E

**File:** `tests/e2e/moderation/lock-management.spec.ts`

Browser-based tests using Playwright:

1. **Claim Submission**
   - Click "Claim Submission" button
   - Verify lock badge appears ("Claimed by you")
   - Verify approve/reject buttons enabled

2. **Lock Timer**
   - Verify countdown displays (14:XX format)
   - Verify lock status badge visible

3. **Extend Lock**
   - Wait for timer to reach < 5 minutes
   - Verify "Extend Lock" button appears
   - Click extend, verify timer resets

4. **Release Lock**
   - Click "Release Lock" button
   - Verify "Claim Submission" button reappears
   - Verify approve/reject buttons disabled

5. **Locked by Another**
   - Verify lock badge for items locked by others
   - Verify actions disabled

**Run:**
```bash
npm run test:e2e -- lock-management
```

### Authentication in E2E Tests

**Global Setup** (`tests/setup/global-setup.ts`):
- Creates test users for all roles (user, moderator, admin, superuser)
- Logs in each user and saves auth state to `.auth/` directory
- Auth states reused across all tests (faster execution)

**Test Usage:**
```typescript
// Use saved auth state
test.use({ storageState: '.auth/moderator.json' });

test('moderator can access queue', async ({ page }) => {
  await page.goto('/moderation/queue');
  // Already authenticated as moderator
});
```

**Manual Login (if needed):**
```typescript
import { loginAsUser } from '../fixtures/auth';

const { userId, accessToken } = await loginAsUser(
  'test@example.com',
  'password'
);
```

## Test Fixtures

### Database Fixtures

**File:** `tests/fixtures/database.ts`

**Functions:**
- `setupTestUser()` - Create test user with specific role
- `cleanupTestData()` - Remove all test data
- `queryDatabase()` - Direct database queries for assertions
- `waitForVersion()` - Wait for version record to be created
- `approveSubmissionDirect()` - Bypass UI for test setup
- `getTestDataStats()` - Get count of test records

**Example:**
```typescript
import { setupTestUser, supabaseAdmin } from '../fixtures/database';

// Create moderator
const { userId } = await setupTestUser(
  'mod@test.com',
  'password',
  'moderator'
);

// Create test submission
const { data } = await supabaseAdmin
  .from('content_submissions')
  .insert({
    submission_type: 'review',
    status: 'pending',
    submitted_by: userId,
    is_test_data: true,
  })
  .select()
  .single();
```

### Auth Fixtures

**File:** `tests/fixtures/auth.ts`

**Functions:**
- `setupAuthStates()` - Create auth states for all roles
- `getTestUserCredentials()` - Get email/password for role
- `loginAsUser()` - Programmatic login
- `logout()` - Programmatic logout

**Test Users:**
```typescript
const TEST_USERS = {
  user: 'test-user@thrillwiki.test',
  moderator: 'test-moderator@thrillwiki.test',
  admin: 'test-admin@thrillwiki.test',
  superuser: 'test-superuser@thrillwiki.test',
};
```

## Running Tests

### All Tests
```bash
npm run test
```

### Unit Tests Only
```bash
npm run test:unit
```

### Integration Tests Only
```bash
npm run test:integration
```

### E2E Tests Only
```bash
npm run test:e2e
```

### Specific Test File
```bash
npm run test:e2e -- lock-management
npm run test:integration -- moderation-security
npm run test:unit -- sanitize
```

### Watch Mode
```bash
npm run test:watch
```

### Coverage Report
```bash
npm run test:coverage
```

## Writing New Tests

### Unit Test Template

```typescript
import { describe, it, expect } from '@playwright/test';
import { functionToTest } from '@/lib/module';

describe('functionToTest', () => {
  it('should handle valid input', () => {
    const result = functionToTest('valid input');
    expect(result).toBe('expected output');
  });

  it('should handle edge case', () => {
    const result = functionToTest('');
    expect(result).toBe('default value');
  });

  it('should throw on invalid input', () => {
    expect(() => functionToTest(null)).toThrow();
  });
});
```

### Integration Test Template

```typescript
import { test, expect } from '@playwright/test';
import { setupTestUser, supabaseAdmin, cleanupTestData } from '../fixtures/database';

test.describe('Feature Name', () => {
  test.beforeAll(async () => {
    await cleanupTestData();
  });

  test.afterAll(async () => {
    await cleanupTestData();
  });

  test('should perform action', async () => {
    // Setup
    const { userId } = await setupTestUser(
      'test@example.com',
      'password',
      'moderator'
    );

    // Action
    const { data, error } = await supabaseAdmin
      .from('table_name')
      .insert({ ... });

    // Assert
    expect(error).toBeNull();
    expect(data).toBeTruthy();
  });
});
```

### E2E Test Template

```typescript
import { test, expect } from '@playwright/test';

test.use({ storageState: '.auth/moderator.json' });

test.describe('Feature Name', () => {
  test.beforeEach(async ({ page }) => {
    await page.goto('/moderation/queue');
    await page.waitForLoadState('networkidle');
  });

  test('should interact with UI', async ({ page }) => {
    // Find element
    const button = page.locator('button:has-text("Action")');
    
    // Assert initial state
    await expect(button).toBeVisible();
    await expect(button).toBeEnabled();
    
    // Perform action
    await button.click();
    
    // Assert result
    await expect(page.locator('text=Success')).toBeVisible();
  });
});
```

## Best Practices

### 1. Test Isolation

Each test should be independent:
- ✅ Clean up test data in `afterEach` or `afterAll`
- ✅ Use unique identifiers for test records
- ❌ Don't rely on data from previous tests

### 2. Realistic Test Data

Use realistic data patterns:
- ✅ Valid email formats
- ✅ Appropriate string lengths
- ✅ Realistic timestamps
- ❌ Don't use `test123` everywhere

### 3. Error Handling

Test both success and failure cases:
```typescript
// Test success
test('should approve valid submission', async () => {
  const { error } = await approveSubmission(validId);
  expect(error).toBeNull();
});

// Test failure
test('should reject invalid submission', async () => {
  const { error } = await approveSubmission(invalidId);
  expect(error).toBeTruthy();
});
```

### 4. Async Handling

Always await async operations:
```typescript
// ❌ WRONG
test('test name', () => {
  asyncFunction();  // Not awaited
  expect(result).toBe(value);  // May run before async completes
});

// ✅ CORRECT
test('test name', async () => {
  await asyncFunction();
  expect(result).toBe(value);
});
```

### 5. Descriptive Test Names

Use clear, descriptive names:
```typescript
// ❌ Vague
test('test 1', () => { ... });

// ✅ Clear
test('should prevent non-moderator from approving submission', () => { ... });
```

## Debugging Tests

### Enable Debug Mode

```bash
# Playwright debug mode (E2E)
PWDEBUG=1 npm run test:e2e -- lock-management

# Show browser during E2E tests
npm run test:e2e -- --headed

# Slow down actions for visibility
npm run test:e2e -- --slow-mo=1000
```

### Console Logging

```typescript
// In tests
console.log('Debug info:', variable);

// View logs
npm run test -- --verbose
```

### Screenshots on Failure

```typescript
// In playwright.config.ts
use: {
  screenshot: 'only-on-failure',
  video: 'retain-on-failure',
}
```

### Database Inspection

```typescript
// Query database during test
const { data } = await supabaseAdmin
  .from('content_submissions')
  .select('*')
  .eq('id', testId);

console.log('Submission state:', data);
```

## Continuous Integration

### GitHub Actions (Example)

```yaml
name: Tests

on: [push, pull_request]

jobs:
  test:
    runs-on: ubuntu-latest
    
    steps:
      - uses: actions/checkout@v3
      
      - name: Setup Node
        uses: actions/setup-node@v3
        with:
          node-version: '18'
      
      - name: Install dependencies
        run: npm ci
      
      - name: Run unit tests
        run: npm run test:unit
      
      - name: Run integration tests
        run: npm run test:integration
        env:
          SUPABASE_SERVICE_ROLE_KEY: ${{ secrets.SUPABASE_SERVICE_ROLE_KEY }}
      
      - name: Run E2E tests
        run: npm run test:e2e
        env:
          BASE_URL: http://localhost:8080
```

## Coverage Goals

- **Unit Tests:** 90%+ coverage
- **Integration Tests:** All critical paths covered
- **E2E Tests:** Happy paths + key error scenarios

**Generate Coverage Report:**
```bash
npm run test:coverage
open coverage/index.html
```

## Troubleshooting

### Test Timeout

```typescript
// Increase timeout for slow operations
test('slow test', async () => {
  test.setTimeout(60000); // 60 seconds
  await slowOperation();
});
```

### Flaky Tests

Common causes and fixes:
- **Race conditions:** Add `waitFor` or `waitForSelector`
- **Network delays:** Increase timeout, add retries
- **Test data conflicts:** Ensure unique IDs

### Database Connection Issues

```typescript
// Check connection
if (!supabaseAdmin) {
  throw new Error('Service role key not configured');
}
```

## Future Test Coverage

- [ ] Unit tests for all custom hooks
- [ ] Component snapshot tests
- [ ] Accessibility tests (axe-core)
- [ ] Performance tests (lighthouse)
- [ ] Load testing (k6 or similar)
- [ ] Visual regression tests (Percy/Chromatic)
