// Copyright 2012 The Chromium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef EXTENSIONS_TEST_EXTENSION_TEST_MESSAGE_LISTENER_H_ #define EXTENSIONS_TEST_EXTENSION_TEST_MESSAGE_LISTENER_H_ #include <optional> #include <string> #include "base/functional/callback.h" #include "base/memory/raw_ptr.h" #include "base/memory/scoped_refptr.h" #include "base/scoped_observation.h" #include "extensions/browser/api/test/test_api_observer.h" #include "extensions/browser/api/test/test_api_observer_registry.h" #include "extensions/common/extension_id.h" namespace content { class BrowserContext; } namespace extensions { class TestSendMessageFunction; } // This class helps us wait for incoming messages sent from javascript via // chrome.test.sendMessage(). A sample usage would be: // // ExtensionTestMessageListener listener("foo"); // ... do some work // ASSERT_TRUE(listener.WaitUntilSatisfied()); // // It is also possible to have the extension wait for our reply. This is // useful for coordinating multiple pages/processes and having them wait on // each other. Example: // // ExtensionTestMessageListener listener1("foo1", ReplyBehavior::kWillReply); // ExtensionTestMessageListener listener2("foo2", ReplyBehavior::kWillReply); // ASSERT_TRUE(listener1.WaitUntilSatisfied()); // ASSERT_TRUE(listener2.WaitUntilSatisfied()); // ... do some work // listener1.Reply("foo2 is ready"); // listener2.Reply("foo1 is ready"); // // Further, we can use this to listen for a success and failure message: // // ExtensionTestMessageListener listener("success", will_reply); // listener.set_failure_message("failure"); // ASSERT_TRUE(listener.WaitUntilSatisfied()); // if (listener.message() == "success") { // HandleSuccess(); // } else { // ASSERT_EQ("failure", listener.message()); // HandleFailure(); // } // // Or, use it to listen to any arbitrary message: // // ExtensionTestMessageListener listener(will_reply); // ASSERT_TRUE(listener.WaitUntilSatisfied()); // if (listener.message() == "foo") // HandleFoo(); // else if (listener.message() == "bar") // HandleBar(); // else if (listener.message() == "baz") // HandleBaz(); // else // NOTREACHED_IN_MIGRATION(); // // You can also use the class to listen for messages from a specified extension: // // ExtensionTestMessageListener listener(will_reply); // listener.set_extension_id(extension->id()); // ASSERT_TRUE(listener.WaitUntilSatisfied()); // ... do some work. // // A callback can be set to react to a message from an extension, instead of // manually waiting. // // ExtensionTestMessageListener listener("do_something"); // listener.SetOnSatisfied(base::BindOnce(&DoSomething)); // ... run test // // SetOnRepeatedlySatisfied could be used if the message is expected // // multiple times. // // Finally, you can reset the listener to reuse it. // // ExtensionTestMessageListener listener(ReplyBehavior::kWillReply); // ASSERT_TRUE(listener.WaitUntilSatisfied()); // while (listener.message() != "end") { // Handle(listener.message()); // listener.Reply("bar"); // listener.Reset(); // ASSERT_TRUE(listener.WaitUntilSatisfied()); // } // // Note that when using it in browser tests, you need to make sure it gets // destructed *before* the browser gets torn down. Two common patterns are to // either make it a local variable inside your test body, or if it's a member // variable of a ExtensionBrowserTest subclass, override the // BrowserTestBase::TearDownOnMainThread() method and clean it up there. // The behavior specifying whether the listener will reply to the // incoming message. This is defined outside the class simply to save authors // from typing out ReplyBehavior::kWillReply. enum class ReplyBehavior { … }; class ExtensionTestMessageListener : public extensions::TestApiObserver { … }; #endif // EXTENSIONS_TEST_EXTENSION_TEST_MESSAGE_LISTENER_H_