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