chromium/chrome/browser/ui/quick_answers/ui/quick_answers_view_unittest.cc

// Copyright 2020 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/quick_answers/ui/quick_answers_view.h"

#include <memory>

#include "base/functional/bind.h"
#include "base/memory/scoped_refptr.h"
#include "base/strings/utf_string_conversions.h"
#include "chrome/browser/ui/quick_answers/quick_answers_controller_impl.h"
#include "chrome/browser/ui/quick_answers/quick_answers_ui_controller.h"
#include "chrome/browser/ui/quick_answers/test/chrome_quick_answers_test_base.h"
#include "chrome/browser/ui/quick_answers/test/mock_quick_answers_client.h"
#include "chrome/browser/ui/quick_answers/ui/result_view.h"
#include "chrome/browser/ui/quick_answers/ui/retry_view.h"
#include "chromeos/components/quick_answers/public/cpp/constants.h"
#include "chromeos/components/quick_answers/public/cpp/controller/quick_answers_controller.h"
#include "chromeos/components/quick_answers/quick_answers_client.h"
#include "chromeos/components/quick_answers/quick_answers_model.h"
#include "chromeos/strings/grit/chromeos_strings.h"
#include "services/network/public/cpp/shared_url_loader_factory.h"
#include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h"
#include "services/network/test/test_url_loader_factory.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/gfx/geometry/point.h"
#include "ui/views/accessibility/view_accessibility.h"
#include "ui/views/controls/menu/menu_controller.h"
#include "ui/views/view_utils.h"

namespace quick_answers {
namespace {

constexpr int kMarginDip = 8;
constexpr int kSmallTop = 30;
constexpr gfx::Rect kDefaultAnchorBoundsInScreen =
    gfx::Rect(gfx::Point(500, 250), gfx::Size(80, 140));
constexpr char kTestQuery[] = "test-query";

// There are U16 variants as it's not allowed to use `base::UTF8ToUTF16` for
// string literals.
constexpr char kWord[] = "Word";
constexpr char kDefinition[] = "Definition";
constexpr char16_t kDefinitionU16[] = u"Definition";
constexpr char kPhoneticsInfoText[] = "PhoneticsInfoText";
constexpr char16_t kDefinitionTitleU16[] = u"Word ยท /PhoneticsInfoText/";
constexpr char kPhoneticsInfoQueryText[] = "PhoneticsInfoQueryText";
constexpr char kPhoneticsInfoAudioUrl[] = "https://example.com/";
constexpr char kSourceLocaleJaJp[] = "ja-JP";
constexpr char kTextToTranslate[] = "TextToTranslate";
constexpr char16_t kTextToTranslateU16[] = u"TextToTranslate";
constexpr char kTranslatedText[] = "TranslatedText";
constexpr char16_t kTranslatedTextU16[] = u"TranslatedText";
constexpr char kSourceText[] = "SourceText";
constexpr char16_t kSourceTextU16[] = u"SourceText";
constexpr char kResultText[] = "ResultText";
constexpr char16_t kResultTextU16[] = u"ResultText";

}  // namespace

// `QuickAnswersViewsTest` will test UI behaviors with layers above
// `QuickAnswersClient`.
//
// Layers:
// UI codes (`QuickAnswersView`, etc)
// `QuickAnswersUiController`
// `QuickAnswersControllerImpl`
// `QuickAnswersClient`
class QuickAnswersViewsTest : public ChromeQuickAnswersTestBase {
 protected:
  QuickAnswersViewsTest() = default;
  QuickAnswersViewsTest(const QuickAnswersViewsTest&) = delete;
  QuickAnswersViewsTest& operator=(const QuickAnswersViewsTest&) = delete;
  ~QuickAnswersViewsTest() override = default;

  // ChromeQuickAnswersTestBase:
  void SetUp() override {
    ChromeQuickAnswersTestBase::SetUp();

    anchor_bounds_ = kDefaultAnchorBoundsInScreen;
    GetUiController()->GetReadWriteCardsUiController().SetContextMenuBounds(
        anchor_bounds_);

    QuickAnswersControllerImpl* controller =
        static_cast<QuickAnswersControllerImpl*>(QuickAnswersController::Get());
    CHECK(controller);
    std::unique_ptr<MockQuickAnswersClient> mock_quick_answers_client =
        std::make_unique<MockQuickAnswersClient>(
            base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>(
                &test_url_loader_factory_),
            controller);
    mock_quick_answers_client_ = mock_quick_answers_client.get();
    controller->SetClient(std::move(mock_quick_answers_client));
  }

