import { act } from "@testing-library/react"
import { describe, expect, it, vi } from "vitest"
import { MediaFile } from "@/features/media/types/media"
import { Transition } from "@/features/transitions/types/transitions"
import { renderWithBase, screen } from "@/test/test-utils"
import { TransitionGroup } from "../../components/transition-group"
// Мокаем TransitionPreview компонент
vi.mock("../../components/transition-preview", () => ({
TransitionPreview: ({ transition, onClick, size, previewWidth, previewHeight }: any) => (
),
}))
describe("TransitionGroup", () => {
const mockTransitions: Transition[] = [
{
id: "fade-1",
type: "fade",
labels: {
ru: "Затухание",
en: "Fade",
},
description: {
ru: "Плавное затухание",
en: "Smooth fade",
},
category: "basic",
complexity: "basic",
tags: ["professional", "standard"],
duration: { min: 0.5, max: 2.0, default: 1.0 },
parameters: { easing: "ease-in-out", intensity: 1.0 },
ffmpegCommand: () => "fade=t=in:st=0:d=1.0",
},
{
id: "zoom-1",
type: "zoom",
labels: {
ru: "Увеличение",
en: "Zoom",
},
description: {
ru: "Эффект увеличения",
en: "Zoom effect",
},
category: "creative",
complexity: "intermediate",
tags: ["professional", "standard"],
duration: { min: 0.5, max: 3.0, default: 1.5 },
parameters: { easing: "ease-out", intensity: 0.8, scale: 2.0 },
ffmpegCommand: () => "zoompan=z='zoom+0.002':d=125",
},
]
const mockDemoVideos = {
source: {
id: "source",
path: "/demo1.mp4",
name: "Source Video",
type: "video",
size: 1000000,
duration: 10,
createdAt: new Date(),
modifiedAt: new Date(),
} as MediaFile,
target: {
id: "target",
path: "/demo2.mp4",
name: "Target Video",
type: "video",
size: 1000000,
duration: 10,
createdAt: new Date(),
modifiedAt: new Date(),
} as MediaFile,
}
const defaultProps = {
title: "Basic Transitions",
transitions: mockTransitions,
previewSize: 2,
previewWidth: 120,
previewHeight: 80,
demoVideos: mockDemoVideos,
onTransitionClick: vi.fn(),
}
beforeEach(() => {
vi.clearAllMocks()
})
it("должен корректно рендериться с переходами", () => {
act(() => {
renderWithBase()
})
// Проверяем заголовок группы
expect(screen.getByText("Basic Transitions")).toBeInTheDocument()
// Проверяем наличие переходов
expect(screen.getByTestId("transition-preview-fade-1")).toBeInTheDocument()
expect(screen.getByTestId("transition-preview-zoom-1")).toBeInTheDocument()
})
it("должен отображать правильное количество переходов", () => {
act(() => {
renderWithBase()
})
const transitionPreviews = screen.getAllByRole("button")
expect(transitionPreviews).toHaveLength(2)
})
it("должен передавать правильные пропсы в TransitionPreview", () => {
act(() => {
renderWithBase()
})
const fadePreview = screen.getByTestId("transition-preview-fade-1")
expect(fadePreview).toHaveAttribute("data-size", "2")
expect(fadePreview).toHaveAttribute("data-width", "120")
expect(fadePreview).toHaveAttribute("data-height", "80")
const zoomPreview = screen.getByTestId("transition-preview-zoom-1")
expect(zoomPreview).toHaveAttribute("data-size", "2")
expect(zoomPreview).toHaveAttribute("data-width", "120")
expect(zoomPreview).toHaveAttribute("data-height", "80")
})
it("должен вызывать onTransitionClick при клике на переход", () => {
const mockOnTransitionClick = vi.fn()
renderWithBase()
const fadePreview = screen.getByTestId("transition-preview-fade-1")
act(() => {
act(() => {
fadePreview.click()
})
})
expect(mockOnTransitionClick).toHaveBeenCalledWith(mockTransitions[0])
})
it("должен вызывать onTransitionClick для разных переходов", () => {
const mockOnTransitionClick = vi.fn()
renderWithBase()
// Кликаем на первый переход
const fadePreview = screen.getByTestId("transition-preview-fade-1")
act(() => {
act(() => {
fadePreview.click()
})
})
// Кликаем на второй переход
const zoomPreview = screen.getByTestId("transition-preview-zoom-1")
act(() => {
act(() => {
zoomPreview.click()
})
})
expect(mockOnTransitionClick).toHaveBeenCalledTimes(2)
expect(mockOnTransitionClick).toHaveBeenNthCalledWith(1, mockTransitions[0])
expect(mockOnTransitionClick).toHaveBeenNthCalledWith(2, mockTransitions[1])
})
it("не должен рендериться если нет переходов", () => {
renderWithBase()
// Проверяем, что нет заголовка группы
expect(screen.queryByText("Basic Transitions")).not.toBeInTheDocument()
// Проверяем, что нет переходов
expect(screen.queryByRole("button")).not.toBeInTheDocument()
})
it("должен рендериться без заголовка если title пустой", () => {
renderWithBase()
// Заголовка не должно быть
expect(screen.queryByText("Basic Transitions")).not.toBeInTheDocument()
// Но переходы должны быть
expect(screen.getByTestId("transition-preview-fade-1")).toBeInTheDocument()
expect(screen.getByTestId("transition-preview-zoom-1")).toBeInTheDocument()
})
it("должен применять правильные CSS классы для сетки", () => {
renderWithBase()
const gridContainer = screen.getByTestId("transition-preview-fade-1").parentElement
expect(gridContainer).toHaveClass("grid")
expect(gridContainer).toHaveClass("gap-2")
expect(gridContainer).toHaveClass("grid-cols-[repeat(auto-fill,minmax(0,calc(var(--preview-size)+12px)))]")
})
it("должен устанавливать правильную CSS переменную для размера превью", () => {
renderWithBase()
const gridContainer = screen.getByTestId("transition-preview-fade-1").parentElement
expect(gridContainer).toHaveStyle({ "--preview-size": "150px" })
})
it("должен обрабатывать изменение размеров превью", () => {
const { rerender } = renderWithBase()
// Проверяем начальные размеры
let fadePreview = screen.getByTestId("transition-preview-fade-1")
expect(fadePreview).toHaveAttribute("data-width", "120")
expect(fadePreview).toHaveAttribute("data-height", "80")
// Изменяем размеры
act(() => {
act(() => {
rerender()
})
})
fadePreview = screen.getByTestId("transition-preview-fade-1")
expect(fadePreview).toHaveAttribute("data-width", "200")
expect(fadePreview).toHaveAttribute("data-height", "150")
expect(fadePreview).toHaveAttribute("data-size", "3")
})
it("должен отображать правильные имена переходов", () => {
renderWithBase()
expect(screen.getByText("Затухание")).toBeInTheDocument()
expect(screen.getByText("Увеличение")).toBeInTheDocument()
})
it("должен обрабатывать один переход", () => {
const singleTransition = [mockTransitions[0]]
renderWithBase()
expect(screen.getByTestId("transition-preview-fade-1")).toBeInTheDocument()
expect(screen.queryByTestId("transition-preview-zoom-1")).not.toBeInTheDocument()
const transitionPreviews = screen.getAllByRole("button")
expect(transitionPreviews).toHaveLength(1)
})
it("должен применять правильные CSS классы к заголовку", () => {
renderWithBase()
const title = screen.getByText("Basic Transitions")
expect(title.tagName).toBe("H3")
expect(title).toHaveClass("text-sm", "font-medium", "text-gray-700", "dark:text-gray-300")
})
it("должен применять правильные CSS классы к контейнеру", () => {
renderWithBase()
const container = screen.getByText("Basic Transitions").parentElement
expect(container).toHaveClass("space-y-2")
})
it("должен передавать правильные demo видео в TransitionPreview", () => {
renderWithBase()
// Проверяем, что TransitionPreview получает правильные demo видео
// Это проверяется через моки - TransitionPreview должен получить sourceVideo и targetVideo
expect(screen.getByTestId("transition-preview-fade-1")).toBeInTheDocument()
expect(screen.getByTestId("transition-preview-zoom-1")).toBeInTheDocument()
})
it("должен обрабатывать изменение demo видео", () => {
const newDemoVideos = {
source: {
...mockDemoVideos.source,
path: "/new-demo1.mp4",
name: "New Source Video",
},
target: {
...mockDemoVideos.target,
path: "/new-demo2.mp4",
name: "New Target Video",
},
}
const { rerender } = renderWithBase()
// Изменяем demo видео
act(() => {
act(() => {
rerender()
})
})
// Проверяем, что компонент перерендерился без ошибок
expect(screen.getByTestId("transition-preview-fade-1")).toBeInTheDocument()
expect(screen.getByTestId("transition-preview-zoom-1")).toBeInTheDocument()
})
})