diff --git a/__tests__/auth-provider.test.tsx b/__tests__/auth-provider.test.tsx index 143d6422..3ce6d947 100644 --- a/__tests__/auth-provider.test.tsx +++ b/__tests__/auth-provider.test.tsx @@ -1087,3 +1087,101 @@ describe('Auth0Provider', () => { expect(screen.queryByText('__main_user__')).not.toBeInTheDocument(); }); }); + +describe('Auth0Provider - useMemo dependency behavior', () => { + + afterEach(() => { + jest.clearAllMocks(); + window.history.pushState({}, document.title, '/'); + }); + + interface TestComponentProps { + clientId?: string; + audience?: string; + scope?: string; + } + + const TestComponent: React.FC = ({ + clientId = '__test_client_id__', + audience = '__test_audience__', + scope = 'read:profile openid' + }) => ( + +
test
+
+ ); + + it('should recreate Auth0Client when clientId changes', async () => { + const { rerender } = render(); + + // Initial render + expect(Auth0Client).toHaveBeenCalledTimes(1); + expect(Auth0Client).toHaveBeenLastCalledWith( + expect.objectContaining({ + clientId: '__test_client_id__', + authorizationParams: { + audience: '__test_audience__', + scope: 'read:profile openid' + } + }) + ); + + // Change clientId - should recreate client + rerender(); + expect(Auth0Client).toHaveBeenCalledTimes(2); + expect(Auth0Client).toHaveBeenLastCalledWith( + expect.objectContaining({ + clientId: '__new_client_id__', + authorizationParams: { + audience: '__test_audience__', + scope: 'read:profile openid' + } + }) + ); + }); + + it('should recreate Auth0Client when audience changes', async () => { + const { rerender } = render(); + + expect(Auth0Client).toHaveBeenCalledTimes(1); + + // Change audience - should recreate client + rerender(); + expect(Auth0Client).toHaveBeenCalledTimes(2); + expect(Auth0Client).toHaveBeenLastCalledWith( + expect.objectContaining({ + clientId: '__test_client_id__', + authorizationParams: { + audience: '__new_audience__', + scope: 'read:profile openid' + } + }) + ); + }); + + it('should recreate Auth0Client when scope changes', async () => { + const { rerender } = render(); + + expect(Auth0Client).toHaveBeenCalledTimes(1); + + // Change scope with multiple permissions - should recreate client + rerender(); + expect(Auth0Client).toHaveBeenCalledTimes(2); + expect(Auth0Client).toHaveBeenLastCalledWith( + expect.objectContaining({ + clientId: '__test_client_id__', + authorizationParams: { + audience: '__test_audience__', + scope: 'read:users write:users admin:all' + } + }) + ); + }); +}); diff --git a/src/auth0-provider.tsx b/src/auth0-provider.tsx index c6bcd5aa..2e0aae6a 100644 --- a/src/auth0-provider.tsx +++ b/src/auth0-provider.tsx @@ -4,7 +4,6 @@ import React, { useMemo, useReducer, useRef, - useState, } from 'react'; import { Auth0Client, @@ -140,8 +139,15 @@ const Auth0Provider = (opts: Auth0ProviderOptions new Auth0Client(toAuth0ClientOptions(clientOpts)) + const client = useMemo( + () => new Auth0Client(toAuth0ClientOptions(clientOpts)), + [ + clientOpts.domain, + clientOpts.clientId, + clientOpts.authorizationParams?.audience, + clientOpts.authorizationParams?.scope, + clientOpts.authorizationParams?.redirect_uri, + ] ); const [state, dispatch] = useReducer(reducer, initialAuthState as AuthState); const didInitialise = useRef(false);