  void TearDown() override {
    // `MockQuickAnswersClient` will be released if the controller gets
    // released. Release a pointer to avoid having a dangling pointer.
    mock_quick_answers_client_ = nullptr;

    ChromeQuickAnswersTestBase::TearDown();
  }

  // Currently instantiated QuickAnswersView instance.
  QuickAnswersView* GetQuickAnswersView() {
    return views::AsViewClass<QuickAnswersView>(
        GetUiController()->quick_answers_view());
  }

  // Needed to poll the current bounds of the mock anchor.
  const gfx::Rect& GetAnchorBounds() { return anchor_bounds_; }

  QuickAnswersUiController* GetUiController() {
    return static_cast<QuickAnswersControllerImpl*>(
               QuickAnswersController::Get())
        ->quick_answers_ui_controller();
  }

  // Create a QuickAnswersView instance with custom anchor-bounds.
  void CreateQuickAnswersView(const gfx::Rect anchor_bounds,
                              std::optional<Intent> intent,
                              bool is_internal) {
    // Set up a companion menu before creating the QuickAnswersView.
    CreateAndShowBasicMenu();

    anchor_bounds_ = anchor_bounds;
    GetUiController()->GetReadWriteCardsUiController().SetContextMenuBounds(
        anchor_bounds_);

    static_cast<QuickAnswersControllerImpl*>(QuickAnswersController::Get())
        ->SetVisibility(QuickAnswersVisibility::kQuickAnswersVisible);
    // TODO(b/222422130): Rewrite QuickAnswersViewsTest to expand coverage.
    GetUiController()->CreateQuickAnswersView(
        GetProfile(), "title", kTestQuery, intent,
        QuickAnswersState::FeatureType::kQuickAnswers, is_internal);
  }

  void SendResult(const DefinitionResult& definition_result) {
    std::unique_ptr<StructuredResult> structured_result =
        std::make_unique<StructuredResult>();
    structured_result->definition_result =
        std::make_unique<DefinitionResult>(definition_result);
    SendResult(std::move(structured_result));
  }

  void SendResult(const TranslationResult& translation_result) {
    std::unique_ptr<StructuredResult> structured_result =
        std::make_unique<StructuredResult>();
    structured_result->translation_result =
        std::make_unique<TranslationResult>(translation_result);
    SendResult(std::move(structured_result));
  }

  void SendResult(const UnitConversionResult& unit_conversion_result) {
    std::unique_ptr<StructuredResult> structured_result =
        std::make_unique<StructuredResult>();
    structured_result->unit_conversion_result =
        std::make_unique<UnitConversionResult>(unit_conversion_result);
    SendResult(std::move(structured_result));
  }

  void SendResult(std::unique_ptr<StructuredResult> structured_result) {
    QuickAnswersControllerImpl* controller =
        static_cast<QuickAnswersControllerImpl*>(QuickAnswersController::Get());
    CHECK(controller);

    std::unique_ptr<QuickAnswersSession> quick_answers_session =
        std::make_unique<QuickAnswersSession>();
    quick_answers_session->structured_result = std::move(structured_result);
    controller->OnQuickAnswerReceived(std::move(quick_answers_session));
  }

  void MockGenerateTtsCallback() {
    GetQuickAnswersView()->SetMockGenerateTtsCallbackForTesting(
        base::BindRepeating(&QuickAnswersViewsTest::MockGenerateTts,
                            base::Unretained(this)));
  }

  void MockOpenSettingsCallback() {
    GetUiController()->SetFakeOpenSettingsCallbackForTesting(
        base::BindRepeating(&QuickAnswersViewsTest::MockOpenSettings,
                            base::Unretained(this)));
  }

  bool is_open_settigns_called() const { return is_open_settings_called_; }

  void MockOpenFeedbackPageCallback() {
    GetUiController()->SetFakeOpenFeedbackPageCallbackForTesting(
        base::BindRepeating(&QuickAnswersViewsTest::MockOpenFeedbackPage,
                            base::Unretained(this)));
  }

  std::string mock_feedback_template() const { return mock_feedback_template_; }

  void MockOpenWebUrlCallback() {
    GetUiController()->SetFakeOpenWebUrlForTesting(base::BindRepeating(
        &QuickAnswersViewsTest::MockOpenWebUrl, base::Unretained(this)));
  }

  GURL mock_open_web_url() const { return mock_open_web_url_; }

