MainViewController+AutoTests.m 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500
  1. /*
  2. * Copyright 2019 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 "MainViewController+AutoTests.h"
  17. #import "AppManager.h"
  18. #import "AuthProviders.h"
  19. #import "MainViewController+Internal.h"
  20. #import "MainViewController+GameCenter.h"
  21. #import "MainViewController+Phone.h"
  22. #import "MainViewController+User.h"
  23. #import "MainViewController+OOB.h"
  24. #import "MainViewController+App.h"
  25. #import "MainViewController+Email.h"
  26. #import "MainViewController+Google.h"
  27. #import "MainViewController+Facebook.h"
  28. #import "MainViewController+Auth.h"
  29. #import "MainViewController+OAuth.h"
  30. #import "MainViewController+Custom.h"
  31. #import "MainViewController+AutoTests.h"
  32. NS_ASSUME_NONNULL_BEGIN
  33. static NSString *const kCustomTokenUrl = @"https://fb-sa-1211.appspot.com/token";
  34. static NSString *const kExpiredCustomTokenUrl = @"https://fb-sa-1211.appspot.com/expired_token";
  35. static NSString *const kInvalidCustomToken = @"invalid custom token.";
  36. static NSString *const kSafariGoogleSignOutMessagePrompt = @"This automated test assumes that no "
  37. "Google account is signed in on Safari, if your are not prompted for a password, sign out on "
  38. "Safari and rerun the test.";
  39. static NSString *const kSafariFacebookSignOutMessagePrompt = @"This automated test assumes that no "
  40. "Facebook account is signed in on Safari, if your are not prompted for a password, sign out on "
  41. "Safari and rerun the test.";
  42. static NSString *const kUnlinkAccountMessagePrompt = @"Sign into gmail with an email address "
  43. "that has not been linked to this sample application before. Delete account if necessary.";
  44. static NSString *const kFakeDisplayPhotoUrl =
  45. @"https://www.gstatic.com/images/branding/product/1x/play_apps_48dp.png";
  46. static NSString *const kFakeDisplayName = @"John GoogleSpeed";
  47. static NSString *const kFakeEmail = @"firemail@example.com";
  48. static NSString *const kFakePassword = @"fakePassword";
  49. @implementation MainViewController (AutoTests)
  50. - (StaticContentTableViewSection *)autoTestsSection {
  51. __weak typeof(self) weakSelf = self;
  52. return [StaticContentTableViewSection sectionWithTitle:@"Automated Tests" cells:@[
  53. [StaticContentTableViewCell cellWithTitle:@"BYOAuth"
  54. action:^{ [weakSelf automatedBYOAuth]; }],
  55. [StaticContentTableViewCell cellWithTitle:@"Sign In With Google"
  56. action:^{ [weakSelf automatedSignInGoogle]; }],
  57. [StaticContentTableViewCell cellWithTitle:@"Sign In With Facebook"
  58. action:^{ [weakSelf automatedSignInFacebook]; }],
  59. [StaticContentTableViewCell cellWithTitle:@"Sign Up With Email/Password"
  60. action:^{ [weakSelf automatedEmailSignUp]; }],
  61. [StaticContentTableViewCell cellWithTitle:@"Sign In Anonymously"
  62. action:^{ [weakSelf automatedAnonymousSignIn]; }],
  63. [StaticContentTableViewCell cellWithTitle:@"Link with Google"
  64. action:^{ [weakSelf automatedAccountLinking]; }],
  65. [StaticContentTableViewCell cellWithTitle:@"Sign in With Phone Number"
  66. action:^{ [weakSelf automatedPhoneNumberSignIn]; }]
  67. ]];
  68. }
  69. - (void)automatedBYOAuth {
  70. [self log:@"INITIATING AUTOMATED MANUAL TEST FOR BYOAUTH:"];
  71. [self showSpinner:^{
  72. NSError *error;
  73. NSString *customToken = [NSString stringWithContentsOfURL:[NSURL URLWithString:kCustomTokenUrl]
  74. encoding:NSUTF8StringEncoding
  75. error:&error];
  76. NSString *expiredCustomToken =
  77. [NSString stringWithContentsOfURL:[NSURL URLWithString:kExpiredCustomTokenUrl]
  78. encoding:NSUTF8StringEncoding
  79. error:&error];
  80. [self hideSpinner:^{
  81. if (error) {
  82. [self log:@"There was an error retrieving the custom token."];
  83. return;
  84. }
  85. FIRAuth *auth = [AppManager auth];
  86. [auth signInWithCustomToken:customToken
  87. completion:^(FIRAuthDataResult *_Nullable result, NSError *_Nullable error) {
  88. if (error) {
  89. [self logFailure:@"sign-in with custom token failed" error:error];
  90. [self logFailedTest:@"A fresh custom token should succeed in signing-in."];
  91. return;
  92. }
  93. [self logSuccess:@"sign-in with custom token succeeded."];
  94. [auth.currentUser getIDTokenForcingRefresh:NO
  95. completion:^(NSString *_Nullable token,
  96. NSError *_Nullable error) {
  97. if (error) {
  98. [self logFailure:@"refresh token failed" error:error];
  99. [self logFailedTest:@"Refresh token should be available."];
  100. return;
  101. }
  102. [self logSuccess:@"refresh token succeeded."];
  103. [auth signOut:NULL];
  104. [auth signInWithCustomToken:expiredCustomToken
  105. completion:^(FIRAuthDataResult *_Nullable result,
  106. NSError *_Nullable error) {
  107. if (!error) {
  108. [self logSuccess:@"sign-in with custom token succeeded."];
  109. [self logFailedTest:@"sign-in with an expired custom token should NOT succeed."];
  110. return;
  111. }
  112. [self logFailure:@"sign-in with custom token failed" error:error];
  113. [auth signInWithCustomToken:kInvalidCustomToken
  114. completion:^(FIRAuthDataResult *_Nullable result,
  115. NSError *_Nullable error) {
  116. if (!error) {
  117. [self logSuccess:@"sign-in with custom token succeeded."];
  118. [self logFailedTest:@"sign-in with an invalid custom token should NOT succeed."];
  119. return;
  120. }
  121. [self logFailure:@"sign-in with custom token failed" error:error];
  122. //next step of automated test.
  123. [self automatedBYOAuthEmailPassword];
  124. }];
  125. }];
  126. }];
  127. }];
  128. }];
  129. }];
  130. }
  131. - (void)automatedSignInGoogle {
  132. [self showMessagePromptWithTitle:@"Sign In With Google"
  133. message:kSafariGoogleSignOutMessagePrompt
  134. showCancelButton:NO
  135. completion:^(BOOL userPressedOK, NSString *_Nullable userInput) {
  136. FIRAuth *auth = [AppManager auth];
  137. if (!auth) {
  138. [self logFailedTest:@"Could not obtain auth object."];
  139. return;
  140. }
  141. [auth signOut:NULL];
  142. [self log:@"INITIATING AUTOMATED MANUAL TEST FOR GOOGLE SIGN IN:"];
  143. [self signInWithProvider:[AuthProviders google] callback:^{
  144. [self logSuccess:@"sign-in with Google provider succeeded."];
  145. [auth signOut:NULL];
  146. [self signInWithProvider:[AuthProviders google] callback:^{
  147. [self logSuccess:@"sign-in with Google provider succeeded."];
  148. [self updateEmailPasswordWithCompletion:^{
  149. [self automatedSignInGoogleDisplayNamePhotoURL];
  150. }];
  151. }];
  152. }];
  153. }];
  154. }
  155. - (void)automatedSignInGoogleDisplayNamePhotoURL {
  156. [self signInWithProvider:[AuthProviders google] callback:^{
  157. [self updateDisplayNameAndPhotoURlWithCompletion:^{
  158. [self log:@"FINISHED AUTOMATED MANUAL TEST FOR SIGN-IN WITH GOOGlE."];
  159. [self reloadUser];
  160. }];
  161. }];
  162. }
  163. - (void)automatedSignInFacebook {
  164. [self showMessagePromptWithTitle:@"Sign In With Facebook"
  165. message:kSafariFacebookSignOutMessagePrompt
  166. showCancelButton:NO
  167. completion:^(BOOL userPressedOK, NSString *_Nullable userInput) {
  168. FIRAuth *auth = [AppManager auth];
  169. if (!auth) {
  170. [self logFailedTest:@"Could not obtain auth object."];
  171. return;
  172. }
  173. [auth signOut:NULL];
  174. [self log:@"INITIATING AUTOMATED MANUAL TEST FOR FACEBOOK SIGN IN:"];
  175. [self signInWithProvider:[AuthProviders facebook] callback:^{
  176. [self logSuccess:@"sign-in with Facebook provider succeeded."];
  177. [auth signOut:NULL];
  178. [self signInWithProvider:[AuthProviders facebook] callback:^{
  179. [self logSuccess:@"sign-in with Facebook provider succeeded."];
  180. [self updateEmailPasswordWithCompletion:^{
  181. [self automatedSignInFacebookDisplayNamePhotoURL];
  182. }];
  183. }];
  184. }];
  185. }];
  186. }
  187. - (void)automatedPhoneNumberSignIn {
  188. [self log:@"Automated phone number sign in"];
  189. FIRAuth *auth = [AppManager auth];
  190. if (!auth) {
  191. [self logFailedTest:@"Could not obtain auth object."];
  192. return;
  193. }
  194. [auth signOut:NULL];
  195. [self log:@"INITIATING AUTOMATED MANUAL TEST FOR PHONE NUMBER SIGN IN:"];
  196. [self commonPhoneNumberInputWithTitle:@"Phone for automation"
  197. completion:^(NSString *_Nullable phone) {
  198. [self signInWithPhoneNumber:phone completion:^(NSError *error) {
  199. if (error) {
  200. [self logFailedTest:@"Could not sign in with phone number reCAPTCHA."];
  201. }
  202. [self logSuccess:@"sign-in with phone number reCAPTCHA test succeeded."];
  203. [auth signOut:NULL];
  204. [self signInWithPhoneNumber:phone completion:^(NSError *error) {
  205. if (error) {
  206. [self logFailedTest:@"Could not sign in with phone number reCAPTCHA."];
  207. }
  208. [self logSuccess:@"second sign-in with phone number reCAPTCHA test succeeded."];
  209. [self updatePhoneNumber:phone completion:^(NSError *error) {
  210. if (error) {
  211. [self logFailedTest:@"Could not update phone number."];
  212. }
  213. [self logSuccess:@"update phone number test succeeded."];
  214. [self unlinkFromProvider:FIRPhoneAuthProviderID completion:^(NSError *error) {
  215. if (error) {
  216. [self logFailedTest:@"Could not unlink phone number."];
  217. }
  218. [self logSuccess:@"unlink phone number test succeeded."];
  219. [self linkPhoneNumber:phone completion:^(NSError *error) {
  220. if (error) {
  221. [self logFailedTest:@"Could not link phone number."];
  222. }
  223. [self logSuccess:@"link phone number test succeeded."];
  224. [self log:@"FINISHED AUTOMATED MANUAL TEST FOR PHONE NUMBER SIGN IN."];
  225. }];
  226. }];
  227. }];
  228. }];
  229. }];
  230. }];
  231. }
  232. - (void)automatedEmailSignUp {
  233. [self log:@"INITIATING AUTOMATED MANUAL TEST FOR FACEBOOK SIGN IN:"];
  234. FIRAuth *auth = [AppManager auth];
  235. if (!auth) {
  236. [self logFailedTest:@"Could not obtain auth object."];
  237. return;
  238. }
  239. [self signUpNewEmail:kFakeEmail password:kFakePassword callback:^(FIRUser *_Nullable user,
  240. NSError *_Nullable error) {
  241. if (error) {
  242. [self logFailedTest: @" Email/Password Account account creation failed"];
  243. return;
  244. }
  245. [auth signOut:NULL];
  246. FIRAuthCredential *credential = [FIREmailAuthProvider credentialWithEmail:kFakeEmail
  247. password:kFakePassword];
  248. [auth signInWithCredential:credential
  249. completion:^(FIRAuthDataResult *_Nullable result,
  250. NSError *_Nullable error) {
  251. if (error) {
  252. [self logFailure:@"sign-in with Email/Password failed" error:error];
  253. [self logFailedTest:@"sign-in with Email/Password should succeed."];
  254. return;
  255. }
  256. [self logSuccess:@"sign-in with Email/Password succeeded."];
  257. [self log:@"FINISHED AUTOMATED MANUAL TEST FOR SIGN-IN WITH EMAIL/PASSWORD."];
  258. // Delete the user so that we can reuse the fake email address for subsequent tests.
  259. [auth.currentUser deleteWithCompletion:^(NSError *_Nullable error) {
  260. if (error) {
  261. [self logFailure:@"Failed to delete user" error:error];
  262. [self logFailedTest:@"Deleting a user that was recently signed-in should succeed."];
  263. return;
  264. }
  265. [self logSuccess:@"User deleted."];
  266. }];
  267. }];
  268. }];
  269. }
  270. - (void)automatedAnonymousSignIn {
  271. [self log:@"INITIATING AUTOMATED MANUAL TEST FOR ANONYMOUS SIGN IN:"];
  272. FIRAuth *auth = [AppManager auth];
  273. if (!auth) {
  274. [self logFailedTest:@"Could not obtain auth object."];
  275. return;
  276. }
  277. [auth signOut:NULL];
  278. [self signInAnonymouslyWithCallback:^(FIRAuthDataResult *_Nullable result,
  279. NSError *_Nullable error) {
  280. if (result.user) {
  281. NSString *anonymousUID = result.user.uid;
  282. [self signInAnonymouslyWithCallback:^(FIRAuthDataResult *_Nullable user,
  283. NSError *_Nullable error) {
  284. if (![result.user.uid isEqual:anonymousUID]) {
  285. [self logFailedTest:@"Consecutive anonymous sign-ins should yeild the same User ID"];
  286. return;
  287. }
  288. [self log:@"FINISHED AUTOMATED MANUAL TEST FOR ANONYMOUS SIGN IN."];
  289. }];
  290. }
  291. }];
  292. }
  293. - (void)automatedBYOAuthEmailPassword {
  294. [self showSpinner:^{
  295. NSError *error;
  296. NSString *customToken = [NSString stringWithContentsOfURL:[NSURL URLWithString:kCustomTokenUrl]
  297. encoding:NSUTF8StringEncoding
  298. error:&error];
  299. [self hideSpinner:^{
  300. if (error) {
  301. [self log:@"There was an error retrieving the custom token."];
  302. return;
  303. }
  304. [[AppManager auth] signInWithCustomToken:customToken
  305. completion:^(FIRAuthDataResult *_Nullable user,
  306. NSError *_Nullable error) {
  307. if (error) {
  308. [self logFailure:@"sign-in with custom token failed" error:error];
  309. [self logFailedTest:@"A fresh custom token should succeed in signing-in."];
  310. return;
  311. }
  312. [self logSuccess:@"sign-in with custom token succeeded."];
  313. [self updateEmailPasswordWithCompletion:^{
  314. [self automatedBYOAuthDisplayNameAndPhotoURl];
  315. }];
  316. }];
  317. }];
  318. }];
  319. }
  320. - (void)automatedBYOAuthDisplayNameAndPhotoURl {
  321. [self showSpinner:^{
  322. NSError *error;
  323. NSString *customToken = [NSString stringWithContentsOfURL:[NSURL URLWithString:kCustomTokenUrl]
  324. encoding:NSUTF8StringEncoding
  325. error:&error];
  326. [self hideSpinner:^{
  327. if (error) {
  328. [self log:@"There was an error retrieving the custom token."];
  329. return;
  330. }
  331. [[AppManager auth] signInWithCustomToken:customToken
  332. completion:^(FIRAuthDataResult *_Nullable result,
  333. NSError *_Nullable error) {
  334. if (error) {
  335. [self logFailure:@"sign-in with custom token failed" error:error];
  336. [self logFailedTest:@"A fresh custom token should succeed in signing-in."];
  337. return;
  338. }
  339. [self logSuccess:@"sign-in with custom token succeeded."];
  340. [self updateDisplayNameAndPhotoURlWithCompletion:^{
  341. [self log:@"FINISHED AUTOMATED MANUAL TEST FOR BYOAUTH."];
  342. [self reloadUser];
  343. }];
  344. }];
  345. }];
  346. }];
  347. }
  348. - (void)updateEmailPasswordWithCompletion:(void(^)(void))completion {
  349. FIRAuth *auth = [AppManager auth];
  350. [auth.currentUser updateEmail:kFakeEmail completion:^(NSError *_Nullable error) {
  351. if (error) {
  352. [self logFailure:@"update email failed" error:error];
  353. [self logFailedTest:@"Update email should succeed when properly signed-in."];
  354. return;
  355. }
  356. [self logSuccess:@"update email succeeded."];
  357. [auth.currentUser updatePassword:kFakePassword completion:^(NSError *_Nullable error) {
  358. if (error) {
  359. [self logFailure:@"update password failed" error:error];
  360. [self logFailedTest:@"Update password should succeed when properly signed-in."];
  361. return;
  362. }
  363. [self logSuccess:@"update password succeeded."];
  364. [auth signOut:NULL];
  365. FIRAuthCredential *credential =
  366. [FIREmailAuthProvider credentialWithEmail:kFakeEmail password:kFakePassword];
  367. [auth signInWithCredential:credential
  368. completion:^(FIRAuthDataResult *_Nullable result,
  369. NSError *_Nullable error) {
  370. if (error) {
  371. [self logFailure:@"sign-in with Email/Password failed" error:error];
  372. [self logFailedTest:@"sign-in with Email/Password should succeed."];
  373. return;
  374. }
  375. [self logSuccess:@"sign-in with Email/Password succeeded."];
  376. // Delete the user so that we can reuse the fake email address for subsequent tests.
  377. [auth.currentUser deleteWithCompletion:^(NSError *_Nullable error) {
  378. if (error) {
  379. [self logFailure:@"Failed to delete user." error:error];
  380. [self logFailedTest:@"Deleting a user that was recently signed-in should succeed"];
  381. return;
  382. }
  383. [self logSuccess:@"User deleted."];
  384. completion();
  385. }];
  386. }];
  387. }];
  388. }];
  389. }
  390. - (void)updateDisplayNameAndPhotoURlWithCompletion:(void(^)(void))completion {
  391. FIRAuth *auth = [AppManager auth];
  392. FIRUserProfileChangeRequest *changeRequest = [auth.currentUser profileChangeRequest];
  393. changeRequest.photoURL = [NSURL URLWithString:kFakeDisplayPhotoUrl];
  394. [changeRequest commitChangesWithCompletion:^(NSError *_Nullable error) {
  395. if (error) {
  396. [self logFailure:@"set photo URL failed" error:error];
  397. [self logFailedTest:@"Change photo Url should succeed when signed-in."];
  398. return;
  399. }
  400. [self logSuccess:@"set PhotoURL succeeded."];
  401. FIRUserProfileChangeRequest *changeRequest = [auth.currentUser profileChangeRequest];
  402. changeRequest.displayName = kFakeDisplayName;
  403. [changeRequest commitChangesWithCompletion:^(NSError *_Nullable error) {
  404. if (error) {
  405. [self logFailure:@"set display name failed" error:error];
  406. [self logFailedTest:@"Change display name should succeed when signed-in."];
  407. return;
  408. }
  409. [self logSuccess:@"set display name succeeded."];
  410. completion();
  411. }];
  412. }];
  413. }
  414. - (void)automatedSignInFacebookDisplayNamePhotoURL {
  415. [self signInWithProvider:[AuthProviders facebook] callback:^{
  416. [self updateDisplayNameAndPhotoURlWithCompletion:^{
  417. [self log:@"FINISHED AUTOMATED MANUAL TEST FOR SIGN-IN WITH FACEBOOK."];
  418. [self reloadUser];
  419. }];
  420. }];
  421. }
  422. - (void)automatedAccountLinking {
  423. [self log:@"INITIATING AUTOMATED MANUAL TEST FOR ACCOUNT LINKING:"];
  424. FIRAuth *auth = [AppManager auth];
  425. if (!auth) {
  426. [self logFailedTest:@"Could not obtain auth object."];
  427. return;
  428. }
  429. [auth signOut:NULL];
  430. [self signInAnonymouslyWithCallback:^(FIRAuthDataResult *_Nullable result,
  431. NSError *_Nullable error) {
  432. if (result.user) {
  433. NSString *anonymousUID = result.user.uid;
  434. [self showMessagePromptWithTitle:@"Sign In Instructions"
  435. message:kUnlinkAccountMessagePrompt
  436. showCancelButton:NO
  437. completion:^(BOOL userPressedOK, NSString *_Nullable userInput) {
  438. [[AuthProviders google]
  439. getAuthCredentialWithPresentingViewController:self
  440. callback:^(FIRAuthCredential *credential,
  441. NSError *error) {
  442. if (credential) {
  443. [result.user linkWithCredential:credential completion:^(FIRAuthDataResult *result,
  444. NSError *error) {
  445. FIRUser *user = result.user;
  446. if (error) {
  447. [self logFailure:@"link auth provider failed" error:error];
  448. [self logFailedTest:@"Account needs to be linked to complete the test."];
  449. return;
  450. }
  451. [self logSuccess:@"link auth provider succeeded."];
  452. if (user.isAnonymous) {
  453. [self logFailure:@"link auth provider failed, user still anonymous" error:error];
  454. [self logFailedTest:@"Account needs to be linked to complete the test."];
  455. }
  456. if (![user.uid isEqual:anonymousUID]){
  457. [self logFailedTest:@"link auth provider failed, UID's are different. Make sure "
  458. "you link an account that has NOT been Linked nor Signed-In before."];
  459. return;
  460. }
  461. [self log:@"FINISHED AUTOMATED MANUAL TEST FOR ACCOUNT LINKING."];
  462. }];
  463. }
  464. }];
  465. }];
  466. }
  467. }];
  468. }
  469. @end
  470. NS_ASSUME_NONNULL_END