chromium/ios/chrome/browser/webui/ui_bundled/web_ui_egtest.mm

// 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 <XCTest/XCTest.h>

#import "base/apple/foundation_util.h"
#import "base/metrics/field_trial.h"
#import "base/strings/sys_string_conversions.h"
#import "base/test/ios/wait_util.h"
#import "components/strings/grit/components_strings.h"
#import "components/version_info/version_info.h"
#import "ios/chrome/browser/shared/model/url/chrome_url_constants.h"
#import "ios/chrome/browser/webui/ui_bundled/web_ui_test_utils.h"
#import "ios/chrome/common/channel_info.h"
#import "ios/chrome/grit/ios_branded_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/components/webui/web_ui_url_constants.h"
#import "ios/testing/earl_grey/earl_grey_test.h"
#import "net/test/embedded_test_server/embedded_test_server.h"
#import "ui/base/device_form_factor.h"
#import "ui/base/l10n/l10n_util.h"

using chrome_test_util::BackButton;
using chrome_test_util::ForwardButton;

// Test case for chrome://* WebUI pages.
@interface WebUITestCase : ChromeTestCase
@end

@implementation WebUITestCase

// Tests that the WebUI pages (chrome://version) have the correct User Agent.
- (void)testUserAgent {
  [ChromeEarlGrey loadURL:WebUIPageUrlWithHost(kChromeUIVersionHost)];

  NSString* userAgent = [ChromeEarlGrey mobileUserAgentString];
  // Verify that JavaScript navigator.userAgent returns the mobile User Agent.
  base::Value result =
      [ChromeEarlGrey evaluateJavaScript:@"navigator.userAgent"];
  GREYAssertTrue(result.is_string(), @"Result is not a string.");
  NSString* navigatorUserAgent = base::SysUTF8ToNSString(result.GetString());
  GREYAssertEqualObjects(userAgent, navigatorUserAgent,
                         @"User-Agent strings did not match");
}

// Tests that chrome://version renders and contains correct version number and
// user agent string.
- (void)testVersion {
  [ChromeEarlGrey loadURL:WebUIPageUrlWithHost(kChromeUIVersionHost)];

  // Verify that app version is present on the page.
  const std::string version(version_info::GetVersionNumber());
  [ChromeEarlGrey waitForWebStateContainingText:version];

  NSString* userAgent = [ChromeEarlGrey mobileUserAgentString];
  std::string userAgentString = base::SysNSStringToUTF8(userAgent);

  // Verify that mobile User Agent string is present on the page. Testing for
  // only a portion of the string is sufficient to ensure the value has been
  // populated in the UI and it is not blank. However, the exact string value is
  // not validated as this test does not have access to get the full User Agent
  // string from the WebClient.
  [ChromeEarlGrey waitForWebStateContainingText:userAgentString];
}

// Tests that clicking on a chrome://terms link from chrome://chrome-urls
// navigates to terms page.
- (void)testChromeURLNavigateToTerms {
  [ChromeEarlGrey loadURL:WebUIPageUrlWithHost(kChromeUIChromeURLsHost)];

  // Tap on chrome://terms link on the page.
  [ChromeEarlGrey
      tapWebStateElementWithID:[NSString
                                   stringWithUTF8String:kChromeUITermsHost]];

  // Verify that the resulting page is chrome://terms.
  GREYAssert(WaitForOmniboxURLString(kChromeUITermsURL),
             @"Omnibox does not contain URL.");
  const std::string kTermsText = "Terms of Service";
  [ChromeEarlGrey waitForWebStateContainingText:kTermsText];
}

// Tests that back navigation functions properly after navigation via anchor
// click.
- (void)testChromeURLBackNavigationFromAnchorClick {
  [ChromeEarlGrey loadURL:GURL(kChromeUIChromeURLsURL)];

  // Tap on chrome://version link on the page.
  [ChromeEarlGrey
      tapWebStateElementWithID:[NSString
                                   stringWithUTF8String:kChromeUIVersionHost]];

  // Verify that the resulting page is chrome://version.
  GREYAssert(WaitForOmniboxURLString(kChromeUIVersionURL),
             @"Omnibox did not contain URL.");
  [ChromeEarlGrey
      waitForWebStateContainingText:l10n_util::GetStringUTF8(
                                        IDS_IOS_ABOUT_VERSION_COMPANY_NAME)];

  // Tap the back button in the toolbar and verify that the resulting page is
  // the previously visited page chrome://chrome-urls.
  [[EarlGrey selectElementWithMatcher:BackButton()] performAction:grey_tap()];
  GREYAssert(WaitForOmniboxURLString(kChromeUIChromeURLsURL),
             @"Omnibox did not contain URL.");
  [ChromeEarlGrey waitForWebStateContainingText:"List of Chrome URLs"];
}

