Skip to content

Commit cb29e7d

Browse files
authored
Add async/await variations for Auth Swift API tests (#9210)
1 parent eaaa0a6 commit cb29e7d

File tree

8 files changed

+212
-49
lines changed

8 files changed

+212
-49
lines changed

FirebaseAuth/Tests/Sample/ApiTests/FacebookAuthTests.m

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -155,8 +155,6 @@ - (NSDictionary *)createFacebookTestingAccount {
155155
error.localizedDescription);
156156
}
157157
}];
158-
NSString *userInfo = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
159-
NSLog(@"The info of created Facebook testing account is: %@", userInfo);
160158
// Parses the access token from the JSON data.
161159
NSDictionary *userInfoDict = [NSJSONSerialization JSONObjectWithData:data
162160
options:kNilOptions

FirebaseAuth/Tests/Sample/ApiTests/GoogleAuthTests.m

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -104,8 +104,6 @@ - (NSDictionary *)getGoogleAccessToken {
104104
error.localizedDescription);
105105
}
106106
}];
107-
NSString *userInfo = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
108-
NSLog(@"The info of exchanged result is: %@", userInfo);
109107
NSDictionary *userInfoDict = [NSJSONSerialization JSONObjectWithData:data
110108
options:kNilOptions
111109
error:nil];

FirebaseAuth/Tests/Sample/SwiftApiTests/AccountInfoTests.swift

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ class AccountInfoTests: TestsBase {
4848
AuthErrorCode.emailAlreadyInUse.rawValue,
4949
"Created a user despite it already exiting.")
5050
} else {
51-
XCTAssertTrue(false, "Did not get error for recreating a user")
51+
XCTFail("Did not get error for recreating a user")
5252
}
5353
expectation1.fulfill()
5454
}
@@ -74,4 +74,30 @@ class AccountInfoTests: TestsBase {
7474
}
7575
waitForExpectations(timeout:TestsBase.kExpectationsTimeout)
7676
}
77+
78+
#if compiler(>=5.5) && canImport(_Concurrency)
79+
@available(iOS 15, tvOS 15, macOS 12, watchOS 8, *)
80+
func testUpdatingUsersEmailAsync() async throws {
81+
let auth = Auth.auth()
82+
do {
83+
let _ = try await auth.createUser(withEmail: kOldUserEmail, password: "password")
84+
XCTFail("Did not get error for recreating a user")
85+
} catch {
86+
XCTAssertEqual((error as NSError).code,
87+
AuthErrorCode.emailAlreadyInUse.rawValue,
88+
"Created a user despite it already exiting.")
89+
}
90+
91+
let user = try await auth.signIn(withEmail: kOldUserEmail, password: "password")
92+
XCTAssertEqual(user.user.email, kOldUserEmail)
93+
XCTAssertEqual(auth.currentUser?.email,
94+
self.kOldUserEmail,
95+
"Signed user does not match request.")
96+
97+
try await auth.currentUser?.updateEmail(to: kNewUserEmail)
98+
XCTAssertEqual(auth.currentUser?.email,
99+
self.kNewUserEmail,
100+
"Signed user does not match change.")
101+
}
102+
#endif
77103
}

FirebaseAuth/Tests/Sample/SwiftApiTests/AnonymousTests.swift

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,21 @@ class AnonymousTests: TestsBase {
2424
if let isAnonymous = Auth.auth().currentUser?.isAnonymous {
2525
XCTAssertTrue(isAnonymous)
2626
} else {
27-
XCTAssertTrue(false, "Missing currentUser after anonymous sign in")
27+
XCTFail("Missing currentUser after anonymous sign in")
2828
}
2929
self.deleteCurrentUser()
3030
}
31+
32+
#if compiler(>=5.5) && canImport(_Concurrency)
33+
@available(iOS 15, tvOS 15, macOS 12, watchOS 8, *)
34+
func testUpdatingUsersEmailAsync() async throws {
35+
try await self.signInAnonymouslyAsync()
36+
if let isAnonymous = Auth.auth().currentUser?.isAnonymous {
37+
XCTAssertTrue(isAnonymous)
38+
} else {
39+
XCTFail("Missing currentUser after anonymous sign in")
40+
}
41+
try await self.deleteCurrentUserAsync()
42+
}
43+
#endif
3144
}

