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 "chrome/browser/ui/views/sync/one_click_signin_bubble_view.h"
6
7#include "base/bind.h"
8#include "base/bind_helpers.h"
9#include "base/memory/scoped_ptr.h"
10#include "chrome/browser/ui/sync/one_click_signin_bubble_delegate.h"
11#include "chrome/test/base/ui_test_utils.h"
12#include "content/public/common/page_transition_types.h"
13#include "ui/views/controls/button/label_button.h"
14#include "ui/views/test/views_test_base.h"
15#include "ui/views/widget/widget.h"
16
17class OneClickSigninBubbleViewTest : public views::ViewsTestBase {
18 public:
19  OneClickSigninBubbleViewTest()
20      : on_start_sync_called_(false),
21        mode_(OneClickSigninSyncStarter::CONFIGURE_SYNC_FIRST),
22        bubble_learn_more_click_count_(0),
23        dialog_learn_more_click_count_(0),
24        advanced_click_count_(0),
25        anchor_widget_(NULL) {
26  }
27
28  virtual void SetUp() OVERRIDE {
29    views::ViewsTestBase::SetUp();
30
31    // Create a widget to host the anchor view.
32    anchor_widget_ = new views::Widget;
33    views::Widget::InitParams widget_params = CreateParams(
34        views::Widget::InitParams::TYPE_WINDOW);
35    anchor_widget_->Init(widget_params);
36    anchor_widget_->Show();
37  }
38
39  virtual void TearDown() OVERRIDE {
40    OneClickSigninBubbleView::Hide();
41    anchor_widget_->Close();
42    anchor_widget_ = NULL;
43    views::ViewsTestBase::TearDown();
44  }
45
46 protected:
47  OneClickSigninBubbleView* ShowOneClickSigninBubble(
48    BrowserWindow::OneClickSigninBubbleType bubble_type) {
49
50    scoped_ptr<OneClickSigninBubbleDelegate> delegate;
51    delegate.reset(new OneClickSigninBubbleTestDelegate(this));
52
53    OneClickSigninBubbleView::ShowBubble(
54        bubble_type,
55        base::string16(),
56        base::string16(),
57        delegate.Pass(),
58        anchor_widget_->GetContentsView(),
59        base::Bind(&OneClickSigninBubbleViewTest::OnStartSync,
60                   base::Unretained(this)));
61
62    OneClickSigninBubbleView* view =
63        OneClickSigninBubbleView::view_for_testing();
64    EXPECT_TRUE(view != NULL);
65    return view;
66  }
67
68  void OnStartSync(OneClickSigninSyncStarter::StartSyncMode mode) {
69    on_start_sync_called_ = true;
70    mode_ = mode;
71  }
72
73  bool on_start_sync_called_;
74  OneClickSigninSyncStarter::StartSyncMode mode_;
75  int bubble_learn_more_click_count_;
76  int dialog_learn_more_click_count_;
77  int advanced_click_count_;
78
79 private:
80  friend class OneClickSigninBubbleTestDelegate;
81
82  class OneClickSigninBubbleTestDelegate
83      : public OneClickSigninBubbleDelegate {
84   public:
85    // |test| is not owned by this object.
86    explicit OneClickSigninBubbleTestDelegate(
87        OneClickSigninBubbleViewTest* test) : test_(test) {}
88
89    // OneClickSigninBubbleDelegate:
90    virtual void OnLearnMoreLinkClicked(bool is_dialog) OVERRIDE {
91      if (is_dialog)
92        ++test_->dialog_learn_more_click_count_;
93      else
94        ++test_->bubble_learn_more_click_count_;
95    }
96    virtual void OnAdvancedLinkClicked() OVERRIDE {
97      ++test_->advanced_click_count_;
98    }
99
100   private:
101    OneClickSigninBubbleViewTest* test_;
102
103    DISALLOW_COPY_AND_ASSIGN(OneClickSigninBubbleTestDelegate);
104  };
105
106  // Widget to host the anchor view of the bubble. Destroys itself when closed.
107  views::Widget* anchor_widget_;
108
109  DISALLOW_COPY_AND_ASSIGN(OneClickSigninBubbleViewTest);
110};
111
112TEST_F(OneClickSigninBubbleViewTest, ShowBubble) {
113  ShowOneClickSigninBubble(BrowserWindow::ONE_CLICK_SIGNIN_BUBBLE_TYPE_BUBBLE);
114  content::RunAllPendingInMessageLoop();
115  EXPECT_TRUE(OneClickSigninBubbleView::IsShowing());
116}
117
118TEST_F(OneClickSigninBubbleViewTest, ShowDialog) {
119  ShowOneClickSigninBubble(
120    BrowserWindow::ONE_CLICK_SIGNIN_BUBBLE_TYPE_MODAL_DIALOG);
121  content::RunAllPendingInMessageLoop();
122  EXPECT_TRUE(OneClickSigninBubbleView::IsShowing());
123}
124
125TEST_F(OneClickSigninBubbleViewTest, HideBubble) {
126  ShowOneClickSigninBubble(BrowserWindow::ONE_CLICK_SIGNIN_BUBBLE_TYPE_BUBBLE);
127
128  OneClickSigninBubbleView::Hide();
129  content::RunAllPendingInMessageLoop();
130  EXPECT_FALSE(OneClickSigninBubbleView::IsShowing());
131}
132
133TEST_F(OneClickSigninBubbleViewTest, HideDialog) {
134  ShowOneClickSigninBubble(
135    BrowserWindow::ONE_CLICK_SIGNIN_BUBBLE_TYPE_MODAL_DIALOG);
136
137  OneClickSigninBubbleView::Hide();
138  content::RunAllPendingInMessageLoop();
139  EXPECT_FALSE(OneClickSigninBubbleView::IsShowing());
140  EXPECT_TRUE(on_start_sync_called_);
141  EXPECT_EQ(OneClickSigninSyncStarter::UNDO_SYNC, mode_);
142}
143
144TEST_F(OneClickSigninBubbleViewTest, BubbleOkButton) {
145  OneClickSigninBubbleView* view =
146    ShowOneClickSigninBubble(
147      BrowserWindow::ONE_CLICK_SIGNIN_BUBBLE_TYPE_BUBBLE);
148
149  // Simulate pressing the OK button.  Set the message loop in the bubble
150  // view so that it can be quit once the bubble is hidden.
151  views::ButtonListener* listener = view;
152  const ui::MouseEvent event(ui::ET_MOUSE_PRESSED,
153                             gfx::Point(), gfx::Point(),
154                             0, 0);
155  listener->ButtonPressed(view->ok_button_, event);
156
157  // View should no longer be showing.  The message loop will exit once the
158  // fade animation of the bubble is done.
159  content::RunAllPendingInMessageLoop();
160  EXPECT_FALSE(OneClickSigninBubbleView::IsShowing());
161}
162
163TEST_F(OneClickSigninBubbleViewTest, DialogOkButton) {
164  OneClickSigninBubbleView* view = ShowOneClickSigninBubble(
165      BrowserWindow::ONE_CLICK_SIGNIN_BUBBLE_TYPE_MODAL_DIALOG);
166
167  // Simulate pressing the OK button.  Set the message loop in the bubble
168  // view so that it can be quit once the bubble is hidden.
169  views::ButtonListener* listener = view;
170  const ui::MouseEvent event(ui::ET_MOUSE_PRESSED,
171                             gfx::Point(), gfx::Point(),
172                             0, 0);
173  listener->ButtonPressed(view->ok_button_, event);
174
175  // View should no longer be showing and sync should start
176  // The message loop will exit once the fade animation of the dialog is done.
177  content::RunAllPendingInMessageLoop();
178  EXPECT_FALSE(OneClickSigninBubbleView::IsShowing());
179  EXPECT_TRUE(on_start_sync_called_);
180  EXPECT_EQ(OneClickSigninSyncStarter::SYNC_WITH_DEFAULT_SETTINGS, mode_);
181}
182
183TEST_F(OneClickSigninBubbleViewTest, DialogUndoButton) {
184  OneClickSigninBubbleView* view = ShowOneClickSigninBubble(
185    BrowserWindow::ONE_CLICK_SIGNIN_BUBBLE_TYPE_MODAL_DIALOG);
186
187  // Simulate pressing the undo button.  Set the message loop in the bubble
188  // view so that it can be quit once the bubble is hidden.
189  views::ButtonListener* listener = view;
190  const ui::MouseEvent event(ui::ET_MOUSE_PRESSED,
191                             gfx::Point(), gfx::Point(),
192                             0, 0);
193  listener->ButtonPressed(view->undo_button_, event);
194
195  // View should no longer be showing.  The message loop will exit once the
196  // fade animation of the bubble is done.
197  content::RunAllPendingInMessageLoop();
198  EXPECT_FALSE(OneClickSigninBubbleView::IsShowing());
199  EXPECT_TRUE(on_start_sync_called_);
200  EXPECT_EQ(OneClickSigninSyncStarter::UNDO_SYNC, mode_);
201}
202
203TEST_F(OneClickSigninBubbleViewTest, BubbleAdvancedLink) {
204  OneClickSigninBubbleView* view = ShowOneClickSigninBubble(
205    BrowserWindow::ONE_CLICK_SIGNIN_BUBBLE_TYPE_BUBBLE);
206
207  // Simulate pressing a link in the bubble.
208  views::LinkListener* listener = view;
209  listener->LinkClicked(view->advanced_link_, 0);
210
211  // View should no longer be showing and the OnAdvancedLinkClicked method
212  // of the delegate should have been called.
213  content::RunAllPendingInMessageLoop();
214  EXPECT_FALSE(OneClickSigninBubbleView::IsShowing());
215  EXPECT_EQ(1, advanced_click_count_);
216}
217
218TEST_F(OneClickSigninBubbleViewTest, DialogAdvancedLink) {
219  OneClickSigninBubbleView* view = ShowOneClickSigninBubble(
220    BrowserWindow::ONE_CLICK_SIGNIN_BUBBLE_TYPE_MODAL_DIALOG);
221
222  // Simulate pressing a link in the bubble.
223  views::LinkListener* listener = view;
224  listener->LinkClicked(view->advanced_link_, 0);
225
226  // View should no longer be showing. No delegate method should have been
227  // called: the callback is responsible to open the settings page.
228  content::RunAllPendingInMessageLoop();
229  EXPECT_TRUE(on_start_sync_called_);
230  EXPECT_EQ(OneClickSigninSyncStarter::CONFIGURE_SYNC_FIRST, mode_);
231  EXPECT_FALSE(OneClickSigninBubbleView::IsShowing());
232  EXPECT_EQ(0, advanced_click_count_);
233}
234
235TEST_F(OneClickSigninBubbleViewTest, BubbleLearnMoreLink) {
236  OneClickSigninBubbleView* view = ShowOneClickSigninBubble(
237    BrowserWindow::ONE_CLICK_SIGNIN_BUBBLE_TYPE_BUBBLE);
238
239  views::LinkListener* listener = view;
240  listener->LinkClicked(view->learn_more_link_, 0);
241
242  // View should no longer be showing and the OnLearnMoreLinkClicked method
243  // of the delegate should have been called with |is_dialog| == false.
244  content::RunAllPendingInMessageLoop();
245  EXPECT_FALSE(OneClickSigninBubbleView::IsShowing());
246  EXPECT_EQ(1, bubble_learn_more_click_count_);
247  EXPECT_EQ(0, dialog_learn_more_click_count_);
248}
249
250TEST_F(OneClickSigninBubbleViewTest, DialogLearnMoreLink) {
251  OneClickSigninBubbleView* view = ShowOneClickSigninBubble(
252      BrowserWindow::ONE_CLICK_SIGNIN_BUBBLE_TYPE_MODAL_DIALOG);
253
254  views::LinkListener* listener = view;
255  listener->LinkClicked(view->learn_more_link_, 0);
256
257  // View should still be showing and the OnLearnMoreLinkClicked method
258  // of the delegate should have been called with |is_dialog| == true.
259  content::RunAllPendingInMessageLoop();
260  EXPECT_TRUE(OneClickSigninBubbleView::IsShowing());
261  EXPECT_EQ(0, bubble_learn_more_click_count_);
262  EXPECT_EQ(1, dialog_learn_more_click_count_);
263}
264
265TEST_F(OneClickSigninBubbleViewTest, BubblePressEnterKey) {
266  OneClickSigninBubbleView* one_click_view = ShowOneClickSigninBubble(
267    BrowserWindow::ONE_CLICK_SIGNIN_BUBBLE_TYPE_BUBBLE);
268
269  // Simulate pressing the Enter key.
270  views::View* view = one_click_view;
271  const ui::Accelerator accelerator(ui::VKEY_RETURN, 0);
272  view->AcceleratorPressed(accelerator);
273
274  // View should no longer be showing.  The message loop will exit once the
275  // fade animation of the bubble is done.
276  content::RunAllPendingInMessageLoop();
277  EXPECT_FALSE(OneClickSigninBubbleView::IsShowing());
278}
279
280TEST_F(OneClickSigninBubbleViewTest, DialogPressEnterKey) {
281  OneClickSigninBubbleView* one_click_view = ShowOneClickSigninBubble(
282    BrowserWindow::ONE_CLICK_SIGNIN_BUBBLE_TYPE_MODAL_DIALOG);
283
284  // Simulate pressing the Enter key.
285  views::View* view = one_click_view;
286  const ui::Accelerator accelerator(ui::VKEY_RETURN, 0);
287  view->AcceleratorPressed(accelerator);
288
289  // View should no longer be showing.  The message loop will exit once the
290  // fade animation of the bubble is done.
291  content::RunAllPendingInMessageLoop();
292  EXPECT_FALSE(OneClickSigninBubbleView::IsShowing());
293  EXPECT_TRUE(on_start_sync_called_);
294  EXPECT_EQ(OneClickSigninSyncStarter::SYNC_WITH_DEFAULT_SETTINGS, mode_);
295}
296
297TEST_F(OneClickSigninBubbleViewTest, BubblePressEscapeKey) {
298  OneClickSigninBubbleView* one_click_view = ShowOneClickSigninBubble(
299    BrowserWindow::ONE_CLICK_SIGNIN_BUBBLE_TYPE_BUBBLE);
300
301  // Simulate pressing the Escape key.
302  views::View* view = one_click_view;
303  const ui::Accelerator accelerator(ui::VKEY_ESCAPE, 0);
304  view->AcceleratorPressed(accelerator);
305
306  // View should no longer be showing.  The message loop will exit once the
307  // fade animation of the bubble is done.
308  content::RunAllPendingInMessageLoop();
309  EXPECT_FALSE(OneClickSigninBubbleView::IsShowing());
310}
311
312TEST_F(OneClickSigninBubbleViewTest, DialogPressEscapeKey) {
313  OneClickSigninBubbleView* one_click_view = ShowOneClickSigninBubble(
314    BrowserWindow::ONE_CLICK_SIGNIN_BUBBLE_TYPE_MODAL_DIALOG);
315
316  // Simulate pressing the Escape key.
317  views::View* view = one_click_view;
318  const ui::Accelerator accelerator(ui::VKEY_ESCAPE, 0);
319  view->AcceleratorPressed(accelerator);
320
321  // View should no longer be showing.  The message loop will exit once the
322  // fade animation of the bubble is done.
323  content::RunAllPendingInMessageLoop();
324  EXPECT_FALSE(OneClickSigninBubbleView::IsShowing());
325  EXPECT_TRUE(on_start_sync_called_);
326  EXPECT_EQ(OneClickSigninSyncStarter::UNDO_SYNC, mode_);
327}
328