extension_browsertests_misc.cc revision 72a454cd3513ac24fbdd0e0cb9ad70b86a99b801
1// Copyright (c) 2011 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/file_util.h" 6#include "base/ref_counted.h" 7#include "base/utf_string_conversions.h" 8#include "chrome/browser/browser_list.h" 9#include "chrome/browser/extensions/autoupdate_interceptor.h" 10#include "chrome/browser/extensions/extension_apitest.h" 11#include "chrome/browser/extensions/extension_browsertest.h" 12#include "chrome/browser/extensions/extension_error_reporter.h" 13#include "chrome/browser/extensions/extension_host.h" 14#include "chrome/browser/extensions/extension_process_manager.h" 15#include "chrome/browser/extensions/extension_tabs_module.h" 16#include "chrome/browser/extensions/extension_service.h" 17#include "chrome/browser/extensions/extension_updater.h" 18#include "chrome/browser/profiles/profile.h" 19#include "chrome/browser/renderer_host/render_view_host.h" 20#include "chrome/browser/renderer_host/site_instance.h" 21#include "chrome/browser/tab_contents/tab_contents.h" 22#include "chrome/browser/tabs/tab_strip_model.h" 23#include "chrome/browser/ui/browser.h" 24#include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h" 25#include "chrome/common/chrome_paths.h" 26#include "chrome/common/extensions/extension_action.h" 27#include "chrome/common/url_constants.h" 28#include "chrome/test/ui_test_utils.h" 29#include "net/base/mock_host_resolver.h" 30#include "net/base/net_util.h" 31#include "net/test/test_server.h" 32 33#if defined(TOOLKIT_VIEWS) 34#include "chrome/browser/ui/views/frame/browser_view.h" 35#endif 36 37const std::string kSubscribePage = "/subscribe.html"; 38const std::string kFeedPage = "files/feeds/feed.html"; 39const std::string kFeedPageMultiRel = "files/feeds/feed_multi_rel.html"; 40const std::string kNoFeedPage = "files/feeds/no_feed.html"; 41const std::string kValidFeed0 = "files/feeds/feed_script.xml"; 42const std::string kValidFeed1 = "files/feeds/feed1.xml"; 43const std::string kValidFeed2 = "files/feeds/feed2.xml"; 44const std::string kValidFeed3 = "files/feeds/feed3.xml"; 45const std::string kValidFeed4 = "files/feeds/feed4.xml"; 46const std::string kValidFeed5 = "files/feeds/feed5.xml"; 47const std::string kValidFeed6 = "files/feeds/feed6.xml"; 48const std::string kValidFeedNoLinks = "files/feeds/feed_nolinks.xml"; 49const std::string kInvalidFeed1 = "files/feeds/feed_invalid1.xml"; 50const std::string kInvalidFeed2 = "files/feeds/feed_invalid2.xml"; 51const std::string kLocalization = 52 "files/extensions/browsertest/title_localized_pa/simple.html"; 53// We need a triple encoded string to prove that we are not decoding twice in 54// subscribe.js because one layer is also stripped off when subscribe.js passes 55// it to the XMLHttpRequest object. 56const std::string kFeedTripleEncoded = "files/feeds/url%25255Fdecoding.html"; 57const std::string kHashPageA = 58 "files/extensions/api_test/page_action/hash_change/test_page_A.html"; 59const std::string kHashPageAHash = kHashPageA + "#asdf"; 60const std::string kHashPageB = 61 "files/extensions/api_test/page_action/hash_change/test_page_B.html"; 62 63// Looks for an ExtensionHost whose URL has the given path component (including 64// leading slash). Also verifies that the expected number of hosts are loaded. 65static ExtensionHost* FindHostWithPath(ExtensionProcessManager* manager, 66 const std::string& path, 67 int expected_hosts) { 68 ExtensionHost* host = NULL; 69 int num_hosts = 0; 70 for (ExtensionProcessManager::const_iterator iter = manager->begin(); 71 iter != manager->end(); ++iter) { 72 if ((*iter)->GetURL().path() == path) { 73 EXPECT_FALSE(host); 74 host = *iter; 75 } 76 num_hosts++; 77 } 78 EXPECT_EQ(expected_hosts, num_hosts); 79 return host; 80} 81 82// Tests that we can load extension pages into the tab area and they can call 83// extension APIs. 84IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, TabContents) { 85 ASSERT_TRUE(LoadExtension( 86 test_data_dir_.AppendASCII("good").AppendASCII("Extensions") 87 .AppendASCII("behllobkkfkfnphdnhnkndlbkcpglgmj") 88 .AppendASCII("1.0.0.0"))); 89 90 ui_test_utils::NavigateToURL( 91 browser(), 92 GURL("chrome-extension://behllobkkfkfnphdnhnkndlbkcpglgmj/page.html")); 93 94 bool result = false; 95 ASSERT_TRUE(ui_test_utils::ExecuteJavaScriptAndExtractBool( 96 browser()->GetSelectedTabContents()->render_view_host(), L"", 97 L"testTabsAPI()", &result)); 98 EXPECT_TRUE(result); 99 100 // There was a bug where we would crash if we navigated to a page in the same 101 // extension because no new render view was getting created, so we would not 102 // do some setup. 103 ui_test_utils::NavigateToURL( 104 browser(), 105 GURL("chrome-extension://behllobkkfkfnphdnhnkndlbkcpglgmj/page.html")); 106 result = false; 107 ASSERT_TRUE(ui_test_utils::ExecuteJavaScriptAndExtractBool( 108 browser()->GetSelectedTabContents()->render_view_host(), L"", 109 L"testTabsAPI()", &result)); 110 EXPECT_TRUE(result); 111} 112 113// Tests that GPU-related WebKit preferences are set for extension background 114// pages. See http://crbug.com/64512. 115IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, WebKitPrefsBackgroundPage) { 116 ASSERT_TRUE(LoadExtension( 117 test_data_dir_.AppendASCII("good").AppendASCII("Extensions") 118 .AppendASCII("behllobkkfkfnphdnhnkndlbkcpglgmj") 119 .AppendASCII("1.0.0.0"))); 120 121 ExtensionProcessManager* manager = 122 browser()->profile()->GetExtensionProcessManager(); 123 ExtensionHost* host = FindHostWithPath(manager, "/backgroundpage.html", 1); 124 WebPreferences prefs = host->GetWebkitPrefs(); 125 ASSERT_FALSE(prefs.experimental_webgl_enabled); 126 ASSERT_FALSE(prefs.accelerated_compositing_enabled); 127 ASSERT_FALSE(prefs.accelerated_2d_canvas_enabled); 128} 129 130// Tests that we can load page actions in the Omnibox. 131IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, PageAction) { 132 ASSERT_TRUE(test_server()->Start()); 133 134 // This page action will not show an icon, since it doesn't specify one but 135 // is included here to test for a crash (http://crbug.com/25562). 136 ASSERT_TRUE(LoadExtension( 137 test_data_dir_.AppendASCII("browsertest") 138 .AppendASCII("crash_25562"))); 139 140 ASSERT_TRUE(LoadExtension( 141 test_data_dir_.AppendASCII("subscribe_page_action"))); 142 143 ASSERT_TRUE(WaitForPageActionVisibilityChangeTo(0)); 144 145 // Navigate to the feed page. 146 GURL feed_url = test_server()->GetURL(kFeedPage); 147 ui_test_utils::NavigateToURL(browser(), feed_url); 148 // We should now have one page action ready to go in the LocationBar. 149 ASSERT_TRUE(WaitForPageActionVisibilityChangeTo(1)); 150 151 // Navigate to a page with no feed. 152 GURL no_feed = test_server()->GetURL(kNoFeedPage); 153 ui_test_utils::NavigateToURL(browser(), no_feed); 154 // Make sure the page action goes away. 155 ASSERT_TRUE(WaitForPageActionVisibilityChangeTo(0)); 156} 157 158// Tests that we don't lose the page action icon on in-page navigations. 159IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, PageActionInPageNavigation) { 160 ASSERT_TRUE(test_server()->Start()); 161 162 FilePath extension_path(test_data_dir_.AppendASCII("api_test") 163 .AppendASCII("page_action") 164 .AppendASCII("hash_change")); 165 ASSERT_TRUE(LoadExtension(extension_path)); 166 167 // Page action should become visible when we navigate here. 168 GURL feed_url = test_server()->GetURL(kHashPageA); 169 ui_test_utils::NavigateToURL(browser(), feed_url); 170 ASSERT_TRUE(WaitForPageActionVisibilityChangeTo(1)); 171 172 // In-page navigation, page action should remain. 173 feed_url = test_server()->GetURL(kHashPageAHash); 174 ui_test_utils::NavigateToURL(browser(), feed_url); 175 ASSERT_TRUE(WaitForPageActionVisibilityChangeTo(1)); 176 177 // Not an in-page navigation, page action should go away. 178 feed_url = test_server()->GetURL(kHashPageB); 179 ui_test_utils::NavigateToURL(browser(), feed_url); 180 ASSERT_TRUE(WaitForPageActionVisibilityChangeTo(0)); 181} 182 183// Tests that the location bar forgets about unloaded page actions. 184IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, UnloadPageAction) { 185 ASSERT_TRUE(test_server()->Start()); 186 187 FilePath extension_path(test_data_dir_.AppendASCII("subscribe_page_action")); 188 ASSERT_TRUE(LoadExtension(extension_path)); 189 190 // Navigation prompts the location bar to load page actions. 191 GURL feed_url = test_server()->GetURL(kFeedPage); 192 ui_test_utils::NavigateToURL(browser(), feed_url); 193 ASSERT_TRUE(WaitForPageActionCountChangeTo(1)); 194 195 UnloadExtension(last_loaded_extension_id_); 196 197 // Make sure the page action goes away when it's unloaded. 198 ASSERT_TRUE(WaitForPageActionCountChangeTo(0)); 199} 200 201// Flaky crash on Mac debug. http://crbug.com/45079 202#if defined(OS_MACOSX) 203#define PageActionRefreshCrash PageActionRefreshCrash 204#endif 205// Tests that we can load page actions in the Omnibox. 206IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, PageActionRefreshCrash) { 207 base::TimeTicks start_time = base::TimeTicks::Now(); 208 209 ExtensionService* service = browser()->profile()->GetExtensionService(); 210 211 size_t size_before = service->extensions()->size(); 212 213 FilePath base_path = test_data_dir_.AppendASCII("browsertest") 214 .AppendASCII("crash_44415"); 215 // Load extension A. 216 ASSERT_TRUE(LoadExtension(base_path.AppendASCII("ExtA"))); 217 ASSERT_TRUE(WaitForPageActionVisibilityChangeTo(1)); 218 ASSERT_EQ(size_before + 1, service->extensions()->size()); 219 const Extension* extensionA = service->extensions()->at(size_before); 220 221 LOG(INFO) << "Load extension A done : " 222 << (base::TimeTicks::Now() - start_time).InMilliseconds() 223 << " ms" << std::flush; 224 225 // Load extension B. 226 ASSERT_TRUE(LoadExtension(base_path.AppendASCII("ExtB"))); 227 ASSERT_TRUE(WaitForPageActionVisibilityChangeTo(2)); 228 ASSERT_EQ(size_before + 2, service->extensions()->size()); 229 const Extension* extensionB = service->extensions()->at(size_before + 1); 230 231 LOG(INFO) << "Load extension B done : " 232 << (base::TimeTicks::Now() - start_time).InMilliseconds() 233 << " ms" << std::flush; 234 235 ReloadExtension(extensionA->id()); 236 // ExtensionA has changed, so refetch it. 237 ASSERT_EQ(size_before + 2, service->extensions()->size()); 238 extensionA = service->extensions()->at(size_before + 1); 239 240 LOG(INFO) << "Reload extension A done: " 241 << (base::TimeTicks::Now() - start_time).InMilliseconds() 242 << " ms" << std::flush; 243 244 ReloadExtension(extensionB->id()); 245 246 LOG(INFO) << "Reload extension B done: " 247 << (base::TimeTicks::Now() - start_time).InMilliseconds() 248 << " ms" << std::flush; 249 250 // This is where it would crash, before http://crbug.com/44415 was fixed. 251 ReloadExtension(extensionA->id()); 252 253 LOG(INFO) << "Test completed : " 254 << (base::TimeTicks::Now() - start_time).InMilliseconds() 255 << " ms" << std::flush; 256} 257 258// Makes sure that the RSS detects RSS feed links, even when rel tag contains 259// more than just "alternate". 260IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, RSSMultiRelLink) { 261 ASSERT_TRUE(test_server()->Start()); 262 263 ASSERT_TRUE(LoadExtension( 264 test_data_dir_.AppendASCII("subscribe_page_action"))); 265 266 ASSERT_TRUE(WaitForPageActionVisibilityChangeTo(0)); 267 268 // Navigate to the feed page. 269 GURL feed_url = test_server()->GetURL(kFeedPageMultiRel); 270 ui_test_utils::NavigateToURL(browser(), feed_url); 271 // We should now have one page action ready to go in the LocationBar. 272 ASSERT_TRUE(WaitForPageActionVisibilityChangeTo(1)); 273} 274 275// Tests that tooltips of a browser action icon can be specified using UTF8. 276// See http://crbug.com/25349. 277IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, TitleLocalizationBrowserAction) { 278 ExtensionService* service = browser()->profile()->GetExtensionService(); 279 const size_t size_before = service->extensions()->size(); 280 FilePath extension_path(test_data_dir_.AppendASCII("browsertest") 281 .AppendASCII("title_localized")); 282 ASSERT_TRUE(LoadExtension(extension_path)); 283 284 ASSERT_EQ(size_before + 1, service->extensions()->size()); 285 const Extension* extension = service->extensions()->at(size_before); 286 287 EXPECT_STREQ(WideToUTF8(L"Hreggvi\u00F0ur: l10n browser action").c_str(), 288 extension->description().c_str()); 289 EXPECT_STREQ(WideToUTF8(L"Hreggvi\u00F0ur is my name").c_str(), 290 extension->name().c_str()); 291 int tab_id = ExtensionTabUtil::GetTabId(browser()->GetSelectedTabContents()); 292 EXPECT_STREQ(WideToUTF8(L"Hreggvi\u00F0ur").c_str(), 293 extension->browser_action()->GetTitle(tab_id).c_str()); 294} 295 296// Tests that tooltips of a page action icon can be specified using UTF8. 297// See http://crbug.com/25349. 298IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, TitleLocalizationPageAction) { 299 ASSERT_TRUE(test_server()->Start()); 300 301 ExtensionService* service = browser()->profile()->GetExtensionService(); 302 const size_t size_before = service->extensions()->size(); 303 304 FilePath extension_path(test_data_dir_.AppendASCII("browsertest") 305 .AppendASCII("title_localized_pa")); 306 ASSERT_TRUE(LoadExtension(extension_path)); 307 308 // Any navigation prompts the location bar to load the page action. 309 GURL url = test_server()->GetURL(kLocalization); 310 ui_test_utils::NavigateToURL(browser(), url); 311 ASSERT_TRUE(WaitForPageActionVisibilityChangeTo(1)); 312 313 ASSERT_EQ(size_before + 1, service->extensions()->size()); 314 const Extension* extension = service->extensions()->at(size_before); 315 316 EXPECT_STREQ(WideToUTF8(L"Hreggvi\u00F0ur: l10n page action").c_str(), 317 extension->description().c_str()); 318 EXPECT_STREQ(WideToUTF8(L"Hreggvi\u00F0ur is my name").c_str(), 319 extension->name().c_str()); 320 int tab_id = ExtensionTabUtil::GetTabId(browser()->GetSelectedTabContents()); 321 EXPECT_STREQ(WideToUTF8(L"Hreggvi\u00F0ur").c_str(), 322 extension->page_action()->GetTitle(tab_id).c_str()); 323} 324 325GURL GetFeedUrl(net::TestServer* server, const std::string& feed_page, 326 bool direct_url, std::string extension_id) { 327 GURL feed_url = server->GetURL(feed_page); 328 if (direct_url) { 329 // We navigate directly to the subscribe page for feeds where the feed 330 // sniffing won't work, in other words, as is the case for malformed feeds. 331 return GURL(std::string(chrome::kExtensionScheme) + 332 chrome::kStandardSchemeSeparator + 333 extension_id + std::string(kSubscribePage) + std::string("?") + 334 feed_url.spec() + std::string("&synchronous")); 335 } else { 336 // Navigate to the feed content (which will cause the extension to try to 337 // sniff the type and display the subscribe page in another tab. 338 return GURL(feed_url.spec()); 339 } 340} 341 342static const wchar_t* jscript_feed_title = 343 L"window.domAutomationController.send(" 344 L" document.getElementById('title') ? " 345 L" document.getElementById('title').textContent : " 346 L" \"element 'title' not found\"" 347 L");"; 348static const wchar_t* jscript_anchor = 349 L"window.domAutomationController.send(" 350 L" document.getElementById('anchor_0') ? " 351 L" document.getElementById('anchor_0').textContent : " 352 L" \"element 'anchor_0' not found\"" 353 L");"; 354static const wchar_t* jscript_desc = 355 L"window.domAutomationController.send(" 356 L" document.getElementById('desc_0') ? " 357 L" document.getElementById('desc_0').textContent : " 358 L" \"element 'desc_0' not found\"" 359 L");"; 360static const wchar_t* jscript_error = 361 L"window.domAutomationController.send(" 362 L" document.getElementById('error') ? " 363 L" document.getElementById('error').textContent : " 364 L" \"No error\"" 365 L");"; 366 367bool ValidatePageElement(TabContents* tab, 368 const std::wstring& frame, 369 const std::wstring& javascript, 370 const std::string& expected_value) { 371 std::string returned_value; 372 std::string error; 373 374 if (!ui_test_utils::ExecuteJavaScriptAndExtractString( 375 tab->render_view_host(), 376 frame, 377 javascript, &returned_value)) 378 return false; 379 380 EXPECT_STREQ(expected_value.c_str(), returned_value.c_str()); 381 return expected_value == returned_value; 382} 383 384// Navigates to a feed page and, if |sniff_xml_type| is set, wait for the 385// extension to kick in, detect the feed and redirect to a feed preview page. 386// |sniff_xml_type| is generally set to true if the feed is sniffable and false 387// for invalid feeds. 388void NavigateToFeedAndValidate(net::TestServer* server, 389 const std::string& url, 390 Browser* browser, 391 bool sniff_xml_type, 392 const std::string& expected_feed_title, 393 const std::string& expected_item_title, 394 const std::string& expected_item_desc, 395 const std::string& expected_error) { 396 if (sniff_xml_type) { 397 // TODO(finnur): Implement this is a non-flaky way. 398 } 399 400 ExtensionService* service = browser->profile()->GetExtensionService(); 401 const Extension* extension = service->extensions()->back(); 402 std::string id = extension->id(); 403 404 // Navigate to the subscribe page directly. 405 ui_test_utils::NavigateToURL(browser, GetFeedUrl(server, url, true, id)); 406 407 TabContents* tab = browser->GetSelectedTabContents(); 408 ASSERT_TRUE(ValidatePageElement(tab, 409 L"", 410 jscript_feed_title, 411 expected_feed_title)); 412 ASSERT_TRUE(ValidatePageElement(tab, 413 L"//html/body/div/iframe[1]", 414 jscript_anchor, 415 expected_item_title)); 416 ASSERT_TRUE(ValidatePageElement(tab, 417 L"//html/body/div/iframe[1]", 418 jscript_desc, 419 expected_item_desc)); 420 ASSERT_TRUE(ValidatePageElement(tab, 421 L"//html/body/div/iframe[1]", 422 jscript_error, 423 expected_error)); 424} 425 426IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, ParseFeedValidFeed1) { 427 ASSERT_TRUE(test_server()->Start()); 428 429 ASSERT_TRUE(LoadExtension( 430 test_data_dir_.AppendASCII("subscribe_page_action"))); 431 432 NavigateToFeedAndValidate(test_server(), kValidFeed1, browser(), true, 433 "Feed for MyFeedTitle", 434 "Title 1", 435 "Desc", 436 "No error"); 437} 438 439IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, ParseFeedValidFeed2) { 440 ASSERT_TRUE(test_server()->Start()); 441 442 ASSERT_TRUE(LoadExtension( 443 test_data_dir_.AppendASCII("subscribe_page_action"))); 444 445 NavigateToFeedAndValidate(test_server(), kValidFeed2, browser(), true, 446 "Feed for MyFeed2", 447 "My item title1", 448 "This is a summary.", 449 "No error"); 450} 451 452IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, ParseFeedValidFeed3) { 453 ASSERT_TRUE(test_server()->Start()); 454 455 ASSERT_TRUE(LoadExtension( 456 test_data_dir_.AppendASCII("subscribe_page_action"))); 457 458 NavigateToFeedAndValidate(test_server(), kValidFeed3, browser(), true, 459 "Feed for Google Code buglist rss feed", 460 "My dear title", 461 "My dear content", 462 "No error"); 463} 464 465IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, ParseFeedValidFeed4) { 466 ASSERT_TRUE(test_server()->Start()); 467 468 ASSERT_TRUE(LoadExtension( 469 test_data_dir_.AppendASCII("subscribe_page_action"))); 470 471 NavigateToFeedAndValidate(test_server(), kValidFeed4, browser(), true, 472 "Feed for Title chars <script> %23 stop", 473 "Title chars %23 stop", 474 "My dear content %23 stop", 475 "No error"); 476} 477 478IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, ParseFeedValidFeed0) { 479 ASSERT_TRUE(test_server()->Start()); 480 481 ASSERT_TRUE(LoadExtension( 482 test_data_dir_.AppendASCII("subscribe_page_action"))); 483 484 // Try a feed with a link with an onclick handler (before r27440 this would 485 // trigger a NOTREACHED). 486 NavigateToFeedAndValidate(test_server(), kValidFeed0, browser(), true, 487 "Feed for MyFeedTitle", 488 "Title 1", 489 "Desc VIDEO", 490 "No error"); 491} 492 493IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, ParseFeedValidFeed5) { 494 ASSERT_TRUE(test_server()->Start()); 495 496 ASSERT_TRUE(LoadExtension( 497 test_data_dir_.AppendASCII("subscribe_page_action"))); 498 499 // Feed with valid but mostly empty xml. 500 NavigateToFeedAndValidate(test_server(), kValidFeed5, browser(), true, 501 "Feed for Unknown feed name", 502 "element 'anchor_0' not found", 503 "element 'desc_0' not found", 504 "This feed contains no entries."); 505} 506 507IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, ParseFeedValidFeed6) { 508 ASSERT_TRUE(test_server()->Start()); 509 510 ASSERT_TRUE(LoadExtension( 511 test_data_dir_.AppendASCII("subscribe_page_action"))); 512 513 // Feed that is technically invalid but still parseable. 514 NavigateToFeedAndValidate(test_server(), kValidFeed6, browser(), true, 515 "Feed for MyFeedTitle", 516 "Title 1", 517 "Desc", 518 "No error"); 519} 520 521IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, ParseFeedInvalidFeed1) { 522 ASSERT_TRUE(test_server()->Start()); 523 524 ASSERT_TRUE(LoadExtension( 525 test_data_dir_.AppendASCII("subscribe_page_action"))); 526 527 // Try an empty feed. 528 NavigateToFeedAndValidate(test_server(), kInvalidFeed1, browser(), false, 529 "Feed for Unknown feed name", 530 "element 'anchor_0' not found", 531 "element 'desc_0' not found", 532 "This feed contains no entries."); 533} 534 535IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, ParseFeedInvalidFeed2) { 536 ASSERT_TRUE(test_server()->Start()); 537 538 ASSERT_TRUE(LoadExtension( 539 test_data_dir_.AppendASCII("subscribe_page_action"))); 540 541 // Try a garbage feed. 542 NavigateToFeedAndValidate(test_server(), kInvalidFeed2, browser(), false, 543 "Feed for Unknown feed name", 544 "element 'anchor_0' not found", 545 "element 'desc_0' not found", 546 "This feed contains no entries."); 547} 548 549IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, ParseFeedInvalidFeed3) { 550 ASSERT_TRUE(test_server()->Start()); 551 552 ASSERT_TRUE(LoadExtension( 553 test_data_dir_.AppendASCII("subscribe_page_action"))); 554 555 // Try a feed that doesn't exist. 556 NavigateToFeedAndValidate(test_server(), "foo.xml", browser(), false, 557 "Feed for Unknown feed name", 558 "element 'anchor_0' not found", 559 "element 'desc_0' not found", 560 "This feed contains no entries."); 561} 562 563IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, ParseFeedInvalidFeed4) { 564 ASSERT_TRUE(test_server()->Start()); 565 566 ASSERT_TRUE(LoadExtension( 567 test_data_dir_.AppendASCII("subscribe_page_action"))); 568 569 // subscribe.js shouldn't double-decode the URL passed in. Otherwise feed 570 // links such as http://search.twitter.com/search.atom?lang=en&q=%23chrome 571 // will result in no feed being downloaded because %23 gets decoded to # and 572 // therefore #chrome is not treated as part of the Twitter query. This test 573 // uses an underscore instead of a hash, but the principle is the same. If 574 // we start erroneously double decoding again, the path (and the feed) will 575 // become valid resulting in a failure for this test. 576 NavigateToFeedAndValidate(test_server(), kFeedTripleEncoded, browser(), true, 577 "Feed for Unknown feed name", 578 "element 'anchor_0' not found", 579 "element 'desc_0' not found", 580 "This feed contains no entries."); 581} 582 583IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, ParseFeedValidFeedNoLinks) { 584 ASSERT_TRUE(test_server()->Start()); 585 586 ASSERT_TRUE(LoadExtension( 587 test_data_dir_.AppendASCII("subscribe_page_action"))); 588 589 // Valid feed but containing no links. 590 NavigateToFeedAndValidate(test_server(), kValidFeedNoLinks, browser(), true, 591 "Feed for MyFeedTitle", 592 "Title with no link", 593 "Desc", 594 "No error"); 595} 596 597// Tests that an error raised during an async function still fires 598// the callback, but sets chrome.extension.lastError. 599IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, LastError) { 600 ASSERT_TRUE(LoadExtension( 601 test_data_dir_.AppendASCII("browsertest").AppendASCII("last_error"))); 602 603 // Get the ExtensionHost that is hosting our toolstrip page. 604 ExtensionProcessManager* manager = 605 browser()->profile()->GetExtensionProcessManager(); 606 ExtensionHost* host = FindHostWithPath(manager, "/bg.html", 1); 607 608 bool result = false; 609 ASSERT_TRUE(ui_test_utils::ExecuteJavaScriptAndExtractBool( 610 host->render_view_host(), L"", L"testLastError()", &result)); 611 EXPECT_TRUE(result); 612} 613 614// Helper function for common code shared by the 3 WindowOpen tests below. 615static void WindowOpenHelper(Browser* browser, const GURL& start_url, 616 const std::string& newtab_url, 617 TabContents** newtab_result) { 618 ui_test_utils::NavigateToURL(browser, start_url); 619 620 ASSERT_TRUE(ui_test_utils::ExecuteJavaScript( 621 browser->GetSelectedTabContents()->render_view_host(), L"", 622 L"window.open('" + UTF8ToWide(newtab_url) + L"');")); 623 624 // Now the active tab in last active window should be the new tab. 625 Browser* last_active_browser = BrowserList::GetLastActive(); 626 EXPECT_TRUE(last_active_browser); 627 TabContents* newtab = last_active_browser->GetSelectedTabContents(); 628 EXPECT_TRUE(newtab); 629 GURL expected_url = start_url.Resolve(newtab_url); 630 if (!newtab->controller().GetLastCommittedEntry() || 631 newtab->controller().GetLastCommittedEntry()->url() != expected_url) 632 ui_test_utils::WaitForNavigation(&newtab->controller()); 633 EXPECT_EQ(expected_url, 634 newtab->controller().GetLastCommittedEntry()->url()); 635 if (newtab_result) 636 *newtab_result = newtab; 637} 638 639// Tests that an extension page can call window.open to an extension URL and 640// the new window has extension privileges. 641IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, WindowOpenExtension) { 642 ASSERT_TRUE(LoadExtension( 643 test_data_dir_.AppendASCII("uitest").AppendASCII("window_open"))); 644 645 TabContents* newtab; 646 ASSERT_NO_FATAL_FAILURE(WindowOpenHelper( 647 browser(), 648 GURL(std::string("chrome-extension://") + last_loaded_extension_id_ + 649 "/test.html"), 650 "newtab.html", &newtab)); 651 652 bool result = false; 653 ASSERT_TRUE(ui_test_utils::ExecuteJavaScriptAndExtractBool( 654 newtab->render_view_host(), L"", L"testExtensionApi()", &result)); 655 EXPECT_TRUE(result); 656} 657 658// Tests that if an extension page calls window.open to an invalid extension 659// URL, the browser doesn't crash. 660IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, WindowOpenInvalidExtension) { 661 ASSERT_TRUE(LoadExtension( 662 test_data_dir_.AppendASCII("uitest").AppendASCII("window_open"))); 663 664 ASSERT_NO_FATAL_FAILURE(WindowOpenHelper( 665 browser(), 666 GURL(std::string("chrome-extension://") + last_loaded_extension_id_ + 667 "/test.html"), 668 "chrome-extension://thisissurelynotavalidextensionid/newtab.html", NULL)); 669 670 // If we got to this point, we didn't crash, so we're good. 671} 672 673// Tests that calling window.open from the newtab page to an extension URL 674// gives the new window extension privileges - even though the opening page 675// does not have extension privileges, we break the script connection, so 676// there is no privilege leak. 677IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, WindowOpenNoPrivileges) { 678 ASSERT_TRUE(LoadExtension( 679 test_data_dir_.AppendASCII("uitest").AppendASCII("window_open"))); 680 681 TabContents* newtab; 682 ASSERT_NO_FATAL_FAILURE(WindowOpenHelper( 683 browser(), 684 GURL("about:blank"), 685 std::string("chrome-extension://") + last_loaded_extension_id_ + 686 "/newtab.html", 687 &newtab)); 688 689 // Extension API should succeed. 690 bool result = false; 691 ASSERT_TRUE(ui_test_utils::ExecuteJavaScriptAndExtractBool( 692 newtab->render_view_host(), L"", L"testExtensionApi()", &result)); 693 EXPECT_TRUE(result); 694} 695 696#if defined(OS_WIN) 697#define MAYBE_PluginLoadUnload PluginLoadUnload 698#elif defined(OS_LINUX) 699// http://crbug.com/47598 700#define MAYBE_PluginLoadUnload DISABLED_PluginLoadUnload 701#else 702// TODO(mpcomplete): http://crbug.com/29900 need cross platform plugin support. 703#define MAYBE_PluginLoadUnload DISABLED_PluginLoadUnload 704#endif 705 706// Tests that a renderer's plugin list is properly updated when we load and 707// unload an extension that contains a plugin. 708IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, MAYBE_PluginLoadUnload) { 709 FilePath extension_dir = 710 test_data_dir_.AppendASCII("uitest").AppendASCII("plugins"); 711 712 ui_test_utils::NavigateToURL(browser(), 713 net::FilePathToFileURL(extension_dir.AppendASCII("test.html"))); 714 TabContents* tab = browser()->GetSelectedTabContents(); 715 716 // With no extensions, the plugin should not be loaded. 717 bool result = false; 718 ASSERT_TRUE(ui_test_utils::ExecuteJavaScriptAndExtractBool( 719 tab->render_view_host(), L"", L"testPluginWorks()", &result)); 720 EXPECT_FALSE(result); 721 722 ExtensionService* service = browser()->profile()->GetExtensionService(); 723 const size_t size_before = service->extensions()->size(); 724 ASSERT_TRUE(LoadExtension(extension_dir)); 725 EXPECT_EQ(size_before + 1, service->extensions()->size()); 726 // Now the plugin should be in the cache, but we have to reload the page for 727 // it to work. 728 ASSERT_TRUE(ui_test_utils::ExecuteJavaScriptAndExtractBool( 729 tab->render_view_host(), L"", L"testPluginWorks()", &result)); 730 EXPECT_FALSE(result); 731 browser()->Reload(CURRENT_TAB); 732 ui_test_utils::WaitForNavigationInCurrentTab(browser()); 733 ASSERT_TRUE(ui_test_utils::ExecuteJavaScriptAndExtractBool( 734 tab->render_view_host(), L"", L"testPluginWorks()", &result)); 735 EXPECT_TRUE(result); 736 737 EXPECT_EQ(size_before + 1, service->extensions()->size()); 738 UnloadExtension(service->extensions()->at(size_before)->id()); 739 EXPECT_EQ(size_before, service->extensions()->size()); 740 741 // Now the plugin should be unloaded, and the page should be broken. 742 743 ASSERT_TRUE(ui_test_utils::ExecuteJavaScriptAndExtractBool( 744 tab->render_view_host(), L"", L"testPluginWorks()", &result)); 745 EXPECT_FALSE(result); 746 747 // If we reload the extension and page, it should work again. 748 749 ASSERT_TRUE(LoadExtension(extension_dir)); 750 EXPECT_EQ(size_before + 1, service->extensions()->size()); 751 browser()->Reload(CURRENT_TAB); 752 ui_test_utils::WaitForNavigationInCurrentTab(browser()); 753 ASSERT_TRUE(ui_test_utils::ExecuteJavaScriptAndExtractBool( 754 tab->render_view_host(), L"", L"testPluginWorks()", &result)); 755 EXPECT_TRUE(result); 756} 757 758#if defined(OS_CHROMEOS) 759// ChromeOS doesn't support NPAPI. 760#define MAYBE_PluginPrivate DISABLED_PluginPrivate 761#elif defined(OS_WIN) || defined(OS_LINUX) 762#define MAYBE_PluginPrivate PluginPrivate 763#else 764// TODO(mpcomplete): http://crbug.com/29900 need cross platform plugin support. 765#define MAYBE_PluginPrivate DISABLED_PluginPrivate 766#endif 767 768// Tests that private extension plugins are only visible to the extension. 769IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, MAYBE_PluginPrivate) { 770 FilePath extension_dir = 771 test_data_dir_.AppendASCII("uitest").AppendASCII("plugins_private"); 772 773 ExtensionService* service = browser()->profile()->GetExtensionService(); 774 const size_t size_before = service->extensions()->size(); 775 ASSERT_TRUE(LoadExtension(extension_dir)); 776 EXPECT_EQ(size_before + 1, service->extensions()->size()); 777 778 // Load the test page through the extension URL, and the plugin should work. 779 const Extension* extension = service->extensions()->back(); 780 ui_test_utils::NavigateToURL(browser(), 781 extension->GetResourceURL("test.html")); 782 TabContents* tab = browser()->GetSelectedTabContents(); 783 bool result = false; 784 ASSERT_TRUE(ui_test_utils::ExecuteJavaScriptAndExtractBool( 785 tab->render_view_host(), L"", L"testPluginWorks()", &result)); 786 EXPECT_TRUE(result); 787 788 // Now load it through a file URL. The plugin should not load. 789 ui_test_utils::NavigateToURL(browser(), 790 net::FilePathToFileURL(extension_dir.AppendASCII("test.html"))); 791 ASSERT_TRUE(ui_test_utils::ExecuteJavaScriptAndExtractBool( 792 tab->render_view_host(), L"", L"testPluginWorks()", &result)); 793 EXPECT_FALSE(result); 794} 795 796// Used to simulate a click on the first button named 'Options'. 797static const wchar_t* jscript_click_option_button = 798 L"(function() { " 799 L" var button = document.evaluate(\"//button[text()='Options']\"," 800 L" document, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE," 801 L" null).snapshotItem(0);" 802 L" button.click();" 803 L"})();"; 804 805// Test that an extension with an options page makes an 'Options' button appear 806// on chrome://extensions, and that clicking the button opens a new tab with the 807// extension's options page. 808// Disabled. See http://crbug.com/26948 for details. 809IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, DISABLED_OptionsPage) { 810 // Install an extension with an options page. 811 ASSERT_TRUE(InstallExtension(test_data_dir_.AppendASCII("options.crx"), 1)); 812 ExtensionService* service = browser()->profile()->GetExtensionService(); 813 const ExtensionList* extensions = service->extensions(); 814 ASSERT_EQ(1u, extensions->size()); 815 const Extension* extension = extensions->at(0); 816 817 // Go to the chrome://extensions page and click the Options button. 818 ui_test_utils::NavigateToURL(browser(), GURL(chrome::kChromeUIExtensionsURL)); 819 TabStripModel* tab_strip = browser()->tabstrip_model(); 820 ASSERT_TRUE(ui_test_utils::ExecuteJavaScript( 821 browser()->GetSelectedTabContents()->render_view_host(), L"", 822 jscript_click_option_button)); 823 824 // If the options page hasn't already come up, wait for it. 825 if (tab_strip->count() == 1) { 826 ui_test_utils::WaitForNewTab(browser()); 827 } 828 ASSERT_EQ(2, tab_strip->count()); 829 830 EXPECT_EQ(extension->GetResourceURL("options.html"), 831 tab_strip->GetTabContentsAt(1)->tab_contents()->GetURL()); 832} 833 834// Test window.chrome.app.isInstalled . 835IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, PropertyAppIsInstalled) { 836 std::string app_host("app.com"); 837 std::string nonapp_host("nonapp.com"); 838 839 host_resolver()->AddRule(app_host, "127.0.0.1"); 840 host_resolver()->AddRule(nonapp_host, "127.0.0.1"); 841 ASSERT_TRUE(test_server()->Start()); 842 843 GURL test_file_url(test_server()->GetURL("extensions/test_file.html")); 844 GURL::Replacements replace_host; 845 846 replace_host.SetHostStr(app_host); 847 GURL app_url(test_file_url.ReplaceComponents(replace_host)); 848 849 replace_host.SetHostStr(nonapp_host); 850 GURL non_app_url(test_file_url.ReplaceComponents(replace_host)); 851 852 853 // Load an app which includes app.com in its extent. 854 ASSERT_TRUE(LoadExtension( 855 test_data_dir_.AppendASCII("app_dot_com_app"))); 856 857 858 // Test that a non-app page has chrome.app.isInstalled = false. 859 ui_test_utils::NavigateToURL(browser(), non_app_url); 860 std::wstring get_app_is_installed = 861 L"window.domAutomationController.send(" 862 L" JSON.stringify(window.chrome.app.isInstalled));"; 863 std::string result; 864 ASSERT_TRUE( 865 ui_test_utils::ExecuteJavaScriptAndExtractString( 866 browser()->GetSelectedTabContents()->render_view_host(), 867 L"", 868 get_app_is_installed.c_str(), 869 &result)); 870 EXPECT_EQ("false", result); 871 872 873 // Check that an app page has chrome.app.isInstalled = true. 874 ui_test_utils::NavigateToURL(browser(), app_url); 875 ASSERT_TRUE( 876 ui_test_utils::ExecuteJavaScriptAndExtractString( 877 browser()->GetSelectedTabContents()->render_view_host(), 878 L"", 879 get_app_is_installed.c_str(), 880 &result)); 881 EXPECT_EQ("true", result); 882 883 884 // Test that trying to set window.chrome.app.isInstalled throws 885 // an exception. 886 ASSERT_TRUE(ui_test_utils::ExecuteJavaScriptAndExtractString( 887 browser()->GetSelectedTabContents()->render_view_host(), 888 L"", 889 L"window.domAutomationController.send(" 890 L" function() {" 891 L" try {" 892 L" window.chrome.app.isInstalled = false;" 893 L" return 'BAD: Should have thrown by now...';" 894 L" } catch (e) {" 895 L" return 'GOOD: Saw expected error.';" 896 L" }" 897 L" }()" 898 L");", 899 &result)); 900 EXPECT_EQ("GOOD: Saw expected error.", result); 901} 902