blob: 4153251f516053e1b658a16c6fe8cc62f86a2caf [file] [log] [blame]
// 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.
#import <XCTest/XCTest.h>
#include "base/bind.h"
#include "base/ios/ios_util.h"
#include "base/strings/sys_string_conversions.h"
#import "ios/chrome/browser/ui/content_suggestions/ntp_home_constant.h"
#import "ios/chrome/browser/ui/omnibox/popup/omnibox_popup_accessibility_identifier_constants.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"
#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"
#if !defined(__has_feature) || !__has_feature(objc_arc)
#error "This file requires ARC support."
#endif
namespace {
// Returns the popup row containing the |url| as suggestion.
id<GREYMatcher> PopupRowWithUrl(GURL url) {
return grey_allOf(
grey_kindOfClassName(@"OmniboxPopupRowCell"),
grey_descendant(chrome_test_util::StaticTextWithAccessibilityLabel(
base::SysUTF8ToNSString(url.GetContent()))),
grey_sufficientlyVisible(), nil);
}
// Returns the switch to open tab element for the |url|.
id<GREYMatcher> SwitchTabElementForUrl(const GURL& url) {
return grey_allOf(
grey_ancestor(PopupRowWithUrl(url)),
grey_accessibilityID(kOmniboxPopupRowSwitchTabAccessibilityIdentifier),
nil);
}
// Web page 1.
const char kPage1[] = "This is the first page";
const char kPage1Title[] = "Title 1";
const char kPage1URL[] = "/page1.html";
// Web page 2.
const char kPage2[] = "This is the second page";
const char kPage2Title[] = "Title 2";
const char kPage2URL[] = "/page2.html";
// Web page 2.
const char kPage3[] = "This is the third page";
const char kPage3Title[] = "Title 3";
const char kPage3URL[] = "/page3.html";
// Provides responses for the different pages.
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);
if (request.relative_url == kPage1URL) {
http_response->set_content(
"<html><head><title>" + std::string(kPage1Title) +
"</title></head><body>" + std::string(kPage1) + "</body></html>");
return std::move(http_response);
}
if (request.relative_url == kPage2URL) {
http_response->set_content(
"<html><head><title>" + std::string(kPage2Title) +
"</title></head><body>" + std::string(kPage2) + "</body></html>");
return std::move(http_response);
}
if (request.relative_url == kPage3URL) {
http_response->set_content(
"<html><head><title>" + std::string(kPage3Title) +
"</title></head><body>" + std::string(kPage3) + "</body></html>");
return std::move(http_response);
}
return nil;
}
} // namespace
@interface OmniboxPopupTestCase : ChromeTestCase
@end
@implementation OmniboxPopupTestCase
- (void)setUp {
[super setUp];
// Start a server to be able to navigate to a web page.
self.testServer->RegisterRequestHandler(
base::BindRepeating(&StandardResponse));
GREYAssertTrue(self.testServer->Start(), @"Test server failed to start.");
[ChromeEarlGrey clearBrowsingHistory];
}
// Tests that tapping the switch to open tab button, switch to the open tab,
// doesn't close the tab.
- (void)testSwitchToOpenTab {
// TODO(crbug.com/1067817): Test won't pass on iPad devices.
#if !TARGET_IPHONE_SIMULATOR
if ([ChromeEarlGrey isIPadIdiom]) {
EARL_GREY_TEST_SKIPPED(@"This test doesn't pass on iPad device.");
}
#endif
// Open the first page.
GURL firstPageURL = self.testServer->GetURL(kPage1URL);
[ChromeEarlGrey loadURL:firstPageURL];
[ChromeEarlGrey waitForWebStateContainingText:kPage1];
// Open the second page in another tab.
[ChromeEarlGreyUI openNewTab];
[ChromeEarlGrey loadURL:self.testServer->GetURL(kPage2URL)];
[ChromeEarlGrey waitForWebStateContainingText:kPage2];
// Type the URL of the first page in the omnibox to trigger it as suggestion.
[ChromeEarlGreyUI focusOmniboxAndType:base::SysUTF8ToNSString(kPage1URL)];
// Switch to the first tab.
[[EarlGrey selectElementWithMatcher:SwitchTabElementForUrl(firstPageURL)]
performAction:grey_tap()];
[ChromeEarlGrey waitForWebStateContainingText:kPage1];
// Check that both tabs are opened (and that we switched tab and not just
// navigated.
[[EarlGrey selectElementWithMatcher:chrome_test_util::ShowTabsButton()]
performAction:grey_tap()];
[[EarlGrey
selectElementWithMatcher:
grey_allOf(chrome_test_util::StaticTextWithAccessibilityLabel(
base::SysUTF8ToNSString(kPage2Title)),
grey_ancestor(chrome_test_util::TabGridCellAtIndex(1)),
nil)] assertWithMatcher:grey_sufficientlyVisible()];
}
// Tests that the switch to open tab button isn't displayed for the current tab.
// TODO(crbug.com/1128463): Test is flaky on simulators.
#if TARGET_IPHONE_SIMULATOR
#define MAYBE_testNotSwitchButtonOnCurrentTab \
DISABLED_testNotSwitchButtonOnCurrentTab
#else
#define MAYBE_testNotSwitchButtonOnCurrentTab testNotSwitchButtonOnCurrentTab
#endif
- (void)MAYBE_testNotSwitchButtonOnCurrentTab {
// TODO(crbug.com/1067817): Test won't pass on iPad devices.
#if !TARGET_IPHONE_SIMULATOR
if ([ChromeEarlGrey isIPadIdiom]) {
EARL_GREY_TEST_SKIPPED(@"This test doesn't pass on iPad device.");
}
#endif
GURL URL2 = self.testServer->GetURL(kPage2URL);
// Open the first page.
[ChromeEarlGrey loadURL:self.testServer->GetURL(kPage1URL)];
[ChromeEarlGrey waitForWebStateContainingText:kPage1];
// Open the second page in another tab.
[ChromeEarlGreyUI openNewTab];
[ChromeEarlGrey loadURL:URL2];
[ChromeEarlGrey waitForWebStateContainingText:kPage2];
// Type the URL of the first page in the omnibox to trigger it as suggestion.
[ChromeEarlGreyUI focusOmniboxAndType:base::SysUTF8ToNSString(kPage2URL)];
// Check that we have the suggestion for the second page, but not the switch
// as it is the current page.
[[EarlGrey selectElementWithMatcher:PopupRowWithUrl(URL2)]
assertWithMatcher:grey_sufficientlyVisible()];
[[EarlGrey selectElementWithMatcher:SwitchTabElementForUrl(URL2)]
assertWithMatcher:grey_nil()];
}
// Tests that the incognito tabs aren't displayed as "opened" tab in the
// non-incognito suggestions and vice-versa. TODO(crbug.com/1059464): Test is
// flaky.
- (void)DISABLED_testIncognitoSeparation {
GURL URL1 = self.testServer->GetURL(kPage1URL);
GURL URL2 = self.testServer->GetURL(kPage2URL);
GURL URL3 = self.testServer->GetURL(kPage3URL);
// Add all the pages to the history.
[ChromeEarlGrey loadURL:URL1];
[ChromeEarlGrey waitForWebStateContainingText:kPage1];
[ChromeEarlGrey loadURL:URL2];
[ChromeEarlGrey waitForWebStateContainingText:kPage2];
[ChromeEarlGrey loadURL:URL3];
[ChromeEarlGrey waitForWebStateContainingText:kPage3];
[[self class] closeAllTabs];
// Load page 1 in non-incognito and page 2 in incognito.
[ChromeEarlGrey openNewTab];
[ChromeEarlGrey loadURL:URL1];
[ChromeEarlGrey waitForWebStateContainingText:kPage1];
[ChromeEarlGrey openNewIncognitoTab];
[ChromeEarlGrey loadURL:URL2];
[ChromeEarlGrey waitForWebStateContainingText:kPage2];
// Open page 3 in non-incognito.
[ChromeEarlGrey openNewTab];
[ChromeEarlGrey loadURL:URL3];
[ChromeEarlGrey waitForWebStateContainingText:kPage3];
NSString* omniboxInput =
[NSString stringWithFormat:@"%@:%@", base::SysUTF8ToNSString(URL3.host()),
base::SysUTF8ToNSString(URL3.port())];
[ChromeEarlGreyUI focusOmniboxAndType:omniboxInput];
// Check that we have the switch button for the first page.
[[EarlGrey
selectElementWithMatcher:
grey_allOf(grey_ancestor(PopupRowWithUrl(URL1)),
grey_accessibilityID(
kOmniboxPopupRowSwitchTabAccessibilityIdentifier),
nil)] assertWithMatcher:grey_sufficientlyVisible()];
// Check that we have the suggestion for the second page, but not the switch.
[[EarlGrey selectElementWithMatcher:PopupRowWithUrl(URL2)]
assertWithMatcher:grey_sufficientlyVisible()];
[[EarlGrey selectElementWithMatcher:SwitchTabElementForUrl(URL2)]
assertWithMatcher:grey_nil()];
// Open page 3 in incognito.
[ChromeEarlGrey openNewIncognitoTab];
[ChromeEarlGrey loadURL:URL3];
[ChromeEarlGrey waitForWebStateContainingText:kPage3];
[ChromeEarlGreyUI focusOmniboxAndType:base::SysUTF8ToNSString(URL3.host())];
// Check that we have the switch button for the second page.
[[EarlGrey
selectElementWithMatcher:
grey_allOf(grey_ancestor(PopupRowWithUrl(URL2)),
grey_accessibilityID(
kOmniboxPopupRowSwitchTabAccessibilityIdentifier),
nil)] assertWithMatcher:grey_sufficientlyVisible()];
// Check that we have the suggestion for the first page, but not the switch.
[[EarlGrey selectElementWithMatcher:PopupRowWithUrl(URL1)]
assertWithMatcher:grey_sufficientlyVisible()];
[[EarlGrey selectElementWithMatcher:SwitchTabElementForUrl(URL1)]
assertWithMatcher:grey_nil()];
}
- (void)testCloseNTPWhenSwitching {
// TODO(crbug.com/1156054): Test won't pass on iPad.
if ([ChromeEarlGrey isIPadIdiom]) {
EARL_GREY_TEST_SKIPPED(@"This test doesn't pass on iPad.");
}
// Open the first page.
GURL URL1 = self.testServer->GetURL(kPage1URL);
[ChromeEarlGrey loadURL:URL1];
[ChromeEarlGrey waitForWebStateContainingText:kPage1];
// Open a new tab and switch to the first tab.
[ChromeEarlGrey openNewTab];
NSString* omniboxInput =
[NSString stringWithFormat:@"%@:%@", base::SysUTF8ToNSString(URL1.host()),
base::SysUTF8ToNSString(URL1.port())];
[[EarlGrey selectElementWithMatcher:chrome_test_util::FakeOmnibox()]
performAction:grey_typeText(omniboxInput)];
[[EarlGrey selectElementWithMatcher:SwitchTabElementForUrl(URL1)]
performAction:grey_tap()];
[ChromeEarlGrey waitForWebStateContainingText:kPage1];
// Check that the other tab is closed.
[ChromeEarlGrey waitForMainTabCount:1];
}
// TODO(crbug.com/1128463): Test is flaky on simulators.
#if TARGET_IPHONE_SIMULATOR
#define MAYBE_testDontCloseNTPWhenSwitchingWithForwardHistory \
DISABLED_testDontCloseNTPWhenSwitchingWithForwardHistory
#else
#define MAYBE_testDontCloseNTPWhenSwitchingWithForwardHistory \
testDontCloseNTPWhenSwitchingWithForwardHistory
#endif
- (void)MAYBE_testDontCloseNTPWhenSwitchingWithForwardHistory {
// TODO(crbug.com/1067817): Test won't pass on iPad devices.
#if !TARGET_IPHONE_SIMULATOR
if ([ChromeEarlGrey isIPadIdiom]) {
EARL_GREY_TEST_SKIPPED(@"This test doesn't pass on iPad device.");
}
#endif
// Open the first page.
GURL URL1 = self.testServer->GetURL(kPage1URL);
[ChromeEarlGrey loadURL:URL1];
[ChromeEarlGrey waitForWebStateContainingText:kPage1];
// Open a new tab, navigate to a page and go back to have forward history.
[ChromeEarlGrey openNewTab];
[ChromeEarlGrey loadURL:URL1];
[ChromeEarlGrey waitForWebStateContainingText:kPage1];
[ChromeEarlGrey goBack];
// Navigate to the other tab.
[[EarlGrey selectElementWithMatcher:chrome_test_util::FakeOmnibox()]
performAction:grey_typeText(base::SysUTF8ToNSString(URL1.host()))];
[[EarlGrey selectElementWithMatcher:SwitchTabElementForUrl(URL1)]
performAction:grey_tap()];
[ChromeEarlGrey waitForWebStateContainingText:kPage1];
// Check that the other tab is not closed.
[ChromeEarlGrey waitForMainTabCount:2];
}
// Tests that switching to closed tab opens the tab in foreground, except if it
// is from NTP without history.
- (void)testSwitchToClosedTab {
if (@available(iOS 13, *)) {
if ([ChromeEarlGrey isIPadIdiom]) {
// TODO(crbug.com/992480):test fails on iPad.
EARL_GREY_TEST_DISABLED(@"Test disabled on iPad.");
}
}
// TODO(crbug.com/1067817): Test won't pass on iPad devices.
#if !TARGET_IPHONE_SIMULATOR
if ([ChromeEarlGrey isIPadIdiom]) {
EARL_GREY_TEST_SKIPPED(@"This test doesn't pass on iPad device.");
}
#endif
GURL URL1 = self.testServer->GetURL(kPage1URL);
// Open the first page.
[ChromeEarlGrey loadURL:URL1];
[ChromeEarlGrey waitForWebStateContainingText:kPage1];
// Open a new tab and load another URL.
[ChromeEarlGrey openNewTab];
[ChromeEarlGrey loadURL:self.testServer->GetURL(kPage2URL)];
[ChromeEarlGrey waitForWebStateContainingText:kPage2];
// Start typing url of the first page.
[ChromeEarlGreyUI focusOmniboxAndType:base::SysUTF8ToNSString(kPage1URL)];
// Make sure that the "Switch to Open Tab" element is visible.
[[EarlGrey selectElementWithMatcher:SwitchTabElementForUrl(URL1)]
assertWithMatcher:grey_sufficientlyVisible()];
// Close the first page.
[ChromeEarlGrey closeTabAtIndex:0];
[ChromeEarlGrey waitForMainTabCount:1];
// Try to switch to the first tab.
[[EarlGrey selectElementWithMatcher:SwitchTabElementForUrl(URL1)]
performAction:grey_tap()];
[ChromeEarlGreyUI waitForAppToIdle];
// Check that the URL has been opened in a new foreground tab.
[ChromeEarlGrey waitForWebStateContainingText:kPage1];
[ChromeEarlGrey waitForMainTabCount:2];
}
// Tests that having multiple suggestions with corresponding opened tabs display
// multiple buttons. TODO(crbug.com/1059464): Test is flaky.
- (void)DISABLED_testMultiplePageOpened {
// TODO(crbug.com/1067817): Test won't pass on iPad devices.
#if !TARGET_IPHONE_SIMULATOR
if ([ChromeEarlGrey isIPadIdiom]) {
EARL_GREY_TEST_SKIPPED(@"This test doesn't pass on iPad device.");
}
#endif
// Open the first page.
GURL URL1 = self.testServer->GetURL(kPage1URL);
[ChromeEarlGrey loadURL:URL1];
[ChromeEarlGrey waitForWebStateContainingText:kPage1];
// Open the second page in a new tab.
[ChromeEarlGrey openNewTab];
GURL URL2 = self.testServer->GetURL(kPage2URL);
[ChromeEarlGrey loadURL:URL2];
[ChromeEarlGrey waitForWebStateContainingText:kPage2];
// Start typing url of the two opened pages in a new tab.
[ChromeEarlGrey openNewTab];
NSString* omniboxInput =
[NSString stringWithFormat:@"%@:%@", base::SysUTF8ToNSString(URL1.host()),
base::SysUTF8ToNSString(URL1.port())];
[[EarlGrey selectElementWithMatcher:chrome_test_util::FakeOmnibox()]
performAction:grey_typeText(omniboxInput)];
// Check that both elements are displayed.
[[EarlGrey selectElementWithMatcher:SwitchTabElementForUrl(URL1)]
assertWithMatcher:grey_sufficientlyVisible()];
[[EarlGrey selectElementWithMatcher:SwitchTabElementForUrl(URL2)]
assertWithMatcher:grey_sufficientlyVisible()];
}
// Test that on iPhones, when the popup is scrolled, the keyboard is dismissed
// but the omnibox is still expanded and the suggestions are visible.
- (void)testScrollingDismissesKeyboardOnPhones {
[[EarlGrey selectElementWithMatcher:chrome_test_util::FakeOmnibox()]
performAction:grey_typeText(@"hello")];
// Matcher for a URL-what-you-typed suggestion.
id<GREYMatcher> row = grey_allOf(
grey_kindOfClassName(@"OmniboxPopupRowCell"),
grey_descendant(
chrome_test_util::StaticTextWithAccessibilityLabel(@"hello")),
grey_sufficientlyVisible(), nil);
[[EarlGrey selectElementWithMatcher:row]
assertWithMatcher:grey_sufficientlyVisible()];
GREYAssertTrue([EarlGrey isKeyboardShownWithError:nil],
@"Keyboard Should be Shown");
// Scroll the popup.
[[EarlGrey
selectElementWithMatcher:
grey_accessibilityID(kOmniboxPopupTableViewAccessibilityIdentifier)]
performAction:grey_swipeFastInDirection(kGREYDirectionUp)];
[[EarlGrey selectElementWithMatcher:row]
assertWithMatcher:grey_sufficientlyVisible()];
// The keyboard should only be dismissed on phones. Ipads, even in
// multitasking, are considered tall enough to fit all suggestions.
if ([ChromeEarlGrey isIPadIdiom]) {
GREYAssertTrue([EarlGrey isKeyboardShownWithError:nil],
@"Keyboard Should be Shown");
} else {
GREYAssertFalse([EarlGrey isKeyboardShownWithError:nil],
@"Keyboard Should not be Shown");
}
}
@end