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. 4 5 #include "base/strings/utf_string_conversions.h" 6 #include "chrome/app/chrome_command_ids.h" 7 #include "chrome/browser/extensions/extension_browsertest.h" 8 #include "chrome/browser/extensions/extension_service.h" 9 #include "chrome/browser/extensions/extension_system.h" 10 #include "chrome/browser/extensions/extension_test_message_listener.h" 11 #include "chrome/browser/extensions/lazy_background_page_test_util.h" 12 #include "chrome/browser/extensions/test_management_policy.h" 13 #include "chrome/browser/profiles/profile.h" 14 #include "chrome/browser/tab_contents/render_view_context_menu.h" 15 #include "chrome/browser/ui/browser.h" 16 #include "chrome/browser/ui/tabs/tab_strip_model.h" 17 #include "chrome/common/chrome_switches.h" 18 #include "chrome/test/base/ui_test_utils.h" 19 #include "content/public/common/context_menu_params.h" 20 #include "net/dns/mock_host_resolver.h" 21 #include "ui/base/models/menu_model.h" 22 23 using content::WebContents; 24 using extensions::MenuItem; 25 using ui::MenuModel; 26 27 namespace { 28 // This test class helps us sidestep platform-specific issues with popping up a 29 // real context menu, while still running through the actual code in 30 // RenderViewContextMenu where extension items get added and executed. 31 class TestRenderViewContextMenu : public RenderViewContextMenu { 32 public: 33 TestRenderViewContextMenu(WebContents* web_contents, 34 const content::ContextMenuParams& params) 35 : RenderViewContextMenu(web_contents, params) {} 36 37 virtual ~TestRenderViewContextMenu() {} 38 39 // Searches for an menu item with |command_id|. If it's found, the return 40 // value is true and the model and index where it appears in that model are 41 // returned in |found_model| and |found_index|. Otherwise returns false. 42 bool GetMenuModelAndItemIndex(int command_id, 43 MenuModel** found_model, 44 int *found_index) { 45 std::vector<MenuModel*> models_to_search; 46 models_to_search.push_back(&menu_model_); 47 48 while (!models_to_search.empty()) { 49 MenuModel* model = models_to_search.back(); 50 models_to_search.pop_back(); 51 for (int i = 0; i < model->GetItemCount(); i++) { 52 if (model->GetCommandIdAt(i) == command_id) { 53 *found_model = model; 54 *found_index = i; 55 return true; 56 } else if (model->GetTypeAt(i) == MenuModel::TYPE_SUBMENU) { 57 models_to_search.push_back(model->GetSubmenuModelAt(i)); 58 } 59 } 60 } 61 62 return false; 63 } 64 65 extensions::ContextMenuMatcher& extension_items() { 66 return extension_items_; 67 } 68 69 protected: 70 // These two functions implement pure virtual methods of 71 // RenderViewContextMenu. 72 virtual bool GetAcceleratorForCommandId( 73 int command_id, 74 ui::Accelerator* accelerator) OVERRIDE { 75 // None of our commands have accelerators, so always return false. 76 return false; 77 } 78 virtual void PlatformInit() OVERRIDE {} 79 virtual void PlatformCancel() OVERRIDE {} 80 }; 81 82 } // namespace 83 84 class ExtensionContextMenuBrowserTest : public ExtensionBrowserTest { 85 public: 86 // Helper to load an extension from context_menus/|subdirectory| in the 87 // extensions test data dir. 88 const extensions::Extension* LoadContextMenuExtension( 89 std::string subdirectory) { 90 base::FilePath extension_dir = 91 test_data_dir_.AppendASCII("context_menus").AppendASCII(subdirectory); 92 return LoadExtension(extension_dir); 93 } 94 95 // Helper to load an extension from context_menus/top_level/|subdirectory| in 96 // the extensions test data dir. 97 const extensions::Extension* LoadTopLevelContextMenuExtension( 98 std::string subdirectory) { 99 base::FilePath extension_dir = 100 test_data_dir_.AppendASCII("context_menus").AppendASCII("top_level"); 101 extension_dir = extension_dir.AppendASCII(subdirectory); 102 return LoadExtension(extension_dir); 103 } 104 105 const extensions::Extension* LoadContextMenuExtensionIncognito( 106 std::string subdirectory) { 107 base::FilePath extension_dir = 108 test_data_dir_.AppendASCII("context_menus").AppendASCII(subdirectory); 109 return LoadExtensionIncognito(extension_dir); 110 } 111 112 TestRenderViewContextMenu* CreateMenu(Browser* browser, 113 const GURL& page_url, 114 const GURL& link_url, 115 const GURL& frame_url) { 116 WebContents* web_contents = 117 browser->tab_strip_model()->GetActiveWebContents(); 118 content::ContextMenuParams params; 119 params.page_url = page_url; 120 params.link_url = link_url; 121 params.frame_url = frame_url; 122 TestRenderViewContextMenu* menu = 123 new TestRenderViewContextMenu(web_contents, params); 124 menu->Init(); 125 return menu; 126 } 127 128 // Shortcut to return the current MenuManager. 129 extensions::MenuManager* menu_manager() { 130 return browser()->profile()->GetExtensionService()->menu_manager(); 131 } 132 133 // Returns a pointer to the currently loaded extension with |name|, or null 134 // if not found. 135 const extensions::Extension* GetExtensionNamed(std::string name) { 136 const ExtensionSet* extensions = 137 browser()->profile()->GetExtensionService()->extensions(); 138 ExtensionSet::const_iterator i; 139 for (i = extensions->begin(); i != extensions->end(); ++i) { 140 if ((*i)->name() == name) { 141 return i->get(); 142 } 143 } 144 return NULL; 145 } 146 147 // This gets all the items that any extension has registered for possible 148 // inclusion in context menus. 149 MenuItem::List GetItems() { 150 MenuItem::List result; 151 std::set<std::string> extension_ids = menu_manager()->ExtensionIds(); 152 std::set<std::string>::iterator i; 153 for (i = extension_ids.begin(); i != extension_ids.end(); ++i) { 154 const MenuItem::List* list = menu_manager()->MenuItems(*i); 155 result.insert(result.end(), list->begin(), list->end()); 156 } 157 return result; 158 } 159 160 // This creates a test menu for a page with |page_url| and |link_url|, looks 161 // for an extension item with the given |label|, and returns true if the item 162 // was found. 163 bool MenuHasItemWithLabel(const GURL& page_url, 164 const GURL& link_url, 165 const GURL& frame_url, 166 const std::string& label) { 167 scoped_ptr<TestRenderViewContextMenu> menu( 168 CreateMenu(browser(), page_url, link_url, frame_url)); 169 return MenuHasExtensionItemWithLabel(menu.get(), label); 170 } 171 172 // This creates an extension that starts |enabled| and then switches to 173 // |!enabled|. 174 void TestEnabledContextMenu(bool enabled) { 175 ExtensionTestMessageListener begin("begin", true); 176 ExtensionTestMessageListener create("create", true); 177 ExtensionTestMessageListener update("update", false); 178 ASSERT_TRUE(LoadContextMenuExtension("enabled")); 179 180 ASSERT_TRUE(begin.WaitUntilSatisfied()); 181 182 if (enabled) 183 begin.Reply("start enabled"); 184 else 185 begin.Reply("start disabled"); 186 187 // Wait for the extension to tell us it's created an item. 188 ASSERT_TRUE(create.WaitUntilSatisfied()); 189 create.Reply("go"); 190 191 GURL page_url("http://www.google.com"); 192 193 // Create and build our test context menu. 194 scoped_ptr<TestRenderViewContextMenu> menu( 195 CreateMenu(browser(), page_url, GURL(), GURL())); 196 197 // Look for the extension item in the menu, and make sure it's |enabled|. 198 int command_id = IDC_EXTENSIONS_CONTEXT_CUSTOM_FIRST; 199 ASSERT_EQ(enabled, menu->IsCommandIdEnabled(command_id)); 200 201 // Update the item and make sure it is now |!enabled|. 202 ASSERT_TRUE(update.WaitUntilSatisfied()); 203 ASSERT_EQ(!enabled, menu->IsCommandIdEnabled(command_id)); 204 } 205 206 bool MenuHasExtensionItemWithLabel(TestRenderViewContextMenu* menu, 207 const std::string& label) { 208 string16 label16 = UTF8ToUTF16(label); 209 std::map<int, MenuItem::Id>::iterator i; 210 for (i = menu->extension_items().extension_item_map_.begin(); 211 i != menu->extension_items().extension_item_map_.end(); ++i) { 212 const MenuItem::Id& id = i->second; 213 string16 tmp_label; 214 EXPECT_TRUE(GetItemLabel(menu, id, &tmp_label)); 215 if (tmp_label == label16) 216 return true; 217 } 218 return false; 219 } 220 221 // Looks in the menu for an extension item with |id|, and if it is found and 222 // has a label, that is put in |result| and we return true. Otherwise returns 223 // false. 224 bool GetItemLabel(TestRenderViewContextMenu* menu, 225 const MenuItem::Id& id, 226 string16* result) { 227 int command_id = 0; 228 if (!FindCommandId(menu, id, &command_id)) 229 return false; 230 231 MenuModel* model = NULL; 232 int index = -1; 233 if (!menu->GetMenuModelAndItemIndex(command_id, &model, &index)) { 234 return false; 235 } 236 *result = model->GetLabelAt(index); 237 return true; 238 } 239 240 // Given an extension menu item id, tries to find the corresponding command id 241 // in the menu. 242 bool FindCommandId(TestRenderViewContextMenu* menu, 243 const MenuItem::Id& id, 244 int* command_id) { 245 std::map<int, MenuItem::Id>::const_iterator i; 246 for (i = menu->extension_items().extension_item_map_.begin(); 247 i != menu->extension_items().extension_item_map_.end(); ++i) { 248 if (i->second == id) { 249 *command_id = i->first; 250 return true; 251 } 252 } 253 return false; 254 } 255 }; 256 257 // Tests adding a simple context menu item. 258 IN_PROC_BROWSER_TEST_F(ExtensionContextMenuBrowserTest, Simple) { 259 ExtensionTestMessageListener listener1("created item", false); 260 ExtensionTestMessageListener listener2("onclick fired", false); 261 ASSERT_TRUE(LoadContextMenuExtension("simple")); 262 263 // Wait for the extension to tell us it's created an item. 264 ASSERT_TRUE(listener1.WaitUntilSatisfied()); 265 266 GURL page_url("http://www.google.com"); 267 268 // Create and build our test context menu. 269 scoped_ptr<TestRenderViewContextMenu> menu( 270 CreateMenu(browser(), page_url, GURL(), GURL())); 271 272 // Look for the extension item in the menu, and execute it. 273 int command_id = IDC_EXTENSIONS_CONTEXT_CUSTOM_FIRST; 274 ASSERT_TRUE(menu->IsCommandIdEnabled(command_id)); 275 menu->ExecuteCommand(command_id, 0); 276 277 // Wait for the extension's script to tell us its onclick fired. 278 ASSERT_TRUE(listener2.WaitUntilSatisfied()); 279 } 280 281 // Tests that setting "documentUrlPatterns" for an item properly restricts 282 // those items to matching pages. 283 IN_PROC_BROWSER_TEST_F(ExtensionContextMenuBrowserTest, Patterns) { 284 ExtensionTestMessageListener listener("created items", false); 285 286 ASSERT_TRUE(LoadContextMenuExtension("patterns")); 287 288 // Wait for the js test code to create its two items with patterns. 289 ASSERT_TRUE(listener.WaitUntilSatisfied()); 290 291 // Check that a document url that should match the items' patterns appears. 292 GURL google_url("http://www.google.com"); 293 ASSERT_TRUE(MenuHasItemWithLabel(google_url, 294 GURL(), 295 GURL(), 296 std::string("test_item1"))); 297 ASSERT_TRUE(MenuHasItemWithLabel(google_url, 298 GURL(), 299 GURL(), 300 std::string("test_item2"))); 301 302 // Now check with a non-matching url. 303 GURL test_url("http://www.test.com"); 304 ASSERT_FALSE(MenuHasItemWithLabel(test_url, 305 GURL(), 306 GURL(), 307 std::string("test_item1"))); 308 ASSERT_FALSE(MenuHasItemWithLabel(test_url, 309 GURL(), 310 GURL(), 311 std::string("test_item2"))); 312 } 313 314 // Tests registering an item with a very long title that should get truncated in 315 // the actual menu displayed. 316 IN_PROC_BROWSER_TEST_F(ExtensionContextMenuBrowserTest, LongTitle) { 317 ExtensionTestMessageListener listener("created", false); 318 319 // Load the extension and wait until it's created a menu item. 320 ASSERT_TRUE(LoadContextMenuExtension("long_title")); 321 ASSERT_TRUE(listener.WaitUntilSatisfied()); 322 323 // Make sure we have an item registered with a long title. 324 size_t limit = extensions::ContextMenuMatcher::kMaxExtensionItemTitleLength; 325 MenuItem::List items = GetItems(); 326 ASSERT_EQ(1u, items.size()); 327 MenuItem* item = items.at(0); 328 ASSERT_GT(item->title().size(), limit); 329 330 // Create a context menu, then find the item's label. It should be properly 331 // truncated. 332 GURL url("http://foo.com/"); 333 scoped_ptr<TestRenderViewContextMenu> menu( 334 CreateMenu(browser(), url, GURL(), GURL())); 335 336 string16 label; 337 ASSERT_TRUE(GetItemLabel(menu.get(), item->id(), &label)); 338 ASSERT_TRUE(label.size() <= limit); 339 } 340 341 // Flaky on Windows debug bots. http://crbug.com/251590 342 #if defined(OS_WIN) 343 #define MAYBE_TopLevel DISABLED_TopLevel 344 #else 345 #define MAYBE_TopLevel TopLevel 346 #endif 347 // Checks that Context Menus are ordered alphabetically by their name when 348 // extensions have only one single Context Menu item and by the extension name 349 // when multiples Context Menu items are created. 350 IN_PROC_BROWSER_TEST_F(ExtensionContextMenuBrowserTest, MAYBE_TopLevel) { 351 // We expect to see the following items in the menu: 352 // An Extension with multiple Context Menus 353 // Context Menu #1 354 // Context Menu #2 355 // Context Menu #1 - Extension #2 356 // Context Menu #2 - Extension #3 357 // Context Menu #3 - Extension #1 358 // Ze Extension with multiple Context Menus 359 // Context Menu #1 360 // Context Menu #2 361 362 // Load extensions and wait until it's created a single menu item. 363 ExtensionTestMessageListener listener1("created item", false); 364 ASSERT_TRUE(LoadTopLevelContextMenuExtension("single1")); 365 ASSERT_TRUE(listener1.WaitUntilSatisfied()); 366 367 ExtensionTestMessageListener listener2("created item", false); 368 ASSERT_TRUE(LoadTopLevelContextMenuExtension("single2")); 369 ASSERT_TRUE(listener2.WaitUntilSatisfied()); 370 371 ExtensionTestMessageListener listener3("created item", false); 372 ASSERT_TRUE(LoadTopLevelContextMenuExtension("single3")); 373 ASSERT_TRUE(listener3.WaitUntilSatisfied()); 374 375 // Load extensions and wait until it's created two menu items. 376 ExtensionTestMessageListener listener4("created items", false); 377 ASSERT_TRUE(LoadTopLevelContextMenuExtension("multi4")); 378 ASSERT_TRUE(listener4.WaitUntilSatisfied()); 379 380 ExtensionTestMessageListener listener5("created items", false); 381 ASSERT_TRUE(LoadTopLevelContextMenuExtension("multi5")); 382 ASSERT_TRUE(listener5.WaitUntilSatisfied()); 383 384 GURL url("http://foo.com/"); 385 scoped_ptr<TestRenderViewContextMenu> menu( 386 CreateMenu(browser(), url, GURL(), GURL())); 387 388 int index = 0; 389 MenuModel* model = NULL; 390 391 ASSERT_TRUE(menu->GetMenuModelAndItemIndex( 392 IDC_EXTENSIONS_CONTEXT_CUSTOM_FIRST, &model, &index)); 393 EXPECT_EQ(UTF8ToUTF16("An Extension with multiple Context Menus"), 394 model->GetLabelAt(index++)); 395 EXPECT_EQ(UTF8ToUTF16("Context Menu #1 - Extension #2"), 396 model->GetLabelAt(index++)); 397 EXPECT_EQ(UTF8ToUTF16("Context Menu #2 - Extension #3"), 398 model->GetLabelAt(index++)); 399 EXPECT_EQ(UTF8ToUTF16("Context Menu #3 - Extension #1"), 400 model->GetLabelAt(index++)); 401 EXPECT_EQ(UTF8ToUTF16("Ze Extension with multiple Context Menus"), 402 model->GetLabelAt(index++)); 403 } 404 405 // Checks that in |menu|, the item at |index| has type |expected_type| and a 406 // label of |expected_label|. 407 static void ExpectLabelAndType(const char* expected_label, 408 MenuModel::ItemType expected_type, 409 const MenuModel& menu, 410 int index) { 411 EXPECT_EQ(expected_type, menu.GetTypeAt(index)); 412 EXPECT_EQ(UTF8ToUTF16(expected_label), menu.GetLabelAt(index)); 413 } 414 415 // In the separators test we build a submenu with items and separators in two 416 // different ways - this is used to verify the results in both cases. 417 static void VerifyMenuForSeparatorsTest(const MenuModel& menu) { 418 // We expect to see the following items in the menu: 419 // radio1 420 // radio2 421 // --separator-- (automatically added) 422 // normal1 423 // --separator-- 424 // normal2 425 // --separator-- 426 // radio3 427 // radio4 428 // --separator-- 429 // normal3 430 431 int index = 0; 432 ASSERT_EQ(11, menu.GetItemCount()); 433 ExpectLabelAndType("radio1", MenuModel::TYPE_RADIO, menu, index++); 434 ExpectLabelAndType("radio2", MenuModel::TYPE_RADIO, menu, index++); 435 EXPECT_EQ(MenuModel::TYPE_SEPARATOR, menu.GetTypeAt(index++)); 436 ExpectLabelAndType("normal1", MenuModel::TYPE_COMMAND, menu, index++); 437 EXPECT_EQ(MenuModel::TYPE_SEPARATOR, menu.GetTypeAt(index++)); 438 ExpectLabelAndType("normal2", MenuModel::TYPE_COMMAND, menu, index++); 439 EXPECT_EQ(MenuModel::TYPE_SEPARATOR, menu.GetTypeAt(index++)); 440 ExpectLabelAndType("radio3", MenuModel::TYPE_RADIO, menu, index++); 441 ExpectLabelAndType("radio4", MenuModel::TYPE_RADIO, menu, index++); 442 EXPECT_EQ(MenuModel::TYPE_SEPARATOR, menu.GetTypeAt(index++)); 443 ExpectLabelAndType("normal3", MenuModel::TYPE_COMMAND, menu, index++); 444 } 445 446 #if defined(OS_WIN) 447 #define MAYBE_Separators DISABLED_Separators 448 #else 449 #define MAYBE_Separators Separators 450 #endif 451 452 // Tests a number of cases for auto-generated and explicitly added separators. 453 IN_PROC_BROWSER_TEST_F(ExtensionContextMenuBrowserTest, Separators) { 454 // Load the extension. 455 ASSERT_TRUE(LoadContextMenuExtension("separators")); 456 const extensions::Extension* extension = GetExtensionNamed("Separators Test"); 457 ASSERT_TRUE(extension != NULL); 458 459 // Navigate to test1.html inside the extension, which should create a bunch 460 // of items at the top-level (but they'll get pushed into an auto-generated 461 // parent). 462 ExtensionTestMessageListener listener1("test1 create finished", false); 463 ui_test_utils::NavigateToURL(browser(), 464 GURL(extension->GetResourceURL("test1.html"))); 465 listener1.WaitUntilSatisfied(); 466 467 GURL url("http://www.google.com/"); 468 scoped_ptr<TestRenderViewContextMenu> menu( 469 CreateMenu(browser(), url, GURL(), GURL())); 470 471 // The top-level item should be an "automagic parent" with the extension's 472 // name. 473 MenuModel* model = NULL; 474 int index = 0; 475 string16 label; 476 ASSERT_TRUE(menu->GetMenuModelAndItemIndex( 477 IDC_EXTENSIONS_CONTEXT_CUSTOM_FIRST, &model, &index)); 478 EXPECT_EQ(UTF8ToUTF16(extension->name()), model->GetLabelAt(index)); 479 ASSERT_EQ(MenuModel::TYPE_SUBMENU, model->GetTypeAt(index)); 480 481 // Get the submenu and verify the items there. 482 MenuModel* submenu = model->GetSubmenuModelAt(index); 483 ASSERT_TRUE(submenu != NULL); 484 VerifyMenuForSeparatorsTest(*submenu); 485 486 // Now run our second test - navigate to test2.html which creates an explicit 487 // parent node and populates that with the same items as in test1. 488 ExtensionTestMessageListener listener2("test2 create finished", false); 489 ui_test_utils::NavigateToURL(browser(), 490 GURL(extension->GetResourceURL("test2.html"))); 491 listener2.WaitUntilSatisfied(); 492 menu.reset(CreateMenu(browser(), url, GURL(), GURL())); 493 ASSERT_TRUE(menu->GetMenuModelAndItemIndex( 494 IDC_EXTENSIONS_CONTEXT_CUSTOM_FIRST, &model, &index)); 495 EXPECT_EQ(UTF8ToUTF16("parent"), model->GetLabelAt(index)); 496 submenu = model->GetSubmenuModelAt(index); 497 ASSERT_TRUE(submenu != NULL); 498 VerifyMenuForSeparatorsTest(*submenu); 499 } 500 501 // Tests that targetUrlPattern keeps items from appearing when there is no 502 // target url. 503 IN_PROC_BROWSER_TEST_F(ExtensionContextMenuBrowserTest, TargetURLs) { 504 ExtensionTestMessageListener listener("created items", false); 505 ASSERT_TRUE(LoadContextMenuExtension("target_urls")); 506 ASSERT_TRUE(listener.WaitUntilSatisfied()); 507 508 GURL google_url("http://www.google.com"); 509 GURL non_google_url("http://www.foo.com"); 510 511 // No target url - the item should not appear. 512 ASSERT_FALSE(MenuHasItemWithLabel( 513 google_url, GURL(), GURL(), std::string("item1"))); 514 515 // A matching target url - the item should appear. 516 ASSERT_TRUE(MenuHasItemWithLabel(google_url, 517 google_url, 518 GURL(), 519 std::string("item1"))); 520 521 // A non-matching target url - the item should not appear. 522 ASSERT_FALSE(MenuHasItemWithLabel(google_url, 523 non_google_url, 524 GURL(), 525 std::string("item1"))); 526 } 527 528 // Tests adding of context menus in incognito mode. 529 #if defined(OS_LINUX) 530 // Flakily hangs on Linux/CrOS - http://crbug.com/88317 531 #define MAYBE_IncognitoSplit DISABLED_IncognitoSplit 532 #else 533 #define MAYBE_IncognitoSplit IncognitoSplit 534 #endif 535 IN_PROC_BROWSER_TEST_F(ExtensionContextMenuBrowserTest, MAYBE_IncognitoSplit) { 536 ExtensionTestMessageListener created("created item regular", false); 537 ExtensionTestMessageListener created_incognito("created item incognito", 538 false); 539 540 ExtensionTestMessageListener onclick("onclick fired regular", false); 541 ExtensionTestMessageListener onclick_incognito("onclick fired incognito", 542 false); 543 544 // Open an incognito window. 545 Browser* browser_incognito = ui_test_utils::OpenURLOffTheRecord( 546 browser()->profile(), GURL("about:blank")); 547 548 ASSERT_TRUE(LoadContextMenuExtensionIncognito("incognito")); 549 550 // Wait for the extension's processes to tell us they've created an item. 551 ASSERT_TRUE(created.WaitUntilSatisfied()); 552 ASSERT_TRUE(created_incognito.WaitUntilSatisfied()); 553 554 GURL page_url("http://www.google.com"); 555 556 // Create and build our test context menu. 557 scoped_ptr<TestRenderViewContextMenu> menu( 558 CreateMenu(browser(), page_url, GURL(), GURL())); 559 scoped_ptr<TestRenderViewContextMenu> menu_incognito( 560 CreateMenu(browser_incognito, page_url, GURL(), GURL())); 561 562 // Look for the extension item in the menu, and execute it. 563 int command_id = IDC_EXTENSIONS_CONTEXT_CUSTOM_FIRST; 564 ASSERT_TRUE(menu->IsCommandIdEnabled(command_id)); 565 menu->ExecuteCommand(command_id, 0); 566 567 // Wait for the extension's script to tell us its onclick fired. Ensure 568 // that the incognito version doesn't fire until we explicitly click the 569 // incognito menu item. 570 ASSERT_TRUE(onclick.WaitUntilSatisfied()); 571 EXPECT_FALSE(onclick_incognito.was_satisfied()); 572 573 ASSERT_TRUE(menu_incognito->IsCommandIdEnabled(command_id)); 574 menu_incognito->ExecuteCommand(command_id, 0); 575 ASSERT_TRUE(onclick_incognito.WaitUntilSatisfied()); 576 } 577 578 // Tests that items with a context of frames only appear when the menu is 579 // invoked in a frame. 580 IN_PROC_BROWSER_TEST_F(ExtensionContextMenuBrowserTest, Frames) { 581 ExtensionTestMessageListener listener("created items", false); 582 ASSERT_TRUE(LoadContextMenuExtension("frames")); 583 ASSERT_TRUE(listener.WaitUntilSatisfied()); 584 585 GURL page_url("http://www.google.com"); 586 GURL no_frame_url; 587 GURL frame_url("http://www.google.com"); 588 589 ASSERT_TRUE(MenuHasItemWithLabel( 590 page_url, GURL(), no_frame_url, std::string("Page item"))); 591 ASSERT_FALSE(MenuHasItemWithLabel( 592 page_url, GURL(), no_frame_url, std::string("Frame item"))); 593 594 ASSERT_TRUE(MenuHasItemWithLabel( 595 page_url, GURL(), frame_url, std::string("Page item"))); 596 ASSERT_TRUE(MenuHasItemWithLabel( 597 page_url, GURL(), frame_url, std::string("Frame item"))); 598 } 599 600 // Tests enabling and disabling a context menu item. 601 IN_PROC_BROWSER_TEST_F(ExtensionContextMenuBrowserTest, Enabled) { 602 TestEnabledContextMenu(true); 603 TestEnabledContextMenu(false); 604 } 605 606 class ExtensionContextMenuBrowserLazyTest : 607 public ExtensionContextMenuBrowserTest { 608 virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE { 609 ExtensionContextMenuBrowserTest::SetUpCommandLine(command_line); 610 // Set shorter delays to prevent test timeouts. 611 command_line->AppendSwitchASCII(switches::kEventPageIdleTime, "0"); 612 command_line->AppendSwitchASCII(switches::kEventPageSuspendingTime, "0"); 613 } 614 }; 615 616 IN_PROC_BROWSER_TEST_F(ExtensionContextMenuBrowserLazyTest, EventPage) { 617 GURL about_blank("about:blank"); 618 LazyBackgroundObserver page_complete; 619 const extensions::Extension* extension = LoadContextMenuExtension( 620 "event_page"); 621 ASSERT_TRUE(extension); 622 page_complete.Wait(); 623 624 // Test that menu items appear while the page is unloaded. 625 ASSERT_TRUE(MenuHasItemWithLabel( 626 about_blank, GURL(), GURL(), std::string("Item 1"))); 627 ASSERT_TRUE(MenuHasItemWithLabel( 628 about_blank, GURL(), GURL(), std::string("Checkbox 1"))); 629 630 // Test that checked menu items retain their checkedness. 631 LazyBackgroundObserver checkbox_checked; 632 scoped_ptr<TestRenderViewContextMenu> menu( 633 CreateMenu(browser(), about_blank, GURL(), GURL())); 634 MenuItem::Id id(false, extension->id()); 635 id.string_uid = "checkbox1"; 636 int command_id = -1; 637 ASSERT_TRUE(FindCommandId(menu.get(), id, &command_id)); 638 EXPECT_FALSE(menu->IsCommandIdChecked(command_id)); 639 640 // Executing the checkbox also fires the onClicked event. 641 ExtensionTestMessageListener listener("onClicked fired for checkbox1", false); 642 menu->ExecuteCommand(command_id, 0); 643 checkbox_checked.WaitUntilClosed(); 644 645 EXPECT_TRUE(menu->IsCommandIdChecked(command_id)); 646 ASSERT_TRUE(listener.WaitUntilSatisfied()); 647 } 648 649 IN_PROC_BROWSER_TEST_F(ExtensionContextMenuBrowserTest, 650 IncognitoSplitContextMenuCount) { 651 ExtensionTestMessageListener created("created item regular", false); 652 ExtensionTestMessageListener created_incognito("created item incognito", 653 false); 654 655 // Create an incognito profile. 656 ASSERT_TRUE(browser()->profile()->GetOffTheRecordProfile()); 657 ASSERT_TRUE(LoadContextMenuExtensionIncognito("incognito")); 658 659 // Wait for the extension's processes to tell us they've created an item. 660 ASSERT_TRUE(created.WaitUntilSatisfied()); 661 ASSERT_TRUE(created_incognito.WaitUntilSatisfied()); 662 ASSERT_EQ(2u, GetItems().size()); 663 664 browser()->profile()->DestroyOffTheRecordProfile(); 665 ASSERT_EQ(1u, GetItems().size()); 666 } 667