FacebookTests.swift 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211
  1. /*
  2. * Copyright 2020 Google LLC
  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. import Foundation
  17. import FirebaseAuth
  18. import GTMSessionFetcher
  19. import XCTest
  20. class FacebookTests: TestsBase {
  21. func testSignInWithFacebook() throws {
  22. let auth = Auth.auth()
  23. let userInfoDict = createFacebookTestingAccount()
  24. let facebookAccessToken: String = try XCTUnwrap(userInfoDict["access_token"] as? String)
  25. let facebookAccountID: String = try XCTUnwrap(userInfoDict["id"] as? String)
  26. let credential = FacebookAuthProvider.credential(withAccessToken: facebookAccessToken)
  27. let expectation = self.expectation(description: "Signing in with Facebook finished.")
  28. auth.signIn(with: credential) { result, error in
  29. if let error = error {
  30. XCTFail("Signing in with Facebook had error: \(error)")
  31. } else {
  32. XCTAssertEqual(auth.currentUser?.displayName, Credentials.kFacebookUserName)
  33. }
  34. expectation.fulfill()
  35. }
  36. waitForExpectations(timeout: TestsBase.kExpectationsTimeout)
  37. // Clean up the created Firebase/Facebook user for future runs.
  38. deleteCurrentUser()
  39. deleteFacebookTestingAccountbyID(facebookAccountID)
  40. }
  41. #if compiler(>=5.5.2) && canImport(_Concurrency)
  42. @available(iOS 13, tvOS 13, macOS 10.15, macCatalyst 13, watchOS 7, *)
  43. func testSignInWithFacebookAsync() async throws {
  44. let auth = Auth.auth()
  45. let userInfoDict = try await createFacebookTestingAccountAsync()
  46. let facebookAccessToken: String = try XCTUnwrap(userInfoDict["access_token"] as? String)
  47. let facebookAccountID: String = try XCTUnwrap(userInfoDict["id"] as? String)
  48. let credential = FacebookAuthProvider.credential(withAccessToken: facebookAccessToken)
  49. try await auth.signIn(with: credential)
  50. XCTAssertEqual(auth.currentUser?.displayName, Credentials.kFacebookUserName)
  51. // Clean up the created Firebase/Facebook user for future runs.
  52. try await deleteCurrentUserAsync()
  53. try await deleteFacebookTestingAccountbyIDAsync(facebookAccountID)
  54. }
  55. #endif
  56. func testLinkAnonymousAccountToFacebookAccount() throws {
  57. let auth = Auth.auth()
  58. signInAnonymously()
  59. let userInfoDict = createFacebookTestingAccount()
  60. let facebookAccessToken: String = try XCTUnwrap(userInfoDict["access_token"] as? String)
  61. let facebookAccountID: String = try XCTUnwrap(userInfoDict["id"] as? String)
  62. let credential = FacebookAuthProvider.credential(withAccessToken: facebookAccessToken)
  63. let expectation = self.expectation(description: "Facebook linking finished.")
  64. auth.currentUser?.link(with: credential, completion: { result, error in
  65. if let error = error {
  66. XCTFail("Link to Firebase error: \(error)")
  67. } else {
  68. guard let providers = (auth.currentUser?.providerData) else {
  69. XCTFail("Failed to get providers")
  70. return
  71. }
  72. XCTAssertEqual(providers.count, 1)
  73. XCTAssertEqual(providers[0].providerID, "facebook.com")
  74. }
  75. expectation.fulfill()
  76. })
  77. waitForExpectations(timeout: TestsBase.kExpectationsTimeout)
  78. // Clean up the created Firebase/Facebook user for future runs.
  79. deleteCurrentUser()
  80. deleteFacebookTestingAccountbyID(facebookAccountID)
  81. }
  82. #if compiler(>=5.5.2) && canImport(_Concurrency)
  83. @available(iOS 13, tvOS 13, macOS 10.15, macCatalyst 13, watchOS 7, *)
  84. func testLinkAnonymousAccountToFacebookAccountAsync() async throws {
  85. let auth = Auth.auth()
  86. try await signInAnonymouslyAsync()
  87. let userInfoDict = try await createFacebookTestingAccountAsync()
  88. let facebookAccessToken: String = try XCTUnwrap(userInfoDict["access_token"] as? String)
  89. let facebookAccountID: String = try XCTUnwrap(userInfoDict["id"] as? String)
  90. let credential = FacebookAuthProvider.credential(withAccessToken: facebookAccessToken)
  91. try await auth.currentUser?.link(with: credential)
  92. guard let providers = (auth.currentUser?.providerData) else {
  93. XCTFail("Failed to get providers")
  94. return
  95. }
  96. XCTAssertEqual(providers.count, 1)
  97. XCTAssertEqual(providers[0].providerID, "facebook.com")
  98. // Clean up the created Firebase/Facebook user for future runs.
  99. try await deleteCurrentUserAsync()
  100. try await deleteFacebookTestingAccountbyIDAsync(facebookAccountID)
  101. }
  102. #endif
  103. /// ** Creates a Facebook testing account using Facebook Graph API and return a dictionary that
  104. // * constains "id", "access_token", "login_url", "email" and "password" of the created account.
  105. // */
  106. func createFacebookTestingAccount() -> [String: Any] {
  107. var returnValue: [String: Any] = [:]
  108. let urltoCreateTestUser = "https://graph.facebook.com/\(Credentials.kFacebookAppID)" +
  109. "/accounts/test-users"
  110. let bodyString = "installed=true&name=\(Credentials.kFacebookUserName)" +
  111. "&permissions=read_stream&access_token=\(Credentials.kFacebookAppAccessToken)"
  112. let postData = bodyString.data(using: .utf8)
  113. let service = GTMSessionFetcherService()
  114. let fetcher = service.fetcher(withURLString: urltoCreateTestUser)
  115. fetcher.bodyData = postData
  116. fetcher.setRequestValue("text/plain", forHTTPHeaderField: "Content-Type")
  117. let expectation = self.expectation(description: "Creating Facebook account finished.")
  118. fetcher.beginFetch { data, error in
  119. if let error = error {
  120. let error = error as NSError
  121. if let message = String(data: error.userInfo["data"] as! Data, encoding: .utf8) {
  122. // May get transient errors here for too many api calls when tests run frequently.
  123. XCTFail("Creating Facebook account failed with error: \(message)")
  124. } else {
  125. XCTFail("Creating Facebook account failed with error: \(error)")
  126. }
  127. } else {
  128. do {
  129. let data = try XCTUnwrap(data)
  130. returnValue = try JSONSerialization.jsonObject(with: data, options: [])
  131. as! [String: Any]
  132. } catch {
  133. XCTFail("Failed to unwrap data \(error)")
  134. }
  135. }
  136. expectation.fulfill()
  137. }
  138. waitForExpectations(timeout: TestsBase.kExpectationsTimeout)
  139. return returnValue
  140. }
  141. #if compiler(>=5.5.2) && canImport(_Concurrency)
  142. @available(iOS 13, tvOS 13, macOS 10.15, macCatalyst 13, watchOS 7, *)
  143. /// ** Creates a Facebook testing account using Facebook Graph API and return a dictionary that
  144. // * constains "id", "access_token", "login_url", "email" and "password" of the created account.
  145. // */
  146. func createFacebookTestingAccountAsync() async throws -> [String: Any] {
  147. let urltoCreateTestUser = "https://graph.facebook.com/\(Credentials.kFacebookAppID)" +
  148. "/accounts/test-users"
  149. let bodyString = "installed=true&name=\(Credentials.kFacebookUserName)" +
  150. "&permissions=read_stream&access_token=\(Credentials.kFacebookAppAccessToken)"
  151. let postData = bodyString.data(using: .utf8)
  152. let service = GTMSessionFetcherService()
  153. let fetcher = service.fetcher(withURLString: urltoCreateTestUser)
  154. fetcher.bodyData = postData
  155. fetcher.setRequestValue("text/plain", forHTTPHeaderField: "Content-Type")
  156. let data = try await fetcher.beginFetch()
  157. guard let returnValue = try JSONSerialization.jsonObject(with: data, options: [])
  158. as? [String: Any] else {
  159. XCTFail("Failed to serialize userInfo as a Dictionary")
  160. fatalError()
  161. }
  162. return returnValue
  163. }
  164. #endif
  165. // ** Delete a Facebook testing account by account Id using Facebook Graph API. */
  166. func deleteFacebookTestingAccountbyID(_ accountID: String) {
  167. let urltoDeleteTestUser = "https://graph.facebook.com/\(accountID)"
  168. let bodyString = "method=delete&access_token=\(Credentials.kFacebookAppAccessToken)"
  169. let postData = bodyString.data(using: .utf8)
  170. let service = GTMSessionFetcherService()
  171. let fetcher = service.fetcher(withURLString: urltoDeleteTestUser)
  172. fetcher.bodyData = postData
  173. fetcher.setRequestValue("text/plain", forHTTPHeaderField: "Content-Type")
  174. let expectation = self.expectation(description: "Deleting Facebook account finished.")
  175. fetcher.beginFetch { data, error in
  176. if let error = error {
  177. XCTFail("Deleting Facebook account failed with error: \(error)")
  178. }
  179. expectation.fulfill()
  180. }
  181. waitForExpectations(timeout: TestsBase.kExpectationsTimeout)
  182. }
  183. #if compiler(>=5.5.2) && canImport(_Concurrency)
  184. @available(iOS 13, tvOS 13, macOS 10.15, macCatalyst 13, watchOS 7, *)
  185. // ** Delete a Facebook testing account by account Id using Facebook Graph API. */
  186. func deleteFacebookTestingAccountbyIDAsync(_ accountID: String) async throws {
  187. let urltoDeleteTestUser = "https://graph.facebook.com/\(accountID)"
  188. let bodyString = "method=delete&access_token=\(Credentials.kFacebookAppAccessToken)"
  189. let postData = bodyString.data(using: .utf8)
  190. let service = GTMSessionFetcherService()
  191. let fetcher = service.fetcher(withURLString: urltoDeleteTestUser)
  192. fetcher.bodyData = postData
  193. fetcher.setRequestValue("text/plain", forHTTPHeaderField: "Content-Type")
  194. try await fetcher.beginFetch()
  195. }
  196. #endif
  197. }