AuthTests.swift 102 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457
  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 FirebaseAuthInterop
  18. import FirebaseCore
  19. @available(iOS 13, tvOS 13, macOS 10.15, macCatalyst 13, watchOS 7, *)
  20. class AuthTests: RPCBaseTests {
  21. static let kAccessToken = "TEST_ACCESS_TOKEN"
  22. static let kNewAccessToken = "NEW_ACCESS_TOKEN"
  23. static let kFakeAPIKey = "FAKE_API_KEY"
  24. static let kFakeRecaptchaResponse = "RecaptchaResponse"
  25. static let kFakeRecaptchaVersion = "RecaptchaVersion"
  26. var auth: Auth!
  27. static var testNum = 0
  28. var authDispatcherCallback: (() -> Void)?
  29. override func setUp() {
  30. super.setUp()
  31. let options = FirebaseOptions(googleAppID: "0:0000000000000:ios:0000000000000000",
  32. gcmSenderID: "00000000000000000-00000000000-000000000")
  33. options.apiKey = AuthTests.kFakeAPIKey
  34. options.projectID = "myProjectID"
  35. let name = "test-AuthTests\(AuthTests.testNum)"
  36. AuthTests.testNum = AuthTests.testNum + 1
  37. FirebaseApp.configure(name: name, options: options)
  38. #if (os(macOS) && !FIREBASE_AUTH_TESTING_USE_MACOS_KEYCHAIN) || SWIFT_PACKAGE
  39. let keychainStorageProvider = FakeAuthKeychainStorage()
  40. #else
  41. let keychainStorageProvider = AuthKeychainStorageReal.shared
  42. #endif // (os(macOS) && !FIREBASE_AUTH_TESTING_USE_MACOS_KEYCHAIN) || SWIFT_PACKAGE
  43. // Stub the implementation to save the token refresh task for later execution.
  44. let authDispatcher = AuthDispatcher { delay, queue, task in
  45. XCTAssertNotNil(task)
  46. XCTAssertGreaterThan(delay, 0)
  47. XCTAssertEqual(kAuthGlobalWorkQueue, queue)
  48. self.authDispatcherCallback = task
  49. }
  50. auth = Auth(
  51. app: FirebaseApp.app(name: name)!,
  52. keychainStorageProvider: keychainStorageProvider,
  53. backend: authBackend,
  54. authDispatcher: authDispatcher
  55. )
  56. // Wait until Auth initialization completes
  57. waitForAuthGlobalWorkQueueDrain()
  58. }
  59. private func waitForAuthGlobalWorkQueueDrain() {
  60. let workerSemaphore = DispatchSemaphore(value: 0)
  61. kAuthGlobalWorkQueue.async {
  62. workerSemaphore.signal()
  63. }
  64. _ = workerSemaphore.wait(timeout: DispatchTime.distantFuture)
  65. }
  66. /** @fn testFetchSignInMethodsForEmailSuccess
  67. @brief Tests the flow of a successful @c fetchSignInMethodsForEmail:completion: call.
  68. */
  69. func testFetchSignInMethodsForEmailSuccess() throws {
  70. let allSignInMethods = ["emailLink", "facebook.com"]
  71. let expectation = self.expectation(description: #function)
  72. rpcIssuer.respondBlock = {
  73. let request = try XCTUnwrap(self.rpcIssuer.request as? CreateAuthURIRequest)
  74. XCTAssertEqual(request.identifier, self.kEmail)
  75. XCTAssertEqual(request.endpoint, "createAuthUri")
  76. XCTAssertEqual(request.apiKey, AuthTests.kFakeAPIKey)
  77. return try self.rpcIssuer.respond(withJSON: ["signinMethods": allSignInMethods])
  78. }
  79. auth?.fetchSignInMethods(forEmail: kEmail) { signInMethods, error in
  80. // 4. After the response triggers the callback, verify the returned signInMethods.
  81. XCTAssertTrue(Thread.isMainThread)
  82. XCTAssertEqual(signInMethods, allSignInMethods)
  83. XCTAssertNil(error)
  84. expectation.fulfill()
  85. }
  86. waitForExpectations(timeout: 5)
  87. }
  88. /** @fn testFetchSignInMethodsForEmailFailure
  89. @brief Tests the flow of a failed @c fetchSignInMethodsForEmail:completion: call.
  90. */
  91. func testFetchSignInMethodsForEmailFailure() throws {
  92. let expectation = self.expectation(description: #function)
  93. rpcIssuer.respondBlock = {
  94. let message = "TOO_MANY_ATTEMPTS_TRY_LATER"
  95. return try self.rpcIssuer.respond(serverErrorMessage: message)
  96. }
  97. auth?.fetchSignInMethods(forEmail: kEmail) { signInMethods, error in
  98. XCTAssertTrue(Thread.isMainThread)
  99. XCTAssertNil(signInMethods)
  100. let rpcError = (error as? NSError)!
  101. XCTAssertEqual(rpcError.code, AuthErrorCode.tooManyRequests.rawValue)
  102. expectation.fulfill()
  103. }
  104. waitForExpectations(timeout: 5)
  105. }
  106. #if os(iOS)
  107. /** @fn testPhoneAuthSuccess
  108. @brief Tests the flow of a successful @c signInWithCredential:completion for phone auth.
  109. */
  110. func testPhoneAuthSuccess() throws {
  111. let kVerificationID = "55432"
  112. let kVerificationCode = "12345678"
  113. let expectation = self.expectation(description: #function)
  114. setFakeGetAccountProvider()
  115. setFakeSecureTokenService()
  116. // 1. Setup respond block to test and fake send request.
  117. rpcIssuer.respondBlock = {
  118. // 2. Validate the created Request instance.
  119. let request = try XCTUnwrap(self.rpcIssuer.request as? VerifyPhoneNumberRequest)
  120. XCTAssertEqual(request.verificationCode, kVerificationCode)
  121. XCTAssertEqual(request.verificationID, kVerificationID)
  122. // 3. Send the response from the fake backend.
  123. return try self.rpcIssuer.respond(withJSON: ["idToken": AuthTests.kAccessToken,
  124. "isNewUser": true,
  125. "refreshToken": self.kRefreshToken])
  126. }
  127. try auth?.signOut()
  128. let credential = PhoneAuthProvider.provider(auth: auth)
  129. .credential(withVerificationID: kVerificationID,
  130. verificationCode: kVerificationCode)
  131. auth?.signIn(with: credential) { authResult, error in
  132. // 4. After the response triggers the callback, verify the returned result.
  133. XCTAssertTrue(Thread.isMainThread)
  134. guard let user = authResult?.user,
  135. let additionalUserInfo = authResult?.additionalUserInfo else {
  136. XCTFail("authResult.user or additionalUserInfo is missing")
  137. return
  138. }
  139. XCTAssertEqual(user.refreshToken, self.kRefreshToken)
  140. XCTAssertFalse(user.isAnonymous)
  141. XCTAssertTrue(additionalUserInfo.isNewUser)
  142. XCTAssertNil(error)
  143. expectation.fulfill()
  144. }
  145. waitForExpectations(timeout: 5)
  146. assertUser(auth?.currentUser)
  147. }
  148. /** @fn testPhoneAuthMissingVerificationCode
  149. @brief Tests the flow of an unsuccessful @c signInWithCredential:completion for phone auth due
  150. to an empty verification code
  151. */
  152. func testPhoneAuthMissingVerificationCode() throws {
  153. let kVerificationID = "55432"
  154. let kVerificationCode = ""
  155. let expectation = self.expectation(description: #function)
  156. setFakeGetAccountProvider()
  157. setFakeSecureTokenService()
  158. try auth?.signOut()
  159. let credential = PhoneAuthProvider.provider(auth: auth)
  160. .credential(withVerificationID: kVerificationID,
  161. verificationCode: kVerificationCode)
  162. auth?.signIn(with: credential) { authResult, error in
  163. XCTAssertTrue(Thread.isMainThread)
  164. XCTAssertNil(authResult)
  165. XCTAssertEqual((error as? NSError)?.code, AuthErrorCode.missingVerificationCode.rawValue)
  166. expectation.fulfill()
  167. }
  168. waitForExpectations(timeout: 5)
  169. }
  170. /** @fn testPhoneAuthMissingVerificationID
  171. @brief Tests the flow of an unsuccessful @c signInWithCredential:completion for phone auth due
  172. to an empty verification ID.
  173. */
  174. func testPhoneAuthMissingVerificationID() throws {
  175. let kVerificationID = ""
  176. let kVerificationCode = "123"
  177. let expectation = self.expectation(description: #function)
  178. setFakeGetAccountProvider()
  179. setFakeSecureTokenService()
  180. try auth?.signOut()
  181. let credential = PhoneAuthProvider.provider(auth: auth)
  182. .credential(withVerificationID: kVerificationID,
  183. verificationCode: kVerificationCode)
  184. auth?.signIn(with: credential) { authResult, error in
  185. XCTAssertTrue(Thread.isMainThread)
  186. XCTAssertNil(authResult)
  187. XCTAssertEqual((error as? NSError)?.code, AuthErrorCode.missingVerificationID.rawValue)
  188. expectation.fulfill()
  189. }
  190. waitForExpectations(timeout: 5)
  191. }
  192. #endif
  193. /** @fn testSignInWithEmailLinkSuccess
  194. @brief Tests the flow of a successful @c signInWithEmail:link:completion: call.
  195. */
  196. func testSignInWithEmailLinkSuccess() throws {
  197. try signInWithEmailLinkSuccessWithLinkOrDeeplink(link: kFakeEmailSignInLink)
  198. }
  199. /** @fn testSignInWithEmailLinkSuccessDeeplink
  200. @brief Tests the flow of a successful @c signInWithEmail:link: call using a deep link.
  201. */
  202. func testSignInWithEmailLinkSuccessDeeplink() throws {
  203. try signInWithEmailLinkSuccessWithLinkOrDeeplink(link: kFakeEmailSignInDeeplink)
  204. }
  205. private func signInWithEmailLinkSuccessWithLinkOrDeeplink(link: String) throws {
  206. let fakeCode = "testoobcode"
  207. let expectation = self.expectation(description: #function)
  208. setFakeGetAccountProvider()
  209. setFakeSecureTokenService()
  210. // 1. Setup respond block to test and fake send request.
  211. rpcIssuer.respondBlock = {
  212. // 2. Validate the created Request instance.
  213. let request = try XCTUnwrap(self.rpcIssuer.request as? EmailLinkSignInRequest)
  214. XCTAssertEqual(request.email, self.kEmail)
  215. XCTAssertEqual(request.oobCode, fakeCode)
  216. XCTAssertEqual(request.apiKey, AuthTests.kFakeAPIKey)
  217. return try self.rpcIssuer.respond(withJSON: ["idToken": AuthTests.kAccessToken,
  218. "email": self.kEmail,
  219. "isNewUser": true,
  220. "refreshToken": self.kRefreshToken])
  221. }
  222. try auth?.signOut()
  223. auth?.signIn(withEmail: kEmail, link: link) { authResult, error in
  224. // 4. After the response triggers the callback, verify the returned result.
  225. XCTAssertTrue(Thread.isMainThread)
  226. guard let user = authResult?.user else {
  227. XCTFail("authResult.user is missing")
  228. return
  229. }
  230. XCTAssertEqual(user.refreshToken, self.kRefreshToken)
  231. XCTAssertFalse(user.isAnonymous)
  232. XCTAssertEqual(user.email, self.kEmail)
  233. XCTAssertNil(error)
  234. expectation.fulfill()
  235. }
  236. waitForExpectations(timeout: 5)
  237. assertUser(auth?.currentUser)
  238. }
  239. /** @fn testSignInWithEmailLinkFailure
  240. @brief Tests the flow of a failed @c signInWithEmail:link:completion: call.
  241. */
  242. func testSignInWithEmailLinkFailure() throws {
  243. let expectation = self.expectation(description: #function)
  244. // 1. Setup respond block to test and fake send request.
  245. rpcIssuer.respondBlock = {
  246. // 2. Send the response from the fake backend.
  247. try self.rpcIssuer.respond(serverErrorMessage: "INVALID_OOB_CODE")
  248. }
  249. try auth?.signOut()
  250. auth?.signIn(withEmail: kEmail, link: kFakeEmailSignInLink) { authResult, error in
  251. // 3. After the response triggers the callback, verify the returned result.
  252. XCTAssertTrue(Thread.isMainThread)
  253. XCTAssertNil(authResult)
  254. XCTAssertEqual((error as? NSError)?.code, AuthErrorCode.invalidActionCode.rawValue)
  255. expectation.fulfill()
  256. }
  257. waitForExpectations(timeout: 5)
  258. XCTAssertNil(auth?.currentUser)
  259. }
  260. #if os(iOS)
  261. /** @fn testSignInWithEmailPasswordWithRecaptchaSuccess
  262. @brief Tests the flow of a successful @c signInWithEmail:password:completion: call.
  263. */
  264. func testSignInWithEmailPasswordWithRecaptchaSuccess() throws {
  265. let kRefreshToken = "fakeRefreshToken"
  266. let expectation = self.expectation(description: #function)
  267. setFakeGetAccountProvider()
  268. setFakeSecureTokenService()
  269. // 1. Setup respond block to test and fake send request.
  270. rpcIssuer.respondBlock = {
  271. // 2. Validate the created Request instance.
  272. let request = try XCTUnwrap(self.rpcIssuer.request as? VerifyPasswordRequest)
  273. XCTAssertEqual(request.email, self.kEmail)
  274. XCTAssertEqual(request.password, self.kFakePassword)
  275. XCTAssertEqual(request.apiKey, AuthTests.kFakeAPIKey)
  276. XCTAssertTrue(request.returnSecureToken)
  277. request.injectRecaptchaFields(recaptchaResponse: AuthTests.kFakeRecaptchaResponse,
  278. recaptchaVersion: AuthTests.kFakeRecaptchaVersion)
  279. // 3. Send the response from the fake backend.
  280. return try self.rpcIssuer.respond(withJSON: ["idToken": AuthTests.kAccessToken,
  281. "email": self.kEmail,
  282. "isNewUser": true,
  283. "refreshToken": kRefreshToken])
  284. }
  285. try auth?.signOut()
  286. auth?.signIn(withEmail: kEmail, password: kFakePassword) { authResult, error in
  287. // 4. After the response triggers the callback, verify the returned result.
  288. XCTAssertTrue(Thread.isMainThread)
  289. guard let user = authResult?.user else {
  290. XCTFail("authResult.user is missing")
  291. return
  292. }
  293. XCTAssertEqual(user.refreshToken, kRefreshToken)
  294. XCTAssertFalse(user.isAnonymous)
  295. XCTAssertEqual(user.email, self.kEmail)
  296. guard let additionalUserInfo = authResult?.additionalUserInfo else {
  297. XCTFail("authResult.additionalUserInfo is missing")
  298. return
  299. }
  300. XCTAssertFalse(additionalUserInfo.isNewUser)
  301. XCTAssertEqual(additionalUserInfo.providerID, EmailAuthProvider.id)
  302. XCTAssertNil(error)
  303. expectation.fulfill()
  304. }
  305. waitForExpectations(timeout: 5)
  306. assertUser(auth?.currentUser)
  307. }
  308. /** @fn testSignInWithEmailPasswordWithRecaptchaFallbackSuccess
  309. @brief Tests the flow of a successful @c signInWithEmail:password:completion: call.
  310. */
  311. func testSignInWithEmailPasswordWithRecaptchaFallbackSuccess() throws {
  312. let kRefreshToken = "fakeRefreshToken"
  313. let expectation = self.expectation(description: #function)
  314. setFakeGetAccountProvider()
  315. setFakeSecureTokenService()
  316. let kTestRecaptchaKey = "projects/123/keys/456"
  317. rpcIssuer.recaptchaSiteKey = kTestRecaptchaKey
  318. // 1. Setup respond block to test and fake send request.
  319. rpcIssuer.respondBlock = {
  320. // 2. Validate the created Request instance.
  321. let request = try XCTUnwrap(self.rpcIssuer.request as? VerifyPasswordRequest)
  322. XCTAssertEqual(request.email, self.kEmail)
  323. XCTAssertEqual(request.password, self.kFakePassword)
  324. XCTAssertEqual(request.apiKey, AuthTests.kFakeAPIKey)
  325. XCTAssertTrue(request.returnSecureToken)
  326. request.injectRecaptchaFields(recaptchaResponse: AuthTests.kFakeRecaptchaResponse,
  327. recaptchaVersion: AuthTests.kFakeRecaptchaVersion)
  328. // 3. Send the response from the fake backend.
  329. return try self.rpcIssuer.respond(serverErrorMessage: "MISSING_RECAPTCHA_TOKEN")
  330. }
  331. rpcIssuer.nextRespondBlock = {
  332. // 4. Validate again the created Request instance after the recaptcha retry.
  333. let request = try XCTUnwrap(self.rpcIssuer.request as? VerifyPasswordRequest)
  334. XCTAssertEqual(request.email, self.kEmail)
  335. XCTAssertEqual(request.password, self.kFakePassword)
  336. XCTAssertEqual(request.apiKey, AuthTests.kFakeAPIKey)
  337. XCTAssertTrue(request.returnSecureToken)
  338. request.injectRecaptchaFields(recaptchaResponse: AuthTests.kFakeRecaptchaResponse,
  339. recaptchaVersion: AuthTests.kFakeRecaptchaVersion)
  340. // 5. Send the response from the fake backend.
  341. return try self.rpcIssuer.respond(withJSON: ["idToken": AuthTests.kAccessToken,
  342. "email": self.kEmail,
  343. "isNewUser": true,
  344. "refreshToken": kRefreshToken])
  345. }
  346. try auth?.signOut()
  347. auth?.signIn(withEmail: kEmail, password: kFakePassword) { authResult, error in
  348. // 6. After the response triggers the callback, verify the returned result.
  349. XCTAssertTrue(Thread.isMainThread)
  350. XCTAssertNil(error)
  351. guard let user = authResult?.user else {
  352. XCTFail("authResult.user is missing")
  353. return
  354. }
  355. XCTAssertEqual(user.refreshToken, kRefreshToken)
  356. XCTAssertFalse(user.isAnonymous)
  357. XCTAssertEqual(user.email, self.kEmail)
  358. guard let additionalUserInfo = authResult?.additionalUserInfo else {
  359. XCTFail("authResult.additionalUserInfo is missing")
  360. return
  361. }
  362. XCTAssertFalse(additionalUserInfo.isNewUser)
  363. XCTAssertEqual(additionalUserInfo.providerID, EmailAuthProvider.id)
  364. expectation.fulfill()
  365. }
  366. waitForExpectations(timeout: 5)
  367. assertUser(auth?.currentUser)
  368. }
  369. #endif
  370. /** @fn testSignInAndRetrieveDataWithEmailPasswordSuccess
  371. @brief Tests the flow of a successful @c signInAndRetrieveDataWithEmail:password:completion:
  372. call. Superset of historical testSignInWithEmailPasswordSuccess.
  373. */
  374. func testSignInAndRetrieveDataWithEmailPasswordSuccess() throws {
  375. let kRefreshToken = "fakeRefreshToken"
  376. let expectation = self.expectation(description: #function)
  377. setFakeGetAccountProvider()
  378. setFakeSecureTokenService()
  379. // 1. Setup respond block to test and fake send request.
  380. rpcIssuer.respondBlock = {
  381. // 2. Validate the created Request instance.
  382. let request = try XCTUnwrap(self.rpcIssuer.request as? VerifyPasswordRequest)
  383. XCTAssertEqual(request.email, self.kEmail)
  384. XCTAssertEqual(request.password, self.kFakePassword)
  385. XCTAssertEqual(request.apiKey, AuthTests.kFakeAPIKey)
  386. XCTAssertTrue(request.returnSecureToken)
  387. // 3. Send the response from the fake backend.
  388. return try self.rpcIssuer.respond(withJSON: ["idToken": AuthTests.kAccessToken,
  389. "email": self.kEmail,
  390. "isNewUser": true,
  391. "refreshToken": kRefreshToken])
  392. }
  393. try auth?.signOut()
  394. auth?.signIn(withEmail: kEmail, password: kFakePassword) { authResult, error in
  395. // 4. After the response triggers the callback, verify the returned result.
  396. XCTAssertTrue(Thread.isMainThread)
  397. guard let user = authResult?.user else {
  398. XCTFail("authResult.user is missing")
  399. return
  400. }
  401. XCTAssertEqual(user.refreshToken, kRefreshToken)
  402. XCTAssertFalse(user.isAnonymous)
  403. XCTAssertEqual(user.email, self.kEmail)
  404. guard let additionalUserInfo = authResult?.additionalUserInfo else {
  405. XCTFail("authResult.additionalUserInfo is missing")
  406. return
  407. }
  408. XCTAssertFalse(additionalUserInfo.isNewUser)
  409. XCTAssertEqual(additionalUserInfo.providerID, EmailAuthProvider.id)
  410. XCTAssertNil(error)
  411. expectation.fulfill()
  412. }
  413. waitForExpectations(timeout: 5)
  414. assertUser(auth?.currentUser)
  415. }
  416. /** @fn testSignInWithEmailPasswordFailure
  417. @brief Tests the flow of a failed @c signInWithEmail:password:completion: call.
  418. */
  419. func testSignInWithEmailPasswordFailure() throws {
  420. let expectation = self.expectation(description: #function)
  421. rpcIssuer.respondBlock = {
  422. // 2. Send the response from the fake backend.
  423. try self.rpcIssuer.respond(serverErrorMessage: "INVALID_PASSWORD")
  424. }
  425. try auth?.signOut()
  426. auth?.signIn(withEmail: kEmail, password: kFakePassword) { authResult, error in
  427. // 3. After the response triggers the callback, verify the returned result.
  428. XCTAssertTrue(Thread.isMainThread)
  429. XCTAssertNil(authResult)
  430. XCTAssertEqual((error as? NSError)?.code, AuthErrorCode.wrongPassword.rawValue)
  431. XCTAssertNotNil((error as? NSError)?.userInfo[NSLocalizedDescriptionKey])
  432. expectation.fulfill()
  433. }
  434. waitForExpectations(timeout: 5)
  435. XCTAssertNil(auth?.currentUser)
  436. }
  437. /** @fn testResetPasswordSuccess
  438. @brief Tests the flow of a successful @c confirmPasswordResetWithCode:newPassword:completion:
  439. call.
  440. */
  441. func testResetPasswordSuccess() throws {
  442. let expectation = self.expectation(description: #function)
  443. // 1. Setup respond block to test and fake send request.
  444. rpcIssuer.respondBlock = {
  445. // 2. Validate the created Request instance.
  446. let request = try XCTUnwrap(self.rpcIssuer.request as? ResetPasswordRequest)
  447. XCTAssertEqual(request.oobCode, self.kFakeOobCode)
  448. XCTAssertEqual(request.updatedPassword, self.kFakePassword)
  449. XCTAssertEqual(request.apiKey, AuthTests.kFakeAPIKey)
  450. // 3. Send the response from the fake backend.
  451. return try self.rpcIssuer.respond(withJSON: [:])
  452. }
  453. try auth?.signOut()
  454. auth?
  455. .confirmPasswordReset(withCode: kFakeOobCode, newPassword: kFakePassword) { error in
  456. // 4. After the response triggers the callback, verify the returned result.
  457. XCTAssertTrue(Thread.isMainThread)
  458. XCTAssertNil(error)
  459. expectation.fulfill()
  460. }
  461. waitForExpectations(timeout: 5)
  462. }
  463. /** @fn testResetPasswordFailure
  464. @brief Tests the flow of a failed @c confirmPasswordResetWithCode:newPassword:completion:
  465. call.
  466. */
  467. func testResetPasswordFailure() throws {
  468. let expectation = self.expectation(description: #function)
  469. rpcIssuer.respondBlock = {
  470. // 2. Send the response from the fake backend.
  471. try self.rpcIssuer.respond(serverErrorMessage: "INVALID_OOB_CODE")
  472. }
  473. try auth?.signOut()
  474. auth?
  475. .confirmPasswordReset(withCode: kFakeOobCode, newPassword: kFakePassword) { error in
  476. // 3. After the response triggers the callback, verify the returned result.
  477. XCTAssertTrue(Thread.isMainThread)
  478. XCTAssertEqual((error as? NSError)?.code, AuthErrorCode.invalidActionCode.rawValue)
  479. XCTAssertNotNil((error as? NSError)?.userInfo[NSLocalizedDescriptionKey])
  480. expectation.fulfill()
  481. }
  482. waitForExpectations(timeout: 5)
  483. XCTAssertNil(auth?.currentUser)
  484. }
  485. /** @fn testCheckActionCodeSuccess
  486. @brief Tests the flow of a successful @c checkActionCode:completion call.
  487. */
  488. func testCheckActionCodeSuccess() throws {
  489. let kNewEmail = "newEmail@example.com"
  490. let verifyEmailRequestType = "verifyEmail"
  491. let expectation = self.expectation(description: #function)
  492. // 1. Setup respond block to test and fake send request.
  493. rpcIssuer.respondBlock = {
  494. // 2. Validate the created Request instance.
  495. let request = try XCTUnwrap(self.rpcIssuer.request as? ResetPasswordRequest)
  496. XCTAssertEqual(request.oobCode, self.kFakeOobCode)
  497. XCTAssertEqual(request.apiKey, AuthTests.kFakeAPIKey)
  498. // 3. Send the response from the fake backend.
  499. return try self.rpcIssuer.respond(withJSON: ["email": self.kEmail,
  500. "requestType": verifyEmailRequestType,
  501. "newEmail": kNewEmail])
  502. }
  503. try auth?.signOut()
  504. auth?.checkActionCode(kFakeOobCode) { info, error in
  505. // 4. After the response triggers the callback, verify the returned result.
  506. XCTAssertTrue(Thread.isMainThread)
  507. XCTAssertNil(error)
  508. XCTAssertEqual(info?.email, kNewEmail)
  509. XCTAssertEqual(info?.operation, ActionCodeOperation.verifyEmail)
  510. expectation.fulfill()
  511. }
  512. waitForExpectations(timeout: 5)
  513. }
  514. /** @fn testCheckActionCodeFailure
  515. @brief Tests the flow of a failed @c checkActionCode:completion call.
  516. */
  517. func testCheckActionCodeFailure() throws {
  518. let expectation = self.expectation(description: #function)
  519. // 1. Setup respond block to test and fake send request.
  520. rpcIssuer.respondBlock = {
  521. // 2. Send the response from the fake backend.
  522. try self.rpcIssuer.respond(serverErrorMessage: "EXPIRED_OOB_CODE")
  523. }
  524. try auth?.signOut()
  525. auth?.checkActionCode(kFakeOobCode) { info, error in
  526. // 3. After the response triggers the callback, verify the returned result.
  527. XCTAssertTrue(Thread.isMainThread)
  528. XCTAssertEqual((error as? NSError)?.code, AuthErrorCode.expiredActionCode.rawValue)
  529. XCTAssertNotNil((error as? NSError)?.userInfo[NSLocalizedDescriptionKey])
  530. expectation.fulfill()
  531. }
  532. waitForExpectations(timeout: 5)
  533. XCTAssertNil(auth?.currentUser)
  534. }
  535. /** @fn testApplyActionCodeSuccess
  536. @brief Tests the flow of a successful @c applyActionCode:completion call.
  537. */
  538. func testApplyActionCodeSuccess() throws {
  539. let expectation = self.expectation(description: #function)
  540. // 1. Setup respond block to test and fake send request.
  541. rpcIssuer.respondBlock = {
  542. // 2. Validate the created Request instance.
  543. let request = try XCTUnwrap(self.rpcIssuer.request as? SetAccountInfoRequest)
  544. XCTAssertEqual(request.apiKey, AuthTests.kFakeAPIKey)
  545. // 3. Send the response from the fake backend.
  546. return try self.rpcIssuer.respond(withJSON: [:])
  547. }
  548. try auth?.signOut()
  549. auth?.applyActionCode(kFakeOobCode) { error in
  550. // 4. After the response triggers the callback, verify the returned result.
  551. XCTAssertTrue(Thread.isMainThread)
  552. XCTAssertNil(error)
  553. expectation.fulfill()
  554. }
  555. waitForExpectations(timeout: 5)
  556. }
  557. /** @fn testApplyActionCodeFailure
  558. @brief Tests the flow of a failed @c checkActionCode:completion call.
  559. */
  560. func testApplyActionCodeFailure() throws {
  561. let expectation = self.expectation(description: #function)
  562. // 1. Setup respond block to test and fake send request.
  563. rpcIssuer.respondBlock = {
  564. // 2. Send the response from the fake backend.
  565. try self.rpcIssuer.respond(serverErrorMessage: "INVALID_OOB_CODE")
  566. }
  567. try auth?.signOut()
  568. auth?.applyActionCode(kFakeOobCode) { error in
  569. // 3. After the response triggers the callback, verify the returned result.
  570. XCTAssertTrue(Thread.isMainThread)
  571. XCTAssertEqual((error as? NSError)?.code, AuthErrorCode.invalidActionCode.rawValue)
  572. XCTAssertNotNil((error as? NSError)?.userInfo[NSLocalizedDescriptionKey])
  573. expectation.fulfill()
  574. }
  575. waitForExpectations(timeout: 5)
  576. XCTAssertNil(auth?.currentUser)
  577. }
  578. /** @fn testVerifyPasswordResetCodeSuccess
  579. @brief Tests the flow of a successful @c verifyPasswordResetCode:completion call.
  580. */
  581. func testVerifyPasswordResetCodeSuccess() throws {
  582. let expectation = self.expectation(description: #function)
  583. // 1. Setup respond block to test and fake send request.
  584. rpcIssuer.respondBlock = {
  585. // 2. Validate the created Request instance.
  586. let request = try XCTUnwrap(self.rpcIssuer.request as? ResetPasswordRequest)
  587. XCTAssertEqual(request.apiKey, AuthTests.kFakeAPIKey)
  588. XCTAssertEqual(request.oobCode, self.kFakeOobCode)
  589. // 3. Send the response from the fake backend.
  590. return try self.rpcIssuer.respond(withJSON: ["email": self.kEmail])
  591. }
  592. try auth?.signOut()
  593. auth?.verifyPasswordResetCode(kFakeOobCode) { email, error in
  594. // 4. After the response triggers the callback, verify the returned result.
  595. XCTAssertTrue(Thread.isMainThread)
  596. XCTAssertEqual(email, self.kEmail)
  597. XCTAssertNil(error)
  598. expectation.fulfill()
  599. }
  600. waitForExpectations(timeout: 5)
  601. }
  602. /** @fn testVerifyPasswordResetCodeFailure
  603. @brief Tests the flow of a failed @c verifyPasswordResetCode:completion call.
  604. */
  605. func testVerifyPasswordResetCodeFailure() throws {
  606. let expectation = self.expectation(description: #function)
  607. // 1. Setup respond block to test and fake send request.
  608. rpcIssuer.respondBlock = {
  609. // 2. Send the response from the fake backend.
  610. try self.rpcIssuer.respond(serverErrorMessage: "INVALID_OOB_CODE")
  611. }
  612. try auth?.signOut()
  613. auth?.verifyPasswordResetCode(kFakeOobCode) { email, error in
  614. // 3. After the response triggers the callback, verify the returned result.
  615. XCTAssertTrue(Thread.isMainThread)
  616. XCTAssertNil(email)
  617. XCTAssertEqual((error as? NSError)?.code, AuthErrorCode.invalidActionCode.rawValue)
  618. XCTAssertNotNil((error as? NSError)?.userInfo[NSLocalizedDescriptionKey])
  619. expectation.fulfill()
  620. }
  621. waitForExpectations(timeout: 5)
  622. XCTAssertNil(auth?.currentUser)
  623. }
  624. /** @fn testSignInWithEmailLinkCredentialSuccess
  625. @brief Tests the flow of a successfully @c signInWithCredential:completion: call with an
  626. email sign-in link credential using FIREmailAuthProvider.
  627. */
  628. func testSignInWithEmailLinkCredentialSuccess() throws {
  629. let expectation = self.expectation(description: #function)
  630. let fakeCode = "testoobcode"
  631. setFakeGetAccountProvider()
  632. setFakeSecureTokenService()
  633. // 1. Setup respond block to test and fake send request.
  634. rpcIssuer.respondBlock = {
  635. // 2. Validate the created Request instance.
  636. let request = try XCTUnwrap(self.rpcIssuer.request as? EmailLinkSignInRequest)
  637. XCTAssertEqual(request.apiKey, AuthTests.kFakeAPIKey)
  638. XCTAssertEqual(request.oobCode, fakeCode)
  639. XCTAssertEqual(request.email, self.kEmail)
  640. // 3. Send the response from the fake backend.
  641. return try self.rpcIssuer.respond(withJSON: ["idToken": AuthTests.kAccessToken,
  642. "isNewUser": true,
  643. "refreshToken": self.kRefreshToken])
  644. }
  645. try auth?.signOut()
  646. let emailCredential = EmailAuthProvider.credential(
  647. withEmail: kEmail,
  648. link: kFakeEmailSignInLink
  649. )
  650. auth?.signIn(with: emailCredential) { authResult, error in
  651. // 4. After the response triggers the callback, verify the returned result.
  652. XCTAssertTrue(Thread.isMainThread)
  653. guard let user = authResult?.user else {
  654. XCTFail("authResult.user or additionalUserInfo is missing")
  655. return
  656. }
  657. XCTAssertEqual(user.refreshToken, self.kRefreshToken)
  658. XCTAssertFalse(user.isAnonymous)
  659. XCTAssertEqual(user.email, self.kEmail)
  660. XCTAssertNil(error)
  661. expectation.fulfill()
  662. }
  663. waitForExpectations(timeout: 5)
  664. }
  665. /** @fn testSignInWithEmailLinkCredentialFailure
  666. @brief Tests the flow of a failed @c signInWithCredential:completion: call with an
  667. email-email sign-in link credential using FIREmailAuthProvider.
  668. */
  669. func testSignInWithEmailLinkCredentialFailure() throws {
  670. let expectation = self.expectation(description: #function)
  671. // 1. Setup respond block to test and fake send request.
  672. rpcIssuer.respondBlock = {
  673. // 2. Send the response from the fake backend.
  674. try self.rpcIssuer.respond(serverErrorMessage: "USER_DISABLED")
  675. }
  676. try auth?.signOut()
  677. let emailCredential = EmailAuthProvider.credential(
  678. withEmail: kEmail,
  679. link: kFakeEmailSignInLink
  680. )
  681. auth?.signIn(with: emailCredential) { authResult, error in
  682. // 3. After the response triggers the callback, verify the returned result.
  683. XCTAssertTrue(Thread.isMainThread)
  684. XCTAssertNil(authResult)
  685. XCTAssertEqual((error as? NSError)?.code, AuthErrorCode.userDisabled.rawValue)
  686. XCTAssertNotNil((error as? NSError)?.userInfo[NSLocalizedDescriptionKey])
  687. expectation.fulfill()
  688. }
  689. waitForExpectations(timeout: 5)
  690. XCTAssertNil(auth?.currentUser)
  691. }
  692. /** @fn testSignInWithEmailCredentialSuccess
  693. @brief Tests the flow of a successfully @c signInWithCredential:completion: call with an
  694. email-password credential.
  695. */
  696. func testSignInWithEmailCredentialSuccess() throws {
  697. let expectation = self.expectation(description: #function)
  698. setFakeGetAccountProvider()
  699. setFakeSecureTokenService()
  700. // 1. Setup respond block to test and fake send request.
  701. rpcIssuer.respondBlock = {
  702. // 2. Validate the created Request instance.
  703. let request = try XCTUnwrap(self.rpcIssuer.request as? VerifyPasswordRequest)
  704. XCTAssertEqual(request.apiKey, AuthTests.kFakeAPIKey)
  705. XCTAssertEqual(request.password, self.kFakePassword)
  706. XCTAssertEqual(request.email, self.kEmail)
  707. // 3. Send the response from the fake backend.
  708. return try self.rpcIssuer.respond(withJSON: ["idToken": AuthTests.kAccessToken,
  709. "isNewUser": true,
  710. "refreshToken": self.kRefreshToken])
  711. }
  712. try auth?.signOut()
  713. let emailCredential = EmailAuthProvider.credential(withEmail: kEmail, password: kFakePassword)
  714. auth?.signIn(with: emailCredential) { authResult, error in
  715. // 4. After the response triggers the callback, verify the returned result.
  716. XCTAssertTrue(Thread.isMainThread)
  717. guard let user = authResult?.user else {
  718. XCTFail("authResult.user or additionalUserInfo is missing")
  719. return
  720. }
  721. XCTAssertEqual(user.refreshToken, self.kRefreshToken)
  722. XCTAssertFalse(user.isAnonymous)
  723. XCTAssertEqual(user.email, self.kEmail)
  724. XCTAssertNil(error)
  725. expectation.fulfill()
  726. }
  727. waitForExpectations(timeout: 5)
  728. }
  729. /** @fn testSignInWithEmailCredentialFailure
  730. @brief Tests the flow of a failed @c signInWithCredential:completion: call with an
  731. email-password credential.
  732. */
  733. func testSignInWithEmailCredentialFailure() throws {
  734. let expectation = self.expectation(description: #function)
  735. // 1. Setup respond block to test and fake send request.
  736. rpcIssuer.respondBlock = {
  737. // 2. Send the response from the fake backend.
  738. try self.rpcIssuer.respond(serverErrorMessage: "USER_DISABLED")
  739. }
  740. try auth?.signOut()
  741. let emailCredential = EmailAuthProvider.credential(withEmail: kEmail, password: kFakePassword)
  742. auth?.signIn(with: emailCredential) { authResult, error in
  743. // 3. After the response triggers the callback, verify the returned result.
  744. XCTAssertTrue(Thread.isMainThread)
  745. XCTAssertNil(authResult)
  746. XCTAssertEqual((error as? NSError)?.code, AuthErrorCode.userDisabled.rawValue)
  747. XCTAssertNotNil((error as? NSError)?.userInfo[NSLocalizedDescriptionKey])
  748. expectation.fulfill()
  749. }
  750. waitForExpectations(timeout: 5)
  751. XCTAssertNil(auth?.currentUser)
  752. }
  753. /** @fn testSignInWithEmailCredentialEmptyPassword
  754. @brief Tests the flow of a failed @c signInWithCredential:completion: call with an
  755. email-password credential using an empty password. This error occurs on the client side,
  756. so there is no need to fake an RPC response.
  757. */
  758. func testSignInWithEmailCredentialEmptyPassword() throws {
  759. let expectation = self.expectation(description: #function)
  760. let emailCredential = EmailAuthProvider.credential(withEmail: kEmail, password: "")
  761. auth?.signIn(with: emailCredential) { authResult, error in
  762. XCTAssertTrue(Thread.isMainThread)
  763. XCTAssertNil(authResult)
  764. XCTAssertEqual((error as? NSError)?.code, AuthErrorCode.wrongPassword.rawValue)
  765. XCTAssertNotNil((error as? NSError)?.userInfo[NSLocalizedDescriptionKey])
  766. expectation.fulfill()
  767. }
  768. waitForExpectations(timeout: 5)
  769. }
  770. #if os(iOS)
  771. class FakeProvider: NSObject, FederatedAuthProvider {
  772. @available(iOS 13, tvOS 13, macOS 10.15, watchOS 8, *)
  773. func credential(with UIDelegate: FirebaseAuth.AuthUIDelegate?) async throws ->
  774. FirebaseAuth.AuthCredential {
  775. let credential = OAuthCredential(withProviderID: GoogleAuthProvider.id,
  776. sessionID: kOAuthSessionID,
  777. OAuthResponseURLString: kOAuthRequestURI)
  778. XCTAssertEqual(credential.OAuthResponseURLString, kOAuthRequestURI)
  779. XCTAssertEqual(credential.sessionID, kOAuthSessionID)
  780. return credential
  781. }
  782. }
  783. /** @fn testSignInWithProviderSuccess
  784. @brief Tests a successful @c signInWithProvider:UIDelegate:completion: call with an OAuth
  785. provider configured for Google.
  786. */
  787. func testSignInWithProviderSuccess() throws {
  788. let expectation = self.expectation(description: #function)
  789. setFakeGoogleGetAccountProvider()
  790. setFakeSecureTokenService()
  791. // 1. Setup respond block to test and fake send request.
  792. rpcIssuer.respondBlock = {
  793. // 2. Validate the created Request instance.
  794. let request = try XCTUnwrap(self.rpcIssuer.request as? VerifyAssertionRequest)
  795. XCTAssertEqual(request.apiKey, AuthTests.kFakeAPIKey)
  796. XCTAssertEqual(request.providerID, GoogleAuthProvider.id)
  797. XCTAssertTrue(request.returnSecureToken)
  798. // 3. Send the response from the fake backend.
  799. return try self.rpcIssuer.respond(withJSON: ["idToken": RPCBaseTests.kFakeAccessToken,
  800. "refreshToken": self.kRefreshToken,
  801. "federatedId": self.kGoogleID,
  802. "providerId": GoogleAuthProvider.id,
  803. "localId": self.kLocalID,
  804. "displayName": self.kDisplayName,
  805. "rawUserInfo": self.kGoogleProfile,
  806. "username": self.kUserName])
  807. }
  808. try auth.signOut()
  809. auth.signIn(with: FakeProvider(), uiDelegate: nil) { authResult, error in
  810. // 4. After the response triggers the callback, verify the returned result.
  811. XCTAssertTrue(Thread.isMainThread)
  812. do {
  813. try self.assertUserGoogle(authResult?.user)
  814. } catch {
  815. XCTFail("\(error)")
  816. }
  817. XCTAssertNil(error)
  818. expectation.fulfill()
  819. }
  820. waitForExpectations(timeout: 5)
  821. try assertUserGoogle(auth.currentUser)
  822. }
  823. /** @fn testSignInWithProviderFailure
  824. @brief Tests a failed @c signInWithProvider:UIDelegate:completion: call with the error code
  825. FIRAuthErrorCodeWebSignInUserInteractionFailure.
  826. */
  827. func testSignInWithProviderFailure() throws {
  828. let expectation = self.expectation(description: #function)
  829. setFakeGoogleGetAccountProvider()
  830. setFakeSecureTokenService()
  831. // 1. Setup respond block to test and fake send request.
  832. rpcIssuer.respondBlock = {
  833. // 2. Validate the created Request instance.
  834. let request = try XCTUnwrap(self.rpcIssuer.request as? VerifyAssertionRequest)
  835. XCTAssertEqual(request.apiKey, AuthTests.kFakeAPIKey)
  836. XCTAssertEqual(request.providerID, GoogleAuthProvider.id)
  837. XCTAssertTrue(request.returnSecureToken)
  838. // 3. Send the response from the fake backend.
  839. return try self.rpcIssuer.respond(serverErrorMessage: "USER_DISABLED")
  840. }
  841. try auth.signOut()
  842. auth.signIn(with: FakeProvider(), uiDelegate: nil) { authResult, error in
  843. // 4. After the response triggers the callback, verify the returned result.
  844. XCTAssertTrue(Thread.isMainThread)
  845. XCTAssertNil(authResult)
  846. XCTAssertEqual((error as? NSError)?.code, AuthErrorCode.userDisabled.rawValue)
  847. expectation.fulfill()
  848. }
  849. waitForExpectations(timeout: 5)
  850. }
  851. /** @fn testSignInWithGoogleAccountExistsError
  852. @brief Tests the flow of a failed @c signInWithCredential:completion: with a Google credential
  853. where the backend returns a needs @needConfirmation equal to true. An
  854. FIRAuthErrorCodeAccountExistsWithDifferentCredential error should be thrown.
  855. */
  856. func testSignInWithGoogleAccountExistsError() throws {
  857. let expectation = self.expectation(description: #function)
  858. setFakeGoogleGetAccountProvider()
  859. setFakeSecureTokenService()
  860. // 1. Setup respond block to test and fake send request.
  861. rpcIssuer.respondBlock = {
  862. // 2. Validate the created Request instance.
  863. let request = try XCTUnwrap(self.rpcIssuer.request as? VerifyAssertionRequest)
  864. XCTAssertEqual(request.apiKey, AuthTests.kFakeAPIKey)
  865. XCTAssertEqual(request.providerID, GoogleAuthProvider.id)
  866. XCTAssertEqual(request.providerIDToken, self.kGoogleIDToken)
  867. XCTAssertEqual(request.providerAccessToken, self.kGoogleAccessToken)
  868. XCTAssertTrue(request.returnSecureToken)
  869. // 3. Send the response from the fake backend.
  870. return try self.rpcIssuer.respond(withJSON: ["idToken": RPCBaseTests.kFakeAccessToken,
  871. "refreshToken": self.kRefreshToken,
  872. "federatedId": self.kGoogleID,
  873. "providerId": GoogleAuthProvider.id,
  874. "localId": self.kLocalID,
  875. "displayName": self.kGoogleDisplayName,
  876. "rawUserInfo": self.kGoogleProfile,
  877. "username": self.kUserName,
  878. "needConfirmation": true])
  879. }
  880. try auth.signOut()
  881. let googleCredential = GoogleAuthProvider.credential(withIDToken: kGoogleIDToken,
  882. accessToken: kGoogleAccessToken)
  883. auth.signIn(with: googleCredential) { authResult, error in
  884. // 4. After the response triggers the callback, verify the returned result.
  885. XCTAssertTrue(Thread.isMainThread)
  886. XCTAssertNil(authResult)
  887. XCTAssertEqual((error as? NSError)?.code,
  888. AuthErrorCode.accountExistsWithDifferentCredential.rawValue)
  889. expectation.fulfill()
  890. }
  891. waitForExpectations(timeout: 5)
  892. }
  893. /** @fn testSignInWithOAuthCredentialSuccess
  894. @brief Tests the flow of a successful @c signInWithCredential:completion: call with a generic
  895. OAuth credential (In this case, configured for the Google IDP).
  896. */
  897. func testSignInWithOAuthCredentialSuccess() throws {
  898. let expectation = self.expectation(description: #function)
  899. setFakeGoogleGetAccountProvider()
  900. setFakeSecureTokenService()
  901. // 1. Setup respond block to test and fake send request.
  902. rpcIssuer.respondBlock = {
  903. // 2. Validate the created Request instance.
  904. let request = try XCTUnwrap(self.rpcIssuer.request as? VerifyAssertionRequest)
  905. XCTAssertEqual(request.apiKey, AuthTests.kFakeAPIKey)
  906. XCTAssertEqual(request.providerID, GoogleAuthProvider.id)
  907. XCTAssertEqual(request.requestURI, AuthTests.kOAuthRequestURI)
  908. XCTAssertEqual(request.sessionID, AuthTests.kOAuthSessionID)
  909. XCTAssertTrue(request.returnSecureToken)
  910. // 3. Send the response from the fake backend.
  911. return try self.rpcIssuer.respond(withJSON: ["idToken": RPCBaseTests.kFakeAccessToken,
  912. "refreshToken": self.kRefreshToken,
  913. "federatedId": self.kGoogleID,
  914. "providerId": GoogleAuthProvider.id,
  915. "localId": self.kLocalID,
  916. "displayName": self.kGoogleDisplayName,
  917. "rawUserInfo": self.kGoogleProfile,
  918. "username": self.kUserName])
  919. }
  920. try auth.signOut()
  921. auth.signIn(with: FakeProvider(), uiDelegate: nil) { authResult, error in
  922. // 4. After the response triggers the callback, verify the returned result.
  923. do {
  924. try self.assertUserGoogle(authResult?.user)
  925. } catch {
  926. XCTFail("\(error)")
  927. }
  928. XCTAssertNil(error)
  929. expectation.fulfill()
  930. }
  931. waitForExpectations(timeout: 5)
  932. try assertUserGoogle(auth.currentUser)
  933. }
  934. #endif
  935. /** @fn testSignInWithCredentialSuccess
  936. @brief Tests the flow of a successful @c signInWithCredential:completion: call
  937. with a Google Sign-In credential.
  938. Note: also a superset of the former testSignInWithGoogleCredentialSuccess
  939. */
  940. func testSignInWithCredentialSuccess() throws {
  941. let expectation = self.expectation(description: #function)
  942. setFakeGoogleGetAccountProvider()
  943. setFakeSecureTokenService()
  944. // 1. Setup respond block to test and fake send request.
  945. rpcIssuer.respondBlock = {
  946. // 2. Validate the created Request instance.
  947. let request = try XCTUnwrap(self.rpcIssuer.request as? VerifyAssertionRequest)
  948. XCTAssertEqual(request.apiKey, AuthTests.kFakeAPIKey)
  949. XCTAssertEqual(request.providerID, GoogleAuthProvider.id)
  950. XCTAssertEqual(request.providerIDToken, self.kGoogleIDToken)
  951. XCTAssertEqual(request.providerAccessToken, self.kGoogleAccessToken)
  952. XCTAssertTrue(request.returnSecureToken)
  953. // 3. Send the response from the fake backend.
  954. return try self.rpcIssuer.respond(withJSON: ["idToken": RPCBaseTests.kFakeAccessToken,
  955. "refreshToken": self.kRefreshToken,
  956. "federatedId": self.kGoogleID,
  957. "providerId": GoogleAuthProvider.id,
  958. "localId": self.kLocalID,
  959. "displayName": self.kGoogleDisplayName,
  960. "rawUserInfo": self.kGoogleProfile,
  961. "username": self.kGoogleDisplayName])
  962. }
  963. try auth.signOut()
  964. let googleCredential = GoogleAuthProvider.credential(withIDToken: kGoogleIDToken,
  965. accessToken: kGoogleAccessToken)
  966. auth.signIn(with: googleCredential) { authResult, error in
  967. // 4. After the response triggers the callback, verify the returned result.
  968. do {
  969. try self.assertUserGoogle(authResult?.user)
  970. guard let additionalUserInfo = authResult?.additionalUserInfo,
  971. let profile = additionalUserInfo.profile as? [String: String] else {
  972. XCTFail("authResult.additionalUserInfo is missing")
  973. return
  974. }
  975. XCTAssertEqual(profile, self.kGoogleProfile)
  976. XCTAssertEqual(additionalUserInfo.username, self.kGoogleDisplayName)
  977. XCTAssertEqual(additionalUserInfo.providerID, GoogleAuthProvider.id)
  978. } catch {
  979. XCTFail("\(error)")
  980. }
  981. XCTAssertNil(error)
  982. expectation.fulfill()
  983. }
  984. waitForExpectations(timeout: 5)
  985. try assertUserGoogle(auth.currentUser)
  986. }
  987. /** @fn testSignInWithGoogleCredentialFailure
  988. @brief Tests the flow of a failed @c signInWithCredential:completion: call with an
  989. Google Sign-In credential.
  990. */
  991. func testSignInWithGoogleCredentialFailure() throws {
  992. let expectation = self.expectation(description: #function)
  993. setFakeGoogleGetAccountProvider()
  994. setFakeSecureTokenService()
  995. // 1. Setup respond block to test and fake send request.
  996. rpcIssuer.respondBlock = {
  997. // 2. Validate the created Request instance.
  998. let request = try XCTUnwrap(self.rpcIssuer.request as? VerifyAssertionRequest)
  999. XCTAssertEqual(request.apiKey, AuthTests.kFakeAPIKey)
  1000. XCTAssertEqual(request.providerID, GoogleAuthProvider.id)
  1001. XCTAssertTrue(request.returnSecureToken)
  1002. // 3. Send the response from the fake backend.
  1003. return try self.rpcIssuer.respond(serverErrorMessage: "EMAIL_EXISTS")
  1004. }
  1005. try auth.signOut()
  1006. let googleCredential = GoogleAuthProvider.credential(withIDToken: kGoogleIDToken,
  1007. accessToken: kGoogleAccessToken)
  1008. auth.signIn(with: googleCredential) { authResult, error in
  1009. // 4. After the response triggers the callback, verify the returned result.
  1010. XCTAssertTrue(Thread.isMainThread)
  1011. XCTAssertNil(authResult)
  1012. XCTAssertEqual((error as? NSError)?.code, AuthErrorCode.emailAlreadyInUse.rawValue)
  1013. XCTAssertEqual((error as? NSError)?.userInfo[NSLocalizedDescriptionKey] as? String,
  1014. "The email address is already in use by another account.")
  1015. expectation.fulfill()
  1016. }
  1017. waitForExpectations(timeout: 5)
  1018. }
  1019. /** @fn testSignInWithAppleCredentialFullNameInRequest
  1020. @brief Tests the flow of a successful @c signInWithCredential:completion: call
  1021. with an Apple Sign-In credential with a full name. This test differentiates from
  1022. @c testSignInWithCredentialSuccess only in verifying the full name.
  1023. */
  1024. func testSignInWithAppleCredentialFullNameInRequest() throws {
  1025. let expectation = self.expectation(description: #function)
  1026. let kAppleIDToken = "APPLE_ID_TOKEN"
  1027. let kFirst = "First"
  1028. let kLast = "Last"
  1029. var fullName = PersonNameComponents()
  1030. fullName.givenName = kFirst
  1031. fullName.familyName = kLast
  1032. setFakeGoogleGetAccountProvider()
  1033. setFakeSecureTokenService()
  1034. // 1. Setup respond block to test and fake send request.
  1035. rpcIssuer.respondBlock = {
  1036. // 2. Validate the created Request instance.
  1037. let request = try XCTUnwrap(self.rpcIssuer.request as? VerifyAssertionRequest)
  1038. XCTAssertEqual(request.apiKey, AuthTests.kFakeAPIKey)
  1039. XCTAssertEqual(request.providerID, AuthProviderID.apple.rawValue)
  1040. XCTAssertEqual(request.providerIDToken, kAppleIDToken)
  1041. XCTAssertEqual(request.fullName, fullName)
  1042. XCTAssertTrue(request.returnSecureToken)
  1043. // 3. Send the response from the fake backend.
  1044. return try self.rpcIssuer.respond(withJSON: ["idToken": RPCBaseTests.kFakeAccessToken,
  1045. "refreshToken": self.kRefreshToken,
  1046. "federatedId": self.kGoogleID,
  1047. "providerId": AuthProviderID.apple.rawValue,
  1048. "localId": self.kLocalID,
  1049. "displayName": self.kGoogleDisplayName,
  1050. "rawUserInfo": self.kGoogleProfile,
  1051. "firstName": kFirst,
  1052. "lastName": kLast,
  1053. "username": self.kGoogleDisplayName])
  1054. }
  1055. try auth.signOut()
  1056. let appleCredential = OAuthProvider.appleCredential(withIDToken: kAppleIDToken,
  1057. rawNonce: nil,
  1058. fullName: fullName)
  1059. auth.signIn(with: appleCredential) { authResult, error in
  1060. // 4. After the response triggers the callback, verify the returned result.
  1061. do {
  1062. try self.assertUserGoogle(authResult?.user)
  1063. guard let additionalUserInfo = authResult?.additionalUserInfo,
  1064. let profile = additionalUserInfo.profile as? [String: String] else {
  1065. XCTFail("authResult.additionalUserInfo is missing")
  1066. return
  1067. }
  1068. XCTAssertEqual(profile, self.kGoogleProfile)
  1069. XCTAssertEqual(additionalUserInfo.username, self.kGoogleDisplayName)
  1070. XCTAssertEqual(additionalUserInfo.providerID, AuthProviderID.apple.rawValue)
  1071. } catch {
  1072. XCTFail("\(error)")
  1073. }
  1074. XCTAssertNil(error)
  1075. expectation.fulfill()
  1076. }
  1077. waitForExpectations(timeout: 5)
  1078. XCTAssertNotNil(auth.currentUser)
  1079. }
  1080. /** @fn testSignInAnonymouslySuccess
  1081. @brief Tests the flow of a successful @c signInAnonymouslyWithCompletion: call.
  1082. */
  1083. func testSignInAnonymouslySuccess() throws {
  1084. let expectation = self.expectation(description: #function)
  1085. setFakeSecureTokenService()
  1086. setFakeGetAccountProviderAnonymous()
  1087. // 1. Setup respond block to test and fake send request.
  1088. rpcIssuer.respondBlock = {
  1089. // 2. Validate the created Request instance.
  1090. let request = try XCTUnwrap(self.rpcIssuer.request as? SignUpNewUserRequest)
  1091. XCTAssertEqual(request.apiKey, AuthTests.kFakeAPIKey)
  1092. XCTAssertNil(request.email)
  1093. XCTAssertNil(request.password)
  1094. XCTAssertTrue(request.returnSecureToken)
  1095. // 3. Send the response from the fake backend.
  1096. return try self.rpcIssuer.respond(withJSON: ["idToken": AuthTests.kAccessToken,
  1097. "email": self.kEmail,
  1098. "isNewUser": true,
  1099. "refreshToken": self.kRefreshToken])
  1100. }
  1101. try auth?.signOut()
  1102. auth?.signInAnonymously { authResult, error in
  1103. // 4. After the response triggers the callback, verify the returned result.
  1104. XCTAssertNil(error)
  1105. XCTAssertTrue(Thread.isMainThread)
  1106. self.assertUserAnonymous(authResult?.user)
  1107. guard let userInfo = authResult?.additionalUserInfo else {
  1108. XCTFail("authResult.additionalUserInfo is missing")
  1109. return
  1110. }
  1111. XCTAssertTrue(userInfo.isNewUser)
  1112. XCTAssertNil(userInfo.username)
  1113. XCTAssertNil(userInfo.profile)
  1114. XCTAssertEqual(userInfo.providerID, "")
  1115. expectation.fulfill()
  1116. }
  1117. waitForExpectations(timeout: 5)
  1118. try assertUserAnonymous(XCTUnwrap(auth?.currentUser))
  1119. }
  1120. /** @fn testSignInAnonymouslyFailure
  1121. @brief Tests the flow of a failed @c signInAnonymouslyWithCompletion: call.
  1122. */
  1123. func testSignInAnonymouslyFailure() throws {
  1124. let expectation = self.expectation(description: #function)
  1125. rpcIssuer.respondBlock = {
  1126. try self.rpcIssuer.respond(serverErrorMessage: "OPERATION_NOT_ALLOWED")
  1127. }
  1128. try auth?.signOut()
  1129. auth?.verifyPasswordResetCode(kFakeOobCode) { email, error in
  1130. XCTAssertTrue(Thread.isMainThread)
  1131. XCTAssertNil(email)
  1132. XCTAssertEqual((error as? NSError)?.code, AuthErrorCode.operationNotAllowed.rawValue)
  1133. XCTAssertNotNil((error as? NSError)?.userInfo[NSLocalizedDescriptionKey])
  1134. expectation.fulfill()
  1135. }
  1136. waitForExpectations(timeout: 5)
  1137. XCTAssertNil(auth?.currentUser)
  1138. }
  1139. /** @fn testSignInWithCustomTokenSuccess
  1140. @brief Tests the flow of a successful @c signInWithCustomToken:completion: call.
  1141. */
  1142. func testSignInWithCustomTokenSuccess() throws {
  1143. let expectation = self.expectation(description: #function)
  1144. setFakeSecureTokenService()
  1145. setFakeGetAccountProvider()
  1146. // 1. Setup respond block to test and fake send request.
  1147. rpcIssuer.respondBlock = {
  1148. // 2. Validate the created Request instance.
  1149. let request = try XCTUnwrap(self.rpcIssuer.request as? VerifyCustomTokenRequest)
  1150. XCTAssertEqual(request.apiKey, AuthTests.kFakeAPIKey)
  1151. XCTAssertEqual(request.token, self.kCustomToken)
  1152. XCTAssertTrue(request.returnSecureToken)
  1153. // 3. Send the response from the fake backend.
  1154. return try self.rpcIssuer.respond(withJSON: ["idToken": AuthTests.kAccessToken,
  1155. "email": self.kEmail,
  1156. "isNewUser": false,
  1157. "refreshToken": self.kRefreshToken])
  1158. }
  1159. try auth?.signOut()
  1160. auth?.signIn(withCustomToken: kCustomToken) { authResult, error in
  1161. // 4. After the response triggers the callback, verify the returned result.
  1162. XCTAssertTrue(Thread.isMainThread)
  1163. self.assertUser(authResult?.user)
  1164. guard let userInfo = authResult?.additionalUserInfo else {
  1165. XCTFail("authResult.additionalUserInfo is missing")
  1166. return
  1167. }
  1168. XCTAssertFalse(userInfo.isNewUser)
  1169. XCTAssertNil(userInfo.username)
  1170. XCTAssertNil(userInfo.profile)
  1171. XCTAssertEqual(userInfo.providerID, "")
  1172. XCTAssertNil(error)
  1173. expectation.fulfill()
  1174. }
  1175. waitForExpectations(timeout: 5)
  1176. assertUser(auth?.currentUser)
  1177. }
  1178. /** @fn testSignInWithCustomTokenFailure
  1179. @brief Tests the flow of a failed @c signInWithCustomToken:completion: call.
  1180. */
  1181. func testSignInWithCustomTokenFailure() throws {
  1182. let expectation = self.expectation(description: #function)
  1183. rpcIssuer.respondBlock = {
  1184. try self.rpcIssuer.respond(serverErrorMessage: "INVALID_CUSTOM_TOKEN")
  1185. }
  1186. try auth?.signOut()
  1187. auth?.signIn(withCustomToken: kCustomToken) { authResult, error in
  1188. XCTAssertTrue(Thread.isMainThread)
  1189. XCTAssertNil(authResult?.user)
  1190. XCTAssertEqual((error as? NSError)?.code, AuthErrorCode.invalidCustomToken.rawValue)
  1191. XCTAssertNotNil((error as? NSError)?.userInfo[NSLocalizedDescriptionKey])
  1192. expectation.fulfill()
  1193. }
  1194. waitForExpectations(timeout: 5)
  1195. XCTAssertNil(auth?.currentUser)
  1196. }
  1197. #if os(iOS)
  1198. /** @fn testCreateUserWithEmailPasswordWithRecaptchaVerificationSuccess
  1199. @brief Tests the flow of a successful @c createUserWithEmail:password:completion: call.
  1200. */
  1201. func testCreateUserWithEmailPasswordWithRecaptchaVerificationSuccess() throws {
  1202. let expectation = self.expectation(description: #function)
  1203. let kTestRecaptchaKey = "projects/123/keys/456"
  1204. rpcIssuer.recaptchaSiteKey = kTestRecaptchaKey
  1205. setFakeSecureTokenService()
  1206. setFakeGetAccountProvider()
  1207. // 1. Setup respond block to test and fake send request.
  1208. rpcIssuer.respondBlock = {
  1209. // 2. Validate the created Request instance.
  1210. let request = try XCTUnwrap(self.rpcIssuer.request as? SignUpNewUserRequest)
  1211. XCTAssertEqual(request.apiKey, AuthTests.kFakeAPIKey)
  1212. XCTAssertEqual(request.email, self.kEmail)
  1213. XCTAssertEqual(request.password, self.kFakePassword)
  1214. XCTAssertTrue(request.returnSecureToken)
  1215. request.injectRecaptchaFields(recaptchaResponse: AuthTests.kFakeRecaptchaResponse,
  1216. recaptchaVersion: AuthTests.kFakeRecaptchaVersion)
  1217. // 3. Send the response from the fake backend.
  1218. return try self.rpcIssuer.respond(withJSON: ["idToken": AuthTests.kAccessToken,
  1219. "email": self.kEmail,
  1220. "isNewUser": true,
  1221. "refreshToken": self.kRefreshToken])
  1222. }
  1223. try auth?.signOut()
  1224. auth?.createUser(withEmail: kEmail, password: kFakePassword) { authResult, error in
  1225. // 4. After the response triggers the callback, verify the returned result.
  1226. XCTAssertTrue(Thread.isMainThread)
  1227. self.assertUser(authResult?.user)
  1228. guard let userInfo = authResult?.additionalUserInfo else {
  1229. XCTFail("authResult.additionalUserInfo is missing")
  1230. return
  1231. }
  1232. XCTAssertTrue(userInfo.isNewUser)
  1233. XCTAssertNil(userInfo.username)
  1234. XCTAssertNil(userInfo.profile)
  1235. XCTAssertEqual(userInfo.providerID, EmailAuthProvider.id)
  1236. XCTAssertNil(error)
  1237. expectation.fulfill()
  1238. }
  1239. waitForExpectations(timeout: 5)
  1240. assertUser(auth?.currentUser)
  1241. }
  1242. /** @fn testCreateUserWithEmailPasswordWithRecaptchaVerificationFallbackSuccess
  1243. @brief Tests the flow of a successful @c createUserWithEmail:password:completion: call.
  1244. */
  1245. func testCreateUserWithEmailPasswordWithRecaptchaVerificationFallbackSuccess() throws {
  1246. let expectation = self.expectation(description: #function)
  1247. let kTestRecaptchaKey = "projects/123/keys/456"
  1248. rpcIssuer.recaptchaSiteKey = kTestRecaptchaKey
  1249. setFakeSecureTokenService()
  1250. setFakeGetAccountProvider()
  1251. // 1. Setup respond block to test and fake send request.
  1252. rpcIssuer.respondBlock = {
  1253. // 2. Validate the created Request instance.
  1254. let request = try XCTUnwrap(self.rpcIssuer.request as? SignUpNewUserRequest)
  1255. XCTAssertEqual(request.apiKey, AuthTests.kFakeAPIKey)
  1256. XCTAssertEqual(request.email, self.kEmail)
  1257. XCTAssertEqual(request.password, self.kFakePassword)
  1258. XCTAssertTrue(request.returnSecureToken)
  1259. request.injectRecaptchaFields(recaptchaResponse: AuthTests.kFakeRecaptchaResponse,
  1260. recaptchaVersion: AuthTests.kFakeRecaptchaVersion)
  1261. // 3. Send the response from the fake backend.
  1262. return try self.rpcIssuer.respond(serverErrorMessage: "MISSING_RECAPTCHA_TOKEN")
  1263. }
  1264. rpcIssuer.nextRespondBlock = {
  1265. // 4. Validate again the created Request instance after the recaptcha retry.
  1266. let request = try XCTUnwrap(self.rpcIssuer.request as? SignUpNewUserRequest)
  1267. XCTAssertEqual(request.email, self.kEmail)
  1268. XCTAssertEqual(request.password, self.kFakePassword)
  1269. XCTAssertEqual(request.apiKey, AuthTests.kFakeAPIKey)
  1270. XCTAssertTrue(request.returnSecureToken)
  1271. request.injectRecaptchaFields(recaptchaResponse: AuthTests.kFakeRecaptchaResponse,
  1272. recaptchaVersion: AuthTests.kFakeRecaptchaVersion)
  1273. // 5. Send the response from the fake backend.
  1274. return try self.rpcIssuer.respond(withJSON: ["idToken": AuthTests.kAccessToken,
  1275. "email": self.kEmail,
  1276. "isNewUser": true,
  1277. "refreshToken": self.kRefreshToken])
  1278. }
  1279. try auth?.signOut()
  1280. auth?.createUser(withEmail: kEmail, password: kFakePassword) { authResult, error in
  1281. // 4. After the response triggers the callback, verify the returned result.
  1282. XCTAssertTrue(Thread.isMainThread)
  1283. self.assertUser(authResult?.user)
  1284. guard let userInfo = authResult?.additionalUserInfo else {
  1285. XCTFail("authResult.additionalUserInfo is missing")
  1286. return
  1287. }
  1288. XCTAssertTrue(userInfo.isNewUser)
  1289. XCTAssertNil(userInfo.username)
  1290. XCTAssertNil(userInfo.profile)
  1291. XCTAssertEqual(userInfo.providerID, EmailAuthProvider.id)
  1292. XCTAssertNil(error)
  1293. expectation.fulfill()
  1294. }
  1295. waitForExpectations(timeout: 5)
  1296. assertUser(auth?.currentUser)
  1297. }
  1298. #endif
  1299. /** @fn testCreateUserWithEmailPasswordSuccess
  1300. @brief Tests the flow of a successful @c createUserWithEmail:password:completion: call.
  1301. */
  1302. func testCreateUserWithEmailPasswordSuccess() throws {
  1303. let expectation = self.expectation(description: #function)
  1304. setFakeSecureTokenService()
  1305. setFakeGetAccountProvider()
  1306. // 1. Setup respond block to test and fake send request.
  1307. rpcIssuer.respondBlock = {
  1308. // 2. Validate the created Request instance.
  1309. let request = try XCTUnwrap(self.rpcIssuer.request as? SignUpNewUserRequest)
  1310. XCTAssertEqual(request.apiKey, AuthTests.kFakeAPIKey)
  1311. XCTAssertEqual(request.email, self.kEmail)
  1312. XCTAssertEqual(request.password, self.kFakePassword)
  1313. XCTAssertTrue(request.returnSecureToken)
  1314. // 3. Send the response from the fake backend.
  1315. return try self.rpcIssuer.respond(withJSON: ["idToken": AuthTests.kAccessToken,
  1316. "email": self.kEmail,
  1317. "isNewUser": true,
  1318. "refreshToken": self.kRefreshToken])
  1319. }
  1320. try auth?.signOut()
  1321. auth?.createUser(withEmail: kEmail, password: kFakePassword) { authResult, error in
  1322. // 4. After the response triggers the callback, verify the returned result.
  1323. XCTAssertTrue(Thread.isMainThread)
  1324. self.assertUser(authResult?.user)
  1325. guard let userInfo = authResult?.additionalUserInfo else {
  1326. XCTFail("authResult.additionalUserInfo is missing")
  1327. return
  1328. }
  1329. XCTAssertTrue(userInfo.isNewUser)
  1330. XCTAssertNil(userInfo.username)
  1331. XCTAssertNil(userInfo.profile)
  1332. XCTAssertEqual(userInfo.providerID, EmailAuthProvider.id)
  1333. XCTAssertNil(error)
  1334. expectation.fulfill()
  1335. }
  1336. waitForExpectations(timeout: 5)
  1337. assertUser(auth?.currentUser)
  1338. }
  1339. /** @fn testCreateUserWithEmailPasswordFailure
  1340. @brief Tests the flow of a failed @c createUserWithEmail:password:completion: call.
  1341. */
  1342. func testCreateUserWithEmailPasswordFailure() throws {
  1343. let expectation = self.expectation(description: #function)
  1344. let reason = "The password must be 6 characters long or more."
  1345. rpcIssuer.respondBlock = {
  1346. try self.rpcIssuer.respond(serverErrorMessage: "WEAK_PASSWORD")
  1347. }
  1348. try auth?.signOut()
  1349. auth?.createUser(withEmail: kEmail, password: kFakePassword) { authResult, error in
  1350. XCTAssertTrue(Thread.isMainThread)
  1351. XCTAssertNil(authResult?.user)
  1352. XCTAssertEqual((error as? NSError)?.code, AuthErrorCode.weakPassword.rawValue)
  1353. XCTAssertEqual((error as? NSError)?.userInfo[NSLocalizedDescriptionKey] as? String, reason)
  1354. expectation.fulfill()
  1355. }
  1356. waitForExpectations(timeout: 5)
  1357. XCTAssertNil(auth?.currentUser)
  1358. }
  1359. /** @fn testCreateUserEmptyPasswordFailure
  1360. @brief Tests the flow of a failed @c createUserWithEmail:password:completion: call due to an
  1361. empty password. This error occurs on the client side, so there is no need to fake an RPC
  1362. response.
  1363. */
  1364. func testCreateUserEmptyPasswordFailure() throws {
  1365. let expectation = self.expectation(description: #function)
  1366. try auth?.signOut()
  1367. auth?.createUser(withEmail: kEmail, password: "") { authResult, error in
  1368. XCTAssertTrue(Thread.isMainThread)
  1369. XCTAssertNil(authResult?.user)
  1370. XCTAssertEqual((error as? NSError)?.code, AuthErrorCode.weakPassword.rawValue)
  1371. expectation.fulfill()
  1372. }
  1373. waitForExpectations(timeout: 5)
  1374. }
  1375. /** @fn testCreateUserEmptyEmailFailure
  1376. @brief Tests the flow of a failed @c createUserWithEmail:password:completion: call due to an
  1377. empty email address. This error occurs on the client side, so there is no need to fake an
  1378. RPC response.
  1379. */
  1380. func testCreateUserEmptyEmailFailure() throws {
  1381. let expectation = self.expectation(description: #function)
  1382. try auth?.signOut()
  1383. auth?.createUser(withEmail: "", password: kFakePassword) { authResult, error in
  1384. XCTAssertTrue(Thread.isMainThread)
  1385. XCTAssertNil(authResult?.user)
  1386. XCTAssertEqual((error as? NSError)?.code, AuthErrorCode.missingEmail.rawValue)
  1387. expectation.fulfill()
  1388. }
  1389. waitForExpectations(timeout: 5)
  1390. }
  1391. #if os(iOS)
  1392. /** @fn testSendPasswordResetEmailWithRecaptchaSuccess
  1393. @brief Tests the flow of a successful @c sendPasswordResetWithEmail:completion: call.
  1394. */
  1395. func testSendPasswordResetEmailWithRecaptchaSuccess() throws {
  1396. let expectation = self.expectation(description: #function)
  1397. let kTestRecaptchaKey = "projects/123/keys/456"
  1398. rpcIssuer.recaptchaSiteKey = kTestRecaptchaKey
  1399. // 1. Setup respond block to test and fake send request.
  1400. rpcIssuer.respondBlock = {
  1401. // 2. Validate the created Request instance.
  1402. let request = try XCTUnwrap(self.rpcIssuer.request as? GetOOBConfirmationCodeRequest)
  1403. XCTAssertEqual(request.email, self.kEmail)
  1404. XCTAssertEqual(request.apiKey, AuthTests.kFakeAPIKey)
  1405. request.injectRecaptchaFields(recaptchaResponse: AuthTests.kFakeRecaptchaResponse,
  1406. recaptchaVersion: AuthTests.kFakeRecaptchaVersion)
  1407. // 3. Send the response from the fake backend.
  1408. return try self.rpcIssuer.respond(withJSON: [:])
  1409. }
  1410. auth?.sendPasswordReset(withEmail: kEmail) { error in
  1411. // 4. After the response triggers the callback, verify success.
  1412. XCTAssertTrue(Thread.isMainThread)
  1413. XCTAssertNil(error)
  1414. expectation.fulfill()
  1415. }
  1416. waitForExpectations(timeout: 5)
  1417. }
  1418. /** @fn testSendPasswordResetEmailWithRecaptchaFallbackSuccess
  1419. @brief Tests the flow of a successful @c sendPasswordResetWithEmail:completion: call.
  1420. */
  1421. func testSendPasswordResetEmailWithRecaptchaFallbackSuccess() throws {
  1422. let expectation = self.expectation(description: #function)
  1423. let kTestRecaptchaKey = "projects/123/keys/456"
  1424. rpcIssuer.recaptchaSiteKey = kTestRecaptchaKey
  1425. // 1. Setup respond block to test and fake send request.
  1426. rpcIssuer.respondBlock = {
  1427. // 2. Validate the created Request instance.
  1428. let request = try XCTUnwrap(self.rpcIssuer.request as? GetOOBConfirmationCodeRequest)
  1429. XCTAssertEqual(request.email, self.kEmail)
  1430. XCTAssertEqual(request.apiKey, AuthTests.kFakeAPIKey)
  1431. request.injectRecaptchaFields(recaptchaResponse: AuthTests.kFakeRecaptchaResponse,
  1432. recaptchaVersion: AuthTests.kFakeRecaptchaVersion)
  1433. // 3. Send the response from the fake backend.
  1434. return try self.rpcIssuer.respond(serverErrorMessage: "MISSING_RECAPTCHA_TOKEN")
  1435. }
  1436. rpcIssuer.nextRespondBlock = {
  1437. // 4. Validate again the created Request instance after the recaptcha retry.
  1438. let request = try XCTUnwrap(self.rpcIssuer.request as? GetOOBConfirmationCodeRequest)
  1439. XCTAssertEqual(request.email, self.kEmail)
  1440. XCTAssertEqual(request.apiKey, AuthTests.kFakeAPIKey)
  1441. request.injectRecaptchaFields(recaptchaResponse: AuthTests.kFakeRecaptchaResponse,
  1442. recaptchaVersion: AuthTests.kFakeRecaptchaVersion)
  1443. // 5. Send the response from the fake backend.
  1444. return try self.rpcIssuer.respond(withJSON: ["idToken": AuthTests.kAccessToken,
  1445. "email": self.kEmail,
  1446. "isNewUser": true,
  1447. "refreshToken": self.kRefreshToken])
  1448. }
  1449. auth?.sendPasswordReset(withEmail: kEmail) { error in
  1450. // 4. After the response triggers the callback, verify success.
  1451. XCTAssertTrue(Thread.isMainThread)
  1452. XCTAssertNil(error)
  1453. expectation.fulfill()
  1454. }
  1455. waitForExpectations(timeout: 5)
  1456. }
  1457. #endif
  1458. /** @fn testSendPasswordResetEmailSuccess
  1459. @brief Tests the flow of a successful @c sendPasswordReset call.
  1460. */
  1461. func testSendPasswordResetEmailSuccess() throws {
  1462. let expectation = self.expectation(description: #function)
  1463. // 1. Setup respond block to test and fake send request.
  1464. rpcIssuer.respondBlock = {
  1465. // 2. Validate the created Request instance.
  1466. let request = try XCTUnwrap(self.rpcIssuer.request as? GetOOBConfirmationCodeRequest)
  1467. XCTAssertEqual(request.email, self.kEmail)
  1468. XCTAssertEqual(request.apiKey, AuthTests.kFakeAPIKey)
  1469. // 3. Send the response from the fake backend.
  1470. return try self.rpcIssuer.respond(withJSON: [:])
  1471. }
  1472. auth?.sendPasswordReset(withEmail: kEmail) { error in
  1473. // 4. After the response triggers the callback, verify success.
  1474. XCTAssertTrue(Thread.isMainThread)
  1475. XCTAssertNil(error)
  1476. expectation.fulfill()
  1477. }
  1478. waitForExpectations(timeout: 5)
  1479. }
  1480. /** @fn testSendPasswordResetEmailFailure
  1481. @brief Tests the flow of a failed @c sendPasswordReset call.
  1482. */
  1483. func testSendPasswordResetEmailFailure() throws {
  1484. let expectation = self.expectation(description: #function)
  1485. rpcIssuer.respondBlock = {
  1486. try self.rpcIssuer.respond(underlyingErrorMessage: "ipRefererBlocked")
  1487. }
  1488. auth?.sendPasswordReset(withEmail: kEmail) { error in
  1489. XCTAssertTrue(Thread.isMainThread)
  1490. let rpcError = (error as? NSError)!
  1491. XCTAssertEqual(rpcError.code, AuthErrorCode.appNotAuthorized.rawValue)
  1492. XCTAssertNotNil(rpcError.userInfo[NSLocalizedDescriptionKey])
  1493. expectation.fulfill()
  1494. }
  1495. waitForExpectations(timeout: 5)
  1496. }
  1497. #if os(iOS)
  1498. /** @fn testSendSignInLinkToEmailWithRecaptchaSuccess
  1499. @brief Tests the flow of a successful @c sendSignInLinkToEmail:actionCodeSettings: call.
  1500. */
  1501. func testSendSignInLinkToEmailWithRecaptchaSuccess() throws {
  1502. let expectation = self.expectation(description: #function)
  1503. let kTestRecaptchaKey = "projects/123/keys/456"
  1504. rpcIssuer.recaptchaSiteKey = kTestRecaptchaKey
  1505. // 1. Setup respond block to test and fake send request.
  1506. rpcIssuer.respondBlock = {
  1507. // 2. Validate the created Request instance.
  1508. let request = try XCTUnwrap(self.rpcIssuer.request as? GetOOBConfirmationCodeRequest)
  1509. XCTAssertEqual(request.email, self.kEmail)
  1510. XCTAssertEqual(request.apiKey, AuthTests.kFakeAPIKey)
  1511. XCTAssertEqual(request.continueURL, self.kContinueURL)
  1512. XCTAssertTrue(request.handleCodeInApp)
  1513. request.injectRecaptchaFields(recaptchaResponse: AuthTests.kFakeRecaptchaResponse,
  1514. recaptchaVersion: AuthTests.kFakeRecaptchaVersion)
  1515. // 3. Send the response from the fake backend.
  1516. return try self.rpcIssuer.respond(withJSON: [:])
  1517. }
  1518. auth?.sendSignInLink(toEmail: kEmail,
  1519. actionCodeSettings: fakeActionCodeSettings()) { error in
  1520. // 4. After the response triggers the callback, verify success.
  1521. XCTAssertTrue(Thread.isMainThread)
  1522. XCTAssertNil(error)
  1523. expectation.fulfill()
  1524. }
  1525. waitForExpectations(timeout: 5)
  1526. }
  1527. /** @fn testSendSignInLinkToEmailWithRecaptchaFallbackSuccess
  1528. @brief Tests the flow of a successful @c sendSignInLinkToEmail:actionCodeSettings: call.
  1529. */
  1530. func testSendSignInLinkToEmailWithRecaptchaFallbackSuccess() throws {
  1531. let expectation = self.expectation(description: #function)
  1532. let kTestRecaptchaKey = "projects/123/keys/456"
  1533. rpcIssuer.recaptchaSiteKey = kTestRecaptchaKey
  1534. // 1. Setup respond block to test and fake send request.
  1535. rpcIssuer.respondBlock = {
  1536. // 2. Validate the created Request instance.
  1537. let request = try XCTUnwrap(self.rpcIssuer.request as? GetOOBConfirmationCodeRequest)
  1538. XCTAssertEqual(request.email, self.kEmail)
  1539. XCTAssertEqual(request.apiKey, AuthTests.kFakeAPIKey)
  1540. XCTAssertEqual(request.continueURL, self.kContinueURL)
  1541. XCTAssertTrue(request.handleCodeInApp)
  1542. request.injectRecaptchaFields(recaptchaResponse: AuthTests.kFakeRecaptchaResponse,
  1543. recaptchaVersion: AuthTests.kFakeRecaptchaVersion)
  1544. // 3. Send the response from the fake backend.
  1545. return try self.rpcIssuer.respond(withJSON: [:])
  1546. }
  1547. rpcIssuer.nextRespondBlock = {
  1548. // 4. Validate again the created Request instance after the recaptcha retry.
  1549. let request = try XCTUnwrap(self.rpcIssuer.request as? GetOOBConfirmationCodeRequest)
  1550. XCTAssertEqual(request.email, self.kEmail)
  1551. XCTAssertEqual(request.apiKey, AuthTests.kFakeAPIKey)
  1552. request.injectRecaptchaFields(recaptchaResponse: AuthTests.kFakeRecaptchaResponse,
  1553. recaptchaVersion: AuthTests.kFakeRecaptchaVersion)
  1554. // 5. Send the response from the fake backend.
  1555. return try self.rpcIssuer.respond(withJSON: ["idToken": AuthTests.kAccessToken,
  1556. "email": self.kEmail,
  1557. "isNewUser": true,
  1558. "refreshToken": self.kRefreshToken])
  1559. }
  1560. auth?.sendSignInLink(toEmail: kEmail,
  1561. actionCodeSettings: fakeActionCodeSettings()) { error in
  1562. // 4. After the response triggers the callback, verify success.
  1563. XCTAssertTrue(Thread.isMainThread)
  1564. XCTAssertNil(error)
  1565. expectation.fulfill()
  1566. }
  1567. waitForExpectations(timeout: 5)
  1568. }
  1569. #endif
  1570. /** @fn testSendSignInLinkToEmailSuccess
  1571. @brief Tests the flow of a successful @c sendSignInLinkToEmail call.
  1572. */
  1573. func testSendSignInLinkToEmailSuccess() throws {
  1574. let expectation = self.expectation(description: #function)
  1575. // 1. Setup respond block to test and fake send request.
  1576. rpcIssuer.respondBlock = {
  1577. // 2. Validate the created Request instance.
  1578. let request = try XCTUnwrap(self.rpcIssuer.request as? GetOOBConfirmationCodeRequest)
  1579. XCTAssertEqual(request.email, self.kEmail)
  1580. XCTAssertEqual(request.apiKey, AuthTests.kFakeAPIKey)
  1581. XCTAssertEqual(request.continueURL, self.kContinueURL)
  1582. XCTAssertTrue(request.handleCodeInApp)
  1583. // 3. Send the response from the fake backend.
  1584. return try self.rpcIssuer.respond(withJSON: [:])
  1585. }
  1586. auth?.sendSignInLink(toEmail: kEmail,
  1587. actionCodeSettings: fakeActionCodeSettings()) { error in
  1588. // 4. After the response triggers the callback, verify success.
  1589. XCTAssertTrue(Thread.isMainThread)
  1590. XCTAssertNil(error)
  1591. expectation.fulfill()
  1592. }
  1593. waitForExpectations(timeout: 5)
  1594. }
  1595. /** @fn testSendSignInLinkToEmailFailure
  1596. @brief Tests the flow of a failed @c sendSignInLink call.
  1597. */
  1598. func testSendSignInLinkToEmailFailure() throws {
  1599. let expectation = self.expectation(description: #function)
  1600. rpcIssuer.respondBlock = {
  1601. try self.rpcIssuer.respond(underlyingErrorMessage: "ipRefererBlocked")
  1602. }
  1603. auth?.sendSignInLink(toEmail: kEmail,
  1604. actionCodeSettings: fakeActionCodeSettings()) { error in
  1605. XCTAssertTrue(Thread.isMainThread)
  1606. let rpcError = error as? NSError
  1607. XCTAssertEqual(rpcError?.code, AuthErrorCode.appNotAuthorized.rawValue)
  1608. XCTAssertNotNil(rpcError?.userInfo[NSLocalizedDescriptionKey])
  1609. expectation.fulfill()
  1610. }
  1611. waitForExpectations(timeout: 5)
  1612. }
  1613. /** @fn testUpdateCurrentUserFailure
  1614. @brief Tests the flow of a failed @c updateCurrentUser:completion:
  1615. call.
  1616. */
  1617. func testUpdateCurrentUserFailure() throws {
  1618. try waitForSignInWithAccessToken()
  1619. let expectation = self.expectation(description: #function)
  1620. let kTestAPIKey2 = "fakeAPIKey2"
  1621. let auth = try XCTUnwrap(auth)
  1622. let user2 = auth.currentUser
  1623. user2?.requestConfiguration = AuthRequestConfiguration(apiKey: kTestAPIKey2,
  1624. appID: kTestFirebaseAppID)
  1625. rpcIssuer.respondBlock = {
  1626. try self.rpcIssuer.respond(underlyingErrorMessage: "keyInvalid")
  1627. }
  1628. // Clear fake so we can inject error
  1629. rpcIssuer.fakeGetAccountProviderJSON = nil
  1630. auth.updateCurrentUser(user2) { error in
  1631. XCTAssertEqual((error as? NSError)?.code, AuthErrorCode.invalidAPIKey.rawValue)
  1632. expectation.fulfill()
  1633. }
  1634. waitForExpectations(timeout: 5)
  1635. }
  1636. /** @fn testUpdateCurrentUserFailureNetworkError
  1637. @brief Tests the flow of a failed @c updateCurrentUser:completion:
  1638. call with a network error.
  1639. */
  1640. func testUpdateCurrentUserFailureNetworkError() throws {
  1641. try waitForSignInWithAccessToken()
  1642. let expectation = self.expectation(description: #function)
  1643. let kTestAPIKey2 = "fakeAPIKey2"
  1644. let auth = try XCTUnwrap(auth)
  1645. let user2 = auth.currentUser
  1646. user2?.requestConfiguration = AuthRequestConfiguration(apiKey: kTestAPIKey2,
  1647. appID: kTestFirebaseAppID)
  1648. rpcIssuer.respondBlock = {
  1649. let kFakeErrorDomain = "fakeDomain"
  1650. let kFakeErrorCode = -1
  1651. let responseError = NSError(domain: kFakeErrorDomain, code: kFakeErrorCode)
  1652. return (nil, responseError)
  1653. }
  1654. // Clear fake so we can inject error
  1655. rpcIssuer.fakeGetAccountProviderJSON = nil
  1656. auth.updateCurrentUser(user2) { error in
  1657. XCTAssertEqual((error as? NSError)?.code, AuthErrorCode.networkError.rawValue)
  1658. expectation.fulfill()
  1659. }
  1660. waitForExpectations(timeout: 5)
  1661. }
  1662. /** @fn testUpdateCurrentUserFailureNullUser
  1663. @brief Tests the flow of a failed @c updateCurrentUser:completion:
  1664. call with FIRAuthErrorCodeNullUser.
  1665. */
  1666. func testUpdateCurrentUserFailureNullUser() throws {
  1667. try waitForSignInWithAccessToken()
  1668. let expectation = self.expectation(description: #function)
  1669. auth.updateCurrentUser(nil) { error in
  1670. XCTAssertEqual((error as? NSError)?.code, AuthErrorCode.nullUser.rawValue)
  1671. expectation.fulfill()
  1672. }
  1673. waitForExpectations(timeout: 5)
  1674. }
  1675. /** @fn testUpdateCurrentUserFailureTenantIDMismatch
  1676. @brief Tests the flow of a failed @c updateCurrentUser:completion:
  1677. call with FIRAuthErrorCodeTenantIDMismatch.
  1678. */
  1679. func testUpdateCurrentUserFailureTenantIDMismatch() throws {
  1680. // User without tenant id
  1681. try waitForSignInWithAccessToken()
  1682. let auth = try XCTUnwrap(auth)
  1683. let user1 = auth.currentUser
  1684. try auth.signOut()
  1685. // User with tenant id "tenant-id"
  1686. auth.tenantID = "tenant-id-1"
  1687. let kTestAccessToken2 = "fakeAccessToken2"
  1688. try waitForSignInWithAccessToken(fakeAccessToken: kTestAccessToken2)
  1689. let user2 = auth.currentUser
  1690. try auth.signOut()
  1691. auth.tenantID = "tenant-id-2"
  1692. let expectation = self.expectation(description: #function)
  1693. auth.updateCurrentUser(user1) { error in
  1694. XCTAssertEqual((error as? NSError)?.code, AuthErrorCode.tenantIDMismatch.rawValue)
  1695. expectation.fulfill()
  1696. }
  1697. try auth.signOut()
  1698. auth.tenantID = "tenant-id-2"
  1699. let expectation2 = self.expectation(description: "tenant-id-test2")
  1700. auth.updateCurrentUser(user2) { error in
  1701. XCTAssertEqual((error as? NSError)?.code, AuthErrorCode.tenantIDMismatch.rawValue)
  1702. expectation2.fulfill()
  1703. }
  1704. try auth.signOut()
  1705. auth.tenantID = nil
  1706. let expectation3 = self.expectation(description: "tenant-id-test3")
  1707. auth.updateCurrentUser(user2) { error in
  1708. XCTAssertEqual((error as? NSError)?.code, AuthErrorCode.tenantIDMismatch.rawValue)
  1709. expectation3.fulfill()
  1710. }
  1711. waitForExpectations(timeout: 5)
  1712. }
  1713. /** @fn testUpdateCurrentUserSuccess
  1714. @brief Tests the flow of a successful @c updateCurrentUser:completion:
  1715. call with a network error.
  1716. */
  1717. func testUpdateCurrentUserSuccess() throws {
  1718. // Sign in with the first user.
  1719. try waitForSignInWithAccessToken()
  1720. let auth = try XCTUnwrap(auth)
  1721. let user1 = auth.currentUser
  1722. let kTestAPIKey = "fakeAPIKey"
  1723. user1?.requestConfiguration = AuthRequestConfiguration(apiKey: kTestAPIKey,
  1724. appID: kTestFirebaseAppID)
  1725. try auth.signOut()
  1726. let kTestAccessToken2 = "fakeAccessToken2"
  1727. try waitForSignInWithAccessToken(fakeAccessToken: kTestAccessToken2)
  1728. let user2 = auth.currentUser
  1729. let expectation = self.expectation(description: #function)
  1730. // Current user should now be user2.
  1731. XCTAssertEqual(auth.currentUser, user2)
  1732. auth.updateCurrentUser(user1) { error in
  1733. XCTAssertNil(error)
  1734. // Current user should now be user1.
  1735. XCTAssertEqual(auth.currentUser, user1)
  1736. XCTAssertNotEqual(auth.currentUser, user2)
  1737. expectation.fulfill()
  1738. }
  1739. waitForExpectations(timeout: 5)
  1740. }
  1741. /** @fn testRevokeTokenSuccess
  1742. @brief Tests the flow of a successful @c revokeToken:completion.
  1743. */
  1744. func testRevokeTokenSuccess() throws {
  1745. try waitForSignInWithAccessToken()
  1746. let expectation = self.expectation(description: #function)
  1747. let code = "code"
  1748. rpcIssuer.respondBlock = {
  1749. let request = try XCTUnwrap(self.rpcIssuer.request as? RevokeTokenRequest)
  1750. XCTAssertEqual(request.apiKey, AuthTests.kFakeAPIKey)
  1751. XCTAssertEqual(request.providerID, AuthProviderID.apple.rawValue)
  1752. XCTAssertEqual(request.token, code)
  1753. XCTAssertEqual(request.tokenType, .authorizationCode)
  1754. // Send the response from the fake backend.
  1755. return try self.rpcIssuer.respond(withJSON: [:])
  1756. }
  1757. auth?.revokeToken(withAuthorizationCode: code) { error in
  1758. // Verify callback success.
  1759. XCTAssertNil(error)
  1760. expectation.fulfill()
  1761. }
  1762. waitForExpectations(timeout: 5)
  1763. }
  1764. /** @fn testRevokeTokenMissingCallback
  1765. @brief Tests the flow of @c revokeToken:completion with a nil callback.
  1766. */
  1767. func testRevokeTokenMissingCallback() throws {
  1768. try waitForSignInWithAccessToken()
  1769. let code = "code"
  1770. let issuer = try XCTUnwrap(rpcIssuer)
  1771. issuer.respondBlock = {
  1772. let request = try XCTUnwrap(issuer.request as? RevokeTokenRequest)
  1773. XCTAssertEqual(request.apiKey, AuthTests.kFakeAPIKey)
  1774. XCTAssertEqual(request.providerID, AuthProviderID.apple.rawValue)
  1775. XCTAssertEqual(request.token, code)
  1776. XCTAssertEqual(request.tokenType, .authorizationCode)
  1777. // Send the response from the fake backend.
  1778. return try issuer.respond(withJSON: [:])
  1779. }
  1780. auth?.revokeToken(withAuthorizationCode: code)
  1781. }
  1782. /** @fn testSignOut
  1783. @brief Tests the @c signOut: method.
  1784. */
  1785. func testSignOut() throws {
  1786. try waitForSignInWithAccessToken()
  1787. // Verify signing out succeeds and clears the current user.
  1788. let auth = try XCTUnwrap(auth)
  1789. try auth.signOut()
  1790. XCTAssertNil(auth.currentUser)
  1791. }
  1792. /** @fn testIsSignInWithEmailLink
  1793. @brief Tests the @c isSignInWithEmailLink: method.
  1794. */
  1795. func testIsSignInWithEmailLink() throws {
  1796. let auth = try XCTUnwrap(auth)
  1797. let kBadSignInEmailLink = "http://www.facebook.com"
  1798. XCTAssertTrue(auth.isSignIn(withEmailLink: kFakeEmailSignInLink))
  1799. XCTAssertTrue(auth.isSignIn(withEmailLink: kFakeEmailSignInDeeplink))
  1800. XCTAssertFalse(auth.isSignIn(withEmailLink: kBadSignInEmailLink))
  1801. XCTAssertFalse(auth.isSignIn(withEmailLink: ""))
  1802. }
  1803. /** @fn testAuthStateChanges
  1804. @brief Tests @c addAuthStateDidChangeListener: and @c removeAuthStateDidChangeListener: methods.
  1805. */
  1806. func testAuthStateChanges() throws {
  1807. // Set up listener.
  1808. let auth = try XCTUnwrap(auth)
  1809. var shouldHaveUser = false
  1810. var expectation: XCTestExpectation?
  1811. let listener = { listenerAuth, user in
  1812. XCTAssertTrue(Thread.isMainThread)
  1813. XCTAssertEqual(auth, listenerAuth)
  1814. XCTAssertEqual(user, auth.currentUser)
  1815. if shouldHaveUser {
  1816. XCTAssertNotNil(user)
  1817. } else {
  1818. XCTAssertNil(user)
  1819. }
  1820. // `expectation` being nil means the listener is not expected to be fired at this moment.
  1821. XCTAssertNotNil(expectation)
  1822. expectation?.fulfill()
  1823. }
  1824. try auth.signOut()
  1825. // Listener should fire immediately when attached.
  1826. expectation = self.expectation(description: "initial")
  1827. shouldHaveUser = false
  1828. let handle = auth.addStateDidChangeListener(listener)
  1829. waitForExpectations(timeout: 5)
  1830. expectation = nil
  1831. // Listener should fire for signing in.
  1832. expectation = self
  1833. .expectation(description: "sign-in") // waited on in waitForSignInWithAccessToken
  1834. shouldHaveUser = true
  1835. try waitForSignInWithAccessToken()
  1836. // Listener should not fire for signing in again.
  1837. expectation = nil
  1838. shouldHaveUser = true
  1839. try waitForSignInWithAccessToken()
  1840. // Listener should fire for signing out.
  1841. expectation = self.expectation(description: "sign-out")
  1842. shouldHaveUser = false
  1843. try auth.signOut()
  1844. waitForExpectations(timeout: 5)
  1845. // Listener should no longer fire once detached.
  1846. expectation = nil
  1847. auth.removeStateDidChangeListener(handle)
  1848. try waitForSignInWithAccessToken()
  1849. }
  1850. /** @fn testIDTokenChanges
  1851. @brief Tests @c addIDTokenDidChangeListener: and @c removeIDTokenDidChangeListener: methods.
  1852. */
  1853. func testIDTokenChanges() throws {
  1854. // Set up listener.
  1855. let auth = try XCTUnwrap(auth)
  1856. var shouldHaveUser = false
  1857. var expectation: XCTestExpectation?
  1858. var fulfilled = false
  1859. let listener = { listenerAuth, user in
  1860. XCTAssertTrue(Thread.isMainThread)
  1861. XCTAssertEqual(auth, listenerAuth)
  1862. XCTAssertEqual(user, auth.currentUser)
  1863. if shouldHaveUser {
  1864. XCTAssertNotNil(user)
  1865. } else {
  1866. XCTAssertNil(user)
  1867. }
  1868. // `expectation` being nil means the listener is not expected to be fired at this moment.
  1869. XCTAssertNotNil(expectation)
  1870. if !fulfilled {
  1871. fulfilled = true
  1872. expectation?.fulfill()
  1873. }
  1874. }
  1875. try auth.signOut()
  1876. // Listener should fire immediately when attached.
  1877. expectation = self.expectation(description: "initial")
  1878. shouldHaveUser = false
  1879. let handle = auth.addIDTokenDidChangeListener(listener)
  1880. waitForExpectations(timeout: 5)
  1881. expectation = nil
  1882. // Listener should fire for signing in. Expectation is waited on in
  1883. // waitForSignInWithAccessToken.
  1884. fulfilled = false
  1885. expectation = self.expectation(description: "sign-in")
  1886. shouldHaveUser = true
  1887. try waitForSignInWithAccessToken()
  1888. // Listener should not fire for signing in again.
  1889. expectation = nil
  1890. shouldHaveUser = true
  1891. try waitForSignInWithAccessToken()
  1892. // Listener should fire for signing in again as the same user with another access token.
  1893. fulfilled = false
  1894. expectation = self.expectation(description: "sign-in")
  1895. shouldHaveUser = true
  1896. try waitForSignInWithAccessToken(fakeAccessToken: AuthTests.kNewAccessToken)
  1897. // Listener should fire for signing out.
  1898. fulfilled = false
  1899. expectation = self.expectation(description: "sign-out")
  1900. shouldHaveUser = false
  1901. try auth.signOut()
  1902. waitForExpectations(timeout: 5)
  1903. // Listener should no longer fire once detached.
  1904. expectation = nil
  1905. auth.removeStateDidChangeListener(handle)
  1906. try waitForSignInWithAccessToken()
  1907. }
  1908. /** @fn testUseEmulator
  1909. @brief Tests the @c useEmulatorWithHost:port: method.
  1910. */
  1911. func testUseEmulator() throws {
  1912. auth.useEmulator(withHost: "host", port: 12345)
  1913. XCTAssertEqual("host:12345", auth.requestConfiguration.emulatorHostAndPort)
  1914. #if os(iOS)
  1915. let settings = try XCTUnwrap(auth.settings)
  1916. XCTAssertTrue(settings.isAppVerificationDisabledForTesting)
  1917. #endif
  1918. }
  1919. /** @fn testUseEmulatorNeverCalled
  1920. @brief Tests that the emulatorHostAndPort stored in @c FIRAuthRequestConfiguration is nil if the
  1921. @c useEmulatorWithHost:port: is not called.
  1922. */
  1923. func testUseEmulatorNeverCalled() throws {
  1924. XCTAssertNil(auth.requestConfiguration.emulatorHostAndPort)
  1925. #if os(iOS)
  1926. let settings = try XCTUnwrap(auth.settings)
  1927. XCTAssertFalse(settings.isAppVerificationDisabledForTesting)
  1928. #endif
  1929. }
  1930. /** @fn testUseEmulatorIPv6Address
  1931. @brief Tests the @c useEmulatorWithHost:port: method with an IPv6 host address.
  1932. */
  1933. func testUseEmulatorIPv6Address() throws {
  1934. auth.useEmulator(withHost: "::1", port: 12345)
  1935. XCTAssertEqual("[::1]:12345", auth.requestConfiguration.emulatorHostAndPort)
  1936. #if os(iOS)
  1937. let settings = try XCTUnwrap(auth.settings)
  1938. XCTAssertTrue(settings.isAppVerificationDisabledForTesting)
  1939. #endif
  1940. }
  1941. // MARK: Automatic Token Refresh Tests.
  1942. /** @fn testAutomaticTokenRefresh
  1943. @brief Tests a successful flow to automatically refresh tokens for a signed in user.
  1944. */
  1945. func testAutomaticTokenRefresh() throws {
  1946. try auth.signOut()
  1947. // Enable auto refresh
  1948. enableAutoTokenRefresh()
  1949. // Sign in a user.
  1950. try waitForSignInWithAccessToken()
  1951. setFakeSecureTokenService(fakeAccessToken: AuthTests.kNewAccessToken)
  1952. // Verify that the current user's access token is the "old" access token before automatic token
  1953. // refresh.
  1954. XCTAssertEqual(AuthTests.kAccessToken, auth.currentUser?.rawAccessToken())
  1955. // Execute saved token refresh task.
  1956. let expectation = self.expectation(description: #function)
  1957. kAuthGlobalWorkQueue.async {
  1958. XCTAssertNotNil(self.authDispatcherCallback)
  1959. self.authDispatcherCallback?()
  1960. expectation.fulfill()
  1961. }
  1962. waitForExpectations(timeout: 5)
  1963. waitForAuthGlobalWorkQueueDrain()
  1964. // Verify that current user's access token is the "new" access token provided in the mock secure
  1965. // token response during automatic token refresh.
  1966. RPCBaseTests.waitSleep()
  1967. XCTAssertEqual(AuthTests.kNewAccessToken, auth.currentUser?.rawAccessToken())
  1968. }
  1969. /** @fn testAutomaticTokenRefreshInvalidTokenFailure
  1970. @brief Tests an unsuccessful flow to auto refresh tokens with an "invalid token" error.
  1971. This error should cause the user to be signed out.
  1972. */
  1973. func testAutomaticTokenRefreshInvalidTokenFailure() throws {
  1974. try auth.signOut()
  1975. // Enable auto refresh
  1976. enableAutoTokenRefresh()
  1977. // Sign in a user.
  1978. try waitForSignInWithAccessToken()
  1979. // Set up expectation for secureToken RPC made by a failed attempt to refresh tokens.
  1980. rpcIssuer.secureTokenErrorString = "INVALID_ID_TOKEN"
  1981. // Verify that the current user's access token is the "old" access token before automatic token
  1982. // refresh.
  1983. XCTAssertEqual(AuthTests.kAccessToken, auth.currentUser?.rawAccessToken())
  1984. // Execute saved token refresh task.
  1985. let expectation = self.expectation(description: #function)
  1986. kAuthGlobalWorkQueue.async {
  1987. XCTAssertNotNil(self.authDispatcherCallback)
  1988. self.authDispatcherCallback?()
  1989. expectation.fulfill()
  1990. }
  1991. waitForExpectations(timeout: 5)
  1992. waitForAuthGlobalWorkQueueDrain()
  1993. // Verify that the user is nil after failed attempt to refresh tokens caused signed out.
  1994. RPCBaseTests.waitSleep()
  1995. XCTAssertNil(auth.currentUser)
  1996. }
  1997. /** @fn testAutomaticTokenRefreshRetry
  1998. @brief Tests that a retry is attempted for a automatic token refresh task (which is not due to
  1999. invalid tokens). The initial attempt to refresh the access token fails, but the second
  2000. attempt is successful.
  2001. */
  2002. func testAutomaticTokenRefreshRetry() throws {
  2003. try auth.signOut()
  2004. // Enable auto refresh
  2005. enableAutoTokenRefresh()
  2006. // Sign in a user.
  2007. try waitForSignInWithAccessToken()
  2008. // Set up expectation for secureToken RPC made by a failed attempt to refresh tokens.
  2009. rpcIssuer.secureTokenNetworkError = NSError(domain: "ERROR", code: -1)
  2010. // Execute saved token refresh task.
  2011. let expectation = self.expectation(description: #function)
  2012. kAuthGlobalWorkQueue.async {
  2013. XCTAssertNotNil(self.authDispatcherCallback)
  2014. self.authDispatcherCallback?()
  2015. self.authDispatcherCallback = nil
  2016. expectation.fulfill()
  2017. }
  2018. waitForExpectations(timeout: 5)
  2019. waitForAuthGlobalWorkQueueDrain()
  2020. rpcIssuer.secureTokenNetworkError = nil
  2021. setFakeSecureTokenService(fakeAccessToken: AuthTests.kNewAccessToken)
  2022. // The old access token should still be the current user's access token and not the new access
  2023. // token (kNewAccessToken).
  2024. XCTAssertEqual(AuthTests.kAccessToken, auth.currentUser?.rawAccessToken())
  2025. // Execute saved token refresh task.
  2026. let expectation2 = self.expectation(description: "dispatchAfterExpectation")
  2027. kAuthGlobalWorkQueue.async {
  2028. RPCBaseTests.waitSleep()
  2029. XCTAssertNotNil(self.authDispatcherCallback)
  2030. self.authDispatcherCallback?()
  2031. expectation2.fulfill()
  2032. }
  2033. waitForExpectations(timeout: 5)
  2034. waitForAuthGlobalWorkQueueDrain()
  2035. // Time for callback to run.
  2036. RPCBaseTests.waitSleep()
  2037. // Verify that current user's access token is the "new" access token provided in the mock secure
  2038. // token response during automatic token refresh.
  2039. XCTAssertEqual(AuthTests.kNewAccessToken, auth.currentUser?.rawAccessToken())
  2040. }
  2041. #if os(iOS)
  2042. /** @fn testAutoRefreshAppForegroundedNotification
  2043. @brief Tests that app foreground notification triggers the scheduling of an automatic token
  2044. refresh task.
  2045. */
  2046. func testAutoRefreshAppForegroundedNotification() throws {
  2047. try auth.signOut()
  2048. // Enable auto refresh
  2049. enableAutoTokenRefresh()
  2050. // Sign in a user.
  2051. try waitForSignInWithAccessToken()
  2052. // Post "UIApplicationDidBecomeActiveNotification" to trigger scheduling token refresh task.
  2053. NotificationCenter.default.post(name: UIApplication.didBecomeActiveNotification, object: nil)
  2054. setFakeSecureTokenService(fakeAccessToken: AuthTests.kNewAccessToken)
  2055. // Verify that the current user's access token is the "old" access token before automatic
  2056. // token refresh.
  2057. XCTAssertEqual(AuthTests.kAccessToken, auth.currentUser?.rawAccessToken())
  2058. // Execute saved token refresh task.
  2059. let expectation = self.expectation(description: #function)
  2060. kAuthGlobalWorkQueue.async {
  2061. XCTAssertNotNil(self.authDispatcherCallback)
  2062. self.authDispatcherCallback?()
  2063. expectation.fulfill()
  2064. }
  2065. waitForExpectations(timeout: 5)
  2066. waitForAuthGlobalWorkQueueDrain()
  2067. // Time for callback to run.
  2068. RPCBaseTests.waitSleep()
  2069. // Verify that current user's access token is the "new" access token provided in the mock
  2070. // secure token response during automatic token refresh.
  2071. XCTAssertEqual(AuthTests.kNewAccessToken, auth.currentUser?.rawAccessToken())
  2072. }
  2073. #endif
  2074. // MARK: Application Delegate tests.
  2075. #if os(iOS)
  2076. func testAppDidRegisterForRemoteNotifications_APNSTokenUpdated() {
  2077. class FakeAuthTokenManager: AuthAPNSTokenManager, @unchecked Sendable {
  2078. override var token: AuthAPNSToken? {
  2079. get {
  2080. return tokenStore
  2081. }
  2082. set(setToken) {
  2083. tokenStore = setToken
  2084. }
  2085. }
  2086. }
  2087. let apnsToken = Data()
  2088. auth.tokenManager = FakeAuthTokenManager(withApplication: UIApplication.shared)
  2089. auth.application(UIApplication.shared,
  2090. didRegisterForRemoteNotificationsWithDeviceToken: apnsToken)
  2091. XCTAssertEqual(auth.tokenManager.token?.data, apnsToken)
  2092. XCTAssertEqual(auth.tokenManager.token?.type, .unknown)
  2093. }
  2094. func testAppDidFailToRegisterForRemoteNotifications_TokenManagerCancels() {
  2095. class FakeAuthTokenManager: AuthAPNSTokenManager, @unchecked Sendable {
  2096. var cancelled = false
  2097. override func cancel(withError error: Error) {
  2098. cancelled = true
  2099. }
  2100. }
  2101. let error = NSError(domain: "AuthTests", code: -1)
  2102. let fakeTokenManager = FakeAuthTokenManager(withApplication: UIApplication.shared)
  2103. auth.tokenManager = fakeTokenManager
  2104. XCTAssertFalse(fakeTokenManager.cancelled)
  2105. auth.application(UIApplication.shared,
  2106. didFailToRegisterForRemoteNotificationsWithError: error)
  2107. XCTAssertTrue(fakeTokenManager.cancelled)
  2108. }
  2109. func testAppDidReceiveRemoteNotificationWithCompletion_NotificationManagerHandleCanNotification() {
  2110. class FakeNotificationManager: AuthNotificationManager {
  2111. var canHandled = false
  2112. override func canHandle(notification: [AnyHashable: Any]) -> Bool {
  2113. canHandled = true
  2114. return true
  2115. }
  2116. }
  2117. let notification = ["test": ""]
  2118. let fakeKeychain = AuthKeychainServices(
  2119. service: "AuthTests",
  2120. storage: FakeAuthKeychainStorage()
  2121. )
  2122. let appCredentialManager = AuthAppCredentialManager(withKeychain: fakeKeychain)
  2123. let fakeNotificationManager = FakeNotificationManager(withApplication: UIApplication.shared,
  2124. appCredentialManager: appCredentialManager)
  2125. auth.notificationManager = fakeNotificationManager
  2126. XCTAssertFalse(fakeNotificationManager.canHandled)
  2127. auth.application(UIApplication.shared,
  2128. didReceiveRemoteNotification: notification) { _ in
  2129. }
  2130. XCTAssertTrue(fakeNotificationManager.canHandled)
  2131. }
  2132. func testAppOpenURL_AuthPresenterCanHandleURL() throws {
  2133. class FakeURLPresenter: AuthURLPresenter {
  2134. var canHandled = false
  2135. override func canHandle(url: URL) -> Bool {
  2136. canHandled = true
  2137. return true
  2138. }
  2139. }
  2140. let url = try XCTUnwrap(URL(string: "https://localhost"))
  2141. let fakeURLPresenter = FakeURLPresenter()
  2142. auth.authURLPresenter = fakeURLPresenter
  2143. XCTAssertFalse(fakeURLPresenter.canHandled)
  2144. XCTAssertTrue(auth.application(UIApplication.shared, open: url, options: [:]))
  2145. XCTAssertTrue(fakeURLPresenter.canHandled)
  2146. }
  2147. #endif // os(iOS)
  2148. // MARK: Interoperability Tests
  2149. func testComponentsRegistered() throws {
  2150. // Verify that the components are registered properly. Check the count, because any time a new
  2151. // component is added it should be added to the test suite as well.
  2152. XCTAssertEqual(AuthComponent.componentsToRegister().count, 1)
  2153. // TODO: Can/should we do something like?
  2154. // XCTAssert(component.protocol == @protocol(FIRAuthInterop));
  2155. }
  2156. // MARK: Helper Functions
  2157. private func enableAutoTokenRefresh() {
  2158. let expectation = self.expectation(description: #function)
  2159. auth.getToken(forcingRefresh: false) { token, error in
  2160. expectation.fulfill()
  2161. }
  2162. waitForExpectations(timeout: 5)
  2163. }
  2164. private func waitForSignInWithAccessToken(fakeAccessToken: String = kAccessToken) throws {
  2165. let kRefreshToken = "fakeRefreshToken"
  2166. let expectation = self.expectation(description: #function)
  2167. setFakeGetAccountProvider()
  2168. setFakeSecureTokenService()
  2169. // 1. Set up respondBlock to test request and send it to generate a fake response.
  2170. rpcIssuer.respondBlock = {
  2171. // 2. Validate the created Request instance.
  2172. let request = try XCTUnwrap(self.rpcIssuer.request as? VerifyPasswordRequest)
  2173. XCTAssertEqual(request.email, self.kEmail)
  2174. XCTAssertEqual(request.password, self.kFakePassword)
  2175. XCTAssertEqual(request.apiKey, AuthTests.kFakeAPIKey)
  2176. XCTAssertTrue(request.returnSecureToken)
  2177. // 3. Send the response from the fake backend.
  2178. return try self.rpcIssuer.respond(withJSON: ["idToken": fakeAccessToken,
  2179. "email": self.kEmail,
  2180. "isNewUser": true,
  2181. "expiresIn": "3600",
  2182. "refreshToken": kRefreshToken])
  2183. }
  2184. auth?.signIn(withEmail: kEmail, password: kFakePassword) { authResult, error in
  2185. // 4. After the response triggers the callback, verify the returned result.
  2186. XCTAssertTrue(Thread.isMainThread)
  2187. guard let user = authResult?.user else {
  2188. XCTFail("authResult.user is missing")
  2189. return
  2190. }
  2191. XCTAssertEqual(user.refreshToken, kRefreshToken)
  2192. XCTAssertFalse(user.isAnonymous)
  2193. XCTAssertEqual(user.email, self.kEmail)
  2194. guard let additionalUserInfo = authResult?.additionalUserInfo else {
  2195. XCTFail("authResult.additionalUserInfo is missing")
  2196. return
  2197. }
  2198. XCTAssertFalse(additionalUserInfo.isNewUser)
  2199. XCTAssertEqual(additionalUserInfo.providerID, EmailAuthProvider.id)
  2200. XCTAssertNil(error)
  2201. expectation.fulfill()
  2202. }
  2203. waitForExpectations(timeout: 5)
  2204. assertUser(auth?.currentUser)
  2205. }
  2206. private func assertUser(_ user: User?) {
  2207. guard let user = user else {
  2208. XCTFail("authResult.additionalUserInfo is missing")
  2209. return
  2210. }
  2211. XCTAssertEqual(user.uid, kLocalID)
  2212. XCTAssertEqual(user.displayName, kDisplayName)
  2213. XCTAssertEqual(user.email, kEmail)
  2214. XCTAssertFalse(user.isAnonymous)
  2215. XCTAssertEqual(user.providerData.count, 1)
  2216. }
  2217. private func assertUserAnonymous(_ user: User?) {
  2218. guard let user = user else {
  2219. XCTFail("authResult.additionalUserInfo is missing")
  2220. return
  2221. }
  2222. XCTAssertEqual(user.uid, kLocalID)
  2223. XCTAssertNil(user.email)
  2224. XCTAssertNil(user.displayName)
  2225. XCTAssertTrue(user.isAnonymous)
  2226. XCTAssertEqual(user.providerData.count, 0)
  2227. }
  2228. }