Files
TREK/client/src/pages/FilesPage.test.tsx
T
Isaias Tavares ecbb1de8de test: update tests to use English translation strings
Tests were asserting against hardcoded German strings that were replaced
with t() calls. Updated to match the English translation values rendered
by TranslationProvider in the test environment.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-12 16:46:03 -03:00

212 lines
6.8 KiB
TypeScript

import React from 'react';
import { describe, it, expect, beforeEach, vi } from 'vitest';
import { render, screen, waitFor, act } from '../../tests/helpers/render';
import { Route, Routes } from 'react-router-dom';
import { http, HttpResponse } from 'msw';
import { server } from '../../tests/helpers/msw/server';
import { resetAllStores, seedStore } from '../../tests/helpers/store';
import { buildUser, buildTrip, buildTripFile } from '../../tests/helpers/factories';
import { useAuthStore } from '../store/authStore';
import { useTripStore } from '../store/tripStore';
import FilesPage from './FilesPage';
vi.mock('../components/Files/FileManager', () => ({
default: ({ files }: { files: unknown[]; onUpload: unknown; onDelete: unknown }) =>
React.createElement('div', { 'data-testid': 'file-manager' }, `${files.length} files`),
}));
vi.mock('../components/Layout/Navbar', () => ({
default: ({ tripTitle }: { tripTitle?: string }) =>
React.createElement('nav', { 'data-testid': 'navbar' }, tripTitle),
}));
function renderFilesPage(tripId: number | string = 1) {
return render(
<Routes>
<Route path="/trips/:id/files" element={<FilesPage />} />
</Routes>,
{ initialEntries: [`/trips/${tripId}/files`] },
);
}
beforeEach(() => {
vi.clearAllMocks();
resetAllStores();
seedStore(useAuthStore, { isAuthenticated: true, user: buildUser() });
seedStore(useTripStore, {
files: [],
loadFiles: vi.fn().mockResolvedValue(undefined),
addFile: vi.fn().mockResolvedValue(undefined),
deleteFile: vi.fn().mockResolvedValue(undefined),
} as any);
});
describe('FilesPage', () => {
describe('FE-PAGE-FILES-001: Loading spinner shown while data fetches', () => {
it('shows a spinner while data is loading', async () => {
server.use(
http.get('/api/trips/:id', async () => {
await new Promise(resolve => setTimeout(resolve, 200));
const trip = buildTrip({ id: 1 });
return HttpResponse.json({ trip });
}),
);
renderFilesPage(1);
expect(document.querySelector('.animate-spin')).toBeInTheDocument();
});
});
describe('FE-PAGE-FILES-002: Trip name displayed in Navbar after load', () => {
it('passes the trip name to Navbar after data loads', async () => {
const trip = buildTrip({ id: 1, name: 'Rome Trip' });
server.use(
http.get('/api/trips/:id', () => HttpResponse.json({ trip })),
);
renderFilesPage(1);
await waitFor(() => {
expect(screen.getByTestId('navbar')).toHaveTextContent('Rome Trip');
});
});
});
describe('FE-PAGE-FILES-003: FileManager renders after load', () => {
it('renders the FileManager after data loads', async () => {
renderFilesPage(1);
await waitFor(() => {
expect(screen.getByTestId('file-manager')).toBeInTheDocument();
});
});
});
describe('FE-PAGE-FILES-004: File count shown in header', () => {
it('shows the correct file count in the header', async () => {
const file1 = buildTripFile();
const file2 = buildTripFile();
seedStore(useTripStore, {
files: [file1, file2],
loadFiles: vi.fn().mockResolvedValue(undefined),
addFile: vi.fn().mockResolvedValue(undefined),
deleteFile: vi.fn().mockResolvedValue(undefined),
} as any);
renderFilesPage(1);
await waitFor(() => {
expect(screen.getByTestId('file-manager')).toBeInTheDocument();
});
expect(screen.getByText(/2 files for/i)).toBeInTheDocument();
});
});
describe('FE-PAGE-FILES-005: Back link navigates to trip planner', () => {
it('back link points to the trip planner page', async () => {
renderFilesPage(1);
await waitFor(() => {
expect(screen.getByTestId('file-manager')).toBeInTheDocument();
});
const backLink = screen.getByRole('link', { name: /back to planning/i });
expect(backLink.getAttribute('href')).toContain('/trips/1');
});
});
describe('FE-PAGE-FILES-006: loadFiles is called with trip ID on mount', () => {
it('calls tripStore.loadFiles with the trip ID from the URL', async () => {
const mockLoadFiles = vi.fn().mockResolvedValue(undefined);
seedStore(useTripStore, {
files: [],
loadFiles: mockLoadFiles,
addFile: vi.fn().mockResolvedValue(undefined),
deleteFile: vi.fn().mockResolvedValue(undefined),
} as any);
renderFilesPage(1);
await waitFor(() => {
expect(mockLoadFiles).toHaveBeenCalledWith('1');
});
});
});
describe('FE-PAGE-FILES-007: Navigation to /dashboard on fetch error', () => {
it('navigates to /dashboard when trip fetch fails', async () => {
server.use(
http.get('/api/trips/:id', () =>
HttpResponse.json({ error: 'Not found' }, { status: 404 }),
),
);
render(
<Routes>
<Route path="/trips/:id/files" element={<FilesPage />} />
<Route path="/dashboard" element={<div data-testid="dashboard">Dashboard</div>} />
</Routes>,
{ initialEntries: ['/trips/1/files'] },
);
await waitFor(() => {
expect(screen.getByTestId('dashboard')).toBeInTheDocument();
});
});
});
describe('FE-PAGE-FILES-008: Files update when tripStore.files changes', () => {
it('FileManager re-renders when store files change', async () => {
seedStore(useTripStore, {
files: [],
loadFiles: vi.fn().mockResolvedValue(undefined),
addFile: vi.fn().mockResolvedValue(undefined),
deleteFile: vi.fn().mockResolvedValue(undefined),
} as any);
renderFilesPage(1);
await waitFor(() => {
expect(screen.getByTestId('file-manager')).toBeInTheDocument();
});
expect(screen.getByTestId('file-manager')).toHaveTextContent('0 files');
// Simulate store update
act(() => {
useTripStore.setState({ files: [buildTripFile({ id: 99, original_name: 'document.pdf' })] } as any);
});
await waitFor(() => {
expect(screen.getByTestId('file-manager')).toHaveTextContent('1 files');
});
});
});
describe('FE-PAGE-FILES-009: Empty file list renders FileManager with 0 files', () => {
it('renders FileManager with 0 files when files array is empty', async () => {
renderFilesPage(1);
await waitFor(() => {
expect(screen.getByTestId('file-manager')).toBeInTheDocument();
});
expect(screen.getByTestId('file-manager')).toHaveTextContent('0 files');
});
});
describe('FE-PAGE-FILES-010: Page title heading present', () => {
it('renders the "Dateien & Dokumente" heading', async () => {
renderFilesPage(1);
await waitFor(() => {
expect(screen.getByTestId('file-manager')).toBeInTheDocument();
});
expect(screen.getByRole('heading', { name: /Files & Documents/i })).toBeInTheDocument();
});
});
});