Frontend Testing Guide
BonardaHR uses Vitest paired with React Testing Library (@testing-library/react) and @testing-library/jest-dom for automated unit and component testing.
Running Tests​
# Run all tests once
npm run test
# Run tests in interactive watch mode
npm run test:watch
Testing Patterns & Examples​
1. Component Testing​
// src/shared/components/ui/Button.test.tsx
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { describe, it, expect, vi } from 'vitest';
import Button from './Button';
describe('Button Component', () => {
it('renders children correctly', () => {
render(<Button>Click Me</Button>);
expect(screen.getByRole('button', { name: /click me/i })).toBeInTheDocument();
});
it('triggers onClick handler when clicked', async () => {
const handleClick = vi.fn();
const user = userEvent.setup();
render(<Button onClick={handleClick}>Submit</Button>);
await user.click(screen.getByRole('button'));
expect(handleClick).toHaveBeenCalledTimes(1);
});
it('disables button when isLoading is true', () => {
render(<Button isLoading>Submit</Button>);
expect(screen.getByRole('button')).toBeDisabled();
});
});
2. Testing Custom React Query Hooks​
When testing custom hooks that consume React Query, wrap the test harness inside a QueryClientProvider:
import { renderHook, waitFor } from '@testing-library/react';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { useEmployees } from './useEmployees';
import { employeeService } from '../services/employeeService';
import { vi, describe, it, expect } from 'vitest';
const createWrapper = () => {
const queryClient = new QueryClient({
defaultOptions: { queries: { retry: false } },
});
return ({ children }: { children: React.ReactNode }) => (
<QueryClientProvider client={queryClient}>{children}</QueryClientProvider>
);
};
describe('useEmployees hook', () => {
it('fetches employees successfully', async () => {
const mockEmployees = [{ id: '1', name: 'John Doe' }];
vi.spyOn(employeeService, 'getAll').mockResolvedValue(mockEmployees as any);
const { result } = renderHook(() => useEmployees({}), {
wrapper: createWrapper(),
});
await waitFor(() => expect(result.current.isSuccess).toBe(true));
expect(result.current.data).toEqual(mockEmployees);
});
});