- Vitest multi-project setup (unit / integration / component) - Real-Postgres integration harness via in-process PGlite (TEST_DATABASE_URL override), migrations applied per worker; production code untouched - Unit: routing, locale, validation/Zod schemas, metadata, mail, site-theme, marquee, media, portfolio helpers, plus architecture-rule tests - Integration: Prisma data layer, API routes, and all server actions - Component: UI primitives and form components (jsdom + Testing Library) - 371 tests passing
93 lines
3.0 KiB
TypeScript
93 lines
3.0 KiB
TypeScript
import { beforeEach, describe, expect, it, vi } from "vitest";
|
|
|
|
vi.mock("next/navigation", async () => ({
|
|
redirect: (await import("@/tests/helpers/next-mocks")).redirect,
|
|
}));
|
|
vi.mock("next/dist/client/components/redirect-error", async () => ({
|
|
isRedirectError: (await import("@/tests/helpers/next-mocks")).isRedirectError,
|
|
}));
|
|
|
|
const { sendContactMessage } = vi.hoisted(() => ({ sendContactMessage: vi.fn(async () => {}) }));
|
|
vi.mock("@/lib/mail", () => ({ sendContactMessage }));
|
|
|
|
import { submitContactFormAction } from "@/app/[locale]/(site)/contact/actions";
|
|
import { captureRedirect, formDataFrom } from "@/tests/helpers/next-mocks";
|
|
|
|
beforeEach(() => {
|
|
sendContactMessage.mockClear();
|
|
});
|
|
|
|
describe("submitContactFormAction", () => {
|
|
it("sends a valid message and redirects to the localized success page", async () => {
|
|
const url = await captureRedirect(() =>
|
|
submitContactFormAction(
|
|
formDataFrom({
|
|
locale: "en",
|
|
name: "Jane Doe",
|
|
email: "jane@example.com",
|
|
message: "Hello, I would like to work together on a project.",
|
|
}),
|
|
),
|
|
);
|
|
expect(url).toBe("/en/success");
|
|
expect(sendContactMessage).toHaveBeenCalledTimes(1);
|
|
expect(sendContactMessage).toHaveBeenCalledWith(
|
|
expect.objectContaining({ locale: "en", name: "Jane Doe", email: "jane@example.com" }),
|
|
);
|
|
});
|
|
|
|
it("uses the default locale (de) and its bare success path", async () => {
|
|
const url = await captureRedirect(() =>
|
|
submitContactFormAction(
|
|
formDataFrom({
|
|
locale: "de",
|
|
name: "Max Mustermann",
|
|
email: "max@example.com",
|
|
message: "Ich interessiere mich fuer eine Zusammenarbeit.",
|
|
}),
|
|
),
|
|
);
|
|
expect(url).toBe("/success");
|
|
});
|
|
|
|
it("redirects back with an error for an invalid email and does not send", async () => {
|
|
const url = await captureRedirect(() =>
|
|
submitContactFormAction(
|
|
formDataFrom({
|
|
locale: "en",
|
|
name: "Jane",
|
|
email: "not-an-email",
|
|
message: "This is a long enough message body.",
|
|
}),
|
|
),
|
|
);
|
|
expect(url).toContain("/en/contact?error=");
|
|
expect(sendContactMessage).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it("rejects a too-short message", async () => {
|
|
const url = await captureRedirect(() =>
|
|
submitContactFormAction(
|
|
formDataFrom({ locale: "de", name: "Jane Doe", email: "jane@example.com", message: "short" }),
|
|
),
|
|
);
|
|
expect(url).toContain("/contact?error=");
|
|
expect(sendContactMessage).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it("redirects with an error when delivery fails", async () => {
|
|
sendContactMessage.mockRejectedValueOnce(new Error("smtp down"));
|
|
const url = await captureRedirect(() =>
|
|
submitContactFormAction(
|
|
formDataFrom({
|
|
locale: "en",
|
|
name: "Jane Doe",
|
|
email: "jane@example.com",
|
|
message: "A perfectly valid message body here.",
|
|
}),
|
|
),
|
|
);
|
|
expect(url).toContain("/en/contact?error=");
|
|
});
|
|
});
|