Agent skill
testing-framework-helper
Generates comprehensive test suites with unit tests, integration tests, and E2E tests for various frameworks (Jest, Pytest, Vitest, etc.). Use when writing tests.
Install this agent skill to your Project
npx add-skill https://github.com/Dexploarer/claudius-skills/tree/main/examples/intermediate/framework-skills/testing-framework-helper
SKILL.md
Testing Framework Helper Skill
Expert at creating comprehensive test suites following testing best practices.
When to Activate
- "write tests for [component/function]"
- "create test suite for [feature]"
- "generate unit/integration/E2E tests"
Jest/Vitest (JavaScript/TypeScript)
// UserService.test.ts
import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
import { UserService } from './UserService';
import { mockDatabase } from '../test-utils/mockDatabase';
describe('UserService', () => {
let userService: UserService;
let db: ReturnType<typeof mockDatabase>;
beforeEach(() => {
db = mockDatabase();
userService = new UserService(db);
});
afterEach(() => {
vi.clearAllMocks();
});
describe('getById', () => {
it('should return user when found', async () => {
const mockUser = {
id: 1,
name: 'John Doe',
email: 'john@example.com',
};
db.user.findUnique.mockResolvedValue(mockUser);
const result = await userService.getById(1);
expect(result).toEqual(mockUser);
expect(db.user.findUnique).toHaveBeenCalledWith({
where: { id: 1 },
});
});
it('should return null when user not found', async () => {
db.user.findUnique.mockResolvedValue(null);
const result = await userService.getById(999);
expect(result).toBeNull();
});
it('should throw error on database failure', async () => {
db.user.findUnique.mockRejectedValue(new Error('DB Error'));
await expect(userService.getById(1)).rejects.toThrow('DB Error');
});
});
describe('create', () => {
it('should create user with valid data', async () => {
const userData = {
name: 'Jane Doe',
email: 'jane@example.com',
password: 'SecurePass123!',
};
const createdUser = {
id: 2,
...userData,
password: 'hashed_password',
};
db.user.create.mockResolvedValue(createdUser);
const result = await userService.create(userData);
expect(result).toEqual(createdUser);
expect(db.user.create).toHaveBeenCalledWith({
data: expect.objectContaining({
name: userData.name,
email: userData.email,
}),
});
});
it('should throw error when email exists', async () => {
const userData = {
name: 'John Doe',
email: 'existing@example.com',
password: 'pass123',
};
db.user.findUnique.mockResolvedValue({ id: 1 });
await expect(userService.create(userData)).rejects.toThrow(
'Email already exists'
);
});
});
});
React Testing Library
// UserList.test.tsx
import { render, screen, fireEvent, waitFor } from '@testing-library/react';
import { UserList } from './UserList';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
const mockUsers = [
{ id: 1, name: 'Alice', email: 'alice@test.com' },
{ id: 2, name: 'Bob', email: 'bob@test.com' },
];
const createWrapper = () => {
const queryClient = new QueryClient({
defaultOptions: { queries: { retry: false } },
});
return ({ children }) => (
<QueryClientProvider client={queryClient}>
{children}
</QueryClientProvider>
);
};
describe('UserList', () => {
beforeEach(() => {
global.fetch = vi.fn();
});
it('renders loading state initially', () => {
(global.fetch as any).mockImplementation(() => new Promise(() => {}));
render(<UserList />, { wrapper: createWrapper() });
expect(screen.getByText(/loading/i)).toBeInTheDocument();
});
it('renders user list after loading', async () => {
(global.fetch as any).mockResolvedValueOnce({
ok: true,
json: async () => mockUsers,
});
render(<UserList />, { wrapper: createWrapper() });
await waitFor(() => {
expect(screen.getByText('Alice')).toBeInTheDocument();
expect(screen.getByText('Bob')).toBeInTheDocument();
});
});
it('handles search functionality', async () => {
render(<UserList />, { wrapper: createWrapper() });
const searchInput = screen.getByPlaceholderText(/search/i);
fireEvent.change(searchInput, { target: { value: 'Alice' } });
await waitFor(() => {
expect(global.fetch).toHaveBeenCalledWith(
expect.stringContaining('search=Alice')
);
});
});
it('handles error state', async () => {
(global.fetch as any).mockRejectedValueOnce(new Error('API Error'));
render(<UserList />, { wrapper: createWrapper() });
await waitFor(() => {
expect(screen.getByText(/error/i)).toBeInTheDocument();
});
});
});
Pytest (Python)
# test_user_service.py
import pytest
from unittest.mock import Mock, patch, AsyncMock
from app.services.user_service import UserService
from app.models.user import User
from app.exceptions import ValidationError, NotFoundError
@pytest.fixture
def user_service():
"""Fixture for UserService instance"""
return UserService()
@pytest.fixture
def mock_user():
"""Fixture for mock user data"""
return User(
id=1,
email="test@example.com",
name="Test User",
role="user"
)
class TestUserService:
@pytest.mark.asyncio
async def test_get_by_id_success(self, user_service, mock_user):
"""Test getting user by ID successfully"""
with patch.object(User, 'get', return_value=mock_user) as mock_get:
result = await user_service.get_by_id(1)
assert result == mock_user
mock_get.assert_called_once_with(id=1)
@pytest.mark.asyncio
async def test_get_by_id_not_found(self, user_service):
"""Test getting non-existent user"""
with patch.object(User, 'get', return_value=None):
with pytest.raises(NotFoundError, match="User not found"):
await user_service.get_by_id(999)
@pytest.mark.asyncio
async def test_create_success(self, user_service):
"""Test creating user successfully"""
user_data = {
"email": "new@example.com",
"name": "New User",
"password": "SecurePass123!"
}
with patch.object(User, 'create', return_value=Mock(id=2)) as mock_create:
result = await user_service.create(user_data)
assert result.id == 2
mock_create.assert_called_once()
@pytest.mark.asyncio
async def test_create_duplicate_email(self, user_service, mock_user):
"""Test creating user with existing email"""
user_data = {
"email": "existing@example.com",
"name": "Test",
"password": "pass123"
}
with patch.object(User, 'get_by_email', return_value=mock_user):
with pytest.raises(ValidationError, match="Email already exists"):
await user_service.create(user_data)
@pytest.mark.parametrize("email,valid", [
("valid@example.com", True),
("invalid-email", False),
("", False),
("test@test", False),
])
def test_validate_email(self, user_service, email, valid):
"""Test email validation with various inputs"""
if valid:
user_service.validate_email(email)
else:
with pytest.raises(ValidationError):
user_service.validate_email(email)
Integration Tests
// user.integration.test.ts
import request from 'supertest';
import { app } from '../app';
import { setupTestDB, cleanupTestDB, seedTestData } from '../test-utils';
describe('User API Integration Tests', () => {
let authToken: string;
beforeAll(async () => {
await setupTestDB();
const seedData = await seedTestData();
authToken = seedData.adminToken;
});
afterAll(async () => {
await cleanupTestDB();
});
describe('GET /api/users', () => {
it('should return paginated users', async () => {
const response = await request(app)
.get('/api/users')
.set('Authorization', `Bearer ${authToken}`)
.query({ page: 1, limit: 10 })
.expect(200);
expect(response.body).toHaveProperty('users');
expect(response.body).toHaveProperty('meta');
expect(Array.isArray(response.body.users)).toBe(true);
expect(response.body.meta).toMatchObject({
page: 1,
limit: 10,
});
});
it('should require authentication', async () => {
await request(app)
.get('/api/users')
.expect(401);
});
});
describe('POST /api/users', () => {
it('should create new user with valid data', async () => {
const userData = {
name: 'New User',
email: 'newuser@test.com',
password: 'SecurePass123!',
};
const response = await request(app)
.post('/api/users')
.send(userData)
.expect(201);
expect(response.body.data).toMatchObject({
name: userData.name,
email: userData.email,
});
expect(response.body.data).not.toHaveProperty('password');
});
it('should reject invalid email', async () => {
const userData = {
name: 'Test',
email: 'invalid-email',
password: 'pass123',
};
const response = await request(app)
.post('/api/users')
.send(userData)
.expect(400);
expect(response.body).toHaveProperty('error');
});
});
});
E2E Tests (Playwright/Cypress)
// e2e/user-management.spec.ts
import { test, expect } from '@playwright/test';
test.describe('User Management', () => {
test.beforeEach(async ({ page }) => {
await page.goto('/login');
await page.fill('[name="email"]', 'admin@test.com');
await page.fill('[name="password"]', 'admin123');
await page.click('button[type="submit"]');
await expect(page).toHaveURL('/dashboard');
});
test('should display user list', async ({ page }) => {
await page.goto('/users');
await expect(page.locator('h1')).toContainText('Users');
await expect(page.locator('[data-testid="user-row"]')).toHaveCount(10);
});
test('should create new user', async ({ page }) => {
await page.goto('/users');
await page.click('[data-testid="add-user-button"]');
await page.fill('[name="name"]', 'Test User');
await page.fill('[name="email"]', 'test@example.com');
await page.fill('[name="password"]', 'SecurePass123!');
await page.click('[data-testid="submit-button"]');
await expect(page.locator('.success-message')).toBeVisible();
await expect(page.locator('text=Test User')).toBeVisible();
});
test('should search users', async ({ page }) => {
await page.goto('/users');
await page.fill('[data-testid="search-input"]', 'Alice');
await page.waitForLoadState('networkidle');
const rows = page.locator('[data-testid="user-row"]');
await expect(rows).toHaveCount(1);
await expect(rows.first()).toContainText('Alice');
});
});
Best Practices
- Follow AAA pattern (Arrange, Act, Assert)
- Use descriptive test names
- Test edge cases and error conditions
- Mock external dependencies
- Use fixtures for test data
- Clean up after tests
- Test both happy and unhappy paths
- Use parameterized tests for similar cases
- Maintain test independence
- Keep tests fast
- Use proper assertion libraries
- Test accessibility
- Use test coverage tools
- Avoid test interdependence
Output Checklist
- ✅ Test file created
- ✅ Setup/teardown configured
- ✅ Unit tests written
- ✅ Integration tests (if needed)
- ✅ E2E tests (if needed)
- ✅ Mocks/fixtures created
- ✅ Edge cases covered
- 📝 Test documentation
Recommended Agent Skills
Expand your agent's capabilities with these related and highly-rated skills.
smart-contract-generator
Generates Solidity smart contracts with security best practices (ERC-20, ERC-721, ERC-1155, custom). Use when user asks to "create smart contract", "solidity contract", "erc20 token", "nft contract", or "web3 contract".
threejs-scene-builder
Comprehensive Three.js and React Three Fiber skill for creating 3D scenes, characters, NPCs, procedural generation, animation retargeting, and interactive experiences. Use when user asks to "create Three.js scene", "setup React Three Fiber", "add 3D character", "create NPC AI", "procedural 3D generation", "retarget animation", "setup avatar system", or "create 3D game".
wcag-compliance-checker
Checks websites for WCAG 2.1 Level AA compliance, identifies accessibility violations, and provides remediation guidance. Use when user asks to "check accessibility", "wcag compliance", "a11y audit", "accessibility violations", or "screen reader testing".
kubernetes-manifest-generator
Generates Kubernetes manifests (Deployments, Services, Ingress, ConfigMaps, Secrets) with best practices for production workloads. Use when user asks to "create k8s manifest", "generate Kubernetes deployment", "setup k8s service", or "create Kubernetes resources".
terraform-module-builder
Generates reusable Terraform modules with best practices for AWS, Azure, GCP infrastructure as code. Use when user asks to "create Terraform module", "generate IaC module", "setup Terraform", or "create infrastructure module".
translation-key-extractor
Extracts hardcoded strings from code and converts them to translation keys for i18n. Use when user asks to "extract translations", "find hardcoded strings", "internationalize code", "setup i18n", or "create translation files".
Didn't find tool you were looking for?