Skip to content

Commit d6e78e0

Browse files
Merge branch 'main' into test-uikit
2 parents 5f7ee84 + 937da2a commit d6e78e0

10 files changed

Lines changed: 275 additions & 502 deletions

File tree

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,3 +29,4 @@ Pods/
2929
Podfile.lock
3030
*.xcworkspace/
3131
samples/**/GoogleService-Info.plist
32+
e2eTest/FirebaseSwiftUIExample/FirebaseSwiftUIExampleUITests.xcresult/

FirebaseSwiftUI/FirebaseAuthSwiftUI/Sources/Views/EmailLinkView.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import FirebaseAuthUIComponents
1717
import FirebaseCore
1818
import SwiftUI
1919

20+
@MainActor
2021
public struct EmailLinkView {
2122
@Environment(AuthService.self) private var authService
2223
@Environment(\.accountConflictHandler) private var accountConflictHandler

FirebaseSwiftUI/FirebaseAuthSwiftUI/Sources/Views/PasswordRecoveryView.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import FirebaseAuthUIComponents
1616
import FirebaseCore
1717
import SwiftUI
1818

19+
@MainActor
1920
public struct PasswordRecoveryView {
2021
@Environment(AuthService.self) private var authService
2122
@State private var email = ""

Gemfile.lock

Lines changed: 16 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,8 @@
11
GEM
22
remote: https://rubygems.org/
33
specs:
4-
CFPropertyList (3.0.7)
5-
base64
6-
nkf
7-
rexml
8-
activesupport (7.1.5.2)
4+
CFPropertyList (3.0.9)
5+
activesupport (7.1.6)
96
base64
107
benchmark (>= 0.3)
118
bigdecimal
@@ -18,15 +15,15 @@ GEM
1815
mutex_m
1916
securerandom (>= 0.3)
2017
tzinfo (~> 2.0)
21-
addressable (2.8.7)
22-
public_suffix (>= 2.0.2, < 7.0)
18+
addressable (2.8.9)
19+
public_suffix (>= 2.0.2, < 8.0)
2320
algoliasearch (1.27.5)
2421
httpclient (~> 2.8, >= 2.8.3)
2522
json (>= 1.5.1)
2623
atomos (0.1.3)
2724
base64 (0.3.0)
28-
benchmark (0.4.1)
29-
bigdecimal (3.2.3)
25+
benchmark (0.5.0)
26+
bigdecimal (4.1.0)
3027
claide (1.1.0)
3128
cocoapods (1.16.2)
3229
addressable (~> 2.8)
@@ -66,35 +63,35 @@ GEM
6663
netrc (~> 0.11)
6764
cocoapods-try (1.2.0)
6865
colored2 (3.1.2)
69-
concurrent-ruby (1.3.5)
70-
connection_pool (2.5.4)
66+
concurrent-ruby (1.3.6)
67+
connection_pool (2.5.5)
7168
drb (2.2.3)
7269
escape (0.0.4)
73-
ethon (0.17.0)
70+
ethon (0.18.0)
7471
ffi (>= 1.15.0)
75-
ffi (1.17.2)
72+
logger
73+
ffi (1.17.4)
7674
fourflusher (2.3.1)
7775
fuzzy_match (2.0.4)
7876
gh_inspector (1.1.3)
7977
httpclient (2.9.0)
8078
mutex_m
81-
i18n (1.14.7)
79+
i18n (1.14.8)
8280
concurrent-ruby (~> 1.0)
83-
json (2.15.0)
81+
json (2.19.3)
8482
logger (1.7.0)
85-
minitest (5.25.5)
83+
minitest (5.26.1)
8684
molinillo (0.8.0)
8785
mutex_m (0.3.0)
8886
nanaimo (0.4.0)
8987
nap (1.1.0)
9088
netrc (0.11.0)
91-
nkf (0.2.0)
9289
public_suffix (4.0.7)
9390
rexml (3.4.4)
9491
ruby-macho (2.5.1)
9592
securerandom (0.3.2)
96-
typhoeus (1.4.1)
97-
ethon (>= 0.9.0)
93+
typhoeus (1.6.0)
94+
ethon (>= 0.18.0)
9895
tzinfo (2.0.6)
9996
concurrent-ruby (~> 1.0)
10097
xcodeproj (1.27.0)

e2eTest/FirebaseSwiftUIExample/FirebaseSwiftUIExampleUITests/FirebaseSwiftUIExampleUITests.swift

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -233,22 +233,15 @@ final class FirebaseSwiftUIExampleUITests: XCTestCase {
233233
let emailField = app.textFields["email-field"]
234234

235235
XCTAssertTrue(emailField.waitForExistence(timeout: 2), "Email field should exist")
236-
// Workaround for updating SecureFields with ConnectHardwareKeyboard enabled
237-
UIPasteboard.general.string = email
238-
emailField.press(forDuration: 1.2)
239-
app.menuItems["Paste"].tap()
236+
try pasteIntoField(emailField, text: email, app: app)
240237

241238
let passwordField = app.secureTextFields["password-field"]
242239
XCTAssertTrue(passwordField.exists, "Password field should exist")
243-
UIPasteboard.general.string = password
244-
passwordField.press(forDuration: 1.2)
245-
app.menuItems["Paste"].tap()
240+
try pasteIntoField(passwordField, text: password, app: app)
246241

247242
let confirmPasswordField = app.secureTextFields["confirm-password-field"]
248243
XCTAssertTrue(confirmPasswordField.exists, "Confirm password field should exist")
249-
UIPasteboard.general.string = password
250-
confirmPasswordField.press(forDuration: 1.2)
251-
app.menuItems["Paste"].tap()
244+
try pasteIntoField(confirmPasswordField, text: password, app: app)
252245

253246
// Create the user (sign up)
254247
let signUpButton = app

e2eTest/FirebaseSwiftUIExample/FirebaseSwiftUIExampleUITests/MFAEnrolmentUITests.swift

Lines changed: 64 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -56,23 +56,7 @@ final class MFAEnrollmentUITests: XCTestCase {
5656
// Sign in first to access MFA management
5757
try signInToApp(app: app, email: email)
5858

59-
// Check MFA management button exists
60-
let mfaManagementButton = app.buttons["mfa-management-button"]
61-
XCTAssertTrue(
62-
mfaManagementButton.waitForExistence(timeout: 5),
63-
"MFA management button should exist"
64-
)
65-
XCTAssertTrue(mfaManagementButton.isEnabled, "MFA management button should be enabled")
66-
67-
// Tap the button
68-
mfaManagementButton.tap()
69-
70-
// Verify we navigated to MFA management view
71-
let managementTitle = app.staticTexts["Two-Factor Authentication"]
72-
XCTAssertTrue(
73-
managementTitle.waitForExistence(timeout: 5),
74-
"Should navigate to MFA management view"
75-
)
59+
try navigateToMFAManagement(app: app)
7660
}
7761

7862
@MainActor
@@ -87,16 +71,16 @@ final class MFAEnrollmentUITests: XCTestCase {
8771

8872
// Sign in and navigate to MFA management
8973
try signInToApp(app: app, email: email)
90-
app.buttons["mfa-management-button"].tap()
74+
try navigateToMFAManagement(app: app)
9175

9276
// Tap setup MFA button (for users with no enrolled factors)
9377
let setupButton = app.buttons["setup-mfa-button"]
94-
if setupButton.waitForExistence(timeout: 3) {
78+
if setupButton.waitForExistence(timeout: 10) {
9579
setupButton.tap()
9680
} else {
9781
// If factors are already enrolled, tap add another method
9882
let addMethodButton = app.buttons["add-mfa-method-button"]
99-
XCTAssertTrue(addMethodButton.waitForExistence(timeout: 3), "Add method button should exist")
83+
XCTAssertTrue(addMethodButton.waitForExistence(timeout: 10), "Add method button should exist")
10084
addMethodButton.tap()
10185
}
10286

@@ -448,27 +432,46 @@ final class MFAEnrollmentUITests: XCTestCase {
448432
signedInText.waitForExistence(timeout: 30),
449433
"SignedInView should be visible after login"
450434
)
435+
dismissAlert(app: app)
451436
XCTAssertTrue(signedInText.exists, "SignedInView should be visible after login")
452437
}
453438

439+
@MainActor
440+
private func navigateToMFAManagement(app: XCUIApplication) throws {
441+
dismissAlert(app: app)
442+
443+
let mfaManagementButton = app.buttons["mfa-management-button"]
444+
XCTAssertTrue(
445+
mfaManagementButton.waitForExistence(timeout: 10),
446+
"MFA management button should exist"
447+
)
448+
XCTAssertTrue(mfaManagementButton.isEnabled, "MFA management button should be enabled")
449+
mfaManagementButton.tap()
450+
451+
let managementTitle = app.staticTexts["Two-Factor Authentication"]
452+
XCTAssertTrue(
453+
managementTitle.waitForExistence(timeout: 10),
454+
"Should navigate to MFA management view"
455+
)
456+
}
457+
454458
@MainActor
455459
private func navigateToMFAEnrollment(app: XCUIApplication) throws {
456-
// Navigate to MFA management
457-
app.buttons["mfa-management-button"].tap()
460+
try navigateToMFAManagement(app: app)
458461

459462
// Navigate to MFA enrollment
460463
let setupButton = app.buttons["setup-mfa-button"]
461-
if setupButton.waitForExistence(timeout: 3) {
464+
if setupButton.waitForExistence(timeout: 10) {
462465
setupButton.tap()
463466
} else {
464467
let addMethodButton = app.buttons["add-mfa-method-button"]
465-
XCTAssertTrue(addMethodButton.waitForExistence(timeout: 3), "Add method button should exist")
468+
XCTAssertTrue(addMethodButton.waitForExistence(timeout: 10), "Add method button should exist")
466469
addMethodButton.tap()
467470
}
468471

469472
// Verify we're in MFA enrollment view
470473
let enrollmentTitle = app.staticTexts["Set Up Two-Factor Authentication"]
471-
XCTAssertTrue(enrollmentTitle.waitForExistence(timeout: 5), "Should be in MFA enrollment view")
474+
XCTAssertTrue(enrollmentTitle.waitForExistence(timeout: 10), "Should be in MFA enrollment view")
472475
}
473476
}
474477

@@ -486,49 +489,51 @@ struct VerificationCode: Codable {
486489
/// - Returns: The verification code as a String
487490
/// - Throws: Error if unable to retrieve codes
488491
private func getLastSmsCode(specificPhone: String? = nil) async throws -> String {
489-
let getSmsCodesUrl =
490-
"http://127.0.0.1:9099/emulator/v1/projects/flutterfire-e2e-tests/verificationCodes"
492+
do {
493+
for projectID in authEmulatorCandidateProjectIDs() {
494+
let getSmsCodesUrl =
495+
"http://127.0.0.1:9099/emulator/v1/projects/\(projectID)/verificationCodes"
491496

492-
guard let url = URL(string: getSmsCodesUrl) else {
493-
throw NSError(
494-
domain: "getLastSmsCode",
495-
code: -1,
496-
userInfo: [NSLocalizedDescriptionKey: "Failed to create URL for SMS codes endpoint"]
497-
)
498-
}
497+
guard let url = URL(string: getSmsCodesUrl) else {
498+
continue
499+
}
499500

500-
do {
501-
let (data, _) = try await URLSession.shared.data(from: url)
501+
guard let (data, _) = try? await URLSession.shared.data(from: url) else {
502+
continue
503+
}
502504

503-
let decoder = JSONDecoder()
504-
let codesResponse = try decoder.decode(VerificationCodesResponse.self, from: data)
505+
let decoder = JSONDecoder()
506+
guard let codesResponse = try? decoder.decode(VerificationCodesResponse.self, from: data) else {
507+
continue
508+
}
505509

506-
guard let codes = codesResponse.verificationCodes, !codes.isEmpty else {
507-
throw NSError(
508-
domain: "getLastSmsCode",
509-
code: -1,
510-
userInfo: [NSLocalizedDescriptionKey: "No SMS verification codes found in emulator"]
511-
)
512-
}
510+
guard let codes = codesResponse.verificationCodes, !codes.isEmpty else {
511+
continue
512+
}
513513

514-
if let specificPhone = specificPhone {
515-
// Search backwards through codes for the specific phone number
516-
for code in codes.reversed() {
517-
if code.phoneNumber == specificPhone {
518-
return code.code
514+
if let specificPhone = specificPhone {
515+
// Search backwards through codes for the specific phone number
516+
for code in codes.reversed() {
517+
if code.phoneNumber == specificPhone {
518+
return code.code
519+
}
519520
}
521+
} else if let lastCode = codes.last {
522+
return lastCode.code
520523
}
521-
throw NSError(
522-
domain: "getLastSmsCode",
523-
code: -1,
524-
userInfo: [
525-
NSLocalizedDescriptionKey: "No SMS verification code found for phone number: \(specificPhone)",
526-
]
527-
)
524+
}
525+
526+
let description = if let specificPhone {
527+
"No SMS verification code found for phone number: \(specificPhone)"
528528
} else {
529-
// Return the last code in the array
530-
return codes.last!.code
529+
"No SMS verification codes found in emulator"
531530
}
531+
532+
throw NSError(
533+
domain: "getLastSmsCode",
534+
code: -1,
535+
userInfo: [NSLocalizedDescriptionKey: description]
536+
)
532537
} catch let error as DecodingError {
533538
throw NSError(
534539
domain: "getLastSmsCode",

0 commit comments

Comments
 (0)