skills/hack23/cia/playwright-ui-testing

playwright-ui-testing

SKILL.md

Playwright UI Testing

Purpose

This skill provides guidance for implementing comprehensive UI testing using Playwright, including browser automation, visual regression testing, accessibility validation, and end-to-end workflow testing for the CIA platform.

When to Use

✅ Use this skill when:

  • Writing end-to-end UI tests
  • Automating browser interactions
  • Performing visual regression testing
  • Validating accessibility (WCAG)
  • Testing across multiple browsers
  • Capturing screenshots for documentation
  • Testing responsive layouts
  • Validating user workflows

❌ Don't use this skill for:

  • Unit testing (use unit-testing-patterns)
  • API testing (use integration-testing)
  • Performance testing (use code-quality-checks)
  • Security testing (use secure-code-review)

Patterns & Examples

Basic Playwright Test Structure

// tests/politician-search.spec.js
const { test, expect } = require('@playwright/test');

test.describe('Politician Search', () => {
  test.beforeEach(async ({ page }) => {
    // Navigate to search page
    await page.goto('https://localhost:28443/cia/');
    await page.waitForLoadState('networkidle');
  });

  test('should search politicians by name', async ({ page }) => {
    // Enter search term
    await page.fill('[aria-label="Search politicians"]', 'Andersson');
    await page.click('button:has-text("Search")');
    
    // Wait for results
    await page.waitForSelector('.politician-card');
    
    // Verify results contain search term
    const results = await page.locator('.politician-card').all();
    expect(results.length).toBeGreaterThan(0);
    
    for (const result of results) {
      const name = await result.locator('.politician-name').textContent();
      expect(name.toLowerCase()).toContain('andersson');
    }
  });

  test('should filter by political party', async ({ page }) => {
    // Select party filter
    await page.selectOption('[aria-label="Filter by party"]', 'S');
    
    // Wait for filtered results
    await page.waitForSelector('.politician-card');
    
    // Verify all results are from selected party
    const partyBadges = await page.locator('.party-badge').allTextContents();
    partyBadges.forEach(badge => {
      expect(badge).toBe('S');
    });
  });

  test('should display politician details', async ({ page }) => {
    // Click on first politician
    await page.click('.politician-card:first-child');
    
    // Verify detail view loaded
    await expect(page.locator('h1.politician-name')).toBeVisible();
    await expect(page.locator('.risk-score')).toBeVisible();
    await expect(page.locator('.voting-history')).toBeVisible();
    
    // Verify risk score is numeric
    const riskScore = await page.locator('.risk-score').textContent();
    expect(parseFloat(riskScore)).toBeGreaterThanOrEqual(0);
    expect(parseFloat(riskScore)).toBeLessThanOrEqual(100);
  });
});

Accessibility Testing with Playwright

// tests/accessibility.spec.js
const { test, expect } = require('@playwright/test');
const { injectAxe, checkA11y, getViolations } = require('axe-playwright');

test.describe('Accessibility Compliance', () => {
  test('homepage should have no accessibility violations', async ({ page }) => {
    await page.goto('https://localhost:28443/cia/');
    await injectAxe(page);
    
    // Check for WCAG 2.1 Level AA violations
    await checkA11y(page, null, {
      detailedReport: true,
      detailedReportOptions: {
        html: true
      },
      axeOptions: {
        runOnly: {
          type: 'tag',
          values: ['wcag2a', 'wcag2aa', 'wcag21a', 'wcag21aa']
        }
      }
    });
  });

  test('politician detail page keyboard navigation', async ({ page }) => {
    await page.goto('https://localhost:28443/cia/politician/123');
    
    // Tab through interactive elements
    await page.keyboard.press('Tab');
    let focused = await page.evaluate(() => document.activeElement.tagName);
    expect(['A', 'BUTTON', 'INPUT']).toContain(focused);
    
    // Verify skip link
    await page.keyboard.press('Tab');
    const skipLink = await page.locator('a.skip-link');
    await expect(skipLink).toBeFocused();
    
    // Test escape key closes modals
    await page.click('[aria-label="Show risk details"]');
    await expect(page.locator('[role="dialog"]')).toBeVisible();
    await page.keyboard.press('Escape');
    await expect(page.locator('[role="dialog"]')).not.toBeVisible();
  });

  test('screen reader landmarks', async ({ page }) => {
    await page.goto('https://localhost:28443/cia/');
    
    // Verify ARIA landmarks
    await expect(page.locator('[role="banner"]')).toBeVisible();
    await expect(page.locator('[role="navigation"]')).toBeVisible();
    await expect(page.locator('[role="main"]')).toBeVisible();
    await expect(page.locator('[role="contentinfo"]')).toBeVisible();
  });
});

