import { render, screen, fireEvent, waitFor } from "@testing-library/react"; import { describe, it, expect, vi, beforeEach } from "vitest"; import { NextIntlClientProvider } from "next-intl"; import messages from "../messages/de.json"; // Mocks MUST be defined before component import to ensure they are picked up vi.mock("../components/Reveal", () => ({ Reveal: ({ children }: any) => <>{children}, Stagger: ({ children }: any) => <>{children}, })); // Better FormData mock for happy-dom global.FormData = class MockFormData { private data = new Map(); constructor(form?: HTMLFormElement) { if (form) { const elements = form.elements as any; for (let i = 0; i < elements.length; i++) { const item = elements.item(i); if (item.name && item.value) { this.data.set(item.name, item.value); } } } } append(key: string, value: any) { this.data.set(key, value); } get(key: string) { return this.data.get(key); } entries() { return Array.from(this.data.entries())[Symbol.iterator](); } } as any; // Mock alert const alertMock = vi.fn(); global.alert = alertMock; // Import component AFTER mocks import Contact from "../components/ContactContent"; // Mock fetch const fetchMock = vi.fn(); global.fetch = fetchMock; const renderContact = () => { return render( , ); }; describe("Contact Page", () => { beforeEach(() => { vi.clearAllMocks(); fetchMock.mockReset(); fetchMock.mockResolvedValue({ ok: true, json: async () => ({ success: true }), }); }); it("renders the contact form correctly", () => { renderContact(); expect(screen.getByLabelText(/Name \*/i)).toBeInTheDocument(); expect(screen.getByLabelText(/Firma/i)).toBeInTheDocument(); expect(screen.getByLabelText(/E-Mail \*/i)).toBeInTheDocument(); expect(screen.getByLabelText(/Nachricht \*/i)).toBeInTheDocument(); }); it("submits the form successfully", async () => { renderContact(); fireEvent.change(screen.getByLabelText(/Name \*/i), { target: { value: "John Doe" }, }); fireEvent.change(screen.getByLabelText(/E-Mail \*/i), { target: { value: "john@example.com" }, }); fireEvent.change(screen.getByLabelText(/Nachricht \*/i), { target: { value: "This is a test message that is long enough." }, }); const form = screen.getByRole("form"); fireEvent.submit(form); await waitFor( () => { expect(fetchMock).toHaveBeenCalled(); }, { timeout: 2000 }, ); expect( (await screen.findAllByText(/Anfrage erfolgreich übermittelt/i)).length, ).toBeGreaterThanOrEqual(1); expect( (await screen.findAllByText(/Ihr Anliegen wurde erfasst/i)).length, ).toBeGreaterThanOrEqual(1); }); it("handles submission errors", async () => { fetchMock.mockResolvedValueOnce({ ok: false, json: async () => ({ error: "Server error" }), }); renderContact(); fireEvent.change(screen.getByLabelText(/Name \*/i), { target: { value: "John Doe" }, }); fireEvent.change(screen.getByLabelText(/E-Mail \*/i), { target: { value: "john@example.com" }, }); fireEvent.change(screen.getByLabelText(/Nachricht \*/i), { target: { value: "This is a test message." }, }); const form = screen.getByRole("form"); fireEvent.submit(form); expect(await screen.findByText(/Server error/i)).toBeInTheDocument(); }); });