chromium/ios/chrome/browser/autofill/ui_bundled/branding/branding_view_controller_egtest.mm

// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#import "base/ios/ios_util.h"
#import "base/test/ios/wait_util.h"
#import "ios/chrome/browser/autofill/ui_bundled/autofill_app_interface.h"
#import "ios/chrome/browser/autofill/ui_bundled/manual_fill/manual_fill_matchers.h"
#import "ios/chrome/browser/shared/model/prefs/pref_names.h"
#import "ios/chrome/common/ui/elements/form_input_accessory_view.h"
#import "ios/chrome/grit/ios_strings.h"
#import "ios/chrome/test/earl_grey/chrome_actions.h"
#import "ios/chrome/test/earl_grey/chrome_earl_grey.h"
#import "ios/chrome/test/earl_grey/chrome_earl_grey_ui.h"
#import "ios/chrome/test/earl_grey/chrome_matchers.h"
#import "ios/chrome/test/earl_grey/chrome_test_case.h"
#import "ios/testing/earl_grey/app_launch_manager.h"
#import "ios/testing/earl_grey/earl_grey_test.h"
#import "net/test/embedded_test_server/embedded_test_server.h"
#import "ui/base/l10n/l10n_util.h"

using chrome_test_util::ButtonWithAccessibilityLabelId;
using chrome_test_util::TapWebElementWithId;
using chrome_test_util::WebViewMatcher;

namespace {
// HTML test page with form fields.
const char kFormHTMLFile[] = "/username_password_field_form.html";
// The "username" field in the test page.
const char kFormElementUsername[] = "username";

// Save a set of credentials to the profile store so that the manual fill
// password button is visible in keyboard accessories.
void EnableManualFillButtonForPasswordInProfileStore() {
  [AutofillAppInterface saveExamplePasswordFormToProfileStore];
}

// Save an address so that the manual fill address button is visible in keyboard
// accessories.
void EnableManualFillButtonForProfile() {
  [AutofillAppInterface saveExampleProfile];
}

// Save a credit card information so that the manual fill credit card button is
// visible in keyboard accessories.
void EnableManualFillButtonForCreditCard() {
  [AutofillAppInterface saveLocalCreditCard];
}

// Remove all passwords in profile store, all credit cards and all addresses so
// that no manual fill buttons will show in keyboard accessories.
void DisableManualFillButtonsInProfileStore() {
  [AutofillAppInterface clearProfilePasswordStore];
  [AutofillAppInterface clearProfilesStore];
  [AutofillAppInterface clearCreditCardStore];
}

// Taps a form field to bring up the system keyboard.
void BringUpKeyboard() {
  [[EarlGrey selectElementWithMatcher:WebViewMatcher()]
      performAction:TapWebElementWithId(kFormElementUsername)];
  [ChromeEarlGrey waitForKeyboardToAppear];
}

// Dismisses the keyboard, if it exist.
void DismissKeyboard() {
  [EarlGrey dismissKeyboardWithError:nil];
  [ChromeEarlGrey waitForKeyboardToDisappear];
}

// Check that the branding visibility matches the parameter `visibility`.
void CheckBrandingHasVisiblity(BOOL visibility) {
  [[EarlGrey
      selectElementWithMatcher:grey_accessibilityID(@"kBrandingButtonAXId")]
      assertWithMatcher:visibility ? grey_sufficientlyVisible()
                                   : grey_notVisible()];
}

// Opens the manual fallback menu by pressing the right keyboard accessory
// button.
void OpenManualFallback() {
  id<GREYMatcher> button_to_tap;
  if ([AutofillAppInterface isKeyboardAccessoryUpgradeEnabled]) {
    button_to_tap = grey_allOf(grey_accessibilityLabel(l10n_util::GetNSString(
                                   IDS_IOS_AUTOFILL_PASSWORD_AUTOFILL_DATA)),
                               grey_ancestor(grey_accessibilityID(
                                   kFormInputAccessoryViewAccessibilityID)),
                               nil);
  } else {
    button_to_tap = manual_fill::PasswordIconMatcher();
  }

  [[EarlGrey selectElementWithMatcher:button_to_tap] performAction:grey_tap()];
}

}  // namespace

// Super class for integration Tests for Brandings View Controller. This class
// only defines setUp and tearDown methods; actual tests are implemented in
// subclasses with different feature flags.
@interface BrandingViewControllerTestCase : ChromeTestCase
@end

@implementation BrandingViewControllerTestCase

- (AppLaunchConfiguration)appConfigurationForTestCase {
  AppLaunchConfiguration config;
  // Relaunch app at each test to rewind the startup state.
  config.relaunch_policy = ForceRelaunchByCleanShutdown;
  return config;
}

