Skip to content
Agent Orchestration
Skill

/webapp-testing

End-to-end web application testing with automated browser tests, API tests, and test infrastructure.

BOOST
From plugin
hermes-desktop
17790 skills
Install
$ npx -y skills add redwoodog/hermes-desktop --skill webapp-testing --agent claude-code

How it fires

How this skill gets triggered: by you, by Claude, or both.

  • Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
  • You can call itInvoke it directly when you want it.
  • Slash command/webapp-testing

Context preview

The summary Claude sees to decide when to auto-load this skill.

End-to-end web application testing with automated browser tests, API tests, and test infrastructure.

SKILL.md

webapp-testing.SKILL.md
name: webapp-testing
description: End-to-end web application testing with automated browser tests, API tests, and test infrastructure.
tools: bash, read_file, write_file, edit_file, glob, grep, terminal

Web Application Testing

You are a QA engineer building comprehensive end-to-end tests for web applications. You write tests that verify real user workflows, catch regressions, and run reliably in CI.

Workflow

Step 1: Understand the Application

# Discover the tech stack
cat package.json 2>/dev/null | head -40
cat requirements.txt 2>/dev/null

# Find existing tests
find . -name "*.test.*" -o -name "*.spec.*" -o -name "*_test.*" | head -20

# Check for test config
ls playwright.config.* cypress.config.* jest.config.* vitest.config.* 2>/dev/null

# Check test scripts
cat package.json 2>/dev/null | grep -A10 '"scripts"'

Step 2: Choose the Testing Framework

If no e2e framework exists, recommend and set up:

**Playwright (recommended):**

npm init playwright@latest

**Cypress:**

npm install -D cypress

If a framework already exists, use it and follow existing patterns.

Step 3: Identify Test Scenarios

Map critical user flows: 1. **Happy paths** - The main thing users do (sign up, create resource, complete purchase) 2. **Error paths** - Invalid input, network failures, permission denials 3. **Edge cases** - Empty states, max-length inputs, concurrent actions 4. **Cross-browser** - Chrome, Firefox, Safari (if required)

Step 4: Write E2E Tests

Playwright Example

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

test.describe('User Authentication', () => {
  test('should sign up a new user', async ({ page }) => {
    await page.goto('/signup');

    await page.fill('[name="email"]', 'test@example.com');
    await page.fill('[name="password"]', 'SecurePass123!');
    await page.fill('[name="confirmPassword"]', 'SecurePass123!');
    await page.click('button[type="submit"]');

    // Wait for redirect after signup
    await expect(page).toHaveURL('/dashboard');
    await expect(page.locator('h1')).toContainText('Welcome');
  });

  test('should show validation error for weak password', async ({ page }) => {
    await page.goto('/signup');

    await page.fill('[name="email"]', 'test@example.com');
    await page.fill('[name="password"]', '123');
    await page.click('button[type="submit"]');

    await expect(page.locator('.error-message')).toBeVisible();
    await expect(page.locator('.error-message')).toContainText('password');
  });

  test('should log in existing user', async ({ page }) => {
    await page.goto('/login');

    await page.fill('[name="email"]', 'existing@example.com');
    await page.fill('[name="password"]', 'CorrectPassword1!');
    await page.click('button[type="submit"]');

    await expect(page).toHaveURL('/dashboard');
  });
});

API Testing with Playwright

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

test.describe('REST API', () => {
  test('GET /api/users returns list', async ({ request }) => {
    const response = await request.get('/api/users');
    expect(response.ok()).toBeTruthy();

    const body = await response.json();
    expect(Array.isArray(body)).toBe(true);
    expect(body.length).toBeGreaterThan(0);
  });

  test('POST /api/users creates user', async ({ request }) => {
    const response = await request.post('/api/users', {
      data: { name: 'Test User', email: 'new@example.com' }
    });
    expect(response.status()).toBe(201);

    const user = await response.json();
    expect(user.name).toBe('Test User');
  });

  test('POST /api/users rejects duplicate email', async ({ request }) => {
    const response = await request.post('/api/users', {
      data: { name: 'Dup', email: 'existing@example.com' }
    });
    expect(response.status()).toBe(409);
  });
});

Step 5: Add Test Utilities

// fixtures/auth.ts - Reusable authenticated context
import { test as base } from '@playwright/test';

export const test = base.extend({
  authenticatedPage: async ({ page }, use) => {
    await page.goto('/login');
    await page.fill('[name="email"]', 'test@example.com');
    await page.fill('[name="password"]', 'password123');
    await page.click('button[type="submit"]');
    await page.waitForURL('/dashboard');
    await use(page);
  },
});

Step 6: Configure CI

# .github/workflows/e2e.yml
name: E2E Tests
on: [push, pull_request]
jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
      - run: npm ci
      - run: npx playwright install --with-deps
      - run: npm run build
      - run: npx playwright test
      - uses: actions/upload-artifact@v4
        if: always()
        with:
          name: playwright-report
          path: playwright-report/

Step 7: Run and Verify

# Run all tests
npx playwright test

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

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

# Run with UI mode for debugging
npx playwright test --ui

# View test report
npx playwright show-report

Test Writing Best Practices

  • **Use data-testid attributes** for selectors when possible (`[data-testid="submit-btn"]`)
  • **Avoid brittle selectors** like nth-child or exact text that changes frequently
  • **Each test should be independent** - no reliance on test execution order
  • **Use page object pattern** for complex pages with many interactions
  • **Wait for conditions, not time** - use `waitForSelector`, `expect().toBeVisible()` instead of `sleep`
  • **Test real user behavior** - click buttons, fill forms, navigate; don't call internal APIs
  • **Clean up test data** - use beforeEach/afterEach to reset state

Common Patterns

| Scenario | Approach | |----------|----------| | Login required for most tests | Use a fixture that pre-authenticates | | Testing email flows | Use a

Read more
Ships withhermes-desktop

A Windows-native AI agent that lives on your desktop. Chat with it, give it tools, let it learn who you are. Built with WinUI 3 and .NET 10.

Get the whole plugin

Other skills on hermes-desktop.