1456 lines
44 KiB
TypeScript
1456 lines
44 KiB
TypeScript
import { describe, it, expect, vi, afterEach } from "vitest";
|
|
import { render, screen, fireEvent, cleanup } from "@testing-library/react";
|
|
import { FormInputPropertiesPanel } from "@/app/editor/forms/FormInputPropertiesPanel";
|
|
import { FormSelectPropertiesPanel } from "@/app/editor/forms/FormSelectPropertiesPanel";
|
|
import { FormCheckboxPropertiesPanel } from "@/app/editor/forms/FormCheckboxPropertiesPanel";
|
|
import { FormRadioPropertiesPanel } from "@/app/editor/forms/FormRadioPropertiesPanel";
|
|
import type {
|
|
Block,
|
|
FormInputBlockProps,
|
|
FormSelectBlockProps,
|
|
FormCheckboxBlockProps,
|
|
FormRadioBlockProps,
|
|
} from "@/features/editor/state/editorStore";
|
|
|
|
// Form*PropertiesPanel 컨트롤 TDD
|
|
// - 각 패널의 색상 HEX 인풋과 필드 너비 셀렉트가 updateBlock 을 올바르게 호출하는지 검증한다.
|
|
|
|
function makeBlock<T extends Block["props"]>(id: string, type: Block["type"], props: T): Block {
|
|
return { id, type, props } as any;
|
|
}
|
|
|
|
describe("FormInputPropertiesPanel", () => {
|
|
const baseProps: FormInputBlockProps = {
|
|
label: "이메일",
|
|
formFieldName: "email",
|
|
} as any;
|
|
|
|
afterEach(() => {
|
|
cleanup();
|
|
});
|
|
|
|
it("텍스트 색상 HEX 인풋 변경 시 updateBlock 이 textColorCustom 으로 호출되어야 한다", () => {
|
|
const updateBlock = vi.fn();
|
|
|
|
const block = makeBlock<FormInputBlockProps>("f-input-1", "formInput", {
|
|
...baseProps,
|
|
textColorCustom: "#ffffff",
|
|
});
|
|
|
|
render(
|
|
<FormInputPropertiesPanel
|
|
block={block}
|
|
selectedBlockId="f-input-1"
|
|
updateBlock={updateBlock}
|
|
/>,
|
|
);
|
|
|
|
const hexInput = screen.getByLabelText("필드 텍스트 색상 HEX");
|
|
fireEvent.change(hexInput, { target: { value: "#112233" } });
|
|
|
|
expect(updateBlock).toHaveBeenCalledWith(
|
|
"f-input-1",
|
|
expect.objectContaining({ textColorCustom: "#112233" }),
|
|
);
|
|
});
|
|
|
|
it("채움 색상 HEX 인풋 변경 시 updateBlock 이 fillColorCustom 으로 호출되어야 한다", () => {
|
|
const updateBlock = vi.fn();
|
|
|
|
const block = makeBlock<FormInputBlockProps>("f-input-2", "formInput", {
|
|
...baseProps,
|
|
fillColorCustom: "#000000",
|
|
});
|
|
|
|
render(
|
|
<FormInputPropertiesPanel
|
|
block={block}
|
|
selectedBlockId="f-input-2"
|
|
updateBlock={updateBlock}
|
|
/>,
|
|
);
|
|
|
|
const hexInput = screen.getByLabelText("필드 채움 색상 HEX");
|
|
fireEvent.change(hexInput, { target: { value: "#445566" } });
|
|
|
|
expect(updateBlock).toHaveBeenCalledWith(
|
|
"f-input-2",
|
|
expect.objectContaining({ fillColorCustom: "#445566" }),
|
|
);
|
|
});
|
|
|
|
it("테두리 색상 HEX 인풋 변경 시 updateBlock 이 strokeColorCustom 으로 호출되어야 한다", () => {
|
|
const updateBlock = vi.fn();
|
|
|
|
const block = makeBlock<FormInputBlockProps>("f-input-3", "formInput", {
|
|
...baseProps,
|
|
strokeColorCustom: "#000000",
|
|
});
|
|
|
|
render(
|
|
<FormInputPropertiesPanel
|
|
block={block}
|
|
selectedBlockId="f-input-3"
|
|
updateBlock={updateBlock}
|
|
/>,
|
|
);
|
|
|
|
const hexInput = screen.getByLabelText("필드 테두리 색상 HEX");
|
|
fireEvent.change(hexInput, { target: { value: "#778899" } });
|
|
|
|
expect(updateBlock).toHaveBeenCalledWith(
|
|
"f-input-3",
|
|
expect.objectContaining({ strokeColorCustom: "#778899" }),
|
|
);
|
|
});
|
|
|
|
it("필드 너비 셀렉트 변경 시 updateBlock 이 widthMode 로 호출되어야 한다", () => {
|
|
const updateBlock = vi.fn();
|
|
|
|
const block = makeBlock<FormInputBlockProps>("f-input-4", "formInput", {
|
|
...baseProps,
|
|
widthMode: "auto",
|
|
fullWidth: false,
|
|
});
|
|
|
|
render(
|
|
<FormInputPropertiesPanel
|
|
block={block}
|
|
selectedBlockId="f-input-4"
|
|
updateBlock={updateBlock}
|
|
/>,
|
|
);
|
|
|
|
const select = screen.getByLabelText("너비");
|
|
fireEvent.change(select, { target: { value: "fixed" } });
|
|
|
|
expect(updateBlock).toHaveBeenCalledWith(
|
|
"f-input-4",
|
|
expect.objectContaining({ widthMode: "fixed" }),
|
|
);
|
|
});
|
|
|
|
it("FormInput 레이아웃 셀렉트는 라벨 표시 방식이 visible 일 때만 보여야 한다", () => {
|
|
const updateBlock = vi.fn();
|
|
|
|
const visibleBlock = makeBlock<FormInputBlockProps>("f-input-layout-visible", "formInput", {
|
|
...baseProps,
|
|
labelDisplay: "visible",
|
|
labelLayout: "inline",
|
|
} as any);
|
|
|
|
render(
|
|
<FormInputPropertiesPanel
|
|
block={visibleBlock}
|
|
selectedBlockId="f-input-layout-visible"
|
|
updateBlock={updateBlock}
|
|
/>,
|
|
);
|
|
|
|
const layoutSelect = screen.getByLabelText("레이아웃");
|
|
expect(layoutSelect).toBeTruthy();
|
|
|
|
cleanup();
|
|
|
|
const floatingBlock = makeBlock<FormInputBlockProps>("f-input-layout-floating", "formInput", {
|
|
...baseProps,
|
|
labelDisplay: "floating",
|
|
labelLayout: "inline",
|
|
} as any);
|
|
|
|
render(
|
|
<FormInputPropertiesPanel
|
|
block={floatingBlock}
|
|
selectedBlockId="f-input-layout-floating"
|
|
updateBlock={updateBlock}
|
|
/>,
|
|
);
|
|
|
|
expect(screen.queryByLabelText("레이아웃")).toBeNull();
|
|
});
|
|
|
|
it("폼 입력 텍스트/줄간격/자간 px 컨트롤이 fontSizeCustom/lineHeightCustom/letterSpacingCustom 으로 저장되어야 한다", () => {
|
|
const updateBlock = vi.fn();
|
|
|
|
const block = makeBlock<FormInputBlockProps>("f-input-typo-1", "formInput", {
|
|
...baseProps,
|
|
fontSizeCustom: "14px",
|
|
lineHeightCustom: "20px",
|
|
letterSpacingCustom: "0px",
|
|
} as any);
|
|
|
|
render(
|
|
<FormInputPropertiesPanel
|
|
block={block}
|
|
selectedBlockId="f-input-typo-1"
|
|
updateBlock={updateBlock}
|
|
/>,
|
|
);
|
|
|
|
const fontSizeInput = screen.getByLabelText("필드 텍스트 크기 (px) 커스텀 (px)");
|
|
fireEvent.change(fontSizeInput, { target: { value: "24" } });
|
|
|
|
const lineHeightInput = screen.getByLabelText("필드 줄간격 (px) 커스텀 (px)");
|
|
fireEvent.change(lineHeightInput, { target: { value: "30" } });
|
|
|
|
const letterSpacingInput = screen.getByLabelText("필드 자간 (px) 커스텀 (px)");
|
|
fireEvent.change(letterSpacingInput, { target: { value: "1.5" } });
|
|
|
|
expect(updateBlock).toHaveBeenCalledWith(
|
|
"f-input-typo-1",
|
|
expect.objectContaining({ fontSizeCustom: "24px" }),
|
|
);
|
|
expect(updateBlock).toHaveBeenCalledWith(
|
|
"f-input-typo-1",
|
|
expect.objectContaining({ lineHeightCustom: "30px" }),
|
|
);
|
|
expect(updateBlock).toHaveBeenCalledWith(
|
|
"f-input-typo-1",
|
|
expect.objectContaining({ letterSpacingCustom: "1.5px" }),
|
|
);
|
|
});
|
|
|
|
it("폼 입력 정렬/고정 너비/패딩 컨트롤이 align/widthPx/paddingX/paddingY 로 저장되어야 한다", () => {
|
|
const updateBlock = vi.fn();
|
|
|
|
const block = makeBlock<FormInputBlockProps>("f-input-layout-1", "formInput", {
|
|
...baseProps,
|
|
align: "left",
|
|
widthMode: "auto",
|
|
widthPx: 240,
|
|
paddingX: 12,
|
|
paddingY: 10,
|
|
} as any);
|
|
|
|
render(
|
|
<FormInputPropertiesPanel
|
|
block={block}
|
|
selectedBlockId="f-input-layout-1"
|
|
updateBlock={updateBlock}
|
|
/>,
|
|
);
|
|
|
|
const alignSelect = screen.getByLabelText("텍스트 정렬");
|
|
fireEvent.change(alignSelect, { target: { value: "center" } });
|
|
|
|
const widthModeSelect = screen.getByLabelText("너비");
|
|
fireEvent.change(widthModeSelect, { target: { value: "fixed" } });
|
|
|
|
const widthPxInput = screen.getByLabelText("필드 고정 너비 커스텀 (px)");
|
|
fireEvent.change(widthPxInput, { target: { value: "320" } });
|
|
|
|
const paddingXInput = screen.getByLabelText("필드 가로 패딩 (px) 커스텀 (px)");
|
|
fireEvent.change(paddingXInput, { target: { value: "16" } });
|
|
|
|
const paddingYInput = screen.getByLabelText("필드 세로 패딩 (px) 커스텀 (px)");
|
|
fireEvent.change(paddingYInput, { target: { value: "12" } });
|
|
|
|
expect(updateBlock).toHaveBeenCalledWith(
|
|
"f-input-layout-1",
|
|
expect.objectContaining({ align: "center" }),
|
|
);
|
|
expect(updateBlock).toHaveBeenCalledWith(
|
|
"f-input-layout-1",
|
|
expect.objectContaining({ widthMode: "fixed" }),
|
|
);
|
|
expect(updateBlock).toHaveBeenCalledWith(
|
|
"f-input-layout-1",
|
|
expect.objectContaining({ widthPx: 320 }),
|
|
);
|
|
expect(updateBlock).toHaveBeenCalledWith(
|
|
"f-input-layout-1",
|
|
expect.objectContaining({ paddingX: 16 }),
|
|
);
|
|
expect(updateBlock).toHaveBeenCalledWith(
|
|
"f-input-layout-1",
|
|
expect.objectContaining({ paddingY: 12 }),
|
|
);
|
|
});
|
|
});
|
|
|
|
describe("FormSelectPropertiesPanel", () => {
|
|
const baseProps: FormSelectBlockProps = {
|
|
label: "카테고리",
|
|
formFieldName: "category",
|
|
options: [{ label: "A", value: "a" }],
|
|
} as any;
|
|
|
|
afterEach(() => {
|
|
cleanup();
|
|
});
|
|
|
|
it("텍스트 색상 HEX 인풋 변경 시 updateBlock 이 textColorCustom 으로 호출되어야 한다", () => {
|
|
const updateBlock = vi.fn();
|
|
|
|
const block = makeBlock<FormSelectBlockProps>("f-select-1", "formSelect", {
|
|
...baseProps,
|
|
textColorCustom: "#ffffff",
|
|
});
|
|
|
|
render(
|
|
<FormSelectPropertiesPanel
|
|
block={block}
|
|
selectedBlockId="f-select-1"
|
|
updateBlock={updateBlock}
|
|
/>,
|
|
);
|
|
|
|
const hexInput = screen.getByLabelText("셀렉트 텍스트 색상 HEX");
|
|
fireEvent.change(hexInput, { target: { value: "#112233" } });
|
|
|
|
expect(updateBlock).toHaveBeenCalledWith(
|
|
"f-select-1",
|
|
expect.objectContaining({ textColorCustom: "#112233" }),
|
|
);
|
|
});
|
|
|
|
it("채움 색상 HEX 인풋 변경 시 updateBlock 이 fillColorCustom 으로 호출되어야 한다", () => {
|
|
const updateBlock = vi.fn();
|
|
|
|
const block = makeBlock<FormSelectBlockProps>("f-select-2", "formSelect", {
|
|
...baseProps,
|
|
fillColorCustom: "#000000",
|
|
});
|
|
|
|
render(
|
|
<FormSelectPropertiesPanel
|
|
block={block}
|
|
selectedBlockId="f-select-2"
|
|
updateBlock={updateBlock}
|
|
/>,
|
|
);
|
|
|
|
const hexInput = screen.getByLabelText("셀렉트 채움 색상 HEX");
|
|
fireEvent.change(hexInput, { target: { value: "#445566" } });
|
|
|
|
expect(updateBlock).toHaveBeenCalledWith(
|
|
"f-select-2",
|
|
expect.objectContaining({ fillColorCustom: "#445566" }),
|
|
);
|
|
});
|
|
|
|
it("테두리 색상 HEX 인풋 변경 시 updateBlock 이 strokeColorCustom 으로 호출되어야 한다", () => {
|
|
const updateBlock = vi.fn();
|
|
|
|
const block = makeBlock<FormSelectBlockProps>("f-select-3", "formSelect", {
|
|
...baseProps,
|
|
strokeColorCustom: "#000000",
|
|
});
|
|
|
|
render(
|
|
<FormSelectPropertiesPanel
|
|
block={block}
|
|
selectedBlockId="f-select-3"
|
|
updateBlock={updateBlock}
|
|
/>,
|
|
);
|
|
|
|
const hexInput = screen.getByLabelText("셀렉트 테두리 색상 HEX");
|
|
fireEvent.change(hexInput, { target: { value: "#778899" } });
|
|
|
|
expect(updateBlock).toHaveBeenCalledWith(
|
|
"f-select-3",
|
|
expect.objectContaining({ strokeColorCustom: "#778899" }),
|
|
);
|
|
});
|
|
|
|
it("필드 너비 셀렉트 변경 시 updateBlock 이 widthMode 로 호출되어야 한다", () => {
|
|
const updateBlock = vi.fn();
|
|
|
|
const block = makeBlock<FormSelectBlockProps>("f-select-4", "formSelect", {
|
|
...baseProps,
|
|
widthMode: "auto",
|
|
fullWidth: false,
|
|
});
|
|
|
|
render(
|
|
<FormSelectPropertiesPanel
|
|
block={block}
|
|
selectedBlockId="f-select-4"
|
|
updateBlock={updateBlock}
|
|
/>,
|
|
);
|
|
|
|
const select = screen.getByLabelText("필드 너비");
|
|
fireEvent.change(select, { target: { value: "fixed" } });
|
|
|
|
expect(updateBlock).toHaveBeenCalledWith(
|
|
"f-select-4",
|
|
expect.objectContaining({ widthMode: "fixed" }),
|
|
);
|
|
});
|
|
|
|
it("폼 셀렉트 텍스트/줄간격/자간 px 컨트롤이 fontSizeCustom/lineHeightCustom/letterSpacingCustom 으로 저장되어야 한다", () => {
|
|
const updateBlock = vi.fn();
|
|
|
|
const block = makeBlock<FormSelectBlockProps>("f-select-typo-1", "formSelect", {
|
|
...baseProps,
|
|
fontSizeCustom: "14px",
|
|
lineHeightCustom: "20px",
|
|
letterSpacingCustom: "0px",
|
|
} as any);
|
|
|
|
render(
|
|
<FormSelectPropertiesPanel
|
|
block={block}
|
|
selectedBlockId="f-select-typo-1"
|
|
updateBlock={updateBlock}
|
|
/>,
|
|
);
|
|
|
|
const fontSizeInput = screen.getByLabelText("셀렉트 텍스트 크기 (px) 커스텀 (px)");
|
|
fireEvent.change(fontSizeInput, { target: { value: "24" } });
|
|
|
|
const lineHeightInput = screen.getByLabelText("셀렉트 줄간격 (px) 커스텀 (px)");
|
|
fireEvent.change(lineHeightInput, { target: { value: "30" } });
|
|
|
|
const letterSpacingInput = screen.getByLabelText("셀렉트 자간 (px) 커스텀 (px)");
|
|
fireEvent.change(letterSpacingInput, { target: { value: "1.5" } });
|
|
|
|
expect(updateBlock).toHaveBeenCalledWith(
|
|
"f-select-typo-1",
|
|
expect.objectContaining({ fontSizeCustom: "24px" }),
|
|
);
|
|
expect(updateBlock).toHaveBeenCalledWith(
|
|
"f-select-typo-1",
|
|
expect.objectContaining({ lineHeightCustom: "30px" }),
|
|
);
|
|
expect(updateBlock).toHaveBeenCalledWith(
|
|
"f-select-typo-1",
|
|
expect.objectContaining({ letterSpacingCustom: "1.5px" }),
|
|
);
|
|
});
|
|
|
|
it("폼 셀렉트 너비/패딩 컨트롤이 widthPx/paddingX/paddingY 로 저장되어야 한다", () => {
|
|
const updateBlock = vi.fn();
|
|
|
|
const block = makeBlock<FormSelectBlockProps>("f-select-layout-1", "formSelect", {
|
|
...baseProps,
|
|
widthMode: "fixed",
|
|
widthPx: 240,
|
|
paddingX: 12,
|
|
paddingY: 10,
|
|
} as any);
|
|
|
|
render(
|
|
<FormSelectPropertiesPanel
|
|
block={block}
|
|
selectedBlockId="f-select-layout-1"
|
|
updateBlock={updateBlock}
|
|
/>,
|
|
);
|
|
|
|
const widthPxInput = screen.getByLabelText("필드 고정 너비 커스텀 (px)");
|
|
fireEvent.change(widthPxInput, { target: { value: "320" } });
|
|
|
|
const paddingXInput = screen.getByLabelText("셀렉트 가로 패딩 (px) 커스텀 (px)");
|
|
fireEvent.change(paddingXInput, { target: { value: "16" } });
|
|
|
|
const paddingYInput = screen.getByLabelText("셀렉트 세로 패딩 (px) 커스텀 (px)");
|
|
fireEvent.change(paddingYInput, { target: { value: "12" } });
|
|
|
|
expect(updateBlock).toHaveBeenCalledWith(
|
|
"f-select-layout-1",
|
|
expect.objectContaining({ widthPx: 320 }),
|
|
);
|
|
expect(updateBlock).toHaveBeenCalledWith(
|
|
"f-select-layout-1",
|
|
expect.objectContaining({ paddingX: 16 }),
|
|
);
|
|
expect(updateBlock).toHaveBeenCalledWith(
|
|
"f-select-layout-1",
|
|
expect.objectContaining({ paddingY: 12 }),
|
|
);
|
|
});
|
|
|
|
it("FormSelect 레이아웃 셀렉트는 라벨 표시 방식이 visible 일 때만 보여야 한다", () => {
|
|
const updateBlock = vi.fn();
|
|
|
|
const visibleBlock = makeBlock<FormSelectBlockProps>("f-select-layout-visible", "formSelect", {
|
|
...baseProps,
|
|
labelDisplay: "visible",
|
|
labelLayout: "inline",
|
|
} as any);
|
|
|
|
render(
|
|
<FormSelectPropertiesPanel
|
|
block={visibleBlock}
|
|
selectedBlockId="f-select-layout-visible"
|
|
updateBlock={updateBlock}
|
|
/>,
|
|
);
|
|
|
|
const layoutSelect = screen.getByLabelText("레이아웃");
|
|
expect(layoutSelect).toBeTruthy();
|
|
|
|
cleanup();
|
|
|
|
const hiddenBlock = makeBlock<FormSelectBlockProps>("f-select-layout-hidden", "formSelect", {
|
|
...baseProps,
|
|
labelDisplay: "hidden",
|
|
labelLayout: "inline",
|
|
} as any);
|
|
|
|
render(
|
|
<FormSelectPropertiesPanel
|
|
block={hiddenBlock}
|
|
selectedBlockId="f-select-layout-hidden"
|
|
updateBlock={updateBlock}
|
|
/>,
|
|
);
|
|
|
|
expect(screen.queryByLabelText("레이아웃")).toBeNull();
|
|
});
|
|
|
|
it("라벨 타입 셀렉트 변경 시 updateBlock 이 labelMode 로 호출되어야 한다", () => {
|
|
const updateBlock = vi.fn();
|
|
|
|
const block = makeBlock<FormSelectBlockProps>("f-select-label-mode", "formSelect", {
|
|
...baseProps,
|
|
labelMode: "text",
|
|
} as any);
|
|
|
|
render(
|
|
<FormSelectPropertiesPanel
|
|
block={block}
|
|
selectedBlockId="f-select-label-mode"
|
|
updateBlock={updateBlock}
|
|
/>,
|
|
);
|
|
|
|
const select = screen.getByLabelText("라벨 타입");
|
|
fireEvent.change(select, { target: { value: "image" } });
|
|
|
|
expect(updateBlock).toHaveBeenCalledWith(
|
|
"f-select-label-mode",
|
|
expect.objectContaining({ labelMode: "image" }),
|
|
);
|
|
});
|
|
|
|
it("라벨 표시 방식 셀렉트 변경 시 updateBlock 이 labelDisplay 로 호출되어야 한다", () => {
|
|
const updateBlock = vi.fn();
|
|
|
|
const block = makeBlock<FormSelectBlockProps>("f-select-label-display", "formSelect", {
|
|
...baseProps,
|
|
labelDisplay: "visible",
|
|
} as any);
|
|
|
|
render(
|
|
<FormSelectPropertiesPanel
|
|
block={block}
|
|
selectedBlockId="f-select-label-display"
|
|
updateBlock={updateBlock}
|
|
/>,
|
|
);
|
|
|
|
const select = screen.getByLabelText("라벨 표시 방식");
|
|
fireEvent.change(select, { target: { value: "hidden" } });
|
|
|
|
expect(updateBlock).toHaveBeenCalledWith(
|
|
"f-select-label-display",
|
|
expect.objectContaining({ labelDisplay: "hidden" }),
|
|
);
|
|
});
|
|
|
|
it("레이아웃 셀렉트 변경 시 updateBlock 이 labelLayout 으로 호출되어야 한다", () => {
|
|
const updateBlock = vi.fn();
|
|
|
|
const block = makeBlock<FormSelectBlockProps>("f-select-label-layout", "formSelect", {
|
|
...baseProps,
|
|
labelDisplay: "visible",
|
|
labelLayout: "stacked",
|
|
} as any);
|
|
|
|
render(
|
|
<FormSelectPropertiesPanel
|
|
block={block}
|
|
selectedBlockId="f-select-label-layout"
|
|
updateBlock={updateBlock}
|
|
/>,
|
|
);
|
|
|
|
const select = screen.getByLabelText("레이아웃");
|
|
fireEvent.change(select, { target: { value: "inline" } });
|
|
|
|
expect(updateBlock).toHaveBeenCalledWith(
|
|
"f-select-label-layout",
|
|
expect.objectContaining({ labelLayout: "inline" }),
|
|
);
|
|
});
|
|
|
|
it("라벨/필드 간격 (px) 컨트롤 변경 시 updateBlock 이 labelGapPx 로 호출되어야 한다", () => {
|
|
const updateBlock = vi.fn();
|
|
|
|
const block = makeBlock<FormSelectBlockProps>("f-select-label-gap", "formSelect", {
|
|
...baseProps,
|
|
labelDisplay: "visible",
|
|
labelLayout: "inline",
|
|
labelGapPx: 8,
|
|
} as any);
|
|
|
|
render(
|
|
<FormSelectPropertiesPanel
|
|
block={block}
|
|
selectedBlockId="f-select-label-gap"
|
|
updateBlock={updateBlock}
|
|
/>,
|
|
);
|
|
|
|
const gapInput = screen.getByLabelText("라벨/필드 간격 (px) 커스텀 (px)");
|
|
fireEvent.change(gapInput, { target: { value: "16" } });
|
|
|
|
expect(updateBlock).toHaveBeenCalledWith(
|
|
"f-select-label-gap",
|
|
expect.objectContaining({ labelGapPx: 16 }),
|
|
);
|
|
});
|
|
|
|
it("필드 라벨 인풋 변경 시 updateBlock 이 label 로 호출되어야 한다", () => {
|
|
const updateBlock = vi.fn();
|
|
|
|
const block = makeBlock<FormSelectBlockProps>("f-select-label", "formSelect", {
|
|
...baseProps,
|
|
label: "카테고리",
|
|
} as any);
|
|
|
|
render(
|
|
<FormSelectPropertiesPanel
|
|
block={block}
|
|
selectedBlockId="f-select-label"
|
|
updateBlock={updateBlock}
|
|
/>,
|
|
);
|
|
|
|
const input = screen.getByLabelText("필드 라벨");
|
|
fireEvent.change(input, { target: { value: "새 카테고리" } });
|
|
|
|
expect(updateBlock).toHaveBeenCalledWith(
|
|
"f-select-label",
|
|
expect.objectContaining({ label: "새 카테고리" }),
|
|
);
|
|
});
|
|
|
|
it("전송 키 인풋 변경 시 updateBlock 이 formFieldName 으로 호출되어야 한다", () => {
|
|
const updateBlock = vi.fn();
|
|
|
|
const block = makeBlock<FormSelectBlockProps>("f-select-name", "formSelect", {
|
|
...baseProps,
|
|
formFieldName: "category",
|
|
} as any);
|
|
|
|
render(
|
|
<FormSelectPropertiesPanel
|
|
block={block}
|
|
selectedBlockId="f-select-name"
|
|
updateBlock={updateBlock}
|
|
/>,
|
|
);
|
|
|
|
const input = screen.getByLabelText("전송 키");
|
|
fireEvent.change(input, { target: { value: "category_new" } });
|
|
|
|
expect(updateBlock).toHaveBeenCalledWith(
|
|
"f-select-name",
|
|
expect.objectContaining({ formFieldName: "category_new" }),
|
|
);
|
|
});
|
|
|
|
it("필드 모서리 둥글기 컨트롤 변경 시 updateBlock 이 borderRadius 로 호출되어야 한다", () => {
|
|
const updateBlock = vi.fn();
|
|
|
|
const block = makeBlock<FormSelectBlockProps>("f-select-radius", "formSelect", {
|
|
...baseProps,
|
|
borderRadius: "md",
|
|
} as any);
|
|
|
|
render(
|
|
<FormSelectPropertiesPanel
|
|
block={block}
|
|
selectedBlockId="f-select-radius"
|
|
updateBlock={updateBlock}
|
|
/>,
|
|
);
|
|
|
|
const radiusInput = screen.getByLabelText("필드 모서리 둥글기 커스텀");
|
|
fireEvent.change(radiusInput, { target: { value: "8" } });
|
|
|
|
expect(updateBlock).toHaveBeenCalledWith(
|
|
"f-select-radius",
|
|
expect.objectContaining({ borderRadius: "full" }),
|
|
);
|
|
});
|
|
});
|
|
|
|
describe("FormCheckboxPropertiesPanel", () => {
|
|
const baseProps: FormCheckboxBlockProps = {
|
|
groupLabel: "옵션들",
|
|
formFieldName: "features",
|
|
options: [{ label: "옵션 1", value: "opt1" }],
|
|
} as any;
|
|
|
|
afterEach(() => {
|
|
cleanup();
|
|
});
|
|
|
|
it("텍스트 색상 HEX 인풋 변경 시 updateBlock 이 textColorCustom 으로 호출되어야 한다", () => {
|
|
const updateBlock = vi.fn();
|
|
|
|
const block = makeBlock<FormCheckboxBlockProps>("f-check-1", "formCheckbox", {
|
|
...baseProps,
|
|
textColorCustom: "#ffffff",
|
|
});
|
|
|
|
render(
|
|
<FormCheckboxPropertiesPanel
|
|
block={block}
|
|
selectedBlockId="f-check-1"
|
|
updateBlock={updateBlock}
|
|
/>,
|
|
);
|
|
|
|
const hexInput = screen.getByLabelText("체크박스 텍스트 색상 HEX");
|
|
fireEvent.change(hexInput, { target: { value: "#112233" } });
|
|
|
|
expect(updateBlock).toHaveBeenCalledWith(
|
|
"f-check-1",
|
|
expect.objectContaining({ textColorCustom: "#112233" }),
|
|
);
|
|
});
|
|
|
|
it("폼 체크박스 텍스트/줄간격/자간 px 컨트롤이 fontSizeCustom/lineHeightCustom/letterSpacingCustom 으로 저장되어야 한다", () => {
|
|
const updateBlock = vi.fn();
|
|
|
|
const block = makeBlock<FormCheckboxBlockProps>("f-check-typo-1", "formCheckbox", {
|
|
...baseProps,
|
|
fontSizeCustom: "14px",
|
|
lineHeightCustom: "20px",
|
|
letterSpacingCustom: "0px",
|
|
} as any);
|
|
|
|
render(
|
|
<FormCheckboxPropertiesPanel
|
|
block={block}
|
|
selectedBlockId="f-check-typo-1"
|
|
updateBlock={updateBlock}
|
|
/>,
|
|
);
|
|
|
|
const fontSizeInput = screen.getByLabelText("체크박스 텍스트 크기 (px) 커스텀 (px)");
|
|
fireEvent.change(fontSizeInput, { target: { value: "24" } });
|
|
|
|
const lineHeightInput = screen.getByLabelText("체크박스 줄간격 (px) 커스텀 (px)");
|
|
fireEvent.change(lineHeightInput, { target: { value: "30" } });
|
|
|
|
const letterSpacingInput = screen.getByLabelText("체크박스 자간 (px) 커스텀 (px)");
|
|
fireEvent.change(letterSpacingInput, { target: { value: "1.5" } });
|
|
|
|
expect(updateBlock).toHaveBeenCalledWith(
|
|
"f-check-typo-1",
|
|
expect.objectContaining({ fontSizeCustom: "24px" }),
|
|
);
|
|
expect(updateBlock).toHaveBeenCalledWith(
|
|
"f-check-typo-1",
|
|
expect.objectContaining({ lineHeightCustom: "30px" }),
|
|
);
|
|
expect(updateBlock).toHaveBeenCalledWith(
|
|
"f-check-typo-1",
|
|
expect.objectContaining({ letterSpacingCustom: "1.5px" }),
|
|
);
|
|
});
|
|
|
|
it("폼 체크박스 너비/패딩 컨트롤이 widthPx/paddingX/paddingY 로 저장되어야 한다", () => {
|
|
const updateBlock = vi.fn();
|
|
|
|
const block = makeBlock<FormCheckboxBlockProps>("f-check-layout-1", "formCheckbox", {
|
|
...baseProps,
|
|
widthMode: "fixed",
|
|
widthPx: 240,
|
|
paddingX: 12,
|
|
paddingY: 10,
|
|
} as any);
|
|
|
|
render(
|
|
<FormCheckboxPropertiesPanel
|
|
block={block}
|
|
selectedBlockId="f-check-layout-1"
|
|
updateBlock={updateBlock}
|
|
/>,
|
|
);
|
|
|
|
const widthPxInput = screen.getByLabelText("필드 고정 너비 커스텀 (px)");
|
|
fireEvent.change(widthPxInput, { target: { value: "320" } });
|
|
|
|
const paddingXInput = screen.getByLabelText("체크박스 가로 패딩 (px) 커스텀 (px)");
|
|
fireEvent.change(paddingXInput, { target: { value: "16" } });
|
|
|
|
const paddingYInput = screen.getByLabelText("체크박스 세로 패딩 (px) 커스텀 (px)");
|
|
fireEvent.change(paddingYInput, { target: { value: "12" } });
|
|
|
|
expect(updateBlock).toHaveBeenCalledWith(
|
|
"f-check-layout-1",
|
|
expect.objectContaining({ widthPx: 320 }),
|
|
);
|
|
expect(updateBlock).toHaveBeenCalledWith(
|
|
"f-check-layout-1",
|
|
expect.objectContaining({ paddingX: 16 }),
|
|
);
|
|
expect(updateBlock).toHaveBeenCalledWith(
|
|
"f-check-layout-1",
|
|
expect.objectContaining({ paddingY: 12 }),
|
|
);
|
|
});
|
|
|
|
it("FormCheckbox 레이아웃 셀렉트는 그룹 라벨 표시 방식이 visible 일 때만 보여야 한다", () => {
|
|
const updateBlock = vi.fn();
|
|
|
|
const visibleBlock = makeBlock<FormCheckboxBlockProps>("f-check-layout-visible", "formCheckbox", {
|
|
...baseProps,
|
|
groupLabelDisplay: "visible",
|
|
labelLayout: "inline",
|
|
} as any);
|
|
|
|
render(
|
|
<FormCheckboxPropertiesPanel
|
|
block={visibleBlock}
|
|
selectedBlockId="f-check-layout-visible"
|
|
updateBlock={updateBlock}
|
|
/>,
|
|
);
|
|
|
|
const layoutSelect = screen.getByLabelText("레이아웃");
|
|
expect(layoutSelect).toBeTruthy();
|
|
|
|
cleanup();
|
|
|
|
const hiddenBlock = makeBlock<FormCheckboxBlockProps>("f-check-layout-hidden", "formCheckbox", {
|
|
...baseProps,
|
|
groupLabelDisplay: "hidden",
|
|
labelLayout: "inline",
|
|
} as any);
|
|
|
|
render(
|
|
<FormCheckboxPropertiesPanel
|
|
block={hiddenBlock}
|
|
selectedBlockId="f-check-layout-hidden"
|
|
updateBlock={updateBlock}
|
|
/>,
|
|
);
|
|
|
|
expect(screen.queryByLabelText("레이아웃")).toBeNull();
|
|
});
|
|
|
|
it("그룹 타이틀 타입 셀렉트 변경 시 updateBlock 이 groupLabelMode 로 호출되어야 한다", () => {
|
|
const updateBlock = vi.fn();
|
|
|
|
const block = makeBlock<FormCheckboxBlockProps>("f-check-group-mode", "formCheckbox", {
|
|
...baseProps,
|
|
groupLabelMode: "text",
|
|
} as any);
|
|
|
|
render(
|
|
<FormCheckboxPropertiesPanel
|
|
block={block}
|
|
selectedBlockId="f-check-group-mode"
|
|
updateBlock={updateBlock}
|
|
/>,
|
|
);
|
|
|
|
const select = screen.getByLabelText("그룹 타이틀 타입");
|
|
fireEvent.change(select, { target: { value: "image" } });
|
|
|
|
expect(updateBlock).toHaveBeenCalledWith(
|
|
"f-check-group-mode",
|
|
expect.objectContaining({ groupLabelMode: "image" }),
|
|
);
|
|
});
|
|
|
|
it("그룹 타이틀 표시 방식 셀렉트 변경 시 updateBlock 이 groupLabelDisplay 로 호출되어야 한다", () => {
|
|
const updateBlock = vi.fn();
|
|
|
|
const block = makeBlock<FormCheckboxBlockProps>("f-check-group-display", "formCheckbox", {
|
|
...baseProps,
|
|
groupLabelDisplay: "visible",
|
|
} as any);
|
|
|
|
render(
|
|
<FormCheckboxPropertiesPanel
|
|
block={block}
|
|
selectedBlockId="f-check-group-display"
|
|
updateBlock={updateBlock}
|
|
/>,
|
|
);
|
|
|
|
const select = screen.getByLabelText("그룹 타이틀 표시 방식");
|
|
fireEvent.change(select, { target: { value: "hidden" } });
|
|
|
|
expect(updateBlock).toHaveBeenCalledWith(
|
|
"f-check-group-display",
|
|
expect.objectContaining({ groupLabelDisplay: "hidden" }),
|
|
);
|
|
});
|
|
|
|
it("레이아웃 셀렉트 변경 시 updateBlock 이 labelLayout 으로 호출되어야 한다", () => {
|
|
const updateBlock = vi.fn();
|
|
|
|
const block = makeBlock<FormCheckboxBlockProps>("f-check-label-layout", "formCheckbox", {
|
|
...baseProps,
|
|
groupLabelDisplay: "visible",
|
|
labelLayout: "stacked",
|
|
} as any);
|
|
|
|
render(
|
|
<FormCheckboxPropertiesPanel
|
|
block={block}
|
|
selectedBlockId="f-check-label-layout"
|
|
updateBlock={updateBlock}
|
|
/>,
|
|
);
|
|
|
|
const select = screen.getByLabelText("레이아웃");
|
|
fireEvent.change(select, { target: { value: "inline" } });
|
|
|
|
expect(updateBlock).toHaveBeenCalledWith(
|
|
"f-check-label-layout",
|
|
expect.objectContaining({ labelLayout: "inline" }),
|
|
);
|
|
});
|
|
|
|
it("라벨/필드 간격 (px) 컨트롤 변경 시 updateBlock 이 labelGapPx 로 호출되어야 한다", () => {
|
|
const updateBlock = vi.fn();
|
|
|
|
const block = makeBlock<FormCheckboxBlockProps>("f-check-label-gap", "formCheckbox", {
|
|
...baseProps,
|
|
groupLabelDisplay: "visible",
|
|
labelLayout: "inline",
|
|
labelGapPx: 8,
|
|
} as any);
|
|
|
|
render(
|
|
<FormCheckboxPropertiesPanel
|
|
block={block}
|
|
selectedBlockId="f-check-label-gap"
|
|
updateBlock={updateBlock}
|
|
/>,
|
|
);
|
|
|
|
const gapInput = screen.getByLabelText("라벨/필드 간격 (px) 커스텀 (px)");
|
|
fireEvent.change(gapInput, { target: { value: "16" } });
|
|
|
|
expect(updateBlock).toHaveBeenCalledWith(
|
|
"f-check-label-gap",
|
|
expect.objectContaining({ labelGapPx: 16 }),
|
|
);
|
|
});
|
|
|
|
it("그룹 타이틀 인풋 변경 시 updateBlock 이 groupLabel 로 호출되어야 한다", () => {
|
|
const updateBlock = vi.fn();
|
|
|
|
const block = makeBlock<FormCheckboxBlockProps>("f-check-group-label", "formCheckbox", {
|
|
...baseProps,
|
|
groupLabel: "옵션들",
|
|
} as any);
|
|
|
|
render(
|
|
<FormCheckboxPropertiesPanel
|
|
block={block}
|
|
selectedBlockId="f-check-group-label"
|
|
updateBlock={updateBlock}
|
|
/>,
|
|
);
|
|
|
|
const input = screen.getByLabelText("그룹 타이틀");
|
|
fireEvent.change(input, { target: { value: "새 옵션들" } });
|
|
|
|
expect(updateBlock).toHaveBeenCalledWith(
|
|
"f-check-group-label",
|
|
expect.objectContaining({ groupLabel: "새 옵션들" }),
|
|
);
|
|
});
|
|
|
|
it("체크박스 옵션 간격 (px) 컨트롤 변경 시 updateBlock 이 optionGapPx 로 호출되어야 한다", () => {
|
|
const updateBlock = vi.fn();
|
|
|
|
const block = makeBlock<FormCheckboxBlockProps>("f-check-option-gap", "formCheckbox", {
|
|
...baseProps,
|
|
optionGapPx: 4,
|
|
} as any);
|
|
|
|
render(
|
|
<FormCheckboxPropertiesPanel
|
|
block={block}
|
|
selectedBlockId="f-check-option-gap"
|
|
updateBlock={updateBlock}
|
|
/>,
|
|
);
|
|
|
|
const gapInput = screen.getByLabelText("체크박스 옵션 간격 (px) 커스텀 (px)");
|
|
fireEvent.change(gapInput, { target: { value: "10" } });
|
|
|
|
expect(updateBlock).toHaveBeenCalledWith(
|
|
"f-check-option-gap",
|
|
expect.objectContaining({ optionGapPx: 10 }),
|
|
);
|
|
});
|
|
|
|
it("체크박스 옵션 레이아웃 셀렉트 변경 시 updateBlock 이 optionLayout 으로 호출되어야 한다", () => {
|
|
const updateBlock = vi.fn();
|
|
|
|
const block = makeBlock<FormCheckboxBlockProps>("f-check-option-layout", "formCheckbox", {
|
|
...baseProps,
|
|
optionLayout: "stacked",
|
|
} as any);
|
|
|
|
render(
|
|
<FormCheckboxPropertiesPanel
|
|
block={block}
|
|
selectedBlockId="f-check-option-layout"
|
|
updateBlock={updateBlock}
|
|
/>,
|
|
);
|
|
|
|
const select = screen.getByLabelText("옵션 레이아웃");
|
|
fireEvent.change(select, { target: { value: "inline" } });
|
|
|
|
expect(updateBlock).toHaveBeenCalledWith(
|
|
"f-check-option-layout",
|
|
expect.objectContaining({ optionLayout: "inline" }),
|
|
);
|
|
});
|
|
|
|
it("체크박스 필드 모서리 둥글기 컨트롤 변경 시 updateBlock 이 borderRadius 로 호출되어야 한다", () => {
|
|
const updateBlock = vi.fn();
|
|
|
|
const block = makeBlock<FormCheckboxBlockProps>("f-check-radius", "formCheckbox", {
|
|
...baseProps,
|
|
borderRadius: "md",
|
|
} as any);
|
|
|
|
render(
|
|
<FormCheckboxPropertiesPanel
|
|
block={block}
|
|
selectedBlockId="f-check-radius"
|
|
updateBlock={updateBlock}
|
|
/>,
|
|
);
|
|
|
|
const radiusInput = screen.getByLabelText("필드 모서리 둥글기 커스텀");
|
|
fireEvent.change(radiusInput, { target: { value: "8" } });
|
|
|
|
expect(updateBlock).toHaveBeenCalledWith(
|
|
"f-check-radius",
|
|
expect.objectContaining({ borderRadius: "full" }),
|
|
);
|
|
});
|
|
|
|
it("폼 라디오 텍스트/줄간격/자간 px 컨트롤이 fontSizeCustom/lineHeightCustom/letterSpacingCustom 으로 저장되어야 한다", () => {
|
|
const updateBlock = vi.fn();
|
|
|
|
const block = makeBlock<FormRadioBlockProps>("f-radio-typo-1", "formRadio", {
|
|
...baseProps,
|
|
fontSizeCustom: "14px",
|
|
lineHeightCustom: "20px",
|
|
letterSpacingCustom: "0px",
|
|
} as any);
|
|
|
|
render(
|
|
<FormRadioPropertiesPanel
|
|
block={block}
|
|
selectedBlockId="f-radio-typo-1"
|
|
updateBlock={updateBlock}
|
|
/>,
|
|
);
|
|
|
|
const fontSizeInput = screen.getByLabelText("라디오 텍스트 크기 (px) 커스텀 (px)");
|
|
fireEvent.change(fontSizeInput, { target: { value: "24" } });
|
|
|
|
const lineHeightInput = screen.getByLabelText("라디오 줄간격 (px) 커스텀 (px)");
|
|
fireEvent.change(lineHeightInput, { target: { value: "30" } });
|
|
|
|
const letterSpacingInput = screen.getByLabelText("라디오 자간 (px) 커스텀 (px)");
|
|
fireEvent.change(letterSpacingInput, { target: { value: "1.5" } });
|
|
|
|
expect(updateBlock).toHaveBeenCalledWith(
|
|
"f-radio-typo-1",
|
|
expect.objectContaining({ fontSizeCustom: "24px" }),
|
|
);
|
|
expect(updateBlock).toHaveBeenCalledWith(
|
|
"f-radio-typo-1",
|
|
expect.objectContaining({ lineHeightCustom: "30px" }),
|
|
);
|
|
expect(updateBlock).toHaveBeenCalledWith(
|
|
"f-radio-typo-1",
|
|
expect.objectContaining({ letterSpacingCustom: "1.5px" }),
|
|
);
|
|
});
|
|
|
|
it("폼 라디오 너비/패딩/옵션 간격 컨트롤이 widthPx/paddingX/paddingY/optionGapPx 로 저장되어야 한다", () => {
|
|
const updateBlock = vi.fn();
|
|
|
|
const block = makeBlock<FormRadioBlockProps>("f-radio-layout-1", "formRadio", {
|
|
...baseProps,
|
|
widthMode: "fixed",
|
|
widthPx: 240,
|
|
paddingX: 8,
|
|
paddingY: 4,
|
|
optionGapPx: 8,
|
|
} as any);
|
|
|
|
render(
|
|
<FormRadioPropertiesPanel
|
|
block={block}
|
|
selectedBlockId="f-radio-layout-1"
|
|
updateBlock={updateBlock}
|
|
/>,
|
|
);
|
|
|
|
const widthPxInput = screen.getByLabelText("필드 고정 너비 커스텀 (px)");
|
|
fireEvent.change(widthPxInput, { target: { value: "320" } });
|
|
|
|
const paddingXInput = screen.getByLabelText("라디오 가로 패딩 (px) 커스텀 (px)");
|
|
fireEvent.change(paddingXInput, { target: { value: "12" } });
|
|
|
|
const paddingYInput = screen.getByLabelText("라디오 세로 패딩 (px) 커스텀 (px)");
|
|
fireEvent.change(paddingYInput, { target: { value: "6" } });
|
|
|
|
const optionGapInput = screen.getByLabelText("라디오 옵션 간격 (px) 커스텀 (px)");
|
|
fireEvent.change(optionGapInput, { target: { value: "10" } });
|
|
|
|
expect(updateBlock).toHaveBeenCalledWith(
|
|
"f-radio-layout-1",
|
|
expect.objectContaining({ widthPx: 320 }),
|
|
);
|
|
expect(updateBlock).toHaveBeenCalledWith(
|
|
"f-radio-layout-1",
|
|
expect.objectContaining({ paddingX: 12 }),
|
|
);
|
|
expect(updateBlock).toHaveBeenCalledWith(
|
|
"f-radio-layout-1",
|
|
expect.objectContaining({ paddingY: 6 }),
|
|
);
|
|
expect(updateBlock).toHaveBeenCalledWith(
|
|
"f-radio-layout-1",
|
|
expect.objectContaining({ optionGapPx: 10 }),
|
|
);
|
|
});
|
|
|
|
it("FormRadio 그룹 타이틀 레이아웃 셀렉트는 그룹 타이틀 표시 방식이 visible 일 때만 보여야 한다", () => {
|
|
const updateBlock = vi.fn();
|
|
|
|
const visibleBlock = makeBlock<FormRadioBlockProps>("f-radio-layout-visible", "formRadio", {
|
|
...baseProps,
|
|
groupLabelDisplay: "visible",
|
|
labelLayout: "inline",
|
|
} as any);
|
|
|
|
render(
|
|
<FormRadioPropertiesPanel
|
|
block={visibleBlock}
|
|
selectedBlockId="f-radio-layout-visible"
|
|
updateBlock={updateBlock}
|
|
/>,
|
|
);
|
|
|
|
const layoutSelect = screen.getByLabelText("그룹 타이틀 레이아웃");
|
|
expect(layoutSelect).toBeTruthy();
|
|
|
|
cleanup();
|
|
|
|
const hiddenBlock = makeBlock<FormRadioBlockProps>("f-radio-layout-hidden", "formRadio", {
|
|
...baseProps,
|
|
groupLabelDisplay: "hidden",
|
|
labelLayout: "inline",
|
|
} as any);
|
|
|
|
render(
|
|
<FormRadioPropertiesPanel
|
|
block={hiddenBlock}
|
|
selectedBlockId="f-radio-layout-hidden"
|
|
updateBlock={updateBlock}
|
|
/>,
|
|
);
|
|
|
|
expect(screen.queryByLabelText("그룹 타이틀 레이아웃")).toBeNull();
|
|
});
|
|
|
|
it("그룹 타이틀 타입 셀렉트 변경 시 updateBlock 이 groupLabelMode 로 호출되어야 한다", () => {
|
|
const updateBlock = vi.fn();
|
|
|
|
const block = makeBlock<FormRadioBlockProps>("f-radio-group-mode", "formRadio", {
|
|
...baseProps,
|
|
groupLabelMode: "text",
|
|
} as any);
|
|
|
|
render(
|
|
<FormRadioPropertiesPanel
|
|
block={block}
|
|
selectedBlockId="f-radio-group-mode"
|
|
updateBlock={updateBlock}
|
|
/>,
|
|
);
|
|
|
|
const select = screen.getByLabelText("그룹 타이틀 타입");
|
|
fireEvent.change(select, { target: { value: "image" } });
|
|
|
|
expect(updateBlock).toHaveBeenCalledWith(
|
|
"f-radio-group-mode",
|
|
expect.objectContaining({ groupLabelMode: "image" }),
|
|
);
|
|
});
|
|
|
|
it("그룹 타이틀 표시 방식 셀렉트 변경 시 updateBlock 이 groupLabelDisplay 로 호출되어야 한다", () => {
|
|
const updateBlock = vi.fn();
|
|
|
|
const block = makeBlock<FormRadioBlockProps>("f-radio-group-display", "formRadio", {
|
|
...baseProps,
|
|
groupLabelDisplay: "visible",
|
|
} as any);
|
|
|
|
render(
|
|
<FormRadioPropertiesPanel
|
|
block={block}
|
|
selectedBlockId="f-radio-group-display"
|
|
updateBlock={updateBlock}
|
|
/>,
|
|
);
|
|
|
|
const select = screen.getByLabelText("그룹 타이틀 표시 방식");
|
|
fireEvent.change(select, { target: { value: "hidden" } });
|
|
|
|
expect(updateBlock).toHaveBeenCalledWith(
|
|
"f-radio-group-display",
|
|
expect.objectContaining({ groupLabelDisplay: "hidden" }),
|
|
);
|
|
});
|
|
|
|
it("그룹 타이틀 레이아웃 셀렉트 변경 시 updateBlock 이 labelLayout 으로 호출되어야 한다", () => {
|
|
const updateBlock = vi.fn();
|
|
|
|
const block = makeBlock<FormRadioBlockProps>("f-radio-label-layout", "formRadio", {
|
|
...baseProps,
|
|
groupLabelDisplay: "visible",
|
|
labelLayout: "stacked",
|
|
} as any);
|
|
|
|
render(
|
|
<FormRadioPropertiesPanel
|
|
block={block}
|
|
selectedBlockId="f-radio-label-layout"
|
|
updateBlock={updateBlock}
|
|
/>,
|
|
);
|
|
|
|
const select = screen.getByLabelText("그룹 타이틀 레이아웃");
|
|
fireEvent.change(select, { target: { value: "inline" } });
|
|
|
|
expect(updateBlock).toHaveBeenCalledWith(
|
|
"f-radio-label-layout",
|
|
expect.objectContaining({ labelLayout: "inline" }),
|
|
);
|
|
});
|
|
|
|
it("라벨/필드 간격 (px) 컨트롤 변경 시 updateBlock 이 labelGapPx 로 호출되어야 한다", () => {
|
|
const updateBlock = vi.fn();
|
|
|
|
const block = makeBlock<FormRadioBlockProps>("f-radio-label-gap", "formRadio", {
|
|
...baseProps,
|
|
groupLabelDisplay: "visible",
|
|
labelLayout: "inline",
|
|
labelGapPx: 8,
|
|
} as any);
|
|
|
|
render(
|
|
<FormRadioPropertiesPanel
|
|
block={block}
|
|
selectedBlockId="f-radio-label-gap"
|
|
updateBlock={updateBlock}
|
|
/>,
|
|
);
|
|
|
|
const gapInput = screen.getByLabelText("라벨/필드 간격 (px) 커스텀 (px)");
|
|
fireEvent.change(gapInput, { target: { value: "16" } });
|
|
|
|
expect(updateBlock).toHaveBeenCalledWith(
|
|
"f-radio-label-gap",
|
|
expect.objectContaining({ labelGapPx: 16 }),
|
|
);
|
|
});
|
|
|
|
it("그룹 타이틀 인풋 변경 시 updateBlock 이 groupLabel 로 호출되어야 한다", () => {
|
|
const updateBlock = vi.fn();
|
|
|
|
const block = makeBlock<FormRadioBlockProps>("f-radio-group-label", "formRadio", {
|
|
...baseProps,
|
|
groupLabel: "플랜",
|
|
} as any);
|
|
|
|
render(
|
|
<FormRadioPropertiesPanel
|
|
block={block}
|
|
selectedBlockId="f-radio-group-label"
|
|
updateBlock={updateBlock}
|
|
/>,
|
|
);
|
|
|
|
const input = screen.getByLabelText("그룹 타이틀");
|
|
fireEvent.change(input, { target: { value: "새 플랜" } });
|
|
|
|
expect(updateBlock).toHaveBeenCalledWith(
|
|
"f-radio-group-label",
|
|
expect.objectContaining({ groupLabel: "새 플랜" }),
|
|
);
|
|
});
|
|
|
|
it("그룹 타이틀 이미지 소스 셀렉트 변경 시 updateBlock 이 groupLabelImageSource 로 호출되어야 한다", () => {
|
|
const updateBlock = vi.fn();
|
|
|
|
const block = makeBlock<FormRadioBlockProps>("f-radio-group-image-source", "formRadio", {
|
|
...baseProps,
|
|
groupLabelMode: "image",
|
|
groupLabelImageSource: "url",
|
|
} as any);
|
|
|
|
render(
|
|
<FormRadioPropertiesPanel
|
|
block={block}
|
|
selectedBlockId="f-radio-group-image-source"
|
|
updateBlock={updateBlock}
|
|
/>,
|
|
);
|
|
|
|
const select = screen.getByLabelText("그룹 타이틀 이미지 소스");
|
|
fireEvent.change(select, { target: { value: "upload" } });
|
|
|
|
expect(updateBlock).toHaveBeenCalledWith(
|
|
"f-radio-group-image-source",
|
|
expect.objectContaining({ groupLabelImageSource: "upload" }),
|
|
);
|
|
});
|
|
|
|
it("그룹 타이틀 이미지 URL 인풋 변경 시 updateBlock 이 groupLabelImageUrl 로 호출되어야 한다", () => {
|
|
const updateBlock = vi.fn();
|
|
|
|
const block = makeBlock<FormRadioBlockProps>("f-radio-group-image-url", "formRadio", {
|
|
...baseProps,
|
|
groupLabelMode: "image",
|
|
groupLabelImageSource: "url",
|
|
groupLabelImageUrl: "https://example.com/old.png",
|
|
} as any);
|
|
|
|
render(
|
|
<FormRadioPropertiesPanel
|
|
block={block}
|
|
selectedBlockId="f-radio-group-image-url"
|
|
updateBlock={updateBlock}
|
|
/>,
|
|
);
|
|
|
|
const input = screen.getByLabelText("그룹 타이틀 이미지 URL");
|
|
fireEvent.change(input, { target: { value: "https://example.com/new.png" } });
|
|
|
|
expect(updateBlock).toHaveBeenCalledWith(
|
|
"f-radio-group-image-url",
|
|
expect.objectContaining({ groupLabelImageUrl: "https://example.com/new.png" }),
|
|
);
|
|
});
|
|
|
|
it("옵션 이미지 소스 셀렉트 변경 시 updateBlock 이 optionImageSource 로 호출되어야 한다", () => {
|
|
const updateBlock = vi.fn();
|
|
|
|
const block = makeBlock<FormRadioBlockProps>("f-radio-option-image-source", "formRadio", {
|
|
...baseProps,
|
|
optionImageSource: "url",
|
|
} as any);
|
|
|
|
render(
|
|
<FormRadioPropertiesPanel
|
|
block={block}
|
|
selectedBlockId="f-radio-option-image-source"
|
|
updateBlock={updateBlock}
|
|
/>,
|
|
);
|
|
|
|
const select = screen.getByLabelText("옵션 이미지 소스");
|
|
fireEvent.change(select, { target: { value: "upload" } });
|
|
|
|
expect(updateBlock).toHaveBeenCalledWith(
|
|
"f-radio-option-image-source",
|
|
expect.objectContaining({ optionImageSource: "upload" }),
|
|
);
|
|
});
|
|
|
|
it("라디오 배경 색상 HEX 인풋 변경 시 updateBlock 이 fillColorCustom 으로 호출되어야 한다", () => {
|
|
const updateBlock = vi.fn();
|
|
|
|
const block = makeBlock<FormRadioBlockProps>("f-radio-fill-color", "formRadio", {
|
|
...baseProps,
|
|
fillColorCustom: "#000000",
|
|
} as any);
|
|
|
|
render(
|
|
<FormRadioPropertiesPanel
|
|
block={block}
|
|
selectedBlockId="f-radio-fill-color"
|
|
updateBlock={updateBlock}
|
|
/>,
|
|
);
|
|
|
|
const hexInput = screen.getByLabelText("라디오 배경 색상 HEX");
|
|
fireEvent.change(hexInput, { target: { value: "#445566" } });
|
|
|
|
expect(updateBlock).toHaveBeenCalledWith(
|
|
"f-radio-fill-color",
|
|
expect.objectContaining({ fillColorCustom: "#445566" }),
|
|
);
|
|
});
|
|
|
|
it("라디오 테두리 색상 HEX 인풋 변경 시 updateBlock 이 strokeColorCustom 으로 호출되어야 한다", () => {
|
|
const updateBlock = vi.fn();
|
|
|
|
const block = makeBlock<FormRadioBlockProps>("f-radio-stroke-color", "formRadio", {
|
|
...baseProps,
|
|
strokeColorCustom: "#000000",
|
|
} as any);
|
|
|
|
render(
|
|
<FormRadioPropertiesPanel
|
|
block={block}
|
|
selectedBlockId="f-radio-stroke-color"
|
|
updateBlock={updateBlock}
|
|
/>,
|
|
);
|
|
|
|
const hexInput = screen.getByLabelText("라디오 테두리 색상 HEX");
|
|
fireEvent.change(hexInput, { target: { value: "#778899" } });
|
|
|
|
expect(updateBlock).toHaveBeenCalledWith(
|
|
"f-radio-stroke-color",
|
|
expect.objectContaining({ strokeColorCustom: "#778899" }),
|
|
);
|
|
});
|
|
|
|
it("라디오 필드 모서리 둥글기 컨트롤 변경 시 updateBlock 이 borderRadius 로 호출되어야 한다", () => {
|
|
const updateBlock = vi.fn();
|
|
|
|
const block = makeBlock<FormRadioBlockProps>("f-radio-radius", "formRadio", {
|
|
...baseProps,
|
|
borderRadius: "md",
|
|
} as any);
|
|
|
|
render(
|
|
<FormRadioPropertiesPanel
|
|
block={block}
|
|
selectedBlockId="f-radio-radius"
|
|
updateBlock={updateBlock}
|
|
/>,
|
|
);
|
|
|
|
const radiusInput = screen.getByLabelText("필드 모서리 둥글기 커스텀");
|
|
fireEvent.change(radiusInput, { target: { value: "8" } });
|
|
|
|
expect(updateBlock).toHaveBeenCalledWith(
|
|
"f-radio-radius",
|
|
expect.objectContaining({ borderRadius: "full" }),
|
|
);
|
|
});
|
|
});
|