From 61a50f9fcdd1a347c782e0b768c19d6a63464e01 Mon Sep 17 00:00:00 2001 From: chandel-aman Date: Sat, 11 Nov 2023 21:06:31 +0530 Subject: [PATCH 1/3] refresh token --- src/App.tsx | 37 +++++++++++------------ src/GraphQl/Mutations/mutations.ts | 19 ++++++++++++ src/index.tsx | 47 +++++++++++++++++++++++++++-- src/screens/LoginPage/LoginPage.tsx | 1 + src/utils/getRefreshToken.ts | 31 +++++++++++++++++++ 5 files changed, 113 insertions(+), 22 deletions(-) create mode 100644 src/utils/getRefreshToken.ts diff --git a/src/App.tsx b/src/App.tsx index cf20c722e5..367f11c309 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,4 +1,4 @@ -import React from 'react'; +import React, { useEffect } from 'react'; import { Route, Switch } from 'react-router-dom'; import { useQuery } from '@apollo/client'; import * as installedPlugins from 'components/plugins/index'; @@ -62,6 +62,23 @@ function app(): JSX.Element { const { data, loading } = useQuery(CHECK_AUTH); + useEffect(() => { + if (data) { + localStorage.setItem( + 'name', + `${data.checkAuth.firstName} ${data.checkAuth.lastName}` + ); + localStorage.setItem('id', data.checkAuth._id); + localStorage.setItem('email', data.checkAuth.email); + localStorage.setItem('IsLoggedIn', 'TRUE'); + localStorage.setItem('UserType', data.checkAuth.userType); + localStorage.setItem('FirstName', data.checkAuth.firstName); + localStorage.setItem('LastName', data.checkAuth.lastName); + localStorage.setItem('UserImage', data.checkAuth.image); + localStorage.setItem('Email', data.checkAuth.email); + } + }, [data, loading]); + const extraRoutes = Object.entries(installedPlugins).map( (plugin: any, index) => { const extraComponent = plugin[1]; @@ -78,24 +95,6 @@ function app(): JSX.Element { if (loading) { return ; } - - if (data) { - localStorage.setItem( - 'name', - `${data.checkAuth.firstName} ${data.checkAuth.lastName}` - ); - localStorage.setItem('id', data.checkAuth._id); - localStorage.setItem('email', data.checkAuth.email); - localStorage.setItem('IsLoggedIn', 'TRUE'); - localStorage.setItem('UserType', data.checkAuth.userType); - localStorage.setItem('FirstName', data.checkAuth.firstName); - localStorage.setItem('LastName', data.checkAuth.lastName); - localStorage.setItem('UserImage', data.checkAuth.image); - localStorage.setItem('Email', data.checkAuth.email); - } else { - localStorage.clear(); - } - return ( <> diff --git a/src/GraphQl/Mutations/mutations.ts b/src/GraphQl/Mutations/mutations.ts index 7090bd10d7..3fb537c472 100644 --- a/src/GraphQl/Mutations/mutations.ts +++ b/src/GraphQl/Mutations/mutations.ts @@ -150,6 +150,25 @@ export const LOGIN_MUTATION = gql` } `; +// to get the refresh token + +export const REFRESH_TOKEN_MUTATION = gql` + mutation RefreshToken($refreshToken: String!) { + refreshToken(refreshToken: $refreshToken) { + newRefreshToken + accessToken + } + } +`; + +// to revoke a refresh token + +export const REVOKE_REFRESH_TOKEN = gql` + mutation RevokeRefreshTokenForUser($userId: String!) { + revokeRefreshTokenForUser(userId: $userId) + } +`; + // To verify the google recaptcha export const RECAPTCHA_MUTATION = gql` diff --git a/src/index.tsx b/src/index.tsx index 6471e29e21..908a371788 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -8,6 +8,7 @@ import { InMemoryCache, HttpLink, split, + ApolloLink, } from '@apollo/client'; import { getMainDefinition } from '@apollo/client/utilities'; import { GraphQLWsLink } from '@apollo/client/link/subscriptions'; @@ -30,11 +31,51 @@ import { BACKEND_URL, REACT_APP_BACKEND_WEBSOCKET_URL, } from 'Constant/constant'; +import { refreshToken } from 'utils/getRefreshToken'; -onError(({ graphQLErrors }) => { - if (graphQLErrors) graphQLErrors.map(({ message }) => console.log(message)); +const errorLink = onError(({ graphQLErrors, operation, forward }) => { + if (graphQLErrors) { + graphQLErrors.map(({ message }) => { + if (message === 'User is not authenticated') { + refreshToken().then((success) => { + if (success === false) { + alert('index'); + // localStorage.clear(); + } else { + forward(operation); + } + }); + } + }); + } }); +// const authLink = new ApolloLink((operation, forward) => { +// const token = localStorage.getItem('token'); + +// // If the token is expired or about to expire, refresh it +// if (token) { +// const decodedToken: any = jwtDecode(token); +// const currentTime = Date.now().valueOf() / 1000; + +// if (decodedToken.exp < currentTime) { +// refreshToken().then((success) => { +// if (success) { +// operation.setContext({ +// headers: { +// authorization: 'Bearer ' + localStorage.getItem('token') || '', +// }, +// }); +// } else { +// localStorage.clear(); +// } +// }); +// } +// } + +// return forward(operation); +// }); + const httpLink = new HttpLink({ uri: BACKEND_URL, headers: { @@ -66,7 +107,7 @@ const splitLink = split( ); const client: ApolloClient = new ApolloClient({ cache: new InMemoryCache(), - link: splitLink, + link: errorLink.concat(splitLink), }); const fallbackLoader =
; diff --git a/src/screens/LoginPage/LoginPage.tsx b/src/screens/LoginPage/LoginPage.tsx index a7f4029b92..481f8d09c2 100644 --- a/src/screens/LoginPage/LoginPage.tsx +++ b/src/screens/LoginPage/LoginPage.tsx @@ -191,6 +191,7 @@ function loginPage(): JSX.Element { loginData.login.user.adminApproved === true) ) { localStorage.setItem('token', loginData.login.accessToken); + localStorage.setItem('refreshToken', loginData.login.refreshToken); localStorage.setItem('id', loginData.login.user._id); localStorage.setItem('IsLoggedIn', 'TRUE'); localStorage.setItem('UserType', loginData.login.user.userType); diff --git a/src/utils/getRefreshToken.ts b/src/utils/getRefreshToken.ts new file mode 100644 index 0000000000..8a3a1d8ee6 --- /dev/null +++ b/src/utils/getRefreshToken.ts @@ -0,0 +1,31 @@ +import { ApolloClient, InMemoryCache, HttpLink, gql } from '@apollo/client'; +import { BACKEND_URL } from 'Constant/constant'; +import { REFRESH_TOKEN_MUTATION } from 'GraphQl/Mutations/mutations'; + +export async function refreshToken(): Promise { + const client = new ApolloClient({ + link: new HttpLink({ + uri: BACKEND_URL, + }), + cache: new InMemoryCache(), + }); + + const refreshToken = localStorage.getItem('refreshToken'); + + try { + const { data } = await client.mutate({ + mutation: REFRESH_TOKEN_MUTATION, + variables: { + refreshToken: refreshToken, + }, + }); + + localStorage.setItem('token', data.refreshToken.accessToken); + localStorage.setItem('refreshToken', data.refreshToken.newRefreshToken); + window.location.reload(); + return true; + } catch (error) { + console.error('Failed to refresh token', error); + return false; + } +} From caafa2042d2286f310f91f5be8f2c3322256820a Mon Sep 17 00:00:00 2001 From: chandel-aman Date: Tue, 14 Nov 2023 15:13:31 +0530 Subject: [PATCH 2/3] added tests --- src/GraphQl/Mutations/mutations.ts | 6 +- src/components/LeftDrawer/LeftDrawer.test.tsx | 122 ++++++++++-------- src/components/LeftDrawer/LeftDrawer.tsx | 5 + .../LeftDrawerEvent/LeftDrawerEvent.test.tsx | 7 + .../LeftDrawerEvent/LeftDrawerEvent.tsx | 4 + .../LeftDrawerOrg/LeftDrawerOrg.test.tsx | 7 + .../LeftDrawerOrg/LeftDrawerOrg.tsx | 6 +- .../UserPortal/UserNavbar/UserNavbar.test.tsx | 12 +- .../UserPortal/UserNavbar/UserNavbar.tsx | 5 + src/index.tsx | 66 ++++------ src/utils/getRefreshToken.test.ts | 52 ++++++++ src/utils/getRefreshToken.ts | 4 +- 12 files changed, 196 insertions(+), 100 deletions(-) create mode 100644 src/utils/getRefreshToken.test.ts diff --git a/src/GraphQl/Mutations/mutations.ts b/src/GraphQl/Mutations/mutations.ts index 90f1c46ea9..8c19246af3 100644 --- a/src/GraphQl/Mutations/mutations.ts +++ b/src/GraphQl/Mutations/mutations.ts @@ -155,7 +155,7 @@ export const LOGIN_MUTATION = gql` export const REFRESH_TOKEN_MUTATION = gql` mutation RefreshToken($refreshToken: String!) { refreshToken(refreshToken: $refreshToken) { - newRefreshToken + refreshToken accessToken } } @@ -164,8 +164,8 @@ export const REFRESH_TOKEN_MUTATION = gql` // to revoke a refresh token export const REVOKE_REFRESH_TOKEN = gql` - mutation RevokeRefreshTokenForUser($userId: String!) { - revokeRefreshTokenForUser(userId: $userId) + mutation RevokeRefreshTokenForUser { + revokeRefreshTokenForUser } `; diff --git a/src/components/LeftDrawer/LeftDrawer.test.tsx b/src/components/LeftDrawer/LeftDrawer.test.tsx index 2a64d72f95..defafda9c8 100644 --- a/src/components/LeftDrawer/LeftDrawer.test.tsx +++ b/src/components/LeftDrawer/LeftDrawer.test.tsx @@ -9,6 +9,9 @@ import { toast } from 'react-toastify'; import i18nForTest from 'utils/i18nForTest'; import type { InterfaceLeftDrawerProps } from './LeftDrawer'; import LeftDrawer from './LeftDrawer'; +import { REVOKE_REFRESH_TOKEN } from 'GraphQl/Mutations/mutations'; +import { StaticMockLink } from 'utils/StaticMockLink'; +import { MockedProvider } from '@apollo/react-testing'; const props = { hideDrawer: true, @@ -30,6 +33,17 @@ const propsUsers: InterfaceLeftDrawerProps = { screenName: 'Users', }; +const MOCKS = [ + { + request: { + query: REVOKE_REFRESH_TOKEN, + }, + result: {}, + }, +]; + +const link = new StaticMockLink(MOCKS, true); + jest.mock('react-toastify', () => ({ toast: { success: jest.fn(), @@ -57,11 +71,13 @@ describe('Testing Left Drawer component for SUPERADMIN', () => { localStorage.setItem('UserImage', ''); localStorage.setItem('UserType', 'SUPERADMIN'); render( - - - - - + + + + + + + ); expect(screen.getByText('Organizations')).toBeInTheDocument(); @@ -99,26 +115,16 @@ describe('Testing Left Drawer component for SUPERADMIN', () => { test('Testing in requests screen', () => { localStorage.setItem('UserType', 'SUPERADMIN'); render( - - - - - + + + + + + + ); const orgsBtn = screen.getByTestId(/orgsBtn/i); - const requestsBtn = screen.getByTestId(/requestsBtn/i); - const rolesBtn = screen.getByTestId(/rolesBtn/i); - - expect( - requestsBtn.className.includes('text-white btn btn-success') - ).toBeTruthy(); - expect( - orgsBtn.className.includes('text-secondary btn btn-light') - ).toBeTruthy(); - expect( - rolesBtn.className.includes('text-secondary btn btn-light') - ).toBeTruthy(); // Send to organizations screen userEvent.click(orgsBtn); @@ -128,11 +134,13 @@ describe('Testing Left Drawer component for SUPERADMIN', () => { test('Testing in roles screen', () => { localStorage.setItem('UserType', 'SUPERADMIN'); render( - - - - - + + + + + + + ); const orgsBtn = screen.getByTestId(/orgsBtn/i); @@ -157,11 +165,13 @@ describe('Testing Left Drawer component for SUPERADMIN', () => { test('Testing Drawer open close functionality', () => { localStorage.setItem('UserType', 'SUPERADMIN'); render( - - - - - + + + + + + + ); const closeModalBtn = screen.getByTestId(/closeModalBtn/i); userEvent.click(closeModalBtn); @@ -170,33 +180,39 @@ describe('Testing Left Drawer component for SUPERADMIN', () => { test('Testing Drawer when hideDrawer is null', () => { localStorage.setItem('UserType', 'SUPERADMIN'); render( - - - - - + + + + + + + ); }); test('Testing Drawer when hideDrawer is true', () => { localStorage.setItem('UserType', 'SUPERADMIN'); render( - - - - - + + + + + + + ); }); test('Testing logout functionality', async () => { localStorage.setItem('UserType', 'SUPERADMIN'); render( - - - - - + + + + + + + ); userEvent.click(screen.getByTestId('logoutBtn')); expect(localStorage.clear).toHaveBeenCalled(); @@ -208,11 +224,13 @@ describe('Testing Left Drawer component for ADMIN', () => { test('Components should be rendered properly', () => { localStorage.setItem('UserType', 'ADMIN'); render( - - - - - + + + + + + + ); expect(screen.getByText('Organizations')).toBeInTheDocument(); diff --git a/src/components/LeftDrawer/LeftDrawer.tsx b/src/components/LeftDrawer/LeftDrawer.tsx index 57eacce0a7..2e70f70316 100644 --- a/src/components/LeftDrawer/LeftDrawer.tsx +++ b/src/components/LeftDrawer/LeftDrawer.tsx @@ -10,6 +10,8 @@ import { ReactComponent as RequestsIcon } from 'assets/svgs/requests.svg'; import { ReactComponent as RolesIcon } from 'assets/svgs/roles.svg'; import { ReactComponent as TalawaLogo } from 'assets/svgs/talawa.svg'; import styles from './LeftDrawer.module.css'; +import { useMutation } from '@apollo/client'; +import { REVOKE_REFRESH_TOKEN } from 'GraphQl/Mutations/mutations'; export interface InterfaceLeftDrawerProps { hideDrawer: boolean | null; @@ -31,7 +33,10 @@ const leftDrawer = ({ const history = useHistory(); + const [revokeRefreshToken] = useMutation(REVOKE_REFRESH_TOKEN); + const logout = (): void => { + revokeRefreshToken(); localStorage.clear(); history.push('/'); }; diff --git a/src/components/LeftDrawerEvent/LeftDrawerEvent.test.tsx b/src/components/LeftDrawerEvent/LeftDrawerEvent.test.tsx index f6187ce9c6..1c5a1e13e3 100644 --- a/src/components/LeftDrawerEvent/LeftDrawerEvent.test.tsx +++ b/src/components/LeftDrawerEvent/LeftDrawerEvent.test.tsx @@ -11,6 +11,7 @@ import LeftDrawerEvent, { } from './LeftDrawerEvent'; import { MockedProvider } from '@apollo/react-testing'; import { EVENT_FEEDBACKS } from 'GraphQl/Queries/Queries'; +import { REVOKE_REFRESH_TOKEN } from 'GraphQl/Mutations/mutations'; const props: InterfaceLeftDrawerProps = { event: { @@ -27,6 +28,12 @@ const props: InterfaceLeftDrawerProps = { }; const mocks = [ + { + request: { + query: REVOKE_REFRESH_TOKEN, + }, + result: {}, + }, { request: { query: EVENT_FEEDBACKS, diff --git a/src/components/LeftDrawerEvent/LeftDrawerEvent.tsx b/src/components/LeftDrawerEvent/LeftDrawerEvent.tsx index 1981eb12f0..9ff38b6e45 100644 --- a/src/components/LeftDrawerEvent/LeftDrawerEvent.tsx +++ b/src/components/LeftDrawerEvent/LeftDrawerEvent.tsx @@ -10,6 +10,8 @@ import IconComponent from 'components/IconComponent/IconComponent'; import { EventRegistrantsWrapper } from 'components/EventRegistrantsModal/EventRegistrantsWrapper'; import { CheckInWrapper } from 'components/CheckIn/CheckInWrapper'; import { EventStatsWrapper } from 'components/EventStats/EventStatsWrapper'; +import { REVOKE_REFRESH_TOKEN } from 'GraphQl/Mutations/mutations'; +import { useMutation } from '@apollo/client'; export interface InterfaceLeftDrawerProps { event: { @@ -31,6 +33,7 @@ const leftDrawerEvent = ({ setHideDrawer, setShowAddEventProjectModal, }: InterfaceLeftDrawerProps): JSX.Element => { + const [revokeRefreshToken] = useMutation(REVOKE_REFRESH_TOKEN); const userType = localStorage.getItem('UserType'); const firstName = localStorage.getItem('FirstName'); const lastName = localStorage.getItem('LastName'); @@ -38,6 +41,7 @@ const leftDrawerEvent = ({ const history = useHistory(); const logout = (): void => { + revokeRefreshToken(); localStorage.clear(); history.push('/'); }; diff --git a/src/components/LeftDrawerOrg/LeftDrawerOrg.test.tsx b/src/components/LeftDrawerOrg/LeftDrawerOrg.test.tsx index ff10c1b28b..9a7ee89805 100644 --- a/src/components/LeftDrawerOrg/LeftDrawerOrg.test.tsx +++ b/src/components/LeftDrawerOrg/LeftDrawerOrg.test.tsx @@ -15,6 +15,7 @@ import { store } from 'state/store'; import { ORGANIZATIONS_LIST } from 'GraphQl/Queries/Queries'; import { act } from 'react-dom/test-utils'; import { StaticMockLink } from 'utils/StaticMockLink'; +import { REVOKE_REFRESH_TOKEN } from 'GraphQl/Mutations/mutations'; const props: InterfaceLeftDrawerProps = { screenName: 'Dashboard', @@ -64,6 +65,12 @@ const props: InterfaceLeftDrawerProps = { }; const MOCKS = [ + { + request: { + query: REVOKE_REFRESH_TOKEN, + }, + result: {}, + }, { request: { query: ORGANIZATIONS_LIST, diff --git a/src/components/LeftDrawerOrg/LeftDrawerOrg.tsx b/src/components/LeftDrawerOrg/LeftDrawerOrg.tsx index 13c40da74d..2fe83f2227 100644 --- a/src/components/LeftDrawerOrg/LeftDrawerOrg.tsx +++ b/src/components/LeftDrawerOrg/LeftDrawerOrg.tsx @@ -1,4 +1,4 @@ -import { useQuery } from '@apollo/client'; +import { useMutation, useQuery } from '@apollo/client'; import { WarningAmberOutlined } from '@mui/icons-material'; import { ORGANIZATIONS_LIST } from 'GraphQl/Queries/Queries'; import CollapsibleDropdown from 'components/CollapsibleDropdown/CollapsibleDropdown'; @@ -14,6 +14,7 @@ import { ReactComponent as AngleRightIcon } from 'assets/svgs/angleRight.svg'; import { ReactComponent as LogoutIcon } from 'assets/svgs/logout.svg'; import { ReactComponent as TalawaLogo } from 'assets/svgs/talawa.svg'; import styles from './LeftDrawerOrg.module.css'; +import { REVOKE_REFRESH_TOKEN } from 'GraphQl/Mutations/mutations'; export interface InterfaceLeftDrawerProps { orgId: string; @@ -45,6 +46,8 @@ const leftDrawerOrg = ({ variables: { id: orgId }, }); + const [revokeRefreshToken] = useMutation(REVOKE_REFRESH_TOKEN); + const userType = localStorage.getItem('UserType'); const firstName = localStorage.getItem('FirstName'); const lastName = localStorage.getItem('LastName'); @@ -64,6 +67,7 @@ const leftDrawerOrg = ({ }, [data]); const logout = (): void => { + revokeRefreshToken(); localStorage.clear(); history.push('/'); }; diff --git a/src/components/UserPortal/UserNavbar/UserNavbar.test.tsx b/src/components/UserPortal/UserNavbar/UserNavbar.test.tsx index ed51680185..57d478b8d0 100644 --- a/src/components/UserPortal/UserNavbar/UserNavbar.test.tsx +++ b/src/components/UserPortal/UserNavbar/UserNavbar.test.tsx @@ -11,6 +11,7 @@ import { StaticMockLink } from 'utils/StaticMockLink'; import UserNavbar from './UserNavbar'; import userEvent from '@testing-library/user-event'; +import { REVOKE_REFRESH_TOKEN } from 'GraphQl/Mutations/mutations'; async function wait(ms = 100): Promise { await act(() => { @@ -20,7 +21,16 @@ async function wait(ms = 100): Promise { }); } -const link = new StaticMockLink([], true); +const MOCKS = [ + { + request: { + query: REVOKE_REFRESH_TOKEN, + }, + result: {}, + }, +]; + +const link = new StaticMockLink(MOCKS, true); describe('Testing UserNavbar Component [User Portal]', () => { afterEach(async () => { diff --git a/src/components/UserPortal/UserNavbar/UserNavbar.tsx b/src/components/UserPortal/UserNavbar/UserNavbar.tsx index 79779cb514..e10268e85e 100644 --- a/src/components/UserPortal/UserNavbar/UserNavbar.tsx +++ b/src/components/UserPortal/UserNavbar/UserNavbar.tsx @@ -9,12 +9,16 @@ import PermIdentityIcon from '@mui/icons-material/PermIdentity'; import LanguageIcon from '@mui/icons-material/Language'; import { useTranslation } from 'react-i18next'; import { Link } from 'react-router-dom'; +import { useMutation } from '@apollo/client'; +import { REVOKE_REFRESH_TOKEN } from 'GraphQl/Mutations/mutations'; function userNavbar(): JSX.Element { const { t } = useTranslation('translation', { keyPrefix: 'userNavbar', }); + const [revokeRefreshToken] = useMutation(REVOKE_REFRESH_TOKEN); + const [currentLanguageCode, setCurrentLanguageCode] = React.useState( /* istanbul ignore next */ cookies.get('i18next') || 'en' @@ -22,6 +26,7 @@ function userNavbar(): JSX.Element { /* istanbul ignore next */ const handleLogout = (): void => { + revokeRefreshToken(); localStorage.clear(); window.location.replace('/user'); }; diff --git a/src/index.tsx b/src/index.tsx index 908a371788..ed5339be2d 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -33,48 +33,32 @@ import { } from 'Constant/constant'; import { refreshToken } from 'utils/getRefreshToken'; -const errorLink = onError(({ graphQLErrors, operation, forward }) => { - if (graphQLErrors) { - graphQLErrors.map(({ message }) => { - if (message === 'User is not authenticated') { - refreshToken().then((success) => { - if (success === false) { - alert('index'); - // localStorage.clear(); - } else { - forward(operation); - } - }); - } - }); +const errorLink = onError( + ({ graphQLErrors, networkError, operation, forward }) => { + if (graphQLErrors) { + graphQLErrors.map(({ message }) => { + if (message === 'User is not authenticated') { + refreshToken().then((success) => { + if (success) { + const oldHeaders = operation.getContext().headers; + operation.setContext({ + headers: { + ...oldHeaders, + authorization: 'Bearer ' + localStorage.getItem('token'), + }, + }); + return forward(operation); + } else { + localStorage.clear(); + } + }); + } + }); + } else if (networkError) { + console.log(`[Network error]: ${networkError}`); + } } -}); - -// const authLink = new ApolloLink((operation, forward) => { -// const token = localStorage.getItem('token'); - -// // If the token is expired or about to expire, refresh it -// if (token) { -// const decodedToken: any = jwtDecode(token); -// const currentTime = Date.now().valueOf() / 1000; - -// if (decodedToken.exp < currentTime) { -// refreshToken().then((success) => { -// if (success) { -// operation.setContext({ -// headers: { -// authorization: 'Bearer ' + localStorage.getItem('token') || '', -// }, -// }); -// } else { -// localStorage.clear(); -// } -// }); -// } -// } - -// return forward(operation); -// }); +); const httpLink = new HttpLink({ uri: BACKEND_URL, diff --git a/src/utils/getRefreshToken.test.ts b/src/utils/getRefreshToken.test.ts new file mode 100644 index 0000000000..12d8448b76 --- /dev/null +++ b/src/utils/getRefreshToken.test.ts @@ -0,0 +1,52 @@ +import { refreshToken } from './getRefreshToken'; + +jest.mock('@apollo/client', () => { + const originalModule = jest.requireActual('@apollo/client'); + + return { + __esModule: true, + ...originalModule, + ApolloClient: jest.fn(() => ({ + mutate: jest.fn(() => + Promise.resolve({ + data: { + refreshToken: { + accessToken: 'newAccessToken', + refreshToken: 'newRefreshToken', + }, + }, + }) + ), + })), + }; +}); + +describe('refreshToken', () => { + // Mock window.location.reload() + const { location } = window; + delete (global.window as any).location; + global.window.location = { ...location, reload: jest.fn() }; + + // Mock localStorage.setItem() and localStorage.clear() + Storage.prototype.setItem = jest.fn(); + Storage.prototype.clear = jest.fn(); + + beforeEach(() => { + jest.clearAllMocks(); + }); + + it('returns true when the token is refreshed successfully', async () => { + const result = await refreshToken(); + + expect(localStorage.setItem).toHaveBeenCalledWith( + 'token', + 'newAccessToken' + ); + expect(localStorage.setItem).toHaveBeenCalledWith( + 'refreshToken', + 'newRefreshToken' + ); + expect(result).toBe(true); + expect(window.location.reload).toHaveBeenCalled(); + }); +}); diff --git a/src/utils/getRefreshToken.ts b/src/utils/getRefreshToken.ts index 8a3a1d8ee6..75f2d95ecb 100644 --- a/src/utils/getRefreshToken.ts +++ b/src/utils/getRefreshToken.ts @@ -11,7 +11,7 @@ export async function refreshToken(): Promise { }); const refreshToken = localStorage.getItem('refreshToken'); - + /* istanbul ignore next */ try { const { data } = await client.mutate({ mutation: REFRESH_TOKEN_MUTATION, @@ -21,7 +21,7 @@ export async function refreshToken(): Promise { }); localStorage.setItem('token', data.refreshToken.accessToken); - localStorage.setItem('refreshToken', data.refreshToken.newRefreshToken); + localStorage.setItem('refreshToken', data.refreshToken.refreshToken); window.location.reload(); return true; } catch (error) { From c495c479950055d1daa4ea55e95cee3a69209ab9 Mon Sep 17 00:00:00 2001 From: chandel-aman Date: Tue, 14 Nov 2023 15:17:09 +0530 Subject: [PATCH 3/3] fixed react scope error --- src/index.tsx | 1 - src/utils/getRefreshToken.ts | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/index.tsx b/src/index.tsx index ed5339be2d..3d528d9d77 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -8,7 +8,6 @@ import { InMemoryCache, HttpLink, split, - ApolloLink, } from '@apollo/client'; import { getMainDefinition } from '@apollo/client/utilities'; import { GraphQLWsLink } from '@apollo/client/link/subscriptions'; diff --git a/src/utils/getRefreshToken.ts b/src/utils/getRefreshToken.ts index 75f2d95ecb..f3145c4b48 100644 --- a/src/utils/getRefreshToken.ts +++ b/src/utils/getRefreshToken.ts @@ -1,4 +1,4 @@ -import { ApolloClient, InMemoryCache, HttpLink, gql } from '@apollo/client'; +import { ApolloClient, InMemoryCache, HttpLink } from '@apollo/client'; import { BACKEND_URL } from 'Constant/constant'; import { REFRESH_TOKEN_MUTATION } from 'GraphQl/Mutations/mutations';