@openmrs/esm-stock-management-app 1.0.1-pre.783 → 1.0.1-pre.785

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (121) hide show
  1. package/__mocks__/index.ts +1 -0
  2. package/__mocks__/operation-type.mock.ts +532 -0
  3. package/dist/155.js +1 -0
  4. package/dist/155.js.map +1 -0
  5. package/dist/172.js +1 -1
  6. package/dist/20.js +1 -1
  7. package/dist/290.js +1 -1
  8. package/dist/493.js +2 -0
  9. package/dist/493.js.map +1 -0
  10. package/dist/606.js +1 -1
  11. package/dist/627.js +1 -1
  12. package/dist/914.js +1 -0
  13. package/dist/914.js.map +1 -0
  14. package/dist/main.js +1 -1
  15. package/dist/main.js.map +1 -1
  16. package/dist/openmrs-esm-stock-management-app.js +1 -1
  17. package/dist/openmrs-esm-stock-management-app.js.buildmanifest.json +75 -51
  18. package/dist/openmrs-esm-stock-management-app.js.map +1 -1
  19. package/dist/routes.json +1 -1
  20. package/package.json +1 -1
  21. package/src/core/utils/utils.ts +29 -0
  22. package/src/index.ts +4 -0
  23. package/src/routes.json +9 -0
  24. package/src/stock-items/add-stock-item/transactions/printout/transactions-stockcard-printout.component.tsx +8 -12
  25. package/src/stock-items/add-stock-item/transactions/transactions.component.tsx +8 -12
  26. package/src/stock-items/stock-items.resource.ts +5 -5
  27. package/src/stock-lookups/stock-lookups.resource.ts +2 -2
  28. package/src/stock-operations/edit-stock-operation/edit-stock-operation-action-menu.component.tsx +41 -16
  29. package/src/stock-operations/{add-stock-operation/received-items.component.tsx → received-items.component.tsx} +1 -1
  30. package/src/stock-operations/stock-operation-reference.component.tsx +64 -0
  31. package/src/stock-operations/stock-operation-status/stock-operation-status-row.tsx +77 -0
  32. package/src/stock-operations/stock-operation-status/stock-operation-status.scss +32 -0
  33. package/src/stock-operations/stock-operation-status/stock-operation-status.tsx +45 -0
  34. package/src/stock-operations/stock-operation-types-selector/stock-operation-types-selector.component.tsx +30 -29
  35. package/src/stock-operations/stock-operation.utils.tsx +16 -79
  36. package/src/stock-operations/stock-operations-dialog/stock-operations-issue-stock-button.component.tsx +27 -39
  37. package/src/stock-operations/stock-operations-dialog/stock-operations-print-button.component.tsx +51 -59
  38. package/src/stock-operations/{stock-item-selector/stock-item-selector.resource.tsx → stock-operations-forms/hooks/useFilterableStockItems.ts} +4 -4
  39. package/src/stock-operations/stock-operations-forms/hooks/useFilteredOperationTypesByRoles.ts +30 -0
  40. package/src/stock-operations/stock-operations-forms/hooks/useOperationTypePermisions.ts +29 -0
  41. package/src/stock-operations/stock-operations-forms/hooks/useParties.ts +73 -0
  42. package/src/stock-operations/{users-selector/users-selector.resource.tsx → stock-operations-forms/hooks/useSearchUser.ts} +9 -7
  43. package/src/stock-operations/{batch-no-selector/batch-no-selector.resource.tsx → stock-operations-forms/hooks/useStockItemBatchNumbers.ts} +3 -3
  44. package/src/stock-operations/stock-operations-forms/hooks/useStockOperationLinks.ts +20 -0
  45. package/src/stock-operations/stock-operations-forms/input-components/batch-no-selector.component.tsx +72 -0
  46. package/src/stock-operations/stock-operations-forms/input-components/batch-no-selector.test.tsx +90 -0
  47. package/src/stock-operations/{add-stock-operation/stock-item-search/stock-item-search.scss → stock-operations-forms/input-components/input-components-styles.scss} +2 -2
  48. package/src/stock-operations/stock-operations-forms/input-components/qty-uim-selector.test.tsx +157 -0
  49. package/src/stock-operations/stock-operations-forms/input-components/quantity-uom-selector.component.tsx +53 -0
  50. package/src/stock-operations/stock-operations-forms/input-components/stock-item-search.component.tsx +56 -0
  51. package/src/stock-operations/stock-operations-forms/input-components/stock-operation-reason-selector.component.tsx +59 -0
  52. package/src/stock-operations/stock-operations-forms/input-components/stock-operation-reason-selector.test.tsx +216 -0
  53. package/src/stock-operations/{batch-no-selector → stock-operations-forms/input-components}/unique-batch-no-entry-input.component.tsx +12 -7
  54. package/src/stock-operations/stock-operations-forms/input-components/user-selector.test.tsx +110 -0
  55. package/src/stock-operations/stock-operations-forms/input-components/users-selector.component.tsx +111 -0
  56. package/src/stock-operations/stock-operations-forms/step1.test.tsx +303 -0
  57. package/src/stock-operations/stock-operations-forms/step2.test.tsx +250 -0
  58. package/src/stock-operations/stock-operations-forms/step3.test.tsx +223 -0
  59. package/src/stock-operations/stock-operations-forms/steps/base-operation-details-form-step.tsx +241 -0
  60. package/src/stock-operations/stock-operations-forms/steps/quantity-uom-cell.component.tsx +33 -0
  61. package/src/stock-operations/stock-operations-forms/steps/stock-availability-cell.component.tsx +51 -0
  62. package/src/stock-operations/stock-operations-forms/steps/stock-operation-item-batch-no-cell.component.tsx +40 -0
  63. package/src/stock-operations/stock-operations-forms/steps/stock-operation-item-cell.component.tsx +38 -0
  64. package/src/stock-operations/stock-operations-forms/steps/stock-operation-item-expiry-cell.component.tsx +41 -0
  65. package/src/stock-operations/stock-operations-forms/steps/stock-operation-items-form-step.component.tsx +281 -0
  66. package/src/stock-operations/stock-operations-forms/steps/stock-operation-items-form-step.scc.scss +64 -0
  67. package/src/stock-operations/stock-operations-forms/steps/stock-operation-submission-form-step.component.tsx +236 -0
  68. package/src/stock-operations/stock-operations-forms/stock-issue-form-initializer-with-related-requisition-operation.component.tsx +55 -0
  69. package/src/stock-operations/stock-operations-forms/stock-item-form/stock-item-form.scss +41 -0
  70. package/src/stock-operations/stock-operations-forms/stock-item-form/stock-item-form.workspace.tsx +197 -0
  71. package/src/stock-operations/stock-operations-forms/stock-operation-form-header.component.tsx +166 -0
  72. package/src/stock-operations/stock-operations-forms/stock-operation-form.component.tsx +200 -0
  73. package/src/stock-operations/stock-operations-forms/stock-operation-form.scss +111 -0
  74. package/src/stock-operations/stock-operations-forms/stock-operation-related-link.component.tsx +45 -0
  75. package/src/stock-operations/stock-operations-forms/stock-operation-stepper/stepper.scss +41 -0
  76. package/src/stock-operations/stock-operations-forms/stock-operation-stepper/stock-operation-stepper.component.tsx +52 -0
  77. package/src/stock-operations/stock-operations-forms/stock-operations-form-utils.ts +32 -0
  78. package/src/stock-operations/stock-operations-table.component.tsx +20 -56
  79. package/src/stock-operations/stock-operations.resource.ts +16 -13
  80. package/src/stock-operations/validation-schema.ts +72 -14
  81. package/dist/766.js +0 -2
  82. package/dist/766.js.map +0 -1
  83. package/dist/822.js +0 -1
  84. package/dist/822.js.map +0 -1
  85. package/src/stock-operations/add-stock-operation/add-stock-operation.component.tsx +0 -349
  86. package/src/stock-operations/add-stock-operation/add-stock-operation.resource.tsx +0 -27
  87. package/src/stock-operations/add-stock-operation/add-stock-operation.scss +0 -60
  88. package/src/stock-operations/add-stock-operation/add-stock-operation.test.tsx +0 -192
  89. package/src/stock-operations/add-stock-operation/add-stock-operation.utils.tsx +0 -152
  90. package/src/stock-operations/add-stock-operation/add-stock-utils.ts +0 -103
  91. package/src/stock-operations/add-stock-operation/base-operation-details.component.tsx +0 -439
  92. package/src/stock-operations/add-stock-operation/base-operation-details.scss +0 -30
  93. package/src/stock-operations/add-stock-operation/stock-item-search/stock-item-search.component.tsx +0 -70
  94. package/src/stock-operations/add-stock-operation/stock-items-addition-row.component.tsx +0 -357
  95. package/src/stock-operations/add-stock-operation/stock-items-addition-row.resource.tsx +0 -0
  96. package/src/stock-operations/add-stock-operation/stock-items-addition-row.scss +0 -12
  97. package/src/stock-operations/add-stock-operation/stock-items-addition-row.test.tsx +0 -10
  98. package/src/stock-operations/add-stock-operation/stock-items-addition.component.scss +0 -17
  99. package/src/stock-operations/add-stock-operation/stock-items-addition.component.tsx +0 -254
  100. package/src/stock-operations/add-stock-operation/stock-operation-context/useStockOperationContext.tsx +0 -16
  101. package/src/stock-operations/add-stock-operation/stock-operation-reference.component.tsx +0 -39
  102. package/src/stock-operations/add-stock-operation/stock-operation-related-link.component.tsx +0 -38
  103. package/src/stock-operations/add-stock-operation/stock-operation-status.component.tsx +0 -170
  104. package/src/stock-operations/add-stock-operation/stock-operation-submission.component.tsx +0 -189
  105. package/src/stock-operations/add-stock-operation/stock-operation-submission.test.tsx +0 -138
  106. package/src/stock-operations/add-stock-operation/types.ts +0 -55
  107. package/src/stock-operations/add-stock-operation/validationSchema.ts +0 -54
  108. package/src/stock-operations/batch-no-selector/batch-no-selector.component.tsx +0 -114
  109. package/src/stock-operations/batch-no-selector/batch-no-selector.scss +0 -0
  110. package/src/stock-operations/batch-no-selector/batch-no-selector.test.tsx +0 -101
  111. package/src/stock-operations/party-selector/party-selector.component.tsx +0 -59
  112. package/src/stock-operations/qty-uom-selector/qty-uom-selector.component.tsx +0 -65
  113. package/src/stock-operations/qty-uom-selector/qty-uom-selector.resource.tsx +0 -0
  114. package/src/stock-operations/qty-uom-selector/qty-uom-selector.scss +0 -0
  115. package/src/stock-operations/qty-uom-selector/qty-uom-selector.test.tsx +0 -10
  116. package/src/stock-operations/stock-item-selector/stock-item-selector.component.tsx +0 -69
  117. package/src/stock-operations/stock-item-selector/stock-item-selector.scss +0 -0
  118. package/src/stock-operations/stock-item-selector/stock-item-selector.test.tsx +0 -10
  119. package/src/stock-operations/stock-operation-reason-selector/stock-operation-reason-selector.component.tsx +0 -62
  120. package/src/stock-operations/users-selector/users-selector.component.tsx +0 -75
  121. /package/dist/{766.js.LICENSE.txt → 493.js.LICENSE.txt} +0 -0
