UserTests.swift 82 KB

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