|
| 1 | +// Copyright 2018 The Chromium Authors. All rights reserved. |
| 2 | +// Use of this source code is governed by a BSD-style license that can be |
| 3 | +// found in the LICENSE file. |
| 4 | + |
| 5 | +#import <EarlGrey/EarlGrey.h> |
| 6 | +#import <XCTest/XCTest.h> |
| 7 | + |
| 8 | +#include "base/strings/sys_string_conversions.h" |
| 9 | +#include "base/test/scoped_feature_list.h" |
| 10 | +#include "ios/chrome/browser/browser_state/chrome_browser_state.h" |
| 11 | +#include "ios/chrome/browser/ui/ui_feature_flags.h" |
| 12 | +#import "ios/chrome/test/app/chrome_test_util.h" |
| 13 | +#import "ios/chrome/test/earl_grey/chrome_earl_grey.h" |
| 14 | +#import "ios/chrome/test/earl_grey/chrome_earl_grey_ui.h" |
| 15 | +#import "ios/chrome/test/earl_grey/chrome_matchers.h" |
| 16 | +#import "ios/chrome/test/earl_grey/chrome_test_case.h" |
| 17 | +#include "net/test/embedded_test_server/http_request.h" |
| 18 | +#include "net/test/embedded_test_server/http_response.h" |
| 19 | + |
| 20 | +#if !defined(__has_feature) || !__has_feature(objc_arc) |
| 21 | +#error "This file requires ARC support." |
| 22 | +#endif |
| 23 | + |
| 24 | +namespace { |
| 25 | + |
| 26 | +// Web page that will show up as one of the most visited tiles. |
| 27 | +const char kTilePageLoadedString[] = "This is a web page that you visit often"; |
| 28 | +const char kTilePageURL[] = "/tile-page.html"; |
| 29 | +const char kTilePageTitle[] = "Often visited page"; |
| 30 | + |
| 31 | +// Web page for navigation. |
| 32 | +const char kPageLoadedString[] = "Page loaded!"; |
| 33 | +const char kPageURL[] = "/test-page.html"; |
| 34 | +const char kPageTitle[] = "Page title!"; |
| 35 | + |
| 36 | +// Provides responses for redirect and changed window location URLs. |
| 37 | +std::unique_ptr<net::test_server::HttpResponse> StandardResponse( |
| 38 | + const net::test_server::HttpRequest& request) { |
| 39 | + std::unique_ptr<net::test_server::BasicHttpResponse> http_response = |
| 40 | + std::make_unique<net::test_server::BasicHttpResponse>(); |
| 41 | + http_response->set_code(net::HTTP_OK); |
| 42 | + |
| 43 | + if (request.relative_url == kPageURL) { |
| 44 | + http_response->set_content("<html><head><title>" + std::string(kPageTitle) + |
| 45 | + "</title></head><body>" + |
| 46 | + std::string(kPageLoadedString) + |
| 47 | + "</body></html>"); |
| 48 | + return std::move(http_response); |
| 49 | + } |
| 50 | + |
| 51 | + if (request.relative_url == kTilePageURL) { |
| 52 | + http_response->set_content( |
| 53 | + "<html><head><title>" + std::string(kTilePageTitle) + |
| 54 | + "</title></head><body>" + std::string(kTilePageLoadedString) + |
| 55 | + "</body></html>"); |
| 56 | + return std::move(http_response); |
| 57 | + } |
| 58 | + |
| 59 | + return nil; |
| 60 | +} |
| 61 | + |
| 62 | +} // namespace |
| 63 | + |
| 64 | +// Test case for the Omnibox Shortcuts UI. |
| 65 | +@interface ShortcutsTestCase : ChromeTestCase |
| 66 | +@end |
| 67 | + |
| 68 | +@implementation ShortcutsTestCase { |
| 69 | + base::test::ScopedFeatureList _featureList; |
| 70 | +} |
| 71 | + |
| 72 | +- (void)setUp { |
| 73 | + [super setUp]; |
| 74 | + // Enable the shortcuts flag. |
| 75 | + _featureList.InitAndEnableFeature(kOmniboxPopupShortcutIconsInZeroState); |
| 76 | + |
| 77 | + // Start a server to be able to navigate to a web page. |
| 78 | + self.testServer->RegisterRequestHandler( |
| 79 | + base::BindRepeating(&StandardResponse)); |
| 80 | + GREYAssertTrue(self.testServer->Start(), @"Test server failed to start."); |
| 81 | + |
| 82 | + [ChromeEarlGrey clearBrowsingHistory]; |
| 83 | + [self prepareMostVisitedTiles]; |
| 84 | + // Clear pasteboard |
| 85 | + [[UIPasteboard generalPasteboard] setItems:@[]]; |
| 86 | +} |
| 87 | + |
| 88 | +#pragma mark - tests |
| 89 | + |
| 90 | +// Tests that the shortcuts show up on a web page. |
| 91 | +- (void)testShowsUp { |
| 92 | + [self navigateToAPage]; |
| 93 | + [ChromeEarlGreyUI focusOmnibox]; |
| 94 | + [[EarlGrey selectElementWithMatcher:[self mostVisitedTileMatcher]] |
| 95 | + assertWithMatcher:grey_sufficientlyVisible()]; |
| 96 | +} |
| 97 | + |
| 98 | +// Tests that shortcuts don't show up when there are other omnibox suggestions |
| 99 | +// available, for example "what you typed" suggestion. |
| 100 | +- (void)testNotShownWhenSuggestionsAvailable { |
| 101 | + [self navigateToAPage]; |
| 102 | + [ChromeEarlGreyUI focusOmniboxAndType:@"foo"]; |
| 103 | + [[EarlGrey selectElementWithMatcher:[self mostVisitedTileMatcher]] |
| 104 | + assertWithMatcher:grey_nil()]; |
| 105 | +} |
| 106 | + |
| 107 | +- (void)testShowsUpWhenOmniboxIsEmpty { |
| 108 | + [self navigateToAPage]; |
| 109 | + // Focus omnibox and hit backspace to erase the text. |
| 110 | + [ChromeEarlGreyUI focusOmniboxAndType:@"\b"]; |
| 111 | + [[EarlGrey selectElementWithMatcher:[self mostVisitedTileMatcher]] |
| 112 | + assertWithMatcher:grey_sufficientlyVisible()]; |
| 113 | +} |
| 114 | + |
| 115 | +// Test that tapping a most visited tile navigates to that page. |
| 116 | +- (void)testTapMostVisitedTile { |
| 117 | + [self navigateToAPage]; |
| 118 | + [ChromeEarlGreyUI focusOmnibox]; |
| 119 | + [[EarlGrey selectElementWithMatcher:[self mostVisitedTileMatcher]] |
| 120 | + performAction:grey_tap()]; |
| 121 | + [ChromeEarlGrey waitForWebViewContainingText:kTilePageLoadedString]; |
| 122 | +} |
| 123 | + |
| 124 | +- (void)testBookmarksShortcut { |
| 125 | + [self navigateToAPage]; |
| 126 | + [ChromeEarlGreyUI focusOmnibox]; |
| 127 | + |
| 128 | + // Tap on bookmarks. |
| 129 | + [[EarlGrey selectElementWithMatcher: |
| 130 | + chrome_test_util::StaticTextWithAccessibilityLabel( |
| 131 | + @"Bookmarks")] performAction:grey_tap()]; |
| 132 | + |
| 133 | + // Verify that the bookmarks dialog opened with Done button and "Bookmarks" |
| 134 | + // title. |
| 135 | + [[EarlGrey |
| 136 | + selectElementWithMatcher:grey_allOf(grey_accessibilityTrait( |
| 137 | + UIAccessibilityTraitHeader), |
| 138 | + grey_accessibilityLabel(@"Bookmarks"), |
| 139 | + nil)] |
| 140 | + assertWithMatcher:grey_sufficientlyVisible()]; |
| 141 | + |
| 142 | + [[EarlGrey selectElementWithMatcher:chrome_test_util:: |
| 143 | + BookmarksNavigationBarDoneButton()] |
| 144 | + performAction:grey_tap()]; |
| 145 | + |
| 146 | + // Verify that after tapping Done the omnibox is defocused. |
| 147 | + [[EarlGrey selectElementWithMatcher:chrome_test_util::DefocusedLocationView()] |
| 148 | + assertWithMatcher:grey_sufficientlyVisible()]; |
| 149 | +} |
| 150 | + |
| 151 | +- (void)testReadingListShortcut { |
| 152 | + [self navigateToAPage]; |
| 153 | + [ChromeEarlGreyUI focusOmnibox]; |
| 154 | + |
| 155 | + // Tap on reading list. |
| 156 | + [[EarlGrey selectElementWithMatcher: |
| 157 | + chrome_test_util::StaticTextWithAccessibilityLabel( |
| 158 | + @"Reading List")] performAction:grey_tap()]; |
| 159 | + |
| 160 | + // Verify that the reading list dialog opened with Done button and "Reading |
| 161 | + // List" title. |
| 162 | + [[EarlGrey |
| 163 | + selectElementWithMatcher:grey_allOf( |
| 164 | + grey_accessibilityTrait( |
| 165 | + UIAccessibilityTraitHeader), |
| 166 | + grey_accessibilityLabel(@"Reading List"), |
| 167 | + nil)] |
| 168 | + assertWithMatcher:grey_sufficientlyVisible()]; |
| 169 | + |
| 170 | + [[EarlGrey |
| 171 | + selectElementWithMatcher:[GREYMatchers matcherForButtonTitle:@"Done"]] |
| 172 | + performAction:grey_tap()]; |
| 173 | + |
| 174 | + // Verify that after tapping Done the omnibox is defocused. |
| 175 | + [[EarlGrey selectElementWithMatcher:chrome_test_util::DefocusedLocationView()] |
| 176 | + assertWithMatcher:grey_sufficientlyVisible()]; |
| 177 | +} |
| 178 | + |
| 179 | +- (void)testRecentTabsShortcut { |
| 180 | + [self navigateToAPage]; |
| 181 | + [ChromeEarlGreyUI focusOmnibox]; |
| 182 | + |
| 183 | + // Tap on recent tabs. |
| 184 | + [[EarlGrey selectElementWithMatcher: |
| 185 | + chrome_test_util::StaticTextWithAccessibilityLabel( |
| 186 | + @"Recent Tabs")] performAction:grey_tap()]; |
| 187 | + |
| 188 | + // Verify that the Recent Tabs dialog opened with Done button and "Recent |
| 189 | + // Tabs" title. |
| 190 | + [[EarlGrey |
| 191 | + selectElementWithMatcher:grey_allOf( |
| 192 | + grey_accessibilityTrait( |
| 193 | + UIAccessibilityTraitHeader), |
| 194 | + grey_accessibilityLabel(@"Recent Tabs"), |
| 195 | + nil)] |
| 196 | + assertWithMatcher:grey_sufficientlyVisible()]; |
| 197 | + |
| 198 | + [[EarlGrey |
| 199 | + selectElementWithMatcher:[GREYMatchers matcherForButtonTitle:@"Done"]] |
| 200 | + performAction:grey_tap()]; |
| 201 | + |
| 202 | + // Verify that after tapping Done the omnibox is defocused. |
| 203 | + [[EarlGrey selectElementWithMatcher:chrome_test_util::DefocusedLocationView()] |
| 204 | + assertWithMatcher:grey_sufficientlyVisible()]; |
| 205 | +} |
| 206 | + |
| 207 | +- (void)testHistoryShortcut { |
| 208 | + [self navigateToAPage]; |
| 209 | + [ChromeEarlGreyUI focusOmnibox]; |
| 210 | + |
| 211 | + // Tap on history. |
| 212 | + [[EarlGrey selectElementWithMatcher: |
| 213 | + chrome_test_util::StaticTextWithAccessibilityLabel(@"History")] |
| 214 | + performAction:grey_tap()]; |
| 215 | + |
| 216 | + // Verify that the History dialog opened with Done button and "History" |
| 217 | + // title. |
| 218 | + [[EarlGrey |
| 219 | + selectElementWithMatcher:grey_allOf(grey_accessibilityTrait( |
| 220 | + UIAccessibilityTraitHeader), |
| 221 | + grey_accessibilityLabel(@"History"), |
| 222 | + nil)] |
| 223 | + assertWithMatcher:grey_sufficientlyVisible()]; |
| 224 | + |
| 225 | + [[EarlGrey |
| 226 | + selectElementWithMatcher:[GREYMatchers matcherForButtonTitle:@"Done"]] |
| 227 | + performAction:grey_tap()]; |
| 228 | + |
| 229 | + // Verify that after tapping Done the omnibox is defocused. |
| 230 | + [[EarlGrey selectElementWithMatcher:chrome_test_util::DefocusedLocationView()] |
| 231 | + assertWithMatcher:grey_sufficientlyVisible()]; |
| 232 | +} |
| 233 | + |
| 234 | +#pragma mark - helpers |
| 235 | + |
| 236 | +- (void)navigateToAPage { |
| 237 | + const GURL pageURL = self.testServer->GetURL(kPageURL); |
| 238 | + [ChromeEarlGrey loadURL:pageURL]; |
| 239 | + [ChromeEarlGrey waitForWebViewContainingText:kPageLoadedString]; |
| 240 | +} |
| 241 | + |
| 242 | +- (void)prepareMostVisitedTiles { |
| 243 | + const GURL pageURL = self.testServer->GetURL(kTilePageURL); |
| 244 | + [ChromeEarlGrey loadURL:pageURL]; |
| 245 | + [ChromeEarlGrey waitForWebViewContainingText:kTilePageLoadedString]; |
| 246 | + |
| 247 | + // After loading URL, need to do another action before opening a new tab |
| 248 | + // with the icon present. |
| 249 | + [ChromeEarlGrey goBack]; |
| 250 | + |
| 251 | + [[self class] closeAllTabs]; |
| 252 | + [ChromeEarlGrey openNewTab]; |
| 253 | +} |
| 254 | + |
| 255 | +- (id<GREYMatcher>)mostVisitedTileMatcher { |
| 256 | + NSString* pageTitle = base::SysUTF8ToNSString(kTilePageTitle); |
| 257 | + return chrome_test_util::StaticTextWithAccessibilityLabel(pageTitle); |
| 258 | +} |
| 259 | + |
| 260 | +@end |
0 commit comments