Files
tolaria/src/utils/autoSave.test.ts
lucaronin 3e05a9425a test: add Playwright smoke test for exact-match search ranking
Verifies that searching "Writing" in Quick Open shows the exact title
match first, followed by prefix matches. Also adds Refactoring test
entries to mock data and demo vault.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-08 23:53:00 +01:00

99 lines
3.6 KiB
TypeScript

import { describe, it, expect, vi, beforeEach } from 'vitest'
import { flushEditorContent, type FlushDeps } from './autoSave'
const mockInvokeFn = vi.fn(() => Promise.resolve(null))
vi.mock('@tauri-apps/api/core', () => ({
invoke: vi.fn(),
}))
vi.mock('../mock-tauri', () => ({
isTauri: () => false,
mockInvoke: (cmd: string, args?: Record<string, unknown>) => mockInvokeFn(cmd, args),
updateMockContent: vi.fn(),
}))
describe('flushEditorContent', () => {
let deps: FlushDeps
beforeEach(() => {
vi.clearAllMocks()
deps = {
savePendingForPath: vi.fn().mockResolvedValue(false),
getTabContent: vi.fn().mockReturnValue(undefined),
isUnsaved: vi.fn().mockReturnValue(false),
onSaved: vi.fn(),
}
})
it('flushes via savePendingForPath when pending content matches path', async () => {
;(deps.savePendingForPath as ReturnType<typeof vi.fn>).mockResolvedValue(true)
await flushEditorContent('/vault/note.md', deps)
expect(deps.savePendingForPath).toHaveBeenCalledWith('/vault/note.md')
// Should NOT check tab content or persist — pending flush handled it
expect(deps.getTabContent).not.toHaveBeenCalled()
expect(mockInvokeFn).not.toHaveBeenCalled()
})
it('saves tab content when note is unsaved (newly created)', async () => {
;(deps.getTabContent as ReturnType<typeof vi.fn>).mockReturnValue('# New note content')
;(deps.isUnsaved as ReturnType<typeof vi.fn>).mockReturnValue(true)
await flushEditorContent('/vault/note.md', deps)
expect(mockInvokeFn).toHaveBeenCalledWith('save_note_content', {
path: '/vault/note.md',
content: '# New note content',
})
expect(deps.onSaved).toHaveBeenCalledWith('/vault/note.md', '# New note content')
})
it('saves tab content when note is marked unsaved (dirty editor)', async () => {
;(deps.getTabContent as ReturnType<typeof vi.fn>).mockReturnValue('edited body')
;(deps.isUnsaved as ReturnType<typeof vi.fn>).mockReturnValue(true)
await flushEditorContent('/vault/note.md', deps)
expect(mockInvokeFn).toHaveBeenCalledWith('save_note_content', {
path: '/vault/note.md',
content: 'edited body',
})
expect(deps.onSaved).toHaveBeenCalledWith('/vault/note.md', 'edited body')
})
it('does not save when note is not unsaved (clean editor)', async () => {
;(deps.getTabContent as ReturnType<typeof vi.fn>).mockReturnValue('same content')
;(deps.isUnsaved as ReturnType<typeof vi.fn>).mockReturnValue(false)
await flushEditorContent('/vault/note.md', deps)
expect(mockInvokeFn).not.toHaveBeenCalled()
expect(deps.onSaved).not.toHaveBeenCalled()
})
it('does nothing when note is not open in any tab', async () => {
// getTabContent returns undefined (no tab for this path)
await flushEditorContent('/vault/note.md', deps)
expect(mockInvokeFn).not.toHaveBeenCalled()
expect(deps.onSaved).not.toHaveBeenCalled()
})
it('propagates errors from persistContent', async () => {
;(deps.getTabContent as ReturnType<typeof vi.fn>).mockReturnValue('content')
;(deps.isUnsaved as ReturnType<typeof vi.fn>).mockReturnValue(true)
mockInvokeFn.mockRejectedValueOnce(new Error('Disk full'))
await expect(flushEditorContent('/vault/note.md', deps)).rejects.toThrow('Disk full')
expect(deps.onSaved).not.toHaveBeenCalled()
})
it('propagates errors from savePendingForPath', async () => {
;(deps.savePendingForPath as ReturnType<typeof vi.fn>).mockRejectedValue(new Error('Save failed'))
await expect(flushEditorContent('/vault/note.md', deps)).rejects.toThrow('Save failed')
})
})