Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / chrome / renderer / translate / translate_helper_browsertest.cc
blob63402b758e33c7afaa4ed29776779b7ef603dd97
1 // Copyright (c) 2012 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.
5 #include "base/time/time.h"
6 #include "chrome/common/chrome_isolated_world_ids.h"
7 #include "chrome/test/base/chrome_render_view_test.h"
8 #include "components/translate/content/common/translate_messages.h"
9 #include "components/translate/content/renderer/translate_helper.h"
10 #include "components/translate/core/common/translate_constants.h"
11 #include "content/public/renderer/render_view.h"
12 #include "extensions/common/constants.h"
13 #include "testing/gmock/include/gmock/gmock.h"
14 #include "testing/gtest/include/gtest/gtest.h"
15 #include "third_party/WebKit/public/web/WebLocalFrame.h"
17 using testing::AtLeast;
18 using testing::Return;
19 using testing::_;
21 class TestTranslateHelper : public translate::TranslateHelper {
22 public:
23 explicit TestTranslateHelper(content::RenderView* render_view)
24 : translate::TranslateHelper(
25 render_view,
26 chrome::ISOLATED_WORLD_ID_TRANSLATE,
28 extensions::kExtensionScheme) {}
30 base::TimeDelta AdjustDelay(int delayInMs) override {
31 // Just returns base::TimeDelta() which has initial value 0.
32 // Tasks doesn't need to be delayed in tests.
33 return base::TimeDelta();
36 void TranslatePage(const std::string& source_lang,
37 const std::string& target_lang,
38 const std::string& translate_script) {
39 OnTranslatePage(0, translate_script, source_lang, target_lang);
42 MOCK_METHOD0(IsTranslateLibAvailable, bool());
43 MOCK_METHOD0(IsTranslateLibReady, bool());
44 MOCK_METHOD0(HasTranslationFinished, bool());
45 MOCK_METHOD0(HasTranslationFailed, bool());
46 MOCK_METHOD0(GetOriginalPageLanguage, std::string());
47 MOCK_METHOD0(StartTranslation, bool());
48 MOCK_METHOD1(ExecuteScript, void(const std::string&));
49 MOCK_METHOD2(ExecuteScriptAndGetBoolResult, bool(const std::string&, bool));
50 MOCK_METHOD1(ExecuteScriptAndGetStringResult,
51 std::string(const std::string&));
52 MOCK_METHOD1(ExecuteScriptAndGetDoubleResult, double(const std::string&));
54 private:
55 DISALLOW_COPY_AND_ASSIGN(TestTranslateHelper);
58 class TranslateHelperBrowserTest : public ChromeRenderViewTest {
59 public:
60 TranslateHelperBrowserTest() : translate_helper_(NULL) {}
62 protected:
63 void SetUp() override {
64 ChromeRenderViewTest::SetUp();
65 translate_helper_ = new TestTranslateHelper(view_);
68 void TearDown() override {
69 delete translate_helper_;
70 ChromeRenderViewTest::TearDown();
73 bool GetPageTranslatedMessage(std::string* original_lang,
74 std::string* target_lang,
75 translate::TranslateErrors::Type* error) {
76 const IPC::Message* message = render_thread_->sink().
77 GetUniqueMessageMatching(ChromeViewHostMsg_PageTranslated::ID);
78 if (!message)
79 return false;
80 base::Tuple<std::string, std::string, translate::TranslateErrors::Type>
81 translate_param;
82 ChromeViewHostMsg_PageTranslated::Read(message, &translate_param);
83 if (original_lang)
84 *original_lang = base::get<0>(translate_param);
85 if (target_lang)
86 *target_lang = base::get<1>(translate_param);
87 if (error)
88 *error = base::get<2>(translate_param);
89 return true;
92 TestTranslateHelper* translate_helper_;
94 private:
95 DISALLOW_COPY_AND_ASSIGN(TranslateHelperBrowserTest);
98 // Tests that the browser gets notified of the translation failure if the
99 // translate library fails/times-out during initialization.
100 TEST_F(TranslateHelperBrowserTest, TranslateLibNeverReady) {
101 // We make IsTranslateLibAvailable true so we don't attempt to inject the
102 // library.
103 EXPECT_CALL(*translate_helper_, IsTranslateLibAvailable())
104 .Times(AtLeast(1))
105 .WillRepeatedly(Return(true));
107 EXPECT_CALL(*translate_helper_, IsTranslateLibReady())
108 .Times(AtLeast(5)) // See kMaxTranslateInitCheckAttempts in
109 // translate_helper.cc
110 .WillRepeatedly(Return(false));
112 translate_helper_->TranslatePage("en", "fr", std::string());
113 base::MessageLoop::current()->RunUntilIdle();
115 translate::TranslateErrors::Type error;
116 ASSERT_TRUE(GetPageTranslatedMessage(NULL, NULL, &error));
117 EXPECT_EQ(translate::TranslateErrors::INITIALIZATION_ERROR, error);
120 // Tests that the browser gets notified of the translation success when the
121 // translation succeeds.
122 TEST_F(TranslateHelperBrowserTest, TranslateSuccess) {
123 // We make IsTranslateLibAvailable true so we don't attempt to inject the
124 // library.
125 EXPECT_CALL(*translate_helper_, IsTranslateLibAvailable())
126 .Times(AtLeast(1))
127 .WillRepeatedly(Return(true));
129 EXPECT_CALL(*translate_helper_, IsTranslateLibReady())
130 .WillOnce(Return(false))
131 .WillOnce(Return(true));
133 EXPECT_CALL(*translate_helper_, StartTranslation()).WillOnce(Return(true));
135 // Succeed after few checks.
136 EXPECT_CALL(*translate_helper_, HasTranslationFailed())
137 .WillRepeatedly(Return(false));
138 EXPECT_CALL(*translate_helper_, HasTranslationFinished())
139 .WillOnce(Return(false))
140 .WillOnce(Return(false))
141 .WillOnce(Return(true));
143 // V8 call for performance monitoring should be ignored.
144 EXPECT_CALL(*translate_helper_,
145 ExecuteScriptAndGetDoubleResult(_)).Times(3);
147 std::string original_lang("en");
148 std::string target_lang("fr");
149 translate_helper_->TranslatePage(original_lang, target_lang, std::string());
150 base::MessageLoop::current()->RunUntilIdle();
152 std::string received_original_lang;
153 std::string received_target_lang;
154 translate::TranslateErrors::Type error;
155 ASSERT_TRUE(GetPageTranslatedMessage(&received_original_lang,
156 &received_target_lang,
157 &error));
158 EXPECT_EQ(original_lang, received_original_lang);
159 EXPECT_EQ(target_lang, received_target_lang);
160 EXPECT_EQ(translate::TranslateErrors::NONE, error);
163 // Tests that the browser gets notified of the translation failure when the
164 // translation fails.
165 TEST_F(TranslateHelperBrowserTest, TranslateFailure) {
166 // We make IsTranslateLibAvailable true so we don't attempt to inject the
167 // library.
168 EXPECT_CALL(*translate_helper_, IsTranslateLibAvailable())
169 .Times(AtLeast(1))
170 .WillRepeatedly(Return(true));
172 EXPECT_CALL(*translate_helper_, IsTranslateLibReady())
173 .WillOnce(Return(true));
175 EXPECT_CALL(*translate_helper_, StartTranslation()).WillOnce(Return(true));
177 // Fail after few checks.
178 EXPECT_CALL(*translate_helper_, HasTranslationFailed())
179 .WillOnce(Return(false))
180 .WillOnce(Return(false))
181 .WillOnce(Return(false))
182 .WillOnce(Return(true));
184 EXPECT_CALL(*translate_helper_, HasTranslationFinished())
185 .Times(AtLeast(1))
186 .WillRepeatedly(Return(false));
188 // V8 call for performance monitoring should be ignored.
189 EXPECT_CALL(*translate_helper_,
190 ExecuteScriptAndGetDoubleResult(_)).Times(2);
192 translate_helper_->TranslatePage("en", "fr", std::string());
193 base::MessageLoop::current()->RunUntilIdle();
195 translate::TranslateErrors::Type error;
196 ASSERT_TRUE(GetPageTranslatedMessage(NULL, NULL, &error));
197 EXPECT_EQ(translate::TranslateErrors::TRANSLATION_ERROR, error);
200 // Tests that when the browser translate a page for which the language is
201 // undefined we query the translate element to get the language.
202 TEST_F(TranslateHelperBrowserTest, UndefinedSourceLang) {
203 // We make IsTranslateLibAvailable true so we don't attempt to inject the
204 // library.
205 EXPECT_CALL(*translate_helper_, IsTranslateLibAvailable())
206 .Times(AtLeast(1))
207 .WillRepeatedly(Return(true));
209 EXPECT_CALL(*translate_helper_, IsTranslateLibReady())
210 .WillOnce(Return(true));
212 EXPECT_CALL(*translate_helper_, GetOriginalPageLanguage())
213 .WillOnce(Return("de"));
215 EXPECT_CALL(*translate_helper_, StartTranslation()).WillOnce(Return(true));
216 EXPECT_CALL(*translate_helper_, HasTranslationFailed())
217 .WillOnce(Return(false));
218 EXPECT_CALL(*translate_helper_, HasTranslationFinished())
219 .Times(AtLeast(1))
220 .WillRepeatedly(Return(true));
222 // V8 call for performance monitoring should be ignored.
223 EXPECT_CALL(*translate_helper_,
224 ExecuteScriptAndGetDoubleResult(_)).Times(3);
226 translate_helper_->TranslatePage(translate::kUnknownLanguageCode,
227 "fr",
228 std::string());
229 base::MessageLoop::current()->RunUntilIdle();
231 translate::TranslateErrors::Type error;
232 std::string original_lang;
233 std::string target_lang;
234 ASSERT_TRUE(GetPageTranslatedMessage(&original_lang, &target_lang, &error));
235 EXPECT_EQ("de", original_lang);
236 EXPECT_EQ("fr", target_lang);
237 EXPECT_EQ(translate::TranslateErrors::NONE, error);
240 // Tests that starting a translation while a similar one is pending does not
241 // break anything.
242 TEST_F(TranslateHelperBrowserTest, MultipleSimilarTranslations) {
243 // We make IsTranslateLibAvailable true so we don't attempt to inject the
244 // library.
245 EXPECT_CALL(*translate_helper_, IsTranslateLibAvailable())
246 .Times(AtLeast(1))
247 .WillRepeatedly(Return(true));
249 EXPECT_CALL(*translate_helper_, IsTranslateLibReady())
250 .WillRepeatedly(Return(true));
251 EXPECT_CALL(*translate_helper_, StartTranslation())
252 .WillRepeatedly(Return(true));
253 EXPECT_CALL(*translate_helper_, HasTranslationFailed())
254 .WillRepeatedly(Return(false));
255 EXPECT_CALL(*translate_helper_, HasTranslationFinished())
256 .WillOnce(Return(true));
258 // V8 call for performance monitoring should be ignored.
259 EXPECT_CALL(*translate_helper_,
260 ExecuteScriptAndGetDoubleResult(_)).Times(3);
262 std::string original_lang("en");
263 std::string target_lang("fr");
264 translate_helper_->TranslatePage(original_lang, target_lang, std::string());
265 // While this is running call again TranslatePage to make sure noting bad
266 // happens.
267 translate_helper_->TranslatePage(original_lang, target_lang, std::string());
268 base::MessageLoop::current()->RunUntilIdle();
270 std::string received_original_lang;
271 std::string received_target_lang;
272 translate::TranslateErrors::Type error;
273 ASSERT_TRUE(GetPageTranslatedMessage(&received_original_lang,
274 &received_target_lang,
275 &error));
276 EXPECT_EQ(original_lang, received_original_lang);
277 EXPECT_EQ(target_lang, received_target_lang);
278 EXPECT_EQ(translate::TranslateErrors::NONE, error);
281 // Tests that starting a translation while a different one is pending works.
282 TEST_F(TranslateHelperBrowserTest, MultipleDifferentTranslations) {
283 EXPECT_CALL(*translate_helper_, IsTranslateLibAvailable())
284 .Times(AtLeast(1))
285 .WillRepeatedly(Return(true));
286 EXPECT_CALL(*translate_helper_, IsTranslateLibReady())
287 .WillRepeatedly(Return(true));
288 EXPECT_CALL(*translate_helper_, StartTranslation())
289 .WillRepeatedly(Return(true));
290 EXPECT_CALL(*translate_helper_, HasTranslationFailed())
291 .WillRepeatedly(Return(false));
292 EXPECT_CALL(*translate_helper_, HasTranslationFinished())
293 .WillOnce(Return(true));
295 // V8 call for performance monitoring should be ignored.
296 EXPECT_CALL(*translate_helper_,
297 ExecuteScriptAndGetDoubleResult(_)).Times(5);
299 std::string original_lang("en");
300 std::string target_lang("fr");
301 translate_helper_->TranslatePage(original_lang, target_lang, std::string());
302 // While this is running call again TranslatePage with a new target lang.
303 std::string new_target_lang("de");
304 translate_helper_->TranslatePage(
305 original_lang, new_target_lang, std::string());
306 base::MessageLoop::current()->RunUntilIdle();
308 std::string received_original_lang;
309 std::string received_target_lang;
310 translate::TranslateErrors::Type error;
311 ASSERT_TRUE(GetPageTranslatedMessage(&received_original_lang,
312 &received_target_lang,
313 &error));
314 EXPECT_EQ(original_lang, received_original_lang);
315 EXPECT_EQ(new_target_lang, received_target_lang);
316 EXPECT_EQ(translate::TranslateErrors::NONE, error);
319 // Tests that we send the right translate language message for a page and that
320 // we respect the "no translate" meta-tag.
321 TEST_F(ChromeRenderViewTest, TranslatablePage) {
322 // Suppress the normal delay that occurs when the page is loaded before which
323 // the renderer sends the page contents to the browser.
324 SendContentStateImmediately();
326 LoadHTML("<html><body>A random page with random content.</body></html>");
327 const IPC::Message* message = render_thread_->sink().GetUniqueMessageMatching(
328 ChromeViewHostMsg_TranslateLanguageDetermined::ID);
329 ASSERT_NE(static_cast<IPC::Message*>(NULL), message);
330 ChromeViewHostMsg_TranslateLanguageDetermined::Param params;
331 ChromeViewHostMsg_TranslateLanguageDetermined::Read(message, &params);
332 EXPECT_TRUE(base::get<1>(params)) << "Page should be translatable.";
333 render_thread_->sink().ClearMessages();
335 // Now the page specifies the META tag to prevent translation.
336 LoadHTML("<html><head><meta name=\"google\" value=\"notranslate\"></head>"
337 "<body>A random page with random content.</body></html>");
338 message = render_thread_->sink().GetUniqueMessageMatching(
339 ChromeViewHostMsg_TranslateLanguageDetermined::ID);
340 ASSERT_NE(static_cast<IPC::Message*>(NULL), message);
341 ChromeViewHostMsg_TranslateLanguageDetermined::Read(message, &params);
342 EXPECT_FALSE(base::get<1>(params)) << "Page should not be translatable.";
343 render_thread_->sink().ClearMessages();
345 // Try the alternate version of the META tag (content instead of value).
346 LoadHTML("<html><head><meta name=\"google\" content=\"notranslate\"></head>"
347 "<body>A random page with random content.</body></html>");
348 message = render_thread_->sink().GetUniqueMessageMatching(
349 ChromeViewHostMsg_TranslateLanguageDetermined::ID);
350 ASSERT_NE(static_cast<IPC::Message*>(NULL), message);
351 ChromeViewHostMsg_TranslateLanguageDetermined::Read(message, &params);
352 EXPECT_FALSE(base::get<1>(params)) << "Page should not be translatable.";
355 // Tests that the language meta tag takes precedence over the CLD when reporting
356 // the page's language.
357 TEST_F(ChromeRenderViewTest, LanguageMetaTag) {
358 // Suppress the normal delay that occurs when the page is loaded before which
359 // the renderer sends the page contents to the browser.
360 SendContentStateImmediately();
362 LoadHTML("<html><head><meta http-equiv=\"content-language\" content=\"es\">"
363 "</head><body>A random page with random content.</body></html>");
364 const IPC::Message* message = render_thread_->sink().GetUniqueMessageMatching(
365 ChromeViewHostMsg_TranslateLanguageDetermined::ID);
366 ASSERT_NE(static_cast<IPC::Message*>(NULL), message);
367 ChromeViewHostMsg_TranslateLanguageDetermined::Param params;
368 ChromeViewHostMsg_TranslateLanguageDetermined::Read(message, &params);
369 EXPECT_EQ("es", base::get<0>(params).adopted_language);
370 render_thread_->sink().ClearMessages();
372 // Makes sure we support multiple languages specified.
373 LoadHTML("<html><head><meta http-equiv=\"content-language\" "
374 "content=\" fr , es,en \">"
375 "</head><body>A random page with random content.</body></html>");
376 message = render_thread_->sink().GetUniqueMessageMatching(
377 ChromeViewHostMsg_TranslateLanguageDetermined::ID);
378 ASSERT_NE(static_cast<IPC::Message*>(NULL), message);
379 ChromeViewHostMsg_TranslateLanguageDetermined::Read(message, &params);
380 EXPECT_EQ("fr", base::get<0>(params).adopted_language);
383 // Tests that the language meta tag works even with non-all-lower-case.
384 // http://code.google.com/p/chromium/issues/detail?id=145689
385 TEST_F(ChromeRenderViewTest, LanguageMetaTagCase) {
386 // Suppress the normal delay that occurs when the page is loaded before which
387 // the renderer sends the page contents to the browser.
388 SendContentStateImmediately();
390 LoadHTML("<html><head><meta http-equiv=\"Content-Language\" content=\"es\">"
391 "</head><body>A random page with random content.</body></html>");
392 const IPC::Message* message = render_thread_->sink().GetUniqueMessageMatching(
393 ChromeViewHostMsg_TranslateLanguageDetermined::ID);
394 ASSERT_NE(static_cast<IPC::Message*>(NULL), message);
395 ChromeViewHostMsg_TranslateLanguageDetermined::Param params;
396 ChromeViewHostMsg_TranslateLanguageDetermined::Read(message, &params);
397 EXPECT_EQ("es", base::get<0>(params).adopted_language);
398 render_thread_->sink().ClearMessages();
400 // Makes sure we support multiple languages specified.
401 LoadHTML("<html><head><meta http-equiv=\"Content-Language\" "
402 "content=\" fr , es,en \">"
403 "</head><body>A random page with random content.</body></html>");
404 message = render_thread_->sink().GetUniqueMessageMatching(
405 ChromeViewHostMsg_TranslateLanguageDetermined::ID);
406 ASSERT_NE(static_cast<IPC::Message*>(NULL), message);
407 ChromeViewHostMsg_TranslateLanguageDetermined::Read(message, &params);
408 EXPECT_EQ("fr", base::get<0>(params).adopted_language);
411 // Tests that the language meta tag is converted to Chrome standard of dashes
412 // instead of underscores and proper capitalization.
413 // http://code.google.com/p/chromium/issues/detail?id=159487
414 TEST_F(ChromeRenderViewTest, LanguageCommonMistakesAreCorrected) {
415 // Suppress the normal delay that occurs when the page is loaded before which
416 // the renderer sends the page contents to the browser.
417 SendContentStateImmediately();
419 LoadHTML("<html><head><meta http-equiv='Content-Language' content='EN_us'>"
420 "</head><body>A random page with random content.</body></html>");
421 const IPC::Message* message = render_thread_->sink().GetUniqueMessageMatching(
422 ChromeViewHostMsg_TranslateLanguageDetermined::ID);
423 ASSERT_NE(static_cast<IPC::Message*>(NULL), message);
424 ChromeViewHostMsg_TranslateLanguageDetermined::Param params;
425 ChromeViewHostMsg_TranslateLanguageDetermined::Read(message, &params);
426 EXPECT_EQ("en", base::get<0>(params).adopted_language);
427 render_thread_->sink().ClearMessages();
429 LoadHTML("<html><head><meta http-equiv='Content-Language' content='ZH_tw'>"
430 "</head><body>A random page with random content.</body></html>");
431 message = render_thread_->sink().GetUniqueMessageMatching(
432 ChromeViewHostMsg_TranslateLanguageDetermined::ID);
433 ASSERT_NE(static_cast<IPC::Message*>(NULL), message);
434 ChromeViewHostMsg_TranslateLanguageDetermined::Read(message, &params);
435 EXPECT_EQ("zh-TW", base::get<0>(params).adopted_language);
436 render_thread_->sink().ClearMessages();
439 // Tests that a back navigation gets a translate language message.
440 TEST_F(ChromeRenderViewTest, BackToTranslatablePage) {
441 SendContentStateImmediately();
442 LoadHTML("<html><head><meta http-equiv=\"content-language\" content=\"zh\">"
443 "</head><body>This page is in Chinese.</body></html>");
444 const IPC::Message* message = render_thread_->sink().GetUniqueMessageMatching(
445 ChromeViewHostMsg_TranslateLanguageDetermined::ID);
446 ASSERT_NE(static_cast<IPC::Message*>(NULL), message);
447 ChromeViewHostMsg_TranslateLanguageDetermined::Param params;
448 ChromeViewHostMsg_TranslateLanguageDetermined::Read(message, &params);
449 EXPECT_EQ("zh", base::get<0>(params).adopted_language);
450 render_thread_->sink().ClearMessages();
452 content::PageState back_state = GetCurrentPageState();
454 LoadHTML("<html><head><meta http-equiv=\"content-language\" content=\"fr\">"
455 "</head><body>This page is in French.</body></html>");
456 message = render_thread_->sink().GetUniqueMessageMatching(
457 ChromeViewHostMsg_TranslateLanguageDetermined::ID);
458 ASSERT_NE(static_cast<IPC::Message*>(NULL), message);
459 ChromeViewHostMsg_TranslateLanguageDetermined::Read(message, &params);
460 EXPECT_EQ("fr", base::get<0>(params).adopted_language);
461 render_thread_->sink().ClearMessages();
463 GoBack(back_state);
465 message = render_thread_->sink().GetUniqueMessageMatching(
466 ChromeViewHostMsg_TranslateLanguageDetermined::ID);
467 ASSERT_NE(static_cast<IPC::Message*>(NULL), message);
468 ChromeViewHostMsg_TranslateLanguageDetermined::Read(message, &params);
469 EXPECT_EQ("zh", base::get<0>(params).adopted_language);
470 render_thread_->sink().ClearMessages();