| // Copyright 2024 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #ifndef COMPONENTS_USER_EDUCATION_TEST_FEATURE_PROMO_CONTROLLER_TEST_BASE_H_ |
| #define COMPONENTS_USER_EDUCATION_TEST_FEATURE_PROMO_CONTROLLER_TEST_BASE_H_ |
| |
| #include <map> |
| #include <memory> |
| #include <optional> |
| |
| #include "base/feature_list.h" |
| #include "base/memory/scoped_refptr.h" |
| #include "base/test/task_environment.h" |
| #include "components/feature_engagement/public/tracker.h" |
| #include "components/feature_engagement/test/mock_tracker.h" |
| #include "components/user_education/common/feature_promo/feature_promo_controller.h" |
| #include "components/user_education/common/feature_promo/feature_promo_registry.h" |
| #include "components/user_education/common/feature_promo/feature_promo_result.h" |
| #include "components/user_education/common/feature_promo/feature_promo_session_policy.h" |
| #include "components/user_education/common/help_bubble/help_bubble_factory_registry.h" |
| #include "components/user_education/common/product_messaging_controller.h" |
| #include "components/user_education/common/tutorial/tutorial_registry.h" |
| #include "components/user_education/common/tutorial/tutorial_service.h" |
| #include "components/user_education/common/user_education_context.h" |
| #include "components/user_education/common/user_education_storage_service.h" |
| #include "components/user_education/test/mock_user_education_context.h" |
| #include "components/user_education/test/test_help_bubble.h" |
| #include "components/user_education/test/test_user_education_storage_service.h" |
| #include "components/user_education/test/user_education_session_mocks.h" |
| #include "testing/gmock/include/gmock/gmock.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| #include "ui/base/accelerators/accelerator.h" |
| #include "ui/base/interaction/element_identifier.h" |
| #include "ui/base/interaction/element_test_util.h" |
| #include "ui/base/interaction/element_tracker.h" |
| #include "ui/events/event_modifiers.h" |
| |
| namespace user_education::test { |
| |
| BASE_DECLARE_FEATURE(kTestIPHFocusHelpBubbleScreenReaderPromoFeature); |
| |
| // Base test fixture that can be used to test a FeaturePromoController. Mocks or |
| // fakes all of the other systems the controller needs to talk to. |
| class FeaturePromoControllerTestBase : public testing::Test { |
| public: |
| DECLARE_CLASS_ELEMENT_IDENTIFIER_VALUE(kAnchorElementId); |
| static const ui::ElementContext kAnchorElementContext; |
| static constexpr char kTestFocusHelpBubbleAcceleratorPromoRead[] = |
| "test_focus_help_bubble_accelerator_promo_read"; |
| |
| FeaturePromoControllerTestBase(); |
| ~FeaturePromoControllerTestBase() override; |
| |
| void SetUp() override; |
| void TearDown() override; |
| |
| protected: |
| // Base class for test wrappers (see below); allows setting/getting help |
| // bubble contexts. |
| class TestPromoControllerBase { |
| public: |
| TestPromoControllerBase(); |
| virtual ~TestPromoControllerBase(); |
| |
| void set_context_for_help_bubble(ui::ElementIdentifier id, |
| UserEducationContextPtr context) { |
| bubble_contexts_[id] = context; |
| } |
| |
| UserEducationContextPtr get_context_for_help_bubble( |
| ui::ElementIdentifier id) const { |
| const auto it = bubble_contexts_.find(id); |
| return it != bubble_contexts_.end() ? it->second : nullptr; |
| } |
| |
| private: |
| std::map<ui::ElementIdentifier, UserEducationContextPtr> bubble_contexts_; |
| }; |
| |
| // Wrapper for a promo controller that implements all the application-specific |
| // methods. |
| template <class T> |
| requires std::derived_from<T, FeaturePromoControllerCommon> |
| class TestPromoController : public T, public TestPromoControllerBase { |
| public: |
| using T::T; |
| ~TestPromoController() override = default; |
| |
| protected: |
| std::u16string GetBodyIconAltText() const override { |
| return u"Body Icon Alt Text"; |
| } |
| const base::Feature* GetScreenReaderPromptPromoFeature() const override { |
| return &kTestIPHFocusHelpBubbleScreenReaderPromoFeature; |
| } |
| const char* GetScreenReaderPromptPromoEventName() const override { |
| return kTestFocusHelpBubbleAcceleratorPromoRead; |
| } |
| std::u16string GetTutorialScreenReaderHint( |
| const ui::AcceleratorProvider*) const override { |
| return u"Tutorial Screen Reader Hint"; |
| } |
| std::u16string GetFocusHelpBubbleScreenReaderHint( |
| FeaturePromoSpecification::PromoType, |
| ui::TrackedElement*, |
| const ui::AcceleratorProvider*) const override { |
| return u"Focus Help Bubble Screen Reader Hint"; |
| } |
| |
| UserEducationContextPtr GetContextForHelpBubble( |
| const ui::TrackedElement* anchor_element) const override { |
| return get_context_for_help_bubble(anchor_element->identifier()); |
| } |
| }; |
| |
| // Sets the mock tracker's initialization success. |
| virtual std::optional<bool> GetTrackerResult() const; |
| void SendTrackerResult(bool result); |
| |
| // Finds the current help bubble. |
| TestHelpBubble* GetHelpBubble( |
| std::optional<ui::ElementContext> context = std::nullopt) const; |
| |
| feature_engagement::test::MockTracker& tracker() { return tracker_; } |
| FeaturePromoRegistry& promo_registry() { return promo_registry_; } |
| HelpBubbleFactoryRegistry& help_bubble_factory_registry() { |
| return help_bubble_factory_registry_; |
| } |
| UserEducationStorageService& storage_service() { return storage_service_; } |
| MockFeaturePromoSessionPolicy& session_policy() { return session_policy_; } |
| TutorialService& tutorial_service() { return tutorial_service_; } |
| ProductMessagingController& messaging_controller() { |
| return messaging_controller_; |
| } |
| FeaturePromoControllerCommon& promo_controller() { |
| return *promo_controller_; |
| } |
| const scoped_refptr<MockUserEducationContext>& promo_context() { |
| return test_promo_context_; |
| } |
| ui::test::TestElement& anchor_element() { return anchor_element_; } |
| |
| // Implemented by derived classes to create the controller. |
| virtual std::unique_ptr<FeaturePromoControllerCommon> CreateController() = 0; |
| |
| private: |
| class TestTutorialService : public TutorialService { |
| public: |
| using TutorialService::TutorialService; |
| ~TestTutorialService() override; |
| |
| protected: |
| // TutorialService: |
| std::u16string GetBodyIconAltText(bool is_last_step) const override; |
| }; |
| |
| base::test::SingleThreadTaskEnvironment task_environment_{ |
| base::test::SingleThreadTaskEnvironment::TimeSource::MOCK_TIME}; |
| feature_engagement::test::MockTracker tracker_; |
| FeaturePromoRegistry promo_registry_; |
| TestUserEducationStorageService storage_service_; |
| |
| // Have a default anchor element that starts visible, to make things easier. |
| // Tests can create their own elements in this context or others. |
| ui::test::TestElement anchor_element_{kAnchorElementId, |
| kAnchorElementContext}; |
| |
| // Don't use a completely faked tutorial service for now; it's sufficient to |
| // use the help bubble factory with test help bubbles instead. |
| HelpBubbleFactoryRegistry help_bubble_factory_registry_; |
| TutorialRegistry tutorial_registry_; |
| TestTutorialService tutorial_service_{&tutorial_registry_, |
| &help_bubble_factory_registry_}; |
| |
| // Use a vanilla product messaging controller since the messages themselves |
| // can be mocked. The associated session provider will never start a new |
| // session since that is not being tested. |
| TestUserEducationSessionProvider session_provider_{false}; |
| ProductMessagingController messaging_controller_; |
| |
| MockFeaturePromoSessionPolicy session_policy_; |
| std::unique_ptr<FeaturePromoControllerCommon> promo_controller_; |
| scoped_refptr<MockUserEducationContext> test_promo_context_; |
| std::vector<feature_engagement::Tracker::OnInitializedCallback> |
| on_initialized_callbacks_; |
| }; |
| |
| } // namespace user_education::test |
| |
| #endif // COMPONENTS_USER_EDUCATION_TEST_FEATURE_PROMO_CONTROLLER_TEST_BASE_H_ |