Update mojo surfaces bindings and mojo/cc/ glue
[chromium-blink-merge.git] / chrome / browser / errorpage_browsertest.cc
blobcb1a181c4b63bc274d6e99ed9e0267c8fcedc3f7
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/bind.h"
6 #include "base/command_line.h"
7 #include "base/compiler_specific.h"
8 #include "base/logging.h"
9 #include "base/memory/scoped_ptr.h"
10 #include "base/memory/weak_ptr.h"
11 #include "base/path_service.h"
12 #include "base/prefs/pref_service.h"
13 #include "base/strings/stringprintf.h"
14 #include "base/strings/utf_string_conversions.h"
15 #include "base/synchronization/lock.h"
16 #include "chrome/browser/browsing_data/browsing_data_helper.h"
17 #include "chrome/browser/browsing_data/browsing_data_remover.h"
18 #include "chrome/browser/google/google_profile_helper.h"
19 #include "chrome/browser/net/url_request_mock_util.h"
20 #include "chrome/browser/profiles/profile.h"
21 #include "chrome/browser/ui/browser.h"
22 #include "chrome/browser/ui/browser_commands.h"
23 #include "chrome/browser/ui/tabs/tab_strip_model.h"
24 #include "chrome/common/chrome_paths.h"
25 #include "chrome/common/chrome_switches.h"
26 #include "chrome/common/pref_names.h"
27 #include "chrome/grit/generated_resources.h"
28 #include "chrome/test/base/in_process_browser_test.h"
29 #include "chrome/test/base/ui_test_utils.h"
30 #include "components/google/core/browser/google_util.h"
31 #include "content/public/browser/browser_thread.h"
32 #include "content/public/browser/notification_service.h"
33 #include "content/public/browser/notification_types.h"
34 #include "content/public/browser/render_frame_host.h"
35 #include "content/public/browser/render_view_host.h"
36 #include "content/public/browser/web_contents.h"
37 #include "content/public/browser/web_contents_observer.h"
38 #include "content/public/test/browser_test_utils.h"
39 #include "content/public/test/test_navigation_observer.h"
40 #include "content/test/net/url_request_failed_job.h"
41 #include "content/test/net/url_request_mock_http_job.h"
42 #include "net/base/net_errors.h"
43 #include "net/base/net_util.h"
44 #include "net/http/failing_http_transaction_factory.h"
45 #include "net/http/http_cache.h"
46 #include "net/test/spawned_test_server/spawned_test_server.h"
47 #include "net/url_request/url_request_context.h"
48 #include "net/url_request/url_request_context_getter.h"
49 #include "net/url_request/url_request_filter.h"
50 #include "net/url_request/url_request_interceptor.h"
51 #include "net/url_request/url_request_job.h"
52 #include "net/url_request/url_request_test_job.h"
53 #include "net/url_request/url_request_test_util.h"
54 #include "ui/base/l10n/l10n_util.h"
56 using content::BrowserThread;
57 using content::NavigationController;
58 using content::URLRequestFailedJob;
59 using net::URLRequestTestJob;
61 namespace {
63 // Returns true if |text| is displayed on the page |browser| is currently
64 // displaying. Uses "innerText", so will miss hidden text, and whitespace
65 // space handling may be weird.
66 bool WARN_UNUSED_RESULT IsDisplayingText(Browser* browser,
67 const std::string& text) {
68 std::string command = base::StringPrintf(
69 "var textContent = document.body.innerText;"
70 "var hasText = textContent.indexOf('%s') >= 0;"
71 "domAutomationController.send(hasText);",
72 text.c_str());
73 bool result = false;
74 EXPECT_TRUE(content::ExecuteScriptAndExtractBool(
75 browser->tab_strip_model()->GetActiveWebContents(), command, &result));
76 return result;
79 // Expands the more box on the currently displayed error page.
80 void ToggleHelpBox(Browser* browser) {
81 EXPECT_TRUE(content::ExecuteScript(
82 browser->tab_strip_model()->GetActiveWebContents(),
83 "document.getElementById('details-button').click();"));
86 // Returns true if |browser| is displaying the text representation of
87 // |error_code| on the current page.
88 bool WARN_UNUSED_RESULT IsDisplayingNetError(Browser* browser,
89 net::Error error_code) {
90 return IsDisplayingText(browser, net::ErrorToShortString(error_code));
93 // Checks that the local error page is being displayed, without remotely
94 // retrieved navigation corrections, and with the specified error code.
95 void ExpectDisplayingLocalErrorPage(Browser* browser, net::Error error_code) {
96 // Expand the help box so innerText will include text below the fold.
97 ToggleHelpBox(browser);
99 EXPECT_TRUE(IsDisplayingNetError(browser, error_code));
101 // Locally generated error pages should not have navigation corrections.
102 EXPECT_FALSE(IsDisplayingText(browser, "http://correction1/"));
103 EXPECT_FALSE(IsDisplayingText(browser, "http://correction2/"));
105 // Locally generated error pages should not have a populated search box.
106 bool search_box_populated = false;
107 ASSERT_TRUE(content::ExecuteScriptAndExtractBool(
108 browser->tab_strip_model()->GetActiveWebContents(),
109 "var searchText = document.getElementById('search-box').value;"
110 "domAutomationController.send(searchText == 'search query');",
111 &search_box_populated));
112 EXPECT_FALSE(search_box_populated);
115 // Checks that an error page with information retrieved from the navigation
116 // correction service is being displayed, with the specified specified error
117 // code.
118 void ExpectDisplayingNavigationCorrections(Browser* browser,
119 net::Error error_code) {
120 // Expand the help box so innerText will include text below the fold.
121 ToggleHelpBox(browser);
123 EXPECT_TRUE(IsDisplayingNetError(browser, error_code));
125 // Check that the mock navigation corrections are displayed.
126 EXPECT_TRUE(IsDisplayingText(browser, "http://correction1/"));
127 EXPECT_TRUE(IsDisplayingText(browser, "http://correction2/"));
129 // Check that the search box is populated correctly.
130 bool search_box_populated = false;
131 ASSERT_TRUE(content::ExecuteScriptAndExtractBool(
132 browser->tab_strip_model()->GetActiveWebContents(),
133 "var searchText = document.getElementById('search-box').value;"
134 "domAutomationController.send(searchText == 'search query');",
135 &search_box_populated));
136 EXPECT_TRUE(search_box_populated);
139 std::string GetLoadStaleButtonLabel() {
140 return l10n_util::GetStringUTF8(IDS_ERRORPAGES_BUTTON_LOAD_STALE);
143 void AddInterceptorForURL(
144 const GURL& url,
145 scoped_ptr<net::URLRequestInterceptor> handler) {
146 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
147 net::URLRequestFilter::GetInstance()->AddUrlInterceptor(
148 url, handler.Pass());
151 // An interceptor that fails a configurable number of requests, then succeeds
152 // all requests after that, keeping count of failures and successes.
153 class FailFirstNRequestsInterceptor : public net::URLRequestInterceptor {
154 public:
155 explicit FailFirstNRequestsInterceptor(int requests_to_fail)
156 : requests_(0), failures_(0), requests_to_fail_(requests_to_fail) {}
157 virtual ~FailFirstNRequestsInterceptor() {}
159 // net::URLRequestInterceptor implementation
160 virtual net::URLRequestJob* MaybeInterceptRequest(
161 net::URLRequest* request,
162 net::NetworkDelegate* network_delegate) const OVERRIDE {
163 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
164 requests_++;
165 if (failures_ < requests_to_fail_) {
166 failures_++;
167 // Note: net::ERR_CONNECTION_RESET does not summon the Link Doctor; see
168 // NetErrorHelperCore::GetErrorPageURL.
169 return new URLRequestFailedJob(request,
170 network_delegate,
171 net::ERR_CONNECTION_RESET);
172 } else {
173 return new URLRequestTestJob(request, network_delegate,
174 URLRequestTestJob::test_headers(),
175 URLRequestTestJob::test_data_1(),
176 true);
180 int requests() const { return requests_; }
181 int failures() const { return failures_; }
183 private:
184 // These are mutable because MaybeCreateJob is const but we want this state
185 // for testing.
186 mutable int requests_;
187 mutable int failures_;
188 int requests_to_fail_;
190 DISALLOW_COPY_AND_ASSIGN(FailFirstNRequestsInterceptor);
193 // An interceptor that serves LinkDoctor responses. It also allows waiting
194 // until a certain number of requests have been sent.
195 // TODO(mmenke): Wait until responses have been received instead.
196 class LinkDoctorInterceptor : public net::URLRequestInterceptor {
197 public:
198 LinkDoctorInterceptor() : num_requests_(0),
199 requests_to_wait_for_(-1),
200 weak_factory_(this) {
203 virtual ~LinkDoctorInterceptor() {}
205 // net::URLRequestInterceptor implementation
206 virtual net::URLRequestJob* MaybeInterceptRequest(
207 net::URLRequest* request,
208 net::NetworkDelegate* network_delegate) const OVERRIDE {
209 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
211 BrowserThread::PostTask(
212 BrowserThread::UI, FROM_HERE,
213 base::Bind(&LinkDoctorInterceptor::RequestCreated,
214 weak_factory_.GetWeakPtr()));
216 base::FilePath root_http;
217 PathService::Get(chrome::DIR_TEST_DATA, &root_http);
218 return new content::URLRequestMockHTTPJob(
219 request, network_delegate,
220 root_http.AppendASCII("mock-link-doctor.json"));
223 void WaitForRequests(int requests_to_wait_for) {
224 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
225 DCHECK_EQ(-1, requests_to_wait_for_);
226 DCHECK(!run_loop_);
228 if (requests_to_wait_for >= num_requests_)
229 return;
231 requests_to_wait_for_ = requests_to_wait_for;
232 run_loop_.reset(new base::RunLoop());
233 run_loop_->Run();
234 run_loop_.reset();
235 requests_to_wait_for_ = -1;
236 EXPECT_EQ(num_requests_, requests_to_wait_for);
239 // It is up to the caller to wait until all relevant requests has been
240 // created, either through calling WaitForRequests or some other manner,
241 // before calling this method.
242 int num_requests() const {
243 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
244 return num_requests_;
247 private:
248 void RequestCreated() {
249 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
251 num_requests_++;
252 if (num_requests_ == requests_to_wait_for_)
253 run_loop_->Quit();
256 // These are only used on the UI thread.
257 int num_requests_;
258 int requests_to_wait_for_;
259 scoped_ptr<base::RunLoop> run_loop_;
261 // This prevents any risk of flake if any test doesn't wait for a request
262 // it sent. Mutable so it can be accessed from a const function.
263 mutable base::WeakPtrFactory<LinkDoctorInterceptor> weak_factory_;
265 DISALLOW_COPY_AND_ASSIGN(LinkDoctorInterceptor);
268 void InstallMockInterceptors(
269 const GURL& search_url,
270 scoped_ptr<net::URLRequestInterceptor> link_doctor_interceptor) {
271 chrome_browser_net::SetUrlRequestMocksEnabled(true);
273 AddInterceptorForURL(google_util::LinkDoctorBaseURL(),
274 link_doctor_interceptor.Pass());
276 // Add a mock for the search engine the error page will use.
277 base::FilePath root_http;
278 PathService::Get(chrome::DIR_TEST_DATA, &root_http);
279 content::URLRequestMockHTTPJob::AddHostnameToFileHandler(
280 search_url.host(), root_http.AppendASCII("title3.html"));
283 class ErrorPageTest : public InProcessBrowserTest {
284 public:
285 enum HistoryNavigationDirection {
286 HISTORY_NAVIGATE_BACK,
287 HISTORY_NAVIGATE_FORWARD,
290 ErrorPageTest() : link_doctor_interceptor_(NULL) {}
291 virtual ~ErrorPageTest() {}
293 // Navigates the active tab to a mock url created for the file at |file_path|.
294 // Needed for StaleCacheStatus and StaleCacheStatusFailedCorrections tests.
295 virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
296 command_line->AppendSwitch(switches::kEnableOfflineLoadStaleCache);
299 // Navigates the active tab to a mock url created for the file at |file_path|.
300 void NavigateToFileURL(const base::FilePath::StringType& file_path) {
301 ui_test_utils::NavigateToURL(
302 browser(),
303 content::URLRequestMockHTTPJob::GetMockUrl(base::FilePath(file_path)));
306 // Navigates to the given URL and waits for |num_navigations| to occur, and
307 // the title to change to |expected_title|.
308 void NavigateToURLAndWaitForTitle(const GURL& url,
309 const std::string& expected_title,
310 int num_navigations) {
311 content::TitleWatcher title_watcher(
312 browser()->tab_strip_model()->GetActiveWebContents(),
313 base::ASCIIToUTF16(expected_title));
315 ui_test_utils::NavigateToURLBlockUntilNavigationsComplete(
316 browser(), url, num_navigations);
318 EXPECT_EQ(base::ASCIIToUTF16(expected_title),
319 title_watcher.WaitAndGetTitle());
322 // Navigates back in the history and waits for |num_navigations| to occur, and
323 // the title to change to |expected_title|.
324 void GoBackAndWaitForTitle(const std::string& expected_title,
325 int num_navigations) {
326 NavigateHistoryAndWaitForTitle(expected_title,
327 num_navigations,
328 HISTORY_NAVIGATE_BACK);
331 // Navigates forward in the history and waits for |num_navigations| to occur,
332 // and the title to change to |expected_title|.
333 void GoForwardAndWaitForTitle(const std::string& expected_title,
334 int num_navigations) {
335 NavigateHistoryAndWaitForTitle(expected_title,
336 num_navigations,
337 HISTORY_NAVIGATE_FORWARD);
340 void GoBackAndWaitForNavigations(int num_navigations) {
341 NavigateHistory(num_navigations, HISTORY_NAVIGATE_BACK);
344 void GoForwardAndWaitForNavigations(int num_navigations) {
345 NavigateHistory(num_navigations, HISTORY_NAVIGATE_FORWARD);
348 // Confirms that the javascript variable indicating whether or not we have
349 // a stale copy in the cache has been set to |expected|, and that the
350 // stale load button is or isn't there based on the same expectation.
351 testing::AssertionResult ProbeStaleCopyValue(bool expected) {
352 const char* js_cache_probe =
353 "try {\n"
354 " domAutomationController.send(\n"
355 " 'staleLoadButton' in templateData ? 'yes' : 'no');\n"
356 "} catch (e) {\n"
357 " domAutomationController.send(e.message);\n"
358 "}\n";
360 std::string result;
361 bool ret =
362 content::ExecuteScriptAndExtractString(
363 browser()->tab_strip_model()->GetActiveWebContents(),
364 js_cache_probe,
365 &result);
366 if (!ret) {
367 return testing::AssertionFailure()
368 << "Failing return from ExecuteScriptAndExtractString.";
371 if ((expected && "yes" == result) || (!expected && "no" == result))
372 return testing::AssertionSuccess();
374 return testing::AssertionFailure() << "Cache probe result is " << result;
377 testing::AssertionResult ReloadStaleCopyFromCache() {
378 const char* js_reload_script =
379 "try {\n"
380 " document.getElementById('stale-load-button').click();\n"
381 " domAutomationController.send('success');\n"
382 "} catch (e) {\n"
383 " domAutomationController.send(e.message);\n"
384 "}\n";
386 std::string result;
387 bool ret = content::ExecuteScriptAndExtractString(
388 browser()->tab_strip_model()->GetActiveWebContents(),
389 js_reload_script,
390 &result);
391 EXPECT_TRUE(ret);
392 if (!ret)
393 return testing::AssertionFailure();
394 return ("success" == result ? testing::AssertionSuccess() :
395 (testing::AssertionFailure() << "Exception message is " << result));
398 LinkDoctorInterceptor* link_doctor_interceptor() {
399 return link_doctor_interceptor_;
402 protected:
403 virtual void SetUpOnMainThread() OVERRIDE {
404 link_doctor_interceptor_ = new LinkDoctorInterceptor();
405 scoped_ptr<net::URLRequestInterceptor> owned_interceptor(
406 link_doctor_interceptor_);
407 // Ownership of the |interceptor_| is passed to an object the IO thread, but
408 // a pointer is kept in the test fixture. As soon as anything calls
409 // URLRequestFilter::ClearHandlers(), |interceptor_| can become invalid.
410 BrowserThread::PostTask(
411 BrowserThread::IO, FROM_HERE,
412 base::Bind(&InstallMockInterceptors,
413 google_util::GetGoogleSearchURL(
414 google_profile_helper::GetGoogleHomePageURL(
415 browser()->profile())),
416 base::Passed(&owned_interceptor)));
419 // Returns a GURL that results in a DNS error.
420 GURL GetDnsErrorURL() const {
421 return URLRequestFailedJob::GetMockHttpUrl(net::ERR_NAME_NOT_RESOLVED);
424 private:
425 // Navigates the browser the indicated direction in the history and waits for
426 // |num_navigations| to occur and the title to change to |expected_title|.
427 void NavigateHistoryAndWaitForTitle(const std::string& expected_title,
428 int num_navigations,
429 HistoryNavigationDirection direction) {
430 content::TitleWatcher title_watcher(
431 browser()->tab_strip_model()->GetActiveWebContents(),
432 base::ASCIIToUTF16(expected_title));
434 NavigateHistory(num_navigations, direction);
436 EXPECT_EQ(title_watcher.WaitAndGetTitle(),
437 base::ASCIIToUTF16(expected_title));
440 void NavigateHistory(int num_navigations,
441 HistoryNavigationDirection direction) {
442 content::TestNavigationObserver test_navigation_observer(
443 browser()->tab_strip_model()->GetActiveWebContents(),
444 num_navigations);
445 if (direction == HISTORY_NAVIGATE_BACK) {
446 chrome::GoBack(browser(), CURRENT_TAB);
447 } else if (direction == HISTORY_NAVIGATE_FORWARD) {
448 chrome::GoForward(browser(), CURRENT_TAB);
449 } else {
450 FAIL();
452 test_navigation_observer.Wait();
455 LinkDoctorInterceptor* link_doctor_interceptor_;
458 class TestFailProvisionalLoadObserver : public content::WebContentsObserver {
459 public:
460 explicit TestFailProvisionalLoadObserver(content::WebContents* contents)
461 : content::WebContentsObserver(contents) {}
462 virtual ~TestFailProvisionalLoadObserver() {}
464 // This method is invoked when the provisional load failed.
465 virtual void DidFailProvisionalLoad(
466 content::RenderFrameHost* render_frame_host,
467 const GURL& validated_url,
468 int error_code,
469 const base::string16& error_description) OVERRIDE {
470 fail_url_ = validated_url;
473 const GURL& fail_url() const { return fail_url_; }
475 private:
476 GURL fail_url_;
478 DISALLOW_COPY_AND_ASSIGN(TestFailProvisionalLoadObserver);
481 void InterceptNetworkTransactions(net::URLRequestContextGetter* getter,
482 net::Error error) {
483 DCHECK(content::BrowserThread::CurrentlyOn(BrowserThread::IO));
484 net::HttpCache* cache(
485 getter->GetURLRequestContext()->http_transaction_factory()->GetCache());
486 DCHECK(cache);
487 scoped_ptr<net::HttpTransactionFactory> factory(
488 new net::FailingHttpTransactionFactory(cache->GetSession(), error));
489 // Throw away old version; since this is a a browser test, we don't
490 // need to restore the old state.
491 cache->SetHttpNetworkTransactionFactoryForTesting(factory.Pass());
494 // Test that a DNS error occuring in the main frame redirects to an error page.
495 IN_PROC_BROWSER_TEST_F(ErrorPageTest, DNSError_Basic) {
496 // The first navigation should fail, and the second one should be the error
497 // page.
498 ui_test_utils::NavigateToURLBlockUntilNavigationsComplete(
499 browser(), GetDnsErrorURL(), 2);
500 ExpectDisplayingNavigationCorrections(browser(), net::ERR_NAME_NOT_RESOLVED);
501 EXPECT_EQ(1, link_doctor_interceptor()->num_requests());
504 // Test that a DNS error occuring in the main frame does not result in an
505 // additional session history entry.
506 IN_PROC_BROWSER_TEST_F(ErrorPageTest, DNSError_GoBack1) {
507 NavigateToFileURL(FILE_PATH_LITERAL("title2.html"));
508 ui_test_utils::NavigateToURLBlockUntilNavigationsComplete(
509 browser(), GetDnsErrorURL(), 2);
510 ExpectDisplayingNavigationCorrections(browser(), net::ERR_NAME_NOT_RESOLVED);
511 GoBackAndWaitForTitle("Title Of Awesomeness", 1);
512 EXPECT_EQ(1, link_doctor_interceptor()->num_requests());
515 // Test that a DNS error occuring in the main frame does not result in an
516 // additional session history entry.
517 IN_PROC_BROWSER_TEST_F(ErrorPageTest, DNSError_GoBack2) {
518 NavigateToFileURL(FILE_PATH_LITERAL("title2.html"));
520 ui_test_utils::NavigateToURLBlockUntilNavigationsComplete(
521 browser(), GetDnsErrorURL(), 2);
522 ExpectDisplayingNavigationCorrections(browser(), net::ERR_NAME_NOT_RESOLVED);
523 EXPECT_EQ(1, link_doctor_interceptor()->num_requests());
525 NavigateToFileURL(FILE_PATH_LITERAL("title3.html"));
527 GoBackAndWaitForNavigations(2);
528 ExpectDisplayingNavigationCorrections(browser(), net::ERR_NAME_NOT_RESOLVED);
529 EXPECT_EQ(2, link_doctor_interceptor()->num_requests());
531 GoBackAndWaitForTitle("Title Of Awesomeness", 1);
532 EXPECT_EQ(2, link_doctor_interceptor()->num_requests());
535 // Test that a DNS error occuring in the main frame does not result in an
536 // additional session history entry.
537 IN_PROC_BROWSER_TEST_F(ErrorPageTest, DNSError_GoBack2AndForward) {
538 NavigateToFileURL(FILE_PATH_LITERAL("title2.html"));
540 ui_test_utils::NavigateToURLBlockUntilNavigationsComplete(
541 browser(), GetDnsErrorURL(), 2);
542 ExpectDisplayingNavigationCorrections(browser(), net::ERR_NAME_NOT_RESOLVED);
543 EXPECT_EQ(1, link_doctor_interceptor()->num_requests());
545 NavigateToFileURL(FILE_PATH_LITERAL("title3.html"));
547 GoBackAndWaitForNavigations(2);
548 ExpectDisplayingNavigationCorrections(browser(), net::ERR_NAME_NOT_RESOLVED);
549 EXPECT_EQ(2, link_doctor_interceptor()->num_requests());
551 GoBackAndWaitForTitle("Title Of Awesomeness", 1);
553 GoForwardAndWaitForNavigations(2);
554 ExpectDisplayingNavigationCorrections(browser(), net::ERR_NAME_NOT_RESOLVED);
555 EXPECT_EQ(3, link_doctor_interceptor()->num_requests());
558 // Test that a DNS error occuring in the main frame does not result in an
559 // additional session history entry.
560 IN_PROC_BROWSER_TEST_F(ErrorPageTest, DNSError_GoBack2Forward2) {
561 NavigateToFileURL(FILE_PATH_LITERAL("title3.html"));
563 ui_test_utils::NavigateToURLBlockUntilNavigationsComplete(
564 browser(), GetDnsErrorURL(), 2);
565 ExpectDisplayingNavigationCorrections(browser(), net::ERR_NAME_NOT_RESOLVED);
566 EXPECT_EQ(1, link_doctor_interceptor()->num_requests());
568 NavigateToFileURL(FILE_PATH_LITERAL("title2.html"));
570 GoBackAndWaitForNavigations(2);
571 ExpectDisplayingNavigationCorrections(browser(), net::ERR_NAME_NOT_RESOLVED);
572 EXPECT_EQ(2, link_doctor_interceptor()->num_requests());
574 GoBackAndWaitForTitle("Title Of More Awesomeness", 1);
576 GoForwardAndWaitForNavigations(2);
577 ExpectDisplayingNavigationCorrections(browser(), net::ERR_NAME_NOT_RESOLVED);
578 EXPECT_EQ(3, link_doctor_interceptor()->num_requests());
580 GoForwardAndWaitForTitle("Title Of Awesomeness", 1);
581 EXPECT_EQ(3, link_doctor_interceptor()->num_requests());
584 // Test that the search button on a DNS error page works.
585 IN_PROC_BROWSER_TEST_F(ErrorPageTest, DNSError_DoSearch) {
586 // The first navigation should fail, and the second one should be the error
587 // page.
588 ui_test_utils::NavigateToURLBlockUntilNavigationsComplete(
589 browser(), GetDnsErrorURL(), 2);
590 ExpectDisplayingNavigationCorrections(browser(), net::ERR_NAME_NOT_RESOLVED);
591 EXPECT_EQ(1, link_doctor_interceptor()->num_requests());
593 content::WebContents* web_contents =
594 browser()->tab_strip_model()->GetActiveWebContents();
596 // Do a search and make sure the browser ends up at the right page.
597 content::TestNavigationObserver nav_observer(web_contents, 1);
598 content::TitleWatcher title_watcher(
599 web_contents,
600 base::ASCIIToUTF16("Title Of More Awesomeness"));
601 // Can't use content::ExecuteScript because it waits for scripts to send
602 // notification that they've run, and scripts that trigger a navigation may
603 // not send that notification.
604 web_contents->GetMainFrame()->ExecuteJavaScript(
605 base::ASCIIToUTF16("document.getElementById('search-button').click();"));
606 nav_observer.Wait();
607 EXPECT_EQ(base::ASCIIToUTF16("Title Of More Awesomeness"),
608 title_watcher.WaitAndGetTitle());
610 // There should have been another Link Doctor request, for tracking purposes.
611 // Have to wait for it, since the search page does not depend on having
612 // sent the tracking request.
613 link_doctor_interceptor()->WaitForRequests(2);
614 EXPECT_EQ(2, link_doctor_interceptor()->num_requests());
616 // Check the path and query string.
617 std::string url;
618 ASSERT_TRUE(content::ExecuteScriptAndExtractString(
619 browser()->tab_strip_model()->GetActiveWebContents(),
620 "domAutomationController.send(window.location.href);",
621 &url));
622 EXPECT_EQ("/search", GURL(url).path());
623 EXPECT_EQ("q=search%20query", GURL(url).query());
625 // Go back to the error page, to make sure the history is correct.
626 GoBackAndWaitForNavigations(2);
627 ExpectDisplayingNavigationCorrections(browser(), net::ERR_NAME_NOT_RESOLVED);
628 EXPECT_EQ(3, link_doctor_interceptor()->num_requests());
631 // Test that the reload button on a DNS error page works.
632 IN_PROC_BROWSER_TEST_F(ErrorPageTest, DNSError_DoReload) {
633 // The first navigation should fail, and the second one should be the error
634 // page.
635 ui_test_utils::NavigateToURLBlockUntilNavigationsComplete(
636 browser(), GetDnsErrorURL(), 2);
637 ExpectDisplayingNavigationCorrections(browser(), net::ERR_NAME_NOT_RESOLVED);
638 EXPECT_EQ(1, link_doctor_interceptor()->num_requests());
640 content::WebContents* web_contents =
641 browser()->tab_strip_model()->GetActiveWebContents();
643 // Clicking the reload button should load the error page again, and there
644 // should be two commits, as before.
645 content::TestNavigationObserver nav_observer(web_contents, 2);
646 // Can't use content::ExecuteScript because it waits for scripts to send
647 // notification that they've run, and scripts that trigger a navigation may
648 // not send that notification.
649 web_contents->GetMainFrame()->ExecuteJavaScript(
650 base::ASCIIToUTF16("document.getElementById('reload-button').click();"));
651 nav_observer.Wait();
652 ExpectDisplayingNavigationCorrections(browser(), net::ERR_NAME_NOT_RESOLVED);
654 // There should have two more requests to the correction service: One for the
655 // new error page, and one for tracking purposes. Have to make sure to wait
656 // for the tracking request, since the new error page does not depend on it.
657 link_doctor_interceptor()->WaitForRequests(3);
658 EXPECT_EQ(3, link_doctor_interceptor()->num_requests());
661 // Test that clicking links on a DNS error page works.
662 IN_PROC_BROWSER_TEST_F(ErrorPageTest, DNSError_DoClickLink) {
663 // The first navigation should fail, and the second one should be the error
664 // page.
665 ui_test_utils::NavigateToURLBlockUntilNavigationsComplete(
666 browser(), GetDnsErrorURL(), 2);
667 ExpectDisplayingNavigationCorrections(browser(), net::ERR_NAME_NOT_RESOLVED);
668 EXPECT_EQ(1, link_doctor_interceptor()->num_requests());
670 content::WebContents* web_contents =
671 browser()->tab_strip_model()->GetActiveWebContents();
673 // Simulate a click on a link.
675 content::TitleWatcher title_watcher(
676 web_contents,
677 base::ASCIIToUTF16("Title Of Awesomeness"));
678 std::string link_selector =
679 "document.querySelector('a[href=\"http://mock.http/title2.html\"]')";
680 // The tracking request is triggered by onmousedown, so it catches middle
681 // mouse button clicks, as well as left clicks.
682 web_contents->GetMainFrame()->ExecuteJavaScript(
683 base::ASCIIToUTF16(link_selector + ".onmousedown();"));
684 // Can't use content::ExecuteScript because it waits for scripts to send
685 // notification that they've run, and scripts that trigger a navigation may
686 // not send that notification.
687 web_contents->GetMainFrame()->ExecuteJavaScript(
688 base::ASCIIToUTF16(link_selector + ".click();"));
689 EXPECT_EQ(base::ASCIIToUTF16("Title Of Awesomeness"),
690 title_watcher.WaitAndGetTitle());
692 // There should have been a tracking request to the correction service. Have
693 // to make sure to wait the tracking request, since the new page does not
694 // depend on it.
695 link_doctor_interceptor()->WaitForRequests(2);
696 EXPECT_EQ(2, link_doctor_interceptor()->num_requests());
699 // Test that a DNS error occuring in an iframe does not result in showing
700 // navigation corrections.
701 IN_PROC_BROWSER_TEST_F(ErrorPageTest, IFrameDNSError_Basic) {
702 NavigateToURLAndWaitForTitle(
703 content::URLRequestMockHTTPJob::GetMockUrl(
704 base::FilePath(FILE_PATH_LITERAL("iframe_dns_error.html"))),
705 "Blah",
707 // We expect to have two history entries, since we started off with navigation
708 // to "about:blank" and then navigated to "iframe_dns_error.html".
709 EXPECT_EQ(2,
710 browser()->tab_strip_model()->GetActiveWebContents()->
711 GetController().GetEntryCount());
712 EXPECT_EQ(0, link_doctor_interceptor()->num_requests());
715 // This test fails regularly on win_rel trybots. See crbug.com/121540
716 #if defined(OS_WIN)
717 #define MAYBE_IFrameDNSError_GoBack DISABLED_IFrameDNSError_GoBack
718 #else
719 #define MAYBE_IFrameDNSError_GoBack IFrameDNSError_GoBack
720 #endif
721 // Test that a DNS error occuring in an iframe does not result in an
722 // additional session history entry.
723 IN_PROC_BROWSER_TEST_F(ErrorPageTest, MAYBE_IFrameDNSError_GoBack) {
724 NavigateToFileURL(FILE_PATH_LITERAL("title2.html"));
725 NavigateToFileURL(FILE_PATH_LITERAL("iframe_dns_error.html"));
726 GoBackAndWaitForTitle("Title Of Awesomeness", 1);
727 EXPECT_EQ(0, link_doctor_interceptor()->num_requests());
730 // This test fails regularly on win_rel trybots. See crbug.com/121540
732 // This fails on linux_aura bringup: http://crbug.com/163931
733 #if defined(OS_WIN) || (defined(OS_LINUX) && !defined(OS_CHROMEOS) && defined(USE_AURA))
734 #define MAYBE_IFrameDNSError_GoBackAndForward DISABLED_IFrameDNSError_GoBackAndForward
735 #else
736 #define MAYBE_IFrameDNSError_GoBackAndForward IFrameDNSError_GoBackAndForward
737 #endif
738 // Test that a DNS error occuring in an iframe does not result in an
739 // additional session history entry.
740 IN_PROC_BROWSER_TEST_F(ErrorPageTest, MAYBE_IFrameDNSError_GoBackAndForward) {
741 NavigateToFileURL(FILE_PATH_LITERAL("title2.html"));
742 NavigateToFileURL(FILE_PATH_LITERAL("iframe_dns_error.html"));
743 GoBackAndWaitForTitle("Title Of Awesomeness", 1);
744 GoForwardAndWaitForTitle("Blah", 1);
745 EXPECT_EQ(0, link_doctor_interceptor()->num_requests());
748 // Test that a DNS error occuring in an iframe, once the main document is
749 // completed loading, does not result in an additional session history entry.
750 // To ensure that the main document has completed loading, JavaScript is used to
751 // inject an iframe after loading is done.
752 IN_PROC_BROWSER_TEST_F(ErrorPageTest, IFrameDNSError_JavaScript) {
753 content::WebContents* wc =
754 browser()->tab_strip_model()->GetActiveWebContents();
755 GURL fail_url =
756 URLRequestFailedJob::GetMockHttpUrl(net::ERR_NAME_NOT_RESOLVED);
758 // Load a regular web page, in which we will inject an iframe.
759 NavigateToFileURL(FILE_PATH_LITERAL("title2.html"));
761 // We expect to have two history entries, since we started off with navigation
762 // to "about:blank" and then navigated to "title2.html".
763 EXPECT_EQ(2, wc->GetController().GetEntryCount());
765 std::string script = "var frame = document.createElement('iframe');"
766 "frame.src = '" + fail_url.spec() + "';"
767 "document.body.appendChild(frame);";
769 TestFailProvisionalLoadObserver fail_observer(wc);
770 content::WindowedNotificationObserver load_observer(
771 content::NOTIFICATION_LOAD_STOP,
772 content::Source<NavigationController>(&wc->GetController()));
773 wc->GetMainFrame()->ExecuteJavaScript(base::ASCIIToUTF16(script));
774 load_observer.Wait();
776 // Ensure we saw the expected failure.
777 EXPECT_EQ(fail_url, fail_observer.fail_url());
779 // Failed initial navigation of an iframe shouldn't be adding any history
780 // entries.
781 EXPECT_EQ(2, wc->GetController().GetEntryCount());
784 // Do the same test, but with an iframe that doesn't have initial URL
785 // assigned.
786 script = "var frame = document.createElement('iframe');"
787 "frame.id = 'target_frame';"
788 "document.body.appendChild(frame);";
790 content::WindowedNotificationObserver load_observer(
791 content::NOTIFICATION_LOAD_STOP,
792 content::Source<NavigationController>(&wc->GetController()));
793 wc->GetMainFrame()->ExecuteJavaScript(base::ASCIIToUTF16(script));
794 load_observer.Wait();
797 script = "var f = document.getElementById('target_frame');"
798 "f.src = '" + fail_url.spec() + "';";
800 TestFailProvisionalLoadObserver fail_observer(wc);
801 content::WindowedNotificationObserver load_observer(
802 content::NOTIFICATION_LOAD_STOP,
803 content::Source<NavigationController>(&wc->GetController()));
804 wc->GetMainFrame()->ExecuteJavaScript(base::ASCIIToUTF16(script));
805 load_observer.Wait();
807 EXPECT_EQ(fail_url, fail_observer.fail_url());
808 EXPECT_EQ(2, wc->GetController().GetEntryCount());
810 EXPECT_EQ(0, link_doctor_interceptor()->num_requests());
813 // Checks that navigation corrections are not loaded when we receive an actual
814 // 404 page.
815 IN_PROC_BROWSER_TEST_F(ErrorPageTest, Page404) {
816 NavigateToURLAndWaitForTitle(
817 content::URLRequestMockHTTPJob::GetMockUrl(
818 base::FilePath(FILE_PATH_LITERAL("page404.html"))),
819 "SUCCESS",
821 EXPECT_EQ(0, link_doctor_interceptor()->num_requests());
824 // Checks that when an error occurs, the stale cache status of the page
825 // is correctly transferred, and that stale cached copied can be loaded
826 // from the javascript.
827 IN_PROC_BROWSER_TEST_F(ErrorPageTest, StaleCacheStatus) {
828 ASSERT_TRUE(test_server()->Start());
829 // Load cache with entry with "nocache" set, to create stale
830 // cache.
831 GURL test_url(test_server()->GetURL("files/nocache.html"));
832 NavigateToURLAndWaitForTitle(test_url, "Nocache Test Page", 1);
834 // Reload same URL after forcing an error from the the network layer;
835 // confirm that the error page is told the cached copy exists.
836 scoped_refptr<net::URLRequestContextGetter> url_request_context_getter =
837 browser()->profile()->GetRequestContext();
838 BrowserThread::PostTask(
839 BrowserThread::IO, FROM_HERE,
840 base::Bind(&InterceptNetworkTransactions, url_request_context_getter,
841 net::ERR_FAILED));
843 ui_test_utils::NavigateToURLBlockUntilNavigationsComplete(
844 // With no navigation corrections to load, there's only one navigation.
845 browser(), test_url, 1);
846 EXPECT_TRUE(ProbeStaleCopyValue(true));
847 EXPECT_TRUE(IsDisplayingText(browser(), GetLoadStaleButtonLabel()));
848 EXPECT_NE(base::ASCIIToUTF16("Nocache Test Page"),
849 browser()->tab_strip_model()->GetActiveWebContents()->GetTitle());
851 // Confirm that loading the stale copy from the cache works.
852 content::TestNavigationObserver same_tab_observer(
853 browser()->tab_strip_model()->GetActiveWebContents(), 1);
854 ASSERT_TRUE(ReloadStaleCopyFromCache());
855 same_tab_observer.Wait();
856 EXPECT_EQ(base::ASCIIToUTF16("Nocache Test Page"),
857 browser()->tab_strip_model()->GetActiveWebContents()->GetTitle());
859 // Clear the cache and reload the same URL; confirm the error page is told
860 // that there is no cached copy.
861 BrowsingDataRemover* remover =
862 BrowsingDataRemover::CreateForUnboundedRange(browser()->profile());
863 remover->Remove(BrowsingDataRemover::REMOVE_CACHE,
864 BrowsingDataHelper::UNPROTECTED_WEB);
865 ui_test_utils::NavigateToURLBlockUntilNavigationsComplete(
866 browser(), test_url, 1);
867 EXPECT_TRUE(ProbeStaleCopyValue(false));
868 EXPECT_FALSE(IsDisplayingText(browser(), GetLoadStaleButtonLabel()));
869 EXPECT_EQ(0, link_doctor_interceptor()->num_requests());
872 class ErrorPageAutoReloadTest : public InProcessBrowserTest {
873 public:
874 virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
875 command_line->AppendSwitch(switches::kEnableOfflineAutoReload);
878 void InstallInterceptor(const GURL& url, int requests_to_fail) {
879 interceptor_ = new FailFirstNRequestsInterceptor(requests_to_fail);
880 scoped_ptr<net::URLRequestInterceptor> owned_interceptor(interceptor_);
882 // Tests don't need to wait for this task to complete before using the
883 // filter; any requests that might be affected by it will end up in the IO
884 // thread's message loop after this posted task anyway.
886 // Ownership of the interceptor is passed to an object the IO thread, but a
887 // pointer is kept in the test fixture. As soon as anything calls
888 // URLRequestFilter::ClearHandlers(), |interceptor_| can become invalid.
889 BrowserThread::PostTask(
890 BrowserThread::IO, FROM_HERE,
891 base::Bind(&AddInterceptorForURL, url,
892 base::Passed(&owned_interceptor)));
895 void NavigateToURLAndWaitForTitle(const GURL& url,
896 const std::string& expected_title,
897 int num_navigations) {
898 content::TitleWatcher title_watcher(
899 browser()->tab_strip_model()->GetActiveWebContents(),
900 base::ASCIIToUTF16(expected_title));
902 ui_test_utils::NavigateToURLBlockUntilNavigationsComplete(
903 browser(), url, num_navigations);
905 EXPECT_EQ(base::ASCIIToUTF16(expected_title),
906 title_watcher.WaitAndGetTitle());
909 FailFirstNRequestsInterceptor* interceptor() {
910 return interceptor_;
913 private:
914 FailFirstNRequestsInterceptor* interceptor_;
917 IN_PROC_BROWSER_TEST_F(ErrorPageAutoReloadTest, AutoReload) {
918 GURL test_url("http://error.page.auto.reload");
919 const int kRequestsToFail = 2;
920 InstallInterceptor(test_url, kRequestsToFail);
921 NavigateToURLAndWaitForTitle(test_url, "Test One", kRequestsToFail + 1);
922 // Note that the interceptor updates these variables on the IO thread,
923 // but this function reads them on the main thread. The requests have to be
924 // created (on the IO thread) before NavigateToURLAndWaitForTitle returns or
925 // this becomes racey.
926 EXPECT_EQ(kRequestsToFail, interceptor()->failures());
927 EXPECT_EQ(kRequestsToFail + 1, interceptor()->requests());
930 // Interceptor that fails all requests with net::ERR_ADDRESS_UNREACHABLE.
931 class AddressUnreachableInterceptor : public net::URLRequestInterceptor {
932 public:
933 AddressUnreachableInterceptor() {}
934 virtual ~AddressUnreachableInterceptor() {}
936 // net::URLRequestInterceptor:
937 virtual net::URLRequestJob* MaybeInterceptRequest(
938 net::URLRequest* request,
939 net::NetworkDelegate* network_delegate) const OVERRIDE {
940 return new URLRequestFailedJob(request,
941 network_delegate,
942 net::ERR_ADDRESS_UNREACHABLE);
945 private:
946 DISALLOW_COPY_AND_ASSIGN(AddressUnreachableInterceptor);
949 // A test fixture that returns ERR_ADDRESS_UNREACHABLE for all navigation
950 // correction requests. ERR_NAME_NOT_RESOLVED is more typical, but need to use
951 // a different error for the correction service and the original page to
952 // validate the right page is being displayed.
953 class ErrorPageNavigationCorrectionsFailTest : public ErrorPageTest {
954 public:
955 // InProcessBrowserTest:
956 virtual void SetUpOnMainThread() OVERRIDE {
957 BrowserThread::PostTask(
958 BrowserThread::IO, FROM_HERE,
959 base::Bind(&ErrorPageNavigationCorrectionsFailTest::AddFilters));
962 virtual void TearDownOnMainThread() OVERRIDE {
963 BrowserThread::PostTask(
964 BrowserThread::IO, FROM_HERE,
965 base::Bind(&ErrorPageNavigationCorrectionsFailTest::RemoveFilters));
968 private:
969 // Adds a filter that causes all correction service requests to fail with
970 // ERR_ADDRESS_UNREACHABLE.
972 // Also adds the content::URLRequestFailedJob filter.
973 static void AddFilters() {
974 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
975 content::URLRequestFailedJob::AddUrlHandler();
977 net::URLRequestFilter::GetInstance()->AddUrlInterceptor(
978 google_util::LinkDoctorBaseURL(),
979 scoped_ptr<net::URLRequestInterceptor>(
980 new AddressUnreachableInterceptor()));
983 static void RemoveFilters() {
984 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
985 net::URLRequestFilter::GetInstance()->ClearHandlers();
989 // Make sure that when corrections fail to load, the network error page is
990 // successfully loaded.
991 IN_PROC_BROWSER_TEST_F(ErrorPageNavigationCorrectionsFailTest,
992 FetchCorrectionsFails) {
993 ui_test_utils::NavigateToURLBlockUntilNavigationsComplete(
994 browser(),
995 URLRequestFailedJob::GetMockHttpUrl(net::ERR_NAME_NOT_RESOLVED),
998 // Verify that the expected error page is being displayed.
999 ExpectDisplayingLocalErrorPage(browser(), net::ERR_NAME_NOT_RESOLVED);
1002 // Checks that when an error occurs and a corrections fail to load, the stale
1003 // cache status of the page is correctly transferred, and we can load the
1004 // stale copy from the javascript. Most logic copied from StaleCacheStatus
1005 // above.
1006 IN_PROC_BROWSER_TEST_F(ErrorPageNavigationCorrectionsFailTest,
1007 StaleCacheStatusFailedCorrections) {
1008 ASSERT_TRUE(test_server()->Start());
1009 // Load cache with entry with "nocache" set, to create stale
1010 // cache.
1011 GURL test_url(test_server()->GetURL("files/nocache.html"));
1012 NavigateToURLAndWaitForTitle(test_url, "Nocache Test Page", 1);
1014 // Reload same URL after forcing an error from the the network layer;
1015 // confirm that the error page is told the cached copy exists.
1016 scoped_refptr<net::URLRequestContextGetter> url_request_context_getter =
1017 browser()->profile()->GetRequestContext();
1018 BrowserThread::PostTask(
1019 BrowserThread::IO, FROM_HERE,
1020 base::Bind(&InterceptNetworkTransactions, url_request_context_getter,
1021 net::ERR_CONNECTION_FAILED));
1023 ui_test_utils::NavigateToURLBlockUntilNavigationsComplete(
1024 browser(), test_url, 2);
1025 EXPECT_TRUE(IsDisplayingText(browser(), GetLoadStaleButtonLabel()));
1026 EXPECT_TRUE(ProbeStaleCopyValue(true));
1028 // Confirm that loading the stale copy from the cache works.
1029 content::TestNavigationObserver same_tab_observer(
1030 browser()->tab_strip_model()->GetActiveWebContents(), 1);
1031 ASSERT_TRUE(ReloadStaleCopyFromCache());
1032 same_tab_observer.Wait();
1033 EXPECT_EQ(base::ASCIIToUTF16("Nocache Test Page"),
1034 browser()->tab_strip_model()->GetActiveWebContents()->GetTitle());
1036 // Clear the cache and reload the same URL; confirm the error page is told
1037 // that there is no cached copy.
1038 BrowsingDataRemover* remover =
1039 BrowsingDataRemover::CreateForUnboundedRange(browser()->profile());
1040 remover->Remove(BrowsingDataRemover::REMOVE_CACHE,
1041 BrowsingDataHelper::UNPROTECTED_WEB);
1042 ui_test_utils::NavigateToURLBlockUntilNavigationsComplete(
1043 browser(), test_url, 2);
1044 EXPECT_TRUE(ProbeStaleCopyValue(false));
1045 EXPECT_FALSE(IsDisplayingText(browser(), GetLoadStaleButtonLabel()));
1048 // A test fixture that simulates failing requests for an IDN domain name.
1049 class ErrorPageForIDNTest : public InProcessBrowserTest {
1050 public:
1051 // Target hostname in different forms.
1052 static const char kHostname[];
1053 static const char kHostnameJSUnicode[];
1055 // InProcessBrowserTest:
1056 virtual void SetUpOnMainThread() OVERRIDE {
1057 // Clear AcceptLanguages to force punycode decoding.
1058 browser()->profile()->GetPrefs()->SetString(prefs::kAcceptLanguages,
1059 std::string());
1060 BrowserThread::PostTask(
1061 BrowserThread::IO, FROM_HERE,
1062 base::Bind(&ErrorPageForIDNTest::AddFilters));
1065 virtual void TearDownOnMainThread() OVERRIDE {
1066 BrowserThread::PostTask(
1067 BrowserThread::IO, FROM_HERE,
1068 base::Bind(&ErrorPageForIDNTest::RemoveFilters));
1071 private:
1072 static void AddFilters() {
1073 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
1074 content::URLRequestFailedJob::AddUrlHandlerForHostname(kHostname);
1077 static void RemoveFilters() {
1078 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
1079 net::URLRequestFilter::GetInstance()->ClearHandlers();
1083 const char ErrorPageForIDNTest::kHostname[] =
1084 "xn--d1abbgf6aiiy.xn--p1ai";
1085 const char ErrorPageForIDNTest::kHostnameJSUnicode[] =
1086 "\\u043f\\u0440\\u0435\\u0437\\u0438\\u0434\\u0435\\u043d\\u0442."
1087 "\\u0440\\u0444";
1089 // Make sure error page shows correct unicode for IDN.
1090 IN_PROC_BROWSER_TEST_F(ErrorPageForIDNTest, IDN) {
1091 // ERR_UNSAFE_PORT will not trigger navigation corrections.
1092 ui_test_utils::NavigateToURLBlockUntilNavigationsComplete(
1093 browser(),
1094 URLRequestFailedJob::GetMockHttpUrlForHostname(net::ERR_UNSAFE_PORT,
1095 kHostname),
1098 ToggleHelpBox(browser());
1099 EXPECT_TRUE(IsDisplayingText(browser(), kHostnameJSUnicode));
1102 } // namespace