// src/features/flyer/BulkImporter.test.tsx import React from 'react'; import { render, screen, fireEvent, waitFor, act } from '@testing-library/react'; import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'; import { BulkImporter } from './BulkImporter'; describe('BulkImporter', () => { const mockOnFilesChange = vi.fn(); const mockCreateObjectURL = vi.fn(); const mockRevokeObjectURL = vi.fn(); beforeEach(() => { vi.clearAllMocks(); // Mock the global URL object methods global.URL.createObjectURL = mockCreateObjectURL; global.URL.revokeObjectURL = mockRevokeObjectURL; }); afterEach(() => { vi.restoreAllMocks(); }); it('should render the initial state correctly', () => { render(); expect(screen.getByText(/click to upload/i)).toBeInTheDocument(); expect(screen.getByText(/drag and drop/i)).toBeInTheDocument(); expect(screen.getByText(/png, jpg, webp, or pdf/i)).toBeInTheDocument(); }); it('should render the processing state', () => { render(); expect(screen.getByText(/processing, please wait.../i)).toBeInTheDocument(); const label = screen.getByText(/processing, please wait.../i).closest('label'); expect(label).toHaveClass('cursor-not-allowed'); expect(label).toHaveClass('opacity-60'); }); it('should call onFilesChange when files are selected via input', async () => { render(); const file = new File(['content'], 'flyer.pdf', { type: 'application/pdf' }); const input = screen.getByLabelText(/click to upload/i); await waitFor(() => fireEvent.change(input, { target: { files: [file] }, }), ); expect(mockOnFilesChange).toHaveBeenCalledTimes(1); expect(mockOnFilesChange.mock.calls[0][0][0]).toBe(file); }); it('should handle drag and drop events', () => { render(); // `getByLabelText` finds the input associated with the label. // We need to test the label itself, as it contains the drag-and-drop handlers and styles. // We can find it by its text content. const dropzone = screen.getByText(/click to upload/i).closest('label'); // Assert that the dropzone element was found before using it. // This satisfies TypeScript's null-check and makes the test more robust. expect(dropzone).not.toBeNull(); // Test drag enter // We need to assert that dropzone is not null before passing it to fireEvent. if (!dropzone) throw new Error('Dropzone not found'); fireEvent.dragEnter(dropzone, { dataTransfer: { files: [] } }); expect(dropzone).toHaveClass('border-brand-primary'); // Test drag leave // We need to assert that dropzone is not null before passing it to fireEvent. if (!dropzone) throw new Error('Dropzone not found'); fireEvent.dragLeave(dropzone); expect(dropzone).not.toHaveClass('border-brand-primary'); }); it('should call onFilesChange when files are dropped', () => { render(); // The drop event handlers are on the