// 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