Преглед на файлове

Update UI tests to detect first or existing sign in

Matthew Mathias преди 3 години
родител
ревизия
f8d2513c76

+ 2 - 0
Samples/Swift/DaysUntilBirthday/DaysUntilBirthdayUITests(iOS)/Credential.swift

@@ -16,6 +16,8 @@
 
 import Foundation
 
+/// An enumeration helping to interact with the configuration file containing
+/// the email and password secrets used for testing the Google sign-in flow.
 enum Credential: String {
   static let bundle: Bundle? = Bundle(identifier: "com.google.DaysUntilBirthdayUITests-iOS-")
   private var emailKey: String { return "EMAIL_SECRET" }

+ 150 - 40
Samples/Swift/DaysUntilBirthday/DaysUntilBirthdayUITests(iOS)/DaysUntilBirthdayUITests_iOS_.swift

@@ -20,40 +20,115 @@ class DaysUntilBirthdayUITests_iOS_: XCTestCase {
   private let signInStaticText =
     "“DaysUntilBirthday(iOS)” Wants to Use “google.com” to Sign In"
   private let timeout: TimeInterval = 5
+
   private let sampleApp = XCUIApplication()
   private let springboardApp = XCUIApplication(
     bundleIdentifier: "com.apple.springboard"
   )
 
-  func testSwiftUIButtonTapStartsFlowForFirstSignIn() {
+  func testSignInNavigateToDaysUntilBirthdayAndDisconnect() {
     sampleApp.launch()
+
+    XCTAssertTrue(signIn())
+    XCTAssertTrue(navigateToDaysUntilBirthday())
+    XCTAssertTrue(navigateBackToUserProfileView())
+
+    // Disconnect so the next test run works as if it is the first time
+    sampleApp.navigationBars.buttons["Disconnect"].tap()
+
+    guard sampleApp
+            .buttons["GoogleSignInButton"]
+            .waitForExistence(timeout: timeout) else {
+      return XCTFail("Disconnecting should return user to sign in view")
+    }
+  }
+
+  func testSignInAndSignOut() {
+    sampleApp.launch()
+    XCTAssertTrue(signIn())
+
+    guard sampleApp
+            .navigationBars
+            .buttons["Sign Out"]
+            .waitForExistence(timeout: timeout) else {
+      return XCTFail("Failed to find the 'Disconnect' button")
+    }
+    sampleApp.buttons["Sign Out"].tap()
+
+    guard sampleApp
+            .buttons["GoogleSignInButton"]
+            .waitForExistence(timeout: timeout) else {
+      return XCTFail("Signing out should return user to sign in view")
+    }
+  }
+}
+
+extension DaysUntilBirthdayUITests_iOS_ {
+  /// Performs a sign in.
+  /// - returns: `true` if the sign in was succesfull.
+  func signIn() -> Bool {
     let signInButton = sampleApp.buttons["GoogleSignInButton"]
-    XCTAssertTrue(signInButton.exists)
+    guard signInButton.exists else {
+      XCTFail("Sign in button does not exist")
+      return false
+    }
     signInButton.tap()
 
     guard springboardApp
             .staticTexts[signInStaticText]
             .waitForExistence(timeout: timeout) else {
-      return XCTFail("Failed to display prompt")
+      XCTFail("Failed to display permission prompt")
+      return false
     }
 
     guard springboardApp
             .buttons["Continue"]
             .waitForExistence(timeout: timeout) else {
-      return XCTFail("Failed to find 'Continue' button")
+      XCTFail("Failed to find 'Continue' button")
+      return false
     }
-
     springboardApp.buttons["Continue"].tap()
+
+    if sampleApp
+        .staticTexts[Credential.email.rawValue]
+        .waitForExistence(timeout: timeout) {
+      // This email was previously used to sign in
+      XCTAssertTrue(useExistingSignIn())
+    } else {
+      // This is a first time sign in
+      XCTAssertTrue(signInForTheFirstTime())
+    }
+
+    guard sampleApp.wait(for: .runningForeground, timeout: timeout) else {
+      XCTFail("Failed to return sample app to foreground")
+      return false
+    }
+    guard sampleApp.staticTexts["User Profile"]
+            .waitForExistence(timeout: timeout) else {
+      XCTFail("Failed to sign in and return to app's User Profile view.")
+      return false
+    }
+
+    return true
+  }
+
+  /// Signs in expecting the first time flow.
+  /// @discussion
+  /// This will assumme the full flow where a user must type in an email and
+  /// password to sign in with.
+  func signInForTheFirstTime() -> Bool {
     guard sampleApp.textFields["Email or phone"]
             .waitForExistence(timeout: timeout) else {
-      return XCTFail("Failed to find email textfield")
+      XCTFail("Failed to find email textfield")
+      return false
     }
     guard sampleApp
             .keyboards
             .element
             .buttons["return"]
             .waitForExistence(timeout: timeout) else {
-      return XCTFail("Failed to find 'Next' button")
+      XCTFail("Failed to find 'return' button")
+      return false
     }
 
     sampleApp.textFields["Email or phone"].typeText(Credential.email.rawValue)
@@ -61,14 +136,16 @@ class DaysUntilBirthdayUITests_iOS_: XCTestCase {
 
     guard sampleApp.secureTextFields["Enter your password"]
             .waitForExistence(timeout: timeout) else {
-      return XCTFail("Failed to find password textfield")
+      XCTFail("Failed to find password textfield")
+      return false
     }
     guard sampleApp
             .keyboards
             .element
             .buttons["go"]
             .waitForExistence(timeout: timeout) else {
-      return XCTFail("Failed to find 'Next' button")
+      XCTFail("Failed to find 'go' button")
+      return false
     }
 
     sampleApp
@@ -76,59 +153,92 @@ class DaysUntilBirthdayUITests_iOS_: XCTestCase {
       .typeText(Credential.password.rawValue)
     sampleApp.keyboards.element.buttons["go"].tap()
 
-    guard sampleApp.wait(for: .runningForeground, timeout: timeout) else {
-      return XCTFail("Failed to return sample app to foreground")
+    return true
+  }
+
+  /// Signs in expecting a prior sign in.
+  /// @discussion
+  /// This will assume that there is a `Credential.email` in a list to select
+  /// and sign in with.
+  func useExistingSignIn() -> Bool {
+    guard sampleApp.staticTexts[Credential.email.rawValue].exists else {
+      XCTFail("Email used for previous sign-in not in list")
+      return false
     }
-    guard sampleApp.staticTexts["User Profile"]
-            .waitForExistence(timeout: timeout) else {
-      return XCTFail("Failed to sign in and return to app's User Profile view.")
+    guard sampleApp.staticTexts[Credential.email.rawValue].isHittable else {
+      XCTFail("Email used for previous sign-in not tappable")
+      return false
     }
+    sampleApp.staticTexts[Credential.email.rawValue].tap()
 
+    return true
+  }
+
+  /// Navigates to the days until birthday view from the user profile view.
+  /// - returns: `true` if the navigation was performed successfully.
+  /// - note: If `firstSignIn` is `true`, then we should expect a pop up asking
+  /// for permission.
+  func navigateToDaysUntilBirthday() -> Bool {
     guard sampleApp.buttons["View Days Until Birthday"]
             .waitForExistence(timeout: timeout) else {
-      return XCTFail("Failed to find button revealing days until birthday")
+      XCTFail("Failed to find button navigating to days until birthday view")
+      return false
     }
     sampleApp.buttons["View Days Until Birthday"].tap()
 
-    // This won't succeed if the app has already granted access; disconnect is needed here in this case
-    guard springboardApp
-            .staticTexts[signInStaticText]
-            .waitForExistence(timeout: timeout) else {
-      return XCTFail("Failed to display prompt")
+    if springboardApp
+        .staticTexts[signInStaticText]
+        .waitForExistence(timeout: timeout) {
+      guard springboardApp
+              .buttons["Continue"]
+              .waitForExistence(timeout: timeout) else {
+        XCTFail("Failed to find 'Continue' button")
+        return false
+      }
+      springboardApp.buttons["Continue"].tap()
+
+      guard sampleApp
+              .staticTexts["Days Until Birthday wants to access your Google Account"]
+              .waitForExistence(timeout: timeout) else {
+        XCTFail("Failed to find permission screen")
+        return false
+      }
+      guard sampleApp.buttons["Allow"].waitForExistence(timeout: timeout) else {
+        XCTFail("Failed to find 'Allow' button")
+        return false
+      }
+      sampleApp.buttons["Allow"].tap()
     }
 
-    guard springboardApp
-            .buttons["Continue"]
+    guard sampleApp.staticTexts["Days Until Birthday"]
             .waitForExistence(timeout: timeout) else {
-      return XCTFail("Failed to find 'Continue' button")
+      XCTFail("Failed to show days until birthday view")
+      return false
     }
-    springboardApp.buttons["Continue"].tap()
 
-    guard sampleApp
-            .staticTexts["Days Until Birthday wants to access your Google Account"]
-            .waitForExistence(timeout: timeout) else {
-      return XCTFail("Failed to find permission screen")
-    }
-    guard sampleApp.buttons["Allow"].waitForExistence(timeout: timeout) else {
-      return XCTFail("Failed to find 'Allow' button")
-    }
-    sampleApp.buttons["Allow"].tap()
+    return true
+  }
 
-    guard sampleApp.staticTexts["Days Until Birthday"]
+  /// Navigates back to the User Profile view from the Days Until Birthday View.
+  /// - returns: `true` if the navigation was successfully performed.
+  func navigateBackToUserProfileView() -> Bool {
+    guard sampleApp
+            .navigationBars
+            .buttons["User Profile"]
             .waitForExistence(timeout: timeout) else {
-      return XCTFail("Failed to return to view showing days until birthday")
+      XCTFail("Failed to show navigation button back to user profile view")
+      return false
     }
-
     sampleApp.navigationBars.buttons["User Profile"].tap()
 
     guard sampleApp
             .navigationBars
-            .buttons["Disconnect scope button"]
+            .buttons["Disconnect"]
             .waitForExistence(timeout: timeout) else {
-      return XCTFail("Failed to find the 'Disconnect' button")
+      XCTFail("Failed to find the 'Disconnect' button")
+      return false
     }
 
-    // Clean up this run so the next works as if it is the first time
-    sampleApp.navigationBars.buttons["Disconnect scope button"].tap()
+    return true
   }
 }

+ 0 - 1
Samples/Swift/DaysUntilBirthday/iOS/UserProfileView.swift

@@ -55,7 +55,6 @@ struct UserProfileView: View {
         .toolbar {
           ToolbarItemGroup(placement: .navigationBarTrailing) {
             Button(NSLocalizedString("Disconnect", comment: "Disconnect button"), action: disconnect)
-              .accessibilityLabel(Text("Disconnect scope button"))
             Button(NSLocalizedString("Sign Out", comment: "Sign out button"), action: signOut)
           }
         }