import { renderHook } from "@testing-library/react"
import { beforeEach, describe, expect, it, vi } from "vitest"
import { useMediaAdapter } from "../../adapters/use-media-adapter"
import { createMockMediaFile } from "./test-utils"
// Мокаем все зависимости напрямую
vi.mock("@/features/app-state", () => ({
AppSettingsProvider: ({ children }: any) => children,
useAppSettings: vi.fn(() => ({
connectionError: null,
projectState: {
project: {
media_pool: {
items: {
"test-1": {
id: "test-1",
name: "test-video.mp4",
path: "/test/video.mp4",
media_type: "Video",
duration: 120.5,
metadata: {
format: "",
codec: null,
resolution: null,
frame_rate: null,
bitrate: null,
audio_channels: null,
sample_rate: null,
},
thumbnail: null,
usage_count: 0,
// Дополнительные поля для совместимости
extension: ".mp4",
size: 1024000,
createdAt: "2024-01-01T00:00:00Z",
startTime: 0,
probeData: {
streams: [{ codec_type: "video" }],
format: { duration: 120.5 },
},
},
"test-2": {
id: "test-2",
name: "test-image.jpg",
path: "/test/image.jpg",
media_type: "Image",
duration: null,
metadata: {
format: "",
codec: null,
resolution: null,
frame_rate: null,
bitrate: null,
audio_channels: null,
sample_rate: null,
},
thumbnail: null,
usage_count: 0,
// Дополнительные поля для совместимости
extension: ".jpg",
size: 512000,
createdAt: "2024-01-02T00:00:00Z",
startTime: 0,
},
},
},
},
},
})),
useFavorites: vi.fn(() => ({
isItemFavorite: vi.fn(() => false),
})),
}))
vi.mock("@/features/media/hooks/use-media-import", () => ({
useMediaImport: vi.fn(() => ({
importFile: vi.fn(),
importFolder: vi.fn(),
isImporting: false,
})),
}))
vi.mock("@/features/media", () => ({
getFileType: vi.fn((file) => {
if (file.extension === ".mp4") return "video"
if (file.extension === ".jpg" || file.extension === ".png") return "image"
if (file.extension === ".mp3") return "audio"
return "unknown"
}),
}))
vi.mock("@/features/browser/utils", () => ({
parseDuration: vi.fn((duration) => duration || 0),
parseFileSize: vi.fn((size) => size || 0),
}))
vi.mock("@/features/browser/utils/grouping", () => ({
getDateGroup: vi.fn((timestamp, _language) => {
if (!timestamp || timestamp === 0) return "Без даты"
return "2024"
}),
getDurationGroup: vi.fn((duration) => {
if (duration <= 60) return "Короткие (≤1мин)"
if (duration <= 180) return "1-3 минуты"
return "Длинные (>3мин)"
}),
}))
vi.mock("@/features/browser/components/preview/media-preview", () => ({
MediaPreview: ({ file, size, showFileName }: any) => (
{file.name} - {size} - {showFileName ? "with-filename" : "no-filename"}
),
}))
vi.mock("@/i18n", () => ({
default: {
t: vi.fn((key) => key),
language: "ru",
on: vi.fn(),
off: vi.fn(),
changeLanguage: vi.fn(() => Promise.resolve()),
},
}))
describe("useMediaAdapter", () => {
beforeEach(() => {
vi.clearAllMocks()
})
it("should return media adapter with correct structure", () => {
const { result } = renderHook(() => useMediaAdapter())
expect(result.current).toHaveProperty("useData")
expect(result.current).toHaveProperty("PreviewComponent")
expect(result.current).toHaveProperty("getSortValue")
expect(result.current).toHaveProperty("getSearchableText")
expect(result.current).toHaveProperty("getGroupValue")
expect(result.current).toHaveProperty("matchesFilter")
expect(result.current).toHaveProperty("importHandlers")
expect(result.current).toHaveProperty("isFavorite")
expect(result.current).toHaveProperty("favoriteType", "media")
})
describe("useData", () => {
it("should return media files data", () => {
const { result } = renderHook(() => useMediaAdapter())
const { result: dataResult } = renderHook(() => result.current.useData())
expect(dataResult.current.loading).toBe(false)
expect(dataResult.current.error).toBe(null)
expect(dataResult.current.items).toHaveLength(2)
expect(dataResult.current.items[0].name).toBe("test-video.mp4")
expect(dataResult.current.items[1].name).toBe("test-image.jpg")
})
})
describe("getSortValue", () => {
it("should sort by different fields correctly", () => {
const { result } = renderHook(() => useMediaAdapter())
const testFile = createMockMediaFile({
name: "Test.mp4",
size: 1024,
createdAt: "2024-01-01T00:00:00Z",
duration: 60,
startTime: 0,
probeData: {
streams: [],
format: { duration: 60 },
},
})
expect(result.current.getSortValue(testFile, "name")).toBe("test.mp4")
expect(result.current.getSortValue(testFile, "size")).toBe(1024)
expect(result.current.getSortValue(testFile, "duration")).toBe(60)
expect(result.current.getSortValue(testFile, "unknown")).toBe(0) // Returns startTime for unknown
})
it("should handle missing duration data", () => {
const { result } = renderHook(() => useMediaAdapter())
const testFile = createMockMediaFile({
duration: undefined,
probeData: undefined,
startTime: 0,
})
expect(result.current.getSortValue(testFile, "duration")).toBe(0)
})
it("should prioritize probe data for size", () => {
const { result } = renderHook(() => useMediaAdapter())
const testFile = createMockMediaFile({
name: "test.mp4",
size: 1024,
startTime: 0,
probeData: {
streams: [],
format: { size: 2048 },
},
})
expect(result.current.getSortValue(testFile, "size")).toBe(2048) // Probe data has priority
})
it("should handle missing probe data for size", () => {
const { result } = renderHook(() => useMediaAdapter())
const testFile = createMockMediaFile({
name: "test.mp4",
size: 1024,
startTime: 0,
probeData: {
streams: [],
format: {},
},
})
expect(result.current.getSortValue(testFile, "size")).toBe(1024) // Falls back to parsed size
})
})
describe("getSearchableText", () => {
it("should return searchable text array", () => {
const { result } = renderHook(() => useMediaAdapter())
const testFile = createMockMediaFile({
name: "test-video.mp4",
startTime: 0,
probeData: {
streams: [],
format: {
tags: {
title: "Test Title",
artist: "Test Artist",
album: "Test Album",
},
},
},
})
const searchableText = result.current.getSearchableText(testFile)
expect(searchableText).toEqual(["test-video.mp4", "Test Title", "Test Artist", "Test Album"])
})
it("should filter out empty values", () => {
const { result } = renderHook(() => useMediaAdapter())
const testFile = createMockMediaFile({
name: "test.mp4",
probeData: undefined,
startTime: 0,
})
const searchableText = result.current.getSearchableText(testFile)
expect(searchableText).toEqual(["test.mp4"])
})
it("should handle missing tags", () => {
const { result } = renderHook(() => useMediaAdapter())
const testFile = createMockMediaFile({
name: "test.mp4",
startTime: 0,
probeData: {
streams: [],
format: {},
},
})
const searchableText = result.current.getSearchableText(testFile)
expect(searchableText).toEqual(["test.mp4"])
})
})
describe("getGroupValue", () => {
it("should group by type", () => {
const { result } = renderHook(() => useMediaAdapter())
const testFile = createMockMediaFile({
name: "test.mp4",
extension: ".mp4",
startTime: 0,
})
const group = result.current.getGroupValue(testFile, "type")
expect(group).toBe("browser.media.video") // i18n key, not translated
})
it("should group by date", () => {
const { result } = renderHook(() => useMediaAdapter())
const testFile = createMockMediaFile({
name: "test.mp4",
startTime: 0, // No date
})
const group = result.current.getGroupValue(testFile, "date")
expect(group).toBe("Без даты") // startTime is 0, so no date
})
it("should group by date with timestamp", () => {
const { result } = renderHook(() => useMediaAdapter())
const testFile = createMockMediaFile({
name: "test.mp4",
startTime: 1672531200, // 2023-01-01
})
const group = result.current.getGroupValue(testFile, "date")
expect(group).not.toBe("Без даты") // Has date
})
it("should group by duration", () => {
const { result } = renderHook(() => useMediaAdapter())
const testFile = createMockMediaFile({
name: "test.mp4",
duration: 120, // 2 minutes
startTime: 0,
})
const group = result.current.getGroupValue(testFile, "duration")
expect(group).toBe("1-3 минуты") // 120 seconds = 2 minutes
})
it("should handle image metadata for date grouping", () => {
const { result } = renderHook(() => useMediaAdapter())
const testFile = createMockMediaFile({
name: "test.jpg",
startTime: 0,
probeData: {
streams: [],
format: {
tags: {
creation_time: "2024-01-01T00:00:00Z",
},
},
},
})
const group = result.current.getGroupValue(testFile, "date")
expect(group).not.toBe("Без даты") // Should use creation_time from metadata
})
it("should return empty string for unknown group type", () => {
const { result } = renderHook(() => useMediaAdapter())
const testFile = createMockMediaFile({
name: "test.mp4",
startTime: 0,
})
const group = result.current.getGroupValue(testFile, "unknown")
expect(group).toBe("") // Default case returns empty string
})
})
describe("matchesFilter", () => {
it("should match video filter", () => {
const { result } = renderHook(() => useMediaAdapter())
const videoFile = createMockMediaFile({
name: "test.mp4",
extension: ".mp4",
isVideo: true,
startTime: 0,
probeData: {
streams: [{ codec_type: "video" }],
format: {},
},
})
expect(result.current.matchesFilter?.(videoFile, "video")).toBe(true)
expect(result.current.matchesFilter?.(videoFile, "audio")).toBe(false)
expect(result.current.matchesFilter?.(videoFile, "image")).toBe(false)
})
it("should match image filter", () => {
const { result } = renderHook(() => useMediaAdapter())
const imageFile = createMockMediaFile({
name: "test.jpg",
extension: ".jpg",
isImage: true,
startTime: 0,
probeData: {
streams: [],
format: {},
},
})
expect(result.current.matchesFilter?.(imageFile, "image")).toBe(true)
expect(result.current.matchesFilter?.(imageFile, "video")).toBe(false)
expect(result.current.matchesFilter?.(imageFile, "audio")).toBe(false)
})
it("should match audio filter", () => {
const { result } = renderHook(() => useMediaAdapter())
const audioFile = createMockMediaFile({
name: "test.mp3",
extension: ".mp3",
isAudio: true,
startTime: 0,
probeData: {
streams: [{ codec_type: "audio" }],
format: {},
},
})
expect(result.current.matchesFilter?.(audioFile, "audio")).toBe(true)
expect(result.current.matchesFilter?.(audioFile, "video")).toBe(false)
expect(result.current.matchesFilter?.(audioFile, "image")).toBe(false)
})
it("should handle loading metadata state", () => {
const { result } = renderHook(() => useMediaAdapter())
const loadingFile = createMockMediaFile({
name: "test.mp4",
extension: ".mp4",
isVideo: true,
isLoadingMetadata: true,
startTime: 0,
})
expect(result.current.matchesFilter?.(loadingFile, "video")).toBe(true) // Uses basic properties
expect(result.current.matchesFilter?.(loadingFile, "audio")).toBe(false)
})
it("should handle image filter by extension when no metadata", () => {
const { result } = renderHook(() => useMediaAdapter())
const imageFile = createMockMediaFile({
name: "test.png",
extension: ".png",
startTime: 0,
probeData: {
streams: [],
format: {},
},
})
expect(result.current.matchesFilter?.(imageFile, "image")).toBe(true) // Uses regex test
})
it("should match 'all' filter", () => {
const { result } = renderHook(() => useMediaAdapter())
const testFile = createMockMediaFile({
name: "test.mp4",
startTime: 0,
})
expect(result.current.matchesFilter?.(testFile, "all")).toBe(true)
})
it("should return false for unknown filter", () => {
const { result } = renderHook(() => useMediaAdapter())
const testFile = createMockMediaFile({
name: "test.mp4",
startTime: 0,
})
expect(result.current.matchesFilter?.(testFile, "unknown")).toBe(false)
})
})
describe("PreviewComponent", () => {
it("should be defined", () => {
const { result } = renderHook(() => useMediaAdapter())
expect(result.current.PreviewComponent).toBeDefined()
expect(typeof result.current.PreviewComponent).toBe("function")
})
it("should render MediaPreview correctly in list mode", () => {
const { result } = renderHook(() => useMediaAdapter())
const PreviewComponent = result.current.PreviewComponent
const mockFile = createMockMediaFile({
name: "test.mp4",
startTime: 0,
})
const mockProps = {
item: mockFile,
size: 100,
viewMode: "list" as const,
onClick: vi.fn(),
onDragStart: vi.fn(),
isSelected: false,
isFavorite: false,
onToggleFavorite: vi.fn(),
onAddToTimeline: vi.fn(),
}
expect(() => ).not.toThrow()
})
it("should handle thumbnails view mode", () => {
const { result } = renderHook(() => useMediaAdapter())
const PreviewComponent = result.current.PreviewComponent
const mockFile = createMockMediaFile({
name: "test.mp4",
startTime: 0,
})
const mockProps = {
item: mockFile,
size: { width: 120, height: 80 },
viewMode: "thumbnails" as const,
onClick: vi.fn(),
onDragStart: vi.fn(),
isSelected: false,
isFavorite: false,
onToggleFavorite: vi.fn(),
onAddToTimeline: vi.fn(),
}
expect(() => ).not.toThrow()
})
it("should handle click events", () => {
const { result } = renderHook(() => useMediaAdapter())
const PreviewComponent = result.current.PreviewComponent
const mockOnClick = vi.fn()
const mockFile = createMockMediaFile({
name: "test.mp4",
startTime: 0,
})
const mockProps = {
item: mockFile,
size: 100,
viewMode: "list" as const,
onClick: mockOnClick,
onDragStart: vi.fn(),
isSelected: false,
isFavorite: false,
onToggleFavorite: vi.fn(),
onAddToTimeline: vi.fn(),
}
// Test that component renders without throwing
expect(() => ).not.toThrow()
})
it("should handle drag events", () => {
const { result } = renderHook(() => useMediaAdapter())
const PreviewComponent = result.current.PreviewComponent
const mockOnDragStart = vi.fn()
const mockFile = createMockMediaFile({
name: "test.mp4",
startTime: 0,
})
const mockProps = {
item: mockFile,
size: 100,
viewMode: "list" as const,
onClick: vi.fn(),
onDragStart: mockOnDragStart,
isSelected: false,
isFavorite: false,
onToggleFavorite: vi.fn(),
onAddToTimeline: vi.fn(),
}
expect(() => ).not.toThrow()
})
})
describe("importHandlers", () => {
it("should provide import functions", () => {
const { result } = renderHook(() => useMediaAdapter())
expect(result.current.importHandlers).toBeDefined()
expect(typeof result.current.importHandlers?.importFile).toBe("function")
expect(typeof result.current.importHandlers?.importFolder).toBe("function")
expect(typeof result.current.importHandlers?.isImporting).toBe("boolean")
})
it("should have correct import function signatures", () => {
const { result } = renderHook(() => useMediaAdapter())
// Test that functions exist and are callable
expect(result.current.importHandlers?.importFile).toBeDefined()
expect(result.current.importHandlers?.importFolder).toBeDefined()
expect(result.current.importHandlers?.isImporting).toBeDefined()
})
})
describe("isFavorite", () => {
it("should check if file is favorite", () => {
const { result } = renderHook(() => useMediaAdapter())
const testFile = createMockMediaFile({
name: "test.mp4",
startTime: 0,
})
expect(typeof result.current.isFavorite).toBe("function")
expect(result.current.isFavorite(testFile)).toBe(false)
})
it("should use correct favorite type", () => {
const { result } = renderHook(() => useMediaAdapter())
const testFile = createMockMediaFile({
name: "test.mp4",
startTime: 0,
})
// The function should call isItemFavorite with "media" type
result.current.isFavorite(testFile)
// We can't easily verify the call since it's mocked, but we test the return type
expect(typeof result.current.isFavorite(testFile)).toBe("boolean")
})
})
describe("favoriteType", () => {
it("should be 'media'", () => {
const { result } = renderHook(() => useMediaAdapter())
expect(result.current.favoriteType).toBe("media")
})
})
})