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/basictypes.h"
6#include "components/autofill/content/renderer/page_click_listener.h"
7#include "components/autofill/content/renderer/page_click_tracker.h"
8#include "content/public/renderer/render_view.h"
9#include "content/public/test/render_view_test.h"
10#include "testing/gtest/include/gtest/gtest.h"
11#include "third_party/WebKit/public/web/WebDocument.h"
12#include "third_party/WebKit/public/web/WebInputElement.h"
13#include "third_party/WebKit/public/web/WebTextAreaElement.h"
14#include "third_party/WebKit/public/web/WebView.h"
15#include "third_party/WebKit/public/platform/WebSize.h"
16#include "ui/events/keycodes/keyboard_codes.h"
17
18namespace autofill {
19
20class TestPageClickListener : public PageClickListener {
21 public:
22  TestPageClickListener()
23      : form_control_element_clicked_called_(false),
24        form_control_element_lost_focus_called_(false),
25        was_focused_(false) {
26  }
27
28  virtual void FormControlElementClicked(
29      const blink::WebFormControlElement& element,
30      bool was_focused)  OVERRIDE {
31    form_control_element_clicked_called_ = true;
32    form_control_element_clicked_ = element;
33    was_focused_ = was_focused;
34  }
35
36  virtual void FormControlElementLostFocus() OVERRIDE {
37    form_control_element_lost_focus_called_ = true;
38  }
39
40  void ClearResults() {
41    form_control_element_clicked_called_ = false;
42    form_control_element_lost_focus_called_ = false;
43    form_control_element_clicked_.reset();
44    was_focused_ = false;
45  }
46
47  bool form_control_element_clicked_called_;
48  bool form_control_element_lost_focus_called_;
49  blink::WebFormControlElement form_control_element_clicked_;
50  bool was_focused_;
51};
52
53class PageClickTrackerTest : public content::RenderViewTest {
54 protected:
55  virtual void SetUp() OVERRIDE {
56    content::RenderViewTest::SetUp();
57
58    // RenderView creates PageClickTracker but it doesn't keep it around.
59    // Rather than make it do so for the test, we create a new object.
60    page_click_tracker_.reset(new PageClickTracker(view_, &test_listener_));
61
62    LoadHTML("<form>"
63             "  <input type='text' id='text_1'></input><br>"
64             "  <input type='text' id='text_2'></input><br>"
65             "  <textarea  id='textarea_1'></textarea><br>"
66             "  <textarea  id='textarea_2'></textarea><br>"
67             "  <input type='button' id='button'></input><br>"
68             "</form>");
69    GetWebWidget()->resize(blink::WebSize(500, 500));
70    GetWebWidget()->setFocus(true);
71    blink::WebDocument document = view_->GetWebView()->mainFrame()->document();
72    text_ = document.getElementById("text_1");
73    textarea_ = document.getElementById("textarea_1");
74    ASSERT_FALSE(text_.isNull());
75    ASSERT_FALSE(textarea_.isNull());
76  }
77
78  virtual void TearDown() OVERRIDE {
79    text_.reset();
80    textarea_.reset();
81    test_listener_.ClearResults();
82    page_click_tracker_.reset();
83    content::RenderViewTest::TearDown();
84  }
85
86  // Send all the messages required for a complete key press.
87  void SendKeyPress(int key_code) {
88    blink::WebKeyboardEvent keyboard_event;
89    keyboard_event.windowsKeyCode = key_code;
90    keyboard_event.setKeyIdentifierFromWindowsKeyCode();
91
92    keyboard_event.type = blink::WebInputEvent::RawKeyDown;
93    SendWebKeyboardEvent(keyboard_event);
94
95    keyboard_event.type = blink::WebInputEvent::Char;
96    SendWebKeyboardEvent(keyboard_event);
97
98    keyboard_event.type = blink::WebInputEvent::KeyUp;
99    SendWebKeyboardEvent(keyboard_event);
100  }
101
102  scoped_ptr<PageClickTracker> page_click_tracker_;
103  TestPageClickListener test_listener_;
104  blink::WebElement text_;
105  blink::WebElement textarea_;
106};
107
108// Tests that PageClickTracker does notify correctly when an input
109// node is clicked.
110TEST_F(PageClickTrackerTest, PageClickTrackerInputClicked) {
111  // Click the text field once.
112  EXPECT_TRUE(SimulateElementClick("text_1"));
113  EXPECT_TRUE(test_listener_.form_control_element_clicked_called_);
114  EXPECT_FALSE(test_listener_.was_focused_);
115  EXPECT_TRUE(text_ == test_listener_.form_control_element_clicked_);
116  test_listener_.ClearResults();
117
118  // Click the text field again to test that was_focused_ is set correctly.
119  EXPECT_TRUE(SimulateElementClick("text_1"));
120  EXPECT_TRUE(test_listener_.form_control_element_clicked_called_);
121  EXPECT_TRUE(test_listener_.was_focused_);
122  EXPECT_TRUE(text_ == test_listener_.form_control_element_clicked_);
123  test_listener_.ClearResults();
124
125  // Click the button, no notification should happen (this is not a text-input).
126  EXPECT_TRUE(SimulateElementClick("button"));
127  EXPECT_FALSE(test_listener_.form_control_element_clicked_called_);
128}
129
130// Tests that PageClickTracker does notify correctly when a textarea
131// node is clicked.
132TEST_F(PageClickTrackerTest, PageClickTrackerTextAreaClicked) {
133  // Click the textarea field once.
134  EXPECT_TRUE(SimulateElementClick("textarea_1"));
135  EXPECT_TRUE(test_listener_.form_control_element_clicked_called_);
136  EXPECT_FALSE(test_listener_.was_focused_);
137  EXPECT_TRUE(textarea_ == test_listener_.form_control_element_clicked_);
138  test_listener_.ClearResults();
139
140  // Click the textarea field again to test that was_focused_ is set correctly.
141  EXPECT_TRUE(SimulateElementClick("textarea_1"));
142  EXPECT_TRUE(test_listener_.form_control_element_clicked_called_);
143  EXPECT_TRUE(test_listener_.was_focused_);
144  EXPECT_TRUE(textarea_ == test_listener_.form_control_element_clicked_);
145  test_listener_.ClearResults();
146
147  // Click the button, no notification should happen (this is not a text-input).
148  EXPECT_TRUE(SimulateElementClick("button"));
149  EXPECT_FALSE(test_listener_.form_control_element_clicked_called_);
150}
151
152TEST_F(PageClickTrackerTest, PageClickTrackerInputFocusLost) {
153  // Gain focus on the text field by using tab.
154  EXPECT_NE(text_, text_.document().focusedElement());
155  SendKeyPress(ui::VKEY_TAB);
156  EXPECT_EQ(text_, text_.document().focusedElement());
157  EXPECT_FALSE(test_listener_.form_control_element_lost_focus_called_);
158
159  // Click a button and ensure that the lost focus notification was sent,
160  // even though focus was gained without the mouse.
161  EXPECT_TRUE(SimulateElementClick("button"));
162  EXPECT_TRUE(test_listener_.form_control_element_lost_focus_called_);
163  test_listener_.ClearResults();
164
165  // Click a text field and test that no lost focus notifications are sent.
166  EXPECT_TRUE(SimulateElementClick("text_1"));
167  EXPECT_FALSE(test_listener_.form_control_element_lost_focus_called_);
168  test_listener_.ClearResults();
169
170  // Select another text field to test that the notification for the
171  // first text field losing focus is sent.
172  EXPECT_TRUE(SimulateElementClick("text_2"));
173  EXPECT_TRUE(test_listener_.form_control_element_lost_focus_called_);
174  test_listener_.ClearResults();
175
176  // Click the button, a notification should happen since a text field has
177  // lost focus.
178  EXPECT_TRUE(SimulateElementClick("button"));
179  EXPECT_TRUE(test_listener_.form_control_element_lost_focus_called_);
180  test_listener_.ClearResults();
181
182  // Click on a text field while the button has focus and ensure no lost focus
183  // notification is sent.
184  EXPECT_TRUE(SimulateElementClick("text_1"));
185  EXPECT_FALSE(test_listener_.form_control_element_lost_focus_called_);
186}
187
188TEST_F(PageClickTrackerTest, PageClickTrackerTextAreaFocusLost) {
189  // Gain focus on the textare field by using tab.
190  EXPECT_NE(textarea_, textarea_.document().focusedElement());
191  SendKeyPress(ui::VKEY_TAB);
192  SendKeyPress(ui::VKEY_TAB);
193  SendKeyPress(ui::VKEY_TAB);
194  EXPECT_EQ(textarea_, textarea_.document().focusedElement());
195  EXPECT_FALSE(test_listener_.form_control_element_lost_focus_called_);
196
197  // Click a button and ensure that the lost focus notification was sent,
198  // even though focus was gained without the mouse.
199  EXPECT_TRUE(SimulateElementClick("button"));
200  EXPECT_TRUE(test_listener_.form_control_element_lost_focus_called_);
201  test_listener_.ClearResults();
202
203  // Click a textarea field and test that no lost focus notifications are sent.
204  EXPECT_TRUE(SimulateElementClick("textarea_1"));
205  EXPECT_FALSE(test_listener_.form_control_element_lost_focus_called_);
206  test_listener_.ClearResults();
207
208  // Select another textarea field to test that the notification for the
209  // first textarea field losing focus is sent.
210  EXPECT_TRUE(SimulateElementClick("textarea_2"));
211  EXPECT_TRUE(test_listener_.form_control_element_lost_focus_called_);
212  test_listener_.ClearResults();
213
214  // Click the button, a notification should happen since a textarea field has
215  // lost focus.
216  EXPECT_TRUE(SimulateElementClick("button"));
217  EXPECT_TRUE(test_listener_.form_control_element_lost_focus_called_);
218  test_listener_.ClearResults();
219
220  // Click on a textarea field while the button has focus and ensure no lost
221  // focus notification is sent.
222  EXPECT_TRUE(SimulateElementClick("textarea_1"));
223  EXPECT_FALSE(test_listener_.form_control_element_lost_focus_called_);
224}
225
226}  // namespace autofill
227