/** * Component: BookDate Recommendation Card Tests * Documentation: documentation/features/bookdate.md */ // @vitest-environment jsdom import React from 'react'; import { act, fireEvent, render, screen } from '@testing-library/react'; import { beforeEach, describe, expect, it, vi } from 'vitest'; const swipeHandlers: { onSwipeStart?: () => void; onSwiping?: (eventData: { deltaX: number; deltaY: number }) => void; onSwiped?: (eventData: { deltaX: number; deltaY: number }) => void; } = {}; vi.mock('react-swipeable', () => ({ useSwipeable: (handlers: any) => { swipeHandlers.onSwipeStart = handlers.onSwipeStart; swipeHandlers.onSwiping = handlers.onSwiping; swipeHandlers.onSwiped = handlers.onSwiped; return {}; }, })); const recommendation = { title: 'Sample Book', author: 'Sample Author', narrator: 'Sample Narrator', rating: 4.5, description: 'A sample description', aiReason: 'Because it matches your tastes.', }; describe('RecommendationCard', () => { beforeEach(() => { swipeHandlers.onSwipeStart = undefined; swipeHandlers.onSwiping = undefined; swipeHandlers.onSwiped = undefined; }); it('shows the request toast and triggers a request action', async () => { const onSwipe = vi.fn(); const { RecommendationCard } = await import('@/components/bookdate/RecommendationCard'); render(); const requestButtons = screen.getAllByRole('button', { name: /Request/ }); fireEvent.click(requestButtons[0]); expect(screen.getByText('Request "Sample Book"?')).toBeInTheDocument(); const toastRequestButtons = screen.getAllByRole('button', { name: /Request/ }); fireEvent.click(toastRequestButtons[toastRequestButtons.length - 1]); expect(onSwipe).toHaveBeenCalledWith('right', false); }); it('marks a recommendation as liked from the toast', async () => { const onSwipe = vi.fn(); const { RecommendationCard } = await import('@/components/bookdate/RecommendationCard'); render(); const requestButtons = screen.getAllByRole('button', { name: /Request/ }); fireEvent.click(requestButtons[0]); fireEvent.click(screen.getByRole('button', { name: 'Mark as Liked' })); expect(onSwipe).toHaveBeenCalledWith('right', true); }); it('triggers dislike and dismiss actions from desktop buttons', async () => { const onSwipe = vi.fn(); const { RecommendationCard } = await import('@/components/bookdate/RecommendationCard'); render(); fireEvent.click(screen.getByRole('button', { name: /Not Interested/ })); fireEvent.click(screen.getByRole('button', { name: /Dismiss/ })); expect(onSwipe).toHaveBeenCalledWith('left'); expect(onSwipe).toHaveBeenCalledWith('up'); }); it('shows drag overlays based on swipe direction', async () => { const onSwipe = vi.fn(); const { RecommendationCard } = await import('@/components/bookdate/RecommendationCard'); render(); act(() => { swipeHandlers.onSwipeStart?.(); swipeHandlers.onSwiping?.({ deltaX: -80, deltaY: 0 }); }); expect(screen.getByText('Dislike')).toBeInTheDocument(); }); it('triggers an upward swipe from gesture handling', async () => { const onSwipe = vi.fn(); const { RecommendationCard } = await import('@/components/bookdate/RecommendationCard'); render(); act(() => { swipeHandlers.onSwiped?.({ deltaX: 0, deltaY: -150 }); }); expect(onSwipe).toHaveBeenCalledWith('up'); }); it('ignores swipe gestures when not draggable', async () => { const onSwipe = vi.fn(); const { RecommendationCard } = await import('@/components/bookdate/RecommendationCard'); render( ); act(() => { swipeHandlers.onSwiped?.({ deltaX: 150, deltaY: 0 }); }); expect(onSwipe).not.toHaveBeenCalled(); expect(screen.queryByText(/Request "Sample Book"/)).toBeNull(); }); it('hides desktop actions when not the top card', async () => { const onSwipe = vi.fn(); const { RecommendationCard } = await import('@/components/bookdate/RecommendationCard'); render( ); expect(screen.queryByRole('button', { name: /Not Interested/ })).toBeNull(); }); });