Skip to content

Commit

Permalink
Cleaning up code, Adding more testing around adding a new email and i…
Browse files Browse the repository at this point in the history
…mproving some UX with snackBar.
  • Loading branch information
dr-bizz committed Aug 2, 2024
1 parent 599149d commit 5d87678
Show file tree
Hide file tree
Showing 2 changed files with 134 additions and 76 deletions.
36 changes: 23 additions & 13 deletions src/components/Tool/FixEmailAddresses/EmailValidationForm.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import { Grid, IconButton, TextField } from '@mui/material';
import { styled } from '@mui/material/styles';
import { Form, Formik } from 'formik';
import { useSnackbar } from 'notistack';
import { useTranslation } from 'react-i18next';
import * as Yup from 'yup';
import * as yup from 'yup';
import { AddIcon } from 'src/components/Contacts/ContactDetails/ContactDetailsTab/StyledComponents';
import { useAccountListId } from 'src/hooks/useAccountListId';
import i18n from 'src/lib/i18n';
import { useEmailAddressesMutation } from './AddEmailAddress.generated';
import { RowWrapper } from './FixEmailAddressPerson';
import {
Expand Down Expand Up @@ -32,10 +34,23 @@ interface EmailValidationFormProps {
personId: string;
}

const validationSchema = yup.object({
email: yup
.string()
.email(i18n.t('Invalid Email Address Format'))
.required(i18n.t('Please enter a valid email address')),
isPrimary: yup.bool().default(false),
updatedAt: yup.string(),
source: yup.string(),
personId: yup.string(),
isValid: yup.bool().default(false),
});

const EmailValidationForm = ({ personId }: EmailValidationFormProps) => {
const { t } = useTranslation();
const accountListId = useAccountListId();
const [emailAddressesMutation] = useEmailAddressesMutation();
const { enqueueSnackbar } = useSnackbar();

const initialEmail = {
email: '',
Expand All @@ -46,21 +61,11 @@ const EmailValidationForm = ({ personId }: EmailValidationFormProps) => {
isValid: false,
} as EmailValidationFormEmail;

const validationSchema = Yup.object({
email: Yup.string()
.email(t('Invalid Email Address Format'))
.required('Please enter a valid email address'),
isPrimary: Yup.bool().default(false),
updatedAt: Yup.string(),
source: Yup.string(),
personId: Yup.string(),
isValid: Yup.bool().default(false),
});

const onSubmit = (values, actions) => {
emailAddressesMutation({
variables: {
input: {
accountListId: accountListId || '',
attributes: {
id: personId,
emailAddresses: [
Expand All @@ -69,7 +74,6 @@ const EmailValidationForm = ({ personId }: EmailValidationFormProps) => {
},
],
},
accountListId: accountListId || '',
},
},
update: (cache, { data: addEmailAddressData }) => {
Expand Down Expand Up @@ -114,6 +118,12 @@ const EmailValidationForm = ({ personId }: EmailValidationFormProps) => {
});
}
},
onCompleted: () => {
enqueueSnackbar(t('Added email address'), { variant: 'success' });
},
onError: () => {
enqueueSnackbar(t('Failed to add email address'), { variant: 'error' });

Check warning on line 125 in src/components/Tool/FixEmailAddresses/EmailValidationForm.tsx

View check run for this annotation

Codecov / codecov/patch

src/components/Tool/FixEmailAddresses/EmailValidationForm.tsx#L124-L125

Added lines #L124 - L125 were not covered by tests
},
});
};

Expand Down
174 changes: 111 additions & 63 deletions src/components/Tool/FixEmailAddresses/FixEmailAddresses.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ import { ThemeProvider } from '@mui/material/styles';
import { render, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { ApolloErgonoMockMap, ErgonoMockShape } from 'graphql-ergonomock';
import { SnackbarProvider } from 'notistack';
import TestRouter from '__tests__/util/TestRouter';
import TestWrapper from '__tests__/util/TestWrapper';
import { GqlMockedProvider } from '__tests__/util/graphqlMocking';
import { GetInvalidEmailAddressesQuery } from 'src/components/Tool/FixEmailAddresses/FixEmailAddresses.generated';
import theme from '../../../theme';
Expand All @@ -21,43 +21,58 @@ import {
newEmail,
} from './FixEmailAddressesMocks';

const accountListId = 'test121';
const accountListId = 'accountListId';
const router = {
query: { accountListId },
isReady: true,
};

const setContactFocus = jest.fn();
const mutationSpy = jest.fn();
const mockEnqueue = jest.fn();

jest.mock('notistack', () => ({
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
...jest.requireActual('notistack'),
useSnackbar: () => {
return {
enqueueSnackbar: mockEnqueue,
};
},
}));

const Components = ({
mocks = {
GetInvalidEmailAddresses: {
people: { nodes: mockInvalidEmailAddressesResponse },
},
const defaultGraphQLMock = {
GetInvalidEmailAddresses: {
people: { nodes: mockInvalidEmailAddressesResponse },
},
cache,
}: {
};

interface ComponentsProps {
mocks?: ApolloErgonoMockMap;
cache?: ApolloCache<object>;
}) => (
<ThemeProvider theme={theme}>
<TestRouter router={router}>
<TestWrapper>
}

const Components = ({ mocks = defaultGraphQLMock, cache }: ComponentsProps) => (
<SnackbarProvider>
<ThemeProvider theme={theme}>
<TestRouter router={router}>
<GqlMockedProvider<{
GetInvalidEmailAddresses: GetInvalidEmailAddressesQuery;
EmailAddresses: EmailAddressesMutation;
}>
mocks={mocks}
cache={cache}
onCall={mutationSpy}
>
<FixEmailAddresses
accountListId={accountListId}
setContactFocus={setContactFocus}
/>
</GqlMockedProvider>
</TestWrapper>
</TestRouter>
</ThemeProvider>
</TestRouter>
</ThemeProvider>
</SnackbarProvider>
);

describe('FixEmailAddresses-Home', () => {
Expand Down Expand Up @@ -92,6 +107,39 @@ describe('FixEmailAddresses-Home', () => {
expect(getByTestId('starOutlineIcon-testid-0')).toBeInTheDocument();
});

it('should add an new email address, firing a GraphQL mutation and resetting the form', async () => {
const { getByTestId, getAllByLabelText } = render(<Components />);
await waitFor(() => {
expect(getByTestId('textfield-testid-0')).toBeInTheDocument();
});
const textFieldNew = getAllByLabelText('New Email Address')[0];
userEvent.type(textFieldNew, newEmail.email);
const addButton = getByTestId('addButton-testid');
expect(textFieldNew).toHaveValue(newEmail.email);

userEvent.click(addButton);

await waitFor(() =>
expect(mockEnqueue).toHaveBeenCalledWith('Added email address', {
variant: 'success',
}),
);

expect(mutationSpy.mock.calls[1][0].operation.operationName).toEqual(
'EmailAddresses',
);
expect(mutationSpy.mock.calls[1][0].operation.variables).toEqual({
input: {
accountListId: accountListId,
attributes: {
id: 'testid',
emailAddresses: [{ email: newEmail.email }],
},
},
});
expect(textFieldNew).toHaveValue('');
});

//TODO: Fix during MPDX-7936
it.skip('delete third email from first person', async () => {
const { getByTestId, queryByTestId } = render(<Components />);
Expand Down Expand Up @@ -124,7 +172,53 @@ describe('FixEmailAddresses-Home', () => {
expect(getByTestId('starIcon-testid2-0')).toBeInTheDocument();
});

describe('add email address', () => {
it('should render no contacts with no data', async () => {
const { getByText, getByTestId } = render(
<Components
mocks={{
GetInvalidEmailAddresses: {
people: { nodes: [] },
},
}}
/>,
);
await waitFor(() =>
expect(getByTestId('fixEmailAddresses-null-state')).toBeInTheDocument(),
);
expect(
getByText('No people with email addresses need attention'),
).toBeInTheDocument();
});

it('should modify first email of first contact', async () => {
const { getByTestId } = render(<Components />);
await waitFor(() => {
expect(getByTestId('textfield-testid-0')).toBeInTheDocument();
});
const firstInput = getByTestId('textfield-testid-0');

expect(firstInput).toHaveValue('[email protected]');
userEvent.type(firstInput, '123');
expect(firstInput).toHaveValue('[email protected]');
});

describe('setContactFocus()', () => {
it('should open up contact details', async () => {
const { getByText, queryByTestId } = render(<Components />);
await waitFor(() =>
expect(queryByTestId('loading')).not.toBeInTheDocument(),
);
expect(setContactFocus).not.toHaveBeenCalled();

const contactName = getByText('Test Contact');

expect(contactName).toBeInTheDocument();
userEvent.click(contactName);
expect(setContactFocus).toHaveBeenCalledWith(contactId);
});
});

describe('Add email address - Testing cache', () => {
interface AddEmailAddressProps {
postSaveResponse: object;
emailAddressNodes: object[];
Expand Down Expand Up @@ -254,50 +348,4 @@ describe('FixEmailAddresses-Home', () => {
});
});
});

it('should render no contacts with no data', async () => {
const { getByText, getByTestId } = render(
<Components
mocks={{
GetInvalidEmailAddresses: {
people: { nodes: [] },
},
}}
/>,
);
await waitFor(() =>
expect(getByTestId('fixEmailAddresses-null-state')).toBeInTheDocument(),
);
expect(
getByText('No people with email addresses need attention'),
).toBeInTheDocument();
});

it('should modify first email of first contact', async () => {
const { getByTestId } = render(<Components />);
await waitFor(() => {
expect(getByTestId('textfield-testid-0')).toBeInTheDocument();
});
const firstInput = getByTestId('textfield-testid-0');

expect(firstInput).toHaveValue('[email protected]');
userEvent.type(firstInput, '123');
expect(firstInput).toHaveValue('[email protected]');
});

describe('setContactFocus()', () => {
it('should open up contact details', async () => {
const { getByText, queryByTestId } = render(<Components />);
await waitFor(() =>
expect(queryByTestId('loading')).not.toBeInTheDocument(),
);
expect(setContactFocus).not.toHaveBeenCalled();

const contactName = getByText('Test Contact');

expect(contactName).toBeInTheDocument();
userEvent.click(contactName);
expect(setContactFocus).toHaveBeenCalledWith(contactId);
});
});
});

0 comments on commit 5d87678

Please sign in to comment.