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