import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest' import { render, screen, fireEvent, waitFor, cleanup } from '@testing-library/react' import Home from './page' global.fetch = vi.fn() const mockFetch = vi.mocked(global.fetch) describe('Home Page', () => { beforeEach(() => { vi.clearAllMocks() }) afterEach(() => { cleanup() }) it('renders the main heading', () => { render() expect(screen.getByText('Downlink')).toBeInTheDocument() }) it('renders the URL input', () => { render() const inputs = screen.getAllByPlaceholderText('Paste YouTube URL here...') expect(inputs.length).toBeGreaterThanOrEqual(1) }) it('renders the Fetch button', () => { render() const buttons = screen.getAllByRole('button', { name: /fetch/i }) expect(buttons.length).toBeGreaterThanOrEqual(1) }) it('shows error for empty URL on fetch', async () => { render() const fetchButtons = screen.getAllByRole('button', { name: /fetch/i }) fireEvent.click(fetchButtons[0]) await waitFor(() => { expect(screen.getByText('Please enter a YouTube URL')).toBeInTheDocument() }) }) it('shows error for invalid YouTube URL', async () => { render() const inputs = screen.getAllByPlaceholderText('Paste YouTube URL here...') fireEvent.change(inputs[0], { target: { value: 'https://vimeo.com/123' } }) const fetchButtons = screen.getAllByRole('button', { name: /fetch/i }) fireEvent.click(fetchButtons[0]) await waitFor(() => { expect(screen.getByText('Please enter a valid YouTube URL')).toBeInTheDocument() }) }) it('fetches video info for valid URL', async () => { const mockVideoInfo = { title: 'Test Video', duration: 180, thumbnail: 'https://example.com/thumb.jpg', } mockFetch.mockResolvedValueOnce({ json: () => Promise.resolve({ success: true, videoInfo: mockVideoInfo }), } as Response) render() const inputs = screen.getAllByPlaceholderText('Paste YouTube URL here...') fireEvent.change(inputs[0], { target: { value: 'https://youtube.com/watch?v=dQw4w9WgXcQ' } }) const fetchButtons = screen.getAllByRole('button', { name: /fetch/i }) fireEvent.click(fetchButtons[0]) await waitFor(() => { expect(screen.getByText('Test Video')).toBeInTheDocument() }) expect(mockFetch).toHaveBeenCalledWith('/api/info', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ url: 'https://youtube.com/watch?v=dQw4w9WgXcQ' }), }) }) it('displays video duration after fetch', async () => { const mockVideoInfo = { title: 'Test Video', duration: 125, thumbnail: 'https://example.com/thumb.jpg', } mockFetch.mockResolvedValueOnce({ json: () => Promise.resolve({ success: true, videoInfo: mockVideoInfo }), } as Response) render() const inputs = screen.getAllByPlaceholderText('Paste YouTube URL here...') fireEvent.change(inputs[0], { target: { value: 'https://youtube.com/watch?v=dQw4w9WgXcQ' } }) const fetchButtons = screen.getAllByRole('button', { name: /fetch/i }) fireEvent.click(fetchButtons[0]) await waitFor(() => { expect(screen.getByText('2:05')).toBeInTheDocument() }) }) it('shows download options after fetching video info', async () => { const mockVideoInfo = { title: 'Test Video', duration: 180, thumbnail: 'https://example.com/thumb.jpg', } mockFetch.mockResolvedValueOnce({ json: () => Promise.resolve({ success: true, videoInfo: mockVideoInfo }), } as Response) render() const inputs = screen.getAllByPlaceholderText('Paste YouTube URL here...') fireEvent.change(inputs[0], { target: { value: 'https://youtube.com/watch?v=dQw4w9WgXcQ' } }) const fetchButtons = screen.getAllByRole('button', { name: /fetch/i }) fireEvent.click(fetchButtons[0]) await waitFor(() => { expect(screen.getByText('Download Options')).toBeInTheDocument() }) }) it('handles API error response', async () => { mockFetch.mockResolvedValueOnce({ json: () => Promise.resolve({ success: false, error: 'Video not found' }), } as Response) render() const inputs = screen.getAllByPlaceholderText('Paste YouTube URL here...') fireEvent.change(inputs[0], { target: { value: 'https://youtube.com/watch?v=dQw4w9WgXcQ' } }) const fetchButtons = screen.getAllByRole('button', { name: /fetch/i }) fireEvent.click(fetchButtons[0]) await waitFor(() => { expect(screen.getByText('Video not found')).toBeInTheDocument() }) }) it('handles fetch network error', async () => { mockFetch.mockRejectedValueOnce(new Error('Network error')) render() const inputs = screen.getAllByPlaceholderText('Paste YouTube URL here...') fireEvent.change(inputs[0], { target: { value: 'https://youtube.com/watch?v=dQw4w9WgXcQ' } }) const fetchButtons = screen.getAllByRole('button', { name: /fetch/i }) fireEvent.click(fetchButtons[0]) await waitFor(() => { expect(screen.getByText('Network error')).toBeInTheDocument() }) }) it('allows switching between video and audio format types', async () => { const mockVideoInfo = { title: 'Test Video', duration: 180, thumbnail: 'https://example.com/thumb.jpg', } mockFetch.mockResolvedValueOnce({ json: () => Promise.resolve({ success: true, videoInfo: mockVideoInfo }), } as Response) render() const inputs = screen.getAllByPlaceholderText('Paste YouTube URL here...') fireEvent.change(inputs[0], { target: { value: 'https://youtube.com/watch?v=dQw4w9WgXcQ' } }) const fetchButtons = screen.getAllByRole('button', { name: /fetch/i }) fireEvent.click(fetchButtons[0]) await waitFor(() => { expect(screen.getByText('Download Options')).toBeInTheDocument() }) const audioButton = screen.getByRole('button', { name: /audio/i }) fireEvent.click(audioButton) expect(screen.getByText('Audio Format')).toBeInTheDocument() }) it('triggers download on button click', async () => { const mockVideoInfo = { title: 'Test Video', duration: 180, thumbnail: 'https://example.com/thumb.jpg', } mockFetch .mockResolvedValueOnce({ json: () => Promise.resolve({ success: true, videoInfo: mockVideoInfo }), } as Response) .mockResolvedValueOnce({ json: () => Promise.resolve({ success: true, downloadUrl: '/downloads/test.mp4', filename: 'test.mp4', }), } as Response) render() const inputs = screen.getAllByPlaceholderText('Paste YouTube URL here...') fireEvent.change(inputs[0], { target: { value: 'https://youtube.com/watch?v=dQw4w9WgXcQ' } }) const fetchButtons = screen.getAllByRole('button', { name: /fetch/i }) fireEvent.click(fetchButtons[0]) await waitFor(() => { expect(screen.getByText('Download Options')).toBeInTheDocument() }) const downloadButton = screen.getByRole('button', { name: /download mp4/i }) fireEvent.click(downloadButton) await waitFor(() => { expect(mockFetch).toHaveBeenCalledTimes(2) }) expect(mockFetch).toHaveBeenLastCalledWith('/api/download', expect.objectContaining({ method: 'POST', })) }) it('shows success message after download completes', async () => { const mockVideoInfo = { title: 'Test Video', duration: 180, thumbnail: 'https://example.com/thumb.jpg', } mockFetch .mockResolvedValueOnce({ json: () => Promise.resolve({ success: true, videoInfo: mockVideoInfo }), } as Response) .mockResolvedValueOnce({ json: () => Promise.resolve({ success: true, downloadUrl: '/downloads/test.mp4', filename: 'test.mp4', }), } as Response) render() const inputs = screen.getAllByPlaceholderText('Paste YouTube URL here...') fireEvent.change(inputs[0], { target: { value: 'https://youtube.com/watch?v=dQw4w9WgXcQ' } }) const fetchButtons = screen.getAllByRole('button', { name: /fetch/i }) fireEvent.click(fetchButtons[0]) await waitFor(() => { expect(screen.getByText('Download Options')).toBeInTheDocument() }) fireEvent.click(screen.getByRole('button', { name: /download mp4/i })) await waitFor(() => { expect(screen.getByText('Ready to Download')).toBeInTheDocument() }) }) })