AuthTests.swift 85 KB

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