Files
tolaria/src/components/editorAttachmentActions.test.ts
2026-05-08 14:19:52 +02:00

129 lines
3.8 KiB
TypeScript

import { beforeEach, describe, expect, it, vi } from 'vitest'
import { handleEditorFileBlockClick } from './editorAttachmentActions'
import { openExternalUrl, openLocalFile } from '../utils/url'
vi.mock('../utils/url', () => ({
normalizeExternalUrl: vi.fn((url: string) => (
url.startsWith('http://') || url.startsWith('https://') ? url : null
)),
openExternalUrl: vi.fn().mockResolvedValue(undefined),
openLocalFile: vi.fn().mockResolvedValue(undefined),
}))
const mockOpenExternalUrl = vi.mocked(openExternalUrl)
const mockOpenLocalFile = vi.mocked(openLocalFile)
function fileBlockClickTarget(blockId = 'file-block') {
const blockContainer = document.createElement('div')
blockContainer.setAttribute('data-node-type', 'blockContainer')
blockContainer.dataset.id = blockId
const fileBlock = document.createElement('div')
fileBlock.setAttribute('data-file-block', '')
const fileName = document.createElement('span')
fileName.className = 'bn-file-name-with-icon'
fileName.textContent = 'report.pdf'
fileBlock.appendChild(fileName)
blockContainer.appendChild(fileBlock)
return fileName
}
function clickRequest(target: HTMLElement) {
return {
target,
preventDefault: vi.fn(),
stopPropagation: vi.fn(),
}
}
describe('handleEditorFileBlockClick', () => {
beforeEach(() => {
vi.clearAllMocks()
})
it.each([
{
blockId: 'file-block',
blockType: 'file',
url: 'asset://localhost/%2Fvault%2Fattachments%2Freport.pdf',
expectedPath: '/vault/attachments/report.pdf',
},
{
blockId: 'image-block',
blockType: 'image',
url: 'asset://localhost/%2Fvault%2Fattachments%2Fphoto.png',
expectedPath: '/vault/attachments/photo.png',
},
])('opens $blockType block names through the active vault path', ({
blockId,
blockType,
expectedPath,
url,
}) => {
const event = clickRequest(fileBlockClickTarget(blockId))
const editor = {
getBlock: vi.fn(() => ({
type: blockType,
props: { url },
})),
}
expect(handleEditorFileBlockClick({
event: event as never,
editor,
vaultPath: '/vault',
})).toBe(true)
expect(event.preventDefault).toHaveBeenCalledTimes(1)
expect(event.stopPropagation).toHaveBeenCalledTimes(1)
expect(mockOpenLocalFile).toHaveBeenCalledWith(expectedPath, '/vault')
expect(mockOpenExternalUrl).not.toHaveBeenCalled()
})
it('consumes stale file block clicks without opening or crashing', () => {
const warn = vi.spyOn(console, 'warn').mockImplementation(() => {})
const event = clickRequest(fileBlockClickTarget('stale-file-block'))
const editor = {
getBlock: vi.fn(() => {
throw new Error('Block with ID stale-file-block not found')
}),
}
expect(() => {
expect(handleEditorFileBlockClick({
event: event as never,
editor,
vaultPath: '/vault',
})).toBe(true)
}).not.toThrow()
expect(event.preventDefault).toHaveBeenCalledTimes(1)
expect(event.stopPropagation).toHaveBeenCalledTimes(1)
expect(warn).toHaveBeenCalledWith(
'[file] Ignored stale file block click:',
expect.any(Error),
)
expect(mockOpenLocalFile).not.toHaveBeenCalled()
expect(mockOpenExternalUrl).not.toHaveBeenCalled()
warn.mockRestore()
})
it('ignores clicks outside file block actions', () => {
const target = document.createElement('div')
const event = clickRequest(target)
expect(handleEditorFileBlockClick({
event: event as never,
editor: { getBlock: vi.fn() },
vaultPath: '/vault',
})).toBe(false)
expect(event.preventDefault).not.toHaveBeenCalled()
expect(event.stopPropagation).not.toHaveBeenCalled()
expect(mockOpenLocalFile).not.toHaveBeenCalled()
expect(mockOpenExternalUrl).not.toHaveBeenCalled()
})
})