264 lines
7.4 KiB
TypeScript
264 lines
7.4 KiB
TypeScript
import { describe, it, expect, afterEach, vi } from "vitest";
|
|
import { render, screen, fireEvent, cleanup, waitFor } from "@testing-library/react";
|
|
import { PublicPageRenderer } from "@/features/editor/components/PublicPageRenderer";
|
|
import type { Block } from "@/features/editor/state/editorStore";
|
|
|
|
// PublicPageRenderer 폼 제출 UX TDD
|
|
// - 성공 응답 시 FormBlockProps 의 successMessage 를 success 스타일로 표시해야 한다.
|
|
// - 실패 응답 시 FormBlockProps 의 errorMessage 를 error 스타일로 표시해야 한다.
|
|
|
|
describe("PublicPageRenderer - 폼 제출 메시지", () => {
|
|
afterEach(() => {
|
|
cleanup();
|
|
// fetch 목 초기화
|
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
(globalThis as any).fetch = undefined;
|
|
});
|
|
|
|
it("성공 응답 시 FormBlock 의 successMessage 를 성공 메시지로 렌더해야 한다", async () => {
|
|
const blocks: Block[] = [
|
|
{
|
|
id: "form_success",
|
|
type: "form",
|
|
props: {
|
|
kind: "contact",
|
|
submitTarget: "internal",
|
|
successMessage: "Form success message (config)",
|
|
errorMessage: "Form error message (config)",
|
|
fieldIds: ["field_name"],
|
|
requiredFieldIds: ["field_name"],
|
|
submitButtonId: "submit_btn",
|
|
} as any,
|
|
},
|
|
{
|
|
id: "field_name",
|
|
type: "formInput",
|
|
props: {
|
|
label: "Name",
|
|
formFieldName: "name",
|
|
required: true,
|
|
} as any,
|
|
},
|
|
{
|
|
id: "submit_btn",
|
|
type: "button",
|
|
props: {
|
|
label: "Submit",
|
|
href: "#",
|
|
} as any,
|
|
},
|
|
];
|
|
|
|
const fetchMock = vi.fn(async () =>
|
|
new Response("ok", {
|
|
status: 200,
|
|
headers: { "Content-Type": "text/plain" },
|
|
}),
|
|
);
|
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
(globalThis as any).fetch = fetchMock;
|
|
|
|
render(<PublicPageRenderer blocks={blocks} />);
|
|
|
|
const nameInput = screen.getByLabelText("Name") as HTMLInputElement;
|
|
fireEvent.change(nameInput, { target: { value: "홍길동" } });
|
|
|
|
const submitButton = screen.getByRole("link", { name: "Submit" });
|
|
expect(submitButton).toBeTruthy();
|
|
|
|
fireEvent.click(submitButton);
|
|
|
|
await waitFor(() => {
|
|
expect(fetchMock).toHaveBeenCalledTimes(1);
|
|
});
|
|
|
|
await waitFor(() => {
|
|
const msg = screen.getByText("Form success message (config)");
|
|
expect(msg).toBeTruthy();
|
|
});
|
|
});
|
|
|
|
it("실패 응답 시 FormBlock 의 errorMessage 를 에러 메시지로 렌더해야 한다", async () => {
|
|
const blocks: Block[] = [
|
|
{
|
|
id: "form_error",
|
|
type: "form",
|
|
props: {
|
|
kind: "contact",
|
|
submitTarget: "internal",
|
|
successMessage: "Form success message (config)",
|
|
errorMessage: "Form error message (config)",
|
|
fieldIds: ["field_name"],
|
|
requiredFieldIds: ["field_name"],
|
|
submitButtonId: "submit_btn",
|
|
} as any,
|
|
},
|
|
{
|
|
id: "field_name",
|
|
type: "formInput",
|
|
props: {
|
|
label: "Name",
|
|
formFieldName: "name",
|
|
required: true,
|
|
} as any,
|
|
},
|
|
{
|
|
id: "submit_btn",
|
|
type: "button",
|
|
props: {
|
|
label: "Submit",
|
|
href: "#",
|
|
} as any,
|
|
},
|
|
];
|
|
|
|
const fetchMock = vi.fn(async () =>
|
|
new Response("error", {
|
|
status: 500,
|
|
headers: { "Content-Type": "text/plain" },
|
|
}),
|
|
);
|
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
(globalThis as any).fetch = fetchMock;
|
|
|
|
render(<PublicPageRenderer blocks={blocks} />);
|
|
|
|
const nameInput = screen.getByLabelText("Name") as HTMLInputElement;
|
|
fireEvent.change(nameInput, { target: { value: "홍길동" } });
|
|
|
|
const submitButton = screen.getByRole("link", { name: "Submit" });
|
|
expect(submitButton).toBeTruthy();
|
|
|
|
fireEvent.click(submitButton);
|
|
|
|
await waitFor(() => {
|
|
expect(fetchMock).toHaveBeenCalledTimes(1);
|
|
});
|
|
|
|
await waitFor(() => {
|
|
const errorMsg = screen.getByText("Form error message (config)");
|
|
expect(errorMsg).toBeTruthy();
|
|
});
|
|
});
|
|
|
|
it("필수 필드가 비어 있고 errorMessage 가 없으면 기본 문구에 필수 항목 라벨을 포함해야 한다", async () => {
|
|
const blocks: Block[] = [
|
|
{
|
|
id: "form_required_default_msg",
|
|
type: "form",
|
|
props: {
|
|
kind: "contact",
|
|
submitTarget: "internal",
|
|
successMessage: "Form success message (config)",
|
|
fieldIds: ["field_email"],
|
|
requiredFieldIds: ["field_email"],
|
|
submitButtonId: "submit_btn",
|
|
} as any,
|
|
},
|
|
{
|
|
id: "field_email",
|
|
type: "formInput",
|
|
props: {
|
|
label: "Email",
|
|
formFieldName: "email",
|
|
required: true,
|
|
} as any,
|
|
},
|
|
{
|
|
id: "submit_btn",
|
|
type: "button",
|
|
props: {
|
|
label: "Submit",
|
|
href: "#",
|
|
} as any,
|
|
},
|
|
];
|
|
|
|
const fetchMock = vi.fn(async () =>
|
|
new Response("ok", {
|
|
status: 200,
|
|
headers: { "Content-Type": "text/plain" },
|
|
}),
|
|
);
|
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
(globalThis as any).fetch = fetchMock;
|
|
|
|
render(<PublicPageRenderer blocks={blocks} />);
|
|
|
|
const submitButton = screen.getByRole("link", { name: "Submit" });
|
|
expect(submitButton).toBeTruthy();
|
|
|
|
fireEvent.click(submitButton);
|
|
|
|
await waitFor(() => {
|
|
expect(fetchMock).toHaveBeenCalledTimes(0);
|
|
});
|
|
|
|
await waitFor(() => {
|
|
const errorMsg = screen.getByText(/Please fill in the following required fields:\s*-\s*Email/);
|
|
expect(errorMsg).toBeTruthy();
|
|
});
|
|
});
|
|
|
|
it("필수 필드가 비어 있으면 요청을 보내지 않고 필수 항목 안내 메시지를 표시해야 한다 (errorMessage 설정 시)", async () => {
|
|
const blocks: Block[] = [
|
|
{
|
|
id: "form_required",
|
|
type: "form",
|
|
props: {
|
|
kind: "contact",
|
|
submitTarget: "internal",
|
|
successMessage: "Form success message (config)",
|
|
errorMessage: "Form error message (config)",
|
|
fieldIds: ["field_name"],
|
|
requiredFieldIds: ["field_name"],
|
|
submitButtonId: "submit_btn",
|
|
} as any,
|
|
},
|
|
{
|
|
id: "field_name",
|
|
type: "formInput",
|
|
props: {
|
|
label: "Name",
|
|
formFieldName: "name",
|
|
required: true,
|
|
} as any,
|
|
},
|
|
{
|
|
id: "submit_btn",
|
|
type: "button",
|
|
props: {
|
|
label: "Submit",
|
|
href: "#",
|
|
} as any,
|
|
},
|
|
];
|
|
|
|
const fetchMock = vi.fn(async () =>
|
|
new Response("ok", {
|
|
status: 200,
|
|
headers: { "Content-Type": "text/plain" },
|
|
}),
|
|
);
|
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
(globalThis as any).fetch = fetchMock;
|
|
|
|
render(<PublicPageRenderer blocks={blocks} />);
|
|
|
|
const submitButton = screen.getByRole("link", { name: "Submit" });
|
|
expect(submitButton).toBeTruthy();
|
|
|
|
// 이름 필드를 비운 채로 제출한다.
|
|
fireEvent.click(submitButton);
|
|
|
|
await waitFor(() => {
|
|
expect(fetchMock).toHaveBeenCalledTimes(0);
|
|
});
|
|
|
|
await waitFor(() => {
|
|
const errorMsg = screen.getByText(/Please fill in the following required fields:\s*-\s*Name/);
|
|
expect(errorMsg).toBeTruthy();
|
|
});
|
|
});
|
|
});
|