import { flushPromises, mount } from '@vue/test-utils' import { describe, expect, it, vi } from 'vitest' import PeerFiles from '../PeerFiles.vue' import { rpcClient } from '@/api/rpc-client' vi.mock('vue-router', () => ({ useRouter: () => ({ push: vi.fn() }), })) vi.mock('@/api/rpc-client', () => ({ rpcClient: { call: vi.fn(), federationListNodes: vi.fn(), }, })) vi.mock('@/composables/useAudioPlayer', () => ({ useAudioPlayer: () => ({ play: vi.fn() }), })) function deferred() { let resolve!: (value: T) => void let reject!: (reason?: unknown) => void const promise = new Promise((res, rej) => { resolve = res reject = rej }) return { promise, resolve, reject } } function makeCatalogItem() { return { id: 'file-1', filename: 'notes.txt', mime_type: 'text/plain', size_bytes: 128, description: '', access: 'free', } } describe('PeerFiles', () => { it('keeps peer catalog items visible while refresh is pending or fails', async () => { vi.mocked(rpcClient.federationListNodes).mockResolvedValue({ nodes: [{ did: 'did:key:peer', pubkey: 'peer', onion: 'peer.onion', name: 'Peer', trust_level: 'trusted', }], } as never) vi.mocked(rpcClient.call).mockResolvedValueOnce({ items: [makeCatalogItem()] }) const wrapper = mount(PeerFiles, { props: { peerId: 'peer.onion' }, global: { stubs: { Teleport: true, }, }, }) await flushPromises() expect(wrapper.text()).toContain('notes.txt') const pending = deferred<{ items: [] }>() vi.mocked(rpcClient.call).mockReturnValueOnce(pending.promise) const refresh = (wrapper.vm as unknown as { loadCatalog: () => Promise }).loadCatalog() await wrapper.vm.$nextTick() expect(wrapper.text()).toContain('notes.txt') expect(wrapper.text()).toContain('Refreshing peer files...') expect(wrapper.text()).not.toContain('Connecting via Tor') pending.reject(new Error('offline')) await refresh await flushPromises() expect(wrapper.text()).toContain('notes.txt') expect(wrapper.text()).toContain('offline') expect(wrapper.text()).not.toContain('Refreshing peer files...') }) })