import { renderHook, waitFor } from '@testing-library/react' import { beforeEach, describe, expect, it, vi } from 'vitest' import type { VaultEntry } from '../types' import { useVaultLoader } from './useVaultLoader' const backendInvokeFn = vi.fn() let mockIsTauri = true vi.mock('@tauri-apps/api/core', () => ({ invoke: (...args: unknown[]) => backendInvokeFn(...args), })) vi.mock('../mock-tauri', () => ({ isTauri: () => mockIsTauri, mockInvoke: (command: string, args?: Record) => backendInvokeFn(command, args), })) function makeEntry(path: string, title: string): VaultEntry { return { path, filename: path.split('/').pop() ?? 'note.md', title, isA: 'Note', aliases: [], belongsTo: [], relatedTo: [], status: 'Active', archived: false, modifiedAt: 1, createdAt: 1, 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: true, fileKind: 'markdown', } } function commandKey(command: string, args?: Record): string { return `${command}:${typeof args?.path === 'string' ? args.path : ''}` } describe('useVaultLoader empty cache recovery', () => { beforeEach(() => { vi.clearAllMocks() mockIsTauri = true }) it('keeps mounted workspace entries visible while a newly active empty workspace loads', async () => { const laputa = { label: 'Laputa', path: '/laputa', alias: 'laputa', available: true, mounted: true } const refactoring = { label: 'Refactoring', path: '/refactoring', alias: 'refactoring', available: true, mounted: true } const commandResults = new Map([ ['reload_vault:/laputa', [makeEntry('/laputa/note/hello.md', 'Laputa Hello')]], ['reload_vault:/refactoring', []], ['list_vault:/refactoring', []], ['get_modified_files:', []], ['list_vault_folders:', []], ['list_views:', []], ]) backendInvokeFn.mockImplementation((command: string, args?: Record) => { return Promise.resolve(commandResults.get(commandKey(command, args)) ?? null) }) const { result, rerender } = renderHook( ({ activePath, vaults }) => useVaultLoader(activePath, vaults, activePath, vaults), { initialProps: { activePath: '/laputa', vaults: [laputa] } }, ) await waitFor(() => { expect(result.current.entries.map((entry) => entry.title)).toEqual(['Laputa Hello']) }) rerender({ activePath: '/refactoring', vaults: [laputa, refactoring] }) expect(result.current.entries.map((entry) => entry.title)).toContain('Laputa Hello') await waitFor(() => { expect(result.current.entries.map((entry) => entry.title)).toContain('Laputa Hello') }) }) it('reloads a background workspace when its cached startup listing is empty in Tauri mode', async () => { const brian = { label: 'Brian', path: '/brian', alias: 'brian', available: true, mounted: true } const laputa = { label: 'Laputa', path: '/laputa', alias: 'laputa', available: true, mounted: true } const commandResults = new Map([ ['reload_vault:/brian', [makeEntry('/brian/note/hello.md', 'Brian Hello')]], ['list_vault:/laputa', []], ['reload_vault:/laputa', [makeEntry('/laputa/note/hello.md', 'Laputa Hello')]], ['get_modified_files:', []], ['list_vault_folders:', []], ['list_views:', []], ]) backendInvokeFn.mockImplementation((command: string, args?: Record) => { return Promise.resolve(commandResults.get(commandKey(command, args)) ?? null) }) const vaults = [brian, laputa] const { result } = renderHook(() => useVaultLoader('/brian', vaults, '/brian', vaults)) await waitFor(() => { expect(result.current.entries.map((entry) => entry.title).sort()).toEqual(['Brian Hello', 'Laputa Hello']) }) const laputaLoads = backendInvokeFn.mock.calls .filter(([command, args]) => { return args?.path === '/laputa' && (command === 'list_vault' || command === 'reload_vault') }) .map(([command]) => command) expect(laputaLoads).toEqual(['list_vault', 'reload_vault']) }) })