blob: 150b7dac232a83e61309641b8ebbfe6a248e7822 [file] [log] [blame]
// Copyright 2023 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/ui/ash/user_education/chrome_user_education_delegate.h"
#include <memory>
#include "ash/session/test_session_controller_client.h"
#include "ash/test/ash_test_helper.h"
#include "ash/user_education/user_education_class_properties.h"
#include "ash/user_education/user_education_types.h"
#include "ash/user_education/user_education_util.h"
#include "base/functional/callback.h"
#include "base/functional/callback_helpers.h"
#include "base/memory/raw_ptr.h"
#include "chrome/browser/ash/login/users/fake_chrome_user_manager.h"
#include "chrome/browser/ui/user_education/user_education_service.h"
#include "chrome/browser/ui/user_education/user_education_service_factory.h"
#include "chrome/test/base/browser_with_test_window_test.h"
#include "chrome/test/base/testing_profile.h"
#include "chrome/test/base/testing_profile_manager.h"
#include "chromeos/ash/components/browser_context_helper/browser_context_helper.h"
#include "components/strings/grit/components_strings.h"
#include "components/user_education/common/help_bubble_params.h"
#include "components/user_education/common/tutorial_description.h"
#include "components/user_education/common/tutorial_registry.h"
#include "components/user_education/common/tutorial_service.h"
#include "components/user_manager/scoped_user_manager.h"
#include "components/user_manager/user.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/base/interaction/element_identifier.h"
#include "ui/base/interaction/element_test_util.h"
#include "ui/base/interaction/interaction_sequence.h"
#include "ui/views/interaction/element_tracker_views.h"
#include "ui/views/view.h"
#include "ui/views/view_class_properties.h"
#include "ui/views/widget/widget.h"
namespace {
// Element identifiers.
DEFINE_LOCAL_ELEMENT_IDENTIFIER_VALUE(kElementId);
} // namespace
// ChromeUserEducationDelegateTest ---------------------------------------------
// Base class for tests of the `ChromeUserEducationDelegate`.
class ChromeUserEducationDelegateTest : public BrowserWithTestWindowTest {
public:
ChromeUserEducationDelegateTest()
: user_manager_(new ash::FakeChromeUserManager()),
user_manager_enabler_(base::WrapUnique(user_manager_.get())) {}
// Returns the `AccountId` for the primary `profile()`.
const AccountId& account_id() const {
return ash::BrowserContextHelper::Get()
->GetUserByBrowserContext(profile())
->GetAccountId();
}
// Returns a pointer to the `delegate_` instance under test.
ash::UserEducationDelegate* delegate() { return delegate_.get(); }
private:
// BrowserWithTestWindowTest:
void SetUp() override {
BrowserWithTestWindowTest::SetUp();
// Instantiate the `delegate_` after `BrowserWithTestWindowTest::SetUp()`
// so that the browser process has fully initialized.
delegate_ = std::make_unique<ChromeUserEducationDelegate>();
}
TestingProfile* CreateProfile() override {
constexpr char kUserEmail[] = "user@test";
const AccountId kUserAccountId(AccountId::FromUserEmail(kUserEmail));
// Register user.
user_manager_->AddUser(kUserAccountId);
user_manager_->LoginUser(kUserAccountId);
// Activate session.
auto* client = ash_test_helper()->test_session_controller_client();
client->AddUserSession(kUserEmail);
client->SwitchActiveUser(kUserAccountId);
// Create profile.
return profile_manager()->CreateTestingProfile(kUserEmail);
}
// User management.
const raw_ptr<ash::FakeChromeUserManager, ExperimentalAsh> user_manager_;
user_manager::ScopedUserManager user_manager_enabler_;
// The delegate instance under test.
std::unique_ptr<ChromeUserEducationDelegate> delegate_;
};
// Tests -----------------------------------------------------------------------
// Verifies `CreateHelpBubble()` is working as intended.
TEST_F(ChromeUserEducationDelegateTest, CreateHelpBubble) {
// Create and show a `widget`.
views::Widget widget;
views::Widget::InitParams params;
params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
params.type = views::Widget::InitParams::TYPE_WINDOW_FRAMELESS;
widget.Init(std::move(params));
widget.SetContentsView(std::make_unique<views::View>());
widget.CenterWindow(gfx::Size(100, 100));
widget.Show();
// Cache `element_context` for the widget.
const ui::ElementContext element_context =
views::ElementTrackerViews::GetContextForWidget(&widget);
// Verify that a help bubble is *not* created for the specified `kElementId`
// and `element_context` pair since no tracked element matching that pair has
// been registered with the element tracker framework.
EXPECT_FALSE(delegate()->CreateHelpBubble(
account_id(), ash::HelpBubbleId::kTest,
user_education::HelpBubbleParams(), kElementId, element_context));
// Register the `widget`s contents `view` with the element tracker framework.
views::View* const view = widget.GetContentsView();
view->SetProperty(ash::kHelpBubbleContextKey, ash::HelpBubbleContext::kAsh);
view->SetProperty(views::kElementIdentifierKey, kElementId);
// Verify that a help bubble *is* created for the specified `kElementId` and
// `element_context` pair.
EXPECT_TRUE(delegate()->CreateHelpBubble(
account_id(), ash::HelpBubbleId::kTest,
user_education::HelpBubbleParams(), kElementId, element_context));
}
// Verifies `RegisterTutorial()` registers a tutorial with the browser registry.
TEST_F(ChromeUserEducationDelegateTest, RegisterTutorial) {
const ash::TutorialId tutorial_id = ash::TutorialId::kTest;
const auto tutorial_id_str = ash::user_education_util::ToString(tutorial_id);
// Initially there should be no tutorial registered.
user_education::TutorialRegistry& tutorial_registry =
UserEducationServiceFactory::GetForProfile(profile())
->tutorial_registry();
EXPECT_FALSE(tutorial_registry.IsTutorialRegistered(tutorial_id_str));
// Attempt to register a tutorial.
delegate()->RegisterTutorial(account_id(), tutorial_id,
user_education::TutorialDescription());
// Confirm tutorial registration.
EXPECT_TRUE(tutorial_registry.IsTutorialRegistered(tutorial_id_str));
}
// Verifies `StartTutorial()` starts a tutorial with the browser service.
TEST_F(ChromeUserEducationDelegateTest, StartTutorial) {
// Create a test element.
const ui::ElementContext element_context(1);
ui::test::TestElement test_element(kElementId, element_context);
// Create a tutorial description.
user_education::TutorialDescription tutorial_description;
tutorial_description.steps.emplace_back(
/*title_text_id_=*/0, /*body_text_id_=*/IDS_OK,
ui::InteractionSequence::StepType::kShown, kElementId,
/*element_name=*/std::string(), user_education::HelpBubbleArrow::kNone);
// Register the tutorial.
delegate()->RegisterTutorial(account_id(), ash::TutorialId::kTest,
std::move(tutorial_description));
// Verify the tutorial is not running.
user_education::TutorialService& tutorial_service =
UserEducationServiceFactory::GetForProfile(profile())->tutorial_service();
EXPECT_FALSE(tutorial_service.IsRunningTutorial());
// Attempt to start the tutorial.
delegate()->StartTutorial(account_id(), ash::TutorialId::kTest,
element_context,
/*completed_callback=*/base::DoNothing(),
/*aborted_callback=*/base::DoNothing());
// Confirm the tutorial is running.
EXPECT_TRUE(tutorial_service.IsRunningTutorial());
}