1// Copyright 2013 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#include "base/command_line.h"
6#include "base/files/file_path.h"
7#include "base/strings/string_util.h"
8#include "base/strings/utf_string_conversions.h"
9#include "chrome/browser/chrome_notification_types.h"
10#include "chrome/browser/infobars/infobar_service.h"
11#include "chrome/browser/translate/translate_service.h"
12#include "chrome/browser/ui/browser.h"
13#include "chrome/browser/ui/tabs/tab_strip_model.h"
14#include "chrome/test/base/in_process_browser_test.h"
15#include "chrome/test/base/test_switches.h"
16#include "chrome/test/base/ui_test_utils.h"
17#include "components/infobars/core/infobar.h"
18#include "components/translate/core/browser/translate_infobar_delegate.h"
19#include "components/translate/core/browser/translate_manager.h"
20#include "components/translate/core/browser/translate_script.h"
21#include "components/translate/core/common/translate_switches.h"
22#include "content/public/browser/notification_service.h"
23#include "content/public/test/browser_test_utils.h"
24#include "net/http/http_status_code.h"
25#include "net/test/embedded_test_server/embedded_test_server.h"
26#include "net/test/spawned_test_server/spawned_test_server.h"
27#include "net/url_request/test_url_fetcher_factory.h"
28#include "net/url_request/url_fetcher_delegate.h"
29
30namespace {
31
32const base::FilePath::CharType kTranslateRoot[] =
33    FILE_PATH_LITERAL("chrome/test/data/translate");
34const char kNonSecurePrefix[] = "/translate/";
35const char kSecurePrefix[] = "files/";
36const char kFrenchTestPath[] = "fr_test.html";
37const char kRefreshMetaTagTestPath[] = "refresh_meta_tag.html";
38const char kRefreshMetaTagCaseInsensitiveTestPath[] =
39    "refresh_meta_tag_casei.html";
40const char kRefreshMetaTagAtOnloadTestPath[] =
41    "refresh_meta_tag_at_onload.html";
42const char kUpdateLocationTestPath[] = "update_location.html";
43const char kUpdateLocationAtOnloadTestPath[] = "update_location_at_onload.html";
44const char kMainScriptPath[] = "pseudo_main.js";
45const char kElementMainScriptPath[] = "pseudo_element_main.js";
46
47};  // namespace
48
49class TranslateBrowserTest : public InProcessBrowserTest {
50 public:
51  TranslateBrowserTest()
52      : https_server_(net::SpawnedTestServer::TYPE_HTTPS,
53                      SSLOptions(SSLOptions::CERT_OK),
54                      base::FilePath(kTranslateRoot)),
55        infobar_service_(NULL) {}
56
57  virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
58    ASSERT_TRUE(https_server_.Start());
59    // Setup alternate security origin for testing in order to allow XHR against
60    // local test server. Note that this flag shows a confirm infobar in tests.
61    GURL base_url = GetSecureURL("");
62    command_line->AppendSwitchASCII(
63        translate::switches::kTranslateSecurityOrigin,
64        base_url.GetOrigin().spec());
65  }
66
67 protected:
68  GURL GetNonSecureURL(const std::string& path) const {
69    std::string prefix(kNonSecurePrefix);
70    return embedded_test_server()->GetURL(prefix + path);
71  }
72
73  GURL GetSecureURL(const std::string& path) const {
74    std::string prefix(kSecurePrefix);
75    return https_server_.GetURL(prefix + path);
76  }
77
78  translate::TranslateInfoBarDelegate* GetExistingTranslateInfoBarDelegate() {
79    if (!infobar_service_) {
80      content::WebContents* web_contents =
81          browser()->tab_strip_model()->GetActiveWebContents();
82      if (web_contents)
83        infobar_service_ = InfoBarService::FromWebContents(web_contents);
84    }
85    if (!infobar_service_) {
86      ADD_FAILURE() << "infobar service is not available";
87      return NULL;
88    }
89
90    translate::TranslateInfoBarDelegate* delegate = NULL;
91    for (size_t i = 0; i < infobar_service_->infobar_count(); ++i) {
92      // Check if the shown infobar is a confirm infobar coming from the
93      // |kTranslateSecurityOrigin| flag specified in SetUpCommandLine().
94      // This infobar appears in all tests of TranslateBrowserTest and can be
95      // ignored here.
96      if (infobar_service_->infobar_at(i)->delegate()->
97              AsConfirmInfoBarDelegate()) {
98        continue;
99      }
100
101      translate::TranslateInfoBarDelegate* translate =
102          infobar_service_->infobar_at(i)
103              ->delegate()
104              ->AsTranslateInfoBarDelegate();
105      if (translate) {
106        EXPECT_FALSE(delegate) << "multiple infobars are shown unexpectedly";
107        delegate = translate;
108        continue;
109      }
110
111      // Other infobar should not be shown.
112      EXPECT_TRUE(delegate);
113    }
114    return delegate;
115  }
116
117 private:
118  net::SpawnedTestServer https_server_;
119  InfoBarService* infobar_service_;
120
121  typedef net::SpawnedTestServer::SSLOptions SSLOptions;
122
123  DISALLOW_COPY_AND_ASSIGN(TranslateBrowserTest);
124};
125
126IN_PROC_BROWSER_TEST_F(TranslateBrowserTest, TranslateInIsolatedWorld) {
127  // TODO(port): Test corresponding bubble translate UX: http://crbug.com/383235
128  if (TranslateService::IsTranslateBubbleEnabled())
129    return;
130
131  net::TestURLFetcherFactory factory;
132  ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
133
134  // Check if there is no Translate infobar.
135  translate::TranslateInfoBarDelegate* translate =
136      GetExistingTranslateInfoBarDelegate();
137  EXPECT_FALSE(translate);
138
139  // Setup infobar observer.
140  content::WindowedNotificationObserver infobar(
141      chrome::NOTIFICATION_TAB_CONTENTS_INFOBAR_ADDED,
142      content::NotificationService::AllSources());
143
144  // Setup page title observer.
145  content::WebContents* web_contents =
146      browser()->tab_strip_model()->GetActiveWebContents();
147  ASSERT_TRUE(web_contents);
148  content::TitleWatcher watcher(web_contents, base::ASCIIToUTF16("PASS"));
149  watcher.AlsoWaitForTitle(base::ASCIIToUTF16("FAIL"));
150
151  // Visit non-secure page which is going to be translated.
152  ui_test_utils::NavigateToURL(browser(), GetNonSecureURL(kFrenchTestPath));
153
154  // Wait for Chrome Translate infobar.
155  infobar.Wait();
156
157  // Perform Chrome Translate.
158  translate = GetExistingTranslateInfoBarDelegate();
159  ASSERT_TRUE(translate);
160  translate->Translate();
161
162  // Hook URLFetcher for element.js.
163  GURL script1_url = GetSecureURL(kMainScriptPath);
164  GURL script2_url = GetSecureURL(kElementMainScriptPath);
165  std::string element_js = "main_script_url = '" + script1_url.spec() + "';\n";
166  element_js += "element_main_script_url = '" + script2_url.spec() + "';\n";
167  element_js +=
168    "google = { 'translate' : { 'TranslateService' : function() { return {\n"
169    "  isAvailable: function() {\n"
170    "    cr.googleTranslate.onLoadJavascript(main_script_url);\n"
171    "    return true;\n"
172    "  },\n"
173    "  translatePage: function(sl, tl, cb) {\n"
174    "    cb(1, true);\n"
175    "  }\n"
176    "} } } };\n"
177    "cr.googleTranslate.onTranslateElementLoad();\n";
178  net::TestURLFetcher* fetcher =
179      factory.GetFetcherByID(translate::TranslateScript::kFetcherId);
180  ASSERT_TRUE(fetcher);
181  net::URLRequestStatus status;
182  status.set_status(net::URLRequestStatus::SUCCESS);
183  fetcher->set_status(status);
184  fetcher->set_url(fetcher->GetOriginalURL());
185  fetcher->set_response_code(net::HTTP_OK);
186  fetcher->SetResponseString(element_js);
187  fetcher->delegate()->OnURLFetchComplete(fetcher);
188
189  // Wait for the page title is changed after the test finished.
190  const base::string16 result = watcher.WaitAndGetTitle();
191  EXPECT_EQ("PASS", base::UTF16ToASCII(result));
192}
193
194IN_PROC_BROWSER_TEST_F(TranslateBrowserTest, IgnoreRefreshMetaTag) {
195  // TODO(port): Test corresponding bubble translate UX: http://crbug.com/383235
196  if (TranslateService::IsTranslateBubbleEnabled())
197    return;
198
199  ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
200
201  // Check if there is no Translate infobar.
202  translate::TranslateInfoBarDelegate* translate =
203      GetExistingTranslateInfoBarDelegate();
204  EXPECT_FALSE(translate);
205
206  // Setup page title observer.
207  content::WebContents* web_contents =
208      browser()->tab_strip_model()->GetActiveWebContents();
209  ASSERT_TRUE(web_contents);
210  content::TitleWatcher watcher(web_contents, base::ASCIIToUTF16("PASS"));
211  watcher.AlsoWaitForTitle(base::ASCIIToUTF16("FAIL"));
212
213  // Visit a test page.
214  ui_test_utils::NavigateToURL(
215      browser(),
216      GetNonSecureURL(kRefreshMetaTagTestPath));
217
218  // Wait for the page title is changed after the test finished.
219  const base::string16 result = watcher.WaitAndGetTitle();
220  EXPECT_EQ("PASS", base::UTF16ToASCII(result));
221
222  // Check if there is no Translate infobar.
223  translate = GetExistingTranslateInfoBarDelegate();
224  EXPECT_FALSE(translate);
225}
226
227IN_PROC_BROWSER_TEST_F(TranslateBrowserTest,
228                       IgnoreRefreshMetaTagInCaseInsensitive) {
229  // TODO(port): Test corresponding bubble translate UX: http://crbug.com/383235
230  if (TranslateService::IsTranslateBubbleEnabled())
231    return;
232
233  ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
234
235  // Check if there is no Translate infobar.
236  translate::TranslateInfoBarDelegate* translate =
237      GetExistingTranslateInfoBarDelegate();
238  EXPECT_FALSE(translate);
239
240  // Setup page title observer.
241  content::WebContents* web_contents =
242      browser()->tab_strip_model()->GetActiveWebContents();
243  ASSERT_TRUE(web_contents);
244  content::TitleWatcher watcher(web_contents, base::ASCIIToUTF16("PASS"));
245  watcher.AlsoWaitForTitle(base::ASCIIToUTF16("FAIL"));
246
247  // Visit a test page.
248  ui_test_utils::NavigateToURL(
249      browser(),
250      GetNonSecureURL(kRefreshMetaTagCaseInsensitiveTestPath));
251
252  // Wait for the page title is changed after the test finished.
253  const base::string16 result = watcher.WaitAndGetTitle();
254  EXPECT_EQ("PASS", base::UTF16ToASCII(result));
255
256  // Check if there is no Translate infobar.
257  translate = GetExistingTranslateInfoBarDelegate();
258  EXPECT_FALSE(translate);
259}
260
261IN_PROC_BROWSER_TEST_F(TranslateBrowserTest, IgnoreRefreshMetaTagAtOnload) {
262  // TODO(port): Test corresponding bubble translate UX: http://crbug.com/383235
263  if (TranslateService::IsTranslateBubbleEnabled())
264    return;
265
266  ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
267
268  // Check if there is no Translate infobar.
269  translate::TranslateInfoBarDelegate* translate =
270      GetExistingTranslateInfoBarDelegate();
271  EXPECT_FALSE(translate);
272
273  // Setup page title observer.
274  content::WebContents* web_contents =
275      browser()->tab_strip_model()->GetActiveWebContents();
276  ASSERT_TRUE(web_contents);
277  content::TitleWatcher watcher(web_contents, base::ASCIIToUTF16("PASS"));
278  watcher.AlsoWaitForTitle(base::ASCIIToUTF16("FAIL"));
279
280  // Visit a test page.
281  ui_test_utils::NavigateToURL(
282      browser(),
283      GetNonSecureURL(kRefreshMetaTagAtOnloadTestPath));
284
285  // Wait for the page title is changed after the test finished.
286  const base::string16 result = watcher.WaitAndGetTitle();
287  EXPECT_EQ("PASS", base::UTF16ToASCII(result));
288
289  // Check if there is no Translate infobar.
290  translate = GetExistingTranslateInfoBarDelegate();
291  EXPECT_FALSE(translate);
292}
293
294IN_PROC_BROWSER_TEST_F(TranslateBrowserTest, UpdateLocation) {
295  // TODO(port): Test corresponding bubble translate UX: http://crbug.com/383235
296  if (TranslateService::IsTranslateBubbleEnabled())
297    return;
298
299  ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
300
301  // Check if there is no Translate infobar.
302  translate::TranslateInfoBarDelegate* translate =
303      GetExistingTranslateInfoBarDelegate();
304  EXPECT_FALSE(translate);
305
306  // Setup page title observer.
307  content::WebContents* web_contents =
308      browser()->tab_strip_model()->GetActiveWebContents();
309  ASSERT_TRUE(web_contents);
310  content::TitleWatcher watcher(web_contents, base::ASCIIToUTF16("PASS"));
311  watcher.AlsoWaitForTitle(base::ASCIIToUTF16("FAIL"));
312
313  // Visit a test page.
314  ui_test_utils::NavigateToURL(
315      browser(),
316      GetNonSecureURL(kUpdateLocationTestPath));
317
318  // Wait for the page title is changed after the test finished.
319  const base::string16 result = watcher.WaitAndGetTitle();
320  EXPECT_EQ("PASS", base::UTF16ToASCII(result));
321
322  // Check if there is no Translate infobar.
323  translate = GetExistingTranslateInfoBarDelegate();
324  EXPECT_FALSE(translate);
325}
326
327IN_PROC_BROWSER_TEST_F(TranslateBrowserTest, UpdateLocationAtOnload) {
328  // TODO(port): Test corresponding bubble translate UX: http://crbug.com/383235
329  if (TranslateService::IsTranslateBubbleEnabled())
330    return;
331
332  ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
333
334  // Check if there is no Translate infobar.
335  translate::TranslateInfoBarDelegate* translate =
336      GetExistingTranslateInfoBarDelegate();
337  EXPECT_FALSE(translate);
338
339  // Setup page title observer.
340  content::WebContents* web_contents =
341      browser()->tab_strip_model()->GetActiveWebContents();
342  ASSERT_TRUE(web_contents);
343  content::TitleWatcher watcher(web_contents, base::ASCIIToUTF16("PASS"));
344  watcher.AlsoWaitForTitle(base::ASCIIToUTF16("FAIL"));
345
346  // Visit a test page.
347  ui_test_utils::NavigateToURL(
348      browser(),
349      GetNonSecureURL(kUpdateLocationAtOnloadTestPath));
350
351  // Wait for the page title is changed after the test finished.
352  const base::string16 result = watcher.WaitAndGetTitle();
353  EXPECT_EQ("PASS", base::UTF16ToASCII(result));
354
355  // Check if there is no Translate infobar.
356  translate = GetExistingTranslateInfoBarDelegate();
357  EXPECT_FALSE(translate);
358}
359