import React from 'react';
import { vi, describe, it, expect, beforeEach } from 'vitest';
import { render, screen } from '@testing-library/react';
import { useConfig, useSession } from '@openmrs/esm-framework';
import {
adjustmentOpeationTypeMock,
disposalOperationTypeMock,
openingStockOperationTypeMock,
receiptOperationTypeMock,
requisitionOperationTypeMock,
returnOperationTypeMock,
stockIssueOperationtypeMock,
stockTakeOperationTypeMock,
tranferOutOperationTypeMock,
} from '@mocks';
import { useStockOperationTypes } from '../../stock-lookups/stock-lookups.resource';
import { useStockOperations } from '../stock-operations.resource';
import useParties from './hooks/useParties';
import StockOperationForm from './stock-operation-form.component';
const mockUseParties = vi.mocked(useParties);
const mockUseStockOperationTypes = vi.mocked(useStockOperationTypes);
const mockUseStockOperations = vi.mocked(useStockOperations);
const mockUseConfig = vi.mocked(useConfig);
const mockUseSession = vi.mocked(useSession);
vi.mock('../../stock-lookups/stock-lookups.resource', () => ({
useStockOperationTypes: vi.fn(),
useUsers: vi.fn().mockReturnValue({ items: { results: [] }, isLoading: false }),
useUser: vi.fn().mockReturnValue({ data: { display: 'Test User' }, isLoading: false, error: null }),
useConcept: vi.fn().mockReturnValue({ items: { answers: [] }, isLoading: false, error: null }),
}));
vi.mock('../stock-operations.resource', () => ({
getStockOperationLinks: vi.fn(),
operationStatusColor: vi.fn(() => 'some-color'),
useStockOperations: vi.fn().mockReturnValue({
items: {
results: [],
links: [],
totalCount: 0,
},
isLoading: false,
error: null,
}),
useStockOperation: vi.fn().mockReturnValue({
items: undefined,
isLoading: false,
error: null,
}),
useStockOperationAndItems: vi.fn().mockReturnValue({
items: undefined,
isLoading: false,
error: null,
}),
}));
vi.mock('./hooks/useParties', () => ({
default: vi.fn(),
useParties: vi.fn(),
}));
describe('Stock Operation step 1 (baseoperation details)', () => {
beforeEach(() => {
const mockStockOperationTypes = {
results: [],
links: [],
totalCount: 0,
};
mockUseStockOperationTypes.mockReturnValue({
types: mockStockOperationTypes,
isLoading: false,
error: null,
});
mockUseStockOperations.mockReturnValue({
items: {
results: [],
links: [],
totalCount: 0,
},
isLoading: false,
error: null,
});
mockUseConfig.mockReturnValue({ autoPopulateResponsiblePerson: true });
mockUseSession.mockReturnValue({
authenticated: true,
sessionId: 'test-session-id',
user: {
uuid: 'test-user-uuid',
display: 'Test User',
username: 'testuser',
systemId: 'test-system-id',
userProperties: {},
person: { uuid: 'test-person-uuid' },
privileges: [],
roles: [],
retired: false,
links: [],
locale: 'en',
allowedLocales: ['en'],
},
sessionLocation: {
uuid: 'test-location-uuid',
display: 'Test Location',
links: [],
},
});
});
it('should render loading state when loading parties info', async () => {
mockUseParties.mockReturnValue({
destinationParties: [],
destinationPartiesFilter: () => true,
destinationTags: [],
error: null,
isLoading: true,
mutate: vi.fn(),
parties: [],
sourceParties: [],
sourcePartiesFilter: () => true,
sourceTags: [],
});
render(
,
);
expect(screen.getByRole('progressbar')).toBeInTheDocument();
});
it('should render error state when parties loading fails', async () => {
mockUseParties.mockReturnValue({
destinationParties: [],
destinationPartiesFilter: () => true,
destinationTags: [],
error: 'error',
isLoading: false,
mutate: vi.fn(),
parties: [],
sourceParties: [],
sourcePartiesFilter: () => true,
sourceTags: [],
});
render(
,
);
expect(screen.getByText(/error state/i)).toBeInTheDocument();
});
it('should have only next btn and not previous btn', async () => {
mockUseParties.mockReturnValue({
destinationParties: [],
destinationPartiesFilter: () => true,
destinationTags: [],
error: undefined,
isLoading: false,
mutate: vi.fn(),
parties: [],
sourceParties: [],
sourcePartiesFilter: () => true,
sourceTags: [],
});
render(
,
);
expect(screen.getByRole('button', { name: /next/i })).toBeInTheDocument();
expect(screen.queryByRole('button', { name: /previous/i })).not.toBeInTheDocument();
});
it('should render operation type in title', async () => {
mockUseParties.mockReturnValue({
destinationParties: [],
sourceParties: [],
isLoading: false,
error: undefined,
sourceTags: [],
destinationTags: [],
parties: [],
mutate: vi.fn(),
sourcePartiesFilter: () => true,
destinationPartiesFilter: () => true,
});
render(
,
);
expect(screen.getByRole('heading', { name: `${receiptOperationTypeMock.name} Details` })).toBeInTheDocument();
});
it("should render combobox with 'from' name and 'choose a source' placeholder for receipt operation", async () => {
mockUseParties.mockReturnValue({
destinationParties: [],
sourceParties: [],
isLoading: false,
error: undefined,
sourceTags: [],
destinationTags: [],
parties: [],
mutate: vi.fn(),
sourcePartiesFilter: () => true,
destinationPartiesFilter: () => true,
});
render(
,
);
const sourceInput = screen.getByRole('combobox', {
name: (_, element) =>
element.getAttribute('placeholder') === 'Choose a source' && element.getAttribute('name') === 'sourceUuid',
});
expect(sourceInput).toBeInTheDocument();
expect(screen.getByRole('combobox', { name: /from/i })).toBeInTheDocument();
});
it("should render combobox with 'to' name and defaulted to 'main store' location in receipt operation", async () => {
mockUseParties.mockReturnValue({
destinationParties: [],
sourceParties: [],
isLoading: false,
error: undefined,
sourceTags: [],
destinationTags: [],
parties: [],
mutate: vi.fn(),
sourcePartiesFilter: () => true,
destinationPartiesFilter: () => true,
});
render(
,
);
expect(screen.getByRole('combobox', { name: /to/i })).toBeInTheDocument();
});
it("should render combobox with 'destinationUuid' name and 'chooseADestination' placeholder", async () => {
mockUseParties.mockReturnValue({
destinationParties: [],
sourceParties: [],
isLoading: false,
error: undefined,
sourceTags: [],
destinationTags: [],
parties: [],
mutate: vi.fn(),
sourcePartiesFilter: () => true,
destinationPartiesFilter: () => true,
});
render(
,
);
expect(
screen.getByRole('combobox', {
name: (_, element) =>
element.getAttribute('placeholder') === 'Choose a destination' &&
element.getAttribute('name') === 'destinationUuid',
}),
).toBeInTheDocument();
expect(screen.getByRole('combobox', { name: /to/i })).toBeInTheDocument();
});
it("should render combobox with 'sourceUuid' name and 'chooseALocation' placeholder for disposal operation", async () => {
mockUseParties.mockReturnValue({
destinationParties: [],
sourceParties: [],
isLoading: false,
error: undefined,
sourceTags: [],
destinationTags: [],
parties: [],
mutate: vi.fn(),
sourcePartiesFilter: () => true,
destinationPartiesFilter: () => true,
});
render(
,
);
expect(
screen.getByRole('combobox', {
name: (_, element) =>
element.getAttribute('placeholder') === 'Choose a location' && element.getAttribute('name') === 'sourceUuid',
}),
).toBeInTheDocument();
expect(screen.getByRole('combobox', { name: /location/i })).toBeInTheDocument();
});
it('should not render reason input field for receipt operation', async () => {
mockUseParties.mockReturnValue({
destinationParties: [],
sourceParties: [],
isLoading: false,
error: undefined,
sourceTags: [],
destinationTags: [],
parties: [],
mutate: vi.fn(),
sourcePartiesFilter: () => true,
destinationPartiesFilter: () => true,
});
render(
,
);
expect(screen.queryByRole('combobox', { name: /reason/i })).not.toBeInTheDocument();
});
it('should render reason input field for adjustment operation', async () => {
mockUseParties.mockReturnValue({
destinationParties: [],
sourceParties: [],
isLoading: false,
error: undefined,
sourceTags: [],
destinationTags: [],
parties: [],
mutate: vi.fn(),
sourcePartiesFilter: () => true,
destinationPartiesFilter: () => true,
});
render(
,
);
expect(screen.getByRole('combobox', { name: /reason/i })).toBeInTheDocument();
});
it('should not render reason input field for opening stock operation', async () => {
mockUseParties.mockReturnValue({
destinationParties: [],
sourceParties: [],
isLoading: false,
error: undefined,
sourceTags: [],
destinationTags: [],
parties: [],
mutate: vi.fn(),
sourcePartiesFilter: () => true,
destinationPartiesFilter: () => true,
});
render(
,
);
expect(screen.queryByRole('combobox', { name: /reason/i })).not.toBeInTheDocument();
});
it('should not render reason input field for requisition operation', async () => {
mockUseParties.mockReturnValue({
destinationParties: [],
sourceParties: [],
isLoading: false,
error: undefined,
sourceTags: [],
destinationTags: [],
parties: [],
mutate: vi.fn(),
sourcePartiesFilter: () => true,
destinationPartiesFilter: () => true,
});
render(
,
);
expect(screen.queryByRole('combobox', { name: /reason/i })).not.toBeInTheDocument();
});
it('should not render reason input field for return operation', async () => {
mockUseParties.mockReturnValue({
destinationParties: [],
sourceParties: [],
isLoading: false,
error: undefined,
sourceTags: [],
destinationTags: [],
parties: [],
mutate: vi.fn(),
sourcePartiesFilter: () => true,
destinationPartiesFilter: () => true,
});
render(
,
);
expect(screen.queryByRole('combobox', { name: /reason/i })).not.toBeInTheDocument();
});
it('should not render reason input field for issue operation', async () => {
mockUseParties.mockReturnValue({
destinationParties: [],
sourceParties: [],
isLoading: false,
error: undefined,
sourceTags: [],
destinationTags: [],
parties: [],
mutate: vi.fn(),
sourcePartiesFilter: () => true,
destinationPartiesFilter: () => true,
});
render(
,
);
expect(screen.queryByRole('combobox', { name: /reason/i })).not.toBeInTheDocument();
});
it('should not render reason input field for tranfer out operation', async () => {
mockUseParties.mockReturnValue({
destinationParties: [],
sourceParties: [],
isLoading: false,
error: undefined,
sourceTags: [],
destinationTags: [],
parties: [],
mutate: vi.fn(),
sourcePartiesFilter: () => true,
destinationPartiesFilter: () => true,
});
render(
,
);
expect(screen.queryByRole('combobox', { name: /reason/i })).not.toBeInTheDocument();
});
it('should render reason input field for disposal operation', async () => {
mockUseParties.mockReturnValue({
destinationParties: [],
sourceParties: [],
isLoading: false,
error: undefined,
sourceTags: [],
destinationTags: [],
parties: [],
mutate: vi.fn(),
sourcePartiesFilter: () => true,
destinationPartiesFilter: () => true,
});
render(
,
);
expect(screen.getByRole('combobox', { name: /reason/i })).toBeInTheDocument();
});
it('should render reason input field for stock take operation', async () => {
mockUseParties.mockReturnValue({
destinationParties: [],
sourceParties: [],
isLoading: false,
error: undefined,
sourceTags: [],
destinationTags: [],
parties: [],
mutate: vi.fn(),
sourcePartiesFilter: () => true,
destinationPartiesFilter: () => true,
});
render(
,
);
expect(screen.getByRole('combobox', { name: /reason/i })).toBeInTheDocument();
});
});