메인 플랜 및 에디터/폼 관련 변경 사항 main에 머지
This commit is contained in:
@@ -137,6 +137,34 @@ test("텍스트 블록의 정렬과 글자 크기를 속성 패널에서 변경
|
||||
await expect(block).toHaveClass(/text-lg/);
|
||||
});
|
||||
|
||||
test("텍스트 블록 인라인 툴바에서 정렬과 글자 크기를 변경할 수 있어야 한다", async ({ page }) => {
|
||||
test.skip(process.env.CI === "true");
|
||||
await page.goto("/editor");
|
||||
|
||||
// 텍스트 블록을 하나 추가한다.
|
||||
await page.getByRole("button", { name: "텍스트 블록 추가" }).click();
|
||||
|
||||
const canvas = page.getByTestId("editor-canvas");
|
||||
const block = canvas.getByTestId("editor-block").nth(0);
|
||||
|
||||
// 더블클릭하여 인라인 편집 모드로 진입한다.
|
||||
await block.dblclick({ force: true });
|
||||
|
||||
// 인라인 툴바 버튼을 이용해 가운데 정렬 및 큰 글자 크기로 변경한다.
|
||||
const centerAlignButton = page.getByRole("button", { name: "가운데 정렬" });
|
||||
const largeSizeButton = page.getByRole("button", { name: "글자 크게" });
|
||||
|
||||
await centerAlignButton.click();
|
||||
await largeSizeButton.click();
|
||||
|
||||
// 편집을 종료하기 위해 블록 밖을 클릭한다.
|
||||
await canvas.click({ position: { x: 5, y: 5 } });
|
||||
|
||||
// 캔버스 블록에 text-center 와 text-lg 클래스가 적용되어 있어야 한다.
|
||||
await expect(block).toHaveClass(/text-center/);
|
||||
await expect(block).toHaveClass(/text-lg/);
|
||||
});
|
||||
|
||||
test("에디터 상태를 JSON으로 내보내고 다시 불러오면 동일한 블록 상태가 복원되어야 한다", async ({ page }) => {
|
||||
test.skip(process.env.CI === "true");
|
||||
await page.goto("/editor");
|
||||
|
||||
@@ -0,0 +1,94 @@
|
||||
import { describe, it, expect, vi } from "vitest";
|
||||
import { render, screen, fireEvent } from "@testing-library/react";
|
||||
import { PropertySliderField } from "@/features/editor/components/PropertySliderField";
|
||||
import { ColorPickerField } from "@/features/editor/components/ColorPickerField";
|
||||
|
||||
// 슬라이더 필드가 라벨과 슬라이더, 입력 박스를 렌더링하고 onChange를 호출하는지 테스트
|
||||
|
||||
describe("PropertySliderField", () => {
|
||||
it("라벨과 슬라이더, 텍스트 입력을 렌더링한다", () => {
|
||||
const handleChange = vi.fn();
|
||||
|
||||
render(
|
||||
<PropertySliderField
|
||||
label="글자 크기"
|
||||
ariaLabelSlider="글자 크기 슬라이더"
|
||||
ariaLabelInput="글자 크기 커스텀"
|
||||
value={16}
|
||||
min={10}
|
||||
max={72}
|
||||
step={1}
|
||||
onChange={handleChange}
|
||||
/>,
|
||||
);
|
||||
|
||||
expect(screen.getByText("글자 크기")).toBeInTheDocument();
|
||||
expect(screen.getByLabelText("글자 크기 슬라이더")).toBeInTheDocument();
|
||||
expect(screen.getByLabelText("글자 크기 커스텀")).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("슬라이더 변경 시 onChange가 호출된다", () => {
|
||||
const handleChange = vi.fn();
|
||||
|
||||
render(
|
||||
<PropertySliderField
|
||||
label="줄 간격"
|
||||
ariaLabelSlider="줄 간격 슬라이더"
|
||||
ariaLabelInput="줄 간격 커스텀"
|
||||
value={1.5}
|
||||
min={0.5}
|
||||
max={3}
|
||||
step={0.1}
|
||||
onChange={handleChange}
|
||||
/>,
|
||||
);
|
||||
|
||||
const slider = screen.getByLabelText("줄 간격 슬라이더") as HTMLInputElement;
|
||||
fireEvent.change(slider, { target: { value: "2" } });
|
||||
|
||||
expect(handleChange).toHaveBeenCalledWith(2);
|
||||
});
|
||||
});
|
||||
|
||||
// 컬러 피커 필드가 컬러 인풋과 텍스트 입력, 팔레트 버튼을 렌더링하고 상호작용 되는지 테스트
|
||||
|
||||
describe("ColorPickerField", () => {
|
||||
it("HEX 인풋과 컬러 인풋을 렌더링한다", () => {
|
||||
const handleChange = vi.fn();
|
||||
|
||||
render(
|
||||
<ColorPickerField
|
||||
label="텍스트 색상"
|
||||
ariaLabelColorInput="텍스트 색상 피커"
|
||||
ariaLabelHexInput="텍스트 색상 HEX"
|
||||
value="#ffffff"
|
||||
onChange={handleChange}
|
||||
palette={[{ id: "default", label: "기본", color: "#e5e7eb" }]}
|
||||
/>,
|
||||
);
|
||||
|
||||
expect(screen.getByText("텍스트 색상")).toBeInTheDocument();
|
||||
expect(screen.getByLabelText("텍스트 색상 피커")).toBeInTheDocument();
|
||||
expect(screen.getByLabelText("텍스트 색상 HEX")).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("컬러 인풋 변경 시 onChange가 호출된다", () => {
|
||||
const handleChange = vi.fn();
|
||||
|
||||
render(
|
||||
<ColorPickerField
|
||||
label="텍스트 색상"
|
||||
ariaLabelColorInput="텍스트 색상 피커"
|
||||
ariaLabelHexInput="텍스트 색상 HEX"
|
||||
value="#ffffff"
|
||||
onChange={handleChange}
|
||||
palette={[{ id: "default", label: "기본", color: "#e5e7eb" }]}
|
||||
/>,
|
||||
);
|
||||
|
||||
const colorInput = screen.getByLabelText("텍스트 색상 피커") as HTMLInputElement;
|
||||
fireEvent.change(colorInput, { target: { value: "#000000" } });
|
||||
|
||||
expect(handleChange).toHaveBeenCalledWith("#000000");
|
||||
});
|
||||
});
|
||||
@@ -25,6 +25,27 @@ describe("editorStore", () => {
|
||||
expect(selectedBlockId).toBe(blocks[0].id);
|
||||
});
|
||||
|
||||
it("텍스트 블록에 글자 간격(letterSpacingCustom)을 em 단위로 설정할 수 있어야 한다", () => {
|
||||
const store = createEditorStore();
|
||||
|
||||
store.getState().addTextBlock();
|
||||
|
||||
const { blocks } = store.getState();
|
||||
const textBlock = blocks[0];
|
||||
const textProps = textBlock.props as TextBlockProps;
|
||||
|
||||
expect(textProps.letterSpacingCustom).toBeUndefined();
|
||||
|
||||
store.getState().updateBlock(textBlock.id, {
|
||||
letterSpacingCustom: "0.05em",
|
||||
} as any);
|
||||
|
||||
const { blocks: updatedBlocks } = store.getState();
|
||||
const updatedTextProps = updatedBlocks[0].props as TextBlockProps;
|
||||
|
||||
expect(updatedTextProps.letterSpacingCustom).toBe("0.05em");
|
||||
});
|
||||
|
||||
it("구분선 블록을 추가하면 기본 align/thickness 와 함께 추가되고 선택되어야 한다", () => {
|
||||
const store = createEditorStore();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user