blob: c222323f4b929cc00ee942020709d435f4abf176 [file] [log] [blame]
// Copyright 2019 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/path_service.h"
#include "base/strings/stringprintf.h"
#include "chrome/browser/extensions/extension_browsertest.h"
#include "chrome/common/chrome_paths.h"
#include "content/public/test/browser_test.h"
#include "content/public/test/browser_test_utils.h"
#include "extensions/common/extension.h"
#include "extensions/common/manifest.h"
#include "extensions/common/manifest_constants.h"
#include "extensions/common/manifest_handlers/externally_connectable.h"
#include "extensions/common/url_pattern.h"
#include "extensions/test/test_extension_dir.h"
#if !BUILDFLAG(IS_ANDROID)
#include "chrome/browser/extensions/extension_browsertest.h"
#endif
namespace extensions {
namespace {
#if !BUILDFLAG(IS_ANDROID)
constexpr char kComponentExtensionKey[] =
"MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC+uU63MD6T82Ldq5wjrDFn5mGmPnnnj"
"WZBWxYXfpG4kVf0s+p24VkXwTXsxeI12bRm8/ft9sOq0XiLfgQEh5JrVUZqvFlaZYoS+g"
"iZfUqzKFGMLa4uiSMDnvv+byxrqAepKz5G8XX/q5Wm5cvpdjwgiu9z9iM768xJy+Ca/G5"
"qQwIDAQAB";
#endif
// The value set by the script
// in chrome/test/data/extensions/test_resources_test/script.js.
constexpr int kSentinelValue = 42;
// Returns the value of window.injectedSentinel from the web contents.
int RetrieveSentinelValue(content::WebContents* web_contents) {
return content::EvalJs(web_contents, "window.injectedSentinel;").ExtractInt();
}
class ExtensionBrowserTestWithCustomTestResourcesLocation
: public ExtensionBrowserTest {
public:
ExtensionBrowserTestWithCustomTestResourcesLocation() = default;
ExtensionBrowserTestWithCustomTestResourcesLocation(
const ExtensionBrowserTestWithCustomTestResourcesLocation&) = delete;
ExtensionBrowserTestWithCustomTestResourcesLocation& operator=(
const ExtensionBrowserTestWithCustomTestResourcesLocation&) = delete;
~ExtensionBrowserTestWithCustomTestResourcesLocation() override = default;
private:
// Instead of serving _test_resources/ paths from chrome/test/data/extensions,
// serve them from chrome/test/data/extensions/test_resources_test.
base::FilePath GetTestResourcesParentDir() override {
base::FilePath test_root_path;
base::PathService::Get(chrome::DIR_TEST_DATA, &test_root_path);
return test_root_path.AppendASCII("extensions/test_resources_test");
}
};
} // namespace
// A simple test to ensure resources can be served from _test_resources/, and
// properly load.
IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, TestResourcesLoad) {
TestExtensionDir test_dir;
test_dir.WriteManifest(
R"({
"name": "Test Extension",
"version": "0.1",
"manifest_version": 3
})");
constexpr char kPageHtml[] =
R"(<html>
<script src="_test_resources/test_resources_test/test_script.js">
</script>
</html>)";
test_dir.WriteFile(FILE_PATH_LITERAL("page.html"), kPageHtml);
const Extension* extension = LoadExtension(test_dir.UnpackedPath());
ASSERT_TRUE(extension);
ASSERT_TRUE(content::NavigateToURL(
GetActiveWebContents(), extension->ResolveExtensionURL("page.html")));
EXPECT_EQ(kSentinelValue, RetrieveSentinelValue(GetActiveWebContents()));
}
// TODO(crbug.com/356905053): Enable the tests for component extensions on
// desktop android.
#if !BUILDFLAG(IS_ANDROID)
// Tests that resources from _test_resources work in component extensions
// (which have a slightly different load path).
IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest,
TestResourcesLoadInComponentExtension) {
TestExtensionDir test_dir;
constexpr char kManifestTemplate[] =
R"({
"name": "Test Extension",
"version": "0.1",
"manifest_version": 2,
"key": "%s"
})";
test_dir.WriteManifest(
base::StringPrintf(kManifestTemplate, kComponentExtensionKey));
constexpr char kPageHtml[] =
R"(<html>
<script src="_test_resources/test_resources_test/test_script.js">
</script>
</html>)";
test_dir.WriteFile(FILE_PATH_LITERAL("page.html"), kPageHtml);
const Extension* extension =
LoadExtensionAsComponent(test_dir.UnpackedPath());
ASSERT_TRUE(extension);
EXPECT_EQ(mojom::ManifestLocation::kComponent, extension->location());
ASSERT_TRUE(content::NavigateToURL(
GetActiveWebContents(), extension->ResolveExtensionURL("page.html")));
EXPECT_EQ(kSentinelValue, RetrieveSentinelValue(GetActiveWebContents()));
}
IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest,
LoadComponentExtensionUpdateWithManifestChanges) {
TestExtensionDir test_dir;
static constexpr char test_domain1[] = "http://*.domain1.com/*";
static constexpr char test_domain2[] = "http://*.domain2.com/*";
static constexpr char kManifestTemplate[] =
R"({
"name": "Test Component Extension",
"version": "1",
"description": "",
"manifest_version": 3,
"key": "%s",
"externally_connectable": {
"matches": [
"%s"
]
}
})";
test_dir.WriteManifest(base::StringPrintf(
kManifestTemplate, kComponentExtensionKey, test_domain1));
const Extension* extension1 =
LoadExtensionAsComponent(test_dir.UnpackedPath());
ASSERT_TRUE(extension1);
EXPECT_EQ(mojom::ManifestLocation::kComponent, extension1->location());
ExternallyConnectableInfo* info1 = static_cast<ExternallyConnectableInfo*>(
extension1->GetManifestData(manifest_keys::kExternallyConnectable));
ASSERT_TRUE(info1);
EXPECT_EQ(1ul, info1->matches.size());
EXPECT_EQ(URLPattern(URLPattern::SCHEME_ALL, test_domain1),
*info1->matches.begin());
// Update the manifest and load the extension again.
test_dir.WriteManifest(base::StringPrintf(
kManifestTemplate, kComponentExtensionKey, test_domain2));
const Extension* extension2 =
LoadExtensionAsComponent(test_dir.UnpackedPath());
ASSERT_TRUE(extension2);
EXPECT_EQ(mojom::ManifestLocation::kComponent, extension2->location());
ExternallyConnectableInfo* info2 = static_cast<ExternallyConnectableInfo*>(
extension2->GetManifestData(manifest_keys::kExternallyConnectable));
ASSERT_TRUE(info2);
EXPECT_EQ(1ul, info2->matches.size());
EXPECT_EQ(URLPattern(URLPattern::SCHEME_ALL, test_domain2),
*info2->matches.begin());
}
#endif // !BUILDFLAG(IS_ANDROID)
// Tests that resources from _test_resources can be loaded from different
// directories. Though the default is chrome/test/data/extensions, a test class
// can specify its own.
IN_PROC_BROWSER_TEST_F(ExtensionBrowserTestWithCustomTestResourcesLocation,
TestResourcesLoadFromCustomPath) {
TestExtensionDir test_dir;
test_dir.WriteManifest(
R"({
"name": "Test Extension",
"version": "0.1",
"manifest_version": 3
})");
// Note: Since this class serves _test_resources from
// chrome/test/data/extensions/test_resources_test, the
// path is just _test_resources/test_script.js.
constexpr char kPageHtml[] =
R"(<html>
<script src="_test_resources/test_script.js"></script>
</html>)";
test_dir.WriteFile(FILE_PATH_LITERAL("page.html"), kPageHtml);
const Extension* extension = LoadExtension(test_dir.UnpackedPath());
ASSERT_TRUE(extension);
ASSERT_TRUE(content::NavigateToURL(
GetActiveWebContents(), extension->ResolveExtensionURL("page.html")));
EXPECT_EQ(kSentinelValue, RetrieveSentinelValue(GetActiveWebContents()));
}
} // namespace extensions