summaryrefslogtreecommitdiffstats
path: root/chromium/chrome/browser/extensions/api/extension_action
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@qt.io>2022-02-02 12:21:57 +0100
committerAllan Sandfeld Jensen <allan.jensen@qt.io>2022-02-12 08:13:00 +0000
commit606d85f2a5386472314d39923da28c70c60dc8e7 (patch)
treea8f4d7bf997f349f45605e6058259fba0630e4d7 /chromium/chrome/browser/extensions/api/extension_action
parent5786336dda477d04fb98483dca1a5426eebde2d7 (diff)
BASELINE: Update Chromium to 96.0.4664.181
Change-Id: I762cd1da89d73aa6313b4a753fe126c34833f046 Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io>
Diffstat (limited to 'chromium/chrome/browser/extensions/api/extension_action')
-rw-r--r--chromium/chrome/browser/extensions/api/extension_action/browser_action_apitest.cc166
-rw-r--r--chromium/chrome/browser/extensions/api/extension_action/browser_action_interactive_test.cc115
-rw-r--r--chromium/chrome/browser/extensions/api/extension_action/extension_action_api.cc47
-rw-r--r--chromium/chrome/browser/extensions/api/extension_action/extension_action_api.h35
-rw-r--r--chromium/chrome/browser/extensions/api/extension_action/extension_action_apitest.cc56
-rw-r--r--chromium/chrome/browser/extensions/api/extension_action/page_action_apitest.cc61
-rw-r--r--chromium/chrome/browser/extensions/api/extension_action/test_extension_action_api_observer.h8
-rw-r--r--chromium/chrome/browser/extensions/api/extension_action/test_icon_image_observer.h6
8 files changed, 264 insertions, 230 deletions
diff --git a/chromium/chrome/browser/extensions/api/extension_action/browser_action_apitest.cc b/chromium/chrome/browser/extensions/api/extension_action/browser_action_apitest.cc
index 93cd9dfd4b4..064063e51fb 100644
--- a/chromium/chrome/browser/extensions/api/extension_action/browser_action_apitest.cc
+++ b/chromium/chrome/browser/extensions/api/extension_action/browser_action_apitest.cc
@@ -8,8 +8,6 @@
#include "base/files/file_util.h"
#include "base/files/scoped_temp_dir.h"
#include "base/macros.h"
-#include "base/run_loop.h"
-#include "base/scoped_observation.h"
#include "base/strings/string_piece.h"
#include "base/strings/stringprintf.h"
#include "base/test/metrics/histogram_tester.h"
@@ -52,7 +50,7 @@
#include "extensions/browser/extension_action.h"
#include "extensions/browser/extension_action_manager.h"
#include "extensions/browser/extension_host.h"
-#include "extensions/browser/extension_host_observer.h"
+#include "extensions/browser/extension_host_test_helper.h"
#include "extensions/browser/extension_registry.h"
#include "extensions/browser/extension_system.h"
#include "extensions/browser/process_manager.h"
@@ -65,11 +63,11 @@
#include "ui/base/resource/resource_bundle.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/geometry/size.h"
+#include "ui/gfx/geometry/skia_conversions.h"
#include "ui/gfx/image/canvas_image_source.h"
#include "ui/gfx/image/image_skia.h"
#include "ui/gfx/image/image_skia_operations.h"
#include "ui/gfx/image/image_unittest_util.h"
-#include "ui/gfx/skia_util.h"
using content::WebContents;
@@ -102,9 +100,12 @@ void VerifyIconsMatch(const gfx::Image& bar_rendering,
.GetBitmap()));
}
+using ContextType = ExtensionBrowserTest::ContextType;
+
class BrowserActionApiTest : public ExtensionApiTest {
public:
- BrowserActionApiTest() = default;
+ explicit BrowserActionApiTest(ContextType context_type = ContextType::kNone)
+ : ExtensionApiTest(context_type) {}
~BrowserActionApiTest() override = default;
BrowserActionApiTest(const BrowserActionApiTest&) = delete;
BrowserActionApiTest& operator=(const BrowserActionApiTest&) = delete;
@@ -149,13 +150,11 @@ class BrowserActionApiCanvasTest : public BrowserActionApiTest {
}
};
-using ContextType = ExtensionBrowserTest::ContextType;
-
class BrowserActionApiTestWithContextType
: public BrowserActionApiTest,
public testing::WithParamInterface<ContextType> {
public:
- BrowserActionApiTestWithContextType() = default;
+ BrowserActionApiTestWithContextType() : BrowserActionApiTest(GetParam()) {}
~BrowserActionApiTestWithContextType() override = default;
BrowserActionApiTestWithContextType(
const BrowserActionApiTestWithContextType&) = delete;
@@ -163,17 +162,11 @@ class BrowserActionApiTestWithContextType
const BrowserActionApiTestWithContextType&) = delete;
protected:
- const extensions::Extension* LoadExtensionWithParamOptions(
- const base::FilePath& path) {
- return LoadExtension(path, {.load_as_service_worker =
- GetParam() == ContextType::kServiceWorker});
- }
-
void RunUpdateTest(base::StringPiece path, bool expect_failure) {
ExtensionTestMessageListener ready_listener("ready", true);
ASSERT_TRUE(embedded_test_server()->Start());
const Extension* extension =
- LoadExtensionWithParamOptions(test_data_dir_.AppendASCII(path));
+ LoadExtension(test_data_dir_.AppendASCII(path));
ASSERT_TRUE(extension) << message_;
// Test that there is a browser action in the toolbar.
ASSERT_EQ(1, GetBrowserActionsBar()->NumberOfBrowserActions());
@@ -210,7 +203,7 @@ class BrowserActionApiTestWithContextType
void RunEnableTest(base::StringPiece path, bool start_enabled) {
ExtensionTestMessageListener ready_listener("ready", true);
const Extension* extension =
- LoadExtensionWithParamOptions(test_data_dir_.AppendASCII(path));
+ LoadExtension(test_data_dir_.AppendASCII(path));
ASSERT_TRUE(extension) << message_;
// Test that there is a browser action in the toolbar.
ASSERT_EQ(1, GetBrowserActionsBar()->NumberOfBrowserActions());
@@ -235,12 +228,6 @@ class BrowserActionApiTestWithContextType
action->GetIsVisible(ExtensionAction::kDefaultTabId));
}
- bool RunTest(const char* name) WARN_UNUSED_RESULT {
- return RunExtensionTest(
- name, {},
- {.load_as_service_worker = GetParam() == ContextType::kServiceWorker});
- }
-
private:
base::test::ScopedFeatureList feature_list_;
};
@@ -248,8 +235,8 @@ class BrowserActionApiTestWithContextType
IN_PROC_BROWSER_TEST_P(BrowserActionApiTestWithContextType, Basic) {
ExtensionTestMessageListener ready_listener("ready", false);
ASSERT_TRUE(embedded_test_server()->Start());
- const Extension* extension = LoadExtensionWithParamOptions(
- test_data_dir_.AppendASCII("browser_action/basics"));
+ const Extension* extension =
+ LoadExtension(test_data_dir_.AppendASCII("browser_action/basics"));
ASSERT_TRUE(extension) << message_;
// Test that there is a browser action in the toolbar.
@@ -259,8 +246,8 @@ IN_PROC_BROWSER_TEST_P(BrowserActionApiTestWithContextType, Basic) {
// Open a URL in the tab, so the event handler can check the tab's
// "url" and "title" properties.
- ui_test_utils::NavigateToURL(
- browser(), embedded_test_server()->GetURL("/extensions/test_file.txt"));
+ ASSERT_TRUE(ui_test_utils::NavigateToURL(
+ browser(), embedded_test_server()->GetURL("/extensions/test_file.txt")));
ResultCatcher catcher;
// Simulate the browser action being clicked.
@@ -305,8 +292,8 @@ IN_PROC_BROWSER_TEST_F(BrowserActionApiCanvasTest, DynamicBrowserAction) {
// We need this on mac so we don't loose 2x representations from browser icon
// in transformations gfx::ImageSkia -> NSImage -> gfx::ImageSkia.
std::vector<ui::ResourceScaleFactor> supported_scale_factors;
- supported_scale_factors.push_back(ui::SCALE_FACTOR_100P);
- supported_scale_factors.push_back(ui::SCALE_FACTOR_200P);
+ supported_scale_factors.push_back(ui::k100Percent);
+ supported_scale_factors.push_back(ui::k200Percent);
ui::SetSupportedResourceScaleFactors(supported_scale_factors);
#endif
@@ -541,7 +528,8 @@ IN_PROC_BROWSER_TEST_F(BrowserActionApiCanvasTest, InvisibleIconBrowserAction) {
IN_PROC_BROWSER_TEST_P(BrowserActionApiTestWithContextType,
TabSpecificBrowserActionState) {
- ASSERT_TRUE(RunTest("browser_action/tab_specific_state")) << message_;
+ ASSERT_TRUE(RunExtensionTest("browser_action/tab_specific_state"))
+ << message_;
const Extension* extension = GetSingleLoadedExtension();
ASSERT_TRUE(extension) << message_;
@@ -567,14 +555,14 @@ IN_PROC_BROWSER_TEST_P(BrowserActionApiTestWithContextType,
GetBrowserActionsBar()->GetTooltip(extension->id()));
// Reload that tab, default title should come back.
- ui_test_utils::NavigateToURL(browser(), GURL("about:blank"));
+ ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), GURL("about:blank")));
EXPECT_EQ("hi!", GetBrowserActionsBar()->GetTooltip(extension->id()));
}
// Test that calling chrome.browserAction.setIcon() can set the icon for
// extension.
IN_PROC_BROWSER_TEST_P(BrowserActionApiTestWithContextType, SetIcon) {
- ASSERT_TRUE(RunTest("browser_action/set_icon")) << message_;
+ ASSERT_TRUE(RunExtensionTest("browser_action/set_icon")) << message_;
const Extension* extension = GetSingleLoadedExtension();
ASSERT_TRUE(extension) << message_;
@@ -608,7 +596,7 @@ IN_PROC_BROWSER_TEST_P(BrowserActionApiTestWithContextType, SetIcon) {
// Test that calling chrome.browserAction.setPopup() can enable and change
// a popup.
IN_PROC_BROWSER_TEST_P(BrowserActionApiTestWithContextType, AddPopup) {
- ASSERT_TRUE(RunTest("browser_action/add_popup")) << message_;
+ ASSERT_TRUE(RunExtensionTest("browser_action/add_popup")) << message_;
const Extension* extension = GetSingleLoadedExtension();
ASSERT_TRUE(extension) << message_;
@@ -647,9 +635,8 @@ IN_PROC_BROWSER_TEST_P(BrowserActionApiTestWithContextType, AddPopup) {
// a page which removes the popup using chrome.browserAction.setPopup().
{
ResultCatcher catcher;
- ui_test_utils::NavigateToURL(
- browser(),
- GURL(extension->GetResourceURL("change_popup.html")));
+ ASSERT_TRUE(ui_test_utils::NavigateToURL(
+ browser(), GURL(extension->GetResourceURL("change_popup.html"))));
ASSERT_TRUE(catcher.GetNextResult());
}
@@ -664,7 +651,7 @@ IN_PROC_BROWSER_TEST_P(BrowserActionApiTestWithContextType, AddPopup) {
// Test that calling chrome.browserAction.setPopup() can remove a popup.
IN_PROC_BROWSER_TEST_P(BrowserActionApiTestWithContextType, RemovePopup) {
// Load the extension, which has a browser action with a default popup.
- ASSERT_TRUE(RunTest("browser_action/remove_popup")) << message_;
+ ASSERT_TRUE(RunExtensionTest("browser_action/remove_popup")) << message_;
const Extension* extension = GetSingleLoadedExtension();
ASSERT_TRUE(extension) << message_;
@@ -683,9 +670,8 @@ IN_PROC_BROWSER_TEST_P(BrowserActionApiTestWithContextType, RemovePopup) {
// Load a page which removes the popup using chrome.browserAction.setPopup().
{
ResultCatcher catcher;
- ui_test_utils::NavigateToURL(
- browser(),
- GURL(extension->GetResourceURL("remove_popup.html")));
+ ASSERT_TRUE(ui_test_utils::NavigateToURL(
+ browser(), GURL(extension->GetResourceURL("remove_popup.html"))));
ASSERT_TRUE(catcher.GetNextResult());
}
@@ -699,8 +685,8 @@ IN_PROC_BROWSER_TEST_P(BrowserActionApiTestWithContextType, RemovePopup) {
IN_PROC_BROWSER_TEST_P(BrowserActionApiTestWithContextType, IncognitoBasic) {
ExtensionTestMessageListener ready_listener("ready", false);
ASSERT_TRUE(embedded_test_server()->Start());
- scoped_refptr<const Extension> extension = LoadExtensionWithParamOptions(
- test_data_dir_.AppendASCII("browser_action/basics"));
+ scoped_refptr<const Extension> extension =
+ LoadExtension(test_data_dir_.AppendASCII("browser_action/basics"));
ASSERT_TRUE(extension) << message_;
// Test that there is a browser action in the toolbar.
@@ -733,9 +719,9 @@ IN_PROC_BROWSER_TEST_P(BrowserActionApiTestWithContextType, IncognitoBasic) {
// Open a URL in the tab, so the event handler can check the tab's
// "url" and "title" properties.
- ui_test_utils::NavigateToURL(
+ ASSERT_TRUE(ui_test_utils::NavigateToURL(
incognito_browser,
- embedded_test_server()->GetURL("/extensions/test_file.txt"));
+ embedded_test_server()->GetURL("/extensions/test_file.txt")));
ResultCatcher catcher;
// Simulate the browser action being clicked.
@@ -748,8 +734,8 @@ IN_PROC_BROWSER_TEST_P(BrowserActionApiTestWithContextType, IncognitoUpdate) {
ASSERT_TRUE(embedded_test_server()->Start());
ExtensionTestMessageListener incognito_not_allowed_listener(
"incognito not allowed", false);
- scoped_refptr<const Extension> extension = LoadExtensionWithParamOptions(
- test_data_dir_.AppendASCII("browser_action/update"));
+ scoped_refptr<const Extension> extension =
+ LoadExtension(test_data_dir_.AppendASCII("browser_action/update"));
ASSERT_TRUE(extension) << message_;
ASSERT_TRUE(incognito_not_allowed_listener.WaitUntilSatisfied());
// Test that there is a browser action in the toolbar.
@@ -807,25 +793,34 @@ IN_PROC_BROWSER_TEST_P(BrowserActionApiTestWithContextType, IncognitoUpdate) {
// Tests that events are dispatched to the correct profile for split mode
// extensions.
-// TODO(https://crbug.com/1212866): Crashes or times out when running as a
-// Service Worker-based extension. When fixed, make this a
-// BrowserActionApiTestWithContextType test.
-IN_PROC_BROWSER_TEST_F(BrowserActionApiTest, IncognitoSplit) {
+IN_PROC_BROWSER_TEST_P(BrowserActionApiTestWithContextType, IncognitoSplit) {
+ ExtensionTestMessageListener listener_ready("regular ready", false);
+ ExtensionTestMessageListener incognito_ready("incognito ready", false);
+
+ // Open an incognito browser.
+ // Note: It is important that we create incognito profile before loading
+ // |extension| below. "event_page" based test fails otherwise.
+ Browser* incognito_browser = CreateIncognitoBrowser(browser()->profile());
+
ResultCatcher catcher;
const Extension* extension =
LoadExtension(test_data_dir_.AppendASCII("browser_action/split_mode"),
{.allow_in_incognito = true});
ASSERT_TRUE(extension) << message_;
- // Open an incognito browser.
- Browser* incognito_browser = CreateIncognitoBrowser(browser()->profile());
ASSERT_EQ(1, ExtensionActionTestHelper::Create(incognito_browser)
->NumberOfBrowserActions());
+ // NOTE: It is necessary to ensure that browser.onClicked listener was
+ // registered from the extension. Otherwise SW based extension occasionally
+ // times out.
+ EXPECT_TRUE(listener_ready.WaitUntilSatisfied());
+
// A click in the regular profile should open a tab in the regular profile.
ExecuteExtensionAction(browser(), extension);
ASSERT_TRUE(catcher.GetNextResult()) << catcher.message();
+ EXPECT_TRUE(incognito_ready.WaitUntilSatisfied());
// A click in the incognito profile should open a tab in the
// incognito profile.
ExecuteExtensionAction(incognito_browser, extension);
@@ -851,40 +846,13 @@ IN_PROC_BROWSER_TEST_F(BrowserActionApiTest, CloseBackgroundPage) {
ASSERT_EQ("",
action->GetExplicitlySetBadgeText(ExtensionAction::kDefaultTabId));
- // A helper class to wait for the ExtensionHost to shut down.
- // TODO(devlin): Hoist this somewhere more common and track down other similar
- // usages.
- class ExtensionHostDestructionObserver : public ExtensionHostObserver {
- public:
- explicit ExtensionHostDestructionObserver(ExtensionHost* host) {
- host_observation_.Observe(host);
- }
- ExtensionHostDestructionObserver(
- const ExtensionHostDestructionObserver& other) = delete;
- ExtensionHostDestructionObserver& operator=(
- const ExtensionHostDestructionObserver& other) = delete;
- ~ExtensionHostDestructionObserver() override = default;
-
- void OnExtensionHostDestroyed(ExtensionHost* host) override {
- ASSERT_TRUE(host_observation_.IsObservingSource(host));
- host_observation_.Reset();
- run_loop_.QuitWhenIdle();
- }
-
- void Wait() { run_loop_.Run(); }
-
- private:
- base::RunLoop run_loop_;
- base::ScopedObservation<ExtensionHost, ExtensionHostObserver>
- host_observation_{this};
- };
-
- ExtensionHostDestructionObserver host_destroyed_observer(extension_host);
+ ExtensionHostTestHelper host_destroyed_observer(profile());
+ host_destroyed_observer.RestrictToHost(extension_host);
// Click the browser action.
ExecuteExtensionAction(browser(), extension);
- host_destroyed_observer.Wait();
+ host_destroyed_observer.WaitForHostDestroyed();
EXPECT_FALSE(manager->GetBackgroundHostForExtension(extension->id()));
EXPECT_EQ("X",
@@ -894,7 +862,7 @@ IN_PROC_BROWSER_TEST_F(BrowserActionApiTest, CloseBackgroundPage) {
IN_PROC_BROWSER_TEST_P(BrowserActionApiTestWithContextType,
BadgeBackgroundColor) {
ASSERT_TRUE(embedded_test_server()->Start());
- ASSERT_TRUE(RunTest("browser_action/color")) << message_;
+ ASSERT_TRUE(RunExtensionTest("browser_action/color")) << message_;
const Extension* extension = GetSingleLoadedExtension();
ASSERT_TRUE(extension) << message_;
@@ -908,24 +876,24 @@ IN_PROC_BROWSER_TEST_P(BrowserActionApiTestWithContextType,
// Tell the extension to update the browser action state.
ResultCatcher catcher;
- ui_test_utils::NavigateToURL(browser(),
- GURL(extension->GetResourceURL("update.html")));
+ ASSERT_TRUE(ui_test_utils::NavigateToURL(
+ browser(), GURL(extension->GetResourceURL("update.html"))));
ASSERT_TRUE(catcher.GetNextResult());
// Test that CSS values (#0F0) set color correctly.
ASSERT_EQ(SkColorSetARGB(255, 0, 255, 0),
action->GetBadgeBackgroundColor(ExtensionAction::kDefaultTabId));
- ui_test_utils::NavigateToURL(browser(),
- GURL(extension->GetResourceURL("update2.html")));
+ ASSERT_TRUE(ui_test_utils::NavigateToURL(
+ browser(), GURL(extension->GetResourceURL("update2.html"))));
ASSERT_TRUE(catcher.GetNextResult());
// Test that array values set color correctly.
ASSERT_EQ(SkColorSetARGB(255, 255, 255, 255),
action->GetBadgeBackgroundColor(ExtensionAction::kDefaultTabId));
- ui_test_utils::NavigateToURL(browser(),
- GURL(extension->GetResourceURL("update3.html")));
+ ASSERT_TRUE(ui_test_utils::NavigateToURL(
+ browser(), GURL(extension->GetResourceURL("update3.html"))));
ASSERT_TRUE(catcher.GetNextResult());
// Test that hsl() values 'hsl(120, 100%, 50%)' set color correctly.
@@ -933,8 +901,8 @@ IN_PROC_BROWSER_TEST_P(BrowserActionApiTestWithContextType,
action->GetBadgeBackgroundColor(ExtensionAction::kDefaultTabId));
// Test basic color keyword set correctly.
- ui_test_utils::NavigateToURL(browser(),
- GURL(extension->GetResourceURL("update4.html")));
+ ASSERT_TRUE(ui_test_utils::NavigateToURL(
+ browser(), GURL(extension->GetResourceURL("update4.html"))));
ASSERT_TRUE(catcher.GetNextResult());
ASSERT_EQ(SkColorSetARGB(255, 0, 0, 255),
@@ -942,7 +910,7 @@ IN_PROC_BROWSER_TEST_P(BrowserActionApiTestWithContextType,
}
IN_PROC_BROWSER_TEST_P(BrowserActionApiTestWithContextType, Getters) {
- ASSERT_TRUE(RunTest("browser_action/getters")) << message_;
+ ASSERT_TRUE(RunExtensionTest("browser_action/getters")) << message_;
const Extension* extension = GetSingleLoadedExtension();
ASSERT_TRUE(extension) << message_;
@@ -951,13 +919,13 @@ IN_PROC_BROWSER_TEST_P(BrowserActionApiTestWithContextType, Getters) {
// Test the getters for defaults.
ResultCatcher catcher;
- ui_test_utils::NavigateToURL(browser(),
- GURL(extension->GetResourceURL("update.html")));
+ ASSERT_TRUE(ui_test_utils::NavigateToURL(
+ browser(), GURL(extension->GetResourceURL("update.html"))));
ASSERT_TRUE(catcher.GetNextResult());
// Test the getters for a specific tab.
- ui_test_utils::NavigateToURL(browser(),
- GURL(extension->GetResourceURL("update2.html")));
+ ASSERT_TRUE(ui_test_utils::NavigateToURL(
+ browser(), GURL(extension->GetResourceURL("update2.html"))));
ASSERT_TRUE(catcher.GetNextResult());
}
@@ -966,15 +934,15 @@ IN_PROC_BROWSER_TEST_P(BrowserActionApiTestWithContextType,
TestTriggerBrowserAction) {
ASSERT_TRUE(embedded_test_server()->Start());
- ASSERT_TRUE(RunTest("trigger_actions/browser_action")) << message_;
+ ASSERT_TRUE(RunExtensionTest("trigger_actions/browser_action")) << message_;
const Extension* extension = GetSingleLoadedExtension();
ASSERT_TRUE(extension) << message_;
// Test that there is a browser action in the toolbar.
ASSERT_EQ(1, GetBrowserActionsBar()->NumberOfBrowserActions());
- ui_test_utils::NavigateToURL(browser(),
- embedded_test_server()->GetURL("/simple.html"));
+ ASSERT_TRUE(ui_test_utils::NavigateToURL(
+ browser(), embedded_test_server()->GetURL("/simple.html")));
ExtensionAction* browser_action = GetBrowserAction(browser(), *extension);
EXPECT_TRUE(browser_action);
@@ -1003,7 +971,7 @@ IN_PROC_BROWSER_TEST_P(BrowserActionApiTestWithContextType,
WithRectangularIcon) {
ExtensionTestMessageListener ready_listener("ready", true);
- const Extension* extension = LoadExtensionWithParamOptions(
+ const Extension* extension = LoadExtension(
test_data_dir_.AppendASCII("browser_action").AppendASCII("rect_icon"));
ASSERT_TRUE(extension);
EXPECT_TRUE(ready_listener.WaitUntilSatisfied());
diff --git a/chromium/chrome/browser/extensions/api/extension_action/browser_action_interactive_test.cc b/chromium/chrome/browser/extensions/api/extension_action/browser_action_interactive_test.cc
index 2d7dc883530..6bb6ddcc3b0 100644
--- a/chromium/chrome/browser/extensions/api/extension_action/browser_action_interactive_test.cc
+++ b/chromium/chrome/browser/extensions/api/extension_action/browser_action_interactive_test.cc
@@ -5,6 +5,7 @@
#include <memory>
#include "base/run_loop.h"
+#include "base/scoped_observation.h"
#include "base/test/test_timeouts.h"
#include "build/build_config.h"
#include "build/chromeos_buildflags.h"
@@ -34,8 +35,9 @@
#include "extensions/browser/extension_action.h"
#include "extensions/browser/extension_action_manager.h"
#include "extensions/browser/extension_host.h"
+#include "extensions/browser/extension_host_registry.h"
+#include "extensions/browser/extension_host_test_helper.h"
#include "extensions/browser/extension_registry.h"
-#include "extensions/browser/notification_types.h"
#include "extensions/common/extension.h"
#include "extensions/common/extension_set.h"
#include "extensions/common/mojom/view_type.mojom.h"
@@ -59,18 +61,20 @@ namespace {
// Helper to ensure all extension hosts are destroyed during the test. If a host
// is still alive, the Profile can not be destroyed in
-// BrowserProcessImpl::StartTearDown(). TODO(tapted): The existence of this
-// helper is probably a bug. Extension hosts do not currently block shutdown the
-// way a browser tab does. Maybe they should. See http://crbug.com/729476.
-class PopupHostWatcher : public content::NotificationObserver {
+// BrowserProcessImpl::StartTearDown().
+// TODO(tapted): The existence of this helper is probably a bug. Extension
+// hosts do not currently block shutdown the way a browser tab does. Maybe they
+// should. See http://crbug.com/729476.
+class PopupHostWatcher : public ExtensionHostRegistry::Observer {
public:
- PopupHostWatcher() {
- registrar_.Add(this, NOTIFICATION_EXTENSION_HOST_CREATED,
- content::NotificationService::AllSources());
- registrar_.Add(this, NOTIFICATION_EXTENSION_HOST_DESTROYED,
- content::NotificationService::AllSources());
+ explicit PopupHostWatcher(content::BrowserContext* browser_context) {
+ host_registry_observation_.Observe(
+ ExtensionHostRegistry::Get(browser_context));
}
+ PopupHostWatcher(const PopupHostWatcher&) = delete;
+ PopupHostWatcher& operator=(const PopupHostWatcher&) = delete;
+
void Wait() {
if (created_ == destroyed_)
return;
@@ -85,29 +89,40 @@ class PopupHostWatcher : public content::NotificationObserver {
int created() const { return created_; }
int destroyed() const { return destroyed_; }
- // NotificationObserver:
- void Observe(int type,
- const content::NotificationSource& source,
- const content::NotificationDetails& details) override {
+ // ExtensionHostRegistry::Observer:
+ void OnExtensionHostRenderProcessReady(
+ content::BrowserContext* browser_context,
+ ExtensionHost* host) override {
+ // Only track lifetimes for popup window ExtensionHost instances.
+ if (host->extension_host_type() != mojom::ViewType::kExtensionPopup)
+ return;
+
+ ++created_;
+ QuitIfSatisfied();
+ }
+
+ void OnExtensionHostDestroyed(content::BrowserContext* browser_context,
+ ExtensionHost* host) override {
// Only track lifetimes for popup window ExtensionHost instances.
- const ExtensionHost* host =
- content::Details<const ExtensionHost>(details).ptr();
- DCHECK(host);
if (host->extension_host_type() != mojom::ViewType::kExtensionPopup)
return;
- ++(type == NOTIFICATION_EXTENSION_HOST_CREATED ? created_ : destroyed_);
+ ++destroyed_;
+ QuitIfSatisfied();
+ }
+
+ private:
+ void QuitIfSatisfied() {
if (!quit_closure_.is_null() && created_ == destroyed_)
quit_closure_.Run();
}
- private:
- content::NotificationRegistrar registrar_;
base::RepeatingClosure quit_closure_;
int created_ = 0;
int destroyed_ = 0;
-
- DISALLOW_COPY_AND_ASSIGN(PopupHostWatcher);
+ base::ScopedObservation<ExtensionHostRegistry,
+ ExtensionHostRegistry::Observer>
+ host_registry_observation_{this};
};
// chrome.browserAction API tests that interact with the UI in such a way that
@@ -116,12 +131,17 @@ class PopupHostWatcher : public content::NotificationObserver {
class BrowserActionInteractiveTest : public ExtensionApiTest {
public:
BrowserActionInteractiveTest() {}
+
+ BrowserActionInteractiveTest(const BrowserActionInteractiveTest&) = delete;
+ BrowserActionInteractiveTest& operator=(const BrowserActionInteractiveTest&) =
+ delete;
+
~BrowserActionInteractiveTest() override {}
// BrowserTestBase:
void SetUpOnMainThread() override {
- host_watcher_ = std::make_unique<PopupHostWatcher>();
ExtensionApiTest::SetUpOnMainThread();
+ host_watcher_ = std::make_unique<PopupHostWatcher>(profile());
host_resolver()->AddRule("*", "127.0.0.1");
EXPECT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser()));
}
@@ -131,9 +151,11 @@ class BrowserActionInteractiveTest : public ExtensionApiTest {
// called after this. But relying on the window close to close the
// extension host can cause flakes. See http://crbug.com/729476.
// Waiting here requires individual tests to ensure their popup has closed.
- ExtensionApiTest::TearDownOnMainThread();
host_watcher_->Wait();
EXPECT_EQ(host_watcher_->created(), host_watcher_->destroyed());
+ // Destroy the PopupHostWatcher to ensure it stops watching the profile.
+ host_watcher_.reset();
+ ExtensionApiTest::TearDownOnMainThread();
}
protected:
@@ -191,9 +213,8 @@ class BrowserActionInteractiveTest : public ExtensionApiTest {
// Trigger a focus loss to close the popup.
void ClosePopupViaFocusLoss() {
EXPECT_TRUE(ExtensionActionTestHelper::Create(browser())->HasPopup());
- content::WindowedNotificationObserver observer(
- extensions::NOTIFICATION_EXTENSION_HOST_DESTROYED,
- content::NotificationService::AllSources());
+
+ ExtensionHostTestHelper host_helper(profile());
#if defined(OS_MAC)
// ClickOnView() in an inactive window is not robust on Mac. The click does
@@ -213,7 +234,7 @@ class BrowserActionInteractiveTest : public ExtensionApiTest {
// Wait for the notification to achieve a consistent state and verify that
// the popup was properly torn down.
- observer.Wait();
+ host_helper.WaitForHostDestroyed();
base::RunLoop().RunUntilIdle();
}
@@ -221,8 +242,6 @@ class BrowserActionInteractiveTest : public ExtensionApiTest {
private:
std::unique_ptr<PopupHostWatcher> host_watcher_;
-
- DISALLOW_COPY_AND_ASSIGN(BrowserActionInteractiveTest);
};
// Tests opening a popup using the chrome.browserAction.openPopup API. This test
@@ -390,13 +409,11 @@ IN_PROC_BROWSER_TEST_F(BrowserActionInteractiveTest, TabSwitchClosesPopup) {
browser()->tab_strip_model()->GetActiveWebContents());
OpenPopupViaAPI(false);
- content::WindowedNotificationObserver observer(
- extensions::NOTIFICATION_EXTENSION_HOST_DESTROYED,
- content::NotificationService::AllSources());
+ ExtensionHostTestHelper host_helper(profile());
// Change active tabs, the extension popup should close.
browser()->tab_strip_model()->ActivateTabAt(
0, {TabStripModel::GestureType::kOther});
- observer.Wait();
+ host_helper.WaitForHostDestroyed();
EXPECT_FALSE(ExtensionActionTestHelper::Create(browser())->HasPopup());
}
@@ -430,8 +447,8 @@ IN_PROC_BROWSER_TEST_F(BrowserActionInteractiveTest, PopupZoomsIndependently) {
ASSERT_TRUE(extension) << message_;
// Navigate to one of the extension's pages in a tab.
- ui_test_utils::NavigateToURL(browser(),
- extension->GetResourceURL("popup.html"));
+ ASSERT_TRUE(ui_test_utils::NavigateToURL(
+ browser(), extension->GetResourceURL("popup.html")));
content::WebContents* tab_contents =
browser()->tab_strip_model()->GetActiveWebContents();
@@ -448,13 +465,10 @@ IN_PROC_BROWSER_TEST_F(BrowserActionInteractiveTest, PopupZoomsIndependently) {
zoom_change_watcher.Wait();
// Open the extension's popup.
- content::WindowedNotificationObserver popup_observer(
- NOTIFICATION_EXTENSION_HOST_CREATED,
- content::NotificationService::AllSources());
+ ExtensionHostTestHelper host_helper(profile(), extension->id());
OpenPopupViaToolbar(extension->id());
- popup_observer.Wait();
- ExtensionHost* extension_host =
- content::Details<ExtensionHost>(popup_observer.details()).ptr();
+ ExtensionHost* extension_host = host_helper.WaitForRenderProcessReady();
+ ASSERT_TRUE(extension_host);
content::WebContents* popup_contents = extension_host->host_contents();
// The popup should not use the per-origin zoom level that was set by zooming
@@ -494,10 +508,13 @@ IN_PROC_BROWSER_TEST_F(BrowserActionInteractiveTest, PopupZoomsIndependently) {
class BrowserActionInteractiveViewsTest : public BrowserActionInteractiveTest {
public:
BrowserActionInteractiveViewsTest() = default;
- ~BrowserActionInteractiveViewsTest() override = default;
- private:
- DISALLOW_COPY_AND_ASSIGN(BrowserActionInteractiveViewsTest);
+ BrowserActionInteractiveViewsTest(const BrowserActionInteractiveViewsTest&) =
+ delete;
+ BrowserActionInteractiveViewsTest& operator=(
+ const BrowserActionInteractiveViewsTest&) = delete;
+
+ ~BrowserActionInteractiveViewsTest() override = default;
};
// Test closing the browser while inspecting an extension popup with dev tools.
@@ -573,7 +590,13 @@ class MainFrameSizeWaiter : public content::WebContentsObserver {
base::RunLoop run_loop_;
};
-IN_PROC_BROWSER_TEST_F(BrowserActionInteractiveTest, BrowserActionPopup) {
+// TODO(crbug.com/1249851): Test crashes on Windows
+#if defined(OS_WIN)
+#define MAYBE_BrowserActionPopup DISABLED_BrowserActionPopup
+#else
+#define MAYBE_BrowserActionPopup BrowserActionPopup
+#endif
+IN_PROC_BROWSER_TEST_F(BrowserActionInteractiveTest, MAYBE_BrowserActionPopup) {
ASSERT_TRUE(
LoadExtension(test_data_dir_.AppendASCII("browser_action/popup")));
const Extension* extension = GetSingleLoadedExtension();
diff --git a/chromium/chrome/browser/extensions/api/extension_action/extension_action_api.cc b/chromium/chrome/browser/extensions/api/extension_action/extension_action_api.cc
index 6463c89b6e4..7b30965ec9d 100644
--- a/chromium/chrome/browser/extensions/api/extension_action/extension_action_api.cc
+++ b/chromium/chrome/browser/extensions/api/extension_action/extension_action_api.cc
@@ -30,7 +30,6 @@
#include "chrome/browser/ui/tabs/tab_strip_model.h"
#include "chrome/browser/ui/toolbar/toolbar_actions_model.h"
#include "components/sessions/content/session_tab_helper.h"
-#include "content/public/browser/notification_service.h"
#include "extensions/browser/api/declarative_net_request/constants.h"
#include "extensions/browser/api/declarative_net_request/utils.h"
#include "extensions/browser/event_router.h"
@@ -39,7 +38,6 @@
#include "extensions/browser/extension_prefs.h"
#include "extensions/browser/extension_registry.h"
#include "extensions/browser/extension_util.h"
-#include "extensions/browser/notification_types.h"
#include "extensions/common/api/extension_action/action_info.h"
#include "extensions/common/error_utils.h"
#include "extensions/common/feature_switch.h"
@@ -283,18 +281,19 @@ bool ExtensionActionFunction::ExtractDataFromArguments() {
// The tabId might appear in details (if it exists), as the first
// argument besides the action type (depends on the function), or be omitted
// entirely.
- base::Value* first_arg = NULL;
- if (!args_->Get(0, &first_arg))
+ if (args().empty())
return true;
- switch (first_arg->type()) {
+ base::Value& first_arg = mutable_args()[0];
+
+ switch (first_arg.type()) {
case base::Value::Type::INTEGER:
- tab_id_ = first_arg->GetInt();
+ tab_id_ = first_arg.GetInt();
break;
case base::Value::Type::DICTIONARY: {
// Found the details argument.
- details_ = static_cast<base::DictionaryValue*>(first_arg);
+ details_ = static_cast<base::DictionaryValue*>(&first_arg);
// Still need to check for the tabId within details.
base::Value* tab_id_value = NULL;
if (details_->Get("tabId", &tab_id_value)) {
@@ -540,10 +539,10 @@ ExtensionFunction::ResponseAction
ExtensionActionGetBadgeBackgroundColorFunction::RunExtensionAction() {
std::unique_ptr<base::ListValue> list(new base::ListValue());
SkColor color = extension_action_->GetBadgeBackgroundColor(tab_id_);
- list->AppendInteger(static_cast<int>(SkColorGetR(color)));
- list->AppendInteger(static_cast<int>(SkColorGetG(color)));
- list->AppendInteger(static_cast<int>(SkColorGetB(color)));
- list->AppendInteger(static_cast<int>(SkColorGetA(color)));
+ list->Append(static_cast<int>(SkColorGetR(color)));
+ list->Append(static_cast<int>(SkColorGetG(color)));
+ list->Append(static_cast<int>(SkColorGetB(color)));
+ list->Append(static_cast<int>(SkColorGetA(color)));
return RespondNow(
OneArgument(base::Value::FromUniquePtrValue(std::move(list))));
}
@@ -577,6 +576,7 @@ ExtensionFunction::ResponseAction ActionGetUserSettingsFunction::Run() {
}
BrowserActionOpenPopupFunction::BrowserActionOpenPopupFunction() = default;
+BrowserActionOpenPopupFunction::~BrowserActionOpenPopupFunction() = default;
ExtensionFunction::ResponseAction BrowserActionOpenPopupFunction::Run() {
// We only allow the popup in the active window.
@@ -608,8 +608,7 @@ ExtensionFunction::ResponseAction BrowserActionOpenPopupFunction::Run() {
// If the extension is spanning, then extension hosts are created with the
// original profile, and if it's split, then we know the api call came from
// the right profile.
- registrar_.Add(this, NOTIFICATION_EXTENSION_HOST_DID_STOP_FIRST_LOAD,
- content::Source<Profile>(profile));
+ host_registry_observation_.Observe(ExtensionHostRegistry::Get(profile));
// Set a timeout for waiting for the notification that the popup is loaded.
// Waiting is required so that the popup view can be retrieved by the custom
@@ -618,10 +617,19 @@ ExtensionFunction::ResponseAction BrowserActionOpenPopupFunction::Run() {
base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
FROM_HERE,
base::BindOnce(&BrowserActionOpenPopupFunction::OpenPopupTimedOut, this),
- base::TimeDelta::FromSeconds(10));
+ base::Seconds(10));
return RespondLater();
}
+void BrowserActionOpenPopupFunction::OnBrowserContextShutdown() {
+ // No point in responding at this point (the context is gone). However, we
+ // need to explicitly remove the ExtensionHostRegistry observation, since the
+ // ExtensionHostRegistry's lifetime is tied to the BrowserContext. Otherwise,
+ // this would cause a UAF when the observation is destructed as part of this
+ // instance's destruction.
+ host_registry_observation_.Reset();
+}
+
void BrowserActionOpenPopupFunction::OpenPopupTimedOut() {
if (did_respond())
return;
@@ -630,21 +638,18 @@ void BrowserActionOpenPopupFunction::OpenPopupTimedOut() {
Respond(Error(kOpenPopupError));
}
-void BrowserActionOpenPopupFunction::Observe(
- int type,
- const content::NotificationSource& source,
- const content::NotificationDetails& details) {
- DCHECK_EQ(NOTIFICATION_EXTENSION_HOST_DID_STOP_FIRST_LOAD, type);
+void BrowserActionOpenPopupFunction::OnExtensionHostCompletedFirstLoad(
+ content::BrowserContext* browser_context,
+ ExtensionHost* host) {
if (did_respond())
return;
- ExtensionHost* host = content::Details<ExtensionHost>(details).ptr();
if (host->extension_host_type() != mojom::ViewType::kExtensionPopup ||
host->extension()->id() != extension_->id())
return;
Respond(NoArguments());
- registrar_.RemoveAll();
+ host_registry_observation_.Reset();
}
} // namespace extensions
diff --git a/chromium/chrome/browser/extensions/api/extension_action/extension_action_api.h b/chromium/chrome/browser/extensions/api/extension_action/extension_action_api.h
index 1fa5f9d74eb..501ed8759b8 100644
--- a/chromium/chrome/browser/extensions/api/extension_action/extension_action_api.h
+++ b/chromium/chrome/browser/extensions/api/extension_action/extension_action_api.h
@@ -9,12 +9,12 @@
#include "base/macros.h"
#include "base/observer_list.h"
-#include "content/public/browser/notification_observer.h"
-#include "content/public/browser/notification_registrar.h"
+#include "base/scoped_observation.h"
#include "extensions/browser/browser_context_keyed_api_factory.h"
#include "extensions/browser/extension_action.h"
#include "extensions/browser/extension_event_histogram_value.h"
#include "extensions/browser/extension_function.h"
+#include "extensions/browser/extension_host_registry.h"
#include "third_party/skia/include/core/SkColor.h"
namespace base {
@@ -29,6 +29,7 @@ class WebContents;
class Browser;
namespace extensions {
+class ExtensionHost;
class ExtensionPrefs;
class ExtensionActionAPI : public BrowserContextKeyedAPI {
@@ -55,6 +56,10 @@ class ExtensionActionAPI : public BrowserContextKeyedAPI {
};
explicit ExtensionActionAPI(content::BrowserContext* context);
+
+ ExtensionActionAPI(const ExtensionActionAPI&) = delete;
+ ExtensionActionAPI& operator=(const ExtensionActionAPI&) = delete;
+
~ExtensionActionAPI() override;
// Convenience method to get the instance for a profile.
@@ -112,8 +117,6 @@ class ExtensionActionAPI : public BrowserContextKeyedAPI {
content::BrowserContext* browser_context_;
ExtensionPrefs* extension_prefs_;
-
- DISALLOW_COPY_AND_ASSIGN(ExtensionActionAPI);
};
// Implementation of the browserAction and pageAction APIs.
@@ -454,26 +457,34 @@ class BrowserActionDisableFunction : public ExtensionActionHideFunction {
};
class BrowserActionOpenPopupFunction : public ExtensionFunction,
- public content::NotificationObserver {
+ public ExtensionHostRegistry::Observer {
public:
DECLARE_EXTENSION_FUNCTION("browserAction.openPopup",
BROWSERACTION_OPEN_POPUP)
BrowserActionOpenPopupFunction();
+ BrowserActionOpenPopupFunction(const BrowserActionOpenPopupFunction&) =
+ delete;
+ BrowserActionOpenPopupFunction& operator=(
+ const BrowserActionOpenPopupFunction&) = delete;
+
private:
- ~BrowserActionOpenPopupFunction() override {}
+ ~BrowserActionOpenPopupFunction() override;
// ExtensionFunction:
ResponseAction Run() override;
+ void OnBrowserContextShutdown() override;
- void Observe(int type,
- const content::NotificationSource& source,
- const content::NotificationDetails& details) override;
- void OpenPopupTimedOut();
+ // ExtensionHostRegistry::Observer:
+ void OnExtensionHostCompletedFirstLoad(
+ content::BrowserContext* browser_context,
+ ExtensionHost* host) override;
- content::NotificationRegistrar registrar_;
+ void OpenPopupTimedOut();
- DISALLOW_COPY_AND_ASSIGN(BrowserActionOpenPopupFunction);
+ base::ScopedObservation<ExtensionHostRegistry,
+ ExtensionHostRegistry::Observer>
+ host_registry_observation_{this};
};
} // namespace extensions
diff --git a/chromium/chrome/browser/extensions/api/extension_action/extension_action_apitest.cc b/chromium/chrome/browser/extensions/api/extension_action/extension_action_apitest.cc
index 408ae9e0781..58715e01eb3 100644
--- a/chromium/chrome/browser/extensions/api/extension_action/extension_action_apitest.cc
+++ b/chromium/chrome/browser/extensions/api/extension_action/extension_action_apitest.cc
@@ -12,6 +12,7 @@
#include "base/strings/strcat.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
+#include "build/build_config.h"
#include "chrome/browser/extensions/api/extension_action/test_extension_action_api_observer.h"
#include "chrome/browser/extensions/api/extension_action/test_icon_image_observer.h"
#include "chrome/browser/extensions/extension_apitest.h"
@@ -46,11 +47,16 @@ namespace {
// A background script that allows for setting the icon dynamically.
constexpr char kSetIconBackgroundJsTemplate[] =
R"(function setIcon(details) {
- chrome.%s.setIcon(details, () => {
- chrome.test.assertNoLastError();
- chrome.test.notifyPass();
- });
- })";
+ chrome.%s.setIcon(details, () => {
+ chrome.test.assertNoLastError();
+ chrome.test.notifyPass();
+ });
+ }
+ function setIconPromise(details) {
+ chrome.%s.setIcon(details)
+ .then(chrome.test.notifyPass)
+ .catch(chrome.test.notifyFail);
+ })";
constexpr char kPageHtmlTemplate[] =
R"(<html><script src="page.js"></script></html>)";
@@ -74,6 +80,10 @@ class TestStateStoreObserver : public StateStore::TestObserver {
: extension_id_(extension_id) {
scoped_observation_.Observe(ExtensionSystem::Get(context)->state_store());
}
+
+ TestStateStoreObserver(const TestStateStoreObserver&) = delete;
+ TestStateStoreObserver& operator=(const TestStateStoreObserver&) = delete;
+
~TestStateStoreObserver() override {}
void WillSetExtensionValue(const std::string& extension_id,
@@ -93,8 +103,6 @@ class TestStateStoreObserver : public StateStore::TestObserver {
base::ScopedObservation<StateStore, StateStore::TestObserver>
scoped_observation_{this};
-
- DISALLOW_COPY_AND_ASSIGN(TestStateStoreObserver);
};
// A helper class to handle setting or getting the values for an action from JS.
@@ -110,6 +118,10 @@ class ActionTestHelper {
get_method_name_(get_method_name),
js_property_key_(js_property_key),
web_contents_(web_contents) {}
+
+ ActionTestHelper(const ActionTestHelper&) = delete;
+ ActionTestHelper& operator=(const ActionTestHelper&) = delete;
+
~ActionTestHelper() = default;
// Checks the value for the given |tab_id|.
@@ -176,8 +188,6 @@ class ActionTestHelper {
const char* const js_property_key_;
// The WebContents to use to execute API calls.
content::WebContents* const web_contents_;
-
- DISALLOW_COPY_AND_ASSIGN(ActionTestHelper);
};
// Forces a flush of the StateStore, where action state is persisted.
@@ -369,7 +379,7 @@ IN_PROC_BROWSER_TEST_P(MultiActionAPITest,
// Navigating should clear the title.
GURL second_url = embedded_test_server()->GetURL("/title2.html");
- ui_test_utils::NavigateToURL(browser(), second_url);
+ ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), second_url));
EXPECT_EQ(second_url, web_contents->GetLastCommittedURL());
EXPECT_FALSE(action->HasTitle(tab_id));
@@ -549,8 +559,16 @@ IN_PROC_BROWSER_TEST_P(MultiActionAPITest, PopupCreation) {
// Tests that sessionStorage does not persist between closing and opening of a
// popup.
+// TODO(crbug/1256760): Flaky on Linux.
+#if defined(OS_LINUX)
+#define MAYBE_SessionStorageDoesNotPersistBetweenOpenings \
+ DISABLED_SessionStorageDoesNotPersistBetweenOpenings
+#else
+#define MAYBE_SessionStorageDoesNotPersistBetweenOpenings \
+ SessionStorageDoesNotPersistBetweenOpenings
+#endif
IN_PROC_BROWSER_TEST_P(MultiActionAPITest,
- SessionStorageDoesNotPersistBetweenOpenings) {
+ MAYBE_SessionStorageDoesNotPersistBetweenOpenings) {
constexpr char kManifestTemplate[] =
R"({
"name": "Test sessionStorage",
@@ -741,6 +759,7 @@ IN_PROC_BROWSER_TEST_P(MultiActionAPICanvasTest, DynamicSetIcon) {
test_dir.WriteFile(FILE_PATH_LITERAL("page.html"), kPageHtmlTemplate);
test_dir.WriteFile(FILE_PATH_LITERAL("page.js"),
base::StringPrintf(kSetIconBackgroundJsTemplate,
+ GetAPINameForActionType(GetParam()),
GetAPINameForActionType(GetParam())));
test_dir.CopyFileTo(test_data_dir_.AppendASCII("icon_rgb_0_0_255.png"),
FILE_PATH_LITERAL("blue_icon.png"));
@@ -834,6 +853,19 @@ IN_PROC_BROWSER_TEST_P(MultiActionAPICanvasTest, DynamicSetIcon) {
EXPECT_FALSE(new_tab_icon.IsEmpty());
EXPECT_EQ(SK_ColorGREEN, new_tab_icon.AsBitmap().getColor(mid_x, mid_y));
+ // Manifest V3 extensions using the action API should also be able to use a
+ // promise version of setIcon.
+ if (GetManifestVersionForActionType(GetParam()) == 3) {
+ constexpr char kSetIconPromiseScript[] =
+ "setIconPromise({tabId: %d, path: 'blue_icon.png'});";
+ RunTestAndWaitForSuccess(
+ web_contents, base::StringPrintf(kSetIconPromiseScript, new_tab_id));
+
+ new_tab_icon = toolbar_helper->GetIcon(extension->id());
+ EXPECT_FALSE(new_tab_icon.IsEmpty());
+ EXPECT_EQ(SK_ColorBLUE, new_tab_icon.AsBitmap().getColor(mid_x, mid_y));
+ }
+
// Switch back to the first tab. The icon should still be red, since the other
// changes were for specific tabs.
browser()->tab_strip_model()->ActivateTabAt(0);
@@ -864,6 +896,7 @@ IN_PROC_BROWSER_TEST_P(MultiActionAPITest, SetIconWithJavascriptHooks) {
test_dir.WriteFile(FILE_PATH_LITERAL("page.html"), kPageHtmlTemplate);
test_dir.WriteFile(FILE_PATH_LITERAL("page.js"),
base::StringPrintf(kSetIconBackgroundJsTemplate,
+ GetAPINameForActionType(GetParam()),
GetAPINameForActionType(GetParam())));
test_dir.CopyFileTo(test_data_dir_.AppendASCII("icon_rgb_0_0_255.png"),
FILE_PATH_LITERAL("blue_icon.png"));
@@ -934,6 +967,7 @@ IN_PROC_BROWSER_TEST_P(MultiActionAPITest, SetIconWithSelfDefined) {
test_dir.WriteFile(FILE_PATH_LITERAL("page.html"), kPageHtmlTemplate);
test_dir.WriteFile(FILE_PATH_LITERAL("page.js"),
base::StringPrintf(kSetIconBackgroundJsTemplate,
+ GetAPINameForActionType(GetParam()),
GetAPINameForActionType(GetParam())));
test_dir.CopyFileTo(test_data_dir_.AppendASCII("icon_rgb_0_0_255.png"),
FILE_PATH_LITERAL("blue_icon.png"));
diff --git a/chromium/chrome/browser/extensions/api/extension_action/page_action_apitest.cc b/chromium/chrome/browser/extensions/api/extension_action/page_action_apitest.cc
index 002338fa762..7c8ef6f371e 100644
--- a/chromium/chrome/browser/extensions/api/extension_action/page_action_apitest.cc
+++ b/chromium/chrome/browser/extensions/api/extension_action/page_action_apitest.cc
@@ -36,7 +36,7 @@ using ContextType = ExtensionBrowserTest::ContextType;
class PageActionApiTest : public ExtensionApiTest,
public testing::WithParamInterface<ContextType> {
public:
- PageActionApiTest() = default;
+ PageActionApiTest() : ExtensionApiTest(GetParam()) {}
~PageActionApiTest() override = default;
PageActionApiTest(const PageActionApiTest&) = delete;
PageActionApiTest& operator=(const PageActionApiTest&) = delete;
@@ -50,12 +50,6 @@ class PageActionApiTest : public ExtensionApiTest,
? extension_action
: nullptr;
}
-
- bool RunTest(const char* name) {
- return RunExtensionTest(
- name, {},
- {.load_as_service_worker = GetParam() == ContextType::kServiceWorker});
- }
};
INSTANTIATE_TEST_SUITE_P(PersistentBackground,
@@ -67,14 +61,14 @@ INSTANTIATE_TEST_SUITE_P(ServiceWorker,
IN_PROC_BROWSER_TEST_P(PageActionApiTest, Basic) {
ASSERT_TRUE(embedded_test_server()->Start());
- ASSERT_TRUE(RunTest("page_action/basics")) << message_;
+ ASSERT_TRUE(RunExtensionTest("page_action/basics")) << message_;
const Extension* extension = GetSingleLoadedExtension();
ASSERT_TRUE(extension) << message_;
{
// Tell the extension to update the page action state.
ResultCatcher catcher;
- ui_test_utils::NavigateToURL(browser(),
- GURL(extension->GetResourceURL("update.html")));
+ ASSERT_TRUE(ui_test_utils::NavigateToURL(
+ browser(), GURL(extension->GetResourceURL("update.html"))));
ASSERT_TRUE(catcher.GetNextResult());
}
@@ -99,8 +93,8 @@ IN_PROC_BROWSER_TEST_P(PageActionApiTest, Basic) {
{
// Tell the extension to update the page action state again.
ResultCatcher catcher;
- ui_test_utils::NavigateToURL(browser(),
- GURL(extension->GetResourceURL("update2.html")));
+ ASSERT_TRUE(ui_test_utils::NavigateToURL(
+ browser(), GURL(extension->GetResourceURL("update2.html"))));
ASSERT_TRUE(catcher.GetNextResult());
}
@@ -119,7 +113,7 @@ IN_PROC_BROWSER_TEST_P(PageActionApiTest, Basic) {
// Test that calling chrome.pageAction.setPopup() can enable a popup.
IN_PROC_BROWSER_TEST_P(PageActionApiTest, AddPopup) {
// Load the extension, which has no default popup.
- ASSERT_TRUE(RunTest("page_action/add_popup")) << message_;
+ ASSERT_TRUE(RunExtensionTest("page_action/add_popup")) << message_;
const Extension* extension = GetSingleLoadedExtension();
ASSERT_TRUE(extension) << message_;
@@ -152,9 +146,8 @@ IN_PROC_BROWSER_TEST_P(PageActionApiTest, AddPopup) {
// Load a page which removes the popup using chrome.pageAction.setPopup().
{
ResultCatcher catcher;
- ui_test_utils::NavigateToURL(
- browser(),
- GURL(extension->GetResourceURL("change_popup.html")));
+ ASSERT_TRUE(ui_test_utils::NavigateToURL(
+ browser(), GURL(extension->GetResourceURL("change_popup.html"))));
ASSERT_TRUE(catcher.GetNextResult());
}
@@ -166,7 +159,7 @@ IN_PROC_BROWSER_TEST_P(PageActionApiTest, AddPopup) {
// Test that calling chrome.pageAction.setPopup() can remove a popup.
IN_PROC_BROWSER_TEST_P(PageActionApiTest, RemovePopup) {
// Load the extension, which has a page action with a default popup.
- ASSERT_TRUE(RunTest("page_action/remove_popup")) << message_;
+ ASSERT_TRUE(RunExtensionTest("page_action/remove_popup")) << message_;
const Extension* extension = GetSingleLoadedExtension();
ASSERT_TRUE(extension) << message_;
@@ -183,9 +176,8 @@ IN_PROC_BROWSER_TEST_P(PageActionApiTest, RemovePopup) {
// Load a page which removes the popup using chrome.pageAction.setPopup().
{
ResultCatcher catcher;
- ui_test_utils::NavigateToURL(
- browser(),
- GURL(extension->GetResourceURL("remove_popup.html")));
+ ASSERT_TRUE(ui_test_utils::NavigateToURL(
+ browser(), GURL(extension->GetResourceURL("remove_popup.html"))));
ASSERT_TRUE(catcher.GetNextResult());
}
@@ -196,29 +188,24 @@ IN_PROC_BROWSER_TEST_P(PageActionApiTest, RemovePopup) {
// Test http://crbug.com/57333: that two page action extensions using the same
// icon for the page action icon and the extension icon do not crash.
IN_PROC_BROWSER_TEST_P(PageActionApiTest, TestCrash57333) {
- const bool load_as_service_worker = GetParam() == ContextType::kServiceWorker;
// Load extension A.
- ASSERT_TRUE(
- LoadExtension(test_data_dir_.AppendASCII("page_action")
- .AppendASCII("crash_57333")
- .AppendASCII("Extension1"),
- {.load_as_service_worker = load_as_service_worker}));
+ ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII("page_action")
+ .AppendASCII("crash_57333")
+ .AppendASCII("Extension1")));
// Load extension B.
- ASSERT_TRUE(
- LoadExtension(test_data_dir_.AppendASCII("page_action")
- .AppendASCII("crash_57333")
- .AppendASCII("Extension2"),
- {.load_as_service_worker = load_as_service_worker}));
+ ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII("page_action")
+ .AppendASCII("crash_57333")
+ .AppendASCII("Extension2")));
}
IN_PROC_BROWSER_TEST_P(PageActionApiTest, Getters) {
- ASSERT_TRUE(RunTest("page_action/getters")) << message_;
+ ASSERT_TRUE(RunExtensionTest("page_action/getters")) << message_;
const Extension* extension = GetSingleLoadedExtension();
ASSERT_TRUE(extension) << message_;
ResultCatcher catcher;
- ui_test_utils::NavigateToURL(browser(),
- GURL(extension->GetResourceURL("update.html")));
+ ASSERT_TRUE(ui_test_utils::NavigateToURL(
+ browser(), GURL(extension->GetResourceURL("update.html"))));
ASSERT_TRUE(catcher.GetNextResult());
}
@@ -226,13 +213,13 @@ IN_PROC_BROWSER_TEST_P(PageActionApiTest, Getters) {
IN_PROC_BROWSER_TEST_P(PageActionApiTest, TestTriggerPageAction) {
ASSERT_TRUE(embedded_test_server()->Start());
- ASSERT_TRUE(RunTest("trigger_actions/page_action")) << message_;
+ ASSERT_TRUE(RunExtensionTest("trigger_actions/page_action")) << message_;
const Extension* extension = GetSingleLoadedExtension();
ASSERT_TRUE(extension) << message_;
// Page action icon is displayed when a tab is created.
- ui_test_utils::NavigateToURL(browser(),
- embedded_test_server()->GetURL("/simple.html"));
+ ASSERT_TRUE(ui_test_utils::NavigateToURL(
+ browser(), embedded_test_server()->GetURL("/simple.html")));
chrome::NewTab(browser());
browser()->tab_strip_model()->ActivateTabAt(
0, {TabStripModel::GestureType::kOther});
diff --git a/chromium/chrome/browser/extensions/api/extension_action/test_extension_action_api_observer.h b/chromium/chrome/browser/extensions/api/extension_action/test_extension_action_api_observer.h
index e2423448cf2..e55d1afec29 100644
--- a/chromium/chrome/browser/extensions/api/extension_action/test_extension_action_api_observer.h
+++ b/chromium/chrome/browser/extensions/api/extension_action/test_extension_action_api_observer.h
@@ -29,6 +29,12 @@ class TestExtensionActionAPIObserver : public ExtensionActionAPI::Observer {
content::BrowserContext* context,
const ExtensionId& extension_id,
const std::set<content::WebContents*>& contents_to_observe);
+
+ TestExtensionActionAPIObserver(const TestExtensionActionAPIObserver&) =
+ delete;
+ TestExtensionActionAPIObserver& operator=(
+ const TestExtensionActionAPIObserver&) = delete;
+
~TestExtensionActionAPIObserver() override;
// Waits until the extension action is updated and the update is seen for all
@@ -57,8 +63,6 @@ class TestExtensionActionAPIObserver : public ExtensionActionAPI::Observer {
// An optional set of web contents to observe for extension action updates.
std::set<content::WebContents*> contents_to_observe_;
-
- DISALLOW_COPY_AND_ASSIGN(TestExtensionActionAPIObserver);
};
} // namespace extensions
diff --git a/chromium/chrome/browser/extensions/api/extension_action/test_icon_image_observer.h b/chromium/chrome/browser/extensions/api/extension_action/test_icon_image_observer.h
index 310eef3c44f..172f11e66f6 100644
--- a/chromium/chrome/browser/extensions/api/extension_action/test_icon_image_observer.h
+++ b/chromium/chrome/browser/extensions/api/extension_action/test_icon_image_observer.h
@@ -19,6 +19,10 @@ class Extension;
class TestIconImageObserver : public IconImage::Observer {
public:
TestIconImageObserver();
+
+ TestIconImageObserver(const TestIconImageObserver&) = delete;
+ TestIconImageObserver& operator=(const TestIconImageObserver&) = delete;
+
~TestIconImageObserver() override;
void Wait(IconImage* icon);
@@ -33,8 +37,6 @@ class TestIconImageObserver : public IconImage::Observer {
base::RunLoop run_loop_;
base::ScopedObservation<IconImage, IconImage::Observer> observation_{this};
-
- DISALLOW_COPY_AND_ASSIGN(TestIconImageObserver);
};
} // namespace extensions