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.
7 #include "base/command_line.h"
8 #include "base/memory/scoped_ptr.h"
9 #include "base/message_loop/message_loop.h"
10 #include "chrome/browser/extensions/active_script_controller.h"
11 #include "chrome/browser/extensions/api/extension_action/extension_action_api.h"
12 #include "chrome/browser/extensions/extension_action.h"
13 #include "chrome/browser/extensions/extension_action_manager.h"
14 #include "chrome/browser/extensions/extension_service.h"
15 #include "chrome/browser/extensions/location_bar_controller.h"
16 #include "chrome/browser/extensions/tab_helper.h"
17 #include "chrome/browser/extensions/test_extension_system.h"
18 #include "chrome/browser/sessions/session_tab_helper.h"
19 #include "chrome/test/base/chrome_render_view_host_test_harness.h"
20 #include "chrome/test/base/testing_profile.h"
21 #include "components/crx_file/id_util.h"
22 #include "extensions/common/extension.h"
23 #include "extensions/common/extension_builder.h"
24 #include "extensions/common/feature_switch.h"
25 #include "extensions/common/value_builder.h"
27 #if defined(OS_CHROMEOS)
28 #include "chrome/browser/chromeos/login/users/scoped_test_user_manager.h"
29 #include "chrome/browser/chromeos/settings/cros_settings.h"
30 #include "chrome/browser/chromeos/settings/device_settings_service.h"
33 namespace extensions
{
36 class LocationBarControllerUnitTest
: public ChromeRenderViewHostTestHarness
{
38 void SetUp() override
{
39 active_script_override_
.reset(new FeatureSwitch::ScopedOverride(
40 FeatureSwitch::scripts_require_action(), true));
42 ChromeRenderViewHostTestHarness::SetUp();
43 #if defined OS_CHROMEOS
44 test_user_manager_
.reset(new chromeos::ScopedTestUserManager());
46 TabHelper::CreateForWebContents(web_contents());
47 // Create an ExtensionService so the LocationBarController can find its
49 base::CommandLine
command_line(base::CommandLine::NO_PROGRAM
);
51 Profile::FromBrowserContext(web_contents()->GetBrowserContext());
52 extension_service_
= static_cast<TestExtensionSystem
*>(
53 ExtensionSystem::Get(profile
))->CreateExtensionService(
54 &command_line
, base::FilePath(), false);
57 void TearDown() override
{
58 #if defined OS_CHROMEOS
59 test_user_manager_
.reset();
61 ChromeRenderViewHostTestHarness::TearDown();
65 return SessionTabHelper::IdForTab(web_contents());
68 const Extension
* AddExtension(bool has_page_actions
,
69 const std::string
& name
) {
70 DictionaryBuilder manifest
;
71 manifest
.Set("name", name
)
72 .Set("version", "1.0.0")
73 .Set("manifest_version", 2)
74 .Set("permissions", ListBuilder().Append("tabs"));
75 if (has_page_actions
) {
76 manifest
.Set("page_action", DictionaryBuilder()
77 .Set("default_title", "Hello"));
79 scoped_refptr
<const Extension
> extension
=
80 ExtensionBuilder().SetManifest(manifest
.Pass())
81 .SetID(crx_file::id_util::GenerateId(name
))
83 extension_service_
->AddExtension(extension
.get());
84 return extension
.get();
87 ExtensionService
* extension_service_
;
90 #if defined OS_CHROMEOS
91 chromeos::ScopedTestDeviceSettingsService test_device_settings_service_
;
92 chromeos::ScopedTestCrosSettings test_cros_settings_
;
93 scoped_ptr
<chromeos::ScopedTestUserManager
> test_user_manager_
;
96 // Since we also test that we show page actions for pending script requests,
97 // we need to enable that feature.
98 scoped_ptr
<FeatureSwitch::ScopedOverride
> active_script_override_
;
101 // Test that the location bar gets the proper current actions.
102 TEST_F(LocationBarControllerUnitTest
, LocationBarDisplaysPageActions
) {
103 // Load up two extensions, one with a page action and one without.
104 const Extension
* page_action
= AddExtension(true, "page_actions");
105 const Extension
* no_action
= AddExtension(false, "no_actions");
107 TabHelper
* tab_helper
= TabHelper::FromWebContents(web_contents());
108 ASSERT_TRUE(tab_helper
);
109 LocationBarController
* controller
= tab_helper
->location_bar_controller();
110 ASSERT_TRUE(controller
);
112 // There should only be one action - the action for the extension with a
114 std::vector
<ExtensionAction
*> current_actions
=
115 controller
->GetCurrentActions();
116 ASSERT_EQ(1u, current_actions
.size());
117 EXPECT_EQ(page_action
->id(), current_actions
[0]->extension_id());
119 // If we request a script injection, then the location bar controller should
120 // also show a page action for that extension.
121 ActiveScriptController
* active_script_controller
=
122 ActiveScriptController::GetForWebContents(web_contents());
123 ASSERT_TRUE(active_script_controller
);
124 active_script_controller
->RequestScriptInjectionForTesting(no_action
,
126 current_actions
= controller
->GetCurrentActions();
127 ASSERT_EQ(2u, current_actions
.size());
128 // Check that each extension is present in the vector.
129 EXPECT_TRUE(current_actions
[0]->extension_id() == no_action
->id() ||
130 current_actions
[1]->extension_id() == no_action
->id());
131 EXPECT_TRUE(current_actions
[0]->extension_id() == page_action
->id() ||
132 current_actions
[1]->extension_id() == page_action
->id());
134 // If we request a script injection for an extension that already has a
135 // page action, only one action should be visible.
136 active_script_controller
->RequestScriptInjectionForTesting(page_action
,
138 current_actions
= controller
->GetCurrentActions();
139 ASSERT_EQ(2u, current_actions
.size());
140 EXPECT_TRUE(current_actions
[0]->extension_id() == no_action
->id() ||
141 current_actions
[1]->extension_id() == no_action
->id());
142 EXPECT_TRUE(current_actions
[0]->extension_id() == page_action
->id() ||
143 current_actions
[1]->extension_id() == page_action
->id());
145 // Navigating away means that only page actions are shown again.
146 NavigateAndCommit(GURL("http://google.com"));
147 current_actions
= controller
->GetCurrentActions();
148 ASSERT_EQ(1u, current_actions
.size());
149 EXPECT_EQ(page_action
->id(), current_actions
[0]->extension_id());
152 // Test that navigating clears all state in a page action.
153 TEST_F(LocationBarControllerUnitTest
, NavigationClearsState
) {
154 const Extension
* extension
= AddExtension(true, "page_actions");
156 NavigateAndCommit(GURL("http://www.google.com"));
158 ExtensionAction
& page_action
=
159 *ExtensionActionManager::Get(profile())->GetPageAction(*extension
);
160 page_action
.SetTitle(tab_id(), "Goodbye");
161 page_action
.SetPopupUrl(tab_id(), extension
->GetResourceURL("popup.html"));
163 ExtensionActionAPI
* extension_action_api
=
164 ExtensionActionAPI::Get(profile());
165 // By default, extensions shouldn't want to act on a page.
166 EXPECT_FALSE(extension_action_api
->ExtensionWantsToRun(extension
,
168 // Showing the page action should indicate that an extension *does* want to
170 page_action
.SetIsVisible(tab_id(), true);
171 EXPECT_TRUE(extension_action_api
->ExtensionWantsToRun(extension
,
174 EXPECT_EQ("Goodbye", page_action
.GetTitle(tab_id()));
175 EXPECT_EQ(extension
->GetResourceURL("popup.html"),
176 page_action
.GetPopupUrl(tab_id()));
178 // Within-page navigation should keep the settings.
179 NavigateAndCommit(GURL("http://www.google.com/#hash"));
181 EXPECT_EQ("Goodbye", page_action
.GetTitle(tab_id()));
182 EXPECT_EQ(extension
->GetResourceURL("popup.html"),
183 page_action
.GetPopupUrl(tab_id()));
184 EXPECT_TRUE(extension_action_api
->ExtensionWantsToRun(extension
,
187 // Should discard the settings, and go back to the defaults.
188 NavigateAndCommit(GURL("http://www.yahoo.com"));
190 EXPECT_EQ("Hello", page_action
.GetTitle(tab_id()));
191 EXPECT_EQ(GURL(), page_action
.GetPopupUrl(tab_id()));
192 EXPECT_FALSE(extension_action_api
->ExtensionWantsToRun(extension
,
197 } // namespace extensions