Testing AI-Generated Code
AI-generated code needs testing more than hand-written code. AI can produce plausible-looking code that fails in subtle ways. Here's how to test effectively.
Why Test AI Code?
- AI doesn't run the code - It can't verify it works
- Hallucinations happen - Non-existent APIs, wrong syntax
- Edge cases are missed - AI optimizes for the happy path
- Integration issues - Generated code may not fit your system
Testing Strategy
The Testing Pyramid for AI Code
/\
/E2E\ <- Fewer, slower, but catch integration issues
/------\
/ Integ. \ <- Test component interactions
/----------\
/ Unit \ <- Many, fast, test individual functions
/--------------\
Unit Testing with Vitest
Setup
npm install -D vitest @testing-library/react @testing-library/jest-dom
// vitest.config.ts
import { defineConfig } from 'vitest/config';
import react from '@vitejs/plugin-react';
export default defineConfig({
plugins: [react()],
test: {
environment: 'jsdom',
globals: true,
setupFiles: './src/test/setup.ts',
},
});
Testing a Utility Function
// utils/format.ts (AI-generated)
export function formatCurrency(amount: number): string {
return new Intl.NumberFormat('en-US', {
style: 'currency',
currency: 'USD',
}).format(amount);
}
// utils/format.test.ts
import { describe, it, expect } from 'vitest';
import { formatCurrency } from './format';
describe('formatCurrency', () => {
it('formats positive numbers', () => {
expect(formatCurrency(1234.56)).toBe('$1,234.56');
});
it('formats zero', () => {
expect(formatCurrency(0)).toBe('$0.00');
});
it('formats negative numbers', () => {
expect(formatCurrency(-50)).toBe('-$50.00');
});
it('handles large numbers', () => {
expect(formatCurrency(1000000)).toBe('$1,000,000.00');
});
// Edge cases AI might miss
it('handles very small decimals', () => {
expect(formatCurrency(0.001)).toBe('$0.00');
});
it('handles NaN', () => {
expect(formatCurrency(NaN)).toBe('NaN');
});
});
Testing React Components
// components/ProjectCard.test.tsx
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { ProjectCard } from './ProjectCard';
const mockProject = {
id: '1',
title: 'Test Project',
description: 'A test project',
bounty: 100,
status: 'open',
};
describe('ProjectCard', () => {
it('renders project information', () => {
render(<ProjectCard project={mockProject} />);
expect(screen.getByText('Test Project')).toBeInTheDocument();
expect(screen.getByText('A test project')).toBeInTheDocument();
expect(screen.getByText('$100')).toBeInTheDocument();
});
it('shows correct status badge', () => {
render(<ProjectCard project={mockProject} />);
expect(screen.getByText('open')).toHaveClass('bg-green-500');
});
it('calls onClick when clicked', async () => {
const handleClick = vi.fn();
render(<ProjectCard project={mockProject} onClick={handleClick} />);
await userEvent.click(screen.getByRole('article'));
expect(handleClick).toHaveBeenCalledWith(mockProject);
});
// Test edge cases
it('handles missing description', () => {
const projectWithoutDesc = { ...mockProject, description: null };
render(<ProjectCard project={projectWithoutDesc} />);
expect(screen.queryByTestId('description')).not.toBeInTheDocument();
});
it('truncates long titles', () => {
const longTitle = 'A'.repeat(100);
render(<ProjectCard project={{ ...mockProject, title: longTitle }} />);
expect(screen.getByText(/A+\.\.\.$/)).toBeInTheDocument();
});
});
Testing Hooks
// hooks/useProjects.test.ts
import { renderHook, waitFor } from '@testing-library/react';
import { useProjects } from './useProjects';
import { createClient } from '@/lib/supabase/client';
vi.mock('@/lib/supabase/client');
describe('useProjects', () => {
it('fetches projects on mount', async () => {
const mockProjects = [{ id: '1', title: 'Test' }];
vi.mocked(createClient).mockReturnValue({
from: () => ({
select: () => ({
eq: () => Promise.resolve({ data: mockProjects, error: null }),
}),
}),
} as any);
const { result } = renderHook(() => useProjects());
expect(result.current.loading).toBe(true);
await waitFor(() => {
expect(result.current.loading).toBe(false);
});
expect(result.current.projects).toEqual(mockProjects);
});
it('handles errors', async () => {
vi.mocked(createClient).mockReturnValue({
from: () => ({
select: () => ({
eq: () => Promise.resolve({ data: null, error: new Error('Failed') }),
}),
}),
} as any);
const { result } = renderHook(() => useProjects());
await waitFor(() => {
expect(result.current.error).toBe('Failed');
});
});
});
Integration Testing
Testing API Routes
// app/api/projects/route.test.ts
import { GET, POST } from './route';
import { createClient } from '@/lib/supabase/server';
vi.mock('@/lib/supabase/server');
describe('Projects API', () => {
describe('GET /api/projects', () => {
it('returns projects for authenticated user', async () => {
vi.mocked(createClient).mockResolvedValue({
auth: { getUser: () => ({ data: { user: { id: '1' } } }) },
from: () => ({
select: () => ({
eq: () => ({ data: [{ id: '1' }], error: null }),
}),
}),
} as any);
const response = await GET();
const data = await response.json();
expect(response.status).toBe(200);
expect(data).toHaveLength(1);
});
it('returns 401 for unauthenticated requests', async () => {
vi.mocked(createClient).mockResolvedValue({
auth: { getUser: () => ({ data: { user: null } }) },
} as any);
const response = await GET();
expect(response.status).toBe(401);
});
});
});
E2E Testing with Playwright
Setup
npm init playwright@latest
Writing E2E Tests
// e2e/auth.spec.ts
import { test, expect } from '@playwright/test';
test.describe('Authentication', () => {
test('user can sign up', async ({ page }) => {
await page.goto('/signup');
await page.fill('[name="email"]', 'test@example.com');
await page.fill('[name="password"]', 'securepassword123');
await page.fill('[name="confirmPassword"]', 'securepassword123');
await page.click('button[type="submit"]');
await expect(page).toHaveURL('/dashboard');
await expect(page.locator('text=Welcome')).toBeVisible();
});
test('shows error for invalid email', async ({ page }) => {
await page.goto('/signup');
await page.fill('[name="email"]', 'invalid-email');
await page.click('button[type="submit"]');
await expect(page.locator('text=Invalid email')).toBeVisible();
});
});
Test Checklist for AI Code
Before shipping AI-generated code, verify:
- [ ] All functions have at least one test
- [ ] Edge cases are covered (null, undefined, empty, large values)
- [ ] Error paths are tested
- [ ] Loading states are tested
- [ ] Integration with other components works
- [ ] API calls are mocked appropriately
- [ ] Types are correct (no
any)
Need help testing your AI-generated code? Post a project on CoderVibez.