@openmrs/esm-stock-management-app 3.0.1-pre.853 → 3.0.1-pre.855

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 (108) hide show
  1. package/.husky/pre-commit +1 -4
  2. package/__mocks__/react-i18next.js +9 -8
  3. package/dist/10.js +1 -1
  4. package/dist/10.js.map +1 -1
  5. package/dist/119.js +1 -1
  6. package/dist/119.js.map +1 -1
  7. package/dist/14.js +1 -1
  8. package/dist/14.js.map +1 -1
  9. package/dist/172.js +1 -1
  10. package/dist/172.js.map +1 -1
  11. package/dist/20.js +1 -1
  12. package/dist/20.js.map +1 -1
  13. package/dist/290.js +1 -1
  14. package/dist/290.js.map +1 -1
  15. package/dist/467.js +1 -1
  16. package/dist/467.js.map +1 -1
  17. package/dist/574.js +1 -1
  18. package/dist/606.js +1 -1
  19. package/dist/606.js.map +1 -1
  20. package/dist/627.js +1 -0
  21. package/dist/627.js.map +1 -0
  22. package/dist/642.js +1 -1
  23. package/dist/642.js.map +1 -1
  24. package/dist/675.js +1 -1
  25. package/dist/675.js.map +1 -1
  26. package/dist/727.js +1 -1
  27. package/dist/727.js.map +1 -1
  28. package/dist/842.js +1 -1
  29. package/dist/842.js.map +1 -1
  30. package/dist/93.js +1 -1
  31. package/dist/93.js.map +1 -1
  32. package/dist/main.js +1 -1
  33. package/dist/main.js.map +1 -1
  34. package/dist/openmrs-esm-stock-management-app.js.buildmanifest.json +70 -70
  35. package/dist/routes.json +1 -1
  36. package/jest.config.js +3 -6
  37. package/package.json +1 -1
  38. package/src/core/components/table/table.component.tsx +2 -2
  39. package/src/index.ts +5 -5
  40. package/src/stock-items/add-bulk-stock-item/add-stock-items-bulk-import-action-button.component.tsx +3 -3
  41. package/src/stock-items/add-bulk-stock-item/{stock-items-bulk-import.modal.tsx → stock-items-bulk-import.component.tsx} +19 -20
  42. package/src/stock-items/add-bulk-stock-item/stock-items-bulk-import.resource.ts +1 -1
  43. package/src/stock-items/add-bulk-stock-item/stock-items-bulk-import.test.tsx +59 -59
  44. package/src/stock-items/add-stock-item/add-stock-action-button.component.tsx +6 -6
  45. package/src/stock-items/add-stock-item/add-stock-item.component.tsx +4 -6
  46. package/src/stock-items/add-stock-item/add-stock-item.scss +0 -5
  47. package/src/stock-items/add-stock-item/add-stock-item.test.tsx +43 -28
  48. package/src/stock-items/add-stock-item/packaging-units/packaging-units-delete-modal.component.tsx +4 -3
  49. package/src/stock-items/add-stock-item/packaging-units/packaging-units.component.tsx +10 -9
  50. package/src/stock-items/add-stock-item/packaging-units/packaging-units.scss +4 -4
  51. package/src/stock-items/add-stock-item/stock-item-details/stock-item-details.component.tsx +19 -27
  52. package/src/stock-items/add-stock-item/stock-item-references/stock-item-references.scss +4 -4
  53. package/src/stock-items/add-stock-item/stock-item-rules/add-stock-rules.component.tsx +9 -15
  54. package/src/stock-items/add-stock-item/stock-item-rules/add-stock-rules.scss +0 -1
  55. package/src/stock-items/add-stock-item/stock-item-rules/delete-stock-rule-modal.component.tsx +1 -2
  56. package/src/stock-items/add-stock-item/stock-item-rules/stock-item-rules.component.tsx +16 -14
  57. package/src/stock-items/add-stock-item/stock-item-rules/stock-item-rules.scss +3 -7
  58. package/src/stock-items/add-stock-item/transactions/printout/transactions-print-bincard-preview.modal.tsx +6 -14
  59. package/src/stock-items/add-stock-item/transactions/printout/transactions-print-stockcard-preview.modal.tsx +8 -14
  60. package/src/stock-items/edit-stock-item/edit-stock-item-action-menu.component.tsx +2 -2
  61. package/src/stock-items/stock-item.utils.tsx +5 -3
  62. package/src/stock-items/stock-items-table.component.tsx +45 -47
  63. package/src/stock-items/stock-items-table.resource.ts +2 -2
  64. package/src/stock-items/stock-items-table.scss +1 -5
  65. package/src/stock-items/stock-items-table.test.tsx +65 -106
  66. package/src/stock-locations/location-admin-form.component.tsx +4 -5
  67. package/src/stock-locations/stock-locations-table.component.tsx +8 -10
  68. package/src/stock-lookups/stock-lookups.resource.ts +2 -3
  69. package/src/stock-operations/stock-operations-dialog/stock-operations-dialog.component.tsx +2 -2
  70. package/src/stock-operations/stock-operations-forms/input-components/batch-no-selector.component.tsx +11 -11
  71. package/src/stock-operations/stock-operations-forms/input-components/batch-no-selector.test.tsx +25 -115
  72. package/src/stock-operations/stock-operations-forms/input-components/qty-uim-selector.test.tsx +65 -107
  73. package/src/stock-operations/stock-operations-forms/input-components/quantity-uom-selector.component.tsx +9 -9
  74. package/src/stock-operations/stock-operations-forms/input-components/stock-operation-reason-selector.test.tsx +153 -35
  75. package/src/stock-operations/stock-operations-forms/input-components/user-selector.test.tsx +29 -82
  76. package/src/stock-operations/stock-operations-forms/step1.test.tsx +69 -204
  77. package/src/stock-operations/stock-operations-forms/step2.test.tsx +63 -140
  78. package/src/stock-operations/stock-operations-forms/step3.test.tsx +60 -79
  79. package/src/stock-operations/stock-operations-forms/steps/stock-operation-items-form-step.component.tsx +5 -6
  80. package/src/stock-operations/stock-operations-forms/steps/stock-operation-submission-form-step.component.tsx +11 -12
  81. package/src/stock-operations/stock-operations-forms/stock-item-form/stock-item-form.scss +0 -1
  82. package/src/stock-operations/stock-operations-forms/stock-item-form/stock-item-form.workspace.tsx +12 -20
  83. package/src/stock-operations/stock-operations-forms/stock-operation-form.scss +0 -1
  84. package/src/stock-operations/stock-operations-forms/stock-operation-stepper/stepper.scss +3 -1
  85. package/src/stock-operations/stock-operations-forms/stock-operation-stepper/stock-operation-stepper.component.tsx +1 -2
  86. package/src/stock-reports/generate-report/create-stock-report.scss +2 -3
  87. package/src/stock-reports/generate-report/create-stock-report.workspace.tsx +25 -32
  88. package/src/stock-reports/report-list/stock-report-parameters.component.tsx +1 -1
  89. package/src/stock-reports/report-list/stock-report-status.component.tsx +1 -1
  90. package/src/stock-reports/report-list/stock-reports.component.tsx +25 -24
  91. package/src/stock-reports/report-list/stock-reports.scss +2 -10
  92. package/src/stock-sources/add-stock-sources/add-stock-sources.scss +4 -11
  93. package/src/stock-sources/add-stock-sources/add-stock-sources.test.tsx +36 -38
  94. package/src/stock-sources/add-stock-sources/add-stock-sources.workspace.tsx +30 -35
  95. package/src/stock-sources/delete-stock-modal.component.tsx +1 -2
  96. package/src/stock-sources/stock-sources-delete/stock-sources-delete.test.tsx +36 -27
  97. package/src/stock-sources/stock-sources-filter/stock-sources-filter.component.tsx +21 -33
  98. package/src/stock-sources/stock-sources-items-table.component.tsx +17 -16
  99. package/src/stock-sources/stock-sources-items-table.resource.ts +6 -8
  100. package/src/stock-sources/stock-sources-items-table.test.tsx +37 -60
  101. package/src/stock-sources/stock-sources.scss +2 -6
  102. package/src/stock-user-role-scopes/add-stock-user-scope/add-stock-user-role-scope.scss +13 -5
  103. package/src/stock-user-role-scopes/add-stock-user-scope/add-stock-user-role-scope.workspace.tsx +2 -2
  104. package/src/stock-user-role-scopes/delete-stock-user-scope-modal.component.tsx +1 -2
  105. package/translations/en.json +6 -5
  106. package/tsconfig.json +0 -4
  107. package/dist/33.js +0 -1
  108. package/dist/33.js.map +0 -1