- (void)setUp {
  [super setUp];
  // Reset pref and restart, if needed.
  if ([ChromeEarlGrey
          localStateIntegerPref:prefs::kAutofillBrandingIconDisplayCount] > 0) {
    [ChromeEarlGrey
        resetDataForLocalStatePref:prefs::kAutofillBrandingIconDisplayCount];
    [ChromeEarlGrey resetDataForLocalStatePref:
                        prefs::kAutofillBrandingIconAnimationRemainingCount];
    [[AppLaunchManager sharedManager]
        ensureAppLaunchedWithConfiguration:[self appConfigurationForTestCase]];
  }
  DisableManualFillButtonsInProfileStore();
  // Turn on test server and load test page.
  GREYAssertTrue(self.testServer->Start(), @"Test server failed to start.");
  GURL url = self.testServer->GetURL(kFormHTMLFile);
  [ChromeEarlGrey loadURL:url];
  [ChromeEarlGrey waitForWebStateContainingText:"hello!"];
}

- (void)tearDown {
  DisableManualFillButtonsInProfileStore();
  // Clear feature related local state prefs.
  [ChromeEarlGrey
      resetDataForLocalStatePref:prefs::kAutofillBrandingIconDisplayCount];
  [ChromeEarlGrey resetDataForLocalStatePref:
                      prefs::kAutofillBrandingIconAnimationRemainingCount];
  [super tearDown];
}

// Tests that the autofill branding icon only shows twice.
- (void)testBrandingTwoImpressions {
  EnableManualFillButtonForPasswordInProfileStore();
  // First time.
  BringUpKeyboard();
  CheckBrandingHasVisiblity(YES);
  OpenManualFallback();

  if (!base::ios::IsRunningOnIOS16OrLater() && [ChromeEarlGrey isIPadIdiom]) {
    [ChromeEarlGreyUI dismissByTappingOnTheWindowOfPopover:
                          manual_fill::PasswordTableViewMatcher()];
  }

  DismissKeyboard();
  // Second time: branding is still visible after user interacts with a keyboard
  // accessory element.
  BringUpKeyboard();
  CheckBrandingHasVisiblity(YES);
  DismissKeyboard();
  // Third time.
  BringUpKeyboard();
  CheckBrandingHasVisiblity(NO);
}

// Tests that the branding is visible when some manual fill button is visible.
- (void)testSomeManualFillButtonsVisible {
  EnableManualFillButtonForPasswordInProfileStore();
  BringUpKeyboard();
  CheckBrandingHasVisiblity(YES);
}

// Tests that the branding is not visible when no manual fill button is visible.
- (void)testAllManualFillButtonsHidden {
  BringUpKeyboard();
  CheckBrandingHasVisiblity(NO);
}

// Tests that the branding is not visible when some manual fill button is
// enabled then disabled before the keyboard is presented.
- (void)testEnableAndDisableManualFillButtonsBeforeKeyboardPresented {
  EnableManualFillButtonForPasswordInProfileStore();
  DisableManualFillButtonsInProfileStore();
  BringUpKeyboard();
  CheckBrandingHasVisiblity(NO);
}

// Tests that the branding is visible when some manual fill button is enabled,
// disabled and re-enabled before the keyboard is presented.
- (void)testEnableDisableAndReenableManualFillButtonsBeforeKeyboardPresented {
  EnableManualFillButtonForPasswordInProfileStore();
  DisableManualFillButtonsInProfileStore();
  EnableManualFillButtonForProfile();
  BringUpKeyboard();
  CheckBrandingHasVisiblity(YES);
}

// Tests that the branding is visible when some manual fill button is enabled,
// then disappears when the manual fill button is disabled.
- (void)testDisableManualFillButtonsDuringKeyboardPresenting {
  EnableManualFillButtonForPasswordInProfileStore();
  BringUpKeyboard();
  CheckBrandingHasVisiblity(YES);
  DisableManualFillButtonsInProfileStore();
  DismissKeyboard();
  BringUpKeyboard();
  CheckBrandingHasVisiblity(NO);
}

// Tests that the branding is invisible until some manual fill button is
// enabled, then disappears when the manual fill button is disabled.
- (void)testEnableAndDisableManualFillButtonsDuringKeyboardPresenting {
  BringUpKeyboard();
  CheckBrandingHasVisiblity(NO);
  EnableManualFillButtonForPasswordInProfileStore();
  DismissKeyboard();
  BringUpKeyboard();
  CheckBrandingHasVisiblity(YES);
  DisableManualFillButtonsInProfileStore();
  DismissKeyboard();
  BringUpKeyboard();
  CheckBrandingHasVisiblity(NO);
}

// Tests that the branding is visible even after one of the multiple manual fill
// buttons is disabled.
- (void)testEnableTwoManualFillButtonsAndDisableOneDuringKeyboardPresenting {
  EnableManualFillButtonForPasswordInProfileStore();
  EnableManualFillButtonForCreditCard();
  BringUpKeyboard();
  CheckBrandingHasVisiblity(YES);
  // Hide manual fill button for password.
  [AutofillAppInterface clearProfilePasswordStore];
  DismissKeyboard();
  BringUpKeyboard();
  CheckBrandingHasVisiblity(YES);
  // Hide manual fill button for credit card.
  [AutofillAppInterface clearCreditCardStore];
  DismissKeyboard();
  BringUpKeyboard();
  CheckBrandingHasVisiblity(NO);
}

@end