1 // Copyright 2014 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/extensions/extension_install_dialog_view.h"
7 #include "base/strings/utf_string_conversions.h"
8 #include "chrome/browser/extensions/extension_browsertest.h"
9 #include "chrome/browser/extensions/extension_icon_manager.h"
10 #include "chrome/browser/extensions/extension_install_prompt.h"
11 #include "chrome/browser/extensions/extension_install_prompt_experiment.h"
12 #include "chrome/browser/ui/browser.h"
13 #include "chrome/browser/ui/tabs/tab_strip_model.h"
14 #include "chrome/browser/ui/webui/extensions/extension_settings_handler.h"
15 #include "chrome/common/extensions/extension_test_util.h"
16 #include "components/constrained_window/constrained_window_views.h"
17 #include "content/public/browser/browser_thread.h"
18 #include "content/public/test/test_utils.h"
19 #include "extensions/common/extension.h"
20 #include "extensions/common/permissions/permissions_data.h"
21 #include "extensions/common/test_util.h"
22 #include "ui/views/controls/scroll_view.h"
23 #include "ui/views/view.h"
24 #include "ui/views/widget/widget.h"
26 // A simple delegate implementation that counts the number of times
27 // |InstallUIProceed| and |InstallUIAbort| are called.
28 class MockExtensionInstallPromptDelegate
29 : public ExtensionInstallPrompt::Delegate {
31 MockExtensionInstallPromptDelegate()
35 // ExtensionInstallPrompt::Delegate overrides.
36 void InstallUIProceed() override;
37 void InstallUIAbort(bool user_initiated) override;
39 int proceed_count() { return proceed_count_; }
40 int abort_count() { return abort_count_; }
47 void MockExtensionInstallPromptDelegate::InstallUIProceed() {
51 void MockExtensionInstallPromptDelegate::InstallUIAbort(bool user_initiated) {
55 // This lets us construct the parent for the prompt we're constructing in our
57 class MockExtensionInstallPrompt : public ExtensionInstallPrompt {
59 explicit MockExtensionInstallPrompt(content::WebContents* web_contents)
60 : ExtensionInstallPrompt(web_contents), prompt_(NULL) {}
61 ~MockExtensionInstallPrompt() override {}
62 void set_prompt(ExtensionInstallPrompt::Prompt* prompt) {
65 ExtensionInstallPrompt::Prompt* get_prompt() {
70 ExtensionInstallPrompt::Prompt* prompt_;
73 class ExtensionInstallDialogViewTestBase : public ExtensionBrowserTest {
75 explicit ExtensionInstallDialogViewTestBase(
76 ExtensionInstallPrompt::PromptType prompt_type);
77 ~ExtensionInstallDialogViewTestBase() override {}
79 void SetUpOnMainThread() override;
81 ExtensionInstallPrompt::Prompt* prompt() { return prompt_.get(); }
82 content::WebContents* web_contents() { return web_contents_; }
83 MockExtensionInstallPromptDelegate* delegate() { return &delegate_; }
85 void SetPromptPermissions(std::vector<base::string16> permissions);
86 void SetPromptDetails(std::vector<base::string16> details);
87 void SetPromptRetainedFiles(std::vector<base::FilePath> files);
90 const extensions::Extension* extension_;
91 MockExtensionInstallPrompt* install_prompt_;
92 scoped_refptr<ExtensionInstallPrompt::Prompt> prompt_;
93 content::WebContents* web_contents_;
94 MockExtensionInstallPromptDelegate delegate_;
96 DISALLOW_COPY_AND_ASSIGN(ExtensionInstallDialogViewTestBase);
99 ExtensionInstallDialogViewTestBase::ExtensionInstallDialogViewTestBase(
100 ExtensionInstallPrompt::PromptType prompt_type)
102 install_prompt_(NULL),
103 prompt_(new ExtensionInstallPrompt::Prompt(prompt_type)),
104 web_contents_(NULL) {
107 void ExtensionInstallDialogViewTestBase::SetUpOnMainThread() {
108 ExtensionBrowserTest::SetUpOnMainThread();
110 extension_ = ExtensionBrowserTest::LoadExtension(test_data_dir_.AppendASCII(
111 "install_prompt/permissions_scrollbar_regression"));
113 web_contents_ = browser()->tab_strip_model()->GetWebContentsAt(0);
115 install_prompt_ = new MockExtensionInstallPrompt(web_contents_);
116 install_prompt_->set_prompt(prompt_.get());
117 prompt_->set_experiment(ExtensionInstallPromptExperiment::ControlGroup());
118 prompt_->set_extension(extension_);
120 scoped_ptr<ExtensionIconManager> icon_manager(new ExtensionIconManager());
121 const SkBitmap icon_bitmap = icon_manager->GetIcon(extension_->id());
122 gfx::Image icon = gfx::Image::CreateFrom1xBitmap(icon_bitmap);
123 prompt_->set_icon(icon);
125 this->SetPromptPermissions(std::vector<base::string16>());
126 this->SetPromptDetails(std::vector<base::string16>());
127 this->SetPromptRetainedFiles(std::vector<base::FilePath>());
130 void ExtensionInstallDialogViewTestBase::SetPromptPermissions(
131 std::vector<base::string16> permissions) {
132 prompt_->SetPermissions(permissions,
133 ExtensionInstallPrompt::REGULAR_PERMISSIONS);
136 void ExtensionInstallDialogViewTestBase::SetPromptDetails(
137 std::vector<base::string16> details) {
138 prompt_->SetPermissionsDetails(details,
139 ExtensionInstallPrompt::REGULAR_PERMISSIONS);
142 void ExtensionInstallDialogViewTestBase::SetPromptRetainedFiles(
143 std::vector<base::FilePath> files) {
144 prompt_->set_retained_files(files);
147 class ScrollbarTest : public ExtensionInstallDialogViewTestBase {
150 ~ScrollbarTest() override {}
152 bool IsScrollbarVisible();
155 DISALLOW_COPY_AND_ASSIGN(ScrollbarTest);
158 ScrollbarTest::ScrollbarTest()
159 : ExtensionInstallDialogViewTestBase(
160 ExtensionInstallPrompt::PERMISSIONS_PROMPT) {
163 bool ScrollbarTest::IsScrollbarVisible() {
164 ExtensionInstallDialogView* dialog = new ExtensionInstallDialogView(
170 // Create the modal view around the install dialog view.
171 views::Widget* modal =
172 CreateBrowserModalDialogViews(dialog,
173 web_contents()->GetTopLevelNativeWindow());
175 content::RunAllBlockingPoolTasksUntilIdle();
177 // Check if the vertical scrollbar is visible.
178 return dialog->scroll_view()->vertical_scroll_bar()->visible();
181 // Tests that a scrollbar _is_ shown for an excessively long extension
183 IN_PROC_BROWSER_TEST_F(ScrollbarTest, LongPromptScrollbar) {
184 base::string16 permission_string(base::ASCIIToUTF16("Test"));
185 std::vector<base::string16> permissions;
186 std::vector<base::string16> details;
187 for (int i = 0; i < 20; i++) {
188 permissions.push_back(permission_string);
189 details.push_back(base::string16());
191 this->SetPromptPermissions(permissions);
192 this->SetPromptDetails(details);
193 ASSERT_TRUE(IsScrollbarVisible()) << "Scrollbar is not visible";
196 // Tests that a scrollbar isn't shown for this regression case.
197 // See crbug.com/385570 for details.
198 IN_PROC_BROWSER_TEST_F(ScrollbarTest, ScrollbarRegression) {
199 base::string16 permission_string(base::ASCIIToUTF16(
200 "Read and modify your data on *.facebook.com"));
201 std::vector<base::string16> permissions;
202 permissions.push_back(permission_string);
203 this->SetPromptPermissions(permissions);
204 std::vector<base::string16> details;
205 details.push_back(base::string16());
206 this->SetPromptDetails(details);
207 ASSERT_FALSE(IsScrollbarVisible()) << "Scrollbar is visible";
210 class ExtensionInstallDialogViewTest
211 : public ExtensionInstallDialogViewTestBase {
213 ExtensionInstallDialogViewTest()
214 : ExtensionInstallDialogViewTestBase(
215 ExtensionInstallPrompt::INSTALL_PROMPT) {}
216 ~ExtensionInstallDialogViewTest() override {}
219 DISALLOW_COPY_AND_ASSIGN(ExtensionInstallDialogViewTest);
222 // Verifies that the delegate is notified when the user selects to accept or
223 // cancel the install.
224 IN_PROC_BROWSER_TEST_F(ExtensionInstallDialogViewTest, NotifyDelegate) {
226 // The user confirms the install.
227 MockExtensionInstallPromptDelegate delegate;
228 scoped_ptr<ExtensionInstallDialogView> dialog(
229 new ExtensionInstallDialogView(
230 profile(), web_contents(), &delegate, prompt()));
231 views::DialogDelegateView* delegate_view = dialog.get();
233 delegate_view->Accept();
234 delegate_view->OnClosed();
237 EXPECT_EQ(0, delegate.abort_count());
238 EXPECT_EQ(1, delegate.proceed_count());
242 // The user cancels the install.
243 MockExtensionInstallPromptDelegate delegate;
244 scoped_ptr<ExtensionInstallDialogView> dialog(
245 new ExtensionInstallDialogView(
246 profile(), web_contents(), &delegate, prompt()));
247 views::DialogDelegateView* delegate_view = dialog.get();
249 delegate_view->Cancel();
250 delegate_view->OnClosed();
253 EXPECT_EQ(1, delegate.abort_count());
254 EXPECT_EQ(0, delegate.proceed_count());
258 // Corner case: Dialog is closed without the user explicitly choosing to
259 // proceed or cancel.
260 MockExtensionInstallPromptDelegate delegate;
261 scoped_ptr<ExtensionInstallDialogView> dialog(
262 new ExtensionInstallDialogView(
263 profile(), web_contents(), &delegate, prompt()));
266 EXPECT_EQ(1, delegate.abort_count());
267 EXPECT_EQ(0, delegate.proceed_count());