FirebaseAuth/Tests/Sample/SwiftApiTests/EmailPasswordTests.swift

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,16 @@ class EmailPasswordTests: TestsBase {
4040
self.deleteCurrentUser()
4141
}
4242

43+
#if compiler(>=5.5) && canImport(_Concurrency)
44+
@available(iOS 15, tvOS 15, macOS 12, watchOS 8, *)
45+
func testCreateAccountWithEmailAndPasswordAsync() async throws {
46+
let auth = Auth.auth()
47+
try await auth.createUser(withEmail: kNewEmailToCreateUser, password: "password")
48+
XCTAssertEqual(auth.currentUser?.email, kNewEmailToCreateUser, "Expected email doesn't match")
49+
try await self.deleteCurrentUserAsync()
50+
}
51+
#endif
52+
4353
func testSignInExistingUserWithEmailAndPassword() {
4454
let auth = Auth.auth()
4555
let expectation = self.expectation(description: "Signed in existing account with email and password.")
@@ -52,4 +62,15 @@ class EmailPasswordTests: TestsBase {
5262
}
5363
waitForExpectations(timeout:TestsBase.kExpectationsTimeout)
5464
}
65+
66+
#if compiler(>=5.5) && canImport(_Concurrency)
67+
@available(iOS 15, tvOS 15, macOS 12, watchOS 8, *)
68+
func testSignInExistingUserWithEmailAndPasswordAsync() async throws {
69+
let auth = Auth.auth()
70+
try await auth.signIn(withEmail: kExistingEmailToSignIn, password: "password")
71+
XCTAssertEqual(auth.currentUser?.email,
72+
self.kExistingEmailToSignIn,
73+
"Signed user does not match request.")
74+
}
75+
#endif
5576
}

FirebaseAuth/Tests/Sample/SwiftApiTests/FacebookTests.swift

Lines changed: 93 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -20,22 +20,16 @@ import GTMSessionFetcher
2020
import XCTest
2121