Visual Regression Testing

// tests/visual-regression.spec.js
const { test, expect } = require('@playwright/test');

test.describe('Visual Regression', () => {
  test('homepage matches baseline', async ({ page }) => {
    await page.goto('https://localhost:28443/cia/');
    await page.waitForLoadState('networkidle');
    
    // Take screenshot and compare to baseline
    await expect(page).toHaveScreenshot('homepage.png', {
      fullPage: true,
      maxDiffPixels: 100
    });
  });

  test('risk dashboard layout', async ({ page }) => {
    await page.goto('https://localhost:28443/cia/dashboard/risk');
    
    // Wait for charts to render
    await page.waitForSelector('canvas.chart-canvas');
    await page.waitForTimeout(1000); // Allow chart animations
    
    await expect(page).toHaveScreenshot('risk-dashboard.png', {
      maxDiffPixelRatio: 0.05
    });
  });

  test('responsive design - mobile', async ({ page }) => {
    // Set mobile viewport
    await page.setViewportSize({ width: 375, height: 667 });
    await page.goto('https://localhost:28443/cia/politician/list');
    
    await expect(page).toHaveScreenshot('politician-list-mobile.png');
  });

  test('responsive design - tablet', async ({ page }) => {
    await page.setViewportSize({ width: 768, height: 1024 });
    await page.goto('https://localhost:28443/cia/politician/list');
    
    await expect(page).toHaveScreenshot('politician-list-tablet.png');
  });
});

Cross-Browser Testing Configuration

// playwright.config.js
const { defineConfig, devices } = require('@playwright/test');

module.exports = defineConfig({
  testDir: './tests',
  fullyParallel: true,
  forbidOnly: !!process.env.CI,
  retries: process.env.CI ? 2 : 0,
  workers: process.env.CI ? 1 : undefined,
  reporter: [
    ['html'],
    ['junit', { outputFile: 'test-results/junit.xml' }]
  ],
  use: {
    baseURL: 'https://localhost:28443',
    trace: 'on-first-retry',
    screenshot: 'only-on-failure',
    video: 'retain-on-failure',
    ignoreHTTPSErrors: true // For self-signed certs in dev
  },

  projects: [
    {
      name: 'chromium',
      use: { ...devices['Desktop Chrome'] }
    },
    {
      name: 'firefox',
      use: { ...devices['Desktop Firefox'] }
    },
    {
      name: 'webkit',
      use: { ...devices['Desktop Safari'] }
    },
    {
      name: 'Mobile Chrome',
      use: { ...devices['Pixel 5'] }
    },
    {
      name: 'Mobile Safari',
      use: { ...devices['iPhone 12'] }
    }
  ],

  webServer: {
    command: 'cd citizen-intelligence-agency && ant start',
    port: 28443,
    timeout: 120 * 1000,
    reuseExistingServer: !process.env.CI
  }
});

GitHub Actions Integration

# .github/workflows/playwright-tests.yml
name: Playwright Tests
on: [push, pull_request]

jobs:
  test:
    timeout-minutes: 60
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v4
    - uses: actions/setup-node@v4
      with:
        node-version: '24'
    - name: Install dependencies
      run: npm ci
    - name: Install Playwright Browsers
      run: npx playwright install --with-deps
    - name: Run Playwright tests
      run: npx playwright test
    - uses: actions/upload-artifact@v4
      if: always()
      with:
        name: playwright-report
        path: playwright-report/
        retention-days: 30

ISMS Compliance Mapping

ISO 27001:2022 Annex A Controls

A.8.29 - Testing in development and acceptance

  • Automated UI testing validates functionality
  • Security testing integrated in test suite
  • Test results documented and reviewed

A.8.31 - Separation of development, test and production

  • Tests run against test environment
  • Production credentials never used in tests

CIS Controls v8

Control 16: Application Software Security

  • 16.10: Apply automated testing tools
  • 16.11: Use standard security configurations

Hack23 ISMS Policy References

References

Playwright Documentation

CIA Documentation

Remember

  • Test real user workflows: Not just individual features
  • Cross-browser testing: Test on Chrome, Firefox, Safari
  • Accessibility is mandatory: Integrate axe-core checks
  • Visual regression: Catch unintended UI changes
  • Parallel execution: Speed up test runs
  • CI/CD integration: Run tests on every commit
  • Test data cleanup: Maintain test isolation
Weekly Installs
11
Repository
hack23/cia
GitHub Stars
213
First Seen
12 days ago
Installed on
opencode11
claude-code11
github-copilot11
codex11
amp11
cline11