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
This commit is contained in:
313
skills/testing-master/SKILL.md
Normal file
313
skills/testing-master/SKILL.md
Normal file
@@ -0,0 +1,313 @@
|
||||
---
|
||||
name: testing-master
|
||||
description: |
|
||||
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
|
||||
```javascript
|
||||
// 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
|
||||
```javascript
|
||||
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
|
||||
```bash
|
||||
npm init playwright@latest
|
||||
npx playwright install chromium
|
||||
```
|
||||
|
||||
### Basic Test Structure
|
||||
```javascript
|
||||
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
|
||||
```javascript
|
||||
// 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
|
||||
```javascript
|
||||
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
|
||||
```javascript
|
||||
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
|
||||
```javascript
|
||||
// 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
|
||||
```javascript
|
||||
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
|
||||
```javascript
|
||||
await page.route('**/api/**', route => {
|
||||
route.fulfill({
|
||||
status: 200,
|
||||
body: JSON.stringify({ data: 'mocked' }),
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
### File Upload
|
||||
```javascript
|
||||
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
|
||||
```javascript
|
||||
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
|
||||
```javascript
|
||||
test('mobile responsive', async ({ page }) => {
|
||||
await page.setViewportSize({ width: 375, height: 667 });
|
||||
await page.goto('/');
|
||||
// Mobile-specific assertions
|
||||
});
|
||||
```
|
||||
|
||||
### API Testing
|
||||
```javascript
|
||||
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
|
||||
```javascript
|
||||
// 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%
|
||||
Reference in New Issue
Block a user