Skip to content

Commit

Permalink
Make useHandleCallback compatible with StrictMode + test it
Browse files Browse the repository at this point in the history
  • Loading branch information
erwanMarmelab committed Jan 30, 2025
1 parent 107db17 commit aa0ec8b
Show file tree
Hide file tree
Showing 2 changed files with 53 additions and 6 deletions.
24 changes: 24 additions & 0 deletions packages/ra-core/src/auth/useHandleAuthCallback.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -160,4 +160,28 @@ describe('useHandleAuthCallback', () => {
expect(abort).toHaveBeenCalled();
});
});

it('should only call handleCallback once when the component is rendered', async () => {
const handleCallback = jest.spyOn(authProvider, 'handleCallback');
render(
<React.StrictMode>
<TestMemoryRouter initialEntries={['/auth-callback']}>
<AuthContext.Provider value={authProvider}>
<QueryClientProvider client={new QueryClient()}>
<Routes>
<Route path="/" element={<div>Home</div>} />
<Route
path="/auth-callback"
element={<TestComponent />}
/>
</Routes>
</QueryClientProvider>
</AuthContext.Provider>
</TestMemoryRouter>
</React.StrictMode>
);

await screen.findByText('Home');
expect(handleCallback).toHaveBeenCalledTimes(1);
});
});
35 changes: 29 additions & 6 deletions packages/ra-core/src/auth/useHandleAuthCallback.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,15 +24,38 @@ export const useHandleAuthCallback = (
const nextSearch = locationState && locationState.nextSearch;
const defaultRedirectUrl = nextPathName ? nextPathName + nextSearch : '/';
const { onSuccess, onError, onSettled, ...queryOptions } = options ?? {};
let handleCallbackPromise: Promise<void> | null;

const queryResult = useQuery({
queryKey: ['auth', 'handleCallback'],
queryFn: ({ signal }) =>
authProvider && typeof authProvider.handleCallback === 'function'
? authProvider
.handleCallback({ signal })
.then(result => result ?? null)
: Promise.resolve(),
queryFn: ({ signal }) => {
console.log('queryFn', handleCallbackPromise);
if (!handleCallbackPromise) {
handleCallbackPromise = new Promise(async (resolve, reject) => {
if (authProvider) {
if (typeof authProvider.handleCallback === 'function') {
try {
const result =
await authProvider.handleCallback({
signal,
});
return resolve(result ?? null);
} catch (error) {
return reject({
redirectTo: false,
message: error.message,
});
}
}
return resolve();
}
return reject({
message: 'Failed to handle login callback.',
});
});
}
return handleCallbackPromise;
},
retry: false,
...queryOptions,
});
Expand Down

0 comments on commit aa0ec8b

Please sign in to comment.