diff --git a/packages/react/src/auth/index.ts b/packages/react/src/auth/index.ts index 2cfdb487..3c419741 100644 --- a/packages/react/src/auth/index.ts +++ b/packages/react/src/auth/index.ts @@ -2,7 +2,7 @@ // useConfirmationResultConfirmMutation (ConfirmationResult) // useUserDeleteMutation (User) // userUserGetIdTokenResultMutation (User) -// useUserGetIdTokenMutation (User) +export { useUserGetIdTokenMutation } from "./useUserGetIdTokenMutation"; // useUserReloadMutation (User) // useVerifyPhoneNumberMutation (PhoneAuthProvider) // useMultiFactorUserEnrollMutation (MultiFactorUser) diff --git a/packages/react/src/auth/useUserGetIdTokenMutation.test.tsx b/packages/react/src/auth/useUserGetIdTokenMutation.test.tsx new file mode 100644 index 00000000..b79411e7 --- /dev/null +++ b/packages/react/src/auth/useUserGetIdTokenMutation.test.tsx @@ -0,0 +1,92 @@ +import { act, renderHook, waitFor } from "@testing-library/react"; +import { + createUserWithEmailAndPassword, + signInWithEmailAndPassword, +} from "firebase/auth"; +import { afterEach, beforeEach, describe, expect, test, vi } from "vitest"; +import { auth, wipeAuth } from "~/testing-utils"; +import { useUserGetIdTokenMutation } from "./useUserGetIdTokenMutation"; +import { queryClient, wrapper } from "../../utils"; + +describe("useUserGetIdTokenMutation", () => { + const email = "tqf@invertase.io"; + const password = "TanstackQueryFirebase#123"; + + beforeEach(async () => { + queryClient.clear(); + await wipeAuth(); + await createUserWithEmailAndPassword(auth, email, password); + }); + + afterEach(async () => { + vi.clearAllMocks(); + await auth.signOut(); + }); + + test("successfully retrieves an ID token with forceRefresh true", async () => { + const userCredential = await signInWithEmailAndPassword( + auth, + email, + password + ); + const { user } = userCredential; + + const { result } = renderHook(() => useUserGetIdTokenMutation(user), { + wrapper, + }); + + await act(async () => { + await result.current.mutateAsync(true); + }); + + await waitFor(() => expect(result.current.isSuccess).toBe(true)); + + expect(typeof result.current.data).toBe("string"); + expect(result.current.data?.length).toBeGreaterThan(0); + }); + + test("successfully retrieves an ID token with forceRefresh false", async () => { + const userCredential = await signInWithEmailAndPassword( + auth, + email, + password + ); + const { user } = userCredential; + + const { result } = renderHook(() => useUserGetIdTokenMutation(user), { + wrapper, + }); + + await act(async () => { + await result.current.mutateAsync(false); + }); + + await waitFor(() => expect(result.current.isSuccess).toBe(true)); + + expect(typeof result.current.data).toBe("string"); + expect(result.current.data?.length).toBeGreaterThan(0); + }); + + test("executes onSuccess callback with token", async () => { + const userCredential = await signInWithEmailAndPassword( + auth, + email, + password + ); + const { user } = userCredential; + const onSuccess = vi.fn(); + + const { result } = renderHook( + () => useUserGetIdTokenMutation(user, { onSuccess }), + { wrapper } + ); + + await act(async () => { + await result.current.mutateAsync(true); + }); + + await waitFor(() => expect(onSuccess).toHaveBeenCalled()); + expect(typeof onSuccess.mock.calls[0][0]).toBe("string"); + expect(onSuccess.mock.calls[0][0].length).toBeGreaterThan(0); + }); +}); diff --git a/packages/react/src/auth/useUserGetIdTokenMutation.ts b/packages/react/src/auth/useUserGetIdTokenMutation.ts new file mode 100644 index 00000000..9adf6ec1 --- /dev/null +++ b/packages/react/src/auth/useUserGetIdTokenMutation.ts @@ -0,0 +1,22 @@ +import { type UseMutationOptions, useMutation } from "@tanstack/react-query"; +import { type User, type AuthError, getIdToken } from "firebase/auth"; + +type AuthUseMutationOptions< + TData = unknown, + TError = Error, + TVariables = void +> = Omit, "mutationFn"> & { + auth?: { + forceRefresh?: boolean; + }; +}; + +export function useUserGetIdTokenMutation( + user: User, + options?: AuthUseMutationOptions +) { + return useMutation({ + ...options, + mutationFn: (forceRefresh?: boolean) => getIdToken(user, forceRefresh), + }); +}