1// Copyright 2014 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 <string>
6
7#include "base/memory/scoped_ptr.h"
8#include "base/strings/string16.h"
9#include "base/strings/utf_string_conversions.h"
10#include "chrome/app/chrome_command_ids.h"
11#include "chrome/browser/chrome_notification_types.h"
12#include "chrome/browser/renderer_context_menu/render_view_context_menu.h"
13#include "chrome/browser/renderer_context_menu/render_view_context_menu_browsertest_util.h"
14#include "chrome/browser/renderer_context_menu/render_view_context_menu_test_util.h"
15#include "chrome/browser/ui/browser.h"
16#include "chrome/browser/ui/tabs/tab_strip_model.h"
17#include "chrome/test/base/in_process_browser_test.h"
18#include "chrome/test/base/ui_test_utils.h"
19#include "content/public/browser/navigation_controller.h"
20#include "content/public/browser/navigation_entry.h"
21#include "content/public/browser/notification_service.h"
22#include "content/public/browser/render_view_host.h"
23#include "content/public/browser/web_contents.h"
24#include "content/public/test/browser_test_utils.h"
25#include "third_party/WebKit/public/web/WebContextMenuData.h"
26#include "third_party/WebKit/public/web/WebInputEvent.h"
27
28using content::WebContents;
29
30namespace {
31
32class ContextMenuBrowserTest : public InProcessBrowserTest {
33 public:
34  ContextMenuBrowserTest() { }
35
36  TestRenderViewContextMenu* CreateContextMenu(GURL unfiltered_url, GURL url) {
37    content::ContextMenuParams params;
38    params.media_type = blink::WebContextMenuData::MediaTypeNone;
39    params.unfiltered_link_url = unfiltered_url;
40    params.link_url = url;
41    WebContents* web_contents =
42        browser()->tab_strip_model()->GetActiveWebContents();
43    params.page_url = web_contents->GetController().GetActiveEntry()->GetURL();
44#if defined(OS_MACOSX)
45    params.writing_direction_default = 0;
46    params.writing_direction_left_to_right = 0;
47    params.writing_direction_right_to_left = 0;
48#endif  // OS_MACOSX
49    TestRenderViewContextMenu* menu = new TestRenderViewContextMenu(
50        browser()->tab_strip_model()->GetActiveWebContents()->GetMainFrame(),
51        params);
52    menu->Init();
53    return menu;
54  }
55};
56
57IN_PROC_BROWSER_TEST_F(ContextMenuBrowserTest,
58                       OpenEntryPresentForNormalURLs) {
59  scoped_ptr<TestRenderViewContextMenu> menu(
60      CreateContextMenu(GURL("http://www.google.com/"),
61                        GURL("http://www.google.com/")));
62
63  ASSERT_TRUE(menu->IsItemPresent(IDC_CONTENT_CONTEXT_OPENLINKNEWTAB));
64  ASSERT_TRUE(menu->IsItemPresent(IDC_CONTENT_CONTEXT_OPENLINKNEWWINDOW));
65  ASSERT_TRUE(menu->IsItemPresent(IDC_CONTENT_CONTEXT_COPYLINKLOCATION));
66}
67
68IN_PROC_BROWSER_TEST_F(ContextMenuBrowserTest,
69                       OpenEntryAbsentForFilteredURLs) {
70  scoped_ptr<TestRenderViewContextMenu> menu(
71      CreateContextMenu(GURL("chrome://history"),
72                        GURL()));
73
74  ASSERT_FALSE(menu->IsItemPresent(IDC_CONTENT_CONTEXT_OPENLINKNEWTAB));
75  ASSERT_FALSE(menu->IsItemPresent(IDC_CONTENT_CONTEXT_OPENLINKNEWWINDOW));
76  ASSERT_TRUE(menu->IsItemPresent(IDC_CONTENT_CONTEXT_COPYLINKLOCATION));
77}
78
79IN_PROC_BROWSER_TEST_F(ContextMenuBrowserTest,
80                       SaveAsImageForCanvas) {
81  content::ContextMenuParams params;
82  params.media_type = blink::WebContextMenuData::MediaTypeCanvas;
83
84  TestRenderViewContextMenu menu(
85      browser()->tab_strip_model()->GetActiveWebContents()->GetMainFrame(),
86      params);
87  menu.Init();
88
89  ASSERT_TRUE(menu.IsItemPresent(IDC_CONTENT_CONTEXT_SAVEIMAGEAS));
90}
91
92// Opens a link in a new tab via a "real" context menu.
93IN_PROC_BROWSER_TEST_F(ContextMenuBrowserTest, RealMenu) {
94  ContextMenuNotificationObserver menu_observer(
95      IDC_CONTENT_CONTEXT_OPENLINKNEWTAB);
96  ui_test_utils::WindowedTabAddedNotificationObserver tab_observer(
97      content::NotificationService::AllSources());
98
99  // Go to a page with a link
100  ui_test_utils::NavigateToURL(
101      browser(), GURL("data:text/html,<a href='about:blank'>link</a>"));
102
103  // Open a context menu.
104  blink::WebMouseEvent mouse_event;
105  mouse_event.type = blink::WebInputEvent::MouseDown;
106  mouse_event.button = blink::WebMouseEvent::ButtonRight;
107  mouse_event.x = 15;
108  mouse_event.y = 15;
109  content::WebContents* tab =
110      browser()->tab_strip_model()->GetActiveWebContents();
111  gfx::Rect offset = tab->GetContainerBounds();
112  mouse_event.globalX = 15 + offset.x();
113  mouse_event.globalY = 15 + offset.y();
114  mouse_event.clickCount = 1;
115  tab->GetRenderViewHost()->ForwardMouseEvent(mouse_event);
116  mouse_event.type = blink::WebInputEvent::MouseUp;
117  tab->GetRenderViewHost()->ForwardMouseEvent(mouse_event);
118
119  // The menu_observer will select "Open in new tab", wait for the new tab to
120  // be added.
121  tab_observer.Wait();
122  tab = tab_observer.GetTab();
123  content::WaitForLoadStop(tab);
124
125  // Verify that it's the correct tab.
126  EXPECT_EQ(GURL("about:blank"), tab->GetURL());
127}
128
129// Verify that "Open Link in New Tab" doesn't send URL fragment as referrer.
130IN_PROC_BROWSER_TEST_F(ContextMenuBrowserTest, OpenInNewTabReferrer) {
131  ui_test_utils::WindowedTabAddedNotificationObserver tab_observer(
132      content::NotificationService::AllSources());
133
134  ASSERT_TRUE(test_server()->Start());
135  GURL echoheader(test_server()->GetURL("echoheader?Referer"));
136
137  // Go to a |page| with a link to echoheader URL.
138  GURL page("data:text/html,<a href='" + echoheader.spec() + "'>link</a>");
139  ui_test_utils::NavigateToURL(browser(), page);
140
141  // Set up referrer URL with fragment.
142  const GURL kReferrerWithFragment("http://foo.com/test#fragment");
143  const std::string kCorrectReferrer("http://foo.com/test");
144
145  // Set up menu with link URL.
146  content::ContextMenuParams context_menu_params;
147  context_menu_params.page_url = kReferrerWithFragment;
148  context_menu_params.link_url = echoheader;
149
150  // Select "Open Link in New Tab" and wait for the new tab to be added.
151  TestRenderViewContextMenu menu(
152      browser()->tab_strip_model()->GetActiveWebContents()->GetMainFrame(),
153      context_menu_params);
154  menu.Init();
155  menu.ExecuteCommand(IDC_CONTENT_CONTEXT_OPENLINKNEWTAB, 0);
156
157  tab_observer.Wait();
158  content::WebContents* tab = tab_observer.GetTab();
159  content::WaitForLoadStop(tab);
160
161  // Verify that it's the correct tab.
162  ASSERT_EQ(echoheader, tab->GetURL());
163  // Verify that the text on the page matches |kCorrectReferrer|.
164  std::string actual_referrer;
165  ASSERT_TRUE(content::ExecuteScriptAndExtractString(
166      tab,
167      "window.domAutomationController.send(window.document.body.textContent);",
168      &actual_referrer));
169  ASSERT_EQ(kCorrectReferrer, actual_referrer);
170
171  // Verify that the referrer on the page matches |kCorrectReferrer|.
172  std::string page_referrer;
173  ASSERT_TRUE(content::ExecuteScriptAndExtractString(
174      tab,
175      "window.domAutomationController.send(window.document.referrer);",
176      &page_referrer));
177  ASSERT_EQ(kCorrectReferrer, page_referrer);
178}
179
180// Verify that "Open Link in Incognito Window " doesn't send referrer URL.
181IN_PROC_BROWSER_TEST_F(ContextMenuBrowserTest, OpenIncognitoNoneReferrer) {
182  ui_test_utils::WindowedTabAddedNotificationObserver tab_observer(
183      content::NotificationService::AllSources());
184
185  ASSERT_TRUE(test_server()->Start());
186  GURL echoheader(test_server()->GetURL("echoheader?Referer"));
187
188  // Go to a |page| with a link to echoheader URL.
189  GURL page("data:text/html,<a href='" + echoheader.spec() + "'>link</a>");
190  ui_test_utils::NavigateToURL(browser(), page);
191
192  // Set up referrer URL with fragment.
193  const GURL kReferrerWithFragment("http://foo.com/test#fragment");
194  const std::string kNoneReferrer("None");
195  const std::string kEmptyReferrer("");
196
197  // Set up menu with link URL.
198  content::ContextMenuParams context_menu_params;
199  context_menu_params.page_url = kReferrerWithFragment;
200  context_menu_params.link_url = echoheader;
201
202  // Select "Open Link in Incognito Window" and wait for window to be added.
203  TestRenderViewContextMenu menu(
204      browser()->tab_strip_model()->GetActiveWebContents()->GetMainFrame(),
205      context_menu_params);
206  menu.Init();
207  menu.ExecuteCommand(IDC_CONTENT_CONTEXT_OPENLINKOFFTHERECORD, 0);
208
209  tab_observer.Wait();
210  content::WebContents* tab = tab_observer.GetTab();
211  content::WaitForLoadStop(tab);
212
213  // Verify that it's the correct tab.
214  ASSERT_EQ(echoheader, tab->GetURL());
215  // Verify that the text on the page matches |kNoneReferrer|.
216  std::string actual_referrer;
217  ASSERT_TRUE(content::ExecuteScriptAndExtractString(
218      tab,
219      "window.domAutomationController.send(window.document.body.textContent);",
220      &actual_referrer));
221  ASSERT_EQ(kNoneReferrer, actual_referrer);
222
223  // Verify that the referrer on the page matches |kEmptyReferrer|.
224  std::string page_referrer;
225  ASSERT_TRUE(content::ExecuteScriptAndExtractString(
226      tab,
227      "window.domAutomationController.send(window.document.referrer);",
228      &page_referrer));
229  ASSERT_EQ(kEmptyReferrer, page_referrer);
230}
231
232// Ensure that View Page Info won't crash if there is no visible entry.
233// See http://crbug.com/370863.
234IN_PROC_BROWSER_TEST_F(ContextMenuBrowserTest, ViewPageInfoWithNoEntry) {
235  // Create a new tab with no committed entry.
236  ui_test_utils::WindowedTabAddedNotificationObserver tab_observer(
237      content::NotificationService::AllSources());
238  ASSERT_TRUE(content::ExecuteScript(
239      browser()->tab_strip_model()->GetActiveWebContents(), "window.open();"));
240  tab_observer.Wait();
241  content::WebContents* tab = tab_observer.GetTab();
242  EXPECT_FALSE(tab->GetController().GetLastCommittedEntry());
243  EXPECT_FALSE(tab->GetController().GetVisibleEntry());
244
245  // Create a context menu.
246  content::ContextMenuParams context_menu_params;
247  TestRenderViewContextMenu menu(tab->GetMainFrame(), context_menu_params);
248  menu.Init();
249
250  // The item shouldn't be enabled in the menu.
251  EXPECT_FALSE(menu.IsCommandIdEnabled(IDC_CONTENT_CONTEXT_VIEWPAGEINFO));
252
253  // Ensure that viewing page info doesn't crash even if you can get to it.
254  menu.ExecuteCommand(IDC_CONTENT_CONTEXT_VIEWPAGEINFO, 0);
255}
256
257}  // namespace
258