import { fireEvent, render, screen, waitFor } from "@testing-library/react" import { beforeEach, describe, expect, it, vi } from "vitest" import "@testing-library/jest-dom" import { ContentType, SceneType } from "@/features/ai-content-intelligence/shared/types/content-analysis" import { AIMarkerControls } from "../ai-marker-controls" // Mock dependencies const mockSend = vi.fn() const mockOpenModal = vi.fn() const mockAnalysisState = { isAnalyzing: false, sceneAnalysis: null, keyMoments: [], insights: null, } vi.mock("@/features/timeline/hooks/use-timeline", () => ({ useTimeline: () => ({ send: mockSend, }), })) vi.mock("@/features/timeline/hooks/use-timeline-ai-analysis", () => ({ useTimelineAIAnalysis: () => ({ state: mockAnalysisState, }), })) vi.mock("@/features/modals/services", () => ({ useModal: () => ({ openModal: mockOpenModal, }), })) // Mock AIMarkerService const mockCreateMarkersFromScenes = vi.fn() const mockCreateMarkersFromKeyMoments = vi.fn() const mockCreateQualityMarkers = vi.fn() const mockCreateEmotionalMarkers = vi.fn() const mockGroupNearbyMarkers = vi.fn() const mockUpdateConfig = vi.fn() vi.mock("@/features/timeline/services/ai-marker-service", () => ({ AIMarkerService: vi.fn().mockImplementation(() => ({ createMarkersFromScenes: mockCreateMarkersFromScenes, createMarkersFromKeyMoments: mockCreateMarkersFromKeyMoments, createQualityMarkers: mockCreateQualityMarkers, createEmotionalMarkers: mockCreateEmotionalMarkers, groupNearbyMarkers: mockGroupNearbyMarkers, updateConfig: mockUpdateConfig, })), })) // Mock Tooltip components vi.mock("@/components/ui/tooltip", () => ({ Tooltip: ({ children }: any) => children, TooltipContent: ({ children }: any) =>
{children}
, TooltipProvider: ({ children }: any) => children, TooltipTrigger: ({ children }: any) => children, })) describe("AIMarkerControls", () => { beforeEach(() => { vi.clearAllMocks() // Reset analysis state mockAnalysisState.isAnalyzing = false mockAnalysisState.sceneAnalysis = null mockAnalysisState.keyMoments = [] mockAnalysisState.insights = null }) it("renders control buttons", () => { render() expect(screen.getByRole("button", { name: /AI Маркеры/i })).toBeInTheDocument() expect(screen.getByRole("button", { name: /settings/i })).toBeInTheDocument() }) it("shows error when no analysis data available", async () => { render() const generateButton = screen.getByRole("button", { name: /AI Маркеры/i }) fireEvent.click(generateButton) await waitFor(() => { expect(screen.getByText("Нет данных анализа. Сначала проанализируйте Timeline.")).toBeInTheDocument() }) }) it("generates markers from scene analysis", async () => { // Setup scene analysis data mockAnalysisState.sceneAnalysis = { scenes: [ { id: "scene1", startTime: 0, endTime: 5, duration: 5, type: SceneType.ESTABLISHING, keyFrames: [], quality: { overall: 90, sharpness: 85, brightness: 80, contrast: 75, saturation: 70, stability: 95, noise: 5, }, content: { objects: [], faces: [], text: [], activities: [] }, transitions: [], }, { id: "scene2", startTime: 5, endTime: 10, duration: 5, type: SceneType.ACTION, keyFrames: [], quality: { overall: 85, sharpness: 80, brightness: 75, contrast: 70, saturation: 65, stability: 90, noise: 10, }, content: { objects: [], faces: [], text: [], activities: [] }, transitions: [], }, ], keyMoments: [], classification: { contentType: ContentType.NARRATIVE, genres: [], confidence: 0.85, }, summary: { totalScenes: 2, averageSceneDuration: 5, dominantColors: [], visualComplexity: 0.5, audioProfile: { hasSpeech: false, hasMusic: false, hasSilence: true, speechPercentage: 0, musicPercentage: 0, averageVolume: 0, dynamicRange: 0, }, }, timeline: { duration: 10, segments: [], keyframes: [], }, } const mockSceneMarkers = [ { id: "marker1", time: 0, label: "Scene 1" }, { id: "marker2", time: 5, label: "Scene 2" }, ] mockCreateMarkersFromScenes.mockReturnValue(mockSceneMarkers) mockGroupNearbyMarkers.mockImplementation((markers) => markers) render() const generateButton = screen.getByRole("button", { name: /AI Маркеры/i }) fireEvent.click(generateButton) await waitFor(() => { expect(mockCreateMarkersFromScenes).toHaveBeenCalledWith(mockAnalysisState.sceneAnalysis.scenes) expect(mockSend).toHaveBeenCalledWith({ type: "ADD_MARKER", marker: mockSceneMarkers[0] }) expect(mockSend).toHaveBeenCalledWith({ type: "ADD_MARKER", marker: mockSceneMarkers[1] }) }) // Check that markers were created and added expect(mockCreateMarkersFromScenes).toHaveBeenCalledWith(mockAnalysisState.sceneAnalysis.scenes) expect(mockSend).toHaveBeenCalledWith({ type: "ADD_MARKER", marker: mockSceneMarkers[0] }) expect(mockSend).toHaveBeenCalledWith({ type: "ADD_MARKER", marker: mockSceneMarkers[1] }) }) it("generates markers from key moments", async () => { // Setup key moments data mockAnalysisState.keyMoments = [ { time: 10, type: "action", confidence: 0.85, description: "Action moment" }, { time: 20, type: "emotion", confidence: 0.9, description: "Emotional moment" }, ] const mockMomentMarkers = [ { id: "moment1", time: 10, label: "Key Moment 1" }, { id: "moment2", time: 20, label: "Key Moment 2" }, ] mockCreateMarkersFromKeyMoments.mockReturnValue(mockMomentMarkers) mockGroupNearbyMarkers.mockImplementation((markers) => markers) render() const generateButton = screen.getByRole("button", { name: /AI Маркеры/i }) fireEvent.click(generateButton) await waitFor(() => { expect(mockCreateMarkersFromKeyMoments).toHaveBeenCalledWith(mockAnalysisState.keyMoments) expect(mockSend).toHaveBeenCalledTimes(2) }) }) it("shows progress during generation", async () => { mockAnalysisState.keyMoments = [{ time: 10, type: "action", confidence: 0.85 }] mockCreateMarkersFromKeyMoments.mockReturnValue([{ id: "marker1", time: 10 }]) mockGroupNearbyMarkers.mockImplementation((markers) => markers) render() const generateButton = screen.getByRole("button", { name: /AI Маркеры/i }) fireEvent.click(generateButton) expect(screen.getByText("Создание...")).toBeInTheDocument() expect(screen.getByRole("progressbar")).toBeInTheDocument() // Check that progress bar is visible during generation expect(screen.getByRole("progressbar")).toBeInTheDocument() }) it("disables generate button when analyzing", () => { mockAnalysisState.isAnalyzing = true render() const generateButton = screen.getByRole("button", { name: /AI Маркеры/i }) expect(generateButton).toBeDisabled() }) it("opens settings modal", () => { render() const settingsButton = screen.getByRole("button", { name: /settings/i }) fireEvent.click(settingsButton) expect(mockOpenModal).toHaveBeenCalledWith("ai-marker-settings", { config: expect.objectContaining({ createSceneMarkers: true, createKeyMomentMarkers: true, createQualityMarkers: false, createEmotionalMarkers: true, minConfidence: 0.7, minSceneDuration: 2, minQualityScore: 80, groupNearbyMarkers: true, groupingThreshold: 2, }), onSave: expect.any(Function), }) }) it("updates marker service config when settings are saved", () => { render() const settingsButton = screen.getByRole("button", { name: /settings/i }) fireEvent.click(settingsButton) const { onSave } = mockOpenModal.mock.calls[0][1] const newConfig = { createSceneMarkers: false, createKeyMomentMarkers: true, createQualityMarkers: true, createEmotionalMarkers: false, minConfidence: 0.8, minSceneDuration: 3, minQualityScore: 90, groupNearbyMarkers: false, groupingThreshold: 1, } onSave(newConfig) expect(mockUpdateConfig).toHaveBeenCalledWith(newConfig) }) it("handles error during marker generation", async () => { mockAnalysisState.keyMoments = [{ time: 10 }] mockCreateMarkersFromKeyMoments.mockImplementation(() => { throw new Error("Generation failed") }) const consoleSpy = vi.spyOn(console, "error").mockImplementation(() => {}) render() const generateButton = screen.getByRole("button", { name: /AI Маркеры/i }) fireEvent.click(generateButton) await waitFor(() => { expect(screen.getByText("Ошибка при создании маркеров")).toBeInTheDocument() }) expect(consoleSpy).toHaveBeenCalledWith("Failed to generate markers:", expect.any(Error)) consoleSpy.mockRestore() }) it("closes result alert", async () => { mockAnalysisState.keyMoments = [{ time: 10 }] mockCreateMarkersFromKeyMoments.mockReturnValue([{ id: "marker1", time: 10 }]) mockGroupNearbyMarkers.mockImplementation((markers) => markers) render() const generateButton = screen.getByRole("button", { name: /AI Маркеры/i }) fireEvent.click(generateButton) // Check that marker was created expect(mockCreateMarkersFromKeyMoments).toHaveBeenCalled() expect(mockSend).toHaveBeenCalledWith({ type: "ADD_MARKER", marker: { id: "marker1", time: 10 } }) }) it("opens settings with current config", async () => { render() const settingsButton = screen.getByRole("button", { name: /settings/i }) fireEvent.click(settingsButton) expect(mockOpenModal).toHaveBeenCalledWith("ai-marker-settings", { config: expect.objectContaining({ createSceneMarkers: true, createKeyMomentMarkers: true, createQualityMarkers: false, // Default is false createEmotionalMarkers: true, minConfidence: 0.7, minSceneDuration: 2, minQualityScore: 80, groupNearbyMarkers: true, groupingThreshold: 2, }), onSave: expect.any(Function), }) }) it("groups nearby markers when enabled", async () => { mockAnalysisState.keyMoments = [ { time: 10, type: "action" }, { time: 11, type: "emotion" }, ] const mockMarkers = [ { id: "marker1", time: 10, label: "Marker 1" }, { id: "marker2", time: 11, label: "Marker 2" }, ] const mockGroupedMarkers = [{ id: "grouped1", time: 10.5, label: "Grouped Marker" }] mockCreateMarkersFromKeyMoments.mockReturnValue(mockMarkers) mockGroupNearbyMarkers.mockReturnValue(mockGroupedMarkers) render() const generateButton = screen.getByRole("button", { name: /AI Маркеры/i }) fireEvent.click(generateButton) await waitFor(() => { expect(mockGroupNearbyMarkers).toHaveBeenCalledWith(mockMarkers) expect(mockSend).toHaveBeenCalledWith({ type: "ADD_MARKER", marker: mockGroupedMarkers[0] }) expect(mockSend).toHaveBeenCalledTimes(1) // Only grouped marker added }) }) it("handles className prop", () => { const { container } = render() expect(container.firstChild).toHaveClass("custom-class") }) it("displays progress bar during generation", async () => { mockAnalysisState.keyMoments = [{ time: 10 }] mockCreateMarkersFromKeyMoments.mockReturnValue([{ id: "marker1", time: 10 }]) mockGroupNearbyMarkers.mockImplementation((markers) => markers) render() const generateButton = screen.getByRole("button", { name: /AI Маркеры/i }) fireEvent.click(generateButton) // Progress should be visible during generation expect(screen.getByRole("progressbar")).toBeInTheDocument() // Check that progress bar is visible during generation expect(screen.getByRole("progressbar")).toBeInTheDocument() }) })