// Tests that back and forward navigation between chrome URLs functions
// properly.
- (void)testChromeURLBackAndForwardAndReloadNavigation {
  // Navigate to the first URL chrome://version.
  [ChromeEarlGrey loadURL:GURL(kChromeUIVersionURL)];

  // Navigate to the second URL chrome://chrome-urls.
  [ChromeEarlGrey loadURL:GURL(kChromeUIChromeURLsURL)];

  // Tap the back button in the toolbar and verify that the resulting page's URL
  // corresponds to the first URL chrome://version that was loaded.
  [[EarlGrey selectElementWithMatcher:BackButton()] performAction:grey_tap()];
  GREYAssert(WaitForOmniboxURLString(kChromeUIVersionURL),
             @"Omnibox did not contain URL.");

  // Tap the forward button in the toolbar and verify that the resulting page's
  // URL corresponds the second URL chrome://chrome-urls that was loaded.
  [[EarlGrey selectElementWithMatcher:ForwardButton()]
      performAction:grey_tap()];
  GREYAssert(WaitForOmniboxURLString(kChromeUIChromeURLsURL),
             @"Omnibox did not contain URL.");

  // Tap the back button in the toolbar then reload, and verify that the
  // resulting page corresponds to the first URL.
  [[EarlGrey selectElementWithMatcher:BackButton()] performAction:grey_tap()];
  [ChromeEarlGrey waitForPageToFinishLoading];
  [ChromeEarlGrey reload];
  GREYAssert(WaitForOmniboxURLString(kChromeUIVersionURL),
             @"Omnibox did not contain URL.");

  // Make sure forward navigation is still possible.
  [[EarlGrey selectElementWithMatcher:ForwardButton()]
      performAction:grey_tap()];
  GREYAssert(WaitForOmniboxURLString(kChromeUIChromeURLsURL),
             @"Omnibox did not contain URL.");
}

// Tests that all URLs on chrome://chrome-urls page load without error.
- (void)testChromeURLsLoadWithoutError {
  // Load WebUI pages and verify they load without any error.
  for (size_t i = 0; i < kNumberOfChromeHostURLs; ++i) {
    const char* host = kChromeHostURLs[i];
    // Exclude non-WebUI pages, as they do not go through a "loading" phase.
    if (host == kChromeUINewTabHost) {
      continue;
    }
    GURL URL = WebUIPageUrlWithHost(host);
    [ChromeEarlGrey loadURL:URL];

    GREYAssert(WaitForOmniboxURLString(URL.spec()),
               @"Omnibox did not contain URL.");
  }
}

// Tests that loading an invalid Chrome URL results in an error page.
- (void)testChromeURLInvalid {
  // Navigate to the native error page chrome://invalidchromeurl.
  const std::string kChromeInvalidURL = "chrome://invalidchromeurl";
  [ChromeEarlGrey loadURL:GURL(kChromeInvalidURL)];

  // Verify that the resulting page is an error page.
  GREYAssert(WaitForOmniboxURLString(kChromeInvalidURL),
             @"Omnibox did not contain URL.");
  std::string errorMessage = net::ErrorToShortString(net::ERR_INVALID_URL);
  [ChromeEarlGrey waitForWebStateContainingText:errorMessage];
}

// Tests that repeated back/forward navigation from web URL is allowed.
- (void)testBackForwardFromWebURL {
  GREYAssertTrue(self.testServer->Start(), @"Test server failed to start.");

  std::string chromeVersionWebText =
      l10n_util::GetStringUTF8(IDS_IOS_ABOUT_VERSION_COMPANY_NAME);
  const char kWebPageText[] = "pony";

  [ChromeEarlGrey loadURL:GURL(kChromeUIVersionURL)];

  GREYAssert(WaitForOmniboxURLString(kChromeUIVersionURL),
             @"Omnibox did not contain URL.");
  [ChromeEarlGrey waitForWebStateContainingText:chromeVersionWebText];

  GURL webURL = self.testServer->GetURL("/pony.html");
  [ChromeEarlGrey loadURL:webURL];
  [ChromeEarlGrey waitForWebStateContainingText:kWebPageText];

  [ChromeEarlGrey goBack];
  GREYAssert(WaitForOmniboxURLString(kChromeUIVersionURL),
             @"Omnibox did not contain URL.");
  [ChromeEarlGrey waitForWebStateContainingText:chromeVersionWebText];

  [ChromeEarlGrey goForward];
  [ChromeEarlGrey waitForWebStateContainingText:kWebPageText];

  [ChromeEarlGrey goBack];
  GREYAssert(WaitForOmniboxURLString(kChromeUIVersionURL),
             @"Omnibox did not contain URL.");
  [ChromeEarlGrey waitForWebStateContainingText:chromeVersionWebText];
}

