158 lines
6.2 KiB
TypeScript
158 lines
6.2 KiB
TypeScript
import { describe, it, expect, vi, afterEach } from "vitest";
|
|
import { render, screen, fireEvent, cleanup } from "@testing-library/react";
|
|
import type { Block } from "@/features/editor/state/editorStore";
|
|
import { PropertiesSidebar } from "@/app/editor/panels/PropertiesSidebar";
|
|
|
|
describe("PropertiesSidebar HELP 튜토리얼 모달", () => {
|
|
afterEach(() => {
|
|
cleanup();
|
|
});
|
|
|
|
const createTextBlock = (): Block => ({
|
|
id: "text-1",
|
|
type: "text",
|
|
props: {
|
|
text: "도움말 테스트",
|
|
align: "left",
|
|
size: "base",
|
|
} as any,
|
|
sectionId: null,
|
|
columnId: null,
|
|
});
|
|
|
|
const defaultProps = (blocks: Block[], selectedBlockId: string | null) => ({
|
|
blocks,
|
|
selectedBlockId,
|
|
selectedListItemId: null,
|
|
updateBlock: vi.fn(),
|
|
removeBlock: vi.fn(),
|
|
duplicateBlock: vi.fn(),
|
|
editingBlockId: null,
|
|
setEditingText: vi.fn(),
|
|
onMoveSelectedItemUp: vi.fn(),
|
|
onMoveSelectedItemDown: vi.fn(),
|
|
onIndentSelectedItem: vi.fn(),
|
|
onOutdentSelectedItem: vi.fn(),
|
|
});
|
|
|
|
it("텍스트 블록이 선택된 상태에서 HELP 버튼을 노출해야 한다", () => {
|
|
const textBlock = createTextBlock();
|
|
|
|
render(<PropertiesSidebar {...defaultProps([textBlock], textBlock.id)} />);
|
|
|
|
const helpButton = screen.getByRole("button", { name: "HELP" });
|
|
expect(helpButton).toBeDefined();
|
|
});
|
|
|
|
it("HELP 버튼 클릭 시 현재 블록 타입에 맞는 튜토리얼 모달이 열려야 한다", () => {
|
|
const textBlock = createTextBlock();
|
|
|
|
render(<PropertiesSidebar {...defaultProps([textBlock], textBlock.id)} />);
|
|
|
|
const helpButton = screen.getByRole("button", { name: "HELP" });
|
|
fireEvent.click(helpButton);
|
|
|
|
expect(screen.getByText("Text block tutorial")).toBeDefined();
|
|
expect(screen.getByText(/basic block for headings and body text/i)).toBeDefined();
|
|
});
|
|
|
|
it("HELP 모달은 라이트/다크 테마에 맞는 카드 배경/테두리/텍스트 클래스를 사용해야 한다", () => {
|
|
const textBlock = createTextBlock();
|
|
|
|
render(<PropertiesSidebar {...defaultProps([textBlock], textBlock.id)} />);
|
|
|
|
const helpButton = screen.getByRole("button", { name: "HELP" });
|
|
fireEvent.click(helpButton);
|
|
|
|
// 모달 카드 컨테이너 (제목 h3 → 헤더 div → 카드 div 순으로 감싸져 있으므로 parentElement.parentElement 사용)
|
|
const heading = screen.getByText("Text block tutorial");
|
|
const modalCard = heading.parentElement?.parentElement as HTMLElement | null;
|
|
expect(modalCard).not.toBeNull();
|
|
const className = modalCard!.getAttribute("class") ?? "";
|
|
|
|
// 라이트 모드: 흰 배경 + 어두운 텍스트 + 연한 테두리
|
|
expect(className).toContain("bg-white");
|
|
expect(className).toContain("text-slate-900");
|
|
expect(className).toContain("border-slate-200");
|
|
// 다크 모드: 기존 다크 톤 유지
|
|
expect(className).toContain("dark:border-slate-700");
|
|
expect(className).toContain("dark:bg-slate-900");
|
|
expect(className).toContain("dark:text-slate-100");
|
|
});
|
|
|
|
it("모달의 닫기 버튼을 클릭하면 튜토리얼 모달이 닫혀야 한다", () => {
|
|
const textBlock = createTextBlock();
|
|
|
|
render(<PropertiesSidebar {...defaultProps([textBlock], textBlock.id)} />);
|
|
|
|
const helpButton = screen.getByRole("button", { name: "HELP" });
|
|
fireEvent.click(helpButton);
|
|
|
|
const closeButton = screen.getByRole("button", { name: "Close" });
|
|
fireEvent.click(closeButton);
|
|
|
|
expect(screen.queryByText("텍스트 블록 튜토리얼")).toBeNull();
|
|
});
|
|
|
|
it("텍스트 블록이 선택된 상태에서 상단 액션 버튼들은 라이트/다크 테마에 맞는 배경/텍스트 클래스를 사용해야 한다", () => {
|
|
const textBlock = createTextBlock();
|
|
|
|
render(<PropertiesSidebar {...defaultProps([textBlock], textBlock.id)} />);
|
|
|
|
const deleteButton = screen.getByRole("button", { name: "Delete block" });
|
|
const duplicateButton = screen.getByRole("button", { name: "Duplicate block" });
|
|
const helpButton = screen.getByRole("button", { name: "HELP" });
|
|
|
|
for (const btn of [deleteButton, duplicateButton, helpButton]) {
|
|
const className = btn.getAttribute("class") ?? "";
|
|
// 라이트 모드: 밝은 배경 + 어두운 텍스트
|
|
expect(className).toContain("bg-slate-50");
|
|
expect(className).toContain("text-slate-900");
|
|
// 다크 모드: 기존 다크 톤 유지
|
|
expect(className).toContain("dark:bg-slate-900");
|
|
expect(className).toContain("dark:text-slate-100");
|
|
}
|
|
});
|
|
|
|
it("텍스트 블록이 선택된 상태에서 내용 편집 textarea는 라이트/다크 테마에 맞는 배경/텍스트 클래스를 사용해야 한다", () => {
|
|
const textBlock = createTextBlock();
|
|
|
|
render(<PropertiesSidebar {...defaultProps([textBlock], textBlock.id)} />);
|
|
|
|
const textarea = screen.getByLabelText("Selected text block content") as HTMLTextAreaElement;
|
|
const className = textarea.getAttribute("class") ?? "";
|
|
|
|
// 라이트 모드: 흰 배경 + 어두운 텍스트
|
|
expect(className).toContain("bg-white");
|
|
expect(className).toContain("text-slate-900");
|
|
// 다크 모드: 다크 배경 + 밝은 텍스트
|
|
expect(className).toContain("dark:bg-slate-900");
|
|
expect(className).toContain("dark:text-slate-100");
|
|
});
|
|
|
|
it("속성 패널 루트는 라이트/다크 테마에 맞는 배경/테두리 클래스를 사용해야 한다", () => {
|
|
const props = defaultProps([], null);
|
|
|
|
render(<PropertiesSidebar {...props} />);
|
|
|
|
const aside = screen.getByTestId("properties-sidebar") as HTMLElement;
|
|
const className = aside.getAttribute("class") ?? "";
|
|
|
|
expect(className).toContain("bg-white");
|
|
expect(className).toContain("border-slate-200");
|
|
expect(className).toContain("dark:border-slate-800");
|
|
expect(className).toContain("dark:bg-slate-950/40");
|
|
});
|
|
|
|
it("속성 패널 루트는 pb-scroll 커스텀 스크롤바 클래스를 사용해 에디터용 스크롤바 테마를 적용해야 한다", () => {
|
|
const props = defaultProps([], null);
|
|
|
|
render(<PropertiesSidebar {...props} />);
|
|
|
|
const aside = screen.getByTestId("properties-sidebar") as HTMLElement;
|
|
const className = aside.getAttribute("class") ?? "";
|
|
|
|
expect(className).toContain("pb-scroll");
|
|
});
|
|
});
|