Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 12 additions & 12 deletions packages/core/src/auth.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 () => {
Expand Down Expand Up @@ -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 () => {
Expand Down Expand Up @@ -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 () => {
Expand Down Expand Up @@ -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 () => {
Expand Down Expand Up @@ -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 () => {
Expand Down Expand Up @@ -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();
});
Expand Down Expand Up @@ -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"]]);
});
});
16 changes: 7 additions & 9 deletions packages/core/src/auth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<UserCredential> {
async function handlePendingCredential(_ui: FirebaseUIConfiguration, user: UserCredential): Promise<UserCredential> {
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 {
Expand All @@ -59,6 +57,7 @@ export async function signInWithEmailAndPassword(
password: string
): Promise<UserCredential> {
try {
ui.setState("pending");
const credential = EmailAuthProvider.credential(email, password);

if (hasBehavior(ui, "autoUpgradeAnonymousCredential")) {
Expand All @@ -69,7 +68,6 @@ export async function signInWithEmailAndPassword(
}
}

ui.setState("pending");
const result = await _signInWithCredential(ui.auth, credential);
return handlePendingCredential(ui, result);
} catch (error) {
Expand All @@ -85,6 +83,7 @@ export async function createUserWithEmailAndPassword(
password: string
): Promise<UserCredential> {
try {
ui.setState("pending");
const credential = EmailAuthProvider.credential(email, password);

if (hasBehavior(ui, "autoUpgradeAnonymousCredential")) {
Expand All @@ -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) {
Expand Down Expand Up @@ -126,6 +124,7 @@ export async function confirmPhoneNumber(
verificationCode: string
): Promise<UserCredential> {
try {
ui.setState("pending");
const currentUser = ui.auth.currentUser;
const credential = PhoneAuthProvider.credential(confirmationResult.verificationId, verificationCode);

Expand All @@ -137,7 +136,6 @@ export async function confirmPhoneNumber(
}
}

ui.setState("pending");
const result = await _signInWithCredential(ui.auth, credential);
return handlePendingCredential(ui, result);
} catch (error) {
Expand All @@ -160,13 +158,13 @@ export async function sendPasswordResetEmail(ui: FirebaseUIConfiguration, email:

export async function sendSignInLinkToEmail(ui: FirebaseUIConfiguration, email: string): Promise<void> {
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);
Expand All @@ -191,6 +189,7 @@ export async function signInWithCredential(
credential: AuthCredential
): Promise<UserCredential> {
try {
ui.setState("pending");
if (hasBehavior(ui, "autoUpgradeAnonymousCredential")) {
const userCredential = await getBehavior(ui, "autoUpgradeAnonymousCredential")(ui, credential);

Expand All @@ -201,7 +200,6 @@ export async function signInWithCredential(
}
}

ui.setState("pending");
const result = await _signInWithCredential(ui.auth, credential);
return handlePendingCredential(ui, result);
} catch (error) {
Expand All @@ -228,6 +226,7 @@ export async function signInWithProvider(
provider: AuthProvider
): Promise<UserCredential | never> {
try {
ui.setState("pending");
if (hasBehavior(ui, "autoUpgradeAnonymousProvider")) {
const credential = await getBehavior(ui, "autoUpgradeAnonymousProvider")(ui, provider);

Expand Down Expand Up @@ -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);
Expand Down
2 changes: 0 additions & 2 deletions packages/core/src/behaviors/anonymous-upgrade.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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);
});

Expand Down
2 changes: 0 additions & 2 deletions packages/core/src/behaviors/anonymous-upgrade.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
};

Expand Down
1 change: 1 addition & 0 deletions packages/core/src/behaviors/auto-anonymous-login.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { InitHandler } from "./utils";

export const autoAnonymousLoginHandler: InitHandler = async (ui) => {
const auth = ui.auth;

if (!auth.currentUser) {
await signInAnonymously(auth);
}
Expand Down
20 changes: 5 additions & 15 deletions packages/core/src/behaviors/provider-strategy.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand All @@ -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;
Expand All @@ -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;
Expand All @@ -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;
Expand All @@ -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");
});
});
16 changes: 4 additions & 12 deletions packages/core/src/behaviors/provider-strategy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,25 +20,17 @@ export type ProviderLinkStrategyHandler = (
) => Promise<never | UserCredential>;

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);
};