Skip to content

Commit

Permalink
UINV-432 100% of total calculation is different on FE and BE (#637)
Browse files Browse the repository at this point in the history
  • Loading branch information
usavkov-epam committed Aug 19, 2022
1 parent f4786a9 commit a77c226
Show file tree
Hide file tree
Showing 2 changed files with 119 additions and 21 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ const FundDistributionFieldsFinal = ({
}) => {
const intl = useIntl();
const [remainingAmount, setRemainingAmount] = useState(0);
const [hasValidationError, setValidationError] = useState(false);

const fundsForSelect = useMemo(() => {
const activeFunds = funds.filter(({ fundStatus }) => fundStatus === 'Active');
Expand Down Expand Up @@ -109,12 +110,16 @@ const FundDistributionFieldsFinal = ({
validateFundDistributionUniqueFunds(records),
].filter(Boolean);

return required
const error = required
? errors[0]
: undefined;

setValidationError(Boolean(error));

return error;
}

return undefined;
return setValidationError(false);
}, [
currency,
fundDistribution,
Expand Down Expand Up @@ -187,6 +192,7 @@ const FundDistributionFieldsFinal = ({
</Col>
<Col xs>
<Field
data-testid="fundDistribution-value"
component={TextField}
fullWidth
label={<FormattedMessage id="stripes-acq-components.fundDistribution.value" />}
Expand Down Expand Up @@ -237,20 +243,32 @@ const FundDistributionFieldsFinal = ({
]);

return (
<FieldArray
key={`${currency}${totalAmount}`}
addLabel={disabled ? null : <FormattedMessage id="stripes-acq-components.fundDistribution.addBtn" />}
component={RepeatableFieldWithValidation}
id={name}
legend={remainingAmountNode}
name={name}
onAdd={onAdd}
onRemove={onRemove}
canAdd={!disabled}
canRemove={!disabled}
renderField={renderSubForm}
validate={debouncedValidate}
/>
<>
{
hasValidationError && (
<Field
name={`${name}-error`}
validate={() => true}
validateFields={[]}
render={() => <></>}
/>
)
}
<FieldArray
key={`${currency}${totalAmount}`}
addLabel={disabled ? null : <FormattedMessage id="stripes-acq-components.fundDistribution.addBtn" />}
component={RepeatableFieldWithValidation}
id={name}
legend={remainingAmountNode}
name={name}
onAdd={onAdd}
onRemove={onRemove}
canAdd={!disabled}
canRemove={!disabled}
renderField={renderSubForm}
validate={debouncedValidate}
/>
</>
);
};

Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,30 @@
import React from 'react';
import { render, screen } from '@testing-library/react';
import { act, render, screen } from '@testing-library/react';
import { MemoryRouter } from 'react-router-dom';
import user from '@testing-library/user-event';

import stripesFinalForm from '@folio/stripes/final-form';

import { FUND_DISTR_TYPE } from '../../constants';
import FundDistributionFieldsFinal from './FundDistributionFieldsFinal';

const FUNDS = [{ id: '1', code: 'AFRICAHIST', name: 'african', fundStatus: 'Active' }, { id: '2', code: 'TEST', name: 'test', fundStatus: 'Active' }];
import { handleValidationErrorResponse } from './handleValidationErrorResponse';
import { validateFundDistributionTotal as validateFundDistributionTotalDefault } from './validateFundDistributionFinal';

jest.useFakeTimers('modern');
jest.mock('./handleValidationErrorResponse', () => ({
handleValidationErrorResponse: jest.fn(() => 'error message'),
}));
jest.mock('./validateFundDistributionFinal', () => ({
...jest.requireActual('./validateFundDistributionFinal'),
validateFundDistributionTotal: jest.fn(() => Promise.resolve()),
}));

const DELAY = 500;
const validateFundDistributionTotal = jest.fn(() => Promise.resolve());
const FUNDS = [
{ id: '1', code: 'AFRICAHIST', name: 'african', fundStatus: 'Active' },
{ id: '2', code: 'TEST', name: 'test', fundStatus: 'Active' },
];
const inactiveFund = {
name: 'TestName',
code: 'TestCode',
Expand All @@ -18,7 +34,13 @@ const inactiveFund = {
};

// eslint-disable-next-line react/prop-types
const renderForm = ({ fundDistribution, onSelectFund = () => { }, totalAmount = 0, funds = FUNDS }) => (
const renderForm = ({
fundDistribution,
onSelectFund = () => { },
totalAmount = 0,
funds = FUNDS,
...rest
}) => (
<form>
<FundDistributionFieldsFinal
currency="USD"
Expand All @@ -29,6 +51,7 @@ const renderForm = ({ fundDistribution, onSelectFund = () => { }, totalAmount =
name="fund-distribution"
onSelectFund={onSelectFund}
totalAmount={totalAmount}
{...rest}
/>
</form>
);
Expand All @@ -42,6 +65,12 @@ const renderComponent = (props = {}) => (render(
));

describe('FundDistributionFieldsFinal', () => {
beforeEach(() => {
handleValidationErrorResponse.mockClear();
validateFundDistributionTotal.mockClear();
validateFundDistributionTotalDefault.mockClear();
});

it('should add new record and call select fund', () => {
const onSelectFund = jest.fn();

Expand All @@ -53,9 +82,10 @@ describe('FundDistributionFieldsFinal', () => {
});

it('should display fund distribution and handle clicks', () => {
const expenseClassesByFundId = { [FUNDS[1].id]: [{ id: 'expClassId', name: 'expClassName' }] };
const fundDistribution = [{ code: 'TEST', fundId: '2', value: 100, distributionType: FUND_DISTR_TYPE.percent }];

renderComponent({ fundDistribution, totalAmount: 5 });
renderComponent({ fundDistribution, totalAmount: 5, expenseClassesByFundId });
user.click(screen.getByText('stripes-acq-components.fundDistribution.addBtn'));
expect(screen.getByText('$5.00')).toBeDefined();
});
Expand All @@ -75,4 +105,54 @@ describe('FundDistributionFieldsFinal', () => {

expect(screen.getAllByText('TestName (TestCode) - stripes-acq-components.fundDistribution.fundStatus.Inactive')).toBeDefined();
});

it('should call fund distribution validator from props', () => {
const fundDistribution = [inactiveFund];

renderComponent({ fundDistribution, funds: fundDistribution, validateFundDistributionTotal });

const valueInput = screen.getByTestId('fundDistribution-value');

user.type(valueInput, '100');
user.tab();

jest.advanceTimersByTime(DELAY * 1.5);

expect(validateFundDistributionTotal).toHaveBeenCalled();
});

it('should call default fund distribution validator', () => {
const fundDistribution = [inactiveFund];

renderComponent({ fundDistribution, funds: fundDistribution, required: false });

const valueInput = screen.getByTestId('fundDistribution-value');

user.type(valueInput, '100');
user.tab();

jest.advanceTimersByTime(DELAY * 1.5);

expect(validateFundDistributionTotalDefault).toHaveBeenCalled();
});

it('should call \'handleValidationErrorResponse\' when validator rejected with an error', async () => {
const fundDistribution = [inactiveFund];

// eslint-disable-next-line prefer-promise-reject-errors
validateFundDistributionTotal.mockClear().mockReturnValue(Promise.reject('error message'));

renderComponent({ fundDistribution, funds: fundDistribution, validateFundDistributionTotal });

const valueInput = screen.getByTestId('fundDistribution-value');

await act(async () => {
user.type(valueInput, '100');
user.tab();

jest.advanceTimersByTime(DELAY * 1.5);
});

expect(handleValidationErrorResponse).toHaveBeenCalled();
});
});

0 comments on commit a77c226

Please sign in to comment.