Files
tolaria/src/components/FilePreview.test.tsx
2026-05-15 01:22:56 +02:00

191 lines
6.3 KiB
TypeScript

import { fireEvent, render, screen } from '@testing-library/react'
import { beforeEach, describe, expect, it, vi } from 'vitest'
import { FilePreview } from './FilePreview'
import type { VaultEntry } from '../types'
const { externalMediaPreviewMock, trackEventMock } = vi.hoisted(() => ({
externalMediaPreviewMock: vi.fn(() => false),
trackEventMock: vi.fn(),
}))
vi.mock('@tauri-apps/api/core', () => ({
convertFileSrc: (path: string) => `asset://${path}`,
}))
vi.mock('../lib/telemetry', () => ({
trackEvent: trackEventMock,
}))
vi.mock('../utils/mediaPreviewRuntime', () => ({
useExternalMediaPreview: externalMediaPreviewMock,
}))
const imageEntry: VaultEntry = {
path: '/vault/Attachments/photo.png',
filename: 'photo.png',
title: 'photo.png',
isA: null,
aliases: [],
belongsTo: [],
relatedTo: [],
status: null,
archived: false,
modifiedAt: 1700000000,
createdAt: 1700000000,
fileSize: 100,
snippet: '',
wordCount: 0,
relationships: {},
icon: null,
color: null,
order: null,
sidebarLabel: null,
template: null,
sort: null,
view: null,
visible: null,
organized: false,
favorite: false,
favoriteIndex: null,
listPropertiesDisplay: [],
outgoingLinks: [],
properties: {},
hasH1: false,
fileKind: 'binary',
}
const pdfEntry: VaultEntry = {
...imageEntry,
path: '/vault/Attachments/report.pdf',
filename: 'report.pdf',
title: 'report.pdf',
}
const audioEntry: VaultEntry = {
...imageEntry,
path: '/vault/Attachments/meeting.mp3',
filename: 'meeting.mp3',
title: 'meeting.mp3',
}
const videoEntry: VaultEntry = {
...imageEntry,
path: '/vault/Attachments/demo.mp4',
filename: 'demo.mp4',
title: 'demo.mp4',
}
describe('FilePreview', () => {
beforeEach(() => {
externalMediaPreviewMock.mockReturnValue(false)
trackEventMock.mockClear()
})
it('routes header file actions to the active file path', () => {
const onRevealFile = vi.fn()
const onCopyFilePath = vi.fn()
const onOpenExternalFile = vi.fn()
render(
<FilePreview
entry={imageEntry}
onRevealFile={onRevealFile}
onCopyFilePath={onCopyFilePath}
onOpenExternalFile={onOpenExternalFile}
/>,
)
expect(trackEventMock).toHaveBeenCalledWith('file_preview_opened', { preview_kind: 'image' })
fireEvent.click(screen.getByRole('button', { name: 'Reveal' }))
fireEvent.click(screen.getByRole('button', { name: 'Copy path' }))
fireEvent.click(screen.getByRole('button', { name: 'Open' }))
expect(onRevealFile).toHaveBeenCalledWith('/vault/Attachments/photo.png')
expect(onCopyFilePath).toHaveBeenCalledWith('/vault/Attachments/photo.png')
expect(onOpenExternalFile).toHaveBeenCalledWith('/vault/Attachments/photo.png')
expect(trackEventMock).toHaveBeenCalledWith('file_preview_action', {
action: 'reveal',
preview_kind: 'image',
})
expect(trackEventMock).toHaveBeenCalledWith('file_preview_action', {
action: 'copy_path',
preview_kind: 'image',
})
expect(trackEventMock).toHaveBeenCalledWith('file_preview_action', {
action: 'open_external',
preview_kind: 'image',
})
})
it('renders supported PDF files through the asset preview path', () => {
render(<FilePreview entry={pdfEntry} />)
expect(screen.getByTestId('pdf-file-preview')).toHaveAttribute('data', 'asset:///vault/Attachments/report.pdf')
expect(screen.getByText('PDF file')).toBeInTheDocument()
})
it('renders supported PDFs when binary metadata is unavailable', () => {
render(<FilePreview entry={{ ...pdfEntry, fileKind: undefined }} />)
expect(screen.getByTestId('pdf-file-preview')).toHaveAttribute('data', 'asset:///vault/Attachments/report.pdf')
})
it('renders supported audio files through the media asset path', () => {
render(<FilePreview entry={audioEntry} />)
expect(screen.getByTestId('audio-file-preview')).toHaveAttribute('src', 'asset:///vault/Attachments/meeting.mp3')
expect(screen.getByText('MP3 file')).toBeInTheDocument()
expect(trackEventMock).toHaveBeenCalledWith('file_preview_opened', { preview_kind: 'audio' })
})
it('renders supported video files through the media asset path', () => {
render(<FilePreview entry={videoEntry} />)
expect(screen.getByTestId('video-file-preview')).toHaveAttribute('src', 'asset:///vault/Attachments/demo.mp4')
expect(screen.getByTestId('video-file-preview')).toHaveAttribute('title', 'demo.mp4')
expect(trackEventMock).toHaveBeenCalledWith('file_preview_opened', { preview_kind: 'video' })
})
it('uses the external-open fallback for media when native playback is unsafe', () => {
const onOpenExternalFile = vi.fn()
externalMediaPreviewMock.mockReturnValue(true)
render(<FilePreview entry={videoEntry} onOpenExternalFile={onOpenExternalFile} />)
expect(screen.queryByTestId('video-file-preview')).not.toBeInTheDocument()
expect(screen.getByTestId('file-preview-fallback')).toHaveTextContent('Preview unavailable')
fireEvent.click(screen.getByRole('button', { name: 'Open in default app' }))
expect(onOpenExternalFile).toHaveBeenCalledWith('/vault/Attachments/demo.mp4')
})
it('provides a graceful fallback when a PDF preview cannot render', () => {
render(<FilePreview entry={pdfEntry} />)
expect(screen.getByTestId('file-preview-fallback')).toHaveTextContent('PDF preview failed')
expect(screen.getByRole('button', { name: 'Open in default app' })).toBeInTheDocument()
})
it('tracks image preview failures without leaking the file path', () => {
render(<FilePreview entry={imageEntry} />)
fireEvent.error(screen.getByTestId('image-file-preview'))
expect(trackEventMock).toHaveBeenCalledWith('file_preview_failed', { preview_kind: 'image' })
expect(trackEventMock).not.toHaveBeenCalledWith(
expect.any(String),
expect.objectContaining({ path: expect.any(String) }),
)
})
it('tracks media preview failures without leaking the file path', () => {
render(<FilePreview entry={audioEntry} />)
fireEvent.error(screen.getByTestId('audio-file-preview'))
expect(trackEventMock).toHaveBeenCalledWith('file_preview_failed', { preview_kind: 'audio' })
expect(trackEventMock).not.toHaveBeenCalledWith(
expect.any(String),
expect.objectContaining({ path: expect.any(String) }),
)
})
})