From b60462727ad06d285f93d9c83f4f1f6b8d576168 Mon Sep 17 00:00:00 2001 From: Alisher Musurmonov Date: Wed, 18 Sep 2024 10:49:02 +0500 Subject: [PATCH 1/9] UISACQCOMP-218: add "Amount must be a positive number" validation for "Set exchange rate" field. --- CHANGELOG.md | 1 + .../CurrencyExchangeRateFields.js | 12 ++++++++++-- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d60b190a..9b7f55cc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,6 +22,7 @@ * Support using custom list of tenants when open the locations modal. Refs UISACQCOMP-210. * ECS - Display all consortium tenants in the affiliation selection of the location lookup. Refs UISACQCOMP-202. * ECS - Add `isLoading` prop for `ConsortiumFieldInventory` component. Refs UISACQCOMP-215. +* Add "Amount must be a positive number" validation for "Set exchange rate" field. Refs UISACQCOMP-218. ## [5.1.2](https://github.com/folio-org/stripes-acq-components/tree/v5.1.2) (2024-09-13) [Full Changelog](https://github.com/folio-org/stripes-acq-components/compare/v5.1.1...v5.1.2) diff --git a/lib/CurrencyExchangeRateFields/CurrencyExchangeRateFields.js b/lib/CurrencyExchangeRateFields/CurrencyExchangeRateFields.js index 3ea28920..f2e1ea06 100644 --- a/lib/CurrencyExchangeRateFields/CurrencyExchangeRateFields.js +++ b/lib/CurrencyExchangeRateFields/CurrencyExchangeRateFields.js @@ -28,7 +28,7 @@ import { } from '../VisibilityControl'; import CurrentExchangeRate from './CurrentExchangeRate'; import { FILED_NAMES } from './constants'; -import { validateRequired } from '../utils'; +import { validateRequired, validateRequiredPositiveAmount } from '../utils'; const CurrencyExchangeRateFields = ({ currencyFieldName, @@ -65,6 +65,14 @@ const CurrencyExchangeRateFields = ({ resetExchangeRate(); }, [change, resetExchangeRate, currencyFieldName]); + const validateExchangeRate = (value) => { + if (value === undefined || value === null) { + return validateRequired(value); + } + + return validateRequiredPositiveAmount(value); + }; + const systemCurrency = stripes.currency; const filledCurrency = get(values, currencyFieldName); const isSetUseExangeRateDisabled = isUseExangeRateDisabled || @@ -146,7 +154,7 @@ const CurrencyExchangeRateFields = ({ readOnly={!isExchangeRateEnabled} tooltipText={tooltipTextExchangeRate} required={isExchangeRateRequired} - validate={isExchangeRateRequired ? validateRequired : undefined} + validate={isExchangeRateRequired ? validateExchangeRate : undefined} key={isExchangeRateRequired ? 1 : 0} isNonInteractive={isSetExchangeRateNonIntaractive ?? isNonInteractive} /> From 731b753e8ccd9526213241cd4159b3222df55e31 Mon Sep 17 00:00:00 2001 From: Alisher Musurmonov Date: Wed, 18 Sep 2024 20:11:28 +0500 Subject: [PATCH 2/9] test: fix failing tests --- lib/AcqUnitFilter/AcqUnitFilter.test.js | 5 +++-- .../AffiliationsSelection.test.js | 5 ++++- .../ConsortiumFieldInventory.test.js | 6 ++++++ lib/CountryFilter/CountryFilter.test.js | 15 +++++--------- .../FieldCurrency/FieldCurrency.test.js | 2 ++ .../CurrencyExchangeRateFields.test.js | 1 + lib/DynamicSelection/DynamicSelection.test.js | 8 +++++--- .../DynamicSelectionFilter.test.js | 4 ++-- lib/FieldHolding/FieldHolding.test.js | 7 ++++++- lib/FieldLocation/FieldLocationFinal.test.js | 5 +++++ .../FieldLocationFinalContainer.test.js | 9 +++++++++ lib/FindLocation/FindLocationLookup.test.js | 1 + .../FundDistributionFieldsFinal.test.js | 2 ++ lib/FundFilter/FundFilter.test.js | 7 ++++--- lib/LanguageFilter/LanguageFilter.test.js | 20 ++++++------------- .../MaterialTypeFilterContainer.test.js | 1 + 16 files changed, 62 insertions(+), 36 deletions(-) diff --git a/lib/AcqUnitFilter/AcqUnitFilter.test.js b/lib/AcqUnitFilter/AcqUnitFilter.test.js index 1284ebb0..3aa0b477 100644 --- a/lib/AcqUnitFilter/AcqUnitFilter.test.js +++ b/lib/AcqUnitFilter/AcqUnitFilter.test.js @@ -1,6 +1,6 @@ -import React from 'react'; -import { render, cleanup } from '@testing-library/react'; import { noop } from 'lodash'; +import { render, cleanup, screen } from '@testing-library/react'; +import user from '@testing-library/user-event'; import AcqUnitFilter from './AcqUnitFilter'; @@ -25,6 +25,7 @@ describe('AcqUnitFilter component', () => { it('should render all passed options', async () => { const { findAllByText } = renderAcqUnitFilter(acqUnitsRecords); + user.click(screen.getByText('stripes-components.selection.controlLabel')); const renderedFilterOptions = await findAllByText(/Unit #[0-9]/); expect(renderedFilterOptions.length).toBe(acqUnitsRecords.length); diff --git a/lib/AffiliationsSelection/AffiliationsSelection.test.js b/lib/AffiliationsSelection/AffiliationsSelection.test.js index e83da191..ddc8da37 100644 --- a/lib/AffiliationsSelection/AffiliationsSelection.test.js +++ b/lib/AffiliationsSelection/AffiliationsSelection.test.js @@ -1,7 +1,9 @@ import { render, + screen, within, } from '@testing-library/react'; +import user from '@testing-library/user-event'; import { affiliations } from '../../test/jest/fixtures'; import { AffiliationsSelection } from './AffiliationsSelection'; @@ -25,13 +27,14 @@ const renderAffiliationsSelection = (props = {}) => render( ); describe('AffiliationsSelection', () => { - it('should render affiliation selection with provided options', () => { + it('should render affiliation selection with provided options', async () => { renderAffiliationsSelection(); expect( within(document.getElementById('test-affiliations-select')) .getByText(affiliations[2].tenantName), ).toBeInTheDocument(); + await user.click(screen.getByText('stripes-components.selection.controlLabel')); affiliations.forEach(({ tenantName, isPrimary }) => { expect( within(document.getElementById('sl-container-test-affiliations-select')) diff --git a/lib/ConsortiumFieldInventory/ConsortiumFieldInventory.test.js b/lib/ConsortiumFieldInventory/ConsortiumFieldInventory.test.js index 33fbc315..c8bc4e9e 100644 --- a/lib/ConsortiumFieldInventory/ConsortiumFieldInventory.test.js +++ b/lib/ConsortiumFieldInventory/ConsortiumFieldInventory.test.js @@ -59,6 +59,12 @@ describe('ConsortiumFieldInventory', () => { renderConsortiumFieldInventory({ onAffiliationChange }); + const button = screen.getAllByText('stripes-components.selection.controlLabel'); + + expect(button[0]).toBeInTheDocument(); + + await userEvent.click(button[0]); + await screen.findByText(tenants[1].name); await userEvent.click(screen.getByText(tenants[1].name)); expect(onAffiliationChange).toHaveBeenCalled(); diff --git a/lib/CountryFilter/CountryFilter.test.js b/lib/CountryFilter/CountryFilter.test.js index bfc065df..e2f42df1 100644 --- a/lib/CountryFilter/CountryFilter.test.js +++ b/lib/CountryFilter/CountryFilter.test.js @@ -1,6 +1,6 @@ -import React from 'react'; -import { render, cleanup, fireEvent } from '@testing-library/react'; import { noop } from 'lodash'; +import { render, cleanup } from '@testing-library/react'; +import user from '@testing-library/user-event'; import CountryFilter from './CountryFilter'; @@ -27,15 +27,10 @@ describe('CountryFilter component', () => { it('should invoke onChange callback when something is selected', async () => { const onChangeFilter = jest.fn(); - const { container, getByText } = renderFilter(false, onChangeFilter); - const afgOption = getByText('AF'); - const button = container.querySelector('[id="org-filter-country-selection"]'); + const { getByText, findByText } = renderFilter(false, onChangeFilter); - expect(button).toBeEnabled(); - expect(onChangeFilter).not.toHaveBeenCalled(); - - fireEvent.click(button); - fireEvent.click(afgOption); + await user.click(getByText('stripes-components.selection.controlLabel')); + await user.click(await findByText('AF')); expect(onChangeFilter).toHaveBeenCalled(); }); diff --git a/lib/Currency/FieldCurrency/FieldCurrency.test.js b/lib/Currency/FieldCurrency/FieldCurrency.test.js index 62ddde09..0bd109a5 100644 --- a/lib/Currency/FieldCurrency/FieldCurrency.test.js +++ b/lib/Currency/FieldCurrency/FieldCurrency.test.js @@ -43,6 +43,8 @@ describe('FieldCurrency', () => { const onChange = jest.fn(); renderComponent({ onChange }); + + user.click(screen.getByText('stripes-components.selection.controlLabel')); user.click(screen.getByText('USD (USD)')); expect(onChange).toHaveBeenCalled(); }); diff --git a/lib/CurrencyExchangeRateFields/CurrencyExchangeRateFields.test.js b/lib/CurrencyExchangeRateFields/CurrencyExchangeRateFields.test.js index 097a74a2..356752d7 100644 --- a/lib/CurrencyExchangeRateFields/CurrencyExchangeRateFields.test.js +++ b/lib/CurrencyExchangeRateFields/CurrencyExchangeRateFields.test.js @@ -39,6 +39,7 @@ describe('CurrencyExchangeRateFields', () => { renderComponent({ onSubmit }); + user.click(screen.getByText('stripes-components.selection.controlLabel')); user.click(screen.getByText('BYN (BYN)')); user.click(screen.getByTestId('use-set-exhange-rate')); user.type(screen.getByTestId('exchange-rate'), '2.66'); diff --git a/lib/DynamicSelection/DynamicSelection.test.js b/lib/DynamicSelection/DynamicSelection.test.js index 6e9b21d4..a01a14ee 100644 --- a/lib/DynamicSelection/DynamicSelection.test.js +++ b/lib/DynamicSelection/DynamicSelection.test.js @@ -47,9 +47,10 @@ describe('DynamicSelection', () => { const input = screen.getByLabelText('stripes-components.selection.filterOptionsLabel', { selector: 'input' }); await act(async () => { - user.type(input, '1'); + await user.type(input, '1'); jest.advanceTimersByTime(1500); }); + await user.click(screen.getByText('stripes-components.selection.controlLabel')); expect(kyMock.get).toHaveBeenCalledWith(ORDERS_API, expect.objectContaining({})); }); @@ -60,11 +61,12 @@ describe('DynamicSelection', () => { const input = screen.getByLabelText('stripes-components.selection.filterOptionsLabel', { selector: 'input' }); await act(async () => { - user.type(input, '1'); + await user.type(input, '1'); jest.advanceTimersByTime(1500); }); + await user.click(screen.getByText('stripes-components.selection.controlLabel')); - user.click(screen.getByText(/11111/)); + user.click(screen.getByText(/1111/)); expect(defaultProps.onChange).toHaveBeenCalled(); }); diff --git a/lib/DynamicSelectionFilter/DynamicSelectionFilter.test.js b/lib/DynamicSelectionFilter/DynamicSelectionFilter.test.js index aa196566..94049423 100644 --- a/lib/DynamicSelectionFilter/DynamicSelectionFilter.test.js +++ b/lib/DynamicSelectionFilter/DynamicSelectionFilter.test.js @@ -59,10 +59,10 @@ describe('DynamicSelectionFilter', () => { const input = screen.getByLabelText('stripes-components.selection.filterOptionsLabel', { selector: 'input' }); await act(async () => { - user.type(input, '1'); + await user.type(input, '1'); jest.advanceTimersByTime(1500); }); - + await user.click(screen.getByText('stripes-components.selection.controlLabel')); user.click(screen.getByText(/11111/)); expect(defaultProps.onChange).toHaveBeenCalled(); diff --git a/lib/FieldHolding/FieldHolding.test.js b/lib/FieldHolding/FieldHolding.test.js index 7455fca7..de5d56e7 100644 --- a/lib/FieldHolding/FieldHolding.test.js +++ b/lib/FieldHolding/FieldHolding.test.js @@ -1,5 +1,6 @@ -import { render, screen, within } from '@testing-library/react'; import keyBy from 'lodash/keyBy'; +import { render, screen, within } from '@testing-library/react'; +import user from '@testing-library/user-event'; import { Form } from 'react-final-form'; import { useInstanceHoldings } from '../hooks'; @@ -60,6 +61,10 @@ describe('FieldHolding component', () => { it('should render holding options', async () => { const { findAllByText } = renderFieldHolding({}); + const button = screen.getByText('stripes-components.selection.controlLabel'); + + await user.click(button); + const renderedHoldingOptions = await findAllByText(/Location #[0-9]/); expect(renderedHoldingOptions.length).toBe(locations.length); diff --git a/lib/FieldLocation/FieldLocationFinal.test.js b/lib/FieldLocation/FieldLocationFinal.test.js index ca8b7b3b..f8e8d524 100644 --- a/lib/FieldLocation/FieldLocationFinal.test.js +++ b/lib/FieldLocation/FieldLocationFinal.test.js @@ -1,4 +1,5 @@ import { render, cleanup, screen } from '@testing-library/react'; +import user from '@testing-library/user-event'; import { Form } from 'react-final-form'; import FieldLocationFinal from './FieldLocationFinal'; @@ -44,6 +45,10 @@ describe('FieldLocationFinal component', () => { it('should render all passed options', async () => { renderFieldLocationFinal(); + const button = screen.getByText('stripes-components.selection.controlLabel'); + + await user.click(button); + const renderedLocationOptions = await screen.findAllByText(/Location #[0-9]/); expect(renderedLocationOptions.length).toBe(locationOptions.length); diff --git a/lib/FieldLocation/FieldLocationFinalContainer.test.js b/lib/FieldLocation/FieldLocationFinalContainer.test.js index e24e89ec..62097935 100644 --- a/lib/FieldLocation/FieldLocationFinalContainer.test.js +++ b/lib/FieldLocation/FieldLocationFinalContainer.test.js @@ -1,4 +1,5 @@ import { render, screen } from '@testing-library/react'; +import user from '@testing-library/user-event'; import { Form } from 'react-final-form'; import FieldLocationFinalContainer from './FieldLocationFinalContainer'; @@ -32,6 +33,14 @@ const renderFieldLocationFinalContainer = (props = {}, formProps = {}) => (rende )); describe('FieldLocationFinalContainer component', () => { + beforeEach(async () => { + renderFieldLocationFinalContainer(); + + const button = screen.getByText('stripes-components.selection.controlLabel'); + + await user.click(button); + }); + it('should display passed label', () => { renderFieldLocationFinalContainer({ labelId: 'Location' }); diff --git a/lib/FindLocation/FindLocationLookup.test.js b/lib/FindLocation/FindLocationLookup.test.js index 979a0614..23b5a938 100644 --- a/lib/FindLocation/FindLocationLookup.test.js +++ b/lib/FindLocation/FindLocationLookup.test.js @@ -177,6 +177,7 @@ describe('FindLocationLookup', () => { const affiliationSelection = await screen.findByText('affiliationsLabel'); + await user.click(screen.getByText('stripes-components.selection.controlLabel')); expect(affiliationSelection).toBeInTheDocument(); await user.click(screen.getByText(mockTenants[1].name)); diff --git a/lib/FundDistribution/FundDistributionFields/FundDistributionFieldsFinal.test.js b/lib/FundDistribution/FundDistributionFields/FundDistributionFieldsFinal.test.js index 12f93657..b1e3c021 100644 --- a/lib/FundDistribution/FundDistributionFields/FundDistributionFieldsFinal.test.js +++ b/lib/FundDistribution/FundDistributionFields/FundDistributionFieldsFinal.test.js @@ -82,6 +82,7 @@ describe('FundDistributionFieldsFinal', () => { renderComponent({ onSelectFund }); user.click(screen.getByText('stripes-acq-components.fundDistribution.addBtn')); + user.click(screen.getByText('stripes-components.selection.controlLabel')); user.click(screen.getByText('african (AFRICAHIST)')); expect(onSelectFund).toHaveBeenCalledWith('fund-distribution[0]', '1'); @@ -243,6 +244,7 @@ describe('FundDistributionFieldsFinal', () => { const { container } = renderComponent({}); user.click(screen.getByText('stripes-acq-components.fundDistribution.addBtn')); + user.click(screen.getByText('stripes-components.selection.controlLabel')); user.click(screen.getByText('african (AFRICAHIST)')); const removeBtn = container.querySelector('.repeatableFieldRemoveItem button'); diff --git a/lib/FundFilter/FundFilter.test.js b/lib/FundFilter/FundFilter.test.js index 2ce359f5..b16c1a61 100644 --- a/lib/FundFilter/FundFilter.test.js +++ b/lib/FundFilter/FundFilter.test.js @@ -1,7 +1,7 @@ -import React from 'react'; -import { render } from '@testing-library/react'; -import { IntlProvider } from 'react-intl'; import { noop } from 'lodash'; +import { render, screen } from '@testing-library/react'; +import user from '@testing-library/user-event'; +import { IntlProvider } from 'react-intl'; import FundFilter from './FundFilter'; @@ -49,6 +49,7 @@ describe('FundFilter component', () => { it('should render all passed options', async () => { const { findAllByText } = renderFundFilter(fundRecords); + user.click(screen.getByText('stripes-components.selection.controlLabel')); const renderedFilterOptions = await findAllByText(/Fund #[0-9]/); expect(renderedFilterOptions.length).toBe(fundRecords.length); diff --git a/lib/LanguageFilter/LanguageFilter.test.js b/lib/LanguageFilter/LanguageFilter.test.js index 21ba4777..fca6084e 100644 --- a/lib/LanguageFilter/LanguageFilter.test.js +++ b/lib/LanguageFilter/LanguageFilter.test.js @@ -1,6 +1,6 @@ -import React from 'react'; -import { render, cleanup, fireEvent } from '@testing-library/react'; import { noop } from 'lodash'; +import { render, screen, waitFor } from '@testing-library/react'; +import user from '@testing-library/user-event'; import LanguageFilter from './LanguageFilter'; @@ -17,8 +17,6 @@ const renderFilter = (disabled = false, onChange = noop) => (render( )); describe('LanguageFilter component', () => { - afterEach(cleanup); - it('should display passed title', () => { const { getByText } = renderFilter(); @@ -27,16 +25,10 @@ describe('LanguageFilter component', () => { it('should invoke onChange callback when something is selected', async () => { const onChangeFilter = jest.fn(); - const { container, getByText } = renderFilter(false, onChangeFilter); - const option = getByText('Abkhazian'); - const button = container.querySelector('[id="org-filter-language-selection"]'); - - expect(button).toBeEnabled(); - expect(onChangeFilter).not.toHaveBeenCalled(); - - fireEvent.click(button); - fireEvent.click(option); + const { findByText } = renderFilter(false, onChangeFilter); - expect(onChangeFilter).toHaveBeenCalled(); + await user.click(screen.getByText('stripes-components.selection.controlLabel')); + await user.click(await findByText('Zulu')); + await waitFor(() => expect(onChangeFilter).toHaveBeenCalled()); }); }); diff --git a/lib/MaterialTypeFilter/MaterialTypeFilterContainer.test.js b/lib/MaterialTypeFilter/MaterialTypeFilterContainer.test.js index e32d387b..fde4d0e4 100644 --- a/lib/MaterialTypeFilter/MaterialTypeFilterContainer.test.js +++ b/lib/MaterialTypeFilter/MaterialTypeFilterContainer.test.js @@ -44,6 +44,7 @@ describe('MaterialTypeFilterContainer', () => { it('should call onChange', async () => { renderComponent({ activeFilter: '1' }); + await user.click(screen.getByText('stripes-components.selection.controlLabel')); await user.click(screen.getByText('type 1')); expect(defaultProps.onChange).toHaveBeenCalled(); From e6c31bbe7c9ca5851427aecc8852e74e19524de5 Mon Sep 17 00:00:00 2001 From: Alisher Musurmonov Date: Thu, 19 Sep 2024 11:17:32 +0500 Subject: [PATCH 3/9] test: add test case --- .../CurrencyExchangeRateFields.js | 4 ++-- .../CurrencyExchangeRateFields.test.js | 23 ++++++++++++++++++- 2 files changed, 24 insertions(+), 3 deletions(-) diff --git a/lib/CurrencyExchangeRateFields/CurrencyExchangeRateFields.js b/lib/CurrencyExchangeRateFields/CurrencyExchangeRateFields.js index f2e1ea06..a106f97d 100644 --- a/lib/CurrencyExchangeRateFields/CurrencyExchangeRateFields.js +++ b/lib/CurrencyExchangeRateFields/CurrencyExchangeRateFields.js @@ -126,9 +126,9 @@ const CurrencyExchangeRateFields = ({ } onChange={enableExchangeRate} vertical diff --git a/lib/CurrencyExchangeRateFields/CurrencyExchangeRateFields.test.js b/lib/CurrencyExchangeRateFields/CurrencyExchangeRateFields.test.js index 356752d7..02fdee32 100644 --- a/lib/CurrencyExchangeRateFields/CurrencyExchangeRateFields.test.js +++ b/lib/CurrencyExchangeRateFields/CurrencyExchangeRateFields.test.js @@ -9,6 +9,7 @@ import { MemoryRouter } from 'react-router-dom'; import { Button } from '@folio/stripes/components'; import stripesFinalForm from '@folio/stripes/final-form'; +import CurrentExchangeRate from './CurrentExchangeRate'; import CurrencyExchangeRateFields from './CurrencyExchangeRateFields'; jest.mock('./CurrentExchangeRate', () => { @@ -34,6 +35,26 @@ const renderComponent = (props = {}) => (render( )); describe('CurrencyExchangeRateFields', () => { + it('should display validation messages', async () => { + const onSubmit = jest.fn(); + + renderComponent({ onSubmit }); + + await user.click(screen.getByText('stripes-components.selection.controlLabel')); + await user.click(screen.getByText('BYN (BYN)')); + await user.click(screen.getByTestId('use-set-exchange-rate')); + + await waitFor(() => expect(screen.getByTestId('use-set-exchange-rate')).toBeChecked()); + + CurrentExchangeRate.mock.calls[0][0].setExchangeRateRequired(true); + await user.click(screen.getByText('Save')); + + await waitFor(() => expect(screen.getByText('stripes-acq-components.validation.required')).toBeInTheDocument()); + await user.type(screen.getByTestId('exchange-rate'), '-1'); + + await waitFor(() => expect(screen.getByText('stripes-acq-components.validation.shouldBePositiveAmount')).toBeInTheDocument()); + }); + it('should pass user input to API', async () => { const onSubmit = jest.fn(); @@ -41,7 +62,7 @@ describe('CurrencyExchangeRateFields', () => { user.click(screen.getByText('stripes-components.selection.controlLabel')); user.click(screen.getByText('BYN (BYN)')); - user.click(screen.getByTestId('use-set-exhange-rate')); + user.click(screen.getByTestId('use-set-exchange-rate')); user.type(screen.getByTestId('exchange-rate'), '2.66'); user.click(screen.getByText('Save')); From bfcf51818bf344f0273c8cdefbc6be16c7fd89d6 Mon Sep 17 00:00:00 2001 From: Alisher Musurmonov Date: Thu, 19 Sep 2024 11:46:51 +0500 Subject: [PATCH 4/9] test: fix failing test --- lib/DeleteHoldingsModal/DeleteHoldingsModal.test.js | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/lib/DeleteHoldingsModal/DeleteHoldingsModal.test.js b/lib/DeleteHoldingsModal/DeleteHoldingsModal.test.js index 18abb429..c64e8632 100644 --- a/lib/DeleteHoldingsModal/DeleteHoldingsModal.test.js +++ b/lib/DeleteHoldingsModal/DeleteHoldingsModal.test.js @@ -46,11 +46,9 @@ describe('DeleteHoldingsModal', () => { it('should call onConfirm when \'Delete holdings\' btn was clicked', async () => { renderDeleteHoldingsModal(); - const deleteBtn = await screen.findByRole('button', { - name: 'stripes-acq-components.holdings.deleteModal.heading', - }); + const button = screen.getAllByText('stripes-acq-components.holdings.deleteModal.heading'); - user.click(deleteBtn); + user.click(button[1]); expect(defaultProps.onConfirm).toHaveBeenCalled(); }); }); From c34d15ff089b6b9e07a59a6a73a3df966a4ee463 Mon Sep 17 00:00:00 2001 From: Alisher Musurmonov Date: Fri, 20 Sep 2024 23:42:21 +0500 Subject: [PATCH 5/9] test: fix failing tests --- lib/AcqUnitFilter/AcqUnitFilter.test.js | 6 ++---- .../AffiliationsSelection.test.js | 4 +--- lib/CountryFilter/CountryFilter.test.js | 5 ++--- lib/DeleteHoldingsModal/DeleteHoldingsModal.test.js | 2 +- lib/DynamicSelection/DynamicSelection.test.js | 2 +- lib/FieldHolding/FieldHolding.test.js | 12 ++++++------ .../FieldLocationFinalContainer.test.js | 4 ---- lib/FindLocation/FindLocationLookup.test.js | 1 - lib/FundFilter/FundFilter.test.js | 2 -- lib/LanguageFilter/LanguageFilter.test.js | 12 ++++++------ 10 files changed, 19 insertions(+), 31 deletions(-) diff --git a/lib/AcqUnitFilter/AcqUnitFilter.test.js b/lib/AcqUnitFilter/AcqUnitFilter.test.js index f53dd90e..b73c4047 100644 --- a/lib/AcqUnitFilter/AcqUnitFilter.test.js +++ b/lib/AcqUnitFilter/AcqUnitFilter.test.js @@ -1,6 +1,5 @@ import { noop } from 'lodash'; -import { render, cleanup } from '@testing-library/react'; -import user from '@testing-library/user-event'; +import { fireEvent, render, cleanup } from '@testing-library/react'; import AcqUnitFilter from './AcqUnitFilter'; @@ -25,9 +24,8 @@ describe('AcqUnitFilter component', () => { it('should render all passed options', async () => { const { findAllByText, getByText } = renderAcqUnitFilter(acqUnitsRecords); - await fireEvent.click(getByText('stripes-components.selection.controlLabel')); + fireEvent.click(getByText('stripes-components.selection.controlLabel')); - user.click(getByText('stripes-components.selection.controlLabel')); const renderedFilterOptions = await findAllByText(/Unit #[0-9]/); expect(renderedFilterOptions.length).toBe(acqUnitsRecords.length); diff --git a/lib/AffiliationsSelection/AffiliationsSelection.test.js b/lib/AffiliationsSelection/AffiliationsSelection.test.js index 7e6b6666..3318f3ce 100644 --- a/lib/AffiliationsSelection/AffiliationsSelection.test.js +++ b/lib/AffiliationsSelection/AffiliationsSelection.test.js @@ -1,9 +1,7 @@ import { render, - screen, within, } from '@testing-library/react'; -import user from '@testing-library/user-event'; import { affiliations } from '../../test/jest/fixtures'; import { AffiliationsSelection } from './AffiliationsSelection'; @@ -45,7 +43,7 @@ describe('AffiliationsSelection', () => { within(document.getElementById('test-affiliations-select')) .getByText(affiliations[2].tenantName), ).toBeInTheDocument(); - await user.click(screen.getByText('stripes-components.selection.controlLabel')); + affiliations.forEach(({ tenantName, isPrimary }) => { expect( within(document.getElementById('test-affiliations-select')) diff --git a/lib/CountryFilter/CountryFilter.test.js b/lib/CountryFilter/CountryFilter.test.js index ae5aeed1..c42d2455 100644 --- a/lib/CountryFilter/CountryFilter.test.js +++ b/lib/CountryFilter/CountryFilter.test.js @@ -1,6 +1,5 @@ import { noop } from 'lodash'; -import { render, cleanup } from '@testing-library/react'; -import user from '@testing-library/user-event'; +import { fireEvent, render, cleanup } from '@testing-library/react'; import CountryFilter from './CountryFilter'; @@ -25,7 +24,7 @@ describe('CountryFilter component', () => { expect(getByText('ui-organizations.filterConfig.country')).toBeDefined(); }); - it('should invoke onChange callback when something is selected', async () => { + it('should invoke onChange callback when something is selected', () => { const onChangeFilter = jest.fn(); const { container, getByText } = renderFilter(false, onChangeFilter); const button = container.querySelector('[id="org-filter-country-selection"]'); diff --git a/lib/DeleteHoldingsModal/DeleteHoldingsModal.test.js b/lib/DeleteHoldingsModal/DeleteHoldingsModal.test.js index d780227d..7cd09440 100644 --- a/lib/DeleteHoldingsModal/DeleteHoldingsModal.test.js +++ b/lib/DeleteHoldingsModal/DeleteHoldingsModal.test.js @@ -51,7 +51,7 @@ describe('DeleteHoldingsModal', () => { hidden: true, }); - user.click(button[1]); + user.click(deleteBtn); expect(defaultProps.onConfirm).toHaveBeenCalled(); }); }); diff --git a/lib/DynamicSelection/DynamicSelection.test.js b/lib/DynamicSelection/DynamicSelection.test.js index 23c307e4..fffe5f1f 100644 --- a/lib/DynamicSelection/DynamicSelection.test.js +++ b/lib/DynamicSelection/DynamicSelection.test.js @@ -64,7 +64,7 @@ describe('DynamicSelection', () => { await user.type(input, '1'); jest.advanceTimersByTime(1500); }); - + user.click(screen.getByText('stripes-components.selection.controlLabel')); user.click(screen.getByText(/11111/)); diff --git a/lib/FieldHolding/FieldHolding.test.js b/lib/FieldHolding/FieldHolding.test.js index 6d91fbbd..9299e4d2 100644 --- a/lib/FieldHolding/FieldHolding.test.js +++ b/lib/FieldHolding/FieldHolding.test.js @@ -1,6 +1,10 @@ import keyBy from 'lodash/keyBy'; -import { fireEvent, render, screen, within } from '@testing-library/react'; -import user from '@testing-library/user-event'; +import { + fireEvent, + render, + screen, + within, +} from '@testing-library/react'; import { Form } from 'react-final-form'; import { useInstanceHoldings } from '../hooks'; @@ -63,10 +67,6 @@ describe('FieldHolding component', () => { fireEvent.click(getByText('stripes-components.selection.controlLabel')); - const button = screen.getByText('stripes-components.selection.controlLabel'); - - await user.click(button); - const renderedHoldingOptions = await findAllByText(/Location #[0-9]/); expect(renderedHoldingOptions.length).toBe(locations.length); diff --git a/lib/FieldLocation/FieldLocationFinalContainer.test.js b/lib/FieldLocation/FieldLocationFinalContainer.test.js index 2633217e..725add2d 100644 --- a/lib/FieldLocation/FieldLocationFinalContainer.test.js +++ b/lib/FieldLocation/FieldLocationFinalContainer.test.js @@ -49,8 +49,6 @@ describe('FieldLocationFinalContainer component', () => { it('should render options based on passed locationIds', async () => { renderFieldLocationFinalContainer(); - fireEvent.click(screen.getByText('stripes-components.selection.controlLabel')); - const renderedLocationOptions = await screen.findAllByText(/Location #[0-9]/); expect(renderedLocationOptions.length).toBe(locationsIds.length); @@ -61,8 +59,6 @@ describe('FieldLocationFinalContainer component', () => { filterLocations: (records) => records.slice(0, 2), }); - fireEvent.click(screen.getByText('stripes-components.selection.controlLabel')); - const renderedLocationOptions = await screen.findAllByText(/Location #[0-9]/); expect(renderedLocationOptions).toHaveLength(2); diff --git a/lib/FindLocation/FindLocationLookup.test.js b/lib/FindLocation/FindLocationLookup.test.js index 0aedd23a..bfb24009 100644 --- a/lib/FindLocation/FindLocationLookup.test.js +++ b/lib/FindLocation/FindLocationLookup.test.js @@ -177,7 +177,6 @@ describe('FindLocationLookup', () => { const affiliationSelection = await screen.findByText('affiliationsLabel'); - await user.click(screen.getByText('stripes-components.selection.controlLabel')); expect(affiliationSelection).toBeInTheDocument(); await user.click(screen.getByText('stripes-components.selection.controlLabel')); diff --git a/lib/FundFilter/FundFilter.test.js b/lib/FundFilter/FundFilter.test.js index 00b5a895..d7bd2f77 100644 --- a/lib/FundFilter/FundFilter.test.js +++ b/lib/FundFilter/FundFilter.test.js @@ -1,6 +1,5 @@ import { noop } from 'lodash'; import { fireEvent, render } from '@testing-library/react'; -import user from '@testing-library/user-event'; import { IntlProvider } from 'react-intl'; import FundFilter from './FundFilter'; @@ -51,7 +50,6 @@ describe('FundFilter component', () => { fireEvent.click(getByText('stripes-components.selection.controlLabel')); - fireEvent.click(getByText('stripes-components.selection.controlLabel')); const renderedFilterOptions = await findAllByText(/Fund #[0-9]/); expect(renderedFilterOptions.length).toBe(fundRecords.length); diff --git a/lib/LanguageFilter/LanguageFilter.test.js b/lib/LanguageFilter/LanguageFilter.test.js index b2e074ff..adf6ff6b 100644 --- a/lib/LanguageFilter/LanguageFilter.test.js +++ b/lib/LanguageFilter/LanguageFilter.test.js @@ -1,6 +1,9 @@ +import { + cleanup, + fireEvent, + render, +} from '@testing-library/react'; import { noop } from 'lodash'; -import { render, screen, waitFor } from '@testing-library/react'; -import user from '@testing-library/user-event'; import LanguageFilter from './LanguageFilter'; @@ -25,7 +28,6 @@ describe('LanguageFilter component', () => { it('should invoke onChange callback when something is selected', async () => { const onChangeFilter = jest.fn(); - const { container, getByText } = renderFilter(false, onChangeFilter); const button = container.querySelector('[id="org-filter-language-selection"]'); @@ -38,8 +40,6 @@ describe('LanguageFilter component', () => { fireEvent.click(option); - await user.click(screen.getByText('stripes-components.selection.controlLabel')); - await user.click(await findByText('Zulu')); - await waitFor(() => expect(onChangeFilter).toHaveBeenCalled()); + expect(onChangeFilter).toHaveBeenCalled(); }); }); From 972efe26b4938ef32df4e375a3dad80e14a2fb83 Mon Sep 17 00:00:00 2001 From: Alisher Musurmonov Date: Wed, 25 Sep 2024 10:20:07 +0500 Subject: [PATCH 6/9] refactor: fix code quality based on comments --- .../AffiliationsSelection.test.js | 2 +- .../FieldLocationFinalContainer.test.js | 16 ++++++++++------ lib/LanguageFilter/LanguageFilter.test.js | 1 - 3 files changed, 11 insertions(+), 8 deletions(-) diff --git a/lib/AffiliationsSelection/AffiliationsSelection.test.js b/lib/AffiliationsSelection/AffiliationsSelection.test.js index 3318f3ce..e2175546 100644 --- a/lib/AffiliationsSelection/AffiliationsSelection.test.js +++ b/lib/AffiliationsSelection/AffiliationsSelection.test.js @@ -36,7 +36,7 @@ const renderAffiliationsSelection = (props = {}) => render( ); describe('AffiliationsSelection', () => { - it('should render affiliation selection with provided options', async () => { + it('should render affiliation selection with provided options', () => { renderAffiliationsSelection(); expect( diff --git a/lib/FieldLocation/FieldLocationFinalContainer.test.js b/lib/FieldLocation/FieldLocationFinalContainer.test.js index 725add2d..3b80b458 100644 --- a/lib/FieldLocation/FieldLocationFinalContainer.test.js +++ b/lib/FieldLocation/FieldLocationFinalContainer.test.js @@ -32,16 +32,12 @@ const renderFieldLocationFinalContainer = (props = {}, formProps = {}) => (rende )); describe('FieldLocationFinalContainer component', () => { - beforeEach(() => { - renderFieldLocationFinalContainer(); + it('should display passed label', () => { + renderFieldLocationFinalContainer({ labelId: 'Location' }); const button = screen.getByText('stripes-components.selection.controlLabel'); fireEvent.click(button); - }); - - it('should display passed label', () => { - renderFieldLocationFinalContainer({ labelId: 'Location' }); expect(screen.getByText(fieldLocationLabel)).toBeDefined(); }); @@ -49,6 +45,10 @@ describe('FieldLocationFinalContainer component', () => { it('should render options based on passed locationIds', async () => { renderFieldLocationFinalContainer(); + const button = screen.getByText('stripes-components.selection.controlLabel'); + + fireEvent.click(button); + const renderedLocationOptions = await screen.findAllByText(/Location #[0-9]/); expect(renderedLocationOptions.length).toBe(locationsIds.length); @@ -59,6 +59,10 @@ describe('FieldLocationFinalContainer component', () => { filterLocations: (records) => records.slice(0, 2), }); + const button = screen.getByText('stripes-components.selection.controlLabel'); + + fireEvent.click(button); + const renderedLocationOptions = await screen.findAllByText(/Location #[0-9]/); expect(renderedLocationOptions).toHaveLength(2); diff --git a/lib/LanguageFilter/LanguageFilter.test.js b/lib/LanguageFilter/LanguageFilter.test.js index adf6ff6b..a9f3acfb 100644 --- a/lib/LanguageFilter/LanguageFilter.test.js +++ b/lib/LanguageFilter/LanguageFilter.test.js @@ -1,5 +1,4 @@ import { - cleanup, fireEvent, render, } from '@testing-library/react'; From 0b7cce560d30e927c52f4834597c3018159d8dec Mon Sep 17 00:00:00 2001 From: Alisher Musurmonov Date: Thu, 26 Sep 2024 13:42:47 +0500 Subject: [PATCH 7/9] remove required message --- .../CurrencyExchangeRateFields.js | 16 ++++------------ .../CurrencyExchangeRateFields.test.js | 9 +++------ 2 files changed, 7 insertions(+), 18 deletions(-) diff --git a/lib/CurrencyExchangeRateFields/CurrencyExchangeRateFields.js b/lib/CurrencyExchangeRateFields/CurrencyExchangeRateFields.js index a106f97d..da83fff8 100644 --- a/lib/CurrencyExchangeRateFields/CurrencyExchangeRateFields.js +++ b/lib/CurrencyExchangeRateFields/CurrencyExchangeRateFields.js @@ -19,16 +19,16 @@ import { Row, } from '@folio/stripes/components'; +import { FILED_NAMES } from './constants'; import { FieldCurrency } from '../Currency'; +import CurrentExchangeRate from './CurrentExchangeRate'; import { TextField } from '../Fields'; import { TooltippedControl } from '../TooltippedControl'; import { IfFieldVisible, VisibilityControl, } from '../VisibilityControl'; -import CurrentExchangeRate from './CurrentExchangeRate'; -import { FILED_NAMES } from './constants'; -import { validateRequired, validateRequiredPositiveAmount } from '../utils'; +import { validateRequiredPositiveAmount } from '../utils'; const CurrencyExchangeRateFields = ({ currencyFieldName, @@ -65,14 +65,6 @@ const CurrencyExchangeRateFields = ({ resetExchangeRate(); }, [change, resetExchangeRate, currencyFieldName]); - const validateExchangeRate = (value) => { - if (value === undefined || value === null) { - return validateRequired(value); - } - - return validateRequiredPositiveAmount(value); - }; - const systemCurrency = stripes.currency; const filledCurrency = get(values, currencyFieldName); const isSetUseExangeRateDisabled = isUseExangeRateDisabled || @@ -154,7 +146,7 @@ const CurrencyExchangeRateFields = ({ readOnly={!isExchangeRateEnabled} tooltipText={tooltipTextExchangeRate} required={isExchangeRateRequired} - validate={isExchangeRateRequired ? validateExchangeRate : undefined} + validate={isExchangeRateRequired ? validateRequiredPositiveAmount : undefined} key={isExchangeRateRequired ? 1 : 0} isNonInteractive={isSetExchangeRateNonIntaractive ?? isNonInteractive} /> diff --git a/lib/CurrencyExchangeRateFields/CurrencyExchangeRateFields.test.js b/lib/CurrencyExchangeRateFields/CurrencyExchangeRateFields.test.js index 02fdee32..043681a8 100644 --- a/lib/CurrencyExchangeRateFields/CurrencyExchangeRateFields.test.js +++ b/lib/CurrencyExchangeRateFields/CurrencyExchangeRateFields.test.js @@ -28,11 +28,11 @@ const renderForm = ({ handleSubmit }) => ( const FormCmpt = stripesFinalForm({})(renderForm); -const renderComponent = (props = {}) => (render( +const renderComponent = (props = {}) => render( { }} initialValues={{}} {...props} /> , -)); +); describe('CurrencyExchangeRateFields', () => { it('should display validation messages', async () => { @@ -47,11 +47,8 @@ describe('CurrencyExchangeRateFields', () => { await waitFor(() => expect(screen.getByTestId('use-set-exchange-rate')).toBeChecked()); CurrentExchangeRate.mock.calls[0][0].setExchangeRateRequired(true); - await user.click(screen.getByText('Save')); - - await waitFor(() => expect(screen.getByText('stripes-acq-components.validation.required')).toBeInTheDocument()); await user.type(screen.getByTestId('exchange-rate'), '-1'); - + await user.click(screen.getByText('Save')); await waitFor(() => expect(screen.getByText('stripes-acq-components.validation.shouldBePositiveAmount')).toBeInTheDocument()); }); From c787856cbaa48b661c8397a2081d9304523fefa3 Mon Sep 17 00:00:00 2001 From: Alisher Musurmonov Date: Fri, 27 Sep 2024 19:37:22 +0500 Subject: [PATCH 8/9] add not required positive amount validation --- .../CurrencyExchangeRateFields.js | 7 +- lib/utils/validateRequired.js | 8 ++ lib/utils/validateRequired.test.js | 107 ++++++++++-------- 3 files changed, 72 insertions(+), 50 deletions(-) diff --git a/lib/CurrencyExchangeRateFields/CurrencyExchangeRateFields.js b/lib/CurrencyExchangeRateFields/CurrencyExchangeRateFields.js index da83fff8..a5f94f68 100644 --- a/lib/CurrencyExchangeRateFields/CurrencyExchangeRateFields.js +++ b/lib/CurrencyExchangeRateFields/CurrencyExchangeRateFields.js @@ -28,7 +28,10 @@ import { IfFieldVisible, VisibilityControl, } from '../VisibilityControl'; -import { validateRequiredPositiveAmount } from '../utils'; +import { + validatePositiveAmount, + validateRequiredPositiveAmount, +} from '../utils'; const CurrencyExchangeRateFields = ({ currencyFieldName, @@ -146,7 +149,7 @@ const CurrencyExchangeRateFields = ({ readOnly={!isExchangeRateEnabled} tooltipText={tooltipTextExchangeRate} required={isExchangeRateRequired} - validate={isExchangeRateRequired ? validateRequiredPositiveAmount : undefined} + validate={isExchangeRateRequired ? validateRequiredPositiveAmount : validatePositiveAmount} key={isExchangeRateRequired ? 1 : 0} isNonInteractive={isSetExchangeRateNonIntaractive ?? isNonInteractive} /> diff --git a/lib/utils/validateRequired.js b/lib/utils/validateRequired.js index cf6693ca..a48de82f 100644 --- a/lib/utils/validateRequired.js +++ b/lib/utils/validateRequired.js @@ -36,6 +36,14 @@ export function validateRequiredPositiveAmount(value) { : ; } +export function validatePositiveAmount(value) { + if (value !== '' || value === undefined || value === null) return undefined; + + return value > 0 + ? undefined + : ; +} + export const validateRequiredMinNumber = ({ minNumber, value }) => { return value >= minNumber ? undefined diff --git a/lib/utils/validateRequired.test.js b/lib/utils/validateRequired.test.js index 07a1184f..63e7046f 100644 --- a/lib/utils/validateRequired.test.js +++ b/lib/utils/validateRequired.test.js @@ -1,5 +1,6 @@ import { validateNoSpaces, + validatePositiveAmount, validateRequired, validateRequiredMaxNumber, validateRequiredMinNumber, @@ -8,58 +9,68 @@ import { validateRequiredPositiveAmount, } from './validateRequired'; -test('validateNoSpaces', () => { - expect(validateNoSpaces('some code')).toBeTruthy(); - expect(validateNoSpaces('some_code')).toBe(undefined); -}); +describe('validateRequired', () => { + it('validateNoSpaces', () => { + expect(validateNoSpaces('some code')).toBeTruthy(); + expect(validateNoSpaces('some_code')).toBe(undefined); + }); -test('validateRequired', () => { - expect(validateRequired('')).toBeTruthy(); - expect(validateRequired(null)).toBeTruthy(); - expect(validateRequired(undefined)).toBeTruthy(); - expect(validateRequired('some value')).toBe(undefined); -}); + it('validateRequired', () => { + expect(validateRequired('')).toBeTruthy(); + expect(validateRequired(null)).toBeTruthy(); + expect(validateRequired(undefined)).toBeTruthy(); + expect(validateRequired('some value')).toBe(undefined); + }); -test('validateRequiredNotNegative', () => { - expect(validateRequiredNotNegative('')).toBeTruthy(); - expect(validateRequiredNotNegative(null)).toBeTruthy(); - expect(validateRequiredNotNegative(undefined)).toBeTruthy(); - expect(validateRequiredNotNegative(-1)).toBeTruthy(); - expect(validateRequiredNotNegative(0)).toBe(undefined); - expect(validateRequiredNotNegative('0')).toBe(undefined); - expect(validateRequiredNotNegative(1)).toBe(undefined); - expect(validateRequiredNotNegative('some value')).toBeTruthy(); -}); + it('validateRequiredNotNegative', () => { + expect(validateRequiredNotNegative('')).toBeTruthy(); + expect(validateRequiredNotNegative(null)).toBeTruthy(); + expect(validateRequiredNotNegative(undefined)).toBeTruthy(); + expect(validateRequiredNotNegative(-1)).toBeTruthy(); + expect(validateRequiredNotNegative(0)).toBe(undefined); + expect(validateRequiredNotNegative('0')).toBe(undefined); + expect(validateRequiredNotNegative(1)).toBe(undefined); + expect(validateRequiredNotNegative('some value')).toBeTruthy(); + }); -test('validateRequiredNumber', () => { - expect(validateRequiredNumber('')).toBeTruthy(); - expect(validateRequiredNumber(null)).toBeTruthy(); - expect(validateRequiredNumber(undefined)).toBeTruthy(); - expect(validateRequiredNumber(-1)).toBe(undefined); - expect(validateRequiredNumber(0)).toBe(undefined); - expect(validateRequiredNumber(1)).toBe(undefined); - expect(validateRequiredNumber('some value')).toBeTruthy(); -}); + it('validateRequiredNumber', () => { + expect(validateRequiredNumber('')).toBeTruthy(); + expect(validateRequiredNumber(null)).toBeTruthy(); + expect(validateRequiredNumber(undefined)).toBeTruthy(); + expect(validateRequiredNumber(-1)).toBe(undefined); + expect(validateRequiredNumber(0)).toBe(undefined); + expect(validateRequiredNumber(1)).toBe(undefined); + expect(validateRequiredNumber('some value')).toBeTruthy(); + }); -test('validateRequiredPositiveAmount', () => { - expect(validateRequiredPositiveAmount('')).toBeTruthy(); - expect(validateRequiredPositiveAmount(null)).toBeTruthy(); - expect(validateRequiredPositiveAmount(undefined)).toBeTruthy(); - expect(validateRequiredPositiveAmount(-1)).toBeTruthy(); - expect(validateRequiredPositiveAmount(0)).toBeTruthy(); - expect(validateRequiredPositiveAmount(0.1)).toBe(undefined); - expect(validateRequiredPositiveAmount(1)).toBe(undefined); - expect(validateRequiredPositiveAmount('some value')).toBeTruthy(); -}); + it('validateRequiredPositiveAmount', () => { + expect(validateRequiredPositiveAmount('')).toBeTruthy(); + expect(validateRequiredPositiveAmount(null)).toBeTruthy(); + expect(validateRequiredPositiveAmount(undefined)).toBeTruthy(); + expect(validateRequiredPositiveAmount(-1)).toBeTruthy(); + expect(validateRequiredPositiveAmount(0)).toBeTruthy(); + expect(validateRequiredPositiveAmount(0.1)).toBe(undefined); + expect(validateRequiredPositiveAmount(1)).toBe(undefined); + expect(validateRequiredPositiveAmount('some value')).toBeTruthy(); + }); -test('validateRequiredMinNumber', () => { - expect(validateRequiredMinNumber({ minNumber: 1, value: 0 })).toBeTruthy(); - expect(validateRequiredMinNumber({ minNumber: 1, value: 1 })).toBe(undefined); - expect(validateRequiredMinNumber({ minNumber: 1, value: 2 })).toBe(undefined); -}); + it('validateRequiredMinNumber', () => { + expect(validateRequiredMinNumber({ minNumber: 1, value: 0 })).toBeTruthy(); + expect(validateRequiredMinNumber({ minNumber: 1, value: 1 })).toBe(undefined); + expect(validateRequiredMinNumber({ minNumber: 1, value: 2 })).toBe(undefined); + }); + + it('validateRequiredMaxNumber', () => { + expect(validateRequiredMaxNumber({ maxNumber: 1, value: 0 })).toBe(undefined); + expect(validateRequiredMaxNumber({ maxNumber: 1, value: 1 })).toBe(undefined); + expect(validateRequiredMaxNumber({ maxNumber: 1, value: 2 })).toBeTruthy(); + }); -test('validateRequiredMaxNumber', () => { - expect(validateRequiredMaxNumber({ maxNumber: 1, value: 0 })).toBe(undefined); - expect(validateRequiredMaxNumber({ maxNumber: 1, value: 1 })).toBe(undefined); - expect(validateRequiredMaxNumber({ maxNumber: 1, value: 2 })).toBeTruthy(); + it('validatePositiveAmount', () => { + expect(validatePositiveAmount('')).toBe(undefined); + expect(validatePositiveAmount(null)).toBe(undefined); + expect(validatePositiveAmount(undefined)).toBe(undefined); + expect(validatePositiveAmount(-1)).toBeTruthy(); + expect(validatePositiveAmount(0)).toBeTruthy(); + }); }); From bcc4a6c4508228e94ad951d0703c6c48c266a004 Mon Sep 17 00:00:00 2001 From: Alisher Musurmonov Date: Fri, 27 Sep 2024 19:55:00 +0500 Subject: [PATCH 9/9] updated validation with number type conversion --- lib/utils/validateRequired.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/utils/validateRequired.js b/lib/utils/validateRequired.js index a48de82f..0e677812 100644 --- a/lib/utils/validateRequired.js +++ b/lib/utils/validateRequired.js @@ -37,9 +37,9 @@ export function validateRequiredPositiveAmount(value) { } export function validatePositiveAmount(value) { - if (value !== '' || value === undefined || value === null) return undefined; + if (value === '' || value === undefined || value === null) return undefined; - return value > 0 + return Number(value) > 0 ? undefined : ; }