Skip to content

Commit 88da289

Browse files
committed
Merge branch '@invertase/v7-development' of https://github.com/firebase/firebaseui-web into @invertase/bb-9
2 parents 0057799 + ed32810 commit 88da289

7 files changed

+311
-205
lines changed

packages/angular/src/lib/auth/forms/email-link-auth-form.spec.ts

Lines changed: 33 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,22 @@ import { FormInputComponent, FormSubmitComponent, FormErrorMessageComponent } fr
2222
import { PoliciesComponent } from "../../components/policies";
2323
import { UserCredential } from "@angular/fire/auth";
2424

25+
// Mock the @firebase-ui/core module but preserve Angular providers
26+
jest.mock("@firebase-ui/core", () => {
27+
const originalModule = jest.requireActual("@firebase-ui/core");
28+
return {
29+
...originalModule,
30+
sendSignInLinkToEmail: jest.fn(),
31+
completeEmailLinkSignIn: jest.fn(),
32+
FirebaseUIError: class FirebaseUIError extends Error {
33+
constructor(message: string) {
34+
super(message);
35+
this.name = "FirebaseUIError";
36+
}
37+
},
38+
};
39+
});
40+
2541
describe("<fui-email-link-auth-form />", () => {
2642
let mockSendSignInLinkToEmail: any;
2743
let mockCompleteEmailLinkSignIn: any;
@@ -34,6 +50,7 @@ describe("<fui-email-link-auth-form />", () => {
3450
mockFirebaseUIError = FirebaseUIError;
3551

3652
mockCompleteEmailLinkSignIn.mockResolvedValue(null);
53+
mockSendSignInLinkToEmail.mockResolvedValue(undefined);
3754
});
3855

3956
afterEach(() => {
@@ -115,6 +132,9 @@ describe("<fui-email-link-auth-form />", () => {
115132
});
116133

117134
it("should prevent default and stop propagation on form submit", async () => {
135+
// Mock the function to resolve immediately for this test
136+
mockSendSignInLinkToEmail.mockResolvedValue(undefined);
137+
118138
const { fixture } = await render(EmailLinkAuthFormComponent, {
119139
imports: [
120140
CommonModule,
@@ -140,11 +160,12 @@ describe("<fui-email-link-auth-form />", () => {
140160
stopPropagation: { value: stopPropagationSpy },
141161
});
142162

163+
// Wait for the async form submission to complete
143164
await component.handleSubmit(submitEvent);
144-
await fixture.whenStable();
145-
146-
expect(preventDefaultSpy).toHaveBeenCalled();
147-
expect(stopPropagationSpy).toHaveBeenCalled();
165+
await waitFor(() => {
166+
expect(preventDefaultSpy).toHaveBeenCalled();
167+
expect(stopPropagationSpy).toHaveBeenCalled();
168+
});
148169
});
149170

150171
it("should handle form submission with valid email", async () => {
@@ -229,11 +250,10 @@ describe("<fui-email-link-auth-form />", () => {
229250
fixture.detectChanges();
230251

231252
await component.form.handleSubmit();
232-
await fixture.whenStable();
233-
fixture.detectChanges();
234-
235-
expect(component.emailSentState()).toBe(false);
236-
expect(screen.getByText(errorMessage)).toBeInTheDocument();
253+
await waitFor(() => {
254+
expect(component.emailSentState()).toBe(false);
255+
expect(screen.getByText(errorMessage)).toBeInTheDocument();
256+
});
237257
});
238258

239259
it("should handle unknown errors and display generic error message", async () => {
@@ -258,11 +278,10 @@ describe("<fui-email-link-auth-form />", () => {
258278
fixture.detectChanges();
259279

260280
await component.form.handleSubmit();
261-
await fixture.whenStable();
262-
fixture.detectChanges();
263-
264-
expect(component.emailSentState()).toBe(false);
265-
expect(screen.getByText("An unknown error occurred")).toBeInTheDocument();
281+
await waitFor(() => {
282+
expect(component.emailSentState()).toBe(false);
283+
expect(screen.getByText("An unknown error occurred")).toBeInTheDocument();
284+
});
266285
});
267286

268287
it("should use the same validation logic as the real createEmailLinkAuthFormSchema", async () => {

packages/angular/src/lib/auth/forms/forgot-password-auth-form.spec.ts

Lines changed: 27 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,21 @@ import {
2626
} from "../../components/form";
2727
import { PoliciesComponent } from "../../components/policies";
2828

29+
// Mock the @firebase-ui/core module but preserve Angular providers
30+
jest.mock("@firebase-ui/core", () => {
31+
const originalModule = jest.requireActual("@firebase-ui/core");
32+
return {
33+
...originalModule,
34+
sendPasswordResetEmail: jest.fn(),
35+
FirebaseUIError: class FirebaseUIError extends Error {
36+
constructor(message: string) {
37+
super(message);
38+
this.name = "FirebaseUIError";
39+
}
40+
},
41+
};
42+
});
43+
2944
describe("<fui-forgot-password-auth-form />", () => {
3045
let mockSendPasswordResetEmail: any;
3146
let mockFirebaseUIError: any;
@@ -187,10 +202,10 @@ describe("<fui-forgot-password-auth-form />", () => {
187202
});
188203

189204
await component.handleSubmit(submitEvent);
190-
await fixture.whenStable();
191-
192-
expect(preventDefaultSpy).toHaveBeenCalled();
193-
expect(stopPropagationSpy).toHaveBeenCalled();
205+
await waitFor(() => {
206+
expect(preventDefaultSpy).toHaveBeenCalled();
207+
expect(stopPropagationSpy).toHaveBeenCalled();
208+
});
194209
});
195210

196211
it("should handle form submission with valid email", async () => {
@@ -278,11 +293,10 @@ describe("<fui-forgot-password-auth-form />", () => {
278293
fixture.detectChanges();
279294

280295
await component.form.handleSubmit();
281-
await fixture.whenStable();
282-
fixture.detectChanges();
283-
284-
expect(component.emailSent()).toBe(false);
285-
expect(component.form.state.errors.length).toBeGreaterThan(0);
296+
await waitFor(() => {
297+
expect(component.emailSent()).toBe(false);
298+
expect(component.form.state.errors.length).toBeGreaterThan(0);
299+
});
286300
});
287301

288302
it("should handle unknown errors and display generic error message", async () => {
@@ -308,11 +322,10 @@ describe("<fui-forgot-password-auth-form />", () => {
308322
fixture.detectChanges();
309323

310324
await component.form.handleSubmit();
311-
await fixture.whenStable();
312-
fixture.detectChanges();
313-
314-
expect(component.emailSent()).toBe(false);
315-
expect(component.form.state.errors.length).toBeGreaterThan(0);
325+
await waitFor(() => {
326+
expect(component.emailSent()).toBe(false);
327+
expect(component.form.state.errors.length).toBeGreaterThan(0);
328+
});
316329
});
317330

318331
it("should use the same validation logic as the real createForgotPasswordAuthFormSchema", async () => {

packages/angular/src/lib/auth/forms/mfa/sms-multi-factor-enrollment-form.spec.ts

Lines changed: 43 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -14,14 +14,42 @@
1414
* limitations under the License.
1515
*/
1616

17-
import { render, screen } from "@testing-library/angular";
17+
import { render, screen, waitFor } from "@testing-library/angular";
1818
import { CommonModule } from "@angular/common";
1919
import { TanStackField, TanStackAppField } from "@tanstack/angular-form";
2020
import { SmsMultiFactorEnrollmentFormComponent } from "./sms-multi-factor-enrollment-form";
2121
import { FormInputComponent, FormSubmitComponent, FormErrorMessageComponent } from "../../../components/form";
2222
import { CountrySelectorComponent } from "../../../components/country-selector";
2323
import { PoliciesComponent } from "../../../components/policies";
2424

25+
jest.mock("@firebase-ui/core", () => {
26+
const originalModule = jest.requireActual("@firebase-ui/core");
27+
return {
28+
...originalModule,
29+
verifyPhoneNumber: jest.fn(),
30+
enrollWithMultiFactorAssertion: jest.fn(),
31+
formatPhoneNumber: jest.fn(),
32+
FirebaseUIError: class FirebaseUIError extends Error {
33+
constructor(message: string) {
34+
super(message);
35+
this.name = "FirebaseUIError";
36+
}
37+
},
38+
};
39+
});
40+
41+
jest.mock("firebase/auth", () => {
42+
const originalModule = jest.requireActual("firebase/auth");
43+
return {
44+
...originalModule,
45+
multiFactor: jest.fn(() => ({
46+
enroll: jest.fn(),
47+
unenroll: jest.fn(),
48+
getEnrolledFactors: jest.fn(),
49+
})),
50+
};
51+
});
52+
2553
describe("<fui-sms-multi-factor-enrollment-form />", () => {
2654
let mockVerifyPhoneNumber: any;
2755
let mockEnrollWithMultiFactorAssertion: any;
@@ -33,18 +61,21 @@ describe("<fui-sms-multi-factor-enrollment-form />", () => {
3361

3462
beforeEach(() => {
3563
const {
36-
verifyPhoneNumber,
37-
enrollWithMultiFactorAssertion,
38-
formatPhoneNumber,
39-
FirebaseUIError,
4064
injectTranslation,
4165
injectUI,
4266
injectMultiFactorPhoneAuthNumberFormSchema,
4367
injectMultiFactorPhoneAuthVerifyFormSchema,
4468
injectDefaultCountry,
4569
injectRecaptchaVerifier,
4670
} = require("../../../tests/test-helpers");
47-
const { PhoneAuthProvider, PhoneMultiFactorGenerator, multiFactor } = require("../../../tests/test-helpers");
71+
const { PhoneAuthProvider, PhoneMultiFactorGenerator } = require("../../../tests/test-helpers");
72+
const {
73+
verifyPhoneNumber,
74+
enrollWithMultiFactorAssertion,
75+
formatPhoneNumber,
76+
FirebaseUIError,
77+
} = require("@firebase-ui/core");
78+
const { multiFactor } = require("firebase/auth");
4879

4980
mockVerifyPhoneNumber = verifyPhoneNumber;
5081
mockEnrollWithMultiFactorAssertion = enrollWithMultiFactorAssertion;
@@ -227,9 +258,9 @@ describe("<fui-sms-multi-factor-enrollment-form />", () => {
227258
fixture.detectChanges();
228259

229260
await component.verificationForm.handleSubmit();
230-
await fixture.whenStable();
231-
232-
expect(enrollmentSpy).toHaveBeenCalled();
261+
await waitFor(() => {
262+
expect(enrollmentSpy).toHaveBeenCalled();
263+
});
233264
});
234265

235266
it("should handle FirebaseUIError in phone verification", async () => {
@@ -291,10 +322,9 @@ describe("<fui-sms-multi-factor-enrollment-form />", () => {
291322
fixture.detectChanges();
292323

293324
await component.verificationForm.handleSubmit();
294-
await fixture.whenStable();
295-
fixture.detectChanges();
296-
297-
expect(screen.getByText(errorMessage)).toBeInTheDocument();
325+
await waitFor(() => {
326+
expect(screen.getByText(errorMessage)).toBeInTheDocument();
327+
});
298328
});
299329

300330
it("should format phone number correctly", async () => {

packages/angular/src/lib/auth/forms/mfa/totp-multi-factor-assertion-form.spec.ts

Lines changed: 35 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,25 @@
1313
* limitations under the License.
1414
*/
1515

16-
import { render, screen } from "@testing-library/angular";
16+
import { render, screen, waitFor } from "@testing-library/angular";
1717

1818
import { TotpMultiFactorAssertionFormComponent } from "./totp-multi-factor-assertion-form";
1919
import { signInWithMultiFactorAssertion, FirebaseUIError } from "../../../tests/test-helpers";
2020

21+
jest.mock("@firebase-ui/core", () => {
22+
const originalModule = jest.requireActual("@firebase-ui/core");
23+
return {
24+
...originalModule,
25+
signInWithMultiFactorAssertion: jest.fn(),
26+
FirebaseUIError: class FirebaseUIError extends Error {
27+
constructor(message: string) {
28+
super(message);
29+
this.name = "FirebaseUIError";
30+
}
31+
},
32+
};
33+
});
34+
2135
describe("<fui-totp-multi-factor-assertion-form>", () => {
2236
let TotpMultiFactorGenerator: any;
2337

@@ -28,6 +42,8 @@ describe("<fui-totp-multi-factor-assertion-form>", () => {
2842
injectMultiFactorTotpAuthVerifyFormSchema,
2943
} = require("../../../tests/test-helpers");
3044

45+
const { signInWithMultiFactorAssertion } = require("@firebase-ui/core");
46+
3147
injectTranslation.mockImplementation((category: string, key: string) => {
3248
const mockTranslations: Record<string, Record<string, string>> = {
3349
labels: {
@@ -124,9 +140,9 @@ describe("<fui-totp-multi-factor-assertion-form>", () => {
124140
fixture.detectChanges();
125141

126142
await component.form.handleSubmit();
127-
await fixture.whenStable();
128-
129-
expect(onSuccessSpy).toHaveBeenCalled();
143+
await waitFor(() => {
144+
expect(onSuccessSpy).toHaveBeenCalled();
145+
});
130146
});
131147

132148
it("calls TotpMultiFactorGenerator.assertionForSignIn with correct parameters", async () => {
@@ -151,9 +167,9 @@ describe("<fui-totp-multi-factor-assertion-form>", () => {
151167
fixture.detectChanges();
152168

153169
await component.form.handleSubmit();
154-
await fixture.whenStable();
155-
156-
expect(assertionForSignInSpy).toHaveBeenCalledWith("test-uid", "123456");
170+
await waitFor(() => {
171+
expect(assertionForSignInSpy).toHaveBeenCalledWith("test-uid", "123456");
172+
});
157173
});
158174

159175
it("calls signInWithMultiFactorAssertion with the assertion", async () => {
@@ -179,12 +195,12 @@ describe("<fui-totp-multi-factor-assertion-form>", () => {
179195
fixture.detectChanges();
180196

181197
await component.form.handleSubmit();
182-
await fixture.whenStable();
183-
184-
expect(signInWithMultiFactorAssertion).toHaveBeenCalledWith(
185-
expect.any(Object), // UI instance
186-
mockAssertion
187-
);
198+
await waitFor(() => {
199+
expect(signInWithMultiFactorAssertion).toHaveBeenCalledWith(
200+
expect.any(Object), // UI instance
201+
mockAssertion
202+
);
203+
});
188204
});
189205

190206
it("handles FirebaseUIError correctly", async () => {
@@ -210,10 +226,9 @@ describe("<fui-totp-multi-factor-assertion-form>", () => {
210226
fixture.detectChanges();
211227

212228
await component.form.handleSubmit();
213-
await fixture.whenStable();
214-
fixture.detectChanges();
215-
216-
expect(screen.getByText(errorMessage)).toBeInTheDocument();
229+
await waitFor(() => {
230+
expect(screen.getByText(errorMessage)).toBeInTheDocument();
231+
});
217232
});
218233

219234
it("handles unknown errors correctly", async () => {
@@ -238,9 +253,8 @@ describe("<fui-totp-multi-factor-assertion-form>", () => {
238253
fixture.detectChanges();
239254

240255
await component.form.handleSubmit();
241-
await fixture.whenStable();
242-
fixture.detectChanges();
243-
244-
expect(screen.getByText("An unknown error occurred")).toBeInTheDocument();
256+
await waitFor(() => {
257+
expect(screen.getByText("An unknown error occurred")).toBeInTheDocument();
258+
});
245259
});
246260
});

0 commit comments

Comments
 (0)