Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
import React from 'react';
import { ThemeProvider } from '@mui/material/styles';
import { render } from '@testing-library/react';
import { render, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import theme from 'src/theme';
import { MockLinkCallHandler } from 'graphql-ergonomock/dist/apollo/MockLink';
import { NsoMpdQuestionnaireTestWrapper } from '../NsoMpdQuestionnaireTestWrapper';
import { FinancialDetails } from './FinancialDetails';

const TestComponent: React.FC = () => (
<ThemeProvider theme={theme}>
const TestComponent: React.FC<{ onCall?: MockLinkCallHandler }> = ({
onCall,
}) => (
<NsoMpdQuestionnaireTestWrapper onCall={onCall}>
<FinancialDetails />
</ThemeProvider>
</NsoMpdQuestionnaireTestWrapper>
);

const studentLoanQuestion =
Expand All @@ -31,6 +33,15 @@ describe('FinancialDetails', () => {
expect(getByRole('radio', { name: 'No' })).toBeInTheDocument();
});

it('shows the debt-question error once the group is touched without a selection', () => {
const { getByRole, getByText } = render(<TestComponent />);

getByRole('radio', { name: 'Yes' }).focus();
userEvent.tab();

expect(getByText('Please select an answer.')).toBeInTheDocument();
});

it('hides the payment fields until Yes is selected', () => {
const { queryByRole } = render(<TestComponent />);

Expand Down Expand Up @@ -90,4 +101,27 @@ describe('FinancialDetails', () => {

expect(queryByText(requiredError)).not.toBeInTheDocument();
});

it('saves zero for every debt field when the user has no debt', async () => {
const mutationSpy = jest.fn();
const { getByRole } = render(<TestComponent onCall={mutationSpy} />);

userEvent.click(getByRole('radio', { name: 'No' }));

await waitFor(() =>
expect(mutationSpy).toHaveGraphqlOperation(
'UpdateNewStaffQuestionnaire',
{
input: {
accountListId: 'account-list-1',
attributes: {
studentLoanMonthlyPayment: 0,
carLoanMonthlyPayment: 0,
creditCardDebtMonthlyPayment: 0,
},
},
},
),
);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -15,25 +15,43 @@ import {
import { TFunction, useTranslation } from 'react-i18next';
import * as yup from 'yup';
import { useOptionalAutosaveForm } from 'src/components/Shared/Autosave/AutosaveForm';
import { useNsoMpdQuestionnaire } from '../Shared/NsoMpdQuestionnaireContext';
import { NumberQuestion } from '../Shared/NumberQuestion';
import { getAmountSchema } from '../Shared/helpers/getAmountSchema';
import { QuestionnaireField } from '../Shared/useQuestionnaireAutoSave';

export const getFinancialDetailsSchema = (t: TFunction) =>
yup.object({
studentLoanPayment: getAmountSchema(t),
carPayment: getAmountSchema(t),
creditCardPayment: getAmountSchema(t),
studentLoanMonthlyPayment: getAmountSchema(t),
carLoanMonthlyPayment: getAmountSchema(t),
creditCardDebtMonthlyPayment: getAmountSchema(t),
});

export const FinancialDetails: React.FC = () => {
const { t } = useTranslation();

const schema = useMemo(() => getFinancialDetailsSchema(t), [t]);

const { saveField } = useNsoMpdQuestionnaire();

// UI only toggle
const [hasDebt, setHasDebt] = useState('');
const [hasDebtTouched, setHasDebtTouched] = useState(false);
const showDebtFields = hasDebt === 'Yes';
const hasDebtError = !hasDebt;
const showHasDebtError = hasDebtError && hasDebtTouched;

const handleHasDebtChange = (event: React.ChangeEvent<HTMLInputElement>) => {
const value = event.target.value;
setHasDebt(value);
if (value === 'No') {
saveField({
studentLoanMonthlyPayment: 0,
carLoanMonthlyPayment: 0,
creditCardDebtMonthlyPayment: 0,
});
}
};

const { markValid, markInvalid } = useOptionalAutosaveForm() ?? {};
useEffect(() => {
Expand All @@ -45,27 +63,31 @@ export const FinancialDetails: React.FC = () => {
return () => markValid?.('hasDebt');
}, [hasDebtError, markValid, markInvalid]);

const debtFields = [
const debtFields: {
fieldName: QuestionnaireField;
debtType: string;
icon: React.ReactNode;
}[] = [
{
fieldName: 'studentLoanPayment',
fieldName: 'studentLoanMonthlyPayment',
debtType: t('student loan debt'),
icon: <School />,
},
{
fieldName: 'carPayment',
fieldName: 'carLoanMonthlyPayment',
debtType: t('car debt'),
icon: <DirectionsCar />,
},
{
fieldName: 'creditCardPayment',
fieldName: 'creditCardDebtMonthlyPayment',
debtType: t('credit card debt'),
icon: <CreditCard />,
},
];

return (
<Stack spacing={4}>
<FormControl error={hasDebtError}>
<FormControl error={showHasDebtError}>
<FormLabel id="has-debt-label" sx={{ color: 'text.primary' }}>
{t('Do you have any student loan, car, or credit card debt?')}
</FormLabel>
Expand All @@ -74,12 +96,13 @@ export const FinancialDetails: React.FC = () => {
sx={{ paddingInline: 2 }}
aria-labelledby="has-debt-label"
value={hasDebt}
onChange={(event) => setHasDebt(event.target.value)}
onChange={handleHasDebtChange}
onBlur={() => setHasDebtTouched(true)}
>
<FormControlLabel value="Yes" control={<Radio />} label={t('Yes')} />
<FormControlLabel value="No" control={<Radio />} label={t('No')} />
</RadioGroup>
{hasDebtError && (
{showHasDebtError && (
<FormHelperText>{t('Please select an answer.')}</FormHelperText>
)}
</FormControl>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,31 +1,16 @@
import React from 'react';
import { ThemeProvider } from '@mui/material/styles';
import { render, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { GqlMockedProvider } from '__tests__/util/graphqlMocking';
import { GoalCalculatorConstantsQuery } from 'src/hooks/goalCalculatorConstants.generated';
import theme from 'src/theme';
import { MockLinkCallHandler } from 'graphql-ergonomock/dist/apollo/MockLink';
import { NsoMpdQuestionnaireTestWrapper } from '../NsoMpdQuestionnaireTestWrapper';
import { MinistryDetails } from './MinistryDetails';

const TestComponent: React.FC = () => (
<ThemeProvider theme={theme}>
<GqlMockedProvider<{
GoalCalculatorConstants: GoalCalculatorConstantsQuery;
}>
mocks={{
GoalCalculatorConstants: {
constant: {
mpdGoalGeographicConstants: [
{ location: 'Atlanta, GA' },
{ location: 'Miami, FL' },
],
},
},
}}
>
<MinistryDetails />
</GqlMockedProvider>
</ThemeProvider>
const TestComponent: React.FC<{ onCall?: MockLinkCallHandler }> = ({
onCall,
}) => (
<NsoMpdQuestionnaireTestWrapper onCall={onCall}>
<MinistryDetails />
</NsoMpdQuestionnaireTestWrapper>
);

describe('MinistryDetails', () => {
Expand Down Expand Up @@ -103,6 +88,25 @@ describe('MinistryDetails', () => {
expect(getByRole('radio', { name: 'Office' })).toBeInTheDocument();
});

it('saves FIELD when the field assignment is chosen', async () => {
const mutationSpy = jest.fn();
const { getByRole } = render(<TestComponent onCall={mutationSpy} />);

userEvent.click(getByRole('radio', { name: 'Field' }));

await waitFor(() =>
expect(mutationSpy).toHaveGraphqlOperation(
'UpdateNewStaffQuestionnaire',
{
input: {
accountListId: 'account-list-1',
attributes: { assignmentType: 'FIELD' },
},
},
),
);
});

it('shows a loading indicator in place of the city field until the constants load', () => {
const { getByRole, queryByRole } = render(<TestComponent />);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,11 +36,11 @@ export const MinistryDetails: React.FC = () => {
const schema = useMemo(
() =>
yup.object({
ministry: yup.string().required(t('Please select a ministry')),
assignmentLocation: yup
ministryName: yup.string().required(t('Please select a ministry')),
ministryLocation: yup
.string()
.required(t('Please enter an assignment location')),
nearestCity: yup
geographicLocation: yup
.string()
.required(
t(
Expand All @@ -55,18 +55,18 @@ export const MinistryDetails: React.FC = () => {
);

const ministryProps = useQuestionnaireAutoSave({
fieldName: 'ministry',
fieldName: 'ministryName',
schema,
saveOnChange: true,
});

const locationProps = useQuestionnaireAutoSave({
fieldName: 'assignmentLocation',
fieldName: 'ministryLocation',
schema,
});

const cityProps = useQuestionnaireAutoSave({
fieldName: 'nearestCity',
fieldName: 'geographicLocation',
schema,
saveOnChange: true,
});
Expand Down Expand Up @@ -148,8 +148,8 @@ export const MinistryDetails: React.FC = () => {
row
label={t('What type of assignment are you expecting?')}
options={[
{ value: 'Field', label: t('Field') },
{ value: 'Office', label: t('Office') },
{ value: 'FIELD', label: t('Field') },
{ value: 'OFFICE', label: t('Office') },
]}
/>
</Stack>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
import React from 'react';
import { ThemeProvider } from '@mui/material/styles';
import { render } from '@testing-library/react';
import { render, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import theme from 'src/theme';
import { MockLinkCallHandler } from 'graphql-ergonomock/dist/apollo/MockLink';
import { NsoMpdQuestionnaireTestWrapper } from '../NsoMpdQuestionnaireTestWrapper';
import { NsoDetails } from './NsoDetails';

const TestComponent: React.FC = () => (
<ThemeProvider theme={theme}>
const TestComponent: React.FC<{ onCall?: MockLinkCallHandler }> = ({
onCall,
}) => (
<NsoMpdQuestionnaireTestWrapper onCall={onCall}>
<NsoDetails />
</ThemeProvider>
</NsoMpdQuestionnaireTestWrapper>
);

describe('NsoDetails', () => {
Expand Down Expand Up @@ -37,6 +39,50 @@ describe('NsoDetails', () => {
).toBeInTheDocument();
});

it('saves the housing enum constant', async () => {
const mutationSpy = jest.fn();
const { getByRole } = render(<TestComponent onCall={mutationSpy} />);

userEvent.click(getByRole('radio', { name: 'Family in a hotel/room' }));

await waitFor(() =>
expect(mutationSpy).toHaveGraphqlOperation(
'UpdateNewStaffQuestionnaire',
{
input: {
accountListId: 'account-list-1',
attributes: { nsoHousing: 'FAMILY_ROOM' },
},
},
),
);
});

it('saves the childcare count as a number', async () => {
const mutationSpy = jest.fn();
const { getByRole } = render(<TestComponent onCall={mutationSpy} />);

userEvent.type(
getByRole('spinbutton', {
name: 'If you are a parent with children in Childcare, please enter how many.',
}),
'3',
);
userEvent.tab();

await waitFor(() =>
expect(mutationSpy).toHaveGraphqlOperation(
'UpdateNewStaffQuestionnaire',
{
input: {
accountListId: 'account-list-1',
attributes: { childcareChildrenCount: 3 },
},
},
),
);
});

it('renders the sessions question with both options', () => {
const { getByRole } = render(<TestComponent />);

Expand Down
Loading
Loading