Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(72)

Unified Diff: ios/chrome/browser/translate/translate_egtest.mm

Issue 2585233003: Upstream Chrome on iOS source code [2/11]. (Closed)
Patch Set: Created 4 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: ios/chrome/browser/translate/translate_egtest.mm
diff --git a/ios/chrome/browser/translate/translate_egtest.mm b/ios/chrome/browser/translate/translate_egtest.mm
new file mode 100644
index 0000000000000000000000000000000000000000..df6696ee649129b6613eb4bd6dc853a1856bc52f
--- /dev/null
+++ b/ios/chrome/browser/translate/translate_egtest.mm
@@ -0,0 +1,845 @@
+// Copyright 2016 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/command_line.h"
+#include "base/mac/bind_objc_block.h"
+#include "base/strings/stringprintf.h"
+#include "base/strings/sys_string_conversions.h"
+#include "base/strings/utf_string_conversions.h"
+#include "components/strings/grit/components_strings.h"
+#include "components/translate/core/browser/translate_download_manager.h"
+#include "components/translate/core/browser/translate_manager.h"
+#include "components/translate/core/common/translate_constants.h"
+#include "components/translate/core/common/translate_pref_names.h"
+#include "components/translate/core/common/translate_switches.h"
+#include "components/translate/ios/browser/ios_translate_driver.h"
+#import "components/translate/ios/browser/js_translate_manager.h"
+#import "components/translate/ios/browser/language_detection_controller.h"
+#include "ios/chrome/browser/browser_state/chrome_browser_state.h"
+#include "ios/chrome/browser/translate/chrome_ios_translate_client.h"
+#import "ios/chrome/test/app/chrome_test_util.h"
+#import "ios/chrome/test/app/tab_test_util.h"
+#include "ios/chrome/test/app/web_view_interaction_test_util.h"
+#import "ios/chrome/test/earl_grey/chrome_earl_grey.h"
+#import "ios/chrome/test/earl_grey/chrome_matchers.h"
+#import "ios/chrome/test/earl_grey/chrome_test_case.h"
+#import "ios/testing/wait_util.h"
+#import "ios/web/public/test/http_server.h"
+#include "ios/web/public/test/http_server_util.h"
+#include "ios/web/public/test/response_providers/data_response_provider.h"
+#include "net/base/url_util.h"
+#include "ui/base/l10n/l10n_util.h"
+
+namespace {
+
+// Some text in English language.
+const char kEnglishText[] =
+ "After flying to an altitude of 39,045 meters (128,100 feet) in a "
+ "helium-filled balloon, Felix Baumgartner completed a record breaking jump "
+ "for the ages from the edge of space, exactly 65 years after Chuck Yeager "
+ "first broke the sound barrier flying in an experimental rocket-powered "
+ "airplane. Felix reached a maximum of speed of 1,342.8 km/h (833mph) "
+ "through the near vacuum of the stratosphere before being slowed by the "
+ "atmosphere later during his 4:20 minute long freefall. The 43-year-old "
+ "Austrian skydiving expert also broke two other world records (highest "
+ "freefall, highest manned balloon flight), leaving the one for the longest "
+ "freefall to project mentor Col. Joe Kittinger.";
+
+// Some text in French language.
+const char kFrenchText[] =
+ "Des yeux qui font baisser les miens. Un rire qui se perd sur sa bouche."
+ "Voilà le portrait sans retouches de l'homme auquel j'appartiens "
+ "Quand il me prend dans ses bras Il me parle tout bas "
+ "Je vois la vie en rose Il me dit des mots d'amour "
+ "Des mots de tous les jours Et ça me fait quelque chose "
+ "Il est entré dans mon cœur Une part de bonheur Dont je connais la cause "
+ "C'est lui pour moi, moi pour lui, dans la vie "
+ "Il me l'a dit, l'a juré, pour la vie Et dès que je l'aperçois "
+ "Alors je sens en moi, Mon cœur qui bat Des nuits d'amour à plus finir "
+ "Un grand bonheur qui prend sa place Les ennuis, les chagrins s'effacent "
+ "Heureux, heureux à en mourir Quand il me prend dans ses bras "
+ "Il me parle tout bas Je vois la vie en rose Il me dit des mots d'amour "
+ "Des mots de tous les jours Et ça me fait quelque chose "
+ "Il est entré dans mon cœur Une part de bonheur Dont je connais la cause "
+ "C'est toi pour moi, moi pour toi, dans la vie "
+ "Tu me l'as dit, l'as juré, pour la vie Et dès que je t'aperçois "
+ "Alors je sens en moi Mon cœur qui bat";
+
+// Various HTML tags.
+const char kHtmlAttribute[] = "<html>";
+const char kHtmlAttributeWithDeLang[] = "<html lang=\"de\">";
+const char kMetaNotranslateContent[] =
+ "<meta name=\"google\" content=\"notranslate\">";
+const char kMetaNotranslateValue[] =
+ "<meta name=\"google\" value=\"notranslate\">";
+const char kMetaItContentLanguage[] =
+ "<meta http-equiv=\"content-language\" content=\"it\">";
+
+// Various link components.
+const char kHttpServerDomain[] = "localhost";
+const char kLanguagePath[] = "/languagepath/";
+const char kLinkPath[] = "/linkpath/";
+const char kSubresourcePath[] = "/subresourcepath/";
+const char kSomeLanguageUrl[] = "http://languagepath/?http=es";
+const char kFrenchPagePath[] = "/frenchpage/";
+const char kFrenchPageWithLinkPath[] = "/frenchpagewithlink/";
+const char kTranslateScriptPath[] = "/translatescript";
+const char kTranslateScript[] = "Fake Translate Script";
+
+// Builds a HTML document with a French text and the given |html| and |meta|
+// tags.
+std::string GetFrenchPageHtml(const std::string& html_tag,
+ const std::string& meta_tags) {
+ return html_tag + meta_tags + "<body>" + kFrenchText + "</body></html>";
+}
+
+// Returns the label of the "Always translate" switch in the Translate infobar.
+NSString* GetTranslateInfobarSwitchLabel(const std::string& language) {
+ return base::SysUTF16ToNSString(l10n_util::GetStringFUTF16(
+ IDS_TRANSLATE_INFOBAR_ALWAYS_TRANSLATE, base::UTF8ToUTF16(language)));
+}
+
+#pragma mark - TestResponseProvider
+
+// A ResponseProvider that provides html responses of texts in different
+// languages or links.
+class TestResponseProvider : public web::DataResponseProvider {
+ public:
+ // TestResponseProvider implementation.
+ bool CanHandleRequest(const Request& request) override;
+ void GetResponseHeadersAndBody(
+ const Request& request,
+ scoped_refptr<net::HttpResponseHeaders>* headers,
+ std::string* response_body) override;
+
+ private:
+ // Generates a page with a HTTP "Content-Language" header and "httpEquiv" meta
+ // tag.
+ // The URL in |request| has two parameters, "http" and "meta", that can be
+ // used to set the values of the header and the meta tag. For example:
+ // http://someurl?http=en&meta=fr generates a page with a "en" HTTP header and
+ // a "fr" meta tag.
+ void GetLanguageResponse(const Request& request,
+ scoped_refptr<net::HttpResponseHeaders>* headers,
+ std::string* response_body);
+};
+
+bool TestResponseProvider::CanHandleRequest(const Request& request) {
+ const GURL& url = request.url;
+ return url.host() == kHttpServerDomain &&
+ (url.path() == kLanguagePath || url.path() == kLinkPath ||
+ url.path() == kSubresourcePath || url.path() == kFrenchPagePath ||
+ url.path() == kFrenchPageWithLinkPath ||
+ url.path() == kTranslateScriptPath);
+}
+
+void TestResponseProvider::GetResponseHeadersAndBody(
+ const Request& request,
+ scoped_refptr<net::HttpResponseHeaders>* headers,
+ std::string* response_body) {
+ const GURL& url = request.url;
+ *headers = web::ResponseProvider::GetDefaultResponseHeaders();
+ if (url.path() == kLanguagePath) {
+ // HTTP header and meta tag read from parameters.
+ return GetLanguageResponse(request, headers, response_body);
+ } else if (url.path() == kSubresourcePath) {
+ // Different "Content-Language" headers in the main page and subresource.
+ (*headers)->AddHeader("Content-Language: fr");
+ *response_body = base::StringPrintf(
+ "<html><body><img src=%s></body></html>", kSomeLanguageUrl);
+ return;
+ } else if (url.path() == kLinkPath) {
+ // Link to a page with "Content Language" headers.
+ GURL url = web::test::HttpServer::MakeUrl(kSomeLanguageUrl);
+ *response_body = base::StringPrintf(
+ "<html><body><a href='%s' id='click'>Click</a></body></html>",
+ url.spec().c_str());
+ return;
+ } else if (url.path() == kFrenchPagePath) {
+ *response_body =
+ base::StringPrintf("<html><body>%s</body></html>", kFrenchText);
+ return;
+ } else if (url.path() == kFrenchPageWithLinkPath) {
+ GURL page_path_url = web::test::HttpServer::MakeUrl(
+ base::StringPrintf("http://%s", kFrenchPagePath));
+ *response_body = base::StringPrintf(
+ "<html><body>%s<br /><a href='%s' id='link'>link</a></body></html>",
+ kFrenchText, page_path_url.spec().c_str());
+ return;
+ } else if (url.path() == kTranslateScriptPath) {
+ *response_body = kTranslateScript;
+ return;
+ }
+ NOTREACHED();
+}
+
+void TestResponseProvider::GetLanguageResponse(
+ const Request& request,
+ scoped_refptr<net::HttpResponseHeaders>* headers,
+ std::string* response_body) {
+ const GURL& url = request.url;
+ // HTTP headers.
+ std::string http;
+ net::GetValueForKeyInQuery(url, "http", &http);
+ if (!http.empty())
+ (*headers)->AddHeader(std::string("Content-Language: ") + http);
+ // Response body.
+ std::string meta;
+ net::GetValueForKeyInQuery(url, "meta", &meta);
+ *response_body = "<html>";
+ if (!meta.empty()) {
+ *response_body +=
+ "<head>"
+ "<meta http-equiv='content-language' content='" +
+ meta +
+ "'>"
+ "</head>";
+ }
+ *response_body += "<body>Some text here.</body></html>";
+}
+
+} // namespace
+
+using translate::LanguageDetectionController;
+
+#pragma mark - MockTranslateScriptManager
+
+// Mock javascript translate manager that does not use the translate servers.
+// Translating the page just adds a 'Translated' button to the page, without
+// changing the text.
+@interface MockTranslateScriptManager : JsTranslateManager {
+ web::WebState* _webState; // weak
+}
+
+// YES if translate status has been checked, indicating that translate callbacks
+// have all been invoked
+@property bool translateStatusChecked;
+
+- (instancetype)initWithWebState:(web::WebState*)webState;
+
+@end
+
+@implementation MockTranslateScriptManager
+
+@synthesize translateStatusChecked = _translateStatusChecked;
+
+- (instancetype)initWithWebState:(web::WebState*)webState {
+ if ((self = [super init])) {
+ _webState = webState;
+ }
+ return self;
+}
+
+- (void)setScript:(NSString*)script {
+}
+
+- (void)startTranslationFrom:(const std::string&)source
+ to:(const std::string&)target {
+ // Add a button with the 'Translated' label to the web page.
+ // The test can check it to determine if this method has been called.
+ _webState->ExecuteJavaScript(base::UTF8ToUTF16(
+ "myButton = document.createElement('button');"
+ "myButton.appendChild(document.createTextNode('Translated'));"
+ "document.body.appendChild(myButton);"));
+}
+
+- (void)inject {
+ // Prevent the actual script from being injected.
+}
+
+- (void)injectTranslateStatusScript {
+ _webState->ExecuteJavaScript(
+ base::UTF8ToUTF16("__gCrWeb.message.invokeOnHost({"
+ " 'command': 'translate.status',"
+ " 'success': true,"
+ " 'originalPageLanguage': 'fr',"
+ " 'translationTime': 0});"));
+ self.translateStatusChecked = true;
+}
+
+- (void)injectWaitUntilTranslateReadyScript {
+ _webState->ExecuteJavaScript(
+ base::UTF8ToUTF16("__gCrWeb.message.invokeOnHost({"
+ " 'command': 'translate.ready',"
+ " 'timeout': false,"
+ " 'loadTime': 0,"
+ " 'readyTime': 0});"));
+}
+
+@end
+
+#pragma mark - TranslateTestCase
+
+// Tests for translate.
+@interface TranslateTestCase : ChromeTestCase {
+ std::unique_ptr<LanguageDetectionController::CallbackList::Subscription>
+ _subscription;
+ std::unique_ptr<LanguageDetectionController::DetectionDetails>
+ _language_detection_details;
+}
+@end
+
+@implementation TranslateTestCase
+
+- (void)setUp {
+ [super setUp];
+ // Creates a LanguageDetectionController::Callback. The callback is deleted in
+ // tearDown.
+ LanguageDetectionController::Callback copyDetailsCallback = base::BindBlock(
+ ^(const LanguageDetectionController::DetectionDetails& details) {
+ _language_detection_details.reset(
+ new LanguageDetectionController::DetectionDetails(details));
+ });
+
+ ChromeIOSTranslateClient* client = ChromeIOSTranslateClient::FromWebState(
+ chrome_test_util::GetCurrentWebState());
+ translate::IOSTranslateDriver* driver =
+ static_cast<translate::IOSTranslateDriver*>(client->GetTranslateDriver());
+ _subscription = driver->language_detection_controller()
+ ->RegisterLanguageDetectionCallback(copyDetailsCallback);
+}
+
+- (void)tearDown {
+ DCHECK(_subscription);
+ _subscription.reset();
+ _language_detection_details.reset();
+ // TODO(crbug.com/642892): Investigate moving into test-specific teardown.
+ // Re-enable translate.
+ chrome_test_util::SetBooleanUserPref(
+ chrome_test_util::GetOriginalBrowserState(), prefs::kEnableTranslate,
+ YES);
+ // Reset translate prefs to default.
+ std::unique_ptr<translate::TranslatePrefs> translatePrefs(
+ ChromeIOSTranslateClient::CreateTranslatePrefs(
+ chrome_test_util::GetOriginalBrowserState()->GetPrefs()));
+ translatePrefs->ResetToDefaults();
+ translate::TranslateManager::SetIgnoreMissingKeyForTesting(false);
+ [super tearDown];
+}
+
+#pragma mark - Test Cases
+
+// Tests that different language signals are detected correcty.
+- (void)testLanguageDetection {
+ const GURL URL =
+ web::test::HttpServer::MakeUrl("http://scenarioLanguageDetection");
+ std::map<GURL, std::string> responses;
+ // A page with French text, German "lang" attribute and Italian content
+ // language.
+ responses[URL] =
+ GetFrenchPageHtml(kHtmlAttributeWithDeLang, kMetaItContentLanguage);
+ web::test::SetUpSimpleHttpServer(responses);
+
+ LanguageDetectionController::DetectionDetails expectedLanguageDetails;
+ expectedLanguageDetails.content_language = "it";
+ expectedLanguageDetails.html_root_language = "de";
+ expectedLanguageDetails.adopted_language = translate::kUnknownLanguageCode;
+
+ [ChromeEarlGrey loadURL:URL];
+ [self assertLanguageDetails:expectedLanguageDetails];
+}
+
+// Tests that hidden text is not considered during detection.
+- (void)testLanguageDetectionIgnoreHiddenText {
+ const GURL URL = web::test::HttpServer::MakeUrl(
+ "http://scenarioLanguageDetectionIgnoreHiddenText");
+ std::map<GURL, std::string> responses;
+ // A page with French text that's hidden via CSS.
+ responses[URL] = base::StringPrintf(
+ "<html><body style='display:none'>%s</body></html>", kFrenchText);
+ web::test::SetUpSimpleHttpServer(responses);
+
+ [ChromeEarlGrey loadURL:URL];
+ // Check for no language detected.
+ LanguageDetectionController::DetectionDetails expectedLanguageDetails;
+ expectedLanguageDetails.adopted_language = translate::kUnknownLanguageCode;
+ [self assertLanguageDetails:expectedLanguageDetails];
+}
+
+// Tests that language detection is not performed when the page specifies that
+// it should not be translated.
+- (void)testLanguageDetectionNoTranslate {
+ const GURL noTranslateContentURL = web::test::HttpServer::MakeUrl(
+ "http://scenarioLanguageDetectionNoTranslate_content");
+ const GURL noTranslateValueURL = web::test::HttpServer::MakeUrl(
+ "http://scenarioLanguageDetectionNoTranslate_value");
+ std::map<GURL, std::string> responses;
+ // A page with French text and a 'content' attribute with "notranslate".
+ responses[noTranslateContentURL] =
+ GetFrenchPageHtml(kHtmlAttribute, kMetaNotranslateContent);
+ // A page with French text and a 'value' attribute with "notranslate".
+ responses[noTranslateValueURL] =
+ GetFrenchPageHtml(kHtmlAttribute, kMetaNotranslateValue);
+ web::test::SetUpSimpleHttpServer(responses);
+
+ // Load some french page with |content="notranslate"| meta tag.
+ [ChromeEarlGrey loadURL:noTranslateContentURL];
+
+ // Check that no language has been detected.
+ GREYAssert(_language_detection_details.get() == nullptr,
+ @"A language has been detected");
+
+ // Load some french page with |value="notranslate"| meta tag.
+ [ChromeEarlGrey loadURL:noTranslateValueURL];
+
+ // Check that no language has been detected.
+ GREYAssert(_language_detection_details.get() == nullptr,
+ @"A language has been detected");
+}
+
+// Tests that history.pushState triggers a new detection.
+- (void)testLanguageDetectionWithPushState {
+ const GURL URL = web::test::HttpServer::MakeUrl(
+ "http://scenarioLanguageDetectionPushState");
+ std::map<GURL, std::string> responses;
+ // Page without meaningful text, language should be undefined ("und").
+ responses[URL] = "<html><body>Blahrg :)</body></html>";
+ web::test::SetUpSimpleHttpServer(responses);
+
+ [ChromeEarlGrey loadURL:URL];
+ // Check for no language detected.
+ LanguageDetectionController::DetectionDetails expectedLanguageDetails;
+ expectedLanguageDetails.adopted_language = "und";
+ [self assertLanguageDetails:expectedLanguageDetails];
+ // Change the text of the page.
+ chrome_test_util::ExecuteJavaScript(
+ [NSString stringWithFormat:@"document.write('%s');", kEnglishText], nil);
+ // Trigger a new detection with pushState.
+ chrome_test_util::ExecuteJavaScript(@"history.pushState(null, null, null);",
+ nil);
+ // Check that the new language has been detected.
+ expectedLanguageDetails.adopted_language = "en";
+ [self assertLanguageDetails:expectedLanguageDetails];
+}
+
+// Tests that language detection is performed on hash changes.
+- (void)testLanguageDetectionWithHashChange {
+ // Generate a page with French text and a button that changes the text to
+ // English and triggers a hash change.
+ std::string html = base::StringPrintf(
+ "<html><head><script>"
+ "function hash() {"
+ " document.getElementById('text').innerHTML = '%s';"
+ " location.href='#1';"
+ "}"
+ "</script></head><body>"
+ "<input type='button' value='Hash' id='Hash' onclick='hash()'>"
+ "<div id='text'>%s</div>"
+ "</body></html>",
+ kEnglishText, kFrenchText);
+
+ // Set up the mock server.
+ std::map<GURL, std::string> responses;
+ const GURL URL =
+ web::test::HttpServer::MakeUrl("http://hashChangeLanguageDetected");
+ responses[URL] = html;
+ web::test::SetUpSimpleHttpServer(responses);
+
+ [ChromeEarlGrey loadURL:URL];
+ // Check that language has been detected.
+ LanguageDetectionController::DetectionDetails expectedLanguageDetails;
+ expectedLanguageDetails.adopted_language = "fr";
+ [self assertLanguageDetails:expectedLanguageDetails];
+ // Trigger the hash change.
+ chrome_test_util::TapWebViewElementWithId("Hash");
+ // Check that language detection has been re-run.
+ expectedLanguageDetails.adopted_language = "en";
+ [self assertLanguageDetails:expectedLanguageDetails];
+}
+
+// Tests that language in http content is detected.
+- (void)testLanguageDetectionHttpContentLanguage {
+ // Start the HTTP server.
+ std::unique_ptr<web::DataResponseProvider> provider(new TestResponseProvider);
+ web::test::SetUpHttpServer(std::move(provider));
+ LanguageDetectionController::DetectionDetails expectedLanguageDetails;
+
+ // The HTTP header is detected.
+ GURL URL = web::test::HttpServer::MakeUrl(std::string("http://") +
+ kLanguagePath + "?http=fr");
+ [ChromeEarlGrey loadURL:URL];
+ expectedLanguageDetails.content_language = "fr";
+ expectedLanguageDetails.adopted_language = "fr";
+ [self assertLanguageDetails:expectedLanguageDetails];
+
+ // Everything after the comma is truncated.
+ URL = web::test::HttpServer::MakeUrl(std::string("http://") + kLanguagePath +
+ "?http=fr,ornot");
+ [ChromeEarlGrey loadURL:URL];
+ expectedLanguageDetails.content_language = "fr";
+ expectedLanguageDetails.adopted_language = "fr";
+ [self assertLanguageDetails:expectedLanguageDetails];
+
+ // The HTTP header is overriden by meta tag.
+ URL = web::test::HttpServer::MakeUrl(std::string("http://") + kLanguagePath +
+ "?http=fr&meta=it");
+ [ChromeEarlGrey loadURL:URL];
+ expectedLanguageDetails.content_language = "it";
+ expectedLanguageDetails.adopted_language = "it";
+ [self assertLanguageDetails:expectedLanguageDetails];
+
+ // Only the header of the main page is detected.
+ URL =
+ web::test::HttpServer::MakeUrl(std::string("http://") + kSubresourcePath);
+ [ChromeEarlGrey loadURL:URL];
+ expectedLanguageDetails.content_language = "fr";
+ expectedLanguageDetails.adopted_language = "fr";
+ [self assertLanguageDetails:expectedLanguageDetails];
+}
+
+// Tests that language in http content is detected when navigating to a link.
+- (void)testLanguageDetectionHttpContentLanguageBehindLink {
+ // Start the HTTP server.
+ std::unique_ptr<web::DataResponseProvider> provider(new TestResponseProvider);
+ web::test::SetUpHttpServer(std::move(provider));
+ LanguageDetectionController::DetectionDetails expectedLanguageDetails;
+
+ // Detection works when clicking on a link.
+ GURL URL = web::test::HttpServer::MakeUrl(std::string("http://") + kLinkPath);
+ GURL someLanguageURL = web::test::HttpServer::MakeUrl(kSomeLanguageUrl);
+ [ChromeEarlGrey loadURL:URL];
+ chrome_test_util::TapWebViewElementWithId("click");
+ [[EarlGrey selectElementWithMatcher:chrome_test_util::omniboxText(
+ someLanguageURL.GetContent())]
+ assertWithMatcher:grey_notNil()];
+ expectedLanguageDetails.content_language = "es";
+ expectedLanguageDetails.adopted_language = "es";
+ [self assertLanguageDetails:expectedLanguageDetails];
+}
+
+// Tests that language detection still happens when a very large quantity of
+// text is present on the page.
+- (void)testLanguageDetectionLargePage {
+ // Generate very large page.
+ std::string html = "<html lang='fr'><body>";
+ NSUInteger targetSize = 1024 * 1024; // More than 1 MB of page content.
+ while (html.length() < targetSize) {
+ html.append(kFrenchText);
+ }
+ html.append("</body></html>");
+
+ // Create map of canned responses and set up the test HTML server.
+ std::map<GURL, std::string> responses;
+ const GURL URL =
+ web::test::HttpServer::MakeUrl("http://languageDetectionLargePage");
+ responses[URL] = html;
+ web::test::SetUpSimpleHttpServer(responses);
+ [ChromeEarlGrey loadURL:URL];
+
+ // Check that language has been detected.
+ LanguageDetectionController::DetectionDetails expectedLanguageDetails;
+ expectedLanguageDetails.html_root_language = "fr";
+ expectedLanguageDetails.adopted_language = "fr";
+ [self assertLanguageDetails:expectedLanguageDetails];
+}
+
+// Tests that language detection is not performed when translate is disabled.
+- (void)testLanguageDetectionDisabled {
+ const GURL URL = web::test::HttpServer::MakeUrl(
+ "http://scenarioLanguageDetectionDisabled");
+ std::map<GURL, std::string> responses;
+ // A page with some text.
+ responses[URL] = "<html><body>Hello world!</body></html>";
+ web::test::SetUpSimpleHttpServer(responses);
+
+ // Disable translate.
+ chrome_test_util::SetBooleanUserPref(
+ chrome_test_util::GetOriginalBrowserState(), prefs::kEnableTranslate, NO);
+
+ // Open some webpage.
+ [ChromeEarlGrey loadURL:URL];
+ // Check that no language has been detected.
+ GREYAssert(_language_detection_details.get() == nullptr,
+ @"A language has been detected");
+}
+
+// Tests that the language detection infobar is displayed.
+- (void)testLanguageDetectionInfobar {
+ // The translate machinery will not auto-fire without API keys, unless that
+ // behavior is overridden for testing.
+ translate::TranslateManager::SetIgnoreMissingKeyForTesting(true);
+
+ // Reset translate prefs to default.
+ std::unique_ptr<translate::TranslatePrefs> translatePrefs(
+ ChromeIOSTranslateClient::CreateTranslatePrefs(
+ chrome_test_util::GetOriginalBrowserState()->GetPrefs()));
+ translatePrefs->ResetToDefaults();
+
+ const GURL URL =
+ web::test::HttpServer::MakeUrl("http://scenarioLanguageDetectionInfobar");
+ std::map<GURL, std::string> responses;
+ // A page with French text.
+ responses[URL] = GetFrenchPageHtml(kHtmlAttribute, "");
+ web::test::SetUpSimpleHttpServer(responses);
+ [ChromeEarlGrey loadURL:URL];
+
+ // Check that the "Before Translate" infobar is displayed.
+ [[EarlGrey
+ selectElementWithMatcher:chrome_test_util::buttonWithAccessibilityLabel(
+ @"English")]
+ assertWithMatcher:grey_notNil()];
+ [[EarlGrey
+ selectElementWithMatcher:chrome_test_util::buttonWithAccessibilityLabelId(
+ IDS_TRANSLATE_INFOBAR_ACCEPT)]
+ assertWithMatcher:grey_notNil()];
+ [[EarlGrey
+ selectElementWithMatcher:chrome_test_util::buttonWithAccessibilityLabelId(
+ IDS_CLOSE)] assertWithMatcher:grey_notNil()];
+
+ // Open the language picker.
+ NSString* kFrench = @"French";
+ [[EarlGrey
+ selectElementWithMatcher:chrome_test_util::buttonWithAccessibilityLabel(
+ kFrench)] performAction:grey_tap()];
+
+ // The language picker uses the system accessibility labels (thus no
+ // IDS_CANCEL here).
+ [[EarlGrey
+ selectElementWithMatcher:chrome_test_util::buttonWithAccessibilityLabel(
+ @"Cancel")] assertWithMatcher:grey_notNil()];
+
+ // Change the language using the picker.
+ NSString* const kPickedLanguage = @"Finnish";
+ id<GREYMatcher> languageMatcher = grey_allOf(
+ chrome_test_util::staticTextWithAccessibilityLabel(kPickedLanguage),
+ grey_sufficientlyVisible(), nil);
+ [[EarlGrey selectElementWithMatcher:languageMatcher]
+ performAction:grey_tap()];
+ [[EarlGrey
+ selectElementWithMatcher:chrome_test_util::buttonWithAccessibilityLabel(
+ @"Done")] performAction:grey_tap()];
+ [[EarlGrey
+ selectElementWithMatcher:chrome_test_util::buttonWithAccessibilityLabel(
+ kPickedLanguage)]
+ assertWithMatcher:grey_notNil()];
+ [[EarlGrey
+ selectElementWithMatcher:chrome_test_util::buttonWithAccessibilityLabel(
+ kFrench)] assertWithMatcher:grey_nil()];
+
+ // Deny the translation, and check that the infobar is dismissed.
+ [[EarlGrey
+ selectElementWithMatcher:chrome_test_util::buttonWithAccessibilityLabelId(
+ IDS_TRANSLATE_INFOBAR_DENY)]
+ performAction:grey_tap()];
+ [[EarlGrey
+ selectElementWithMatcher:chrome_test_util::buttonWithAccessibilityLabel(
+ kPickedLanguage)]
+ assertWithMatcher:grey_nil()];
+}
+
+// Tests that the Translate infobar is displayed after translation.
+- (void)testTranslateInfobar {
+ const GURL URL =
+ web::test::HttpServer::MakeUrl("http://scenarioTranslateInfobar");
+ std::map<GURL, std::string> responses;
+ // A page with some text.
+ responses[URL] = "<html><body>Hello world!</body></html>";
+ web::test::SetUpSimpleHttpServer(responses);
+
+ // Reset translate prefs to default.
+ std::unique_ptr<translate::TranslatePrefs> translatePrefs(
+ ChromeIOSTranslateClient::CreateTranslatePrefs(
+ chrome_test_util::GetOriginalBrowserState()->GetPrefs()));
+ translatePrefs->ResetToDefaults();
+
+ // Assert that Spanish to English translation is disabled.
+ GREYAssert(!translatePrefs->IsLanguagePairWhitelisted("es", "en"),
+ @"Translate Spanish is enabled");
+ // Increase accepted translation count for Spanish
+ for (int i = 0; i < 3; i++) {
+ translatePrefs->IncrementTranslationAcceptedCount("es");
+ }
+
+ // Open a new webpage.
+ [ChromeEarlGrey loadURL:URL];
+ [self simulateTranslationFromSpanishToEnglish];
+
+ // Check that the "Always Translate" switch is displayed in the infobar.
+ NSString* switchLabel = GetTranslateInfobarSwitchLabel("Spanish");
+ [[EarlGrey
+ selectElementWithMatcher:chrome_test_util::buttonWithAccessibilityLabel(
+ switchLabel)]
+ assertWithMatcher:grey_notNil()];
+
+ // Toggle "Always Translate" and check the preference.
+ [[EarlGrey
+ selectElementWithMatcher:chrome_test_util::buttonWithAccessibilityLabel(
+ switchLabel)] performAction:grey_tap()];
+ id<GREYMatcher> switchOn =
+ grey_allOf(chrome_test_util::buttonWithAccessibilityLabel(switchLabel),
+ grey_accessibilityValue(@"1"), nil);
+ [[EarlGrey selectElementWithMatcher:switchOn]
+ assertWithMatcher:grey_notNil()];
+
+ // Assert that Spanish to English translation is enabled.
+ GREYAssert(translatePrefs->IsLanguagePairWhitelisted("es", "en"),
+ @"Translate Spanish is disabled");
+}
+
+// Tests that the "Always Translate" switch is not shown in incognito mode.
+- (void)testIncognitoTranslateInfobar {
+ const GURL URL =
+ web::test::HttpServer::MakeUrl("http://scenarioTranslateInfobar");
+ std::map<GURL, std::string> responses;
+ // A page with some text.
+ responses[URL] = "<html><body>Hello world!</body></html>";
+ web::test::SetUpSimpleHttpServer(responses);
+
+ // Reset translate prefs to default.
+ std::unique_ptr<translate::TranslatePrefs> translatePrefs(
+ ChromeIOSTranslateClient::CreateTranslatePrefs(
+ chrome_test_util::GetOriginalBrowserState()->GetPrefs()));
+ translatePrefs->ResetToDefaults();
+ // Increased accepted translation count for Spanish.
+ for (int i = 0; i < 3; i++) {
+ translatePrefs->IncrementTranslationAcceptedCount("es");
+ }
+
+ // Do a translation in incognito
+ chrome_test_util::OpenNewIncognitoTab();
+ [ChromeEarlGrey loadURL:URL];
+ [self simulateTranslationFromSpanishToEnglish];
+ // Check that the infobar does not contain the "Always Translate" switch.
+ NSString* switchLabel = GetTranslateInfobarSwitchLabel("Spanish");
+ [[EarlGrey
+ selectElementWithMatcher:chrome_test_util::buttonWithAccessibilityLabel(
+ switchLabel)] assertWithMatcher:grey_nil()];
+}
+
+// Tests that translation occurs automatically on second navigation to an
+// already translated page.
+- (void)testAutoTranslate {
+ // The translate machinery will not auto-fire without API keys, unless that
+ // behavior is overridden for testing.
+ translate::TranslateManager::SetIgnoreMissingKeyForTesting(true);
+
+ std::unique_ptr<web::DataResponseProvider> provider(new TestResponseProvider);
+ web::test::SetUpHttpServer(std::move(provider));
+
+ // Reset translate prefs to default.
+ std::unique_ptr<translate::TranslatePrefs> translatePrefs(
+ ChromeIOSTranslateClient::CreateTranslatePrefs(
+ chrome_test_util::GetOriginalBrowserState()->GetPrefs()));
+ translatePrefs->ResetToDefaults();
+
+ // Set up the mock translate script manager.
+ ChromeIOSTranslateClient* client = ChromeIOSTranslateClient::FromWebState(
+ chrome_test_util::GetCurrentWebState());
+ translate::IOSTranslateDriver* driver =
+ static_cast<translate::IOSTranslateDriver*>(client->GetTranslateDriver());
+ base::scoped_nsobject<MockTranslateScriptManager> jsTranslateManager(
+ [[MockTranslateScriptManager alloc]
+ initWithWebState:chrome_test_util::GetCurrentWebState()]);
+ driver->translate_controller()->SetJsTranslateManagerForTesting(
+ jsTranslateManager);
+
+ // Set up a fake URL for the translate script, to avoid hitting real servers.
+ base::CommandLine& command_line = *base::CommandLine::ForCurrentProcess();
+ GURL translateScriptURL =
+ web::test::HttpServer::MakeUrl("http://translatescript");
+ command_line.AppendSwitchASCII(translate::switches::kTranslateScriptURL,
+ translateScriptURL.spec().c_str());
+
+ // Translate the page with the link.
+ GURL frenchPageURL =
+ web::test::HttpServer::MakeUrl("http://frenchpagewithlink");
+ [ChromeEarlGrey loadURL:frenchPageURL];
+ [[EarlGrey
+ selectElementWithMatcher:chrome_test_util::buttonWithAccessibilityLabelId(
+ IDS_TRANSLATE_INFOBAR_ACCEPT)]
+ performAction:grey_tap()];
+
+ // Wait for all callbacks.
+ GREYAssert(testing::WaitUntilConditionOrTimeout(
+ testing::kWaitForJSCompletionTimeout,
+ ^{
+ return jsTranslateManager.get().translateStatusChecked;
+ }),
+ @"Did not receive all translate status callbacks");
+
+ // Check that the translation happened.
+ [[EarlGrey selectElementWithMatcher:chrome_test_util::webViewContainingText(
+ "Translated")]
+ assertWithMatcher:grey_notNil()];
+
+ // Click on the link.
+ [ChromeEarlGrey tapWebViewElementWithID:@"link"];
+ GURL frenchPagePathURL = web::test::HttpServer::MakeUrl(
+ base::StringPrintf("http://%s", kFrenchPagePath));
+ [[EarlGrey
+ selectElementWithMatcher:chrome_test_util::webViewContainingText("link")]
+ assertWithMatcher:grey_nil()];
+ [[EarlGrey selectElementWithMatcher:chrome_test_util::omniboxText(
+ frenchPagePathURL.GetContent())]
+ assertWithMatcher:grey_notNil()];
+
+ // Check that the auto-translation happened.
+ [[EarlGrey selectElementWithMatcher:chrome_test_util::webViewContainingText(
+ "Translated")]
+ assertWithMatcher:grey_notNil()];
+}
+
+#pragma mark - Utility methods
+
+// Waits until a language has been detected and checks the language details.
+- (void)assertLanguageDetails:
+ (const LanguageDetectionController::DetectionDetails&)expectedDetails {
+ GREYAssert(testing::WaitUntilConditionOrTimeout(
+ 2.0,
+ ^{
+ return _language_detection_details.get() != nullptr;
+ }),
+ @"Language not detected");
+
+ LanguageDetectionController::DetectionDetails details =
+ *_language_detection_details.get();
+ _language_detection_details.reset();
+
+ NSString* contentLanguageError =
+ [NSString stringWithFormat:@"Wrong content-language: %s (expected %s)",
+ details.content_language.c_str(),
+ expectedDetails.content_language.c_str()];
+ GREYAssert(expectedDetails.content_language == details.content_language,
+ contentLanguageError);
+
+ NSString* htmlRootLanguageError =
+ [NSString stringWithFormat:@"Wrong html root language: %s (expected %s)",
+ details.html_root_language.c_str(),
+ expectedDetails.html_root_language.c_str()];
+ GREYAssert(expectedDetails.html_root_language == details.html_root_language,
+ htmlRootLanguageError);
+
+ NSString* adoptedLanguageError =
+ [NSString stringWithFormat:@"Wrong adopted language: %s (expected %s)",
+ details.adopted_language.c_str(),
+ expectedDetails.adopted_language.c_str()];
+ GREYAssert(expectedDetails.adopted_language == details.adopted_language,
+ adoptedLanguageError);
+}
+
+// Simulates translation from Spanish to English, and asserts that the translate
+// InfoBar is shown.
+- (void)simulateTranslationFromSpanishToEnglish {
+ // Simulate translation.
+ ChromeIOSTranslateClient* client = ChromeIOSTranslateClient::FromWebState(
+ chrome_test_util::GetCurrentWebState());
+ client->GetTranslateManager()->PageTranslated(
+ "es", "en", translate::TranslateErrors::NONE);
+
+ // Assert that the infobar is visible.
+ [[EarlGrey
+ selectElementWithMatcher:chrome_test_util::buttonWithAccessibilityLabelId(
+ IDS_DONE)] assertWithMatcher:grey_notNil()];
+ [[EarlGrey
+ selectElementWithMatcher:chrome_test_util::buttonWithAccessibilityLabelId(
+ IDS_TRANSLATE_INFOBAR_REVERT)]
+ assertWithMatcher:grey_notNil()];
+ [[EarlGrey
+ selectElementWithMatcher:chrome_test_util::buttonWithAccessibilityLabelId(
+ IDS_CLOSE)] assertWithMatcher:grey_notNil()];
+}
+
+@end
« no previous file with comments | « ios/chrome/browser/translate/js_language_detection_manager_unittest.mm ('k') | ios/chrome/browser/ui/actions/README.md » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698