1차 싱크 완료
This commit is contained in:
@@ -0,0 +1,158 @@
|
||||
import { describe, it, expect, afterEach, vi } from "vitest";
|
||||
import { render, screen, fireEvent, cleanup } from "@testing-library/react";
|
||||
import { BlocksSidebar } from "@/app/editor/panels/BlocksSidebar";
|
||||
|
||||
// BlocksSidebar 템플릿 버튼 TDD
|
||||
// - 각 템플릿 추가 버튼이 대응하는 editorStore 액션(add*TemplateSection)을 호출하는지 검증한다.
|
||||
|
||||
const templateActions = {
|
||||
addHeroTemplateSection: vi.fn(),
|
||||
addFeaturesTemplateSection: vi.fn(),
|
||||
addCtaTemplateSection: vi.fn(),
|
||||
addFaqTemplateSection: vi.fn(),
|
||||
addPricingTemplateSection: vi.fn(),
|
||||
addTestimonialsTemplateSection: vi.fn(),
|
||||
addBlogTemplateSection: vi.fn(),
|
||||
addTeamTemplateSection: vi.fn(),
|
||||
addFooterTemplateSection: vi.fn(),
|
||||
};
|
||||
|
||||
// BlocksSidebar 가 사용하는 나머지 액션들도 더미 함수로 채워둔다.
|
||||
const otherActions = {
|
||||
addTextBlock: vi.fn(),
|
||||
addButtonBlock: vi.fn(),
|
||||
addImageBlock: vi.fn(),
|
||||
addDividerBlock: vi.fn(),
|
||||
addListBlock: vi.fn(),
|
||||
addSectionBlock: vi.fn(),
|
||||
addFormBlock: vi.fn(),
|
||||
addFormInputBlock: vi.fn(),
|
||||
addFormSelectBlock: vi.fn(),
|
||||
addFormCheckboxBlock: vi.fn(),
|
||||
addFormRadioBlock: vi.fn(),
|
||||
};
|
||||
|
||||
const mockState = {
|
||||
...templateActions,
|
||||
...otherActions,
|
||||
};
|
||||
|
||||
vi.mock("@/features/editor/state/editorStore", () => {
|
||||
return {
|
||||
__esModule: true,
|
||||
// useEditorStore(selector) 형태로 사용되므로, selector 에 mockState 를 넘겨준다.
|
||||
useEditorStore: (selector: (state: typeof mockState) => unknown) => selector(mockState),
|
||||
};
|
||||
});
|
||||
|
||||
describe("BlocksSidebar - 템플릿 버튼", () => {
|
||||
afterEach(() => {
|
||||
cleanup();
|
||||
Object.values(templateActions).forEach((fn) => fn.mockReset());
|
||||
});
|
||||
|
||||
it("Hero 템플릿 추가 버튼 클릭 시 addHeroTemplateSection 이 호출되어야 한다", () => {
|
||||
render(<BlocksSidebar />);
|
||||
|
||||
const button = screen.getByRole("button", { name: "Hero 템플릿 추가" });
|
||||
fireEvent.click(button);
|
||||
|
||||
expect(templateActions.addHeroTemplateSection).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it("Features 템플릿 추가 버튼 클릭 시 addFeaturesTemplateSection 이 호출되어야 한다", () => {
|
||||
render(<BlocksSidebar />);
|
||||
|
||||
const button = screen.getByRole("button", { name: "Features 템플릿 추가" });
|
||||
fireEvent.click(button);
|
||||
|
||||
expect(templateActions.addFeaturesTemplateSection).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it("CTA 템플릿 추가 버튼 클릭 시 addCtaTemplateSection 이 호출되어야 한다", () => {
|
||||
render(<BlocksSidebar />);
|
||||
|
||||
const button = screen.getByRole("button", { name: "CTA 템플릿 추가" });
|
||||
fireEvent.click(button);
|
||||
|
||||
expect(templateActions.addCtaTemplateSection).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it("FAQ/Pricing/Testimonials/Blog/Team/Footer 템플릿 버튼도 각각의 액션을 호출해야 한다", () => {
|
||||
render(<BlocksSidebar />);
|
||||
|
||||
fireEvent.click(screen.getByRole("button", { name: "FAQ 템플릿 추가" }));
|
||||
fireEvent.click(screen.getByRole("button", { name: "Pricing 템플릿 추가" }));
|
||||
fireEvent.click(screen.getByRole("button", { name: "Testimonials 템플릿 추가" }));
|
||||
fireEvent.click(screen.getByRole("button", { name: "Blog 템플릿 추가" }));
|
||||
fireEvent.click(screen.getByRole("button", { name: "Team 템플릿 추가" }));
|
||||
fireEvent.click(screen.getByRole("button", { name: "Footer 템플릿 추가" }));
|
||||
|
||||
expect(templateActions.addFaqTemplateSection).toHaveBeenCalledTimes(1);
|
||||
expect(templateActions.addPricingTemplateSection).toHaveBeenCalledTimes(1);
|
||||
expect(templateActions.addTestimonialsTemplateSection).toHaveBeenCalledTimes(1);
|
||||
expect(templateActions.addBlogTemplateSection).toHaveBeenCalledTimes(1);
|
||||
expect(templateActions.addTeamTemplateSection).toHaveBeenCalledTimes(1);
|
||||
expect(templateActions.addFooterTemplateSection).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it("템플릿 섹션에는 각 템플릿의 용도를 설명하는 텍스트가 함께 표시되어야 한다", () => {
|
||||
render(<BlocksSidebar />);
|
||||
|
||||
expect(screen.getByText("페이지 상단 Hero 섹션 (큰 제목 + 서브텍스트 + 버튼)"));
|
||||
expect(screen.getByText("3컬럼 기능 소개 섹션"));
|
||||
expect(screen.getByText("콜투액션(CTA) 섹션"));
|
||||
expect(screen.getByText("자주 묻는 질문(FAQ) 섹션"));
|
||||
expect(screen.getByText("요금제/플랜 소개 섹션"));
|
||||
expect(screen.getByText("고객 후기(Testimonials) 섹션"));
|
||||
expect(screen.getByText("블로그 포스트 목록 섹션"));
|
||||
expect(screen.getByText("팀 소개 섹션"));
|
||||
expect(screen.getByText("페이지 푸터 섹션"));
|
||||
});
|
||||
|
||||
it("템플릿들은 카테고리별로 그룹 헤더를 가져야 한다", () => {
|
||||
render(<BlocksSidebar />);
|
||||
|
||||
expect(screen.getByText("히어로 · CTA")).toBeDefined();
|
||||
expect(screen.getByText("콘텐츠 섹션")).toBeDefined();
|
||||
expect(screen.getByText("신뢰/소개")).toBeDefined();
|
||||
expect(screen.getByText("푸터/기타")).toBeDefined();
|
||||
});
|
||||
|
||||
it("각 템플릿 카드에는 미니 썸네일(레이아웃 힌트)가 렌더링되어야 한다", () => {
|
||||
render(<BlocksSidebar />);
|
||||
|
||||
expect(screen.getByTestId("template-preview-hero")).toBeDefined();
|
||||
expect(screen.getByTestId("template-preview-features")).toBeDefined();
|
||||
expect(screen.getByTestId("template-preview-cta")).toBeDefined();
|
||||
expect(screen.getByTestId("template-preview-faq")).toBeDefined();
|
||||
expect(screen.getByTestId("template-preview-pricing")).toBeDefined();
|
||||
expect(screen.getByTestId("template-preview-testimonials")).toBeDefined();
|
||||
expect(screen.getByTestId("template-preview-blog")).toBeDefined();
|
||||
expect(screen.getByTestId("template-preview-team")).toBeDefined();
|
||||
expect(screen.getByTestId("template-preview-footer")).toBeDefined();
|
||||
});
|
||||
|
||||
it("미니 썸네일은 각 템플릿 레이아웃을 암시하는 구조를 가져야 한다", () => {
|
||||
render(<BlocksSidebar />);
|
||||
|
||||
const heroThumb = screen.getByTestId("template-preview-hero");
|
||||
const ctaThumb = screen.getByTestId("template-preview-cta");
|
||||
const featuresThumb = screen.getByTestId("template-preview-features");
|
||||
const pricingThumb = screen.getByTestId("template-preview-pricing");
|
||||
const blogThumb = screen.getByTestId("template-preview-blog");
|
||||
const teamThumb = screen.getByTestId("template-preview-team");
|
||||
|
||||
// Hero/CTA: 하나의 메인 영역을 가진 1열 구조
|
||||
expect(heroThumb.children.length).toBe(1);
|
||||
expect(ctaThumb.children.length).toBe(1);
|
||||
|
||||
// Features/Blog: 3컬럼 레이아웃을 암시하는 3개의 세그먼트
|
||||
expect(featuresThumb.children.length).toBe(3);
|
||||
expect(blogThumb.children.length).toBe(3);
|
||||
|
||||
// Pricing/Team: 높이가 다른 3개의 바를 가진 3컬럼 카드 레이아웃
|
||||
expect(pricingThumb.children.length).toBe(3);
|
||||
expect(teamThumb.children.length).toBe(3);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user