import { describe, it, expect, vi, afterEach } from 'vitest'; import { render, screen, cleanup, fireEvent } from '@testing-library/svelte'; const setReaction = vi.fn(); const clearReaction = vi.fn(); vi.mock('$lib/api/reactions', () => ({ setReaction: (...a: unknown[]) => setReaction(...a), clearReaction: (...a: unknown[]) => clearReaction(...a) })); import ReactionButtons from './ReactionButtons.svelte'; afterEach(() => { cleanup(); setReaction.mockReset(); clearReaction.mockReset(); }); const pressed = (testid: string) => screen.getByTestId(testid).getAttribute('aria-pressed'); describe('ReactionButtons', () => { it('reflects the initial reaction', () => { render(ReactionButtons, { props: { mangaId: 'm1', initial: 'like' } }); expect(pressed('reaction-like')).toBe('true'); expect(pressed('reaction-dislike')).toBe('false'); }); it('likes when nothing is set', async () => { setReaction.mockResolvedValue({ manga_id: 'm1', reaction: 'like' }); render(ReactionButtons, { props: { mangaId: 'm1', initial: null } }); await fireEvent.click(screen.getByTestId('reaction-like')); expect(setReaction).toHaveBeenCalledWith('m1', 'like'); expect(pressed('reaction-like')).toBe('true'); }); it('clears when clicking the active reaction again', async () => { clearReaction.mockResolvedValue(undefined); render(ReactionButtons, { props: { mangaId: 'm1', initial: 'like' } }); await fireEvent.click(screen.getByTestId('reaction-like')); expect(clearReaction).toHaveBeenCalledWith('m1'); expect(pressed('reaction-like')).toBe('false'); }); it('switches from like to dislike', async () => { setReaction.mockResolvedValue({ manga_id: 'm1', reaction: 'dislike' }); render(ReactionButtons, { props: { mangaId: 'm1', initial: 'like' } }); await fireEvent.click(screen.getByTestId('reaction-dislike')); expect(setReaction).toHaveBeenCalledWith('m1', 'dislike'); expect(pressed('reaction-dislike')).toBe('true'); expect(pressed('reaction-like')).toBe('false'); }); it('rolls back on failure', async () => { setReaction.mockRejectedValue(new Error('boom')); render(ReactionButtons, { props: { mangaId: 'm1', initial: null } }); await fireEvent.click(screen.getByTestId('reaction-like')); // Optimistic update reverted after the rejection. await Promise.resolve(); expect(pressed('reaction-like')).toBe('false'); }); });