UserTests.swift 81 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914
  1. // Copyright 2023 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. import Foundation
  15. import XCTest
  16. @testable import FirebaseAuth
  17. import FirebaseCore
  18. @available(iOS 13, tvOS 13, macOS 10.15, macCatalyst 13, watchOS 7, *)
  19. class UserTests: RPCBaseTests {
  20. static let kFakeAPIKey = "FAKE_API_KEY"
  21. let kFacebookAccessToken = "FACEBOOK_ACCESS_TOKEN"
  22. let kFacebookID = "FACEBOOK_ID"
  23. let kFacebookEmail = "user@facebook.com"
  24. let kFacebookDisplayName = "Facebook Doe"
  25. let kFacebookIDToken: String? = nil // Facebook id Token is always nil.
  26. let kNewEmail = "newuser@company.com"
  27. let kNewPassword = "newpassword"
  28. let kNewDisplayName = "New User Doe"
  29. let kVerificationCode = "12345678"
  30. let kVerificationID = "55432"
  31. let kPhoneNumber = "555-1234"
  32. var auth: Auth?
  33. override func setUp() {
  34. super.setUp()
  35. let options = FirebaseOptions(googleAppID: "0:0000000000000:ios:0000000000000000",
  36. gcmSenderID: "00000000000000000-00000000000-000000000")
  37. options.apiKey = Self.kFakeAPIKey
  38. options.projectID = "myUserProjectID"
  39. FirebaseApp.configure(name: "test-UserTests", options: options)
  40. #if (os(macOS) && !FIREBASE_AUTH_TESTING_USE_MACOS_KEYCHAIN) || SWIFT_PACKAGE
  41. let keychainStorageProvider = FakeAuthKeychainStorage()
  42. #else
  43. let keychainStorageProvider = AuthKeychainStorageReal.shared
  44. #endif // (os(macOS) && !FIREBASE_AUTH_TESTING_USE_MACOS_KEYCHAIN) || SWIFT_PACKAGE
  45. auth = Auth(
  46. app: FirebaseApp.app(name: "test-UserTests")!,
  47. keychainStorageProvider: keychainStorageProvider,
  48. backend: authBackend
  49. )
  50. }
  51. override func tearDown() {
  52. // Verifies that no tasks are left suspended on the AuthSerialTaskQueue.
  53. try? auth?.signOut()
  54. auth = nil
  55. FirebaseApp.resetApps()
  56. super.tearDown()
  57. }
  58. /** @fn testUserPropertiesAndNSSecureCoding
  59. @brief Tests properties of the @c User instance before and after being
  60. serialized/deserialized.
  61. */
  62. func testUserPropertiesAndNSSecureCoding() throws {
  63. let kProviderUserInfoKey = "providerUserInfo"
  64. let kPhotoUrlKey = "photoUrl"
  65. let kProviderIDkey = "providerId"
  66. let kDisplayNameKey = "displayName"
  67. let kFederatedIDKey = "federatedId"
  68. let kEmailKey = "email"
  69. let kPasswordHashKey = "passwordHash"
  70. let kTestPasswordHash = "testPasswordHash"
  71. let kEmailVerifiedKey = "emailVerified"
  72. let kLocalIDKey = "localId"
  73. let kGoogleID = "GOOGLE_ID"
  74. let kGoogleDisplayName = "Google Doe"
  75. let kGoogleEmail = "user@gmail.com"
  76. let kGooglePhotoURL = "https://googleusercontents.com/user/profile"
  77. let kFacebookID = "FACEBOOK_ID"
  78. let kFacebookEmail = "user@facebook.com"
  79. let kEnrollmentID = "fakeEnrollment"
  80. let kPhoneInfo = "+15555555555"
  81. let kEnrolledAt = "2022-08-01T18:31:15.426458Z"
  82. let kEnrolledAtMatch = "2022-08-01 18:31:15 +0000"
  83. let kTwitterID = "TwitterID"
  84. let kGitHubID = "GitHubID"
  85. let kGameCenterID = "GameCenterID"
  86. var providerUserInfos = [[
  87. kProviderIDkey: EmailAuthProvider.id,
  88. kFederatedIDKey: kEmail,
  89. kEmailKey: kEmail,
  90. ],
  91. [
  92. kProviderIDkey: GoogleAuthProvider.id,
  93. kDisplayNameKey: kGoogleDisplayName,
  94. kPhotoUrlKey: kGooglePhotoURL,
  95. kFederatedIDKey: kGoogleID,
  96. kEmailKey: kGoogleEmail,
  97. ],
  98. [
  99. kProviderIDkey: FacebookAuthProvider.id,
  100. kFederatedIDKey: kFacebookID,
  101. kEmailKey: kFacebookEmail,
  102. ],
  103. [
  104. kProviderIDkey: GitHubAuthProvider.id,
  105. kFederatedIDKey: kGitHubID,
  106. kEmailKey: kGoogleEmail,
  107. ],
  108. [
  109. kProviderIDkey: TwitterAuthProvider.id,
  110. kFederatedIDKey: kTwitterID,
  111. kEmailKey: kFacebookEmail,
  112. ]]
  113. #if !os(watchOS)
  114. providerUserInfos.append([
  115. kProviderIDkey: GameCenterAuthProvider.id,
  116. kFederatedIDKey: kGameCenterID,
  117. kEmailKey: kFacebookEmail,
  118. ])
  119. #endif
  120. #if os(iOS)
  121. providerUserInfos.append([
  122. kProviderIDkey: PhoneAuthProvider.id,
  123. kFederatedIDKey: kPhoneNumber,
  124. "phoneNumber": kPhoneNumber,
  125. ])
  126. #endif
  127. var mfaInfo: [[AnyHashable: AnyHashable]] = []
  128. #if os(iOS)
  129. mfaInfo.append([
  130. "phoneInfo": kPhoneInfo,
  131. "mfaEnrollmentId": kEnrollmentID,
  132. "displayName": kDisplayName,
  133. "enrolledAt": kEnrolledAt,
  134. ])
  135. #endif
  136. #if os(iOS) || os(macOS)
  137. mfaInfo.append([
  138. // In practice, this will be an empty dictionary.
  139. "totpInfo": [AnyHashable: AnyHashable](),
  140. "mfaEnrollmentId": kEnrollmentID,
  141. "displayName": kDisplayName,
  142. "enrolledAt": kEnrolledAt,
  143. ])
  144. #endif
  145. rpcIssuer?.fakeGetAccountProviderJSON = [[
  146. kProviderUserInfoKey: providerUserInfos,
  147. kLocalIDKey: kLocalID,
  148. kDisplayNameKey: kDisplayName,
  149. kEmailKey: kEmail,
  150. kPhotoUrlKey: kTestPhotoURL,
  151. kEmailVerifiedKey: true,
  152. kPasswordHashKey: kTestPasswordHash,
  153. "phoneNumber": kPhoneNumber,
  154. "createdAt": String(Int(kCreationDateTimeIntervalInSeconds) * 1000), // to nanoseconds
  155. "lastLoginAt": String(Int(kLastSignInDateTimeIntervalInSeconds) * 1000),
  156. "mfaInfo": mfaInfo,
  157. ]]
  158. let expectation = self.expectation(description: #function)
  159. signInWithEmailPasswordReturnFakeUser { user in
  160. do {
  161. XCTAssertEqual(user.providerID, "Firebase")
  162. XCTAssertEqual(user.uid, self.kLocalID)
  163. XCTAssertEqual(user.displayName, self.kDisplayName)
  164. XCTAssertEqual(user.photoURL, URL(string: self.kTestPhotoURL))
  165. XCTAssertEqual(user.email, self.kEmail)
  166. XCTAssertEqual(user.metadata.creationDate, Date(timeIntervalSince1970:
  167. self.kCreationDateTimeIntervalInSeconds))
  168. XCTAssertEqual(user.metadata.lastSignInDate,
  169. Date(timeIntervalSince1970: self.kLastSignInDateTimeIntervalInSeconds))
  170. // Verify FIRUser properties besides providerData contents.
  171. XCTAssertFalse(user.isAnonymous)
  172. XCTAssertTrue(user.isEmailVerified)
  173. XCTAssertEqual(user.refreshToken, self.kRefreshToken)
  174. XCTAssertEqual(user.providerData.count, providerUserInfos.count)
  175. let providerMap = user.providerData.reduce(into: [String: UserInfo]()) {
  176. $0[$1.providerID] = $1
  177. }
  178. // Verify FIRUserInfo properties from email/password.
  179. let passwordUserInfo = try XCTUnwrap(providerMap[EmailAuthProvider.id])
  180. XCTAssertEqual(passwordUserInfo.uid, self.kEmail)
  181. XCTAssertNil(passwordUserInfo.displayName)
  182. XCTAssertNil(passwordUserInfo.photoURL)
  183. XCTAssertEqual(passwordUserInfo.email, self.kEmail)
  184. // Verify FIRUserInfo properties from the Google auth provider.
  185. let googleUserInfo = try XCTUnwrap(providerMap[GoogleAuthProvider.id])
  186. XCTAssertEqual(googleUserInfo.uid, kGoogleID)
  187. XCTAssertEqual(googleUserInfo.displayName, kGoogleDisplayName)
  188. XCTAssertEqual(googleUserInfo.photoURL, URL(string: kGooglePhotoURL))
  189. XCTAssertEqual(googleUserInfo.email, kGoogleEmail)
  190. // Verify FIRUserInfo properties from the Facebook auth provider.
  191. let facebookUserInfo = try XCTUnwrap(providerMap[FacebookAuthProvider.id])
  192. XCTAssertEqual(facebookUserInfo.uid, kFacebookID)
  193. XCTAssertNil(facebookUserInfo.displayName)
  194. XCTAssertNil(facebookUserInfo.photoURL)
  195. XCTAssertEqual(facebookUserInfo.email, kFacebookEmail)
  196. // Verify FIRUserInfo properties from the GitHub auth provider.
  197. let gitHubUserInfo = try XCTUnwrap(providerMap[GitHubAuthProvider.id])
  198. XCTAssertEqual(gitHubUserInfo.uid, kGitHubID)
  199. XCTAssertNil(gitHubUserInfo.displayName)
  200. XCTAssertNil(gitHubUserInfo.photoURL)
  201. XCTAssertEqual(gitHubUserInfo.email, kGoogleEmail)
  202. // Verify FIRUserInfo properties from the Twitter auth provider.
  203. let twitterUserInfo = try XCTUnwrap(providerMap[TwitterAuthProvider.id])
  204. XCTAssertEqual(twitterUserInfo.uid, kTwitterID)
  205. XCTAssertNil(twitterUserInfo.displayName)
  206. XCTAssertNil(twitterUserInfo.photoURL)
  207. XCTAssertEqual(twitterUserInfo.email, kFacebookEmail)
  208. #if os(iOS)
  209. // Verify UserInfo properties from the phone auth provider.
  210. let phoneUserInfo = try XCTUnwrap(providerMap[PhoneAuthProvider.id])
  211. XCTAssertEqual(phoneUserInfo.phoneNumber, self.kPhoneNumber)
  212. #endif
  213. #if !os(watchOS)
  214. // Verify FIRUserInfo properties from the Game Center auth provider.
  215. let gameCenterUserInfo = try XCTUnwrap(providerMap[GameCenterAuthProvider.id])
  216. XCTAssertEqual(gameCenterUserInfo.uid, kGameCenterID)
  217. XCTAssertNil(gameCenterUserInfo.displayName)
  218. XCTAssertNil(gameCenterUserInfo.photoURL)
  219. XCTAssertEqual(gameCenterUserInfo.email, kFacebookEmail)
  220. #endif
  221. // Test NSSecureCoding
  222. XCTAssertTrue(User.supportsSecureCoding)
  223. let data = try NSKeyedArchiver.archivedData(
  224. withRootObject: user,
  225. requiringSecureCoding: true
  226. )
  227. var encodedClasses = [User.self, NSDictionary.self, NSURL.self, SecureTokenService.self,
  228. UserInfoImpl.self, NSDate.self, UserMetadata.self, NSString.self,
  229. NSArray.self]
  230. #if os(iOS) || os(macOS)
  231. encodedClasses.append(MultiFactor.self)
  232. encodedClasses.append(TOTPMultiFactorInfo.self)
  233. #if os(iOS)
  234. encodedClasses.append(PhoneMultiFactorInfo.self)
  235. #endif
  236. #endif
  237. let unarchivedUser = try XCTUnwrap(NSKeyedUnarchiver.unarchivedObject(
  238. ofClasses: encodedClasses, from: data
  239. )
  240. as? User)
  241. // Verify NSSecureCoding for FIRUser
  242. XCTAssertEqual(unarchivedUser.providerID, user.providerID)
  243. XCTAssertEqual(unarchivedUser.uid, user.uid)
  244. XCTAssertEqual(unarchivedUser.email, user.email)
  245. XCTAssertEqual(unarchivedUser.photoURL, user.photoURL)
  246. XCTAssertEqual(unarchivedUser.displayName, user.displayName)
  247. // Verify NSSecureCoding properties besides providerData contents.
  248. XCTAssertEqual(unarchivedUser.isAnonymous, user.isAnonymous)
  249. XCTAssertEqual(unarchivedUser.isEmailVerified, user.isEmailVerified)
  250. XCTAssertEqual(unarchivedUser.refreshToken, user.refreshToken)
  251. XCTAssertEqual(unarchivedUser.metadata.creationDate, user.metadata.creationDate)
  252. XCTAssertEqual(unarchivedUser.metadata.lastSignInDate, user.metadata.lastSignInDate)
  253. XCTAssertEqual(unarchivedUser.providerData.count, user.providerData.count)
  254. let unarchivedProviderMap = unarchivedUser.providerData.reduce(into: [String: UserInfo]()) {
  255. $0[$1.providerID] = $1
  256. }
  257. // Verify NSSecureCoding properties for AuthDataResult
  258. let kFakeProfile = ["email": "user@mail.com", "given_name": "User", "family_name": "Doe"]
  259. let kUserName = "User Doe"
  260. let kProviderID = "PROVIDER_ID"
  261. let userInfo = AdditionalUserInfo(providerID: kProviderID,
  262. profile: kFakeProfile,
  263. username: kUserName,
  264. isNewUser: true)
  265. let authDataResult = AuthDataResult(withUser: user, additionalUserInfo: userInfo)
  266. XCTAssertTrue(AuthDataResult.supportsSecureCoding)
  267. let authDataResultData = try NSKeyedArchiver.archivedData(
  268. withRootObject: authDataResult,
  269. requiringSecureCoding: true
  270. )
  271. encodedClasses.append(AuthDataResult.self)
  272. encodedClasses.append(AdditionalUserInfo.self)
  273. let unarchivedDataResult = try XCTUnwrap(NSKeyedUnarchiver.unarchivedObject(
  274. ofClasses: encodedClasses, from: authDataResultData
  275. ) as? AuthDataResult)
  276. XCTAssertEqual(unarchivedDataResult.user.providerID, user.providerID)
  277. XCTAssertEqual(unarchivedDataResult.user.uid, user.uid)
  278. XCTAssertEqual(unarchivedDataResult.user.email, user.email)
  279. XCTAssertEqual(unarchivedDataResult.user.photoURL, user.photoURL)
  280. XCTAssertEqual(unarchivedDataResult.user.displayName, user.displayName)
  281. XCTAssertEqual(unarchivedDataResult.additionalUserInfo?.providerID, kProviderID)
  282. XCTAssertEqual(unarchivedDataResult.additionalUserInfo?.profile as? [String: String],
  283. kFakeProfile)
  284. XCTAssertEqual(unarchivedDataResult.additionalUserInfo?.username, kUserName)
  285. // Verify NSSecureCoding properties from email/password.
  286. let unarchivedPasswordUserInfo = try XCTUnwrap(unarchivedProviderMap[EmailAuthProvider.id])
  287. XCTAssertEqual(unarchivedPasswordUserInfo.uid, passwordUserInfo.uid)
  288. XCTAssertEqual(unarchivedPasswordUserInfo.displayName, passwordUserInfo.displayName)
  289. XCTAssertEqual(unarchivedPasswordUserInfo.photoURL, passwordUserInfo.photoURL)
  290. XCTAssertEqual(unarchivedPasswordUserInfo.email, passwordUserInfo.email)
  291. // Verify NSSecureCoding properties from the Google auth provider.
  292. let unarchivedGoogleUserInfo = try XCTUnwrap(unarchivedProviderMap[GoogleAuthProvider.id])
  293. XCTAssertEqual(unarchivedGoogleUserInfo.uid, googleUserInfo.uid)
  294. XCTAssertEqual(unarchivedGoogleUserInfo.displayName, googleUserInfo.displayName)
  295. XCTAssertEqual(unarchivedGoogleUserInfo.photoURL, googleUserInfo.photoURL)
  296. XCTAssertEqual(unarchivedGoogleUserInfo.email, googleUserInfo.email)
  297. // Verify NSSecureCoding properties from the Facebook auth provider.
  298. let unarchivedFacebookUserInfo =
  299. try XCTUnwrap(unarchivedProviderMap[FacebookAuthProvider.id])
  300. XCTAssertEqual(unarchivedFacebookUserInfo.uid, facebookUserInfo.uid)
  301. XCTAssertEqual(unarchivedFacebookUserInfo.displayName, facebookUserInfo.displayName)
  302. XCTAssertEqual(unarchivedFacebookUserInfo.photoURL, facebookUserInfo.photoURL)
  303. XCTAssertEqual(unarchivedFacebookUserInfo.email, facebookUserInfo.email)
  304. #if !os(watchOS)
  305. // Verify NSSecureCoding properties from the GameCenter auth provider.
  306. let unarchivedGameCenterUserInfo =
  307. try XCTUnwrap(unarchivedProviderMap[GameCenterAuthProvider.id])
  308. XCTAssertEqual(unarchivedGameCenterUserInfo.uid, gameCenterUserInfo.uid)
  309. XCTAssertEqual(unarchivedGameCenterUserInfo.displayName, gameCenterUserInfo.displayName)
  310. XCTAssertEqual(unarchivedGameCenterUserInfo.photoURL, gameCenterUserInfo.photoURL)
  311. XCTAssertEqual(unarchivedGameCenterUserInfo.email, gameCenterUserInfo.email)
  312. #endif
  313. // Verify NSSecureCoding properties from the GitHub auth provider.
  314. let unarchivedGitHubUserInfo =
  315. try XCTUnwrap(unarchivedProviderMap[GitHubAuthProvider.id])
  316. XCTAssertEqual(unarchivedGitHubUserInfo.uid, gitHubUserInfo.uid)
  317. XCTAssertEqual(unarchivedGitHubUserInfo.displayName, gitHubUserInfo.displayName)
  318. XCTAssertEqual(unarchivedGitHubUserInfo.photoURL, gitHubUserInfo.photoURL)
  319. XCTAssertEqual(unarchivedGitHubUserInfo.email, gitHubUserInfo.email)
  320. // Verify NSSecureCoding properties from the Twitter auth provider.
  321. let unarchivedTwitterUserInfo =
  322. try XCTUnwrap(unarchivedProviderMap[TwitterAuthProvider.id])
  323. XCTAssertEqual(unarchivedTwitterUserInfo.uid, twitterUserInfo.uid)
  324. XCTAssertEqual(unarchivedTwitterUserInfo.displayName, twitterUserInfo.displayName)
  325. XCTAssertEqual(unarchivedTwitterUserInfo.photoURL, twitterUserInfo.photoURL)
  326. XCTAssertEqual(unarchivedTwitterUserInfo.email, twitterUserInfo.email)
  327. #if os(iOS)
  328. // Verify NSSecureCoding properties from the phone auth provider.
  329. let unarchivedPhoneUserInfo = try XCTUnwrap(unarchivedProviderMap[PhoneAuthProvider.id])
  330. XCTAssertEqual(unarchivedPhoneUserInfo.phoneNumber, phoneUserInfo.phoneNumber)
  331. // Verify MultiFactorInfo properties.
  332. let enrolledFactors = try XCTUnwrap(user.multiFactor.enrolledFactors)
  333. XCTAssertEqual(enrolledFactors.count, 2)
  334. XCTAssertEqual(enrolledFactors[0].factorID, PhoneMultiFactorInfo.PhoneMultiFactorID)
  335. XCTAssertEqual(enrolledFactors[1].factorID, PhoneMultiFactorInfo.TOTPMultiFactorID)
  336. for enrolledFactor in enrolledFactors {
  337. XCTAssertEqual(enrolledFactor.uid, kEnrollmentID)
  338. XCTAssertEqual(enrolledFactor.displayName, self.kDisplayName)
  339. let date = try XCTUnwrap(enrolledFactor.enrollmentDate)
  340. XCTAssertEqual("\(date)", kEnrolledAtMatch)
  341. }
  342. #endif
  343. #if os(macOS)
  344. // Verify TOTP MultiFactorInfo properties.
  345. let enrolledFactors = try XCTUnwrap(user.multiFactor.enrolledFactors)
  346. XCTAssertEqual(enrolledFactors.count, 1)
  347. XCTAssertEqual(enrolledFactors[0].factorID, PhoneMultiFactorInfo.TOTPMultiFactorID)
  348. XCTAssertEqual(enrolledFactors[0].uid, kEnrollmentID)
  349. XCTAssertEqual(enrolledFactors[0].displayName, self.kDisplayName)
  350. let date = try XCTUnwrap(enrolledFactors[0].enrollmentDate)
  351. XCTAssertEqual("\(date)", kEnrolledAtMatch)
  352. #endif
  353. } catch {
  354. XCTFail("Caught an error in \(#function): \(error)")
  355. }
  356. expectation.fulfill()
  357. }
  358. waitForExpectations(timeout: 5)
  359. }
  360. /** @fn testUpdateEmailSuccess
  361. @brief Tests the flow of a successful @c updateEmail:completion: call.
  362. */
  363. func testUpdateEmailSuccess() {
  364. setFakeGetAccountProvider(withPasswordHash: kFakePassword)
  365. let expectation = self.expectation(description: #function)
  366. signInWithEmailPasswordReturnFakeUser { user in
  367. self.changeUserEmail(user: user, changeEmail: true, expectation: expectation)
  368. }
  369. waitForExpectations(timeout: 5)
  370. }
  371. /** @fn testUpdateEmailWithAuthLinkAccountSuccess
  372. @brief Tests a successful @c updateEmail:completion: call updates provider info.
  373. */
  374. func testUpdateEmailWithAuthLinkAccountSuccess() {
  375. setFakeGetAccountProvider()
  376. let expectation = self.expectation(description: #function)
  377. signInWithEmailPasswordReturnFakeUserLink { user in
  378. self.changeUserEmail(user: user, expectation: expectation)
  379. }
  380. waitForExpectations(timeout: 5)
  381. }
  382. /** @fn testUpdateEmailFailure
  383. @brief Tests the flow of a failed @c updateEmail:completion: call.
  384. */
  385. func testUpdateEmailFailure() {
  386. setFakeGetAccountProvider()
  387. let expectation = self.expectation(description: #function)
  388. signInWithEmailPasswordReturnFakeUser { user in
  389. do {
  390. self.rpcIssuer.respondBlock = {
  391. try self.rpcIssuer.respond(serverErrorMessage: "INVALID_EMAIL")
  392. }
  393. user.updateEmail(to: self.kNewEmail) { rawError in
  394. XCTAssertTrue(Thread.isMainThread)
  395. let error = try! XCTUnwrap(rawError)
  396. XCTAssertEqual((error as NSError).code, AuthErrorCode.invalidEmail.rawValue)
  397. // Email should not have changed on the client side.
  398. XCTAssertEqual(user.email, self.kEmail)
  399. // User is still signed in.
  400. XCTAssertEqual(self.auth?.currentUser, user)
  401. expectation.fulfill()
  402. }
  403. }
  404. }
  405. waitForExpectations(timeout: 5)
  406. }
  407. /** @fn testUpdateEmailAutoSignOut
  408. @brief Tests the flow of a failed @c updateEmail:completion: call that automatically signs out.
  409. */
  410. func testUpdateEmailAutoSignOut() {
  411. setFakeGetAccountProvider()
  412. let expectation = self.expectation(description: #function)
  413. signInWithEmailPasswordReturnFakeUser { user in
  414. do {
  415. self.rpcIssuer.respondBlock = {
  416. try self.rpcIssuer.respond(serverErrorMessage: "INVALID_ID_TOKEN")
  417. }
  418. user.updateEmail(to: self.kNewEmail) { rawError in
  419. XCTAssertTrue(Thread.isMainThread)
  420. let error = try! XCTUnwrap(rawError)
  421. XCTAssertEqual((error as NSError).code, AuthErrorCode.invalidUserToken.rawValue)
  422. // Email should not have changed on the client side.
  423. XCTAssertEqual(user.email, self.kEmail)
  424. // User is no longer signed in..
  425. XCTAssertNil(self.auth?.currentUser)
  426. expectation.fulfill()
  427. }
  428. }
  429. }
  430. waitForExpectations(timeout: 5)
  431. }
  432. #if os(iOS)
  433. /** @fn testUpdatePhoneSuccess
  434. @brief Tests the flow of a successful @c updatePhoneNumberCredential:completion: call.
  435. */
  436. func testUpdatePhoneSuccess() throws {
  437. setFakeGetAccountProvider()
  438. let expectation = self.expectation(description: #function)
  439. let auth = try XCTUnwrap(self.auth)
  440. signInWithEmailPasswordReturnFakeUser { user in
  441. do {
  442. self.rpcIssuer.respondBlock = {
  443. try self.rpcIssuer.respond(withJSON: ["idToken": RPCBaseTests.kFakeAccessToken,
  444. "refreshToken": self.kRefreshToken])
  445. }
  446. self.expectVerifyPhoneNumberRequest()
  447. self.rpcIssuer?.fakeGetAccountProviderJSON = [[
  448. "phoneNumber": self.kPhoneNumber,
  449. ]]
  450. let credential = PhoneAuthProvider.provider(auth: auth).credential(
  451. withVerificationID: self.kVerificationID,
  452. verificationCode: self.kVerificationCode
  453. )
  454. user.updatePhoneNumber(credential) { error in
  455. XCTAssertTrue(Thread.isMainThread)
  456. XCTAssertNil(error)
  457. XCTAssertEqual(auth.currentUser?.phoneNumber, self.kPhoneNumber)
  458. expectation.fulfill()
  459. }
  460. }
  461. }
  462. waitForExpectations(timeout: 5)
  463. }
  464. /** @fn testUpdatePhoneNumberFailure
  465. @brief Tests the flow of a failed @c updatePhoneNumberCredential:completion: call.
  466. */
  467. func testUpdatePhoneNumberFailure() throws {
  468. setFakeGetAccountProvider()
  469. let expectation = self.expectation(description: #function)
  470. let auth = try XCTUnwrap(self.auth)
  471. signInWithEmailPasswordReturnFakeUser { user in
  472. do {
  473. self.rpcIssuer.respondBlock = {
  474. try self.rpcIssuer.respond(serverErrorMessage: "INVALID_PHONE_NUMBER")
  475. }
  476. self.expectVerifyPhoneNumberRequest()
  477. let credential = PhoneAuthProvider.provider(auth: auth).credential(
  478. withVerificationID: self.kVerificationID,
  479. verificationCode: self.kVerificationCode
  480. )
  481. user.updatePhoneNumber(credential) { rawError in
  482. XCTAssertTrue(Thread.isMainThread)
  483. let error = try! XCTUnwrap(rawError)
  484. XCTAssertEqual((error as NSError).code, AuthErrorCode.invalidPhoneNumber.rawValue)
  485. XCTAssertEqual(auth.currentUser, user)
  486. expectation.fulfill()
  487. }
  488. }
  489. }
  490. waitForExpectations(timeout: 5)
  491. }
  492. /** @fn testUpdatePhoneNumberFailureAutoSignOut
  493. @brief Tests the flow of a failed @c updatePhoneNumberCredential:completion: call that
  494. automatically signs out.
  495. */
  496. func testUpdatePhoneNumberFailureAutoSignOut() throws {
  497. setFakeGetAccountProvider()
  498. let expectation = self.expectation(description: #function)
  499. let auth = try XCTUnwrap(self.auth)
  500. signInWithEmailPasswordReturnFakeUser { user in
  501. do {
  502. self.rpcIssuer.respondBlock = {
  503. try self.rpcIssuer.respond(serverErrorMessage: "TOKEN_EXPIRED")
  504. }
  505. self.expectVerifyPhoneNumberRequest()
  506. let credential = PhoneAuthProvider.provider(auth: auth).credential(
  507. withVerificationID: self.kVerificationID,
  508. verificationCode: self.kVerificationCode
  509. )
  510. user.updatePhoneNumber(credential) { rawError in
  511. XCTAssertTrue(Thread.isMainThread)
  512. let error = try! XCTUnwrap(rawError)
  513. XCTAssertEqual((error as NSError).code, AuthErrorCode.userTokenExpired.rawValue)
  514. // User is no longer signed in.
  515. XCTAssertNil(self.auth?.currentUser)
  516. expectation.fulfill()
  517. }
  518. }
  519. }
  520. waitForExpectations(timeout: 5)
  521. }
  522. #endif
  523. /** @fn testUpdatePasswordSuccess
  524. @brief Tests the flow of a successful @c updatePassword:completion: call.
  525. */
  526. func testUpdatePasswordSuccess() {
  527. setFakeGetAccountProvider()
  528. let expectation = self.expectation(description: #function)
  529. signInWithEmailPasswordReturnFakeUser { user in
  530. self.changeUserEmail(user: user, expectation: expectation)
  531. }
  532. waitForExpectations(timeout: 5)
  533. }
  534. /** @fn testUpdatePasswordFailure
  535. @brief Tests the flow of a failed @c updatePassword:completion: call.
  536. */
  537. func testUpdatePasswordFailure() {
  538. setFakeGetAccountProvider()
  539. let expectation = self.expectation(description: #function)
  540. signInWithEmailPasswordReturnFakeUser { user in
  541. do {
  542. self.rpcIssuer.respondBlock = {
  543. try self.rpcIssuer.respond(serverErrorMessage: "CREDENTIAL_TOO_OLD_LOGIN_AGAIN")
  544. }
  545. user.updatePassword(to: self.kNewPassword) { rawError in
  546. XCTAssertTrue(Thread.isMainThread)
  547. let error = try! XCTUnwrap(rawError)
  548. XCTAssertEqual((error as NSError).code, AuthErrorCode.requiresRecentLogin.rawValue)
  549. // Email should not have changed on the client side.
  550. XCTAssertEqual(user.email, self.kEmail)
  551. // User is still signed in.
  552. XCTAssertEqual(self.auth?.currentUser, user)
  553. expectation.fulfill()
  554. }
  555. }
  556. }
  557. waitForExpectations(timeout: 5)
  558. }
  559. /** @fn testUpdateEmptyPasswordFailure
  560. @brief Tests the flow of a failed @c updatePassword:completion: call due to an empty password.
  561. */
  562. func testUpdateEmptyPasswordFailure() {
  563. setFakeGetAccountProvider()
  564. let expectation = self.expectation(description: #function)
  565. signInWithEmailPasswordReturnFakeUser { user in
  566. do {
  567. self.rpcIssuer.respondBlock = {
  568. try self.rpcIssuer.respond(serverErrorMessage: "WEAK_PASSWORD")
  569. }
  570. user.updatePassword(to: self.kNewPassword) { rawError in
  571. XCTAssertTrue(Thread.isMainThread)
  572. let error = try! XCTUnwrap(rawError)
  573. XCTAssertEqual((error as NSError).code, AuthErrorCode.weakPassword.rawValue)
  574. // Email should not have changed on the client side.
  575. XCTAssertEqual(user.email, self.kEmail)
  576. // User is still signed in.
  577. XCTAssertEqual(self.auth?.currentUser, user)
  578. expectation.fulfill()
  579. }
  580. }
  581. }
  582. waitForExpectations(timeout: 5)
  583. }
  584. /** @fn testUpdatePasswordFailureAutoSignOut
  585. @brief Tests the flow of a failed @c updatePassword:completion: call that automatically signs
  586. out.
  587. */
  588. func testUpdatePasswordFailureAutoSignOut() {
  589. setFakeGetAccountProvider()
  590. let expectation = self.expectation(description: #function)
  591. signInWithEmailPasswordReturnFakeUser { user in
  592. do {
  593. self.rpcIssuer.respondBlock = {
  594. try self.rpcIssuer.respond(serverErrorMessage: "USER_DISABLED")
  595. }
  596. user.updatePassword(to: self.kNewPassword) { rawError in
  597. XCTAssertTrue(Thread.isMainThread)
  598. let error = try! XCTUnwrap(rawError)
  599. XCTAssertEqual((error as NSError).code, AuthErrorCode.userDisabled.rawValue)
  600. // Email should not have changed on the client side.
  601. XCTAssertEqual(user.email, self.kEmail)
  602. // User is signed out.
  603. XCTAssertNil(self.auth?.currentUser)
  604. expectation.fulfill()
  605. }
  606. }
  607. }
  608. waitForExpectations(timeout: 5)
  609. }
  610. /** @fn testChangeProfileSuccess
  611. @brief Tests a successful user profile change flow.
  612. */
  613. func testChangeProfileSuccess() {
  614. setFakeGetAccountProvider()
  615. let expectation = self.expectation(description: #function)
  616. signInWithEmailPasswordReturnFakeUser { user in
  617. do {
  618. self.rpcIssuer.respondBlock = {
  619. try self.rpcIssuer.respond(withJSON: ["idToken": RPCBaseTests.kFakeAccessToken,
  620. "refreshToken": self.kRefreshToken])
  621. }
  622. let profileChange = user.createProfileChangeRequest()
  623. profileChange.photoURL = URL(string: self.kTestPhotoURL)
  624. profileChange.displayName = self.kNewDisplayName
  625. profileChange.commitChanges { error in
  626. XCTAssertTrue(Thread.isMainThread)
  627. XCTAssertNil(error)
  628. XCTAssertEqual(user.displayName, self.kNewDisplayName)
  629. XCTAssertEqual(user.photoURL, URL(string: self.kTestPhotoURL))
  630. expectation.fulfill()
  631. }
  632. }
  633. }
  634. waitForExpectations(timeout: 5)
  635. }
  636. /** @fn testChangeProfileFailure
  637. @brief Tests a failed user profile change flow.
  638. */
  639. func testChangeProfileFailure() {
  640. setFakeGetAccountProvider()
  641. let expectation = self.expectation(description: #function)
  642. signInWithEmailPasswordReturnFakeUser { user in
  643. do {
  644. self.rpcIssuer.respondBlock = {
  645. try self.rpcIssuer.respond(serverErrorMessage: "TOO_MANY_ATTEMPTS_TRY_LATER")
  646. }
  647. let profileChange = user.createProfileChangeRequest()
  648. profileChange.displayName = self.kNewDisplayName
  649. profileChange.commitChanges { rawError in
  650. XCTAssertTrue(Thread.isMainThread)
  651. let error = try! XCTUnwrap(rawError)
  652. XCTAssertEqual((error as NSError).code, AuthErrorCode.tooManyRequests.rawValue)
  653. // Email should not have changed on the client side.
  654. XCTAssertEqual(user.email, self.kEmail)
  655. XCTAssertEqual(user.displayName, self.kDisplayName)
  656. // User is still signed in.
  657. XCTAssertEqual(self.auth?.currentUser, user)
  658. expectation.fulfill()
  659. }
  660. }
  661. }
  662. waitForExpectations(timeout: 5)
  663. }
  664. /** @fn testChangeProfileFailureAutoSignOut
  665. @brief Tests a failed user profile change flow that automatically signs out.
  666. */
  667. func testChangeProfileFailureAutoSignOut() {
  668. setFakeGetAccountProvider()
  669. let expectation = self.expectation(description: #function)
  670. signInWithEmailPasswordReturnFakeUser { user in
  671. do {
  672. self.rpcIssuer.respondBlock = {
  673. try self.rpcIssuer.respond(serverErrorMessage: "USER_NOT_FOUND")
  674. }
  675. let profileChange = user.createProfileChangeRequest()
  676. profileChange.displayName = self.kNewDisplayName
  677. profileChange.commitChanges { rawError in
  678. XCTAssertTrue(Thread.isMainThread)
  679. let error = try! XCTUnwrap(rawError)
  680. XCTAssertEqual((error as NSError).code, AuthErrorCode.userNotFound.rawValue)
  681. // Email should not have changed on the client side.
  682. XCTAssertEqual(user.email, self.kEmail)
  683. // User is signed out.
  684. XCTAssertNil(self.auth?.currentUser)
  685. expectation.fulfill()
  686. }
  687. }
  688. }
  689. waitForExpectations(timeout: 5)
  690. }
  691. /** @fn testGetIDTokenResultSuccess
  692. @brief Tests the flow of a successful @c getIDTokenResultWithCompletion: call.
  693. */
  694. func testGetIDTokenResultSuccess() {
  695. internalGetIDTokenResult(token: RPCBaseTests.kFakeAccessToken, forceRefresh: false)
  696. }
  697. /** @fn testGetIDTokenResultForcingRefreshSameAccessTokenSuccess
  698. @brief Tests the flow of a successful @c getIDTokenResultForcingRefresh:completion: call when
  699. the returned access token is the same as the stored access token.
  700. */
  701. func testGetIDTokenResultForcingRefreshSameAccessTokenSuccess() {
  702. internalGetIDTokenResult(token: RPCBaseTests.kFakeAccessToken)
  703. }
  704. /** @fn testGetIDTokenResultForcingRefreshSuccess
  705. @brief Tests the flow successful @c getIDTokenResultForcingRefresh:completion: calls.
  706. */
  707. func testGetIDTokenResultForcingRefreshSuccess() {
  708. internalGetIDTokenResult(token: RPCBaseTests.kFakeAccessTokenLength415)
  709. internalGetIDTokenResult(token: RPCBaseTests.kFakeAccessTokenLength416)
  710. internalGetIDTokenResult(token: RPCBaseTests.kFakeAccessTokenLength523,
  711. emailMatch: "aunitestuser4@gmail.com")
  712. }
  713. /** @fn testGetIDTokenResultSuccessWithBase64EncodedURL
  714. @brief Tests the flow of a successful @c getIDTokenResultWithCompletion: call using a base64 url
  715. encoded string.
  716. */
  717. func testGetIDTokenResultSuccessWithBase64EncodedURL() {
  718. internalGetIDTokenResult(token: RPCBaseTests.kFakeAccessTokenWithBase64,
  719. emailMatch: ">>>>>>>>????????@gmail.com",
  720. audMatch: "??????????>>>>>>>>>>")
  721. }
  722. /** @fn testGetIDTokenResultForcingRefreshFailure
  723. @brief Tests the flow of a failed @c getIDTokenResultForcingRefresh:completion: call.
  724. */
  725. func testGetIDTokenResultForcingRefreshFailure() {
  726. setFakeGetAccountProvider()
  727. let expectation = self.expectation(description: #function)
  728. signInWithEmailPasswordReturnFakeUser(fakeAccessToken: RPCBaseTests.kFakeAccessToken) { user in
  729. let underlying = NSError(domain: "Test Error", code: 1)
  730. self.rpcIssuer?.secureTokenNetworkError =
  731. AuthErrorUtils.networkError(underlyingError: underlying) as NSError
  732. user.getIDTokenResult(forcingRefresh: true) { tokenResult, rawError in
  733. do {
  734. XCTAssertTrue(Thread.isMainThread)
  735. XCTAssertNil(tokenResult)
  736. let error = try XCTUnwrap(rawError)
  737. XCTAssertEqual((error as NSError).code, AuthErrorCode.networkError.rawValue)
  738. } catch {
  739. XCTFail("Caught an error in \(#function): \(error)")
  740. }
  741. expectation.fulfill()
  742. }
  743. }
  744. waitForExpectations(timeout: 5)
  745. }
  746. /** @fn testReloadSuccess
  747. @brief Tests the flow of a successful @c reloadWithCompletion: call.
  748. */
  749. func testReloadSuccess() {
  750. setFakeGetAccountProvider()
  751. let expectation = self.expectation(description: #function)
  752. signInWithEmailPasswordReturnFakeUser { user in
  753. user.reload { error in
  754. XCTAssertTrue(Thread.isMainThread)
  755. XCTAssertNil(error)
  756. XCTAssertEqual(user.displayName, self.kDisplayName)
  757. XCTAssertEqual(user.email, self.kEmail)
  758. expectation.fulfill()
  759. }
  760. }
  761. waitForExpectations(timeout: 5)
  762. }
  763. /** @fn testReloadFailure
  764. @brief Tests the flow of a failed @c reloadWithCompletion: call.
  765. */
  766. func testReloadFailure() {
  767. setFakeGetAccountProvider()
  768. let expectation = self.expectation(description: #function)
  769. signInWithEmailPasswordReturnFakeUser { user in
  770. do {
  771. self.rpcIssuer.respondBlock = {
  772. try self.rpcIssuer.respond(serverErrorMessage: "QUOTA_EXCEEDED")
  773. }
  774. // Clear fake so we can inject error
  775. self.rpcIssuer?.fakeGetAccountProviderJSON = nil
  776. user.reload { rawError in
  777. XCTAssertTrue(Thread.isMainThread)
  778. let error = try! XCTUnwrap(rawError)
  779. XCTAssertEqual((error as NSError).code, AuthErrorCode.quotaExceeded.rawValue)
  780. // User is still signed in.
  781. XCTAssertEqual(self.auth?.currentUser, user)
  782. expectation.fulfill()
  783. }
  784. }
  785. }
  786. waitForExpectations(timeout: 5)
  787. }
  788. /** @fn testReloadFailureAutoSignOut
  789. @brief Tests the flow of a failed @c reloadWithCompletion: call that automtatically signs out.
  790. */
  791. func testReloadFailureAutoSignOut() {
  792. setFakeGetAccountProvider()
  793. let expectation = self.expectation(description: #function)
  794. signInWithEmailPasswordReturnFakeUser { user in
  795. do {
  796. self.rpcIssuer.respondBlock = {
  797. try self.rpcIssuer.respond(serverErrorMessage: "TOKEN_EXPIRED")
  798. }
  799. // Clear fake so we can inject error
  800. self.rpcIssuer?.fakeGetAccountProviderJSON = nil
  801. user.reload { rawError in
  802. XCTAssertTrue(Thread.isMainThread)
  803. let error = try! XCTUnwrap(rawError)
  804. XCTAssertEqual((error as NSError).code, AuthErrorCode.userTokenExpired.rawValue)
  805. // User is no longer signed in.
  806. XCTAssertNil(self.auth?.currentUser)
  807. expectation.fulfill()
  808. }
  809. }
  810. }
  811. waitForExpectations(timeout: 5)
  812. }
  813. /** @fn testReauthenticateSuccess
  814. @brief Tests the flow of a successful @c reauthenticateWithCredential:completion: call.
  815. */
  816. func testReauthenticateSuccess() {
  817. setFakeGetAccountProvider()
  818. let expectation = self.expectation(description: #function)
  819. signInWithEmailPasswordReturnFakeUser { user in
  820. do {
  821. self.rpcIssuer.respondBlock = {
  822. try self.rpcIssuer.respond(withJSON: ["idToken": RPCBaseTests.kFakeAccessToken,
  823. "refreshToken": self.kRefreshToken])
  824. }
  825. let emailCredential = EmailAuthProvider.credential(withEmail: self.kEmail,
  826. password: self.kFakePassword)
  827. user.reauthenticate(with: emailCredential) { rawResult, error in
  828. XCTAssertTrue(Thread.isMainThread)
  829. XCTAssertNil(error)
  830. let result = try! XCTUnwrap(rawResult)
  831. XCTAssertEqual(result.user.uid, user.uid)
  832. XCTAssertEqual(result.user.email, user.email)
  833. XCTAssertEqual(result.additionalUserInfo?.isNewUser, false)
  834. // User is still signed in.
  835. XCTAssertEqual(self.auth?.currentUser, user)
  836. expectation.fulfill()
  837. }
  838. }
  839. }
  840. waitForExpectations(timeout: 5)
  841. }
  842. /** @fn testReauthenticateWithCredentialSuccess
  843. @brief Tests the flow of a successful @c reauthenticateWithCredential call.
  844. */
  845. func testReauthenticateWithCredentialSuccess() throws {
  846. let expectation = self.expectation(description: #function)
  847. signInWithGoogleCredential { user in
  848. do {
  849. self.rpcIssuer.respondBlock = {
  850. try self.rpcIssuer.respond(withJSON: ["idToken": RPCBaseTests.kFakeAccessToken,
  851. "refreshToken": self.kRefreshToken,
  852. "federatedId": self.kGoogleID,
  853. "providerId": GoogleAuthProvider.id,
  854. "localId": self.kLocalID,
  855. "displayName": self.kGoogleDisplayName,
  856. "rawUserInfo": self.kGoogleProfile,
  857. "username": self.kUserName])
  858. }
  859. let googleCredential = GoogleAuthProvider.credential(withIDToken: self.kGoogleIDToken,
  860. accessToken: self.kGoogleAccessToken)
  861. user.reauthenticate(with: googleCredential) { reauthenticatedAuthResult, error in
  862. XCTAssertTrue(Thread.isMainThread)
  863. do {
  864. try self.assertUserGoogle(reauthenticatedAuthResult?.user)
  865. } catch {
  866. XCTFail("\(error)")
  867. }
  868. XCTAssertNil(error)
  869. // Verify that the current user is unchanged.
  870. XCTAssertEqual(self.auth?.currentUser, user)
  871. // Verify that the current user and reauthenticated user are not same pointers.
  872. XCTAssertNotEqual(user, reauthenticatedAuthResult?.user)
  873. // Verify that anyway the current user and reauthenticated user have same IDs.
  874. XCTAssertEqual(reauthenticatedAuthResult?.user.uid, user.uid)
  875. XCTAssertEqual(reauthenticatedAuthResult?.user.email, user.email)
  876. XCTAssertEqual(reauthenticatedAuthResult?.user.displayName, user.displayName)
  877. XCTAssertEqual(reauthenticatedAuthResult?.additionalUserInfo?.username, self.kUserName)
  878. XCTAssertEqual(reauthenticatedAuthResult?.additionalUserInfo?.providerID,
  879. GoogleAuthProvider.id)
  880. XCTAssertEqual(
  881. reauthenticatedAuthResult?.additionalUserInfo?.profile as? [String: String],
  882. self.kGoogleProfile
  883. )
  884. expectation.fulfill()
  885. }
  886. }
  887. }
  888. waitForExpectations(timeout: 5)
  889. try assertUserGoogle(auth?.currentUser)
  890. }
  891. /** @fn testReauthenticateFailure
  892. @brief Tests the flow of a failed @c reauthenticateWithCredential:completion: call.
  893. */
  894. func testReauthenticateFailure() {
  895. setFakeGetAccountProvider()
  896. let expectation = self.expectation(description: #function)
  897. signInWithEmailPasswordReturnFakeUser { user in
  898. do {
  899. self.rpcIssuer.respondBlock = {
  900. try self.rpcIssuer.respond(withJSON: ["idToken": RPCBaseTests.kFakeAccessToken,
  901. "refreshToken": self.kRefreshToken])
  902. }
  903. self.setFakeGetAccountProvider(withLocalID: "A different Local ID")
  904. let emailCredential = EmailAuthProvider.credential(withEmail: self.kEmail,
  905. password: self.kFakePassword)
  906. user.reauthenticate(with: emailCredential) { reauthenticatedAuthResult, rawError in
  907. XCTAssertTrue(Thread.isMainThread)
  908. let error = try! XCTUnwrap(rawError)
  909. XCTAssertEqual((error as NSError).code, AuthErrorCode.userMismatch.rawValue)
  910. // Email should not have changed on the client side.
  911. XCTAssertEqual(user.email, self.kEmail)
  912. // User is still signed in.
  913. XCTAssertEqual(self.auth?.currentUser, user)
  914. expectation.fulfill()
  915. }
  916. }
  917. }
  918. waitForExpectations(timeout: 5)
  919. }
  920. /** @fn testReauthenticateUserMismatchFailure
  921. @brief Tests the flow of a failed @c reauthenticateWithCredential:completion: call due to trying
  922. to reauthenticate a user that does not exist.
  923. */
  924. func testReauthenticateUserMismatchFailure() {
  925. setFakeGetAccountProvider()
  926. let expectation = self.expectation(description: #function)
  927. signInWithEmailPasswordReturnFakeUser { user in
  928. do {
  929. self.rpcIssuer.respondBlock = {
  930. try self.rpcIssuer.respond(serverErrorMessage: "USER_NOT_FOUND")
  931. }
  932. let googleCredential = GoogleAuthProvider.credential(withIDToken: self.kGoogleIDToken,
  933. accessToken: self.kGoogleAccessToken)
  934. user.reauthenticate(with: googleCredential) { reauthenticatedAuthResult, rawError in
  935. XCTAssertTrue(Thread.isMainThread)
  936. let error = try! XCTUnwrap(rawError)
  937. XCTAssertEqual((error as NSError).code, AuthErrorCode.userMismatch.rawValue)
  938. // Email should not have changed on the client side.
  939. XCTAssertEqual(user.email, self.kEmail)
  940. // User is still signed in.
  941. XCTAssertEqual(self.auth?.currentUser, user)
  942. expectation.fulfill()
  943. }
  944. }
  945. }
  946. waitForExpectations(timeout: 5)
  947. }
  948. /** @fn testLinkAndRetrieveDataSuccess (and old testLinkCredentialSuccess)
  949. @brief Tests the flow of a successful @c linkWithCredential call.
  950. */
  951. func testLinkAndRetrieveDataSuccess() throws {
  952. setFakeGetAccountProvider()
  953. let expectation = self.expectation(description: #function)
  954. let auth = try XCTUnwrap(self.auth)
  955. signInWithFacebookCredential { user in
  956. XCTAssertNotNil(user)
  957. do {
  958. self.setFakeGoogleGetAccountProvider()
  959. self.rpcIssuer.respondBlock = {
  960. try self.rpcIssuer.respond(withJSON: ["idToken": RPCBaseTests.kFakeAccessToken,
  961. "refreshToken": self.kRefreshToken,
  962. "federatedId": self.kGoogleID,
  963. "providerId": GoogleAuthProvider.id,
  964. "localId": self.kLocalID,
  965. "displayName": self.kGoogleDisplayName,
  966. "rawUserInfo": self.kGoogleProfile,
  967. "username": self.kUserName])
  968. }
  969. let googleCredential = GoogleAuthProvider.credential(withIDToken: self.kGoogleIDToken,
  970. accessToken: self.kGoogleAccessToken)
  971. user.link(with: googleCredential) { linkAuthResult, error in
  972. XCTAssertTrue(Thread.isMainThread)
  973. XCTAssertNil(error)
  974. // Verify that the current user is unchanged.
  975. XCTAssertEqual(auth.currentUser, user)
  976. // Verify that the current user and reauthenticated user are the same pointers.
  977. XCTAssertEqual(user, linkAuthResult?.user)
  978. // Verify that anyway the current user and reauthenticated user have same IDs.
  979. XCTAssertEqual(linkAuthResult?.user.uid, user.uid)
  980. XCTAssertEqual(linkAuthResult?.user.email, user.email)
  981. XCTAssertEqual(linkAuthResult?.user.displayName, user.displayName)
  982. XCTAssertEqual(linkAuthResult?.additionalUserInfo?.username, self.kUserName)
  983. XCTAssertEqual(linkAuthResult?.additionalUserInfo?.providerID,
  984. GoogleAuthProvider.id)
  985. XCTAssertEqual(
  986. linkAuthResult?.additionalUserInfo?.profile as? [String: String],
  987. self.kGoogleProfile
  988. )
  989. XCTAssertEqual(linkAuthResult?.user.providerData.first?.providerID, GoogleAuthProvider.id)
  990. expectation.fulfill()
  991. }
  992. }
  993. }
  994. waitForExpectations(timeout: 5)
  995. try assertUserGoogle(auth.currentUser)
  996. }
  997. /** @fn testLinkAndRetrieveDataError
  998. @brief Tests the flow of an unsuccessful @c linkWithCredential:completion:
  999. call with an error from the backend.
  1000. */
  1001. func testLinkAndRetrieveDataError() throws {
  1002. setFakeGetAccountProvider()
  1003. let expectation = self.expectation(description: #function)
  1004. signInWithFacebookCredential { user in
  1005. XCTAssertNotNil(user)
  1006. do {
  1007. self.setFakeGetAccountProvider()
  1008. self.rpcIssuer.respondBlock = {
  1009. try self.rpcIssuer.respond(serverErrorMessage: "CREDENTIAL_TOO_OLD_LOGIN_AGAIN")
  1010. }
  1011. let googleCredential = GoogleAuthProvider.credential(withIDToken: self.kGoogleIDToken,
  1012. accessToken: self.kGoogleAccessToken)
  1013. user.link(with: googleCredential) { linkAuthResult, rawError in
  1014. XCTAssertTrue(Thread.isMainThread)
  1015. XCTAssertNil(linkAuthResult)
  1016. let error = try! XCTUnwrap(rawError)
  1017. XCTAssertEqual((error as NSError).code, AuthErrorCode.requiresRecentLogin.rawValue)
  1018. // Email should not have changed on the client side.
  1019. XCTAssertEqual(user.email, self.kFacebookEmail)
  1020. // User is still signed in.
  1021. XCTAssertEqual(self.auth?.currentUser, user)
  1022. expectation.fulfill()
  1023. }
  1024. }
  1025. }
  1026. waitForExpectations(timeout: 5)
  1027. }
  1028. /** @fn testLinkAndRetrieveDataProviderAlreadyLinked and old testLinkCredentialProviderAlreadyLinkedError
  1029. @brief Tests the flow of an unsuccessful @c linkWithCredential:completion:
  1030. call with FIRAuthErrorCodeProviderAlreadyLinked, which is a client side error.
  1031. */
  1032. func testLinkAndRetrieveDataProviderAlreadyLinked() throws {
  1033. setFakeGetAccountProvider()
  1034. let expectation = self.expectation(description: #function)
  1035. signInWithFacebookCredential { user in
  1036. XCTAssertNotNil(user)
  1037. do {
  1038. self.setFakeGetAccountProvider()
  1039. let facebookCredential =
  1040. FacebookAuthProvider.credential(withAccessToken: self.kFacebookAccessToken)
  1041. user.link(with: facebookCredential) { linkAuthResult, rawError in
  1042. XCTAssertTrue(Thread.isMainThread)
  1043. XCTAssertNil(linkAuthResult)
  1044. do {
  1045. let error = try XCTUnwrap(rawError)
  1046. XCTAssertEqual((error as NSError).code, AuthErrorCode.providerAlreadyLinked.rawValue)
  1047. } catch {
  1048. XCTFail("Expected to throw providerAlreadyLinked error.")
  1049. }
  1050. // User is still signed in.
  1051. XCTAssertEqual(self.auth?.currentUser, user)
  1052. expectation.fulfill()
  1053. }
  1054. }
  1055. }
  1056. waitForExpectations(timeout: 5)
  1057. }
  1058. /** @fn testLinkAndRetrieveDataErrorAutoSignOut (and old testLinkCredentialError)
  1059. @brief Tests the flow of an unsuccessful @c linkWithCredential:completion:
  1060. call that automatically signs out.
  1061. */
  1062. func testLinkAndRetrieveDataErrorAutoSignOut() throws {
  1063. setFakeGetAccountProvider()
  1064. let expectation = self.expectation(description: #function)
  1065. signInWithFacebookCredential { user in
  1066. XCTAssertNotNil(user)
  1067. do {
  1068. self.setFakeGetAccountProvider()
  1069. self.rpcIssuer.respondBlock = {
  1070. try self.rpcIssuer.respond(serverErrorMessage: "USER_DISABLED")
  1071. }
  1072. let googleCredential = GoogleAuthProvider.credential(withIDToken: self.kGoogleIDToken,
  1073. accessToken: self.kGoogleAccessToken)
  1074. user.link(with: googleCredential) { linkAuthResult, rawError in
  1075. XCTAssertTrue(Thread.isMainThread)
  1076. XCTAssertNil(linkAuthResult)
  1077. let error = try! XCTUnwrap(rawError)
  1078. XCTAssertEqual((error as NSError).code, AuthErrorCode.userDisabled.rawValue)
  1079. // User is signed out.
  1080. XCTAssertNil(self.auth?.currentUser)
  1081. expectation.fulfill()
  1082. }
  1083. }
  1084. }
  1085. waitForExpectations(timeout: 5)
  1086. }
  1087. /** @fn testLinkEmailAndRetrieveDataSuccess
  1088. @brief Tests the flow of a successful @c linkWithCredential:completion:
  1089. invocation for email credential.
  1090. */
  1091. func testLinkEmailAndRetrieveDataSuccess() throws {
  1092. setFakeGetAccountProvider()
  1093. let expectation = self.expectation(description: #function)
  1094. let auth = try XCTUnwrap(self.auth)
  1095. signInWithFacebookCredential { user in
  1096. XCTAssertNotNil(user)
  1097. do {
  1098. self.rpcIssuer.respondBlock = {
  1099. let request = self.rpcIssuer?.request as? SignUpNewUserRequest
  1100. XCTAssertNotNil(request)
  1101. XCTAssertEqual(request?.email, self.kEmail)
  1102. XCTAssertEqual(request?.password, self.kFakePassword)
  1103. XCTAssertNil(request?.displayName)
  1104. let (data, error) = try self.rpcIssuer.respond(withJSON: [
  1105. "idToken": RPCBaseTests.kFakeAccessToken,
  1106. "refreshToken": self.kRefreshToken,
  1107. ])
  1108. self.setFakeGetAccountProvider(withProviderID: EmailAuthProvider.id)
  1109. return (data, error)
  1110. }
  1111. let emailCredential = EmailAuthProvider.credential(withEmail: self.kEmail,
  1112. password: self.kFakePassword)
  1113. user.link(with: emailCredential) { linkAuthResult, error in
  1114. XCTAssertTrue(Thread.isMainThread)
  1115. XCTAssertNil(error)
  1116. // Verify that the current user is unchanged.
  1117. XCTAssertEqual(auth.currentUser, user)
  1118. // Verify that the current user and reauthenticated user are the same pointers.
  1119. XCTAssertEqual(user, linkAuthResult?.user)
  1120. // Verify that anyway the current user and reauthenticated user have same IDs.
  1121. XCTAssertEqual(linkAuthResult?.user.uid, user.uid)
  1122. XCTAssertEqual(linkAuthResult?.user.email, user.email)
  1123. XCTAssertEqual(linkAuthResult?.user.displayName, user.displayName)
  1124. expectation.fulfill()
  1125. }
  1126. }
  1127. }
  1128. waitForExpectations(timeout: 5)
  1129. }
  1130. /** @fn tesLlinkEmailProviderAlreadyLinkedError
  1131. @brief Tests the flow of an unsuccessful @c linkWithCredential:completion:
  1132. invocation for email credential and FIRAuthErrorCodeProviderAlreadyLinked which is a client
  1133. side error.
  1134. */
  1135. func testLinkEmailProviderAlreadyLinkedError() throws {
  1136. setFakeGetAccountProvider()
  1137. let expectation = self.expectation(description: #function)
  1138. signInWithFacebookCredential { user in
  1139. XCTAssertNotNil(user)
  1140. do {
  1141. self.rpcIssuer.respondBlock = {
  1142. let request = self.rpcIssuer?.request as? SignUpNewUserRequest
  1143. XCTAssertNotNil(request)
  1144. XCTAssertEqual(request?.email, self.kEmail)
  1145. XCTAssertEqual(request?.password, self.kFakePassword)
  1146. let (data, error) = try self.rpcIssuer.respond(withJSON: [
  1147. "idToken": RPCBaseTests.kFakeAccessToken,
  1148. "refreshToken": self.kRefreshToken,
  1149. ])
  1150. self.setFakeGetAccountProvider(withProviderID: EmailAuthProvider.id)
  1151. return (data, error)
  1152. }
  1153. let emailCredential = EmailAuthProvider.credential(withEmail: self.kEmail,
  1154. password: self.kFakePassword)
  1155. user.link(with: emailCredential) { linkAuthResult, error in
  1156. XCTAssertEqual(user, linkAuthResult?.user)
  1157. linkAuthResult?.user.link(with: emailCredential) { linkLinkAuthResult, rawError in
  1158. XCTAssertTrue(Thread.isMainThread)
  1159. XCTAssertNil(linkLinkAuthResult)
  1160. do {
  1161. let error = try XCTUnwrap(rawError)
  1162. XCTAssertEqual((error as NSError).code, AuthErrorCode.providerAlreadyLinked.rawValue)
  1163. } catch {
  1164. XCTFail("Expected to throw providerAlreadyLinked error.")
  1165. }
  1166. // User is still signed in.
  1167. XCTAssertEqual(self.auth?.currentUser, user)
  1168. expectation.fulfill()
  1169. }
  1170. }
  1171. }
  1172. }
  1173. waitForExpectations(timeout: 5)
  1174. }
  1175. /** @fn testLinkEmailAndRetrieveDataError
  1176. @brief Tests the flow of an unsuccessful @c linkWithCredential:completion:
  1177. invocation for email credential and an error from the backend.
  1178. */
  1179. func testLinkEmailAndRetrieveDataError() throws {
  1180. setFakeGetAccountProvider()
  1181. let expectation = self.expectation(description: #function)
  1182. signInWithFacebookCredential { user in
  1183. XCTAssertNotNil(user)
  1184. do {
  1185. self.rpcIssuer.respondBlock = {
  1186. let request = self.rpcIssuer?.request as? SignUpNewUserRequest
  1187. XCTAssertNotNil(request)
  1188. XCTAssertEqual(request?.email, self.kEmail)
  1189. XCTAssertEqual(request?.password, self.kFakePassword)
  1190. return try self.rpcIssuer.respond(serverErrorMessage: "TOO_MANY_ATTEMPTS_TRY_LATER")
  1191. }
  1192. let emailCredential = EmailAuthProvider.credential(withEmail: self.kEmail,
  1193. password: self.kFakePassword)
  1194. user.link(with: emailCredential) { linkAuthResult, rawError in
  1195. XCTAssertTrue(Thread.isMainThread)
  1196. XCTAssertNil(linkAuthResult)
  1197. let error = try! XCTUnwrap(rawError)
  1198. XCTAssertEqual((error as NSError).code, AuthErrorCode.tooManyRequests.rawValue)
  1199. // User is still signed in.
  1200. XCTAssertEqual(self.auth?.currentUser, user)
  1201. expectation.fulfill()
  1202. }
  1203. }
  1204. }
  1205. waitForExpectations(timeout: 5)
  1206. }
  1207. /** @fn testLinkEmailAndRetrieveDataErrorAutoSignOut
  1208. @brief Tests the flow of an unsuccessful @c linkWithCredential:completion:
  1209. invocation that automatically signs out.
  1210. */
  1211. func testLinkEmailAndRetrieveDataErrorAutoSignOut() throws {
  1212. setFakeGetAccountProvider()
  1213. let expectation = self.expectation(description: #function)
  1214. signInWithFacebookCredential { user in
  1215. XCTAssertNotNil(user)
  1216. do {
  1217. self.rpcIssuer.respondBlock = {
  1218. XCTAssertNotNil(self.rpcIssuer?.request as? SignUpNewUserRequest)
  1219. return try self.rpcIssuer.respond(serverErrorMessage: "TOKEN_EXPIRED")
  1220. }
  1221. let emailCredential = EmailAuthProvider.credential(withEmail: self.kEmail,
  1222. password: self.kFakePassword)
  1223. user.link(with: emailCredential) { linkAuthResult, rawError in
  1224. XCTAssertTrue(Thread.isMainThread)
  1225. XCTAssertNil(linkAuthResult)
  1226. let error = try! XCTUnwrap(rawError)
  1227. XCTAssertEqual((error as NSError).code, AuthErrorCode.userTokenExpired.rawValue)
  1228. // User is signed out.
  1229. XCTAssertNil(self.auth?.currentUser)
  1230. expectation.fulfill()
  1231. }
  1232. }
  1233. }
  1234. waitForExpectations(timeout: 5)
  1235. }
  1236. #if os(iOS)
  1237. private class FakeOAuthProvider: OAuthProvider {
  1238. override func credential(with uiDelegate: AuthUIDelegate?) async throws -> AuthCredential {
  1239. return OAuthCredential(
  1240. withProviderID: GoogleAuthProvider.id,
  1241. sessionID: UserTests.kOAuthSessionID,
  1242. OAuthResponseURLString: UserTests.kOAuthRequestURI
  1243. )
  1244. }
  1245. }
  1246. /** @fn testLinkProviderFailure
  1247. @brief Tests the flow of a failed @c linkWithProvider:completion:
  1248. call.
  1249. */
  1250. func testLinkProviderFailure() throws {
  1251. setFakeGetAccountProvider()
  1252. let expectation = self.expectation(description: #function)
  1253. let auth = try XCTUnwrap(self.auth)
  1254. signInWithFacebookCredential { user in
  1255. XCTAssertNotNil(user)
  1256. do {
  1257. self.setFakeGetAccountProvider()
  1258. self.rpcIssuer.respondBlock = {
  1259. try self.rpcIssuer.respond(serverErrorMessage: "TOKEN_EXPIRED")
  1260. }
  1261. user.link(with: FakeOAuthProvider(providerID: "foo", auth: auth),
  1262. uiDelegate: nil) { linkAuthResult, rawError in
  1263. XCTAssertTrue(Thread.isMainThread)
  1264. XCTAssertNil(linkAuthResult)
  1265. let error = try! XCTUnwrap(rawError)
  1266. XCTAssertEqual((error as NSError).code, AuthErrorCode.userTokenExpired.rawValue)
  1267. // User is signed out.
  1268. XCTAssertNil(self.auth?.currentUser)
  1269. expectation.fulfill()
  1270. }
  1271. }
  1272. }
  1273. waitForExpectations(timeout: 5)
  1274. }
  1275. /** @fn testReauthenticateWithProviderFailure
  1276. @brief Tests the flow of a failed @c reauthenticateWithProvider:completion: call.
  1277. */
  1278. func testReauthenticateWithProviderFailure() throws {
  1279. setFakeGetAccountProvider()
  1280. let expectation = self.expectation(description: #function)
  1281. let auth = try XCTUnwrap(self.auth)
  1282. signInWithFacebookCredential { user in
  1283. XCTAssertNotNil(user)
  1284. do {
  1285. self.setFakeGetAccountProvider()
  1286. self.rpcIssuer.respondBlock = {
  1287. try self.rpcIssuer.respond(serverErrorMessage: "TOKEN_EXPIRED")
  1288. }
  1289. user.reauthenticate(with: FakeOAuthProvider(providerID: "foo", auth: auth),
  1290. uiDelegate: nil) { linkAuthResult, rawError in
  1291. XCTAssertTrue(Thread.isMainThread)
  1292. XCTAssertNil(linkAuthResult)
  1293. let error = try! XCTUnwrap(rawError)
  1294. XCTAssertEqual((error as NSError).code, AuthErrorCode.userTokenExpired.rawValue)
  1295. // User is still signed in.
  1296. XCTAssertEqual(self.auth?.currentUser, user)
  1297. expectation.fulfill()
  1298. }
  1299. }
  1300. }
  1301. waitForExpectations(timeout: 5)
  1302. }
  1303. /** @fn testLinkPhoneAuthCredentialSuccess
  1304. @brief Tests the flow of a successful @c linkWithCredential call using a phoneAuthCredential.
  1305. */
  1306. func testLinkPhoneAuthCredentialSuccess() throws {
  1307. setFakeGetAccountProvider()
  1308. let expectation = self.expectation(description: #function)
  1309. let auth = try XCTUnwrap(self.auth)
  1310. signInWithEmailPasswordReturnFakeUser { user in
  1311. XCTAssertNotNil(user)
  1312. self.expectVerifyPhoneNumberRequest(isLink: true)
  1313. do {
  1314. self.setFakeGetAccountProvider(withProviderID: PhoneAuthProvider.id)
  1315. self.rpcIssuer.respondBlock = {
  1316. try self.rpcIssuer.respond(withJSON: ["idToken": RPCBaseTests.kFakeAccessToken,
  1317. "refreshToken": self.kRefreshToken])
  1318. }
  1319. let credential = PhoneAuthProvider.provider(auth: auth).credential(
  1320. withVerificationID: self.kVerificationID,
  1321. verificationCode: self.kVerificationCode
  1322. )
  1323. user.link(with: credential) { linkAuthResult, error in
  1324. XCTAssertTrue(Thread.isMainThread)
  1325. XCTAssertNil(error)
  1326. // Verify that the current user is unchanged.
  1327. XCTAssertEqual(auth.currentUser, user)
  1328. // Verify that the current user and reauthenticated user are the same pointers.
  1329. XCTAssertEqual(user, linkAuthResult?.user)
  1330. // Verify that anyway the current user and reauthenticated user have same IDs.
  1331. XCTAssertEqual(linkAuthResult?.user.uid, user.uid)
  1332. XCTAssertEqual(linkAuthResult?.user.email, user.email)
  1333. XCTAssertEqual(linkAuthResult?.user.displayName, user.displayName)
  1334. XCTAssertEqual(auth.currentUser?.providerData.first?.providerID, PhoneAuthProvider.id)
  1335. XCTAssertEqual(
  1336. linkAuthResult?.user.providerData.first?.providerID,
  1337. PhoneAuthProvider.id
  1338. )
  1339. XCTAssertEqual(auth.currentUser?.phoneNumber, self.kTestPhoneNumber)
  1340. expectation.fulfill()
  1341. }
  1342. }
  1343. }
  1344. waitForExpectations(timeout: 5)
  1345. }
  1346. /** @fn testUnlinkPhoneAuthCredentialSuccess
  1347. @brief Tests the flow of a successful @c unlinkFromProvider:completion: call using a
  1348. @c FIRPhoneAuthProvider.
  1349. */
  1350. func testUnlinkPhoneAuthCredentialSuccess() throws {
  1351. setFakeGetAccountProvider()
  1352. let expectation = self.expectation(description: #function)
  1353. let auth = try XCTUnwrap(self.auth)
  1354. signInWithEmailPasswordReturnFakeUser { user in
  1355. XCTAssertNotNil(user)
  1356. self.expectVerifyPhoneNumberRequest(isLink: true)
  1357. do {
  1358. self.setFakeGetAccountProvider(withProviderID: PhoneAuthProvider.id)
  1359. self.rpcIssuer.respondBlock = {
  1360. try self.rpcIssuer.respond(withJSON: ["idToken": RPCBaseTests.kFakeAccessToken,
  1361. "refreshToken": self.kRefreshToken])
  1362. }
  1363. let credential = PhoneAuthProvider.provider(auth: auth).credential(
  1364. withVerificationID: self.kVerificationID,
  1365. verificationCode: self.kVerificationCode
  1366. )
  1367. user.link(with: credential) { linkAuthResult, error in
  1368. XCTAssertTrue(Thread.isMainThread)
  1369. XCTAssertNil(error)
  1370. // Verify that the current user is unchanged.
  1371. XCTAssertEqual(auth.currentUser, user)
  1372. // Verify that the current user and reauthenticated user are the same pointers.
  1373. XCTAssertEqual(user, linkAuthResult?.user)
  1374. // Verify that anyway the current user and reauthenticated user have same IDs.
  1375. XCTAssertEqual(linkAuthResult?.user.uid, user.uid)
  1376. XCTAssertEqual(linkAuthResult?.user.email, user.email)
  1377. XCTAssertEqual(linkAuthResult?.user.displayName, user.displayName)
  1378. XCTAssertEqual(auth.currentUser?.providerData.first?.providerID, PhoneAuthProvider.id)
  1379. XCTAssertEqual(
  1380. linkAuthResult?.user.providerData.first?.providerID,
  1381. PhoneAuthProvider.id
  1382. )
  1383. XCTAssertEqual(auth.currentUser?.phoneNumber, self.kTestPhoneNumber)
  1384. // Immediately unlink the phone auth provider.
  1385. self.rpcIssuer.respondBlock = {
  1386. let request = try XCTUnwrap(self.rpcIssuer?.request as? SetAccountInfoRequest)
  1387. XCTAssertEqual(request.apiKey, UserTests.kFakeAPIKey)
  1388. XCTAssertEqual(request.accessToken, RPCBaseTests.kFakeAccessToken)
  1389. XCTAssertNil(request.email)
  1390. XCTAssertNil(request.password)
  1391. XCTAssertNil(request.localID)
  1392. XCTAssertNil(request.displayName)
  1393. XCTAssertNil(request.photoURL)
  1394. XCTAssertNil(request.providers)
  1395. XCTAssertNil(request.deleteAttributes)
  1396. XCTAssertEqual(try XCTUnwrap(request.deleteProviders?.first), PhoneAuthProvider.id)
  1397. return try self.rpcIssuer.respond(withJSON: ["idToken": RPCBaseTests.kFakeAccessToken,
  1398. "refreshToken": self.kRefreshToken])
  1399. }
  1400. user.unlink(fromProvider: PhoneAuthProvider.id) { user, error in
  1401. XCTAssertNil(error)
  1402. XCTAssertEqual(auth.currentUser, user)
  1403. XCTAssertNil(auth.currentUser?.phoneNumber)
  1404. expectation.fulfill()
  1405. }
  1406. }
  1407. }
  1408. }
  1409. waitForExpectations(timeout: 5)
  1410. }
  1411. /** @fn testlinkPhoneAuthCredentialFailure
  1412. @brief Tests the flow of a failed call to @c linkWithCredential:completion: due
  1413. to a phone provider already being linked.
  1414. */
  1415. func testlinkPhoneAuthCredentialFailure() throws {
  1416. setFakeGetAccountProvider(withPasswordHash: kFakePassword)
  1417. let expectation = self.expectation(description: #function)
  1418. signInWithEmailPasswordReturnFakeUser { user in
  1419. XCTAssertNotNil(user)
  1420. self.expectVerifyPhoneNumberRequest(isLink: true)
  1421. self.setFakeGetAccountProvider(withProviderID: PhoneAuthProvider.id)
  1422. let credential = EmailAuthCredential(withEmail: self.kEmail, password: self.kFakePassword)
  1423. user.link(with: credential) { linkAuthResult, rawError in
  1424. XCTAssertTrue(Thread.isMainThread)
  1425. XCTAssertNil(linkAuthResult)
  1426. if let error = try? XCTUnwrap(rawError) {
  1427. XCTAssertEqual((error as NSError).code, AuthErrorCode.providerAlreadyLinked.rawValue)
  1428. } else {
  1429. XCTFail("Did not throw expected error")
  1430. }
  1431. expectation.fulfill()
  1432. }
  1433. }
  1434. waitForExpectations(timeout: 5)
  1435. }
  1436. /** @fn testlinkPhoneCredentialAlreadyExistsError
  1437. @brief Tests the flow of @c linkWithCredential:completion:
  1438. call using a phoneAuthCredential and a credential already exists error. In this case we
  1439. should get a AuthCredential in the error object.
  1440. */
  1441. func testlinkPhoneCredentialAlreadyExistsError() throws {
  1442. setFakeGetAccountProvider()
  1443. let expectation = self.expectation(description: #function)
  1444. let auth = try XCTUnwrap(self.auth)
  1445. signInWithEmailPasswordReturnFakeUser { user in
  1446. XCTAssertNotNil(user)
  1447. self.expectVerifyPhoneNumberRequest(isLink: true)
  1448. do {
  1449. self.setFakeGetAccountProvider(withProviderID: PhoneAuthProvider.id)
  1450. self.rpcIssuer.respondBlock = {
  1451. try self.rpcIssuer.respond(withJSON: ["idToken": RPCBaseTests.kFakeAccessToken,
  1452. "refreshToken": self.kRefreshToken,
  1453. "phoneNumber": self.kTestPhoneNumber,
  1454. "temporaryProof": "Fake Temporary Proof"])
  1455. }
  1456. let credential = PhoneAuthProvider.provider(auth: auth).credential(
  1457. withVerificationID: self.kVerificationID,
  1458. verificationCode: self.kVerificationCode
  1459. )
  1460. user.link(with: credential) { linkAuthResult, rawError in
  1461. XCTAssertTrue(Thread.isMainThread)
  1462. XCTAssertNil(linkAuthResult)
  1463. do {
  1464. let error = try XCTUnwrap(rawError)
  1465. XCTAssertEqual((error as NSError).code, AuthErrorCode.credentialAlreadyInUse.rawValue)
  1466. let credential = try XCTUnwrap((error as NSError)
  1467. .userInfo[AuthErrors.userInfoUpdatedCredentialKey] as? PhoneAuthCredential)
  1468. switch credential.credentialKind {
  1469. case let .phoneNumber(phoneNumber, temporaryProof):
  1470. XCTAssertEqual(temporaryProof, "Fake Temporary Proof")
  1471. XCTAssertEqual(phoneNumber, self.kTestPhoneNumber)
  1472. case .verification: XCTFail("Should be phoneNumber case")
  1473. }
  1474. } catch {
  1475. XCTFail("Did not throw expected error \(error)")
  1476. }
  1477. expectation.fulfill()
  1478. }
  1479. }
  1480. }
  1481. waitForExpectations(timeout: 5)
  1482. }
  1483. #endif
  1484. func testRetrieveUserWithInvalidToken() async throws {
  1485. let auth = try XCTUnwrap(self.auth)
  1486. do {
  1487. _ = try await User.retrieveUser(
  1488. withAuth: auth,
  1489. accessToken: nil,
  1490. accessTokenExpirationDate: Date(),
  1491. refreshToken: nil,
  1492. anonymous: false
  1493. )
  1494. XCTFail("Expected an error to be thrown")
  1495. } catch let error as NSError {
  1496. XCTAssertEqual(error.domain, AuthErrors.domain)
  1497. XCTAssertEqual(error.code, AuthErrorCode.invalidUserToken.rawValue)
  1498. }
  1499. }
  1500. // MARK: Private helper functions
  1501. private func expectVerifyPhoneNumberRequest(isLink: Bool = false) {
  1502. rpcIssuer?.verifyPhoneNumberRequester = { request in
  1503. XCTAssertEqual(request.verificationID, self.kVerificationID)
  1504. XCTAssertEqual(request.verificationCode, self.kVerificationCode)
  1505. XCTAssertEqual(request.accessToken, RPCBaseTests.kFakeAccessToken)
  1506. if isLink {
  1507. XCTAssertEqual(request.operation, AuthOperationType.link)
  1508. } else {
  1509. XCTAssertEqual(request.operation, AuthOperationType.update)
  1510. }
  1511. }
  1512. }
  1513. private func internalGetIDTokenResult(token: String, forceRefresh: Bool = true,
  1514. emailMatch: String = "aunitestuser@gmail.com",
  1515. audMatch: String = "test_aud") {
  1516. setFakeGetAccountProvider()
  1517. let expectation = self.expectation(description: #function)
  1518. signInWithEmailPasswordReturnFakeUser(fakeAccessToken: token) { user in
  1519. user.getIDTokenResult(forcingRefresh: forceRefresh) { rawTokenResult, error in
  1520. XCTAssertTrue(Thread.isMainThread)
  1521. XCTAssertNil(error)
  1522. XCTAssertEqual(user.displayName, self.kDisplayName)
  1523. XCTAssertEqual(user.email, self.kEmail)
  1524. let tokenResult = try! XCTUnwrap(rawTokenResult)
  1525. XCTAssertEqual(tokenResult.token, token)
  1526. XCTAssertNotNil(tokenResult.issuedAtDate)
  1527. XCTAssertNotNil(tokenResult.authDate)
  1528. XCTAssertNotNil(tokenResult.expirationDate)
  1529. XCTAssertNotNil(tokenResult.signInProvider)
  1530. // The lowercased is for the base64 test which seems to be an erroneously uppercased
  1531. // "Password"?
  1532. XCTAssertEqual(tokenResult.signInProvider.lowercased(), EmailAuthProvider.id)
  1533. XCTAssertEqual(tokenResult.claims["email"] as! String, emailMatch)
  1534. XCTAssertEqual(tokenResult.claims["aud"] as! String, audMatch)
  1535. XCTAssertEqual(tokenResult.signInSecondFactor, "")
  1536. expectation.fulfill()
  1537. }
  1538. }
  1539. waitForExpectations(timeout: 5)
  1540. }
  1541. private func changeUserEmail(user: User, changeEmail: Bool = false,
  1542. expectation: XCTestExpectation) {
  1543. do {
  1544. XCTAssertEqual(user.providerID, "Firebase")
  1545. XCTAssertEqual(user.uid, kLocalID)
  1546. XCTAssertEqual(user.displayName, kDisplayName)
  1547. XCTAssertEqual(user.photoURL, URL(string: kTestPhotoURL))
  1548. XCTAssertEqual(user.email, kEmail)
  1549. // Pretend that the display name on the server has been changed since the original signin.
  1550. setFakeGetAccountProvider(withNewDisplayName: kNewDisplayName)
  1551. rpcIssuer.respondBlock = {
  1552. let request = try XCTUnwrap(self.rpcIssuer?.request as? SetAccountInfoRequest)
  1553. XCTAssertEqual(request.apiKey, UserTests.kFakeAPIKey)
  1554. XCTAssertEqual(request.accessToken, RPCBaseTests.kFakeAccessToken)
  1555. if changeEmail {
  1556. XCTAssertEqual(request.email, self.kNewEmail)
  1557. XCTAssertNil(request.password)
  1558. } else {
  1559. XCTAssertEqual(request.password, self.kNewPassword)
  1560. XCTAssertNil(request.email)
  1561. }
  1562. XCTAssertNil(request.localID)
  1563. XCTAssertNil(request.displayName)
  1564. XCTAssertNil(request.photoURL)
  1565. XCTAssertNil(request.providers)
  1566. XCTAssertNil(request.deleteAttributes)
  1567. XCTAssertNil(request.deleteProviders)
  1568. return try self.rpcIssuer.respond(withJSON: ["idToken": RPCBaseTests.kFakeAccessToken,
  1569. "email": self.kNewEmail,
  1570. "refreshToken": self.kRefreshToken])
  1571. }
  1572. if changeEmail {
  1573. user.updateEmail(to: kNewEmail) { error in
  1574. XCTAssertNil(error)
  1575. XCTAssertEqual(user.email, self.kNewEmail)
  1576. XCTAssertEqual(user.displayName, self.kNewDisplayName)
  1577. XCTAssertFalse(user.isAnonymous)
  1578. expectation.fulfill()
  1579. }
  1580. } else {
  1581. user.updatePassword(to: kNewPassword) { error in
  1582. XCTAssertNil(error)
  1583. XCTAssertEqual(user.displayName, self.kNewDisplayName)
  1584. XCTAssertFalse(user.isAnonymous)
  1585. expectation.fulfill()
  1586. }
  1587. }
  1588. }
  1589. }
  1590. private func signInWithEmailPasswordReturnFakeUser(fakeAccessToken: String = RPCBaseTests
  1591. .kFakeAccessToken,
  1592. completion: @escaping (User) -> Void) {
  1593. let kRefreshToken = "fakeRefreshToken"
  1594. setFakeSecureTokenService(fakeAccessToken: fakeAccessToken)
  1595. rpcIssuer?.verifyPasswordRequester = { request in
  1596. // 2. Validate the created Request instance.
  1597. XCTAssertEqual(request.email, self.kEmail)
  1598. XCTAssertEqual(request.password, self.kFakePassword)
  1599. XCTAssertEqual(request.apiKey, UserTests.kFakeAPIKey)
  1600. XCTAssertTrue(request.returnSecureToken)
  1601. do {
  1602. // 3. Send the response from the fake backend.
  1603. return try self.rpcIssuer.respond(withJSON: ["idToken": fakeAccessToken,
  1604. "isNewUser": true,
  1605. "refreshToken": kRefreshToken])
  1606. } catch {
  1607. XCTFail("Failure sending response: \(error)")
  1608. return (nil, nil)
  1609. }
  1610. }
  1611. // 1. After setting up fakes, sign out and sign in.
  1612. do {
  1613. try auth?.signOut()
  1614. } catch {
  1615. XCTFail("Sign out failed: \(error)")
  1616. return
  1617. }
  1618. auth?.signIn(withEmail: kEmail, password: kFakePassword) { authResult, error in
  1619. // 4. After the response triggers the callback, verify the returned result.
  1620. XCTAssertTrue(Thread.isMainThread)
  1621. guard let user = authResult?.user else {
  1622. XCTFail("authResult.user is missing")
  1623. return
  1624. }
  1625. XCTAssertEqual(user.refreshToken, kRefreshToken)
  1626. XCTAssertFalse(user.isAnonymous)
  1627. XCTAssertEqual(user.email, self.kEmail)
  1628. guard let additionalUserInfo = authResult?.additionalUserInfo else {
  1629. XCTFail("authResult.additionalUserInfo is missing")
  1630. return
  1631. }
  1632. XCTAssertFalse(additionalUserInfo.isNewUser)
  1633. XCTAssertEqual(additionalUserInfo.providerID, EmailAuthProvider.id)
  1634. XCTAssertNil(error)
  1635. // Clear the password Requester to avoid being called again by reauthenticate tests.
  1636. self.rpcIssuer?.verifyPasswordRequester = nil
  1637. completion(user)
  1638. }
  1639. }
  1640. private func signInWithGoogleCredential(completion: @escaping (User) -> Void) {
  1641. setFakeSecureTokenService(fakeAccessToken: RPCBaseTests.kFakeAccessToken)
  1642. setFakeGoogleGetAccountProvider()
  1643. rpcIssuer.respondBlock = {
  1644. try self.verifyGoogleAssertionRequest(
  1645. XCTUnwrap(self.rpcIssuer?.request as? VerifyAssertionRequest)
  1646. )
  1647. // 3. Send the response from the fake backend.
  1648. return try self.rpcIssuer.respond(withJSON: ["idToken": RPCBaseTests.kFakeAccessToken,
  1649. "providerId": GoogleAuthProvider.id,
  1650. "refreshToken": self.kRefreshToken,
  1651. "localId": self.kLocalID,
  1652. "displayName": self.kDisplayName,
  1653. "rawUserInfo": self.kGoogleProfile,
  1654. "username": self.kUserName])
  1655. }
  1656. do {
  1657. try auth?.signOut()
  1658. let googleCredential = GoogleAuthProvider.credential(withIDToken: kGoogleIDToken,
  1659. accessToken: kGoogleAccessToken)
  1660. auth?.signIn(with: googleCredential) { authResult, error in
  1661. // 4. After the response triggers the callback, verify the returned result.
  1662. XCTAssertTrue(Thread.isMainThread)
  1663. guard let user = authResult?.user else {
  1664. XCTFail("authResult.user is missing")
  1665. return
  1666. }
  1667. XCTAssertEqual(user.refreshToken, self.kRefreshToken)
  1668. XCTAssertFalse(user.isAnonymous)
  1669. XCTAssertEqual(user.email, self.kGoogleEmail)
  1670. guard let additionalUserInfo = authResult?.additionalUserInfo,
  1671. let profile = additionalUserInfo.profile as? [String: String] else {
  1672. XCTFail("authResult.additionalUserInfo and/or profile is missing")
  1673. return
  1674. }
  1675. XCTAssertEqual(profile, self.kGoogleProfile)
  1676. XCTAssertFalse(additionalUserInfo.isNewUser)
  1677. XCTAssertEqual(additionalUserInfo.providerID, GoogleAuthProvider.id)
  1678. XCTAssertEqual(additionalUserInfo.username, self.kUserName)
  1679. XCTAssertNil(error)
  1680. completion(user)
  1681. }
  1682. } catch {
  1683. XCTFail("Throw in \(#function): \(error)")
  1684. }
  1685. }
  1686. private func verifyGoogleAssertionRequest(_ request: VerifyAssertionRequest) {
  1687. XCTAssertEqual(request.providerID, GoogleAuthProvider.id)
  1688. XCTAssertEqual(request.providerIDToken, kGoogleIDToken)
  1689. XCTAssertEqual(request.providerAccessToken, kGoogleAccessToken)
  1690. XCTAssertTrue(request.returnSecureToken)
  1691. XCTAssertEqual(request.apiKey, UserTests.kFakeAPIKey)
  1692. XCTAssertTrue(request.returnSecureToken)
  1693. }
  1694. private func signInWithFacebookCredential(completion: @escaping (User) -> Void) {
  1695. setFakeSecureTokenService(fakeAccessToken: RPCBaseTests.kFakeAccessToken)
  1696. setFakeGetAccountProvider(withNewDisplayName: kFacebookDisplayName,
  1697. withProviderID: FacebookAuthProvider.id,
  1698. withFederatedID: kFacebookID,
  1699. withEmail: kFacebookEmail)
  1700. rpcIssuer.respondBlock = {
  1701. let request = try XCTUnwrap(self.rpcIssuer?.request as? VerifyAssertionRequest)
  1702. XCTAssertEqual(request.providerID, FacebookAuthProvider.id)
  1703. XCTAssertEqual(request.providerIDToken, self.kFacebookIDToken)
  1704. XCTAssertEqual(request.providerAccessToken, self.kFacebookAccessToken)
  1705. XCTAssertTrue(request.returnSecureToken)
  1706. XCTAssertEqual(request.apiKey, UserTests.kFakeAPIKey)
  1707. XCTAssertTrue(request.returnSecureToken)
  1708. // 3. Send the response from the fake backend.
  1709. return try self.rpcIssuer.respond(withJSON: ["idToken": RPCBaseTests.kFakeAccessToken,
  1710. "refreshToken": self.kRefreshToken,
  1711. "federatedId": self.kFacebookID,
  1712. "providerId": FacebookAuthProvider.id,
  1713. "localId": self.kLocalID,
  1714. "displayName": self.kDisplayName,
  1715. "rawUserInfo": self.kGoogleProfile,
  1716. "username": self.kUserName])
  1717. }
  1718. do {
  1719. try auth?.signOut()
  1720. let facebookCredential = FacebookAuthProvider
  1721. .credential(withAccessToken: kFacebookAccessToken)
  1722. auth?.signIn(with: facebookCredential) { authResult, error in
  1723. // 4. After the response triggers the callback, verify the returned result.
  1724. XCTAssertTrue(Thread.isMainThread)
  1725. guard let user = authResult?.user else {
  1726. XCTFail("authResult.user is missing")
  1727. return
  1728. }
  1729. XCTAssertEqual(user.refreshToken, self.kRefreshToken)
  1730. XCTAssertFalse(user.isAnonymous)
  1731. XCTAssertEqual(user.email, self.kFacebookEmail)
  1732. XCTAssertEqual(user.displayName, self.kFacebookDisplayName)
  1733. XCTAssertEqual(user.providerData.count, 1)
  1734. guard let additionalUserInfo = authResult?.additionalUserInfo,
  1735. let facebookUserInfo = user.providerData.first,
  1736. let profile = additionalUserInfo.profile as? [String: String] else {
  1737. XCTFail("authResult.additionalUserInfo and/or profile is missing")
  1738. return
  1739. }
  1740. XCTAssertEqual(facebookUserInfo.providerID, FacebookAuthProvider.id)
  1741. XCTAssertEqual(facebookUserInfo.uid, self.kFacebookID)
  1742. XCTAssertEqual(facebookUserInfo.displayName, self.kFacebookDisplayName)
  1743. XCTAssertEqual(facebookUserInfo.email, self.kFacebookEmail)
  1744. XCTAssertEqual(profile, self.kGoogleProfile)
  1745. XCTAssertFalse(additionalUserInfo.isNewUser)
  1746. XCTAssertEqual(additionalUserInfo.providerID, FacebookAuthProvider.id)
  1747. XCTAssertEqual(additionalUserInfo.username, self.kUserName)
  1748. XCTAssertNil(error)
  1749. completion(user)
  1750. }
  1751. } catch {
  1752. XCTFail("Throw in \(#function): \(error)")
  1753. }
  1754. }
  1755. private func signInWithEmailPasswordReturnFakeUserLink(completion: @escaping (User) -> Void) {
  1756. let kRefreshToken = "fakeRefreshToken"
  1757. setFakeSecureTokenService()
  1758. rpcIssuer.respondBlock = {
  1759. let request = try XCTUnwrap(self.rpcIssuer?.request as? EmailLinkSignInRequest)
  1760. XCTAssertEqual(request.email, self.kEmail)
  1761. XCTAssertEqual(request.apiKey, UserTests.kFakeAPIKey)
  1762. XCTAssertEqual(request.oobCode, "aCode")
  1763. XCTAssertNil(request.idToken)
  1764. // Send the response from the fake backend.
  1765. return try self.rpcIssuer.respond(withJSON: ["idToken": RPCBaseTests.kFakeAccessToken,
  1766. "isNewUser": true,
  1767. "refreshToken": kRefreshToken])
  1768. }
  1769. do {
  1770. try auth?.signOut()
  1771. auth?.signIn(
  1772. withEmail: kEmail,
  1773. link: "https://www.google.com?oobCode=aCode&mode=signIn"
  1774. ) { authResult, error in
  1775. // 4. After the response triggers the callback, verify the returned result.
  1776. XCTAssertTrue(Thread.isMainThread)
  1777. guard let user = authResult?.user else {
  1778. XCTFail("authResult.user is missing")
  1779. return
  1780. }
  1781. XCTAssertEqual(user.refreshToken, kRefreshToken)
  1782. XCTAssertFalse(user.isAnonymous)
  1783. XCTAssertEqual(user.email, self.kEmail)
  1784. guard let additionalUserInfo = authResult?.additionalUserInfo else {
  1785. XCTFail("authResult.additionalUserInfo is missing")
  1786. return
  1787. }
  1788. XCTAssertTrue(additionalUserInfo.isNewUser)
  1789. XCTAssertEqual(additionalUserInfo.providerID, EmailAuthProvider.id)
  1790. XCTAssertNil(error)
  1791. completion(user)
  1792. }
  1793. } catch {
  1794. XCTFail("Throw in \(#function): \(error)")
  1795. }
  1796. }
  1797. }