test(11-04): add failing test for TenderDetail component
Covers the three must-have truths: source link with safe target/rel, graceful NULL placeholders for value/deadline, and the mandatory no-local-mirroring notice for Vergabeunterlagen (rawPayload is 100% NULL in the live DB per research - no document URLs exist to mirror). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,125 @@
|
||||
import { cleanup, render, screen, waitFor } from '@testing-library/react';
|
||||
import { afterEach, describe, expect, it, vi } from 'vitest';
|
||||
|
||||
/**
|
||||
* TenderDetail.test — RED-first (TDD) proof for Plan 11-04 (UI-02, D-07).
|
||||
* Mirrors the SourceConfigForm.test.tsx pattern: mock the api client
|
||||
* module (getTender), render with a tenderId prop, assert via waitFor.
|
||||
*
|
||||
* Covers the three must-have truths from the plan:
|
||||
* (a) a source link is rendered and points at the tender's sourceUrl
|
||||
* with a safe target/rel combination (T-11-09).
|
||||
* (b) estimatedValue=null and deadlineAt=null render graceful German
|
||||
* placeholders instead of blank/error output (D-05 applies equally
|
||||
* to the detail view, not just the list).
|
||||
* (c) the mandatory no-local-mirroring notice is always present — no
|
||||
* Vergabeunterlagen are fetched or mirrored locally (rawPayload is
|
||||
* 100% NULL in the live DB; research finding, no document URLs
|
||||
* exist to mirror in the first place).
|
||||
*/
|
||||
|
||||
const mockGetTender = vi.fn();
|
||||
|
||||
vi.mock('@/lib/tender-radar-api', () => ({
|
||||
getTender: (...args: unknown[]) => mockGetTender(...args),
|
||||
}));
|
||||
|
||||
afterEach(() => {
|
||||
cleanup();
|
||||
mockGetTender.mockReset();
|
||||
vi.restoreAllMocks();
|
||||
});
|
||||
|
||||
describe('TenderDetail', () => {
|
||||
it('renders a source link pointing at the tender sourceUrl with safe target/rel', async () => {
|
||||
mockGetTender.mockResolvedValue({
|
||||
id: 't1',
|
||||
sourcePortal: 'doe-opendata',
|
||||
title: 'Sanierung Rathaus',
|
||||
buyerName: 'Stadt Musterhausen',
|
||||
cpvCodes: ['45000000'],
|
||||
region: 'Oberbayern',
|
||||
plz: '80331',
|
||||
bundesland: 'Bayern',
|
||||
deadlineAt: '2026-09-01T00:00:00.000Z',
|
||||
estimatedValue: '150000.00',
|
||||
procedureType: 'Offenes Verfahren',
|
||||
status: 'active',
|
||||
sourceUrl: 'https://example-portal.de/ausschreibung/t1',
|
||||
publishedAt: '2026-07-01T00:00:00.000Z',
|
||||
});
|
||||
|
||||
const { TenderDetail } = await import('./TenderDetail');
|
||||
render(<TenderDetail tenderId="t1" onClose={() => {}} />);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.getByText('Sanierung Rathaus')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
const link = screen.getByRole('link', { name: /Quellportal/i });
|
||||
expect(link).toHaveAttribute(
|
||||
'href',
|
||||
'https://example-portal.de/ausschreibung/t1',
|
||||
);
|
||||
expect(link).toHaveAttribute('target', '_blank');
|
||||
expect(link).toHaveAttribute('rel', 'noopener noreferrer');
|
||||
expect(mockGetTender).toHaveBeenCalledWith('t1');
|
||||
});
|
||||
|
||||
it('shows graceful placeholders when estimatedValue and deadlineAt are null', async () => {
|
||||
mockGetTender.mockResolvedValue({
|
||||
id: 't2',
|
||||
sourcePortal: 'doe-opendata',
|
||||
title: 'Straßenbau Projekt X',
|
||||
buyerName: null,
|
||||
cpvCodes: [],
|
||||
region: null,
|
||||
plz: null,
|
||||
bundesland: null,
|
||||
deadlineAt: null,
|
||||
estimatedValue: null,
|
||||
procedureType: null,
|
||||
status: 'active',
|
||||
sourceUrl: null,
|
||||
publishedAt: '2026-07-01T00:00:00.000Z',
|
||||
});
|
||||
|
||||
const { TenderDetail } = await import('./TenderDetail');
|
||||
render(<TenderDetail tenderId="t2" onClose={() => {}} />);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.getByText('Straßenbau Projekt X')).toBeInTheDocument();
|
||||
});
|
||||
expect(screen.getByText('keine Wertangabe')).toBeInTheDocument();
|
||||
expect(screen.getByText('keine Frist angegeben')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('always shows the no-local-mirroring notice for Vergabeunterlagen', async () => {
|
||||
mockGetTender.mockResolvedValue({
|
||||
id: 't3',
|
||||
sourcePortal: 'doe-opendata',
|
||||
title: 'Beschaffung IT-Ausstattung',
|
||||
buyerName: 'Landkreis Beispiel',
|
||||
cpvCodes: ['30200000'],
|
||||
region: null,
|
||||
plz: null,
|
||||
bundesland: null,
|
||||
deadlineAt: '2026-08-15T00:00:00.000Z',
|
||||
estimatedValue: '25000.00',
|
||||
procedureType: 'Verhandlungsverfahren',
|
||||
status: 'active',
|
||||
sourceUrl: 'https://example-portal.de/ausschreibung/t3',
|
||||
publishedAt: '2026-07-01T00:00:00.000Z',
|
||||
});
|
||||
|
||||
const { TenderDetail } = await import('./TenderDetail');
|
||||
render(<TenderDetail tenderId="t3" onClose={() => {}} />);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.getByText('Beschaffung IT-Ausstattung')).toBeInTheDocument();
|
||||
});
|
||||
expect(
|
||||
screen.getByText(/Vergabeunterlagen werden nicht lokal gespiegelt/i),
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user