video 블록 및 리펙터링
This commit is contained in:
@@ -0,0 +1,296 @@
|
||||
import { describe, it, expect, vi, afterEach } from "vitest";
|
||||
import { render, screen, fireEvent, cleanup } from "@testing-library/react";
|
||||
import { VideoPropertiesPanel } from "@/app/editor/panels/VideoPropertiesPanel";
|
||||
import type { VideoBlockProps } from "@/features/editor/state/editorStore";
|
||||
|
||||
// VideoPropertiesPanel 컨트롤 TDD
|
||||
// - 비디오 URL 인풋/정렬/너비 모드/화면 비율 컨트롤이 updateBlock 을 올바르게 호출하는지 검증한다.
|
||||
|
||||
describe("VideoPropertiesPanel", () => {
|
||||
const baseProps: VideoBlockProps = {
|
||||
sourceUrl: "https://www.youtube.com/watch?v=dQw4w9WgXcQ",
|
||||
align: "center",
|
||||
widthMode: "auto",
|
||||
aspectRatio: "16:9",
|
||||
};
|
||||
|
||||
afterEach(() => {
|
||||
cleanup();
|
||||
});
|
||||
|
||||
it("비디오 URL 인풋 변경 시 updateBlock 이 sourceUrl / sourceType / assetId 로 호출되어야 한다", () => {
|
||||
const updateBlock = vi.fn();
|
||||
|
||||
render(
|
||||
<VideoPropertiesPanel
|
||||
videoProps={{ ...baseProps, sourceType: "externalUrl" }}
|
||||
selectedBlockId="video-1"
|
||||
updateBlock={updateBlock}
|
||||
/>,
|
||||
);
|
||||
|
||||
const urlInput = screen.getByLabelText("비디오 URL");
|
||||
fireEvent.change(urlInput, { target: { value: "https://example.com/video.mp4" } });
|
||||
|
||||
expect(updateBlock).toHaveBeenCalledWith(
|
||||
"video-1",
|
||||
expect.objectContaining({
|
||||
sourceUrl: "https://example.com/video.mp4",
|
||||
sourceType: "externalUrl",
|
||||
assetId: null,
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
it("정렬 셀렉트 변경 시 updateBlock 이 align 으로 호출되어야 한다", () => {
|
||||
const updateBlock = vi.fn();
|
||||
|
||||
render(
|
||||
<VideoPropertiesPanel
|
||||
videoProps={{ ...baseProps, align: "center" }}
|
||||
selectedBlockId="video-2"
|
||||
updateBlock={updateBlock}
|
||||
/>,
|
||||
);
|
||||
|
||||
const select = screen.getByLabelText("비디오 정렬");
|
||||
fireEvent.change(select, { target: { value: "left" } });
|
||||
|
||||
expect(updateBlock).toHaveBeenCalledWith(
|
||||
"video-2",
|
||||
expect.objectContaining({ align: "left" }),
|
||||
);
|
||||
});
|
||||
|
||||
it("너비 모드 셀렉트 변경 시 updateBlock 이 widthMode 로 호출되어야 한다", () => {
|
||||
const updateBlock = vi.fn();
|
||||
|
||||
render(
|
||||
<VideoPropertiesPanel
|
||||
videoProps={{ ...baseProps, widthMode: "auto" }}
|
||||
selectedBlockId="video-3"
|
||||
updateBlock={updateBlock}
|
||||
/>,
|
||||
);
|
||||
|
||||
const select = screen.getByLabelText("비디오 너비 모드");
|
||||
fireEvent.change(select, { target: { value: "fixed" } });
|
||||
|
||||
expect(updateBlock).toHaveBeenCalledWith(
|
||||
"video-3",
|
||||
expect.objectContaining({ widthMode: "fixed" }),
|
||||
);
|
||||
});
|
||||
|
||||
it("화면 비율 셀렉트 변경 시 updateBlock 이 aspectRatio 로 호출되어야 한다", () => {
|
||||
const updateBlock = vi.fn();
|
||||
|
||||
render(
|
||||
<VideoPropertiesPanel
|
||||
videoProps={{ ...baseProps, aspectRatio: "16:9" }}
|
||||
selectedBlockId="video-4"
|
||||
updateBlock={updateBlock}
|
||||
/>,
|
||||
);
|
||||
|
||||
const select = screen.getByLabelText("화면 비율");
|
||||
fireEvent.change(select, { target: { value: "4:3" } });
|
||||
|
||||
expect(updateBlock).toHaveBeenCalledWith(
|
||||
"video-4",
|
||||
expect.objectContaining({ aspectRatio: "4:3" }),
|
||||
);
|
||||
});
|
||||
|
||||
it("카드 배경색 HEX 인풋 변경 시 updateBlock 이 backgroundColorCustom 으로 호출되어야 한다", () => {
|
||||
const updateBlock = vi.fn();
|
||||
|
||||
render(
|
||||
<VideoPropertiesPanel
|
||||
videoProps={{ ...baseProps, sourceType: "externalUrl" }}
|
||||
selectedBlockId="video-card-1"
|
||||
updateBlock={updateBlock}
|
||||
/>,
|
||||
);
|
||||
|
||||
const hexInput = screen.getByLabelText("비디오 카드 배경색 HEX");
|
||||
fireEvent.change(hexInput, { target: { value: "#123456" } });
|
||||
|
||||
expect(updateBlock).toHaveBeenCalledWith(
|
||||
"video-card-1",
|
||||
expect.objectContaining({ backgroundColorCustom: "#123456" }),
|
||||
);
|
||||
});
|
||||
|
||||
it("카드 패딩 슬라이더 변경 시 updateBlock 이 cardPaddingPx 로 호출되어야 한다", () => {
|
||||
const updateBlock = vi.fn();
|
||||
|
||||
render(
|
||||
<VideoPropertiesPanel
|
||||
videoProps={{ ...baseProps, cardPaddingPx: 16 }}
|
||||
selectedBlockId="video-card-2"
|
||||
updateBlock={updateBlock}
|
||||
/>,
|
||||
);
|
||||
|
||||
const slider = screen.getByLabelText("카드 패딩 슬라이더");
|
||||
fireEvent.change(slider, { target: { value: "24" } });
|
||||
|
||||
expect(updateBlock).toHaveBeenCalledWith(
|
||||
"video-card-2",
|
||||
expect.objectContaining({ cardPaddingPx: 24 }),
|
||||
);
|
||||
});
|
||||
|
||||
it("카드 모서리 둥글기 슬라이더 변경 시 updateBlock 이 borderRadiusPx 로 호출되어야 한다", () => {
|
||||
const updateBlock = vi.fn();
|
||||
|
||||
render(
|
||||
<VideoPropertiesPanel
|
||||
videoProps={{ ...baseProps, borderRadiusPx: 8 }}
|
||||
selectedBlockId="video-card-3"
|
||||
updateBlock={updateBlock}
|
||||
/>,
|
||||
);
|
||||
|
||||
const slider = screen.getByLabelText("카드 모서리 둥글기 슬라이더");
|
||||
fireEvent.change(slider, { target: { value: "20" } });
|
||||
|
||||
expect(updateBlock).toHaveBeenCalledWith(
|
||||
"video-card-3",
|
||||
expect.objectContaining({ borderRadiusPx: 20 }),
|
||||
);
|
||||
});
|
||||
|
||||
it("포스터 이미지 URL 인풋 변경 시 updateBlock 이 posterImageSrc / posterSourceType / posterAssetId 로 호출되어야 한다", () => {
|
||||
const updateBlock = vi.fn();
|
||||
|
||||
const posterProps: VideoBlockProps = {
|
||||
...baseProps,
|
||||
sourceType: "externalUrl",
|
||||
posterImageSrc: "https://example.com/poster-before.png",
|
||||
posterSourceType: "externalUrl",
|
||||
posterAssetId: null,
|
||||
};
|
||||
|
||||
render(
|
||||
<VideoPropertiesPanel
|
||||
videoProps={posterProps}
|
||||
selectedBlockId="video-poster-1"
|
||||
updateBlock={updateBlock}
|
||||
/>,
|
||||
);
|
||||
|
||||
const input = screen.getByLabelText("포스터 이미지 URL");
|
||||
fireEvent.change(input, { target: { value: "https://example.com/poster-after.png" } });
|
||||
|
||||
expect(updateBlock).toHaveBeenCalledWith(
|
||||
"video-poster-1",
|
||||
expect.objectContaining({
|
||||
posterImageSrc: "https://example.com/poster-after.png",
|
||||
posterSourceType: "externalUrl",
|
||||
posterAssetId: null,
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
it("시작 시점 슬라이더 변경 시 updateBlock 이 startTimeSec 로 호출되어야 한다", () => {
|
||||
const updateBlock = vi.fn();
|
||||
|
||||
render(
|
||||
<VideoPropertiesPanel
|
||||
videoProps={{ ...baseProps, startTimeSec: 0 }}
|
||||
selectedBlockId="video-range-1"
|
||||
updateBlock={updateBlock}
|
||||
/>,
|
||||
);
|
||||
|
||||
const slider = screen.getByLabelText("시작 시점 (초) 슬라이더");
|
||||
fireEvent.change(slider, { target: { value: "5" } });
|
||||
|
||||
expect(updateBlock).toHaveBeenCalledWith(
|
||||
"video-range-1",
|
||||
expect.objectContaining({ startTimeSec: 5 }),
|
||||
);
|
||||
});
|
||||
|
||||
it("종료 시점 슬라이더 변경 시 updateBlock 이 endTimeSec 로 호출되어야 한다", () => {
|
||||
const updateBlock = vi.fn();
|
||||
|
||||
render(
|
||||
<VideoPropertiesPanel
|
||||
videoProps={{ ...baseProps, endTimeSec: 10 }}
|
||||
selectedBlockId="video-range-2"
|
||||
updateBlock={updateBlock}
|
||||
/>,
|
||||
);
|
||||
|
||||
const slider = screen.getByLabelText("종료 시점 (초) 슬라이더");
|
||||
fireEvent.change(slider, { target: { value: "15" } });
|
||||
|
||||
expect(updateBlock).toHaveBeenCalledWith(
|
||||
"video-range-2",
|
||||
expect.objectContaining({ endTimeSec: 15 }),
|
||||
);
|
||||
});
|
||||
|
||||
it("비디오 제목 인풋 변경 시 updateBlock 이 titleText 로 호출되어야 한다", () => {
|
||||
const updateBlock = vi.fn();
|
||||
|
||||
render(
|
||||
<VideoPropertiesPanel
|
||||
videoProps={{ ...baseProps, titleText: "기존 제목" } as any}
|
||||
selectedBlockId="video-a11y-1"
|
||||
updateBlock={updateBlock}
|
||||
/>,
|
||||
);
|
||||
|
||||
const input = screen.getByLabelText("비디오 제목");
|
||||
fireEvent.change(input, { target: { value: "새 비디오 제목" } });
|
||||
|
||||
expect(updateBlock).toHaveBeenCalledWith(
|
||||
"video-a11y-1",
|
||||
expect.objectContaining({ titleText: "새 비디오 제목" }),
|
||||
);
|
||||
});
|
||||
|
||||
it("비디오 aria-label 인풋 변경 시 updateBlock 이 ariaLabel 로 호출되어야 한다", () => {
|
||||
const updateBlock = vi.fn();
|
||||
|
||||
render(
|
||||
<VideoPropertiesPanel
|
||||
videoProps={{ ...baseProps, ariaLabel: "기존 aria" } as any}
|
||||
selectedBlockId="video-a11y-2"
|
||||
updateBlock={updateBlock}
|
||||
/>,
|
||||
);
|
||||
|
||||
const input = screen.getByLabelText("비디오 aria-label");
|
||||
fireEvent.change(input, { target: { value: "새 aria-label" } });
|
||||
|
||||
expect(updateBlock).toHaveBeenCalledWith(
|
||||
"video-a11y-2",
|
||||
expect.objectContaining({ ariaLabel: "새 aria-label" }),
|
||||
);
|
||||
});
|
||||
|
||||
it("비디오 캡션 텍스트 인풋 변경 시 updateBlock 이 captionText 로 호출되어야 한다", () => {
|
||||
const updateBlock = vi.fn();
|
||||
|
||||
render(
|
||||
<VideoPropertiesPanel
|
||||
videoProps={{ ...baseProps, captionText: "기존 캡션" } as any}
|
||||
selectedBlockId="video-a11y-3"
|
||||
updateBlock={updateBlock}
|
||||
/>,
|
||||
);
|
||||
|
||||
const input = screen.getByLabelText("비디오 캡션 텍스트");
|
||||
fireEvent.change(input, { target: { value: "새 캡션 텍스트" } });
|
||||
|
||||
expect(updateBlock).toHaveBeenCalledWith(
|
||||
"video-a11y-3",
|
||||
expect.objectContaining({ captionText: "새 캡션 텍스트" }),
|
||||
);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user