diff --git a/CHANGELOG.md b/CHANGELOG.md index c098476c..39f3a8df 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ * Fund distribution can be saved with a "blank" expense class. Refs UISACQCOMP-156. * *BREAKING* Update `react` to `v18`. Refs UISACQCOMP-157. * Update `Node.js` to `v18` in GitHub Actions. Refs UISACQCOMP-158. +* A user can not save edited PO line when budget without expense class was selected. Refs UISACQCOMP-159. ## [4.0.2](https://github.com/folio-org/stripes-acq-components/tree/v4.0.2) (2023-03-17) [Full Changelog](https://github.com/folio-org/stripes-acq-components/compare/v4.0.1...v4.0.2) diff --git a/lib/FundDistribution/FundDistributionFields/FundDistributionFieldsFinal.js b/lib/FundDistribution/FundDistributionFields/FundDistributionFieldsFinal.js index 16c79794..50a24101 100644 --- a/lib/FundDistribution/FundDistributionFields/FundDistributionFieldsFinal.js +++ b/lib/FundDistribution/FundDistributionFields/FundDistributionFieldsFinal.js @@ -135,7 +135,8 @@ const FundDistributionFieldsFinal = ({ onSelectFund(elem, selectedFundId); }; - const { fundId, expenseClassId } = fields.value[index]; + const { fundId, expenseClassId, value: fieldValue } = fields.value[index]; + const expenseClassesForSelect = expenseClassesByFundId[fundId]?.map(expenseClass => ({ label: expenseClass.name, value: expenseClass.id, @@ -162,7 +163,7 @@ const FundDistributionFieldsFinal = ({ } return ( - + debouncedValidate(fields.value)} + beforeSubmit={() => (required ? Boolean(fundId) : true)} /> @@ -188,7 +189,7 @@ const FundDistributionFieldsFinal = ({ isNonInteractive={disabled} validateFields={[]} key={expenseClassId} - beforeSubmit={() => Boolean(expenseClassId)} + beforeSubmit={() => (required ? Boolean(expenseClassId) : true)} /> )} @@ -205,6 +206,7 @@ const FundDistributionFieldsFinal = ({ validate={required ? validateRequired : undefined} isNonInteractive={disabled} validateFields={[name]} + beforeSubmit={() => (required ? Boolean(fieldValue) : true)} /> @@ -233,7 +235,6 @@ const FundDistributionFieldsFinal = ({ amounts, currency, disabled, - debouncedValidate, expenseClassesByFundId, funds, fundsForSelect, diff --git a/lib/FundDistribution/FundDistributionFields/FundDistributionFieldsFinal.test.js b/lib/FundDistribution/FundDistributionFields/FundDistributionFieldsFinal.test.js index 66267b7c..665350bb 100644 --- a/lib/FundDistribution/FundDistributionFields/FundDistributionFieldsFinal.test.js +++ b/lib/FundDistribution/FundDistributionFields/FundDistributionFieldsFinal.test.js @@ -142,7 +142,7 @@ describe('FundDistributionFieldsFinal', () => { expect(validateFundDistributionTotalDefault).toHaveBeenCalled(); }); - it('should call validateRequired onBlur fundDistribution selection', async () => { + it('should call validateRequired for fundId selection', async () => { const expenseClassesByFundId = { [FUNDS[0].id]: [{ id: 'expClassId', name: 'expClassName' }] }; const fundDistribution = [{ code: FUNDS[0].code, @@ -167,13 +167,17 @@ describe('FundDistributionFieldsFinal', () => { expect(validation).toHaveBeenCalled(); }); - it('should call beforeSubmit validation on submit form', async () => { + it.each` + required + ${true} + ${false} + `('should call beforeSubmit validation with required = $required for expanseClass field on submit form', async ({ required }) => { const expenseClassesByFundId = { [FUNDS[1].id]: [{ id: 'expClassId', name: 'expClassName 1' }, { id: 'expClassId', name: 'expClassName 2' }], }; const fundDistribution = [{ code: 'TEST', fundId: '2', value: 100, distributionType: FUND_DISTR_TYPE.percent }]; - renderComponent({ required: true, fundDistribution, expenseClassesByFundId }); + renderComponent({ required, fundDistribution, expenseClassesByFundId }); const valueInput = await screen.findByText('stripes-acq-components.fundDistribution.expenseClass'); expect(valueInput).toBeInTheDocument(); @@ -181,7 +185,37 @@ describe('FundDistributionFieldsFinal', () => { user.tab(); user.click(screen.getByText('Submit')); - expect(screen.getByText('error message')).toBeInTheDocument(); + if (required) { + expect(screen.getByText('error message')).toBeInTheDocument(); + } else { + expect(screen.queryByText('error message')).not.toBeInTheDocument(); + } + }); + + it.each` + required + ${true} + ${false} + `('should call beforeSubmit validation with required = $required for value field on submit form', async ({ required }) => { + const expenseClassesByFundId = { + [FUNDS[1].id]: [{ id: 'expClassId', name: 'expClassName 1' }, { id: 'expClassId', name: 'expClassName 2' }], + }; + const fundDistribution = [{ code: 'TEST', fundId: '2', value: null, distributionType: FUND_DISTR_TYPE.percent }]; + + renderComponent({ required, fundDistribution, expenseClassesByFundId }); + const valueInput = await screen.findByText('stripes-acq-components.fundDistribution.value'); + + expect(valueInput).toBeInTheDocument(); + user.type(valueInput, '0'); + user.tab(); + + user.click(screen.getByText('Submit')); + + if (required) { + expect(screen.getByText('error message')).toBeInTheDocument(); + } else { + expect(screen.queryByText('error message')).not.toBeInTheDocument(); + } }); it('should call \'handleValidationErrorResponse\' when validator rejected with an error', async () => {