-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #1216 from CruGlobal/hs-1265656-only-delete-MPDX-s…
…ourced-contacts MPDX-8488 - Prevent users from deleting Siebel contacts
- Loading branch information
Showing
18 changed files
with
616 additions
and
37 deletions.
There are no files selected for viewing
Binary file removed
BIN
-8.93 KB
.yarn/cache/@typescript-eslint-parser-npm-7.5.0-950f9b5b79-c9f85ae638.zip
Binary file not shown.
Binary file added
BIN
+9.15 KB
.yarn/cache/@typescript-eslint-parser-npm-8.17.0-f09f5fe974-3d330fc777.zip
Binary file not shown.
Binary file added
BIN
+351 KB
.yarn/cache/@typescript-eslint-scope-manager-npm-8.17.0-f0be17d23c-c5f628e5b4.zip
Binary file not shown.
Binary file added
BIN
+33.9 KB
.yarn/cache/@typescript-eslint-types-npm-8.17.0-ad6f5ae49f-5f6933903c.zip
Binary file not shown.
Binary file added
BIN
+188 KB
.yarn/cache/@typescript-eslint-typescript-estree-npm-8.17.0-0110955b24-35d3dca3cd.zip
Binary file not shown.
Binary file added
BIN
+9.86 KB
.yarn/cache/@typescript-eslint-visitor-keys-npm-8.17.0-9c7a8b5908-f92f659ec8.zip
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
29 changes: 29 additions & 0 deletions
29
...nts/Contacts/ContactDetails/ContactDetailsHeader/DeleteContactModal/ContactSource.graphql
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
query ContactSource($accountListId: ID!, $contactId: ID!) { | ||
contact(accountListId: $accountListId, id: $contactId) { | ||
id | ||
source | ||
addresses { | ||
nodes { | ||
id | ||
source | ||
} | ||
} | ||
people { | ||
nodes { | ||
id | ||
emailAddresses { | ||
nodes { | ||
id | ||
source | ||
} | ||
} | ||
phoneNumbers { | ||
nodes { | ||
id | ||
source | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} |
219 changes: 219 additions & 0 deletions
219
...ntacts/ContactDetails/ContactDetailsHeader/DeleteContactModal/DeleteContactModal.test.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,219 @@ | ||
import React from 'react'; | ||
import { ThemeProvider } from '@mui/material/styles'; | ||
import { LocalizationProvider } from '@mui/x-date-pickers'; | ||
import { AdapterLuxon } from '@mui/x-date-pickers/AdapterLuxon'; | ||
import { render, waitFor } from '@testing-library/react'; | ||
import { SnackbarProvider } from 'notistack'; | ||
import TestRouter from '__tests__/util/TestRouter'; | ||
import { GqlMockedProvider } from '__tests__/util/graphqlMocking'; | ||
import { ContactSourceEnum } from 'src/graphql/types.generated'; | ||
import theme from 'src/theme'; | ||
import { ContactSourceQuery } from './ContactSource.generated'; | ||
import { DeleteContactModal } from './DeleteContactModal'; | ||
|
||
const contactId = 'contact-id'; | ||
const mutationSpy = jest.fn(); | ||
const setOpen = jest.fn(); | ||
const deleteContact = jest.fn(); | ||
|
||
interface TestComponentProps { | ||
open?: boolean; | ||
deleting?: boolean; | ||
contactSource?: ContactSourceEnum; | ||
addressSources?: string[]; | ||
emailSources?: string[]; | ||
phoneSources?: string[]; | ||
} | ||
|
||
const TestComponent: React.FC<TestComponentProps> = ({ | ||
open = true, | ||
deleting = false, | ||
contactSource = ContactSourceEnum.Mpdx, | ||
addressSources = [], | ||
emailSources = [], | ||
phoneSources = [], | ||
}) => ( | ||
<SnackbarProvider> | ||
<LocalizationProvider dateAdapter={AdapterLuxon}> | ||
<TestRouter router={{ query: { accountListId: 'accountListId' } }}> | ||
<ThemeProvider theme={theme}> | ||
<GqlMockedProvider<{ | ||
ContactSource: ContactSourceQuery; | ||
}> | ||
mocks={{ | ||
ContactSource: { | ||
contact: { | ||
id: contactId, | ||
source: contactSource, | ||
addresses: { | ||
nodes: addressSources.map((source) => ({ source })), | ||
}, | ||
people: { | ||
nodes: [ | ||
{ | ||
emailAddresses: { | ||
nodes: emailSources.map((source) => ({ source })), | ||
}, | ||
phoneNumbers: { | ||
nodes: phoneSources.map((source) => ({ source })), | ||
}, | ||
}, | ||
{ | ||
emailAddresses: { | ||
nodes: emailSources.map((source) => ({ source })), | ||
}, | ||
phoneNumbers: { | ||
nodes: phoneSources.map((source) => ({ source })), | ||
}, | ||
}, | ||
], | ||
}, | ||
}, | ||
}, | ||
}} | ||
onCall={mutationSpy} | ||
> | ||
<DeleteContactModal | ||
open={open} | ||
setOpen={setOpen} | ||
deleting={deleting} | ||
deleteContact={deleteContact} | ||
contactId={contactId} | ||
/> | ||
</GqlMockedProvider> | ||
</ThemeProvider> | ||
</TestRouter> | ||
</LocalizationProvider> | ||
</SnackbarProvider> | ||
); | ||
|
||
describe('DeleteContactModal', () => { | ||
it('should not show modal if not open', () => { | ||
const { queryByText } = render(<TestComponent open={false} />); | ||
|
||
expect( | ||
queryByText(/Are you sure you want to permanently delete this contact?/), | ||
).not.toBeInTheDocument(); | ||
}); | ||
|
||
it('should be able to delete contact', async () => { | ||
const { getByText, getByRole } = render(<TestComponent />); | ||
|
||
await waitFor(() => { | ||
expect(mutationSpy).toHaveGraphqlOperation('ContactSource'); | ||
}); | ||
|
||
expect( | ||
getByText(/Are you sure you want to permanently delete this contact?/), | ||
).toBeInTheDocument(); | ||
|
||
expect(getByRole('button', { name: 'delete contact' })).toBeInTheDocument(); | ||
}); | ||
|
||
it('should prevent user from deleting contact while currently deleting contact', async () => { | ||
const { getByRole } = render(<TestComponent deleting={true} />); | ||
|
||
await waitFor(() => { | ||
expect(mutationSpy).toHaveGraphqlOperation('ContactSource'); | ||
}); | ||
|
||
expect(getByRole('button', { name: 'delete contact' })).toBeDisabled(); | ||
}); | ||
|
||
describe('Show third party message', () => { | ||
interface TestProps { | ||
testName: string; | ||
props: TestComponentProps; | ||
} | ||
const tests: TestProps[] = [ | ||
{ | ||
testName: 'disables deletion if contact created by third party', | ||
props: { contactSource: ContactSourceEnum.GiveSite }, | ||
}, | ||
{ | ||
testName: | ||
"disables deletion if a contact's address is sourced by a third party", | ||
props: { | ||
addressSources: ['Siebel', 'MPDX'], | ||
}, | ||
}, | ||
{ | ||
testName: | ||
"disables deletion if a contact's phone or email is sourced by a third party", | ||
props: { | ||
emailSources: ['Siebel', 'MPDX'], | ||
phoneSources: ['Siebel', 'MPDX'], | ||
}, | ||
}, | ||
{ | ||
testName: | ||
"disables deletion if only one contact's phone number is sourced by a third party", | ||
props: { | ||
emailSources: ['MPDX', 'MPDX'], | ||
phoneSources: ['MPDX', 'Siebel'], | ||
}, | ||
}, | ||
]; | ||
|
||
test.each(tests)('$testName', async ({ props }) => { | ||
const { findByText, getByRole } = render(<TestComponent {...props} />); | ||
|
||
expect( | ||
await findByText( | ||
/its data may sync with Donation Services or other third-party systems/, | ||
), | ||
).toBeInTheDocument(); | ||
|
||
expect( | ||
getByRole('button', { name: 'delete contact' }), | ||
).toBeInTheDocument(); | ||
}); | ||
|
||
it('should show third party source for contact', async () => { | ||
const { findByText } = render( | ||
<TestComponent | ||
contactSource={ContactSourceEnum.GiveSite} | ||
addressSources={['Siebel', 'MPDX']} | ||
emailSources={['Siebel', 'MPDX']} | ||
phoneSources={['Siebel', 'MPDX']} | ||
/>, | ||
); | ||
|
||
expect(await findByText('Contact: GIVE_SITE')).toBeInTheDocument(); | ||
expect( | ||
await findByText('Address: US Donation Services'), | ||
).toBeInTheDocument(); | ||
expect( | ||
await findByText('Email: US Donation Services'), | ||
).toBeInTheDocument(); | ||
expect( | ||
await findByText('Phone: US Donation Services'), | ||
).toBeInTheDocument(); | ||
}); | ||
}); | ||
|
||
describe('Show normal delete message', () => { | ||
it('should show modal and be able to delete user', async () => { | ||
const { getByText, getByRole } = render( | ||
<TestComponent | ||
contactSource={ContactSourceEnum.Mpdx} | ||
addressSources={['MPDX', 'MPDX']} | ||
emailSources={['MPDX', 'MPDX']} | ||
phoneSources={['MPDX', 'MPDX']} | ||
/>, | ||
); | ||
|
||
await waitFor(() => { | ||
expect(mutationSpy).toHaveGraphqlOperation('ContactSource'); | ||
}); | ||
|
||
expect( | ||
getByText(/Are you sure you want to permanently delete this contact?/), | ||
).toBeInTheDocument(); | ||
|
||
expect( | ||
getByRole('button', { name: 'delete contact' }), | ||
).toBeInTheDocument(); | ||
}); | ||
}); | ||
}); |
Oops, something went wrong.