282 lines
8.6 KiB
TypeScript
282 lines
8.6 KiB
TypeScript
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(<Home />)
|
|
expect(screen.getByText('Downlink')).toBeInTheDocument()
|
|
})
|
|
|
|
it('renders the URL input', () => {
|
|
render(<Home />)
|
|
const inputs = screen.getAllByPlaceholderText('Paste YouTube URL here...')
|
|
expect(inputs.length).toBeGreaterThanOrEqual(1)
|
|
})
|
|
|
|
it('renders the Fetch button', () => {
|
|
render(<Home />)
|
|
const buttons = screen.getAllByRole('button', { name: /fetch/i })
|
|
expect(buttons.length).toBeGreaterThanOrEqual(1)
|
|
})
|
|
|
|
it('shows error for empty URL on fetch', async () => {
|
|
render(<Home />)
|
|
|
|
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(<Home />)
|
|
|
|
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(<Home />)
|
|
|
|
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(<Home />)
|
|
|
|
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(<Home />)
|
|
|
|
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(<Home />)
|
|
|
|
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(<Home />)
|
|
|
|
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(<Home />)
|
|
|
|
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(<Home />)
|
|
|
|
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(<Home />)
|
|
|
|
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()
|
|
})
|
|
})
|
|
})
|