Claude Code Plugins

Community-maintained marketplace

Feedback

qa-regression

@plurigrid/asi
0
0

Automate QA regression testing with reusable test skills. Create login

Install Skill

1Download skill
2Enable skills in Claude

Open claude.ai/settings/capabilities and find the "Skills" section

3Upload to Claude

Click "Upload skill" and select the downloaded ZIP file

Note: Please verify skill by going through its instructions before using it.

SKILL.md

name qa-regression
description Automate QA regression testing with reusable test skills. Create login
version 1.0.0

QA Regression Testing

Build and run automated regression tests using Playwright. Each test is a reusable skill that can be composed into full test suites.

Setup

npm init -y
npm install playwright @playwright/test
npx playwright install

Test Structure

Create tests in tests/ folder:

tests/
├── auth/
│   ├── login.spec.ts
│   └── logout.spec.ts
├── dashboard/
│   └── load.spec.ts
├── users/
│   ├── create.spec.ts
│   └── delete.spec.ts
└── regression.spec.ts   # Full suite

Common Test Skills

Login Test

// tests/auth/login.spec.ts
import { test, expect } from '@playwright/test';

test.describe('Login Flow', () => {
  test('should login with valid credentials', async ({ page }) => {
    await page.goto('/login');

    await page.fill('[data-testid="email"]', process.env.TEST_EMAIL!);
    await page.fill('[data-testid="password"]', process.env.TEST_PASSWORD!);
    await page.click('[data-testid="submit"]');

    // Verify redirect to dashboard
    await expect(page).toHaveURL(/dashboard/);
    await expect(page.locator('[data-testid="user-menu"]')).toBeVisible();
  });

  test('should show error for invalid credentials', async ({ page }) => {
    await page.goto('/login');

    await page.fill('[data-testid="email"]', 'wrong@example.com');
    await page.fill('[data-testid="password"]', 'wrongpassword');
    await page.click('[data-testid="submit"]');

    await expect(page.locator('[data-testid="error-message"]')).toBeVisible();
  });
});

Dashboard Load Test

// tests/dashboard/load.spec.ts
import { test, expect } from '@playwright/test';
import { login } from '../helpers/auth';

test.describe('Dashboard', () => {
  test.beforeEach(async ({ page }) => {
    await login(page);
  });

  test('should load dashboard within 3 seconds', async ({ page }) => {
    const start = Date.now();
    await page.goto('/dashboard');
    await page.waitForSelector('[data-testid="dashboard-content"]');
    const loadTime = Date.now() - start;

    expect(loadTime).toBeLessThan(3000);
  });

  test('should display all widgets', async ({ page }) => {
    await page.goto('/dashboard');

    await expect(page.locator('[data-testid="stats-widget"]')).toBeVisible();
    await expect(page.locator('[data-testid="chart-widget"]')).toBeVisible();
    await expect(page.locator('[data-testid="activity-widget"]')).toBeVisible();
  });

  test('should refresh data on button click', async ({ page }) => {
    await page.goto('/dashboard');

    const initialValue = await page.locator('[data-testid="last-updated"]').textContent();
    await page.click('[data-testid="refresh-button"]');
    await page.waitForTimeout(1000);
    const newValue = await page.locator('[data-testid="last-updated"]').textContent();

    expect(newValue).not.toBe(initialValue);
  });
});

Create User Test

// tests/users/create.spec.ts
import { test, expect } from '@playwright/test';
import { login } from '../helpers/auth';
import { generateTestUser, deleteTestUser } from '../helpers/users';

test.describe('User Creation', () => {
  let testUser: { email: string; name: string };

  test.beforeEach(async ({ page }) => {
    await login(page);
    testUser = generateTestUser();
  });

  test.afterEach(async () => {
    // Cleanup
    await deleteTestUser(testUser.email);
  });

  test('should create new user successfully', async ({ page }) => {
    await page.goto('/users/new');

    await page.fill('[data-testid="user-name"]', testUser.name);
    await page.fill('[data-testid="user-email"]', testUser.email);
    await page.selectOption('[data-testid="user-role"]', 'member');
    await page.click('[data-testid="create-user-btn"]');

    // Verify success
    await expect(page.locator('[data-testid="success-toast"]')).toBeVisible();
    await expect(page).toHaveURL(/users/);

    // Verify user appears in list
    await expect(page.locator(`text=${testUser.email}`)).toBeVisible();
  });

  test('should validate required fields', async ({ page }) => {
    await page.goto('/users/new');
    await page.click('[data-testid="create-user-btn"]');

    await expect(page.locator('[data-testid="name-error"]')).toBeVisible();
    await expect(page.locator('[data-testid="email-error"]')).toBeVisible();
  });
});