2222
class FacebookTests: TestsBase {
23-
func testSignInWithFacebook() {
23+
func testSignInWithFacebook() throws {
2424
let auth = Auth.auth()
2525
let userInfoDict = self.createFacebookTestingAccount()
26-
guard let facebookAccessToken = userInfoDict["access_token"] as! String? else {
27-
XCTAssertTrue(false, "Failed to get facebookAccessToken")
28-
return
29-
}
30-
guard let facebookAccountID = userInfoDict["id"] as! String? else {
31-
XCTAssertTrue(false, "Failed to get facebookAccountID")
32-
return
33-
}
26+
let facebookAccessToken: String = try XCTUnwrap(userInfoDict["access_token"] as? String)
27+
let facebookAccountID: String = try XCTUnwrap(userInfoDict["id"] as? String)
3428
let credential = FacebookAuthProvider.credential(withAccessToken: facebookAccessToken)
3529
let expectation = self.expectation(description: "Signing in with Facebook finished.")
3630
auth.signIn(with: credential) { (result, error) in
3731
if let error = error {
38-
XCTAssertTrue(false, "Signing in with Facebook had error: \(error)")
32+
XCTFail("Signing in with Facebook had error: \(error)")
3933
} else {
4034
XCTAssertEqual(auth.currentUser?.displayName, Credentials.kFacebookUserName)
4135
}
@@ -48,26 +42,38 @@ class FacebookTests: TestsBase {
4842
self.deleteFacebookTestingAccountbyID(facebookAccountID)
4943
}
5044

51-
func testLinkAnonymousAccountToFacebookAccount() {
45+
#if compiler(>=5.5) && canImport(_Concurrency)
46+
@available(iOS 15, tvOS 15, macOS 12, watchOS 8, *)
47+
func testSignInWithFacebookAsync() async throws {
48+
let auth = Auth.auth()
49+
let userInfoDict = try await self.createFacebookTestingAccountAsync()
50+
let facebookAccessToken: String = try XCTUnwrap(userInfoDict["access_token"] as? String)
51+
let facebookAccountID: String = try XCTUnwrap(userInfoDict["id"] as? String)
52+
let credential = FacebookAuthProvider.credential(withAccessToken: facebookAccessToken)
53+
54+
try await auth.signIn(with: credential)
55+
XCTAssertEqual(auth.currentUser?.displayName, Credentials.kFacebookUserName)
56+
57+
// Clean up the created Firebase/Facebook user for future runs.
58+
try await self.deleteCurrentUserAsync()
59+
try await self.deleteFacebookTestingAccountbyIDAsync(facebookAccountID)
60+
}
61+
#endif
62+
63+
func testLinkAnonymousAccountToFacebookAccount() throws {
5264
let auth = Auth.auth()
5365
self.signInAnonymously()
5466
let userInfoDict = self.createFacebookTestingAccount()
55-
guard let facebookAccessToken = userInfoDict["access_token"] as! String? else {
56-
XCTAssertTrue(false, "Failed to get facebookAccessToken")
57-
return
58-
}
59-
guard let facebookAccountID = userInfoDict["id"] as! String? else {
60-
XCTAssertTrue(false, "Failed to get facebookAccountID")
61-
return
62-
}
67+
let facebookAccessToken: String = try XCTUnwrap(userInfoDict["access_token"] as? String)
68+
let facebookAccountID: String = try XCTUnwrap(userInfoDict["id"] as? String)
6369
let credential = FacebookAuthProvider.credential(withAccessToken: facebookAccessToken)
6470
let expectation = self.expectation(description: "Facebook linking finished.")
6571
auth.currentUser?.link(with: credential, completion: { (result, error) in
6672
if let error = error {
67-
XCTAssertTrue(false, "Link to Firebase error: \(error)")
73+
XCTFail("Link to Firebase error: \(error)")
6874
} else {
6975
guard let providers = (auth.currentUser?.providerData) else {
70-
XCTAssertTrue(false, "Failed to get providers")
76+
XCTFail("Failed to get providers")
7177
return
7278
}
7379
XCTAssertEqual(providers.count, 1)
@@ -82,6 +88,29 @@ class FacebookTests: TestsBase {
8288
self.deleteFacebookTestingAccountbyID(facebookAccountID)
8389
}
8490

91+
#if compiler(>=5.5) && canImport(_Concurrency)
92+
@available(iOS 15, tvOS 15, macOS 12, watchOS 8, *)
93+
func testLinkAnonymousAccountToFacebookAccountAsync() async throws {
94+
let auth = Auth.auth()
95+
try await self.signInAnonymouslyAsync()
96+
let userInfoDict = try await self.createFacebookTestingAccountAsync()
97+
let facebookAccessToken: String = try XCTUnwrap(userInfoDict["access_token"] as? String)
98+
let facebookAccountID: String = try XCTUnwrap(userInfoDict["id"] as? String)
99+
let credential = FacebookAuthProvider.credential(withAccessToken: facebookAccessToken)
100+
try await auth.currentUser?.link(with: credential)
101+
guard let providers = (auth.currentUser?.providerData) else {
102+
XCTFail("Failed to get providers")
103+
return
104+
}
105+
XCTAssertEqual(providers.count, 1)
106+
XCTAssertEqual(providers[0].providerID, "facebook.com")
107+
108+
// Clean up the created Firebase/Facebook user for future runs.
109+
try await self.deleteCurrentUserAsync()
110+
try await self.deleteFacebookTestingAccountbyIDAsync(facebookAccountID)
111+
}
112+
#endif
113+
85114
///** Creates a Facebook testing account using Facebook Graph API and return a dictionary that
86115
// * constains "id", "access_token", "login_url", "email" and "password" of the created account.
87116
// */
@@ -102,22 +131,17 @@ class FacebookTests: TestsBase {
102131
let error = error as NSError
103132
if let message = String.init(data: error.userInfo["data"] as! Data, encoding: .utf8) {
104133
// May get transient errors here for too many api calls when tests run frequently.
105-
XCTAssertTrue(false, "Creating Facebook account failed with error: \(message)")
134+
XCTFail("Creating Facebook account failed with error: \(message)")
106135
} else {
107-
XCTAssertTrue(false, "Creating Facebook account failed with error: \(error)")
136+
XCTFail("Creating Facebook account failed with error: \(error)")
108137
}
109138
} else {
110139
do {
111140
let data = try XCTUnwrap(data)
112-
guard let userInfo = String.init(data: data, encoding: .utf8) else {
113-
XCTAssertTrue(false, "Failed to convert data to string")
114-
return
115-
}
116-
print("The created Facebook testing account info is: \(String(describing: userInfo))")
117141
returnValue = try JSONSerialization.jsonObject(with: data, options: [])
118142
as! Dictionary<String, Any>
119143
} catch (let error) {
120-
XCTAssertTrue(false, "Failed to unwrap data \(error)")
144+
XCTFail("Failed to unwrap data \(error)")
121145
}
122146
}
123147
expectation.fulfill()
@@ -126,6 +150,31 @@ class FacebookTests: TestsBase {
126150
return returnValue
127151
}
128152

153+
#if compiler(>=5.5) && canImport(_Concurrency)
154+
@available(iOS 15, tvOS 15, macOS 12, watchOS 8, *)
155+
///** Creates a Facebook testing account using Facebook Graph API and return a dictionary that
156+
// * constains "id", "access_token", "login_url", "email" and "password" of the created account.
157+
// */
158+
func createFacebookTestingAccountAsync() async throws -> Dictionary<String, Any> {
159+
let urltoCreateTestUser = "https://graph.facebook.com/\(Credentials.kFacebookAppID)" +
160+
"/accounts/test-users"
161+
let bodyString = "installed=true&name=\(Credentials.kFacebookUserName)" +
162+
"&permissions=read_stream&access_token=\(Credentials.kFacebookAppAccessToken)"
163+
let postData = bodyString.data(using: .utf8)
164+
let service = GTMSessionFetcherService.init()
165+
let fetcher = service.fetcher(withURLString: urltoCreateTestUser)
166+
fetcher.bodyData = postData
167+
fetcher.setRequestValue("text/plain", forHTTPHeaderField: "Content-Type")
168+
let data = try await fetcher.beginFetch()
169+
guard let returnValue = try JSONSerialization.jsonObject(with: data, options: [])
170+
as? Dictionary<String, Any> else {
171+
XCTFail("Failed to serialize userInfo as a Dictionary")
172+
fatalError()
173+
}
174+
return returnValue
175+
}
176+
#endif
177+
129178
//** Delete a Facebook testing account by account Id using Facebook Graph API. */
130179
func deleteFacebookTestingAccountbyID(_ accountID: String) {
131180
let urltoDeleteTestUser = "https://graph.facebook.com/\(accountID)"
@@ -138,10 +187,24 @@ class FacebookTests: TestsBase {
138187
let expectation = self.expectation(description: "Deleting Facebook account finished.")
139188
fetcher.beginFetch { (data, error) in
140189
if let error = error {
141-
XCTAssertTrue(false, "Deleting Facebook account failed with error: \(error)")
190+
XCTFail("Deleting Facebook account failed with error: \(error)")
142191
}
143192
expectation.fulfill()
144193
}
145194
waitForExpectations(timeout:TestsBase.kExpectationsTimeout)
146195
}
196+
#if compiler(>=5.5) && canImport(_Concurrency)
197+
@available(iOS 15, tvOS 15, macOS 12, watchOS 8, *)
198+
//** Delete a Facebook testing account by account Id using Facebook Graph API. */
199+
func deleteFacebookTestingAccountbyIDAsync(_ accountID: String) async throws{
200+
let urltoDeleteTestUser = "https://graph.facebook.com/\(accountID)"
201+
let bodyString = "method=delete&access_token=\(Credentials.kFacebookAppAccessToken)"
202+
let postData = bodyString.data(using: .utf8)
203+
let service = GTMSessionFetcherService.init()
204+
let fetcher = service.fetcher(withURLString: urltoDeleteTestUser)
205+
fetcher.bodyData = postData
206+
fetcher.setRequestValue("text/plain", forHTTPHeaderField: "Content-Type")
207+
try await fetcher.beginFetch()
208+
}
209+
#endif
147210
}

FirebaseAuth/Tests/Sample/SwiftApiTests/GoogleTests.swift

Lines changed: 43 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -21,17 +21,11 @@ import XCTest
2121

2222
class GoogleTests: TestsBase {
2323

24-
func testSignInWithGoogle() {
24+
func testSignInWithGoogle() throws {
2525
let auth = Auth.auth()
2626
let userInfoDict = self.getGoogleAccessToken()
27-
guard let googleAccessToken = userInfoDict["access_token"] as! String? else {
28-
XCTAssertTrue(false, "Failed to get googleAccessToken")
29-
return
30-
}
31-
guard let googleIDToken = userInfoDict["id_token"] as! String? else {
32-
XCTAssertTrue(false, "Failed to get googleIDToken")
33-
return
34-
}
27+
let googleAccessToken: String = try XCTUnwrap(userInfoDict["access_token"] as? String)
28+
let googleIDToken: String = try XCTUnwrap(userInfoDict["id_token"] as? String)
3529
let credential = GoogleAuthProvider.credential(withIDToken: googleIDToken,
3630
accessToken: googleAccessToken)
3731
let expectation = self.expectation(description: "Signing in with Google finished.")
@@ -43,6 +37,18 @@ class GoogleTests: TestsBase {
4337
}
4438
waitForExpectations(timeout:TestsBase.kExpectationsTimeout)
4539
}
40+
#if compiler(>=5.5) && canImport(_Concurrency)
41+
@available(iOS 15, tvOS 15, macOS 12, watchOS 8, *)
42+
func testSignInWithGoogleAsync() async throws {
43+
let auth = Auth.auth()
44+
let userInfoDict = try await self.getGoogleAccessTokenAsync()
45+
let googleAccessToken: String = try XCTUnwrap(userInfoDict["access_token"] as? String)
46+
let googleIDToken: String = try XCTUnwrap(userInfoDict["id_token"] as? String)
47+
let credential = GoogleAuthProvider.credential(withIDToken: googleIDToken,
48+
accessToken: googleAccessToken)
49+
let _ = try await auth.signIn(with: credential)
50+
}
51+
#endif
4652

4753
///** Sends http request to Google OAuth2 token server to use refresh token to exchange for Google
4854
// * access token. Returns a dictionary that constains "access_token", "token_type", "expires_in" and
@@ -62,21 +68,45 @@ class GoogleTests: TestsBase {
6268
let expectation = self.expectation(description: "Exchanging Google account tokens finished.")
6369
fetcher.beginFetch { (data, error) in
6470
if let error = error {
65-
XCTAssertTrue(false, "Exchanging Google account tokens finished with error: \(error)")
71+
XCTFail("Exchanging Google account tokens finished with error: \(error)")
6672
} else {
6773
do {
6874
let data = try XCTUnwrap(data)
69-
let userInfo = String.init(data: data, encoding: .utf8)
70-
print("The info of exchanged result is: \(String(describing: userInfo))")
7175
returnValue = try JSONSerialization.jsonObject(with: data, options: [])
7276
as! Dictionary<String, Any>
7377
} catch (let error) {
74-
XCTAssertTrue(false, "Failed to unwrap data \(error)")
78+
XCTFail("Failed to unwrap data \(error)")
7579
}
7680
}
7781
expectation.fulfill()
7882
}
7983
waitForExpectations(timeout:TestsBase.kExpectationsTimeout)
8084
return returnValue
8185
}
86+
87+
#if compiler(>=5.5) && canImport(_Concurrency)
88+
@available(iOS 15, tvOS 15, macOS 12, watchOS 8, *)
89+
///** Sends http request to Google OAuth2 token server to use refresh token to exchange for Google
90+
// * access token. Returns a dictionary that constains "access_token", "token_type", "expires_in" and
91+
// * sometimes the "id_token". (The id_token is not guaranteed to be returned during a refresh
92+
// * exchange; see https://openid.net/specs/openid-connect-core-1_0.html#RefreshTokenResponse)
93+
// */
94+
func getGoogleAccessTokenAsync() async throws -> Dictionary<String, Any> {
95+
let googleOauth2TokenServerUrl = "https://www.googleapis.com/oauth2/v4/token"
96+
let bodyString = "client_id=\(Credentials.kGoogleClientID)&grant_type=refresh_token" +
97+
"&refresh_token=\(Credentials.kGoogleTestAccountRefreshToken)"
98+
let postData = bodyString.data(using: .utf8)
99+
let service = GTMSessionFetcherService.init()
100+
let fetcher = service.fetcher(withURLString: googleOauth2TokenServerUrl)
101+
fetcher.bodyData = postData
102+
fetcher.setRequestValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
103+
let data = try await fetcher.beginFetch()
104+
guard let returnValue = try JSONSerialization.jsonObject(with: data, options: [])
105+
as? Dictionary<String, Any> else {
106+
XCTFail("Failed to serialize userInfo as a Dictionary")
107+
fatalError()
108+
}
109+
return returnValue
110+
}
111+
#endif
82112
}

0 commit comments

Comments
 (0)