AuthTests.swift 108 KB

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