import { describe, it, expect, vi, afterEach } from "vitest"; import { render, screen, fireEvent, cleanup } from "@testing-library/react"; import { ListPropertiesPanel } from "@/app/editor/panels/ListPropertiesPanel"; import type { ListBlockProps } from "@/features/editor/state/editorStore"; describe("ListPropertiesPanel", () => { const baseProps: ListBlockProps = { items: ["아이템 1", "아이템 2"], ordered: false, align: "left", }; afterEach(() => { cleanup(); }); it("리스트 아이템 textarea 변경 시 items 와 itemsTree 로 updateBlock 이 호출되어야 한다", () => { const updateBlock = vi.fn(); render( , ); const textarea = screen.getByLabelText("리스트 아이템들"); fireEvent.change(textarea, { target: { value: "첫째\n둘째" } }); expect(updateBlock).toHaveBeenCalledWith( "list-1", expect.objectContaining({ items: ["첫째", "둘째"], }), ); }); it("리스트 정렬 셀렉트 변경 시 updateBlock 이 align 으로 호출되어야 한다", () => { const updateBlock = vi.fn(); render( , ); const select = screen.getByLabelText("리스트 정렬"); fireEvent.change(select, { target: { value: "center" } }); expect(updateBlock).toHaveBeenCalledWith( "list-align", expect.objectContaining({ align: "center" }), ); }); it("글자 크기 슬라이더 변경 시 updateBlock 이 fontSizeCustom 을 px 문자열로 호출해야 한다", () => { const updateBlock = vi.fn(); render( , ); const slider = screen.getByLabelText("글자 크기 (px) 슬라이더"); fireEvent.change(slider, { target: { value: "20" } }); expect(updateBlock).toHaveBeenCalledWith( "list-font-size", expect.objectContaining({ fontSizeCustom: "20px" }), ); }); it("줄 간격 슬라이더 변경 시 updateBlock 이 lineHeightCustom 으로 호출되어야 한다", () => { const updateBlock = vi.fn(); render( , ); const slider = screen.getByLabelText("줄 간격 슬라이더"); fireEvent.change(slider, { target: { value: "1.8" } }); expect(updateBlock).toHaveBeenCalledWith( "list-line-height", expect.objectContaining({ lineHeightCustom: "1.8" }), ); }); it("텍스트 색상 HEX 인풋 변경 시 updateBlock 이 textColorCustom 으로 호출되어야 한다", () => { const updateBlock = vi.fn(); render( , ); const hexInput = screen.getByLabelText("리스트 텍스트 색상 HEX"); fireEvent.change(hexInput, { target: { value: "#112233" } }); expect(updateBlock).toHaveBeenCalledWith( "list-text-color", expect.objectContaining({ textColorCustom: "#112233" }), ); }); it("불릿 스타일 셀렉트 변경 시 bulletStyle 과 ordered 가 함께 업데이트되어야 한다 (decimal)", () => { const updateBlock = vi.fn(); render( , ); const select = screen.getByLabelText("리스트 불릿 스타일"); fireEvent.change(select, { target: { value: "decimal" } }); expect(updateBlock).toHaveBeenCalledWith( "list-bullet-decimal", expect.objectContaining({ bulletStyle: "decimal", ordered: true }), ); }); it("불릿 스타일 셀렉트에서 none 선택 시 ordered 가 false 로 설정되어야 한다", () => { const updateBlock = vi.fn(); render( , ); const select = screen.getByLabelText("리스트 불릿 스타일"); fireEvent.change(select, { target: { value: "none" } }); expect(updateBlock).toHaveBeenCalledWith( "list-bullet-none", expect.objectContaining({ bulletStyle: "none", ordered: false }), ); }); it("아이템 간 여백 슬라이더 변경 시 updateBlock 이 gapYPx 로 호출되어야 한다", () => { const updateBlock = vi.fn(); render( , ); const slider = screen.getByLabelText("아이템 간 여백 (px) 슬라이더"); fireEvent.change(slider, { target: { value: "16" } }); expect(updateBlock).toHaveBeenCalledWith( "list-gapY", expect.objectContaining({ gapYPx: 16 }), ); }); });