import { render, screen, waitFor } from "@testing-library/react" import userEvent from "@testing-library/user-event" import { beforeEach, describe, expect, it, vi } from "vitest" // Мокаем MediaRestorationService vi.mock("@/features/media/services/media-restoration-service", () => ({ promptUserToFindFile: vi.fn(), })) import { SavedMediaFile } from "@/features/media/types/saved-media" import { MissingFilesDialog } from "../../components/missing-files-dialog" // Мокаем UI компоненты vi.mock("@/components/ui/alert-dialog", () => ({ AlertDialog: ({ children, open }: any) => (open ?
{children}
: null), AlertDialogContent: ({ children }: any) =>
{children}
, AlertDialogHeader: ({ children }: any) =>
{children}
, AlertDialogTitle: ({ children }: any) =>

{children}

, AlertDialogDescription: ({ children }: any) =>

{children}

, AlertDialogFooter: ({ children }: any) =>
{children}
, AlertDialogAction: ({ children, onClick }: any) => ( ), AlertDialogCancel: ({ children, onClick }: any) => ( ), })) vi.mock("@/components/ui/button", () => ({ Button: ({ children, onClick, variant, size, ...props }: any) => ( ), })) vi.mock("@/components/ui/separator", () => ({ Separator: () =>
, })) // Мокаем иконки vi.mock("lucide-react", () => ({ AlertTriangle: () =>
, CheckCircle: () =>
, FileX: () =>
, Search: () =>
, Trash2: () =>
, })) const { promptUserToFindFile } = await import("@/features/media/services/media-restoration-service") const mockPromptUserToFindFile = vi.mocked(promptUserToFindFile) describe("MissingFilesDialog", () => { const mockMissingFiles: SavedMediaFile[] = [ { id: "file-1", originalPath: "/path/to/video1.mp4", name: "video1.mp4", size: 1024, lastModified: Date.now(), isVideo: true, isAudio: false, isImage: false, metadata: { duration: 120 }, status: "missing", lastChecked: Date.now(), }, { id: "file-2", originalPath: "/path/to/audio.mp3", name: "audio.mp3", size: 512, lastModified: Date.now(), isVideo: false, isAudio: true, isImage: false, metadata: { duration: 180 }, status: "missing", lastChecked: Date.now(), }, ] const mockOnResolve = vi.fn() const mockOnOpenChange = vi.fn() beforeEach(() => { vi.clearAllMocks() }) it("должен отображаться когда open=true", () => { render( , ) expect(screen.getByTestId("alert-dialog")).toBeInTheDocument() expect(screen.getByTestId("dialog-title")).toHaveTextContent("Отсутствующие медиафайлы") }) it("не должен отображаться когда open=false", () => { render( , ) expect(screen.queryByTestId("alert-dialog")).not.toBeInTheDocument() }) it("должен отображать список отсутствующих файлов", () => { render( , ) expect(screen.getByText("video1.mp4")).toBeInTheDocument() expect(screen.getByText("audio.mp3")).toBeInTheDocument() expect(screen.getByText("/path/to/video1.mp4")).toBeInTheDocument() expect(screen.getByText("/path/to/audio.mp3")).toBeInTheDocument() }) it("должен показывать правильные иконки статуса", () => { render( , ) // Должны быть иконки предупреждения: 1 в заголовке + 2 для файлов = 3 expect(screen.getAllByTestId("alert-triangle-icon")).toHaveLength(3) }) it("должен позволять найти файл", async () => { const user = userEvent.setup() mockPromptUserToFindFile.mockResolvedValue("/new/path/video1.mp4") render( , ) const findButtons = screen.getAllByTestId("search-icon") await user.click(findButtons[0].closest("button")!) await waitFor(() => { expect(mockPromptUserToFindFile).toHaveBeenCalledWith(mockMissingFiles[0]) }) // Проверяем, что статус изменился на "найден" await waitFor(() => { expect(screen.getByTestId("check-circle-icon")).toBeInTheDocument() }) }) it("должен позволять удалить файл из проекта", async () => { const user = userEvent.setup() render( , ) const removeButtons = screen.getAllByTestId("trash-icon") await user.click(removeButtons[0].closest("button")!) // Проверяем, что статус изменился на "удален" (иконка остается trash-icon, но меняется текст) await waitFor(() => { expect(screen.getByText("Удалить")).toBeInTheDocument() }) }) it('должен применять изменения при нажатии "Применить изменения"', async () => { const user = userEvent.setup() mockPromptUserToFindFile.mockResolvedValue("/new/path/video1.mp4") render( , ) // Найдем первый файл const findButtons = screen.getAllByTestId("search-icon") await user.click(findButtons[0].closest("button")!) await waitFor(() => { expect(screen.getByTestId("check-circle-icon")).toBeInTheDocument() }) // Удалим второй файл const removeButtons = screen.getAllByTestId("trash-icon") await user.click(removeButtons[0].closest("button")!) await waitFor(() => { expect(screen.getByText("Удалить")).toBeInTheDocument() }) // Применим изменения const applyButton = screen.getByTestId("dialog-action") await user.click(applyButton) expect(mockOnResolve).toHaveBeenCalledWith([ { file: mockMissingFiles[0], newPath: "/new/path/video1.mp4", action: "found", }, { file: mockMissingFiles[1], action: "remove", }, ]) }) it('должен закрываться при нажатии "Пропустить все"', async () => { const user = userEvent.setup() render( , ) const skipButton = screen.getByTestId("dialog-cancel") await user.click(skipButton) expect(mockOnOpenChange).toHaveBeenCalledWith(false) }) it("должен показывать правильное количество файлов в заголовке", () => { render( , ) // Количество файлов показывается в статистике, а не в описании expect(screen.getByText("Файлов: 2")).toBeInTheDocument() }) it("должен обрабатывать отмену поиска файла", async () => { const user = userEvent.setup() mockPromptUserToFindFile.mockResolvedValue(null) // Пользователь отменил render( , ) const findButton = screen.getAllByTestId("search-icon")[0] await user.click(findButton.closest("button")!) await waitFor(() => { expect(mockPromptUserToFindFile).toHaveBeenCalled() }) // Статус должен остаться "отсутствует" expect(screen.getByTestId("alert-triangle-icon")).toBeInTheDocument() }) it("должен показывать размер файла в читаемом формате", () => { render( , ) // Размер показывается в МБ, а не в KB (1024 байт = 0.0 МБ) expect( screen.getByText((content, _element) => { return content.includes("0.0") && content.includes("МБ") }), ).toBeInTheDocument() }) })