Claude
Skills
Sign in
Back

test-specialist

Included with Lifetime
$97 forever

This skill should be used when writing test cases, fixing bugs, analyzing code for potential issues, or improving test coverage for JavaScript/TypeScript applications. Use this for unit tests, integration tests, end-to-end tests, debugging runtime errors, logic bugs, performance issues, security vulnerabilities, and systematic code analysis.

Securityscripts

What this skill does


# Test Specialist

Systematic testing methodologies and debugging techniques for JS/TS applications.

## When to Use

**Use for:**

- Writing unit, integration, or E2E tests
- Fixing bugs and debugging
- Improving test coverage
- Analyzing code for potential issues
- Security and performance testing

**Don't use when:**

- Code review → use `generic-code-reviewer`
- Technical debt → use `tech-debt-analyzer`
- Feature development → use `generic-feature-developer`

## Testing Stack by Project

| Project Type  | Unit Tests  | Component       | E2E        |
| ------------- | ----------- | --------------- | ---------- |
| React/Next.js | Vitest/Jest | Testing Library | Playwright |
| Node.js       | Vitest/Jest | Supertest       | Playwright |
| Static        | Jest        | -               | Playwright |

## Test Patterns

### Unit Tests (AAA Pattern)

```typescript
describe("calculateTotal", () => {
  test("sums amounts correctly", () => {
    // Arrange
    const items = [{ amount: 100 }, { amount: 50 }];
    // Act
    const total = calculateTotal(items);
    // Assert
    expect(total).toBe(150);
  });

  test("handles empty list", () => {
    expect(calculateTotal([])).toBe(0);
  });
});
```

### Component Tests (User Behavior)

```typescript
// ✅ Test user behavior, not implementation
it('creates item when user clicks Add', async () => {
  const user = userEvent.setup();
  render(<ItemList />);

  await user.click(screen.getByRole('button', { name: /add/i }));
  await user.type(screen.getByLabelText(/title/i), 'New item');
  await user.click(screen.getByRole('button', { name: /save/i }));

  expect(screen.getByText('New item')).toBeInTheDocument();
});
```

### E2E Tests (Playwright)

```typescript
import { test, expect } from "@playwright/test";

test("user can complete checkout", async ({ page }) => {
  await page.goto("/products");

  // Add to cart
  await page.click('button:has-text("Add to Cart")');
  await page.click('a:has-text("Cart")');

  // Checkout
  await page.click('button:has-text("Checkout")');
  await page.fill('[name="email"]', "[email protected]");
  await page.click('button:has-text("Place Order")');

  // Verify
  await expect(page.locator("h1")).toContainText("Order Confirmed");
});
```

### Integration Tests

```typescript
test("POST /items creates item", async () => {
  const response = await request(app)
    .post("/api/items")
    .send({ name: "Test" })
    .expect(201);

  expect(response.body).toMatchObject({ id: expect.any(Number) });
});
```

## Bug Analysis Process

1. **Reproduce** - Document exact steps, expected vs actual
2. **Isolate** - Binary search, minimal reproduction
3. **Root Cause** - Trace execution, check assumptions, git blame
4. **Fix** - Write failing test first, implement fix
5. **Validate** - Run full suite, test edge cases

## Debugging Checklist

When debugging an issue:

- [ ] Can reproduce consistently
- [ ] Minimal reproduction created
- [ ] Console/network logs checked
- [ ] State at failure point inspected
- [ ] Git blame checked for recent changes
- [ ] Failing test written before fix

## Common Bug Patterns

### Race Conditions

```typescript
test("handles concurrent updates", async () => {
  const promises = Array.from({ length: 100 }, () => increment());
  await Promise.all(promises);
  expect(getCount()).toBe(100);
});
```

### Null Safety

```typescript
test.each([null, undefined, "", 0])("handles invalid input: %p", (input) => {
  expect(() => process(input)).toThrow("Invalid");
});
```

### Boundary Values

```typescript
test("handles edge cases", () => {
  expect(paginate([], 1, 10)).toEqual([]); // empty
  expect(paginate([item], 1, 10)).toEqual([item]); // single
  expect(paginate(items25, 3, 10)).toHaveLength(5); // partial last page
});
```

