Skip to content

Commit 9118aca

Browse files
authored
Fix and Regression Test for FirebaseUI 1199 (#13505)
1 parent a49431e commit 9118aca

File tree

5 files changed

+208
-4
lines changed

5 files changed

+208
-4
lines changed

FirebaseAuth/CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,10 @@
55
will need expansion. (#13429)
66
- [fixed] Fix crash introduced in 11.0.0 in phone authentication flow from
77
implicitly unwrapping `nil` error after a token timeout. (#13470)
8+
- [fixed] Objective-C only: `[OAuthProvider getCredentialWithUIDelegate]` was not calling its
9+
completion handler in the main thread. Regressed in 11.0.0. The fix is only for CocoaPods and
10+
Swift Package Manager. The zip and Carthage fix will roll out in 11.2.0.
11+
(https://github.com/firebase/FirebaseUI-iOS/issues/1199)
812

913
# 11.0.0
1014
- [fixed] Fixed auth domain matching code to prioritize matching `firebaseapp.com` over `web.app`

FirebaseAuth/Sources/Swift/Auth/Auth.swift

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2320,8 +2320,12 @@ extension Auth: AuthInterop {
23202320

23212321
// MARK: Internal properties
23222322

2323-
/// Allow tests to swap in an alternate mainBundle.
2324-
var mainBundleUrlTypes: [[String: Any]]!
2323+
/// Allow tests to swap in an alternate mainBundle, including ObjC unit tests via CocoaPods.
2324+
#if FIREBASE_CI
2325+
@objc public var mainBundleUrlTypes: [[String: Any]]!
2326+
#else
2327+
var mainBundleUrlTypes: [[String: Any]]!
2328+
#endif
23252329

23262330
/// The configuration object comprising of parameters needed to make a request to Firebase
23272331
/// Auth's backend.

FirebaseAuth/Sources/Swift/AuthProvider/OAuthProvider.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -341,6 +341,7 @@ import Foundation
341341
/// - Parameter uiDelegate: An optional UI delegate used to present the mobile web flow.
342342
@available(iOS 13, tvOS 13, macOS 10.15, watchOS 8, *)
343343
@objc(getCredentialWithUIDelegate:completion:)
344+
@MainActor
344345
open func credential(with uiDelegate: AuthUIDelegate?) async throws -> AuthCredential {
345346
return try await withCheckedThrowingContinuation { continuation in
346347
getCredentialWith(uiDelegate) { credential, error in
Lines changed: 193 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,193 @@
1+
/*
2+
* Copyright 2017 Google
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
#import <TargetConditionals.h>
18+
#if TARGET_OS_IOS
19+
20+
#import <XCTest/XCTest.h>
21+
22+
@import FirebaseAuth;
23+
@import FirebaseCore;
24+
25+
/** @var kExpectationTimeout
26+
@brief The maximum time waiting for expectations to fulfill.
27+
*/
28+
static const NSTimeInterval kExpectationTimeout = 1;
29+
30+
/** @var kFakeAuthorizedDomain
31+
@brief A fake authorized domain for the app.
32+
*/
33+
static NSString *const kFakeAuthorizedDomain = @"test.firebaseapp.com";
34+
35+
/** @var kFakeBundleID
36+
@brief A fake bundle ID.
37+
*/
38+
static NSString *const kFakeBundleID = @"com.firebaseapp.example";
39+
40+
/** @var kFakeAccessToken
41+
@brief A fake access token for testing.
42+
*/
43+
static NSString *const kFakeAccessToken = @"fakeAccessToken";
44+
45+
/** @var kFakeIDToken
46+
@brief A fake ID token for testing.
47+
*/
48+
static NSString *const kFakeIDToken = @"fakeIDToken";
49+
50+
/** @var kFakeProviderID
51+
@brief A fake provider ID for testing.
52+
*/
53+
static NSString *const kFakeProviderID = @"fakeProviderID";
54+
55+
/** @var kFakeGivenName
56+
@brief A fake given name for testing.
57+
*/
58+
static NSString *const kFakeGivenName = @"fakeGivenName";
59+
60+
/** @var kFakeFamilyName
61+
@brief A fake family name for testing.
62+
*/
63+
static NSString *const kFakeFamilyName = @"fakeFamilyName";
64+
65+
/** @var kFakeAPIKey
66+
@brief A fake API key.
67+
*/
68+
static NSString *const kFakeAPIKey = @"asdfghjkl";
69+
70+
/** @var kFakeEmulatorHost
71+
@brief A fake emulator host.
72+
*/
73+
static NSString *const kFakeEmulatorHost = @"emulatorhost";
74+
75+
/** @var kFakeEmulatorPort
76+
@brief A fake emulator port.
77+
*/
78+
static NSString *const kFakeEmulatorPort = @"12345";
79+
80+
/** @var kFakeClientID
81+
@brief A fake client ID.
82+
*/
83+
static NSString *const kFakeClientID = @"123456.apps.googleusercontent.com";
84+
85+
/** @var kFakeReverseClientID
86+
@brief The dot-reversed version of the fake client ID.
87+
*/
88+
static NSString *const kFakeReverseClientID = @"com.googleusercontent.apps.123456";
89+
90+
/** @var kFakeFirebaseAppID
91+
@brief A fake Firebase app ID.
92+
*/
93+
static NSString *const kFakeFirebaseAppID = @"1:123456789:ios:123abc456def";
94+
95+
/** @var kFakeEncodedFirebaseAppID
96+
@brief A fake encoded Firebase app ID to be used as a custom URL scheme.
97+
*/
98+
static NSString *const kFakeEncodedFirebaseAppID = @"app-1-123456789-ios-123abc456def";
99+
100+
/** @var kFakeTenantID
101+
@brief A fake tenant ID.
102+
*/
103+
static NSString *const kFakeTenantID = @"tenantID";
104+
105+
/** @var kFakeOAuthResponseURL
106+
@brief A fake OAuth response URL used in test.
107+
*/
108+
static NSString *const kFakeOAuthResponseURL = @"fakeOAuthResponseURL";
109+
110+
/** @var kFakeRedirectURLResponseURL
111+
@brief A fake callback URL (minus the scheme) containing a fake response URL.
112+
*/
113+
114+
@interface FIROAuthProviderTests : XCTestCase
115+
116+
@end
117+
118+
@implementation FIROAuthProviderTests
119+
120+
/** @fn testObtainingOAuthCredentialNoIDToken
121+
@brief Tests the correct creation of an OAuthCredential without an IDToken.
122+
*/
123+
- (void)testObtainingOAuthCredentialNoIDToken {
124+
FIRAuthCredential *credential = [FIROAuthProvider credentialWithProviderID:kFakeProviderID
125+
accessToken:kFakeAccessToken];
126+
XCTAssertTrue([credential isKindOfClass:[FIROAuthCredential class]]);
127+
FIROAuthCredential *OAuthCredential = (FIROAuthCredential *)credential;
128+
XCTAssertEqualObjects(OAuthCredential.accessToken, kFakeAccessToken);
129+
XCTAssertEqualObjects(OAuthCredential.provider, kFakeProviderID);
130+
XCTAssertNil(OAuthCredential.IDToken);
131+
}
132+
133+
/** @fn testObtainingOAuthCredentialWithFullName
134+
@brief Tests the correct creation of an OAuthCredential with a fullName.
135+
*/
136+
- (void)testObtainingOAuthCredentialWithFullName {
137+
NSPersonNameComponents *fullName = [[NSPersonNameComponents alloc] init];
138+
fullName.givenName = kFakeGivenName;
139+
fullName.familyName = kFakeFamilyName;
140+
FIRAuthCredential *credential = [FIROAuthProvider appleCredentialWithIDToken:kFakeIDToken
141+
rawNonce:nil
142+
fullName:fullName];
143+
144+
XCTAssertTrue([credential isKindOfClass:[FIROAuthCredential class]]);
145+
FIROAuthCredential *OAuthCredential = (FIROAuthCredential *)credential;
146+
XCTAssertEqualObjects(OAuthCredential.provider, @"apple.com");
147+
XCTAssertEqualObjects(OAuthCredential.IDToken, kFakeIDToken);
148+
XCTAssertNil(OAuthCredential.accessToken);
149+
}
150+
151+
/** @fn testObtainingOAuthCredentialWithIDToken
152+
@brief Tests the correct creation of an OAuthCredential with an IDToken
153+
*/
154+
- (void)testObtainingOAuthCredentialWithIDToken {
155+
FIRAuthCredential *credential = [FIROAuthProvider credentialWithProviderID:kFakeProviderID
156+
IDToken:kFakeIDToken
157+
accessToken:kFakeAccessToken];
158+
XCTAssertTrue([credential isKindOfClass:[FIROAuthCredential class]]);
159+
FIROAuthCredential *OAuthCredential = (FIROAuthCredential *)credential;
160+
XCTAssertEqualObjects(OAuthCredential.accessToken, kFakeAccessToken);
161+
XCTAssertEqualObjects(OAuthCredential.provider, kFakeProviderID);
162+
XCTAssertEqualObjects(OAuthCredential.IDToken, kFakeIDToken);
163+
}
164+
165+
/** @fn testGetCredentialWithUIDelegateWithClientIDOnMainThread
166+
@brief Verifies @c getCredentialWithUIDelegate:completion: calls its completion handler on the
167+
main thread. Regression test for firebase/FirebaseUI-iOS#1199.
168+
*/
169+
- (void)testGetCredentialWithUIDelegateWithClientIDOnMainThread {
170+
XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
171+
172+
FIROptions *options =
173+
[[FIROptions alloc] initWithGoogleAppID:@"0:0000000000000:ios:0000000000000000"
174+
GCMSenderID:@"00000000000000000-00000000000-000000000"];
175+
options.APIKey = kFakeAPIKey;
176+
options.projectID = @"myProjectID";
177+
options.clientID = kFakeClientID;
178+
[FIRApp configureWithName:@"objAppName" options:options];
179+
FIRAuth *auth = [FIRAuth authWithApp:[FIRApp appNamed:@"objAppName"]];
180+
[auth setMainBundleUrlTypes:@[ @{@"CFBundleURLSchemes" : @[ kFakeReverseClientID ]} ]];
181+
182+
FIROAuthProvider *provider = [FIROAuthProvider providerWithProviderID:kFakeProviderID auth:auth];
183+
[provider getCredentialWithUIDelegate:nil
184+
completion:^(FIRAuthCredential *_Nullable credential,
185+
NSError *_Nullable error) {
186+
XCTAssertTrue([NSThread isMainThread]);
187+
[expectation fulfill];
188+
}];
189+
[self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
190+
}
191+
@end
192+
193+
#endif // TARGET_OS_IOS

Package.swift

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -461,8 +461,10 @@ let package = Package(
461461
// TODO: these tests rely on a non-zero UIApplication.shared. They run from CocoaPods.
462462
"PhoneAuthProviderTests.swift",
463463
"AuthNotificationManagerTests.swift",
464-
"ObjCAPITests.m", // Only builds via CocoaPods until mixed language or its own target.
465-
"ObjCGlobalTests.m", // Only builds via CocoaPods until mixed language or its own target.
464+
// TODO: The following tests run in CocoaPods only, until mixed language or separate target.
465+
"ObjCAPITests.m",
466+
"ObjCGlobalTests.m",
467+
"FIROAuthProviderTests.m",
466468
]
467469
),
468470
.target(

0 commit comments

Comments
 (0)