1 // Copyright 2018 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/tabs/tab_activity_simulator.h"
6 
7 #include "base/check.h"
8 #include "chrome/browser/profiles/profile.h"
9 #include "chrome/browser/ui/tabs/tab_strip_model.h"
10 #include "content/public/browser/web_contents.h"
11 #include "content/public/browser/web_contents_observer.h"
12 #include "content/public/test/navigation_simulator.h"
13 #include "content/public/test/web_contents_tester.h"
14 
15 // Helper class to respond to WebContents lifecycle events we can't
16 // trigger/simulate.
17 class TabActivitySimulator::TestWebContentsObserver
18     : public content::WebContentsObserver {
19  public:
20   explicit TestWebContentsObserver(content::WebContents* web_contents);
21   TestWebContentsObserver(const TestWebContentsObserver&) = delete;
22   TestWebContentsObserver& operator=(const TestWebContentsObserver&) = delete;
23 
24   // content::WebContentsObserver:
25   void WebContentsDestroyed() override;
26 };
27 
TestWebContentsObserver(content::WebContents * web_contents)28 TabActivitySimulator::TestWebContentsObserver::TestWebContentsObserver(
29     content::WebContents* web_contents)
30     : content::WebContentsObserver(web_contents) {}
31 
WebContentsDestroyed()32 void TabActivitySimulator::TestWebContentsObserver::WebContentsDestroyed() {
33   // Simulate the WebContents hiding during destruction. This lets tests
34   // validate what is logged when a tab is destroyed.
35   web_contents()->WasHidden();
36 }
37 
38 TabActivitySimulator::TabActivitySimulator() = default;
39 TabActivitySimulator::~TabActivitySimulator() = default;
40 
Navigate(content::WebContents * web_contents,const GURL & url,ui::PageTransition page_transition)41 void TabActivitySimulator::Navigate(content::WebContents* web_contents,
42                                     const GURL& url,
43                                     ui::PageTransition page_transition) {
44   std::unique_ptr<content::NavigationSimulator> navigation =
45       content::NavigationSimulator::CreateBrowserInitiated(url, web_contents);
46   navigation->SetTransition(page_transition);
47   navigation->SetKeepLoading(true);
48   navigation->Commit();
49 }
50 
CreateWebContents(content::BrowserContext * browser_context,bool initially_visible)51 std::unique_ptr<content::WebContents> TabActivitySimulator::CreateWebContents(
52     content::BrowserContext* browser_context,
53     bool initially_visible) {
54   content::WebContents::CreateParams params(browser_context, nullptr);
55   params.initially_hidden = !initially_visible;
56   std::unique_ptr<content::WebContents> test_contents(
57       content::WebContentsTester::CreateTestWebContents(params));
58 
59   // Create the TestWebContentsObserver to observe |test_contents|. When the
60   // WebContents is destroyed, the observer will be reset automatically.
61   observers_.push_back(
62       std::make_unique<TestWebContentsObserver>(test_contents.get()));
63   return test_contents;
64 }
65 
AddWebContentsAndNavigate(TabStripModel * tab_strip_model,const GURL & initial_url,ui::PageTransition page_transition)66 content::WebContents* TabActivitySimulator::AddWebContentsAndNavigate(
67     TabStripModel* tab_strip_model,
68     const GURL& initial_url,
69     ui::PageTransition page_transition) {
70   // Create as a foreground tab if it's the only tab in the tab strip.
71   bool initially_visible = tab_strip_model->empty();
72   std::unique_ptr<content::WebContents> test_contents =
73       CreateWebContents(tab_strip_model->profile(), initially_visible);
74   content::WebContents* raw_test_contents = test_contents.get();
75   tab_strip_model->AppendWebContents(std::move(test_contents),
76                                      initially_visible /* foreground */);
77   Navigate(raw_test_contents, initial_url, page_transition);
78   return raw_test_contents;
79 }
80 
SwitchToTabAt(TabStripModel * tab_strip_model,int new_index)81 void TabActivitySimulator::SwitchToTabAt(TabStripModel* tab_strip_model,
82                                          int new_index) {
83   int active_index = tab_strip_model->active_index();
84   CHECK(new_index != active_index);
85 
86   content::WebContents* active_contents =
87       tab_strip_model->GetWebContentsAt(active_index);
88   CHECK(active_contents);
89   content::WebContents* new_contents =
90       tab_strip_model->GetWebContentsAt(new_index);
91   CHECK(new_contents);
92 
93   // Activate the tab. Normally this would hide the active tab's aura::Window,
94   // which is what actually triggers TabActivityWatcher to log the change. For
95   // a TestWebContents, we must manually call WasHidden(), and do the reverse
96   // for the newly activated tab.
97   tab_strip_model->ActivateTabAt(new_index,
98                                  {TabStripModel::GestureType::kOther});
99   active_contents->WasHidden();
100   new_contents->WasShown();
101 }
102