Shared Helpers

// tests/helpers/auth.ts
import { Page } from '@playwright/test';

export async function login(page: Page) {
  await page.goto('/login');
  await page.fill('[data-testid="email"]', process.env.TEST_EMAIL!);
  await page.fill('[data-testid="password"]', process.env.TEST_PASSWORD!);
  await page.click('[data-testid="submit"]');
  await page.waitForURL(/dashboard/);
}

export async function logout(page: Page) {
  await page.click('[data-testid="user-menu"]');
  await page.click('[data-testid="logout"]');
  await page.waitForURL(/login/);
}
// tests/helpers/users.ts
export function generateTestUser() {
  const id = Date.now();
  return {
    name: `Test User ${id}`,
    email: `test-${id}@example.com`,
  };
}

export async function deleteTestUser(email: string) {
  // API call to cleanup test user
  await fetch(`${process.env.API_URL}/admin/users`, {
    method: 'DELETE',
    headers: {
      'Authorization': `Bearer ${process.env.ADMIN_TOKEN}`,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({ email }),
  });
}

Full Regression Suite

// tests/regression.spec.ts
import { test } from '@playwright/test';

// Import all test suites
import './auth/login.spec';
import './auth/logout.spec';
import './dashboard/load.spec';
import './users/create.spec';
import './users/delete.spec';

test.describe('Full Regression Suite', () => {
  // Tests run in order defined above
});

Playwright Config

// playwright.config.ts
import { defineConfig, devices } from '@playwright/test';

export default defineConfig({
  testDir: './tests',
  fullyParallel: true,
  forbidOnly: !!process.env.CI,
  retries: process.env.CI ? 2 : 0,
  workers: process.env.CI ? 1 : undefined,
  reporter: [
    ['html'],
    ['json', { outputFile: 'test-results.json' }],
  ],
  use: {
    baseURL: process.env.BASE_URL || 'http://localhost:3000',
    trace: 'on-first-retry',
    screenshot: 'only-on-failure',
  },
  projects: [
    {
      name: 'chromium',
      use: { ...devices['Desktop Chrome'] },
    },
    {
      name: 'firefox',
      use: { ...devices['Desktop Firefox'] },
    },
    {
      name: 'webkit',
      use: { ...devices['Desktop Safari'] },
    },
  ],
});

Running Tests

# Run all tests
npx playwright test

# Run specific test file
npx playwright test tests/auth/login.spec.ts

# Run tests with UI
npx playwright test --ui

# Run in headed mode (see browser)
npx playwright test --headed

# Generate report
npx playwright show-report

CI Integration

# .github/workflows/regression.yml
name: Regression Tests

on:
  push:
    branches: [main]
  pull_request:
    branches: [main]
  schedule:
    - cron: '0 6 * * *'  # Daily at 6 AM

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: 20

      - name: Install dependencies
        run: npm ci

      - name: Install Playwright
        run: npx playwright install --with-deps

      - name: Run tests
        run: npx playwright test
        env:
          BASE_URL: ${{ secrets.STAGING_URL }}
          TEST_EMAIL: ${{ secrets.TEST_EMAIL }}
          TEST_PASSWORD: ${{ secrets.TEST_PASSWORD }}

      - uses: actions/upload-artifact@v4
        if: always()
        with:
          name: playwright-report
          path: playwright-report/

Best Practices

  1. Use data-testid attributes - More stable than CSS selectors
  2. Clean up test data - Always delete what you create
  3. Avoid hardcoded waits - Use waitForSelector instead of waitForTimeout
  4. Run in parallel - Faster feedback on CI
  5. Screenshot on failure - Easier debugging
  6. Environment variables - Never commit credentials

Quick Commands

Task Command
Run all npx playwright test
Run one file npx playwright test login.spec.ts
Debug mode npx playwright test --debug
UI mode npx playwright test --ui
Update snapshots npx playwright test --update-snapshots

Scientific Skill Interleaving

This skill connects to the K-Dense-AI/claude-scientific-skills ecosystem:

Graph Theory

  • networkx [○] via bicomodule
    • Universal graph hub

Bibliography References

  • general: 734 citations in bib.duckdb

Cat# Integration

This skill maps to Cat# = Comod(P) as a bicomodule in the equipment structure:

Trit: 0 (ERGODIC)
Home: Prof
Poly Op: ⊗
Kan Role: Adj
Color: #26D826

GF(3) Naturality

The skill participates in triads satisfying:

(-1) + (0) + (+1) ≡ 0 (mod 3)

This ensures compositional coherence in the Cat# equipment structure.