Fire an error if a pref used in the UI is missing once all prefs are fetched.
[chromium-blink-merge.git] / chrome / browser / errorpage_browsertest.cc
blob4ec198a6220abb6d10d86679835789eb4b4ebda4
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/net/url_request_mock_util.h"
19 #include "chrome/browser/profiles/profile.h"
20 #include "chrome/browser/search_engines/ui_thread_search_terms_data.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 "net/base/net_errors.h"
41 #include "net/base/net_util.h"
42 #include "net/http/failing_http_transaction_factory.h"
43 #include "net/http/http_cache.h"
44 #include "net/test/spawned_test_server/spawned_test_server.h"
45 #include "net/test/url_request/url_request_failed_job.h"
46 #include "net/test/url_request/url_request_mock_http_job.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 net::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 GetShowSavedButtonLabel() {
140 return l10n_util::GetStringUTF8(IDS_ERRORPAGES_BUTTON_SHOW_SAVED_COPY);
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 ~FailFirstNRequestsInterceptor() override {}
159 // net::URLRequestInterceptor implementation
160 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 ~LinkDoctorInterceptor() override {}
205 // net::URLRequestInterceptor implementation
206 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 net::URLRequestMockHTTPJob(
219 request,
220 network_delegate,
221 root_http.AppendASCII("mock-link-doctor.json"),
222 BrowserThread::GetBlockingPool()->GetTaskRunnerWithShutdownBehavior(
223 base::SequencedWorkerPool::SKIP_ON_SHUTDOWN));
226 void WaitForRequests(int requests_to_wait_for) {
227 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
228 DCHECK_EQ(-1, requests_to_wait_for_);
229 DCHECK(!run_loop_);
231 if (requests_to_wait_for >= num_requests_)
232 return;
234 requests_to_wait_for_ = requests_to_wait_for;
235 run_loop_.reset(new base::RunLoop());
236 run_loop_->Run();
237 run_loop_.reset();
238 requests_to_wait_for_ = -1;
239 EXPECT_EQ(num_requests_, requests_to_wait_for);
242 // It is up to the caller to wait until all relevant requests has been
243 // created, either through calling WaitForRequests or some other manner,
244 // before calling this method.
245 int num_requests() const {
246 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
247 return num_requests_;
250 private:
251 void RequestCreated() {
252 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
254 num_requests_++;
255 if (num_requests_ == requests_to_wait_for_)
256 run_loop_->Quit();
259 // These are only used on the UI thread.
260 int num_requests_;
261 int requests_to_wait_for_;
262 scoped_ptr<base::RunLoop> run_loop_;
264 // This prevents any risk of flake if any test doesn't wait for a request
265 // it sent. Mutable so it can be accessed from a const function.
266 mutable base::WeakPtrFactory<LinkDoctorInterceptor> weak_factory_;
268 DISALLOW_COPY_AND_ASSIGN(LinkDoctorInterceptor);
271 void InstallMockInterceptors(
272 const GURL& search_url,
273 scoped_ptr<net::URLRequestInterceptor> link_doctor_interceptor) {
274 chrome_browser_net::SetUrlRequestMocksEnabled(true);
276 AddInterceptorForURL(google_util::LinkDoctorBaseURL(),
277 link_doctor_interceptor.Pass());
279 // Add a mock for the search engine the error page will use.
280 base::FilePath root_http;
281 PathService::Get(chrome::DIR_TEST_DATA, &root_http);
282 net::URLRequestFilter::GetInstance()->AddHostnameInterceptor(
283 search_url.scheme(), search_url.host(),
284 net::URLRequestMockHTTPJob::CreateInterceptorForSingleFile(
285 root_http.AppendASCII("title3.html"),
286 BrowserThread::GetBlockingPool()));
289 class ErrorPageTest : public InProcessBrowserTest {
290 public:
291 enum HistoryNavigationDirection {
292 HISTORY_NAVIGATE_BACK,
293 HISTORY_NAVIGATE_FORWARD,
296 ErrorPageTest() : link_doctor_interceptor_(NULL) {}
297 ~ErrorPageTest() override {}
299 // Navigates the active tab to a mock url created for the file at |file_path|.
300 // Needed for StaleCacheStatus and StaleCacheStatusFailedCorrections tests.
301 void SetUpCommandLine(base::CommandLine* command_line) override {
302 command_line->AppendSwitchASCII(switches::kShowSavedCopy,
303 switches::kEnableShowSavedCopyPrimary);
306 // Navigates the active tab to a mock url created for the file at |file_path|.
307 void NavigateToFileURL(const base::FilePath::StringType& file_path) {
308 ui_test_utils::NavigateToURL(
309 browser(),
310 net::URLRequestMockHTTPJob::GetMockUrl(base::FilePath(file_path)));
313 // Navigates to the given URL and waits for |num_navigations| to occur, and
314 // the title to change to |expected_title|.
315 void NavigateToURLAndWaitForTitle(const GURL& url,
316 const std::string& expected_title,
317 int num_navigations) {
318 content::TitleWatcher title_watcher(
319 browser()->tab_strip_model()->GetActiveWebContents(),
320 base::ASCIIToUTF16(expected_title));
322 ui_test_utils::NavigateToURLBlockUntilNavigationsComplete(
323 browser(), url, num_navigations);
325 EXPECT_EQ(base::ASCIIToUTF16(expected_title),
326 title_watcher.WaitAndGetTitle());
329 // Navigates back in the history and waits for |num_navigations| to occur, and
330 // the title to change to |expected_title|.
331 void GoBackAndWaitForTitle(const std::string& expected_title,
332 int num_navigations) {
333 NavigateHistoryAndWaitForTitle(expected_title,
334 num_navigations,
335 HISTORY_NAVIGATE_BACK);
338 // Navigates forward in the history and waits for |num_navigations| to occur,
339 // and the title to change to |expected_title|.
340 void GoForwardAndWaitForTitle(const std::string& expected_title,
341 int num_navigations) {
342 NavigateHistoryAndWaitForTitle(expected_title,
343 num_navigations,
344 HISTORY_NAVIGATE_FORWARD);
347 void GoBackAndWaitForNavigations(int num_navigations) {
348 NavigateHistory(num_navigations, HISTORY_NAVIGATE_BACK);
351 void GoForwardAndWaitForNavigations(int num_navigations) {
352 NavigateHistory(num_navigations, HISTORY_NAVIGATE_FORWARD);
355 // Confirms that the javascript variable indicating whether or not we have
356 // a stale copy in the cache has been set to |expected|, and that the
357 // stale load button is or isn't there based on the same expectation.
358 testing::AssertionResult ProbeStaleCopyValue(bool expected) {
359 const char* js_cache_probe =
360 "try {\n"
361 " domAutomationController.send(\n"
362 " loadTimeData.valueExists('showSavedCopyButton') ?"
363 " 'yes' : 'no');\n"
364 "} catch (e) {\n"
365 " domAutomationController.send(e.message);\n"
366 "}\n";
368 std::string result;
369 bool ret =
370 content::ExecuteScriptAndExtractString(
371 browser()->tab_strip_model()->GetActiveWebContents(),
372 js_cache_probe,
373 &result);
374 if (!ret) {
375 return testing::AssertionFailure()
376 << "Failing return from ExecuteScriptAndExtractString.";
379 if ((expected && "yes" == result) || (!expected && "no" == result))
380 return testing::AssertionSuccess();
382 return testing::AssertionFailure() << "Cache probe result is " << result;
385 testing::AssertionResult ReloadStaleCopyFromCache() {
386 const char* js_reload_script =
387 "try {\n"
388 " document.getElementById('show-saved-copy-button').click();\n"
389 " domAutomationController.send('success');\n"
390 "} catch (e) {\n"
391 " domAutomationController.send(e.message);\n"
392 "}\n";
394 std::string result;
395 bool ret = content::ExecuteScriptAndExtractString(
396 browser()->tab_strip_model()->GetActiveWebContents(),
397 js_reload_script,
398 &result);
399 EXPECT_TRUE(ret);
400 if (!ret)
401 return testing::AssertionFailure();
402 return ("success" == result ? testing::AssertionSuccess() :
403 (testing::AssertionFailure() << "Exception message is " << result));
406 LinkDoctorInterceptor* link_doctor_interceptor() {
407 return link_doctor_interceptor_;
410 protected:
411 void SetUpOnMainThread() override {
412 link_doctor_interceptor_ = new LinkDoctorInterceptor();
413 scoped_ptr<net::URLRequestInterceptor> owned_interceptor(
414 link_doctor_interceptor_);
415 // Ownership of the |interceptor_| is passed to an object the IO thread, but
416 // a pointer is kept in the test fixture. As soon as anything calls
417 // URLRequestFilter::ClearHandlers(), |interceptor_| can become invalid.
418 UIThreadSearchTermsData search_terms_data(browser()->profile());
419 BrowserThread::PostTask(
420 BrowserThread::IO, FROM_HERE,
421 base::Bind(&InstallMockInterceptors,
422 GURL(search_terms_data.GoogleBaseURLValue()),
423 base::Passed(&owned_interceptor)));
426 // Returns a GURL that results in a DNS error.
427 GURL GetDnsErrorURL() const {
428 return URLRequestFailedJob::GetMockHttpUrl(net::ERR_NAME_NOT_RESOLVED);
431 private:
432 // Navigates the browser the indicated direction in the history and waits for
433 // |num_navigations| to occur and the title to change to |expected_title|.
434 void NavigateHistoryAndWaitForTitle(const std::string& expected_title,
435 int num_navigations,
436 HistoryNavigationDirection direction) {
437 content::TitleWatcher title_watcher(
438 browser()->tab_strip_model()->GetActiveWebContents(),
439 base::ASCIIToUTF16(expected_title));
441 NavigateHistory(num_navigations, direction);
443 EXPECT_EQ(title_watcher.WaitAndGetTitle(),
444 base::ASCIIToUTF16(expected_title));
447 void NavigateHistory(int num_navigations,
448 HistoryNavigationDirection direction) {
449 content::TestNavigationObserver test_navigation_observer(
450 browser()->tab_strip_model()->GetActiveWebContents(),
451 num_navigations);
452 if (direction == HISTORY_NAVIGATE_BACK) {
453 chrome::GoBack(browser(), CURRENT_TAB);
454 } else if (direction == HISTORY_NAVIGATE_FORWARD) {
455 chrome::GoForward(browser(), CURRENT_TAB);
456 } else {
457 FAIL();
459 test_navigation_observer.Wait();
462 LinkDoctorInterceptor* link_doctor_interceptor_;
465 class TestFailProvisionalLoadObserver : public content::WebContentsObserver {
466 public:
467 explicit TestFailProvisionalLoadObserver(content::WebContents* contents)
468 : content::WebContentsObserver(contents) {}
469 ~TestFailProvisionalLoadObserver() override {}
471 // This method is invoked when the provisional load failed.
472 void DidFailProvisionalLoad(
473 content::RenderFrameHost* render_frame_host,
474 const GURL& validated_url,
475 int error_code,
476 const base::string16& error_description) override {
477 fail_url_ = validated_url;
480 const GURL& fail_url() const { return fail_url_; }
482 private:
483 GURL fail_url_;
485 DISALLOW_COPY_AND_ASSIGN(TestFailProvisionalLoadObserver);
488 void InterceptNetworkTransactions(net::URLRequestContextGetter* getter,
489 net::Error error) {
490 DCHECK(content::BrowserThread::CurrentlyOn(BrowserThread::IO));
491 net::HttpCache* cache(
492 getter->GetURLRequestContext()->http_transaction_factory()->GetCache());
493 DCHECK(cache);
494 scoped_ptr<net::HttpTransactionFactory> factory(
495 new net::FailingHttpTransactionFactory(cache->GetSession(), error));
496 // Throw away old version; since this is a a browser test, we don't
497 // need to restore the old state.
498 cache->SetHttpNetworkTransactionFactoryForTesting(factory.Pass());
501 // Test that a DNS error occuring in the main frame redirects to an error page.
502 IN_PROC_BROWSER_TEST_F(ErrorPageTest, DNSError_Basic) {
503 // The first navigation should fail, and the second one should be the error
504 // page.
505 ui_test_utils::NavigateToURLBlockUntilNavigationsComplete(
506 browser(), GetDnsErrorURL(), 2);
507 ExpectDisplayingNavigationCorrections(browser(), net::ERR_NAME_NOT_RESOLVED);
508 EXPECT_EQ(1, link_doctor_interceptor()->num_requests());
511 // Test that a DNS error occuring in the main frame does not result in an
512 // additional session history entry.
513 IN_PROC_BROWSER_TEST_F(ErrorPageTest, DNSError_GoBack1) {
514 NavigateToFileURL(FILE_PATH_LITERAL("title2.html"));
515 ui_test_utils::NavigateToURLBlockUntilNavigationsComplete(
516 browser(), GetDnsErrorURL(), 2);
517 ExpectDisplayingNavigationCorrections(browser(), net::ERR_NAME_NOT_RESOLVED);
518 GoBackAndWaitForTitle("Title Of Awesomeness", 1);
519 EXPECT_EQ(1, link_doctor_interceptor()->num_requests());
522 // Test that a DNS error occuring in the main frame does not result in an
523 // additional session history entry.
524 IN_PROC_BROWSER_TEST_F(ErrorPageTest, DNSError_GoBack2) {
525 NavigateToFileURL(FILE_PATH_LITERAL("title2.html"));
527 ui_test_utils::NavigateToURLBlockUntilNavigationsComplete(
528 browser(), GetDnsErrorURL(), 2);
529 ExpectDisplayingNavigationCorrections(browser(), net::ERR_NAME_NOT_RESOLVED);
530 EXPECT_EQ(1, link_doctor_interceptor()->num_requests());
532 NavigateToFileURL(FILE_PATH_LITERAL("title3.html"));
534 GoBackAndWaitForNavigations(2);
535 ExpectDisplayingNavigationCorrections(browser(), net::ERR_NAME_NOT_RESOLVED);
536 EXPECT_EQ(2, link_doctor_interceptor()->num_requests());
538 GoBackAndWaitForTitle("Title Of Awesomeness", 1);
539 EXPECT_EQ(2, link_doctor_interceptor()->num_requests());
542 // Test that a DNS error occuring in the main frame does not result in an
543 // additional session history entry.
544 IN_PROC_BROWSER_TEST_F(ErrorPageTest, DNSError_GoBack2AndForward) {
545 NavigateToFileURL(FILE_PATH_LITERAL("title2.html"));
547 ui_test_utils::NavigateToURLBlockUntilNavigationsComplete(
548 browser(), GetDnsErrorURL(), 2);
549 ExpectDisplayingNavigationCorrections(browser(), net::ERR_NAME_NOT_RESOLVED);
550 EXPECT_EQ(1, link_doctor_interceptor()->num_requests());
552 NavigateToFileURL(FILE_PATH_LITERAL("title3.html"));
554 GoBackAndWaitForNavigations(2);
555 ExpectDisplayingNavigationCorrections(browser(), net::ERR_NAME_NOT_RESOLVED);
556 EXPECT_EQ(2, link_doctor_interceptor()->num_requests());
558 GoBackAndWaitForTitle("Title Of Awesomeness", 1);
560 GoForwardAndWaitForNavigations(2);
561 ExpectDisplayingNavigationCorrections(browser(), net::ERR_NAME_NOT_RESOLVED);
562 EXPECT_EQ(3, link_doctor_interceptor()->num_requests());
565 // Test that a DNS error occuring in the main frame does not result in an
566 // additional session history entry.
567 IN_PROC_BROWSER_TEST_F(ErrorPageTest, DNSError_GoBack2Forward2) {
568 NavigateToFileURL(FILE_PATH_LITERAL("title3.html"));
570 ui_test_utils::NavigateToURLBlockUntilNavigationsComplete(
571 browser(), GetDnsErrorURL(), 2);
572 ExpectDisplayingNavigationCorrections(browser(), net::ERR_NAME_NOT_RESOLVED);
573 EXPECT_EQ(1, link_doctor_interceptor()->num_requests());
575 NavigateToFileURL(FILE_PATH_LITERAL("title2.html"));
577 GoBackAndWaitForNavigations(2);
578 ExpectDisplayingNavigationCorrections(browser(), net::ERR_NAME_NOT_RESOLVED);
579 EXPECT_EQ(2, link_doctor_interceptor()->num_requests());
581 GoBackAndWaitForTitle("Title Of More Awesomeness", 1);
583 GoForwardAndWaitForNavigations(2);
584 ExpectDisplayingNavigationCorrections(browser(), net::ERR_NAME_NOT_RESOLVED);
585 EXPECT_EQ(3, link_doctor_interceptor()->num_requests());
587 GoForwardAndWaitForTitle("Title Of Awesomeness", 1);
588 EXPECT_EQ(3, link_doctor_interceptor()->num_requests());
591 // Test that the search button on a DNS error page works.
592 IN_PROC_BROWSER_TEST_F(ErrorPageTest, DNSError_DoSearch) {
593 // The first navigation should fail, and the second one should be the error
594 // page.
595 ui_test_utils::NavigateToURLBlockUntilNavigationsComplete(
596 browser(), GetDnsErrorURL(), 2);
597 ExpectDisplayingNavigationCorrections(browser(), net::ERR_NAME_NOT_RESOLVED);
598 EXPECT_EQ(1, link_doctor_interceptor()->num_requests());
600 content::WebContents* web_contents =
601 browser()->tab_strip_model()->GetActiveWebContents();
603 // Do a search and make sure the browser ends up at the right page.
604 content::TestNavigationObserver nav_observer(web_contents, 1);
605 content::TitleWatcher title_watcher(
606 web_contents,
607 base::ASCIIToUTF16("Title Of More Awesomeness"));
608 // Can't use content::ExecuteScript because it waits for scripts to send
609 // notification that they've run, and scripts that trigger a navigation may
610 // not send that notification.
611 web_contents->GetMainFrame()->ExecuteJavaScript(
612 base::ASCIIToUTF16("document.getElementById('search-button').click();"));
613 nav_observer.Wait();
614 EXPECT_EQ(base::ASCIIToUTF16("Title Of More Awesomeness"),
615 title_watcher.WaitAndGetTitle());
617 // There should have been another Link Doctor request, for tracking purposes.
618 // Have to wait for it, since the search page does not depend on having
619 // sent the tracking request.
620 link_doctor_interceptor()->WaitForRequests(2);
621 EXPECT_EQ(2, link_doctor_interceptor()->num_requests());
623 // Check the path and query string.
624 std::string url;
625 ASSERT_TRUE(content::ExecuteScriptAndExtractString(
626 browser()->tab_strip_model()->GetActiveWebContents(),
627 "domAutomationController.send(window.location.href);",
628 &url));
629 EXPECT_EQ("/search", GURL(url).path());
630 EXPECT_EQ("q=search%20query", GURL(url).query());
632 // Go back to the error page, to make sure the history is correct.
633 GoBackAndWaitForNavigations(2);
634 ExpectDisplayingNavigationCorrections(browser(), net::ERR_NAME_NOT_RESOLVED);
635 EXPECT_EQ(3, link_doctor_interceptor()->num_requests());
638 // Test that the reload button on a DNS error page works.
639 IN_PROC_BROWSER_TEST_F(ErrorPageTest, DNSError_DoReload) {
640 // The first navigation should fail, and the second one should be the error
641 // page.
642 ui_test_utils::NavigateToURLBlockUntilNavigationsComplete(
643 browser(), GetDnsErrorURL(), 2);
644 ExpectDisplayingNavigationCorrections(browser(), net::ERR_NAME_NOT_RESOLVED);
645 EXPECT_EQ(1, link_doctor_interceptor()->num_requests());
647 content::WebContents* web_contents =
648 browser()->tab_strip_model()->GetActiveWebContents();
650 // Clicking the reload button should load the error page again, and there
651 // should be two commits, as before.
652 content::TestNavigationObserver nav_observer(web_contents, 2);
653 // Can't use content::ExecuteScript because it waits for scripts to send
654 // notification that they've run, and scripts that trigger a navigation may
655 // not send that notification.
656 web_contents->GetMainFrame()->ExecuteJavaScript(
657 base::ASCIIToUTF16("document.getElementById('reload-button').click();"));
658 nav_observer.Wait();
659 ExpectDisplayingNavigationCorrections(browser(), net::ERR_NAME_NOT_RESOLVED);
661 // There should have two more requests to the correction service: One for the
662 // new error page, and one for tracking purposes. Have to make sure to wait
663 // for the tracking request, since the new error page does not depend on it.
664 link_doctor_interceptor()->WaitForRequests(3);
665 EXPECT_EQ(3, link_doctor_interceptor()->num_requests());
668 // Test that clicking links on a DNS error page works.
669 IN_PROC_BROWSER_TEST_F(ErrorPageTest, DNSError_DoClickLink) {
670 // The first navigation should fail, and the second one should be the error
671 // page.
672 ui_test_utils::NavigateToURLBlockUntilNavigationsComplete(
673 browser(), GetDnsErrorURL(), 2);
674 ExpectDisplayingNavigationCorrections(browser(), net::ERR_NAME_NOT_RESOLVED);
675 EXPECT_EQ(1, link_doctor_interceptor()->num_requests());
677 content::WebContents* web_contents =
678 browser()->tab_strip_model()->GetActiveWebContents();
680 // Simulate a click on a link.
682 content::TitleWatcher title_watcher(
683 web_contents,
684 base::ASCIIToUTF16("Title Of Awesomeness"));
685 std::string link_selector =
686 "document.querySelector('a[href=\"http://mock.http/title2.html\"]')";
687 // The tracking request is triggered by onmousedown, so it catches middle
688 // mouse button clicks, as well as left clicks.
689 web_contents->GetMainFrame()->ExecuteJavaScript(
690 base::ASCIIToUTF16(link_selector + ".onmousedown();"));
691 // Can't use content::ExecuteScript because it waits for scripts to send
692 // notification that they've run, and scripts that trigger a navigation may
693 // not send that notification.
694 web_contents->GetMainFrame()->ExecuteJavaScript(
695 base::ASCIIToUTF16(link_selector + ".click();"));
696 EXPECT_EQ(base::ASCIIToUTF16("Title Of Awesomeness"),
697 title_watcher.WaitAndGetTitle());
699 // There should have been a tracking request to the correction service. Have
700 // to make sure to wait the tracking request, since the new page does not
701 // depend on it.
702 link_doctor_interceptor()->WaitForRequests(2);
703 EXPECT_EQ(2, link_doctor_interceptor()->num_requests());
706 // Test that a DNS error occuring in an iframe does not result in showing
707 // navigation corrections.
708 IN_PROC_BROWSER_TEST_F(ErrorPageTest, IFrameDNSError_Basic) {
709 NavigateToURLAndWaitForTitle(
710 net::URLRequestMockHTTPJob::GetMockUrl(
711 base::FilePath(FILE_PATH_LITERAL("iframe_dns_error.html"))),
712 "Blah",
714 // We expect to have two history entries, since we started off with navigation
715 // to "about:blank" and then navigated to "iframe_dns_error.html".
716 EXPECT_EQ(2,
717 browser()->tab_strip_model()->GetActiveWebContents()->
718 GetController().GetEntryCount());
719 EXPECT_EQ(0, link_doctor_interceptor()->num_requests());
722 // This test fails regularly on win_rel trybots. See crbug.com/121540
723 #if defined(OS_WIN)
724 #define MAYBE_IFrameDNSError_GoBack DISABLED_IFrameDNSError_GoBack
725 #else
726 #define MAYBE_IFrameDNSError_GoBack IFrameDNSError_GoBack
727 #endif
728 // Test that a DNS error occuring in an iframe does not result in an
729 // additional session history entry.
730 IN_PROC_BROWSER_TEST_F(ErrorPageTest, MAYBE_IFrameDNSError_GoBack) {
731 NavigateToFileURL(FILE_PATH_LITERAL("title2.html"));
732 NavigateToFileURL(FILE_PATH_LITERAL("iframe_dns_error.html"));
733 GoBackAndWaitForTitle("Title Of Awesomeness", 1);
734 EXPECT_EQ(0, link_doctor_interceptor()->num_requests());
737 // This test fails regularly on win_rel trybots. See crbug.com/121540
739 // This fails on linux_aura bringup: http://crbug.com/163931
740 #if defined(OS_WIN) || (defined(OS_LINUX) && !defined(OS_CHROMEOS) && defined(USE_AURA))
741 #define MAYBE_IFrameDNSError_GoBackAndForward DISABLED_IFrameDNSError_GoBackAndForward
742 #else
743 #define MAYBE_IFrameDNSError_GoBackAndForward IFrameDNSError_GoBackAndForward
744 #endif
745 // Test that a DNS error occuring in an iframe does not result in an
746 // additional session history entry.
747 IN_PROC_BROWSER_TEST_F(ErrorPageTest, MAYBE_IFrameDNSError_GoBackAndForward) {
748 NavigateToFileURL(FILE_PATH_LITERAL("title2.html"));
749 NavigateToFileURL(FILE_PATH_LITERAL("iframe_dns_error.html"));
750 GoBackAndWaitForTitle("Title Of Awesomeness", 1);
751 GoForwardAndWaitForTitle("Blah", 1);
752 EXPECT_EQ(0, link_doctor_interceptor()->num_requests());
755 // Test that a DNS error occuring in an iframe, once the main document is
756 // completed loading, does not result in an additional session history entry.
757 // To ensure that the main document has completed loading, JavaScript is used to
758 // inject an iframe after loading is done.
759 IN_PROC_BROWSER_TEST_F(ErrorPageTest, IFrameDNSError_JavaScript) {
760 content::WebContents* wc =
761 browser()->tab_strip_model()->GetActiveWebContents();
762 GURL fail_url =
763 URLRequestFailedJob::GetMockHttpUrl(net::ERR_NAME_NOT_RESOLVED);
765 // Load a regular web page, in which we will inject an iframe.
766 NavigateToFileURL(FILE_PATH_LITERAL("title2.html"));
768 // We expect to have two history entries, since we started off with navigation
769 // to "about:blank" and then navigated to "title2.html".
770 EXPECT_EQ(2, wc->GetController().GetEntryCount());
772 std::string script = "var frame = document.createElement('iframe');"
773 "frame.src = '" + fail_url.spec() + "';"
774 "document.body.appendChild(frame);";
776 TestFailProvisionalLoadObserver fail_observer(wc);
777 content::WindowedNotificationObserver load_observer(
778 content::NOTIFICATION_LOAD_STOP,
779 content::Source<NavigationController>(&wc->GetController()));
780 wc->GetMainFrame()->ExecuteJavaScript(base::ASCIIToUTF16(script));
781 load_observer.Wait();
783 // Ensure we saw the expected failure.
784 EXPECT_EQ(fail_url, fail_observer.fail_url());
786 // Failed initial navigation of an iframe shouldn't be adding any history
787 // entries.
788 EXPECT_EQ(2, wc->GetController().GetEntryCount());
791 // Do the same test, but with an iframe that doesn't have initial URL
792 // assigned.
793 script = "var frame = document.createElement('iframe');"
794 "frame.id = 'target_frame';"
795 "document.body.appendChild(frame);";
797 content::WindowedNotificationObserver load_observer(
798 content::NOTIFICATION_LOAD_STOP,
799 content::Source<NavigationController>(&wc->GetController()));
800 wc->GetMainFrame()->ExecuteJavaScript(base::ASCIIToUTF16(script));
801 load_observer.Wait();
804 script = "var f = document.getElementById('target_frame');"
805 "f.src = '" + fail_url.spec() + "';";
807 TestFailProvisionalLoadObserver fail_observer(wc);
808 content::WindowedNotificationObserver load_observer(
809 content::NOTIFICATION_LOAD_STOP,
810 content::Source<NavigationController>(&wc->GetController()));
811 wc->GetMainFrame()->ExecuteJavaScript(base::ASCIIToUTF16(script));
812 load_observer.Wait();
814 EXPECT_EQ(fail_url, fail_observer.fail_url());
815 EXPECT_EQ(2, wc->GetController().GetEntryCount());
817 EXPECT_EQ(0, link_doctor_interceptor()->num_requests());
820 // Checks that navigation corrections are not loaded when we receive an actual
821 // 404 page.
822 IN_PROC_BROWSER_TEST_F(ErrorPageTest, Page404) {
823 NavigateToURLAndWaitForTitle(
824 net::URLRequestMockHTTPJob::GetMockUrl(
825 base::FilePath(FILE_PATH_LITERAL("page404.html"))),
826 "SUCCESS",
828 EXPECT_EQ(0, link_doctor_interceptor()->num_requests());
831 // Checks that when an error occurs, the stale cache status of the page
832 // is correctly transferred, and that stale cached copied can be loaded
833 // from the javascript.
834 IN_PROC_BROWSER_TEST_F(ErrorPageTest, StaleCacheStatus) {
835 ASSERT_TRUE(test_server()->Start());
836 // Load cache with entry with "nocache" set, to create stale
837 // cache.
838 GURL test_url(test_server()->GetURL("files/nocache.html"));
839 NavigateToURLAndWaitForTitle(test_url, "Nocache Test Page", 1);
841 // Reload same URL after forcing an error from the the network layer;
842 // confirm that the error page is told the cached copy exists.
843 scoped_refptr<net::URLRequestContextGetter> url_request_context_getter =
844 browser()->profile()->GetRequestContext();
845 BrowserThread::PostTask(
846 BrowserThread::IO, FROM_HERE,
847 base::Bind(&InterceptNetworkTransactions, url_request_context_getter,
848 net::ERR_FAILED));
850 // With no navigation corrections to load, there's only one navigation.
851 ui_test_utils::NavigateToURL(browser(), test_url);
852 EXPECT_TRUE(ProbeStaleCopyValue(true));
853 EXPECT_TRUE(IsDisplayingText(browser(), GetShowSavedButtonLabel()));
854 EXPECT_NE(base::ASCIIToUTF16("Nocache Test Page"),
855 browser()->tab_strip_model()->GetActiveWebContents()->GetTitle());
857 // Confirm that loading the stale copy from the cache works.
858 content::TestNavigationObserver same_tab_observer(
859 browser()->tab_strip_model()->GetActiveWebContents(), 1);
860 ASSERT_TRUE(ReloadStaleCopyFromCache());
861 same_tab_observer.Wait();
862 EXPECT_EQ(base::ASCIIToUTF16("Nocache Test Page"),
863 browser()->tab_strip_model()->GetActiveWebContents()->GetTitle());
865 // Reload the same URL with a post request; confirm the error page is told
866 // that there is no cached copy.
867 ui_test_utils::NavigateToURLWithPost(browser(), test_url);
868 EXPECT_TRUE(ProbeStaleCopyValue(false));
869 EXPECT_FALSE(IsDisplayingText(browser(), GetShowSavedButtonLabel()));
870 EXPECT_EQ(0, link_doctor_interceptor()->num_requests());
872 // Clear the cache and reload the same URL; confirm the error page is told
873 // that there is no cached copy.
874 BrowsingDataRemover* remover =
875 BrowsingDataRemover::CreateForUnboundedRange(browser()->profile());
876 remover->Remove(BrowsingDataRemover::REMOVE_CACHE,
877 BrowsingDataHelper::UNPROTECTED_WEB);
878 ui_test_utils::NavigateToURL(browser(), test_url);
879 EXPECT_TRUE(ProbeStaleCopyValue(false));
880 EXPECT_FALSE(IsDisplayingText(browser(), GetShowSavedButtonLabel()));
881 EXPECT_EQ(0, link_doctor_interceptor()->num_requests());
884 class ErrorPageAutoReloadTest : public InProcessBrowserTest {
885 public:
886 void SetUpCommandLine(base::CommandLine* command_line) override {
887 command_line->AppendSwitch(switches::kEnableOfflineAutoReload);
890 void InstallInterceptor(const GURL& url, int requests_to_fail) {
891 interceptor_ = new FailFirstNRequestsInterceptor(requests_to_fail);
892 scoped_ptr<net::URLRequestInterceptor> owned_interceptor(interceptor_);
894 // Tests don't need to wait for this task to complete before using the
895 // filter; any requests that might be affected by it will end up in the IO
896 // thread's message loop after this posted task anyway.
898 // Ownership of the interceptor is passed to an object the IO thread, but a
899 // pointer is kept in the test fixture. As soon as anything calls
900 // URLRequestFilter::ClearHandlers(), |interceptor_| can become invalid.
901 BrowserThread::PostTask(
902 BrowserThread::IO, FROM_HERE,
903 base::Bind(&AddInterceptorForURL, url,
904 base::Passed(&owned_interceptor)));
907 void NavigateToURLAndWaitForTitle(const GURL& url,
908 const std::string& expected_title,
909 int num_navigations) {
910 content::TitleWatcher title_watcher(
911 browser()->tab_strip_model()->GetActiveWebContents(),
912 base::ASCIIToUTF16(expected_title));
914 ui_test_utils::NavigateToURLBlockUntilNavigationsComplete(
915 browser(), url, num_navigations);
917 EXPECT_EQ(base::ASCIIToUTF16(expected_title),
918 title_watcher.WaitAndGetTitle());
921 FailFirstNRequestsInterceptor* interceptor() {
922 return interceptor_;
925 private:
926 FailFirstNRequestsInterceptor* interceptor_;
929 IN_PROC_BROWSER_TEST_F(ErrorPageAutoReloadTest, AutoReload) {
930 GURL test_url("http://error.page.auto.reload");
931 const int kRequestsToFail = 2;
932 InstallInterceptor(test_url, kRequestsToFail);
933 NavigateToURLAndWaitForTitle(test_url, "Test One", kRequestsToFail + 1);
934 // Note that the interceptor updates these variables on the IO thread,
935 // but this function reads them on the main thread. The requests have to be
936 // created (on the IO thread) before NavigateToURLAndWaitForTitle returns or
937 // this becomes racey.
938 EXPECT_EQ(kRequestsToFail, interceptor()->failures());
939 EXPECT_EQ(kRequestsToFail + 1, interceptor()->requests());
942 IN_PROC_BROWSER_TEST_F(ErrorPageAutoReloadTest, ManualReloadNotSuppressed) {
943 GURL test_url("http://error.page.auto.reload");
944 const int kRequestsToFail = 3;
945 InstallInterceptor(test_url, kRequestsToFail);
946 ui_test_utils::NavigateToURLBlockUntilNavigationsComplete(
947 browser(), test_url, 2);
949 EXPECT_EQ(2, interceptor()->failures());
950 EXPECT_EQ(2, interceptor()->requests());
952 ToggleHelpBox(browser());
953 EXPECT_TRUE(IsDisplayingText(browser(), "error.page.auto.reload"));
955 content::WebContents* web_contents =
956 browser()->tab_strip_model()->GetActiveWebContents();
957 content::TestNavigationObserver nav_observer(web_contents, 1);
958 web_contents->GetMainFrame()->ExecuteJavaScript(
959 base::ASCIIToUTF16("document.getElementById('reload-button').click();"));
960 nav_observer.Wait();
961 EXPECT_FALSE(IsDisplayingText(browser(), "error.page.auto.reload"));
964 // Interceptor that fails all requests with net::ERR_ADDRESS_UNREACHABLE.
965 class AddressUnreachableInterceptor : public net::URLRequestInterceptor {
966 public:
967 AddressUnreachableInterceptor() {}
968 ~AddressUnreachableInterceptor() override {}
970 // net::URLRequestInterceptor:
971 net::URLRequestJob* MaybeInterceptRequest(
972 net::URLRequest* request,
973 net::NetworkDelegate* network_delegate) const override {
974 return new URLRequestFailedJob(request,
975 network_delegate,
976 net::ERR_ADDRESS_UNREACHABLE);
979 private:
980 DISALLOW_COPY_AND_ASSIGN(AddressUnreachableInterceptor);
983 // A test fixture that returns ERR_ADDRESS_UNREACHABLE for all navigation
984 // correction requests. ERR_NAME_NOT_RESOLVED is more typical, but need to use
985 // a different error for the correction service and the original page to
986 // validate the right page is being displayed.
987 class ErrorPageNavigationCorrectionsFailTest : public ErrorPageTest {
988 public:
989 // InProcessBrowserTest:
990 void SetUpOnMainThread() override {
991 BrowserThread::PostTask(
992 BrowserThread::IO, FROM_HERE,
993 base::Bind(&ErrorPageNavigationCorrectionsFailTest::AddFilters));
996 void TearDownOnMainThread() override {
997 BrowserThread::PostTask(
998 BrowserThread::IO, FROM_HERE,
999 base::Bind(&ErrorPageNavigationCorrectionsFailTest::RemoveFilters));
1002 private:
1003 // Adds a filter that causes all correction service requests to fail with
1004 // ERR_ADDRESS_UNREACHABLE.
1006 // Also adds the net::URLRequestFailedJob filter.
1007 static void AddFilters() {
1008 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
1009 URLRequestFailedJob::AddUrlHandler();
1011 net::URLRequestFilter::GetInstance()->AddUrlInterceptor(
1012 google_util::LinkDoctorBaseURL(),
1013 scoped_ptr<net::URLRequestInterceptor>(
1014 new AddressUnreachableInterceptor()));
1017 static void RemoveFilters() {
1018 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
1019 net::URLRequestFilter::GetInstance()->ClearHandlers();
1023 // Make sure that when corrections fail to load, the network error page is
1024 // successfully loaded.
1025 IN_PROC_BROWSER_TEST_F(ErrorPageNavigationCorrectionsFailTest,
1026 FetchCorrectionsFails) {
1027 ui_test_utils::NavigateToURLBlockUntilNavigationsComplete(
1028 browser(),
1029 URLRequestFailedJob::GetMockHttpUrl(net::ERR_NAME_NOT_RESOLVED),
1032 // Verify that the expected error page is being displayed.
1033 ExpectDisplayingLocalErrorPage(browser(), net::ERR_NAME_NOT_RESOLVED);
1036 // Checks that when an error occurs and a corrections fail to load, the stale
1037 // cache status of the page is correctly transferred, and we can load the
1038 // stale copy from the javascript. Most logic copied from StaleCacheStatus
1039 // above.
1040 IN_PROC_BROWSER_TEST_F(ErrorPageNavigationCorrectionsFailTest,
1041 StaleCacheStatusFailedCorrections) {
1042 ASSERT_TRUE(test_server()->Start());
1043 // Load cache with entry with "nocache" set, to create stale
1044 // cache.
1045 GURL test_url(test_server()->GetURL("files/nocache.html"));
1046 NavigateToURLAndWaitForTitle(test_url, "Nocache Test Page", 1);
1048 // Reload same URL after forcing an error from the the network layer;
1049 // confirm that the error page is told the cached copy exists.
1050 scoped_refptr<net::URLRequestContextGetter> url_request_context_getter =
1051 browser()->profile()->GetRequestContext();
1052 BrowserThread::PostTask(
1053 BrowserThread::IO, FROM_HERE,
1054 base::Bind(&InterceptNetworkTransactions, url_request_context_getter,
1055 net::ERR_CONNECTION_FAILED));
1057 ui_test_utils::NavigateToURLBlockUntilNavigationsComplete(
1058 browser(), test_url, 2);
1059 EXPECT_TRUE(IsDisplayingText(browser(), GetShowSavedButtonLabel()));
1060 EXPECT_TRUE(ProbeStaleCopyValue(true));
1062 // Confirm that loading the stale copy from the cache works.
1063 content::TestNavigationObserver same_tab_observer(
1064 browser()->tab_strip_model()->GetActiveWebContents(), 1);
1065 ASSERT_TRUE(ReloadStaleCopyFromCache());
1066 same_tab_observer.Wait();
1067 EXPECT_EQ(base::ASCIIToUTF16("Nocache Test Page"),
1068 browser()->tab_strip_model()->GetActiveWebContents()->GetTitle());
1070 // Clear the cache and reload the same URL; confirm the error page is told
1071 // that there is no cached copy.
1072 BrowsingDataRemover* remover =
1073 BrowsingDataRemover::CreateForUnboundedRange(browser()->profile());
1074 remover->Remove(BrowsingDataRemover::REMOVE_CACHE,
1075 BrowsingDataHelper::UNPROTECTED_WEB);
1076 ui_test_utils::NavigateToURLBlockUntilNavigationsComplete(
1077 browser(), test_url, 2);
1078 EXPECT_TRUE(ProbeStaleCopyValue(false));
1079 EXPECT_FALSE(IsDisplayingText(browser(), GetShowSavedButtonLabel()));
1082 // A test fixture that simulates failing requests for an IDN domain name.
1083 class ErrorPageForIDNTest : public InProcessBrowserTest {
1084 public:
1085 // Target hostname in different forms.
1086 static const char kHostname[];
1087 static const char kHostnameJSUnicode[];
1089 // InProcessBrowserTest:
1090 void SetUpOnMainThread() override {
1091 // Clear AcceptLanguages to force punycode decoding.
1092 browser()->profile()->GetPrefs()->SetString(prefs::kAcceptLanguages,
1093 std::string());
1094 BrowserThread::PostTask(
1095 BrowserThread::IO, FROM_HERE,
1096 base::Bind(&ErrorPageForIDNTest::AddFilters));
1099 void TearDownOnMainThread() override {
1100 BrowserThread::PostTask(
1101 BrowserThread::IO, FROM_HERE,
1102 base::Bind(&ErrorPageForIDNTest::RemoveFilters));
1105 private:
1106 static void AddFilters() {
1107 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
1108 URLRequestFailedJob::AddUrlHandlerForHostname(kHostname);
1111 static void RemoveFilters() {
1112 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
1113 net::URLRequestFilter::GetInstance()->ClearHandlers();
1117 const char ErrorPageForIDNTest::kHostname[] =
1118 "xn--d1abbgf6aiiy.xn--p1ai";
1119 const char ErrorPageForIDNTest::kHostnameJSUnicode[] =
1120 "\\u043f\\u0440\\u0435\\u0437\\u0438\\u0434\\u0435\\u043d\\u0442."
1121 "\\u0440\\u0444";
1123 // Make sure error page shows correct unicode for IDN.
1124 IN_PROC_BROWSER_TEST_F(ErrorPageForIDNTest, IDN) {
1125 // ERR_UNSAFE_PORT will not trigger navigation corrections.
1126 ui_test_utils::NavigateToURL(
1127 browser(),
1128 URLRequestFailedJob::GetMockHttpUrlForHostname(net::ERR_UNSAFE_PORT,
1129 kHostname));
1131 ToggleHelpBox(browser());
1132 EXPECT_TRUE(IsDisplayingText(browser(), kHostnameJSUnicode));
1135 } // namespace