Files
page-builder/tests/unit/videoHelpers.spec.ts
T
jaybe 48e13d2a75
CI / pr_and_merge (push) Has been skipped
CI / test (push) Failing after 46m46s
CI / test (pull_request) Failing after 43m8s
CI / pr_and_merge (pull_request) Has been skipped
video 블록 및 리펙터링
2025-11-27 10:07:59 +09:00

263 lines
8.9 KiB
TypeScript

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");
});
});