-
Notifications
You must be signed in to change notification settings - Fork 270
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[SDK-1577] [SDK-1578] Add login functionality (#5)
Add login functionality
- Loading branch information
1 parent
009a909
commit ceb2f16
Showing
20 changed files
with
471 additions
and
80 deletions.
There are no files selected for viewing
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
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,19 @@ | ||
export const handleRedirectCallback = jest | ||
.fn() | ||
.mockResolvedValue({ appState: {} }); | ||
export const getTokenSilently = jest.fn(); | ||
export const getUser = jest.fn(); | ||
export const isAuthenticated = jest.fn().mockResolvedValue(false); | ||
export const loginWithRedirect = jest.fn(); | ||
export const logout = jest.fn(); | ||
|
||
export const Auth0Client = jest.fn().mockImplementation(() => { | ||
return { | ||
handleRedirectCallback, | ||
getTokenSilently, | ||
getUser, | ||
isAuthenticated, | ||
loginWithRedirect, | ||
logout, | ||
}; | ||
}); |
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,174 @@ | ||
import { useContext } from 'react'; | ||
import Auth0Context from '../src/auth0-context'; | ||
import { renderHook } from '@testing-library/react-hooks'; | ||
import { | ||
Auth0Client, | ||
// @ts-ignore | ||
getTokenSilently, | ||
// @ts-ignore | ||
isAuthenticated, | ||
// @ts-ignore | ||
getUser, | ||
// @ts-ignore | ||
handleRedirectCallback, | ||
// @ts-ignore | ||
loginWithRedirect, | ||
// @ts-ignore | ||
logout, | ||
} from '@auth0/auth0-spa-js'; | ||
import { createWrapper } from './helpers'; | ||
|
||
describe('Auth0Provider', () => { | ||
it('should provide the Auth0Provider result', async () => { | ||
const wrapper = createWrapper(); | ||
const { result, waitForNextUpdate } = renderHook( | ||
() => useContext(Auth0Context), | ||
{ wrapper } | ||
); | ||
expect(result.current).toBeDefined(); | ||
await waitForNextUpdate(); | ||
}); | ||
|
||
it('should configure an instance of the Auth0Client', async () => { | ||
const opts = { | ||
client_id: 'foo', | ||
domain: 'bar', | ||
}; | ||
const wrapper = createWrapper(opts); | ||
const { waitForNextUpdate } = renderHook(() => useContext(Auth0Context), { | ||
wrapper, | ||
}); | ||
expect(Auth0Client).toHaveBeenCalledWith(opts); | ||
await waitForNextUpdate(); | ||
}); | ||
|
||
it('should get token silently when logged out', async () => { | ||
const wrapper = createWrapper(); | ||
const { waitForNextUpdate, result } = renderHook( | ||
() => useContext(Auth0Context), | ||
{ wrapper } | ||
); | ||
expect(result.current.isLoading).toBe(true); | ||
await waitForNextUpdate(); | ||
expect(result.current.isLoading).toBe(false); | ||
expect(getTokenSilently).toHaveBeenCalled(); | ||
expect(result.current.isAuthenticated).toBe(false); | ||
}); | ||
|
||
it('should get token silently when logged in', async () => { | ||
isAuthenticated.mockResolvedValue(true); | ||
getUser.mockResolvedValue('__test_user__'); | ||
const wrapper = createWrapper(); | ||
const { waitForNextUpdate, result } = renderHook( | ||
() => useContext(Auth0Context), | ||
{ wrapper } | ||
); | ||
await waitForNextUpdate(); | ||
expect(getTokenSilently).toHaveBeenCalled(); | ||
expect(result.current.isAuthenticated).toBe(true); | ||
expect(result.current.user).toBe('__test_user__'); | ||
}); | ||
|
||
it('should handle login_required errors when getting token', async () => { | ||
getTokenSilently.mockRejectedValue({ error: 'login_required' }); | ||
const wrapper = createWrapper(); | ||
const { waitForNextUpdate, result } = renderHook( | ||
() => useContext(Auth0Context), | ||
{ wrapper } | ||
); | ||
await waitForNextUpdate(); | ||
expect(getTokenSilently).toHaveBeenCalled(); | ||
expect(result.current.error).toBeUndefined(); | ||
expect(result.current.isAuthenticated).toBe(false); | ||
}); | ||
|
||
it('should handle other errors when getting token', async () => { | ||
getTokenSilently.mockRejectedValue({ error: '__test_error__' }); | ||
const wrapper = createWrapper(); | ||
const { waitForNextUpdate, result } = renderHook( | ||
() => useContext(Auth0Context), | ||
{ wrapper } | ||
); | ||
await waitForNextUpdate(); | ||
expect(getTokenSilently).toHaveBeenCalled(); | ||
expect(result.current.error).toStrictEqual({ error: '__test_error__' }); | ||
expect(result.current.isAuthenticated).toBe(false); | ||
}); | ||
|
||
it('should handle redirect callback success and clear the url', async () => { | ||
window.history.pushState( | ||
{}, | ||
document.title, | ||
'/?code=__test_code__&state=__test_state__' | ||
); | ||
expect(window.location.href).toBe( | ||
'https://www.example.com/?code=__test_code__&state=__test_state__' | ||
); | ||
const wrapper = createWrapper(); | ||
const { waitForNextUpdate } = renderHook(() => useContext(Auth0Context), { | ||
wrapper, | ||
}); | ||
await waitForNextUpdate(); | ||
expect(handleRedirectCallback).toHaveBeenCalled(); | ||
expect(window.location.href).toBe('https://www.example.com/'); | ||
}); | ||
|
||
it('should handle redirect callback errors', async () => { | ||
window.history.pushState({}, document.title, '/?error=__test_error__'); | ||
handleRedirectCallback.mockRejectedValue('__test_error__'); | ||
const wrapper = createWrapper(); | ||
const { waitForNextUpdate, result } = renderHook( | ||
() => useContext(Auth0Context), | ||
{ wrapper } | ||
); | ||
await waitForNextUpdate(); | ||
expect(handleRedirectCallback).toHaveBeenCalled(); | ||
expect(result.current.error).toStrictEqual('__test_error__'); | ||
}); | ||
|
||
it('should handle redirect and call a custom handler', async () => { | ||
window.history.pushState( | ||
{}, | ||
document.title, | ||
'/?code=__test_code__&state=__test_state__' | ||
); | ||
handleRedirectCallback.mockResolvedValue({ appState: { foo: 'bar' } }); | ||
const onRedirectCallback = jest.fn(); | ||
const wrapper = createWrapper({ | ||
onRedirectCallback, | ||
}); | ||
const { waitForNextUpdate } = renderHook(() => useContext(Auth0Context), { | ||
wrapper, | ||
}); | ||
await waitForNextUpdate(); | ||
expect(onRedirectCallback).toHaveBeenCalledWith({ foo: 'bar' }); | ||
}); | ||
|
||
it('should provide a login method', async () => { | ||
const wrapper = createWrapper(); | ||
const { waitForNextUpdate, result } = renderHook( | ||
() => useContext(Auth0Context), | ||
{ wrapper } | ||
); | ||
await waitForNextUpdate(); | ||
expect(result.current.login).toBeInstanceOf(Function); | ||
await result.current.login({ redirect_uri: '__redirect_uri__' }); | ||
expect(loginWithRedirect).toHaveBeenCalledWith({ | ||
redirect_uri: '__redirect_uri__', | ||
}); | ||
}); | ||
|
||
it('should provide a logout method', async () => { | ||
const wrapper = createWrapper(); | ||
const { waitForNextUpdate, result } = renderHook( | ||
() => useContext(Auth0Context), | ||
{ wrapper } | ||
); | ||
await waitForNextUpdate(); | ||
expect(result.current.logout).toBeInstanceOf(Function); | ||
await result.current.logout({ returnTo: '__return_to__' }); | ||
expect(logout).toHaveBeenCalledWith({ | ||
returnTo: '__return_to__', | ||
}); | ||
}); | ||
}); |
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,42 @@ | ||
import { reducer } from '../src/reducer'; | ||
import { initialAuthState } from '../src/auth-state'; | ||
|
||
describe('reducer', () => { | ||
it('should initialise when authenticated', async () => { | ||
const payload = { | ||
isAuthenticated: true, | ||
user: 'Bob', | ||
}; | ||
expect( | ||
reducer(initialAuthState, { type: 'INITIALISED', ...payload }) | ||
).toEqual({ | ||
...initialAuthState, | ||
isLoading: false, | ||
...payload, | ||
}); | ||
}); | ||
|
||
it('should initialise when not authenticated', async () => { | ||
const payload = { | ||
isAuthenticated: false, | ||
}; | ||
expect( | ||
reducer(initialAuthState, { type: 'INITIALISED', ...payload }) | ||
).toEqual({ | ||
...initialAuthState, | ||
isLoading: false, | ||
...payload, | ||
}); | ||
}); | ||
|
||
it('should handle error state', async () => { | ||
const payload = { | ||
error: new Error('__test_error__'), | ||
}; | ||
expect(reducer(initialAuthState, { type: 'ERROR', ...payload })).toEqual({ | ||
...initialAuthState, | ||
isLoading: false, | ||
...payload, | ||
}); | ||
}); | ||
}); |
This file was deleted.
Oops, something went wrong.
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
import useAuth0 from '../src/use-auth0'; | ||
import { renderHook } from '@testing-library/react-hooks'; | ||
import { createWrapper } from './helpers'; | ||
|
||
describe('useAuth0', () => { | ||
it('should provide the auth context', async () => { | ||
const wrapper = createWrapper(); | ||
const { | ||
result: { current }, | ||
waitForNextUpdate, | ||
} = renderHook(useAuth0, { wrapper }); | ||
await waitForNextUpdate(); | ||
expect(current).toBeDefined(); | ||
}); | ||
|
||
it('should throw with no provider', () => { | ||
const { | ||
result: { current }, | ||
} = renderHook(useAuth0); | ||
expect(current.login).toThrowError( | ||
'You forgot to wrap your component in <Auth0Provider>.' | ||
); | ||
}); | ||
}); |
This file was deleted.
Oops, something went wrong.
Oops, something went wrong.