import { beforeEach, describe, expect, it, vi } from 'vitest'; import { useEmailStore } from '../email-store'; import type { Email, Mailbox } from '@/lib/jmap/types'; import type { IJMAPClient } from '@/lib/jmap/client-interface'; function makeMailbox(overrides: Partial = {}): Mailbox { return { id: overrides.id ?? 'inbox', name: overrides.name ?? 'Inbox', sortOrder: 0, totalEmails: 0, unreadEmails: 0, totalThreads: 0, unreadThreads: 0, myRights: { mayReadItems: true, mayAddItems: true, mayRemoveItems: true, maySetSeen: true, maySetKeywords: true, mayCreateChild: true, mayRename: true, mayDelete: true, maySubmit: true, }, isSubscribed: true, isShared: false, ...overrides, }; } function makeEmail(id: string, threadId: string, mailboxId = 'inbox'): Email { return { id, threadId, mailboxIds: { [mailboxId]: true }, keywords: {}, size: 100, receivedAt: new Date().toISOString(), from: [{ name: 'Test', email: 'test@example.com' }], to: [{ name: 'User', email: 'user@example.com' }], subject: `Email ${id}`, preview: 'preview', hasAttachment: false, textBody: [], htmlBody: [], bodyValues: {}, }; } describe('email-store archive thread behavior', () => { beforeEach(() => { const inbox = makeMailbox({ id: 'shared-inbox', role: 'inbox', isShared: true, accountId: 'shared-account', originalId: 'server-inbox' }); const archive = makeMailbox({ id: 'archive-local', role: 'archive', accountId: 'shared-account', originalId: 'server-archive' }); const threadEmailA = makeEmail('email-1', 'thread-1', 'shared-inbox'); const threadEmailB = makeEmail('email-2', 'thread-1', 'shared-inbox'); const otherEmail = makeEmail('email-3', 'thread-2', 'shared-inbox'); useEmailStore.setState({ emails: [threadEmailA, threadEmailB, otherEmail], mailboxes: [inbox, archive], selectedMailbox: 'shared-inbox', selectedEmail: threadEmailA, selectedEmailIds: new Set(['email-1', 'email-2']), expandedThreadIds: new Set(['thread-1']), threadEmailsCache: new Map([['thread-1', [threadEmailA, threadEmailB]]]), error: null, }); }); it('archives the full thread and removes cached thread state', async () => { const client = { getThread: vi.fn().mockResolvedValue({ id: 'thread-1', emailIds: ['email-1', 'email-2'] }), batchMoveEmails: vi.fn().mockResolvedValue(undefined), } as unknown as IJMAPClient; await useEmailStore.getState().moveThreadToMailbox(client, 'email-1', 'archive-local'); expect(client.getThread).toHaveBeenCalledWith('thread-1', 'shared-account'); expect(client.batchMoveEmails).toHaveBeenCalledWith(['email-1', 'email-2'], 'server-archive', 'shared-account'); const state = useEmailStore.getState(); expect(state.emails.map(email => email.id)).toEqual(['email-3']); expect(state.selectedEmail?.id).toBe('email-3'); expect(Array.from(state.selectedEmailIds)).toEqual([]); expect(state.expandedThreadIds.has('thread-1')).toBe(false); expect(state.threadEmailsCache.has('thread-1')).toBe(false); }); });