diff --git a/packages/core/src/auth.test.ts b/packages/core/src/auth.test.ts index 408c8beb..daa4e6e9 100644 --- a/packages/core/src/auth.test.ts +++ b/packages/core/src/auth.test.ts @@ -112,8 +112,8 @@ describe("signInWithEmailAndPassword", () => { expect(mockBehavior).toHaveBeenCalledWith(mockUI, credential); expect(result.providerId).toBe("password"); - // Only the `finally` block is called here. - expect(vi.mocked(mockUI.setState).mock.calls).toEqual([["idle"]]); + // Auth method sets pending at start, then idle in finally block. + expect(vi.mocked(mockUI.setState).mock.calls).toEqual([["pending"], ["idle"]]); }); it("should call the autoUpgradeAnonymousCredential behavior if enabled and handle no result from the behavior", async () => { @@ -205,8 +205,8 @@ describe("createUserWithEmailAndPassword", () => { expect(mockBehavior).toHaveBeenCalledWith(mockUI, credential); expect(result.providerId).toBe("password"); - // Only the `finally` block is called here. - expect(vi.mocked(mockUI.setState).mock.calls).toEqual([["idle"]]); + // Auth method sets pending at start, then idle in finally block. + expect(vi.mocked(mockUI.setState).mock.calls).toEqual([["pending"], ["idle"]]); }); it("should call the autoUpgradeAnonymousCredential behavior if enabled and handle no result from the behavior", async () => { @@ -368,8 +368,8 @@ describe("confirmPhoneNumber", () => { expect(mockBehavior).toHaveBeenCalledWith(mockUI, credential); expect(result.providerId).toBe("phone"); - // Only the `finally` block is called here. - expect(vi.mocked(mockUI.setState).mock.calls).toEqual([["idle"]]); + // Auth method sets pending at start, then idle in finally block. + expect(vi.mocked(mockUI.setState).mock.calls).toEqual([["pending"], ["idle"]]); }); it("should not call behavior when user is not anonymous", async () => { @@ -641,8 +641,8 @@ describe("signInWithEmailLink", () => { expect(mockBehavior).toHaveBeenCalledWith(mockUI, credential); expect(result.providerId).toBe("emailLink"); - // Only the `finally` block is called here. - expect(vi.mocked(mockUI.setState).mock.calls).toEqual([["idle"]]); + // Auth method sets pending at start, then idle in finally block. + expect(vi.mocked(mockUI.setState).mock.calls).toEqual([["pending"], ["idle"]]); }); it("should call the autoUpgradeAnonymousCredential behavior if enabled and handle no result from the behavior", async () => { @@ -739,8 +739,8 @@ describe("signInWithCredential", () => { expect(mockBehavior).toHaveBeenCalledWith(mockUI, credential); expect(result.providerId).toBe("password"); - // Only the `finally` block is called here. - expect(vi.mocked(mockUI.setState).mock.calls).toEqual([["idle"]]); + // Auth method sets pending at start, then idle in finally block. + expect(vi.mocked(mockUI.setState).mock.calls).toEqual([["pending"], ["idle"]]); }); it("should call the autoUpgradeAnonymousCredential behavior if enabled and handle no result from the behavior", async () => { @@ -794,7 +794,7 @@ describe("signInWithCredential", () => { expect(handleFirebaseError).toHaveBeenCalledWith(mockUI, error); - expect(vi.mocked(mockUI.setState).mock.calls).toEqual([["idle"]]); + expect(vi.mocked(mockUI.setState).mock.calls).toEqual([["pending"], ["idle"]]); expect(_signInWithCredential).not.toHaveBeenCalled(); }); @@ -921,6 +921,6 @@ describe("signInWithProvider", () => { await signInWithProvider(mockUI, provider); expect(handleFirebaseError).toHaveBeenCalledWith(mockUI, error); - expect(vi.mocked(mockUI.setState).mock.calls).toEqual([["idle"]]); + expect(vi.mocked(mockUI.setState).mock.calls).toEqual([["pending"], ["idle"]]); }); }); diff --git a/packages/core/src/auth.ts b/packages/core/src/auth.ts index ca9b042c..a35ba4d2 100644 --- a/packages/core/src/auth.ts +++ b/packages/core/src/auth.ts @@ -36,15 +36,13 @@ import { FirebaseUIConfiguration } from "./config"; import { handleFirebaseError } from "./errors"; import { hasBehavior, getBehavior } from "./behaviors/index"; -async function handlePendingCredential(ui: FirebaseUIConfiguration, user: UserCredential): Promise { +async function handlePendingCredential(_ui: FirebaseUIConfiguration, user: UserCredential): Promise { const pendingCredString = window.sessionStorage.getItem("pendingCred"); if (!pendingCredString) return user; try { const pendingCred = JSON.parse(pendingCredString); - ui.setState("pending"); const result = await linkWithCredential(user.user, pendingCred); - ui.setState("idle"); window.sessionStorage.removeItem("pendingCred"); return result; } catch { @@ -59,6 +57,7 @@ export async function signInWithEmailAndPassword( password: string ): Promise { try { + ui.setState("pending"); const credential = EmailAuthProvider.credential(email, password); if (hasBehavior(ui, "autoUpgradeAnonymousCredential")) { @@ -69,7 +68,6 @@ export async function signInWithEmailAndPassword( } } - ui.setState("pending"); const result = await _signInWithCredential(ui.auth, credential); return handlePendingCredential(ui, result); } catch (error) { @@ -85,6 +83,7 @@ export async function createUserWithEmailAndPassword( password: string ): Promise { try { + ui.setState("pending"); const credential = EmailAuthProvider.credential(email, password); if (hasBehavior(ui, "autoUpgradeAnonymousCredential")) { @@ -95,7 +94,6 @@ export async function createUserWithEmailAndPassword( } } - ui.setState("pending"); const result = await _createUserWithEmailAndPassword(ui.auth, email, password); return handlePendingCredential(ui, result); } catch (error) { @@ -126,6 +124,7 @@ export async function confirmPhoneNumber( verificationCode: string ): Promise { try { + ui.setState("pending"); const currentUser = ui.auth.currentUser; const credential = PhoneAuthProvider.credential(confirmationResult.verificationId, verificationCode); @@ -137,7 +136,6 @@ export async function confirmPhoneNumber( } } - ui.setState("pending"); const result = await _signInWithCredential(ui.auth, credential); return handlePendingCredential(ui, result); } catch (error) { @@ -160,13 +158,13 @@ export async function sendPasswordResetEmail(ui: FirebaseUIConfiguration, email: export async function sendSignInLinkToEmail(ui: FirebaseUIConfiguration, email: string): Promise { try { + ui.setState("pending"); const actionCodeSettings = { url: window.location.href, // TODO(ehesp): Check this... handleCodeInApp: true, } satisfies ActionCodeSettings; - ui.setState("pending"); await _sendSignInLinkToEmail(ui.auth, email, actionCodeSettings); // TODO: Should this be a behavior ("storageStrategy")? window.localStorage.setItem("emailForSignIn", email); @@ -191,6 +189,7 @@ export async function signInWithCredential( credential: AuthCredential ): Promise { try { + ui.setState("pending"); if (hasBehavior(ui, "autoUpgradeAnonymousCredential")) { const userCredential = await getBehavior(ui, "autoUpgradeAnonymousCredential")(ui, credential); @@ -201,7 +200,6 @@ export async function signInWithCredential( } } - ui.setState("pending"); const result = await _signInWithCredential(ui.auth, credential); return handlePendingCredential(ui, result); } catch (error) { @@ -228,6 +226,7 @@ export async function signInWithProvider( provider: AuthProvider ): Promise { try { + ui.setState("pending"); if (hasBehavior(ui, "autoUpgradeAnonymousProvider")) { const credential = await getBehavior(ui, "autoUpgradeAnonymousProvider")(ui, provider); @@ -265,7 +264,6 @@ export async function completeEmailLinkSignIn( ui.setState("pending"); const result = await signInWithEmailLink(ui, email, currentUrl); - ui.setState("idle"); // TODO(ehesp): Do we need this here? return handlePendingCredential(ui, result); } catch (error) { handleFirebaseError(ui, error); diff --git a/packages/core/src/behaviors/anonymous-upgrade.test.ts b/packages/core/src/behaviors/anonymous-upgrade.test.ts index 8844c8d2..a8e6fdae 100644 --- a/packages/core/src/behaviors/anonymous-upgrade.test.ts +++ b/packages/core/src/behaviors/anonymous-upgrade.test.ts @@ -43,8 +43,6 @@ describe("autoUpgradeAnonymousCredentialHandler", () => { const result = await autoUpgradeAnonymousCredentialHandler(mockUI, mockCredential); expect(linkWithCredential).toHaveBeenCalledWith(mockUser, mockCredential); - expect(mockUI.setState).toHaveBeenCalledWith("pending"); - expect(mockUI.setState).toHaveBeenCalledWith("idle"); expect(result).toBe(mockResult); }); diff --git a/packages/core/src/behaviors/anonymous-upgrade.ts b/packages/core/src/behaviors/anonymous-upgrade.ts index 3886e240..75044048 100644 --- a/packages/core/src/behaviors/anonymous-upgrade.ts +++ b/packages/core/src/behaviors/anonymous-upgrade.ts @@ -21,14 +21,12 @@ export const autoUpgradeAnonymousCredentialHandler = async ( const oldUserId = currentUser.uid; - ui.setState("pending"); const result = await linkWithCredential(currentUser, credential); if (onUpgrade) { await onUpgrade(ui, oldUserId, result); } - ui.setState("idle"); return result; }; diff --git a/packages/core/src/behaviors/auto-anonymous-login.ts b/packages/core/src/behaviors/auto-anonymous-login.ts index 53805844..ba1caa70 100644 --- a/packages/core/src/behaviors/auto-anonymous-login.ts +++ b/packages/core/src/behaviors/auto-anonymous-login.ts @@ -3,6 +3,7 @@ import { InitHandler } from "./utils"; export const autoAnonymousLoginHandler: InitHandler = async (ui) => { const auth = ui.auth; + if (!auth.currentUser) { await signInAnonymously(auth); } diff --git a/packages/core/src/behaviors/provider-strategy.test.ts b/packages/core/src/behaviors/provider-strategy.test.ts index 1148bb99..9eda32cb 100644 --- a/packages/core/src/behaviors/provider-strategy.test.ts +++ b/packages/core/src/behaviors/provider-strategy.test.ts @@ -38,13 +38,12 @@ describe("signInWithRediectHandler", () => { await signInWithRediectHandler(mockUI, mockProvider); - expect(mockUI.setState).toHaveBeenCalledWith("pending"); expect(signInWithRedirect).toHaveBeenCalledWith(mockAuth, mockProvider); }); }); describe("signInWithPopupHandler", () => { - it("should set state to pending, call signInWithPopup, set state to idle, and return result", async () => { + it("should call signInWithPopup and return result", async () => { const mockAuth = {} as Auth; const mockUI = createMockUI({ auth: mockAuth }); const mockProvider = { providerId: "google.com" } as AuthProvider; @@ -54,13 +53,11 @@ describe("signInWithPopupHandler", () => { const result = await signInWithPopupHandler(mockUI, mockProvider); - expect(mockUI.setState).toHaveBeenCalledWith("pending"); expect(signInWithPopup).toHaveBeenCalledWith(mockAuth, mockProvider); - expect(mockUI.setState).toHaveBeenCalledWith("idle"); expect(result).toBe(mockResult); }); - it("should not set state to idle when signInWithPopup fails", async () => { + it("should throw error when signInWithPopup fails", async () => { const mockAuth = {} as Auth; const mockUI = createMockUI({ auth: mockAuth }); const mockProvider = { providerId: "google.com" } as AuthProvider; @@ -69,13 +66,11 @@ describe("signInWithPopupHandler", () => { vi.mocked(signInWithPopup).mockRejectedValue(mockError); await expect(signInWithPopupHandler(mockUI, mockProvider)).rejects.toThrow("Popup sign in failed"); - expect(mockUI.setState).toHaveBeenCalledWith("pending"); - expect(mockUI.setState).not.toHaveBeenCalledWith("idle"); }); }); describe("linkWithRedirectHandler", () => { - it("should set state to pending and call linkWithRedirect", async () => { + it("should call linkWithRedirect", async () => { const mockAuth = {} as Auth; const mockUI = createMockUI({ auth: mockAuth }); const mockUser = { uid: "test-user" } as User; @@ -85,13 +80,12 @@ describe("linkWithRedirectHandler", () => { await linkWithRedirectHandler(mockUI, mockUser, mockProvider); - expect(mockUI.setState).toHaveBeenCalledWith("pending"); expect(linkWithRedirect).toHaveBeenCalledWith(mockUser, mockProvider); }); }); describe("linkWithPopupHandler", () => { - it("should set state to pending, call linkWithPopup, set state to idle, and return result", async () => { + it("should call linkWithPopup and return result", async () => { const mockAuth = {} as Auth; const mockUI = createMockUI({ auth: mockAuth }); const mockUser = { uid: "test-user" } as User; @@ -102,13 +96,11 @@ describe("linkWithPopupHandler", () => { const result = await linkWithPopupHandler(mockUI, mockUser, mockProvider); - expect(mockUI.setState).toHaveBeenCalledWith("pending"); expect(linkWithPopup).toHaveBeenCalledWith(mockUser, mockProvider); - expect(mockUI.setState).toHaveBeenCalledWith("idle"); expect(result).toBe(mockResult); }); - it("should not set state to idle when linkWithPopup fails", async () => { + it("should throw error when linkWithPopup fails", async () => { const mockAuth = {} as Auth; const mockUI = createMockUI({ auth: mockAuth }); const mockUser = { uid: "test-user" } as User; @@ -118,7 +110,5 @@ describe("linkWithPopupHandler", () => { vi.mocked(linkWithPopup).mockRejectedValue(mockError); await expect(linkWithPopupHandler(mockUI, mockUser, mockProvider)).rejects.toThrow("Popup link failed"); - expect(mockUI.setState).toHaveBeenCalledWith("pending"); - expect(mockUI.setState).not.toHaveBeenCalledWith("idle"); }); }); diff --git a/packages/core/src/behaviors/provider-strategy.ts b/packages/core/src/behaviors/provider-strategy.ts index 7680af02..f28af921 100644 --- a/packages/core/src/behaviors/provider-strategy.ts +++ b/packages/core/src/behaviors/provider-strategy.ts @@ -20,25 +20,17 @@ export type ProviderLinkStrategyHandler = ( ) => Promise; export const signInWithRediectHandler: ProviderSignInStrategyHandler = async (ui, provider) => { - ui.setState("pending"); return signInWithRedirect(ui.auth, provider); }; export const signInWithPopupHandler: ProviderSignInStrategyHandler = async (ui, provider) => { - ui.setState("pending"); - const result = await signInWithPopup(ui.auth, provider); - ui.setState("idle"); - return result; + return signInWithPopup(ui.auth, provider); }; -export const linkWithRedirectHandler: ProviderLinkStrategyHandler = async (ui, user, provider) => { - ui.setState("pending"); +export const linkWithRedirectHandler: ProviderLinkStrategyHandler = async (_ui, user, provider) => { return linkWithRedirect(user, provider); }; -export const linkWithPopupHandler: ProviderLinkStrategyHandler = async (ui, user, provider) => { - ui.setState("pending"); - const result = await linkWithPopup(user, provider); - ui.setState("idle"); - return result; +export const linkWithPopupHandler: ProviderLinkStrategyHandler = async (_ui, user, provider) => { + return linkWithPopup(user, provider); };