mirror of
https://github.com/mauriceboe/TREK.git
synced 2026-06-19 21:31:46 +00:00
ecbb1de8de
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>
212 lines
6.8 KiB
TypeScript
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();
|
|
});
|
|
});
|
|
});
|