blob: b204c0ba28f33e1835dbf3120a69d3403a9f1eb4 [file] [log] [blame]
// Copyright 2025 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "base/test/metrics/histogram_tester.h"
#include "base/test/test_future.h"
#include "chrome/browser/contextual_cueing/contextual_cueing_features.h"
#include "chrome/browser/contextual_cueing/contextual_cueing_service.h"
#include "chrome/browser/contextual_cueing/contextual_cueing_service_factory.h"
#include "chrome/browser/contextual_cueing/zero_state_suggestions_page_data.h"
#include "chrome/browser/glic/glic_pref_names.h"
#include "chrome/browser/optimization_guide/browser_test_util.h"
#include "chrome/browser/optimization_guide/optimization_guide_keyed_service_factory.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_commands.h"
#include "chrome/test/base/in_process_browser_test.h"
#include "chrome/test/base/ui_test_utils.h"
#include "components/optimization_guide/core/optimization_guide_features.h"
#include "components/optimization_guide/core/optimization_guide_model_executor.h"
#include "components/optimization_guide/core/optimization_guide_proto_util.h"
#include "components/optimization_guide/core/optimization_guide_switches.h"
#include "components/optimization_guide/proto/contextual_cueing_metadata.pb.h"
#include "components/optimization_guide/proto/features/zero_state_suggestions.pb.h"
#include "components/prefs/pref_service.h"
#include "content/public/test/browser_test.h"
namespace contextual_cueing {
enum class ContentExtraction {
kFetchInnerTextOnly,
kFetchAnnotatedPageContentOnly,
kFetchInnerTextAndAnnotatedPageContent,
};
class ZeroStateSuggestionsBrowserTest
: public InProcessBrowserTest,
public ::testing::WithParamInterface<ContentExtraction> {
public:
ZeroStateSuggestionsBrowserTest() {
base::FieldTrialParams zss_params;
switch (GetParam()) {
case ContentExtraction::kFetchInnerTextOnly:
zss_params = {{"ZSSExtractInnerText", "true"},
{"ZSSExtractAnnotatedPageContent", "false"}};
break;
case ContentExtraction::kFetchAnnotatedPageContentOnly:
zss_params = {{"ZSSExtractInnerText", "false"},
{"ZSSExtractAnnotatedPageContent", "true"}};
break;
case ContentExtraction::kFetchInnerTextAndAnnotatedPageContent:
zss_params = {{"ZSSExtractInnerText", "true"},
{"ZSSExtractAnnotatedPageContent", "true"}};
break;
}
scoped_feature_list_.InitWithFeaturesAndParameters(
{{contextual_cueing::kContextualCueing, {}},
{contextual_cueing::kGlicZeroStateSuggestions, zss_params}},
/*disabled_features=*/{});
}
void SetUp() override {
ASSERT_TRUE(embedded_test_server()->Start());
url_ = embedded_test_server()->GetURL("/optimization_guide/zss_page.html");
InProcessBrowserTest::SetUp();
}
void SetUpOnMainThread() override {
// Override glic tab context sharing to be always on.
browser()->profile()->GetPrefs()->SetBoolean(
glic::prefs::kGlicTabContextEnabled, true);
}
void DisableOptimizationPermissionCheck() {
base::CommandLine::ForCurrentProcess()->AppendSwitch(
optimization_guide::switches::
kDisableCheckingUserPermissionsForTesting);
}
GURL url() { return url_; }
ContentExtraction GetContentExtraction() const { return GetParam(); }
void SetUpOnDemandHints(const GURL& url,
bool allow_contextual,
const std::vector<std::string>& suggestions) {
optimization_guide::proto::GlicZeroStateSuggestionsMetadata metadata;
metadata.set_contextual_suggestions_eligible(allow_contextual);
*metadata.mutable_contextual_suggestions() = {suggestions.begin(),
suggestions.end()};
optimization_guide::OptimizationGuideDecisionWithMetadata
decision_with_metadata;
decision_with_metadata.decision =
optimization_guide::OptimizationGuideDecision::kTrue;
decision_with_metadata.metadata.set_any_metadata(
optimization_guide::AnyWrapProto(metadata));
OptimizationGuideKeyedServiceFactory::GetInstance()
->GetForProfile(browser()->profile())
->AddOnDemandHintForTesting(
url, optimization_guide::proto::GLIC_ZERO_STATE_SUGGESTIONS,
decision_with_metadata);
}
void SetUpHints(const GURL& url,
bool allow_contextual,
const std::vector<std::string>& suggestions) {
optimization_guide::proto::GlicZeroStateSuggestionsMetadata metadata;
metadata.set_contextual_suggestions_eligible(allow_contextual);
*metadata.mutable_contextual_suggestions() = {suggestions.begin(),
suggestions.end()};
optimization_guide::OptimizationMetadata og_metadata;
og_metadata.set_any_metadata(optimization_guide::AnyWrapProto(metadata));
OptimizationGuideKeyedServiceFactory::GetInstance()
->GetForProfile(browser()->profile())
->AddHintForTesting(
url, optimization_guide::proto::GLIC_ZERO_STATE_SUGGESTIONS,
og_metadata);
}
void SetUpHintsNoResult(const GURL& url) {
OptimizationGuideKeyedServiceFactory::GetInstance()
->GetForProfile(browser()->profile())
->AddHintForTesting(
url, optimization_guide::proto::GLIC_ZERO_STATE_SUGGESTIONS,
std::nullopt);
}
void SetUpSuccessfulModelExecution() {
optimization_guide::proto::ZeroStateSuggestionsResponse response;
response.add_suggestions()->set_label("suggestion 1");
response.add_suggestions()->set_label("suggestion 2");
response.add_suggestions()->set_label("suggestion 3");
std::string serialized_metadata;
response.SerializeToString(&serialized_metadata);
optimization_guide::proto::Any any_result;
any_result.set_type_url(
base::StrCat({"type.googleapis.com/", response.GetTypeName()}));
any_result.set_value(serialized_metadata);
OptimizationGuideKeyedServiceFactory::GetInstance()
->GetForProfile(browser()->profile())
->AddExecutionResultForTesting(
optimization_guide::ModelBasedCapabilityKey::kZeroStateSuggestions,
optimization_guide::OptimizationGuideModelExecutionResult(
any_result, nullptr));
}
void SetUpEmptyModelExecutionResult() {
optimization_guide::proto::Any any_result;
OptimizationGuideKeyedServiceFactory::GetInstance()
->GetForProfile(browser()->profile())
->AddExecutionResultForTesting(
optimization_guide::ModelBasedCapabilityKey::kZeroStateSuggestions,
optimization_guide::OptimizationGuideModelExecutionResult(
any_result, nullptr));
}
private:
GURL url_;
base::test::ScopedFeatureList scoped_feature_list_;
};
INSTANTIATE_TEST_SUITE_P(
WithContentExtraction,
ZeroStateSuggestionsBrowserTest,
::testing::Values(
ContentExtraction::kFetchInnerTextOnly,
ContentExtraction::kFetchAnnotatedPageContentOnly,
ContentExtraction::kFetchInnerTextAndAnnotatedPageContent));
IN_PROC_BROWSER_TEST_P(ZeroStateSuggestionsBrowserTest, BasicFlow) {
base::HistogramTester histogram_tester;
DisableOptimizationPermissionCheck();
SetUpSuccessfulModelExecution();
auto* web_contents = browser()->tab_strip_model()->GetActiveWebContents();
SetUpHints(url(), /*allow_contextual=*/true, /*suggestions=*/{});
ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), url()));
base::test::TestFuture<std::vector<std::string>> future;
ContextualCueingServiceFactory::GetForProfile(browser()->profile())
->GetContextualGlicZeroStateSuggestionsForFocusedTab(
web_contents, /*is_fre=*/false, /*supported_tools=*/{},
future.GetCallback());
ASSERT_TRUE(future.Wait());
EXPECT_EQ(3u, future.Get().size());
EXPECT_EQ("suggestion 1", future.Get()[0]);
EXPECT_EQ("suggestion 2", future.Get()[1]);
EXPECT_EQ("suggestion 3", future.Get()[2]);
histogram_tester.ExpectUniqueSample(
"ContextualCueing.ZeroStateSuggestions.ContextExtractionDone", true, 1);
histogram_tester.ExpectTotalCount(
"ContextualCueing.GlicSuggestions.MesFetchLatency", 1);
histogram_tester.ExpectTotalCount(
"ContextualCueing.GlicSuggestions.SuggestionsFetchLatency."
"ValidSuggestions",
1);
histogram_tester.ExpectTotalCount(
"ContextualCueing.GlicSuggestions.SuggestionsFetchLatency."
"EmptySuggestions",
0);
}
IN_PROC_BROWSER_TEST_P(ZeroStateSuggestionsBrowserTest,
HoldsOntoSuccessiveRequests) {
base::HistogramTester histogram_tester;
DisableOptimizationPermissionCheck();
SetUpHints(url(), /*allow_contextual=*/true, /*suggestions=*/{});
SetUpSuccessfulModelExecution();
auto* web_contents = browser()->tab_strip_model()->GetActiveWebContents();
ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), url()));
ContextualCueingService* contextual_cueing_service =
ContextualCueingServiceFactory::GetForProfile(browser()->profile());
// Set up two concurrent calls (simulates mouse down and then on load).
base::test::TestFuture<std::vector<std::string>> future;
contextual_cueing_service->GetContextualGlicZeroStateSuggestionsForFocusedTab(
web_contents, /*is_fre=*/false, /*supported_tools=*/{},
future.GetCallback());
base::test::TestFuture<std::vector<std::string>> future2;
contextual_cueing_service->GetContextualGlicZeroStateSuggestionsForFocusedTab(
web_contents, /*is_fre=*/false, /*supported_tools=*/{},
future2.GetCallback());
// Wait until page is extracted.
optimization_guide::RetryForHistogramUntilCountReached(
&histogram_tester,
"ContextualCueing.ZeroStateSuggestions.ContextExtractionDone", 1);
histogram_tester.ExpectUniqueSample(
"ContextualCueing.ZeroStateSuggestions.ContextExtractionDone", true, 1);
// Both calls should be fulfilled using the same response.
ASSERT_TRUE(future.Wait());
ASSERT_TRUE(future2.Wait());
EXPECT_EQ(3u, future.Get().size());
EXPECT_EQ("suggestion 1", future.Get()[0]);
EXPECT_EQ("suggestion 2", future.Get()[1]);
EXPECT_EQ("suggestion 3", future.Get()[2]);
EXPECT_EQ(3u, future2.Get().size());
EXPECT_EQ("suggestion 1", future2.Get()[0]);
EXPECT_EQ("suggestion 2", future2.Get()[1]);
EXPECT_EQ("suggestion 3", future2.Get()[2]);
histogram_tester.ExpectTotalCount(
"ContextualCueing.GlicSuggestions.MesFetchLatency", 1);
}
IN_PROC_BROWSER_TEST_P(ZeroStateSuggestionsBrowserTest,
CreateDataDoesNotFetchWithoutExplicitCall) {
base::HistogramTester histogram_tester;
DisableOptimizationPermissionCheck();
SetUpHintsNoResult(url());
auto* web_contents = browser()->tab_strip_model()->GetActiveWebContents();
ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), url()));
ZeroStateSuggestionsPageData::CreateForPage(web_contents->GetPrimaryPage());
optimization_guide::RetryForHistogramUntilCountReached(
&histogram_tester,
"ContextualCueing.ZeroStateSuggestions.ContextExtractionDone", 1);
histogram_tester.ExpectUniqueSample(
"ContextualCueing.ZeroStateSuggestions.ContextExtractionDone", true, 1);
histogram_tester.ExpectTotalCount(
"ContextualCueing.GlicSuggestions.MesFetchLatency", 0);
}
IN_PROC_BROWSER_TEST_P(ZeroStateSuggestionsBrowserTest,
ContextualSuggestionsNotAllowed) {
base::HistogramTester histogram_tester;
DisableOptimizationPermissionCheck();
SetUpHints(url(), /*allow_contextual=*/false, /*suggestions=*/{});
auto* web_contents = browser()->tab_strip_model()->GetActiveWebContents();
ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), url()));
base::test::TestFuture<std::vector<std::string>> future;
ContextualCueingServiceFactory::GetForProfile(browser()->profile())
->GetContextualGlicZeroStateSuggestionsForFocusedTab(
web_contents, /*is_fre=*/false, /*supported_tools=*/{},
future.GetCallback());
ASSERT_TRUE(future.Wait());
EXPECT_TRUE(future.Get().empty());
histogram_tester.ExpectTotalCount(
"ContextualCueing.GlicSuggestions.SuggestionsFetchLatency."
"EmptySuggestions",
1);
histogram_tester.ExpectTotalCount(
"ContextualCueing.GlicSuggestions.SuggestionsFetchLatency."
"ValidSuggestions",
0);
}
IN_PROC_BROWSER_TEST_P(ZeroStateSuggestionsBrowserTest, NoResultFromHints) {
DisableOptimizationPermissionCheck();
// Assumes page is eligible for contextual suggestions without hints result.
SetUpHintsNoResult(url());
SetUpSuccessfulModelExecution();
auto* web_contents = browser()->tab_strip_model()->GetActiveWebContents();
ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), url()));
base::test::TestFuture<std::vector<std::string>> future;
ContextualCueingServiceFactory::GetForProfile(browser()->profile())
->GetContextualGlicZeroStateSuggestionsForFocusedTab(
web_contents, /*is_fre=*/false, /*supported_tools=*/{},
future.GetCallback());
ASSERT_TRUE(future.Wait());
EXPECT_EQ(3u, future.Get().size());
EXPECT_EQ("suggestion 1", future.Get()[0]);
EXPECT_EQ("suggestion 2", future.Get()[1]);
EXPECT_EQ("suggestion 3", future.Get()[2]);
}
IN_PROC_BROWSER_TEST_P(ZeroStateSuggestionsBrowserTest, CacheBehavior) {
DisableOptimizationPermissionCheck();
auto* web_contents = browser()->tab_strip_model()->GetActiveWebContents();
ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), url()));
// Set up initial flow.
{
base::test::TestFuture<std::vector<std::string>> future;
base::HistogramTester histogram_tester;
SetUpHints(url(), /*allow_contextual=*/true, /*suggestions=*/{});
SetUpSuccessfulModelExecution();
ContextualCueingServiceFactory::GetForProfile(browser()->profile())
->GetContextualGlicZeroStateSuggestionsForFocusedTab(
web_contents, /*is_fre=*/false, /*supported_tools=*/{},
future.GetCallback());
ASSERT_TRUE(future.Wait());
EXPECT_EQ(3u, future.Get().size());
EXPECT_EQ("suggestion 1", future.Get()[0]);
EXPECT_EQ("suggestion 2", future.Get()[1]);
EXPECT_EQ("suggestion 3", future.Get()[2]);
histogram_tester.ExpectTotalCount(
"ContextualCueing.GlicSuggestions.MesFetchLatency", 1);
}
// Make sure model execution not called.
{
base::HistogramTester histogram_tester;
base::test::TestFuture<std::vector<std::string>> future;
ContextualCueingServiceFactory::GetForProfile(browser()->profile())
->GetContextualGlicZeroStateSuggestionsForFocusedTab(
web_contents, /*is_fre=*/false, /*supported_tools=*/{},
future.GetCallback());
ASSERT_TRUE(future.Wait());
EXPECT_EQ(3u, future.Get().size());
EXPECT_EQ("suggestion 1", future.Get()[0]);
EXPECT_EQ("suggestion 2", future.Get()[1]);
EXPECT_EQ("suggestion 3", future.Get()[2]);
histogram_tester.ExpectTotalCount(
"ContextualCueing.GlicSuggestions.MesFetchLatency", 0);
}
}
IN_PROC_BROWSER_TEST_P(ZeroStateSuggestionsBrowserTest, CacheBehaviorError) {
DisableOptimizationPermissionCheck();
auto* web_contents = browser()->tab_strip_model()->GetActiveWebContents();
ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), url()));
// Set up initial flow.
{
base::HistogramTester histogram_tester;
SetUpHints(url(), /*allow_contextual=*/true, /*suggestions=*/{});
base::test::TestFuture<std::vector<std::string>> future;
// Set up non-transient error.
optimization_guide::proto::ErrorResponse error_response;
error_response.set_error_state(
optimization_guide::proto::ErrorState::
ERROR_STATE_INTERNAL_SERVER_ERROR_NO_RETRY);
OptimizationGuideKeyedServiceFactory::GetInstance()
->GetForProfile(browser()->profile())
->AddExecutionResultForTesting(
optimization_guide::ModelBasedCapabilityKey::kZeroStateSuggestions,
optimization_guide::OptimizationGuideModelExecutionResult(
base::unexpected(
optimization_guide::OptimizationGuideModelExecutionError::
FromModelExecutionServerError(error_response)),
nullptr));
ContextualCueingServiceFactory::GetForProfile(browser()->profile())
->GetContextualGlicZeroStateSuggestionsForFocusedTab(
web_contents, /*is_fre=*/false, /*supported_tools=*/{},
future.GetCallback());
ASSERT_TRUE(future.Wait());
EXPECT_TRUE(future.Get().empty());
histogram_tester.ExpectTotalCount(
"ContextualCueing.GlicSuggestions.MesFetchLatency", 1);
}
// Make sure model execution not called.
{
base::HistogramTester histogram_tester;
base::test::TestFuture<std::vector<std::string>> future;
ContextualCueingServiceFactory::GetForProfile(browser()->profile())
->GetContextualGlicZeroStateSuggestionsForFocusedTab(
web_contents, /*is_fre=*/false, /*supported_tools=*/{},
future.GetCallback());
ASSERT_TRUE(future.Wait());
EXPECT_TRUE(future.Get().empty());
histogram_tester.ExpectTotalCount(
"ContextualCueing.GlicSuggestions.MesFetchLatency", 0);
}
}
IN_PROC_BROWSER_TEST_P(ZeroStateSuggestionsBrowserTest,
NonMSBBFlowContextualNotAllowed) {
base::HistogramTester histogram_tester;
SetUpOnDemandHints(url(), /*allow_contextual=*/false, /*suggestions=*/{});
auto* web_contents = browser()->tab_strip_model()->GetActiveWebContents();
ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), url()));
base::test::TestFuture<std::vector<std::string>> future;
ContextualCueingServiceFactory::GetForProfile(browser()->profile())
->GetContextualGlicZeroStateSuggestionsForFocusedTab(
web_contents, /*is_fre=*/false, /*supported_tools=*/{},
future.GetCallback());
ASSERT_TRUE(future.Wait());
EXPECT_TRUE(future.Get().empty());
}
IN_PROC_BROWSER_TEST_P(ZeroStateSuggestionsBrowserTest,
NonMSBBFlowContextualNotAllowedForAllPinnedTabs) {
base::HistogramTester histogram_tester;
SetUpOnDemandHints(url(), /*allow_contextual=*/false, /*suggestions=*/{});
GURL url2 =
embedded_test_server()->GetURL("/optimization_guide/hellow_world.html");
SetUpOnDemandHints(url2, /*allow_contextual=*/false, /*suggestions=*/{});
SetUpSuccessfulModelExecution();
// Navigate in one tab.
auto* initial_web_contents =
browser()->tab_strip_model()->GetActiveWebContents();
ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), url()));
// Navigate to a new URL in a second tab.
ui_test_utils::NavigateToURLWithDisposition(
browser(), url2, WindowOpenDisposition::NEW_FOREGROUND_TAB,
ui_test_utils::BROWSER_TEST_WAIT_FOR_LOAD_STOP);
auto* web_contents2 = browser()->tab_strip_model()->GetActiveWebContents();
base::test::TestFuture<std::vector<std::string>> future;
// This is true since we do not know the answer yet.
EXPECT_TRUE(
ContextualCueingServiceFactory::GetForProfile(browser()->profile())
->GetContextualGlicZeroStateSuggestionsForPinnedTabs(
{initial_web_contents, web_contents2}, /*is_fre=*/false,
/*supported_tools=*/{}, initial_web_contents,
future.GetCallback()));
ASSERT_TRUE(future.Wait());
EXPECT_TRUE(future.Get().empty());
}
IN_PROC_BROWSER_TEST_P(ZeroStateSuggestionsBrowserTest,
NonMSBBFlowContextualAllowedForOnePinnedTab) {
base::HistogramTester histogram_tester;
SetUpOnDemandHints(url(), /*allow_contextual=*/true, /*suggestions=*/{});
GURL url2 =
embedded_test_server()->GetURL("/optimization_guide/hellow_world.html");
SetUpOnDemandHints(url2, /*allow_contextual=*/false, /*suggestions=*/{});
SetUpSuccessfulModelExecution();
// Navigate in one tab.
auto* initial_web_contents =
browser()->tab_strip_model()->GetActiveWebContents();
ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), url()));
// Navigate to a new URL in a second tab.
ui_test_utils::NavigateToURLWithDisposition(
browser(), url2, WindowOpenDisposition::NEW_FOREGROUND_TAB,
ui_test_utils::BROWSER_TEST_WAIT_FOR_LOAD_STOP);
auto* web_contents2 = browser()->tab_strip_model()->GetActiveWebContents();
base::test::TestFuture<std::vector<std::string>> future;
EXPECT_TRUE(
ContextualCueingServiceFactory::GetForProfile(browser()->profile())
->GetContextualGlicZeroStateSuggestionsForPinnedTabs(
{initial_web_contents, web_contents2}, /*is_fre=*/false,
/*supported_tools=*/{}, initial_web_contents,
future.GetCallback()));
EXPECT_EQ(3u, future.Get().size());
EXPECT_EQ("suggestion 1", future.Get()[0]);
EXPECT_EQ("suggestion 2", future.Get()[1]);
EXPECT_EQ("suggestion 3", future.Get()[2]);
histogram_tester.ExpectTotalCount(
"ContextualCueing.GlicSuggestions.MesFetchLatency", 1);
}
IN_PROC_BROWSER_TEST_P(ZeroStateSuggestionsBrowserTest,
AllPinnedTabsIneligibleForContextual) {
base::HistogramTester histogram_tester;
// Open 2 tabs with new tab page.
chrome::NewTab(browser());
auto* initial_web_contents =
browser()->tab_strip_model()->GetActiveWebContents();
chrome::NewTab(browser());
auto* web_contents2 = browser()->tab_strip_model()->GetActiveWebContents();
SetUpSuccessfulModelExecution();
base::test::TestFuture<std::vector<std::string>> future;
EXPECT_FALSE(
ContextualCueingServiceFactory::GetForProfile(browser()->profile())
->GetContextualGlicZeroStateSuggestionsForPinnedTabs(
{initial_web_contents, web_contents2}, /*is_fre=*/false,
/*supported_tools=*/{}, nullptr, future.GetCallback()));
ASSERT_TRUE(future.Wait());
EXPECT_TRUE(future.Get().empty());
histogram_tester.ExpectTotalCount(
"ContextualCueing.ZeroStateSuggestions.ContextExtractionDone", 0);
histogram_tester.ExpectTotalCount(
"OptimizationGuide.ModelExecutionFetcher.RequestStatus."
"ZeroStateSuggestions",
0);
}
IN_PROC_BROWSER_TEST_P(ZeroStateSuggestionsBrowserTest, BasicPinnedTabsFlow) {
base::HistogramTester histogram_tester;
GURL url2 =
embedded_test_server()->GetURL("/optimization_guide/hellow_world.html");
SetUpSuccessfulModelExecution();
// Navigate in one tab.
auto* initial_web_contents =
browser()->tab_strip_model()->GetActiveWebContents();
ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), url()));
// Navigate to a new URL in a second tab.
ui_test_utils::NavigateToURLWithDisposition(
browser(), url2, WindowOpenDisposition::NEW_FOREGROUND_TAB,
ui_test_utils::BROWSER_TEST_WAIT_FOR_LOAD_STOP);
auto* web_contents2 = browser()->tab_strip_model()->GetActiveWebContents();
base::test::TestFuture<std::vector<std::string>> future;
EXPECT_TRUE(
ContextualCueingServiceFactory::GetForProfile(browser()->profile())
->GetContextualGlicZeroStateSuggestionsForPinnedTabs(
{initial_web_contents, web_contents2}, /*is_fre=*/false,
/*supported_tools=*/{}, initial_web_contents,
future.GetCallback()));
ASSERT_TRUE(future.Wait());
EXPECT_EQ(3u, future.Get().size());
EXPECT_EQ("suggestion 1", future.Get()[0]);
EXPECT_EQ("suggestion 2", future.Get()[1]);
EXPECT_EQ("suggestion 3", future.Get()[2]);
histogram_tester.ExpectTotalCount(
"ContextualCueing.GlicSuggestions.MesFetchLatency", 1);
}
} // namespace contextual_cueing