| // Copyright 2018 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "base/bind.h" |
| #include "base/strings/sys_string_conversions.h" |
| #include "components/strings/grit/components_strings.h" |
| #import "ios/chrome/browser/ui/toolbar/adaptive_toolbar_app_interface.h" |
| #import "ios/chrome/browser/ui/toolbar/public/toolbar_constants.h" |
| #import "ios/chrome/browser/ui/util/named_guide.h" |
| #include "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_app_interface.h" |
| #import "ios/chrome/test/earl_grey/chrome_matchers.h" |
| #import "ios/chrome/test/earl_grey/chrome_test_case.h" |
| #include "ios/testing/earl_grey/disabled_test_macros.h" |
| #import "ios/testing/earl_grey/disabled_test_macros.h" |
| #import "ios/testing/earl_grey/earl_grey_test.h" |
| #include "ios/web/public/test/element_selector.h" |
| #include "net/test/embedded_test_server/embedded_test_server.h" |
| #include "net/test/embedded_test_server/http_request.h" |
| #include "net/test/embedded_test_server/http_response.h" |
| #include "ui/base/l10n/l10n_util_mac.h" |
| |
| #if !defined(__has_feature) || !__has_feature(objc_arc) |
| #error "This file requires ARC support." |
| #endif |
| |
| #if defined(CHROME_EARL_GREY_2) |
| // TODO(crbug.com/1015113) The EG2 macro is breaking indexing for some reason |
| // without the trailing semicolon. For now, disable the extra semi warning |
| // so Xcode indexing works for the egtest. |
| #pragma clang diagnostic push |
| #pragma clang diagnostic ignored "-Wc++98-compat-extra-semi" |
| GREY_STUB_CLASS_IN_APP_MAIN_QUEUE(AdaptiveToolbarAppInterface); |
| #pragma clang diagnostic pop |
| #endif // defined(CHROME_EARL_GREY_2) |
| |
| namespace { |
| |
| using chrome_test_util::BackButton; |
| using chrome_test_util::ForwardButton; |
| using chrome_test_util::WebStateScrollViewMatcher; |
| using chrome_test_util::WebViewMatcher; |
| |
| const char kPageURL[] = "/test-page.html"; |
| const char kPageURL2[] = "/test-page-2.html"; |
| const char kPageURL3[] = "/test-page-3.html"; |
| const char kLinkID[] = "linkID"; |
| const char kPageLoadedString[] = "Page loaded!"; |
| |
| // The title of the test infobar. |
| NSString* kTestInfoBarTitle = @"TestInfoBar"; |
| |
| // Defines the visibility of an element, in relation to the toolbar. |
| typedef NS_ENUM(NSInteger, ButtonVisibility) { |
| ButtonVisibilityNone, |
| ButtonVisibilityPrimary, |
| ButtonVisibilitySecondary |
| }; |
| |
| // Provides responses for redirect and changed window location 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); |
| http_response->set_content( |
| "<html><body><p>" + std::string(kPageLoadedString) + "</p><a href=\"" + |
| kPageURL3 + "\" id=\"" + kLinkID + "\">link!</a></body></html>"); |
| return std::move(http_response); |
| } |
| |
| // Returns a matcher for the bookmark button. |
| id<GREYMatcher> BookmarkButton() { |
| return chrome_test_util::ButtonWithAccessibilityLabelId(IDS_TOOLTIP_STAR); |
| } |
| |
| // Returns a matcher for the visible share button. |
| id<GREYMatcher> ShareButton() { |
| return grey_allOf(grey_accessibilityID(kToolbarShareButtonIdentifier), |
| grey_sufficientlyVisible(), nil); |
| } |
| |
| // Returns a matcher for the reload button. |
| id<GREYMatcher> ReloadButton() { |
| return chrome_test_util::ButtonWithAccessibilityLabelId( |
| IDS_IOS_ACCNAME_RELOAD); |
| } |
| |
| // Returns a matcher for the tools menu button. |
| id<GREYMatcher> ToolsMenuButton() { |
| return chrome_test_util::ButtonWithAccessibilityLabelId( |
| IDS_IOS_TOOLBAR_SETTINGS); |
| } |
| |
| // Returns a matcher for the cancel button. |
| id<GREYMatcher> CancelButton() { |
| return chrome_test_util::ButtonWithAccessibilityLabelId(IDS_CANCEL); |
| } |
| |
| // Returns a matcher for the search button. |
| id<GREYMatcher> NewTabButton() { |
| return grey_accessibilityID(kToolbarNewTabButtonIdentifier); |
| } |
| |
| // Returns a matcher for the tab grid button. |
| id<GREYMatcher> TabGridButton() { |
| return chrome_test_util::ButtonWithAccessibilityLabelId( |
| IDS_IOS_TOOLBAR_SHOW_TABS); |
| } |
| |
| // Returns a matcher for a UIResponder object being first responder. |
| id<GREYMatcher> firstResponder() { |
| GREYMatchesBlock matches = ^BOOL(UIResponder* responder) { |
| return [responder isFirstResponder]; |
| }; |
| GREYDescribeToBlock describe = ^void(id<GREYDescription> description) { |
| [description appendText:@"first responder"]; |
| }; |
| return grey_allOf( |
| grey_kindOfClass([UIResponder class]), |
| [[GREYElementMatcherBlock alloc] initWithMatchesBlock:matches |
| descriptionBlock:describe], |
| nil); |
| } |
| |
| // Returns a matcher for elements being subviews of the PrimaryToolbarView and |
| // sufficientlyVisible. |
| id<GREYMatcher> VisibleInPrimaryToolbar() { |
| return grey_allOf(grey_ancestor(grey_kindOfClassName(@"PrimaryToolbarView")), |
| grey_sufficientlyVisible(), nil); |
| } |
| |
| // Returns a matcher for elements being subviews of the SecondaryToolbarView and |
| // sufficientlyVisible. |
| id<GREYMatcher> VisibleInSecondaryToolbar() { |
| return grey_allOf( |
| grey_ancestor(grey_kindOfClassName(@"SecondaryToolbarView")), |
| grey_sufficientlyVisible(), nil); |
| } |
| |
| // Checks that the element designated by |matcher| is |visible| in the primary |
| // toolbar. |
| void CheckVisibleInPrimaryToolbar(id<GREYMatcher> matcher, BOOL visible) { |
| id<GREYMatcher> assertionMatcher = visible ? grey_notNil() : grey_nil(); |
| [[EarlGrey |
| selectElementWithMatcher:grey_allOf(matcher, VisibleInPrimaryToolbar(), |
| nil)] |
| assertWithMatcher:assertionMatcher]; |
| } |
| |
| // Checks that the element designed by |matcher| is |visible| in the secondary |
| // toolbar. |
| void CheckVisibleInSecondaryToolbar(id<GREYMatcher> matcher, BOOL visible) { |
| id<GREYMatcher> assertionMatcher = visible ? grey_notNil() : grey_nil(); |
| [[EarlGrey |
| selectElementWithMatcher:grey_allOf(matcher, VisibleInSecondaryToolbar(), |
| nil)] |
| assertWithMatcher:assertionMatcher]; |
| } |
| |
| // Returns a matcher for a UIControl object being spotlighted. |
| id<GREYMatcher> Spotlighted() { |
| GREYMatchesBlock matches = ^BOOL(UIControl* control) { |
| return control.state & kControlStateSpotlighted; |
| }; |
| GREYDescribeToBlock describe = ^void(id<GREYDescription> description) { |
| [description appendText:@"is spotlighted"]; |
| }; |
| return grey_allOf( |
| grey_kindOfClass([UIControl class]), |
| [[GREYElementMatcherBlock alloc] initWithMatchesBlock:matches |
| descriptionBlock:describe], |
| nil); |
| } |
| |
| // Rotate the device if it is an iPhone or change the trait collection to |
| // compact width if it is an iPad. Returns the new trait collection. |
| UITraitCollection* RotateOrChangeTraitCollection( |
| UITraitCollection* originalTraitCollection, |
| UIViewController* topViewController) { |
| // Change the orientation or the trait collection. |
| if ([ChromeEarlGrey isIPadIdiom]) { |
| // Simulate a multitasking by overriding the trait collections of the view |
| // controllers. The rotation doesn't work on iPad. |
| return [AdaptiveToolbarAppInterface |
| changeTraitCollection:originalTraitCollection |
| forViewController:topViewController]; |
| } else { |
| // On iPhone rotate to test the the landscape orientation. |
| [ChromeEarlGrey rotateDeviceToOrientation:UIDeviceOrientationLandscapeLeft |
| error:nil]; |
| return topViewController.traitCollection; |
| } |
| } |
| |
| // Checks that the element associated with |matcher| is visible in the toolbar |
| // defined by |visibility|. |
| void CheckVisibilityInToolbar(id<GREYMatcher> matcher, |
| ButtonVisibility visibility) { |
| CheckVisibleInPrimaryToolbar(matcher, visibility == ButtonVisibilityPrimary); |
| CheckVisibleInSecondaryToolbar(matcher, |
| visibility == ButtonVisibilitySecondary); |
| } |
| |
| // Checks the visibility of the different part of the omnibox, depending on it |
| // being focused or not. |
| void CheckOmniboxVisibility(BOOL omniboxFocused) { |
| // Check omnibox/steady view visibility. |
| if (omniboxFocused) { |
| // Check that the omnibox is visible. |
| CheckVisibleInPrimaryToolbar(chrome_test_util::Omnibox(), YES); |
| } else { |
| // Check that location view is visible. |
| CheckVisibleInPrimaryToolbar(chrome_test_util::DefocusedLocationView(), |
| YES); |
| } |
| } |
| |
| // Check the visibility of the buttons if the device is an iPhone in portrait or |
| // an iPad in multitasking. |
| void CheckButtonsVisibilityIPhonePortrait(BOOL omniboxFocused) { |
| // Check that the cancel button visibility. |
| if (omniboxFocused) { |
| CheckVisibilityInToolbar(CancelButton(), ButtonVisibilityPrimary); |
| |
| CheckVisibilityInToolbar(ShareButton(), ButtonVisibilityNone); |
| CheckVisibilityInToolbar(ReloadButton(), ButtonVisibilityNone); |
| CheckVisibilityInToolbar(BookmarkButton(), ButtonVisibilityNone); |
| |
| // Those buttons are hidden by the keyboard. |
| CheckVisibilityInToolbar(BackButton(), ButtonVisibilityNone); |
| CheckVisibilityInToolbar(ForwardButton(), ButtonVisibilityNone); |
| CheckVisibilityInToolbar(NewTabButton(), ButtonVisibilityNone); |
| CheckVisibilityInToolbar(TabGridButton(), ButtonVisibilityNone); |
| CheckVisibilityInToolbar(ToolsMenuButton(), ButtonVisibilityNone); |
| } else { |
| CheckVisibilityInToolbar(CancelButton(), ButtonVisibilityNone); |
| |
| CheckVisibilityInToolbar(ShareButton(), ButtonVisibilityNone); |
| CheckVisibilityInToolbar(ReloadButton(), ButtonVisibilityNone); |
| CheckVisibilityInToolbar(BookmarkButton(), ButtonVisibilityNone); |
| |
| CheckVisibilityInToolbar(BackButton(), ButtonVisibilitySecondary); |
| CheckVisibilityInToolbar(ForwardButton(), ButtonVisibilitySecondary); |
| CheckVisibilityInToolbar(NewTabButton(), ButtonVisibilitySecondary); |
| CheckVisibilityInToolbar(TabGridButton(), ButtonVisibilitySecondary); |
| CheckVisibilityInToolbar(ToolsMenuButton(), ButtonVisibilitySecondary); |
| } |
| } |
| |
| // Check the visibility of the buttons if the device is an iPhone in landscape. |
| void CheckButtonsVisibilityIPhoneLandscape(BOOL omniboxFocused) { |
| if (omniboxFocused) { |
| // Omnibox focused in iPhone landscape. |
| CheckVisibilityInToolbar(CancelButton(), ButtonVisibilityPrimary); |
| |
| CheckVisibilityInToolbar(ShareButton(), ButtonVisibilityNone); |
| CheckVisibilityInToolbar(ReloadButton(), ButtonVisibilityNone); |
| CheckVisibilityInToolbar(BookmarkButton(), ButtonVisibilityNone); |
| |
| CheckVisibilityInToolbar(BackButton(), ButtonVisibilityNone); |
| CheckVisibilityInToolbar(ForwardButton(), ButtonVisibilityNone); |
| CheckVisibilityInToolbar(NewTabButton(), ButtonVisibilityNone); |
| CheckVisibilityInToolbar(TabGridButton(), ButtonVisibilityNone); |
| CheckVisibilityInToolbar(ToolsMenuButton(), ButtonVisibilityNone); |
| } else { |
| CheckVisibilityInToolbar(CancelButton(), ButtonVisibilityNone); |
| |
| CheckVisibilityInToolbar(ShareButton(), ButtonVisibilityPrimary); |
| CheckVisibilityInToolbar(ReloadButton(), ButtonVisibilityPrimary); |
| CheckVisibilityInToolbar(BookmarkButton(), ButtonVisibilityNone); |
| |
| CheckVisibilityInToolbar(BackButton(), ButtonVisibilityPrimary); |
| CheckVisibilityInToolbar(ForwardButton(), ButtonVisibilityPrimary); |
| CheckVisibilityInToolbar(NewTabButton(), ButtonVisibilityNone); |
| CheckVisibilityInToolbar(TabGridButton(), ButtonVisibilityPrimary); |
| CheckVisibilityInToolbar(ToolsMenuButton(), ButtonVisibilityPrimary); |
| } |
| // The secondary toolbar is not visible. |
| [[EarlGrey |
| selectElementWithMatcher:grey_kindOfClassName(@"SecondaryToolbarView")] |
| assertWithMatcher:grey_not(grey_sufficientlyVisible())]; |
| } |
| |
| // Check the visibility of the buttons if the device is an iPad not in |
| // multitasking. |
| void CheckButtonsVisibilityIPad() { |
| CheckVisibilityInToolbar(CancelButton(), ButtonVisibilityNone); |
| |
| CheckVisibilityInToolbar(ShareButton(), ButtonVisibilityPrimary); |
| CheckVisibilityInToolbar(ReloadButton(), ButtonVisibilityPrimary); |
| if ([ChromeEarlGrey isChangeTabSwitcherPositionEnabled]) { |
| CheckVisibilityInToolbar(BookmarkButton(), ButtonVisibilityNone); |
| CheckVisibilityInToolbar(TabGridButton(), ButtonVisibilityPrimary); |
| } else { |
| CheckVisibilityInToolbar(BookmarkButton(), ButtonVisibilityPrimary); |
| CheckVisibilityInToolbar(TabGridButton(), ButtonVisibilityNone); |
| } |
| |
| CheckVisibilityInToolbar(BackButton(), ButtonVisibilityPrimary); |
| CheckVisibilityInToolbar(ForwardButton(), ButtonVisibilityPrimary); |
| CheckVisibilityInToolbar(NewTabButton(), ButtonVisibilityNone); |
| CheckVisibilityInToolbar(ToolsMenuButton(), ButtonVisibilityPrimary); |
| |
| // The secondary toolbar is not visible. |
| [[EarlGrey |
| selectElementWithMatcher:grey_kindOfClassName(@"SecondaryToolbarView")] |
| assertWithMatcher:grey_not(grey_sufficientlyVisible())]; |
| } |
| |
| // Check that the button displayed are the ones which should be displayed in the |
| // environment described by |traitCollection| and with |omniboxFocused|. |
| void CheckToolbarButtonVisibility(UITraitCollection* traitCollection, |
| BOOL omniboxFocused) { |
| CheckOmniboxVisibility(omniboxFocused); |
| |
| // Button checks. |
| if (traitCollection.horizontalSizeClass == UIUserInterfaceSizeClassCompact && |
| traitCollection.verticalSizeClass != UIUserInterfaceSizeClassCompact) { |
| CheckButtonsVisibilityIPhonePortrait(omniboxFocused); |
| } else if (traitCollection.verticalSizeClass == |
| UIUserInterfaceSizeClassCompact) { |
| CheckButtonsVisibilityIPhoneLandscape(omniboxFocused); |
| } else { |
| CheckButtonsVisibilityIPad(); |
| } |
| } |
| |
| // Check that current URL contains a given string by tapping on the location |
| // view to focus the omnibox where the full URL can be seen, then comparing |
| // the strings, and finally defocusing the omnibox. |
| void CheckCurrentURLContainsString(std::string string) { |
| [[EarlGrey |
| selectElementWithMatcher:chrome_test_util::DefocusedLocationView()] |
| performAction:grey_tap()]; |
| [[EarlGrey selectElementWithMatcher:chrome_test_util::Omnibox()] |
| assertWithMatcher:chrome_test_util::OmniboxContainingText(string)]; |
| |
| if ([ChromeEarlGrey isIPadIdiom]) { |
| // Defocus omnibox by tapping the typing shield. |
| [[EarlGrey |
| selectElementWithMatcher:grey_accessibilityID(@"Typing Shield")] |
| performAction:grey_tap()]; |
| |
| } else { |
| [[EarlGrey |
| selectElementWithMatcher: |
| grey_accessibilityID(kToolbarCancelOmniboxEditButtonIdentifier)] |
| performAction:grey_tap()]; |
| } |
| } |
| |
| void FocusOmnibox() { |
| [[EarlGrey |
| selectElementWithMatcher:chrome_test_util::DefocusedLocationView()] |
| performAction:grey_tap()]; |
| [[EarlGrey selectElementWithMatcher:chrome_test_util::Omnibox()] |
| assertWithMatcher:firstResponder()]; |
| } |
| |
| UIViewController* TopPresentedViewControllerFrom( |
| UIViewController* base_view_controller) { |
| UIViewController* topController = base_view_controller; |
| for (UIViewController* controller = [topController presentedViewController]; |
| controller && ![controller isBeingDismissed]; |
| controller = [controller presentedViewController]) { |
| topController = controller; |
| } |
| return topController; |
| } |
| |
| UIViewController* TopPresentedViewController() { |
| UIViewController* rootViewController = |
| #if defined(CHROME_EARL_GREY_1) |
| [[UIApplication sharedApplication] keyWindow].rootViewController; |
| #else |
| [[GREY_REMOTE_CLASS_IN_APP(UIApplication) sharedApplication] keyWindow] |
| .rootViewController; |
| #endif |
| return TopPresentedViewControllerFrom(rootViewController); |
| } |
| |
| } // namespace |
| |
| #pragma mark - TestCase |
| |
| // Test case for the adaptive toolbar UI. |
| @interface AdaptiveToolbarTestCase : ChromeTestCase |
| |
| @end |
| |
| @implementation AdaptiveToolbarTestCase |
| |
| // Tests that bookmarks button is spotlighted for the bookmarked pages. |
| - (void)testBookmarkButton { |
| if (![ChromeEarlGrey isRegularXRegularSizeClass] || |
| [ChromeEarlGrey isChangeTabSwitcherPositionEnabled]) { |
| EARL_GREY_TEST_SKIPPED( |
| @"The bookmark button is only visible on Regular x Regular size " |
| @"classes."); |
| } |
| |
| // Setup the bookmarks. |
| [ChromeEarlGrey waitForBookmarksToFinishLoading]; |
| [ChromeEarlGrey clearBookmarks]; |
| |
| // Setup the server. |
| self.testServer->RegisterRequestHandler( |
| base::BindRepeating(&StandardResponse)); |
| GREYAssertTrue(self.testServer->Start(), @"Test server failed to start."); |
| |
| // Navigate to a page and check the bookmark button is not spotlighted. |
| [ChromeEarlGrey loadURL:self.testServer->GetURL(kPageURL)]; |
| [[EarlGrey selectElementWithMatcher:BookmarkButton()] |
| assertWithMatcher:grey_allOf(grey_kindOfClass([UIControl class]), |
| grey_not(Spotlighted()), nil)]; |
| |
| // Bookmark the page. |
| [[EarlGrey selectElementWithMatcher:BookmarkButton()] |
| performAction:grey_tap()]; |
| [[EarlGrey selectElementWithMatcher:BookmarkButton()] |
| assertWithMatcher:Spotlighted()]; |
| |
| // Navigate to a different page and check the button is not selected. |
| [ChromeEarlGrey loadURL:self.testServer->GetURL(kPageURL2)]; |
| [[EarlGrey selectElementWithMatcher:BookmarkButton()] |
| assertWithMatcher:grey_allOf(grey_kindOfClass([UIControl class]), |
| grey_not(Spotlighted()), nil)]; |
| |
| // Navigate back to the bookmarked page and check the button. |
| [ChromeEarlGrey loadURL:self.testServer->GetURL(kPageURL)]; |
| [[EarlGrey selectElementWithMatcher:BookmarkButton()] |
| assertWithMatcher:Spotlighted()]; |
| |
| // Clean the bookmarks |
| [ChromeEarlGrey clearBookmarks]; |
| } |
| |
| // Tests that tapping a button cancels the focus on the omnibox. |
| - (void)testCancelOmniboxEdit { |
| if ([ChromeEarlGrey isCompactWidth]) { |
| EARL_GREY_TEST_SKIPPED(@"No button to tap in compact width."); |
| } |
| |
| // Navigate to a page to enable the back button. |
| [ChromeEarlGrey loadURL:GURL("chrome://version")]; |
| |
| FocusOmnibox(); |
| |
| // Tap the back button and check the omnibox is unfocused. |
| [[EarlGrey selectElementWithMatcher:chrome_test_util::BackButton()] |
| performAction:grey_tap()]; |
| [[EarlGrey selectElementWithMatcher:chrome_test_util::Omnibox()] |
| assertWithMatcher:grey_not(firstResponder())]; |
| } |
| |
| // Check the button visibility of the toolbar when the omnibox is focused from a |
| // different orientation than the default one. |
| - (void)testFocusOmniboxFromOtherOrientation { |
| // Load a page to have the toolbar visible (hidden on NTP). |
| [ChromeEarlGrey loadURL:GURL("chrome://version")]; |
| |
| // Get the original trait collection. |
| UIViewController* topViewController = TopPresentedViewController(); |
| UITraitCollection* originalTraitCollection = |
| topViewController.traitCollection; |
| |
| // Change the orientation or the trait collection. |
| UITraitCollection* secondTraitCollection = |
| RotateOrChangeTraitCollection(originalTraitCollection, topViewController); |
| |
| FocusOmnibox(); |
| |
| // Check the visiblity when focusing the omnibox. |
| CheckToolbarButtonVisibility(secondTraitCollection, YES); |
| |
| // Revert the orientation/trait collection to the original. |
| if ([ChromeEarlGrey isIPadIdiom]) { |
| // Remove the override. |
| for (UIViewController* child in topViewController.childViewControllers) { |
| [topViewController setOverrideTraitCollection:originalTraitCollection |
| forChildViewController:child]; |
| } |
| } else { |
| // Cancel the rotation. |
| [ChromeEarlGrey rotateDeviceToOrientation:UIDeviceOrientationPortrait |
| error:nil]; |
| } |
| |
| // Check the visiblity after a rotation. |
| CheckToolbarButtonVisibility(originalTraitCollection, YES); |
| } |
| |
| // Check the button visibility of the toolbar when the omnibox is focused from |
| // the default orientation. |
| - (void)testFocusOmniboxFromPortrait { |
| // Load a page to have the toolbar visible (hidden on NTP). |
| [ChromeEarlGrey loadURL:GURL("chrome://version")]; |
| |
| FocusOmnibox(); |
| |
| // Get the original trait collection. |
| UIViewController* topViewController = TopPresentedViewController(); |
| UITraitCollection* originalTraitCollection = |
| topViewController.traitCollection; |
| |
| // Check the button visibility. |
| CheckToolbarButtonVisibility(originalTraitCollection, YES); |
| |
| // Change the orientation or the trait collection. |
| UITraitCollection* secondTraitCollection = |
| RotateOrChangeTraitCollection(originalTraitCollection, topViewController); |
| |
| // Check the visiblity after a size class change. |
| CheckToolbarButtonVisibility(secondTraitCollection, YES); |
| |
| if ([ChromeEarlGrey isIPadIdiom]) { |
| // Remove the override. |
| for (UIViewController* child in topViewController.childViewControllers) { |
| [topViewController setOverrideTraitCollection:originalTraitCollection |
| forChildViewController:child]; |
| } |
| } else { |
| // Cancel the rotation. |
| [ChromeEarlGrey rotateDeviceToOrientation:UIDeviceOrientationPortrait |
| error:nil]; |
| } |
| |
| // Check the visiblity after a size class change. This should let the trait |
| // collection change come into effect. |
| CheckToolbarButtonVisibility(originalTraitCollection, YES); |
| } |
| |
| // Verifies that the back/forward buttons are working and are correctly enabled |
| // during navigations. |
| - (void)testNavigationButtons { |
| // Setup the server. |
| self.testServer->RegisterRequestHandler( |
| base::BindRepeating(&StandardResponse)); |
| GREYAssertTrue(self.testServer->Start(), @"Test server failed to start."); |
| |
| // Loads two url and check the navigation buttons status. |
| [ChromeEarlGrey loadURL:self.testServer->GetURL(kPageURL)]; |
| [ChromeEarlGrey loadURL:self.testServer->GetURL(kPageURL2)]; |
| [[EarlGrey selectElementWithMatcher:chrome_test_util::BackButton()] |
| assertWithMatcher:grey_interactable()]; |
| [[EarlGrey selectElementWithMatcher:chrome_test_util::ForwardButton()] |
| assertWithMatcher:grey_not(grey_enabled())]; |
| |
| // Check the navigation to the second page occurred. |
| CheckCurrentURLContainsString(kPageURL2); |
| |
| // Go back. |
| [[EarlGrey selectElementWithMatcher:chrome_test_util::BackButton()] |
| performAction:grey_tap()]; |
| CheckCurrentURLContainsString(kPageURL); |
| |
| // Check the buttons status. |
| [[EarlGrey selectElementWithMatcher:chrome_test_util::BackButton()] |
| assertWithMatcher:grey_interactable()]; |
| [[EarlGrey selectElementWithMatcher:chrome_test_util::ForwardButton()] |
| assertWithMatcher:grey_interactable()]; |
| |
| // Go forward. |
| [[EarlGrey selectElementWithMatcher:chrome_test_util::ForwardButton()] |
| performAction:grey_tap()]; |
| CheckCurrentURLContainsString(kPageURL2); |
| |
| // Check the buttons status. |
| [[EarlGrey selectElementWithMatcher:chrome_test_util::BackButton()] |
| assertWithMatcher:grey_interactable()]; |
| [[EarlGrey selectElementWithMatcher:chrome_test_util::ForwardButton()] |
| assertWithMatcher:grey_not(grey_enabled())]; |
| |
| // Open a page in a new incognito tab to have the focus. |
| [[EarlGrey selectElementWithMatcher:WebViewMatcher()] |
| performAction:chrome_test_util::LongPressElementForContextMenu( |
| [ElementSelector selectorWithElementID:kLinkID], |
| true /* menu should appear */)]; |
| [[EarlGrey selectElementWithMatcher: |
| chrome_test_util::StaticTextWithAccessibilityLabelId( |
| IDS_IOS_CONTENT_CONTEXT_OPENLINKNEWINCOGNITOTAB)] |
| performAction:grey_tap()]; |
| |
| // Check the buttons status. |
| [[EarlGrey selectElementWithMatcher:chrome_test_util::BackButton()] |
| assertWithMatcher:grey_not(grey_enabled())]; |
| [[EarlGrey selectElementWithMatcher:chrome_test_util::ForwardButton()] |
| assertWithMatcher:grey_not(grey_enabled())]; |
| } |
| |
| // Tests that tapping the NewTab button opens a new tab. |
| - (void)testNewTabButton { |
| if (![ChromeEarlGrey isSplitToolbarMode]) { |
| EARL_GREY_TEST_SKIPPED(@"No button to tap."); |
| } |
| |
| [ChromeEarlGrey waitForMainTabCount:1]; |
| |
| [[EarlGrey selectElementWithMatcher:grey_accessibilityID( |
| kToolbarNewTabButtonIdentifier)] |
| performAction:grey_tap()]; |
| |
| [ChromeEarlGrey waitForMainTabCount:2]; |
| } |
| |
| // Tests share button is enabled only on pages that can be shared. |
| - (void)testShareButton { |
| if (![ChromeEarlGrey isIPadIdiom]) { |
| // If this test is run on an iPhone, rotate it to have the unsplit toolbar. |
| [ChromeEarlGrey rotateDeviceToOrientation:UIDeviceOrientationLandscapeLeft |
| error:nil]; |
| } |
| |
| // Setup the server. |
| self.testServer->RegisterRequestHandler( |
| base::BindRepeating(&StandardResponse)); |
| GREYAssertTrue(self.testServer->Start(), @"Test server failed to start."); |
| const GURL pageURL = self.testServer->GetURL(kPageURL); |
| |
| // Navigate to another page and check that the share button is enabled. |
| [ChromeEarlGrey loadURL:pageURL]; |
| [[EarlGrey selectElementWithMatcher:ShareButton()] |
| assertWithMatcher:grey_interactable()]; |
| |
| if (![ChromeEarlGrey isIPadIdiom]) { |
| // Cancel rotation. |
| [ChromeEarlGrey rotateDeviceToOrientation:UIDeviceOrientationPortrait |
| error:nil]; |
| } |
| } |
| |
| // Test that the bottom toolbar is still visible after closing the last |
| // incognito tab using long press. See https://crbug.com/849937. |
| - (void)testBottomToolbarHeightAfterClosingTab { |
| if (![ChromeEarlGrey isSplitToolbarMode]) |
| EARL_GREY_TEST_SKIPPED(@"This test needs a bottom toolbar."); |
| // Close all tabs. |
| [[EarlGrey selectElementWithMatcher:TabGridButton()] |
| performAction:grey_tap()]; |
| [[EarlGrey selectElementWithMatcher:chrome_test_util:: |
| TabGridCloseButtonForCellAtIndex(0)] |
| performAction:grey_tap()]; |
| |
| // Open incognito tab. |
| [[EarlGrey selectElementWithMatcher:chrome_test_util:: |
| TabGridIncognitoTabsPanelButton()] |
| performAction:grey_tap()]; |
| [[EarlGrey |
| selectElementWithMatcher:chrome_test_util::TabGridNewIncognitoTabButton()] |
| performAction:grey_tap()]; |
| [[GREYUIThreadExecutor sharedInstance] drainUntilIdleWithTimeout:2]; |
| |
| [[self class] closeAllTabs]; |
| [ChromeEarlGrey openNewTab]; |
| |
| // Check that the bottom toolbar is visible. |
| [[EarlGrey selectElementWithMatcher:NewTabButton()] |
| assertWithMatcher:grey_sufficientlyVisible()]; |
| } |
| |
| // Verifies the existence and state of toolbar UI elements. |
| - (void)testToolbarUI { |
| // Load a page to have the toolbar visible (hidden on NTP). |
| [ChromeEarlGrey loadURL:GURL("chrome://version")]; |
| |
| // Get the original trait collection. |
| UIViewController* topViewController = TopPresentedViewController(); |
| UITraitCollection* originalTraitCollection = |
| topViewController.traitCollection; |
| |
| // Check the button visibility. |
| CheckToolbarButtonVisibility(originalTraitCollection, NO); |
| |
| // Change the orientation or the trait collection. |
| UITraitCollection* secondTraitCollection = |
| RotateOrChangeTraitCollection(originalTraitCollection, topViewController); |
| |
| // Check the visiblity after a size class change. |
| CheckToolbarButtonVisibility(secondTraitCollection, NO); |
| |
| if ([ChromeEarlGrey isIPadIdiom]) { |
| // Remove the override. |
| for (UIViewController* child in topViewController.childViewControllers) { |
| [topViewController setOverrideTraitCollection:originalTraitCollection |
| forChildViewController:child]; |
| } |
| } else { |
| // Cancel the rotation. |
| [ChromeEarlGrey rotateDeviceToOrientation:UIDeviceOrientationPortrait |
| error:nil]; |
| } |
| } |
| |
| @end |