Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

(Test): O3-3755: Add Tests for stock item bulk import #215

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,17 @@ const ImportDialogPopup: React.FC<ImportDialogPopupProps> = ({ closeModal }) =>

const onFileChanged = (event: React.ChangeEvent<HTMLInputElement>) => {
const file = event?.target?.files?.[0];
if (file) {
if (file && file.size <= 2 * 1024 * 1024) {
setSelectedFile(file);
} else {
event.preventDefault();
setSelectedFile(null);
event.target.value = "";
showSnackbar({
title: t("fileSizeError", "File size error"),
kind: "error",
isLowContrast: true,
subtitle: t("fileSizeErrorMessage", "File size must be 2MB or less"),
});
}
};

Expand All @@ -64,7 +71,7 @@ const ImportDialogPopup: React.FC<ImportDialogPopupProps> = ({ closeModal }) =>
labelDescription="Only .csv files at 2mb or less"
filenameStatus="edit"
labelTitle=""
size="small"
size="sm"
onChange={onFileChanged}
/>
</ModalBody>
Expand Down
134 changes: 134 additions & 0 deletions src/stock-items/add-bulk-stock-item/stock-items-bulk-import.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
import React from 'react';
import { render, screen, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import ImportDialogPopup from './stock-items-bulk-import.component';
import { showSnackbar } from '@openmrs/esm-framework';
import { UploadStockItems } from './stock-items-bulk-import.resource';

jest.mock('@openmrs/esm-framework', () => ({
showSnackbar: jest.fn(),
}));

jest.mock('./stock-items-bulk-import.resource', () => ({
UploadStockItems: jest.fn(),
}));

describe('ImportDialogPopup', () => {
const mockCloseModal = jest.fn();

beforeEach(() => {
jest.clearAllMocks();
});

it('renders with initial state and UI elements', () => {
render(<ImportDialogPopup closeModal={mockCloseModal} />);

expect(screen.getByText('Import Stock Items')).toBeInTheDocument();
expect(screen.getByRole('button', { name: 'Select file' })).toBeInTheDocument();
expect(screen.getByText('Only .csv files at 2mb or less')).toBeInTheDocument();
expect(screen.getByRole('button', { name: 'Cancel' })).toBeInTheDocument();
expect(screen.getByRole('button', { name: 'Upload StockItems' })).toBeInTheDocument();
});

it('allows only CSV files', async () => {
render(<ImportDialogPopup closeModal={mockCloseModal} />);

const fileInput = screen.getByLabelText('Select file') as HTMLInputElement;
expect(fileInput.accept).toBe('.csv');
});

it('does not allow files larger than 2MB', async () => {
render(<ImportDialogPopup closeModal={mockCloseModal} />);

const largeFile = new File(['x'.repeat(2 * 1024 * 1024 + 1)], 'large.csv', { type: 'text/csv' });
const fileInput = screen.getByLabelText('Select file') as HTMLInputElement;

await userEvent.upload(fileInput, largeFile);

expect(fileInput.files).toHaveLength(0);
expect(showSnackbar).toHaveBeenCalledWith(
expect.objectContaining({
kind: 'error',
title: 'File size error',
}),
);
});

it('allows files 2MB or smaller', async () => {
render(<ImportDialogPopup closeModal={mockCloseModal} />);

const validFile = new File(['x'.repeat(2 * 1024 * 1024)], 'valid.csv', { type: 'text/csv' });
const fileInput = screen.getByLabelText('Select file') as HTMLInputElement;

await userEvent.upload(fileInput, validFile);

expect(fileInput.files).toHaveLength(1);
expect(fileInput.files[0]).toBe(validFile);
});

it('closes modal when cancel button is clicked', async () => {
render(<ImportDialogPopup closeModal={mockCloseModal} />);

const cancelButton = screen.getByRole('button', { name: 'Cancel' });
await userEvent.click(cancelButton);

expect(mockCloseModal).toHaveBeenCalledTimes(1);
});

it('does nothing when upload is clicked without a file', async () => {
render(<ImportDialogPopup closeModal={mockCloseModal} />);

const uploadButton = screen.getByRole('button', { name: 'Upload StockItems' });
await userEvent.click(uploadButton);

expect(UploadStockItems).not.toHaveBeenCalled();
expect(showSnackbar).not.toHaveBeenCalled();
expect(mockCloseModal).not.toHaveBeenCalled();
});

it('uploads file successfully and shows success snackbar', async () => {
(UploadStockItems as jest.Mock).mockResolvedValue({});
render(<ImportDialogPopup closeModal={mockCloseModal} />);

const validFile = new File(['test content'], 'valid.csv', { type: 'text/csv' });
const fileInput = screen.getByLabelText('Select file') as HTMLInputElement;
await userEvent.upload(fileInput, validFile);

const uploadButton = screen.getByRole('button', { name: 'Upload StockItems' });
await userEvent.click(uploadButton);

await waitFor(() => expect(UploadStockItems).toHaveBeenCalled());
await waitFor(() =>
expect(showSnackbar).toHaveBeenCalledWith(
expect.objectContaining({
kind: 'success',
title: 'Uploaded Order',
}),
),
);
await waitFor(() => expect(mockCloseModal).toHaveBeenCalledTimes(1));
});

it('shows error snackbar on upload failure', async () => {
(UploadStockItems as jest.Mock).mockRejectedValue(new Error('Upload failed'));
render(<ImportDialogPopup closeModal={mockCloseModal} />);

const validFile = new File(['test content'], 'valid.csv', { type: 'text/csv' });
const fileInput = screen.getByLabelText('Select file') as HTMLInputElement;
await userEvent.upload(fileInput, validFile);

const uploadButton = screen.getByRole('button', { name: 'Upload StockItems' });
await userEvent.click(uploadButton);

await waitFor(() => expect(UploadStockItems).toHaveBeenCalled());
await waitFor(() =>
expect(showSnackbar).toHaveBeenCalledWith(
expect.objectContaining({
kind: 'error',
title: 'An error occurred uploading stock items',
}),
),
);
await waitFor(() => expect(mockCloseModal).not.toHaveBeenCalled());
});
});