From 66f177bcf03a34dadf72d21e341556b275bd9f00 Mon Sep 17 00:00:00 2001 From: YuryR Date: Wed, 12 Oct 2016 16:46:31 -0700 Subject: [PATCH] implement FirebaseUI UIAutomation tests --- FirebaseUISample/Base.lproj/Main.storyboard | 240 ++++++++++++++++-- FirebaseUISample/FIRViewController.h | 2 +- FirebaseUISample/FIRViewController.m | 238 ++++++++++++++--- .../FirebaseUISampleUITests.m | 70 ++++- 4 files changed, 489 insertions(+), 61 deletions(-) diff --git a/FirebaseUISample/Base.lproj/Main.storyboard b/FirebaseUISample/Base.lproj/Main.storyboard index 5dc4dfe2e96..4bb75bb4861 100644 --- a/FirebaseUISample/Base.lproj/Main.storyboard +++ b/FirebaseUISample/Base.lproj/Main.storyboard @@ -1,40 +1,232 @@ - + - - + + - - - - - - + + - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + + - - + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/FirebaseUISample/FIRViewController.h b/FirebaseUISample/FIRViewController.h index 8f22b767658..0acb42926d9 100644 --- a/FirebaseUISample/FIRViewController.h +++ b/FirebaseUISample/FIRViewController.h @@ -16,7 +16,7 @@ #import -@interface FIRViewController : UIViewController +@interface FIRViewController : UITableViewController @end diff --git a/FirebaseUISample/FIRViewController.m b/FirebaseUISample/FIRViewController.m index 4dcf01731b1..b26e432ed22 100644 --- a/FirebaseUISample/FIRViewController.m +++ b/FirebaseUISample/FIRViewController.m @@ -19,13 +19,39 @@ #import #import #import +#import +#import #import -@interface FIRViewController () -@property (weak, nonatomic) IBOutlet UIButton *btnAuthorization; +typedef enum : NSUInteger { + kSectionsSignedInAs = 0, + kSectionsSimulationBehavior, + kSectionsProviders +} UISections; + +typedef enum : NSUInteger { + kSimulationNoMocks = 0, + kSimulationExistingUser, + kSimulationNewUser, + kSimulationEmailRecovery, + kSimulationUnknown, +} FIRSimulationChoise; + +typedef enum : NSUInteger { + kIDPEmail = 0, + kIDPGoogle, + kIDPFacebook, + kIDPTwitter +} FIRProviders; + +@interface FIRViewController () +@property (weak, nonatomic) IBOutlet UIBarButtonItem *btnAuthorization; +@property (weak, nonatomic) IBOutlet UILabel *labelUserEmail; +@property (nonatomic, assign) FIRSimulationChoise selectedSimulationChoise; @property (nonatomic) id authMock; @property (nonatomic) id authUIMock; +@property (nonatomic) FIRAuthStateDidChangeListenerHandle authStateDidChangeHandle; @end @@ -34,48 +60,47 @@ @implementation FIRViewController - (void)viewDidLoad { [super viewDidLoad]; - self.authMock = OCMPartialMock([FIRAuth auth]); + [self.tableView selectRowAtIndexPath:[NSIndexPath indexPathForRow:kSimulationNoMocks + inSection:kSectionsSimulationBehavior] + animated:NO + scrollPosition:UITableViewScrollPositionNone]; - OCMStub(ClassMethod([self.authMock auth])).andReturn(self.authMock); + [self.tableView selectRowAtIndexPath:[NSIndexPath indexPathForRow:kIDPEmail + inSection:kSectionsProviders] + animated:NO + scrollPosition:UITableViewScrollPositionNone]; +} - NSArray> *providers = [NSArray arrayWithObjects: - [[FIRGoogleAuthUI alloc] init], - nil]; +- (IBAction)onAuthorization:(id)sender { + [self prepareStubs]; + UIViewController *controller = [self.authUIMock authViewController]; + [self presentViewController:controller animated:YES completion:nil]; +} - FIRAuthUI *authUI = [FIRAuthUI defaultAuthUI]; - authUI.providers = providers; - authUI.delegate = self; - self.authUIMock = OCMPartialMock(authUI); - OCMStub([self.authMock fetchProvidersForEmail:OCMOCK_ANY completion:OCMOCK_ANY]).andDo(^(NSInvocation *invocation) { - FIRProviderQueryCallback mockedResponse; - [invocation getArgument:&mockedResponse atIndex:3]; - mockedResponse(@[@"password"], nil); - }); -} +#pragma mark - UITableViewControllerDelegate methods -- (IBAction)onAuthorization:(id)sender { - if (![self.authMock currentUser]) { - UIViewController *controller = [self.authUIMock authViewController]; - [self presentViewController:controller animated:YES completion:nil]; - } else { - [self signOut]; +- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { + if (indexPath.section != kSectionsProviders) { + _selectedSimulationChoise = indexPath.row; + [self deselectAllCellsExcept:indexPath]; } } -- (void)signOut { - // sign out from Firebase - NSError *error; - [self.authUIMock signOutWithError:&error]; - if (error) { - [self showAlert:error.localizedDescription]; +- (void)deselectAllCellsExcept:(NSIndexPath *)indexPath { + + NSInteger count = [self tableView:self.tableView numberOfRowsInSection:indexPath.section]; + for (NSInteger index = 0; index < count; index++) { + if (index != indexPath.row) { + [self.tableView deselectRowAtIndexPath:[NSIndexPath indexPathForRow:index + inSection:indexPath.section] + animated:YES]; + } } - } #pragma mark - FIRAuthUIDelegate methods -// this method is called only when FIRAuthViewController is delgate of AuthUI - (void)authUI:(FIRAuthUI *)authUI didSignInWithUser:(nullable FIRUser *)user error:(nullable NSError *)error { if (error) { if (error.code == FIRAuthUIErrorCodeUserCancelledSignIn) { @@ -87,6 +112,10 @@ - (void)authUI:(FIRAuthUI *)authUI didSignInWithUser:(nullable FIRUser *)user er } [self showAlert:detailedError.localizedDescription]; } + } else { + _labelUserEmail.text = user.email; + [self.tableView reloadSections:[NSIndexSet indexSetWithIndex:kSectionsSignedInAs] + withRowAnimation:UITableViewRowAnimationNone]; } } @@ -103,4 +132,151 @@ - (void)showAlert:(NSString *)message { } +#pragma mark - helper methods + +- (void)prepareStubs { + + [self prepareStubsForTests]; + + switch (_selectedSimulationChoise) { + case kSimulationUnknown: + [self prepareGenuineExample]; + break; + case kSimulationExistingUser: + [self prepareStubsForSimulationExistingUser]; + break; + case kSimulationNewUser: + [self prepareStubsForSimulationNewUser]; + break; + case kSimulationEmailRecovery: + [self prepareStubsForEmailRecovery]; + break; + + default: + break; + } +} + +- (void)prepareGenuineExample { + self.authMock = [FIRAuth auth]; + self.authUIMock = [self configureFirAuthUI]; + +} + +- (void)prepareStubsForTests { + self.authMock = OCMPartialMock([FIRAuth auth]); + + OCMStub(ClassMethod([self.authMock auth])).andReturn(self.authMock); + + self.authUIMock = OCMPartialMock([self configureFirAuthUI]); +} + +- (void)prepareStubsForSimulationExistingUser { + OCMStub([self.authMock fetchProvidersForEmail:OCMOCK_ANY completion:OCMOCK_ANY]).andDo(^(NSInvocation *invocation) { + FIRProviderQueryCallback mockedCallback; + [invocation getArgument:&mockedCallback atIndex:3]; + mockedCallback(@[@"password"], nil); + }); + + + OCMStub([self.authMock signInWithEmail:OCMOCK_ANY password:OCMOCK_ANY completion:OCMOCK_ANY]).andDo(^(NSInvocation *invocation) { + FIRAuthResultCallback mockedResponse; + [invocation getArgument:&mockedResponse atIndex:4]; + + NSString *responseEmail; + [invocation getArgument:&responseEmail atIndex:2]; + + id mockUser = OCMClassMock([FIRUser class]); + OCMStub([mockUser email]).andReturn(responseEmail); + + mockedResponse(mockUser, nil); + }); +} + +- (void)prepareStubsForSimulationNewUser { + OCMStub([self.authMock fetchProvidersForEmail:OCMOCK_ANY completion:OCMOCK_ANY]).andDo(^(NSInvocation *invocation) { + FIRProviderQueryCallback mockedResponse; + [invocation getArgument:&mockedResponse atIndex:3]; + mockedResponse(nil, nil); + }); + + + OCMStub([self.authMock createUserWithEmail:OCMOCK_ANY password:OCMOCK_ANY completion:OCMOCK_ANY]).andDo(^(NSInvocation *invocation) { + FIRAuthResultCallback mockedCallback; + [invocation getArgument:&mockedCallback atIndex:4]; + + NSString *responseEmail; + [invocation getArgument:&responseEmail atIndex:2]; + + id mockUser = OCMClassMock([FIRUser class]); + id mockRequest = OCMClassMock([FIRUserProfileChangeRequest class]); + OCMStub([mockUser email]).andReturn(responseEmail); + OCMStub([mockUser profileChangeRequest]).andReturn(mockRequest); + OCMStub([mockRequest commitChangesWithCompletion:OCMOCK_ANY]).andDo(^(NSInvocation *invocation) { + FIRUserProfileChangeCallback mockedCallBack; + [invocation getArgument:&mockedCallBack atIndex:2]; + mockedCallBack(nil); + }); + + + mockedCallback(mockUser, nil); + }); + +} + +- (void)prepareStubsForEmailRecovery { + OCMStub([self.authMock fetchProvidersForEmail:OCMOCK_ANY completion:OCMOCK_ANY]).andDo(^(NSInvocation *invocation) { + FIRProviderQueryCallback mockedCallback; + [invocation getArgument:&mockedCallback atIndex:3]; + mockedCallback(@[@"password"], nil); + }); + + OCMStub([self.authMock sendPasswordResetWithEmail:OCMOCK_ANY completion:OCMOCK_ANY]).andDo(^(NSInvocation *invocation) { + FIRSendPasswordResetCallback mockedCallback; + [invocation getArgument:&mockedCallback atIndex:3]; + mockedCallback(nil); + }); + +} + +- (NSArray *)getListOfIDPs { + NSArray *selectedRows = [self.tableView indexPathsForSelectedRows]; + NSMutableArray *providers = [NSMutableArray new]; + + for (NSIndexPath *indexPath in selectedRows) { + if (indexPath.section == kSectionsProviders) { + switch (indexPath.row) { + case kIDPGoogle: + [providers addObject:[[FIRGoogleAuthUI alloc] init]]; + break; + case kIDPFacebook: + [providers addObject:[[FIRFacebookAuthUI alloc] init]]; + break; + case kIDPTwitter: + [providers addObject:[[FIRTwitterAuthUI alloc] init]]; + break; + + default: + break; + } + } + } + + return providers; +} + +- (BOOL)isEmailEnabled { + NSArray *selectedRows = [self.tableView indexPathsForSelectedRows]; + return [selectedRows containsObject:[NSIndexPath + indexPathForRow:kIDPEmail + inSection:kSectionsProviders]]; +} + +- (FIRAuthUI *)configureFirAuthUI { + FIRAuthUI *authUI = [FIRAuthUI defaultAuthUI]; + authUI.providers = [self getListOfIDPs]; + authUI.signInWithEmailHidden = ![self isEmailEnabled]; + authUI.delegate = self; + return authUI; +} @end diff --git a/FirebaseUISampleUITests/FirebaseUISampleUITests.m b/FirebaseUISampleUITests/FirebaseUISampleUITests.m index 4a40a1285c6..4ab3b147166 100644 --- a/FirebaseUISampleUITests/FirebaseUISampleUITests.m +++ b/FirebaseUISampleUITests/FirebaseUISampleUITests.m @@ -28,23 +28,83 @@ - (void)setUp { [[[XCUIApplication alloc] init] launch]; } -- (void)testEmailProviderEnterEmail { +- (void)testSuccesSignIn { XCUIApplication *app = [[XCUIApplication alloc] init]; - [app.buttons[@"Sign In"] tap]; - [app.buttons[@"EmailButtonAccessibilityID"] tap]; + XCUIElementQuery *tablesQuery = app.tables; + [tablesQuery.cells.staticTexts[@"Simulate Existing User"] tap]; + [app.toolbars.buttons[@"Sign In"] tap]; + [tablesQuery.cells[@"EmailCellAccessibilityID"].textFields[@"Enter your email"] tap]; + [[tablesQuery.cells[@"EmailCellAccessibilityID"] childrenMatchingType:XCUIElementTypeTextField].element typeText:@"test@test.com"]; + [app.navigationBars[@"Sign in with email"].buttons[@"NextButtonAccessibilityID"] tap]; + [tablesQuery.secureTextFields[@"Enter your password"] tap]; + [[[tablesQuery.cells containingType:XCUIElementTypeStaticText identifier:@"Password"] childrenMatchingType:XCUIElementTypeSecureTextField].element typeText:@"test"]; + [app.navigationBars[@"Sign in"].buttons[@"Sign in"] tap]; +} + +- (void)testSuccesSignUp { + XCUIApplication *app = [[XCUIApplication alloc] init]; + XCUIElementQuery *tablesQuery = app.tables; + [tablesQuery.staticTexts[@"Simulate New User"] tap]; + [app.toolbars.buttons[@"Sign In"] tap]; + [tablesQuery.cells[@"EmailCellAccessibilityID"].textFields[@"Enter your email"] tap]; + [[tablesQuery.cells[@"EmailCellAccessibilityID"] childrenMatchingType:XCUIElementTypeTextField].element typeText:@"test2@test2.com"]; + [app.navigationBars[@"Sign in with email"].buttons[@"NextButtonAccessibilityID"] tap]; + [tablesQuery.cells[@"NameSignUpCellAccessibilityID"].textFields[@"First & last name"] tap]; + [[tablesQuery.cells[@"NameSignUpCellAccessibilityID"] childrenMatchingType:XCUIElementTypeTextField].element typeText:@"test2"]; + + [tablesQuery.cells[@"PasswordSignUpCellAccessibilityID"].secureTextFields[@"Choose password"] tap]; + [[tablesQuery.secureTextFields containingType:XCUIElementTypeButton identifier:@"ic visibility"].element typeText:@"test"]; + [tablesQuery.buttons[@"ic visibility"] tap]; + [tablesQuery.buttons[@"ic visibility off"] tap]; + [app.navigationBars[@"Create account"].buttons[@"NextButtonAccessibilityID"] tap]; +} + +- (void)testSeveralIDPs { + + XCUIApplication *app = [[XCUIApplication alloc] init]; XCUIElementQuery *tablesQuery = app.tables; + [tablesQuery.cells.staticTexts[@"Google"] tap]; + [tablesQuery.cells.staticTexts[@"Simulate Existing User"] tap]; + [app.toolbars.buttons[@"Sign In"] tap]; + [app.buttons[@"EmailButtonAccessibilityID"] tap]; [tablesQuery.cells[@"EmailCellAccessibilityID"].textFields[@"Enter your email"] tap]; [[tablesQuery.cells[@"EmailCellAccessibilityID"] childrenMatchingType:XCUIElementTypeTextField].element typeText:@"test@test.com"]; XCUIElement *signInWithEmailNavigationBar = app.navigationBars[@"Sign in with email"]; [signInWithEmailNavigationBar.buttons[@"NextButtonAccessibilityID"] tap]; - [tablesQuery.buttons[@"Trouble signing in?"] tap]; - [[[[app.navigationBars[@"Recover password"] childrenMatchingType:XCUIElementTypeButton] matchingIdentifier:@"Back"] elementBoundByIndex:0] tap]; [[[[app.navigationBars[@"Sign in"] childrenMatchingType:XCUIElementTypeButton] matchingIdentifier:@"Back"] elementBoundByIndex:0] tap]; [[[[signInWithEmailNavigationBar childrenMatchingType:XCUIElementTypeButton] matchingIdentifier:@"Back"] elementBoundByIndex:0] tap]; [app.navigationBars[@"Welcome"].buttons[@"Cancel"] tap]; [app.alerts[@"Error"].buttons[@"Close"] tap]; } +- (void)testEmailRecovery { + + XCUIApplication *app = [[XCUIApplication alloc] init]; + XCUIElementQuery *tablesQuery = app.tables; + [tablesQuery.cells.staticTexts[@"Simulate Email Recovery"] tap]; + [app.toolbars.buttons[@"Sign In"] tap]; + + XCUIElement *enterYourEmailTextField = tablesQuery.cells[@"EmailCellAccessibilityID"].textFields[@"Enter your email"]; + [enterYourEmailTextField tap]; + [enterYourEmailTextField tap]; + [[tablesQuery.cells[@"EmailCellAccessibilityID"] childrenMatchingType:XCUIElementTypeTextField].element typeText:@"test@test.com"]; + + XCUIElement *signInWithEmailNavigationBar = app.navigationBars[@"Sign in with email"]; + [signInWithEmailNavigationBar.buttons[@"NextButtonAccessibilityID"] tap]; + [tablesQuery.secureTextFields[@"Enter your password"] tap]; + [tablesQuery.buttons[@"Trouble signing in?"] tap]; + + XCUIElement *recoverPasswordNavigationBar = app.navigationBars[@"Recover password"]; + [recoverPasswordNavigationBar.buttons[@"Send"] tap]; + XCUIElement *okButton = app.alerts.buttons[@"OK"]; + [okButton tap]; + [[[[recoverPasswordNavigationBar childrenMatchingType:XCUIElementTypeButton] matchingIdentifier:@"Back"] elementBoundByIndex:0] tap]; + [[[[app.navigationBars[@"Sign in"] childrenMatchingType:XCUIElementTypeButton] matchingIdentifier:@"Back"] elementBoundByIndex:0] tap]; + [signInWithEmailNavigationBar.buttons[@"Cancel"] tap]; + [app.alerts[@"Error"].buttons[@"Close"] tap]; + +} + @end