@@ -1,27 +1,44 @@
1
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, useStockOperations } from '../stock-operations.resource';
6
+ import { StockOperationDTO } from '../../core/api/types/stockOperation/StockOperationDTO';
7
+ import { StockOperationType } from '../../core/api/types/stockOperation/StockOperationType';
8
+ import { closeOverlay } from '../../core/components/overlay/hook';
9
+ import StockOperationForm from './stock-operation-form.component';
10
+ import useParties from './hooks/useParties';
2
11
  import userEvent from '@testing-library/user-event';
3
- import { render, screen } from '@testing-library/react';
4
- import { useFormContext, type UseFormReturn } from 'react-hook-form';
5
- import { useConfig, useSession } from '@openmrs/esm-framework';
6
- import { formatForDatePicker } from '../../constants';
7
- import { receiptOperationTypeMock } from '@mocks';
8
- import { type BaseStockOperationItemFormData } from '../validation-schema';
9
12
  import { type StockItemDTO } from '../../core/api/types/stockItem/StockItem';
13
+ import { useStockItem, useStockItems, useStockBatches } 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 { type BaseStockOperationItemFormData, StockOperationItemFormData } from '../validation-schema';
17
+ import { useStockItemBatchInformationHook } from '../../stock-items/add-stock-item/batch-information/batch-information.resource';
10
18
  import { useFilterableStockItems } from './hooks/useFilterableStockItems';