  void TriggerNetworkError() {
    QuickAnswersControllerImpl* controller =
        static_cast<QuickAnswersControllerImpl*>(QuickAnswersController::Get());
    controller->OnNetworkError();
  }

  void FakeOnRetryPressed() {
    GetUiController()->SetFakeOnRetryLabelPressedCallbackForTesting(
        base::BindRepeating(&QuickAnswersViewsTest::OnRetryPressed,
                            base::Unretained(this)));
  }

  void OnRetryPressed() {
    DefinitionResult definition_result;
    definition_result.word = kWord;
    definition_result.sense.definition = kDefinition;
    SendResult(definition_result);
  }

  PhoneticsInfo mock_phonetics_info() { return mock_phonetics_info_; }

  MockQuickAnswersClient* mock_quick_answers_client() {
    return mock_quick_answers_client_;
  }

 private:
  void MockGenerateTts(const PhoneticsInfo& phonetics_info) {
    mock_phonetics_info_ = phonetics_info;
  }

  void MockOpenSettings() { is_open_settings_called_ = true; }

  void MockOpenFeedbackPage(const std::string& feedback_template_) {
    mock_feedback_template_ = feedback_template_;
  }

  void MockOpenWebUrl(const GURL& url) { mock_open_web_url_ = url; }

  raw_ptr<MockQuickAnswersClient> mock_quick_answers_client_ = nullptr;
  network::TestURLLoaderFactory test_url_loader_factory_;
  PhoneticsInfo mock_phonetics_info_;
  bool is_open_settings_called_ = false;
  std::string mock_feedback_template_;
  GURL mock_open_web_url_;
  chromeos::ReadWriteCardsUiController controller_;
  gfx::Rect anchor_bounds_;
};

TEST_F(QuickAnswersViewsTest, DefaultLayoutAroundAnchor) {
  gfx::Rect anchor_bounds = GetAnchorBounds();
  CreateQuickAnswersView(anchor_bounds, Intent::kDefinition,
                         /*is_internal=*/false);
  gfx::Rect view_bounds = GetQuickAnswersView()->GetBoundsInScreen();

  // Vertically aligned with anchor.
  EXPECT_EQ(view_bounds.x(), anchor_bounds.x());
  EXPECT_EQ(view_bounds.right(), anchor_bounds.right());

  // View is positioned above the anchor.
  EXPECT_EQ(view_bounds.bottom() + kMarginDip, anchor_bounds.y());
}

TEST_F(QuickAnswersViewsTest, PositionedBelowAnchorIfLessSpaceAbove) {
  gfx::Rect anchor_bounds = GetAnchorBounds();
  // Update anchor-bounds' position so that it does not leave enough vertical
  // space above it to show the QuickAnswersView.
  anchor_bounds.set_y(kSmallTop);

  CreateQuickAnswersView(anchor_bounds, Intent::kDefinition,
                         /*is_internal=*/false);
  gfx::Rect view_bounds = GetQuickAnswersView()->GetBoundsInScreen();

  // Anchor is positioned above the view.
  EXPECT_EQ(anchor_bounds.bottom() + kMarginDip, view_bounds.y());
}

TEST_F(QuickAnswersViewsTest, FocusProperties) {
  CreateQuickAnswersView(GetAnchorBounds(), Intent::kDefinition,
                         /*is_internal=*/false);
  CHECK(views::MenuController::GetActiveInstance() &&
        views::MenuController::GetActiveInstance()->owner());

  // Gains focus only upon request, if an owned menu was active when the view
  // was created.
  CHECK(views::MenuController::GetActiveInstance() != nullptr);
  EXPECT_FALSE(GetQuickAnswersView()->HasFocus());
  GetQuickAnswersView()->RequestFocus();
  EXPECT_TRUE(GetQuickAnswersView()->HasFocus());
}

TEST_F(QuickAnswersViewsTest, Retry) {
  // TODO(b/335701090): change this to use `MockQuickAnswersClient` with a fake
  // behavior.
  FakeOnRetryPressed();

  CreateQuickAnswersView(GetAnchorBounds(), Intent::kDefinition,
                         /*is_internal=*/false);

  TriggerNetworkError();

  RetryView* retry_view = GetQuickAnswersView()->GetRetryViewForTesting();
  ASSERT_TRUE(retry_view);
  EXPECT_TRUE(retry_view->GetVisible());
  GetEventGenerator()->MoveMouseTo(
      retry_view->retry_label_button()->GetBoundsInScreen().CenterPoint());
  GetEventGenerator()->ClickLeftButton();

  EXPECT_FALSE(GetQuickAnswersView()->GetRetryViewForTesting()->GetVisible());
  EXPECT_TRUE(GetQuickAnswersView()->GetResultViewForTesting()->GetVisible());
}

TEST_F(QuickAnswersViewsTest, Result) {
  CreateQuickAnswersView(GetAnchorBounds(), Intent::kDefinition,
                         /*is_internal=*/false);

  DefinitionResult definition_result;
  definition_result.word = kWord;
  definition_result.sense.definition = kDefinition;
  SendResult(definition_result);

  ResultView* result_view = GetQuickAnswersView()->GetResultViewForTesting();
  ASSERT_TRUE(result_view);
  EXPECT_TRUE(result_view->GetVisible());
  EXPECT_FALSE(result_view->phonetics_audio_button()->GetVisible());
}

TEST_F(QuickAnswersViewsTest, ResultWithPhoneticsAudio) {
  CreateQuickAnswersView(GetAnchorBounds(), Intent::kDefinition,
                         /*is_internal=*/false);
  MockGenerateTtsCallback();
  EXPECT_CALL(*mock_quick_answers_client(), OnQuickAnswerClick(testing::_))
      .Times(0);
  EXPECT_CALL(*mock_quick_answers_client(),
              OnQuickAnswersDismissed(testing::_, testing::_))
      .Times(0);

  DefinitionResult definition_result;
  definition_result.word = kWord;
  definition_result.sense.definition = kDefinition;
  definition_result.phonetics_info.text = kPhoneticsInfoText;
  definition_result.phonetics_info.query_text = kPhoneticsInfoQueryText;
  definition_result.phonetics_info.phonetics_audio =
      GURL(kPhoneticsInfoAudioUrl);
  definition_result.phonetics_info.tts_audio_enabled = true;
  SendResult(definition_result);

  ResultView* result_view = GetQuickAnswersView()->GetResultViewForTesting();
  ASSERT_TRUE(result_view);
  EXPECT_TRUE(result_view->GetVisible());
  EXPECT_TRUE(result_view->phonetics_audio_button()->GetVisible());
  EXPECT_TRUE(result_view->GetBoundsInScreen().Contains(
      result_view->phonetics_audio_button()->GetBoundsInScreen()))
      << "Phonetics audio button must be inside ResultView";

  GetEventGenerator()->MoveMouseTo(
      result_view->phonetics_audio_button()->GetBoundsInScreen().CenterPoint());
  GetEventGenerator()->ClickLeftButton();

  EXPECT_EQ(mock_phonetics_info().phonetics_audio,
            GURL(kPhoneticsInfoAudioUrl));
  EXPECT_TRUE(GetQuickAnswersView());
}

TEST_F(QuickAnswersViewsTest, OpenSettings) {
  CreateQuickAnswersView(GetAnchorBounds(), Intent::kDefinition,
                         /*is_internal=*/false);
  MockOpenSettingsCallback();
  EXPECT_CALL(*mock_quick_answers_client(), OnQuickAnswerClick(testing::_))
      .Times(0);
  EXPECT_CALL(*mock_quick_answers_client(),
              OnQuickAnswersDismissed(testing::_, testing::_))
      .Times(0);

  DefinitionResult definition_result;
  definition_result.word = kWord;
  definition_result.sense.definition = kDefinition;
  SendResult(definition_result);

  GetEventGenerator()->MoveMouseTo(GetQuickAnswersView()
                                       ->GetSettingsButtonForTesting()
                                       ->GetBoundsInScreen()
                                       .CenterPoint());
  GetEventGenerator()->ClickLeftButton();

  EXPECT_TRUE(is_open_settigns_called());
  EXPECT_FALSE(GetQuickAnswersView());
}

TEST_F(QuickAnswersViewsTest, OpenFeedbackPage) {
  CreateQuickAnswersView(GetAnchorBounds(), Intent::kDefinition,
                         /*is_internal=*/true);
  MockOpenFeedbackPageCallback();
  EXPECT_CALL(*mock_quick_answers_client(), OnQuickAnswerClick(testing::_))
      .Times(0);
  EXPECT_CALL(*mock_quick_answers_client(),
              OnQuickAnswersDismissed(testing::_, testing::_))
      .Times(0);

  DefinitionResult definition_result;
  definition_result.word = kWord;
  definition_result.sense.definition = kDefinition;
  SendResult(definition_result);

  ASSERT_TRUE(
      GetQuickAnswersView()->GetDogfoodButtonForTesting()->GetVisible());
  GetEventGenerator()->MoveMouseTo(GetQuickAnswersView()
                                       ->GetDogfoodButtonForTesting()
                                       ->GetBoundsInScreen()
                                       .CenterPoint());
  GetEventGenerator()->ClickLeftButton();

  EXPECT_NE(mock_feedback_template().find(kTestQuery), std::string::npos);
  EXPECT_FALSE(GetQuickAnswersView());
}

TEST_F(QuickAnswersViewsTest, ClickResultCard) {
  CreateQuickAnswersView(GetAnchorBounds(), Intent::kDefinition,
                         /*is_internal=*/false);
  MockOpenWebUrlCallback();
  EXPECT_CALL(*mock_quick_answers_client(), OnQuickAnswerClick(testing::_))
      .Times(1);
  EXPECT_CALL(*mock_quick_answers_client(),
              OnQuickAnswersDismissed(testing::_, testing::_))
      .Times(0);

  DefinitionResult definition_result;
  definition_result.word = kWord;
  definition_result.sense.definition = kDefinition;
  SendResult(definition_result);

  GetEventGenerator()->MoveMouseTo(
      GetQuickAnswersView()->GetBoundsInScreen().CenterPoint());
  GetEventGenerator()->ClickLeftButton();

  EXPECT_EQ(GURL("https://www.google.com/search?q=test-query"),
            mock_open_web_url());
  EXPECT_FALSE(GetQuickAnswersView());
}

TEST_F(QuickAnswersViewsTest, ClickLoadingCard) {
  CreateQuickAnswersView(GetAnchorBounds(), Intent::kDefinition,
                         /*is_internal=*/false);
  MockOpenWebUrlCallback();
  EXPECT_CALL(*mock_quick_answers_client(), OnQuickAnswerClick(testing::_))
      .Times(0);
  EXPECT_CALL(*mock_quick_answers_client(),
              OnQuickAnswersDismissed(testing::_, testing::_))
      .Times(0);

  GetEventGenerator()->MoveMouseTo(
      GetQuickAnswersView()->GetBoundsInScreen().CenterPoint());
  GetEventGenerator()->ClickLeftButton();

  EXPECT_EQ(GURL("https://www.google.com/search?q=test-query"),
            mock_open_web_url());
  EXPECT_FALSE(GetQuickAnswersView());
}

TEST_F(QuickAnswersViewsTest, ClickRetryCard) {
  CreateQuickAnswersView(GetAnchorBounds(), Intent::kDefinition,
                         /*is_internal=*/false);
  MockOpenWebUrlCallback();
  EXPECT_CALL(*mock_quick_answers_client(), OnQuickAnswerClick(testing::_))
      .Times(0);
  EXPECT_CALL(*mock_quick_answers_client(),
              OnQuickAnswersDismissed(testing::_, testing::_))
      .Times(0);

  TriggerNetworkError();

  gfx::Point cursor =
      GetQuickAnswersView()->GetBoundsInScreen().bottom_center();
  cursor.Offset(0, -10);
  ASSERT_FALSE(GetQuickAnswersView()
                   ->GetRetryViewForTesting()
                   ->retry_label_button()
                   ->GetBoundsInScreen()
                   .Contains(cursor))
      << "Make sure to click outside of a retry button";
  ASSERT_TRUE(GetQuickAnswersView()->GetBoundsInScreen().Contains(cursor));
  GetEventGenerator()->MoveMouseTo(cursor);
  GetEventGenerator()->ClickLeftButton();

  EXPECT_EQ(GURL("https://www.google.com/search?q=test-query"),
            mock_open_web_url());
  EXPECT_FALSE(GetQuickAnswersView());
}

TEST_F(QuickAnswersViewsTest, Definition) {
  CreateQuickAnswersView(GetAnchorBounds(), Intent::kDefinition,
                         /*is_internal=*/false);

  DefinitionResult definition_result;
  definition_result.word = kWord;
  definition_result.sense.definition = kDefinition;
  definition_result.phonetics_info.text = kPhoneticsInfoText;
  definition_result.phonetics_info.query_text = kPhoneticsInfoQueryText;
  definition_result.phonetics_info.phonetics_audio =
      GURL(kPhoneticsInfoAudioUrl);
  definition_result.phonetics_info.tts_audio_enabled = true;
  SendResult(definition_result);

  ResultView* result_view = GetQuickAnswersView()->GetResultViewForTesting();
  ASSERT_TRUE(result_view->GetVisible());
  EXPECT_EQ(result_view->GetFirstLineText(), kDefinitionTitleU16);
  EXPECT_TRUE(result_view->GetFirstLineSubText().empty());
  EXPECT_EQ(result_view->GetSecondLineText(), kDefinitionU16);
  EXPECT_TRUE(result_view->phonetics_audio_button()->GetVisible());
}

TEST_F(QuickAnswersViewsTest, Translation) {
  CreateQuickAnswersView(GetAnchorBounds(), Intent::kTranslation,
                         /*is_internal=*/false);

  TranslationResult translation_result;
  translation_result.source_locale = kSourceLocaleJaJp;
  translation_result.text_to_translate = kTextToTranslate;
  translation_result.translated_text = kTranslatedText;
  SendResult(translation_result);

  ResultView* result_view = GetQuickAnswersView()->GetResultViewForTesting();
  ASSERT_TRUE(result_view->GetVisible());
  EXPECT_EQ(result_view->GetFirstLineText(), kTextToTranslateU16);
  EXPECT_EQ(result_view->GetFirstLineSubText(), u"Japanese");
  EXPECT_EQ(result_view->GetSecondLineText(), kTranslatedTextU16);
}

TEST_F(QuickAnswersViewsTest, UnitConversion) {
  CreateQuickAnswersView(GetAnchorBounds(), Intent::kUnitConversion,
                         /*is_internal=*/false);

  UnitConversionResult unit_conversion_result;
  unit_conversion_result.source_text = kSourceText;
  unit_conversion_result.result_text = kResultText;
  SendResult(unit_conversion_result);

  ResultView* result_view = GetQuickAnswersView()->GetResultViewForTesting();
  ASSERT_TRUE(result_view->GetVisible());
  EXPECT_EQ(result_view->GetFirstLineText(), kSourceTextU16);
  EXPECT_EQ(result_view->GetSecondLineText(), kResultTextU16);
}

TEST_F(QuickAnswersViewsTest, IntentTransition) {
  CreateQuickAnswersView(GetAnchorBounds(), /*intent=*/std::nullopt,
                         /*is_internal=*/false);
  EXPECT_EQ(std::nullopt, GetQuickAnswersView()->GetIntent());

  UnitConversionResult unit_conversion_result;
  unit_conversion_result.source_text = kSourceText;
  unit_conversion_result.result_text = kResultText;
  SendResult(unit_conversion_result);
  EXPECT_EQ(Intent::kUnitConversion, GetQuickAnswersView()->GetIntent());
}

TEST_F(QuickAnswersViewsTest, AccessibleProperties) {
  FakeOnRetryPressed();
  CreateQuickAnswersView(GetAnchorBounds(), Intent::kDefinition,
                         /*is_internal=*/false);

  TriggerNetworkError();

  // When RetryView is visible, accessible name for QuickAnswersView should be
  // set to empty.
  RetryView* retry_view = GetQuickAnswersView()->GetRetryViewForTesting();
  EXPECT_TRUE(retry_view->GetVisible());
  ui::AXNodeData data;
  GetQuickAnswersView()->GetViewAccessibility().GetAccessibleNodeData(&data);
  EXPECT_EQ(data.GetString16Attribute(ax::mojom::StringAttribute::kName),
            std::u16string());
  EXPECT_EQ(data.GetIntAttribute(ax::mojom::IntAttribute::kNameFrom),
            static_cast<int>(ax::mojom::NameFrom::kAttributeExplicitlyEmpty));

  // When RetryView is not visible, accessible name for QuickAnswersView should
  // be set to non-empty pre-determined value.
  retry_view = GetQuickAnswersView()->GetRetryViewForTesting();
  GetEventGenerator()->MoveMouseTo(
      retry_view->retry_label_button()->GetBoundsInScreen().CenterPoint());
  GetEventGenerator()->ClickLeftButton();
  EXPECT_FALSE(retry_view->GetVisible());
  data = ui::AXNodeData();
  GetQuickAnswersView()->GetViewAccessibility().GetAccessibleNodeData(&data);
  EXPECT_EQ(data.GetStringAttribute(ax::mojom::StringAttribute::kName),
            l10n_util::GetStringUTF8(IDS_QUICK_ANSWERS_VIEW_A11Y_NAME_TEXT));
}

}  // namespace quick_answers