import { render, screen, userEvent } from '../../test-utils'; import UploadButton, { UploadButtonProps, TEST_IDS } from './UploadButton'; import { imageFileTypes } from './defaults'; describe('UploadButton', () => { const pngFile = new File(['foo'], 'foo.png', { type: 'image/png' }); const jpgFile = new File(['foo'], 'foo.jpg', { type: 'image/jpg' }); const props: UploadButtonProps = { onChange: jest.fn(), }; const renderComponent = (customProps = props) => render(); describe('single file upload', () => { beforeEach(() => { renderComponent(); }); it('should render the file input form', () => { expect(screen.getByText('Upload file')).toBeInTheDocument(); }); it('should render the file input button with title, if provided', () => { const buttonTitle = 'Upload your id'; renderComponent({ ...props, uploadButtonTitle: buttonTitle }); expect(screen.getByText(buttonTitle)).toBeInTheDocument(); }); it('should set accept to imageTypes', () => { expect(screen.getByTestId(TEST_IDS.uploadInput)).toHaveAttribute( 'accept', imageFileTypes.join(','), ); }); it('trigger onChange callback with a FileList', async () => { const input = screen.getByTestId(TEST_IDS.uploadInput); await userEvent.upload(input, [pngFile, jpgFile]); expect(props.onChange).toHaveBeenCalledTimes(1); // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access expect((props.onChange as jest.Mock).mock.calls[0][0]).toHaveLength(1); }); }); describe('multiple file upload', () => { beforeEach(() => { (props.onChange as jest.Mock).mockClear(); renderComponent({ ...props, multiple: true }); }); it('should disable the file input', () => { expect(screen.getByTestId(TEST_IDS.uploadInput)).toHaveAttribute('multiple'); }); it('trigger onChange callback with a FileList', async () => { const input = screen.getByTestId(TEST_IDS.uploadInput); await userEvent.upload(input, [pngFile, jpgFile]); expect(props.onChange).toHaveBeenCalledTimes(1); // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access expect((props.onChange as jest.Mock).mock.calls[0][0]).toHaveLength(2); }); }); describe('disabled state', () => { beforeEach(() => { renderComponent({ ...props, disabled: true }); }); it('should disable the file input', () => { expect(screen.getByTestId(TEST_IDS.uploadInput)).toBeDisabled(); }); }); describe('accept all file types', () => { beforeEach(() => { renderComponent({ ...props, fileTypes: ['*'] }); }); it('should not add accept attribute to file input', () => { expect(screen.getByTestId(TEST_IDS.uploadInput)).not.toHaveAttribute('accept'); }); }); describe('description for the button', () => { it('should show default description based on the default file types provided', () => { renderComponent({ ...props }); expect(screen.getByText('PDF, JPG, JPEG, PNG, less than 5MB')).toBeInTheDocument(); }); it('should show default all files allowed description if all files are accepted', () => { renderComponent({ ...props, fileTypes: ['*'] }); expect(screen.getByText('All file types, less than 5MB')).toBeInTheDocument(); }); it('should show no file size limit if sizeLimit is set to `null`', () => { renderComponent({ ...props, fileTypes: ['*'], sizeLimit: null }); expect(screen.getByText('All file types')).toBeInTheDocument(); expect(screen.queryByText(/less than/i)).not.toBeInTheDocument(); }); it('should show custom description if provided', () => { const description = 'Test description'; renderComponent({ ...props, fileTypes: ['*'], description }); expect(screen.getByText('Test description')).toBeInTheDocument(); }); it('should show maxFiles next to the description, if provided', () => { renderComponent({ ...props, fileTypes: ['*'], maxFiles: 5 }); expect(screen.getByText(/Maximum 5 files\./)).toBeInTheDocument(); }); }); });