11
- import { useStockItem } from '../../stock-items/stock-items.resource';
12
- import { useStockOperations } from '../stock-operations.resource';
13
- import { useStockOperationTypes } from '../../stock-lookups/stock-lookups.resource';
14
- import useParties from './hooks/useParties';
15
- import StockOperationForm from './stock-operation-form.component';
19
+ import { formatForDatePicker } from '../../constants';
20
+ import { receiptOperationTypeMock } from '../../../__mocks__';
21
+ jest.mock('react-i18next', () => ({
22
+ useTranslation: jest.fn().mockReturnValue({ t: (key) => key }),
23
+ }));
16
24
 
17
- const mockUseConfig = jest.mocked(useConfig);
18
- const mockUseFilterableStockItems = jest.mocked(useFilterableStockItems);
19
- const mockUseFormContext = jest.mocked(useFormContext);
20
- const mockUseParties = jest.mocked(useParties);
21
- const mockUseSession = jest.mocked(useSession);
22
- const mockUseStockItem = jest.mocked(useStockItem);
23
- const mockUseStockOperations = jest.mocked(useStockOperations);
24
- const mockUseStockOperationTypes = jest.mocked(useStockOperationTypes);
25
+ jest.mock('@openmrs/esm-framework', () => ({
26
+ ActionMenu: jest.fn(() => null),
27
+ showSnackbar: jest.fn(),
28
+ useDebounce: jest.fn((x) => x),
29
+ getGlobalStore: jest.fn(() => ({
30
+ getState: jest.fn(),
31
+ subscribe: jest.fn(),
32
+ setState: jest.fn(),
33
+ })),
34
+ parseDate: jest.fn((date) => new Date(date)),
35
+ showNotification: jest.fn(),
36
+ usePagination: jest.fn(() => ({ currentPage: 1, setPage: jest.fn() })),
37
+ useSession: jest.fn(() => ({ user: { display: 'Test User' } })),
38
+ useConfig: jest.fn(),
39
+ ErrorState: jest.fn(({ error }: { error: any }) => <div>{error}</div>),
40
+ launchWorkspace: jest.fn(),
41
+ }));
25
42
 
