blob: 4ab8a19fa0dc7637277199788070ab90f19113ad [file] [log] [blame]
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/ui/views/extensions/extension_install_dialog_view.h"
#include <utility>
#include "base/macros.h"
#include "base/run_loop.h"
#include "base/strings/utf_string_conversions.h"
#include "chrome/browser/extensions/extension_browsertest.h"
#include "chrome/browser/extensions/extension_icon_manager.h"
#include "chrome/browser/extensions/extension_install_prompt.h"
#include "chrome/browser/extensions/extension_install_prompt_test_helper.h"
#include "chrome/browser/platform_util.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_window.h"
#include "chrome/browser/ui/tabs/tab_strip_model.h"
#include "chrome/browser/ui/webui/extensions/extension_settings_handler.h"
#include "chrome/common/extensions/extension_test_util.h"
#include "components/constrained_window/constrained_window_views.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/test/test_utils.h"
#include "extensions/common/extension.h"
#include "extensions/common/permissions/permission_message_provider.h"
#include "extensions/common/permissions/permissions_data.h"
#include "ui/views/controls/scroll_view.h"
#include "ui/views/view.h"
#include "ui/views/widget/widget.h"
#include "ui/views/window/dialog_client_view.h"
using extensions::PermissionIDSet;
using extensions::PermissionMessage;
using extensions::PermissionMessages;
class ExtensionInstallDialogViewTestBase : public ExtensionBrowserTest {
protected:
explicit ExtensionInstallDialogViewTestBase(
ExtensionInstallPrompt::PromptType prompt_type);
~ExtensionInstallDialogViewTestBase() override {}
void SetUpOnMainThread() override;
// Creates and returns an install prompt of |prompt_type_|, optionally setting
// |permissions|.
std::unique_ptr<ExtensionInstallPrompt::Prompt> CreatePrompt();
std::unique_ptr<ExtensionInstallPrompt::Prompt> CreatePrompt(
const PermissionMessages& permissions);
content::WebContents* web_contents() { return web_contents_; }
private:
const extensions::Extension* extension_;
ExtensionInstallPrompt::PromptType prompt_type_;
content::WebContents* web_contents_;
DISALLOW_COPY_AND_ASSIGN(ExtensionInstallDialogViewTestBase);
};
ExtensionInstallDialogViewTestBase::ExtensionInstallDialogViewTestBase(
ExtensionInstallPrompt::PromptType prompt_type)
: extension_(NULL), prompt_type_(prompt_type), web_contents_(NULL) {}
void ExtensionInstallDialogViewTestBase::SetUpOnMainThread() {
ExtensionBrowserTest::SetUpOnMainThread();
extension_ = ExtensionBrowserTest::LoadExtension(test_data_dir_.AppendASCII(
"install_prompt/permissions_scrollbar_regression"));
web_contents_ = browser()->tab_strip_model()->GetWebContentsAt(0);
}
std::unique_ptr<ExtensionInstallPrompt::Prompt>
ExtensionInstallDialogViewTestBase::CreatePrompt() {
std::unique_ptr<ExtensionInstallPrompt::Prompt> prompt(
new ExtensionInstallPrompt::Prompt(prompt_type_));
prompt->set_extension(extension_);
std::unique_ptr<ExtensionIconManager> icon_manager(
new ExtensionIconManager());
prompt->set_icon(icon_manager->GetIcon(extension_->id()));
return prompt;
}
class ScrollbarTest : public ExtensionInstallDialogViewTestBase {
protected:
ScrollbarTest();
~ScrollbarTest() override {}
bool IsScrollbarVisible(
std::unique_ptr<ExtensionInstallPrompt::Prompt> prompt);
private:
DISALLOW_COPY_AND_ASSIGN(ScrollbarTest);
};
ScrollbarTest::ScrollbarTest()
: ExtensionInstallDialogViewTestBase(
ExtensionInstallPrompt::PERMISSIONS_PROMPT) {
}
bool ScrollbarTest::IsScrollbarVisible(
std::unique_ptr<ExtensionInstallPrompt::Prompt> prompt) {
ExtensionInstallDialogView* dialog = new ExtensionInstallDialogView(
profile(), web_contents(), ExtensionInstallPrompt::DoneCallback(),
std::move(prompt));
// Create the modal view around the install dialog view.
views::Widget* modal = constrained_window::CreateBrowserModalDialogViews(
dialog, web_contents()->GetTopLevelNativeWindow());
modal->Show();
content::RunAllTasksUntilIdle();
// Check if the vertical scrollbar is visible.
return dialog->scroll_view()->vertical_scroll_bar()->visible();
}
// Tests that a scrollbar _is_ shown for an excessively long extension
// install prompt.
IN_PROC_BROWSER_TEST_F(ScrollbarTest, LongPromptScrollbar) {
base::string16 permission_string(base::ASCIIToUTF16("Test"));
PermissionMessages permissions;
for (int i = 0; i < 20; i++) {
permissions.push_back(PermissionMessage(permission_string,
PermissionIDSet()));
}
std::unique_ptr<ExtensionInstallPrompt::Prompt> prompt = CreatePrompt();
prompt->AddPermissions(permissions,
ExtensionInstallPrompt::REGULAR_PERMISSIONS);
ASSERT_TRUE(IsScrollbarVisible(std::move(prompt)))
<< "Scrollbar is not visible";
}
// Tests that a scrollbar isn't shown for this regression case.
// See crbug.com/385570 for details.
IN_PROC_BROWSER_TEST_F(ScrollbarTest, ScrollbarRegression) {
base::string16 permission_string(base::ASCIIToUTF16(
"Read and modify your data on *.facebook.com"));
PermissionMessages permissions;
permissions.push_back(PermissionMessage(permission_string,
PermissionIDSet()));
std::unique_ptr<ExtensionInstallPrompt::Prompt> prompt = CreatePrompt();
prompt->AddPermissions(permissions,
ExtensionInstallPrompt::REGULAR_PERMISSIONS);
ASSERT_FALSE(IsScrollbarVisible(std::move(prompt))) << "Scrollbar is visible";
}
class ExtensionInstallDialogViewTest
: public ExtensionInstallDialogViewTestBase {
protected:
ExtensionInstallDialogViewTest()
: ExtensionInstallDialogViewTestBase(
ExtensionInstallPrompt::INSTALL_PROMPT) {}
~ExtensionInstallDialogViewTest() override {}
views::DialogDelegateView* CreateAndShowPrompt(
ExtensionInstallPromptTestHelper* helper) {
std::unique_ptr<ExtensionInstallDialogView> dialog(
new ExtensionInstallDialogView(profile(), web_contents(),
helper->GetCallback(), CreatePrompt()));
views::DialogDelegateView* delegate_view = dialog.get();
views::Widget* modal_dialog = views::DialogDelegate::CreateDialogWidget(
dialog.release(), nullptr,
platform_util::GetViewForWindow(
browser()->window()->GetNativeWindow()));
modal_dialog->Show();
return delegate_view;
}
private:
DISALLOW_COPY_AND_ASSIGN(ExtensionInstallDialogViewTest);
};
// Verifies that the delegate is notified when the user selects to accept or
// cancel the install.
IN_PROC_BROWSER_TEST_F(ExtensionInstallDialogViewTest, NotifyDelegate) {
{
// User presses install.
ExtensionInstallPromptTestHelper helper;
views::DialogDelegateView* delegate_view = CreateAndShowPrompt(&helper);
delegate_view->GetDialogClientView()->AcceptWindow();
EXPECT_EQ(ExtensionInstallPrompt::Result::ACCEPTED, helper.result());
}
{
// User presses cancel.
ExtensionInstallPromptTestHelper helper;
views::DialogDelegateView* delegate_view = CreateAndShowPrompt(&helper);
delegate_view->GetDialogClientView()->CancelWindow();
EXPECT_EQ(ExtensionInstallPrompt::Result::USER_CANCELED, helper.result());
}
{
// Dialog is closed without the user explicitly choosing to proceed or
// cancel.
ExtensionInstallPromptTestHelper helper;
views::DialogDelegateView* delegate_view = CreateAndShowPrompt(&helper);
delegate_view->GetWidget()->Close();
// TODO(devlin): Should this be ABORTED?
EXPECT_EQ(ExtensionInstallPrompt::Result::USER_CANCELED, helper.result());
}
}
// Verifies that the "Add extension" button is disabled initally, but re-enabled
// after a short time delay.
IN_PROC_BROWSER_TEST_F(ExtensionInstallDialogViewTest, InstallButtonDelay) {
ExtensionInstallDialogView::SetInstallButtonDelayForTesting(0);
ExtensionInstallPromptTestHelper helper;
views::DialogDelegateView* delegate_view = CreateAndShowPrompt(&helper);
// Check that dialog is visible.
EXPECT_TRUE(delegate_view->visible());
// Check initial button states.
EXPECT_FALSE(delegate_view->IsDialogButtonEnabled(ui::DIALOG_BUTTON_OK));
EXPECT_TRUE(delegate_view->IsDialogButtonEnabled(ui::DIALOG_BUTTON_CANCEL));
EXPECT_TRUE(delegate_view->GetInitiallyFocusedView()->HasFocus());
// Check OK button state after timeout to verify that it is re-enabled.
base::RunLoop().RunUntilIdle();
EXPECT_TRUE(delegate_view->IsDialogButtonEnabled(ui::DIALOG_BUTTON_OK));
// Ensure default button (cancel) has focus.
EXPECT_TRUE(delegate_view->GetInitiallyFocusedView()->HasFocus());
delegate_view->Close();
}