chromium/ios/chrome/browser/ui/omnibox/omnibox_edit_egtest.mm

// Copyright 2024 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/strings/sys_string_conversions.h"
#import "components/omnibox/common/omnibox_features.h"
#import "ios/chrome/browser/shared/public/features/features.h"
#import "ios/chrome/browser/ui/omnibox/omnibox_app_interface.h"
#import "ios/chrome/browser/ui/omnibox/omnibox_earl_grey.h"
#import "ios/chrome/browser/ui/omnibox/omnibox_matchers.h"
#import "ios/chrome/browser/ui/omnibox/omnibox_test_util.h"
#import "ios/chrome/browser/ui/omnibox/omnibox_ui_features.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_matchers_app_interface.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"

// Tests the omnibox text field when editing.
@interface OmniboxEditTestCase : ChromeTestCase
@end

@implementation OmniboxEditTestCase

- (void)setUp {
  [super setUp];

  // Start a server to be able to navigate to a web page.
  self.testServer->RegisterRequestHandler(
      base::BindRepeating(&omnibox::OmniboxHTTPResponses));
  GREYAssertTrue(self.testServer->Start(), @"Test server failed to start.");

  [ChromeEarlGrey clearBrowsingHistory];
}

- (AppLaunchConfiguration)appConfigurationForTestCase {
  AppLaunchConfiguration config = [super appConfigurationForTestCase];

  // Enable flags for rich inline autocomplete tests.
  if ([self isRunningTest:@selector(testRichInlineDefaultSuggestion)]) {
    config.features_enabled.push_back(omnibox::kRichAutocompletion);
  }

  // Disable AutocompleteProvider types: TYPE_SEARCH and TYPE_ON_DEVICE_HEAD.
  omnibox::DisableAutocompleteProviders(config, 1056);

  return config;
}

#pragma mark - Test clear button

// Tests clearing text in the pre-edit state of the omnibox.
- (void)testClearButtonPreEditState {
  [OmniboxEarlGrey openPage:omnibox::Page(1) testServer:self.testServer];
  [ChromeEarlGreyUI focusOmnibox];

  // Tap the clear button.
  [[EarlGrey selectElementWithMatcher:omnibox::ClearButtonMatcher()]
      performAction:grey_tap()];

  // Verify that the omnibox is empty.
  [[EarlGrey selectElementWithMatcher:chrome_test_util::Omnibox()]
      assertWithMatcher:chrome_test_util::OmniboxText("")];

  // Verify that the clear button is not visible.
  [[EarlGrey selectElementWithMatcher:omnibox::ClearButtonMatcher()]
      assertWithMatcher:grey_notVisible()];
}

// Tests clearing text in the edit state of the omnibox.
- (void)testClearButtonEditState {
  [OmniboxEarlGrey openPage:omnibox::Page(1) testServer:self.testServer];
  [ChromeEarlGreyUI focusOmniboxAndReplaceText:@"something"];

  // Tap the clear button.
  [[EarlGrey selectElementWithMatcher:omnibox::ClearButtonMatcher()]
      performAction:grey_tap()];

  // Verify that the omnibox is empty.
  [[EarlGrey selectElementWithMatcher:chrome_test_util::Omnibox()]
      assertWithMatcher:chrome_test_util::OmniboxText("")];

  // Verify that the clear button is not visible.
  [[EarlGrey selectElementWithMatcher:omnibox::ClearButtonMatcher()]
      assertWithMatcher:grey_notVisible()];
}

#pragma mark - Test rich inline

// Tests navigating to a shortcut as a default match.
- (void)testRichInlineDefaultSuggestion {
  // Add 2 shortcuts Page(1) and Page(2).
  [OmniboxEarlGrey addShorcuts:2 toTestServer:self.testServer];

  omnibox::Page shortcutPage = omnibox::Page(1);

  // Type the shortcut input in the omnibox.
  [ChromeEarlGreyUI
      focusOmniboxAndReplaceText:base::SysUTF8ToNSString(
                                     omnibox::PageTitle(shortcutPage))];

  // The shortcut suggestion should be default match. Press enter to navigate to
  // it.
  // TODO(crbug.com/40916974): Use simulatePhysicalKeyboardEvent until
  // replaceText can properly handle \n.
  [ChromeEarlGrey simulatePhysicalKeyboardEvent:@"\n" flags:0];

  [ChromeEarlGrey
      waitForWebStateContainingText:omnibox::PageContent(shortcutPage)];
}

@end

// Tests the omnibox text field when editing, with search provider.
@interface OmniboxEditAllowSearchTestCase : ChromeTestCase
@end

@implementation OmniboxEditAllowSearchTestCase