- (void)testChromeFlagsOnNTP {
  // Start with NTP and load chrome://flags.
  [ChromeEarlGrey loadURL:GURL(kChromeUIFlagsURL)];

  GREYAssert(WaitForOmniboxURLString(kChromeUIFlagsURL),
             @"Omnibox did not contain URL.");

  // Validates that some of the expected text on the page exists.
  [ChromeEarlGrey waitForWebStateContainingText:"Experiments"];
  [ChromeEarlGrey waitForWebStateContainingText:"Available"];

  // Validates that the experimental flags container is visible.
  NSString* flags_page_warning =
      l10n_util::GetNSString(IDS_FLAGS_UI_PAGE_WARNING);
  [ChromeEarlGrey waitForWebStateContainingText:base::SysNSStringToUTF8(
                                                    flags_page_warning)];
}

- (void)testChromeFlagsOnWebsite {
  // Starts with loading a website.
  GREYAssertTrue(self.testServer->Start(), @"Test server failed to start.");

  const char kWebPageText[] = "pony";
  GURL webURL = self.testServer->GetURL("/pony.html");
  [ChromeEarlGrey loadURL:webURL];
  [ChromeEarlGrey waitForWebStateContainingText:kWebPageText];

  // Then load chrome://flags in the same tab that has loaded a website.
  [ChromeEarlGrey loadURL:WebUIPageUrlWithHost(kChromeUIFlagsHost)];

  GREYAssert(WaitForOmniboxURLString(kChromeUIFlagsURL),
             @"Omnibox did not contain URL.");

  // Validates that some of the expected text on the page exists.
  [ChromeEarlGrey waitForWebStateContainingText:"Experiments"];
  [ChromeEarlGrey waitForWebStateContainingText:"Available"];

  NSString* flags_page_warning =
      l10n_util::GetNSString(IDS_FLAGS_UI_PAGE_WARNING);
  [ChromeEarlGrey waitForWebStateContainingText:base::SysNSStringToUTF8(
                                                    flags_page_warning)];
}

- (void)testChromePasswordManagerInternalsSite {
  GURL URL = WebUIPageUrlWithHost(kChromeUIPasswordManagerInternalsHost);
  [ChromeEarlGrey loadURL:URL];

  GREYAssert(WaitForOmniboxURLString(URL.spec()),
             @"Omnibox did not contain URL.");

  // Validates that some of the expected text on the page exists.
  [ChromeEarlGrey waitForWebStateContainingText:"Variations"];
  [ChromeEarlGrey waitForWebStateContainingText:"Password Manager Internals"];
}

- (void)testChromeAutofillInternalsSite {
  GURL URL = WebUIPageUrlWithHost(kChromeUIAutofillInternalsHost);
  [ChromeEarlGrey loadURL:URL];

  // Autofill-Internals stores the log filter configuration in the URL's
  // fragment identifier (after the hash).
  GREYAssert(WaitForOmniboxURLString(URL.spec(), false),
             @"Omnibox did not contain URL.");

  // Validates that some of the expected text on the page exists.
  [ChromeEarlGrey waitForWebStateContainingText:"Variations"];
  [ChromeEarlGrey waitForWebStateContainingText:"Autofill Internals"];
}

// Test chrome://userdefaults-internals page.
- (void)testChromeUserdefaultsInternalSite {
  if (GetChannel() == version_info::Channel::STABLE) {
    // This page is not supported on STABLE build.
    return;
  }

  // Start with NTP and load chrome://userdefaults-internals.
  GURL URL = WebUIPageUrlWithHost(kChromeUIUserDefaultsInternalsHost);
  [ChromeEarlGrey loadURL:URL];

  // Autofill-Internals stores the log filter configuration in the URL's
  // fragment identifier (after the hash).
  GREYAssert(WaitForOmniboxURLString(URL.spec()),
             @"Omnibox did not contain URL");

  // Validates that some of the expected text on the page exists.
  [ChromeEarlGrey waitForWebStateContainingText:"List of user defaults:"];
}

// Test chrome://userdefaults-internals page in incognito.
- (void)testChromeUserdefaultsInternalIncognitoSite {
  if (GetChannel() == version_info::Channel::STABLE) {
    // This page is not supported on STABLE build.
    return;
  }

  // Start with incognito NTP and load chrome://userdefaults-internals.
  GURL URL = WebUIPageUrlWithHost(kChromeUIUserDefaultsInternalsHost);
  [ChromeEarlGrey openNewIncognitoTab];
  [ChromeEarlGrey loadURL:URL];

  // Autofill-Internals stores the log filter configuration in the URL's
  // fragment identifier (after the hash).
  GREYAssert(WaitForOmniboxURLString(URL.spec()),
             @"Omnibox did not contain URL");

  // Validates that some of the expected text on the page exists.
  [ChromeEarlGrey waitForWebStateContainingText:
                      "This page is not available in incognito mode."];
}

@end