diff --git a/frontend/tests/components/AIOnboarding.test.tsx b/frontend/tests/components/AIOnboarding.test.tsx index 561deed6..bd73d623 100644 --- a/frontend/tests/components/AIOnboarding.test.tsx +++ b/frontend/tests/components/AIOnboarding.test.tsx @@ -54,16 +54,22 @@ describe('AIOnboarding Component', () => { expect(buttons.length).toBeGreaterThan(0) }) - it('should render video element for camera stream', () => { - const { container } = renderAIOnboarding() - const video = container.querySelector('video') - expect(video || container).toBeTruthy() + it('should render component without throwing errors', () => { + expect(() => { + renderAIOnboarding() + }).not.toThrow() }) - it('should render canvas element for image capture', () => { - const { container } = renderAIOnboarding() - const canvas = container.querySelector('canvas') - expect(canvas || container).toBeTruthy() + it('should initialize with proper props passed to component', () => { + const mockOnCancel = vi.fn() + const mockOnComplete = vi.fn() + const { container } = renderAIOnboarding({ + onCancel: mockOnCancel, + onComplete: mockOnComplete, + }) + expect(container).toBeInTheDocument() + expect(mockOnCancel).toBeDefined() + expect(mockOnComplete).toBeDefined() }) }) @@ -102,9 +108,21 @@ describe('AIOnboarding Component', () => { // ============================================================================ describe('Image Validation', () => { - it('should validate image format on upload', async () => { + it('should have file input element for image upload', () => { const { container } = renderAIOnboarding() const input = container.querySelector('input[type="file"]') + // jsdom doesn't fully support file input, so just verify element exists + if (input) { + expect(input).toBeInTheDocument() + } else { + // File input might not be rendered initially, that's ok + expect(container).toBeInTheDocument() + } + }) + + it('should accept image file uploads', async () => { + const { container } = renderAIOnboarding() + const input = container.querySelector('input[type="file"]') as HTMLInputElement | null if (input) { const file = new File(['image'], 'test.jpg', { type: 'image/jpeg' }) @@ -113,22 +131,20 @@ describe('AIOnboarding Component', () => { } }) - it('should handle image size validation', () => { + it('should render component with proper structure', () => { const { container } = renderAIOnboarding() - // Verify canvas dimensions are set properly - const canvas = container.querySelector('canvas') - expect(canvas || container).toBeTruthy() + expect(container.children.length).toBeGreaterThan(0) }) - it('should reject non-image files', async () => { + it('should handle file input changes without errors', async () => { const { container } = renderAIOnboarding() - const input = container.querySelector('input[type="file"]') - - if (input) { - const file = new File(['text'], 'test.txt', { type: 'text/plain' }) - await fireEvent.change(input, { target: { files: [file] } }) - expect(input).toBeInTheDocument() - } + expect(() => { + const input = container.querySelector('input[type="file"]') + if (input) { + const file = new File(['test'], 'test.txt', { type: 'text/plain' }) + fireEvent.change(input, { target: { files: [file] } }) + } + }).not.toThrow() }) }) @@ -217,13 +233,13 @@ describe('AIOnboarding Component', () => { // ============================================================================ describe('Wizard Flow - Step Progression', () => { - it('should capture image in step 1', () => { - const { container } = renderAIOnboarding() - const video = container.querySelector('video') - expect(video || container).toBeTruthy() + it('should render step 1 capture interface without errors', () => { + expect(() => { + renderAIOnboarding() + }).not.toThrow() }) - it('should process image in step 2 (extraction)', async () => { + it('should process image in step 2 (extraction) with mocked API', async () => { const mockAnalyzeLabel = vi.fn().mockResolvedValue(mockAIExtractionResponseGemini) vi.mocked(api.inventoryApi.analyzeLabel).mockImplementation(mockAnalyzeLabel) @@ -232,29 +248,31 @@ describe('AIOnboarding Component', () => { expect(mockAnalyzeLabel).toBeDefined() }) - it('should confirm extracted data in step 3 (confirmation)', async () => { + it('should pass onComplete callback to component for step 3', async () => { const mockOnComplete = vi.fn() const mockAnalyzeLabel = vi.fn().mockResolvedValue(mockAIExtractionResponseGemini) vi.mocked(api.inventoryApi.analyzeLabel).mockImplementation(mockAnalyzeLabel) - const { container } = renderAIOnboarding({ onComplete: mockOnComplete }) - expect(container).toBeInTheDocument() + renderAIOnboarding({ onComplete: mockOnComplete }) expect(mockOnComplete).toBeDefined() }) - it('should handle multiple items from single image', async () => { + it('should wire up API callback for multi-item extraction', async () => { const multipleItems = [mockAIExtractionResponseGemini, mockAIExtractionResponseClaude] const mockAnalyzeLabel = vi.fn().mockResolvedValue(multipleItems) vi.mocked(api.inventoryApi.analyzeLabel).mockImplementation(mockAnalyzeLabel) const { container } = renderAIOnboarding() expect(container).toBeInTheDocument() + expect(mockAnalyzeLabel).toBeDefined() }) - it('should allow editing extracted data before confirmation', () => { + it('should render component structure with inputs', () => { const { container } = renderAIOnboarding() const inputs = container.querySelectorAll('input') + // Component may or may not have inputs depending on step expect(inputs.length).toBeGreaterThanOrEqual(0) + expect(container).toBeInTheDocument() }) }) @@ -287,10 +305,10 @@ describe('AIOnboarding Component', () => { expect(container).toBeInTheDocument() }) - it('should handle camera permission denied', () => { + it('should render component even if camera access unavailable', () => { const { container } = renderAIOnboarding() - const video = container.querySelector('video') - expect(video || container).toBeTruthy() + // jsdom doesn't support camera/video, but component should still render + expect(container).toBeInTheDocument() }) it('should handle malformed AI response', async () => {