import { test, expect, vi } from 'vitest'; import { screen, render, fireEvent } from '@testing-library/react'; import FileUpload from './FileUpload'; const ID = 'my-file-upload' const LABEL_TEXT = 'Upload a file'; test('file upload renders correctly', () => { render( ); const fileUploadElement = screen.getByTestId('file-upload'); const label = screen.getByText(LABEL_TEXT); const dropzoneButton = document.getElementById(ID + '-dropzone'); const statusSpan = document.getElementById(ID + '-status'); const commaSpan = document.getElementById(ID + '-comma'); const buttonContainer = document.querySelector('.ds_file-upload__button-container'); const pseudoButton = document.querySelector('.ds_file-upload__button'); const instructionSpan = document.getElementById(ID + '-instruction'); const fileInput = document.getElementById(ID); expect(fileUploadElement).toHaveClass('ds_file-upload'); expect(fileUploadElement.tagName).toEqual('DIV'); expect(label).toHaveClass('ds_label'); expect(label).toHaveAttribute('for', ID); expect(label).toHaveAttribute('id', ID + '-label'); expect(label.tagName).toEqual('LABEL'); expect(label.textContent).toEqual(LABEL_TEXT); expect(label.parentElement).toEqual(fileUploadElement); expect(dropzoneButton).toHaveClass('ds_file-upload__dropzone'); expect(dropzoneButton).toHaveAttribute('id', ID + '-dropzone'); expect(dropzoneButton).toHaveAttribute('type', 'button'); expect(dropzoneButton?.tagName).toEqual('BUTTON'); expect(dropzoneButton).toHaveAttribute('aria-labelledby', `${label.id} ${commaSpan?.id} ${dropzoneButton?.id}`); expect(dropzoneButton?.parentElement).toEqual(fileUploadElement); expect(dropzoneButton?.previousElementSibling).toEqual(label); expect(statusSpan).toHaveClass('ds_file-upload__status'); expect(statusSpan).toHaveAttribute('aria-live', 'polite'); expect(statusSpan?.tagName).toEqual('SPAN'); expect(statusSpan?.textContent).toEqual('No file chosen'); expect(statusSpan?.parentElement).toEqual(dropzoneButton); expect(commaSpan).toHaveClass('visually-hidden'); expect(commaSpan?.tagName).toEqual('SPAN'); expect(commaSpan?.parentElement).toEqual(dropzoneButton); expect(commaSpan?.previousElementSibling).toEqual(statusSpan); expect(buttonContainer?.tagName).toEqual('SPAN'); expect(buttonContainer?.parentElement).toEqual(dropzoneButton); expect(buttonContainer?.previousElementSibling).toEqual(commaSpan); expect(pseudoButton?.tagName).toEqual('SPAN'); expect(pseudoButton?.textContent).toEqual('Choose file'); expect(pseudoButton?.parentElement).toEqual(buttonContainer); expect(instructionSpan).toHaveClass('ds_file-upload__instruction'); expect(instructionSpan?.tagName).toEqual('SPAN'); expect(instructionSpan?.textContent).toEqual('or drag and drop file here'); expect(instructionSpan?.parentElement).toEqual(buttonContainer); expect(instructionSpan?.previousElementSibling).toEqual(pseudoButton); expect(fileInput).not.toHaveAttribute('aria-describedby'); expect(fileInput).toHaveAttribute('aria-hidden', 'true'); expect(fileInput).toHaveClass('ds_file-upload__input'); expect(fileInput).toHaveAttribute('hidden', 'true'); expect(fileInput).toHaveAttribute('name', ID); expect(fileInput).toHaveAttribute('tabindex', '-1'); expect(fileInput).toHaveAttribute('type', 'file'); }); test('multiple file upload', () => { const LABEL_TEXT = 'Upload files'; render( ); const label = screen.getByText(LABEL_TEXT); const statusSpan = document.getElementById(ID + '-status'); const pseudoButton = document.querySelector('.ds_file-upload__button'); const instructionSpan = document.getElementById(ID + '-instruction'); const fileInput = document.getElementById(ID); expect(label.textContent).toEqual(LABEL_TEXT); expect(statusSpan?.textContent).toEqual('No files chosen'); expect(pseudoButton?.textContent).toEqual('Choose files'); expect(instructionSpan?.textContent).toEqual('or drag and drop files here'); expect(fileInput).toHaveAttribute('multiple'); }); test('with hint text', () => { const HINT_TEXT = 'My hint text' render( ); const label = screen.getByText(LABEL_TEXT); const hintText = document.getElementById('hint-text-' + ID); expect(hintText).toBeInTheDocument(); expect(hintText).toHaveClass('ds_hint-text'); expect(hintText?.textContent).toEqual(HINT_TEXT); expect(hintText?.previousElementSibling).toEqual(label); }); test('with error text', () => { const ERROR_TEXT = 'My error text' render( ); const label = screen.getByText(LABEL_TEXT); const errorText = document.getElementById('error-message-' + ID); expect(errorText).toBeInTheDocument(); expect(errorText).toHaveClass('ds_question__error-message'); expect(errorText?.textContent).toEqual(ERROR_TEXT); expect(errorText?.previousElementSibling).toEqual(label); }); test('with blur fn', () => { const ONBLUR_FUNCTION = vi.fn(); render( ); const fileInput = document.getElementById(ID); if (fileInput) { fireEvent.blur(fileInput); } expect(ONBLUR_FUNCTION).toHaveBeenCalled(); }); test('with change fn', () => { const ONCHANGE_FUNCTION = vi.fn(); render( ); const fileInput = document.getElementById(ID); if (fileInput) { fireEvent.change(fileInput); } expect(ONCHANGE_FUNCTION).toHaveBeenCalled(); }); test('passing additional props', () => { render( ); const fileUploadElement = screen.getByTestId('file-upload'); expect(fileUploadElement?.dataset.test).toEqual('foo'); }); test('passing additional CSS classes', () => { render( ); const fileUploadElement = screen.getByTestId('file-upload'); expect(fileUploadElement).toHaveClass('foo'); });