import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; import { render, screen, fireEvent, waitFor } from "@testing-library/react"; import SearchPage from "./page"; const ORIGINAL_ENV = process.env; beforeEach(() => { process.env = { ...ORIGINAL_ENV, NEXT_PUBLIC_MAIL_TENANT_SLUG: "acme" }; }); afterEach(() => { process.env = ORIGINAL_ENV; vi.restoreAllMocks(); }); function mockSearchResponse(hits: unknown[]) { vi.stubGlobal( "fetch", vi.fn().mockResolvedValue(new Response(JSON.stringify({ hits }), { status: 200 })) ); } // Akzeptanzkriterium 1: Eingabe liefert Trefferliste mit hervorgehobenen // Suchbegriffen im Snippet. describe("SearchPage — Trefferliste mit Hervorhebung", () => { it("rendert Treffer mit um den hervorgehobenen Suchbegriff", async () => { mockSearchResponse([ { messageId: "msg-1", subjectSnippet: "Quartalsbericht ⦃⦃Umsatz⦄⦄", bodySnippet: "hoher ⦃⦃Umsatz⦄⦄ im dritten Quartal", score: 100, }, ]); render(); fireEvent.change(screen.getByLabelText("Suchbegriff"), { target: { value: "Umsatz" } }); fireEvent.submit(screen.getByLabelText("Suchbegriff").closest("form")!); await waitFor(() => { const marks = document.querySelectorAll("mark"); expect(marks.length).toBeGreaterThan(0); }); const marks = Array.from(document.querySelectorAll("mark")).map((m) => m.textContent); expect(marks).toContain("Umsatz"); }); // Akzeptanzkriterium 3: leere Ergebnisse zeigen verständlichen Hinweis // statt leerer Fläche. it("zeigt bei leerem Ergebnis einen verständlichen Hinweis", async () => { mockSearchResponse([]); render(); fireEvent.change(screen.getByLabelText("Suchbegriff"), { target: { value: "nichts-vorhanden" } }); fireEvent.submit(screen.getByLabelText("Suchbegriff").closest("form")!); await waitFor(() => { expect(screen.getByRole("status")).toHaveTextContent("Keine Treffer"); }); }); // Pflichtprüfung 3: Sonderzeichen in der Suchanfrage bringen die Anzeige // nicht zum Absturz. it("wirft bei Sonderzeichen in der Suchanfrage keinen Fehler", async () => { mockSearchResponse([ { messageId: "msg-2", subjectSnippet: `⦃⦃⦄⦄ & "Zitat" 日本語`, bodySnippet: "", score: 1, }, ]); render(); fireEvent.change(screen.getByLabelText("Suchbegriff"), { target: { value: '"