import { fireEvent, render, screen, waitFor } from "@testing-library/react"
import { beforeEach, describe, expect, it, vi } from "vitest"
import { SpeedCurveEditor } from "../../../components/speed-ramping/speed-curve-editor"
// Mock компонентов
vi.mock("@/components/ui/button", () => ({
Button: ({ children, onClick, ...props }: any) => (
),
}))
vi.mock("@/components/ui/dropdown-menu", () => ({
DropdownMenu: ({ children }: any) =>
{children}
,
DropdownMenuContent: ({ children }: any) => {children}
,
DropdownMenuItem: ({ children, onClick }: any) => {children}
,
DropdownMenuSeparator: () =>
,
DropdownMenuTrigger: ({ children }: any) => {children}
,
}))
vi.mock("@/components/ui/tooltip", () => ({
TooltipProvider: ({ children }: any) => {children}
,
Tooltip: ({ children }: any) => {children}
,
TooltipContent: ({ children }: any) => {children}
,
TooltipTrigger: ({ children }: any) => {children}
,
}))
// Mock хука speed ramping
const mockUseSpeedRamping = {
getConfig: vi.fn(),
addKeyframe: vi.fn(),
updateKeyframe: vi.fn(),
removeKeyframe: vi.fn(),
applyPreset: vi.fn(),
resetToConstantSpeed: vi.fn(),
getSpeedCurveData: vi.fn(),
}
vi.mock("../../../hooks/use-speed-ramping", () => ({
useSpeedRamping: () => mockUseSpeedRamping,
}))
describe("SpeedCurveEditor", () => {
const defaultProps = {
clipId: "test-clip-1",
clipDuration: 10,
pixelsPerSecond: 100,
height: 120,
onClose: vi.fn(),
}
beforeEach(() => {
vi.clearAllMocks()
// Mock конфигурации по умолчанию
mockUseSpeedRamping.getConfig.mockReturnValue({
enabled: true,
keyframes: [
{ id: "kf1", time: 2, value: 0.5, interpolation: "linear" },
{ id: "kf2", time: 5, value: 2.0, interpolation: "ease" },
{ id: "kf3", time: 8, value: 1.0, interpolation: "ease-out" },
],
maintainPitch: true,
minSpeed: 0.1,
maxSpeed: 4.0,
showGraph: true,
graphHeight: 120,
graphOpacity: 0.8,
})
mockUseSpeedRamping.getSpeedCurveData.mockReturnValue([
{ time: 0, speed: 1.0 },
{ time: 2, speed: 0.5 },
{ time: 5, speed: 2.0 },
{ time: 8, speed: 1.0 },
{ time: 10, speed: 1.0 },
])
})
it("рендерит компонент с базовыми элементами", () => {
render()
expect(screen.getByText("Speed Ramping")).toBeInTheDocument()
expect(screen.getByText("Presets")).toBeInTheDocument()
expect(screen.getByText("Reset to normal speed")).toBeInTheDocument()
})
it("отображает canvas с правильными размерами", () => {
render()
const canvas = screen.getByTestId("speed-curve-canvas")
expect(canvas).toHaveAttribute("width", "1000") // 10 сек * 100 пикс/сек
expect(canvas).toHaveAttribute("height", "120")
})
it("добавляет keyframe при клике на canvas", async () => {
render()
const canvas = screen.getByTestId("speed-curve-canvas")
// Симулируем клик по canvas
fireEvent.click(canvas, {
clientX: 300, // 3 секунды при 100 пикс/сек
clientY: 60, // Середина по высоте (speed = 2.0)
})
await waitFor(() => {
expect(mockUseSpeedRamping.addKeyframe).toHaveBeenCalledWith(
"test-clip-1",
expect.any(Number), // время
expect.any(Number), // значение скорости
"ease",
)
})
})
it("применяет пресет при выборе из меню", async () => {
render()
// Находим кнопку пресетов и кликаем
const presetsButton = screen.getByText("Presets")
fireEvent.click(presetsButton)
// Симулируем выбор пресета slow-motion
const slowMotionPreset = screen.getByText("Slow Motion")
fireEvent.click(slowMotionPreset)
await waitFor(() => {
expect(mockUseSpeedRamping.applyPreset).toHaveBeenCalledWith("test-clip-1", "slow-motion")
})
})
it("сбрасывает скорость к нормальной при клике на reset", async () => {
render()
// Ищем кнопку с иконкой RotateCcw
const resetButton = screen.getByTestId("rotateccw-icon").closest("button")
expect(resetButton).toBeInTheDocument()
fireEvent.click(resetButton!)
await waitFor(() => {
expect(mockUseSpeedRamping.resetToConstantSpeed).toHaveBeenCalledWith("test-clip-1", 1.0)
})
})
it("вызывает onClose при клике на кнопку закрытия", () => {
const onClose = vi.fn()
render()
const closeButton = screen.getByText("✕")
fireEvent.click(closeButton)
expect(onClose).toHaveBeenCalled()
})
it("отображает подсказку при отсутствии keyframes", () => {
mockUseSpeedRamping.getConfig.mockReturnValue({
enabled: true,
keyframes: [], // Нет keyframes
maintainPitch: true,
minSpeed: 0.1,
maxSpeed: 4.0,
showGraph: true,
graphHeight: 120,
graphOpacity: 0.8,
})
render()
expect(screen.getByText("Click to add speed keyframes")).toBeInTheDocument()
})
it("обрабатывает клики по canvas для взаимодействия с keyframes", async () => {
render()
// Симулируем клик по canvas
const canvas = screen.getByTestId("speed-curve-canvas")
fireEvent.click(canvas, {
clientX: 200, // Позиция на canvas
clientY: 90,
})
// Проверяем что canvas корректно обрабатывает клики
// В реальном использовании это может добавить keyframe или выбрать существующий
expect(canvas).toBeInTheDocument()
})
it("показывает Y-axis labels с правильными значениями скорости", () => {
render()
expect(screen.getByText("4x")).toBeInTheDocument()
expect(screen.getByText("3x")).toBeInTheDocument()
expect(screen.getByText("2x")).toBeInTheDocument()
expect(screen.getByText("1x")).toBeInTheDocument()
expect(screen.getByText("0x")).toBeInTheDocument()
})
})