AuthTests.swift 85 KB

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