blob: ef7d4870a8398e2f6f38e6b3024e3aa46b9b1232 [file] [log] [blame]
// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/ui/extensions/extension_installed_bubble_model.h"
#include "base/command_line.h"
#include "base/values.h"
#include "build/build_config.h"
#include "chrome/browser/extensions/chrome_test_extension_loader.h"
#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/extensions/extension_service_test_with_install.h"
#include "chrome/common/extensions/api/omnibox.h"
#include "components/signin/public/base/signin_switches.h"
#include "content/public/test/browser_task_environment.h"
#include "extensions/browser/extension_registrar.h"
#include "extensions/common/api/extension_action/action_info.h"
#include "extensions/common/extension_builder.h"
#include "extensions/common/manifest_constants.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/base/accelerators/accelerator.h"
using extensions::Extension;
class ExtensionInstalledBubbleModelTest
: public extensions::ExtensionServiceTestWithInstall {
public:
ExtensionInstalledBubbleModelTest() {
scoped_feature_list_.InitAndDisableFeature(
switches::kEnableExtensionsExplicitBrowserSignin);
}
~ExtensionInstalledBubbleModelTest() override = default;
void SetUp() override {
InitializeEmptyExtensionService();
service()->Init();
}
protected:
void AddOmniboxKeyword(extensions::ExtensionBuilder* builder,
const std::string& keyword) {
using ManifestKeys = extensions::api::omnibox::ManifestKeys;
base::Value::Dict info;
info.Set(ManifestKeys::Omnibox::kKeyword, keyword);
builder->SetManifestKey(ManifestKeys::kOmnibox, std::move(info));
}
void AddRegularAction(extensions::ExtensionBuilder* builder) {
builder->SetManifestKey(extensions::manifest_keys::kAction,
base::Value::Dict());
}
void AddBrowserActionKeyBinding(extensions::ExtensionBuilder* builder,
const std::string& key) {
builder->SetManifestKey(
extensions::manifest_keys::kCommands,
base::Value::Dict().Set(
extensions::manifest_values::kBrowserActionCommandEvent,
base::Value::Dict()
.Set("suggested_key", key)
.Set("description", "Invoke the page action")));
}
private:
base::test::ScopedFeatureList scoped_feature_list_;
};
TEST_F(ExtensionInstalledBubbleModelTest, SyntheticPageActionExtension) {
// An extension with no action info in the manifest at all gets a synthesized
// page action.
auto extension = extensions::ExtensionBuilder("Foo").Build();
registrar()->AddExtension(extension);
ExtensionInstalledBubbleModel model(profile(), extension.get(), SkBitmap());
// It should anchor to the synthesized action...
EXPECT_TRUE(model.anchor_to_action());
EXPECT_FALSE(model.anchor_to_omnibox());
// ... but there should not be how-to-use text, since it has no actual way to
// activate it other than that synthesized action.
EXPECT_FALSE(model.show_how_to_use());
EXPECT_TRUE(model.show_how_to_manage());
EXPECT_FALSE(model.show_key_binding());
}
TEST_F(ExtensionInstalledBubbleModelTest, OmniboxExtension) {
// An extension with a regular action and an omnibox keyword...
auto builder = extensions::ExtensionBuilder("Foo");
AddOmniboxKeyword(&builder, "fookey");
builder.AddFlags(extensions::Extension::WAS_INSTALLED_BY_DEFAULT);
auto extension = builder.Build();
registrar()->AddExtension(extension);
ExtensionInstalledBubbleModel model(profile(), extension.get(), SkBitmap());
// ... should be anchored to the omnibox, not to the action ...
EXPECT_FALSE(model.anchor_to_action());
EXPECT_TRUE(model.anchor_to_omnibox());
// ... and should have how-to-use and how-to-manage text, but not show a key
// binding, since it doesn't have one.
EXPECT_TRUE(model.show_how_to_use());
EXPECT_TRUE(model.show_how_to_manage());
EXPECT_FALSE(model.show_key_binding());
}
TEST_F(ExtensionInstalledBubbleModelTest, PageActionExtension) {
// An extension with a page action...
auto extension = extensions::ExtensionBuilder("Foo")
.SetManifestVersion(2)
.SetAction(extensions::ActionInfo::Type::kPage)
.Build();
registrar()->AddExtension(extension);
ExtensionInstalledBubbleModel model(profile(), extension.get(), SkBitmap());
// should anchor to that action
EXPECT_TRUE(model.anchor_to_action());
EXPECT_FALSE(model.anchor_to_omnibox());
// and have how-to-use and how-to-manage but no key binding, since it doesn't
// have one.
EXPECT_TRUE(model.show_how_to_use());
EXPECT_TRUE(model.show_how_to_manage());
EXPECT_FALSE(model.show_key_binding());
}
// TODO(crbug.com/405148986): Modify this test once the appropriate how to use
// text is decided for extensions with actions.
TEST_F(ExtensionInstalledBubbleModelTest, ActionExtension) {
auto extension = extensions::ExtensionBuilder("Foo")
.SetAction(extensions::ActionInfo::Type::kAction)
.Build();
registrar()->AddExtension(extension);
ExtensionInstalledBubbleModel model(profile(), extension.get(), SkBitmap());
// should anchor to that action
EXPECT_TRUE(model.anchor_to_action());
EXPECT_FALSE(model.anchor_to_omnibox());
// and have how-to-manage but no how-to-use and key binding.
EXPECT_FALSE(model.show_how_to_use());
EXPECT_TRUE(model.show_how_to_manage());
EXPECT_FALSE(model.show_key_binding());
}
TEST_F(ExtensionInstalledBubbleModelTest, ExtensionWithKeyBinding) {
// An extension with a browser action and a key binding...
auto builder = extensions::ExtensionBuilder("Foo");
builder.SetAction(extensions::ActionInfo::Type::kBrowser);
builder.SetManifestVersion(2);
AddBrowserActionKeyBinding(&builder, "Alt+Shift+E");
auto extension = builder.Build();
// Note that we have to OnExtensionInstalled() here rather than just adding it
// - hotkeys are picked up at install time, not add time.
registrar()->OnExtensionInstalled(extension.get(), syncer::StringOrdinal());
ExtensionInstalledBubbleModel model(profile(), extension.get(), SkBitmap());
// Should have a how-to-use that lists the key, but *not* a how-to-manage,
// since it crowds the UI.
EXPECT_TRUE(model.show_how_to_use());
EXPECT_FALSE(model.show_how_to_manage());
EXPECT_TRUE(model.show_key_binding());
// Note that we can't just check for "Alt+Shift+E" in
// model.GetHowToUseText(), since on Mac, modifier keys are represented by
// special sigils rather than their textual names.
ui::Accelerator accelerator(ui::VKEY_E, ui::EF_SHIFT_DOWN | ui::EF_ALT_DOWN);
EXPECT_NE(std::u16string::npos,
model.GetHowToUseText().find(accelerator.GetShortcutText()));
}
TEST_F(ExtensionInstalledBubbleModelTest, OmniboxKeywordAndSyntheticAction) {
auto builder = extensions::ExtensionBuilder("Foo");
AddOmniboxKeyword(&builder, "fookey");
auto extension = builder.Build();
registrar()->AddExtension(extension);
ExtensionInstalledBubbleModel model(profile(), extension.get(), SkBitmap());
// This extension has a synthesized action and an omnibox keyword. It should
// have how-to-use text, and be anchored to its (synthesized) page action.
EXPECT_TRUE(model.show_how_to_use());
EXPECT_TRUE(model.anchor_to_action());
}