import { describe, it, expect, afterEach } from "vitest"; import { render, screen, cleanup } from "@testing-library/react"; import type { Block, ProjectConfig } from "@/features/editor/state/editorStore"; import { EditorCanvas, EditorCanvasDragPreview } from "@/app/editor/EditorCanvas"; import { LocaleProvider } from "@/features/i18n/LocaleProvider"; import { DEFAULT_LOCALE } from "@/features/i18n/locale"; // 에디터 캔버스/페이지 배경색 적용 규칙에 대한 최소 TDD // - canvasBgColorHex: 실제 캔버스 영역(editor-canvas-inner)의 배경색 // - bodyBgColorHex: 에디터 내 페이지 배경(캔버스 바깥 래퍼)의 배경색 afterEach(() => { cleanup(); }); describe("EditorCanvas - 캔버스/페이지 배경색", () => { const baseProjectConfig: ProjectConfig = { title: "배경 테스트", slug: "bg-test", canvasPreset: "full", canvasBgColorHex: "#111111", bodyBgColorHex: "#222222", }; const baseProps = { blocks: [] as Block[], rootBlocks: [] as Block[], selectedBlockId: null as string | null, editingBlockId: null as string | null, editingText: "", activeDragId: null as string | null, sensors: null as any, onCanvasEmptyClick: () => {}, renderBlocks: () => null as any, handleDragStart: () => {}, handleDragEnd: () => {}, handleDragCancel: () => {}, projectConfig: baseProjectConfig, }; it("canvasBgColorHex 는 editor-canvas-inner 배경색에 적용되어야 한다", () => { render( , ); const inner = screen.getByTestId("editor-canvas-inner") as HTMLElement; expect(inner.style.backgroundColor).toBe("rgb(17, 17, 17)"); }); it("blocks 가 없을 때 en 로케일에서는 영어 안내 문구를 표시해야 한다", () => { render( , ); const hint = screen.getByText( 'Click the "Text" button on the left to add your first block.', ); expect(hint.textContent).toBe( 'Click the "Text" button on the left to add your first block.', ); }); it("bodyBgColorHex 는 editor-canvas 바깥 래퍼(editor-canvas)의 배경색에 적용되어야 한다", () => { const { container } = render( , ); const outer = container.querySelector('[data-testid="editor-canvas"]') as HTMLElement | null; expect(outer).not.toBeNull(); expect(outer!.style.backgroundColor).toBe("rgb(34, 34, 34)"); }); it("canvasPreset / canvasWidthPx 에 따라 editor-canvas-inner 의 maxWidth 가 설정되어야 한다", () => { const renderWithConfig = (partial: Partial) => { const projectConfig = { ...baseProjectConfig, ...partial } as ProjectConfig; const { getByTestId, unmount } = render( , ); const inner = getByTestId("editor-canvas-inner") as HTMLElement; const maxWidth = inner.style.maxWidth; unmount(); return maxWidth; }; expect(renderWithConfig({ canvasPreset: "mobile", canvasWidthPx: 390 })).toBe("390px"); expect(renderWithConfig({ canvasPreset: "tablet", canvasWidthPx: 768 })).toBe("768px"); expect(renderWithConfig({ canvasPreset: "desktop", canvasWidthPx: 1200 })).toBe("1200px"); // full 프리셋에서 canvasWidthPx 가 없으면 maxWidth 는 비워져 있어야 한다. expect(renderWithConfig({ canvasPreset: "full", canvasWidthPx: undefined })).toBe(""); // custom 프리셋에서는 canvasWidthPx 값이 그대로 사용된다. expect(renderWithConfig({ canvasPreset: "custom", canvasWidthPx: 1024 })).toBe("1024px"); }); it("DragOverlay 프리뷰는 라이트/다크 듀얼 테마 크롬을 사용해야 한다", () => { const block: Block = { id: "drag_1", type: "text", props: { text: "드래그 미리보기", align: "left", size: "base", }, } as any; const { container } = render( , ); const overlay = container.querySelector( "div.pointer-events-none.rounded.border", ) as HTMLElement | null; expect(overlay).not.toBeNull(); const className = overlay!.getAttribute("class") ?? ""; expect(className).toContain("border-sky-500"); 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("en 로케일에서는 EditorCanvasDragPreview 의 텍스트 블록 fallback 라벨이 영어로 표시되어야 한다", () => { const block: Block = { id: "text_fallback_1", type: "text", props: { text: "", align: "left", size: "base", }, } as any; render( , ); const fallbackLabel = screen.getByText("Text block"); expect(fallbackLabel.textContent).toBe("Text block"); }); });