Skip to content

Commit 2b58f2d

Browse files
authored
test(auth): cover AuthMethodPickerState routing to the MFA, conflict and error handlers
1 parent 1b274f0 commit 2b58f2d

1 file changed

Lines changed: 100 additions & 0 deletions

File tree

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
// Copyright 2025 Google LLC
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
import FirebaseAuth
16+
@testable import FirebaseAuthSwiftUI
17+
import Foundation
18+
import Testing
19+
20+
/// Records which handler `AuthMethodPickerState.route` called.
21+
@MainActor
22+
private final class RouteRecorder {
23+
var mfa: MFARequired?
24+
var conflict: AccountConflictContext?
25+
var error: Error?
26+
27+
func route(_ result: Result<SignInOutcome?, Error>, handlesConflicts: Bool = true) {
28+
AuthMethodPickerState.route(
29+
result,
30+
mfaHandler: { self.mfa = $0 },
31+
accountConflictHandler: handlesConflicts ? { self.conflict = $0 } : nil,
32+
reportError: { self.error = $0 }
33+
)
34+
}
35+
}
36+
37+
private struct TestError: Error {}
38+
39+
private func conflictContext() -> AccountConflictContext {
40+
AccountConflictContext(
41+
conflictType: .accountExistsWithDifferentCredential,
42+
credential: EmailAuthProvider.credential(withEmail: "test@example.com", password: "123456"),
43+
underlyingError: TestError(),
44+
message: "conflict",
45+
email: "test@example.com"
46+
)
47+
}
48+
49+
@Suite("AuthMethodPickerState routing")
50+
@MainActor
51+
struct AuthMethodPickerStateRoutingTests {
52+
@Test("MFA required goes to the MFA handler")
53+
func mfaRequired() {
54+
let recorder = RouteRecorder()
55+
let mfa = MFARequired(hints: [.totp(displayName: nil, uid: "uid")])
56+
recorder.route(.success(.mfaRequired(mfa)))
57+
#expect(recorder.mfa == mfa)
58+
#expect(recorder.conflict == nil)
59+
#expect(recorder.error == nil)
60+
}
61+
62+
@Test("A completed sign-in calls no handler")
63+
func signedIn() {
64+
let recorder = RouteRecorder()
65+
recorder.route(.success(.signedIn(nil)))
66+
recorder.route(.success(nil))
67+
#expect(recorder.mfa == nil)
68+
#expect(recorder.conflict == nil)
69+
#expect(recorder.error == nil)
70+
}
71+
72+
@Test("An account conflict goes to the conflict handler")
73+
func accountConflict() {
74+
let recorder = RouteRecorder()
75+
let context = conflictContext()
76+
recorder.route(.failure(AuthServiceError.accountConflict(context)))
77+
#expect(recorder.conflict == context)
78+
#expect(recorder.error == nil)
79+
}
80+
81+
@Test("An account conflict is reported when there is no conflict handler")
82+
func accountConflictWithoutHandler() {
83+
let recorder = RouteRecorder()
84+
recorder.route(
85+
.failure(AuthServiceError.accountConflict(conflictContext())),
86+
handlesConflicts: false
87+
)
88+
#expect(recorder.conflict == nil)
89+
#expect(recorder.error != nil)
90+
}
91+
92+
@Test("Other errors are reported")
93+
func otherError() {
94+
let recorder = RouteRecorder()
95+
recorder.route(.failure(TestError()))
96+
#expect(recorder.error is TestError)
97+
#expect(recorder.mfa == nil)
98+
#expect(recorder.conflict == nil)
99+
}
100+
}

0 commit comments

Comments
 (0)