testing-server-actions
Testing Server Actions
For Vitest mocking patterns (vi.mock(), vi.fn(), mockResolvedValue), see vitest-4/skills/writing-vitest-tests/SKILL.md.
Basic Server Action Test
import { submitContact } from './actions';
test('submitContact validates email', async () => {
const formData = new FormData();
formData.set('email', 'invalid');
formData.set('message', 'Hello');
const result = await submitContact(null, formData);
expect(result.error).toBeTruthy();
});
test('submitContact succeeds with valid data', async () => {
const formData = new FormData();
formData.set('email', 'test@example.com');
formData.set('message', 'Hello');
const result = await submitContact(null, formData);
expect(result.success).toBe(true);
});
Mocking Database Calls
import { createUser } from './actions';
import { db } from './db';
vi.mock('./db', () => ({
db: {
users: {
create: vi.fn(),
},
},
}));
test('createUser creates database record', async () => {
db.users.create.mockResolvedValue({ id: '123', name: 'Alice' });
const formData = new FormData();
formData.set('name', 'Alice');
formData.set('email', 'alice@example.com');
const result = await createUser(null, formData);
expect(db.users.create).toHaveBeenCalledWith({
name: 'Alice',
email: 'alice@example.com',
});
expect(result.success).toBe(true);
expect(result.userId).toBe('123');
});
Testing with Authentication
import { deletePost } from './actions';
import { getSession } from './auth';
vi.mock('./auth');
test('deletePost requires authentication', async () => {
getSession.mockResolvedValue(null);
await expect(deletePost('post-123')).rejects.toThrow('Unauthorized');
});
test('deletePost checks ownership', async () => {
getSession.mockResolvedValue({ user: { id: 'user-1' } });
await expect(deletePost('post-owned-by-user-2')).rejects.toThrow('Forbidden');
});
For comprehensive Server Action testing, test the function directly in isolation.
References
- @vitest-4/skills/writing-vitest-tests - Mocking and spy patterns
More from djankies/claude-configs
optimizing-with-react-compiler
Teaches what React Compiler handles automatically in React 19, reducing need for manual memoization. Use when optimizing performance or deciding when to use useMemo/useCallback.
16reviewing-prisma-patterns
Review Prisma code for common violations, security issues, and performance anti-patterns found in AI coding agent stress testing. Use when reviewing Prisma Client usage, database operations, or performing code reviews on projects using Prisma ORM.
8migrating-from-v3
Migrate from Tailwind CSS v3 to v4 including configuration migration (JS to CSS), utility renames, opacity changes, and color system updates. Use when upgrading existing projects to v4.
6implementing-query-pagination
Implement cursor-based or offset pagination for Prisma queries. Use for datasets 100k+, APIs with page navigation, or infinite scroll/pagination mentions.
5using-reducers
Teaches useReducer for complex state logic in React 19. Use when state updates depend on previous state, multiple related state values, or complex update logic.
5implementing-code-splitting
Teaches code splitting with lazy() and Suspense in React 19 for reducing initial bundle size. Use when implementing lazy loading, route-based splitting, or optimizing performance.
5