From 4175e9746de2c4b21679cfa7da4707f15d65ad18 Mon Sep 17 00:00:00 2001 From: Rita Zerrizuela Date: Wed, 6 Jan 2021 13:15:06 -0300 Subject: [PATCH 1/3] Add error management to useUser --- EXAMPLES.md | 3 +- README.md | 3 +- examples/basic-example/pages/index.jsx | 23 ++++++++----- .../basic-example/pages/protected-page.jsx | 13 ++++++-- examples/kitchen-sink-example/pages/index.tsx | 23 ++++++++----- .../kitchen-sink-example/pages/profile.tsx | 15 ++++++--- src/frontend/use-user.tsx | 22 +++++++++---- src/frontend/with-page-auth-required.tsx | 33 ++++++++++++++++--- tests/fixtures/frontend.tsx | 13 +++----- tests/frontend/use-user.test.tsx | 5 +++ .../frontend/with-page-auth-required.test.tsx | 10 ++++++ 11 files changed, 117 insertions(+), 46 deletions(-) diff --git a/EXAMPLES.md b/EXAMPLES.md index e4d0bc752..84b945080 100644 --- a/EXAMPLES.md +++ b/EXAMPLES.md @@ -61,9 +61,10 @@ Check the user's authentication state and log them in or out from the front end import { useUser } from '@auth0/nextjs-auth0'; export default () => { - const { user, isLoading } = useUser(); + const { user, error, isLoading } = useUser(); if (isLoading) return
Loading...
; + if (error) return
{error.message}
; if (user) { return ( diff --git a/README.md b/README.md index a98a4622d..fb2584981 100644 --- a/README.md +++ b/README.md @@ -105,9 +105,10 @@ Check whether a user is authenticated by checking that `user` has a value, and l import { useUser } from '@auth0/nextjs-auth0'; export default () => { - const { user, isLoading } = useUser(); + const { user, error, isLoading } = useUser(); if (isLoading) return
Loading...
; + if (error) return
{error.message}
; if (user) { return ( diff --git a/examples/basic-example/pages/index.jsx b/examples/basic-example/pages/index.jsx index e3940e651..fc61c5ab0 100644 --- a/examples/basic-example/pages/index.jsx +++ b/examples/basic-example/pages/index.jsx @@ -4,7 +4,7 @@ import { useUser } from '@auth0/nextjs-auth0'; import Layout from '../components/layout'; export default function Home() { - const { user, isLoading } = useUser(); + const { user, error, isLoading } = useUser(); return ( @@ -12,14 +12,10 @@ export default function Home() { {isLoading &&

Loading login info...

} - {!isLoading && !user && ( + {error && ( <> -

- To test the login click in Login -

-

- Once you have logged in you should be able to click in Protected Page and Logout -

+

Error

+
{error.message}
)} @@ -29,6 +25,17 @@ export default function Home() {
{JSON.stringify(user, null, 2)}
)} + + {!isLoading && !error && !user && ( + <> +

+ To test the login click in Login +

+

+ Once you have logged in you should be able to click in Protected Page and Logout +

+ + )}
); } diff --git a/examples/basic-example/pages/protected-page.jsx b/examples/basic-example/pages/protected-page.jsx index 1b50251b7..e2a056a83 100644 --- a/examples/basic-example/pages/protected-page.jsx +++ b/examples/basic-example/pages/protected-page.jsx @@ -4,7 +4,7 @@ import { useUser, withPageAuthRequired } from '@auth0/nextjs-auth0'; import Layout from '../components/layout'; export default function ProtectedPage() { - const { user, isLoading } = useUser(); + const { user, error, isLoading } = useUser(); return ( @@ -12,9 +12,16 @@ export default function ProtectedPage() { {isLoading &&

Loading profile...

} - {!isLoading && user && ( + {error && ( <> -

Profile:

+

Error

+
{error.message}
+ + )} + + {user && ( + <> +

Profile

{JSON.stringify(user, null, 2)}
)} diff --git a/examples/kitchen-sink-example/pages/index.tsx b/examples/kitchen-sink-example/pages/index.tsx index eee707566..960500188 100644 --- a/examples/kitchen-sink-example/pages/index.tsx +++ b/examples/kitchen-sink-example/pages/index.tsx @@ -4,7 +4,7 @@ import { useUser } from '@auth0/nextjs-auth0'; import Layout from '../components/layout'; export default function Home(): React.ReactElement { - const { user, isLoading } = useUser(); + const { user, error, isLoading } = useUser(); return ( @@ -12,14 +12,10 @@ export default function Home(): React.ReactElement { {isLoading &&

Loading login info...

} - {!isLoading && !user && ( + {error && ( <> -

- To test the login click in Login -

-

- Once you have logged in you should be able to click in Profile and Logout -

+

Error

+
{error.message}
)} @@ -29,6 +25,17 @@ export default function Home(): React.ReactElement {
{JSON.stringify(user, null, 2)}
)} + + {!isLoading && !error && !user && ( + <> +

+ To test the login click in Login +

+

+ Once you have logged in you should be able to click in Protected Page and Logout +

+ + )}
); } diff --git a/examples/kitchen-sink-example/pages/profile.tsx b/examples/kitchen-sink-example/pages/profile.tsx index d01966d6f..e9b0844af 100644 --- a/examples/kitchen-sink-example/pages/profile.tsx +++ b/examples/kitchen-sink-example/pages/profile.tsx @@ -4,7 +4,7 @@ import { useUser, withPageAuthRequired } from '@auth0/nextjs-auth0'; import Layout from '../components/layout'; export default withPageAuthRequired(function Profile(): React.ReactElement { - const { user, isLoading } = useUser(); + const { user, error, isLoading } = useUser(); return ( @@ -12,10 +12,17 @@ export default withPageAuthRequired(function Profile(): React.ReactElement { {isLoading &&

Loading profile...

} - {!isLoading && user && ( + {error && ( <> -

Profile:

-
{JSON.stringify(user, null, 2)}
+

Error

+
{error.message}
+ + )} + + {user && ( + <> +

Profile

+
{JSON.stringify(user, null, 2)}
)}
diff --git a/src/frontend/use-user.tsx b/src/frontend/use-user.tsx index 1d29b7711..dc405deb7 100644 --- a/src/frontend/use-user.tsx +++ b/src/frontend/use-user.tsx @@ -23,6 +23,7 @@ export interface UserProfile { */ export interface UserContext { user?: UserProfile; + error?: Error; isLoading: boolean; } @@ -42,7 +43,7 @@ export interface UserContext { * export default function App({ Component, pageProps }) { * // If you've used `withAuth`, pageProps.user can pre-populate the hook * // if you haven't used `withAuth`, pageProps.user is undefined so the hook - * // fetches the user from the API routes + * // fetches the user from the API route * const { user } = pageProps; * * return ( @@ -75,9 +76,10 @@ const User = createContext({ isLoading: false }); * import { useUser } from '@auth0/nextjs-auth0`; * * export default function Profile() { - * const { user, isLoading } = useUser(); + * const { user, error, isLoading } = useUser(); * * if (isLoading) return
Loading...
; + * if (error) return
{error.message}
; * if (!user) return Login; * return
Hello {user.name}, Logout
; * } @@ -105,19 +107,25 @@ export default ({ profileUrl = '/api/auth/me' }: UserProviderProps): ReactElement => { const [user, setUser] = useState(() => initialUser); + const [error, setError] = useState(); const [isLoading, setIsLoading] = useState(() => !initialUser); useEffect((): void => { if (user) return; (async (): Promise => { - const response = await fetch(profileUrl); - const result = response.ok ? await response.json() : undefined; + try { + const response = await fetch(profileUrl); - setUser(result); - setIsLoading(false); + setUser(await response.json()); + setError(undefined); + } catch (_e) { + setError(new Error(`The request to ${profileUrl} failed`)); + } finally { + setIsLoading(false); + } })(); }, [user]); - return {children}; + return {children}; }; diff --git a/src/frontend/with-page-auth-required.tsx b/src/frontend/with-page-auth-required.tsx index e2b9b6052..c58935699 100644 --- a/src/frontend/with-page-auth-required.tsx +++ b/src/frontend/with-page-auth-required.tsx @@ -8,6 +8,11 @@ import { useUser } from './use-user'; */ const defaultOnRedirecting = (): JSX.Element => <>; +/** + * @ignore + */ +const defaultOnError = (): JSX.Element => <>; + /** * Options for the withPageAuthRequired Higher Order Component * @@ -43,6 +48,16 @@ export interface WithPageAuthRequiredOptions { * Render a message to show that the user is being redirected to the login. */ onRedirecting?: () => JSX.Element; + /** + * ```js + * withPageAuthRequired(Profile, { + * onError: error =>
Error: {error.message}
+ * }); + * ``` + * + * Render a fallback in case of error fetching the user from the profile API route. + */ + onError?: (error: Error) => JSX.Element; } /** @@ -66,18 +81,26 @@ export type WithPageAuthRequired =

( const withPageAuthRequired: WithPageAuthRequired = (Component, options = {}) => { return function withPageAuthRequired(props): JSX.Element { const router = useRouter(); - const { returnTo = router.asPath, onRedirecting = defaultOnRedirecting, loginUrl = '/api/auth/login' } = options; - const { user, isLoading } = useUser(); + const { + returnTo = router.asPath, + onRedirecting = defaultOnRedirecting, + onError = defaultOnError, + loginUrl = '/api/auth/login' + } = options; + const { user, error, isLoading } = useUser(); useEffect(() => { - if (user || isLoading) return; + if ((user && !error) || isLoading) return; (async (): Promise => { await router.push(`${loginUrl}?returnTo=${returnTo}`); })(); - }, [user, isLoading, router, loginUrl, returnTo]); + }, [user, error, isLoading]); + + if (error) return onError(error); + else if (user) return ; - return user ? : onRedirecting(); + return onRedirecting(); }; }; diff --git a/tests/fixtures/frontend.tsx b/tests/fixtures/frontend.tsx index 617bcc6db..a55e765a5 100644 --- a/tests/fixtures/frontend.tsx +++ b/tests/fixtures/frontend.tsx @@ -2,7 +2,6 @@ import React from 'react'; import { UserProfile, UserProvider } from '../../src'; type FetchUserMock = { - ok: boolean; json?: () => Promise; }; @@ -20,12 +19,8 @@ export const withUser = (user?: UserProfile): React.ComponentType => { return (props: any): React.ReactElement => ; }; -export const fetchUserMock = (): FetchUserMock => ({ - ok: true, - json: (): Promise => Promise.resolve(user) -}); +export const fetchUserMock = (): Promise => { + return Promise.resolve({ json: (): Promise => Promise.resolve(user) }); +}; -export const fetchUserFailureMock = (): FetchUserMock => ({ - ok: false, - json: undefined -}); +export const fetchUserFailureMock = (): Promise => Promise.reject(new Error('Error')); diff --git a/tests/frontend/use-user.test.tsx b/tests/frontend/use-user.test.tsx index 618170394..7c60cc4ee 100644 --- a/tests/frontend/use-user.test.tsx +++ b/tests/frontend/use-user.test.tsx @@ -8,6 +8,7 @@ describe('context wrapper', () => { const { result } = renderHook(() => useUser(), { wrapper: withUser(user) }); expect(result.current.user).toEqual(user); + expect(result.current.error).toEqual(undefined); expect(result.current.isLoading).toEqual(false); }); @@ -17,11 +18,13 @@ describe('context wrapper', () => { const { result, waitForValueToChange } = renderHook(() => useUser(), { wrapper: withUser() }); expect(result.current.user).toEqual(undefined); + expect(result.current.error).toEqual(undefined); expect(result.current.isLoading).toEqual(true); await waitForValueToChange(() => result.current.isLoading); expect(result.current.user).toEqual(user); + expect(result.current.error).toEqual(undefined); expect(result.current.isLoading).toEqual(false); }); @@ -31,11 +34,13 @@ describe('context wrapper', () => { const { result, waitForValueToChange } = renderHook(() => useUser(), { wrapper: withUser() }); expect(result.current.user).toEqual(undefined); + expect(result.current.error).toEqual(undefined); expect(result.current.isLoading).toEqual(true); await waitForValueToChange(() => result.current.isLoading); expect(result.current.user).toEqual(undefined); + expect(result.current.error).toEqual(new Error('The request to /api/auth/me failed')); expect(result.current.isLoading).toEqual(false); }); diff --git a/tests/frontend/with-page-auth-required.test.tsx b/tests/frontend/with-page-auth-required.test.tsx index d1b135430..c1a2deb4c 100644 --- a/tests/frontend/with-page-auth-required.test.tsx +++ b/tests/frontend/with-page-auth-required.test.tsx @@ -44,6 +44,16 @@ describe('with-page-auth-required csr', () => { await waitFor(() => expect(screen.getByText('Redirecting')).toBeInTheDocument()); }); + it('should show a fallback in case of error', async () => { + (global as any).fetch = fetchUserFailureMock; + const MyPage = (): JSX.Element => <>Private; + const OnError = (): JSX.Element => <>Error; + const ProtectedPage = withPageAuthRequired(MyPage, { onError: OnError }); + + render(, { wrapper: withUser() }); + await waitFor(() => expect(screen.getByText('Error')).toBeInTheDocument()); + }); + it('should accept a returnTo url', async () => { const MyPage = (): JSX.Element => <>Private; const ProtectedPage = withPageAuthRequired(MyPage, { returnTo: '/foo' }); From 554034a11c080f9014fdeb991785d5808c5a4e9e Mon Sep 17 00:00:00 2001 From: Rita Zerrizuela Date: Wed, 6 Jan 2021 14:46:50 -0300 Subject: [PATCH 2/3] Re-add response conditional --- .../kitchen-sink-example/pages/profile.tsx | 2 +- src/frontend/index.ts | 2 +- src/frontend/use-user.tsx | 5 +- tests/fixtures/frontend.tsx | 20 +++++-- tests/frontend/use-user.test.tsx | 52 +++++++++++++++---- .../frontend/with-page-auth-required.test.tsx | 16 +++--- 6 files changed, 68 insertions(+), 29 deletions(-) diff --git a/examples/kitchen-sink-example/pages/profile.tsx b/examples/kitchen-sink-example/pages/profile.tsx index e9b0844af..bb63bfa30 100644 --- a/examples/kitchen-sink-example/pages/profile.tsx +++ b/examples/kitchen-sink-example/pages/profile.tsx @@ -22,7 +22,7 @@ export default withPageAuthRequired(function Profile(): React.ReactElement { {user && ( <>

Profile

-
{JSON.stringify(user, null, 2)}
+
{JSON.stringify(user, null, 2)}
)}
diff --git a/src/frontend/index.ts b/src/frontend/index.ts index d960b171a..c652b9e4b 100644 --- a/src/frontend/index.ts +++ b/src/frontend/index.ts @@ -1,2 +1,2 @@ -export { default as UserProvider, UserProfile, UserContext, useUser } from './use-user'; +export { default as UserProvider, UserProviderProps, UserProfile, UserContext, useUser } from './use-user'; export { default as withPageAuthRequired, WithPageAuthRequired } from './with-page-auth-required'; diff --git a/src/frontend/use-user.tsx b/src/frontend/use-user.tsx index ab5049a4f..02965a53b 100644 --- a/src/frontend/use-user.tsx +++ b/src/frontend/use-user.tsx @@ -58,7 +58,7 @@ export interface UserContext { * * @category Client */ -type UserProviderProps = React.PropsWithChildren<{ user?: UserProfile; profileUrl?: string }>; +export type UserProviderProps = React.PropsWithChildren<{ user?: UserProfile; profileUrl?: string }>; /** * @ignore @@ -115,8 +115,7 @@ export default ({ (async (): Promise => { try { const response = await fetch(profileUrl); - - setUser(await response.json()); + setUser(response.ok ? await response.json() : undefined); setError(undefined); } catch (_e) { setError(new Error(`The request to ${profileUrl} failed`)); diff --git a/tests/fixtures/frontend.tsx b/tests/fixtures/frontend.tsx index a55e765a5..f37850497 100644 --- a/tests/fixtures/frontend.tsx +++ b/tests/fixtures/frontend.tsx @@ -1,7 +1,8 @@ import React from 'react'; -import { UserProfile, UserProvider } from '../../src'; +import { UserProvider, UserProviderProps, UserProfile } from '../../src/frontend'; type FetchUserMock = { + ok: boolean; json?: () => Promise; }; @@ -15,12 +16,21 @@ export const user: UserProfile = { updated_at: null }; -export const withUser = (user?: UserProfile): React.ComponentType => { - return (props: any): React.ReactElement => ; +export const withUserProvider = ({ user, profileUrl }: UserProviderProps = {}): React.ComponentType => { + return (props: any): React.ReactElement => ; }; export const fetchUserMock = (): Promise => { - return Promise.resolve({ json: (): Promise => Promise.resolve(user) }); + return Promise.resolve({ + ok: true, + json: () => Promise.resolve(user) + }); }; -export const fetchUserFailureMock = (): Promise => Promise.reject(new Error('Error')); +export const fetchUserUnsuccessfulMock = (): Promise => { + return Promise.resolve({ + ok: false + }); +}; + +export const fetchUserErrorMock = (): Promise => Promise.reject(new Error('Error')); diff --git a/tests/frontend/use-user.test.tsx b/tests/frontend/use-user.test.tsx index 7c60cc4ee..51e1fe8ea 100644 --- a/tests/frontend/use-user.test.tsx +++ b/tests/frontend/use-user.test.tsx @@ -1,21 +1,33 @@ import { renderHook } from '@testing-library/react-hooks'; import { useUser } from '../../src'; -import { fetchUserMock, fetchUserFailureMock, withUser, user } from '../fixtures/frontend'; +import { + fetchUserMock, + fetchUserUnsuccessfulMock, + fetchUserErrorMock, + withUserProvider, + user +} from '../fixtures/frontend'; describe('context wrapper', () => { - test('should use the initial user', async () => { - const { result } = renderHook(() => useUser(), { wrapper: withUser(user) }); + test('should fetch the user', async () => { + (global as any).fetch = fetchUserMock; + const { result, waitForValueToChange } = renderHook(() => useUser(), { wrapper: withUserProvider() }); + + expect(result.current.user).toEqual(undefined); + expect(result.current.error).toEqual(undefined); + expect(result.current.isLoading).toEqual(true); + + await waitForValueToChange(() => result.current.isLoading); expect(result.current.user).toEqual(user); expect(result.current.error).toEqual(undefined); expect(result.current.isLoading).toEqual(false); }); - test('should fetch the user', async () => { - (global as any).fetch = fetchUserMock; - - const { result, waitForValueToChange } = renderHook(() => useUser(), { wrapper: withUser() }); + test('should discard the response when the status code is not successful', async () => { + (global as any).fetch = fetchUserUnsuccessfulMock; + const { result, waitForValueToChange } = renderHook(() => useUser(), { wrapper: withUserProvider() }); expect(result.current.user).toEqual(undefined); expect(result.current.error).toEqual(undefined); @@ -23,15 +35,14 @@ describe('context wrapper', () => { await waitForValueToChange(() => result.current.isLoading); - expect(result.current.user).toEqual(user); + expect(result.current.user).toEqual(undefined); expect(result.current.error).toEqual(undefined); expect(result.current.isLoading).toEqual(false); }); test('should fail to fetch the user', async () => { - (global as any).fetch = fetchUserFailureMock; - - const { result, waitForValueToChange } = renderHook(() => useUser(), { wrapper: withUser() }); + (global as any).fetch = fetchUserErrorMock; + const { result, waitForValueToChange } = renderHook(() => useUser(), { wrapper: withUserProvider() }); expect(result.current.user).toEqual(undefined); expect(result.current.error).toEqual(undefined); @@ -44,6 +55,25 @@ describe('context wrapper', () => { expect(result.current.isLoading).toEqual(false); }); + test('should use the existing user', async () => { + const { result } = renderHook(() => useUser(), { wrapper: withUserProvider({ user }) }); + + expect(result.current.user).toEqual(user); + expect(result.current.error).toEqual(undefined); + expect(result.current.isLoading).toEqual(false); + }); + + test('should use a custom profileUrl', async () => { + const fetchSpy = jest.fn(); + (global as any).fetch = fetchSpy; + const { result, waitForValueToChange } = renderHook(() => useUser(), { + wrapper: withUserProvider({ profileUrl: '/api/custom-url' }) + }); + + await waitForValueToChange(() => result.current.isLoading); + expect(fetchSpy).toHaveBeenCalledWith('/api/custom-url'); + }); + afterAll(() => { delete (global as any).fetch; }); diff --git a/tests/frontend/with-page-auth-required.test.tsx b/tests/frontend/with-page-auth-required.test.tsx index c1a2deb4c..7c1a4f8b7 100644 --- a/tests/frontend/with-page-auth-required.test.tsx +++ b/tests/frontend/with-page-auth-required.test.tsx @@ -5,7 +5,7 @@ import '@testing-library/jest-dom/extend-expect'; import React from 'react'; import { render, screen, waitFor } from '@testing-library/react'; -import { fetchUserFailureMock, withUser, user } from '../fixtures/frontend'; +import { fetchUserUnsuccessfulMock, fetchUserErrorMock, withUserProvider, user } from '../fixtures/frontend'; import { withPageAuthRequired } from '../../src/frontend'; const routerMock = { @@ -17,11 +17,11 @@ jest.mock('next/router', () => ({ useRouter: (): any => routerMock })); describe('with-page-auth-required csr', () => { it('should block access to a CSR page when not authenticated', async () => { - (global as any).fetch = fetchUserFailureMock; + (global as any).fetch = fetchUserUnsuccessfulMock; const MyPage = (): JSX.Element => <>Private; const ProtectedPage = withPageAuthRequired(MyPage); - render(, { wrapper: withUser() }); + render(, { wrapper: withUserProvider() }); await waitFor(() => expect(routerMock.push).toHaveBeenCalledTimes(1)); await waitFor(() => expect(screen.queryByText('Private')).not.toBeInTheDocument()); }); @@ -30,7 +30,7 @@ describe('with-page-auth-required csr', () => { const MyPage = (): JSX.Element => <>Private; const ProtectedPage = withPageAuthRequired(MyPage); - render(, { wrapper: withUser(user) }); + render(, { wrapper: withUserProvider({ user }) }); await waitFor(() => expect(routerMock.push).not.toHaveBeenCalled()); await waitFor(() => expect(screen.getByText('Private')).toBeInTheDocument()); }); @@ -40,17 +40,17 @@ describe('with-page-auth-required csr', () => { const OnRedirecting = (): JSX.Element => <>Redirecting; const ProtectedPage = withPageAuthRequired(MyPage, { onRedirecting: OnRedirecting }); - render(, { wrapper: withUser() }); + render(, { wrapper: withUserProvider() }); await waitFor(() => expect(screen.getByText('Redirecting')).toBeInTheDocument()); }); it('should show a fallback in case of error', async () => { - (global as any).fetch = fetchUserFailureMock; + (global as any).fetch = fetchUserErrorMock; const MyPage = (): JSX.Element => <>Private; const OnError = (): JSX.Element => <>Error; const ProtectedPage = withPageAuthRequired(MyPage, { onError: OnError }); - render(, { wrapper: withUser() }); + render(, { wrapper: withUserProvider() }); await waitFor(() => expect(screen.getByText('Error')).toBeInTheDocument()); }); @@ -58,7 +58,7 @@ describe('with-page-auth-required csr', () => { const MyPage = (): JSX.Element => <>Private; const ProtectedPage = withPageAuthRequired(MyPage, { returnTo: '/foo' }); - render(, { wrapper: withUser() }); + render(, { wrapper: withUserProvider() }); await waitFor(() => expect(routerMock.push).toHaveBeenCalledWith(expect.stringContaining('?returnTo=/foo'))); }); From 6ceda646787bd2c0676ecc0a288522b2645e49de Mon Sep 17 00:00:00 2001 From: Rita Zerrizuela Date: Thu, 7 Jan 2021 09:40:03 -0300 Subject: [PATCH 3/3] Address review feedback --- src/frontend/with-page-auth-required.tsx | 2 +- src/index.browser.ts | 1 + src/index.ts | 2 +- tests/fixtures/frontend.tsx | 2 +- 4 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/frontend/with-page-auth-required.tsx b/src/frontend/with-page-auth-required.tsx index c58935699..3b20ab301 100644 --- a/src/frontend/with-page-auth-required.tsx +++ b/src/frontend/with-page-auth-required.tsx @@ -98,7 +98,7 @@ const withPageAuthRequired: WithPageAuthRequired = (Component, options = {}) => }, [user, error, isLoading]); if (error) return onError(error); - else if (user) return ; + if (user) return ; return onRedirecting(); }; diff --git a/src/index.browser.ts b/src/index.browser.ts index 04eb734bc..d8de45732 100644 --- a/src/index.browser.ts +++ b/src/index.browser.ts @@ -4,6 +4,7 @@ import { WithApiAuthRequired } from './helpers'; import { HandleAuth, HandleCallback, HandleLogin, HandleLogout, HandleProfile } from './handlers'; export { UserProvider, + UserProviderProps, UserProfile, UserContext, useUser, diff --git a/src/index.ts b/src/index.ts index 30bb77987..106f3fd6e 100644 --- a/src/index.ts +++ b/src/index.ts @@ -92,7 +92,7 @@ export const handleCallback: HandleCallback = (...args) => getInstance().handleC export const handleProfile: HandleProfile = (...args) => getInstance().handleProfile(...args); export const handleAuth: HandleAuth = (...args) => getInstance().handleAuth(...args); -export { UserProvider, UserProfile, UserContext, useUser } from './frontend'; +export { UserProvider, UserProviderProps, UserProfile, UserContext, useUser } from './frontend'; export { Config, diff --git a/tests/fixtures/frontend.tsx b/tests/fixtures/frontend.tsx index f37850497..688771a71 100644 --- a/tests/fixtures/frontend.tsx +++ b/tests/fixtures/frontend.tsx @@ -1,5 +1,5 @@ import React from 'react'; -import { UserProvider, UserProviderProps, UserProfile } from '../../src/frontend'; +import { UserProvider, UserProviderProps, UserProfile } from '../../src'; type FetchUserMock = { ok: boolean;