FIRAuthTests.m 156 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326
  1. /*
  2. * Copyright 2017 Google
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. #import <Foundation/Foundation.h>
  17. #import <OCMock/OCMock.h>
  18. #import <XCTest/XCTest.h>
  19. #import <GoogleUtilities/GULAppDelegateSwizzler.h>
  20. #import "FirebaseAuth/Interop/FIRAuthInterop.h"
  21. #import "FirebaseAuth/Sources/Public/FirebaseAuth/FIRActionCodeSettings.h"
  22. #import "FirebaseAuth/Sources/Public/FirebaseAuth/FIRAdditionalUserInfo.h"
  23. #import "FirebaseAuth/Sources/Public/FirebaseAuth/FIRAuthSettings.h"
  24. #import "FirebaseAuth/Sources/Public/FirebaseAuth/FIREmailAuthProvider.h"
  25. #import "FirebaseAuth/Sources/Public/FirebaseAuth/FIRFacebookAuthProvider.h"
  26. #import "FirebaseAuth/Sources/Public/FirebaseAuth/FIRGoogleAuthProvider.h"
  27. #import "FirebaseAuth/Sources/Public/FirebaseAuth/FIROAuthProvider.h"
  28. #import "FirebaseCore/Extension/FirebaseCoreInternal.h"
  29. #import "FirebaseAuth/Sources/Auth/FIRAuthDispatcher.h"
  30. #import "FirebaseAuth/Sources/Auth/FIRAuthGlobalWorkQueue.h"
  31. #import "FirebaseAuth/Sources/Auth/FIRAuthOperationType.h"
  32. #import "FirebaseAuth/Sources/Auth/FIRAuth_Internal.h"
  33. #import "FirebaseAuth/Sources/AuthProvider/OAuth/FIROAuthCredential_Internal.h"
  34. #import "FirebaseAuth/Sources/Backend/FIRAuthBackend.h"
  35. #import "FirebaseAuth/Sources/Backend/RPC/FIRCreateAuthURIRequest.h"
  36. #import "FirebaseAuth/Sources/Backend/RPC/FIRCreateAuthURIResponse.h"
  37. #import "FirebaseAuth/Sources/Backend/RPC/FIREmailLinkSignInRequest.h"
  38. #import "FirebaseAuth/Sources/Backend/RPC/FIREmailLinkSignInResponse.h"
  39. #import "FirebaseAuth/Sources/Backend/RPC/FIRGetAccountInfoRequest.h"
  40. #import "FirebaseAuth/Sources/Backend/RPC/FIRGetAccountInfoResponse.h"
  41. #import "FirebaseAuth/Sources/Backend/RPC/FIRGetOOBConfirmationCodeRequest.h"
  42. #import "FirebaseAuth/Sources/Backend/RPC/FIRGetOOBConfirmationCodeResponse.h"
  43. #import "FirebaseAuth/Sources/Backend/RPC/FIRResetPasswordRequest.h"
  44. #import "FirebaseAuth/Sources/Backend/RPC/FIRResetPasswordResponse.h"
  45. #import "FirebaseAuth/Sources/Backend/RPC/FIRRevokeTokenRequest.h"
  46. #import "FirebaseAuth/Sources/Backend/RPC/FIRRevokeTokenResponse.h"
  47. #import "FirebaseAuth/Sources/Backend/RPC/FIRSecureTokenRequest.h"
  48. #import "FirebaseAuth/Sources/Backend/RPC/FIRSecureTokenResponse.h"
  49. #import "FirebaseAuth/Sources/Backend/RPC/FIRSetAccountInfoRequest.h"
  50. #import "FirebaseAuth/Sources/Backend/RPC/FIRSetAccountInfoResponse.h"
  51. #import "FirebaseAuth/Sources/Backend/RPC/FIRSignUpNewUserRequest.h"
  52. #import "FirebaseAuth/Sources/Backend/RPC/FIRSignUpNewUserResponse.h"
  53. #import "FirebaseAuth/Sources/Backend/RPC/FIRVerifyAssertionRequest.h"
  54. #import "FirebaseAuth/Sources/Backend/RPC/FIRVerifyAssertionResponse.h"
  55. #import "FirebaseAuth/Sources/Backend/RPC/FIRVerifyCustomTokenRequest.h"
  56. #import "FirebaseAuth/Sources/Backend/RPC/FIRVerifyCustomTokenResponse.h"
  57. #import "FirebaseAuth/Sources/Backend/RPC/FIRVerifyPasswordRequest.h"
  58. #import "FirebaseAuth/Sources/Backend/RPC/FIRVerifyPasswordResponse.h"
  59. #import "FirebaseAuth/Sources/Backend/RPC/FIRVerifyPhoneNumberRequest.h"
  60. #import "FirebaseAuth/Sources/Backend/RPC/FIRVerifyPhoneNumberResponse.h"
  61. #import "FirebaseAuth/Sources/User/FIRUser_Internal.h"
  62. #import "FirebaseAuth/Sources/Utilities/FIRAuthErrorUtils.h"
  63. #import "FirebaseAuth/Sources/Utilities/FIRAuthRecaptchaVerifier.h"
  64. #import "FirebaseAuth/Tests/Unit/FIRApp+FIRAuthUnitTests.h"
  65. #import "FirebaseAuth/Tests/Unit/OCMStubRecorder+FIRAuthUnitTests.h"
  66. #if TARGET_OS_IOS
  67. #import "FirebaseAuth/Sources/Public/FirebaseAuth/FIRAuthUIDelegate.h"
  68. #import "FirebaseAuth/Sources/Public/FirebaseAuth/FIRPhoneAuthCredential.h"
  69. #import "FirebaseAuth/Sources/Public/FirebaseAuth/FIRPhoneAuthProvider.h"
  70. #import "FirebaseAuth/Sources/SystemService/FIRAuthAPNSToken.h"
  71. #import "FirebaseAuth/Sources/SystemService/FIRAuthAPNSTokenManager.h"
  72. #import "FirebaseAuth/Sources/SystemService/FIRAuthNotificationManager.h"
  73. #import "FirebaseAuth/Sources/Utilities/FIRAuthURLPresenter.h"
  74. #endif // TARGET_OS_IOS
  75. /** @var kAPIKey
  76. @brief The fake API key.
  77. */
  78. static NSString *const kAPIKey = @"FAKE_API_KEY";
  79. /** @var kFirebaseAppID
  80. @brief The fake Firebase app ID.
  81. */
  82. static NSString *const kFirebaseAppID = @"FAKE_APP_ID";
  83. /** @var kAccessToken
  84. @brief The fake access token.
  85. */
  86. static NSString *const kAccessToken = @"ACCESS_TOKEN";
  87. /** @var kNewAccessToken
  88. @brief Another fake access token used to simulate token refreshed via automatic token refresh.
  89. */
  90. NSString *kNewAccessToken = @"NewAccessToken";
  91. /** @var kAccessTokenValidInterval
  92. @brief The time to live for the fake access token.
  93. */
  94. static const NSTimeInterval kAccessTokenTimeToLive = 60 * 60;
  95. /** @var kTestTokenExpirationTimeInterval
  96. @brief The fake time interval that it takes a token to expire.
  97. */
  98. static const NSTimeInterval kTestTokenExpirationTimeInterval = 55 * 60;
  99. /** @var kRefreshToken
  100. @brief The fake refresh token.
  101. */
  102. static NSString *const kRefreshToken = @"REFRESH_TOKEN";
  103. /** @var kEmail
  104. @brief The fake user email.
  105. */
  106. static NSString *const kEmail = @"user@company.com";
  107. /** @var kFakePassword
  108. @brief The fake user password.
  109. */
  110. static NSString *const kFakePassword = @"!@#$%^";
  111. /** @var kPasswordHash
  112. @brief The fake user password hash.
  113. */
  114. static NSString *const kPasswordHash = @"UkVEQUNURUQ=";
  115. /** @var kLocalID
  116. @brief The fake local user ID.
  117. */
  118. static NSString *const kLocalID = @"LOCAL_ID";
  119. /** @var kDisplayName
  120. @brief The fake user display name.
  121. */
  122. static NSString *const kDisplayName = @"User Doe";
  123. /** @var kFakeGivenName
  124. @brief The fake user given name.
  125. */
  126. static NSString *const kFakeGivenName = @"Firstname";
  127. /** @var kFakeFamilyName
  128. @brief The fake user family name.
  129. */
  130. static NSString *const kFakeFamilyName = @"Lastname";
  131. /** @var kGoogleUD
  132. @brief The fake user ID under Google Sign-In.
  133. */
  134. static NSString *const kGoogleID = @"GOOGLE_ID";
  135. /** @var kGoogleEmail
  136. @brief The fake user email under Google Sign-In.
  137. */
  138. static NSString *const kGoogleEmail = @"user@gmail.com";
  139. /** @var kGoogleDisplayName
  140. @brief The fake user display name under Google Sign-In.
  141. */
  142. static NSString *const kGoogleDisplayName = @"Google Doe";
  143. /** @var kGoogleAccessToken
  144. @brief The fake access token from Google Sign-In.
  145. */
  146. static NSString *const kGoogleAccessToken = @"GOOGLE_ACCESS_TOKEN";
  147. /** @var kGoogleIDToken
  148. @brief The fake ID token from Google Sign-In.
  149. */
  150. static NSString *const kGoogleIDToken = @"GOOGLE_ID_TOKEN";
  151. /** @var kAppleAuthProviderID
  152. @brief The provider ID for Apple Sign-In.
  153. */
  154. static NSString *const kAppleAuthProviderID = @"apple.com";
  155. /** @var kAppleIDToken
  156. @brief The fake ID token from Apple Sign-In.
  157. */
  158. static NSString *const kAppleIDToken = @"APPLE_ID_TOKEN";
  159. /** @var kCustomToken
  160. @brief The fake custom token to sign in.
  161. */
  162. static NSString *const kCustomToken = @"CUSTOM_TOKEN";
  163. /** @var kVerificationCode
  164. @brief Fake verification code used for testing.
  165. */
  166. static NSString *const kVerificationCode = @"12345678";
  167. /** @var kVerificationID
  168. @brief Fake verification ID for testing.
  169. */
  170. static NSString *const kVerificationID = @"55432";
  171. /** @var kOAuthRequestURI
  172. @brief Fake OAuthRequest URI for testing.
  173. */
  174. static NSString *const kOAuthRequestURI = @"requestURI";
  175. /** @var kOAuthSessionID
  176. @brief Fake session ID for testing.
  177. */
  178. static NSString *const kOAuthSessionID = @"sessionID";
  179. /** @var kFakeWebSignInUserInteractionFailureReason
  180. @brief Fake reason for FIRAuthErrorCodeWebSignInUserInteractionFailure error while testing.
  181. */
  182. static NSString *const kFakeWebSignInUserInteractionFailureReason = @"fake_reason";
  183. /** @var kContinueURL
  184. @brief Fake string value of continue url.
  185. */
  186. static NSString *const kContinueURL = @"continueURL";
  187. /** @var kCanHandleCodeInAppKey
  188. @brief The key for the request parameter indicating whether the action code can be handled in
  189. the app or not.
  190. */
  191. static NSString *const kCanHandleCodeInAppKey = @"canHandleCodeInApp";
  192. /** @var kFIREmailLinkAuthSignInMethod
  193. @brief Fake email link sign-in method for testing.
  194. */
  195. static NSString *const kFIREmailLinkAuthSignInMethod = @"emailLink";
  196. /** @var kFIRFacebookAuthSignInMethod
  197. @brief Fake Facebook sign-in method for testing.
  198. */
  199. static NSString *const kFIRFacebookAuthSignInMethod = @"facebook.com";
  200. /** @var kBadSignInEmailLink
  201. @brief Bad sign-in link to test email link sign-in
  202. */
  203. static NSString *const kBadSignInEmailLink = @"http://www.facebook.com";
  204. /** @var kFakeEmailSignInDeeplink
  205. @brief Fake email sign-in link
  206. */
  207. static NSString *const kFakeEmailSignInDeeplink =
  208. @"https://example.domain.com/?apiKey=testAPIKey&oobCode=testoobcode&mode=signIn";
  209. /** @var kFakeEmailSignInlink
  210. @brief Fake email sign-in link
  211. */
  212. static NSString *const kFakeEmailSignInlink =
  213. @"https://test.app.goo.gl/?link=https://test.firebase"
  214. "app.com/__/auth/"
  215. "action?apiKey%3DtestAPIKey%26mode%3DsignIn%26oobCode%3Dtestoobcode%26continueU"
  216. "rl%3Dhttps://test.apps.com&ibi=com.test.com&ifl=https://test.firebaseapp.com/__/auth/"
  217. "action?ap"
  218. "iKey%3DtestAPIKey%26mode%3DsignIn%26oobCode%3Dtestoobcode%26continueUrl%3Dhttps://"
  219. "test.apps.co"
  220. "m";
  221. /** @var kExpectationTimeout
  222. @brief The maximum time waiting for expectations to fulfill.
  223. */
  224. static const NSTimeInterval kExpectationTimeout = 2;
  225. /** @var kWaitInterval
  226. @brief The time waiting for background tasks to finish before continue when necessary.
  227. */
  228. static const NSTimeInterval kWaitInterval = .5;
  229. /** @var kFakeRecaptchaResponse
  230. @brief The fake recaptcha response.
  231. */
  232. static NSString *const kFakeRecaptchaResponse = @"RecaptchaResponse";
  233. /** @var kFakeRecaptchaVersion
  234. @brief The fake recaptcha version.
  235. */
  236. static NSString *const kFakeRecaptchaVersion = @"RecaptchaVersion";
  237. #if TARGET_OS_IOS
  238. /** @class FIRAuthAppDelegate
  239. @brief Application delegate implementation to test the app delegate proxying
  240. */
  241. @interface FIRAuthAppDelegate : NSObject <UIApplicationDelegate>
  242. @end
  243. @implementation FIRAuthAppDelegate
  244. - (void)application:(UIApplication *)application
  245. didReceiveRemoteNotification:(NSDictionary *)userInfo
  246. fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {
  247. }
  248. - (BOOL)application:(UIApplication *)app
  249. openURL:(NSURL *)url
  250. options:(NSDictionary<UIApplicationOpenURLOptionsKey, id> *)options {
  251. return NO;
  252. }
  253. @end
  254. #endif // TARGET_OS_IOS
  255. @interface GULAppDelegateSwizzler (FIRMessagingRemoteNotificationsProxyTest)
  256. + (void)resetProxyOriginalDelegateOnceToken;
  257. @end
  258. /** Category for FIRAuth to expose FIRComponentRegistrant conformance. */
  259. @interface FIRAuth () <FIRLibrary>
  260. @end
  261. /** @class FIRAuthTests
  262. @brief Tests for @c FIRAuth.
  263. */
  264. @interface FIRAuthTests : XCTestCase
  265. #if TARGET_OS_IOS
  266. /// A partial mock of `[FIRAuth auth].tokenManager`
  267. @property(nonatomic, strong) id mockTokenManager;
  268. /// A partial mock of `[FIRAuth auth].notificationManager`
  269. @property(nonatomic, strong) id mockNotificationManager;
  270. /// A partial mock of `[FIRAuth auth].authURLPresenter`
  271. @property(nonatomic, strong) id mockAuthURLPresenter;
  272. /// An application delegate instance returned by `self.mockApplication.delegate`
  273. @property(nonatomic, strong) FIRAuthAppDelegate *fakeApplicationDelegate;
  274. #endif // TARGET_OS_IOS
  275. @end
  276. @implementation FIRAuthTests {
  277. /** @var _mockBackend
  278. @brief The mock @c FIRAuthBackendImplementation .
  279. */
  280. id _mockBackend;
  281. /** @var _FIRAuthDispatcherCallback
  282. @brief Used to save a task from FIRAuthDispatcher to be executed later.
  283. */
  284. __block void (^_Nonnull _FIRAuthDispatcherCallback)(void);
  285. }
  286. /** @fn googleProfile
  287. @brief The fake user profile under additional user data in @c FIRVerifyAssertionResponse.
  288. */
  289. + (NSDictionary *)googleProfile {
  290. static NSDictionary *kGoogleProfile = nil;
  291. static dispatch_once_t onceToken;
  292. dispatch_once(&onceToken, ^{
  293. kGoogleProfile = @{
  294. @"iss" : @"https://accounts.google.com\\",
  295. @"email" : kGoogleEmail,
  296. @"given_name" : @"User",
  297. @"family_name" : @"Doe"
  298. };
  299. });
  300. return kGoogleProfile;
  301. }
  302. - (void)setUp {
  303. [super setUp];
  304. #if TARGET_OS_IOS
  305. // Make sure the `self.fakeApplicationDelegate` will be swizzled on FIRAuth init.
  306. [GULAppDelegateSwizzler resetProxyOriginalDelegateOnceToken];
  307. self.fakeApplicationDelegate = [[FIRAuthAppDelegate alloc] init];
  308. [[GULAppDelegateSwizzler sharedApplication]
  309. setDelegate:(id<UIApplicationDelegate>)self.fakeApplicationDelegate];
  310. #endif // TARGET_OS_IOS
  311. _mockBackend = OCMProtocolMock(@protocol(FIRAuthBackendImplementation));
  312. [FIRAuthBackend setBackendImplementation:_mockBackend];
  313. [FIRApp resetAppForAuthUnitTests];
  314. // Set FIRAuthDispatcher implementation in order to save the token refresh task for later
  315. // execution.
  316. [[FIRAuthDispatcher sharedInstance]
  317. setDispatchAfterImplementation:^(NSTimeInterval delay, dispatch_queue_t _Nonnull queue,
  318. void (^task)(void)) {
  319. XCTAssertNotNil(task);
  320. XCTAssert(delay > 0);
  321. XCTAssertEqualObjects(FIRAuthGlobalWorkQueue(), queue);
  322. self->_FIRAuthDispatcherCallback = task;
  323. }];
  324. #if TARGET_OS_IOS
  325. // Wait until FIRAuth initialization completes
  326. [self waitForAuthGlobalWorkQueueDrain];
  327. self.mockTokenManager = OCMPartialMock([FIRAuth auth].tokenManager);
  328. self.mockNotificationManager = OCMPartialMock([FIRAuth auth].notificationManager);
  329. self.mockAuthURLPresenter = OCMPartialMock([FIRAuth auth].authURLPresenter);
  330. #endif // TARGET_OS_IOS
  331. }
  332. - (void)tearDown {
  333. [FIRAuthBackend setDefaultBackendImplementationWithRPCIssuer:nil];
  334. [[FIRAuthDispatcher sharedInstance] setDispatchAfterImplementation:nil];
  335. #if TARGET_OS_IOS
  336. [self.mockAuthURLPresenter stopMocking];
  337. self.mockAuthURLPresenter = nil;
  338. [self.mockNotificationManager stopMocking];
  339. self.mockNotificationManager = nil;
  340. [self.mockTokenManager stopMocking];
  341. self.mockTokenManager = nil;
  342. self.fakeApplicationDelegate = nil;
  343. #endif // TARGET_OS_IOS
  344. [super tearDown];
  345. }
  346. #pragma mark - Server API Tests
  347. /** @fn testFetchSignInMethodsForEmailSuccess
  348. @brief Tests the flow of a successful @c fetchSignInMethodsForEmail:completion: call.
  349. */
  350. - (void)testFetchSignInMethodsForEmailSuccess {
  351. NSArray<NSString *> *allSignInMethods =
  352. @[ kFIREmailLinkAuthSignInMethod, kFIRFacebookAuthSignInMethod ];
  353. OCMExpect([_mockBackend createAuthURI:[OCMArg any] callback:[OCMArg any]])
  354. .andCallBlock2(
  355. ^(FIRCreateAuthURIRequest *_Nullable request, FIRCreateAuthURIResponseCallback callback) {
  356. XCTAssertEqualObjects(request.identifier, kEmail);
  357. XCTAssertNotNil(request.endpoint);
  358. XCTAssertEqualObjects(request.APIKey, kAPIKey);
  359. dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
  360. id mockCreateAuthURIResponse = OCMClassMock([FIRCreateAuthURIResponse class]);
  361. OCMStub([mockCreateAuthURIResponse signinMethods]).andReturn(allSignInMethods);
  362. callback(mockCreateAuthURIResponse, nil);
  363. });
  364. });
  365. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  366. [[FIRAuth auth] fetchSignInMethodsForEmail:kEmail
  367. completion:^(NSArray<NSString *> *_Nullable signInMethods,
  368. NSError *_Nullable error) {
  369. XCTAssertTrue([NSThread isMainThread]);
  370. XCTAssertEqualObjects(signInMethods, allSignInMethods);
  371. XCTAssertTrue([allSignInMethods isKindOfClass:[NSArray class]]);
  372. XCTAssertNil(error);
  373. [expectation fulfill];
  374. }];
  375. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  376. OCMVerifyAll(_mockBackend);
  377. }
  378. /** @fn testFetchSignInMethodsForEmailFailure
  379. @brief Tests the flow of a failed @c fetchSignInMethodsForEmail:completion: call.
  380. */
  381. - (void)testFetchSignInMethodsForEmailFailure {
  382. OCMExpect([_mockBackend createAuthURI:[OCMArg any] callback:[OCMArg any]])
  383. .andDispatchError2([FIRAuthErrorUtils tooManyRequestsErrorWithMessage:nil]);
  384. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  385. [[FIRAuth auth] fetchSignInMethodsForEmail:kEmail
  386. completion:^(NSArray<NSString *> *_Nullable signInMethods,
  387. NSError *_Nullable error) {
  388. XCTAssertTrue([NSThread isMainThread]);
  389. XCTAssertNil(signInMethods);
  390. XCTAssertEqual(error.code, FIRAuthErrorCodeTooManyRequests);
  391. XCTAssertNotNil(error.userInfo[NSLocalizedDescriptionKey]);
  392. [expectation fulfill];
  393. }];
  394. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  395. OCMVerifyAll(_mockBackend);
  396. }
  397. #if TARGET_OS_IOS
  398. /** @fn testPhoneAuthSuccess
  399. @brief Tests the flow of a successful @c signInWithCredential:completion for phone auth.
  400. */
  401. - (void)testPhoneAuthSuccess {
  402. OCMExpect([_mockBackend verifyPhoneNumber:[OCMArg any] callback:[OCMArg any]])
  403. .andCallBlock2(^(FIRVerifyPhoneNumberRequest *_Nullable request,
  404. FIRVerifyPhoneNumberResponseCallback callback) {
  405. XCTAssertEqualObjects(request.verificationCode, kVerificationCode);
  406. XCTAssertEqualObjects(request.verificationID, kVerificationID);
  407. XCTAssertEqual(request.operation, FIRAuthOperationTypeSignUpOrSignIn);
  408. dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
  409. id mockVerifyPhoneResponse = OCMClassMock([FIRVerifyPhoneNumberResponse class]);
  410. [self stubTokensWithMockResponse:mockVerifyPhoneResponse];
  411. // Stub isNewUser flag in the response.
  412. OCMStub([mockVerifyPhoneResponse isNewUser]).andReturn(YES);
  413. callback(mockVerifyPhoneResponse, nil);
  414. });
  415. });
  416. [self expectGetAccountInfo];
  417. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  418. [[FIRAuth auth] signOut:NULL];
  419. FIRAuthCredential *credential =
  420. [[FIRPhoneAuthProvider provider] credentialWithVerificationID:kVerificationID
  421. verificationCode:kVerificationCode];
  422. [[FIRAuth auth] signInWithCredential:credential
  423. completion:^(FIRAuthDataResult *_Nullable authDataResult,
  424. NSError *_Nullable error) {
  425. XCTAssertTrue([NSThread isMainThread]);
  426. [self assertUser:authDataResult.user];
  427. XCTAssertTrue(authDataResult.additionalUserInfo.isNewUser);
  428. XCTAssertNil(error);
  429. [expectation fulfill];
  430. }];
  431. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  432. [self assertUser:[FIRAuth auth].currentUser];
  433. OCMVerifyAll(_mockBackend);
  434. }
  435. /** @fn testPhoneAuthMissingVerificationCode
  436. @brief Tests the flow of an unsuccessful @c signInWithCredential:completion for phone auth due
  437. to an empty verification code
  438. */
  439. - (void)testPhoneAuthMissingVerificationCode {
  440. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  441. [[FIRAuth auth] signOut:NULL];
  442. FIRAuthCredential *credential =
  443. [[FIRPhoneAuthProvider provider] credentialWithVerificationID:kVerificationID
  444. verificationCode:@""];
  445. [[FIRAuth auth]
  446. signInWithCredential:credential
  447. completion:^(FIRAuthDataResult *_Nullable result, NSError *_Nullable error) {
  448. XCTAssertTrue([NSThread isMainThread]);
  449. XCTAssertNil(result);
  450. XCTAssertEqual(error.code, FIRAuthErrorCodeMissingVerificationCode);
  451. [expectation fulfill];
  452. }];
  453. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  454. }
  455. /** @fn testPhoneAuthMissingVerificationID
  456. @brief Tests the flow of an unsuccessful @c signInWithCredential:completion for phone auth due
  457. to an empty verification ID.
  458. */
  459. - (void)testPhoneAuthMissingVerificationID {
  460. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  461. [[FIRAuth auth] signOut:NULL];
  462. FIRAuthCredential *credential =
  463. [[FIRPhoneAuthProvider provider] credentialWithVerificationID:@""
  464. verificationCode:kVerificationCode];
  465. [[FIRAuth auth]
  466. signInWithCredential:credential
  467. completion:^(FIRAuthDataResult *_Nullable result, NSError *_Nullable error) {
  468. XCTAssertTrue([NSThread isMainThread]);
  469. XCTAssertNil(result);
  470. XCTAssertEqual(error.code, FIRAuthErrorCodeMissingVerificationID);
  471. [expectation fulfill];
  472. }];
  473. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  474. }
  475. #endif
  476. /** @fn testSignInWithEmailLinkSuccess
  477. @brief Tests the flow of a successful @c signInWithEmail:link:completion: call.
  478. */
  479. - (void)testSignInWithEmailLinkSuccess {
  480. NSString *fakeCode = @"testoobcode";
  481. OCMExpect([_mockBackend emailLinkSignin:[OCMArg any] callback:[OCMArg any]])
  482. .andCallBlock2(^(FIREmailLinkSignInRequest *_Nullable request,
  483. FIREmailLinkSigninResponseCallback callback) {
  484. XCTAssertEqualObjects(request.email, kEmail);
  485. XCTAssertEqualObjects(request.oobCode, fakeCode);
  486. dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
  487. id mockEmailLinkSignInResponse = OCMClassMock([FIREmailLinkSignInResponse class]);
  488. [self stubTokensWithMockResponse:mockEmailLinkSignInResponse];
  489. callback(mockEmailLinkSignInResponse, nil);
  490. OCMStub([mockEmailLinkSignInResponse refreshToken]).andReturn(kRefreshToken);
  491. });
  492. });
  493. [self expectGetAccountInfo];
  494. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  495. [[FIRAuth auth] signOut:NULL];
  496. [[FIRAuth auth]
  497. signInWithEmail:kEmail
  498. link:kFakeEmailSignInlink
  499. completion:^(FIRAuthDataResult *_Nullable authResult, NSError *_Nullable error) {
  500. XCTAssertTrue([NSThread isMainThread]);
  501. XCTAssertNotNil(authResult.user);
  502. XCTAssertEqualObjects(authResult.user.refreshToken, kRefreshToken);
  503. XCTAssertFalse(authResult.user.anonymous);
  504. XCTAssertEqualObjects(authResult.user.email, kEmail);
  505. XCTAssertNil(error);
  506. [expectation fulfill];
  507. }];
  508. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  509. [self assertUser:[FIRAuth auth].currentUser];
  510. OCMVerifyAll(_mockBackend);
  511. }
  512. /** @fn testSignInWithEmailLinkSuccessDeeplink
  513. @brief Tests the flow of a successful @c signInWithEmail:link:completion: call using a deep
  514. link.
  515. */
  516. - (void)testSignInWithEmailLinkSuccessDeeplink {
  517. NSString *fakeCode = @"testoobcode";
  518. OCMExpect([_mockBackend emailLinkSignin:[OCMArg any] callback:[OCMArg any]])
  519. .andCallBlock2(^(FIREmailLinkSignInRequest *_Nullable request,
  520. FIREmailLinkSigninResponseCallback callback) {
  521. XCTAssertEqualObjects(request.email, kEmail);
  522. XCTAssertEqualObjects(request.oobCode, fakeCode);
  523. dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
  524. id mockEmailLinkSignInResponse = OCMClassMock([FIREmailLinkSignInResponse class]);
  525. [self stubTokensWithMockResponse:mockEmailLinkSignInResponse];
  526. callback(mockEmailLinkSignInResponse, nil);
  527. OCMStub([mockEmailLinkSignInResponse refreshToken]).andReturn(kRefreshToken);
  528. });
  529. });
  530. [self expectGetAccountInfo];
  531. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  532. [[FIRAuth auth] signOut:NULL];
  533. [[FIRAuth auth]
  534. signInWithEmail:kEmail
  535. link:kFakeEmailSignInDeeplink
  536. completion:^(FIRAuthDataResult *_Nullable authResult, NSError *_Nullable error) {
  537. XCTAssertTrue([NSThread isMainThread]);
  538. XCTAssertNotNil(authResult.user);
  539. XCTAssertEqualObjects(authResult.user.refreshToken, kRefreshToken);
  540. XCTAssertFalse(authResult.user.anonymous);
  541. XCTAssertEqualObjects(authResult.user.email, kEmail);
  542. XCTAssertNil(error);
  543. [expectation fulfill];
  544. }];
  545. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  546. [self assertUser:[FIRAuth auth].currentUser];
  547. OCMVerifyAll(_mockBackend);
  548. }
  549. /** @fn testSignInWithEmailLinkFailure
  550. @brief Tests the flow of a failed @c signInWithEmail:link:completion: call.
  551. */
  552. - (void)testSignInWithEmailLinkFailure {
  553. OCMExpect([_mockBackend emailLinkSignin:[OCMArg any] callback:[OCMArg any]])
  554. ._andDispatchError2([FIRAuthErrorUtils invalidActionCodeErrorWithMessage:nil]);
  555. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  556. [[FIRAuth auth] signOut:NULL];
  557. [[FIRAuth auth]
  558. signInWithEmail:kEmail
  559. link:kFakeEmailSignInlink
  560. completion:^(FIRAuthDataResult *_Nullable authResult, NSError *_Nullable error) {
  561. XCTAssertTrue([NSThread isMainThread]);
  562. XCTAssertEqual(error.code, FIRAuthErrorCodeInvalidActionCode);
  563. [expectation fulfill];
  564. }];
  565. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  566. OCMVerifyAll(_mockBackend);
  567. }
  568. #if TARGET_OS_IOS && !TARGET_OS_MACCATALYST
  569. /** @fn testSignInWithEmailPasswordWithRecaptchaSuccess
  570. @brief Tests the flow of a successful @c signInWithEmail:password:completion: call.
  571. */
  572. - (void)testSignInWithEmailPasswordWithRecaptchaSuccess {
  573. id mockVerifier = OCMClassMock([FIRAuthRecaptchaVerifier class]);
  574. OCMStub([mockVerifier sharedRecaptchaVerifier:[FIRAuth auth]]).andReturn(mockVerifier);
  575. OCMExpect([mockVerifier enablementStatusForProvider:FIRAuthRecaptchaProviderPassword])
  576. .andReturn(YES);
  577. FIRVerifyPasswordRequest *constRequestWithRecaptchaToken =
  578. [[FIRVerifyPasswordRequest alloc] initWithEmail:kEmail
  579. password:kFakePassword
  580. requestConfiguration:[FIRAuth auth].requestConfiguration];
  581. [constRequestWithRecaptchaToken injectRecaptchaFields:kFakeRecaptchaResponse
  582. recaptchaVersion:kFakeRecaptchaVersion];
  583. OCMStub([mockVerifier
  584. injectRecaptchaFields:[OCMArg any]
  585. provider:FIRAuthRecaptchaProviderPassword
  586. action:FIRAuthRecaptchaActionSignInWithPassword
  587. completion:([OCMArg invokeBlockWithArgs:constRequestWithRecaptchaToken, nil])]);
  588. OCMExpect([_mockBackend verifyPassword:[OCMArg any] callback:[OCMArg any]])
  589. .andCallBlock2(^(FIRVerifyPasswordRequest *_Nullable request,
  590. FIRVerifyPasswordResponseCallback callback) {
  591. XCTAssertEqualObjects(request.APIKey, kAPIKey);
  592. XCTAssertEqualObjects(request.email, kEmail);
  593. XCTAssertEqualObjects(request.password, kFakePassword);
  594. XCTAssertTrue(request.returnSecureToken);
  595. dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
  596. id mockVerifyPasswordResponse = OCMClassMock([FIRVerifyPasswordResponse class]);
  597. [self stubTokensWithMockResponse:mockVerifyPasswordResponse];
  598. callback(mockVerifyPasswordResponse, nil);
  599. });
  600. });
  601. [self expectGetAccountInfo];
  602. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  603. [[FIRAuth auth] signOut:NULL];
  604. [[FIRAuth auth] signInWithEmail:kEmail
  605. password:kFakePassword
  606. completion:^(FIRAuthDataResult *_Nullable result, NSError *_Nullable error) {
  607. XCTAssertTrue([NSThread isMainThread]);
  608. [self assertUser:result.user];
  609. XCTAssertNil(error);
  610. [expectation fulfill];
  611. }];
  612. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  613. [self assertUser:[FIRAuth auth].currentUser];
  614. }
  615. /** @fn testSignInWithEmailPasswordWithRecaptchaFallbackSuccess
  616. @brief Tests the flow of a successful @c signInWithEmail:password:completion: call.
  617. */
  618. - (void)testSignInWithEmailPasswordWithRecaptchaFallbackSuccess {
  619. id mockVerifier = OCMClassMock([FIRAuthRecaptchaVerifier class]);
  620. OCMStub([mockVerifier sharedRecaptchaVerifier:[FIRAuth auth]]).andReturn(mockVerifier);
  621. OCMExpect([mockVerifier enablementStatusForProvider:FIRAuthRecaptchaProviderPassword])
  622. .andReturn(NO);
  623. FIRVerifyPasswordRequest *constRequestWithRecaptchaToken =
  624. [[FIRVerifyPasswordRequest alloc] initWithEmail:kEmail
  625. password:kFakePassword
  626. requestConfiguration:[FIRAuth auth].requestConfiguration];
  627. [constRequestWithRecaptchaToken injectRecaptchaFields:kFakeRecaptchaResponse
  628. recaptchaVersion:kFakeRecaptchaVersion];
  629. OCMStub([mockVerifier
  630. injectRecaptchaFields:[OCMArg any]
  631. provider:FIRAuthRecaptchaProviderPassword
  632. action:FIRAuthRecaptchaActionSignInWithPassword
  633. completion:([OCMArg invokeBlockWithArgs:constRequestWithRecaptchaToken, nil])]);
  634. OCMExpect([_mockBackend verifyPassword:[OCMArg any] callback:[OCMArg any]])
  635. .andCallBlock2(^(FIRVerifyPasswordRequest *_Nullable request,
  636. FIRVerifyPasswordResponseCallback callback) {
  637. XCTAssertEqualObjects(request.APIKey, kAPIKey);
  638. XCTAssertEqualObjects(request.email, kEmail);
  639. XCTAssertEqualObjects(request.password, kFakePassword);
  640. XCTAssertTrue(request.returnSecureToken);
  641. NSError *underlyingError =
  642. [[NSError alloc] initWithDomain:FIRAuthErrorDomain
  643. code:FIRAuthErrorCodeInternalError
  644. userInfo:@{
  645. FIRAuthErrorUserInfoDeserializedResponseKey :
  646. @{@"message" : @"MISSING_RECAPTCHA_TOKEN"}
  647. }];
  648. NSError *error = [[NSError alloc] initWithDomain:FIRAuthErrorDomain
  649. code:FIRAuthErrorCodeInternalError
  650. userInfo:@{NSUnderlyingErrorKey : underlyingError}];
  651. dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
  652. callback(nil, error);
  653. });
  654. });
  655. OCMExpect([_mockBackend verifyPassword:[OCMArg any] callback:[OCMArg any]])
  656. .andCallBlock2(^(FIRVerifyPasswordRequest *_Nullable request,
  657. FIRVerifyPasswordResponseCallback callback) {
  658. XCTAssertEqualObjects(request.APIKey, kAPIKey);
  659. XCTAssertEqualObjects(request.email, kEmail);
  660. XCTAssertEqualObjects(request.password, kFakePassword);
  661. XCTAssertTrue(request.returnSecureToken);
  662. dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
  663. id mockVerifyPasswordResponse = OCMClassMock([FIRVerifyPasswordResponse class]);
  664. [self stubTokensWithMockResponse:mockVerifyPasswordResponse];
  665. callback(mockVerifyPasswordResponse, nil);
  666. });
  667. });
  668. [self expectGetAccountInfo];
  669. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  670. [[FIRAuth auth] signOut:NULL];
  671. [[FIRAuth auth] signInWithEmail:kEmail
  672. password:kFakePassword
  673. completion:^(FIRAuthDataResult *_Nullable result, NSError *_Nullable error) {
  674. XCTAssertTrue([NSThread isMainThread]);
  675. [self assertUser:result.user];
  676. XCTAssertNil(error);
  677. [expectation fulfill];
  678. }];
  679. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  680. [self assertUser:[FIRAuth auth].currentUser];
  681. }
  682. #endif
  683. /** @fn testSignInWithEmailPasswordSuccess
  684. @brief Tests the flow of a successful @c signInWithEmail:password:completion: call.
  685. */
  686. - (void)testSignInWithEmailPasswordSuccess {
  687. OCMExpect([_mockBackend verifyPassword:[OCMArg any] callback:[OCMArg any]])
  688. .andCallBlock2(^(FIRVerifyPasswordRequest *_Nullable request,
  689. FIRVerifyPasswordResponseCallback callback) {
  690. XCTAssertEqualObjects(request.APIKey, kAPIKey);
  691. XCTAssertEqualObjects(request.email, kEmail);
  692. XCTAssertEqualObjects(request.password, kFakePassword);
  693. XCTAssertTrue(request.returnSecureToken);
  694. dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
  695. id mockVerifyPasswordResponse = OCMClassMock([FIRVerifyPasswordResponse class]);
  696. [self stubTokensWithMockResponse:mockVerifyPasswordResponse];
  697. callback(mockVerifyPasswordResponse, nil);
  698. });
  699. });
  700. [self expectGetAccountInfo];
  701. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  702. [[FIRAuth auth] signOut:NULL];
  703. [[FIRAuth auth] signInWithEmail:kEmail
  704. password:kFakePassword
  705. completion:^(FIRAuthDataResult *_Nullable result, NSError *_Nullable error) {
  706. XCTAssertTrue([NSThread isMainThread]);
  707. [self assertUser:result.user];
  708. XCTAssertNil(error);
  709. [expectation fulfill];
  710. }];
  711. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  712. [self assertUser:[FIRAuth auth].currentUser];
  713. OCMVerifyAll(_mockBackend);
  714. }
  715. /** @fn testSignInWithEmailPasswordFailure
  716. @brief Tests the flow of a failed @c signInWithEmail:password:completion: call.
  717. */
  718. - (void)testSignInWithEmailPasswordFailure {
  719. OCMExpect([_mockBackend verifyPassword:[OCMArg any] callback:[OCMArg any]])
  720. .andDispatchError2([FIRAuthErrorUtils wrongPasswordErrorWithMessage:nil]);
  721. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  722. [[FIRAuth auth] signOut:NULL];
  723. [[FIRAuth auth] signInWithEmail:kEmail
  724. password:kFakePassword
  725. completion:^(FIRAuthDataResult *_Nullable result, NSError *_Nullable error) {
  726. XCTAssertTrue([NSThread isMainThread]);
  727. XCTAssertNil(result.user);
  728. XCTAssertEqual(error.code, FIRAuthErrorCodeWrongPassword);
  729. XCTAssertNotNil(error.userInfo[NSLocalizedDescriptionKey]);
  730. [expectation fulfill];
  731. }];
  732. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  733. XCTAssertNil([FIRAuth auth].currentUser);
  734. OCMVerifyAll(_mockBackend);
  735. }
  736. /** @fn testSignInAndRetrieveDataWithEmailPasswordSuccess
  737. @brief Tests the flow of a successful @c signInAndRetrieveDataWithEmail:password:completion:
  738. call.
  739. */
  740. - (void)testSignInAndRetrieveDataWithEmailPasswordSuccess {
  741. OCMExpect([_mockBackend verifyPassword:[OCMArg any] callback:[OCMArg any]])
  742. .andCallBlock2(^(FIRVerifyPasswordRequest *_Nullable request,
  743. FIRVerifyPasswordResponseCallback callback) {
  744. XCTAssertEqualObjects(request.APIKey, kAPIKey);
  745. XCTAssertEqualObjects(request.email, kEmail);
  746. XCTAssertEqualObjects(request.password, kFakePassword);
  747. XCTAssertTrue(request.returnSecureToken);
  748. dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
  749. id mockVerifyPasswordResponse = OCMClassMock([FIRVerifyPasswordResponse class]);
  750. [self stubTokensWithMockResponse:mockVerifyPasswordResponse];
  751. callback(mockVerifyPasswordResponse, nil);
  752. });
  753. });
  754. [self expectGetAccountInfo];
  755. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  756. [[FIRAuth auth] signOut:NULL];
  757. [[FIRAuth auth]
  758. signInWithEmail:kEmail
  759. password:kFakePassword
  760. completion:^(FIRAuthDataResult *_Nullable result, NSError *_Nullable error) {
  761. XCTAssertTrue([NSThread isMainThread]);
  762. [self assertUser:result.user];
  763. XCTAssertFalse(result.additionalUserInfo.isNewUser);
  764. XCTAssertEqualObjects(result.additionalUserInfo.providerID, FIREmailAuthProviderID);
  765. XCTAssertNil(error);
  766. [expectation fulfill];
  767. }];
  768. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  769. [self assertUser:[FIRAuth auth].currentUser];
  770. OCMVerifyAll(_mockBackend);
  771. }
  772. /** @fn testSignInAndRetrieveDataWithEmailPasswordFailure
  773. @brief Tests the flow of a failed @c signInAndRetrieveDataWithEmail:password:completion: call.
  774. */
  775. - (void)testSignInAndRetrieveDataWithEmailPasswordFailure {
  776. OCMExpect([_mockBackend verifyPassword:[OCMArg any] callback:[OCMArg any]])
  777. .andDispatchError2([FIRAuthErrorUtils wrongPasswordErrorWithMessage:nil]);
  778. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  779. [[FIRAuth auth] signOut:NULL];
  780. [[FIRAuth auth] signInWithEmail:kEmail
  781. password:kFakePassword
  782. completion:^(FIRAuthDataResult *_Nullable result, NSError *_Nullable error) {
  783. XCTAssertTrue([NSThread isMainThread]);
  784. XCTAssertNil(result);
  785. XCTAssertEqual(error.code, FIRAuthErrorCodeWrongPassword);
  786. XCTAssertNotNil(error.userInfo[NSLocalizedDescriptionKey]);
  787. [expectation fulfill];
  788. }];
  789. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  790. XCTAssertNil([FIRAuth auth].currentUser);
  791. OCMVerifyAll(_mockBackend);
  792. }
  793. /** @fn testResetPasswordSuccess
  794. @brief Tests the flow of a successful @c confirmPasswordResetWithCode:newPassword:completion:
  795. call.
  796. */
  797. - (void)testResetPasswordSuccess {
  798. NSString *fakeEmail = @"fakeEmail";
  799. NSString *fakeCode = @"fakeCode";
  800. NSString *fakeNewPassword = @"fakeNewPassword";
  801. OCMExpect([_mockBackend resetPassword:[OCMArg any] callback:[OCMArg any]])
  802. .andCallBlock2(
  803. ^(FIRResetPasswordRequest *_Nullable request, FIRResetPasswordCallback callback) {
  804. XCTAssertEqualObjects(request.APIKey, kAPIKey);
  805. XCTAssertEqualObjects(request.oobCode, fakeCode);
  806. XCTAssertEqualObjects(request.updatedPassword, fakeNewPassword);
  807. dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
  808. id mockResetPasswordResponse = OCMClassMock([FIRResetPasswordResponse class]);
  809. OCMStub([mockResetPasswordResponse email]).andReturn(fakeEmail);
  810. callback(mockResetPasswordResponse, nil);
  811. });
  812. });
  813. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  814. [[FIRAuth auth] signOut:NULL];
  815. [[FIRAuth auth] confirmPasswordResetWithCode:fakeCode
  816. newPassword:fakeNewPassword
  817. completion:^(NSError *_Nullable error) {
  818. XCTAssertTrue([NSThread isMainThread]);
  819. XCTAssertNil(error);
  820. [expectation fulfill];
  821. }];
  822. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  823. OCMVerifyAll(_mockBackend);
  824. }
  825. /** @fn testResetPasswordFailure
  826. @brief Tests the flow of a failed @c confirmPasswordResetWithCode:newPassword:completion:
  827. call.
  828. */
  829. - (void)testResetPasswordFailure {
  830. NSString *fakeCode = @"fakeCode";
  831. NSString *fakeNewPassword = @"fakeNewPassword";
  832. OCMExpect([_mockBackend resetPassword:[OCMArg any] callback:[OCMArg any]])
  833. ._andDispatchError2([FIRAuthErrorUtils invalidActionCodeErrorWithMessage:nil]);
  834. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  835. [[FIRAuth auth] signOut:NULL];
  836. [[FIRAuth auth] confirmPasswordResetWithCode:fakeCode
  837. newPassword:fakeNewPassword
  838. completion:^(NSError *_Nullable error) {
  839. XCTAssertTrue([NSThread isMainThread]);
  840. XCTAssertEqual(error.code, FIRAuthErrorCodeInvalidActionCode);
  841. [expectation fulfill];
  842. }];
  843. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  844. OCMVerifyAll(_mockBackend);
  845. }
  846. /** @fn testCheckActionCodeSuccess
  847. @brief Tests the flow of a successful @c checkActionCode:completion call.
  848. */
  849. - (void)testCheckActionCodeSuccess {
  850. NSString *verifyEmailRequestType = @"VERIFY_EMAIL";
  851. NSString *fakeEmail = @"fakeEmail";
  852. NSString *fakeNewEmail = @"fakeNewEmail";
  853. NSString *fakeCode = @"fakeCode";
  854. OCMExpect([_mockBackend resetPassword:[OCMArg any] callback:[OCMArg any]])
  855. .andCallBlock2(
  856. ^(FIRResetPasswordRequest *_Nullable request, FIRResetPasswordCallback callback) {
  857. XCTAssertEqualObjects(request.APIKey, kAPIKey);
  858. XCTAssertEqualObjects(request.oobCode, fakeCode);
  859. dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
  860. id mockResetPasswordResponse = OCMClassMock([FIRResetPasswordResponse class]);
  861. OCMStub([mockResetPasswordResponse email]).andReturn(fakeEmail);
  862. OCMStub([mockResetPasswordResponse verifiedEmail]).andReturn(fakeNewEmail);
  863. OCMStubRecorder *stub =
  864. OCMStub([(FIRResetPasswordResponse *)mockResetPasswordResponse requestType]);
  865. stub.andReturn(verifyEmailRequestType);
  866. callback(mockResetPasswordResponse, nil);
  867. });
  868. });
  869. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  870. [[FIRAuth auth] checkActionCode:fakeCode
  871. completion:^(FIRActionCodeInfo *_Nullable info, NSError *_Nullable error) {
  872. XCTAssertTrue([NSThread isMainThread]);
  873. XCTAssertNil(error);
  874. XCTAssertEqual(info.operation, FIRActionCodeOperationVerifyEmail);
  875. XCTAssert([fakeNewEmail isEqualToString:info.email]);
  876. [expectation fulfill];
  877. }];
  878. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  879. OCMVerifyAll(_mockBackend);
  880. }
  881. /** @fn testCheckActionCodeFailure
  882. @brief Tests the flow of a failed @c checkActionCode:completion call.
  883. */
  884. - (void)testCheckActionCodeFailure {
  885. NSString *fakeCode = @"fakeCode";
  886. OCMExpect([_mockBackend resetPassword:[OCMArg any] callback:[OCMArg any]])
  887. ._andDispatchError2([FIRAuthErrorUtils expiredActionCodeErrorWithMessage:nil]);
  888. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  889. [[FIRAuth auth] signOut:NULL];
  890. [[FIRAuth auth] checkActionCode:fakeCode
  891. completion:^(FIRActionCodeInfo *_Nullable info, NSError *_Nullable error) {
  892. XCTAssertTrue([NSThread isMainThread]);
  893. XCTAssertNotNil(error);
  894. XCTAssertEqual(error.code, FIRAuthErrorCodeExpiredActionCode);
  895. [expectation fulfill];
  896. }];
  897. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  898. OCMVerifyAll(_mockBackend);
  899. }
  900. /** @fn testApplyActionCodeSuccess
  901. @brief Tests the flow of a successful @c applyActionCode:completion call.
  902. */
  903. - (void)testApplyActionCodeSuccess {
  904. NSString *fakeCode = @"fakeCode";
  905. OCMExpect([_mockBackend setAccountInfo:[OCMArg any] callback:[OCMArg any]])
  906. .andCallBlock2(^(FIRSetAccountInfoRequest *_Nullable request,
  907. FIRSetAccountInfoResponseCallback callback) {
  908. XCTAssertEqualObjects(request.APIKey, kAPIKey);
  909. XCTAssertEqualObjects(request.OOBCode, fakeCode);
  910. dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
  911. id mockSetAccountInfoResponse = OCMClassMock([FIRSetAccountInfoResponse class]);
  912. callback(mockSetAccountInfoResponse, nil);
  913. });
  914. });
  915. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  916. [[FIRAuth auth] applyActionCode:fakeCode
  917. completion:^(NSError *_Nullable error) {
  918. XCTAssertTrue([NSThread isMainThread]);
  919. XCTAssertNil(error);
  920. [expectation fulfill];
  921. }];
  922. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  923. OCMVerifyAll(_mockBackend);
  924. }
  925. /** @fn testApplyActionCodeFailure
  926. @brief Tests the flow of a failed @c checkActionCode:completion call.
  927. */
  928. - (void)testApplyActionCodeFailure {
  929. NSString *fakeCode = @"fakeCode";
  930. OCMExpect([_mockBackend setAccountInfo:[OCMArg any] callback:[OCMArg any]])
  931. ._andDispatchError2([FIRAuthErrorUtils invalidActionCodeErrorWithMessage:nil]);
  932. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  933. [[FIRAuth auth] signOut:NULL];
  934. [[FIRAuth auth] applyActionCode:fakeCode
  935. completion:^(NSError *_Nullable error) {
  936. XCTAssertTrue([NSThread isMainThread]);
  937. XCTAssertNotNil(error);
  938. XCTAssertEqual(error.code, FIRAuthErrorCodeInvalidActionCode);
  939. [expectation fulfill];
  940. }];
  941. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  942. OCMVerifyAll(_mockBackend);
  943. }
  944. /** @fn testVerifyPasswordResetCodeSuccess
  945. @brief Tests the flow of a successful @c verifyPasswordResetCode:completion call.
  946. */
  947. - (void)testVerifyPasswordResetCodeSuccess {
  948. NSString *passwordResetRequestType = @"PASSWORD_RESET";
  949. NSString *fakeEmail = @"fakeEmail";
  950. NSString *fakeCode = @"fakeCode";
  951. OCMExpect([_mockBackend resetPassword:[OCMArg any] callback:[OCMArg any]])
  952. .andCallBlock2(
  953. ^(FIRResetPasswordRequest *_Nullable request, FIRResetPasswordCallback callback) {
  954. XCTAssertEqualObjects(request.APIKey, kAPIKey);
  955. XCTAssertEqualObjects(request.oobCode, fakeCode);
  956. dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
  957. id mockResetPasswordResponse = OCMClassMock([FIRResetPasswordResponse class]);
  958. OCMStub([mockResetPasswordResponse email]).andReturn(fakeEmail);
  959. OCMStubRecorder *stub =
  960. OCMStub([(FIRResetPasswordResponse *)mockResetPasswordResponse requestType]);
  961. stub.andReturn(passwordResetRequestType);
  962. callback(mockResetPasswordResponse, nil);
  963. });
  964. });
  965. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  966. [[FIRAuth auth] verifyPasswordResetCode:fakeCode
  967. completion:^(NSString *_Nullable email, NSError *_Nullable error) {
  968. XCTAssertTrue([NSThread isMainThread]);
  969. XCTAssertNil(error);
  970. XCTAssertEqual(email, fakeEmail);
  971. [expectation fulfill];
  972. }];
  973. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  974. OCMVerifyAll(_mockBackend);
  975. }
  976. /** @fn testVerifyPasswordResetCodeFailure
  977. @brief Tests the flow of a failed @c verifyPasswordResetCode:completion call.
  978. */
  979. - (void)testVeridyPasswordResetCodeFailure {
  980. NSString *fakeCode = @"fakeCode";
  981. OCMExpect([_mockBackend resetPassword:[OCMArg any] callback:[OCMArg any]])
  982. ._andDispatchError2([FIRAuthErrorUtils invalidActionCodeErrorWithMessage:nil]);
  983. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  984. [[FIRAuth auth] signOut:NULL];
  985. [[FIRAuth auth] verifyPasswordResetCode:fakeCode
  986. completion:^(NSString *_Nullable email, NSError *_Nullable error) {
  987. XCTAssertTrue([NSThread isMainThread]);
  988. XCTAssertNotNil(error);
  989. XCTAssertEqual(error.code, FIRAuthErrorCodeInvalidActionCode);
  990. [expectation fulfill];
  991. }];
  992. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  993. OCMVerifyAll(_mockBackend);
  994. }
  995. /** @fn testSignInWithEmailLinkCredentialSuccess
  996. @brief Tests the flow of a successfully @c signInWithCredential:completion: call with an
  997. email sign-in link credential using FIREmailAuthProvider.
  998. */
  999. - (void)testSignInWithEmailLinkCredentialSuccess {
  1000. NSString *fakeCode = @"testoobcode";
  1001. OCMExpect([_mockBackend emailLinkSignin:[OCMArg any] callback:[OCMArg any]])
  1002. .andCallBlock2(^(FIREmailLinkSignInRequest *_Nullable request,
  1003. FIREmailLinkSigninResponseCallback callback) {
  1004. XCTAssertEqualObjects(request.email, kEmail);
  1005. XCTAssertEqualObjects(request.oobCode, fakeCode);
  1006. dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
  1007. id mockEmailLinkSigninResponse = OCMClassMock([FIREmailLinkSignInResponse class]);
  1008. [self stubTokensWithMockResponse:mockEmailLinkSigninResponse];
  1009. callback(mockEmailLinkSigninResponse, nil);
  1010. });
  1011. });
  1012. [self expectGetAccountInfo];
  1013. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  1014. [[FIRAuth auth] signOut:NULL];
  1015. FIRAuthCredential *emailCredential =
  1016. [FIREmailAuthProvider credentialWithEmail:kEmail link:kFakeEmailSignInlink];
  1017. [[FIRAuth auth]
  1018. signInWithCredential:emailCredential
  1019. completion:^(FIRAuthDataResult *_Nullable authResult, NSError *_Nullable error) {
  1020. XCTAssertTrue([NSThread isMainThread]);
  1021. XCTAssertNotNil(authResult.user);
  1022. XCTAssertEqualObjects(authResult.user.refreshToken, kRefreshToken);
  1023. XCTAssertFalse(authResult.user.anonymous);
  1024. XCTAssertEqualObjects(authResult.user.email, kEmail);
  1025. XCTAssertNil(error);
  1026. [expectation fulfill];
  1027. }];
  1028. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  1029. [self assertUser:[FIRAuth auth].currentUser];
  1030. OCMVerifyAll(_mockBackend);
  1031. }
  1032. /** @fn testSignInWithEmailLinkCredentialFailure
  1033. @brief Tests the flow of a failed @c signInWithCredential:completion: call with an
  1034. email-email sign-in link credential using FIREmailAuthProvider.
  1035. */
  1036. - (void)testSignInWithEmailLinkCredentialFailure {
  1037. OCMExpect([_mockBackend emailLinkSignin:[OCMArg any] callback:[OCMArg any]])
  1038. .andDispatchError2([FIRAuthErrorUtils userDisabledErrorWithMessage:nil]);
  1039. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  1040. [[FIRAuth auth] signOut:NULL];
  1041. FIRAuthCredential *emailCredential =
  1042. [FIREmailAuthProvider credentialWithEmail:kEmail link:kFakeEmailSignInlink];
  1043. [[FIRAuth auth]
  1044. signInWithCredential:emailCredential
  1045. completion:^(FIRAuthDataResult *_Nullable result, NSError *_Nullable error) {
  1046. XCTAssertTrue([NSThread isMainThread]);
  1047. XCTAssertNil(result);
  1048. XCTAssertEqual(error.code, FIRAuthErrorCodeUserDisabled);
  1049. XCTAssertNotNil(error.userInfo[NSLocalizedDescriptionKey]);
  1050. [expectation fulfill];
  1051. }];
  1052. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  1053. XCTAssertNil([FIRAuth auth].currentUser);
  1054. OCMVerifyAll(_mockBackend);
  1055. }
  1056. /** @fn testSignInWithEmailCredentialSuccess
  1057. @brief Tests the flow of a successfully @c signInWithCredential:completion: call with an
  1058. email-password credential.
  1059. */
  1060. - (void)testSignInWithEmailCredentialSuccess {
  1061. OCMExpect([_mockBackend verifyPassword:[OCMArg any] callback:[OCMArg any]])
  1062. .andCallBlock2(^(FIRVerifyPasswordRequest *_Nullable request,
  1063. FIRVerifyPasswordResponseCallback callback) {
  1064. XCTAssertEqualObjects(request.APIKey, kAPIKey);
  1065. XCTAssertEqualObjects(request.email, kEmail);
  1066. XCTAssertEqualObjects(request.password, kFakePassword);
  1067. XCTAssertTrue(request.returnSecureToken);
  1068. dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
  1069. id mockVerifyPasswordResponse = OCMClassMock([FIRVerifyPasswordResponse class]);
  1070. [self stubTokensWithMockResponse:mockVerifyPasswordResponse];
  1071. callback(mockVerifyPasswordResponse, nil);
  1072. });
  1073. });
  1074. [self expectGetAccountInfo];
  1075. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  1076. [[FIRAuth auth] signOut:NULL];
  1077. FIRAuthCredential *emailCredential = [FIREmailAuthProvider credentialWithEmail:kEmail
  1078. password:kFakePassword];
  1079. [[FIRAuth auth]
  1080. signInWithCredential:emailCredential
  1081. completion:^(FIRAuthDataResult *_Nullable result, NSError *_Nullable error) {
  1082. XCTAssertTrue([NSThread isMainThread]);
  1083. [self assertUser:result.user];
  1084. XCTAssertNil(error);
  1085. [expectation fulfill];
  1086. }];
  1087. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  1088. [self assertUser:[FIRAuth auth].currentUser];
  1089. OCMVerifyAll(_mockBackend);
  1090. }
  1091. /** @fn testSignInWithEmailCredentialFailure
  1092. @brief Tests the flow of a failed @c signInWithCredential:completion: call with an
  1093. email-password credential.
  1094. */
  1095. - (void)testSignInWithEmailCredentialFailure {
  1096. OCMExpect([_mockBackend verifyPassword:[OCMArg any] callback:[OCMArg any]])
  1097. .andDispatchError2([FIRAuthErrorUtils userDisabledErrorWithMessage:nil]);
  1098. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  1099. [[FIRAuth auth] signOut:NULL];
  1100. FIRAuthCredential *emailCredential = [FIREmailAuthProvider credentialWithEmail:kEmail
  1101. password:kFakePassword];
  1102. [[FIRAuth auth]
  1103. signInWithCredential:emailCredential
  1104. completion:^(FIRAuthDataResult *_Nullable result, NSError *_Nullable error) {
  1105. XCTAssertTrue([NSThread isMainThread]);
  1106. XCTAssertNil(result);
  1107. XCTAssertEqual(error.code, FIRAuthErrorCodeUserDisabled);
  1108. XCTAssertNotNil(error.userInfo[NSLocalizedDescriptionKey]);
  1109. [expectation fulfill];
  1110. }];
  1111. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  1112. XCTAssertNil([FIRAuth auth].currentUser);
  1113. OCMVerifyAll(_mockBackend);
  1114. }
  1115. /** @fn testSignInWithEmailCredentialEmptyPassword
  1116. @brief Tests the flow of a failed @c signInWithCredential:completion: call with an
  1117. email-password credential using an empty password. This error occurs on the client side,
  1118. so there is no need to fake an RPC response.
  1119. */
  1120. - (void)testSignInWithEmailCredentialEmptyPassword {
  1121. NSString *emptyString = @"";
  1122. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  1123. [[FIRAuth auth] signOut:NULL];
  1124. FIRAuthCredential *emailCredential = [FIREmailAuthProvider credentialWithEmail:kEmail
  1125. password:emptyString];
  1126. [[FIRAuth auth]
  1127. signInWithCredential:emailCredential
  1128. completion:^(FIRAuthDataResult *_Nullable result, NSError *_Nullable error) {
  1129. XCTAssertTrue([NSThread isMainThread]);
  1130. XCTAssertEqual(error.code, FIRAuthErrorCodeWrongPassword);
  1131. [expectation fulfill];
  1132. }];
  1133. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  1134. }
  1135. #if TARGET_OS_IOS
  1136. /** @fn testSignInWithProviderSuccess
  1137. @brief Tests a successful @c signInWithProvider:UIDelegate:completion: call with an OAuth
  1138. provider configured for Google.
  1139. */
  1140. - (void)testSignInWithProviderSuccess {
  1141. OCMExpect([_mockBackend verifyAssertion:[OCMArg any] callback:[OCMArg any]])
  1142. .andCallBlock2(^(FIRVerifyAssertionRequest *_Nullable request,
  1143. FIRVerifyAssertionResponseCallback callback) {
  1144. XCTAssertEqualObjects(request.APIKey, kAPIKey);
  1145. XCTAssertEqualObjects(request.providerID, FIRGoogleAuthProviderID);
  1146. XCTAssertTrue(request.returnSecureToken);
  1147. dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
  1148. id mockVerifyAssertionResponse = OCMClassMock([FIRVerifyAssertionResponse class]);
  1149. OCMStub([mockVerifyAssertionResponse federatedID]).andReturn(kGoogleID);
  1150. OCMStub([mockVerifyAssertionResponse providerID]).andReturn(FIRGoogleAuthProviderID);
  1151. OCMStub([mockVerifyAssertionResponse localID]).andReturn(kLocalID);
  1152. OCMStub([mockVerifyAssertionResponse displayName]).andReturn(kGoogleDisplayName);
  1153. [self stubTokensWithMockResponse:mockVerifyAssertionResponse];
  1154. callback(mockVerifyAssertionResponse, nil);
  1155. });
  1156. });
  1157. [self expectGetAccountInfoGoogle];
  1158. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  1159. [[FIRAuth auth] signOut:NULL];
  1160. id mockProvider = OCMClassMock([FIROAuthProvider class]);
  1161. OCMExpect([mockProvider getCredentialWithUIDelegate:[OCMArg any] completion:[OCMArg any]])
  1162. .andCallBlock2(^(id<FIRAuthUIDelegate> delegate, FIRAuthCredentialCallback callback) {
  1163. dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
  1164. FIROAuthCredential *credential =
  1165. [[FIROAuthCredential alloc] initWithProviderID:FIRGoogleAuthProviderID
  1166. sessionID:kOAuthSessionID
  1167. OAuthResponseURLString:kOAuthRequestURI];
  1168. callback(credential, nil);
  1169. });
  1170. });
  1171. [[FIRAuth auth]
  1172. signInWithProvider:mockProvider
  1173. UIDelegate:nil
  1174. completion:^(FIRAuthDataResult *_Nullable authResult, NSError *_Nullable error) {
  1175. XCTAssertTrue([NSThread isMainThread]);
  1176. [self assertUserGoogle:authResult.user];
  1177. XCTAssertNil(error);
  1178. [expectation fulfill];
  1179. }];
  1180. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  1181. OCMVerifyAll(_mockBackend);
  1182. }
  1183. /** @fn testSignInWithProviderFailure
  1184. @brief Tests a failed @c signInWithProvider:UIDelegate:completion: call with the error code
  1185. FIRAuthErrorCodeWebSignInUserInteractionFailure.
  1186. */
  1187. - (void)testSignInWithProviderFailure {
  1188. OCMExpect([_mockBackend verifyAssertion:[OCMArg any] callback:[OCMArg any]])
  1189. .andDispatchError2([FIRAuthErrorUtils
  1190. webSignInUserInteractionFailureWithReason:kFakeWebSignInUserInteractionFailureReason]);
  1191. [[FIRAuth auth] signOut:NULL];
  1192. id mockProvider = OCMClassMock([FIROAuthProvider class]);
  1193. OCMExpect([mockProvider getCredentialWithUIDelegate:[OCMArg any] completion:[OCMArg any]])
  1194. .andCallBlock2(^(id<FIRAuthUIDelegate> delegate, FIRAuthCredentialCallback callback) {
  1195. dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
  1196. FIROAuthCredential *credential =
  1197. [[FIROAuthCredential alloc] initWithProviderID:FIRGoogleAuthProviderID
  1198. sessionID:kOAuthSessionID
  1199. OAuthResponseURLString:kOAuthRequestURI];
  1200. callback(credential, nil);
  1201. });
  1202. });
  1203. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  1204. [[FIRAuth auth]
  1205. signInWithProvider:mockProvider
  1206. UIDelegate:nil
  1207. completion:^(FIRAuthDataResult *_Nullable authResult, NSError *_Nullable error) {
  1208. XCTAssertTrue([NSThread isMainThread]);
  1209. XCTAssertNil(authResult);
  1210. XCTAssertEqual(error.code, FIRAuthErrorCodeWebSignInUserInteractionFailure);
  1211. XCTAssertEqualObjects(error.userInfo[NSLocalizedFailureReasonErrorKey],
  1212. kFakeWebSignInUserInteractionFailureReason);
  1213. [expectation fulfill];
  1214. }];
  1215. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  1216. OCMVerifyAll(_mockBackend);
  1217. }
  1218. /** @fn testSignInWithGoogleAccountExistsError
  1219. @brief Tests the flow of a failed @c signInWithCredential:completion: with a Google credential
  1220. where the backend returns a needs @needConfirmation equal to true. An
  1221. FIRAuthErrorCodeAccountExistsWithDifferentCredential error should be thrown.
  1222. */
  1223. - (void)testSignInWithGoogleAccountExistsError {
  1224. OCMExpect([_mockBackend verifyAssertion:[OCMArg any] callback:[OCMArg any]])
  1225. .andCallBlock2(^(FIRVerifyAssertionRequest *_Nullable request,
  1226. FIRVerifyAssertionResponseCallback callback) {
  1227. XCTAssertEqualObjects(request.APIKey, kAPIKey);
  1228. XCTAssertEqualObjects(request.providerID, FIRGoogleAuthProviderID);
  1229. XCTAssertEqualObjects(request.providerIDToken, kGoogleIDToken);
  1230. XCTAssertEqualObjects(request.providerAccessToken, kGoogleAccessToken);
  1231. XCTAssertTrue(request.returnSecureToken);
  1232. dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
  1233. id mockVerifyAssertionResponse = OCMClassMock([FIRVerifyAssertionResponse class]);
  1234. OCMStub([mockVerifyAssertionResponse needConfirmation]).andReturn(YES);
  1235. OCMStub([mockVerifyAssertionResponse email]).andReturn(kEmail);
  1236. [self stubTokensWithMockResponse:mockVerifyAssertionResponse];
  1237. callback(mockVerifyAssertionResponse, nil);
  1238. });
  1239. });
  1240. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  1241. [[FIRAuth auth] signOut:NULL];
  1242. FIRAuthCredential *googleCredential =
  1243. [FIRGoogleAuthProvider credentialWithIDToken:kGoogleIDToken accessToken:kGoogleAccessToken];
  1244. [[FIRAuth auth]
  1245. signInWithCredential:googleCredential
  1246. completion:^(FIRAuthDataResult *_Nullable result, NSError *_Nullable error) {
  1247. XCTAssertTrue([NSThread isMainThread]);
  1248. XCTAssertEqual(error.code, FIRAuthErrorCodeAccountExistsWithDifferentCredential);
  1249. XCTAssertEqualObjects(error.userInfo[FIRAuthErrorUserInfoEmailKey], kEmail);
  1250. [expectation fulfill];
  1251. }];
  1252. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  1253. OCMVerifyAll(_mockBackend);
  1254. }
  1255. /** @fn testSignInWithGoogleCredentialSuccess
  1256. @brief Tests the flow of a successful @c signInWithCredential:completion: call with an
  1257. Google Sign-In credential.
  1258. */
  1259. - (void)testSignInWithGoogleCredentialSuccess {
  1260. OCMExpect([_mockBackend verifyAssertion:[OCMArg any] callback:[OCMArg any]])
  1261. .andCallBlock2(^(FIRVerifyAssertionRequest *_Nullable request,
  1262. FIRVerifyAssertionResponseCallback callback) {
  1263. XCTAssertEqualObjects(request.APIKey, kAPIKey);
  1264. XCTAssertEqualObjects(request.providerID, FIRGoogleAuthProviderID);
  1265. XCTAssertEqualObjects(request.providerIDToken, kGoogleIDToken);
  1266. XCTAssertEqualObjects(request.providerAccessToken, kGoogleAccessToken);
  1267. XCTAssertTrue(request.returnSecureToken);
  1268. dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
  1269. id mockVerifyAssertionResponse = OCMClassMock([FIRVerifyAssertionResponse class]);
  1270. OCMStub([mockVerifyAssertionResponse federatedID]).andReturn(kGoogleID);
  1271. OCMStub([mockVerifyAssertionResponse providerID]).andReturn(FIRGoogleAuthProviderID);
  1272. OCMStub([mockVerifyAssertionResponse localID]).andReturn(kLocalID);
  1273. OCMStub([mockVerifyAssertionResponse displayName]).andReturn(kGoogleDisplayName);
  1274. [self stubTokensWithMockResponse:mockVerifyAssertionResponse];
  1275. callback(mockVerifyAssertionResponse, nil);
  1276. });
  1277. });
  1278. [self expectGetAccountInfoGoogle];
  1279. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  1280. [[FIRAuth auth] signOut:NULL];
  1281. FIRAuthCredential *googleCredential =
  1282. [FIRGoogleAuthProvider credentialWithIDToken:kGoogleIDToken accessToken:kGoogleAccessToken];
  1283. [[FIRAuth auth]
  1284. signInWithCredential:googleCredential
  1285. completion:^(FIRAuthDataResult *_Nullable result, NSError *_Nullable error) {
  1286. XCTAssertTrue([NSThread isMainThread]);
  1287. [self assertUserGoogle:result.user];
  1288. XCTAssertNil(error);
  1289. [expectation fulfill];
  1290. }];
  1291. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  1292. [self assertUserGoogle:[FIRAuth auth].currentUser];
  1293. OCMVerifyAll(_mockBackend);
  1294. }
  1295. /** @fn testSignInWithOAuthCredentialSuccess
  1296. @brief Tests the flow of a successful @c signInWithCredential:completion: call with a generic
  1297. OAuth credential (In this case, configured for the Google IDP).
  1298. */
  1299. - (void)testSignInWithOAuthCredentialSuccess {
  1300. OCMExpect([_mockBackend verifyAssertion:[OCMArg any] callback:[OCMArg any]])
  1301. .andCallBlock2(^(FIRVerifyAssertionRequest *_Nullable request,
  1302. FIRVerifyAssertionResponseCallback callback) {
  1303. XCTAssertEqualObjects(request.APIKey, kAPIKey);
  1304. XCTAssertEqualObjects(request.providerID, FIRGoogleAuthProviderID);
  1305. XCTAssertEqualObjects(request.requestURI, kOAuthRequestURI);
  1306. XCTAssertEqualObjects(request.sessionID, kOAuthSessionID);
  1307. XCTAssertTrue(request.returnSecureToken);
  1308. dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
  1309. id mockVerifyAssertionResponse = OCMClassMock([FIRVerifyAssertionResponse class]);
  1310. OCMStub([mockVerifyAssertionResponse federatedID]).andReturn(kGoogleID);
  1311. OCMStub([mockVerifyAssertionResponse providerID]).andReturn(FIRGoogleAuthProviderID);
  1312. OCMStub([mockVerifyAssertionResponse localID]).andReturn(kLocalID);
  1313. OCMStub([mockVerifyAssertionResponse displayName]).andReturn(kGoogleDisplayName);
  1314. [self stubTokensWithMockResponse:mockVerifyAssertionResponse];
  1315. callback(mockVerifyAssertionResponse, nil);
  1316. });
  1317. });
  1318. [self expectGetAccountInfoGoogle];
  1319. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  1320. [[FIRAuth auth] signOut:NULL];
  1321. id mockProvider = OCMClassMock([FIROAuthProvider class]);
  1322. OCMExpect([mockProvider getCredentialWithUIDelegate:[OCMArg any] completion:[OCMArg any]])
  1323. .andCallBlock2(^(id<FIRAuthUIDelegate> delegate, FIRAuthCredentialCallback callback) {
  1324. dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
  1325. FIROAuthCredential *credential =
  1326. [[FIROAuthCredential alloc] initWithProviderID:FIRGoogleAuthProviderID
  1327. sessionID:kOAuthSessionID
  1328. OAuthResponseURLString:kOAuthRequestURI];
  1329. callback(credential, nil);
  1330. });
  1331. });
  1332. [mockProvider
  1333. getCredentialWithUIDelegate:nil
  1334. completion:^(FIRAuthCredential *_Nullable credential,
  1335. NSError *_Nullable error) {
  1336. XCTAssertTrue([credential isKindOfClass:[FIROAuthCredential class]]);
  1337. FIROAuthCredential *OAuthCredential = (FIROAuthCredential *)credential;
  1338. XCTAssertEqualObjects(OAuthCredential.OAuthResponseURLString,
  1339. kOAuthRequestURI);
  1340. XCTAssertEqualObjects(OAuthCredential.sessionID, kOAuthSessionID);
  1341. [[FIRAuth auth] signInWithCredential:OAuthCredential
  1342. completion:^(FIRAuthDataResult *_Nullable result,
  1343. NSError *_Nullable error) {
  1344. XCTAssertTrue([NSThread isMainThread]);
  1345. [self assertUserGoogle:result.user];
  1346. XCTAssertNil(error);
  1347. [expectation fulfill];
  1348. }];
  1349. }];
  1350. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  1351. [self assertUserGoogle:[FIRAuth auth].currentUser];
  1352. OCMVerifyAll(_mockBackend);
  1353. }
  1354. #endif // TARGET_OS_IOS
  1355. /** @fn testSignInWithCredentialSuccess
  1356. @brief Tests the flow of a successful @c signInWithCredential:completion: call
  1357. with an Google Sign-In credential.
  1358. */
  1359. - (void)testSignInWithCredentialSuccess {
  1360. OCMExpect([_mockBackend verifyAssertion:[OCMArg any] callback:[OCMArg any]])
  1361. .andCallBlock2(^(FIRVerifyAssertionRequest *_Nullable request,
  1362. FIRVerifyAssertionResponseCallback callback) {
  1363. XCTAssertEqualObjects(request.APIKey, kAPIKey);
  1364. XCTAssertEqualObjects(request.providerID, FIRGoogleAuthProviderID);
  1365. XCTAssertEqualObjects(request.providerIDToken, kGoogleIDToken);
  1366. XCTAssertEqualObjects(request.providerAccessToken, kGoogleAccessToken);
  1367. XCTAssertTrue(request.returnSecureToken);
  1368. dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
  1369. id mockVerifyAssertionResponse = OCMClassMock([FIRVerifyAssertionResponse class]);
  1370. OCMStub([mockVerifyAssertionResponse federatedID]).andReturn(kGoogleID);
  1371. OCMStub([mockVerifyAssertionResponse providerID]).andReturn(FIRGoogleAuthProviderID);
  1372. OCMStub([mockVerifyAssertionResponse localID]).andReturn(kLocalID);
  1373. OCMStub([mockVerifyAssertionResponse displayName]).andReturn(kGoogleDisplayName);
  1374. OCMStub([mockVerifyAssertionResponse profile]).andReturn([[self class] googleProfile]);
  1375. OCMStub([mockVerifyAssertionResponse username]).andReturn(kDisplayName);
  1376. [self stubTokensWithMockResponse:mockVerifyAssertionResponse];
  1377. callback(mockVerifyAssertionResponse, nil);
  1378. });
  1379. });
  1380. [self expectGetAccountInfoGoogle];
  1381. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  1382. [[FIRAuth auth] signOut:NULL];
  1383. FIRAuthCredential *googleCredential =
  1384. [FIRGoogleAuthProvider credentialWithIDToken:kGoogleIDToken accessToken:kGoogleAccessToken];
  1385. [[FIRAuth auth]
  1386. signInWithCredential:googleCredential
  1387. completion:^(FIRAuthDataResult *_Nullable authResult, NSError *_Nullable error) {
  1388. XCTAssertTrue([NSThread isMainThread]);
  1389. [self assertUserGoogle:authResult.user];
  1390. XCTAssertEqualObjects(authResult.additionalUserInfo.profile,
  1391. [[self class] googleProfile]);
  1392. XCTAssertEqualObjects(authResult.additionalUserInfo.username, kDisplayName);
  1393. XCTAssertEqualObjects(authResult.additionalUserInfo.providerID,
  1394. FIRGoogleAuthProviderID);
  1395. XCTAssertNil(error);
  1396. [expectation fulfill];
  1397. }];
  1398. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  1399. [self assertUserGoogle:[FIRAuth auth].currentUser];
  1400. OCMVerifyAll(_mockBackend);
  1401. }
  1402. /** @fn testSignInWithGoogleCredentialFailure
  1403. @brief Tests the flow of a failed @c signInWithCredential:completion: call with an
  1404. Google Sign-In credential.
  1405. */
  1406. - (void)testSignInWithGoogleCredentialFailure {
  1407. OCMExpect([_mockBackend verifyAssertion:[OCMArg any] callback:[OCMArg any]])
  1408. .andDispatchError2([FIRAuthErrorUtils emailAlreadyInUseErrorWithEmail:kGoogleEmail]);
  1409. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  1410. [[FIRAuth auth] signOut:NULL];
  1411. FIRAuthCredential *googleCredential =
  1412. [FIRGoogleAuthProvider credentialWithIDToken:kGoogleIDToken accessToken:kGoogleAccessToken];
  1413. [[FIRAuth auth]
  1414. signInWithCredential:googleCredential
  1415. completion:^(FIRAuthDataResult *_Nullable result, NSError *_Nullable error) {
  1416. XCTAssertTrue([NSThread isMainThread]);
  1417. XCTAssertNil(result.user);
  1418. XCTAssertEqual(error.code, FIRAuthErrorCodeEmailAlreadyInUse);
  1419. XCTAssertNotNil(error.userInfo[NSLocalizedDescriptionKey]);
  1420. [expectation fulfill];
  1421. }];
  1422. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  1423. XCTAssertNil([FIRAuth auth].currentUser);
  1424. OCMVerifyAll(_mockBackend);
  1425. }
  1426. /** @fn testSignInWithAppleCredentialFullNameInRequest
  1427. @brief Tests the flow of a successful @c signInWithCredential:completion: call
  1428. with an Apple Sign-In credential with a full name. This test differentiates from
  1429. @c testSignInWithCredentialSuccess only in verifying the full name.
  1430. */
  1431. - (void)testSignInWithAppleCredentialFullNameInRequestSuccess {
  1432. NSPersonNameComponents *fullName = [[NSPersonNameComponents alloc] init];
  1433. fullName.givenName = kFakeGivenName;
  1434. fullName.familyName = kFakeFamilyName;
  1435. OCMExpect([_mockBackend verifyAssertion:[OCMArg any] callback:[OCMArg any]])
  1436. .andCallBlock2(^(FIRVerifyAssertionRequest *_Nullable request,
  1437. FIRVerifyAssertionResponseCallback callback) {
  1438. XCTAssertEqualObjects(request.APIKey, kAPIKey);
  1439. XCTAssertEqualObjects(request.providerID, kAppleAuthProviderID);
  1440. XCTAssertEqualObjects(request.providerIDToken, kAppleIDToken);
  1441. // Verify that the full name is passed to the backend request.
  1442. XCTAssertEqualObjects(request.fullName, fullName);
  1443. XCTAssertTrue(request.returnSecureToken);
  1444. dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
  1445. id mockVerifyAssertionResponse = OCMClassMock([FIRVerifyAssertionResponse class]);
  1446. OCMStub([mockVerifyAssertionResponse providerID]).andReturn(kAppleAuthProviderID);
  1447. [self stubTokensWithMockResponse:mockVerifyAssertionResponse];
  1448. callback(mockVerifyAssertionResponse, nil);
  1449. });
  1450. });
  1451. OCMExpect([_mockBackend getAccountInfo:[OCMArg any] callback:[OCMArg any]])
  1452. .andCallBlock2(^(FIRGetAccountInfoRequest *_Nullable request,
  1453. FIRGetAccountInfoResponseCallback callback) {
  1454. XCTAssertEqualObjects(request.APIKey, kAPIKey);
  1455. XCTAssertEqualObjects(request.accessToken, kAccessToken);
  1456. dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
  1457. id mockAppleUserInfo = OCMClassMock([FIRGetAccountInfoResponseProviderUserInfo class]);
  1458. OCMStub([mockAppleUserInfo providerID]).andReturn(kAppleAuthProviderID);
  1459. id mockGetAccountInfoResponseUser = OCMClassMock([FIRGetAccountInfoResponseUser class]);
  1460. OCMStub([mockGetAccountInfoResponseUser providerUserInfo])
  1461. .andReturn((@[ mockAppleUserInfo ]));
  1462. id mockGetAccountInfoResponse = OCMClassMock([FIRGetAccountInfoResponse class]);
  1463. OCMStub([mockGetAccountInfoResponse users]).andReturn(@[
  1464. mockGetAccountInfoResponseUser
  1465. ]);
  1466. callback(mockGetAccountInfoResponse, nil);
  1467. });
  1468. });
  1469. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  1470. [[FIRAuth auth] signOut:NULL];
  1471. FIRAuthCredential *appleCredential = [FIROAuthProvider appleCredentialWithIDToken:kAppleIDToken
  1472. rawNonce:nil
  1473. fullName:fullName];
  1474. [[FIRAuth auth]
  1475. signInWithCredential:appleCredential
  1476. completion:^(FIRAuthDataResult *_Nullable authResult, NSError *_Nullable error) {
  1477. XCTAssertTrue([NSThread isMainThread]);
  1478. XCTAssertNil(error);
  1479. [expectation fulfill];
  1480. }];
  1481. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  1482. XCTAssertNotNil([FIRAuth auth].currentUser);
  1483. OCMVerifyAll(_mockBackend);
  1484. }
  1485. /** @fn testSignInAnonymouslySuccess
  1486. @brief Tests the flow of a successful @c signInAnonymouslyWithCompletion: call.
  1487. */
  1488. - (void)testSignInAnonymouslySuccess {
  1489. OCMExpect([_mockBackend signUpNewUser:[OCMArg any] callback:[OCMArg any]])
  1490. .andCallBlock2(
  1491. ^(FIRSignUpNewUserRequest *_Nullable request, FIRSignupNewUserCallback callback) {
  1492. XCTAssertEqualObjects(request.APIKey, kAPIKey);
  1493. XCTAssertNil(request.email);
  1494. XCTAssertNil(request.password);
  1495. XCTAssertTrue(request.returnSecureToken);
  1496. dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
  1497. id mockSignUpNewUserResponse = OCMClassMock([FIRSignUpNewUserResponse class]);
  1498. [self stubTokensWithMockResponse:mockSignUpNewUserResponse];
  1499. callback(mockSignUpNewUserResponse, nil);
  1500. });
  1501. });
  1502. [self expectGetAccountInfoAnonymous];
  1503. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  1504. [[FIRAuth auth] signOut:NULL];
  1505. [[FIRAuth auth] signInAnonymouslyWithCompletion:^(FIRAuthDataResult *_Nullable result,
  1506. NSError *_Nullable error) {
  1507. XCTAssertTrue([NSThread isMainThread]);
  1508. [self assertUserAnonymous:result.user];
  1509. XCTAssertNil(error);
  1510. FIRAdditionalUserInfo *userInfo = result.additionalUserInfo;
  1511. XCTAssertNotNil(userInfo);
  1512. XCTAssertTrue(userInfo.isNewUser);
  1513. XCTAssertNil(userInfo.username);
  1514. XCTAssertNil(userInfo.profile);
  1515. XCTAssertNil(userInfo.providerID);
  1516. [expectation fulfill];
  1517. }];
  1518. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  1519. [self assertUserAnonymous:[FIRAuth auth].currentUser];
  1520. OCMVerifyAll(_mockBackend);
  1521. }
  1522. /** @fn testSignInAnonymouslyFailure
  1523. @brief Tests the flow of a failed @c signInAnonymouslyWithCompletion: call.
  1524. */
  1525. - (void)testSignInAnonymouslyFailure {
  1526. OCMExpect([_mockBackend signUpNewUser:[OCMArg any] callback:[OCMArg any]])
  1527. .andDispatchError2([FIRAuthErrorUtils operationNotAllowedErrorWithMessage:nil]);
  1528. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  1529. [[FIRAuth auth] signOut:NULL];
  1530. [[FIRAuth auth] signInAnonymouslyWithCompletion:^(FIRAuthDataResult *_Nullable result,
  1531. NSError *_Nullable error) {
  1532. XCTAssertTrue([NSThread isMainThread]);
  1533. XCTAssertNil(result.user);
  1534. XCTAssertEqual(error.code, FIRAuthErrorCodeOperationNotAllowed);
  1535. XCTAssertNotNil(error.userInfo[NSLocalizedDescriptionKey]);
  1536. [expectation fulfill];
  1537. }];
  1538. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  1539. XCTAssertNil([FIRAuth auth].currentUser);
  1540. OCMVerifyAll(_mockBackend);
  1541. }
  1542. /** @fn testSignInAnonymouslyAndRetrieveDataSuccess
  1543. @brief Tests the flow of a successful @c signInAnonymouslyAndRetrieveDataWithCompletion: call.
  1544. */
  1545. - (void)testSignInAnonymouslyAndRetrieveDataSuccess {
  1546. OCMExpect([_mockBackend signUpNewUser:[OCMArg any] callback:[OCMArg any]])
  1547. .andCallBlock2(
  1548. ^(FIRSignUpNewUserRequest *_Nullable request, FIRSignupNewUserCallback callback) {
  1549. XCTAssertEqualObjects(request.APIKey, kAPIKey);
  1550. XCTAssertNil(request.email);
  1551. XCTAssertNil(request.password);
  1552. XCTAssertTrue(request.returnSecureToken);
  1553. dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
  1554. id mockSignUpNewUserResponse = OCMClassMock([FIRSignUpNewUserResponse class]);
  1555. [self stubTokensWithMockResponse:mockSignUpNewUserResponse];
  1556. callback(mockSignUpNewUserResponse, nil);
  1557. });
  1558. });
  1559. [self expectGetAccountInfoAnonymous];
  1560. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  1561. [[FIRAuth auth] signOut:NULL];
  1562. [[FIRAuth auth] signInAnonymouslyWithCompletion:^(FIRAuthDataResult *_Nullable result,
  1563. NSError *_Nullable error) {
  1564. XCTAssertTrue([NSThread isMainThread]);
  1565. [self assertUserAnonymous:result.user];
  1566. XCTAssertNil(error);
  1567. [expectation fulfill];
  1568. }];
  1569. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  1570. [self assertUserAnonymous:[FIRAuth auth].currentUser];
  1571. OCMVerifyAll(_mockBackend);
  1572. }
  1573. /** @fn testSignInAnonymouslyAndRetrieveDataFailure
  1574. @brief Tests the flow of a failed @c signInAnonymouslyAndRetrieveDataWithCompletion: call.
  1575. */
  1576. - (void)testSignInAnonymouslyAndRetrieveDataFailure {
  1577. OCMExpect([_mockBackend signUpNewUser:[OCMArg any] callback:[OCMArg any]])
  1578. .andDispatchError2([FIRAuthErrorUtils operationNotAllowedErrorWithMessage:nil]);
  1579. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  1580. [[FIRAuth auth] signOut:NULL];
  1581. [[FIRAuth auth] signInAnonymouslyWithCompletion:^(FIRAuthDataResult *_Nullable result,
  1582. NSError *_Nullable error) {
  1583. XCTAssertTrue([NSThread isMainThread]);
  1584. XCTAssertNil(result);
  1585. XCTAssertEqual(error.code, FIRAuthErrorCodeOperationNotAllowed);
  1586. XCTAssertNotNil(error.userInfo[NSLocalizedDescriptionKey]);
  1587. [expectation fulfill];
  1588. }];
  1589. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  1590. XCTAssertNil([FIRAuth auth].currentUser);
  1591. OCMVerifyAll(_mockBackend);
  1592. }
  1593. /** @fn testSignInWithCustomTokenSuccess
  1594. @brief Tests the flow of a successful @c signInWithCustomToken:completion: call.
  1595. */
  1596. - (void)testSignInWithCustomTokenSuccess {
  1597. OCMExpect([_mockBackend verifyCustomToken:[OCMArg any] callback:[OCMArg any]])
  1598. .andCallBlock2(^(FIRVerifyCustomTokenRequest *_Nullable request,
  1599. FIRVerifyCustomTokenResponseCallback callback) {
  1600. XCTAssertEqualObjects(request.APIKey, kAPIKey);
  1601. XCTAssertEqualObjects(request.token, kCustomToken);
  1602. XCTAssertTrue(request.returnSecureToken);
  1603. dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
  1604. id mockVerifyCustomTokenResponse = OCMClassMock([FIRVerifyCustomTokenResponse class]);
  1605. [self stubTokensWithMockResponse:mockVerifyCustomTokenResponse];
  1606. callback(mockVerifyCustomTokenResponse, nil);
  1607. });
  1608. });
  1609. [self expectGetAccountInfo];
  1610. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  1611. [[FIRAuth auth] signOut:NULL];
  1612. [[FIRAuth auth]
  1613. signInWithCustomToken:kCustomToken
  1614. completion:^(FIRAuthDataResult *_Nullable result, NSError *_Nullable error) {
  1615. XCTAssertTrue([NSThread isMainThread]);
  1616. [self assertUser:result.user];
  1617. XCTAssertNil(error);
  1618. [expectation fulfill];
  1619. }];
  1620. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  1621. [self assertUser:[FIRAuth auth].currentUser];
  1622. OCMVerifyAll(_mockBackend);
  1623. }
  1624. /** @fn testSignInWithCustomTokenFailure
  1625. @brief Tests the flow of a failed @c signInWithCustomToken:completion: call.
  1626. */
  1627. - (void)testSignInWithCustomTokenFailure {
  1628. OCMExpect([_mockBackend verifyCustomToken:[OCMArg any] callback:[OCMArg any]])
  1629. .andDispatchError2([FIRAuthErrorUtils invalidCustomTokenErrorWithMessage:nil]);
  1630. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  1631. [[FIRAuth auth] signOut:NULL];
  1632. [[FIRAuth auth]
  1633. signInWithCustomToken:kCustomToken
  1634. completion:^(FIRAuthDataResult *_Nullable result, NSError *_Nullable error) {
  1635. XCTAssertTrue([NSThread isMainThread]);
  1636. XCTAssertNil(result.user);
  1637. XCTAssertEqual(error.code, FIRAuthErrorCodeInvalidCustomToken);
  1638. XCTAssertNotNil(error.userInfo[NSLocalizedDescriptionKey]);
  1639. [expectation fulfill];
  1640. }];
  1641. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  1642. XCTAssertNil([FIRAuth auth].currentUser);
  1643. OCMVerifyAll(_mockBackend);
  1644. }
  1645. /** @fn testSignInAndRetrieveDataWithCustomTokenSuccess
  1646. @brief Tests the flow of a successful @c signInAndRetrieveDataWithCustomToken:completion: call.
  1647. */
  1648. - (void)testSignInAndRetrieveDataWithCustomTokenSuccess {
  1649. OCMExpect([_mockBackend verifyCustomToken:[OCMArg any] callback:[OCMArg any]])
  1650. .andCallBlock2(^(FIRVerifyCustomTokenRequest *_Nullable request,
  1651. FIRVerifyCustomTokenResponseCallback callback) {
  1652. XCTAssertEqualObjects(request.APIKey, kAPIKey);
  1653. XCTAssertEqualObjects(request.token, kCustomToken);
  1654. XCTAssertTrue(request.returnSecureToken);
  1655. dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
  1656. id mockVerifyCustomTokenResponse = OCMClassMock([FIRVerifyCustomTokenResponse class]);
  1657. [self stubTokensWithMockResponse:mockVerifyCustomTokenResponse];
  1658. callback(mockVerifyCustomTokenResponse, nil);
  1659. });
  1660. });
  1661. [self expectGetAccountInfo];
  1662. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  1663. [[FIRAuth auth] signOut:NULL];
  1664. [[FIRAuth auth]
  1665. signInWithCustomToken:kCustomToken
  1666. completion:^(FIRAuthDataResult *_Nullable result, NSError *_Nullable error) {
  1667. XCTAssertTrue([NSThread isMainThread]);
  1668. [self assertUser:result.user];
  1669. XCTAssertFalse(result.additionalUserInfo.isNewUser);
  1670. XCTAssertNil(error);
  1671. [expectation fulfill];
  1672. }];
  1673. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  1674. [self assertUser:[FIRAuth auth].currentUser];
  1675. OCMVerifyAll(_mockBackend);
  1676. }
  1677. /** @fn testSignInAndRetrieveDataWithCustomTokenFailure
  1678. @brief Tests the flow of a failed @c signInAndRetrieveDataWithCustomToken:completion: call.
  1679. */
  1680. - (void)testSignInAndRetrieveDataWithCustomTokenFailure {
  1681. OCMExpect([_mockBackend verifyCustomToken:[OCMArg any] callback:[OCMArg any]])
  1682. .andDispatchError2([FIRAuthErrorUtils invalidCustomTokenErrorWithMessage:nil]);
  1683. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  1684. [[FIRAuth auth] signOut:NULL];
  1685. [[FIRAuth auth]
  1686. signInWithCustomToken:kCustomToken
  1687. completion:^(FIRAuthDataResult *_Nullable result, NSError *_Nullable error) {
  1688. XCTAssertTrue([NSThread isMainThread]);
  1689. XCTAssertNil(result);
  1690. XCTAssertEqual(error.code, FIRAuthErrorCodeInvalidCustomToken);
  1691. XCTAssertNotNil(error.userInfo[NSLocalizedDescriptionKey]);
  1692. [expectation fulfill];
  1693. }];
  1694. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  1695. XCTAssertNil([FIRAuth auth].currentUser);
  1696. OCMVerifyAll(_mockBackend);
  1697. }
  1698. #if TARGET_OS_IOS && !TARGET_OS_MACCATALYST
  1699. /** @fn testCreateUserWithEmailPasswordWithRecaptchaVerificationSuccess
  1700. @brief Tests the flow of a successful @c createUserWithEmail:password:completion: call.
  1701. */
  1702. - (void)testCreateUserWithEmailPasswordWithRecaptchaVerificationSuccess {
  1703. id mockVerifier = OCMClassMock([FIRAuthRecaptchaVerifier class]);
  1704. OCMStub([mockVerifier sharedRecaptchaVerifier:[FIRAuth auth]]).andReturn(mockVerifier);
  1705. OCMExpect([mockVerifier enablementStatusForProvider:FIRAuthRecaptchaProviderPassword])
  1706. .andReturn(YES);
  1707. FIRSignUpNewUserRequest *constRequestWithRecaptchaToken =
  1708. [[FIRSignUpNewUserRequest alloc] initWithEmail:kEmail
  1709. password:kFakePassword
  1710. displayName:kDisplayName
  1711. requestConfiguration:[FIRAuth auth].requestConfiguration];
  1712. [constRequestWithRecaptchaToken injectRecaptchaFields:kFakeRecaptchaResponse
  1713. recaptchaVersion:kFakeRecaptchaVersion];
  1714. OCMStub([mockVerifier
  1715. injectRecaptchaFields:[OCMArg any]
  1716. provider:FIRAuthRecaptchaProviderPassword
  1717. action:FIRAuthRecaptchaActionSignUpPassword
  1718. completion:([OCMArg invokeBlockWithArgs:constRequestWithRecaptchaToken, nil])]);
  1719. OCMExpect([_mockBackend signUpNewUser:[OCMArg any] callback:[OCMArg any]])
  1720. .andCallBlock2(
  1721. ^(FIRSignUpNewUserRequest *_Nullable request, FIRSignupNewUserCallback callback) {
  1722. XCTAssertEqualObjects(request.APIKey, kAPIKey);
  1723. XCTAssertEqualObjects(request.email, kEmail);
  1724. XCTAssertEqualObjects(request.password, kFakePassword);
  1725. XCTAssertTrue(request.returnSecureToken);
  1726. dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
  1727. id mockSignUpNewUserResponse = OCMClassMock([FIRSignUpNewUserResponse class]);
  1728. [self stubTokensWithMockResponse:mockSignUpNewUserResponse];
  1729. callback(mockSignUpNewUserResponse, nil);
  1730. });
  1731. });
  1732. [self expectGetAccountInfo];
  1733. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  1734. [[FIRAuth auth] signOut:NULL];
  1735. [[FIRAuth auth]
  1736. createUserWithEmail:kEmail
  1737. password:kFakePassword
  1738. completion:^(FIRAuthDataResult *_Nullable result, NSError *_Nullable error) {
  1739. XCTAssertTrue([NSThread isMainThread]);
  1740. [self assertUser:result.user];
  1741. XCTAssertNil(error);
  1742. [expectation fulfill];
  1743. }];
  1744. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  1745. [self assertUser:[FIRAuth auth].currentUser];
  1746. }
  1747. /** @fn testCreateUserWithEmailPasswordWithRecaptchaFallbackSuccess
  1748. @brief Tests the flow of a successful @c createUserWithEmail:password:completion: call.
  1749. */
  1750. - (void)testCreateUserWithEmailPasswordWithRecaptchaFallbackSuccess {
  1751. id mockVerifier = OCMClassMock([FIRAuthRecaptchaVerifier class]);
  1752. OCMStub([mockVerifier sharedRecaptchaVerifier:[FIRAuth auth]]).andReturn(mockVerifier);
  1753. OCMExpect([mockVerifier enablementStatusForProvider:FIRAuthRecaptchaProviderPassword])
  1754. .andReturn(NO);
  1755. FIRSignUpNewUserRequest *constRequestWithRecaptchaToken =
  1756. [[FIRSignUpNewUserRequest alloc] initWithEmail:kEmail
  1757. password:kFakePassword
  1758. displayName:kDisplayName
  1759. requestConfiguration:[FIRAuth auth].requestConfiguration];
  1760. [constRequestWithRecaptchaToken injectRecaptchaFields:kFakeRecaptchaResponse
  1761. recaptchaVersion:kFakeRecaptchaVersion];
  1762. OCMStub([mockVerifier
  1763. injectRecaptchaFields:[OCMArg any]
  1764. provider:FIRAuthRecaptchaProviderPassword
  1765. action:FIRAuthRecaptchaActionSignUpPassword
  1766. completion:([OCMArg invokeBlockWithArgs:constRequestWithRecaptchaToken, nil])]);
  1767. OCMExpect([_mockBackend signUpNewUser:[OCMArg any] callback:[OCMArg any]])
  1768. .andCallBlock2(^(FIRSignUpNewUserRequest *_Nullable request,
  1769. FIRSignupNewUserCallback callback) {
  1770. XCTAssertEqualObjects(request.APIKey, kAPIKey);
  1771. XCTAssertEqualObjects(request.email, kEmail);
  1772. XCTAssertEqualObjects(request.password, kFakePassword);
  1773. XCTAssertTrue(request.returnSecureToken);
  1774. NSError *underlyingError =
  1775. [[NSError alloc] initWithDomain:FIRAuthErrorDomain
  1776. code:FIRAuthErrorCodeInternalError
  1777. userInfo:@{
  1778. FIRAuthErrorUserInfoDeserializedResponseKey :
  1779. @{@"message" : @"MISSING_RECAPTCHA_TOKEN"}
  1780. }];
  1781. NSError *error = [[NSError alloc] initWithDomain:FIRAuthErrorDomain
  1782. code:FIRAuthErrorCodeInternalError
  1783. userInfo:@{NSUnderlyingErrorKey : underlyingError}];
  1784. dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
  1785. callback(nil, error);
  1786. });
  1787. });
  1788. OCMExpect([_mockBackend signUpNewUser:[OCMArg any] callback:[OCMArg any]])
  1789. .andCallBlock2(
  1790. ^(FIRSignUpNewUserRequest *_Nullable request, FIRSignupNewUserCallback callback) {
  1791. XCTAssertEqualObjects(request.APIKey, kAPIKey);
  1792. XCTAssertEqualObjects(request.email, kEmail);
  1793. XCTAssertEqualObjects(request.password, kFakePassword);
  1794. XCTAssertTrue(request.returnSecureToken);
  1795. dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
  1796. id mockSignUpNewUserResponse = OCMClassMock([FIRSignUpNewUserResponse class]);
  1797. [self stubTokensWithMockResponse:mockSignUpNewUserResponse];
  1798. callback(mockSignUpNewUserResponse, nil);
  1799. });
  1800. });
  1801. [self expectGetAccountInfo];
  1802. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  1803. [[FIRAuth auth] signOut:NULL];
  1804. [[FIRAuth auth]
  1805. createUserWithEmail:kEmail
  1806. password:kFakePassword
  1807. completion:^(FIRAuthDataResult *_Nullable result, NSError *_Nullable error) {
  1808. XCTAssertTrue([NSThread isMainThread]);
  1809. [self assertUser:result.user];
  1810. XCTAssertNil(error);
  1811. [expectation fulfill];
  1812. }];
  1813. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  1814. [self assertUser:[FIRAuth auth].currentUser];
  1815. }
  1816. #endif
  1817. /** @fn testCreateUserWithEmailPasswordSuccess
  1818. @brief Tests the flow of a successful @c createUserWithEmail:password:completion: call.
  1819. */
  1820. - (void)testCreateUserWithEmailPasswordSuccess {
  1821. OCMExpect([_mockBackend signUpNewUser:[OCMArg any] callback:[OCMArg any]])
  1822. .andCallBlock2(
  1823. ^(FIRSignUpNewUserRequest *_Nullable request, FIRSignupNewUserCallback callback) {
  1824. XCTAssertEqualObjects(request.APIKey, kAPIKey);
  1825. XCTAssertEqualObjects(request.email, kEmail);
  1826. XCTAssertEqualObjects(request.password, kFakePassword);
  1827. XCTAssertTrue(request.returnSecureToken);
  1828. dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
  1829. id mockSignUpNewUserResponse = OCMClassMock([FIRSignUpNewUserResponse class]);
  1830. [self stubTokensWithMockResponse:mockSignUpNewUserResponse];
  1831. callback(mockSignUpNewUserResponse, nil);
  1832. });
  1833. });
  1834. [self expectGetAccountInfo];
  1835. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  1836. [[FIRAuth auth] signOut:NULL];
  1837. [[FIRAuth auth]
  1838. createUserWithEmail:kEmail
  1839. password:kFakePassword
  1840. completion:^(FIRAuthDataResult *_Nullable result, NSError *_Nullable error) {
  1841. XCTAssertTrue([NSThread isMainThread]);
  1842. [self assertUser:result.user];
  1843. XCTAssertNil(error);
  1844. [expectation fulfill];
  1845. }];
  1846. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  1847. [self assertUser:[FIRAuth auth].currentUser];
  1848. OCMVerifyAll(_mockBackend);
  1849. }
  1850. /** @fn testCreateUserWithEmailPasswordFailure
  1851. @brief Tests the flow of a failed @c createUserWithEmail:password:completion: call.
  1852. */
  1853. - (void)testCreateUserWithEmailPasswordFailure {
  1854. NSString *reason = @"Password shouldn't be a common word.";
  1855. OCMExpect([_mockBackend signUpNewUser:[OCMArg any] callback:[OCMArg any]])
  1856. .andDispatchError2([FIRAuthErrorUtils weakPasswordErrorWithServerResponseReason:reason]);
  1857. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  1858. [[FIRAuth auth] signOut:NULL];
  1859. [[FIRAuth auth]
  1860. createUserWithEmail:kEmail
  1861. password:kFakePassword
  1862. completion:^(FIRAuthDataResult *_Nullable result, NSError *_Nullable error) {
  1863. XCTAssertTrue([NSThread isMainThread]);
  1864. XCTAssertNil(result.user);
  1865. XCTAssertEqual(error.code, FIRAuthErrorCodeWeakPassword);
  1866. XCTAssertNotNil(error.userInfo[NSLocalizedDescriptionKey]);
  1867. XCTAssertEqualObjects(error.userInfo[NSLocalizedFailureReasonErrorKey], reason);
  1868. [expectation fulfill];
  1869. }];
  1870. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  1871. XCTAssertNil([FIRAuth auth].currentUser);
  1872. OCMVerifyAll(_mockBackend);
  1873. }
  1874. /** @fn testCreateUserAndRetrieveDataWithEmailPasswordSuccess
  1875. @brief Tests the flow of a successful @c createUserAndRetrieveDataWithEmail:password:completion:
  1876. call.
  1877. */
  1878. - (void)testCreateUserAndRetrieveDataWithEmailPasswordSuccess {
  1879. OCMExpect([_mockBackend signUpNewUser:[OCMArg any] callback:[OCMArg any]])
  1880. .andCallBlock2(
  1881. ^(FIRSignUpNewUserRequest *_Nullable request, FIRSignupNewUserCallback callback) {
  1882. XCTAssertEqualObjects(request.APIKey, kAPIKey);
  1883. XCTAssertEqualObjects(request.email, kEmail);
  1884. XCTAssertEqualObjects(request.password, kFakePassword);
  1885. XCTAssertTrue(request.returnSecureToken);
  1886. dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
  1887. id mockSignUpNewUserResponse = OCMClassMock([FIRSignUpNewUserResponse class]);
  1888. [self stubTokensWithMockResponse:mockSignUpNewUserResponse];
  1889. callback(mockSignUpNewUserResponse, nil);
  1890. });
  1891. });
  1892. [self expectGetAccountInfo];
  1893. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  1894. [[FIRAuth auth] signOut:NULL];
  1895. [[FIRAuth auth]
  1896. createUserWithEmail:kEmail
  1897. password:kFakePassword
  1898. completion:^(FIRAuthDataResult *_Nullable result, NSError *_Nullable error) {
  1899. XCTAssertTrue([NSThread isMainThread]);
  1900. [self assertUser:result.user];
  1901. XCTAssertTrue(result.additionalUserInfo.isNewUser);
  1902. XCTAssertNil(error);
  1903. [expectation fulfill];
  1904. }];
  1905. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  1906. [self assertUser:[FIRAuth auth].currentUser];
  1907. OCMVerifyAll(_mockBackend);
  1908. }
  1909. /** @fn testCreateUserAndRetrieveDataWithEmailPasswordFailure
  1910. @brief Tests the flow of a failed @c createUserAndRetrieveDataWithEmail:password:completion:
  1911. call.
  1912. */
  1913. - (void)testCreateUserAndRetrieveDataWithEmailPasswordFailure {
  1914. NSString *reason = @"Password shouldn't be a common word.";
  1915. OCMExpect([_mockBackend signUpNewUser:[OCMArg any] callback:[OCMArg any]])
  1916. .andDispatchError2([FIRAuthErrorUtils weakPasswordErrorWithServerResponseReason:reason]);
  1917. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  1918. [[FIRAuth auth] signOut:NULL];
  1919. [[FIRAuth auth]
  1920. createUserWithEmail:kEmail
  1921. password:kFakePassword
  1922. completion:^(FIRAuthDataResult *_Nullable result, NSError *_Nullable error) {
  1923. XCTAssertTrue([NSThread isMainThread]);
  1924. XCTAssertNil(result);
  1925. XCTAssertEqual(error.code, FIRAuthErrorCodeWeakPassword);
  1926. XCTAssertNotNil(error.userInfo[NSLocalizedDescriptionKey]);
  1927. XCTAssertEqualObjects(error.userInfo[NSLocalizedFailureReasonErrorKey], reason);
  1928. [expectation fulfill];
  1929. }];
  1930. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  1931. XCTAssertNil([FIRAuth auth].currentUser);
  1932. OCMVerifyAll(_mockBackend);
  1933. }
  1934. /** @fn testCreateUserEmptyPasswordFailure
  1935. @brief Tests the flow of a failed @c createUserWithEmail:password:completion: call due to an
  1936. empty password. This error occurs on the client side, so there is no need to fake an RPC
  1937. response.
  1938. */
  1939. - (void)testCreateUserEmptyPasswordFailure {
  1940. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  1941. [[FIRAuth auth] signOut:NULL];
  1942. [[FIRAuth auth]
  1943. createUserWithEmail:kEmail
  1944. password:@""
  1945. completion:^(FIRAuthDataResult *_Nullable result, NSError *_Nullable error) {
  1946. XCTAssertTrue([NSThread isMainThread]);
  1947. XCTAssertEqual(error.code, FIRAuthErrorCodeWeakPassword);
  1948. [expectation fulfill];
  1949. }];
  1950. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  1951. }
  1952. /** @fn testCreateUserEmptyEmailFailure
  1953. @brief Tests the flow of a failed @c createUserWithEmail:password:completion: call due to an
  1954. empty email adress. This error occurs on the client side, so there is no need to fake an RPC
  1955. response.
  1956. */
  1957. - (void)testCreateUserEmptyEmailFailure {
  1958. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  1959. [[FIRAuth auth] signOut:NULL];
  1960. [[FIRAuth auth]
  1961. createUserWithEmail:@""
  1962. password:kFakePassword
  1963. completion:^(FIRAuthDataResult *_Nullable result, NSError *_Nullable error) {
  1964. XCTAssertTrue([NSThread isMainThread]);
  1965. XCTAssertEqual(error.code, FIRAuthErrorCodeMissingEmail);
  1966. [expectation fulfill];
  1967. }];
  1968. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  1969. }
  1970. #if TARGET_OS_IOS && !TARGET_OS_MACCATALYST
  1971. /** @fn testSendPasswordResetEmailWithRecaptchaSuccess
  1972. @brief Tests the flow of a successful @c sendPasswordResetWithEmail:completion: call.
  1973. */
  1974. - (void)testSendPasswordResetEmailWithRecaptchaSuccess {
  1975. id mockVerifier = OCMClassMock([FIRAuthRecaptchaVerifier class]);
  1976. OCMStub([mockVerifier sharedRecaptchaVerifier:[FIRAuth auth]]).andReturn(mockVerifier);
  1977. OCMExpect([mockVerifier enablementStatusForProvider:FIRAuthRecaptchaProviderPassword])
  1978. .andReturn(YES);
  1979. FIRGetOOBConfirmationCodeRequest *constRequestWithRecaptchaToken =
  1980. [FIRGetOOBConfirmationCodeRequest
  1981. passwordResetRequestWithEmail:kEmail
  1982. actionCodeSettings:nil
  1983. requestConfiguration:[FIRAuth auth].requestConfiguration];
  1984. [constRequestWithRecaptchaToken injectRecaptchaFields:kFakeRecaptchaResponse
  1985. recaptchaVersion:kFakeRecaptchaVersion];
  1986. OCMStub([mockVerifier
  1987. injectRecaptchaFields:[OCMArg any]
  1988. provider:FIRAuthRecaptchaProviderPassword
  1989. action:FIRAuthRecaptchaActionGetOobCode
  1990. completion:([OCMArg invokeBlockWithArgs:constRequestWithRecaptchaToken, nil])]);
  1991. OCMExpect([_mockBackend getOOBConfirmationCode:[OCMArg any] callback:[OCMArg any]])
  1992. .andCallBlock2(^(FIRGetOOBConfirmationCodeRequest *_Nullable request,
  1993. FIRGetOOBConfirmationCodeResponseCallback callback) {
  1994. XCTAssertEqualObjects(request.APIKey, kAPIKey);
  1995. XCTAssertEqualObjects(request.email, kEmail);
  1996. dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
  1997. callback([[FIRGetOOBConfirmationCodeResponse alloc] init], nil);
  1998. });
  1999. });
  2000. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  2001. [[FIRAuth auth] sendPasswordResetWithEmail:kEmail
  2002. completion:^(NSError *_Nullable error) {
  2003. XCTAssertTrue([NSThread isMainThread]);
  2004. XCTAssertNil(error);
  2005. [expectation fulfill];
  2006. }];
  2007. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  2008. }
  2009. /** @fn testSendPasswordResetEmailWithRecaptchaFallbackSuccess
  2010. @brief Tests the flow of a successful @c sendPasswordResetWithEmail:completion: call.
  2011. */
  2012. - (void)testSendPasswordResetEmailWithRecaptchaFallbackSuccess {
  2013. id mockVerifier = OCMClassMock([FIRAuthRecaptchaVerifier class]);
  2014. OCMStub([mockVerifier sharedRecaptchaVerifier:[FIRAuth auth]]).andReturn(mockVerifier);
  2015. OCMExpect([mockVerifier enablementStatusForProvider:FIRAuthRecaptchaProviderPassword])
  2016. .andReturn(NO);
  2017. FIRGetOOBConfirmationCodeRequest *constRequestWithRecaptchaToken =
  2018. [FIRGetOOBConfirmationCodeRequest
  2019. passwordResetRequestWithEmail:kEmail
  2020. actionCodeSettings:nil
  2021. requestConfiguration:[FIRAuth auth].requestConfiguration];
  2022. [constRequestWithRecaptchaToken injectRecaptchaFields:kFakeRecaptchaResponse
  2023. recaptchaVersion:kFakeRecaptchaVersion];
  2024. OCMStub([mockVerifier
  2025. injectRecaptchaFields:[OCMArg any]
  2026. provider:FIRAuthRecaptchaProviderPassword
  2027. action:FIRAuthRecaptchaActionGetOobCode
  2028. completion:([OCMArg invokeBlockWithArgs:constRequestWithRecaptchaToken, nil])]);
  2029. OCMExpect([_mockBackend getOOBConfirmationCode:[OCMArg any] callback:[OCMArg any]])
  2030. .andCallBlock2(^(FIRGetOOBConfirmationCodeRequest *_Nullable request,
  2031. FIRGetOOBConfirmationCodeResponseCallback callback) {
  2032. XCTAssertEqualObjects(request.APIKey, kAPIKey);
  2033. XCTAssertEqualObjects(request.email, kEmail);
  2034. NSError *underlyingError =
  2035. [[NSError alloc] initWithDomain:FIRAuthErrorDomain
  2036. code:FIRAuthErrorCodeInternalError
  2037. userInfo:@{
  2038. FIRAuthErrorUserInfoDeserializedResponseKey :
  2039. @{@"message" : @"MISSING_RECAPTCHA_TOKEN"}
  2040. }];
  2041. NSError *error = [[NSError alloc] initWithDomain:FIRAuthErrorDomain
  2042. code:FIRAuthErrorCodeInternalError
  2043. userInfo:@{NSUnderlyingErrorKey : underlyingError}];
  2044. dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
  2045. callback(nil, error);
  2046. });
  2047. });
  2048. OCMExpect([_mockBackend getOOBConfirmationCode:[OCMArg any] callback:[OCMArg any]])
  2049. .andCallBlock2(^(FIRGetOOBConfirmationCodeRequest *_Nullable request,
  2050. FIRGetOOBConfirmationCodeResponseCallback callback) {
  2051. XCTAssertEqualObjects(request.APIKey, kAPIKey);
  2052. XCTAssertEqualObjects(request.email, kEmail);
  2053. dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
  2054. callback([[FIRGetOOBConfirmationCodeResponse alloc] init], nil);
  2055. });
  2056. });
  2057. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  2058. [[FIRAuth auth] sendPasswordResetWithEmail:kEmail
  2059. completion:^(NSError *_Nullable error) {
  2060. XCTAssertTrue([NSThread isMainThread]);
  2061. XCTAssertNil(error);
  2062. [expectation fulfill];
  2063. }];
  2064. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  2065. }
  2066. #endif
  2067. /** @fn testSendPasswordResetEmailSuccess
  2068. @brief Tests the flow of a successful @c sendPasswordResetWithEmail:completion: call.
  2069. */
  2070. - (void)testSendPasswordResetEmailSuccess {
  2071. OCMExpect([_mockBackend getOOBConfirmationCode:[OCMArg any] callback:[OCMArg any]])
  2072. .andCallBlock2(^(FIRGetOOBConfirmationCodeRequest *_Nullable request,
  2073. FIRGetOOBConfirmationCodeResponseCallback callback) {
  2074. XCTAssertEqualObjects(request.APIKey, kAPIKey);
  2075. XCTAssertEqualObjects(request.email, kEmail);
  2076. dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
  2077. callback([[FIRGetOOBConfirmationCodeResponse alloc] init], nil);
  2078. });
  2079. });
  2080. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  2081. [[FIRAuth auth] sendPasswordResetWithEmail:kEmail
  2082. completion:^(NSError *_Nullable error) {
  2083. XCTAssertTrue([NSThread isMainThread]);
  2084. XCTAssertNil(error);
  2085. [expectation fulfill];
  2086. }];
  2087. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  2088. OCMVerifyAll(_mockBackend);
  2089. }
  2090. /** @fn testSendPasswordResetEmailFailure
  2091. @brief Tests the flow of a failed @c sendPasswordResetWithEmail:completion: call.
  2092. */
  2093. - (void)testSendPasswordResetEmailFailure {
  2094. OCMExpect([_mockBackend getOOBConfirmationCode:[OCMArg any] callback:[OCMArg any]])
  2095. .andDispatchError2([FIRAuthErrorUtils appNotAuthorizedError]);
  2096. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  2097. [[FIRAuth auth] sendPasswordResetWithEmail:kEmail
  2098. completion:^(NSError *_Nullable error) {
  2099. XCTAssertTrue([NSThread isMainThread]);
  2100. XCTAssertEqual(error.code, FIRAuthErrorCodeAppNotAuthorized);
  2101. XCTAssertNotNil(error.userInfo[NSLocalizedDescriptionKey]);
  2102. [expectation fulfill];
  2103. }];
  2104. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  2105. OCMVerifyAll(_mockBackend);
  2106. }
  2107. #if TARGET_OS_IOS && !TARGET_OS_MACCATALYST
  2108. /** @fn testSendSignInLinkToEmailWithRecaptchaSuccess
  2109. @brief Tests the flow of a successful @c sendSignInLinkToEmail:actionCodeSettings:completion:
  2110. call.
  2111. */
  2112. - (void)testSendSignInLinkToEmailWithRecaptchaSuccess {
  2113. id mockVerifier = OCMClassMock([FIRAuthRecaptchaVerifier class]);
  2114. OCMStub([mockVerifier sharedRecaptchaVerifier:[FIRAuth auth]]).andReturn(mockVerifier);
  2115. OCMExpect([mockVerifier enablementStatusForProvider:FIRAuthRecaptchaProviderPassword])
  2116. .andReturn(YES);
  2117. FIRGetOOBConfirmationCodeRequest *constRequestWithRecaptchaToken =
  2118. [FIRGetOOBConfirmationCodeRequest
  2119. signInWithEmailLinkRequest:kEmail
  2120. actionCodeSettings:[self fakeActionCodeSettings]
  2121. requestConfiguration:[FIRAuth auth].requestConfiguration];
  2122. [constRequestWithRecaptchaToken injectRecaptchaFields:kFakeRecaptchaResponse
  2123. recaptchaVersion:kFakeRecaptchaVersion];
  2124. OCMStub([mockVerifier
  2125. injectRecaptchaFields:[OCMArg any]
  2126. provider:FIRAuthRecaptchaProviderPassword
  2127. action:FIRAuthRecaptchaActionGetOobCode
  2128. completion:([OCMArg invokeBlockWithArgs:constRequestWithRecaptchaToken, nil])]);
  2129. OCMExpect([_mockBackend getOOBConfirmationCode:[OCMArg any] callback:[OCMArg any]])
  2130. .andCallBlock2(^(FIRGetOOBConfirmationCodeRequest *_Nullable request,
  2131. FIRGetOOBConfirmationCodeResponseCallback callback) {
  2132. XCTAssertEqualObjects(request.APIKey, kAPIKey);
  2133. XCTAssertEqualObjects(request.email, kEmail);
  2134. XCTAssertEqualObjects(request.continueURL, kContinueURL);
  2135. XCTAssertTrue(request.handleCodeInApp);
  2136. dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
  2137. callback([[FIRGetOOBConfirmationCodeResponse alloc] init], nil);
  2138. });
  2139. });
  2140. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  2141. [[FIRAuth auth] sendSignInLinkToEmail:kEmail
  2142. actionCodeSettings:[self fakeActionCodeSettings]
  2143. completion:^(NSError *_Nullable error) {
  2144. XCTAssertTrue([NSThread isMainThread]);
  2145. XCTAssertNil(error);
  2146. [expectation fulfill];
  2147. }];
  2148. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  2149. }
  2150. /** @fn testSendSignInLinkToEmailWithRecaptchaFallbackSuccess
  2151. @brief Tests the flow of a successful @c sendSignInLinkToEmail:actionCodeSettings:completion:
  2152. call.
  2153. */
  2154. - (void)testSendSignInLinkToEmailWithRecaptchaFallbackSuccess {
  2155. id mockVerifier = OCMClassMock([FIRAuthRecaptchaVerifier class]);
  2156. OCMStub([mockVerifier sharedRecaptchaVerifier:[FIRAuth auth]]).andReturn(mockVerifier);
  2157. OCMExpect([mockVerifier enablementStatusForProvider:FIRAuthRecaptchaProviderPassword])
  2158. .andReturn(NO);
  2159. FIRGetOOBConfirmationCodeRequest *constRequestWithRecaptchaToken =
  2160. [FIRGetOOBConfirmationCodeRequest
  2161. signInWithEmailLinkRequest:kEmail
  2162. actionCodeSettings:[self fakeActionCodeSettings]
  2163. requestConfiguration:[FIRAuth auth].requestConfiguration];
  2164. [constRequestWithRecaptchaToken injectRecaptchaFields:kFakeRecaptchaResponse
  2165. recaptchaVersion:kFakeRecaptchaVersion];
  2166. OCMStub([mockVerifier
  2167. injectRecaptchaFields:[OCMArg any]
  2168. provider:FIRAuthRecaptchaProviderPassword
  2169. action:FIRAuthRecaptchaActionGetOobCode
  2170. completion:([OCMArg invokeBlockWithArgs:constRequestWithRecaptchaToken, nil])]);
  2171. OCMExpect([_mockBackend getOOBConfirmationCode:[OCMArg any] callback:[OCMArg any]])
  2172. .andCallBlock2(^(FIRGetOOBConfirmationCodeRequest *_Nullable request,
  2173. FIRGetOOBConfirmationCodeResponseCallback callback) {
  2174. XCTAssertEqualObjects(request.APIKey, kAPIKey);
  2175. XCTAssertEqualObjects(request.email, kEmail);
  2176. XCTAssertEqualObjects(request.continueURL, kContinueURL);
  2177. XCTAssertTrue(request.handleCodeInApp);
  2178. NSError *underlyingError =
  2179. [[NSError alloc] initWithDomain:FIRAuthErrorDomain
  2180. code:FIRAuthErrorCodeInternalError
  2181. userInfo:@{
  2182. FIRAuthErrorUserInfoDeserializedResponseKey :
  2183. @{@"message" : @"MISSING_RECAPTCHA_TOKEN"}
  2184. }];
  2185. NSError *error = [[NSError alloc] initWithDomain:FIRAuthErrorDomain
  2186. code:FIRAuthErrorCodeInternalError
  2187. userInfo:@{NSUnderlyingErrorKey : underlyingError}];
  2188. dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
  2189. callback(nil, error);
  2190. });
  2191. });
  2192. OCMExpect([_mockBackend getOOBConfirmationCode:[OCMArg any] callback:[OCMArg any]])
  2193. .andCallBlock2(^(FIRGetOOBConfirmationCodeRequest *_Nullable request,
  2194. FIRGetOOBConfirmationCodeResponseCallback callback) {
  2195. XCTAssertEqualObjects(request.APIKey, kAPIKey);
  2196. XCTAssertEqualObjects(request.email, kEmail);
  2197. XCTAssertEqualObjects(request.continueURL, kContinueURL);
  2198. XCTAssertTrue(request.handleCodeInApp);
  2199. dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
  2200. callback([[FIRGetOOBConfirmationCodeResponse alloc] init], nil);
  2201. });
  2202. });
  2203. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  2204. [[FIRAuth auth] sendSignInLinkToEmail:kEmail
  2205. actionCodeSettings:[self fakeActionCodeSettings]
  2206. completion:^(NSError *_Nullable error) {
  2207. XCTAssertTrue([NSThread isMainThread]);
  2208. XCTAssertNil(error);
  2209. [expectation fulfill];
  2210. }];
  2211. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  2212. }
  2213. #endif
  2214. /** @fn testSendSignInLinkToEmailSuccess
  2215. @brief Tests the flow of a successful @c sendSignInLinkToEmail:actionCodeSettings:completion:
  2216. call.
  2217. */
  2218. - (void)testSendSignInLinkToEmailSuccess {
  2219. OCMExpect([_mockBackend getOOBConfirmationCode:[OCMArg any] callback:[OCMArg any]])
  2220. .andCallBlock2(^(FIRGetOOBConfirmationCodeRequest *_Nullable request,
  2221. FIRGetOOBConfirmationCodeResponseCallback callback) {
  2222. XCTAssertEqualObjects(request.APIKey, kAPIKey);
  2223. XCTAssertEqualObjects(request.email, kEmail);
  2224. XCTAssertEqualObjects(request.continueURL, kContinueURL);
  2225. XCTAssertTrue(request.handleCodeInApp);
  2226. dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
  2227. callback([[FIRGetOOBConfirmationCodeResponse alloc] init], nil);
  2228. });
  2229. });
  2230. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  2231. [[FIRAuth auth] sendSignInLinkToEmail:kEmail
  2232. actionCodeSettings:[self fakeActionCodeSettings]
  2233. completion:^(NSError *_Nullable error) {
  2234. XCTAssertTrue([NSThread isMainThread]);
  2235. XCTAssertNil(error);
  2236. [expectation fulfill];
  2237. }];
  2238. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  2239. OCMVerifyAll(_mockBackend);
  2240. }
  2241. /** @fn testSendSignInLinkToEmailFailure
  2242. @brief Tests the flow of a failed @c sendSignInLinkToEmail:actionCodeSettings:completion:
  2243. call.
  2244. */
  2245. - (void)testSendSignInLinkToEmailFailure {
  2246. OCMExpect([_mockBackend getOOBConfirmationCode:[OCMArg any] callback:[OCMArg any]])
  2247. .andDispatchError2([FIRAuthErrorUtils appNotAuthorizedError]);
  2248. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  2249. [[FIRAuth auth] sendSignInLinkToEmail:kEmail
  2250. actionCodeSettings:[self fakeActionCodeSettings]
  2251. completion:^(NSError *_Nullable error) {
  2252. XCTAssertTrue([NSThread isMainThread]);
  2253. XCTAssertEqual(error.code, FIRAuthErrorCodeAppNotAuthorized);
  2254. XCTAssertNotNil(error.userInfo[NSLocalizedDescriptionKey]);
  2255. [expectation fulfill];
  2256. }];
  2257. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  2258. OCMVerifyAll(_mockBackend);
  2259. }
  2260. /** @fn fakeActionCodeSettings
  2261. @brief Constructs and returns a fake instance of @c FIRActionCodeSettings for testing.
  2262. @return An instance of @c FIRActionCodeSettings for testing.
  2263. */
  2264. - (FIRActionCodeSettings *)fakeActionCodeSettings {
  2265. FIRActionCodeSettings *actionCodeSettings = [[FIRActionCodeSettings alloc] init];
  2266. actionCodeSettings.URL = [NSURL URLWithString:kContinueURL];
  2267. actionCodeSettings.handleCodeInApp = YES;
  2268. return actionCodeSettings;
  2269. }
  2270. /** @fn testUpdateCurrentUserFailure
  2271. @brief Tests the flow of a failed @c updateCurrentUser:completion:
  2272. call.
  2273. */
  2274. - (void)testUpdateCurrentUserFailure {
  2275. NSString *kTestAccessToken = @"fakeAccessToken";
  2276. NSString *kTestAPIKey = @"fakeAPIKey";
  2277. [self waitForSignInWithAccessToken:kTestAccessToken APIKey:kTestAPIKey completion:nil];
  2278. NSString *kTestAPIKey2 = @"fakeAPIKey2";
  2279. FIRUser *user2 = [FIRAuth auth].currentUser;
  2280. user2.requestConfiguration = [[FIRAuthRequestConfiguration alloc] initWithAPIKey:kTestAPIKey2
  2281. appID:kFirebaseAppID];
  2282. OCMExpect([_mockBackend getAccountInfo:[OCMArg any] callback:[OCMArg any]])
  2283. .andDispatchError2([FIRAuthErrorUtils invalidAPIKeyError]);
  2284. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  2285. [[FIRAuth auth] updateCurrentUser:user2
  2286. completion:^(NSError *_Nullable error) {
  2287. XCTAssertEqual(error.code, FIRAuthErrorCodeInvalidAPIKey);
  2288. [expectation fulfill];
  2289. }];
  2290. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  2291. OCMVerifyAll(_mockBackend);
  2292. }
  2293. /** @fn testUpdateCurrentUserFailureNetworkError
  2294. @brief Tests the flow of a failed @c updateCurrentUser:completion:
  2295. call with a network error.
  2296. */
  2297. - (void)testUpdateCurrentUserFailureNetworkError {
  2298. NSString *kTestAPIKey = @"fakeAPIKey";
  2299. NSString *kTestAccessToken = @"fakeAccessToken";
  2300. [self waitForSignInWithAccessToken:kTestAccessToken APIKey:kTestAPIKey completion:nil];
  2301. NSString *kTestAPIKey2 = @"fakeAPIKey2";
  2302. FIRUser *user2 = [FIRAuth auth].currentUser;
  2303. user2.requestConfiguration = [[FIRAuthRequestConfiguration alloc] initWithAPIKey:kTestAPIKey2
  2304. appID:kFirebaseAppID];
  2305. NSError *underlyingError = [NSError errorWithDomain:@"Test Error" code:1 userInfo:nil];
  2306. OCMExpect([_mockBackend getAccountInfo:[OCMArg any] callback:[OCMArg any]])
  2307. .andDispatchError2([FIRAuthErrorUtils networkErrorWithUnderlyingError:underlyingError]);
  2308. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  2309. [[FIRAuth auth] updateCurrentUser:user2
  2310. completion:^(NSError *_Nullable error) {
  2311. XCTAssertEqual(error.code, FIRAuthErrorCodeNetworkError);
  2312. [expectation fulfill];
  2313. }];
  2314. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  2315. OCMVerifyAll(_mockBackend);
  2316. }
  2317. /** @fn testUpdateCurrentUserFailureNUllUser
  2318. @brief Tests the flow of a failed @c updateCurrentUser:completion:
  2319. call with FIRAuthErrorCodeNullUser.
  2320. */
  2321. - (void)testUpdateCurrentUserFailureNUllUser {
  2322. NSString *kTestAccessToken = @"fakeAccessToken";
  2323. NSString *kTestAPIKey = @"fakeAPIKey";
  2324. [self waitForSignInWithAccessToken:kTestAccessToken APIKey:kTestAPIKey completion:nil];
  2325. FIRUser *fakeNilUser = nil;
  2326. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  2327. [[FIRAuth auth] updateCurrentUser:fakeNilUser
  2328. completion:^(NSError *_Nullable error) {
  2329. XCTAssertEqual(error.code, FIRAuthErrorCodeNullUser);
  2330. [expectation fulfill];
  2331. }];
  2332. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  2333. OCMVerifyAll(_mockBackend);
  2334. }
  2335. /** @fn testUpdateCurrentUserFailureTenantIDMismatch
  2336. @brief Tests the flow of a failed @c updateCurrentUser:completion:
  2337. call with FIRAuthErrorCodeTenantIDMismatch.
  2338. */
  2339. - (void)testUpdateCurrentUserFailureTenantIDMismatch {
  2340. // User without tenant id
  2341. [self waitForSignInWithAccessToken:kAccessToken APIKey:kAPIKey completion:nil];
  2342. FIRUser *user1 = [FIRAuth auth].currentUser;
  2343. [[FIRAuth auth] signOut:nil];
  2344. // User with tenant id "tenant-id"
  2345. [FIRAuth auth].tenantID = @"tenant-id-1";
  2346. NSString *kTestAccessToken2 = @"fakeAccessToken2";
  2347. [self waitForSignInWithAccessToken:kTestAccessToken2 APIKey:kAPIKey completion:nil];
  2348. FIRUser *user2 = [FIRAuth auth].currentUser;
  2349. [[FIRAuth auth] signOut:nil];
  2350. [FIRAuth auth].tenantID = @"tenant-id-2";
  2351. XCTestExpectation *expectation1 = [self expectationWithDescription:@"callback"];
  2352. [[FIRAuth auth] updateCurrentUser:user1
  2353. completion:^(NSError *_Nullable error) {
  2354. XCTAssertEqual(error.code, FIRAuthErrorCodeTenantIDMismatch);
  2355. [expectation1 fulfill];
  2356. }];
  2357. [[FIRAuth auth] signOut:nil];
  2358. [FIRAuth auth].tenantID = @"tenant-id-2";
  2359. XCTestExpectation *expectation2 = [self expectationWithDescription:@"callback"];
  2360. [[FIRAuth auth] updateCurrentUser:user2
  2361. completion:^(NSError *_Nullable error) {
  2362. XCTAssertEqual(error.code, FIRAuthErrorCodeTenantIDMismatch);
  2363. [expectation2 fulfill];
  2364. }];
  2365. [[FIRAuth auth] signOut:nil];
  2366. [FIRAuth auth].tenantID = nil;
  2367. XCTestExpectation *expectation3 = [self expectationWithDescription:@"callback"];
  2368. [[FIRAuth auth] updateCurrentUser:user2
  2369. completion:^(NSError *_Nullable error) {
  2370. XCTAssertEqual(error.code, FIRAuthErrorCodeTenantIDMismatch);
  2371. [expectation3 fulfill];
  2372. }];
  2373. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  2374. OCMVerifyAll(_mockBackend);
  2375. }
  2376. /** @fn testUpdateCurrentUserSuccess
  2377. @brief Tests the flow of a successful @c updateCurrentUser:completion:
  2378. call with a network error.
  2379. */
  2380. - (void)testUpdateCurrentUserSuccess {
  2381. // Sign in with the first user.
  2382. [self waitForSignInWithAccessToken:kAccessToken APIKey:kAPIKey completion:nil];
  2383. FIRUser *user1 = [FIRAuth auth].currentUser;
  2384. NSString *kTestAPIKey = @"fakeAPIKey";
  2385. user1.requestConfiguration = [[FIRAuthRequestConfiguration alloc] initWithAPIKey:kTestAPIKey
  2386. appID:kFirebaseAppID];
  2387. [[FIRAuth auth] signOut:nil];
  2388. NSString *kTestAccessToken2 = @"fakeAccessToken2";
  2389. [self waitForSignInWithAccessToken:kTestAccessToken2 APIKey:kAPIKey completion:nil];
  2390. FIRUser *user2 = [FIRAuth auth].currentUser;
  2391. [self expectGetAccountInfoWithAccessToken:kAccessToken];
  2392. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  2393. // Current user should now be user2.
  2394. XCTAssertEqualObjects([FIRAuth auth].currentUser, user2);
  2395. [[FIRAuth auth] updateCurrentUser:user1
  2396. completion:^(NSError *_Nullable error) {
  2397. XCTAssertNil(error);
  2398. // Current user should now be user1.
  2399. XCTAssertEqualObjects([FIRAuth auth].currentUser, user1);
  2400. XCTAssertNotEqualObjects([FIRAuth auth].currentUser, user2);
  2401. [expectation fulfill];
  2402. }];
  2403. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  2404. OCMVerifyAll(_mockBackend);
  2405. }
  2406. /** @fn testSignOut
  2407. @brief Tests the @c signOut: method.
  2408. */
  2409. - (void)testSignOut {
  2410. [self waitForSignIn];
  2411. // Verify signing out succeeds and clears the current user.
  2412. NSError *error;
  2413. XCTAssertTrue([[FIRAuth auth] signOut:&error]);
  2414. XCTAssertNil([FIRAuth auth].currentUser);
  2415. }
  2416. /** @fn testIsSignInWithEmailLink
  2417. @brief Tests the @c isSignInWithEmailLink: method.
  2418. */
  2419. - (void)testIsSignInWithEmailLink {
  2420. XCTAssertTrue([[FIRAuth auth] isSignInWithEmailLink:kFakeEmailSignInlink]);
  2421. XCTAssertTrue([[FIRAuth auth] isSignInWithEmailLink:kFakeEmailSignInDeeplink]);
  2422. XCTAssertFalse([[FIRAuth auth] isSignInWithEmailLink:kBadSignInEmailLink]);
  2423. XCTAssertFalse([[FIRAuth auth] isSignInWithEmailLink:@""]);
  2424. }
  2425. /** @fn testAuthStateChanges
  2426. @brief Tests @c addAuthStateDidChangeListener: and @c removeAuthStateDidChangeListener: methods.
  2427. */
  2428. - (void)testAuthStateChanges {
  2429. // Set up listener.
  2430. __block XCTestExpectation *expectation;
  2431. __block BOOL shouldHaveUser;
  2432. FIRAuthStateDidChangeListenerBlock listener = ^(FIRAuth *auth, FIRUser *_Nullable user) {
  2433. XCTAssertTrue([NSThread isMainThread]);
  2434. XCTAssertEqual(auth, [FIRAuth auth]);
  2435. XCTAssertEqual(user, [FIRAuth auth].currentUser);
  2436. if (shouldHaveUser) {
  2437. XCTAssertNotNil(user);
  2438. } else {
  2439. XCTAssertNil(user);
  2440. }
  2441. // `expectation` being nil means the listener is not expected to be fired at this moment.
  2442. XCTAssertNotNil(expectation);
  2443. [expectation fulfill];
  2444. };
  2445. [[FIRAuth auth] signOut:NULL];
  2446. [self waitForTimeIntervel:kWaitInterval]; // Wait until dust settled from previous tests.
  2447. // Listener should fire immediately when attached.
  2448. expectation = [self expectationWithDescription:@"initial"];
  2449. shouldHaveUser = NO;
  2450. FIRAuthStateDidChangeListenerHandle handle =
  2451. [[FIRAuth auth] addAuthStateDidChangeListener:listener];
  2452. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  2453. // Listener should fire for signing in.
  2454. expectation = [self expectationWithDescription:@"sign-in"];
  2455. shouldHaveUser = YES;
  2456. [self waitForSignIn];
  2457. // Listener should not fire for signing in again.
  2458. shouldHaveUser = YES;
  2459. [self waitForSignIn];
  2460. [self waitForTimeIntervel:kWaitInterval]; // make sure listener is not called
  2461. // Listener should fire for signing out.
  2462. expectation = [self expectationWithDescription:@"sign-out"];
  2463. shouldHaveUser = NO;
  2464. [[FIRAuth auth] signOut:NULL];
  2465. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  2466. // Listener should no longer fire once detached.
  2467. expectation = nil;
  2468. [[FIRAuth auth] removeAuthStateDidChangeListener:handle];
  2469. [self waitForSignIn];
  2470. [self waitForTimeIntervel:kWaitInterval]; // make sure listener is no longer called
  2471. }
  2472. /** @fn testIDTokenChanges
  2473. @brief Tests @c addIDTokenDidChangeListener: and @c removeIDTokenDidChangeListener: methods.
  2474. */
  2475. - (void)testIDTokenChanges {
  2476. // Set up listener.
  2477. __block XCTestExpectation *expectation;
  2478. __block BOOL shouldHaveUser;
  2479. FIRIDTokenDidChangeListenerBlock listener = ^(FIRAuth *auth, FIRUser *_Nullable user) {
  2480. XCTAssertTrue([NSThread isMainThread]);
  2481. XCTAssertEqual(auth, [FIRAuth auth]);
  2482. XCTAssertEqual(user, [FIRAuth auth].currentUser);
  2483. if (shouldHaveUser) {
  2484. XCTAssertNotNil(user);
  2485. } else {
  2486. XCTAssertNil(user);
  2487. }
  2488. // `expectation` being nil means the listener is not expected to be fired at this moment.
  2489. XCTAssertNotNil(expectation);
  2490. [expectation fulfill];
  2491. };
  2492. [[FIRAuth auth] signOut:NULL];
  2493. [self waitForTimeIntervel:kWaitInterval]; // Wait until dust settled from previous tests.
  2494. // Listener should fire immediately when attached.
  2495. expectation = [self expectationWithDescription:@"initial"];
  2496. shouldHaveUser = NO;
  2497. FIRIDTokenDidChangeListenerHandle handle = [[FIRAuth auth] addIDTokenDidChangeListener:listener];
  2498. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  2499. // Listener should fire for signing in.
  2500. expectation = [self expectationWithDescription:@"sign-in"];
  2501. shouldHaveUser = YES;
  2502. [self waitForSignIn];
  2503. // Listener should fire for signing in again as the same user with another access token.
  2504. expectation = [self expectationWithDescription:@"sign-in again"];
  2505. shouldHaveUser = YES;
  2506. [self waitForSignInWithAccessToken:kNewAccessToken APIKey:nil completion:nil];
  2507. // Listener should fire for signing out.
  2508. expectation = [self expectationWithDescription:@"sign-out"];
  2509. shouldHaveUser = NO;
  2510. [[FIRAuth auth] signOut:NULL];
  2511. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  2512. // Listener should no longer fire once detached.
  2513. expectation = nil;
  2514. [[FIRAuth auth] removeIDTokenDidChangeListener:handle];
  2515. [self waitForSignIn];
  2516. [self waitForTimeIntervel:kWaitInterval]; // make sure listener is no longer called
  2517. }
  2518. /** @fn testUseEmulator
  2519. @brief Tests the @c useEmulatorWithHost:port: method.
  2520. */
  2521. - (void)testUseEmulator {
  2522. [[FIRAuth auth] useEmulatorWithHost:@"host" port:12345];
  2523. XCTAssertEqualObjects(@"host:12345", [FIRAuth auth].requestConfiguration.emulatorHostAndPort);
  2524. #if TARGET_OS_IOS
  2525. XCTAssertTrue([FIRAuth auth].settings.isAppVerificationDisabledForTesting);
  2526. #endif
  2527. }
  2528. /** @fn testUseEmulatorNeverCalled
  2529. @brief Tests that the emulatorHostAndPort stored in @c FIRAuthRequestConfiguration is nil if the
  2530. @c useEmulatorWithHost:port: is not called.
  2531. */
  2532. - (void)testUseEmulatorNeverCalled {
  2533. XCTAssertEqualObjects(nil, [FIRAuth auth].requestConfiguration.emulatorHostAndPort);
  2534. #if TARGET_OS_IOS
  2535. XCTAssertFalse([FIRAuth auth].settings.isAppVerificationDisabledForTesting);
  2536. #endif
  2537. }
  2538. /** @fn testUseEmulatorIPv6Address
  2539. @brief Tests the @c useEmulatorWithHost:port: method with an IPv6 host address.
  2540. */
  2541. - (void)testUseEmulatorIPv6Address {
  2542. [[FIRAuth auth] useEmulatorWithHost:@"::1" port:12345];
  2543. XCTAssertEqualObjects(@"[::1]:12345", [FIRAuth auth].requestConfiguration.emulatorHostAndPort);
  2544. #if TARGET_OS_IOS
  2545. XCTAssertTrue([FIRAuth auth].settings.isAppVerificationDisabledForTesting);
  2546. #endif
  2547. }
  2548. #pragma mark - Automatic Token Refresh Tests.
  2549. /** @fn testAutomaticTokenRefresh
  2550. @brief Tests a successful flow to automatically refresh tokens for a signed in user.
  2551. */
  2552. - (void)testAutomaticTokenRefresh {
  2553. [[FIRAuth auth] signOut:NULL];
  2554. // Enable auto refresh
  2555. [self enableAutoTokenRefresh];
  2556. // Sign in a user.
  2557. [self waitForSignIn];
  2558. // Set up expectation for secureToken RPC made by token refresh task. We call this twice, because
  2559. // we retry once if the access token is already expired.
  2560. [self mockSecureTokenResponseWithError:nil];
  2561. [self mockSecureTokenResponseWithError:nil];
  2562. // Verify that the current user's access token is the "old" access token before automatic token
  2563. // refresh.
  2564. XCTAssertEqualObjects(kAccessToken, [FIRAuth auth].currentUser.rawAccessToken);
  2565. // Execute saved token refresh task.
  2566. XCTestExpectation *dispatchAfterExpectation =
  2567. [self expectationWithDescription:@"dispatchAfterExpectation"];
  2568. dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
  2569. XCTAssertNotNil(self->_FIRAuthDispatcherCallback);
  2570. self->_FIRAuthDispatcherCallback();
  2571. [dispatchAfterExpectation fulfill];
  2572. });
  2573. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  2574. // Verify that current user's access token is the "new" access token provided in the mock secure
  2575. // token response during automatic token refresh.
  2576. XCTAssertEqualObjects(kNewAccessToken, [FIRAuth auth].currentUser.rawAccessToken);
  2577. OCMVerifyAll(_mockBackend);
  2578. }
  2579. /** @fn testAutomaticTokenRefreshInvalidTokenFailure
  2580. @brief Tests an unsuccessful flow to auto refresh tokens with an "invalid token" error.
  2581. This error should cause the user to be signed out.
  2582. */
  2583. - (void)testAutomaticTokenRefreshInvalidTokenFailure {
  2584. [[FIRAuth auth] signOut:NULL];
  2585. // Enable auto refresh
  2586. [self enableAutoTokenRefresh];
  2587. // Sign in a user.
  2588. [self waitForSignIn];
  2589. // Set up expectation for secureToken RPC made by a failed attempt to refresh tokens.
  2590. [self mockSecureTokenResponseWithError:[FIRAuthErrorUtils invalidUserTokenErrorWithMessage:nil]];
  2591. // Verify that current user is still valid.
  2592. XCTAssertEqualObjects(kAccessToken, [FIRAuth auth].currentUser.rawAccessToken);
  2593. // Execute saved token refresh task.
  2594. XCTestExpectation *dispatchAfterExpectation =
  2595. [self expectationWithDescription:@"dispatchAfterExpectation"];
  2596. dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
  2597. XCTAssertNotNil(self->_FIRAuthDispatcherCallback);
  2598. self->_FIRAuthDispatcherCallback();
  2599. [dispatchAfterExpectation fulfill];
  2600. });
  2601. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  2602. // Verify that the user is nil after failed attempt to refresh tokens caused signed out.
  2603. XCTAssertNil([FIRAuth auth].currentUser);
  2604. OCMVerifyAll(_mockBackend);
  2605. }
  2606. /** @fn testAutomaticTokenRefreshRetry
  2607. @brief Tests that a retry is attempted for a automatic token refresh task (which is not due to
  2608. invalid tokens). The initial attempt to refresh the access token fails, but the second
  2609. attempt is successful.
  2610. */
  2611. - (void)testAutomaticTokenRefreshRetry {
  2612. [[FIRAuth auth] signOut:NULL];
  2613. // Enable auto refresh
  2614. [self enableAutoTokenRefresh];
  2615. // Sign in a user.
  2616. [self waitForSignIn];
  2617. // Set up expectation for secureToken RPC made by a failed attempt to refresh tokens.
  2618. [self mockSecureTokenResponseWithError:[NSError errorWithDomain:@"ERROR" code:-1 userInfo:nil]];
  2619. // Execute saved token refresh task.
  2620. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  2621. dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
  2622. XCTAssertNotNil(self->_FIRAuthDispatcherCallback);
  2623. self->_FIRAuthDispatcherCallback();
  2624. self->_FIRAuthDispatcherCallback = nil;
  2625. [expectation fulfill];
  2626. });
  2627. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  2628. // The old access token should still be the current user's access token and not the new access
  2629. // token (kNewAccessToken).
  2630. XCTAssertEqualObjects(kAccessToken, [FIRAuth auth].currentUser.rawAccessToken);
  2631. // Set up expectation for secureToken RPC made by a successful attempt to refresh tokens. We call
  2632. // this twice, because we retry once if the access token is already expired.
  2633. [self mockSecureTokenResponseWithError:nil];
  2634. [self mockSecureTokenResponseWithError:nil];
  2635. // Execute saved token refresh task.
  2636. XCTestExpectation *dispatchAfterExpectation =
  2637. [self expectationWithDescription:@"dispatchAfterExpectation"];
  2638. dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
  2639. XCTAssertNotNil(self->_FIRAuthDispatcherCallback);
  2640. self->_FIRAuthDispatcherCallback();
  2641. [dispatchAfterExpectation fulfill];
  2642. });
  2643. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  2644. // Verify that current user's access token is the "new" access token provided in the mock secure
  2645. // token response during automatic token refresh.
  2646. XCTAssertEqualObjects([FIRAuth auth].currentUser.rawAccessToken, kNewAccessToken);
  2647. OCMVerifyAll(_mockBackend);
  2648. }
  2649. #if TARGET_OS_IOS
  2650. /** @fn testAutomaticTokenRefreshInvalidTokenFailure
  2651. @brief Tests that app foreground notification triggers the scheduling of an automatic token
  2652. refresh task.
  2653. */
  2654. - (void)testAutoRefreshAppForegroundedNotification {
  2655. [[FIRAuth auth] signOut:NULL];
  2656. // Enable auto refresh
  2657. [self enableAutoTokenRefresh];
  2658. // Sign in a user.
  2659. [self waitForSignIn];
  2660. // Post "UIApplicationDidBecomeActiveNotification" to trigger scheduling token refresh task.
  2661. [[NSNotificationCenter defaultCenter]
  2662. postNotificationName:UIApplicationDidBecomeActiveNotification
  2663. object:nil];
  2664. // Verify that current user is still valid with old access token.
  2665. XCTAssertEqualObjects(kAccessToken, [FIRAuth auth].currentUser.rawAccessToken);
  2666. // Set up expectation for secureToken RPC made by a successful attempt to refresh tokens. We call
  2667. // this twice, because we retry once if the access token is already expired.
  2668. [self mockSecureTokenResponseWithError:nil];
  2669. [self mockSecureTokenResponseWithError:nil];
  2670. // Execute saved token refresh task.
  2671. XCTestExpectation *dispatchAfterExpectation =
  2672. [self expectationWithDescription:@"dispatchAfterExpectation"];
  2673. dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
  2674. XCTAssertNotNil(self->_FIRAuthDispatcherCallback);
  2675. self->_FIRAuthDispatcherCallback();
  2676. [dispatchAfterExpectation fulfill];
  2677. });
  2678. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  2679. // Verify that current user is still valid with new access token.
  2680. XCTAssertEqualObjects(kNewAccessToken, [FIRAuth auth].currentUser.rawAccessToken);
  2681. OCMVerifyAll(_mockBackend);
  2682. }
  2683. #endif
  2684. #if TARGET_OS_IOS
  2685. #pragma mark - Application Delegate tests
  2686. - (void)testAppDidRegisterForRemoteNotifications_APNSTokenUpdated {
  2687. NSData *apnsToken = [NSData data];
  2688. OCMExpect([self.mockTokenManager setToken:[OCMArg checkWithBlock:^BOOL(FIRAuthAPNSToken *token) {
  2689. XCTAssertEqual(token.data, apnsToken);
  2690. XCTAssertEqual(token.type, FIRAuthAPNSTokenTypeUnknown);
  2691. return YES;
  2692. }]]);
  2693. [self.fakeApplicationDelegate application:[GULAppDelegateSwizzler sharedApplication]
  2694. didRegisterForRemoteNotificationsWithDeviceToken:apnsToken];
  2695. [self.mockTokenManager verify];
  2696. }
  2697. - (void)testAppDidFailToRegisterForRemoteNotifications_TokenManagerCancels {
  2698. NSError *error = [NSError errorWithDomain:@"FIRAuthTests" code:-1 userInfo:nil];
  2699. OCMExpect([self.mockTokenManager cancelWithError:error]);
  2700. [self.fakeApplicationDelegate application:[GULAppDelegateSwizzler sharedApplication]
  2701. didFailToRegisterForRemoteNotificationsWithError:error];
  2702. [self.mockTokenManager verify];
  2703. }
  2704. - (void)testAppDidReceiveRemoteNotification_NotificationManagerHandleCanNotification {
  2705. NSDictionary *notification = @{@"test" : @""};
  2706. OCMExpect([self.mockNotificationManager canHandleNotification:notification]);
  2707. #pragma clang diagnostic push
  2708. #pragma clang diagnostic ignored "-Wdeprecated-declarations"
  2709. [self.fakeApplicationDelegate application:[GULAppDelegateSwizzler sharedApplication]
  2710. didReceiveRemoteNotification:notification];
  2711. #pragma clang diagnostic pop
  2712. [self.mockNotificationManager verify];
  2713. }
  2714. - (void)testAppDidReceiveRemoteNotificationWithCompletion_NotificationManagerHandleCanNotification {
  2715. NSDictionary *notification = @{@"test" : @""};
  2716. OCMExpect([self.mockNotificationManager canHandleNotification:notification]);
  2717. [self.fakeApplicationDelegate application:[GULAppDelegateSwizzler sharedApplication]
  2718. didReceiveRemoteNotification:notification
  2719. fetchCompletionHandler:^(UIBackgroundFetchResult result){
  2720. }];
  2721. [self.mockNotificationManager verify];
  2722. }
  2723. - (void)testAppOpenURL_AuthPresenterCanHandleURL {
  2724. if (@available(iOS 9.0, *)) {
  2725. // 'application:openURL:options:' is only available on iOS 9.0 or newer.
  2726. NSURL *url = [NSURL URLWithString:@"https://localhost"];
  2727. OCMExpect([self.mockAuthURLPresenter canHandleURL:url]).andReturn(YES);
  2728. XCTAssertTrue([self.fakeApplicationDelegate
  2729. application:[GULAppDelegateSwizzler sharedApplication]
  2730. openURL:url
  2731. options:@{}]);
  2732. [self.mockAuthURLPresenter verify];
  2733. }
  2734. }
  2735. - (void)testAppOpenURLWithSourceApplication_AuthPresenterCanHandleURL {
  2736. NSURL *url = [NSURL URLWithString:@"https://localhost"];
  2737. OCMExpect([self.mockAuthURLPresenter canHandleURL:url]).andReturn(YES);
  2738. #pragma clang diagnostic push
  2739. #pragma clang diagnostic ignored "-Wdeprecated-declarations"
  2740. XCTAssertTrue([self.fakeApplicationDelegate application:[GULAppDelegateSwizzler sharedApplication]
  2741. openURL:url
  2742. sourceApplication:@""
  2743. annotation:[[NSObject alloc] init]]);
  2744. #pragma clang diagnostic pop
  2745. [self.mockAuthURLPresenter verify];
  2746. }
  2747. #endif // TARGET_OS_IOS
  2748. #pragma mark - Interoperability Tests
  2749. /** @fn testComponentsBeingRegistered
  2750. @brief Tests that Auth provides the necessary components for interoperability with other SDKs.
  2751. */
  2752. - (void)testComponentsBeingRegistered {
  2753. // Verify that the components are registered properly. Check the count, because any time a new
  2754. // component is added it should be added to the test suite as well.
  2755. NSArray<FIRComponent *> *components = [FIRAuth componentsToRegister];
  2756. XCTAssertTrue(components.count == 1);
  2757. FIRComponent *component = [components firstObject];
  2758. XCTAssert(component.protocol == @protocol(FIRAuthInterop));
  2759. }
  2760. #pragma mark - Helpers
  2761. /** @fn mockSecureTokenResponseWithError:
  2762. @brief Set up expectation for secureToken RPC.
  2763. @param error The error that the mock should return if any.
  2764. */
  2765. - (void)mockSecureTokenResponseWithError:(nullable NSError *)error {
  2766. // Set up expectation for secureToken RPC made by a successful attempt to refresh tokens.
  2767. XCTestExpectation *secureTokenResponseExpectation =
  2768. [self expectationWithDescription:@"secureTokenResponseExpectation"];
  2769. OCMExpect([_mockBackend secureToken:[OCMArg any] callback:[OCMArg any]])
  2770. .andCallBlock2(
  2771. ^(FIRSecureTokenRequest *_Nullable request, FIRSecureTokenResponseCallback callback) {
  2772. XCTAssertEqualObjects(request.APIKey, kAPIKey);
  2773. XCTAssertEqualObjects(request.refreshToken, kRefreshToken);
  2774. dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
  2775. if (error) {
  2776. callback(nil, error);
  2777. [secureTokenResponseExpectation fulfill];
  2778. return;
  2779. }
  2780. id mockSecureTokenResponse = OCMClassMock([FIRSecureTokenResponse class]);
  2781. OCMStub([mockSecureTokenResponse accessToken]).andReturn(kNewAccessToken);
  2782. NSDate *futureDate =
  2783. [[NSDate date] dateByAddingTimeInterval:kTestTokenExpirationTimeInterval];
  2784. OCMStub([mockSecureTokenResponse approximateExpirationDate]).andReturn(futureDate);
  2785. callback(mockSecureTokenResponse, nil);
  2786. [secureTokenResponseExpectation fulfill];
  2787. });
  2788. });
  2789. }
  2790. /** @fn enableAutoTokenRefresh
  2791. @brief Enables automatic token refresh by invoking FIRAuth's implementation of FIRApp's
  2792. |getTokenWithImplementation|.
  2793. */
  2794. - (void)enableAutoTokenRefresh {
  2795. XCTestExpectation *expectation = [self expectationWithDescription:@"autoTokenRefreshcallback"];
  2796. [[FIRAuth auth] getTokenForcingRefresh:NO
  2797. withCallback:^(NSString *_Nullable token, NSError *_Nullable error) {
  2798. [expectation fulfill];
  2799. }];
  2800. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  2801. }
  2802. /** @fn stubSecureTokensWithMockResponse
  2803. @brief Creates stubs on the mock response object with access and refresh tokens
  2804. @param mockResponse The mock response object.
  2805. */
  2806. - (void)stubTokensWithMockResponse:(id)mockResponse {
  2807. OCMStub([mockResponse IDToken]).andReturn(kAccessToken);
  2808. OCMStub([mockResponse approximateExpirationDate])
  2809. .andReturn([NSDate dateWithTimeIntervalSinceNow:kAccessTokenTimeToLive]);
  2810. OCMStub([mockResponse refreshToken]).andReturn(kRefreshToken);
  2811. }
  2812. /** @fn expectGetAccountInfo
  2813. @brief Expects a GetAccountInfo request on the mock backend and calls back with fake account
  2814. data.
  2815. */
  2816. - (void)expectGetAccountInfo {
  2817. [self expectGetAccountInfoWithAccessToken:kAccessToken];
  2818. }
  2819. /** @fn expectGetAccountInfoWithAccessToken
  2820. @param accessToken The access token for the user to check against.
  2821. @brief Expects a GetAccountInfo request on the mock backend and calls back with fake account
  2822. data.
  2823. */
  2824. - (void)expectGetAccountInfoWithAccessToken:(NSString *)accessToken {
  2825. OCMExpect([_mockBackend getAccountInfo:[OCMArg any] callback:[OCMArg any]])
  2826. .andCallBlock2(^(FIRGetAccountInfoRequest *_Nullable request,
  2827. FIRGetAccountInfoResponseCallback callback) {
  2828. XCTAssertEqualObjects(request.APIKey, kAPIKey);
  2829. XCTAssertEqualObjects(request.accessToken, accessToken);
  2830. dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
  2831. id mockGetAccountInfoResponseUser = OCMClassMock([FIRGetAccountInfoResponseUser class]);
  2832. OCMStub([mockGetAccountInfoResponseUser localID]).andReturn(kLocalID);
  2833. OCMStub([mockGetAccountInfoResponseUser displayName]).andReturn(kDisplayName);
  2834. OCMStub([mockGetAccountInfoResponseUser email]).andReturn(kEmail);
  2835. OCMStub([mockGetAccountInfoResponseUser passwordHash]).andReturn(kPasswordHash);
  2836. id mockGetAccountInfoResponse = OCMClassMock([FIRGetAccountInfoResponse class]);
  2837. OCMStub([mockGetAccountInfoResponse users]).andReturn(@[
  2838. mockGetAccountInfoResponseUser
  2839. ]);
  2840. callback(mockGetAccountInfoResponse, nil);
  2841. });
  2842. });
  2843. }
  2844. /** @fn assertUser
  2845. @brief Asserts the given FIRUser matching the fake data returned by @c expectGetAccountInfo.
  2846. @param user The user object to be verified.
  2847. */
  2848. - (void)assertUser:(FIRUser *)user {
  2849. XCTAssertNotNil(user);
  2850. XCTAssertEqualObjects(user.uid, kLocalID);
  2851. XCTAssertEqualObjects(user.displayName, kDisplayName);
  2852. XCTAssertEqualObjects(user.email, kEmail);
  2853. XCTAssertFalse(user.anonymous);
  2854. XCTAssertEqual(user.providerData.count, 0u);
  2855. }
  2856. /** @fn expectGetAccountInfoGoogle
  2857. @brief Expects a GetAccountInfo request on the mock backend and calls back with fake account
  2858. data for a Google Sign-In user.
  2859. */
  2860. - (void)expectGetAccountInfoGoogle {
  2861. OCMExpect([_mockBackend getAccountInfo:[OCMArg any] callback:[OCMArg any]])
  2862. .andCallBlock2(^(FIRGetAccountInfoRequest *_Nullable request,
  2863. FIRGetAccountInfoResponseCallback callback) {
  2864. XCTAssertEqualObjects(request.APIKey, kAPIKey);
  2865. XCTAssertEqualObjects(request.accessToken, kAccessToken);
  2866. dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
  2867. id mockGoogleUserInfo = OCMClassMock([FIRGetAccountInfoResponseProviderUserInfo class]);
  2868. OCMStub([mockGoogleUserInfo providerID]).andReturn(FIRGoogleAuthProviderID);
  2869. OCMStub([mockGoogleUserInfo displayName]).andReturn(kGoogleDisplayName);
  2870. OCMStub([mockGoogleUserInfo federatedID]).andReturn(kGoogleID);
  2871. OCMStub([mockGoogleUserInfo email]).andReturn(kGoogleEmail);
  2872. id mockGetAccountInfoResponseUser = OCMClassMock([FIRGetAccountInfoResponseUser class]);
  2873. OCMStub([mockGetAccountInfoResponseUser localID]).andReturn(kLocalID);
  2874. OCMStub([mockGetAccountInfoResponseUser displayName]).andReturn(kDisplayName);
  2875. OCMStub([mockGetAccountInfoResponseUser providerUserInfo])
  2876. .andReturn((@[ mockGoogleUserInfo ]));
  2877. id mockGetAccountInfoResponse = OCMClassMock([FIRGetAccountInfoResponse class]);
  2878. OCMStub([mockGetAccountInfoResponse users]).andReturn(@[
  2879. mockGetAccountInfoResponseUser
  2880. ]);
  2881. callback(mockGetAccountInfoResponse, nil);
  2882. });
  2883. });
  2884. }
  2885. /** @fn assertUserGoogle
  2886. @brief Asserts the given FIRUser matching the fake data returned by
  2887. @c expectGetAccountInfoGoogle.
  2888. @param user The user object to be verified.
  2889. */
  2890. - (void)assertUserGoogle:(FIRUser *)user {
  2891. XCTAssertNotNil(user);
  2892. XCTAssertEqualObjects(user.uid, kLocalID);
  2893. XCTAssertEqualObjects(user.displayName, kDisplayName);
  2894. XCTAssertEqual(user.providerData.count, 1u);
  2895. id<FIRUserInfo> googleUserInfo = user.providerData[0];
  2896. XCTAssertEqualObjects(googleUserInfo.providerID, FIRGoogleAuthProviderID);
  2897. XCTAssertEqualObjects(googleUserInfo.uid, kGoogleID);
  2898. XCTAssertEqualObjects(googleUserInfo.displayName, kGoogleDisplayName);
  2899. XCTAssertEqualObjects(googleUserInfo.email, kGoogleEmail);
  2900. }
  2901. /** @fn expectGetAccountInfoAnonymous
  2902. @brief Expects a GetAccountInfo request on the mock backend and calls back with fake anonymous
  2903. account data.
  2904. */
  2905. - (void)expectGetAccountInfoAnonymous {
  2906. OCMExpect([_mockBackend getAccountInfo:[OCMArg any] callback:[OCMArg any]])
  2907. .andCallBlock2(^(FIRGetAccountInfoRequest *_Nullable request,
  2908. FIRGetAccountInfoResponseCallback callback) {
  2909. XCTAssertEqualObjects(request.APIKey, kAPIKey);
  2910. XCTAssertEqualObjects(request.accessToken, kAccessToken);
  2911. dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
  2912. id mockGetAccountInfoResponseUser = OCMClassMock([FIRGetAccountInfoResponseUser class]);
  2913. OCMStub([mockGetAccountInfoResponseUser localID]).andReturn(kLocalID);
  2914. id mockGetAccountInfoResponse = OCMClassMock([FIRGetAccountInfoResponse class]);
  2915. OCMStub([mockGetAccountInfoResponse users]).andReturn(@[
  2916. mockGetAccountInfoResponseUser
  2917. ]);
  2918. callback(mockGetAccountInfoResponse, nil);
  2919. });
  2920. });
  2921. }
  2922. /** @fn assertUserAnonymous
  2923. @brief Asserts the given FIRUser matching the fake data returned by
  2924. @c expectGetAccountInfoAnonymous.
  2925. @param user The user object to be verified.
  2926. */
  2927. - (void)assertUserAnonymous:(FIRUser *)user {
  2928. XCTAssertNotNil(user);
  2929. XCTAssertEqualObjects(user.uid, kLocalID);
  2930. XCTAssertNil(user.displayName);
  2931. XCTAssertTrue(user.anonymous);
  2932. XCTAssertEqual(user.providerData.count, 0u);
  2933. }
  2934. /** @fn waitForSignIn
  2935. @brief Signs in a user to prepare for tests.
  2936. @remarks This method also waits for all other pending @c XCTestExpectation instances.
  2937. */
  2938. - (void)waitForSignIn {
  2939. [self waitForSignInWithAccessToken:kAccessToken APIKey:nil completion:nil];
  2940. }
  2941. /** @fn waitForSignInWithAccessToken:
  2942. @brief Signs in a user to prepare for tests.
  2943. @param accessToken The access token for the user to have.
  2944. @param APIKey Optionally, The API key associated with the user.
  2945. @param completion Optionally, The completion invoked at the end of the flow.
  2946. @remarks This method also waits for all other pending @c XCTestExpectation instances.
  2947. */
  2948. - (void)waitForSignInWithAccessToken:(NSString *)accessToken
  2949. APIKey:(nullable NSString *)APIKey
  2950. completion:(nullable FIRAuthResultCallback)completion {
  2951. OCMExpect([_mockBackend verifyPassword:[OCMArg any] callback:[OCMArg any]])
  2952. .andCallBlock2(^(FIRVerifyPasswordRequest *_Nullable request,
  2953. FIRVerifyPasswordResponseCallback callback) {
  2954. dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
  2955. id mockVerifyPasswordResponse = OCMClassMock([FIRVerifyPasswordResponse class]);
  2956. OCMStub([mockVerifyPasswordResponse IDToken]).andReturn(accessToken);
  2957. OCMStub([mockVerifyPasswordResponse approximateExpirationDate])
  2958. .andReturn([NSDate dateWithTimeIntervalSinceNow:kAccessTokenTimeToLive]);
  2959. OCMStub([mockVerifyPasswordResponse refreshToken]).andReturn(kRefreshToken);
  2960. callback(mockVerifyPasswordResponse, nil);
  2961. });
  2962. });
  2963. [self expectGetAccountInfoWithAccessToken:accessToken];
  2964. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  2965. [[FIRAuth auth] signInWithEmail:kEmail
  2966. password:kFakePassword
  2967. completion:^(FIRAuthDataResult *_Nullable result, NSError *_Nullable error) {
  2968. result.user.requestConfiguration =
  2969. [[FIRAuthRequestConfiguration alloc] initWithAPIKey:APIKey
  2970. appID:kFirebaseAppID];
  2971. [expectation fulfill];
  2972. if (completion) {
  2973. completion(result.user, error);
  2974. }
  2975. }];
  2976. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  2977. OCMVerifyAll(_mockBackend);
  2978. XCTAssertNotNil([FIRAuth auth].currentUser);
  2979. }
  2980. /** @fn waitForTimeInterval:
  2981. @brief Wait for a particular time interval.
  2982. @remarks This method also waits for all other pending @c XCTestExpectation instances.
  2983. */
  2984. - (void)waitForTimeIntervel:(NSTimeInterval)timeInterval {
  2985. static dispatch_queue_t queue;
  2986. static dispatch_once_t onceToken;
  2987. XCTestExpectation *expectation = [self expectationWithDescription:@"waitForTimeIntervel:"];
  2988. dispatch_once(&onceToken, ^{
  2989. queue = dispatch_queue_create("com.google.FIRAuthUnitTests.waitForTimeIntervel", NULL);
  2990. });
  2991. dispatch_after(dispatch_time(DISPATCH_TIME_NOW, timeInterval * NSEC_PER_SEC), queue, ^() {
  2992. [expectation fulfill];
  2993. });
  2994. [self waitForExpectationsWithTimeout:timeInterval + kExpectationTimeout handler:nil];
  2995. }
  2996. - (void)waitForAuthGlobalWorkQueueDrain {
  2997. dispatch_semaphore_t workerSemaphore = dispatch_semaphore_create(0);
  2998. dispatch_async(FIRAuthGlobalWorkQueue(), ^{
  2999. dispatch_semaphore_signal(workerSemaphore);
  3000. });
  3001. dispatch_semaphore_wait(workerSemaphore,
  3002. DISPATCH_TIME_FOREVER /*DISPATCH_TIME_NOW + 10 * NSEC_PER_SEC*/);
  3003. }
  3004. /** @fn testRevokeTokenSuccess
  3005. @brief Tests the flow of a successful @c revokeToken:completion.
  3006. */
  3007. - (void)testRevokeTokenSuccess {
  3008. OCMExpect([_mockBackend verifyPassword:[OCMArg any] callback:[OCMArg any]])
  3009. .andCallBlock2(^(FIRVerifyPasswordRequest *_Nullable request,
  3010. FIRVerifyPasswordResponseCallback callback) {
  3011. XCTAssertEqualObjects(request.APIKey, kAPIKey);
  3012. XCTAssertEqualObjects(request.email, kEmail);
  3013. XCTAssertEqualObjects(request.password, kFakePassword);
  3014. XCTAssertTrue(request.returnSecureToken);
  3015. dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
  3016. id mockVerifyPasswordResponse = OCMClassMock([FIRVerifyPasswordResponse class]);
  3017. [self stubTokensWithMockResponse:mockVerifyPasswordResponse];
  3018. callback(mockVerifyPasswordResponse, nil);
  3019. });
  3020. });
  3021. [self expectGetAccountInfo];
  3022. XCTestExpectation *signInExpectation = [self expectationWithDescription:@"signIn"];
  3023. [[FIRAuth auth] signOut:NULL];
  3024. [[FIRAuth auth] signInWithEmail:kEmail
  3025. password:kFakePassword
  3026. completion:^(FIRAuthDataResult *_Nullable result, NSError *_Nullable error) {
  3027. [self assertUser:result.user];
  3028. XCTAssertNil(error);
  3029. [signInExpectation fulfill];
  3030. }];
  3031. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  3032. [self assertUser:[FIRAuth auth].currentUser];
  3033. OCMExpect([_mockBackend revokeToken:[OCMArg any] callback:[OCMArg any]])
  3034. .andCallBlock2(
  3035. ^(FIRRevokeTokenRequest *_Nullable request, FIRRevokeTokenResponseCallback callback) {
  3036. dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
  3037. id mockRevokeTokenResponse = OCMClassMock([FIRRevokeTokenResponse class]);
  3038. callback(mockRevokeTokenResponse, nil);
  3039. });
  3040. });
  3041. XCTestExpectation *revokeExpectation = [self expectationWithDescription:@"callback"];
  3042. NSString *code = @"code";
  3043. [[FIRAuth auth] revokeTokenWithAuthorizationCode:code
  3044. completion:^(NSError *_Nullable error) {
  3045. XCTAssertNil(error);
  3046. [revokeExpectation fulfill];
  3047. }];
  3048. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  3049. }
  3050. /** @fn testRevokeTokenMissingCallback
  3051. @brief Tests the flow of @c revokeToken:completion with a nil callback.
  3052. */
  3053. - (void)testRevokeTokenMissingCallback {
  3054. OCMExpect([_mockBackend verifyPassword:[OCMArg any] callback:[OCMArg any]])
  3055. .andCallBlock2(^(FIRVerifyPasswordRequest *_Nullable request,
  3056. FIRVerifyPasswordResponseCallback callback) {
  3057. XCTAssertEqualObjects(request.APIKey, kAPIKey);
  3058. XCTAssertEqualObjects(request.email, kEmail);
  3059. XCTAssertEqualObjects(request.password, kFakePassword);
  3060. XCTAssertTrue(request.returnSecureToken);
  3061. dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
  3062. id mockVerifyPasswordResponse = OCMClassMock([FIRVerifyPasswordResponse class]);
  3063. [self stubTokensWithMockResponse:mockVerifyPasswordResponse];
  3064. callback(mockVerifyPasswordResponse, nil);
  3065. });
  3066. });
  3067. [self expectGetAccountInfo];
  3068. XCTestExpectation *signInExpectation = [self expectationWithDescription:@"signIn"];
  3069. [[FIRAuth auth] signOut:NULL];
  3070. [[FIRAuth auth] signInWithEmail:kEmail
  3071. password:kFakePassword
  3072. completion:^(FIRAuthDataResult *_Nullable result, NSError *_Nullable error) {
  3073. [self assertUser:result.user];
  3074. XCTAssertNil(error);
  3075. [signInExpectation fulfill];
  3076. }];
  3077. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  3078. [self assertUser:[FIRAuth auth].currentUser];
  3079. XCTestExpectation *revokeExpectation = [self expectationWithDescription:@"revoke"];
  3080. OCMExpect([_mockBackend revokeToken:[OCMArg any] callback:[OCMArg any]])
  3081. .andCallBlock2(
  3082. ^(FIRRevokeTokenRequest *_Nullable request, FIRRevokeTokenResponseCallback callback) {
  3083. dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
  3084. id mockRevokeTokenResponse = OCMClassMock([FIRRevokeTokenResponse class]);
  3085. callback(mockRevokeTokenResponse, nil);
  3086. [revokeExpectation fulfill];
  3087. });
  3088. });
  3089. NSString *code = @"code";
  3090. [[FIRAuth auth] revokeTokenWithAuthorizationCode:code completion:nil];
  3091. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  3092. }
  3093. @end