// Copyright 2016 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#import <UIKit/UIKit.h>
#import <XCTest/XCTest.h>
#import "base/ios/ios_util.h"
#import "base/strings/stringprintf.h"
#import "base/strings/sys_string_conversions.h"
#import "base/strings/utf_string_conversions.h"
#import "base/test/ios/wait_util.h"
#import "components/sync/base/command_line_switches.h"
#import "components/url_formatter/elide_url.h"
#import "ios/chrome/browser/shared/public/features/features.h"
#import "ios/chrome/browser/shared/ui/table_view/table_view_constants.h"
#import "ios/chrome/browser/signin/model/fake_system_identity.h"
#import "ios/chrome/browser/ui/authentication/signin_earl_grey.h"
#import "ios/chrome/browser/ui/authentication/signin_earl_grey_ui_test_util.h"
#import "ios/chrome/browser/history/ui_bundled/history_ui_constants.h"
#import "ios/chrome/browser/ui/popup_menu/popup_menu_constants.h"
#import "ios/chrome/browser/ui/settings/cells/clear_browsing_data_constants.h"
#import "ios/chrome/browser/ui/settings/clear_browsing_data/features.h"
#import "ios/chrome/common/string_util.h"
#import "ios/chrome/grit/ios_strings.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/earl_grey_test.h"
#import "net/base/apple/url_conversions.h"
#import "net/test/embedded_test_server/embedded_test_server.h"
#import "net/test/embedded_test_server/http_request.h"
#import "net/test/embedded_test_server/http_response.h"
using chrome_test_util::ButtonWithAccessibilityLabelId;
using chrome_test_util::HistoryEntry;
using chrome_test_util::NavigationBarDoneButton;
using chrome_test_util::OpenLinkInNewWindowButton;
using chrome_test_util::DeleteButton;
using chrome_test_util::WindowWithNumber;
namespace {
char kURL1[] = "/firstURL";
char kURL2[] = "/secondURL";
char kURL3[] = "/thirdURL";
char kTitle1[] = "Page 1";
char kTitle2[] = "Page 2";
char kResponse1[] = "Test Page 1 content";
char kResponse2[] = "Test Page 2 content";
char kResponse3[] = "Test Page 3 content";
// Constant for timeout while waiting for asynchronous sync operations.
constexpr base::TimeDelta kSyncOperationTimeout = base::Seconds(10);
// Matcher for the edit button in the navigation bar.
id<GREYMatcher> NavigationEditButton() {
return grey_accessibilityID(kHistoryToolbarEditButtonIdentifier);
}
// Matcher for the delete button.
id<GREYMatcher> DeleteHistoryEntriesButton() {
return grey_accessibilityID(kHistoryToolbarDeleteButtonIdentifier);
}
// Matcher for the search button.
id<GREYMatcher> SearchIconButton() {
return grey_accessibilityID(kHistorySearchControllerSearchBarIdentifier);
}
// Matcher for the cancel button.
id<GREYMatcher> CancelButton() {
return grey_accessibilityID(kHistoryToolbarCancelButtonIdentifier);
}
// Matcher for the empty TableView illustrated background
id<GREYMatcher> EmptyIllustratedTableViewBackground() {
return grey_accessibilityID(kTableViewIllustratedEmptyViewID);
}
// Provides responses for URLs.
std::unique_ptr<net::test_server::HttpResponse> StandardResponse(
const net::test_server::HttpRequest& request) {
std::unique_ptr<net::test_server::BasicHttpResponse> http_response =
std::make_unique<net::test_server::BasicHttpResponse>();
http_response->set_code(net::HTTP_OK);
const char kPageFormat[] = "<head><title>%s</title></head><body>%s</body>";
if (request.relative_url == kURL1) {
std::string page_html =
base::StringPrintf(kPageFormat, kTitle1, kResponse1);
http_response->set_content(page_html);
} else if (request.relative_url == kURL2) {
std::string page_html =
base::StringPrintf(kPageFormat, kTitle2, kResponse2);
http_response->set_content(page_html);
} else if (request.relative_url == kURL3) {
http_response->set_content(
base::StringPrintf("<body>%s</body>", kResponse3));
} else {
return nullptr;
}
return std::move(http_response);
}
} // namespace
// History UI tests.
@interface HistoryUITestCase : ChromeTestCase {
GURL _URL1;
GURL _URL2;
GURL _URL3;
}
// Loads three test URLs.
- (void)loadTestURLs;
// Displays the history UI.
- (void)openHistoryPanel;
@end
@implementation HistoryUITestCase
- (AppLaunchConfiguration)appConfigurationForTestCase {
AppLaunchConfiguration config = [super appConfigurationForTestCase];
config.additional_args.push_back(std::string("--") +
syncer::kSyncShortNudgeDelayForTest);
config.features_disabled.push_back(kIOSQuickDelete);
return config;
}
- (void)setUp {
[super setUp];
self.testServer->RegisterRequestHandler(
base::BindRepeating(&StandardResponse));
GREYAssertTrue(self.testServer->Start(), @"Server did not start.");
_URL1 = self.testServer->GetURL(kURL1);
_URL2 = self.testServer->GetURL(kURL2);
_URL3 = self.testServer->GetURL(kURL3);
[ChromeEarlGrey clearBrowsingHistory];
// Some tests rely on a clean state for the "Clear Browsing Data" settings
// screen.
[ChromeEarlGrey resetBrowsingDataPrefs];
}
- (void)tearDown {
NSError* error = nil;
// Dismiss search bar by pressing cancel, if present. Passing error prevents
// failure if the element is not found.
[[EarlGrey selectElementWithMatcher:CancelButton()] performAction:grey_tap()
error:&error];
// Dismiss history panel by pressing done, if present. Passing error prevents
// failure if the element is not found.
[[EarlGrey selectElementWithMatcher:NavigationBarDoneButton()]
performAction:grey_tap()
error:&error];
// Some tests change the default values for the "Clear Browsing Data" settings
// screen.
[ChromeEarlGrey resetBrowsingDataPrefs];
// Shutdown network process after tests run to avoid hanging from
// clearing browsing history.
[ChromeEarlGrey killWebKitNetworkProcess];
[super tearDown];
}
#pragma mark Tests
// Tests that no history is shown if there has been no navigation.
- (void)testDisplayNoHistory {
[self openHistoryPanel];
[ChromeEarlGreyUI assertHistoryHasNoEntries];
}
// Tests that the history panel displays navigation history.
- (void)testDisplayHistory {
[self loadTestURLs];
[self openHistoryPanel];
// Assert that history displays three entries.
[[EarlGrey
selectElementWithMatcher:
HistoryEntry(
base::UTF16ToUTF8(
url_formatter::
FormatUrlForDisplayOmitSchemePathTrivialSubdomainsAndMobilePrefix(
_URL1)),
kTitle1)] assertWithMatcher:grey_notNil()];
[[EarlGrey
selectElementWithMatcher:
HistoryEntry(
base::UTF16ToUTF8(
url_formatter::
FormatUrlForDisplayOmitSchemePathTrivialSubdomainsAndMobilePrefix(
_URL2)),
kTitle2)] assertWithMatcher:grey_notNil()];
[[EarlGrey
selectElementWithMatcher:
HistoryEntry(
base::UTF16ToUTF8(
url_formatter::
FormatUrlForDisplayOmitSchemePathTrivialSubdomainsAndMobilePrefix(
_URL3)),
_URL3.GetContent())] assertWithMatcher:grey_notNil()];
// Tap a history entry and assert that navigation to that entry's URL occurs.
[[EarlGrey
selectElementWithMatcher:
HistoryEntry(
base::UTF16ToUTF8(
url_formatter::
FormatUrlForDisplayOmitSchemePathTrivialSubdomainsAndMobilePrefix(
_URL1)),
kTitle1)] performAction:grey_tap()];
[ChromeEarlGrey waitForWebStateContainingText:kResponse1];
}
// Tests that history is not changed after performing back navigation.
- (void)testHistoryUpdateAfterBackNavigation {
[ChromeEarlGrey loadURL:_URL1];
[ChromeEarlGrey loadURL:_URL2];
[[EarlGrey selectElementWithMatcher:chrome_test_util::BackButton()]
performAction:grey_tap()];
[ChromeEarlGrey waitForWebStateContainingText:kResponse1];
[self openHistoryPanel];
[[EarlGrey
selectElementWithMatcher:
HistoryEntry(
base::UTF16ToUTF8(
url_formatter::
FormatUrlForDisplayOmitSchemePathTrivialSubdomainsAndMobilePrefix(
_URL1)),
kTitle1)] assertWithMatcher:grey_notNil()];
[[EarlGrey
selectElementWithMatcher:
HistoryEntry(
base::UTF16ToUTF8(
url_formatter::
FormatUrlForDisplayOmitSchemePathTrivialSubdomainsAndMobilePrefix(
_URL2)),
kTitle2)] assertWithMatcher:grey_notNil()];
}
// Tests that searching history displays only entries matching the search term.
- (void)testSearchHistory {
[self loadTestURLs];
[self openHistoryPanel];
[[EarlGrey selectElementWithMatcher:SearchIconButton()]
performAction:grey_tap()];
// Verify that scrim is visible.
[[EarlGrey selectElementWithMatcher:grey_accessibilityID(
kHistorySearchScrimIdentifier)]
assertWithMatcher:grey_notNil()];
NSString* searchString =
[NSString stringWithFormat:@"%s", _URL1.path().c_str()];
[[EarlGrey selectElementWithMatcher:SearchIconButton()]
performAction:grey_replaceText(searchString)];
// Verify that scrim is not visible.
[[EarlGrey selectElementWithMatcher:grey_accessibilityID(
kHistorySearchScrimIdentifier)]
assertWithMatcher:grey_nil()];
[[EarlGrey
selectElementWithMatcher:
HistoryEntry(
base::UTF16ToUTF8(
url_formatter::
FormatUrlForDisplayOmitSchemePathTrivialSubdomainsAndMobilePrefix(
_URL1)),
kTitle1)] assertWithMatcher:grey_notNil()];
[[EarlGrey
selectElementWithMatcher:
HistoryEntry(
base::UTF16ToUTF8(
url_formatter::
FormatUrlForDisplayOmitSchemePathTrivialSubdomainsAndMobilePrefix(
_URL2)),
kTitle2)] assertWithMatcher:grey_nil()];
[[EarlGrey
selectElementWithMatcher:
HistoryEntry(
base::UTF16ToUTF8(
url_formatter::
FormatUrlForDisplayOmitSchemePathTrivialSubdomainsAndMobilePrefix(
_URL3)),
_URL3.GetContent())] assertWithMatcher:grey_nil()];
}
// Tests that searching a typed URL (after history sync is enabled and the URL
// is uploaded to the sync server) displays only entries matching the search
// term.
- (void)testSearchSyncedHistory {
const char syncedURL[] = "http://mockurl/sync/";
const GURL mockURL(syncedURL);
// Sign in and enable history sync.
FakeSystemIdentity* fakeIdentity = [FakeSystemIdentity fakeIdentity1];
[SigninEarlGrey addFakeIdentity:fakeIdentity];
[SigninEarlGreyUI signinWithFakeIdentity:fakeIdentity enableHistorySync:YES];
[ChromeEarlGrey
waitForSyncTransportStateActiveWithTimeout:kSyncOperationTimeout];
// Add a typed URL and wait for it to show up on the server.
[ChromeEarlGrey addHistoryServiceTypedURL:mockURL];
NSArray<NSURL*>* URLs = @[
net::NSURLWithGURL(mockURL),
];
[ChromeEarlGrey waitForSyncServerHistoryURLs:URLs
timeout:kSyncOperationTimeout];
[self loadTestURLs];
[self openHistoryPanel];
[[EarlGrey selectElementWithMatcher:SearchIconButton()]
performAction:grey_tap()];
// Verify that scrim is visible.
[[EarlGrey selectElementWithMatcher:grey_accessibilityID(
kHistorySearchScrimIdentifier)]
assertWithMatcher:grey_notNil()];
NSString* searchString = base::SysUTF8ToNSString(mockURL.spec().c_str());
[[EarlGrey selectElementWithMatcher:SearchIconButton()]
performAction:grey_replaceText(searchString)];
// Verify that scrim is not visible.
[[EarlGrey selectElementWithMatcher:grey_accessibilityID(
kHistorySearchScrimIdentifier)]
assertWithMatcher:grey_nil()];
[[EarlGrey
selectElementWithMatcher:
grey_allOf(chrome_test_util::StaticTextWithAccessibilityLabel(
@"mockurl/sync/"),
grey_ancestor(grey_kindOfClassName(@"TableViewURLCell")),
grey_sufficientlyVisible(), nil)]
assertWithMatcher:grey_notNil()];
[[EarlGrey
selectElementWithMatcher:
HistoryEntry(
base::UTF16ToUTF8(
url_formatter::
FormatUrlForDisplayOmitSchemePathTrivialSubdomainsAndMobilePrefix(
_URL1)),
kTitle1)] assertWithMatcher:grey_nil()];
[[EarlGrey
selectElementWithMatcher:
HistoryEntry(
base::UTF16ToUTF8(
url_formatter::
FormatUrlForDisplayOmitSchemePathTrivialSubdomainsAndMobilePrefix(
_URL2)),
kTitle2)] assertWithMatcher:grey_nil()];
[[EarlGrey
selectElementWithMatcher:
HistoryEntry(
base::UTF16ToUTF8(
url_formatter::
FormatUrlForDisplayOmitSchemePathTrivialSubdomainsAndMobilePrefix(
_URL3)),
_URL3.GetContent())] assertWithMatcher:grey_nil()];
}
// Tests that long press on scrim while search box is enabled dismisses the
// search controller.
- (void)testSearchLongPressOnScrimCancelsSearchController {
[self loadTestURLs];
[self openHistoryPanel];
[[EarlGrey selectElementWithMatcher:SearchIconButton()]
performAction:grey_tap()];
// Try long press.
[[EarlGrey
selectElementWithMatcher:
HistoryEntry(
base::UTF16ToUTF8(
url_formatter::
FormatUrlForDisplayOmitSchemePathTrivialSubdomainsAndMobilePrefix(
_URL1)),
kTitle1)] performAction:grey_longPress()];
// Verify context menu is not visible.
[[EarlGrey
selectElementWithMatcher:ButtonWithAccessibilityLabelId(
IDS_IOS_CONTENT_CONTEXT_OPENLINKNEWTAB)]
assertWithMatcher:grey_nil()];
// Verify that scrim is not visible.
[[EarlGrey selectElementWithMatcher:grey_accessibilityID(
kHistorySearchScrimIdentifier)]
assertWithMatcher:grey_nil()];
// Verifiy we went back to original folder content.
[[EarlGrey
selectElementWithMatcher:
HistoryEntry(
base::UTF16ToUTF8(
url_formatter::
FormatUrlForDisplayOmitSchemePathTrivialSubdomainsAndMobilePrefix(
_URL1)),
kTitle1)] assertWithMatcher:grey_notNil()];
[[EarlGrey
selectElementWithMatcher:
HistoryEntry(
base::UTF16ToUTF8(
url_formatter::
FormatUrlForDisplayOmitSchemePathTrivialSubdomainsAndMobilePrefix(
_URL2)),
kTitle2)] assertWithMatcher:grey_notNil()];
[[EarlGrey
selectElementWithMatcher:
HistoryEntry(
base::UTF16ToUTF8(
url_formatter::
FormatUrlForDisplayOmitSchemePathTrivialSubdomainsAndMobilePrefix(
_URL3)),
_URL3.GetContent())] assertWithMatcher:grey_notNil()];
}
// Tests deletion of history entries.
- (void)testDeleteHistory {
[self loadTestURLs];
[self openHistoryPanel];
// Assert that three history elements are present.
[[EarlGrey
selectElementWithMatcher:
HistoryEntry(
base::UTF16ToUTF8(
url_formatter::
FormatUrlForDisplayOmitSchemePathTrivialSubdomainsAndMobilePrefix(
_URL1)),
kTitle1)] assertWithMatcher:grey_notNil()];
[[EarlGrey
selectElementWithMatcher:
HistoryEntry(
base::UTF16ToUTF8(
url_formatter::
FormatUrlForDisplayOmitSchemePathTrivialSubdomainsAndMobilePrefix(
_URL2)),
kTitle2)] assertWithMatcher:grey_notNil()];
[[EarlGrey
selectElementWithMatcher:
HistoryEntry(
base::UTF16ToUTF8(
url_formatter::
FormatUrlForDisplayOmitSchemePathTrivialSubdomainsAndMobilePrefix(
_URL3)),
_URL3.GetContent())] assertWithMatcher:grey_notNil()];
// Enter edit mode, select a history element, and press delete.
[[EarlGrey selectElementWithMatcher:NavigationEditButton()]
performAction:grey_tap()];
[[EarlGrey
selectElementWithMatcher:
HistoryEntry(
base::UTF16ToUTF8(
url_formatter::
FormatUrlForDisplayOmitSchemePathTrivialSubdomainsAndMobilePrefix(
_URL1)),
kTitle1)] performAction:grey_tap()];
[[EarlGrey selectElementWithMatcher:DeleteHistoryEntriesButton()]
performAction:grey_tap()];
// Assert that the deleted entry is gone and the other two remain.
[[EarlGrey
selectElementWithMatcher:
HistoryEntry(
base::UTF16ToUTF8(
url_formatter::
FormatUrlForDisplayOmitSchemePathTrivialSubdomainsAndMobilePrefix(
_URL1)),
kTitle1)] assertWithMatcher:grey_nil()];
[[EarlGrey
selectElementWithMatcher:
HistoryEntry(
base::UTF16ToUTF8(
url_formatter::
FormatUrlForDisplayOmitSchemePathTrivialSubdomainsAndMobilePrefix(
_URL2)),
kTitle2)] assertWithMatcher:grey_notNil()];
[[EarlGrey
selectElementWithMatcher:
HistoryEntry(
base::UTF16ToUTF8(
url_formatter::
FormatUrlForDisplayOmitSchemePathTrivialSubdomainsAndMobilePrefix(
_URL3)),
_URL3.GetContent())] assertWithMatcher:grey_notNil()];
// Enter edit mode, select both remaining entries, and press delete.
[[EarlGrey selectElementWithMatcher:NavigationEditButton()]
performAction:grey_tap()];
[[EarlGrey
selectElementWithMatcher:
HistoryEntry(
base::UTF16ToUTF8(
url_formatter::
FormatUrlForDisplayOmitSchemePathTrivialSubdomainsAndMobilePrefix(
_URL2)),
kTitle2)] performAction:grey_tap()];
[[EarlGrey
selectElementWithMatcher:
HistoryEntry(
base::UTF16ToUTF8(
url_formatter::
FormatUrlForDisplayOmitSchemePathTrivialSubdomainsAndMobilePrefix(
_URL3)),
_URL3.GetContent())] performAction:grey_tap()];
[[EarlGrey selectElementWithMatcher:DeleteHistoryEntriesButton()]
performAction:grey_tap()];
[ChromeEarlGreyUI assertHistoryHasNoEntries];
}
// Tests clear browsing history.
// TODO(crbug.com/40888582): Fix flakiness.
- (void)DISABLED_testClearBrowsingHistory {
[self loadTestURLs];
[self openHistoryPanel];
[ChromeEarlGreyUI openAndClearBrowsingDataFromHistory];
[ChromeEarlGrey waitForSufficientlyVisibleElementWithMatcher:
grey_accessibilityID(kHistoryTableViewIdentifier)];
[ChromeEarlGreyUI assertHistoryHasNoEntries];
}
// Tests clear browsing history.
- (void)testClearBrowsingHistorySwipeDownDismiss {
[self loadTestURLs];
[self openHistoryPanel];
// Open Clear Browsing Data
[[EarlGrey selectElementWithMatcher:chrome_test_util::
HistoryClearBrowsingDataButton()]
performAction:grey_tap()];
// Check that the TableView is presented.
[[EarlGrey
selectElementWithMatcher:
grey_accessibilityID(kClearBrowsingDataViewAccessibilityIdentifier)]
assertWithMatcher:grey_notNil()];
// Swipe TableView down.
[[EarlGrey
selectElementWithMatcher:
grey_accessibilityID(kClearBrowsingDataViewAccessibilityIdentifier)]
performAction:grey_swipeFastInDirection(kGREYDirectionDown)];
// Check that the TableView has been dismissed.
[[EarlGrey
selectElementWithMatcher:
grey_accessibilityID(kClearBrowsingDataViewAccessibilityIdentifier)]
assertWithMatcher:grey_nil()];
}
// Tests display and selection of 'Open in New Tab' in a context menu on a
// history entry.
- (void)testContextMenuOpenInNewTab {
[self loadTestURLs];
[self openHistoryPanel];
// Long press on the history element.
[[EarlGrey
selectElementWithMatcher:
HistoryEntry(
base::UTF16ToUTF8(
url_formatter::
FormatUrlForDisplayOmitSchemePathTrivialSubdomainsAndMobilePrefix(
_URL1)),
kTitle1)] performAction:grey_longPress()];
// Select "Open in New Tab" and confirm that new tab is opened with selected
// URL.
[ChromeEarlGrey verifyOpenInNewTabActionWithURL:_URL1.GetContent()];
}
// Tests display and selection of 'Open in New Window' in a context menu on a
// history entry.
- (void)testContextMenuOpenInNewWindow {
if (![ChromeEarlGrey areMultipleWindowsSupported])
EARL_GREY_TEST_DISABLED(@"Multiple windows can't be opened.");
[self loadTestURLs];
[self openHistoryPanel];
// Long press on the history element.
[[EarlGrey
selectElementWithMatcher:
HistoryEntry(
base::UTF16ToUTF8(
url_formatter::
FormatUrlForDisplayOmitSchemePathTrivialSubdomainsAndMobilePrefix(
_URL1)),
kTitle1)] performAction:grey_longPress()];
[ChromeEarlGrey verifyOpenInNewWindowActionWithContent:kResponse1];
}
// Tests display and selection of 'Open in New Incognito Tab' in a context menu
// on a history entry.
- (void)testContextMenuOpenInNewIncognitoTab {
[self loadTestURLs];
[self openHistoryPanel];
// Long press on the history element.
[[EarlGrey
selectElementWithMatcher:
HistoryEntry(
base::UTF16ToUTF8(
url_formatter::
FormatUrlForDisplayOmitSchemePathTrivialSubdomainsAndMobilePrefix(
_URL1)),
kTitle1)] performAction:grey_longPress()];
// Select "Open in New Incognito Tab" and confirm that new tab is opened in
// incognito with the selected URL.
[ChromeEarlGrey verifyOpenInIncognitoActionWithURL:_URL1.GetContent()];
}
// Tests display and selection of 'Copy URL' in a context menu on a history
// entry.
- (void)testContextMenuCopy {
[self loadTestURLs];
[self openHistoryPanel];
// Long press on the history element.
[[EarlGrey
selectElementWithMatcher:
HistoryEntry(
base::UTF16ToUTF8(
url_formatter::
FormatUrlForDisplayOmitSchemePathTrivialSubdomainsAndMobilePrefix(
_URL1)),
kTitle1)] performAction:grey_longPress()];
// Tap "Copy URL" and wait for the URL to be copied to the pasteboard.
[ChromeEarlGrey
verifyCopyLinkActionWithText:[NSString
stringWithUTF8String:_URL1.spec()
.c_str()]];
}
// Tests display and selection of "Share" in the context menu for a history
// entry.
- (void)testContextMenuShare {
[self loadTestURLs];
[self openHistoryPanel];
// Long press on the history element.
[[EarlGrey
selectElementWithMatcher:
HistoryEntry(
base::UTF16ToUTF8(
url_formatter::
FormatUrlForDisplayOmitSchemePathTrivialSubdomainsAndMobilePrefix(
_URL1)),
kTitle1)] performAction:grey_longPress()];
[ChromeEarlGrey
verifyShareActionWithURL:_URL1
pageTitle:[NSString stringWithUTF8String:kTitle1]];
}
// Tests the Delete context menu action for a History entry.
- (void)testContextMenuDelete {
[self loadTestURLs];
[self openHistoryPanel];
// Long press on the history element.
[[EarlGrey
selectElementWithMatcher:
HistoryEntry(
base::UTF16ToUTF8(
url_formatter::
FormatUrlForDisplayOmitSchemePathTrivialSubdomainsAndMobilePrefix(
_URL1)),
kTitle1)] performAction:grey_longPress()];
[[EarlGrey selectElementWithMatcher:DeleteButton()] performAction:grey_tap()];
// Assert that the deleted entry is gone and the other two remain.
[[EarlGrey
selectElementWithMatcher:
HistoryEntry(
base::UTF16ToUTF8(
url_formatter::
FormatUrlForDisplayOmitSchemePathTrivialSubdomainsAndMobilePrefix(
_URL1)),
kTitle1)] assertWithMatcher:grey_nil()];
// Wait for the animations to be done, then validate.
[ChromeEarlGrey
waitForSufficientlyVisibleElementWithMatcher:
HistoryEntry(
base::UTF16ToUTF8(
url_formatter::
FormatUrlForDisplayOmitSchemePathTrivialSubdomainsAndMobilePrefix(
_URL2)),
kTitle2)];
[[EarlGrey
selectElementWithMatcher:
HistoryEntry(
base::UTF16ToUTF8(
url_formatter::
FormatUrlForDisplayOmitSchemePathTrivialSubdomainsAndMobilePrefix(
_URL2)),
kTitle2)] assertWithMatcher:grey_notNil()];
[[EarlGrey
selectElementWithMatcher:
HistoryEntry(
base::UTF16ToUTF8(
url_formatter::
FormatUrlForDisplayOmitSchemePathTrivialSubdomainsAndMobilePrefix(
_URL3)),
_URL3.GetContent())] assertWithMatcher:grey_notNil()];
}
// Tests that the VC can be dismissed by swiping down.
- (void)testSwipeDownDismiss {
[self loadTestURLs];
[self openHistoryPanel];
// Check that the TableView is presented.
[[EarlGrey selectElementWithMatcher:grey_accessibilityID(
kHistoryTableViewIdentifier)]
assertWithMatcher:grey_notNil()];
// Swipe TableView down.
[[EarlGrey selectElementWithMatcher:grey_accessibilityID(
kHistoryTableViewIdentifier)]
performAction:grey_swipeFastInDirection(kGREYDirectionDown)];
// Check that the TableView has been dismissed.
[[EarlGrey selectElementWithMatcher:grey_accessibilityID(
kHistoryTableViewIdentifier)]
assertWithMatcher:grey_nil()];
}
// Tests that the VC can be dismissed by swiping down while its searching.
- (void)testSwipeDownDismissWhileSearching {
// TODO(crbug.com/40689184): Test fails on iOS 13+ iPad devices.
#if !TARGET_IPHONE_SIMULATOR
if ([ChromeEarlGrey isIPadIdiom]) {
EARL_GREY_TEST_DISABLED(@"This test fails on iOS 13+ iPad device.");
}
#endif
[self loadTestURLs];
[self openHistoryPanel];
// Check that the TableView is presented.
[[EarlGrey selectElementWithMatcher:grey_accessibilityID(
kHistoryTableViewIdentifier)]
assertWithMatcher:grey_notNil()];
// Search for the first URL.
[[EarlGrey selectElementWithMatcher:SearchIconButton()]
performAction:grey_tap()];
NSString* searchString =
[NSString stringWithFormat:@"%s", _URL1.path().c_str()];
[[EarlGrey selectElementWithMatcher:SearchIconButton()]
performAction:grey_replaceText(searchString)];
// Swipe TableView down.
[[EarlGrey selectElementWithMatcher:grey_accessibilityID(
kHistoryTableViewIdentifier)]
performAction:grey_swipeFastInDirection(kGREYDirectionDown)];
// Check that the TableView has been dismissed.
[[EarlGrey selectElementWithMatcher:grey_accessibilityID(
kHistoryTableViewIdentifier)]
assertWithMatcher:grey_nil()];
}
// Navigates to history and checks elements for accessibility.
- (void)testAccessibilityOnHistory {
[self loadTestURLs];
[self openHistoryPanel];
[ChromeEarlGrey waitForSufficientlyVisibleElementWithMatcher:
grey_accessibilityID(kHistoryTableViewIdentifier)];
[ChromeEarlGrey verifyAccessibilityForCurrentScreen];
// Close history.
id<GREYMatcher> exitMatcher =
grey_accessibilityID(kHistoryNavigationControllerDoneButtonIdentifier);
[[EarlGrey selectElementWithMatcher:exitMatcher] performAction:grey_tap()];
}
- (void)testEmptyState {
[self loadTestURLs];
[self openHistoryPanel];
// The toolbar should contain the CBD and edit buttons.
[[EarlGrey selectElementWithMatcher:chrome_test_util::
HistoryClearBrowsingDataButton()]
assertWithMatcher:grey_notNil()];
[[EarlGrey selectElementWithMatcher:NavigationEditButton()]
assertWithMatcher:grey_notNil()];
[ChromeEarlGreyUI openAndClearBrowsingDataFromHistory];
// Toolbar should only contain CBD button and the background should contain
// the Illustrated empty view
[[EarlGrey selectElementWithMatcher:chrome_test_util::
HistoryClearBrowsingDataButton()]
assertWithMatcher:grey_notNil()];
[[EarlGrey selectElementWithMatcher:NavigationEditButton()]
assertWithMatcher:grey_nil()];
[[EarlGrey selectElementWithMatcher:EmptyIllustratedTableViewBackground()]
assertWithMatcher:grey_notNil()];
}
#pragma mark Multiwindow
- (void)testHistorySyncInMultiwindow {
// TODO(crbug.com/40198758): Test is flaky on iPad devices.
if ([ChromeEarlGrey isIPadIdiom]) {
EARL_GREY_TEST_DISABLED(@"This test is flaky on iPad devices.");
}
if (![ChromeEarlGrey areMultipleWindowsSupported])
EARL_GREY_TEST_DISABLED(@"Multiple windows can't be opened.");
// Create history in first window.
[self loadTestURLs];
// Open history panel in a second window
[ChromeEarlGrey openNewWindow];
[ChromeEarlGrey waitUntilReadyWindowWithNumber:1];
[ChromeEarlGrey waitForForegroundWindowCount:2];
[self openHistoryPanelInWindowWithNumber:1];
// Assert that three history elements are present in second window.
[[EarlGrey
selectElementWithMatcher:
HistoryEntry(
base::UTF16ToUTF8(
url_formatter::
FormatUrlForDisplayOmitSchemePathTrivialSubdomainsAndMobilePrefix(
_URL1)),
kTitle1)] assertWithMatcher:grey_notNil()];
[[EarlGrey
selectElementWithMatcher:
HistoryEntry(
base::UTF16ToUTF8(
url_formatter::
FormatUrlForDisplayOmitSchemePathTrivialSubdomainsAndMobilePrefix(
_URL2)),
kTitle2)] assertWithMatcher:grey_notNil()];
[[EarlGrey
selectElementWithMatcher:
HistoryEntry(
base::UTF16ToUTF8(
url_formatter::
FormatUrlForDisplayOmitSchemePathTrivialSubdomainsAndMobilePrefix(
_URL3)),
_URL3.GetContent())] assertWithMatcher:grey_notNil()];
// Open history panel in first window also.
[self openHistoryPanelInWindowWithNumber:0];
// Assert that three history elements are present in first window.
[[EarlGrey
selectElementWithMatcher:
HistoryEntry(
base::UTF16ToUTF8(
url_formatter::
FormatUrlForDisplayOmitSchemePathTrivialSubdomainsAndMobilePrefix(
_URL1)),
kTitle1)] assertWithMatcher:grey_notNil()];
[[EarlGrey
selectElementWithMatcher:
HistoryEntry(
base::UTF16ToUTF8(
url_formatter::
FormatUrlForDisplayOmitSchemePathTrivialSubdomainsAndMobilePrefix(
_URL2)),
kTitle2)] assertWithMatcher:grey_notNil()];
[[EarlGrey
selectElementWithMatcher:
HistoryEntry(
base::UTF16ToUTF8(
url_formatter::
FormatUrlForDisplayOmitSchemePathTrivialSubdomainsAndMobilePrefix(
_URL3)),
_URL3.GetContent())] assertWithMatcher:grey_notNil()];
// Delete item 1 from first window.
[[EarlGrey
selectElementWithMatcher:
HistoryEntry(
base::UTF16ToUTF8(
url_formatter::
FormatUrlForDisplayOmitSchemePathTrivialSubdomainsAndMobilePrefix(
_URL1)),
kTitle1)] performAction:grey_longPress()];
[[EarlGrey selectElementWithMatcher:DeleteButton()] performAction:grey_tap()];
[[EarlGrey
selectElementWithMatcher:
HistoryEntry(
base::UTF16ToUTF8(
url_formatter::
FormatUrlForDisplayOmitSchemePathTrivialSubdomainsAndMobilePrefix(
_URL1)),
kTitle1)] assertWithMatcher:grey_nil()];
// And make sure it has disappeared from second window.
[EarlGrey setRootMatcherForSubsequentInteractions:WindowWithNumber(1)];
[[EarlGrey
selectElementWithMatcher:
HistoryEntry(
base::UTF16ToUTF8(
url_formatter::
FormatUrlForDisplayOmitSchemePathTrivialSubdomainsAndMobilePrefix(
_URL1)),
kTitle1)] assertWithMatcher:grey_nil()];
}
#pragma mark Helper Methods
- (void)loadTestURLs {
[ChromeEarlGrey loadURL:_URL1];
[ChromeEarlGrey waitForWebStateContainingText:kResponse1];
[ChromeEarlGrey loadURL:_URL2];
[ChromeEarlGrey waitForWebStateContainingText:kResponse2];
[ChromeEarlGrey loadURL:_URL3];
[ChromeEarlGrey waitForWebStateContainingText:kResponse3];
}
- (void)openHistoryPanel {
[ChromeEarlGreyUI openToolsMenu];
[ChromeEarlGreyUI
tapToolsMenuButton:chrome_test_util::HistoryDestinationButton()];
}
- (void)openHistoryPanelInWindowWithNumber:(int)windowNumber {
[ChromeEarlGreyUI openToolsMenuInWindowWithNumber:windowNumber];
[ChromeEarlGreyUI
tapToolsMenuButton:chrome_test_util::HistoryDestinationButton()];
}
@end