diff --git a/client/src/ImageUpload/ImageUpload.test.js b/client/src/ImageUpload/ImageUpload.test.js new file mode 100644 index 0000000..ea9c250 --- /dev/null +++ b/client/src/ImageUpload/ImageUpload.test.js @@ -0,0 +1,135 @@ +import React from 'react' +import { render, screen, fireEvent, waitFor } from '@testing-library/react' +import '@testing-library/jest-dom' +import axios from 'axios' +import ImageUpload from './index' +import { useSnackbar } from '../SnackbarContext' + +jest.mock('../../config.js', () => ({ + DEMO_SITE_URL: "https://annotate-docs.dwaste.live/", + VITE_SERVER_URL: "http://localhost:5000", + UPLOAD_LIMIT: 5, +})); + +jest.mock('axios') + +// Mock the useTranslation hook +jest.mock('react-i18next', () => ({ + useTranslation: () => ({ + t: key => ({ + "configuration.image_upload.description": "Upload images", + "error.server_connection": "Server connection error", + }[key]), + }), + })); + + +jest.mock('../SnackbarContext', () => ({ + useSnackbar: jest.fn(), +})) + +const mockShowSnackbar = jest.fn() +useSnackbar.mockReturnValue({ showSnackbar: mockShowSnackbar }) + +const renderComponent = (props = {}) => + render( + + ) + +describe('ImageUpload', () => { + beforeEach(() => { + console.error = jest.fn() + jest.clearAllMocks() + }) + + test('renders the component', () => { + renderComponent() + expect(screen.getByText(/Upload images/i)).toBeInTheDocument() + }) + + test('displays an error message for rejected files', async () => { + renderComponent() + global.URL.createObjectURL = jest.fn(); + const file = new File(['dummy content'], 'example.txt', { type: 'text/plain' }) + const input = screen.getByTestId('file-input') + + fireEvent.change(input, { target: { files: [file] } }) + await waitFor(() => expect(mockShowSnackbar).toHaveBeenCalledWith(expect.anything(), 'error')) + }) + + test('uploads files and shows progress', async () => { + const mockResponse = { + data: { + message: 'Upload successful', + files: [{ url: 'http://example.com/image.jpg', filename: 'image.jpg' }], + }, + } + + axios.post.mockResolvedValueOnce(mockResponse) + + renderComponent({ onImageUpload: jest.fn() }) + global.URL.createObjectURL = jest.fn(); + + const file = new File(['dummy content'], 'example.jpg', { type: 'image/jpeg' }) + const input = screen.getByTestId('file-input') + + fireEvent.change(input, { target: { files: [file] } }) + await waitFor(() => expect(mockShowSnackbar).toHaveBeenCalledWith(expect.anything(), 'success')) + // await waitFor(() => expect(screen.getByText('Upload successful')).toBeInTheDocument()) + const image = screen.getByRole('img'); + const expectedSrc = 'http://example.com/image.jpg'; + + expect(image.getAttribute('src')).toBe(expectedSrc); + }) + + + test('handles upload error', async () => { + axios.post.mockRejectedValueOnce({ response: { data: { message: 'Upload failed' } } }) + + renderComponent() + global.URL.createObjectURL = jest.fn(); + + const file = new File(['dummy content'], 'example.jpg', { type: 'image/jpeg' }) + const input = screen.getByTestId('file-input') + + fireEvent.change(input, { target: { files: [file] } }) + + await waitFor(() => expect(mockShowSnackbar).toHaveBeenCalledWith('Upload failed', 'error')) + }) + + test('deletes an image', async () => { + const mockUploadResponse = { + data: { + message: 'Upload successful', + files: [{ url: 'http://example.com/image.jpg', filename: 'image.jpg' }], + }, + } + const mockDeleteResponse = { + data: { + message: 'Delete successful', + }, + } + + axios.post.mockResolvedValueOnce(mockUploadResponse) + axios.delete.mockResolvedValueOnce(mockDeleteResponse) + + renderComponent({ onImageUpload: jest.fn() }) + global.URL.createObjectURL = jest.fn(); + + const file = new File(['dummy content'], 'example.jpg', { type: 'image/jpeg' }) + const input = screen.getByTestId('file-input') + + fireEvent.change(input, { target: { files: [file] } }) + + await waitFor(() => expect(mockShowSnackbar).toHaveBeenCalledWith("Upload successful", 'success')) + const image = screen.getByRole('img'); + const expectedSrc = 'http://example.com/image.jpg'; + + expect(image.getAttribute('src')).toBe(expectedSrc); + + const deleteButton = screen.getByTestId("DeleteIcon") + fireEvent.click(deleteButton) + + await waitFor(() => expect(mockShowSnackbar).toHaveBeenCalledWith('Delete successful', 'success')) + }) +}) diff --git a/client/src/ImageUpload/index.jsx b/client/src/ImageUpload/index.jsx index 2c85ef8..d46f252 100644 --- a/client/src/ImageUpload/index.jsx +++ b/client/src/ImageUpload/index.jsx @@ -131,7 +131,7 @@ const ImageUpload = ({ onImageUpload }) => { borderRadius: '4px', }} > - + {isDragActive ? ( {t("configuration.image_upload.file_drop")} ) : (