26
43
  jest.mock('../../stock-lookups/stock-lookups.resource', () => ({
27
44
  useStockOperationTypes: jest.fn(),
@@ -33,11 +50,7 @@ jest.mock('../stock-operations.resource', () => ({
33
50
  operationStatusColor: jest.fn(() => 'some-color'),
34
51
  getStockOperationLinks: jest.fn(),
35
52
  useStockOperations: jest.fn().mockReturnValue({
36
- items: {
37
- results: [],
38
- links: [],
39
- totalCount: 0,
40
- },
53
+ items: { results: [] },
41
54
  isLoading: false,
42
55
  error: null,
43
56
  }),
@@ -65,7 +78,6 @@ jest.mock('../../stock-items/stock-items.resource', () => ({
65
78
  items: {},
66
79
  }),
67
80
  }));
68
-
69
81
  jest.mock('./hooks/useFilterableStockItems', () => ({
70
82
  useFilterableStockItems: jest.fn().mockReturnValue({
71
83
  stockItemsList: [],
@@ -75,9 +87,7 @@ jest.mock('./hooks/useFilterableStockItems', () => ({
75
87
  isLoading: false,
76
88
  }),
77
89
  }));
78
-
79
90
  jest.mock('./hooks/useParties', () => jest.fn());
80
-
81
91
  jest.mock('react-hook-form', () => ({
82
92
  useForm: jest.fn().mockReturnValue({
83
93
  watch: jest.fn(),
@@ -93,17 +103,6 @@ jest.mock('react-hook-form', () => ({
93
103
  watch: jest.fn(),
94
104
  formState: {
95
105
  errors: {},
96
- isDirty: false,
97
- isLoading: false,
98
- isSubmitted: false,
99
- isSubmitSuccessful: false,
100
- isSubmitting: false,
101
- isValid: true,
102
- isValidating: false,
103
- submitCount: 0,
104
- touchedFields: {},
105
- dirtyFields: {},
106
- disabled: false,
107
106
  },
108
107
  resetField: jest.fn(),
109
108
  getValues: jest.fn(),
@@ -135,71 +134,21 @@ jest.mock('../../stock-items/add-stock-item/batch-information/batch-information.
135
134
 
136
135
  describe('Stock Operation step 2 (stock operation items details)', () => {
137
136
  beforeEach(() => {
138
- const mockStockOperationTypes = {
139
- types: {
140
- results: [],
141
- links: [],
142
- totalCount: 0,
143
- },
144
- isLoading: false,
145
- error: null,
146
- };
147
-
148
- mockUseStockOperationTypes.mockReturnValue(mockStockOperationTypes);
149
-
150
- mockUseStockOperations.mockReturnValue({
151
- items: {
152
- results: [],
153
- links: [],
154
- totalCount: 0,
155
- },
156
- isLoading: false,
157
- error: null,
158
- });
159
-
160
- mockUseConfig.mockReturnValue({ autoPopulateResponsiblePerson: true });
161
-
162
- mockUseParties.mockReturnValue({
137
+ const mockStockOperationTypes = { results: [] };
138
+ (useStockOperationTypes as jest.Mock).mockReturnValue(mockStockOperationTypes);
139
+ (useStockOperations as jest.Mock).mockReturnValue({ items: { results: [] }, isLoading: false, error: null });
140
+ (useConfig as jest.Mock).mockReturnValue({ autoPopulateResponsiblePerson: true });
141
+ (useParties as jest.Mock).mockReturnValue({
163
142
  destinationParties: [],
164
- destinationPartiesFilter: jest.fn(),
165
- destinationTags: [],
166
- error: undefined,
167
- isLoading: false,
168
- mutate: jest.fn(),
169
- parties: [],
170
143
  sourceParties: [],
171
- sourcePartiesFilter: jest.fn(),
144
+ isLoading: false,
145
+ error: undefined,
172
146
  sourceTags: [],
173
- });
174
-
175
- mockUseSession.mockReturnValue({
176
- authenticated: true,
177
- sessionId: 'test-session-id',
178
- user: {
179
- uuid: 'test-user-uuid',
180
- display: 'Test User',
181
- username: 'testuser',
182
- systemId: 'test-system-id',
183
- userProperties: {},
184
- person: { uuid: 'test-person-uuid' },
185
- privileges: [],
186
- roles: [],
187
- retired: false,
188
- links: [],
189
- locale: 'en',
190
- allowedLocales: ['en'],
191
- },
192
- sessionLocation: {
193
- uuid: 'test-location-uuid',
194
- display: 'Test Location',
195
- links: [],
196
- },
147
+ destinationTags: [],
197
148
  });
198
149
  });
199
150
 
200
151
  it('should have both previous and next btns', async () => {
201
- const user = userEvent.setup();
202
-
203
152
  render(
204
153
  <StockOperationForm
205
154
  stockOperationType={receiptOperationTypeMock as any}
@@ -210,15 +159,13 @@ describe('Stock Operation step 2 (stock operation items details)', () => {
210
159
  />,
211
160
  );
212
161
  // MOVE TO STEP 2
213
- await user.click(screen.getByRole('button', { name: /Next/i }));
162
+ await userEvent.click(screen.getByRole('button', { name: /Next/i }));
214
163
 
215
164
  expect(screen.getByRole('button', { name: /Next/i })).toBeInTheDocument();
216
165
  expect(screen.getByTestId('previous-btn')).toBeInTheDocument();
217
166
  });
218
167
 
219
168
  it('should render stock operation items table with item search component', async () => {
220
- const user = userEvent.setup();
221
-
222
169
  render(
223
170
  <StockOperationForm
224
171
  stockOperationType={receiptOperationTypeMock as any}
@@ -228,17 +175,16 @@ describe('Stock Operation step 2 (stock operation items details)', () => {
228
175
  promptBeforeClosing={jest.fn()}
229
176
  />,
230
177
  );
231
-
232
178
  const nextButton = screen.getByRole('button', { name: /Next/i });
233
179
  expect(nextButton).toBeInTheDocument();
234
- await user.click(nextButton);
180
+ await userEvent.click(nextButton);
235
181
  expect(screen.getByRole('table')).toBeInTheDocument();
236
182
  expect(
237
183
  screen.getByRole('searchbox', {
238
184
  name(accessibleName, element) {
239
185
  return (
240
186
  element.getAttribute('id') === 'search-stock-operation-item' &&
241
- element.getAttribute('placeholder') === 'Find your items' &&
187
+ element.getAttribute('placeholder') === 'findItems' &&
242
188
  element.getAttribute('name') === 'search-stock-operation-item'
243
189
  );
244
190
  },
@@ -247,10 +193,8 @@ describe('Stock Operation step 2 (stock operation items details)', () => {
247
193
  });
248
194
 
249
195
  it('should search stock operation item and render results', async () => {
250
- const user = userEvent.setup();
251
-
252
196
  const mocksetSearchString = jest.fn();
253
- mockUseFilterableStockItems.mockReturnValue({
197
+ (useFilterableStockItems as jest.Mock).mockReturnValue({
254
198
  stockItemsList: [
255
199
  { uuid: 'mock-uuid', commonName: 'mock-common-name', drugName: 'mock-common-name' },
256
200
  ] as Array<StockItemDTO>,
@@ -259,7 +203,6 @@ describe('Stock Operation step 2 (stock operation items details)', () => {
259
203
  isLoading: false,
260
204
  setSearchString: mocksetSearchString,
261
205
  });
262
-
263
206
  render(
264
207
  <StockOperationForm
265
208
  stockOperationType={receiptOperationTypeMock as any}
@@ -269,24 +212,21 @@ describe('Stock Operation step 2 (stock operation items details)', () => {
269
212
  promptBeforeClosing={jest.fn()}
270
213
  />,
271
214
  );
272
-
273
215
  // ----- CLICK NEXT TO MOVE TO STEP 2 ---------
274
- await user.click(screen.getByRole('button', { name: /Next/i }));
216
+ await userEvent.click(screen.getByRole('button', { name: /Next/i }));
275
217
  // -------------------------------
276
218
  const searchInput = screen.getByRole('searchbox', {
277
- name: /search/i,
219
+ name: (_, element) => element.getAttribute('id') === 'search-stock-operation-item',
278
220
  });
279
221
  expect(searchInput).toBeInTheDocument();
280
- await user.click(searchInput);
281
- await user.type(searchInput, 'stock');
222
+ await userEvent.click(searchInput);
223
+ await userEvent.type(searchInput, 'stock');
282
224
  expect(mocksetSearchString).toHaveBeenCalledWith('stock');
283
225
  expect(screen.getByText('mock-common-name'));
284
226
  });
285
227
 
286
228
  it('should properly handle stock operation item selection', async () => {
287
- const user = userEvent.setup();
288
-
289
- mockUseFilterableStockItems.mockReturnValue({
229
+ (useFilterableStockItems as jest.Mock).mockReturnValue({
290
230
  stockItemsList: [
291
231
  { uuid: 'mock-uuid', commonName: 'mock-common-name', drugName: 'mock-common-name' },
292
232
  ] as Array<StockItemDTO>,
@@ -295,7 +235,6 @@ describe('Stock Operation step 2 (stock operation items details)', () => {
295
235
  isLoading: false,
296
236
  setSearchString: jest.fn(),
297
237
  });
298
-
299
238
  render(
300
239
  <StockOperationForm
301
240
  stockOperationType={receiptOperationTypeMock as any}
@@ -306,30 +245,27 @@ describe('Stock Operation step 2 (stock operation items details)', () => {
306
245
  />,
307
246
  );
308
247
  // ----- CLICK NEXT TO MOVE TO STEP 2 ---------
309
- await user.click(screen.getByRole('button', { name: /Next/i }));
248
+ await userEvent.click(screen.getByRole('button', { name: /Next/i }));
310
249
  // -------------------------------
311
250
  const searchInput = screen.getByRole('searchbox', {
312
251
  name: (_, element) => element.getAttribute('id') === 'search-stock-operation-item',
313
252
  });
314
- await user.click(searchInput);
315
- await user.type(searchInput, 'stock');
316
- await user.click(screen.getByText('mock-common-name'));
253
+ await userEvent.click(searchInput);
254
+ await userEvent.type(searchInput, 'stock');
255
+ await userEvent.click(screen.getByText('mock-common-name'));
317
256
  // Look for common name at the top of workspace
318
- expect(screen.getByText(/no drug name available|no common name available|mock-common-name/i)).toBeInTheDocument();
257
+ expect(screen.getByText(/noDrugNameAvailable|noCommonNameAvailable|mock-common-name/i)).toBeInTheDocument();
319
258
  });
320
259
 
321
260
  it('should render stock operation items in data table', async () => {
322
- const user = userEvent.setup();
323
-
324
- mockUseStockItem.mockReturnValue({
261
+ (useStockItem as jest.Mock).mockReturnValue({
325
262
  isLoading: false,
326
263
  error: null,
327
264
  item: { commonName: 'mock-stock-item-common name', uuid: 'mock-uuid' } as StockItemDTO,
328
265
  });
329
-
330
266
  const mockQuantity = 99999;
331
267
  const mockExpiration = new Date();
332
- mockUseFormContext.mockReturnValue({
268
+ (useFormContext as jest.Mock).mockReturnValue({
333
269
  watch: jest.fn().mockReturnValue([
334
270
  {
335
271
  quantity: mockQuantity,
@@ -339,23 +275,11 @@ describe('Stock Operation step 2 (stock operation items details)', () => {
339
275
  resetField: jest.fn(),
340
276
  formState: {
341
277
  errors: {},
342
- isDirty: false,
343
- isLoading: false,
344
- isSubmitted: false,
345
- isSubmitSuccessful: false,
346
- isSubmitting: false,
347
- isValid: true,
348
- isValidating: false,
349
- submitCount: 0,
350
- touchedFields: {},
351
- dirtyFields: {},
352
- disabled: false,
353
278
  },
354
279
  getValues: jest.fn(),
355
280
  setValue: jest.fn(),
356
281
  handleSubmit: jest.fn(),
357
- } as unknown as UseFormReturn<BaseStockOperationItemFormData>);
358
-
282
+ });
359
283
  render(
360
284
  <StockOperationForm
361
285
  stockOperationType={receiptOperationTypeMock as any}
@@ -365,9 +289,8 @@ describe('Stock Operation step 2 (stock operation items details)', () => {
365
289
  promptBeforeClosing={jest.fn()}
366
290
  />,
367
291
  );
368
-
369
292
  // ----- CLICK NEXT TO MOVE TO STEP 2 ---------
370
- await user.click(screen.getByRole('button', { name: /Next/i }));
293
+ await userEvent.click(screen.getByRole('button', { name: /Next/i }));
371
294
  // -------------------------------
372
295
  expect(screen.getByText(mockQuantity.toLocaleString())).toBeInTheDocument(); //Find by quentity
373
296
  expect(screen.getByText(formatForDatePicker(mockExpiration))).toBeInTheDocument(); //Find by quentity
@@ -1,18 +1,44 @@
1
- import React from 'react';
2
- import userEvent from '@testing-library/user-event';
3
- import { render, screen } from '@testing-library/react';
4
- import { useConfig, useSession } from '@openmrs/esm-framework';
5
- import { receiptOperationTypeMock, returnOperationTypeMock, stockIssueOperationtypeMock } from '@mocks';
6
- import { useStockOperations } from '../stock-operations.resource';
7
- import { useStockOperationTypes } from '../../stock-lookups/stock-lookups.resource';
8
- import useParties from './hooks/useParties';
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, useStockOperations } from '../stock-operations.resource';
5
+ import { StockOperationDTO } from '../../core/api/types/stockOperation/StockOperationDTO';
6
+ import { StockOperationType } from '../../core/api/types/stockOperation/StockOperationType';
7
+ import { closeOverlay } from '../../core/components/overlay/hook';
9
8
  import StockOperationForm from './stock-operation-form.component';
9
+ import useParties from './hooks/useParties';
10
+ import userEvent from '@testing-library/user-event';
11
+ import { StockItemDTO } from '../../core/api/types/stockItem/StockItem';
12
+ import { useStockItem, useStockItems } from '../../stock-items/stock-items.resource';
13
+ import { initialStockOperationValue } from '../../core/utils/utils';
14
+ import { useForm, useFormContext, Controller, FormProvider } from 'react-hook-form';
15
+ import { BaseStockOperationItemFormData, StockOperationItemFormData } from '../validation-schema';
16
+ import { useStockItemBatchInformationHook } from '../../stock-items/add-stock-item/batch-information/batch-information.resource';
17
+ import { useFilterableStockItems } from './hooks/useFilterableStockItems';
18
+ import { formatForDatePicker } from '../../constants';
19
+ import React from 'react';
20
+ import { receiptOperationTypeMock, returnOperationTypeMock, stockIssueOperationtypeMock } from '../../../__mocks__';
21
+ jest.mock('react-i18next', () => ({
22
+ useTranslation: jest.fn().mockReturnValue({ t: (key) => key }),
23
+ }));
10
24
 
11
- const mockUseParties = jest.mocked(useParties);
12
- const mockUseStockOperationTypes = jest.mocked(useStockOperationTypes);
13
- const mockUseStockOperations = jest.mocked(useStockOperations);
14
- const mockUseConfig = jest.mocked(useConfig);
15
- const mockUseSession = jest.mocked(useSession);
25
+ jest.mock('@openmrs/esm-framework', () => ({
26
+ ActionMenu: jest.fn(() => null),
27
+ showSnackbar: jest.fn(),
28
+ useDebounce: jest.fn((x) => x),
29
+ getGlobalStore: jest.fn(() => ({
30
+ getState: jest.fn(),
31
+ subscribe: jest.fn(),
32
+ setState: jest.fn(),
33
+ })),
34
+ parseDate: jest.fn((date) => new Date(date)),
35
+ showNotification: jest.fn(),
36
+ usePagination: jest.fn(() => ({ currentPage: 1, setPage: jest.fn() })),
37
+ useSession: jest.fn(() => ({ user: { display: 'Test User' } })),
38
+ useConfig: jest.fn(),
39
+ ErrorState: jest.fn(({ error }: { error: any }) => <div>{error}</div>),
40
+ launchWorkspace: jest.fn(),
41
+ }));
16
42
 
17
43
  jest.mock('../../stock-lookups/stock-lookups.resource', () => ({
18
44
  useStockOperationTypes: jest.fn(),
@@ -52,7 +78,6 @@ jest.mock('../../stock-items/stock-items.resource', () => ({
52
78
  items: {},
53
79
  }),
54
80
  }));
55
-
56
81
  jest.mock('./hooks/useFilterableStockItems', () => ({
57
82
  useFilterableStockItems: jest.fn().mockReturnValue({
58
83
  stockItemsList: [],
@@ -62,9 +87,7 @@ jest.mock('./hooks/useFilterableStockItems', () => ({
62
87
  isLoading: false,
63
88
  }),
64
89
  }));
65
-
66
90
  jest.mock('./hooks/useParties', () => jest.fn());
67
-
68
91
  jest.mock('react-hook-form', () => ({
69
92
  useForm: jest.fn().mockReturnValue({
70
93
  watch: jest.fn(),
@@ -111,55 +134,17 @@ jest.mock('../../stock-items/add-stock-item/batch-information/batch-information.
111
134
 
112
135
  describe('Stock Operation form step 3 (stock submision)', () => {
113
136
  beforeEach(() => {
114
- mockUseStockOperationTypes.mockReturnValue({
115
- types: { results: [], links: [], totalCount: 0 },
116
- isLoading: false,
117
- error: null,
118
- });
119
-
120
- mockUseStockOperations.mockReturnValue({
121
- items: { results: [], links: [], totalCount: 0 },
122
- isLoading: false,
123
- error: null,
124
- });
125
-
126
- mockUseConfig.mockReturnValue({ autoPopulateResponsiblePerson: true });
127
-
128
- mockUseParties.mockReturnValue({
137
+ const mockStockOperationTypes = { results: [] };
138
+ (useStockOperationTypes as jest.Mock).mockReturnValue(mockStockOperationTypes);
139
+ (useStockOperations as jest.Mock).mockReturnValue({ items: { results: [] }, isLoading: false, error: null });
140
+ (useConfig as jest.Mock).mockReturnValue({ autoPopulateResponsiblePerson: true });
141
+ (useParties as jest.Mock).mockReturnValue({
129
142
  destinationParties: [],
130
143
  sourceParties: [],
131
144
  isLoading: false,
132
145
  error: undefined,
133
146
  sourceTags: [],
134
147
  destinationTags: [],
135
- parties: [],
136
- mutate: jest.fn(),
137
- sourcePartiesFilter: () => true,
138
- destinationPartiesFilter: () => true,
139
- });
140
-
141
- mockUseSession.mockReturnValue({
142
- authenticated: true,
143
- sessionId: 'test-session-id',
144
- user: {
145
- uuid: 'test-user-uuid',
146
- display: 'Test User',
147
- username: 'testuser',
148
- systemId: 'test-system-id',
149
- userProperties: {},
150
- person: { uuid: 'test-person-uuid' },
151
- privileges: [],
152
- roles: [],
153
- retired: false,
154
- links: [],
155
- locale: 'en',
156
- allowedLocales: ['en'],
157
- },
158
- sessionLocation: {
159
- uuid: 'test-location-uuid',
160
- display: 'Test Location',
161
- links: [],
162
- },
163
148
  });
164
149
  });
165
150
 
@@ -174,11 +159,11 @@ describe('Stock Operation form step 3 (stock submision)', () => {
174
159
  />,
175
160
  );
176
161
  // MOVE TO STEP 2
177
- await userEvent.click(screen.getByRole('button', { name: /next/i }));
162
+ await userEvent.click(screen.getByRole('button', { name: /Next/i }));
178
163
  // MOVE TO STEP3
179
- await userEvent.click(screen.getByRole('button', { name: /next/i }));
164
+ await userEvent.click(screen.getByRole('button', { name: /Next/i }));
180
165
 
181
- expect(screen.queryByRole('button', { name: /next/i })).not.toBeInTheDocument();
166
+ expect(screen.queryByRole('button', { name: /Next/i })).not.toBeInTheDocument();
182
167
  expect(screen.getByTestId('previous-btn')).toBeInTheDocument();
183
168
  });
184
169
 
@@ -193,15 +178,14 @@ describe('Stock Operation form step 3 (stock submision)', () => {
193
178
  />,
194
179
  );
195
180
  // MOVE TO STEP 2
196
- await userEvent.click(screen.getByRole('button', { name: /next/i }));
181
+ await userEvent.click(screen.getByRole('button', { name: /Next/i }));
197
182
  // MOVE TO STEP3
198
- await userEvent.click(screen.getByRole('button', { name: /next/i }));
183
+ await userEvent.click(screen.getByRole('button', { name: /Next/i }));
199
184
 
200
185
  // Shouls have save button
201
186
  expect(screen.getByRole('button', { name: /save/i })).toBeInTheDocument();
202
187
  expect(screen.getAllByRole('radio', { name: /yes|no/i })).toHaveLength(2);
203
188
  });
204
-
205
189
  it('should render submitForReview button when require aprroval radion button is checked yes', async () => {
206
190
  render(
207
191
  <StockOperationForm
@@ -213,19 +197,18 @@ describe('Stock Operation form step 3 (stock submision)', () => {
213
197
  />,
214
198
  );
215
199
  // MOVE TO STEP 2
216
- await userEvent.click(screen.getByRole('button', { name: /next/i }));
200
+ await userEvent.click(screen.getByRole('button', { name: /Next/i }));
217
201
  // MOVE TO STEP3
218
- await userEvent.click(screen.getByRole('button', { name: /next/i }));
202
+ await userEvent.click(screen.getByRole('button', { name: /Next/i }));
219
203
 
220
204
  const yesRadioButton = screen.getByRole('radio', { name: /yes/i });
221
205
  expect(yesRadioButton).toBeInTheDocument();
222
206
  // Submit for review shouldnt be in doc
223
- expect(screen.queryByRole('button', { name: /submit for review/i })).not.toBeInTheDocument();
207
+ expect(screen.queryByRole('button', { name: /submitForReview/i })).not.toBeInTheDocument();
224
208
  await userEvent.click(yesRadioButton);
225
209
  // On require aprooval should now show
226
- expect(screen.getByRole('button', { name: /submit for review/i })).toBeInTheDocument();
210
+ expect(screen.getByRole('button', { name: /submitForReview/i })).toBeInTheDocument();
227
211
  });
228
-
229
212
  it('should render complete button when require aprroval radion button is checked no', async () => {
230
213
  render(
231
214
  <StockOperationForm
@@ -237,9 +220,9 @@ describe('Stock Operation form step 3 (stock submision)', () => {
237
220
  />,
238
221
  );
239
222
  // MOVE TO STEP 2
240
- await userEvent.click(screen.getByRole('button', { name: /next/i }));
223
+ await userEvent.click(screen.getByRole('button', { name: /Next/i }));
241
224
  // MOVE TO STEP3
242
- await userEvent.click(screen.getByRole('button', { name: /next/i }));
225
+ await userEvent.click(screen.getByRole('button', { name: /Next/i }));
243
226
 
244
227
  const noRadioButton = screen.getByRole('radio', { name: /no/i });
245
228
  expect(noRadioButton).toBeInTheDocument();
@@ -247,7 +230,6 @@ describe('Stock Operation form step 3 (stock submision)', () => {
247
230
  // On require aprooval should now show complete btn
248
231
  expect(screen.getByTestId('complete-button')).toBeInTheDocument();
249
232
  });
250
-
251
233
  it('should render dispatch btn for stock return operation and dont require aproval', async () => {
252
234
  render(
253
235
  <StockOperationForm
@@ -259,9 +241,9 @@ describe('Stock Operation form step 3 (stock submision)', () => {
259
241
  />,
260
242
  );
261
243
  // MOVE TO STEP 2
262
- await userEvent.click(screen.getByRole('button', { name: /next/i }));
244
+ await userEvent.click(screen.getByRole('button', { name: /Next/i }));
263
245
  // MOVE TO STEP3
264
- await userEvent.click(screen.getByRole('button', { name: /next/i }));
246
+ await userEvent.click(screen.getByRole('button', { name: /Next/i }));
265
247
 
266
248
  const noRadioButton = screen.getByRole('radio', { name: /no/i });
267
249
  expect(noRadioButton).toBeInTheDocument();
@@ -269,7 +251,6 @@ describe('Stock Operation form step 3 (stock submision)', () => {
269
251
  // On require aprooval should now show complete btn
270
252
  expect(screen.getByTestId('dipatch-button')).toBeInTheDocument();
271
253
  });
272
-
273
254
  it('should render dispatch btn for stock issue operation and dont require aproval', async () => {
274
255
  render(
275
256
  <StockOperationForm
@@ -281,14 +262,14 @@ describe('Stock Operation form step 3 (stock submision)', () => {
281
262
  />,
282
263
  );
283
264
  // MOVE TO STEP 2
284
- await userEvent.click(screen.getByRole('button', { name: /next/i }));
265
+ await userEvent.click(screen.getByRole('button', { name: /Next/i }));
285
266
  // MOVE TO STEP3
286
- await userEvent.click(screen.getByRole('button', { name: /next/i }));
267
+ await userEvent.click(screen.getByRole('button', { name: /Next/i }));
287
268
 
288
269
  const noRadioButton = screen.getByRole('radio', { name: /no/i });
289
270
  expect(noRadioButton).toBeInTheDocument();
290
271
  await userEvent.click(noRadioButton);
291
- // On require approval should now show complete btn
272
+ // On require aprooval should now show complete btn
292
273
  expect(screen.getByTestId('dipatch-button')).toBeInTheDocument();
293
274
  });
294
275
  });
@@ -1,5 +1,3 @@
1
- import React, { useCallback, useId, useMemo } from 'react';
2
- import { ArrowLeft, ArrowRight, Edit, TrashCan } from '@carbon/react/icons';
3
1
  import {
4
2
  Button,
5
3
  DataTable,
@@ -11,6 +9,8 @@ import {
11
9
  TableHeader,
12
10
  TableRow,
13
11
  } from '@carbon/react';
12
+ import { ArrowLeft, ArrowRight, Edit, TrashCan } from '@carbon/react/icons';
13
+ import React, { useCallback, useMemo } from 'react';
14
14
  import { useFormContext } from 'react-hook-form';
15
15
  import { useTranslation } from 'react-i18next';
16
16
  import { type StockOperationDTO } from '../../../core/api/types/stockOperation/StockOperationDTO';
@@ -42,7 +42,6 @@ const StockOperationItemsFormStep: React.FC<StockOperationItemsFormStepProps> =
42
42
  }) => {
43
43
  const { t } = useTranslation();
44
44
  const operationTypePermision = useOperationTypePermisions(stockOperationType);
45
- const uniqueId = useId();
46
45
 
47
46
  const form = useFormContext<StockOperationItemDtoSchema>();
48
47
  const observableOperationItems = form.watch('stockOperationItems');
@@ -112,7 +111,7 @@ const StockOperationItemsFormStep: React.FC<StockOperationItemsFormStepProps> =
112
111
  );
113
112
 
114
113
  const tableRows = useMemo(() => {
115
- return observableOperationItems?.map((item, index) => {
114
+ return observableOperationItems?.map((item) => {
116
115
  const {
117
116
  batchNo,
118
117
  expiration,
@@ -125,7 +124,7 @@ const StockOperationItemsFormStep: React.FC<StockOperationItemsFormStepProps> =
125
124
  } = item;
126
125
 
127
126
  return {
128
- id: uuid || `${uniqueId}-${index}`,
127
+ id: uuid,
129
128
  item: stockItemUuid ? <StockOperationItemCell stockItemUuid={stockItemUuid} /> : '--',
130
129
  itemDetails: stockItemUuid ? <StockAvailability stockItemUuid={stockItemUuid} /> : '--',
131
130
  batch: (
@@ -179,7 +178,7 @@ const StockOperationItemsFormStep: React.FC<StockOperationItemsFormStepProps> =
179
178
  ),
180
179
  };
181
180
  });
182
- }, [observableOperationItems, onLaunchItemsForm, stockOperationType, uniqueId]);
181
+ }, [observableOperationItems, onLaunchItemsForm, stockOperationType]);
183
182
 
184
183
  const headerTitle = t('stockoperationItems', 'Stock operation items');
185
184