test(web): increase frontend test coverage to ~70% page coverage

- Fix vitest config to include [locale] directory tests (was excluded)
- Fix register.spec.tsx: use getByRole('heading') to avoid duplicate text match
- Fix search.spec.tsx: add QueryClientProvider wrapper and mock saved searches hook
- Add 12 new page test files covering dashboard, admin, public, and OAuth pages:
  - dashboard (main, profile, payments, subscription, KYC)
  - admin (dashboard, users)
  - public (landing, pricing)
  - analytics
  - OAuth callbacks (Google, Zalo)
- 29 test files, 174 tests, 16/23 pages covered (69.6%)

Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
Ho Ngoc Hai
2026-04-10 23:14:16 +07:00
parent d62eb5f164
commit 68b65cb848
15 changed files with 1122 additions and 7 deletions

View File

@@ -106,9 +106,28 @@ vi.mock('@/lib/listings-api', () => ({
},
}));
vi.mock('@/lib/hooks/use-saved-searches', () => ({
useCreateSavedSearch: () => ({
mutateAsync: vi.fn(),
isPending: false,
}),
useSavedSearches: () => ({ data: [], isLoading: false }),
}));
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { listingsApi } from '@/lib/listings-api';
import SearchPage from '../page';
const queryClient = new QueryClient({
defaultOptions: { queries: { retry: false } },
});
function Wrapper({ children }: { children: React.ReactNode }) {
return (
<QueryClientProvider client={queryClient}>{children}</QueryClientProvider>
);
}
const mockedListingsApi = vi.mocked(listingsApi);
describe('SearchPage', () => {
@@ -118,7 +137,7 @@ describe('SearchPage', () => {
});
it('renders the search page title', async () => {
render(<SearchPage />);
render(<SearchPage />, { wrapper: Wrapper });
await waitFor(() => {
expect(screen.getByText('Tìm kiếm bất động sản')).toBeInTheDocument();
@@ -126,7 +145,7 @@ describe('SearchPage', () => {
});
it('renders view mode toggle buttons', async () => {
render(<SearchPage />);
render(<SearchPage />, { wrapper: Wrapper });
await waitFor(() => {
expect(screen.getByRole('button', { name: /danh sách/i })).toBeInTheDocument();
@@ -135,7 +154,7 @@ describe('SearchPage', () => {
});
it('calls listings API on mount', async () => {
render(<SearchPage />);
render(<SearchPage />, { wrapper: Wrapper });
await waitFor(() => {
expect(mockedListingsApi.search).toHaveBeenCalled();
@@ -143,7 +162,7 @@ describe('SearchPage', () => {
});
it('displays listing results after loading', async () => {
render(<SearchPage />);
render(<SearchPage />, { wrapper: Wrapper });
await waitFor(() => {
expect(screen.getByText(/căn hộ quận 7/i)).toBeInTheDocument();
@@ -151,7 +170,7 @@ describe('SearchPage', () => {
});
it('switches to map view when map button is clicked', async () => {
render(<SearchPage />);
render(<SearchPage />, { wrapper: Wrapper });
await waitFor(() => {
expect(screen.getByRole('button', { name: /bản đồ/i })).toBeInTheDocument();