blob: 0cb6f3bcc92f1918ef7b827be0025a753d795c13 [file] [log] [blame]
// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <optional>
#include "base/test/scoped_feature_list.h"
#include "chrome/browser/extensions/api/side_panel/side_panel_service.h"
#include "chrome/browser/extensions/extension_apitest.h"
#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/profiles/profile.h"
#include "components/version_info/channel.h"
#include "content/public/test/browser_test.h"
#include "extensions/browser/disable_reason.h"
#include "extensions/browser/extension_host_test_helper.h"
#include "extensions/browser/test_extension_registry_observer.h"
#include "extensions/common/extension_features.h"
#include "extensions/test/test_extension_dir.h"
namespace extensions {
class SidePanelApiTest : public ExtensionApiTest {
public:
SidePanelApiTest() {
feature_list_.InitAndEnableFeature(
extensions_features::kExtensionSidePanelIntegration);
}
private:
base::test::ScopedFeatureList feature_list_;
ScopedCurrentChannel current_channel_{version_info::Channel::CANARY};
};
// Verify normal chrome.sidePanel functionality.
IN_PROC_BROWSER_TEST_F(SidePanelApiTest, Extension) {
ASSERT_TRUE(StartEmbeddedTestServer());
ASSERT_TRUE(RunExtensionTest("side_panel/extension")) << message_;
}
// Verify chrome.sidePanel behavior without permissions.
IN_PROC_BROWSER_TEST_F(SidePanelApiTest, PermissionMissing) {
ASSERT_TRUE(RunExtensionTest("side_panel/permission_missing")) << message_;
}
// Verify chrome.sidePanel.getOptions behavior without side_panel manifest key.
IN_PROC_BROWSER_TEST_F(SidePanelApiTest, MissingManifestKey) {
ASSERT_TRUE(RunExtensionTest("side_panel/missing_manifest_key")) << message_;
}
// Verify chrome.sidePanel.get/setPanelBehavior behavior.
IN_PROC_BROWSER_TEST_F(SidePanelApiTest, PanelBehavior) {
ASSERT_TRUE(RunExtensionTest("side_panel/panel_behavior")) << message_;
}
// Verify normal chrome.sidePanel functionality.
IN_PROC_BROWSER_TEST_F(SidePanelApiTest, ApiOnly) {
ASSERT_TRUE(StartEmbeddedTestServer());
ASSERT_TRUE(RunExtensionTest("side_panel/api_only")) << message_;
}
class SidePanelApiWithExtensionTest : public SidePanelApiTest {
public:
// Load and get extension.
const Extension* GetExtension() {
static constexpr char kManifest[] =
R"({
"name": "Test",
"manifest_version": 3,
"version": "0.1",
"side_panel": {"default_path": "default_path.html"}
})";
static constexpr char kDefaultPathHtml[] = "<html><body>Test</body></html>";
static constexpr char kCustomPathHtml[] =
"<html><body>Custom</body></html>";
TestExtensionDir test_dir;
test_dir.WriteManifest(kManifest);
test_dir.WriteFile(FILE_PATH_LITERAL("default_path.html"),
kDefaultPathHtml);
test_dir.WriteFile(FILE_PATH_LITERAL("custom_path.html"), kCustomPathHtml);
const Extension* extension = LoadExtension(test_dir.UnpackedPath());
return extension;
}
};
// Test the behavior of SetOptions for a tab and fallbacks on disable/uninstall.
IN_PROC_BROWSER_TEST_F(SidePanelApiWithExtensionTest, ExtensionRegistry) {
static constexpr int tab_id = 0;
// Test cases.
void (*test_cases[])(const ExtensionId& id,
extensions::TestExtensionRegistryObserver* observer,
ExtensionService* extension_service) = {
// "Unload extension"
[](const ExtensionId& id,
extensions::TestExtensionRegistryObserver* observer,
ExtensionService* extension_service) {
extension_service->DisableExtension(
id, disable_reason::DISABLE_USER_ACTION);
observer->WaitForExtensionUnloaded();
},
// "Uninstall extension",
// The uninstall case should technically not finish as default_path.html.
// However, the good news is that it's cleared from `panels_`, as
// desired. A real extension would not be able to GetOptions() after it
// has been uninstalled. Therefore this test vacuously succeeds.
// Confirmation is obtained via `HasExtensionPanelOptions()`.
[](const ExtensionId& id,
extensions::TestExtensionRegistryObserver* observer,
ExtensionService* extension_service) {
extension_service->UninstallExtension(
id, UninstallReason::UNINSTALL_REASON_FOR_TESTING, nullptr);
observer->WaitForExtensionUninstalled();
}};
// Run test cases.
for (const auto& test_case : test_cases) {
auto* extension = GetExtension();
ASSERT_TRUE(extension);
// Set panel options for extension and verify they are stored as expected.
SidePanelService* service = SidePanelService::Get(profile());
auto options = service->GetOptions(*extension, tab_id);
EXPECT_EQ("default_path.html", options.path.value());
options.path = "custom_path.html";
options.tab_id = tab_id;
service->SetOptions(*extension, std::move(options));
options = service->GetOptions(*extension, tab_id);
EXPECT_EQ("custom_path.html", options.path.value());
// The options for a different tab should still be default.
options = service->GetOptions(*extension, tab_id + 1);
EXPECT_EQ("default_path.html", options.path.value());
// Test case to verify that stored options are cleared on un-load/install.
EXPECT_TRUE(service->HasExtensionPanelOptionsForTest(extension->id()));
extensions::TestExtensionRegistryObserver observer(
extensions::ExtensionRegistry::Get(profile()), extension->id());
test_case(extension->id(), &observer, extension_service());
options = service->GetOptions(*extension, tab_id);
EXPECT_EQ("default_path.html", options.path.value());
EXPECT_FALSE(service->HasExtensionPanelOptionsForTest(extension->id()));
}
}
IN_PROC_BROWSER_TEST_F(SidePanelApiTest, OpenPanelErrors) {
ASSERT_TRUE(RunExtensionTest("side_panel/open_panel_errors"));
}
} // namespace extensions