FIRAuthTests.m 75 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794
  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 <XCTest/XCTest.h>
  18. #import "FirebaseCommunity/FIRAppInternal.h"
  19. #import "FirebaseCommunity/FIREmailAuthProvider.h"
  20. #import "FirebaseCommunity/FIRGoogleAuthProvider.h"
  21. #import "FirebaseCommunity/FIRAdditionalUserInfo.h"
  22. #import "FIRAuth_Internal.h"
  23. #import "FIRAuthOperationType.h"
  24. #import "FIRAuthErrorUtils.h"
  25. #import "FIRAuthDispatcher.h"
  26. #import "FIRAuthGlobalWorkQueue.h"
  27. #import "FIRUser_Internal.h"
  28. #import "FIRAuthBackend.h"
  29. #import "FIRCreateAuthURIRequest.h"
  30. #import "FIRCreateAuthURIResponse.h"
  31. #import "FIRGetAccountInfoRequest.h"
  32. #import "FIRGetAccountInfoResponse.h"
  33. #import "FIRGetOOBConfirmationCodeRequest.h"
  34. #import "FIRGetOOBConfirmationCodeResponse.h"
  35. #import "FIRSecureTokenRequest.h"
  36. #import "FIRSecureTokenResponse.h"
  37. #import "FIRResetPasswordRequest.h"
  38. #import "FIRResetPasswordResponse.h"
  39. #import "FIRSetAccountInfoRequest.h"
  40. #import "FIRSetAccountInfoResponse.h"
  41. #import "FIRSignUpNewUserRequest.h"
  42. #import "FIRSignUpNewUserResponse.h"
  43. #import "FIRVerifyCustomTokenRequest.h"
  44. #import "FIRVerifyCustomTokenResponse.h"
  45. #import "FIRVerifyAssertionRequest.h"
  46. #import "FIRVerifyAssertionResponse.h"
  47. #import "FIRVerifyPasswordRequest.h"
  48. #import "FIRVerifyPasswordResponse.h"
  49. #import "FIRVerifyPhoneNumberRequest.h"
  50. #import "FIRVerifyPhoneNumberResponse.h"
  51. #import "FIRApp+FIRAuthUnitTests.h"
  52. #import "OCMStubRecorder+FIRAuthUnitTests.h"
  53. #import <OCMock/OCMock.h>
  54. #if TARGET_OS_IOS
  55. #import "FIRPhoneAuthCredential.h"
  56. #import "FIRPhoneAuthProvider.h"
  57. #endif
  58. /** @var kFirebaseAppName1
  59. @brief A fake Firebase app name.
  60. */
  61. static NSString *const kFirebaseAppName1 = @"FIREBASE_APP_NAME_1";
  62. /** @var kFirebaseAppName2
  63. @brief Another fake Firebase app name.
  64. */
  65. static NSString *const kFirebaseAppName2 = @"FIREBASE_APP_NAME_2";
  66. /** @var kAPIKey
  67. @brief The fake API key.
  68. */
  69. static NSString *const kAPIKey = @"FAKE_API_KEY";
  70. /** @var kAccessToken
  71. @brief The fake access token.
  72. */
  73. static NSString *const kAccessToken = @"ACCESS_TOKEN";
  74. /** @var kNewAccessToken
  75. @brief Another fake access token used to simulate token refreshed via automatic token refresh.
  76. */
  77. NSString *kNewAccessToken = @"NewAccessToken";
  78. /** @var kAccessTokenValidInterval
  79. @brief The time to live for the fake access token.
  80. */
  81. static const NSTimeInterval kAccessTokenTimeToLive = 60 * 60;
  82. /** @var kTestTokenExpirationTimeInterval
  83. @brief The fake time interval that it takes a token to expire.
  84. */
  85. static const NSTimeInterval kTestTokenExpirationTimeInterval = 55 * 60;
  86. /** @var kRefreshToken
  87. @brief The fake refresh token.
  88. */
  89. static NSString *const kRefreshToken = @"REFRESH_TOKEN";
  90. /** @var kEmail
  91. @brief The fake user email.
  92. */
  93. static NSString *const kEmail = @"user@company.com";
  94. /** @var kFakePassword
  95. @brief The fake user password.
  96. */
  97. static NSString *const kFakePassword = @"!@#$%^";
  98. /** @var kPasswordHash
  99. @brief The fake user password hash.
  100. */
  101. static NSString *const kPasswordHash = @"UkVEQUNURUQ=";
  102. /** @var kLocalID
  103. @brief The fake local user ID.
  104. */
  105. static NSString *const kLocalID = @"LOCAL_ID";
  106. /** @var kDisplayName
  107. @brief The fake user display name.
  108. */
  109. static NSString *const kDisplayName = @"User Doe";
  110. /** @var kGoogleUD
  111. @brief The fake user ID under Google Sign-In.
  112. */
  113. static NSString *const kGoogleID = @"GOOGLE_ID";
  114. /** @var kGoogleEmail
  115. @brief The fake user email under Google Sign-In.
  116. */
  117. static NSString *const kGoogleEmail = @"user@gmail.com";
  118. /** @var kGoogleDisplayName
  119. @brief The fake user display name under Google Sign-In.
  120. */
  121. static NSString *const kGoogleDisplayName = @"Google Doe";
  122. /** @var kGoogleAccessToken
  123. @brief The fake access token from Google Sign-In.
  124. */
  125. static NSString *const kGoogleAccessToken = @"GOOGLE_ACCESS_TOKEN";
  126. /** @var kGoogleIDToken
  127. @brief The fake ID token from Google Sign-In.
  128. */
  129. static NSString *const kGoogleIDToken = @"GOOGLE_ID_TOKEN";
  130. /** @var kCustomToken
  131. @brief The fake custom token to sign in.
  132. */
  133. static NSString *const kCustomToken = @"CUSTOM_TOKEN";
  134. /** @var kVerificationCode
  135. @brief Fake verification code used for testing.
  136. */
  137. static NSString *const kVerificationCode = @"12345678";
  138. /** @var kVerificationID
  139. @brief Fake verification ID for testing.
  140. */
  141. static NSString *const kVerificationID = @"55432";
  142. /** @var kExpectationTimeout
  143. @brief The maximum time waiting for expectations to fulfill.
  144. */
  145. static const NSTimeInterval kExpectationTimeout = 1;
  146. /** @var kWaitInterval
  147. @brief The time waiting for background tasks to finish before continue when necessary.
  148. */
  149. static const NSTimeInterval kWaitInterval = .5;
  150. /** @class FIRAuthTests
  151. @brief Tests for @c FIRAuth.
  152. */
  153. @interface FIRAuthTests : XCTestCase
  154. @end
  155. @implementation FIRAuthTests {
  156. /** @var _mockBackend
  157. @brief The mock @c FIRAuthBackendImplementation .
  158. */
  159. id _mockBackend;
  160. /** @var _FIRAuthDispatcherCallback
  161. @brief Used to save a task from FIRAuthDispatcher to be executed later.
  162. */
  163. __block void (^_Nonnull _FIRAuthDispatcherCallback)(void);
  164. }
  165. /** @fn googleProfile
  166. @brief The fake user profile under additional user data in @c FIRVerifyAssertionResponse.
  167. */
  168. + (NSDictionary *)googleProfile {
  169. static NSDictionary *kGoogleProfile = nil;
  170. static dispatch_once_t onceToken;
  171. dispatch_once(&onceToken, ^{
  172. kGoogleProfile = @{
  173. @"iss": @"https://accounts.google.com\\",
  174. @"email": kGoogleEmail,
  175. @"given_name": @"User",
  176. @"family_name": @"Doe"
  177. };
  178. });
  179. return kGoogleProfile;
  180. }
  181. - (void)setUp {
  182. [super setUp];
  183. _mockBackend = OCMProtocolMock(@protocol(FIRAuthBackendImplementation));
  184. [FIRAuthBackend setBackendImplementation:_mockBackend];
  185. [FIRApp resetAppForAuthUnitTests];
  186. // Set FIRAuthDispatcher implementation in order to save the token refresh task for later
  187. // execution.
  188. [[FIRAuthDispatcher sharedInstance]
  189. setDispatchAfterImplementation:^(NSTimeInterval delay,
  190. dispatch_queue_t _Nonnull queue,
  191. void (^task)(void)) {
  192. XCTAssertNotNil(task);
  193. XCTAssert(delay > 0);
  194. XCTAssertEqualObjects(FIRAuthGlobalWorkQueue(), queue);
  195. _FIRAuthDispatcherCallback = task;
  196. }];
  197. }
  198. - (void)tearDown {
  199. [FIRAuthBackend setDefaultBackendImplementationWithRPCIssuer:nil];
  200. [[FIRAuthDispatcher sharedInstance] setDispatchAfterImplementation:nil];
  201. [super tearDown];
  202. }
  203. #pragma mark - Life Cycle Tests
  204. /** @fn testSingleton
  205. @brief Verifies the @c auth method behaves like a singleton.
  206. */
  207. - (void)testSingleton {
  208. FIRAuth *auth1 = [FIRAuth auth];
  209. XCTAssertNotNil(auth1);
  210. FIRAuth *auth2 = [FIRAuth auth];
  211. XCTAssertEqual(auth1, auth2);
  212. }
  213. /** @fn testDefaultAuth
  214. @brief Verifies the @c auth method associates with the default Firebase app.
  215. */
  216. - (void)testDefaultAuth {
  217. FIRAuth *auth1 = [FIRAuth auth];
  218. FIRAuth *auth2 = [FIRAuth authWithApp:[FIRApp defaultApp]];
  219. XCTAssertEqual(auth1, auth2);
  220. XCTAssertEqual(auth1.app, [FIRApp defaultApp]);
  221. }
  222. /** @fn testNilAppException
  223. @brief Verifies the @c auth method raises an exception if the default FIRApp is not configured.
  224. */
  225. - (void)testNilAppException {
  226. [FIRApp resetApps];
  227. XCTAssertThrows([FIRAuth auth]);
  228. }
  229. /** @fn testAppAPIkey
  230. @brief Verifies the API key is correctly copied from @c FIRApp to @c FIRAuth .
  231. */
  232. - (void)testAppAPIkey {
  233. FIRAuth *auth = [FIRAuth auth];
  234. XCTAssertEqualObjects(auth.requestConfiguration.APIKey, kAPIKey);
  235. }
  236. /** @fn testAppAssociation
  237. @brief Verifies each @c FIRApp instance associates with a @c FIRAuth .
  238. */
  239. - (void)testAppAssociation {
  240. FIRApp *app1 = [self app1];
  241. FIRAuth *auth1 = [FIRAuth authWithApp:app1];
  242. XCTAssertNotNil(auth1);
  243. XCTAssertEqual(auth1.app, app1);
  244. FIRApp *app2 = [self app2];
  245. FIRAuth *auth2 = [FIRAuth authWithApp:app2];
  246. XCTAssertNotNil(auth2);
  247. XCTAssertEqual(auth2.app, app2);
  248. XCTAssertNotEqual(auth1, auth2);
  249. }
  250. /** @fn testLifeCycle
  251. @brief Verifies the life cycle of @c FIRAuth is the same as its associated @c FIRApp .
  252. */
  253. - (void)testLifeCycle {
  254. __weak FIRApp *app;
  255. __weak FIRAuth *auth;
  256. @autoreleasepool {
  257. FIRApp *app1 = [self app1];
  258. app = app1;
  259. auth = [FIRAuth authWithApp:app1];
  260. // Verify that neither the app nor the auth is released yet, i.e., the app owns the auth
  261. // because nothing else retains the auth.
  262. XCTAssertNotNil(app);
  263. XCTAssertNotNil(auth);
  264. }
  265. [self waitForTimeIntervel:kWaitInterval];
  266. // Verify that both the app and the auth are released upon exit of the autorelease pool,
  267. // i.e., the app is the sole owner of the auth.
  268. XCTAssertNil(app);
  269. XCTAssertNil(auth);
  270. }
  271. /** @fn testGetUID
  272. @brief Verifies that FIRApp's getUIDImplementation is correctly set by FIRAuth.
  273. */
  274. - (void)testGetUID {
  275. FIRApp *app = [FIRApp defaultApp];
  276. XCTAssertNotNil(app.getUIDImplementation);
  277. [[FIRAuth auth] signOut:NULL];
  278. XCTAssertNil(app.getUIDImplementation());
  279. [self waitForSignIn];
  280. XCTAssertEqualObjects(app.getUIDImplementation(), kLocalID);
  281. }
  282. #pragma mark - Server API Tests
  283. /** @fn testFetchProvidersForEmailSuccess
  284. @brief Tests the flow of a successful @c fetchProvidersForEmail:completion: call.
  285. */
  286. - (void)testFetchProvidersForEmailSuccess {
  287. NSArray<NSString *> *allProviders =
  288. @[ FIRGoogleAuthProviderID, FIREmailAuthProviderID ];
  289. OCMExpect([_mockBackend createAuthURI:[OCMArg any]
  290. callback:[OCMArg any]])
  291. .andCallBlock2(^(FIRCreateAuthURIRequest *_Nullable request,
  292. FIRCreateAuthURIResponseCallback callback) {
  293. XCTAssertEqualObjects(request.identifier, kEmail);
  294. XCTAssertNotNil(request.endpoint);
  295. XCTAssertEqualObjects(request.APIKey, kAPIKey);
  296. dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
  297. id mockCreateAuthURIResponse = OCMClassMock([FIRCreateAuthURIResponse class]);
  298. OCMStub([mockCreateAuthURIResponse allProviders]).andReturn(allProviders);
  299. callback(mockCreateAuthURIResponse, nil);
  300. });
  301. });
  302. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  303. [[FIRAuth auth] fetchProvidersForEmail:kEmail
  304. completion:^(NSArray<NSString *> *_Nullable providers,
  305. NSError *_Nullable error) {
  306. XCTAssertTrue([NSThread isMainThread]);
  307. XCTAssertEqualObjects(providers, allProviders);
  308. XCTAssertNil(error);
  309. [expectation fulfill];
  310. }];
  311. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  312. OCMVerifyAll(_mockBackend);
  313. }
  314. /** @fn testFetchProvidersForEmailSuccessDeprecatedProviderID
  315. @brief Tests the flow of a successful @c fetchProvidersForEmail:completion: call using the
  316. deprecated FIREmailPasswordAuthProviderID.
  317. */
  318. - (void)testFetchProvidersForEmailSuccessDeprecatedProviderID {
  319. #pragma clang diagnostic push
  320. #pragma clang diagnostic ignored "-Wdeprecated-declarations"
  321. NSArray<NSString *> *allProviders =
  322. @[ FIRGoogleAuthProviderID, FIREmailPasswordAuthProviderID ];
  323. #pragma clang diagnostic pop
  324. OCMExpect([_mockBackend createAuthURI:[OCMArg any]
  325. callback:[OCMArg any]])
  326. .andCallBlock2(^(FIRCreateAuthURIRequest *_Nullable request,
  327. FIRCreateAuthURIResponseCallback callback) {
  328. XCTAssertEqualObjects(request.identifier, kEmail);
  329. XCTAssertNotNil(request.endpoint);
  330. XCTAssertEqualObjects(request.APIKey, kAPIKey);
  331. dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
  332. id mockCreateAuthURIResponse = OCMClassMock([FIRCreateAuthURIResponse class]);
  333. OCMStub([mockCreateAuthURIResponse allProviders]).andReturn(allProviders);
  334. callback(mockCreateAuthURIResponse, nil);
  335. });
  336. });
  337. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  338. [[FIRAuth auth] fetchProvidersForEmail:kEmail
  339. completion:^(NSArray<NSString *> *_Nullable providers,
  340. NSError *_Nullable error) {
  341. XCTAssertTrue([NSThread isMainThread]);
  342. XCTAssertEqualObjects(providers, allProviders);
  343. XCTAssertNil(error);
  344. [expectation fulfill];
  345. }];
  346. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  347. OCMVerifyAll(_mockBackend);
  348. }
  349. /** @fn testFetchProvidersForEmailFailure
  350. @brief Tests the flow of a failed @c fetchProvidersForEmail:completion: call.
  351. */
  352. - (void)testFetchProvidersForEmailFailure {
  353. OCMExpect([_mockBackend createAuthURI:[OCMArg any] callback:[OCMArg any]])
  354. .andDispatchError2([FIRAuthErrorUtils tooManyRequestsErrorWithMessage:nil]);
  355. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  356. [[FIRAuth auth] fetchProvidersForEmail:kEmail
  357. completion:^(NSArray<NSString *> *_Nullable providers,
  358. NSError *_Nullable error) {
  359. XCTAssertTrue([NSThread isMainThread]);
  360. XCTAssertNil(providers);
  361. XCTAssertEqual(error.code, FIRAuthErrorCodeTooManyRequests);
  362. XCTAssertNotNil(error.userInfo[NSLocalizedDescriptionKey]);
  363. [expectation fulfill];
  364. }];
  365. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  366. OCMVerifyAll(_mockBackend);
  367. }
  368. #if TARGET_OS_IOS
  369. /** @fn testPhoneAuthSuccess
  370. @brief Tests the flow of a successful @c signInWithCredential:completion for phone auth.
  371. */
  372. - (void)testPhoneAuthSuccess {
  373. OCMExpect([_mockBackend verifyPhoneNumber:[OCMArg any] callback:[OCMArg any]])
  374. .andCallBlock2(^(FIRVerifyPhoneNumberRequest *_Nullable request,
  375. FIRVerifyPhoneNumberResponseCallback callback) {
  376. XCTAssertEqualObjects(request.verificationCode, kVerificationCode);
  377. XCTAssertEqualObjects(request.verificationID, kVerificationID);
  378. XCTAssertEqual(request.operation, FIRAuthOperationTypeSignUpOrSignIn);
  379. dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
  380. id mockVerifyPhoneResponse = OCMClassMock([FIRVerifyPhoneNumberResponse class]);
  381. [self stubTokensWithMockResponse:mockVerifyPhoneResponse];
  382. callback(mockVerifyPhoneResponse, nil);
  383. });
  384. });
  385. [self expectGetAccountInfo];
  386. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  387. [[FIRAuth auth] signOut:NULL];
  388. FIRAuthCredential *credential =
  389. [[FIRPhoneAuthProvider provider] credentialWithVerificationID:kVerificationID
  390. verificationCode:kVerificationCode];
  391. [[FIRAuth auth] signInWithCredential:credential completion:^(FIRUser *_Nullable user,
  392. NSError *_Nullable error) {
  393. XCTAssertTrue([NSThread isMainThread]);
  394. [self assertUser:user];
  395. XCTAssertNil(error);
  396. [expectation fulfill];
  397. }];
  398. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  399. [self assertUser:[FIRAuth auth].currentUser];
  400. OCMVerifyAll(_mockBackend);
  401. }
  402. /** @fn testPhoneAuthMissingVerificationCode
  403. @brief Tests the flow of an unsuccessful @c signInWithCredential:completion for phone auth due
  404. to an empty verification code
  405. */
  406. - (void)testPhoneAuthMissingVerificationCode {
  407. [self expectGetAccountInfo];
  408. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  409. [[FIRAuth auth] signOut:NULL];
  410. FIRAuthCredential *credential =
  411. [[FIRPhoneAuthProvider provider] credentialWithVerificationID:kVerificationID
  412. verificationCode:@""];
  413. [[FIRAuth auth] signInWithCredential:credential completion:^(FIRUser *_Nullable user,
  414. NSError *_Nullable error) {
  415. XCTAssertTrue([NSThread isMainThread]);
  416. XCTAssertNil(user);
  417. XCTAssertEqual(error.code, FIRAuthErrorCodeMissingVerificationCode);
  418. [expectation fulfill];
  419. }];
  420. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  421. }
  422. /** @fn testPhoneAuthMissingVerificationID
  423. @brief Tests the flow of an unsuccessful @c signInWithCredential:completion for phone auth due
  424. to an empty verification ID.
  425. */
  426. - (void)testPhoneAuthMissingVerificationID {
  427. [self expectGetAccountInfo];
  428. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  429. [[FIRAuth auth] signOut:NULL];
  430. FIRAuthCredential *credential =
  431. [[FIRPhoneAuthProvider provider] credentialWithVerificationID:@""
  432. verificationCode:kVerificationCode];
  433. [[FIRAuth auth] signInWithCredential:credential completion:^(FIRUser *_Nullable user,
  434. NSError *_Nullable error) {
  435. XCTAssertTrue([NSThread isMainThread]);
  436. XCTAssertNil(user);
  437. XCTAssertEqual(error.code, FIRAuthErrorCodeMissingVerificationID);
  438. [expectation fulfill];
  439. }];
  440. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  441. }
  442. #endif
  443. /** @fn testSignInWithEmailPasswordSuccess
  444. @brief Tests the flow of a successful @c signInWithEmail:password:completion: call.
  445. */
  446. - (void)testSignInWithEmailPasswordSuccess {
  447. OCMExpect([_mockBackend verifyPassword:[OCMArg any] callback:[OCMArg any]])
  448. .andCallBlock2(^(FIRVerifyPasswordRequest *_Nullable request,
  449. FIRVerifyPasswordResponseCallback callback) {
  450. XCTAssertEqualObjects(request.APIKey, kAPIKey);
  451. XCTAssertEqualObjects(request.email, kEmail);
  452. XCTAssertEqualObjects(request.password, kFakePassword);
  453. XCTAssertTrue(request.returnSecureToken);
  454. dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
  455. id mockVerifyPasswordResponse = OCMClassMock([FIRVerifyPasswordResponse class]);
  456. [self stubTokensWithMockResponse:mockVerifyPasswordResponse];
  457. callback(mockVerifyPasswordResponse, nil);
  458. });
  459. });
  460. [self expectGetAccountInfo];
  461. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  462. [[FIRAuth auth] signOut:NULL];
  463. [[FIRAuth auth] signInWithEmail:kEmail password:kFakePassword completion:^(FIRUser *_Nullable user,
  464. NSError *_Nullable error) {
  465. XCTAssertTrue([NSThread isMainThread]);
  466. [self assertUser:user];
  467. XCTAssertNil(error);
  468. [expectation fulfill];
  469. }];
  470. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  471. [self assertUser:[FIRAuth auth].currentUser];
  472. OCMVerifyAll(_mockBackend);
  473. }
  474. /** @fn testSignInWithEmailPasswordFailure
  475. @brief Tests the flow of a failed @c signInWithEmail:password:completion: call.
  476. */
  477. - (void)testSignInWithEmailPasswordFailure {
  478. OCMExpect([_mockBackend verifyPassword:[OCMArg any] callback:[OCMArg any]])
  479. .andDispatchError2([FIRAuthErrorUtils wrongPasswordErrorWithMessage:nil]);
  480. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  481. [[FIRAuth auth] signOut:NULL];
  482. [[FIRAuth auth] signInWithEmail:kEmail password:kFakePassword completion:^(FIRUser *_Nullable user,
  483. NSError *_Nullable error) {
  484. XCTAssertTrue([NSThread isMainThread]);
  485. XCTAssertNil(user);
  486. XCTAssertEqual(error.code, FIRAuthErrorCodeWrongPassword);
  487. XCTAssertNotNil(error.userInfo[NSLocalizedDescriptionKey]);
  488. [expectation fulfill];
  489. }];
  490. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  491. XCTAssertNil([FIRAuth auth].currentUser);
  492. OCMVerifyAll(_mockBackend);
  493. }
  494. /** @fn testResetPasswordSuccess
  495. @brief Tests the flow of a successful @c confirmPasswordResetWithCode:newPassword:completion:
  496. call.
  497. */
  498. - (void)testResetPasswordSuccess {
  499. NSString *fakeEmail = @"fakeEmail";
  500. NSString *fakeCode = @"fakeCode";
  501. NSString *fakeNewPassword = @"fakeNewPassword";
  502. OCMExpect([_mockBackend resetPassword:[OCMArg any] callback:[OCMArg any]])
  503. .andCallBlock2(^(FIRResetPasswordRequest *_Nullable request,
  504. FIRResetPasswordCallback callback) {
  505. XCTAssertEqualObjects(request.APIKey, kAPIKey);
  506. XCTAssertEqualObjects(request.oobCode, fakeCode);
  507. XCTAssertEqualObjects(request.updatedPassword, fakeNewPassword);
  508. dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
  509. id mockResetPasswordResponse = OCMClassMock([FIRResetPasswordResponse class]);
  510. OCMStub([mockResetPasswordResponse email]).andReturn(fakeEmail);
  511. callback(mockResetPasswordResponse, nil);
  512. });
  513. });
  514. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  515. [[FIRAuth auth] signOut:NULL];
  516. [[FIRAuth auth] confirmPasswordResetWithCode:fakeCode
  517. newPassword:fakeNewPassword
  518. completion:^(NSError *_Nullable error) {
  519. XCTAssertTrue([NSThread isMainThread]);
  520. XCTAssertNil(error);
  521. [expectation fulfill];
  522. }];
  523. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  524. OCMVerifyAll(_mockBackend);
  525. }
  526. /** @fn testResetPasswordFailure
  527. @brief Tests the flow of a failed @c confirmPasswordResetWithCode:newPassword:completion:
  528. call.
  529. */
  530. - (void)testResetPasswordFailure {
  531. NSString *fakeCode = @"fakeCode";
  532. NSString *fakeNewPassword = @"fakeNewPassword";
  533. OCMExpect([_mockBackend resetPassword:[OCMArg any] callback:[OCMArg any]])
  534. ._andDispatchError2([FIRAuthErrorUtils invalidActionCodeErrorWithMessage:nil]);
  535. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  536. [[FIRAuth auth] signOut:NULL];
  537. [[FIRAuth auth] confirmPasswordResetWithCode:fakeCode
  538. newPassword:fakeNewPassword
  539. completion:^(NSError *_Nullable error) {
  540. XCTAssertTrue([NSThread isMainThread]);
  541. XCTAssertEqual(error.code, FIRAuthErrorCodeInvalidActionCode);
  542. [expectation fulfill];
  543. }];
  544. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  545. OCMVerifyAll(_mockBackend);
  546. }
  547. /** @fn testCheckActionCodeSuccess
  548. @brief Tests the flow of a successful @c checkActionCode:completion call.
  549. */
  550. - (void)testCheckActionCodeSuccess {
  551. NSString *verifyEmailRequestType = @"VERIFY_EMAIL";
  552. NSString *fakeEmail = @"fakeEmail";
  553. NSString *fakeNewEmail = @"fakeNewEmail";
  554. NSString *fakeCode = @"fakeCode";
  555. OCMExpect([_mockBackend resetPassword:[OCMArg any] callback:[OCMArg any]])
  556. .andCallBlock2(^(FIRResetPasswordRequest *_Nullable request,
  557. FIRResetPasswordCallback callback) {
  558. XCTAssertEqualObjects(request.APIKey, kAPIKey);
  559. XCTAssertEqualObjects(request.oobCode, fakeCode);
  560. dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
  561. id mockResetPasswordResponse = OCMClassMock([FIRResetPasswordResponse class]);
  562. OCMStub([mockResetPasswordResponse email]).andReturn(fakeEmail);
  563. OCMStub([mockResetPasswordResponse verifiedEmail]).andReturn(fakeNewEmail);
  564. OCMStubRecorder *stub =
  565. OCMStub([(FIRResetPasswordResponse *) mockResetPasswordResponse requestType]);
  566. stub.andReturn(verifyEmailRequestType);
  567. callback(mockResetPasswordResponse, nil);
  568. });
  569. });
  570. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  571. [[FIRAuth auth] checkActionCode:fakeCode completion:^(FIRActionCodeInfo *_Nullable info,
  572. NSError *_Nullable error) {
  573. XCTAssertTrue([NSThread isMainThread]);
  574. XCTAssertNil(error);
  575. XCTAssertEqual(info.operation, FIRActionCodeOperationVerifyEmail);
  576. XCTAssert([fakeNewEmail isEqualToString:[info dataForKey:FIRActionCodeEmailKey]]);
  577. [expectation fulfill];
  578. }];
  579. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  580. OCMVerifyAll(_mockBackend);
  581. }
  582. /** @fn testCheckActionCodeFailure
  583. @brief Tests the flow of a failed @c checkActionCode:completion call.
  584. */
  585. - (void)testCheckActionCodeFailure {
  586. NSString *fakeCode = @"fakeCode";
  587. OCMExpect([_mockBackend resetPassword:[OCMArg any] callback:[OCMArg any]])
  588. ._andDispatchError2([FIRAuthErrorUtils expiredActionCodeErrorWithMessage:nil]);
  589. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  590. [[FIRAuth auth] signOut:NULL];
  591. [[FIRAuth auth] checkActionCode:fakeCode completion:^(FIRActionCodeInfo *_Nullable info,
  592. NSError *_Nullable error) {
  593. XCTAssertTrue([NSThread isMainThread]);
  594. XCTAssertNotNil(error);
  595. XCTAssertEqual(error.code, FIRAuthErrorCodeExpiredActionCode);
  596. [expectation fulfill];
  597. }];
  598. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  599. OCMVerifyAll(_mockBackend);
  600. }
  601. /** @fn testApplyActionCodeSuccess
  602. @brief Tests the flow of a successful @c applyActionCode:completion call.
  603. */
  604. - (void)testApplyActionCodeSuccess {
  605. NSString *fakeCode = @"fakeCode";
  606. OCMExpect([_mockBackend setAccountInfo:[OCMArg any] callback:[OCMArg any]])
  607. .andCallBlock2(^(FIRSetAccountInfoRequest *_Nullable request,
  608. FIRSetAccountInfoResponseCallback callback) {
  609. XCTAssertEqualObjects(request.APIKey, kAPIKey);
  610. XCTAssertEqualObjects(request.OOBCode, fakeCode);
  611. dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
  612. id mockSetAccountInfoResponse = OCMClassMock([FIRSetAccountInfoResponse class]);
  613. callback(mockSetAccountInfoResponse, nil);
  614. });
  615. });
  616. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  617. [[FIRAuth auth] applyActionCode:fakeCode completion:^(NSError *_Nullable error) {
  618. XCTAssertTrue([NSThread isMainThread]);
  619. XCTAssertNil(error);
  620. [expectation fulfill];
  621. }];
  622. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  623. OCMVerifyAll(_mockBackend);
  624. }
  625. /** @fn testApplyActionCodeFailure
  626. @brief Tests the flow of a failed @c checkActionCode:completion call.
  627. */
  628. - (void)testApplyActionCodeFailure {
  629. NSString *fakeCode = @"fakeCode";
  630. OCMExpect([_mockBackend setAccountInfo:[OCMArg any] callback:[OCMArg any]])
  631. ._andDispatchError2([FIRAuthErrorUtils invalidActionCodeErrorWithMessage:nil]);
  632. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  633. [[FIRAuth auth] signOut:NULL];
  634. [[FIRAuth auth] applyActionCode:fakeCode completion:^(NSError *_Nullable error) {
  635. XCTAssertTrue([NSThread isMainThread]);
  636. XCTAssertNotNil(error);
  637. XCTAssertEqual(error.code, FIRAuthErrorCodeInvalidActionCode);
  638. [expectation fulfill];
  639. }];
  640. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  641. OCMVerifyAll(_mockBackend);
  642. }
  643. /** @fn testVerifyPasswordResetCodeSuccess
  644. @brief Tests the flow of a successful @c verifyPasswordResetCode:completion call.
  645. */
  646. - (void)testVerifyPasswordResetCodeSuccess {
  647. NSString *passwordResetRequestType = @"PASSWORD_RESET";
  648. NSString *fakeEmail = @"fakeEmail";
  649. NSString *fakeCode = @"fakeCode";
  650. OCMExpect([_mockBackend resetPassword:[OCMArg any] callback:[OCMArg any]])
  651. .andCallBlock2(^(FIRResetPasswordRequest *_Nullable request,
  652. FIRResetPasswordCallback callback) {
  653. XCTAssertEqualObjects(request.APIKey, kAPIKey);
  654. XCTAssertEqualObjects(request.oobCode, fakeCode);
  655. dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
  656. id mockResetPasswordResponse = OCMClassMock([FIRResetPasswordResponse class]);
  657. OCMStub([mockResetPasswordResponse email]).andReturn(fakeEmail);
  658. OCMStubRecorder *stub =
  659. OCMStub([(FIRResetPasswordResponse *) mockResetPasswordResponse requestType]);
  660. stub.andReturn(passwordResetRequestType);
  661. callback(mockResetPasswordResponse, nil);
  662. });
  663. });
  664. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  665. [[FIRAuth auth] verifyPasswordResetCode:fakeCode completion:^(NSString *_Nullable email,
  666. NSError *_Nullable error) {
  667. XCTAssertTrue([NSThread isMainThread]);
  668. XCTAssertNil(error);
  669. XCTAssertEqual(email, fakeEmail);
  670. [expectation fulfill];
  671. }];
  672. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  673. OCMVerifyAll(_mockBackend);
  674. }
  675. /** @fn testVerifyPasswordResetCodeFailure
  676. @brief Tests the flow of a failed @c verifyPasswordResetCode:completion call.
  677. */
  678. - (void)testVeridyPasswordResetCodeFailure {
  679. NSString *fakeCode = @"fakeCode";
  680. OCMExpect([_mockBackend resetPassword:[OCMArg any] callback:[OCMArg any]])
  681. ._andDispatchError2([FIRAuthErrorUtils invalidActionCodeErrorWithMessage:nil]);
  682. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  683. [[FIRAuth auth] signOut:NULL];
  684. [[FIRAuth auth] verifyPasswordResetCode:fakeCode completion:^(NSString *_Nullable email,
  685. NSError *_Nullable error) {
  686. XCTAssertTrue([NSThread isMainThread]);
  687. XCTAssertNotNil(error);
  688. XCTAssertEqual(error.code, FIRAuthErrorCodeInvalidActionCode);
  689. [expectation fulfill];
  690. }];
  691. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  692. OCMVerifyAll(_mockBackend);
  693. }
  694. /** @fn testSignInWithEmailCredentialSuccess
  695. @brief Tests the flow of a successfully @c signInWithCredential:completion: call with an
  696. email-password credential.
  697. */
  698. - (void)testSignInWithEmailCredentialSuccess {
  699. OCMExpect([_mockBackend verifyPassword:[OCMArg any] callback:[OCMArg any]])
  700. .andCallBlock2(^(FIRVerifyPasswordRequest *_Nullable request,
  701. FIRVerifyPasswordResponseCallback callback) {
  702. XCTAssertEqualObjects(request.APIKey, kAPIKey);
  703. XCTAssertEqualObjects(request.email, kEmail);
  704. XCTAssertEqualObjects(request.password, kFakePassword);
  705. XCTAssertTrue(request.returnSecureToken);
  706. dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
  707. id mockVeriyPasswordResponse = OCMClassMock([FIRVerifyPasswordResponse class]);
  708. [self stubTokensWithMockResponse:mockVeriyPasswordResponse];
  709. callback(mockVeriyPasswordResponse, nil);
  710. });
  711. });
  712. [self expectGetAccountInfo];
  713. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  714. [[FIRAuth auth] signOut:NULL];
  715. FIRAuthCredential *emailCredential =
  716. [FIREmailAuthProvider credentialWithEmail:kEmail password:kFakePassword];
  717. [[FIRAuth auth] signInWithCredential:emailCredential completion:^(FIRUser *_Nullable user,
  718. NSError *_Nullable error) {
  719. XCTAssertTrue([NSThread isMainThread]);
  720. [self assertUser:user];
  721. XCTAssertNil(error);
  722. [expectation fulfill];
  723. }];
  724. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  725. [self assertUser:[FIRAuth auth].currentUser];
  726. OCMVerifyAll(_mockBackend);
  727. }
  728. /** @fn testSignInWithEmailCredentialSuccess
  729. @brief Tests the flow of a successfully @c signInWithCredential:completion: call with an
  730. email-password credential using the deprecated FIREmailPasswordAuthProvider.
  731. */
  732. - (void)testSignInWithEmailCredentialSuccessWithDepricatedProvider {
  733. OCMExpect([_mockBackend verifyPassword:[OCMArg any] callback:[OCMArg any]])
  734. .andCallBlock2(^(FIRVerifyPasswordRequest *_Nullable request,
  735. FIRVerifyPasswordResponseCallback callback) {
  736. XCTAssertEqualObjects(request.APIKey, kAPIKey);
  737. XCTAssertEqualObjects(request.email, kEmail);
  738. XCTAssertEqualObjects(request.password, kFakePassword);
  739. XCTAssertTrue(request.returnSecureToken);
  740. dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
  741. id mockVeriyPasswordResponse = OCMClassMock([FIRVerifyPasswordResponse class]);
  742. [self stubTokensWithMockResponse:mockVeriyPasswordResponse];
  743. callback(mockVeriyPasswordResponse, nil);
  744. });
  745. });
  746. [self expectGetAccountInfo];
  747. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  748. [[FIRAuth auth] signOut:NULL];
  749. #pragma clang diagnostic push
  750. #pragma clang diagnostic ignored "-Wdeprecated-declarations"
  751. FIRAuthCredential *emailCredential =
  752. [FIREmailPasswordAuthProvider credentialWithEmail:kEmail password:kFakePassword];
  753. #pragma clang diagnostic pop
  754. [[FIRAuth auth] signInWithCredential:emailCredential completion:^(FIRUser *_Nullable user,
  755. NSError *_Nullable error) {
  756. XCTAssertTrue([NSThread isMainThread]);
  757. [self assertUser:user];
  758. XCTAssertNil(error);
  759. [expectation fulfill];
  760. }];
  761. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  762. [self assertUser:[FIRAuth auth].currentUser];
  763. OCMVerifyAll(_mockBackend);
  764. }
  765. /** @fn testSignInWithEmailCredentialFailure
  766. @brief Tests the flow of a failed @c signInWithCredential:completion: call with an
  767. email-password credential.
  768. */
  769. - (void)testSignInWithEmailCredentialFailure {
  770. OCMExpect([_mockBackend verifyPassword:[OCMArg any] callback:[OCMArg any]])
  771. .andDispatchError2([FIRAuthErrorUtils userDisabledErrorWithMessage:nil]);
  772. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  773. [[FIRAuth auth] signOut:NULL];
  774. FIRAuthCredential *emailCredential =
  775. [FIREmailAuthProvider credentialWithEmail:kEmail password:kFakePassword];
  776. [[FIRAuth auth] signInWithCredential:emailCredential completion:^(FIRUser *_Nullable user,
  777. NSError *_Nullable error) {
  778. XCTAssertTrue([NSThread isMainThread]);
  779. XCTAssertNil(user);
  780. XCTAssertEqual(error.code, FIRAuthErrorCodeUserDisabled);
  781. XCTAssertNotNil(error.userInfo[NSLocalizedDescriptionKey]);
  782. [expectation fulfill];
  783. }];
  784. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  785. XCTAssertNil([FIRAuth auth].currentUser);
  786. OCMVerifyAll(_mockBackend);
  787. }
  788. /** @fn testSignInWithEmailCredentialEmptyPassword
  789. @brief Tests the flow of a failed @c signInWithCredential:completion: call with an
  790. email-password credential using an empty password. This error occurs on the client side,
  791. so there is no need to fake an RPC response.
  792. */
  793. - (void)testSignInWithEmailCredentialEmptyPassword {
  794. NSString *emptyString = @"";
  795. [self expectGetAccountInfo];
  796. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  797. [[FIRAuth auth] signOut:NULL];
  798. FIRAuthCredential *emailCredential =
  799. [FIREmailAuthProvider credentialWithEmail:kEmail password:emptyString];
  800. [[FIRAuth auth] signInWithCredential:emailCredential completion:^(FIRUser *_Nullable user,
  801. NSError *_Nullable error) {
  802. XCTAssertTrue([NSThread isMainThread]);
  803. XCTAssertEqual(error.code, FIRAuthErrorCodeWrongPassword);
  804. [expectation fulfill];
  805. }];
  806. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  807. }
  808. /** @fn testSignInWithGoogleAccountExistsError
  809. @brief Tests the flow of a failed @c signInWithCredential:completion: with a Google credential
  810. where the backend returns a needs @needConfirmation equal to true. An
  811. FIRAuthErrorCodeAccountExistsWithDifferentCredential error should be thrown.
  812. */
  813. - (void)testSignInWithGoogleAccountExistsError {
  814. OCMExpect([_mockBackend verifyAssertion:[OCMArg any] callback:[OCMArg any]])
  815. .andCallBlock2(^(FIRVerifyAssertionRequest *_Nullable request,
  816. FIRVerifyAssertionResponseCallback callback) {
  817. XCTAssertEqualObjects(request.APIKey, kAPIKey);
  818. XCTAssertEqualObjects(request.providerID, FIRGoogleAuthProviderID);
  819. XCTAssertEqualObjects(request.providerIDToken, kGoogleIDToken);
  820. XCTAssertEqualObjects(request.providerAccessToken, kGoogleAccessToken);
  821. XCTAssertTrue(request.returnSecureToken);
  822. dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
  823. id mockVeriyAssertionResponse = OCMClassMock([FIRVerifyAssertionResponse class]);
  824. OCMStub([mockVeriyAssertionResponse needConfirmation]).andReturn(YES);
  825. OCMStub([mockVeriyAssertionResponse email]).andReturn(kEmail);
  826. [self stubTokensWithMockResponse:mockVeriyAssertionResponse];
  827. callback(mockVeriyAssertionResponse, nil);
  828. });
  829. });
  830. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  831. [[FIRAuth auth] signOut:NULL];
  832. FIRAuthCredential *googleCredential =
  833. [FIRGoogleAuthProvider credentialWithIDToken:kGoogleIDToken accessToken:kGoogleAccessToken];
  834. [[FIRAuth auth] signInWithCredential:googleCredential completion:^(FIRUser *_Nullable user,
  835. NSError *_Nullable error) {
  836. XCTAssertTrue([NSThread isMainThread]);
  837. XCTAssertEqual(error.code, FIRAuthErrorCodeAccountExistsWithDifferentCredential);
  838. XCTAssertEqualObjects(error.userInfo[FIRAuthErrorUserInfoEmailKey], kEmail);
  839. [expectation fulfill];
  840. }];
  841. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  842. OCMVerifyAll(_mockBackend);
  843. }
  844. /** @fn testSignInWithGoogleCredentialSuccess
  845. @brief Tests the flow of a successful @c signInWithCredential:completion: call with an
  846. Google Sign-In credential.
  847. */
  848. - (void)testSignInWithGoogleCredentialSuccess {
  849. OCMExpect([_mockBackend verifyAssertion:[OCMArg any] callback:[OCMArg any]])
  850. .andCallBlock2(^(FIRVerifyAssertionRequest *_Nullable request,
  851. FIRVerifyAssertionResponseCallback callback) {
  852. XCTAssertEqualObjects(request.APIKey, kAPIKey);
  853. XCTAssertEqualObjects(request.providerID, FIRGoogleAuthProviderID);
  854. XCTAssertEqualObjects(request.providerIDToken, kGoogleIDToken);
  855. XCTAssertEqualObjects(request.providerAccessToken, kGoogleAccessToken);
  856. XCTAssertTrue(request.returnSecureToken);
  857. dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
  858. id mockVeriyAssertionResponse = OCMClassMock([FIRVerifyAssertionResponse class]);
  859. OCMStub([mockVeriyAssertionResponse federatedID]).andReturn(kGoogleID);
  860. OCMStub([mockVeriyAssertionResponse providerID]).andReturn(FIRGoogleAuthProviderID);
  861. OCMStub([mockVeriyAssertionResponse localID]).andReturn(kLocalID);
  862. OCMStub([mockVeriyAssertionResponse displayName]).andReturn(kGoogleDisplayName);
  863. [self stubTokensWithMockResponse:mockVeriyAssertionResponse];
  864. callback(mockVeriyAssertionResponse, nil);
  865. });
  866. });
  867. [self expectGetAccountInfoGoogle];
  868. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  869. [[FIRAuth auth] signOut:NULL];
  870. FIRAuthCredential *googleCredential =
  871. [FIRGoogleAuthProvider credentialWithIDToken:kGoogleIDToken accessToken:kGoogleAccessToken];
  872. [[FIRAuth auth] signInWithCredential:googleCredential completion:^(FIRUser *_Nullable user,
  873. NSError *_Nullable error) {
  874. XCTAssertTrue([NSThread isMainThread]);
  875. [self assertUserGoogle:user];
  876. XCTAssertNil(error);
  877. [expectation fulfill];
  878. }];
  879. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  880. [self assertUserGoogle:[FIRAuth auth].currentUser];
  881. OCMVerifyAll(_mockBackend);
  882. }
  883. /** @fn testSignInAndRetrieveDataWithCredentialSuccess
  884. @brief Tests the flow of a successful @c signInAndRetrieveDataWithCredential:completion: call
  885. with an Google Sign-In credential.
  886. */
  887. - (void)testSignInAndRetrieveDataWithCredentialSuccess {
  888. OCMExpect([_mockBackend verifyAssertion:[OCMArg any] callback:[OCMArg any]])
  889. .andCallBlock2(^(FIRVerifyAssertionRequest *_Nullable request,
  890. FIRVerifyAssertionResponseCallback callback) {
  891. XCTAssertEqualObjects(request.APIKey, kAPIKey);
  892. XCTAssertEqualObjects(request.providerID, FIRGoogleAuthProviderID);
  893. XCTAssertEqualObjects(request.providerIDToken, kGoogleIDToken);
  894. XCTAssertEqualObjects(request.providerAccessToken, kGoogleAccessToken);
  895. XCTAssertTrue(request.returnSecureToken);
  896. dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
  897. id mockVeriyAssertionResponse = OCMClassMock([FIRVerifyAssertionResponse class]);
  898. OCMStub([mockVeriyAssertionResponse federatedID]).andReturn(kGoogleID);
  899. OCMStub([mockVeriyAssertionResponse providerID]).andReturn(FIRGoogleAuthProviderID);
  900. OCMStub([mockVeriyAssertionResponse localID]).andReturn(kLocalID);
  901. OCMStub([mockVeriyAssertionResponse displayName]).andReturn(kGoogleDisplayName);
  902. OCMStub([mockVeriyAssertionResponse profile]).andReturn([[self class] googleProfile]);
  903. OCMStub([mockVeriyAssertionResponse username]).andReturn(kDisplayName);
  904. [self stubTokensWithMockResponse:mockVeriyAssertionResponse];
  905. callback(mockVeriyAssertionResponse, nil);
  906. });
  907. });
  908. [self expectGetAccountInfoGoogle];
  909. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  910. [[FIRAuth auth] signOut:NULL];
  911. FIRAuthCredential *googleCredential =
  912. [FIRGoogleAuthProvider credentialWithIDToken:kGoogleIDToken accessToken:kGoogleAccessToken];
  913. [[FIRAuth auth] signInAndRetrieveDataWithCredential:googleCredential
  914. completion:^(FIRAuthDataResult *_Nullable authResult,
  915. NSError *_Nullable error) {
  916. XCTAssertTrue([NSThread isMainThread]);
  917. [self assertUserGoogle:authResult.user];
  918. XCTAssertEqualObjects(authResult.additionalUserInfo.profile, [[self class] googleProfile]);
  919. XCTAssertEqualObjects(authResult.additionalUserInfo.username, kDisplayName);
  920. XCTAssertEqualObjects(authResult.additionalUserInfo.providerID, FIRGoogleAuthProviderID);
  921. XCTAssertNil(error);
  922. [expectation fulfill];
  923. }];
  924. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  925. [self assertUserGoogle:[FIRAuth auth].currentUser];
  926. OCMVerifyAll(_mockBackend);
  927. }
  928. /** @fn testSignInWithGoogleCredentialFailure
  929. @brief Tests the flow of a failed @c signInWithCredential:completion: call with an
  930. Google Sign-In credential.
  931. */
  932. - (void)testSignInWithGoogleCredentialFailure {
  933. OCMExpect([_mockBackend verifyAssertion:[OCMArg any] callback:[OCMArg any]])
  934. .andDispatchError2([FIRAuthErrorUtils emailAlreadyInUseErrorWithEmail:kGoogleEmail]);
  935. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  936. [[FIRAuth auth] signOut:NULL];
  937. FIRAuthCredential *googleCredential =
  938. [FIRGoogleAuthProvider credentialWithIDToken:kGoogleIDToken accessToken:kGoogleAccessToken];
  939. [[FIRAuth auth] signInWithCredential:googleCredential completion:^(FIRUser *_Nullable user,
  940. NSError *_Nullable error) {
  941. XCTAssertTrue([NSThread isMainThread]);
  942. XCTAssertNil(user);
  943. XCTAssertEqual(error.code, FIRAuthErrorCodeEmailAlreadyInUse);
  944. XCTAssertNotNil(error.userInfo[NSLocalizedDescriptionKey]);
  945. [expectation fulfill];
  946. }];
  947. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  948. XCTAssertNil([FIRAuth auth].currentUser);
  949. OCMVerifyAll(_mockBackend);
  950. }
  951. /** @fn testSignInAnonymouslySuccess
  952. @brief Tests the flow of a successful @c signInAnonymously:completion: call.
  953. */
  954. - (void)testSignInAnonymouslySuccess {
  955. OCMExpect([_mockBackend signUpNewUser:[OCMArg any] callback:[OCMArg any]])
  956. .andCallBlock2(^(FIRSignUpNewUserRequest *_Nullable request,
  957. FIRSignupNewUserCallback callback) {
  958. XCTAssertEqualObjects(request.APIKey, kAPIKey);
  959. XCTAssertNil(request.email);
  960. XCTAssertNil(request.password);
  961. XCTAssertTrue(request.returnSecureToken);
  962. dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
  963. id mockSignUpNewUserResponse = OCMClassMock([FIRSignUpNewUserResponse class]);
  964. [self stubTokensWithMockResponse:mockSignUpNewUserResponse];
  965. callback(mockSignUpNewUserResponse, nil);
  966. });
  967. });
  968. [self expectGetAccountInfoAnonymous];
  969. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  970. [[FIRAuth auth] signOut:NULL];
  971. [[FIRAuth auth] signInAnonymouslyWithCompletion:^(FIRUser *_Nullable user,
  972. NSError *_Nullable error) {
  973. XCTAssertTrue([NSThread isMainThread]);
  974. [self assertUserAnonymous:user];
  975. XCTAssertNil(error);
  976. [expectation fulfill];
  977. }];
  978. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  979. [self assertUserAnonymous:[FIRAuth auth].currentUser];
  980. OCMVerifyAll(_mockBackend);
  981. }
  982. /** @fn testSignInAnonymouslyFailure
  983. @brief Tests the flow of a failed @c signInAnonymously:completion: call.
  984. */
  985. - (void)testSignInAnonymouslyFailure {
  986. OCMExpect([_mockBackend signUpNewUser:[OCMArg any] callback:[OCMArg any]])
  987. .andDispatchError2([FIRAuthErrorUtils operationNotAllowedErrorWithMessage:nil]);
  988. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  989. [[FIRAuth auth] signOut:NULL];
  990. [[FIRAuth auth] signInAnonymouslyWithCompletion:^(FIRUser *_Nullable user,
  991. NSError *_Nullable error) {
  992. XCTAssertTrue([NSThread isMainThread]);
  993. XCTAssertNil(user);
  994. XCTAssertEqual(error.code, FIRAuthErrorCodeOperationNotAllowed);
  995. XCTAssertNotNil(error.userInfo[NSLocalizedDescriptionKey]);
  996. [expectation fulfill];
  997. }];
  998. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  999. XCTAssertNil([FIRAuth auth].currentUser);
  1000. OCMVerifyAll(_mockBackend);
  1001. }
  1002. /** @fn testSignInWithCustomTokenSuccess
  1003. @brief Tests the flow of a successful @c signInWithCustomToken:completion: call.
  1004. */
  1005. - (void)testSignInWithCustomTokenSuccess {
  1006. OCMExpect([_mockBackend verifyCustomToken:[OCMArg any] callback:[OCMArg any]])
  1007. .andCallBlock2(^(FIRVerifyCustomTokenRequest *_Nullable request,
  1008. FIRVerifyCustomTokenResponseCallback callback) {
  1009. XCTAssertEqualObjects(request.APIKey, kAPIKey);
  1010. XCTAssertEqualObjects(request.token, kCustomToken);
  1011. XCTAssertTrue(request.returnSecureToken);
  1012. dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
  1013. id mockVeriyCustomTokenResponse = OCMClassMock([FIRVerifyCustomTokenResponse class]);
  1014. [self stubTokensWithMockResponse:mockVeriyCustomTokenResponse];
  1015. callback(mockVeriyCustomTokenResponse, nil);
  1016. });
  1017. });
  1018. [self expectGetAccountInfo];
  1019. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  1020. [[FIRAuth auth] signOut:NULL];
  1021. [[FIRAuth auth] signInWithCustomToken:kCustomToken completion:^(FIRUser *_Nullable user,
  1022. NSError *_Nullable error) {
  1023. XCTAssertTrue([NSThread isMainThread]);
  1024. [self assertUser:user];
  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 testSignInWithCustomTokenFailure
  1033. @brief Tests the flow of a failed @c signInWithCustomToken:completion: call.
  1034. */
  1035. - (void)testSignInWithCustomTokenFailure {
  1036. OCMExpect([_mockBackend verifyCustomToken:[OCMArg any] callback:[OCMArg any]])
  1037. .andDispatchError2([FIRAuthErrorUtils invalidCustomTokenErrorWithMessage:nil]);
  1038. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  1039. [[FIRAuth auth] signOut:NULL];
  1040. [[FIRAuth auth] signInWithCustomToken:kCustomToken completion:^(FIRUser *_Nullable user,
  1041. NSError *_Nullable error) {
  1042. XCTAssertTrue([NSThread isMainThread]);
  1043. XCTAssertNil(user);
  1044. XCTAssertEqual(error.code, FIRAuthErrorCodeInvalidCustomToken);
  1045. XCTAssertNotNil(error.userInfo[NSLocalizedDescriptionKey]);
  1046. [expectation fulfill];
  1047. }];
  1048. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  1049. XCTAssertNil([FIRAuth auth].currentUser);
  1050. OCMVerifyAll(_mockBackend);
  1051. }
  1052. /** @fn testCreateUserWithEmailPasswordSuccess
  1053. @brief Tests the flow of a successful @c createUserWithEmail:password:completion: call.
  1054. */
  1055. - (void)testCreateUserWithEmailPasswordSuccess {
  1056. OCMExpect([_mockBackend signUpNewUser:[OCMArg any] callback:[OCMArg any]])
  1057. .andCallBlock2(^(FIRSignUpNewUserRequest *_Nullable request,
  1058. FIRSignupNewUserCallback callback) {
  1059. XCTAssertEqualObjects(request.APIKey, kAPIKey);
  1060. XCTAssertEqualObjects(request.email, kEmail);
  1061. XCTAssertEqualObjects(request.password, kFakePassword);
  1062. XCTAssertTrue(request.returnSecureToken);
  1063. dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
  1064. id mockSignUpNewUserResponse = OCMClassMock([FIRSignUpNewUserResponse class]);
  1065. [self stubTokensWithMockResponse:mockSignUpNewUserResponse];
  1066. callback(mockSignUpNewUserResponse, nil);
  1067. });
  1068. });
  1069. [self expectGetAccountInfo];
  1070. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  1071. [[FIRAuth auth] signOut:NULL];
  1072. [[FIRAuth auth] createUserWithEmail:kEmail
  1073. password:kFakePassword
  1074. completion:^(FIRUser *_Nullable user, NSError *_Nullable error) {
  1075. XCTAssertTrue([NSThread isMainThread]);
  1076. [self assertUser:user];
  1077. XCTAssertNil(error);
  1078. [expectation fulfill];
  1079. }];
  1080. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  1081. [self assertUser:[FIRAuth auth].currentUser];
  1082. OCMVerifyAll(_mockBackend);
  1083. }
  1084. /** @fn testCreateUserWithEmailPasswordFailure
  1085. @brief Tests the flow of a failed @c createUserWithEmail:password:completion: call.
  1086. */
  1087. - (void)testCreateUserWithEmailPasswordFailure {
  1088. NSString *reason = @"Password shouldn't be a common word.";
  1089. OCMExpect([_mockBackend signUpNewUser:[OCMArg any] callback:[OCMArg any]])
  1090. .andDispatchError2([FIRAuthErrorUtils weakPasswordErrorWithServerResponseReason:reason]);
  1091. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  1092. [[FIRAuth auth] signOut:NULL];
  1093. [[FIRAuth auth] createUserWithEmail:kEmail
  1094. password:kFakePassword
  1095. completion:^(FIRUser *_Nullable user, NSError *_Nullable error) {
  1096. XCTAssertTrue([NSThread isMainThread]);
  1097. XCTAssertNil(user);
  1098. XCTAssertEqual(error.code, FIRAuthErrorCodeWeakPassword);
  1099. XCTAssertNotNil(error.userInfo[NSLocalizedDescriptionKey]);
  1100. XCTAssertEqualObjects(error.userInfo[NSLocalizedFailureReasonErrorKey], reason);
  1101. [expectation fulfill];
  1102. }];
  1103. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  1104. XCTAssertNil([FIRAuth auth].currentUser);
  1105. OCMVerifyAll(_mockBackend);
  1106. }
  1107. /** @fn testCreateUserEmptyPasswordFailure
  1108. @brief Tests the flow of a failed @c createUserWithEmail:password:completion: call due to an
  1109. empty password. This error occurs on the client side, so there is no need to fake an RPC
  1110. response.
  1111. */
  1112. - (void)testCreateUserEmptyPasswordFailure {
  1113. [self expectGetAccountInfo];
  1114. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  1115. [[FIRAuth auth] signOut:NULL];
  1116. [[FIRAuth auth] createUserWithEmail:kEmail
  1117. password:@""
  1118. completion:^(FIRUser *_Nullable user, NSError *_Nullable error) {
  1119. XCTAssertTrue([NSThread isMainThread]);
  1120. XCTAssertEqual(error.code, FIRAuthErrorCodeWeakPassword);
  1121. [expectation fulfill];
  1122. }];
  1123. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  1124. }
  1125. /** @fn testCreateUserEmptyEmailFailure
  1126. @brief Tests the flow of a failed @c createUserWithEmail:password:completion: call due to an
  1127. empty email adress. This error occurs on the client side, so there is no need to fake an RPC
  1128. response.
  1129. */
  1130. - (void)testCreateUserEmptyEmailFailure {
  1131. [self expectGetAccountInfo];
  1132. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  1133. [[FIRAuth auth] signOut:NULL];
  1134. [[FIRAuth auth] createUserWithEmail:@""
  1135. password:kFakePassword
  1136. completion:^(FIRUser *_Nullable user, NSError *_Nullable error) {
  1137. XCTAssertTrue([NSThread isMainThread]);
  1138. XCTAssertEqual(error.code, FIRAuthErrorCodeMissingEmail);
  1139. [expectation fulfill];
  1140. }];
  1141. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  1142. }
  1143. /** @fn testSendPasswordResetEmailSuccess
  1144. @brief Tests the flow of a successful @c sendPasswordResetWithEmail:completion: call.
  1145. */
  1146. - (void)testSendPasswordResetEmailSuccess {
  1147. OCMExpect([_mockBackend getOOBConfirmationCode:[OCMArg any] callback:[OCMArg any]])
  1148. .andCallBlock2(^(FIRGetOOBConfirmationCodeRequest *_Nullable request,
  1149. FIRGetOOBConfirmationCodeResponseCallback callback) {
  1150. XCTAssertEqualObjects(request.APIKey, kAPIKey);
  1151. XCTAssertEqualObjects(request.email, kEmail);
  1152. dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
  1153. callback([[FIRGetOOBConfirmationCodeResponse alloc] init], nil);
  1154. });
  1155. });
  1156. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  1157. [[FIRAuth auth] sendPasswordResetWithEmail:kEmail completion:^(NSError *_Nullable error) {
  1158. XCTAssertTrue([NSThread isMainThread]);
  1159. XCTAssertNil(error);
  1160. [expectation fulfill];
  1161. }];
  1162. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  1163. OCMVerifyAll(_mockBackend);
  1164. }
  1165. /** @fn testSendPasswordResetEmailFailure
  1166. @brief Tests the flow of a failed @c sendPasswordResetWithEmail:completion: call.
  1167. */
  1168. - (void)testSendPasswordResetEmailFailure {
  1169. OCMExpect([_mockBackend getOOBConfirmationCode:[OCMArg any] callback:[OCMArg any]])
  1170. .andDispatchError2([FIRAuthErrorUtils appNotAuthorizedError]);
  1171. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  1172. [[FIRAuth auth] sendPasswordResetWithEmail:kEmail completion:^(NSError *_Nullable error) {
  1173. XCTAssertTrue([NSThread isMainThread]);
  1174. XCTAssertEqual(error.code, FIRAuthErrorCodeAppNotAuthorized);
  1175. XCTAssertNotNil(error.userInfo[NSLocalizedDescriptionKey]);
  1176. [expectation fulfill];
  1177. }];
  1178. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  1179. OCMVerifyAll(_mockBackend);
  1180. }
  1181. /** @fn testSignOut
  1182. @brief Tests the @c signOut: method.
  1183. */
  1184. - (void)testSignOut {
  1185. [self waitForSignIn];
  1186. // Verify signing out succeeds and clears the current user.
  1187. NSError *error;
  1188. XCTAssertTrue([[FIRAuth auth] signOut:&error]);
  1189. XCTAssertNil([FIRAuth auth].currentUser);
  1190. }
  1191. /** @fn testAuthStateChanges
  1192. @brief Tests @c addAuthStateDidChangeListener: and @c removeAuthStateDidChangeListener: methods.
  1193. */
  1194. - (void)testAuthStateChanges {
  1195. // Set up listener.
  1196. __block XCTestExpectation *expectation;
  1197. __block BOOL shouldHaveUser;
  1198. FIRAuthStateDidChangeListenerBlock listener = ^(FIRAuth *auth, FIRUser *_Nullable user) {
  1199. XCTAssertTrue([NSThread isMainThread]);
  1200. XCTAssertEqual(auth, [FIRAuth auth]);
  1201. XCTAssertEqual(user, [FIRAuth auth].currentUser);
  1202. if (shouldHaveUser) {
  1203. XCTAssertNotNil(user);
  1204. } else {
  1205. XCTAssertNil(user);
  1206. }
  1207. // `expectation` being nil means the listener is not expected to be fired at this moment.
  1208. XCTAssertNotNil(expectation);
  1209. [expectation fulfill];
  1210. };
  1211. [[FIRAuth auth] signOut:NULL];
  1212. [self waitForTimeIntervel:kWaitInterval]; // Wait until dust settled from previous tests.
  1213. // Listener should fire immediately when attached.
  1214. expectation = [self expectationWithDescription:@"initial"];
  1215. shouldHaveUser = NO;
  1216. FIRAuthStateDidChangeListenerHandle handle =
  1217. [[FIRAuth auth] addAuthStateDidChangeListener:listener];
  1218. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  1219. // Listener should fire for signing in.
  1220. expectation = [self expectationWithDescription:@"sign-in"];
  1221. shouldHaveUser = YES;
  1222. [self waitForSignIn];
  1223. // Listener should not fire for signing in again.
  1224. shouldHaveUser = YES;
  1225. [self waitForSignIn];
  1226. [self waitForTimeIntervel:kWaitInterval]; // make sure listener is not called
  1227. // Listener should fire for signing out.
  1228. expectation = [self expectationWithDescription:@"sign-out"];
  1229. shouldHaveUser = NO;
  1230. [[FIRAuth auth] signOut:NULL];
  1231. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  1232. // Listener should no longer fire once detached.
  1233. expectation = nil;
  1234. [[FIRAuth auth] removeAuthStateDidChangeListener:handle];
  1235. [self waitForSignIn];
  1236. [self waitForTimeIntervel:kWaitInterval]; // make sure listener is no longer called
  1237. }
  1238. /** @fn testIDTokenChanges
  1239. @brief Tests @c addIDTokenDidChangeListener: and @c removeIDTokenDidChangeListener: methods.
  1240. */
  1241. - (void)testIDTokenChanges {
  1242. // Set up listener.
  1243. __block XCTestExpectation *expectation;
  1244. __block BOOL shouldHaveUser;
  1245. FIRIDTokenDidChangeListenerBlock listener = ^(FIRAuth *auth, FIRUser *_Nullable user) {
  1246. XCTAssertTrue([NSThread isMainThread]);
  1247. XCTAssertEqual(auth, [FIRAuth auth]);
  1248. XCTAssertEqual(user, [FIRAuth auth].currentUser);
  1249. if (shouldHaveUser) {
  1250. XCTAssertNotNil(user);
  1251. } else {
  1252. XCTAssertNil(user);
  1253. }
  1254. // `expectation` being nil means the listener is not expected to be fired at this moment.
  1255. XCTAssertNotNil(expectation);
  1256. [expectation fulfill];
  1257. };
  1258. [[FIRAuth auth] signOut:NULL];
  1259. [self waitForTimeIntervel:kWaitInterval]; // Wait until dust settled from previous tests.
  1260. // Listener should fire immediately when attached.
  1261. expectation = [self expectationWithDescription:@"initial"];
  1262. shouldHaveUser = NO;
  1263. FIRIDTokenDidChangeListenerHandle handle =
  1264. [[FIRAuth auth] addIDTokenDidChangeListener:listener];
  1265. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  1266. // Listener should fire for signing in.
  1267. expectation = [self expectationWithDescription:@"sign-in"];
  1268. shouldHaveUser = YES;
  1269. [self waitForSignIn];
  1270. // Listener should fire for signing in again as the same user with another access token.
  1271. expectation = [self expectationWithDescription:@"sign-in again"];
  1272. shouldHaveUser = YES;
  1273. [self waitForSignInWithAccessToken:kNewAccessToken];
  1274. // Listener should fire for signing out.
  1275. expectation = [self expectationWithDescription:@"sign-out"];
  1276. shouldHaveUser = NO;
  1277. [[FIRAuth auth] signOut:NULL];
  1278. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  1279. // Listener should no longer fire once detached.
  1280. expectation = nil;
  1281. [[FIRAuth auth] removeIDTokenDidChangeListener:handle];
  1282. [self waitForSignIn];
  1283. [self waitForTimeIntervel:kWaitInterval]; // make sure listener is no longer called
  1284. }
  1285. #pragma mark - Automatic Token Refresh Tests.
  1286. /** @fn testAutomaticTokenRefresh
  1287. @brief Tests a successful flow to automatically refresh tokens for a signed in user.
  1288. */
  1289. - (void)testAutomaticTokenRefresh {
  1290. [[FIRAuth auth] signOut:NULL];
  1291. // Enable auto refresh
  1292. [self enableAutoTokenRefresh];
  1293. // Sign in a user.
  1294. [self waitForSignIn];
  1295. // Set up expectation for secureToken RPC made by token refresh task.
  1296. [self mockSecureTokenResponseWithError:nil];
  1297. // Verify that the current user's access token is the "old" access token before automatic token
  1298. // refresh.
  1299. XCTAssertEqualObjects(kAccessToken, [FIRAuth auth].currentUser.rawAccessToken);
  1300. // Execute saved token refresh task.
  1301. XCTestExpectation *dispatchAfterExpectation =
  1302. [self expectationWithDescription:@"dispatchAfterExpectation"];
  1303. dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
  1304. XCTAssertNotNil(_FIRAuthDispatcherCallback);
  1305. _FIRAuthDispatcherCallback();
  1306. [dispatchAfterExpectation fulfill];
  1307. });
  1308. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  1309. // Verify that current user's access token is the "new" access token provided in the mock secure
  1310. // token response during automatic token refresh.
  1311. XCTAssertEqualObjects(kNewAccessToken, [FIRAuth auth].currentUser.rawAccessToken);
  1312. OCMVerifyAll(_mockBackend);
  1313. }
  1314. /** @fn testAutomaticTokenRefreshInvalidTokenFailure
  1315. @brief Tests an unsuccessful flow to auto refresh tokens with an "invalid token" error.
  1316. This error should cause the user to be signed out.
  1317. */
  1318. - (void)testAutomaticTokenRefreshInvalidTokenFailure {
  1319. [[FIRAuth auth] signOut:NULL];
  1320. // Enable auto refresh
  1321. [self enableAutoTokenRefresh];
  1322. // Sign in a user.
  1323. [self waitForSignIn];
  1324. // Set up expectation for secureToken RPC made by a failed attempt to refresh tokens.
  1325. [self mockSecureTokenResponseWithError:[FIRAuthErrorUtils invalidUserTokenErrorWithMessage:nil]];
  1326. // Verify that current user is still valid.
  1327. XCTAssertEqualObjects(kAccessToken, [FIRAuth auth].currentUser.rawAccessToken);
  1328. // Execute saved token refresh task.
  1329. XCTestExpectation *dispatchAfterExpectation =
  1330. [self expectationWithDescription:@"dispatchAfterExpectation"];
  1331. dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
  1332. XCTAssertNotNil(_FIRAuthDispatcherCallback);
  1333. _FIRAuthDispatcherCallback();
  1334. [dispatchAfterExpectation fulfill];
  1335. });
  1336. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  1337. // Verify that the user is nil after failed attempt to refresh tokens caused signed out.
  1338. XCTAssertNil([FIRAuth auth].currentUser);
  1339. OCMVerifyAll(_mockBackend);
  1340. }
  1341. /** @fn testAutomaticTokenRefreshRetry
  1342. @brief Tests that a retry is attempted for a automatic token refresh task (which is not due to
  1343. invalid tokens). The initial attempt to refresh the access token fails, but the second
  1344. attempt is successful.
  1345. */
  1346. - (void)testAutomaticTokenRefreshRetry {
  1347. [[FIRAuth auth] signOut:NULL];
  1348. // Enable auto refresh
  1349. [self enableAutoTokenRefresh];
  1350. // Sign in a user.
  1351. [self waitForSignIn];
  1352. // Set up expectation for secureToken RPC made by a failed attempt to refresh tokens.
  1353. [self mockSecureTokenResponseWithError:[NSError errorWithDomain:@"ERROR" code:-1 userInfo:nil]];
  1354. // Execute saved token refresh task.
  1355. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  1356. dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
  1357. XCTAssertNotNil(_FIRAuthDispatcherCallback);
  1358. _FIRAuthDispatcherCallback();
  1359. _FIRAuthDispatcherCallback = nil;
  1360. [expectation fulfill];
  1361. });
  1362. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  1363. // The old access token should still be the current user's access token and not the new access
  1364. // token (kNewAccessToken).
  1365. XCTAssertEqualObjects(kAccessToken, [FIRAuth auth].currentUser.rawAccessToken);
  1366. // Set up expectation for secureToken RPC made by a successful attempt to refresh tokens.
  1367. [self mockSecureTokenResponseWithError:nil];
  1368. // Execute saved token refresh task.
  1369. XCTestExpectation *dispatchAfterExpectation =
  1370. [self expectationWithDescription:@"dispatchAfterExpectation"];
  1371. dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
  1372. XCTAssertNotNil(_FIRAuthDispatcherCallback);
  1373. _FIRAuthDispatcherCallback();
  1374. [dispatchAfterExpectation fulfill];
  1375. });
  1376. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  1377. // Verify that current user's access token is the "new" access token provided in the mock secure
  1378. // token response during automatic token refresh.
  1379. XCTAssertEqualObjects([FIRAuth auth].currentUser.rawAccessToken, kNewAccessToken);
  1380. OCMVerifyAll(_mockBackend);
  1381. }
  1382. #if TARGET_OS_IOS
  1383. /** @fn testAutomaticTokenRefreshInvalidTokenFailure
  1384. @brief Tests that app foreground notification triggers the scheduling of an automatic token
  1385. refresh task.
  1386. */
  1387. - (void)testAutoRefreshAppForegroundedNotification {
  1388. [[FIRAuth auth] signOut:NULL];
  1389. // Enable auto refresh
  1390. [self enableAutoTokenRefresh];
  1391. // Sign in a user.
  1392. [self waitForSignIn];
  1393. // Post "UIApplicationDidBecomeActiveNotification" to trigger scheduling token refresh task.
  1394. [[NSNotificationCenter defaultCenter]
  1395. postNotificationName:UIApplicationDidBecomeActiveNotification object:nil];
  1396. // Verify that current user is still valid with old access token.
  1397. XCTAssertEqualObjects(kAccessToken, [FIRAuth auth].currentUser.rawAccessToken);
  1398. // Set up expectation for secureToken RPC made by a successful attempt to refresh tokens.
  1399. [self mockSecureTokenResponseWithError:nil];
  1400. // Execute saved token refresh task.
  1401. XCTestExpectation *dispatchAfterExpectation =
  1402. [self expectationWithDescription:@"dispatchAfterExpectation"];
  1403. dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
  1404. XCTAssertNotNil(_FIRAuthDispatcherCallback);
  1405. _FIRAuthDispatcherCallback();
  1406. [dispatchAfterExpectation fulfill];
  1407. });
  1408. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  1409. // Verify that current user is still valid with new access token.
  1410. XCTAssertEqualObjects(kNewAccessToken, [FIRAuth auth].currentUser.rawAccessToken);
  1411. OCMVerifyAll(_mockBackend);
  1412. }
  1413. #endif
  1414. #pragma mark - Helpers
  1415. /** @fn mockSecureTokenResponseWithError:
  1416. @brief Set up expectation for secureToken RPC.
  1417. @param error The error that the mock should return if any.
  1418. */
  1419. - (void)mockSecureTokenResponseWithError:(nullable NSError *)error {
  1420. // Set up expectation for secureToken RPC made by a successful attempt to refresh tokens.
  1421. XCTestExpectation *secureTokenResponseExpectation =
  1422. [self expectationWithDescription:@"secureTokenResponseExpectation"];
  1423. OCMExpect([_mockBackend secureToken:[OCMArg any] callback:[OCMArg any]])
  1424. .andCallBlock2(^(FIRSecureTokenRequest *_Nullable request,
  1425. FIRSecureTokenResponseCallback callback) {
  1426. XCTAssertEqualObjects(request.APIKey, kAPIKey);
  1427. XCTAssertEqualObjects(request.refreshToken, kRefreshToken);
  1428. dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
  1429. if (error) {
  1430. callback(nil, error);
  1431. [secureTokenResponseExpectation fulfill];
  1432. return;
  1433. }
  1434. id mockSecureTokenResponse = OCMClassMock([FIRSecureTokenResponse class]);
  1435. OCMStub([mockSecureTokenResponse accessToken]).andReturn(kNewAccessToken);
  1436. NSDate *futureDate =
  1437. [[NSDate date] dateByAddingTimeInterval:kTestTokenExpirationTimeInterval];
  1438. OCMStub([mockSecureTokenResponse approximateExpirationDate]).andReturn(futureDate);
  1439. callback(mockSecureTokenResponse, nil);
  1440. [secureTokenResponseExpectation fulfill];
  1441. });
  1442. });
  1443. }
  1444. /** @fn enableAutoTokenRefresh
  1445. @brief Enables automatic token refresh by invoking FIRAuth's implementation of FIRApp's
  1446. |getTokenWithImplementation|.
  1447. */
  1448. - (void)enableAutoTokenRefresh {
  1449. XCTestExpectation *expectation = [self expectationWithDescription:@"autoTokenRefreshcallback"];
  1450. [[FIRAuth auth].app getTokenForcingRefresh:NO withCallback:^(NSString *_Nullable token,
  1451. NSError *_Nullable error) {
  1452. [expectation fulfill];
  1453. }];
  1454. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  1455. }
  1456. /** @fn app1
  1457. @brief Creates a Firebase app.
  1458. @return A @c FIRApp with some name.
  1459. */
  1460. - (FIRApp *)app1 {
  1461. return [FIRApp appForAuthUnitTestsWithName:kFirebaseAppName1];
  1462. }
  1463. /** @fn app2
  1464. @brief Creates another Firebase app.
  1465. @return A @c FIRApp with some other name.
  1466. */
  1467. - (FIRApp *)app2 {
  1468. return [FIRApp appForAuthUnitTestsWithName:kFirebaseAppName2];
  1469. }
  1470. /** @fn stubSecureTokensWithMockResponse
  1471. @brief Creates stubs on the mock response object with access and refresh tokens
  1472. @param mockResponse The mock response object.
  1473. */
  1474. - (void)stubTokensWithMockResponse:(id)mockResponse {
  1475. OCMStub([mockResponse IDToken]).andReturn(kAccessToken);
  1476. OCMStub([mockResponse approximateExpirationDate])
  1477. .andReturn([NSDate dateWithTimeIntervalSinceNow:kAccessTokenTimeToLive]);
  1478. OCMStub([mockResponse refreshToken]).andReturn(kRefreshToken);
  1479. }
  1480. /** @fn expectGetAccountInfo
  1481. @brief Expects a GetAccountInfo request on the mock backend and calls back with fake account
  1482. data.
  1483. */
  1484. - (void)expectGetAccountInfo {
  1485. [self expectGetAccountInfoWithAccessToken:kAccessToken];
  1486. }
  1487. /** @fn expectGetAccountInfoWithAccessToken
  1488. @param accessToken The access token for the user to check against.
  1489. @brief Expects a GetAccountInfo request on the mock backend and calls back with fake account
  1490. data.
  1491. */
  1492. - (void)expectGetAccountInfoWithAccessToken:(NSString *)accessToken {
  1493. OCMExpect([_mockBackend getAccountInfo:[OCMArg any] callback:[OCMArg any]])
  1494. .andCallBlock2(^(FIRGetAccountInfoRequest *_Nullable request,
  1495. FIRGetAccountInfoResponseCallback callback) {
  1496. XCTAssertEqualObjects(request.APIKey, kAPIKey);
  1497. XCTAssertEqualObjects(request.accessToken, accessToken);
  1498. dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
  1499. id mockGetAccountInfoResponseUser = OCMClassMock([FIRGetAccountInfoResponseUser class]);
  1500. OCMStub([mockGetAccountInfoResponseUser localID]).andReturn(kLocalID);
  1501. OCMStub([mockGetAccountInfoResponseUser displayName]).andReturn(kDisplayName);
  1502. OCMStub([mockGetAccountInfoResponseUser email]).andReturn(kEmail);
  1503. OCMStub([mockGetAccountInfoResponseUser passwordHash]).andReturn(kPasswordHash);
  1504. id mockGetAccountInfoResponse = OCMClassMock([FIRGetAccountInfoResponse class]);
  1505. OCMStub([mockGetAccountInfoResponse users]).andReturn(@[ mockGetAccountInfoResponseUser ]);
  1506. callback(mockGetAccountInfoResponse, nil);
  1507. });
  1508. });
  1509. }
  1510. /** @fn assertUser
  1511. @brief Asserts the given FIRUser matching the fake data returned by @c expectGetAccountInfo.
  1512. @param user The user object to be verified.
  1513. */
  1514. - (void)assertUser:(FIRUser *)user {
  1515. XCTAssertNotNil(user);
  1516. XCTAssertEqualObjects(user.uid, kLocalID);
  1517. XCTAssertEqualObjects(user.displayName, kDisplayName);
  1518. XCTAssertEqualObjects(user.email, kEmail);
  1519. XCTAssertFalse(user.anonymous);
  1520. XCTAssertEqual(user.providerData.count, 0u);
  1521. }
  1522. /** @fn expectGetAccountInfoGoogle
  1523. @brief Expects a GetAccountInfo request on the mock backend and calls back with fake account
  1524. data for a Google Sign-In user.
  1525. */
  1526. - (void)expectGetAccountInfoGoogle {
  1527. OCMExpect([_mockBackend getAccountInfo:[OCMArg any] callback:[OCMArg any]])
  1528. .andCallBlock2(^(FIRGetAccountInfoRequest *_Nullable request,
  1529. FIRGetAccountInfoResponseCallback callback) {
  1530. XCTAssertEqualObjects(request.APIKey, kAPIKey);
  1531. XCTAssertEqualObjects(request.accessToken, kAccessToken);
  1532. dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
  1533. id mockGoogleUserInfo = OCMClassMock([FIRGetAccountInfoResponseProviderUserInfo class]);
  1534. OCMStub([mockGoogleUserInfo providerID]).andReturn(FIRGoogleAuthProviderID);
  1535. OCMStub([mockGoogleUserInfo displayName]).andReturn(kGoogleDisplayName);
  1536. OCMStub([mockGoogleUserInfo federatedID]).andReturn(kGoogleID);
  1537. OCMStub([mockGoogleUserInfo email]).andReturn(kGoogleEmail);
  1538. id mockGetAccountInfoResponseUser = OCMClassMock([FIRGetAccountInfoResponseUser class]);
  1539. OCMStub([mockGetAccountInfoResponseUser localID]).andReturn(kLocalID);
  1540. OCMStub([mockGetAccountInfoResponseUser displayName]).andReturn(kDisplayName);
  1541. OCMStub([mockGetAccountInfoResponseUser providerUserInfo])
  1542. .andReturn((@[ mockGoogleUserInfo ]));
  1543. id mockGetAccountInfoResponse = OCMClassMock([FIRGetAccountInfoResponse class]);
  1544. OCMStub([mockGetAccountInfoResponse users]).andReturn(@[ mockGetAccountInfoResponseUser ]);
  1545. callback(mockGetAccountInfoResponse, nil);
  1546. });
  1547. });
  1548. }
  1549. /** @fn assertUserGoogle
  1550. @brief Asserts the given FIRUser matching the fake data returned by
  1551. @c expectGetAccountInfoGoogle.
  1552. @param user The user object to be verified.
  1553. */
  1554. - (void)assertUserGoogle:(FIRUser *)user {
  1555. XCTAssertNotNil(user);
  1556. XCTAssertEqualObjects(user.uid, kLocalID);
  1557. XCTAssertEqualObjects(user.displayName, kDisplayName);
  1558. XCTAssertEqual(user.providerData.count, 1u);
  1559. id<FIRUserInfo> googleUserInfo = user.providerData[0];
  1560. XCTAssertEqualObjects(googleUserInfo.providerID, FIRGoogleAuthProviderID);
  1561. XCTAssertEqualObjects(googleUserInfo.uid, kGoogleID);
  1562. XCTAssertEqualObjects(googleUserInfo.displayName, kGoogleDisplayName);
  1563. XCTAssertEqualObjects(googleUserInfo.email, kGoogleEmail);
  1564. }
  1565. /** @fn expectGetAccountInfoAnonymous
  1566. @brief Expects a GetAccountInfo request on the mock backend and calls back with fake anonymous
  1567. account data.
  1568. */
  1569. - (void)expectGetAccountInfoAnonymous {
  1570. OCMExpect([_mockBackend getAccountInfo:[OCMArg any] callback:[OCMArg any]])
  1571. .andCallBlock2(^(FIRGetAccountInfoRequest *_Nullable request,
  1572. FIRGetAccountInfoResponseCallback callback) {
  1573. XCTAssertEqualObjects(request.APIKey, kAPIKey);
  1574. XCTAssertEqualObjects(request.accessToken, kAccessToken);
  1575. dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
  1576. id mockGetAccountInfoResponseUser = OCMClassMock([FIRGetAccountInfoResponseUser class]);
  1577. OCMStub([mockGetAccountInfoResponseUser localID]).andReturn(kLocalID);
  1578. id mockGetAccountInfoResponse = OCMClassMock([FIRGetAccountInfoResponse class]);
  1579. OCMStub([mockGetAccountInfoResponse users]).andReturn(@[ mockGetAccountInfoResponseUser ]);
  1580. callback(mockGetAccountInfoResponse, nil);
  1581. });
  1582. });
  1583. }
  1584. /** @fn assertUserAnonymous
  1585. @brief Asserts the given FIRUser matching the fake data returned by
  1586. @c expectGetAccountInfoAnonymous.
  1587. @param user The user object to be verified.
  1588. */
  1589. - (void)assertUserAnonymous:(FIRUser *)user {
  1590. XCTAssertNotNil(user);
  1591. XCTAssertEqualObjects(user.uid, kLocalID);
  1592. XCTAssertNil(user.displayName);
  1593. XCTAssertTrue(user.anonymous);
  1594. XCTAssertEqual(user.providerData.count, 0u);
  1595. }
  1596. /** @fn waitForSignIn
  1597. @brief Signs in a user to prepare for tests.
  1598. @remarks This method also waits for all other pending @c XCTestExpectation instances.
  1599. */
  1600. - (void)waitForSignIn {
  1601. [self waitForSignInWithAccessToken:kAccessToken];
  1602. }
  1603. /** @fn waitForSignInWithAccessToken:
  1604. @brief Signs in a user to prepare for tests.
  1605. @param accessToken The access token for the user to have.
  1606. @remarks This method also waits for all other pending @c XCTestExpectation instances.
  1607. */
  1608. - (void)waitForSignInWithAccessToken:(NSString *)accessToken {
  1609. OCMExpect([_mockBackend verifyPassword:[OCMArg any] callback:[OCMArg any]])
  1610. .andCallBlock2(^(FIRVerifyPasswordRequest *_Nullable request,
  1611. FIRVerifyPasswordResponseCallback callback) {
  1612. dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
  1613. id mockVeriyPasswordResponse = OCMClassMock([FIRVerifyPasswordResponse class]);
  1614. OCMStub([mockVeriyPasswordResponse IDToken]).andReturn(accessToken);
  1615. OCMStub([mockVeriyPasswordResponse approximateExpirationDate])
  1616. .andReturn([NSDate dateWithTimeIntervalSinceNow:kAccessTokenTimeToLive]);
  1617. OCMStub([mockVeriyPasswordResponse refreshToken]).andReturn(kRefreshToken);
  1618. callback(mockVeriyPasswordResponse, nil);
  1619. });
  1620. });
  1621. [self expectGetAccountInfoWithAccessToken:accessToken];
  1622. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  1623. [[FIRAuth auth] signInWithEmail:kEmail password:kFakePassword completion:^(FIRUser *_Nullable user,
  1624. NSError *_Nullable error) {
  1625. [expectation fulfill];
  1626. }];
  1627. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  1628. OCMVerifyAll(_mockBackend);
  1629. XCTAssertNotNil([FIRAuth auth].currentUser);
  1630. }
  1631. /** @fn waitForTimeInterval:
  1632. @brief Wait for a particular time interval.
  1633. @remarks This method also waits for all other pending @c XCTestExpectation instances.
  1634. */
  1635. - (void)waitForTimeIntervel:(NSTimeInterval)timeInterval {
  1636. static dispatch_queue_t queue;
  1637. static dispatch_once_t onceToken;
  1638. XCTestExpectation *expectation = [self expectationWithDescription:@"waitForTimeIntervel:"];
  1639. dispatch_once(&onceToken, ^{
  1640. queue = dispatch_queue_create("com.google.FIRAuthUnitTests.waitForTimeIntervel", NULL);
  1641. });
  1642. dispatch_after(dispatch_time(DISPATCH_TIME_NOW, timeInterval * NSEC_PER_SEC), queue, ^() {
  1643. [expectation fulfill];
  1644. });
  1645. [self waitForExpectationsWithTimeout:timeInterval + kExpectationTimeout handler:nil];
  1646. }
  1647. @end