1// Copyright 2013 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/basictypes.h"
6#include "base/files/file_path.h"
7#include "chrome/browser/chrome_notification_types.h"
8#include "chrome/browser/ui/browser.h"
9#include "chrome/browser/ui/browser_commands.h"
10#include "chrome/browser/ui/browser_tabstrip.h"
11#include "chrome/browser/ui/tabs/tab_strip_model.h"
12#include "chrome/test/base/in_process_browser_test.h"
13#include "chrome/test/base/ui_test_utils.h"
14#include "content/public/browser/notification_service.h"
15#include "content/public/browser/notification_source.h"
16#include "content/public/browser/render_view_host.h"
17#include "content/public/browser/web_contents.h"
18#include "content/public/test/browser_test_utils.h"
19#include "net/base/net_util.h"
20#include "url/gurl.h"
21
22class ChromeRenderWidgetHostViewMacDelegateTest : public InProcessBrowserTest {
23 public:
24  ChromeRenderWidgetHostViewMacDelegateTest() {
25    const base::FilePath base_path(FILE_PATH_LITERAL("scroll"));
26    url1_ = ui_test_utils::GetTestUrl(
27        base_path, base::FilePath(FILE_PATH_LITERAL("text.html")));
28    url2_ = ui_test_utils::GetTestUrl(
29        base_path, base::FilePath(FILE_PATH_LITERAL("blank.html")));
30  }
31
32 protected:
33  // Navigates back.
34  void GoBack() {
35    content::WindowedNotificationObserver observer(
36        content::NOTIFICATION_LOAD_STOP,
37        content::NotificationService::AllSources());
38    chrome::GoBack(browser(), CURRENT_TAB);
39    observer.Wait();
40  }
41
42  // Returns the active web contents.
43  content::WebContents* GetWebContents() {
44    return browser()->tab_strip_model()->GetActiveWebContents();
45  }
46
47  // Returns the value of |query| from Javascript as an int.
48  int GetScriptIntValue(const std::string& query) {
49    int value = 0;
50    EXPECT_TRUE(content::ExecuteScriptAndExtractInt(
51        GetWebContents(),
52        "domAutomationController.send(" + query + ")",
53        &value));
54    return value;
55  }
56
57  // Returns the vertical scroll offset of the current page.
58  int GetScrollTop() {
59    return GetScriptIntValue("document.body.scrollTop");
60  }
61
62  // Returns the horizontal scroll offset of the current page.
63  int GetScrollLeft() {
64    return GetScriptIntValue("document.body.scrollLeft");
65  }
66
67  // Simulates a mouse wheel event, forwarding it to the renderer.
68  void SendWheelEvent(int dx, int dy, blink::WebMouseWheelEvent::Phase phase) {
69    blink::WebMouseWheelEvent event;
70    event.type = blink::WebInputEvent::MouseWheel;
71    event.phase = phase;
72    event.deltaX = dx;
73    event.deltaY = dy;
74    event.wheelTicksY = -2;
75    event.hasPreciseScrollingDeltas = 1;
76    GetWebContents()->GetRenderViewHost()->ForwardWheelEvent(event);
77  }
78
79  GURL url1_;
80  GURL url2_;
81
82 private:
83  DISALLOW_COPY_AND_ASSIGN(ChromeRenderWidgetHostViewMacDelegateTest);
84};
85
86IN_PROC_BROWSER_TEST_F(ChromeRenderWidgetHostViewMacDelegateTest,
87                       GoBackScrollOffset) {
88  ui_test_utils::NavigateToURL(browser(), url1_);
89  ASSERT_EQ(url1_, GetWebContents()->GetURL());
90
91  SendWheelEvent(0, -200, blink::WebMouseWheelEvent::PhaseNone);
92  const int scroll_offset = GetScrollTop();
93  ASSERT_NE(0, scroll_offset);
94
95  ui_test_utils::NavigateToURL(browser(), url2_);
96  ASSERT_EQ(url2_, GetWebContents()->GetURL());
97  ASSERT_EQ(0, GetScrollTop());
98
99  GoBack();
100  ASSERT_EQ(url1_, GetWebContents()->GetURL());
101  ASSERT_EQ(scroll_offset, GetScrollTop());
102}
103
104IN_PROC_BROWSER_TEST_F(ChromeRenderWidgetHostViewMacDelegateTest,
105                       GoBackUsingGestureScrollOffset) {
106  ui_test_utils::NavigateToURL(browser(), url1_);
107  ASSERT_EQ(url1_, GetWebContents()->GetURL());
108
109  SendWheelEvent(0, -200, blink::WebMouseWheelEvent::PhaseNone);
110  const int scroll_offset = GetScrollTop();
111  ASSERT_NE(0, scroll_offset);
112
113  ui_test_utils::NavigateToURL(browser(), url2_);
114  ASSERT_EQ(url2_, GetWebContents()->GetURL());
115  ASSERT_EQ(0, GetScrollTop());
116
117  // Send wheel events that shouldn't be handled by the web content since it's
118  // not scrollable in the horizontal direction.
119  SendWheelEvent(500, 0, blink::WebMouseWheelEvent::PhaseBegan);
120  SendWheelEvent(500, 0, blink::WebMouseWheelEvent::PhaseEnded);
121  ASSERT_EQ(0, GetScrollLeft());
122
123  // Simulate a back being triggered as a result of the unhandled wheel events.
124  // This doesn't invoke the code in ChromeRenderWidgetHostViewMacDelegate
125  // because that expects NSEvents which are much harder to fake.
126  GoBack();
127  ASSERT_EQ(url1_, GetWebContents()->GetURL());
128  ASSERT_EQ(scroll_offset, GetScrollTop());
129}
130