Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / chrome / browser / ui / views / ash / tab_scrubber_browsertest.cc
blob5209b39639d2af1050d9c5d931a039e5e71bfd84
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.
5 #include "chrome/browser/ui/views/ash/tab_scrubber.h"
7 #include "ash/display/event_transformation_handler.h"
8 #include "ash/shell.h"
9 #include "base/command_line.h"
10 #include "base/memory/scoped_ptr.h"
11 #include "base/run_loop.h"
12 #include "chrome/browser/ui/browser_tabstrip.h"
13 #include "chrome/browser/ui/tabs/tab_strip_model.h"
14 #include "chrome/browser/ui/tabs/tab_strip_model_observer.h"
15 #include "chrome/browser/ui/views/frame/browser_view.h"
16 #include "chrome/browser/ui/views/tabs/tab.h"
17 #include "chrome/browser/ui/views/tabs/tab_strip.h"
18 #include "chrome/common/chrome_switches.h"
19 #include "chrome/test/base/in_process_browser_test.h"
20 #include "content/public/browser/notification_service.h"
21 #include "content/public/common/url_constants.h"
22 #include "content/public/test/test_utils.h"
23 #include "ui/aura/window.h"
24 #include "ui/events/event_utils.h"
25 #include "ui/events/test/event_generator.h"
27 #if defined(OS_CHROMEOS)
28 #include "chromeos/chromeos_switches.h"
29 #endif
31 namespace {
33 class TabScrubberTest : public InProcessBrowserTest,
34 public TabStripModelObserver {
35 public:
36 TabScrubberTest()
37 : target_index_(-1) {
40 void SetUpCommandLine(base::CommandLine* command_line) override {
41 #if defined(OS_CHROMEOS)
42 command_line->AppendSwitch(chromeos::switches::kNaturalScrollDefault);
43 #endif
44 command_line->AppendSwitch(switches::kOpenAsh);
47 void SetUpOnMainThread() override {
48 TabScrubber::GetInstance()->set_activation_delay(0);
50 // Disable external monitor scaling of coordinates.
51 ash::Shell* shell = ash::Shell::GetInstance();
52 shell->event_transformation_handler()->set_transformation_mode(
53 ash::EventTransformationHandler::TRANSFORM_NONE);
56 void TearDownOnMainThread() override {
57 browser()->tab_strip_model()->RemoveObserver(this);
60 TabStrip* GetTabStrip(Browser* browser) {
61 aura::Window* window = browser->window()->GetNativeWindow();
62 return BrowserView::GetBrowserViewForNativeWindow(window)->tabstrip();
65 float GetStartX(Browser* browser,
66 int index,
67 TabScrubber::Direction direction) {
68 return static_cast<float>(TabScrubber::GetStartPoint(
69 GetTabStrip(browser), index, direction).x());
72 float GetTabCenter(Browser* browser, int index) {
73 return static_cast<float>(GetTabStrip(browser)
74 ->tab_at(index)
75 ->GetMirroredBounds()
76 .CenterPoint()
77 .x());
80 // The simulated scroll event's offsets are calculated in the tests rather
81 // than generated by the real event system. For the offsets calculation to be
82 // correct in an RTL layout, we must invert the direction since it is
83 // calculated here in the tests based on the indices and they're inverted in
84 // RTL layouts:
85 // Tab indices in an English layout : 0 - 1 - 2 - 3 - 4.
86 // Tab indices in an Arabic layout : 4 - 3 - 2 - 1 - 0.
87 TabScrubber::Direction InvertDirectionIfNeeded(
88 TabScrubber::Direction direction) {
89 if (base::i18n::IsRTL()) {
90 return direction == TabScrubber::LEFT ? TabScrubber::RIGHT
91 : TabScrubber::LEFT;
94 return direction;
97 // Sends one scroll event synchronously without initial or final
98 // fling events.
99 void SendScrubEvent(Browser* browser, int index) {
100 aura::Window* window = browser->window()->GetNativeWindow();
101 aura::Window* root = window->GetRootWindow();
102 ui::test::EventGenerator event_generator(root, window);
103 int active_index = browser->tab_strip_model()->active_index();
104 TabScrubber::Direction direction = index < active_index ?
105 TabScrubber::LEFT : TabScrubber::RIGHT;
107 direction = InvertDirectionIfNeeded(direction);
109 float offset = GetTabCenter(browser, index) -
110 GetStartX(browser, active_index, direction);
111 ui::ScrollEvent scroll_event(ui::ET_SCROLL,
112 gfx::PointF(0, 0),
113 ui::EventTimeForNow(),
115 offset, 0,
116 offset, 0,
118 event_generator.Dispatch(&scroll_event);
121 enum ScrubType {
122 EACH_TAB,
123 SKIP_TABS,
124 REPEAT_TABS,
127 // Sends asynchronous events and waits for tab at |index| to become
128 // active.
129 void Scrub(Browser* browser, int index, ScrubType scrub_type) {
130 aura::Window* window = browser->window()->GetNativeWindow();
131 aura::Window* root = window->GetRootWindow();
132 ui::test::EventGenerator event_generator(root, window);
133 event_generator.set_async(true);
134 activation_order_.clear();
135 int active_index = browser->tab_strip_model()->active_index();
136 ASSERT_NE(index, active_index);
137 ASSERT_TRUE(scrub_type != SKIP_TABS || ((index - active_index) % 2) == 0);
138 TabScrubber::Direction direction;
139 int increment;
140 if (index < active_index) {
141 direction = TabScrubber::LEFT;
142 increment = -1;
143 } else {
144 direction = TabScrubber::RIGHT;
145 increment = 1;
148 direction = InvertDirectionIfNeeded(direction);
150 if (scrub_type == SKIP_TABS)
151 increment *= 2;
152 float last = GetStartX(browser, active_index, direction);
153 std::vector<gfx::PointF> offsets;
154 for (int i = active_index + increment; i != (index + increment);
155 i += increment) {
156 float tab_center = GetTabCenter(browser, i);
157 offsets.push_back(gfx::PointF(tab_center - last, 0));
158 last = GetStartX(browser, i, direction);
159 if (scrub_type == REPEAT_TABS) {
160 offsets.push_back(gfx::PointF(static_cast<float>(increment), 0));
161 last += increment;
164 event_generator.ScrollSequence(gfx::Point(0, 0),
165 base::TimeDelta::FromMilliseconds(100),
166 offsets,
168 RunUntilTabActive(browser, index);
171 // Sends events and waits for tab at |index| to become active
172 // if it's different from the currently active tab.
173 // If the active tab is expected to stay the same, send events
174 // synchronously (as we don't have anything to wait for).
175 void SendScrubSequence(Browser* browser, float x_offset, int index) {
176 aura::Window* window = browser->window()->GetNativeWindow();
177 aura::Window* root = window->GetRootWindow();
178 ui::test::EventGenerator event_generator(root, window);
179 bool wait_for_active = false;
180 if (index != browser->tab_strip_model()->active_index()) {
181 wait_for_active = true;
182 event_generator.set_async(true);
184 event_generator.ScrollSequence(gfx::Point(0, 0),
185 ui::EventTimeForNow(),
186 x_offset,
190 if (wait_for_active)
191 RunUntilTabActive(browser, index);
194 void AddTabs(Browser* browser, int num_tabs) {
195 TabStrip* tab_strip = GetTabStrip(browser);
196 for (int i = 0; i < num_tabs; ++i)
197 AddBlankTabAndShow(browser);
198 ASSERT_EQ(num_tabs + 1, browser->tab_strip_model()->count());
199 ASSERT_EQ(num_tabs, browser->tab_strip_model()->active_index());
200 tab_strip->StopAnimating(true);
201 ASSERT_FALSE(tab_strip->IsAnimating());
204 // TabStripModelObserver overrides.
205 void TabInsertedAt(content::WebContents* contents,
206 int index,
207 bool foreground) override {}
208 void TabClosingAt(TabStripModel* tab_strip_model,
209 content::WebContents* contents,
210 int index) override {}
211 void TabDetachedAt(content::WebContents* contents, int index) override {}
212 void TabDeactivated(content::WebContents* contents) override {}
213 void ActiveTabChanged(content::WebContents* old_contents,
214 content::WebContents* new_contents,
215 int index,
216 int reason) override {
217 activation_order_.push_back(index);
218 if (index == target_index_)
219 quit_closure_.Run();
222 void TabSelectionChanged(TabStripModel* tab_strip_model,
223 const ui::ListSelectionModel& old_model) override {}
224 void TabMoved(content::WebContents* contents,
225 int from_index,
226 int to_index) override {}
227 void TabChangedAt(content::WebContents* contents,
228 int index,
229 TabChangeType change_type) override {}
230 void TabReplacedAt(TabStripModel* tab_strip_model,
231 content::WebContents* old_contents,
232 content::WebContents* new_contents,
233 int index) override {}
234 void TabPinnedStateChanged(content::WebContents* contents,
235 int index) override {}
236 void TabBlockedStateChanged(content::WebContents* contents,
237 int index) override {}
238 void TabStripEmpty() override {}
239 void TabStripModelDeleted() override {}
241 // History of tab activation. Scrub() resets it.
242 std::vector<int> activation_order_;
244 private:
245 void RunUntilTabActive(Browser* browser, int target) {
246 base::RunLoop run_loop;
247 quit_closure_ = content::GetQuitTaskForRunLoop(&run_loop);
248 browser->tab_strip_model()->AddObserver(this);
249 target_index_ = target;
250 content::RunThisRunLoop(&run_loop);
251 browser->tab_strip_model()->RemoveObserver(this);
252 target_index_ = -1;
255 base::Closure quit_closure_;
256 int target_index_;
258 DISALLOW_COPY_AND_ASSIGN(TabScrubberTest);
261 } // namespace
263 #if defined(OS_CHROMEOS)
264 // Swipe a single tab in each direction.
265 IN_PROC_BROWSER_TEST_F(TabScrubberTest, Single) {
266 AddTabs(browser(), 1);
268 Scrub(browser(), 0, EACH_TAB);
269 EXPECT_EQ(1U, activation_order_.size());
270 EXPECT_EQ(0, activation_order_[0]);
271 EXPECT_EQ(0, browser()->tab_strip_model()->active_index());
273 Scrub(browser(), 1, EACH_TAB);
274 EXPECT_EQ(1U, activation_order_.size());
275 EXPECT_EQ(1, activation_order_[0]);
276 EXPECT_EQ(1, browser()->tab_strip_model()->active_index());
279 // Swipe 4 tabs in each direction. Each of the tabs should become active.
280 IN_PROC_BROWSER_TEST_F(TabScrubberTest, Multi) {
281 AddTabs(browser(), 4);
283 Scrub(browser(), 0, EACH_TAB);
284 ASSERT_EQ(4U, activation_order_.size());
285 EXPECT_EQ(3, activation_order_[0]);
286 EXPECT_EQ(2, activation_order_[1]);
287 EXPECT_EQ(1, activation_order_[2]);
288 EXPECT_EQ(0, activation_order_[3]);
289 EXPECT_EQ(0, browser()->tab_strip_model()->active_index());
291 Scrub(browser(), 4, EACH_TAB);
292 ASSERT_EQ(4U, activation_order_.size());
293 EXPECT_EQ(1, activation_order_[0]);
294 EXPECT_EQ(2, activation_order_[1]);
295 EXPECT_EQ(3, activation_order_[2]);
296 EXPECT_EQ(4, activation_order_[3]);
297 EXPECT_EQ(4, browser()->tab_strip_model()->active_index());
300 IN_PROC_BROWSER_TEST_F(TabScrubberTest, MultiBrowser) {
301 AddTabs(browser(), 1);
302 Scrub(browser(), 0, EACH_TAB);
303 EXPECT_EQ(0, browser()->tab_strip_model()->active_index());
305 Browser* browser2 = CreateBrowser(browser()->profile());
306 browser2->window()->Activate();
307 ASSERT_TRUE(browser2->window()->IsActive());
308 ASSERT_FALSE(browser()->window()->IsActive());
309 AddTabs(browser2, 1);
311 Scrub(browser2, 0, EACH_TAB);
312 EXPECT_EQ(0, browser2->tab_strip_model()->active_index());
315 // Swipe 4 tabs in each direction with an extra swipe within each. The same
316 // 4 tabs should become active.
317 IN_PROC_BROWSER_TEST_F(TabScrubberTest, Repeated) {
318 AddTabs(browser(), 4);
320 Scrub(browser(), 0, REPEAT_TABS);
321 ASSERT_EQ(4U, activation_order_.size());
322 EXPECT_EQ(3, activation_order_[0]);
323 EXPECT_EQ(2, activation_order_[1]);
324 EXPECT_EQ(1, activation_order_[2]);
325 EXPECT_EQ(0, activation_order_[3]);
326 EXPECT_EQ(0, browser()->tab_strip_model()->active_index());
328 Scrub(browser(), 4, REPEAT_TABS);
329 ASSERT_EQ(4U, activation_order_.size());
330 EXPECT_EQ(1, activation_order_[0]);
331 EXPECT_EQ(2, activation_order_[1]);
332 EXPECT_EQ(3, activation_order_[2]);
333 EXPECT_EQ(4, activation_order_[3]);
334 EXPECT_EQ(4, browser()->tab_strip_model()->active_index());
337 // Confirm that we get the last tab made active when we skip tabs.
338 // These tests have 5 total tabs. We will only received scroll events
339 // on tabs 0, 2 and 4.
340 IN_PROC_BROWSER_TEST_F(TabScrubberTest, Skipped) {
341 AddTabs(browser(), 4);
343 Scrub(browser(), 0, SKIP_TABS);
344 EXPECT_EQ(2U, activation_order_.size());
345 EXPECT_EQ(2, activation_order_[0]);
346 EXPECT_EQ(0, activation_order_[1]);
347 EXPECT_EQ(0, browser()->tab_strip_model()->active_index());
349 Scrub(browser(), 4, SKIP_TABS);
350 EXPECT_EQ(2U, activation_order_.size());
351 EXPECT_EQ(2, activation_order_[0]);
352 EXPECT_EQ(4, activation_order_[1]);
353 EXPECT_EQ(4, browser()->tab_strip_model()->active_index());
356 // Confirm that nothing happens when the swipe is small.
357 IN_PROC_BROWSER_TEST_F(TabScrubberTest, NoChange) {
358 AddTabs(browser(), 1);
360 SendScrubSequence(browser(), -1, 1);
361 EXPECT_EQ(1, browser()->tab_strip_model()->active_index());
363 SendScrubSequence(browser(), 1, 1);
364 EXPECT_EQ(1, browser()->tab_strip_model()->active_index());
367 // Confirm that very large swipes go to the beginning and and of the tabstrip.
368 IN_PROC_BROWSER_TEST_F(TabScrubberTest, Bounds) {
369 AddTabs(browser(), 1);
371 SendScrubSequence(browser(), -10000, 0);
372 EXPECT_EQ(0, browser()->tab_strip_model()->active_index());
374 SendScrubSequence(browser(), 10000, 1);
375 EXPECT_EQ(1, browser()->tab_strip_model()->active_index());
378 IN_PROC_BROWSER_TEST_F(TabScrubberTest, DeleteHighlighted) {
379 AddTabs(browser(), 1);
381 SendScrubEvent(browser(), 0);
382 EXPECT_TRUE(TabScrubber::GetInstance()->IsActivationPending());
383 browser()->tab_strip_model()->CloseWebContentsAt(0,
384 TabStripModel::CLOSE_NONE);
385 EXPECT_FALSE(TabScrubber::GetInstance()->IsActivationPending());
388 // Delete the currently highlighted tab. Make sure the TabScrubber is aware.
389 IN_PROC_BROWSER_TEST_F(TabScrubberTest, DeleteBeforeHighlighted) {
390 AddTabs(browser(), 2);
392 SendScrubEvent(browser(), 1);
393 EXPECT_TRUE(TabScrubber::GetInstance()->IsActivationPending());
394 browser()->tab_strip_model()->CloseWebContentsAt(0,
395 TabStripModel::CLOSE_NONE);
396 EXPECT_EQ(0, TabScrubber::GetInstance()->highlighted_tab());
399 // Move the currently highlighted tab and confirm it gets tracked.
400 IN_PROC_BROWSER_TEST_F(TabScrubberTest, MoveHighlighted) {
401 AddTabs(browser(), 1);
403 SendScrubEvent(browser(), 0);
404 EXPECT_TRUE(TabScrubber::GetInstance()->IsActivationPending());
405 browser()->tab_strip_model()->ToggleSelectionAt(0);
406 browser()->tab_strip_model()->ToggleSelectionAt(1);
407 browser()->tab_strip_model()->MoveSelectedTabsTo(1);
408 EXPECT_EQ(1, TabScrubber::GetInstance()->highlighted_tab());
411 // Move a tab to before the highlighted one. Make sure that the highlighted tab
412 // index is updated correctly.
413 IN_PROC_BROWSER_TEST_F(TabScrubberTest, MoveBefore) {
414 AddTabs(browser(), 2);
416 SendScrubEvent(browser(), 1);
417 EXPECT_TRUE(TabScrubber::GetInstance()->IsActivationPending());
418 browser()->tab_strip_model()->ToggleSelectionAt(0);
419 browser()->tab_strip_model()->ToggleSelectionAt(2);
420 browser()->tab_strip_model()->MoveSelectedTabsTo(2);
421 EXPECT_EQ(0, TabScrubber::GetInstance()->highlighted_tab());
424 // Move a tab to after the highlighted one. Make sure that the highlighted tab
425 // index is updated correctly.
426 IN_PROC_BROWSER_TEST_F(TabScrubberTest, MoveAfter) {
427 AddTabs(browser(), 2);
429 SendScrubEvent(browser(), 1);
430 EXPECT_TRUE(TabScrubber::GetInstance()->IsActivationPending());
431 browser()->tab_strip_model()->MoveSelectedTabsTo(0);
432 EXPECT_EQ(2, TabScrubber::GetInstance()->highlighted_tab());
435 // Close the browser while an activation is pending.
436 IN_PROC_BROWSER_TEST_F(TabScrubberTest, CloseBrowser) {
437 AddTabs(browser(), 1);
439 SendScrubEvent(browser(), 0);
440 EXPECT_TRUE(TabScrubber::GetInstance()->IsActivationPending());
441 browser()->window()->Close();
442 EXPECT_FALSE(TabScrubber::GetInstance()->IsActivationPending());
445 // In an RTL layout, swipe 4 tabs in each direction. Each of the tabs should
446 // become active.
447 IN_PROC_BROWSER_TEST_F(TabScrubberTest, RTLMulti) {
448 base::i18n::SetICUDefaultLocale("ar");
449 ASSERT_TRUE(base::i18n::IsRTL());
451 AddTabs(browser(), 4);
453 Scrub(browser(), 0, EACH_TAB);
454 ASSERT_EQ(4U, activation_order_.size());
455 EXPECT_EQ(3, activation_order_[0]);
456 EXPECT_EQ(2, activation_order_[1]);
457 EXPECT_EQ(1, activation_order_[2]);
458 EXPECT_EQ(0, activation_order_[3]);
459 EXPECT_EQ(0, browser()->tab_strip_model()->active_index());
461 Scrub(browser(), 4, EACH_TAB);
462 ASSERT_EQ(4U, activation_order_.size());
463 EXPECT_EQ(1, activation_order_[0]);
464 EXPECT_EQ(2, activation_order_[1]);
465 EXPECT_EQ(3, activation_order_[2]);
466 EXPECT_EQ(4, activation_order_[3]);
467 EXPECT_EQ(4, browser()->tab_strip_model()->active_index());
470 // In an RTL layout, confirm that we get the last tab made active when we skip
471 // tabs. These tests have 5 total tabs. We will only received scroll events
472 // on tabs 0, 2 and 4.
473 IN_PROC_BROWSER_TEST_F(TabScrubberTest, RTLSkipped) {
474 base::i18n::SetICUDefaultLocale("ar");
475 ASSERT_TRUE(base::i18n::IsRTL());
477 AddTabs(browser(), 4);
479 Scrub(browser(), 0, SKIP_TABS);
480 EXPECT_EQ(2U, activation_order_.size());
481 EXPECT_EQ(2, activation_order_[0]);
482 EXPECT_EQ(0, activation_order_[1]);
483 EXPECT_EQ(0, browser()->tab_strip_model()->active_index());
485 Scrub(browser(), 4, SKIP_TABS);
486 EXPECT_EQ(2U, activation_order_.size());
487 EXPECT_EQ(2, activation_order_[0]);
488 EXPECT_EQ(4, activation_order_[1]);
489 EXPECT_EQ(4, browser()->tab_strip_model()->active_index());
492 // In an RTL layout, move a tab to before the highlighted one. Make sure that
493 // the highlighted tab index is updated correctly.
494 IN_PROC_BROWSER_TEST_F(TabScrubberTest, RTLMoveBefore) {
495 base::i18n::SetICUDefaultLocale("ar");
496 ASSERT_TRUE(base::i18n::IsRTL());
498 AddTabs(browser(), 2);
500 SendScrubEvent(browser(), 1);
501 EXPECT_TRUE(TabScrubber::GetInstance()->IsActivationPending());
502 browser()->tab_strip_model()->ToggleSelectionAt(0);
503 browser()->tab_strip_model()->ToggleSelectionAt(2);
504 browser()->tab_strip_model()->MoveSelectedTabsTo(2);
505 EXPECT_EQ(0, TabScrubber::GetInstance()->highlighted_tab());
508 #endif // defined(OS_CHROMEOS)