video 블록 및 리펙터링
This commit is contained in:
@@ -0,0 +1,262 @@
|
||||
import { describe, it, expect } from "vitest";
|
||||
import {
|
||||
normalizeVideoSourceUrl,
|
||||
resolveVideoPlatform,
|
||||
buildVideoEmbedUrl,
|
||||
computeVideoPublicTokens,
|
||||
computeVideoEditorTokens,
|
||||
computeVideoExportTokens,
|
||||
} from "@/features/editor/utils/videoHelpers";
|
||||
import type { VideoBlockProps } from "@/features/editor/state/editorStore";
|
||||
|
||||
describe("videoHelpers", () => {
|
||||
it("normalizeVideoSourceUrl 은 null/undefined 를 빈 문자열로 만들고 공백을 제거해야 한다", () => {
|
||||
expect(normalizeVideoSourceUrl(undefined)).toBe("");
|
||||
expect(normalizeVideoSourceUrl(null)).toBe("");
|
||||
expect(normalizeVideoSourceUrl("")).toBe("");
|
||||
expect(normalizeVideoSourceUrl(" https://example.com/video.mp4 ")).toBe("https://example.com/video.mp4");
|
||||
});
|
||||
|
||||
it("resolveVideoPlatform 은 platform 이 auto 일 때 URL 로부터 youtube/vimeo/html5 를 판별해야 한다", () => {
|
||||
expect(resolveVideoPlatform("https://www.youtube.com/watch?v=dQw4w9WgXcQ", "auto")).toBe("youtube");
|
||||
expect(resolveVideoPlatform("https://youtu.be/dQw4w9WgXcQ", "auto")).toBe("youtube");
|
||||
expect(resolveVideoPlatform("https://vimeo.com/123456", "auto")).toBe("vimeo");
|
||||
expect(resolveVideoPlatform("/videos/local.mp4", "auto")).toBe("html5");
|
||||
});
|
||||
|
||||
it("resolveVideoPlatform 은 platform 이 명시된 경우 해당 값을 우선 사용해야 한다", () => {
|
||||
expect(resolveVideoPlatform("https://example.com/video", "youtube")).toBe("youtube");
|
||||
expect(resolveVideoPlatform("https://example.com/video", "vimeo")).toBe("vimeo");
|
||||
expect(resolveVideoPlatform("https://www.youtube.com/watch?v=dQw4w9WgXcQ", "html5")).toBe("html5");
|
||||
});
|
||||
|
||||
it("buildVideoEmbedUrl 은 YouTube URL 을 embed URL 로 변환해야 한다", () => {
|
||||
expect(buildVideoEmbedUrl("https://www.youtube.com/watch?v=dQw4w9WgXcQ", "youtube")).toBe(
|
||||
"https://www.youtube.com/embed/dQw4w9WgXcQ",
|
||||
);
|
||||
expect(buildVideoEmbedUrl("https://youtu.be/dQw4w9WgXcQ", "youtube")).toBe(
|
||||
"https://www.youtube.com/embed/dQw4w9WgXcQ",
|
||||
);
|
||||
expect(buildVideoEmbedUrl("https://www.youtube.com/shorts/dQw4w9WgXcQ", "youtube")).toBe(
|
||||
"https://www.youtube.com/embed/dQw4w9WgXcQ",
|
||||
);
|
||||
});
|
||||
|
||||
it("buildVideoEmbedUrl 은 Vimeo URL 에 대해 옵션에 따라 embed URL 또는 원본 URL 을 반환해야 한다", () => {
|
||||
const url = "https://vimeo.com/123456";
|
||||
expect(buildVideoEmbedUrl(url, "vimeo", { enableVimeoEmbed: true })).toBe(
|
||||
"https://player.vimeo.com/video/123456",
|
||||
);
|
||||
expect(buildVideoEmbedUrl(url, "vimeo", { enableVimeoEmbed: false })).toBe("https://vimeo.com/123456");
|
||||
expect(buildVideoEmbedUrl(url, "vimeo")).toBe("https://vimeo.com/123456");
|
||||
});
|
||||
|
||||
it("buildVideoEmbedUrl 은 html5 플랫폼에서는 정규화된 원본 URL 을 그대로 반환해야 한다", () => {
|
||||
expect(buildVideoEmbedUrl(" /videos/local.mp4 ", "html5")).toBe("/videos/local.mp4");
|
||||
});
|
||||
});
|
||||
|
||||
describe("videoHelpers.computeVideoPublicTokens", () => {
|
||||
const baseProps: VideoBlockProps = {
|
||||
sourceUrl: "/videos/sample.mp4",
|
||||
align: "center",
|
||||
widthMode: "auto",
|
||||
aspectRatio: "16:9",
|
||||
};
|
||||
|
||||
it("fixed width / 카드 스타일을 em 단위로 계산해야 한다", () => {
|
||||
const tokens = computeVideoPublicTokens({
|
||||
...baseProps,
|
||||
align: "left",
|
||||
widthMode: "fixed",
|
||||
widthPx: 640,
|
||||
backgroundColorCustom: "#123456",
|
||||
cardPaddingPx: 32,
|
||||
borderRadiusPx: 16,
|
||||
} as any);
|
||||
|
||||
expect(tokens.justifyClass).toBe("justify-start");
|
||||
expect(tokens.wrapperStyle.width).toBe("40em");
|
||||
expect(tokens.videoStyle.width).toBe("40em");
|
||||
expect(tokens.wrapperStyle.backgroundColor).toBe("#123456");
|
||||
expect(tokens.wrapperStyle.padding).toBe("2em");
|
||||
expect(tokens.wrapperStyle.borderRadius).toBe("1em");
|
||||
});
|
||||
|
||||
it("widthMode 가 full 이면 wrapper/video width 를 100% 로 설정해야 한다", () => {
|
||||
const tokens = computeVideoPublicTokens({
|
||||
...baseProps,
|
||||
widthMode: "full",
|
||||
widthPx: 640,
|
||||
} as any);
|
||||
|
||||
expect(tokens.wrapperStyle.width).toBe("100%");
|
||||
expect(tokens.videoStyle.width).toBe("100%");
|
||||
});
|
||||
|
||||
it("aspectRatio 에 따라 aspectClass 를 설정해야 한다", () => {
|
||||
const defaultTokens = computeVideoPublicTokens({
|
||||
...baseProps,
|
||||
aspectRatio: "16:9",
|
||||
} as any);
|
||||
const fourThree = computeVideoPublicTokens({
|
||||
...baseProps,
|
||||
aspectRatio: "4:3",
|
||||
} as any);
|
||||
const oneOne = computeVideoPublicTokens({
|
||||
...baseProps,
|
||||
aspectRatio: "1:1",
|
||||
} as any);
|
||||
|
||||
expect(defaultTokens.aspectClass).toBe("");
|
||||
expect(fourThree.aspectClass).toBe(" pb-video-wrapper--4by3");
|
||||
expect(oneOne.aspectClass).toBe(" pb-video-wrapper--1by1");
|
||||
});
|
||||
});
|
||||
|
||||
describe("videoHelpers.computeVideoExportTokens", () => {
|
||||
const baseProps: VideoBlockProps = {
|
||||
sourceUrl: "/videos/sample-export.mp4",
|
||||
align: "center",
|
||||
widthMode: "auto",
|
||||
aspectRatio: "16:9",
|
||||
};
|
||||
|
||||
const escapers = { escapeAttr: (value: string) => value };
|
||||
|
||||
it("fixed width / 카드 스타일을 px 단위 스타일 파트로 계산해야 한다", () => {
|
||||
const tokens = computeVideoExportTokens(
|
||||
{
|
||||
...baseProps,
|
||||
align: "left",
|
||||
widthMode: "fixed",
|
||||
widthPx: 640,
|
||||
backgroundColorCustom: "#123456",
|
||||
cardPaddingPx: 24,
|
||||
borderRadiusPx: 16,
|
||||
} as any,
|
||||
escapers,
|
||||
);
|
||||
|
||||
expect(tokens.aspectClass).toBe("");
|
||||
expect(tokens.wrapperStyleParts).toContain("width:640px");
|
||||
expect(tokens.videoStyleParts).toContain("width:640px");
|
||||
expect(tokens.wrapperStyleParts).toContain("background-color:#123456");
|
||||
expect(tokens.wrapperStyleParts).toContain("padding:24px");
|
||||
expect(tokens.wrapperStyleParts).toContain("border-radius:16px");
|
||||
expect(tokens.outerStyleParts).toContain("display:flex");
|
||||
expect(tokens.outerStyleParts).toContain("justify-content:flex-start");
|
||||
});
|
||||
|
||||
it("widthMode 가 full 이면 width:100% 로 설정하고 align 에 따라 justify-content 를 계산해야 한다", () => {
|
||||
const right = computeVideoExportTokens(
|
||||
{
|
||||
...baseProps,
|
||||
align: "right",
|
||||
widthMode: "full",
|
||||
} as any,
|
||||
escapers,
|
||||
);
|
||||
|
||||
expect(right.wrapperStyleParts).toContain("width:100%");
|
||||
expect(right.videoStyleParts).toContain("width:100%");
|
||||
expect(right.outerStyleParts).toContain("justify-content:flex-end");
|
||||
|
||||
const center = computeVideoExportTokens(
|
||||
{
|
||||
...baseProps,
|
||||
align: "center",
|
||||
widthMode: "auto",
|
||||
} as any,
|
||||
escapers,
|
||||
);
|
||||
|
||||
expect(center.outerStyleParts).toContain("justify-content:center");
|
||||
});
|
||||
|
||||
it("aspectRatio 에 따라 aspectClass 를 설정해야 한다", () => {
|
||||
const def = computeVideoExportTokens(
|
||||
{
|
||||
...baseProps,
|
||||
aspectRatio: "16:9",
|
||||
} as any,
|
||||
escapers,
|
||||
);
|
||||
const fourThree = computeVideoExportTokens(
|
||||
{
|
||||
...baseProps,
|
||||
aspectRatio: "4:3",
|
||||
} as any,
|
||||
escapers,
|
||||
);
|
||||
const oneOne = computeVideoExportTokens(
|
||||
{
|
||||
...baseProps,
|
||||
aspectRatio: "1:1",
|
||||
} as any,
|
||||
escapers,
|
||||
);
|
||||
|
||||
expect(def.aspectClass).toBe("");
|
||||
expect(fourThree.aspectClass).toBe(" pb-video-wrapper--4by3");
|
||||
expect(oneOne.aspectClass).toBe(" pb-video-wrapper--1by1");
|
||||
});
|
||||
});
|
||||
|
||||
describe("videoHelpers.computeVideoEditorTokens", () => {
|
||||
const baseProps: VideoBlockProps = {
|
||||
sourceUrl: "/videos/sample-editor.mp4",
|
||||
align: "center",
|
||||
widthMode: "auto",
|
||||
aspectRatio: "16:9",
|
||||
};
|
||||
|
||||
it("fixed width / 카드 스타일을 px 단위로 계산해야 한다", () => {
|
||||
const tokens = computeVideoEditorTokens({
|
||||
...baseProps,
|
||||
align: "left",
|
||||
widthMode: "fixed",
|
||||
widthPx: 640,
|
||||
backgroundColorCustom: "#123456",
|
||||
cardPaddingPx: 24,
|
||||
borderRadiusPx: 16,
|
||||
} as any);
|
||||
|
||||
expect(tokens.justifyClass).toBe("justify-start");
|
||||
expect(tokens.wrapperStyle.width).toBe("640px");
|
||||
expect(tokens.videoStyle.width).toBe("640px");
|
||||
expect(tokens.wrapperStyle.backgroundColor).toBe("#123456");
|
||||
expect(tokens.wrapperStyle.padding).toBe("24px");
|
||||
expect(tokens.wrapperStyle.borderRadius).toBe("16px");
|
||||
});
|
||||
|
||||
it("widthMode 가 full 이면 wrapper/video width 를 100% 로 설정해야 한다", () => {
|
||||
const tokens = computeVideoEditorTokens({
|
||||
...baseProps,
|
||||
widthMode: "full",
|
||||
widthPx: 640,
|
||||
} as any);
|
||||
|
||||
expect(tokens.wrapperStyle.width).toBe("100%");
|
||||
expect(tokens.videoStyle.width).toBe("100%");
|
||||
});
|
||||
|
||||
it("aspectRatio 에 따라 aspectClass 를 설정해야 한다", () => {
|
||||
const defaultTokens = computeVideoEditorTokens({
|
||||
...baseProps,
|
||||
aspectRatio: "16:9",
|
||||
} as any);
|
||||
const fourThree = computeVideoEditorTokens({
|
||||
...baseProps,
|
||||
aspectRatio: "4:3",
|
||||
} as any);
|
||||
const oneOne = computeVideoEditorTokens({
|
||||
...baseProps,
|
||||
aspectRatio: "1:1",
|
||||
} as any);
|
||||
|
||||
expect(defaultTokens.aspectClass).toBe("");
|
||||
expect(fourThree.aspectClass).toBe(" pb-video-wrapper--4by3");
|
||||
expect(oneOne.aspectClass).toBe(" pb-video-wrapper--1by1");
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user