diff --git a/__mocks__/gatsby-plugin-firebase/auth/auth.js b/__mocks__/gatsby-plugin-firebase/auth/auth.js index edb718c9..017dfbbc 100644 --- a/__mocks__/gatsby-plugin-firebase/auth/auth.js +++ b/__mocks__/gatsby-plugin-firebase/auth/auth.js @@ -77,10 +77,6 @@ class Auth { this._currentUser = null; await delay(Constants.defaultDelayInMilliseconds); - - this.onAuthStateChangedObservers.forEach((observer) => - observer(this._currentUser), - ); } } diff --git a/src/contexts/UserContext.js b/src/contexts/UserContext.js index 5132927c..d071a7e2 100644 --- a/src/contexts/UserContext.js +++ b/src/contexts/UserContext.js @@ -66,8 +66,8 @@ const UserProvider = ({ children }) => { } }; - const logout = () => { - firebase.auth().signOut(); + const logout = async () => { + await firebase.auth().signOut(); localStorage.removeItem('user'); setUser(null); navigate('/'); @@ -123,7 +123,7 @@ const UserProvider = ({ children }) => { } catch (error) { toast.error(error.message); } finally { - logout(); + await logout(); toast( "It's sad to see you go, but we respect your privacy. All your data has been deleted successfully. Hope to see you again soon!", ); diff --git a/src/pages/app/__tests__/builder.settings.deleteAccount.test.js b/src/pages/app/__tests__/builder.settings.deleteAccount.test.js index 44706d81..3c304462 100644 --- a/src/pages/app/__tests__/builder.settings.deleteAccount.test.js +++ b/src/pages/app/__tests__/builder.settings.deleteAccount.test.js @@ -1,4 +1,5 @@ import { navigate as mockNavigateFunction } from '@reach/router'; +import { toast } from 'react-toastify'; import { fireEvent, screen, waitFor } from '@testing-library/react'; import FirebaseStub, { @@ -6,9 +7,7 @@ import FirebaseStub, { FunctionsConstants, } from 'gatsby-plugin-firebase'; -import { delay } from '../../../utils/index'; - -import { setupAndWait, findAndDismissNotification } from './helpers/builder'; +import { setupAndWait } from './helpers/builder'; const testTimeoutInMilliseconds = 20000; jest.setTimeout(testTimeoutInMilliseconds); @@ -17,9 +16,7 @@ async function setup() { const resumeId = DatabaseConstants.demoStateResume1Id; await setupAndWait(resumeId, true, true); - const mockFirebaseDeleteUserCloudFunction = jest.fn(async () => { - await delay(FunctionsConstants.defaultDelayInMilliseconds); - }); + const mockFirebaseDeleteUserCloudFunction = jest.fn(async () => {}); const mockFirebaseFunctionsHttpsCallable = jest.fn((name) => name === FunctionsConstants.deleteUserFunctionName ? mockFirebaseDeleteUserCloudFunction @@ -27,19 +24,38 @@ async function setup() { ); FirebaseStub.functions().httpsCallable = mockFirebaseFunctionsHttpsCallable; - const mockFirebaseCurrentUserDelete = jest.spyOn( - FirebaseStub.auth().currentUser, - 'delete', - ); - - const button = screen.getByRole('button', { - name: /Delete Account/i, + const mockFirebaseCurrentUserDelete = jest.fn(async () => { + throw new Error('Error occurred while deleting user.'); }); + FirebaseStub.auth().currentUser.delete = mockFirebaseCurrentUserDelete; + + const mockFirebaseAuthSignOut = jest.fn(async () => { + throw new Error('Error occurred while signing out.'); + }); + FirebaseStub.auth().signOut = mockFirebaseAuthSignOut; + + // eslint-disable-next-line no-unused-vars + const mockToastError = jest.fn((content, options) => {}); + toast.error = mockToastError; + + const deleteAccountRegExp = /Delete Account/i; + const button = screen.getByRole('button', { + name: deleteAccountRegExp, + }); + + const waitForButtonNameToBeSetToDeleteAccount = async () => { + waitFor(() => { + expect(button).toHaveTextContent(deleteAccountRegExp); + }); + }; return { button, - mockFirebaseCurrentUserDelete, mockFirebaseDeleteUserCloudFunction, + mockFirebaseCurrentUserDelete, + mockFirebaseAuthSignOut, + mockToastError, + waitForButtonNameToBeSetToDeleteAccount, }; } @@ -48,44 +64,94 @@ test('prompts for confirmation', async () => { button, mockFirebaseDeleteUserCloudFunction, mockFirebaseCurrentUserDelete, + mockFirebaseAuthSignOut, + mockToastError, } = await setup(); fireEvent.click(button); - expect(button).toHaveTextContent('Are you sure?'); + expect(button).toHaveTextContent(/Are you sure?/i); - await waitFor(() => - expect(mockFirebaseDeleteUserCloudFunction).not.toHaveBeenCalledTimes(1), - ); - await waitFor(() => - expect(mockFirebaseCurrentUserDelete).not.toHaveBeenCalled(), - ); + expect(mockFirebaseDeleteUserCloudFunction).not.toHaveBeenCalled(); + expect(mockFirebaseCurrentUserDelete).not.toHaveBeenCalled(); + expect(mockFirebaseAuthSignOut).not.toHaveBeenCalled(); + expect(mockNavigateFunction).not.toHaveBeenCalled(); + expect(mockToastError).not.toHaveBeenCalled(); }); -/* test('calls Firebase delete user cloud function', async () => { - const { button, mockFirebaseDeleteUserCloudFunction } = await setup(); + const { + button, + mockFirebaseDeleteUserCloudFunction, + waitForButtonNameToBeSetToDeleteAccount, + } = await setup(); fireEvent.click(button); fireEvent.click(button); - await waitFor(() => expect(mockNavigateFunction).toHaveBeenCalledTimes(1)); - await findAndDismissNotification(); + await waitForButtonNameToBeSetToDeleteAccount(); await waitFor(() => expect(mockFirebaseDeleteUserCloudFunction).toHaveBeenCalledTimes(1), ); }); test('calls Firebase current user delete', async () => { - const { button, mockFirebaseCurrentUserDelete } = await setup(); + const { + button, + mockFirebaseCurrentUserDelete, + waitForButtonNameToBeSetToDeleteAccount, + } = await setup(); fireEvent.click(button); fireEvent.click(button); - await waitFor(() => expect(mockNavigateFunction).toHaveBeenCalledTimes(1)); - await findAndDismissNotification(); + await waitForButtonNameToBeSetToDeleteAccount(); await waitFor(() => expect(mockFirebaseCurrentUserDelete).toHaveBeenCalledTimes(1), ); }); -*/ + +test('calls Firebase auth sign out', async () => { + const { + button, + mockFirebaseAuthSignOut, + waitForButtonNameToBeSetToDeleteAccount, + } = await setup(); + + fireEvent.click(button); + fireEvent.click(button); + + await waitForButtonNameToBeSetToDeleteAccount(); + await waitFor(() => expect(mockFirebaseAuthSignOut).toHaveBeenCalledTimes(1)); +}); + +describe('if an error occurs while signing out the current user', () => { + test('does not navigate away', async () => { + const { button, waitForButtonNameToBeSetToDeleteAccount } = await setup(); + + fireEvent.click(button); + fireEvent.click(button); + + await waitForButtonNameToBeSetToDeleteAccount(); + expect(mockNavigateFunction).not.toHaveBeenCalled(); + }); + + /* + test('displays toast', async () => { + const { + button, + waitForButtonNameToBeSetToDeleteAccount, + mockToastError, + } = await setup(); + + fireEvent.click(button); + fireEvent.click(button); + + await waitForButtonNameToBeSetToDeleteAccount(); + expect(mockToastError).toHaveBeenCalledTimes(2); + expect(mockToastError).toHaveBeenLastCalledWith( + 'An error occurred deleting your account.', + ); + }); + */ +}); diff --git a/src/pages/app/__tests__/helpers/builder.js b/src/pages/app/__tests__/helpers/builder.js index 8f5f30de..e63c9346 100644 --- a/src/pages/app/__tests__/helpers/builder.js +++ b/src/pages/app/__tests__/helpers/builder.js @@ -47,15 +47,6 @@ const expectDatabaseUpdateToHaveCompleted = async ( ); }; -const dismissNotification = (notification) => { - fireEvent.click(notification); -}; - -const findAndDismissNotification = async () => { - const notification = await screen.findByRole('alert'); - dismissNotification(notification); -}; - const dragAndDropDirectionUp = 'DND_DIRECTION_UP'; const dragAndDropDirectionDown = 'DND_DIRECTION_DOWN'; @@ -167,6 +158,4 @@ export { dragAndDropDirectionUp, dragAndDropDirectionDown, dragAndDropListItem, - dismissNotification, - findAndDismissNotification, };