Files
Kunthawat Greethong 7edf5bc4d0 feat: Import 35+ skills, merge duplicates, add openclaw installer
Major updates:
- Added 35+ new skills from awesome-opencode-skills and antigravity repos
- Merged SEO skills into seo-master
- Merged architecture skills into architecture
- Merged security skills into security-auditor and security-coder
- Merged testing skills into testing-master and testing-patterns
- Merged pentesting skills into pentesting
- Renamed website-creator to thai-frontend-dev
- Replaced skill-creator with github version
- Removed Chutes references (use MiniMax API instead)
- Added install-openclaw-skills.sh for cross-platform installation
- Updated .env.example with MiniMax API credentials
2026-03-26 11:37:39 +07:00

7.4 KiB

name, description
name description
testing-master Master testing skill combining TDD, E2E testing, Playwright, and webapp testing. Use when writing tests, setting up testing infrastructure, or fixing failing tests.

Testing Master

Comprehensive testing skill combining: TDD, E2E testing, Playwright, webapp testing, and testing patterns.


Quick Reference

Task Use Section
Write tests first TDD
E2E browser tests E2E Testing
Playwright automation Playwright
Fix failing tests Test Fixing
Generate unit tests Unit Testing
Web app testing Webapp Testing

Test-Driven Development (TDD)

Core Principle

"Write the test first. Watch it fail. Write minimal code to pass."

The Iron Law

NO PRODUCTION CODE WITHOUT A FAILING TEST FIRST

TDD Cycle (Red-Green-Refactor)

  1. RED - Write a failing test
  2. GREEN - Write minimal code to pass
  3. REFACTOR - Improve code while keeping tests passing

When to Use TDD

  • New features
  • Bug fixes
  • Refactoring
  • Behavior changes
  • Throwaway prototypes
  • Generated code
  • Configuration files

Example: TDD Cycle

// 1. RED - Write failing test
describe('Calculator', () => {
  it('should add two numbers', () => {
    const calc = new Calculator();
    expect(calc.add(2, 3)).toBe(5);
  });
});

// 2. GREEN - Minimal implementation
class Calculator {
  add(a, b) {
    return a + b;
  }
}

// 3. REFACTOR - Improve (if needed)

Test Naming Conventions

describe('UserService', () => {
  it('should return null for non-existent user', () => {});
  it('should hash password before storing', () => {});
  it('should throw ValidationError for invalid email', () => {});
});

E2E Testing

Playwright Setup

npm init playwright@latest
npx playwright install chromium

Basic Test Structure

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

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

  test('should login with valid credentials', async ({ page }) => {
    await page.fill('[name="email"]', 'user@example.com');
    await page.fill('[name="password"]', 'password123');
    await page.click('[type="submit"]');
    await expect(page).toHaveURL('/dashboard');
  });

  test('should show error for invalid credentials', async ({ page }) => {
    await page.fill('[name="email"]', 'invalid@example.com');
    await page.fill('[name="password"]', 'wrong');
    await page.click('[type="submit"]');
    await expect(page.locator('.error')).toContainText('Invalid credentials');
  });
});

Page Object Model

// pages/LoginPage.js
class LoginPage {
  constructor(page) {
    this.page = page;
    this.emailInput = page.locator('[name="email"]');
    this.passwordInput = page.locator('[name="password"]');
    this.submitButton = page.locator('[type="submit"]');
  }

  async login(email, password) {
    await this.emailInput.fill(email);
    await this.passwordInput.fill(password);
    await this.submitButton.click();
  }
}

// test.js
test('login', async ({ page }) => {
  const loginPage = new LoginPage(page);
  await loginPage.login('user@example.com', 'password123');
});

Visual Regression Testing

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

test('homepage visual regression', async ({ page }) => {
  await page.goto('/');
  const screenshot = await page.screenshot();
  expect(screenshot).toMatchSnapshot('homepage.png');
});

Cross-Browser Testing

test.describe('Browser Compatibility', () => {
  test('works on Chrome', async ({ browserName }) => {
    test.skip(browserName !== 'chromium', 'Skip on non-Chrome');
    // Chrome-specific test
  });
});

Playwright Testing

Locators (Priority Order)

  1. role - getByRole('button', { name: 'Submit' })
  2. label - getByLabel('Email')
  3. placeholder - getByPlaceholder('Enter email')
  4. text - getByText('Sign in')
  5. testid - getByTestId('submit-btn')
  6. CSS - locator('.submit')
  7. XPath - locator('//button[@type="submit"]')

Common Actions

// Click
await page.click('button');

// Fill input
await page.fill('input[name="email"]', 'test@example.com');

// Select
await page.selectOption('select', 'Option 1');

// Checkbox
await page.check('input[type="checkbox"]');

// Hover
await page.hover('.dropdown');

// Drag and drop
await page.dragAndDrop('.source', '.target');

Assertions

expect(locator).toBeVisible()
expect(locator).toBeHidden()
expect(locator).toBeEnabled()
expect(locator).toBeDisabled()
expect(locator).toHaveText('expected')
expect(locator).toContainText('partial')
expect(locator).toHaveValue('value')
expect(locator).toHaveCount(5)
expect(page).toHaveURL('**/dashboard')
expect(page).toHaveTitle('Dashboard')

Network Interception

await page.route('**/api/**', route => {
  route.fulfill({
    status: 200,
    body: JSON.stringify({ data: 'mocked' }),
  });
});

File Upload

await page.setInputFiles('input[type="file"]', 'path/to/file.pdf');

Webapp Testing

Test Coverage Checklist

  • Homepage loads
  • Navigation works
  • Forms submit correctly
  • Validation messages appear
  • Error states handled
  • Loading states work
  • Authentication flows
  • Responsive design
  • Accessibility (a11y)
  • Performance

Accessibility Testing

test('accessibility check', async ({ page }) => {
  await page.goto('/');
  
  // Check for accessibility violations
  const violations = await new AxeBuilder({ page }).analyze();
  expect(violations.length).toBe(0);
});

Mobile Testing

test('mobile responsive', async ({ page }) => {
  await page.setViewportSize({ width: 375, height: 667 });
  await page.goto('/');
  // Mobile-specific assertions
});

API Testing

test('API integration', async ({ request }) => {
  const response = await request.get('https://api.example.com/users');
  expect(response.status()).toBe(200);
  expect(response.ok()).toBeTruthy();
});

Test Fixing

Debugging Failing Tests

  1. Read the error - What is it saying?
  2. Check the test - Is it testing the right thing?
  3. Check the code - Is the implementation correct?
  4. Check the mocks - Are they set up correctly?
  5. Check the data - Is the test data valid?

Common Issues

Issue Solution
Flaky tests Add retries, stabilize timing
Race conditions Add waits, use explicit conditions
Environment differences Use Docker, consistent setup
Data dependencies Use fixtures, clean state

Test Isolation

// Bad - shared state
let user;
test('creates user', () => { user = createUser(); });
test('modifies user', () => { modifyUser(user.id); });

// Good - isolated
test('creates and modifies user', () => {
  const user = createUser();
  modifyUser(user.id);
  // assertions
});

Best Practices

  1. AAA Pattern - Arrange, Act, Assert
  2. One Assertion - Per test when possible
  3. Descriptive Names - it('should return 404 for missing resource')
  4. Fast Tests - Mock external dependencies
  5. Independent Tests - No order dependency
  6. Real Data - Don't over-mock
  7. Coverage - Aim for meaningful coverage, not 100%