FirebaseAuthApiTests.m 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679
  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 <FirebaseCore/FIRApp.h>
  19. #import "FirebaseAuth.h"
  20. #import "AuthCredentials.h"
  21. #ifdef NO_NETWORK
  22. #import "ITUIOSTestUtil.h"
  23. #import "ioReplayer/IORManager.h"
  24. #import "ioReplayer/IORTestCase.h"
  25. #endif
  26. #import <GTMSessionFetcher/GTMSessionFetcher.h>
  27. #import <GTMSessionFetcher/GTMSessionFetcherService.h>
  28. /** The user name string for Custom Auth testing account. */
  29. static NSString *const kCustomAuthTestingAccountUserID = KCUSTOM_AUTH_USER_ID;
  30. /** The url for obtaining a valid custom token string used to test Custom Auth. */
  31. static NSString *const kCustomTokenUrl = KCUSTOM_AUTH_TOKEN_URL;
  32. /** The url for obtaining an expired but valid custom token string used to test Custom Auth failure.
  33. */
  34. static NSString *const kExpiredCustomTokenUrl = KCUSTOM_AUTH_TOKEN_EXPIRED_URL;
  35. /** Facebook app access token that will be used for Facebook Graph API, which is different from
  36. * account access token.
  37. */
  38. static NSString *const kFacebookAppAccessToken = KFACEBOOK_APP_ACCESS_TOKEN;
  39. /** Facebook app ID that will be used for Facebook Graph API. */
  40. static NSString *const kFacebookAppID = KFACEBOOK_APP_ID;
  41. static NSString *const kFacebookGraphApiAuthority = @"graph.facebook.com";
  42. static NSString *const kFacebookTestAccountName = KFACEBOOK_USER_NAME;
  43. static NSString *const kGoogleTestAccountName = KGOOGLE_USER_NAME;
  44. /** The invalid custom token string for testing Custom Auth. */
  45. static NSString *const kInvalidCustomToken = @"invalid token.";
  46. /** The testing email address for testCreateAccountWithEmailAndPassword. */
  47. static NSString *const kTestingEmailToCreateUser = @"abc@xyz.com";
  48. /** The testing email address for testSignInExistingUserWithEmailAndPassword. */
  49. static NSString *const kExistingTestingEmailToSignIn = @"456@abc.com";
  50. /** The testing email address for testUpdatingUsersEmail. */
  51. static NSString *const kNewTestingEmail = @"updatedEmail@abc.com";
  52. /** The testing password for testSignInExistingUserWithModifiedEmailAndPassword. */
  53. static NSString *const kNewTestingPasswordToSignIn = @"password_new";
  54. /** Error message for invalid custom token sign in. */
  55. NSString *kInvalidTokenErrorMessage =
  56. @"The custom token format is incorrect. Please check the documentation.";
  57. NSString *kGoogleCliendId = KGOOGLE_CLIENT_ID;
  58. /** Refresh token of Google test account to exchange for access token. Refresh token never expires
  59. * unless user revokes it. If this refresh token expires, tests in record mode will fail and this
  60. * token needs to be updated.
  61. */
  62. NSString *kGoogleTestAccountRefreshToken = KGOOGLE_TEST_ACCOUNT_REFRESH_TOKEN;
  63. static NSTimeInterval const kExpectationsTimeout = 10;
  64. #ifdef NO_NETWORK
  65. #define SKIP_IF_ON_MOBILE_HARNESS \
  66. if ([ITUIOSTestUtil isOnMobileHarness]) { \
  67. NSLog(@"Skipping '%@' on mobile harness", NSStringFromSelector(_cmd)); \
  68. return; \
  69. }
  70. #else
  71. #define SKIP_IF_ON_MOBILE_HARNESS
  72. #endif
  73. #ifdef NO_NETWORK
  74. @interface ApiTests : IORTestCase
  75. #else
  76. @interface ApiTests : XCTestCase
  77. #endif
  78. @end
  79. @implementation ApiTests
  80. /** To reset the app so that each test sees the app in a clean state. */
  81. - (void)setUp {
  82. [super setUp];
  83. [self signOut];
  84. }
  85. #pragma mark - Tests
  86. /**
  87. * This test runs in replay mode by default. To run in a different mode follow the instructions
  88. * below.
  89. *
  90. * Blaze: --test_arg=\'--networkReplayMode=(replay|record|disabled|observe)\'
  91. *
  92. * Xcode:
  93. * Update the following flag in the xcscheme.
  94. * --networkReplayMode=(replay|record|disabled|observe)
  95. */
  96. - (void)testCreateAccountWithEmailAndPassword {
  97. SKIP_IF_ON_MOBILE_HARNESS
  98. FIRAuth *auth = [FIRAuth auth];
  99. if (!auth) {
  100. XCTFail(@"Could not obtain auth object.");
  101. }
  102. XCTestExpectation *expectation =
  103. [self expectationWithDescription:@"Created account with email and password."];
  104. [auth createUserWithEmail:kTestingEmailToCreateUser
  105. password:@"password"
  106. completion:^(FIRAuthDataResult *result, NSError *error) {
  107. if (error) {
  108. NSLog(@"createUserWithEmail has error: %@", error);
  109. }
  110. [expectation fulfill];
  111. }];
  112. [self waitForExpectationsWithTimeout:kExpectationsTimeout
  113. handler:^(NSError *error) {
  114. if (error != nil) {
  115. XCTFail(@"Failed to wait for expectations "
  116. @"in creating account. Error: %@",
  117. error.localizedDescription);
  118. }
  119. }];
  120. XCTAssertEqualObjects(auth.currentUser.email, kTestingEmailToCreateUser);
  121. // Clean up the created Firebase user for future runs.
  122. [self deleteCurrentFirebaseUser];
  123. }
  124. - (void)testUpdatingUsersEmail {
  125. SKIP_IF_ON_MOBILE_HARNESS
  126. FIRAuth *auth = [FIRAuth auth];
  127. if (!auth) {
  128. XCTFail(@"Could not obtain auth object.");
  129. }
  130. __block NSError *apiError;
  131. XCTestExpectation *expectation =
  132. [self expectationWithDescription:@"Created account with email and password."];
  133. [auth createUserWithEmail:kTestingEmailToCreateUser
  134. password:@"password"
  135. completion:^(FIRAuthDataResult *user, NSError *error) {
  136. apiError = error;
  137. [expectation fulfill];
  138. }];
  139. [self waitForExpectationsWithTimeout:kExpectationsTimeout handler:nil];
  140. expectation = [self expectationWithDescription:@"Created account with email and password."];
  141. XCTAssertEqualObjects(auth.currentUser.email, kTestingEmailToCreateUser);
  142. XCTAssertNil(apiError);
  143. [auth.currentUser updateEmail:kNewTestingEmail
  144. completion:^(NSError *_Nullable error) {
  145. apiError = error;
  146. [expectation fulfill];
  147. }];
  148. [self waitForExpectationsWithTimeout:kExpectationsTimeout handler:nil];
  149. XCTAssertNil(apiError);
  150. XCTAssertEqualObjects(auth.currentUser.email, kNewTestingEmail);
  151. // Clean up the created Firebase user for future runs.
  152. [self deleteCurrentFirebaseUser];
  153. }
  154. - (void)testLinkAnonymousAccountToFacebookAccount {
  155. FIRAuth *auth = [FIRAuth auth];
  156. if (!auth) {
  157. XCTFail(@"Could not obtain auth object.");
  158. }
  159. [self signInAnonymously];
  160. NSDictionary *userInfoDict = [self createFacebookTestingAccount];
  161. NSString *facebookAccessToken = userInfoDict[@"access_token"];
  162. NSLog(@"Facebook testing account access token is: %@", facebookAccessToken);
  163. NSString *facebookAccountId = userInfoDict[@"id"];
  164. NSLog(@"Facebook testing account id is: %@", facebookAccountId);
  165. FIRAuthCredential *credential =
  166. [FIRFacebookAuthProvider credentialWithAccessToken:facebookAccessToken];
  167. XCTestExpectation *expectation = [self expectationWithDescription:@"Facebook linking finished."];
  168. [auth.currentUser linkWithCredential:credential
  169. completion:^(FIRUser *user, NSError *error) {
  170. if (error) {
  171. NSLog(@"Link to Facebok error: %@", error);
  172. }
  173. [expectation fulfill];
  174. }];
  175. [self waitForExpectationsWithTimeout:kExpectationsTimeout
  176. handler:^(NSError *error) {
  177. if (error != nil) {
  178. XCTFail(@"Failed to wait for expectations "
  179. @"in linking to Facebook. Error: %@",
  180. error.localizedDescription);
  181. }
  182. }];
  183. NSArray<id<FIRUserInfo>> *providerData = auth.currentUser.providerData;
  184. XCTAssertEqual([providerData count], 1);
  185. XCTAssertEqualObjects([providerData[0] providerID], @"facebook.com");
  186. // Clean up the created Firebase/Facebook user for future runs.
  187. [self deleteCurrentFirebaseUser];
  188. [self deleteFacebookTestingAccountbyId:facebookAccountId];
  189. }
  190. - (void)testSignInAnonymously {
  191. [self signInAnonymously];
  192. XCTAssertTrue([FIRAuth auth].currentUser.anonymous);
  193. [self deleteCurrentFirebaseUser];
  194. }
  195. - (void)testSignInExistingUserWithEmailAndPassword {
  196. FIRAuth *auth = [FIRAuth auth];
  197. if (!auth) {
  198. XCTFail(@"Could not obtain auth object.");
  199. }
  200. XCTestExpectation *expectation =
  201. [self expectationWithDescription:@"Signed in existing account with email and password."];
  202. [auth signInWithEmail:kExistingTestingEmailToSignIn
  203. password:@"password"
  204. completion:^(FIRAuthDataResult *user, NSError *error) {
  205. if (error) {
  206. NSLog(@"Signing in existing account has error: %@", error);
  207. }
  208. [expectation fulfill];
  209. }];
  210. [self waitForExpectationsWithTimeout:kExpectationsTimeout
  211. handler:^(NSError *error) {
  212. if (error != nil) {
  213. XCTFail(@"Failed to wait for expectations "
  214. @"in signing in existing account. Error: %@",
  215. error.localizedDescription);
  216. }
  217. }];
  218. XCTAssertEqualObjects(auth.currentUser.email, kExistingTestingEmailToSignIn);
  219. }
  220. - (void)testSignInWithValidCustomAuthToken {
  221. FIRAuth *auth = [FIRAuth auth];
  222. if (!auth) {
  223. XCTFail(@"Could not obtain auth object.");
  224. }
  225. NSError *error;
  226. NSString *customToken = [NSString stringWithContentsOfURL:[NSURL URLWithString:kCustomTokenUrl]
  227. encoding:NSUTF8StringEncoding
  228. error:&error];
  229. if (!customToken) {
  230. XCTFail(@"There was an error retrieving the custom token: %@", error);
  231. }
  232. NSLog(@"The valid token is: %@", customToken);
  233. XCTestExpectation *expectation =
  234. [self expectationWithDescription:@"CustomAuthToken sign-in finished."];
  235. [auth signInWithCustomToken:customToken
  236. completion:^(FIRAuthDataResult *_Nullable result, NSError *_Nullable error) {
  237. if (error) {
  238. NSLog(@"Valid token sign in error: %@", error);
  239. }
  240. [expectation fulfill];
  241. }];
  242. [self waitForExpectationsWithTimeout:kExpectationsTimeout
  243. handler:^(NSError *error) {
  244. if (error != nil) {
  245. XCTFail(@"Failed to wait for expectations "
  246. @"in CustomAuthToken sign in. Error: %@",
  247. error.localizedDescription);
  248. }
  249. }];
  250. XCTAssertEqualObjects(auth.currentUser.uid, kCustomAuthTestingAccountUserID);
  251. }
  252. - (void)testSignInWithValidCustomAuthExpiredToken {
  253. FIRAuth *auth = [FIRAuth auth];
  254. if (!auth) {
  255. XCTFail(@"Could not obtain auth object.");
  256. }
  257. NSError *error;
  258. NSString *customToken =
  259. [NSString stringWithContentsOfURL:[NSURL URLWithString:kExpiredCustomTokenUrl]
  260. encoding:NSUTF8StringEncoding
  261. error:&error];
  262. if (!customToken) {
  263. XCTFail(@"There was an error retrieving the custom token: %@", error);
  264. }
  265. XCTestExpectation *expectation =
  266. [self expectationWithDescription:@"CustomAuthToken sign-in finished."];
  267. __block NSError *apiError;
  268. [auth signInWithCustomToken:customToken
  269. completion:^(FIRAuthDataResult *_Nullable result, NSError *_Nullable error) {
  270. if (error) {
  271. apiError = error;
  272. }
  273. [expectation fulfill];
  274. }];
  275. [self waitForExpectationsWithTimeout:kExpectationsTimeout
  276. handler:^(NSError *error) {
  277. if (error != nil) {
  278. XCTFail(@"Failed to wait for expectations "
  279. @"in CustomAuthToken sign in. Error: %@",
  280. error.localizedDescription);
  281. }
  282. }];
  283. XCTAssertNil(auth.currentUser);
  284. XCTAssertEqual(apiError.code, FIRAuthErrorCodeInvalidCustomToken);
  285. }
  286. - (void)testInMemoryUserAfterSignOut {
  287. FIRAuth *auth = [FIRAuth auth];
  288. if (!auth) {
  289. XCTFail(@"Could not obtain auth object.");
  290. }
  291. NSError *error;
  292. NSString *customToken = [NSString stringWithContentsOfURL:[NSURL URLWithString:kCustomTokenUrl]
  293. encoding:NSUTF8StringEncoding
  294. error:&error];
  295. if (!customToken) {
  296. XCTFail(@"There was an error retrieving the custom token: %@", error);
  297. }
  298. XCTestExpectation *expectation =
  299. [self expectationWithDescription:@"CustomAuthToken sign-in finished."];
  300. __block NSError *rpcError;
  301. [auth signInWithCustomToken:customToken
  302. completion:^(FIRAuthDataResult *_Nullable result, NSError *_Nullable error) {
  303. if (error) {
  304. rpcError = error;
  305. }
  306. [expectation fulfill];
  307. }];
  308. [self waitForExpectationsWithTimeout:kExpectationsTimeout
  309. handler:^(NSError *error) {
  310. if (error != nil) {
  311. XCTFail(@"Failed to wait for expectations "
  312. @"in CustomAuthToken sign in. Error: %@",
  313. error.localizedDescription);
  314. }
  315. }];
  316. XCTAssertEqualObjects(auth.currentUser.uid, kCustomAuthTestingAccountUserID);
  317. XCTAssertNil(rpcError);
  318. FIRUser *inMemoryUser = auth.currentUser;
  319. XCTestExpectation *expectation1 = [self expectationWithDescription:@"Profile data change."];
  320. [auth signOut:NULL];
  321. rpcError = nil;
  322. NSString *newEmailAddress = [self fakeRandomEmail];
  323. XCTAssertNotEqualObjects(newEmailAddress, inMemoryUser.email);
  324. [inMemoryUser updateEmail:newEmailAddress completion:^(NSError *_Nullable error) {
  325. rpcError = error;
  326. [expectation1 fulfill];
  327. }];
  328. [self waitForExpectationsWithTimeout:kExpectationsTimeout handler:nil];
  329. XCTAssertEqualObjects(inMemoryUser.email, newEmailAddress);
  330. XCTAssertNil(rpcError);
  331. XCTAssertNil(auth.currentUser);
  332. }
  333. - (void)testSignInWithInvalidCustomAuthToken {
  334. FIRAuth *auth = [FIRAuth auth];
  335. if (!auth) {
  336. XCTFail(@"Could not obtain auth object.");
  337. }
  338. XCTestExpectation *expectation =
  339. [self expectationWithDescription:@"Invalid CustomAuthToken sign-in finished."];
  340. [auth signInWithCustomToken:kInvalidCustomToken
  341. completion:^(FIRAuthDataResult *_Nullable result, NSError *_Nullable error) {
  342. XCTAssertEqualObjects(error.localizedDescription, kInvalidTokenErrorMessage);
  343. [expectation fulfill];
  344. }];
  345. [self waitForExpectationsWithTimeout:kExpectationsTimeout
  346. handler:^(NSError *error) {
  347. if (error != nil) {
  348. XCTFail(@"Failed to wait for expectations "
  349. @"in CustomAuthToken sign in. Error: %@",
  350. error.localizedDescription);
  351. }
  352. }];
  353. }
  354. - (void)testSignInWithFaceboook {
  355. FIRAuth *auth = [FIRAuth auth];
  356. if (!auth) {
  357. XCTFail(@"Could not obtain auth object.");
  358. }
  359. NSDictionary *userInfoDict = [self createFacebookTestingAccount];
  360. NSString *facebookAccessToken = userInfoDict[@"access_token"];
  361. NSLog(@"Facebook testing account access token is: %@", facebookAccessToken);
  362. NSString *facebookAccountId = userInfoDict[@"id"];
  363. NSLog(@"Facebook testing account id is: %@", facebookAccountId);
  364. FIRAuthCredential *credential =
  365. [FIRFacebookAuthProvider credentialWithAccessToken:facebookAccessToken];
  366. XCTestExpectation *expectation = [self expectationWithDescription:@"Facebook sign-in finished."];
  367. [auth signInWithCredential:credential
  368. completion:^(FIRUser *user, NSError *error) {
  369. if (error) {
  370. NSLog(@"Facebook sign in error: %@", error);
  371. }
  372. [expectation fulfill];
  373. }];
  374. [self waitForExpectationsWithTimeout:kExpectationsTimeout
  375. handler:^(NSError *error) {
  376. if (error != nil) {
  377. XCTFail(@"Failed to wait for expectations "
  378. @"in Facebook sign in. Error: %@",
  379. error.localizedDescription);
  380. }
  381. }];
  382. XCTAssertEqualObjects(auth.currentUser.displayName, kFacebookTestAccountName);
  383. // Clean up the created Firebase/Facebook user for future runs.
  384. [self deleteCurrentFirebaseUser];
  385. [self deleteFacebookTestingAccountbyId:facebookAccountId];
  386. }
  387. - (void)testSignInWithGoogle {
  388. FIRAuth *auth = [FIRAuth auth];
  389. if (!auth) {
  390. XCTFail(@"Could not obtain auth object.");
  391. }
  392. NSDictionary *userInfoDict = [self getGoogleAccessToken];
  393. NSString *googleAccessToken = userInfoDict[@"access_token"];
  394. NSString *googleIdToken = userInfoDict[@"id_token"];
  395. FIRAuthCredential *credential =
  396. [FIRGoogleAuthProvider credentialWithIDToken:googleIdToken accessToken:googleAccessToken];
  397. XCTestExpectation *expectation =
  398. [self expectationWithDescription:@"Signing in with Google finished."];
  399. [auth signInWithCredential:credential
  400. completion:^(FIRUser *user, NSError *error) {
  401. if (error) {
  402. NSLog(@"Signing in with Google had error: %@", error);
  403. }
  404. [expectation fulfill];
  405. }];
  406. [self waitForExpectationsWithTimeout:kExpectationsTimeout
  407. handler:^(NSError *error) {
  408. if (error != nil) {
  409. XCTFail(@"Failed to wait for expectations "
  410. @"in Signing in with Google. Error: %@",
  411. error.localizedDescription);
  412. }
  413. }];
  414. XCTAssertEqualObjects(auth.currentUser.displayName, kGoogleTestAccountName);
  415. // Clean up the created Firebase/Facebook user for future runs.
  416. [self deleteCurrentFirebaseUser];
  417. }
  418. #pragma mark - Helpers
  419. /** Generate fake random email address */
  420. - (NSString *)fakeRandomEmail {
  421. NSMutableString *fakeEmail = [[NSMutableString alloc] init];
  422. for (int i=0; i<10; i++) {
  423. [fakeEmail appendString:
  424. [NSString stringWithFormat:@"%c", 'a' + arc4random_uniform('z' - 'a' + 1)]];
  425. }
  426. [fakeEmail appendString:@"@gmail.com"];
  427. return fakeEmail;
  428. }
  429. /** Sign out current account. */
  430. - (void)signOut {
  431. NSError *signOutError;
  432. BOOL status = [[FIRAuth auth] signOut:&signOutError];
  433. // Just log the error because we don't want to fail the test if signing out
  434. // fails.
  435. if (!status) {
  436. NSLog(@"Error signing out: %@", signOutError);
  437. }
  438. }
  439. /** Creates a Facebook testing account using Facebook Graph API and return a dictionary that
  440. * constains "id", "access_token", "login_url", "email" and "password" of the created account.
  441. */
  442. - (NSDictionary *)createFacebookTestingAccount {
  443. // Build the URL.
  444. NSString *urltoCreateTestUser =
  445. [NSString stringWithFormat:@"https://%@/%@/accounts/test-users", kFacebookGraphApiAuthority,
  446. kFacebookAppID];
  447. // Build the POST request.
  448. NSString *bodyString =
  449. [NSString stringWithFormat:@"installed=true&name=%@&permissions=read_stream&access_token=%@",
  450. kFacebookTestAccountName, kFacebookAppAccessToken];
  451. NSData *postData = [bodyString dataUsingEncoding:NSUTF8StringEncoding];
  452. GTMSessionFetcherService *service = [[GTMSessionFetcherService alloc] init];
  453. GTMSessionFetcher *fetcher = [service fetcherWithURLString:urltoCreateTestUser];
  454. fetcher.bodyData = postData;
  455. [fetcher setRequestValue:@"text/plain" forHTTPHeaderField:@"Content-Type"];
  456. XCTestExpectation *expectation =
  457. [self expectationWithDescription:@"Creating Facebook account finished."];
  458. __block NSData *data = nil;
  459. [fetcher beginFetchWithCompletionHandler:^(NSData *receivedData, NSError *error) {
  460. if (error) {
  461. NSLog(@"Creating Facebook account finished with error: %@", error);
  462. return;
  463. }
  464. data = receivedData;
  465. [expectation fulfill];
  466. }];
  467. [self waitForExpectationsWithTimeout:kExpectationsTimeout
  468. handler:^(NSError *error) {
  469. if (error != nil) {
  470. XCTFail(@"Failed to wait for expectations "
  471. @"in creating Facebook account. Error: %@",
  472. error.localizedDescription);
  473. }
  474. }];
  475. NSString *userInfo = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
  476. NSLog(@"The info of created Facebook testing account is: %@", userInfo);
  477. // Parses the access token from the JSON data.
  478. NSDictionary *userInfoDict =
  479. [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:nil];
  480. return userInfoDict;
  481. }
  482. /** Clean up the created user for tests' future runs. */
  483. - (void)deleteCurrentFirebaseUser {
  484. FIRAuth *auth = [FIRAuth auth];
  485. if (!auth) {
  486. NSLog(@"Could not obtain auth object.");
  487. }
  488. XCTestExpectation *expectation =
  489. [self expectationWithDescription:@"Delete current user finished."];
  490. [auth.currentUser deleteWithCompletion:^(NSError *_Nullable error) {
  491. if (error) {
  492. XCTFail(@"Failed to delete user. Error: %@.", error);
  493. }
  494. [expectation fulfill];
  495. }];
  496. [self waitForExpectationsWithTimeout:kExpectationsTimeout
  497. handler:^(NSError *error) {
  498. if (error != nil) {
  499. XCTFail(@"Failed to wait for expectations "
  500. @"in deleting user. Error: %@",
  501. error.localizedDescription);
  502. }
  503. }];
  504. }
  505. - (void)signInAnonymously {
  506. FIRAuth *auth = [FIRAuth auth];
  507. if (!auth) {
  508. XCTFail(@"Could not obtain auth object.");
  509. }
  510. XCTestExpectation *expectation =
  511. [self expectationWithDescription:@"Anonymousy sign-in finished."];
  512. [auth signInAnonymouslyWithCompletion:^(FIRAuthDataResult *result, NSError *error) {
  513. if (error) {
  514. NSLog(@"Anonymousy sign in error: %@", error);
  515. }
  516. [expectation fulfill];
  517. }];
  518. [self waitForExpectationsWithTimeout:kExpectationsTimeout
  519. handler:^(NSError *error) {
  520. if (error != nil) {
  521. XCTFail(@"Failed to wait for expectations "
  522. @"in anonymousy sign in. Error: %@",
  523. error.localizedDescription);
  524. }
  525. }];
  526. }
  527. /** Delete a Facebook testing account by account Id using Facebook Graph API. */
  528. - (void)deleteFacebookTestingAccountbyId:(NSString *)accountId {
  529. // Build the URL.
  530. NSString *urltoDeleteTestUser =
  531. [NSString stringWithFormat:@"https://%@/%@", kFacebookGraphApiAuthority, accountId];
  532. // Build the POST request.
  533. NSString *bodyString =
  534. [NSString stringWithFormat:@"method=delete&access_token=%@", kFacebookAppAccessToken];
  535. NSData *postData = [bodyString dataUsingEncoding:NSUTF8StringEncoding];
  536. GTMSessionFetcherService *service = [[GTMSessionFetcherService alloc] init];
  537. GTMSessionFetcher *fetcher = [service fetcherWithURLString:urltoDeleteTestUser];
  538. fetcher.bodyData = postData;
  539. [fetcher setRequestValue:@"text/plain" forHTTPHeaderField:@"Content-Type"];
  540. XCTestExpectation *expectation =
  541. [self expectationWithDescription:@"Deleting Facebook account finished."];
  542. [fetcher beginFetchWithCompletionHandler:^(NSData *receivedData, NSError *error) {
  543. NSString *deleteResult =
  544. [[NSString alloc] initWithData:receivedData encoding:NSUTF8StringEncoding];
  545. NSLog(@"The result of deleting Facebook account is: %@", deleteResult);
  546. if (error) {
  547. NSLog(@"Deleting Facebook account finished with error: %@", error);
  548. }
  549. [expectation fulfill];
  550. }];
  551. [self waitForExpectationsWithTimeout:kExpectationsTimeout
  552. handler:^(NSError *error) {
  553. if (error != nil) {
  554. XCTFail(@"Failed to wait for expectations "
  555. @"in deleting Facebook account. Error: %@",
  556. error.localizedDescription);
  557. }
  558. }];
  559. }
  560. /** Sends http request to Google OAuth2 token server to use refresh token to exchange for Google
  561. * access token. Returns a dictionary that constains "access_token", "token_type", "expires_in" and
  562. * "id_token".
  563. */
  564. - (NSDictionary *)getGoogleAccessToken {
  565. NSString *googleOauth2TokenServerUrl = @"https://www.googleapis.com/oauth2/v4/token";
  566. NSString *bodyString =
  567. [NSString stringWithFormat:@"client_id=%@&grant_type=refresh_token&refresh_token=%@",
  568. kGoogleCliendId, kGoogleTestAccountRefreshToken];
  569. NSData *postData = [bodyString dataUsingEncoding:NSUTF8StringEncoding];
  570. GTMSessionFetcherService *service = [[GTMSessionFetcherService alloc] init];
  571. GTMSessionFetcher *fetcher = [service fetcherWithURLString:googleOauth2TokenServerUrl];
  572. fetcher.bodyData = postData;
  573. [fetcher setRequestValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-Type"];
  574. XCTestExpectation *expectation =
  575. [self expectationWithDescription:@"Exchanging Google account tokens finished."];
  576. __block NSData *data = nil;
  577. [fetcher beginFetchWithCompletionHandler:^(NSData *receivedData, NSError *error) {
  578. if (error) {
  579. NSLog(@"Exchanging Google account tokens finished with error: %@", error);
  580. return;
  581. }
  582. data = receivedData;
  583. [expectation fulfill];
  584. }];
  585. [self waitForExpectationsWithTimeout:kExpectationsTimeout
  586. handler:^(NSError *error) {
  587. if (error != nil) {
  588. XCTFail(@"Failed to wait for expectations "
  589. @"in exchanging Google account tokens. Error: %@",
  590. error.localizedDescription);
  591. }
  592. }];
  593. NSString *userInfo = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
  594. NSLog(@"The info of exchanged result is: %@", userInfo);
  595. NSDictionary *userInfoDict =
  596. [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:nil];
  597. return userInfoDict;
  598. }
  599. @end