@@ -0,0 +1,250 @@
1
+ import React from 'react';
2
+ import { render, waitFor, screen, fireEvent } from '@testing-library/react';
3
+ import { showSnackbar, useConfig, ErrorState, launchWorkspace } from '@openmrs/esm-framework';
4
+ import { useStockOperationTypes, useUser } from '../../stock-lookups/stock-lookups.resource';
5
+ import { getStockOperationLinks } from '../stock-operations.resource';
6
+ import { StockOperationDTO } from '../../core/api/types/stockOperation/StockOperationDTO';
7
+ import { StockOperationType } from '../../core/api/types/stockOperation/StockOperationType';
8
+ import { useStockOperations } from '../stock-operations.resource';
9
+ import { closeOverlay } from '../../core/components/overlay/hook';
10
+ import StockOperationForm from './stock-operation-form.component';
11
+ import useParties from './hooks/useParties';
12
+ import userEvent from '@testing-library/user-event';
13
+ import { StockItemDTO } from '../../core/api/types/stockItem/StockItem';
14
+ import { useStockItem, useStockItems, useStockBatches } from '../../stock-items/stock-items.resource';
15
+ import { initialStockOperationValue } from '../../core/utils/utils';
16
+ import { useForm, useFormContext, Controller, FormProvider } from 'react-hook-form';
17
+ import { BaseStockOperationItemFormData, StockOperationItemFormData } from '../validation-schema';
18
+ import { useStockItemBatchInformationHook } from '../../stock-items/add-stock-item/batch-information/batch-information.resource';
19
+ import { useFilterableStockItems } from './hooks/useFilterableStockItems';
20
+ import { formatForDatePicker } from '../../constants';
21
+ import { receiptOperationTypeMock } from '../../../__mocks__';
22
+ jest.mock('react-i18next', () => ({
23
+ useTranslation: jest.fn().mockReturnValue({ t: (key) => key }),
24
+ }));
25
+
26
+ jest.mock('@openmrs/esm-framework', () => ({
27
+ ActionMenu: jest.fn(() => null),
28
+ showSnackbar: jest.fn(),
29
+ useDebounce: jest.fn((x) => x),
30
+ getGlobalStore: jest.fn(() => ({
31
+ getState: jest.fn(),
32
+ subscribe: jest.fn(),
33
+ setState: jest.fn(),
34
+ })),
35
+ parseDate: jest.fn((date) => new Date(date)),
36
+ showNotification: jest.fn(),
37
+ usePagination: jest.fn(() => ({ currentPage: 1, setPage: jest.fn() })),
38
+ useSession: jest.fn(() => ({ user: { display: 'Test User' } })),
39
+ useConfig: jest.fn(),
40
+ ErrorState: jest.fn(({ error }: { error: any }) => <div>{error}</div>),
41
+ launchWorkspace: jest.fn(),
42
+ }));
43
+
44
+ jest.mock('../../stock-lookups/stock-lookups.resource', () => ({
45
+ useStockOperationTypes: jest.fn(),
46
+ useUsers: jest.fn().mockReturnValue({ items: { results: [] }, isLoading: false }),
47
+ useUser: jest.fn().mockReturnValue({ data: { display: 'Test User' }, isLoading: false, error: null }),
48
+ }));
49
+
50
+ jest.mock('../stock-operations.resource', () => ({
51
+ operationStatusColor: jest.fn(() => 'some-color'),
52
+ getStockOperationLinks: jest.fn(),
53
+ useStockOperations: jest.fn().mockReturnValue({
54
+ items: { results: [] },
55
+ isLoading: false,
56
+ error: null,
57
+ }),
58
+ }));
59
+
60
+ jest.mock('../../core/components/overlay/hook', () => ({
61
+ closeOverlay: jest.fn(),
62
+ }));
63
+
64
+ jest.mock('../../stock-items/stock-items.resource', () => ({
65
+ useStockItem: jest.fn(),
66
+ useStockItems: jest.fn().mockReturnValue({
67
+ isLoading: false,
68
+ error: null,
69
+ items: {},
70
+ }),
71
+ useStockBatches: jest.fn().mockReturnValue({
72
+ isLoading: false,
73
+ error: null,
74
+
75
+ items: {},
76
+ }),
77
+ }));
78
+ jest.mock('./hooks/useFilterableStockItems', () => ({
79
+ useFilterableStockItems: jest.fn().mockReturnValue({
80
+ stockItemsList: [],
81
+ setLimit: jest.fn(),
82
+ setRepresentation: jest.fn(),
83
+ setSearchString: jest.fn(),
84
+ isLoading: false,
85
+ }),
86
+ }));
87
+ jest.mock('./hooks/useParties', () => jest.fn());
88
+ jest.mock('react-hook-form', () => ({
89
+ useForm: jest.fn().mockReturnValue({
90
+ watch: jest.fn(),
91
+ formState: {
92
+ errors: {},
93
+ },
94
+ resetField: jest.fn(),
95
+ getValues: jest.fn(),
96
+ setValue: jest.fn(),
97
+ handleSubmit: jest.fn(),
98
+ }),
99
+ useFormContext: jest.fn().mockReturnValue({
100
+ watch: jest.fn(),
101
+ formState: {
102
+ errors: {},
103
+ },
104
+ resetField: jest.fn(),
105
+ getValues: jest.fn(),
106
+ setValue: jest.fn(),
107
+ handleSubmit: jest.fn(),
108
+ }),
109
+ Controller: ({ render }) => render({ field: {}, fieldState: {} }),
110
+ FormProvider: ({ children }: { children: React.ReactNode }) => <>{children}</>,
111
+ }));
112
+
113
+ jest.mock('../../stock-items/add-stock-item/batch-information/batch-information.resource', () => ({
114
+ useStockItemBatchInformationHook: jest.fn().mockReturnValue({
115
+ items: [],
116
+ totalCount: 0,
117
+ currentPage: 1,
118
+ currentPageSize: 10,
119
+ setCurrentPage: jest.fn(),
120
+ setPageSize: jest.fn(),
121
+ pageSizes: [],
122
+ isLoading: false,
123
+ error: undefined,
124
+ setSearchString: jest.fn(),
125
+ setStockItemUuid: jest.fn(),
126
+ setLocationUuid: jest.fn(),
127
+ setPartyUuid: jest.fn(),
128
+ setStockBatchUuid: jest.fn(),
129
+ }),
130
+ }));
131
+
132
+ describe('Stock Operation step 2 (stock operation items details)', () => {
133
+ beforeEach(() => {
134
+ const mockStockOperationTypes = { results: [] };
135
+ (useStockOperationTypes as jest.Mock).mockReturnValue(mockStockOperationTypes);
136
+ (useStockOperations as jest.Mock).mockReturnValue({ items: { results: [] }, isLoading: false, error: null });
137
+ (useConfig as jest.Mock).mockReturnValue({ autoPopulateResponsiblePerson: true });
138
+ (useParties as jest.Mock).mockReturnValue({
139
+ destinationParties: [],
140
+ sourceParties: [],
141
+ isLoading: false,
142
+ error: undefined,
143
+ sourceTags: [],
144
+ destinationTags: [],
145
+ });
146
+ });
147
+
148
+ it('should have both previous and next btns', async () => {
149
+ render(<StockOperationForm stockOperationType={receiptOperationTypeMock as any} />);
150
+ // MOVE TO STEP 2
151
+ await userEvent.click(screen.getByRole('button', { name: /Next/i }));
152
+
153
+ expect(screen.getByRole('button', { name: /Next/i })).toBeInTheDocument();
154
+ expect(screen.getByRole('button', { name: /previous/i })).toBeInTheDocument();
155
+ });
156
+
157
+ it('should render stock operation items table with item search component', async () => {
158
+ render(<StockOperationForm stockOperationType={receiptOperationTypeMock as any} />);
159
+ const nextButton = screen.getByRole('button', { name: /Next/i });
160
+ expect(nextButton).toBeInTheDocument();
161
+ await userEvent.click(nextButton);
162
+ expect(screen.getByRole('table')).toBeInTheDocument();
163
+ expect(
164
+ screen.getByRole('searchbox', {
165
+ name(accessibleName, element) {
166
+ return (
167
+ element.getAttribute('id') === 'search-stock-operation-item' &&
168
+ element.getAttribute('placeholder') === 'findItems' &&
169
+ element.getAttribute('name') === 'search-stock-operation-item'
170
+ );
171
+ },
172
+ }),
173
+ ).toBeInTheDocument();
174
+ });
175
+
176
+ it('should search stock operation item and render results', async () => {
177
+ const mocksetSearchString = jest.fn();
178
+ (useFilterableStockItems as jest.Mock).mockReturnValue({
179
+ stockItemsList: [{ uuid: 'mock-uuid', commonName: 'mock-common-name' }] as Array<StockItemDTO>,
180
+ setLimit: jest.fn(),
181
+ setRepresentation: jest.fn(),
182
+ isLoading: false,
183
+ setSearchString: mocksetSearchString,
184
+ });
185
+ render(<StockOperationForm stockOperationType={receiptOperationTypeMock as any} />);
186
+ // ----- CLICK NEXT TO MOVE TO STEP 2 ---------
187
+ await userEvent.click(screen.getByRole('button', { name: /Next/i }));
188
+ // -------------------------------
189
+ const searchInput = screen.getByRole('searchbox', {
190
+ name: (_, element) => element.getAttribute('id') === 'search-stock-operation-item',
191
+ });
192
+ expect(searchInput).toBeInTheDocument();
193
+ await userEvent.click(searchInput);
194
+ await userEvent.type(searchInput, 'stock');
195
+ expect(mocksetSearchString).toHaveBeenCalledWith('stock');
196
+ expect(screen.getByText('mock-common-name'));
197
+ });
198
+
199
+ it('should properly handle stock operation item selection', async () => {
200
+ (useFilterableStockItems as jest.Mock).mockReturnValue({
201
+ stockItemsList: [{ uuid: 'mock-uuid', commonName: 'mock-common-name' }] as Array<StockItemDTO>,
202
+ setLimit: jest.fn(),
203
+ setRepresentation: jest.fn(),
204
+ isLoading: false,
205
+ setSearchString: jest.fn(),
206
+ });
207
+ render(<StockOperationForm stockOperationType={receiptOperationTypeMock as any} />);
208
+ // ----- CLICK NEXT TO MOVE TO STEP 2 ---------
209
+ await userEvent.click(screen.getByRole('button', { name: /Next/i }));
210
+ // -------------------------------
211
+ const searchInput = screen.getByRole('searchbox', {
212
+ name: (_, element) => element.getAttribute('id') === 'search-stock-operation-item',
213
+ });
214
+ await userEvent.click(searchInput);
215
+ await userEvent.type(searchInput, 'stock');
216
+ await userEvent.click(screen.getByText('mock-common-name'));
217
+ expect(launchWorkspace).toHaveBeenCalled();
218
+ });
219
+
220
+ it('should render stock operation items in data table', async () => {
221
+ (useStockItem as jest.Mock).mockReturnValue({
222
+ isLoading: false,
223
+ error: null,
224
+ item: { commonName: 'mock-stock-item-common name', uuid: 'mock-uuid' } as StockItemDTO,
225
+ });
226
+ const mockQuantity = 99999;
227
+ const mockExpiration = new Date();
228
+ (useFormContext as jest.Mock).mockReturnValue({
229
+ watch: jest.fn().mockReturnValue([
230
+ {
231
+ quantity: mockQuantity,
232
+ expiration: mockExpiration,
233
+ },
234
+ ] as BaseStockOperationItemFormData),
235
+ resetField: jest.fn(),
236
+ formState: {
237
+ errors: {},
238
+ },
239
+ getValues: jest.fn(),
240
+ setValue: jest.fn(),
241
+ handleSubmit: jest.fn(),
242
+ });
243
+ render(<StockOperationForm stockOperationType={receiptOperationTypeMock as any} />);
244
+ // ----- CLICK NEXT TO MOVE TO STEP 2 ---------
245
+ await userEvent.click(screen.getByRole('button', { name: /Next/i }));
246
+ // -------------------------------
247
+ expect(screen.getByText(mockQuantity.toLocaleString())).toBeInTheDocument(); //Find by quentity
248
+ expect(screen.getByText(formatForDatePicker(mockExpiration))).toBeInTheDocument(); //Find by quentity
249
+ });
250
+ });
@@ -0,0 +1,223 @@
1
+ import { render, waitFor, screen, fireEvent } from '@testing-library/react';
2
+ import { showSnackbar, useConfig, ErrorState, launchWorkspace } from '@openmrs/esm-framework';
3
+ import { useStockOperationTypes, useUser } from '../../stock-lookups/stock-lookups.resource';
4
+ import { getStockOperationLinks, useStockOperation } from '../stock-operations.resource';
5
+ import { StockOperationDTO } from '../../core/api/types/stockOperation/StockOperationDTO';
6
+ import { StockOperationType } from '../../core/api/types/stockOperation/StockOperationType';
7
+ import { useStockOperations } from '../stock-operations.resource';
8
+ import { closeOverlay } from '../../core/components/overlay/hook';
9
+ import StockOperationForm from './stock-operation-form.component';
10
+ import useParties from './hooks/useParties';
11
+ import userEvent from '@testing-library/user-event';
12
+ import { StockItemDTO } from '../../core/api/types/stockItem/StockItem';
13
+ import { useStockItem, useStockItems } from '../../stock-items/stock-items.resource';
14
+ import { initialStockOperationValue } from '../../core/utils/utils';
15
+ import { useForm, useFormContext, Controller, FormProvider } from 'react-hook-form';
16
+ import { BaseStockOperationItemFormData, StockOperationItemFormData } from '../validation-schema';
17
+ import { useStockItemBatchInformationHook } from '../../stock-items/add-stock-item/batch-information/batch-information.resource';
18
+ import { useFilterableStockItems } from './hooks/useFilterableStockItems';
19
+ import { formatForDatePicker } from '../../constants';
20
+ import React from 'react';
21
+ import { receiptOperationTypeMock, returnOperationTypeMock, stockIssueOperationtypeMock } from '../../../__mocks__';
22
+ jest.mock('react-i18next', () => ({
23
+ useTranslation: jest.fn().mockReturnValue({ t: (key) => key }),
24
+ }));
25
+
26
+ jest.mock('@openmrs/esm-framework', () => ({
27
+ ActionMenu: jest.fn(() => null),
28
+ showSnackbar: jest.fn(),
29
+ useDebounce: jest.fn((x) => x),
30
+ getGlobalStore: jest.fn(() => ({
31
+ getState: jest.fn(),
32
+ subscribe: jest.fn(),
33
+ setState: jest.fn(),
34
+ })),
35
+ parseDate: jest.fn((date) => new Date(date)),
36
+ showNotification: jest.fn(),
37
+ usePagination: jest.fn(() => ({ currentPage: 1, setPage: jest.fn() })),
38
+ useSession: jest.fn(() => ({ user: { display: 'Test User' } })),
39
+ useConfig: jest.fn(),
40
+ ErrorState: jest.fn(({ error }: { error: any }) => <div>{error}</div>),
41
+ launchWorkspace: jest.fn(),
42
+ }));
43
+
44
+ jest.mock('../../stock-lookups/stock-lookups.resource', () => ({
45
+ useStockOperationTypes: jest.fn(),
46
+ useUsers: jest.fn().mockReturnValue({ items: { results: [] }, isLoading: false }),
47
+ useUser: jest.fn().mockReturnValue({ data: { display: 'Test User' }, isLoading: false, error: null }),
48
+ }));
49
+
50
+ jest.mock('../stock-operations.resource', () => ({
51
+ operationStatusColor: jest.fn(() => 'some-color'),
52
+ getStockOperationLinks: jest.fn(),
53
+ useStockOperations: jest.fn().mockReturnValue({
54
+ items: { results: [] },
55
+ isLoading: false,
56
+ error: null,
57
+ }),
58
+ useStockOperation: jest.fn().mockReturnValue({
59
+ items: undefined,
60
+ isLoading: false,
61
+ error: null,
62
+ }),
63
+ }));
64
+
65
+ jest.mock('../../core/components/overlay/hook', () => ({
66
+ closeOverlay: jest.fn(),
67
+ }));
68
+
69
+ jest.mock('../../stock-items/stock-items.resource', () => ({
70
+ useStockItem: jest.fn(),
71
+ useStockItems: jest.fn().mockReturnValue({
72
+ isLoading: false,
73
+ error: null,
74
+ items: {},
75
+ }),
76
+ }));
77
+ jest.mock('./hooks/useFilterableStockItems', () => ({
78
+ useFilterableStockItems: jest.fn().mockReturnValue({
79
+ stockItemsList: [],
80
+ setLimit: jest.fn(),
81
+ setRepresentation: jest.fn(),
82
+ setSearchString: jest.fn(),
83
+ isLoading: false,
84
+ }),
85
+ }));
86
+ jest.mock('./hooks/useParties', () => jest.fn());
87
+ jest.mock('react-hook-form', () => ({
88
+ useForm: jest.fn().mockReturnValue({
89
+ watch: jest.fn(),
90
+ formState: {
91
+ errors: {},
92
+ },
93
+ resetField: jest.fn(),
94
+ getValues: jest.fn(),
95
+ setValue: jest.fn(),
96
+ handleSubmit: jest.fn(),
97
+ }),
98
+ useFormContext: jest.fn().mockReturnValue({
99
+ watch: jest.fn(),
100
+ formState: {
101
+ errors: {},
102
+ },
103
+ resetField: jest.fn(),
104
+ getValues: jest.fn(),
105
+ setValue: jest.fn(),
106
+ handleSubmit: jest.fn(),
107
+ }),
108
+ Controller: ({ render }) => render({ field: {}, fieldState: {} }),
109
+ FormProvider: ({ children }: { children: React.ReactNode }) => <>{children}</>,
110
+ }));
111
+
112
+ jest.mock('../../stock-items/add-stock-item/batch-information/batch-information.resource', () => ({
113
+ useStockItemBatchInformationHook: jest.fn().mockReturnValue({
114
+ items: [],
115
+ totalCount: 0,
116
+ currentPage: 1,
117
+ currentPageSize: 10,
118
+ setCurrentPage: jest.fn(),
119
+ setPageSize: jest.fn(),
120
+ pageSizes: [],
121
+ isLoading: false,
122
+ error: undefined,
123
+ setSearchString: jest.fn(),
124
+ setStockItemUuid: jest.fn(),
125
+ setLocationUuid: jest.fn(),
126
+ setPartyUuid: jest.fn(),
127
+ setStockBatchUuid: jest.fn(),
128
+ }),
129
+ }));
130
+
131
+ describe('Stock Operation form step 3 (stock submision)', () => {
132
+ beforeEach(() => {
133
+ const mockStockOperationTypes = { results: [] };
134
+ (useStockOperationTypes as jest.Mock).mockReturnValue(mockStockOperationTypes);
135
+ (useStockOperations as jest.Mock).mockReturnValue({ items: { results: [] }, isLoading: false, error: null });
136
+ (useConfig as jest.Mock).mockReturnValue({ autoPopulateResponsiblePerson: true });
137
+ (useParties as jest.Mock).mockReturnValue({
138
+ destinationParties: [],
139
+ sourceParties: [],
140
+ isLoading: false,
141
+ error: undefined,
142
+ sourceTags: [],
143
+ destinationTags: [],
144
+ });
145
+ });
146
+
147
+ it('should have previous btn and not next btn', async () => {
148
+ render(<StockOperationForm stockOperationType={receiptOperationTypeMock as any} />);
149
+ // MOVE TO STEP 2
150
+ await userEvent.click(screen.getByRole('button', { name: /Next/i }));
151
+ // MOVE TO STEP3
152
+ await userEvent.click(screen.getByRole('button', { name: /Next/i }));
153
+
154
+ expect(screen.queryByRole('button', { name: /Next/i })).not.toBeInTheDocument();
155
+ expect(screen.getByRole('button', { name: /previous/i })).toBeInTheDocument();
156
+ });
157
+
158
+ it('should render require approval radio button and save button', async () => {
159
+ render(<StockOperationForm stockOperationType={receiptOperationTypeMock as any} />);
160
+ // MOVE TO STEP 2
161
+ await userEvent.click(screen.getByRole('button', { name: /Next/i }));
162
+ // MOVE TO STEP3
163
+ await userEvent.click(screen.getByRole('button', { name: /Next/i }));
164
+
165
+ // Shouls have save button
166
+ expect(screen.getByRole('button', { name: /save/i })).toBeInTheDocument();
167
+ expect(screen.getAllByRole('radio', { name: /yes|no/i })).toHaveLength(2);
168
+ });
169
+ it('should render submitForReview button when require aprroval radion button is checked yes', async () => {
170
+ render(<StockOperationForm stockOperationType={receiptOperationTypeMock as any} />);
171
+ // MOVE TO STEP 2
172
+ await userEvent.click(screen.getByRole('button', { name: /Next/i }));
173
+ // MOVE TO STEP3
174
+ await userEvent.click(screen.getByRole('button', { name: /Next/i }));
175
+
176
+ const yesRadioButton = screen.getByRole('radio', { name: /yes/i });
177
+ expect(yesRadioButton).toBeInTheDocument();
178
+ // Submit for review shouldnt be in doc
179
+ expect(screen.queryByRole('button', { name: /submitForReview/i })).not.toBeInTheDocument();
180
+ await userEvent.click(yesRadioButton);
181
+ // On require aprooval should now show
182
+ expect(screen.getByRole('button', { name: /submitForReview/i })).toBeInTheDocument();
183
+ });
184
+ it('should render complete button when require aprroval radion button is checked no', async () => {
185
+ render(<StockOperationForm stockOperationType={receiptOperationTypeMock as any} />);
186
+ // MOVE TO STEP 2
187
+ await userEvent.click(screen.getByRole('button', { name: /Next/i }));
188
+ // MOVE TO STEP3
189
+ await userEvent.click(screen.getByRole('button', { name: /Next/i }));
190
+
191
+ const noRadioButton = screen.getByRole('radio', { name: /no/i });
192
+ expect(noRadioButton).toBeInTheDocument();
193
+ await userEvent.click(noRadioButton);
194
+ // On require aprooval should now show complete btn
195
+ expect(screen.getByRole('button', { name: /complete/i })).toBeInTheDocument();
196
+ });
197
+ it('should render dispatch btn for stock return operation and dont require aproval', async () => {
198
+ render(<StockOperationForm stockOperationType={returnOperationTypeMock as any} />);
199
+ // MOVE TO STEP 2
200
+ await userEvent.click(screen.getByRole('button', { name: /Next/i }));
201
+ // MOVE TO STEP3
202
+ await userEvent.click(screen.getByRole('button', { name: /Next/i }));
203
+
204
+ const noRadioButton = screen.getByRole('radio', { name: /no/i });
205
+ expect(noRadioButton).toBeInTheDocument();
206
+ await userEvent.click(noRadioButton);
207
+ // On require aprooval should now show complete btn
208
+ expect(screen.getByRole('button', { name: /dispatch/i })).toBeInTheDocument();
209
+ });
210
+ it('should render dispatch btn for stock issue operation and dont require aproval', async () => {
211
+ render(<StockOperationForm stockOperationType={stockIssueOperationtypeMock as any} />);
212
+ // MOVE TO STEP 2
213
+ await userEvent.click(screen.getByRole('button', { name: /Next/i }));
214
+ // MOVE TO STEP3
215
+ await userEvent.click(screen.getByRole('button', { name: /Next/i }));
216
+
217
+ const noRadioButton = screen.getByRole('radio', { name: /no/i });
218
+ expect(noRadioButton).toBeInTheDocument();
219
+ await userEvent.click(noRadioButton);
220
+ // On require aprooval should now show complete btn
221
+ expect(screen.getByRole('button', { name: /dispatch/i })).toBeInTheDocument();
222
+ });
223
+ });