--- description: globs: alwaysApply: false --- # Testing Guidelines ## Test Structure (AAA Pattern) ```typescript describe('UserService', () => { describe('when getting user by ID', () => { it('should return user data for valid ID', async () => { // Arrange const userId = '123'; const expectedUser = { id: '123', name: 'John' }; mockUserRepository.findById.mockResolvedValue(expectedUser); // Act const result = await userService.getUserById(userId); // Assert expect(result).toEqual(expectedUser); }); }); }); ``` ## React Component Testing ```typescript // ✅ Test user behavior, not implementation describe('LoginForm', () => { it('should display error message for invalid credentials', async () => { const mockOnSubmit = jest.fn().mockRejectedValue(new Error('Invalid credentials')); render(); await user.type(screen.getByLabelText(/email/i), 'invalid@example.com'); await user.type(screen.getByLabelText(/password/i), 'wrongpassword'); await user.click(screen.getByRole('button', { name: /sign in/i })); expect(await screen.findByText(/invalid credentials/i)).toBeInTheDocument(); }); }); ``` ## Mocking Patterns ```typescript // ✅ Service mocking const mockEmailService = { sendEmail: jest.fn().mockResolvedValue({ success: true }), validateEmail: jest.fn().mockReturnValue(true), }; // ✅ Test data factories const createTestUser = (overrides = {}) => ({ id: uuid(), email: 'test@example.com', name: 'Test User', ...overrides, }); beforeEach(() => { jest.clearAllMocks(); }); ``` ## Testing Principles - **Test behavior, not implementation** - Focus on what users see/do - **Use descriptive test names** - "should [behavior] when [condition]" - **Query by user-visible elements** - text, roles, labels over test IDs - **Keep tests isolated** - Independent and repeatable - **70% unit, 20% integration, 10% E2E** - Test pyramid ## Common Patterns ```typescript // Async testing await waitFor(() => { expect(screen.getByText('Loading...')).not.toBeInTheDocument(); }); // User interactions await user.click(screen.getByRole('button')); await user.type(screen.getByLabelText(/search/i), 'query'); // API integration tests const response = await request(app) .post('/api/users') .send(userData) .expect(201); ```