## Security Tests

```typescript
test("prevents SQL injection", async () => {
  const malicious = "'; DROP TABLE users; --";
  await expect(search(malicious)).resolves.not.toThrow();
});

test("sanitizes XSS", () => {
  const xss = '<script>alert("xss")</script>';
  expect(sanitize(xss)).not.toContain("<script>");
});

test("requires auth", async () => {
  await request(app).post("/api/items").expect(401);
});
```

## Performance Tests

```typescript
test("handles large datasets efficiently", () => {
  const largeList = Array.from({ length: 10000 }, (_, i) => ({ value: i }));
  const start = performance.now();
  process(largeList);
  expect(performance.now() - start).toBeLessThan(100);
});
```

## Coverage Targets

| Code Type      | Target |
| -------------- | ------ |
| Critical paths | 90%+   |
| Business logic | 85%+   |
| UI components  | 75%+   |
| Utilities      | 70%+   |

## Test Quality Principles

1. **One behavior per test**
2. **Descriptive names** - test names explain scenario
3. **Independent tests** - no shared state
4. **Cover edge cases** - null, empty, boundaries, errors
5. **Mock external deps** - tests should be fast
6. **Test behavior** - not implementation details

## Workflow Decision Tree

| Situation          | Action                               |
| ------------------ | ------------------------------------ |
| Adding feature     | Write test first (TDD)               |
| Fixing bug         | Write failing test, then fix         |
| Improving coverage | Find gaps, prioritize critical paths |
| Code review        | Check edge cases, error handling     |

---

## Python Testing (pytest)

### Fixtures and Parametrize

```python
import pytest
from myapp.services import UserService

@pytest.fixture
def user_service(db_session):
    """Provide a UserService with test database."""
    return UserService(session=db_session)

@pytest.fixture
def sample_user(user_service):
    """Create and return a sample user."""
    return user_service.create(name="Test User", email="[email protected]")

class TestUserService:
    def test_create_user(self, user_service):
        user = user_service.create(name="John", email="[email protected]")
        assert user.name == "John"
        assert user.id is not None

    def test_get_user_not_found(self, user_service):
        with pytest.raises(UserNotFoundError, match="User 999 not found"):
            user_service.get(999)

    @pytest.mark.parametrize("email,is_valid", [
        ("[email protected]", True),
        ("[email protected]", True),
        ("invalid", False),
        ("@example.com", False),
        ("", False),
    ])
    def test_validate_email(self, user_service, email: str, is_valid: bool):
        assert user_service.validate_email(email) == is_valid
```

### Mocking

```python
from unittest.mock import Mock, patch, AsyncMock

def test_send_notification(user_service):
    with patch("myapp.services.email_client") as mock_email:
        mock_email.send = Mock(return_value=True)
        user_service.notify(user_id=1, message="Hello")
        mock_email.send.assert_called_once_with(
            to="[email protected]",
            body="Hello",
        )

# Async mocking
@pytest.mark.asyncio
async def test_fetch_data():
    with patch("myapp.client.fetch", new_callable=AsyncMock) as mock_fetch:
        mock_fetch.return_value = {"status": "ok"}
        result = await process_data()
        assert result["status"] == "ok"
```

### conftest.py Patterns

```python
# tests/conftest.py
import pytest
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker

@pytest.fixture(scope="session")
def engine():
    return create_engine("sqlite:///:memory:")

@pytest.fixture(scope="function")
def db_session(engine):
    Base.metadata.create_all(engine)
    Session = sessionmaker(bind=engine)
    session = Session()
    yield session
    session.rollback()
    session.close()
    Base.metadata.drop_all(engine)
```

---

## Go Testing

### Table-Driven Tests

```go
func TestCalculateDiscount(t *testing.T) {
    tests := []struct {
        name     string
        amount   float64
        code     string
        want     float64
        wantErr  bool
    }{
        {
    
Files: 7
Size: 46.3 KB
Complexity: 66/100
Category: Security

Related in Security