chromium/ash/user_education/views/help_bubble_view_ash_pixeltest.cc

// 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 <optional>
#include <string>
#include <vector>

#include "ash/test/pixel/ash_pixel_differ.h"
#include "ash/test/pixel/ash_pixel_test_init_params.h"
#include "ash/user_education/user_education_types.h"
#include "ash/user_education/views/help_bubble_view_ash.h"
#include "ash/user_education/views/help_bubble_view_ash_test_base.h"
#include "base/test/scoped_feature_list.h"
#include "chromeos/constants/chromeos_features.h"
#include "components/user_education/common/help_bubble_params.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/gfx/color_palette.h"
#include "ui/views/view.h"
#include "ui/views/widget/widget.h"

namespace ash {
namespace {

// Aliases.
using user_education::HelpBubbleArrow;

// Helpers ---------------------------------------------------------------------

void EmplaceBackIf(std::vector<std::string>& container,
                   std::string value,
                   bool condition) {
  if (condition) {
    container.emplace_back(std::move(value));
  }
}

}  // namespace

// HelpBubbleViewAshPixelTestBase ----------------------------------------------

// Base class for pixel tests of `HelpBubbleViewAsh`.
class HelpBubbleViewAshPixelTestBase : public HelpBubbleViewAshTestBase {
 public:
  HelpBubbleViewAshPixelTestBase() {
    // Features using help bubble views are not launching until post-Jelly, so
    // ensure that benchmark images are taken with the Jelly flag enabled.
    scoped_feature_list_.InitAndEnableFeature(chromeos::features::kJelly);
  }

 private:
  // HelpBubbleViewAshTestBase:
  std::optional<pixel_test::InitParams> CreatePixelTestInitParams()
      const override {
    return pixel_test::InitParams();
  }

  // Used to enable the Jelly flag so that benchmark images accurately reflect
  // the state of the world when features using help bubble views launch.
  base::test::ScopedFeatureList scoped_feature_list_;
};

// HelpBubbleViewPixelTest -----------------------------------------------------

// Base class for pixel tests of `HelpBubbleViewAsh` parameterized by attributes
// to include when creating help bubble views.
class HelpBubbleViewAshPixelTest
    : public HelpBubbleViewAshPixelTestBase,
      public testing::WithParamInterface<std::tuple<
          /*with_title_text=*/bool,
          /*with_body_icon=*/bool,
          /*with_buttons=*/bool,
          /*with_progress=*/bool>> {
 public:
  // Returns whether an attribute should be included when creating help bubble
  // views given test parameterization.
  bool with_title_text() const { return std::get<0>(GetParam()); }
  bool with_body_icon() const { return std::get<1>(GetParam()); }
  bool with_buttons() const { return std::get<2>(GetParam()); }
  bool with_progress() const { return std::get<3>(GetParam()); }
};

INSTANTIATE_TEST_SUITE_P(
    All,
    HelpBubbleViewAshPixelTest,
    testing::Combine(
        /*with_title_text=*/testing::Bool(),
        /*with_body_icon=*/testing::Bool(),
        /*with_buttons=*/testing::Bool(),
        /*with_progress=*/testing::Bool()),
    [](const auto& info) {
      std::vector<std::string> param_name{"HelpBubbleViewAsh"};
      EmplaceBackIf(param_name, "WithTitleText", std::get<0>(info.param));
      EmplaceBackIf(param_name, "WithBodyIcon", std::get<1>(info.param));
      EmplaceBackIf(param_name, "WithButtons", std::get<2>(info.param));
      EmplaceBackIf(param_name, "WithProgress", std::get<3>(info.param));
      return base::JoinString(param_name, "_");
    });

// Tests -----------------------------------------------------------------------

// Protects against regression in `HelpBubbleViewAsh` appearance by comparing
// help bubble views created with attributes according to test parameterization
// against benchmark images.
TEST_P(HelpBubbleViewAshPixelTest, Appearance) {
  auto* help_bubble_view =
      CreateHelpBubbleView(HelpBubbleArrow::kNone, with_title_text(),
                           with_body_icon(), with_buttons(), with_progress());

  EXPECT_TRUE(GetPixelDiffer()->CompareUiComponentsOnPrimaryScreen(
      "appearance", /*revision_number=*/7, help_bubble_view,
      help_bubble_view->anchor_widget()));
}

// HelpBubbleViewAshArrowPixelTest ---------------------------------------------

// Base class for pixel tests of `HelpBubbleArrow` as it relates to
// `HelpBubbleViewAsh`, parameterized by arrow to use when creating help bubble
// views.
class HelpBubbleViewAshArrowPixelTest
    : public HelpBubbleViewAshPixelTestBase,
      public testing::WithParamInterface<HelpBubbleArrow> {
 public:
  // Returns the arrow to use when creating help bubble views given test
  // parameterization.
  HelpBubbleArrow arrow() const { return GetParam(); }
};

#define ENUM_CASE(Enum, Value) \
  case Enum::Value:            \
    return #Enum "_" #Value;

INSTANTIATE_TEST_SUITE_P(All,
                         HelpBubbleViewAshArrowPixelTest,
                         testing::Values(HelpBubbleArrow::kNone,
                                         HelpBubbleArrow::kTopLeft,
                                         HelpBubbleArrow::kTopRight,
                                         HelpBubbleArrow::kBottomLeft,
                                         HelpBubbleArrow::kBottomRight,
                                         HelpBubbleArrow::kLeftTop,
                                         HelpBubbleArrow::kRightTop,
                                         HelpBubbleArrow::kLeftBottom,
                                         HelpBubbleArrow::kRightBottom,
                                         HelpBubbleArrow::kTopCenter,
                                         HelpBubbleArrow::kBottomCenter,
                                         HelpBubbleArrow::kLeftCenter,
                                         HelpBubbleArrow::kRightCenter),
                         [](const auto& info) {
                           switch (info.param) {
                             ENUM_CASE(HelpBubbleArrow, kNone);
                             ENUM_CASE(HelpBubbleArrow, kTopLeft);
                             ENUM_CASE(HelpBubbleArrow, kTopRight);
                             ENUM_CASE(HelpBubbleArrow, kBottomLeft);
                             ENUM_CASE(HelpBubbleArrow, kBottomRight);
                             ENUM_CASE(HelpBubbleArrow, kLeftTop);
                             ENUM_CASE(HelpBubbleArrow, kRightTop);
                             ENUM_CASE(HelpBubbleArrow, kLeftBottom);
                             ENUM_CASE(HelpBubbleArrow, kRightBottom);
                             ENUM_CASE(HelpBubbleArrow, kTopCenter);
                             ENUM_CASE(HelpBubbleArrow, kBottomCenter);
                             ENUM_CASE(HelpBubbleArrow, kLeftCenter);
                             ENUM_CASE(HelpBubbleArrow, kRightCenter);
                           }
                         });

// Tests -----------------------------------------------------------------------

// Protects against regression in `HelpBubbleViewAsh` placement by comparing
// help bubble views created with arrows according to test parameterization
// against benchmark images.
TEST_P(HelpBubbleViewAshArrowPixelTest, Placement) {
  auto* help_bubble_view = CreateHelpBubbleView(
      arrow(), /*with_title_text=*/true, /*with_body_icon=*/true,
      /*with_buttons=*/true, /*with_progress=*/true);

  EXPECT_TRUE(GetPixelDiffer()->CompareUiComponentsOnPrimaryScreen(
      "placement", /*revision_number=*/7, help_bubble_view,
      help_bubble_view->anchor_widget()));
}

}  // namespace ash