import { fireEvent, render, screen, waitFor } from "@testing-library/react" import { beforeEach, describe, expect, it, vi } from "vitest" import { GpuEncoder } from "@/types/video-compiler" import { GpuStatus, GpuStatusBadge } from "../../components/gpu-status" import * as useGpuCapabilitiesModule from "../../hooks/use-gpu-capabilities" // Мокаем хук useGpuCapabilities vi.mock("../../hooks/use-gpu-capabilities", () => ({ useGpuCapabilities: vi.fn(), formatGpuMemory: (bytes: number) => `${(bytes / 1024 / 1024 / 1024).toFixed(1)} GB`, formatGpuUtilization: (percent: number) => `${percent}%`, getGpuEncoderDisplayName: (encoder: string) => encoder, getGpuRecommendations: () => ["Recommendation 1", "Recommendation 2"], getGpuStatusColor: () => "text-green-600", })) // Мокаем sonner vi.mock("sonner", () => ({ toast: { error: vi.fn(), success: vi.fn(), info: vi.fn(), }, })) describe("GpuStatus", () => { const mockGpuCapabilities = { hardware_acceleration_supported: true, available_encoders: [GpuEncoder.Nvenc, GpuEncoder.QuickSync], recommended_encoder: GpuEncoder.Nvenc, current_gpu: { id: "0", name: "NVIDIA GeForce RTX 3080", vendor: "NVIDIA", driver_version: "535.123.01", memory_total: 10737418240, // 10GB memory_used: 2147483648, // 2GB memory_free: 8589934592, // 8GB utilization: 45, temperature: 65, }, gpus: [], } const mockSystemInfo = { os: { type: "Linux", version: "5.15.0", architecture: "x86_64", }, cpu: { cores: 16, arch: "x86_64", }, memory: { total_bytes: 34359738368, // 32GB total_mb: 32768, total_gb: 32, }, runtime: { rust_version: "0.25.0", tauri_version: "2.0.0", }, } const mockCompilerSettings = { hardware_acceleration: true, preferred_encoder: GpuEncoder.Auto, quality: 85, max_concurrent_jobs: 2, cache_size_mb: 2048, temp_directory: "/tmp/timeline-studio", preview_quality: 85, } const mockUseGpuCapabilities = { gpuCapabilities: mockGpuCapabilities, currentGpu: mockGpuCapabilities.current_gpu, systemInfo: mockSystemInfo, ffmpegCapabilities: null, compilerSettings: mockCompilerSettings, isLoading: false, error: null, refreshCapabilities: vi.fn(), updateSettings: vi.fn(), checkHardwareAcceleration: vi.fn(), } beforeEach(async () => { vi.clearAllMocks() const { useGpuCapabilities } = await import("../../hooks/use-gpu-capabilities") vi.mocked(useGpuCapabilities).mockReturnValue(mockUseGpuCapabilities) }) it("should render GPU status with acceleration available", () => { render() expect(screen.getByText("videoCompiler.gpu.acceleration")).toBeInTheDocument() expect(screen.getByText("videoCompiler.gpu.accelerationAvailable")).toBeInTheDocument() expect(screen.getByText("NVIDIA GeForce RTX 3080")).toBeInTheDocument() }) it("should show loading skeleton when loading", () => { vi.mocked(useGpuCapabilitiesModule.useGpuCapabilities).mockReturnValue({ ...mockUseGpuCapabilities, isLoading: true, }) const { container } = render() expect(container.querySelector('[data-slot="skeleton"]')).toBeInTheDocument() }) it("should show error state", () => { const errorMessage = "Failed to get GPU info" vi.mocked(useGpuCapabilitiesModule.useGpuCapabilities).mockReturnValue({ ...mockUseGpuCapabilities, error: errorMessage, }) render() expect(screen.getByText("videoCompiler.gpu.error")).toBeInTheDocument() expect(screen.getByText(errorMessage)).toBeInTheDocument() expect(screen.getByText("videoCompiler.gpu.retry")).toBeInTheDocument() }) it("should handle retry on error", async () => { const errorMessage = "Failed to get GPU info" vi.mocked(useGpuCapabilitiesModule.useGpuCapabilities).mockReturnValue({ ...mockUseGpuCapabilities, error: errorMessage, }) render() const retryButton = screen.getByText("videoCompiler.gpu.retry") fireEvent.click(retryButton) expect(mockUseGpuCapabilities.refreshCapabilities).toHaveBeenCalled() }) it("should toggle GPU acceleration", async () => { render() const switchElement = screen.getByRole("switch") expect(switchElement).toBeChecked() fireEvent.click(switchElement) await waitFor(() => { expect(mockUseGpuCapabilities.updateSettings).toHaveBeenCalledWith({ ...mockCompilerSettings, hardware_acceleration: false, }) }) }) it("should disable switch when GPU not available", () => { vi.mocked(useGpuCapabilitiesModule.useGpuCapabilities).mockReturnValue({ ...mockUseGpuCapabilities, gpuCapabilities: { ...mockGpuCapabilities, hardware_acceleration_supported: false, }, }) render() const switchElement = screen.getByRole("switch") expect(switchElement).toBeDisabled() }) it("should show GPU memory usage", () => { render() expect(screen.getByText("videoCompiler.gpu.videoMemory")).toBeInTheDocument() expect(screen.getByText("videoCompiler.gpu.memoryUsed")).toBeInTheDocument() // Memory values are formatted by utility functions expect(screen.getByText(/2\.0 GB.*\/.*10\.0 GB/)).toBeInTheDocument() }) it("should show GPU utilization", () => { render() expect(screen.getByText("videoCompiler.gpu.gpuLoad")).toBeInTheDocument() expect(screen.getByText("videoCompiler.gpu.usage")).toBeInTheDocument() expect(screen.getByText("45%")).toBeInTheDocument() }) it("should show available encoders", () => { render() expect(screen.getByText("videoCompiler.gpu.encoders")).toBeInTheDocument() expect(screen.getByText("Nvenc")).toBeInTheDocument() expect(screen.getByText("QuickSync")).toBeInTheDocument() }) it("should show system info", () => { render() expect(screen.getByText("videoCompiler.gpu.system")).toBeInTheDocument() expect(screen.getByText(/Linux.*5\.15\.0.*x86_64/)).toBeInTheDocument() expect(screen.getByText(/16.*videoCompiler\.gpu\.cores.*x86_64/)).toBeInTheDocument() }) it("should show recommendations", () => { render() expect(screen.getByText("videoCompiler.gpu.recommendations")).toBeInTheDocument() }) it("should call settings callback when button clicked", () => { const mockSettingsClick = vi.fn() render() const settingsButton = screen.getByTestId("settings-icon").closest("button") expect(settingsButton).toBeInTheDocument() fireEvent.click(settingsButton!) expect(mockSettingsClick).toHaveBeenCalled() }) it("should hide details when showDetails is false", () => { render() expect(screen.queryByText("videoCompiler.gpu.videoMemory")).not.toBeInTheDocument() expect(screen.queryByText("videoCompiler.gpu.system")).not.toBeInTheDocument() }) }) describe("GpuStatusBadge", () => { const mockUseGpuCapabilities = { gpuCapabilities: { hardware_acceleration_supported: true, available_encoders: [GpuEncoder.Nvenc], recommended_encoder: GpuEncoder.Nvenc, current_gpu: null, gpus: [], }, currentGpu: null, systemInfo: null, ffmpegCapabilities: null, compilerSettings: null, isLoading: false, error: null, refreshCapabilities: vi.fn(), updateSettings: vi.fn(), checkHardwareAcceleration: vi.fn(), } beforeEach(async () => { vi.clearAllMocks() const { useGpuCapabilities } = await import("../../hooks/use-gpu-capabilities") vi.mocked(useGpuCapabilities).mockReturnValue(mockUseGpuCapabilities) }) it("should render badge with GPU encoder", () => { render() expect(screen.getByText("Nvenc")).toBeInTheDocument() }) it("should show loading skeleton", () => { vi.mocked(useGpuCapabilitiesModule.useGpuCapabilities).mockReturnValue({ ...mockUseGpuCapabilities, isLoading: true, }) const { container } = render() expect(container.querySelector('[data-slot="skeleton"]')).toBeInTheDocument() }) it("should show CPU only when no GPU available", () => { vi.mocked(useGpuCapabilitiesModule.useGpuCapabilities).mockReturnValue({ ...mockUseGpuCapabilities, gpuCapabilities: { hardware_acceleration_supported: false, available_encoders: [], recommended_encoder: null, current_gpu: null, gpus: [], }, }) render() expect(screen.getByText("videoCompiler.gpu.cpuOnly")).toBeInTheDocument() }) it("should render as tooltip trigger", () => { const { container } = render() const badge = screen.getByText("Nvenc") expect(badge).toBeInTheDocument() // Check that the badge is wrapped in tooltip trigger const trigger = container.querySelector('[data-slot="tooltip-trigger"]') expect(trigger).toBeInTheDocument() }) })