2026-04-26 02:16:20 +02:00
|
|
|
import { afterEach, describe, expect, it, vi } from 'vitest'
|
2026-04-29 14:15:17 +02:00
|
|
|
import { invoke } from '@tauri-apps/api/core'
|
|
|
|
|
import { revealItemInDir } from '@tauri-apps/plugin-opener'
|
2026-04-27 01:45:16 +02:00
|
|
|
import {
|
|
|
|
|
copyLocalPath,
|
2026-05-19 23:30:59 -07:00
|
|
|
isUrlValue,
|
2026-04-27 01:45:16 +02:00
|
|
|
normalizeExternalUrl,
|
|
|
|
|
openExternalUrl,
|
|
|
|
|
openLocalFile,
|
|
|
|
|
revealLocalPath,
|
|
|
|
|
} from './url'
|
|
|
|
|
|
2026-04-29 14:15:17 +02:00
|
|
|
vi.mock('@tauri-apps/api/core', () => ({
|
|
|
|
|
invoke: vi.fn(),
|
|
|
|
|
}))
|
|
|
|
|
|
2026-04-27 01:45:16 +02:00
|
|
|
const originalClipboard = navigator.clipboard
|
|
|
|
|
|
|
|
|
|
function setClipboard(writeText: (value: string) => Promise<void>) {
|
|
|
|
|
Object.defineProperty(navigator, 'clipboard', {
|
|
|
|
|
configurable: true,
|
|
|
|
|
value: { writeText },
|
|
|
|
|
})
|
|
|
|
|
}
|
2026-04-26 02:16:20 +02:00
|
|
|
|
|
|
|
|
describe('normalizeExternalUrl', () => {
|
|
|
|
|
it('keeps valid http URLs and normalizes bare domains', () => {
|
2026-05-19 23:30:59 -07:00
|
|
|
expect(normalizeExternalUrl('https://example.com')).toBe('https://example.com')
|
2026-04-26 02:16:20 +02:00
|
|
|
expect(normalizeExternalUrl('https://example.com/docs')).toBe('https://example.com/docs')
|
|
|
|
|
expect(normalizeExternalUrl('example.com/docs')).toBe('https://example.com/docs')
|
|
|
|
|
})
|
|
|
|
|
|
2026-05-19 23:30:59 -07:00
|
|
|
it('rejects pure numeric values instead of treating them as bare domains', () => {
|
|
|
|
|
expect(normalizeExternalUrl('2026')).toBeNull()
|
|
|
|
|
expect(normalizeExternalUrl('0')).toBeNull()
|
|
|
|
|
expect(isUrlValue('2026')).toBe(false)
|
|
|
|
|
})
|
|
|
|
|
|
2026-04-26 02:16:20 +02:00
|
|
|
it('rejects malformed or unsupported URLs', () => {
|
|
|
|
|
expect(normalizeExternalUrl('https://exa mple.com')).toBeNull()
|
|
|
|
|
expect(normalizeExternalUrl('javascript:alert(1)')).toBeNull()
|
|
|
|
|
expect(normalizeExternalUrl('not a url')).toBeNull()
|
|
|
|
|
})
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
describe('openExternalUrl', () => {
|
|
|
|
|
afterEach(() => {
|
2026-04-27 01:45:16 +02:00
|
|
|
vi.unstubAllGlobals()
|
2026-04-26 02:16:20 +02:00
|
|
|
vi.restoreAllMocks()
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
it('does not ask the browser to open malformed URLs', async () => {
|
|
|
|
|
const open = vi.spyOn(window, 'open').mockImplementation(() => null)
|
|
|
|
|
|
|
|
|
|
await openExternalUrl('https://exa mple.com')
|
|
|
|
|
|
|
|
|
|
expect(open).not.toHaveBeenCalled()
|
|
|
|
|
})
|
|
|
|
|
})
|
2026-04-27 01:45:16 +02:00
|
|
|
|
|
|
|
|
describe('local file actions', () => {
|
|
|
|
|
afterEach(() => {
|
|
|
|
|
Object.defineProperty(navigator, 'clipboard', {
|
|
|
|
|
configurable: true,
|
|
|
|
|
value: originalClipboard,
|
|
|
|
|
})
|
|
|
|
|
vi.unstubAllGlobals()
|
|
|
|
|
vi.clearAllMocks()
|
|
|
|
|
})
|
|
|
|
|
|
2026-04-29 14:15:17 +02:00
|
|
|
it('opens local paths through the vault-scoped backend command', async () => {
|
2026-04-27 01:45:16 +02:00
|
|
|
vi.stubGlobal('isTauri', true)
|
|
|
|
|
|
2026-04-29 14:15:17 +02:00
|
|
|
await openLocalFile('/vault/attachments/report.pdf', '/vault')
|
2026-04-27 01:45:16 +02:00
|
|
|
|
2026-04-29 14:15:17 +02:00
|
|
|
expect(invoke).toHaveBeenCalledWith('open_vault_file_external', {
|
|
|
|
|
path: '/vault/attachments/report.pdf',
|
|
|
|
|
vaultPath: '/vault',
|
|
|
|
|
})
|
2026-04-27 01:45:16 +02:00
|
|
|
})
|
|
|
|
|
|
|
|
|
|
it('reveals local paths through the Tauri opener plugin', async () => {
|
|
|
|
|
vi.stubGlobal('isTauri', true)
|
|
|
|
|
|
|
|
|
|
await revealLocalPath('/vault/notes/project.md')
|
|
|
|
|
|
|
|
|
|
expect(revealItemInDir).toHaveBeenCalledWith('/vault/notes/project.md')
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
it('copies local paths to the clipboard', async () => {
|
|
|
|
|
const writeText = vi.fn().mockResolvedValue(undefined)
|
|
|
|
|
setClipboard(writeText)
|
|
|
|
|
|
|
|
|
|
await copyLocalPath('/vault/Folder With Spaces/项目.md')
|
|
|
|
|
|
|
|
|
|
expect(writeText).toHaveBeenCalledWith('/vault/Folder With Spaces/项目.md')
|
|
|
|
|
})
|
|
|
|
|
})
|