- (void)setUp {
  [super setUp];

  // Start a server to be able to navigate to a web page.
  self.testServer->RegisterRequestHandler(
      base::BindRepeating(&omnibox::OmniboxHTTPResponses));
  GREYAssertTrue(self.testServer->Start(), @"Test server failed to start.");

  [OmniboxAppInterface
      setUpFakeSuggestionsService:@"fake_suggestions_sample.json"];

  [ChromeEarlGrey clearBrowsingHistory];
}

- (void)tearDown {
  [super tearDown];
  [OmniboxAppInterface tearDownFakeSuggestionsService];
}

- (AppLaunchConfiguration)appConfigurationForTestCase {
  AppLaunchConfiguration config = [super appConfigurationForTestCase];

  // Enable flags for rich inline autocomplete tests.
  if ([self isRunningTest:@selector(testRichInlineRemovedByTap)] ||
      [self isRunningTest:@selector(testRichInlineRemovedByDelete)] ||
      [self isRunningTest:@selector(testRichInlineRemovedWithArrowKey)]) {
    config.features_enabled.push_back(omnibox::kRichAutocompletion);
  }

  // Disable AutocompleteProvider type TYPE_ON_DEVICE_HEAD.
  omnibox::DisableAutocompleteProviders(config, 1024);

  return config;
}

/// Verifies that the first suggestion is of type search.
- (void)assertFirstSuggestionIsSearch {
  NSIndexPath* firstRow = [NSIndexPath indexPathForRow:0 inSection:0];
  // Verifies that the first suggestion doesn't contain a secondary text.
  [[EarlGrey
      selectElementWithMatcher:grey_allOf(
                                   grey_ancestor(
                                       omnibox::PopupRowAtIndex(firstRow)),
                                   omnibox::PopupRowSecondaryTextMatcher(),
                                   nil)] assertWithMatcher:grey_nil()];
}

/// Verifies that the first suggestion is not of type search.
- (void)assertFirstSuggestionIsURL {
  NSIndexPath* firstRow = [NSIndexPath indexPathForRow:0 inSection:0];
  // Verifies that the first suggestion contains a secondary text.
  [[EarlGrey
      selectElementWithMatcher:grey_allOf(
                                   grey_ancestor(
                                       omnibox::PopupRowAtIndex(firstRow)),
                                   omnibox::PopupRowSecondaryTextMatcher(),
                                   nil)]
      assertWithMatcher:[OmniboxEarlGrey isURLMatcher]];
}

#pragma mark - Test rich inline

// Tests removing rich inline autocomplete by tapping the omnibox.
- (void)testRichInlineRemovedByTap {
  // Add 2 shortcuts Page(1) and Page(2).
  [OmniboxEarlGrey addShorcuts:2 toTestServer:self.testServer];

  omnibox::Page shortcutPage = omnibox::Page(1);

  // Type the shortcut input in the omnibox.
  [ChromeEarlGreyUI
      focusOmniboxAndReplaceText:base::SysUTF8ToNSString(
                                     omnibox::PageTitle(shortcutPage))];

  [self assertFirstSuggestionIsURL];

  [[EarlGrey selectElementWithMatcher:chrome_test_util::Omnibox()]
      performAction:grey_tap()];

  [self assertFirstSuggestionIsSearch];
}

// Tests removing rich inline autocomplete by pressing delete.
- (void)testRichInlineRemovedByDelete {
  // Add 2 shortcuts Page(1) and Page(2).
  [OmniboxEarlGrey addShorcuts:2 toTestServer:self.testServer];

  omnibox::Page shortcutPage = omnibox::Page(1);

  // Type the shortcut input in the omnibox.
  [ChromeEarlGreyUI
      focusOmniboxAndReplaceText:base::SysUTF8ToNSString(
                                     omnibox::PageTitle(shortcutPage))];

  [self assertFirstSuggestionIsURL];

  // Press the backspace HW keyboard key.
  [ChromeEarlGrey simulatePhysicalKeyboardEvent:@"\b" flags:0];

  [self assertFirstSuggestionIsSearch];
}

// Tests removing rich inline autocomplete by pressing an arrow key.
- (void)testRichInlineRemovedWithArrowKey {
  // Add 2 shortcuts Page(1) and Page(2).
  [OmniboxEarlGrey addShorcuts:2 toTestServer:self.testServer];

  omnibox::Page shortcutPage = omnibox::Page(1);

  // Type the shortcut input in the omnibox.
  [ChromeEarlGreyUI
      focusOmniboxAndReplaceText:base::SysUTF8ToNSString(
                                     omnibox::PageTitle(shortcutPage))];

  [self assertFirstSuggestionIsURL];

  // Simulate press the HW left arrow key.
  [ChromeEarlGrey simulatePhysicalKeyboardEvent:@"leftArrow" flags:0];

  [self assertFirstSuggestionIsSearch];
}

@end