import { describe, it, expect, vi, beforeEach } from 'vitest' import { render, screen, waitFor } from '@testing-library/react' import ItemPhotoUpload from '@/components/ItemPhotoUpload' import * as api from '@/lib/api' // Mock react-hot-toast vi.mock('react-hot-toast', () => ({ toast: { error: vi.fn(), success: vi.fn(), loading: vi.fn(), }, })) // Mock the API vi.mock('@/lib/api', () => ({ inventoryApi: { uploadItemPhoto: vi.fn(), }, })) describe('ItemPhotoUpload Component', () => { const mockOnUploadSuccess = vi.fn() const mockOnError = vi.fn() beforeEach(() => { vi.clearAllMocks() }) it('should render with upload and camera buttons', () => { render( ) expect(screen.getByRole('button', { name: /upload/i })).toBeInTheDocument() expect(screen.getByRole('button', { name: /camera/i })).toBeInTheDocument() }) it('should render hidden file input for uploads', () => { const { container } = render( ) const fileInputs = container.querySelectorAll('input[type="file"]') expect(fileInputs.length).toBeGreaterThanOrEqual(1) }) it('should render file input with accept image/* attribute', () => { const { container } = render( ) const fileInputs = Array.from(container.querySelectorAll('input[type="file"]')) const uploadInput = fileInputs.find( (el) => (el as HTMLInputElement).accept.includes('image') ) as HTMLInputElement expect(uploadInput).toBeTruthy() expect(uploadInput.accept).toContain('image') }) it('should render camera input with capture environment attribute', () => { const { container } = render( ) const fileInputs = Array.from(container.querySelectorAll('input[type="file"]')) const cameraInput = fileInputs.find( (el) => (el as HTMLInputElement).getAttribute('capture') !== null ) as HTMLInputElement expect(cameraInput).toBeTruthy() expect(cameraInput.getAttribute('capture')).toBe('environment') }) it('should accept itemId prop', () => { const { rerender } = render( ) // Component should render without errors with different itemId rerender( ) const buttons = screen.queryAllByRole('button') expect(buttons.length).toBeGreaterThan(0) }) it('should have onUploadSuccess callback prop', () => { const customCallback = vi.fn() render( ) const buttons = screen.queryAllByRole('button') expect(buttons.length).toBeGreaterThan(0) }) it('should have onError callback prop', () => { const customErrorCallback = vi.fn() render( ) const buttons = screen.queryAllByRole('button') expect(buttons.length).toBeGreaterThan(0) }) it('should render buttons with proper styling', () => { const { container } = render( ) const uploadButton = screen.getByRole('button', { name: /upload/i }) const cameraButton = screen.getByRole('button', { name: /camera/i }) // Check for Tailwind classes (basic check) expect(uploadButton.className).toContain('rounded') expect(cameraButton.className).toContain('rounded') }) it('should render responsive layout with gap', () => { const { container } = render( ) const wrapper = container.querySelector('.flex.flex-col.gap-3') expect(wrapper).toBeInTheDocument() }) it('should display loading state message when isLoading is true', async () => { // Since component manages loading state internally, we check if the // component can display loading messages (integration tested via hook) const { container } = render( ) // Component renders with buttons const buttons = screen.queryAllByRole('button') expect(buttons.length).toBeGreaterThan(0) }) it('should be accessible with aria labels', () => { const { container } = render( ) const fileInputs = Array.from(container.querySelectorAll('input[type="file"]')) fileInputs.forEach((input) => { expect((input as HTMLInputElement).getAttribute('aria-label')).toBeTruthy() }) }) it('should work on mobile and desktop without errors', () => { // Component should render without throwing const { container } = render( ) expect(container.firstChild).toBeTruthy() }) })