chromium/chrome/renderer/cart/commerce_hint_agent_browsertest.cc

// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include <string_view>

#include "base/memory/raw_ptr.h"
#include "base/test/metrics/histogram_tester.h"
#include "base/test/scoped_feature_list.h"
#include "base/test/test_timeouts.h"
#include "build/build_config.h"
#include "build/chromeos_buildflags.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/cart/commerce_hint_service.h"
#include "chrome/browser/new_tab_page/new_tab_page_util.h"
#include "chrome/browser/optimization_guide/optimization_guide_keyed_service.h"
#include "chrome/browser/optimization_guide/optimization_guide_keyed_service_factory.h"
#include "chrome/browser/profiles/profile_manager.h"
#include "chrome/browser/profiles/profile_test_util.h"
#include "chrome/common/chrome_features.h"
#include "chrome/common/pref_names.h"
#include "chrome/test/base/chrome_test_utils.h"
#include "chrome/test/base/platform_browser_test.h"
#include "components/commerce/core/commerce_feature_list.h"
#include "components/commerce/core/commerce_heuristics_data.h"
#include "components/commerce/core/commerce_heuristics_data_metrics_helper.h"
#include "components/metrics/content/subprocess_metrics_provider.h"
#include "components/network_session_configurator/common/network_switches.h"
#include "components/optimization_guide/core/optimization_guide_features.h"
#include "components/prefs/pref_service.h"
#include "components/ukm/test_ukm_recorder.h"
#include "content/public/common/content_features.h"
#include "content/public/test/back_forward_cache_util.h"
#include "content/public/test/browser_test.h"
#include "content/public/test/browser_test_utils.h"
#include "content/public/test/fenced_frame_test_util.h"
#include "content/public/test/test_navigation_observer.h"
#include "net/dns/mock_host_resolver.h"
#include "net/test/embedded_test_server/embedded_test_server.h"
#include "net/test/embedded_test_server/http_request.h"
#include "net/test/embedded_test_server/http_response.h"
#include "services/metrics/public/cpp/ukm_builders.h"
#include "third_party/blink/public/common/features.h"

#if !BUILDFLAG(IS_ANDROID)
#include "chrome/browser/cart/cart_service.h"
#include "chrome/browser/signin/identity_manager_factory.h"
#include "chrome/test/base/scoped_browser_locale.h"
#include "components/commerce/core/proto/cart_db_content.pb.h"
#include "components/session_proto_db/session_proto_db.h"
#include "components/signin/public/identity_manager/identity_manager.h"
#include "components/signin/public/identity_manager/identity_test_utils.h"
#include "components/variations/service/variations_service.h"
#include "components/variations/variations_switches.h"
#endif

namespace {

#if !BUILDFLAG(IS_ANDROID)
cart_db::ChromeCartContentProto BuildProto(const char* domain,
                                           const char* cart_url) {}

cart_db::ChromeCartProductProto BuildProductInfoProto(const char* product_id) {}

cart_db::ChromeCartContentProto BuildProtoWithProducts(
    const char* domain,
    const char* cart_url,
    const std::vector<const char*>& product_urls) {}

cart_db::ChromeCartContentProto BuildProtoWithProducts(
    const char* domain,
    const char* cart_url,
    const std::vector<const char*>& product_urls,
    const std::vector<const char*>& product_ids) {}

const char kMockExample[] =;
const char kMockExampleFallbackURL[] =;
const char kMockExampleLinkURL[] =;
const char kMockExampleURL[] =;

const cart_db::ChromeCartContentProto kMockExampleProtoFallbackCart =;
const cart_db::ChromeCartContentProto kMockExampleProtoLinkCart =;
const cart_db::ChromeCartContentProto kMockExampleProto =;
const cart_db::ChromeCartContentProto kMockExampleProtoWithProducts =;
const cart_db::ChromeCartContentProto
    kMockExampleProtoWithProductsWithoutSaved =;

const char kMockAmazon[] =;
const char kMockAmazonURL[] =;
const cart_db::ChromeCartContentProto kMockAmazonProto =;

const char kMockWalmart[] =;
const char kMockWalmartURL[] =;
const cart_db::ChromeCartContentProto kMockWalmartProto =;

ShoppingCarts;
const ShoppingCarts kExpectedExampleFallbackCart =;
const ShoppingCarts kExpectedExampleLinkCart =;
const ShoppingCarts kExpectedExample =;
const ShoppingCarts kExpectedExampleWithProducts =;
const ShoppingCarts kExpectedExampleWithProductsWithoutSaved =;
const ShoppingCarts kExpectedAmazon =;
const ShoppingCarts kExpectedWalmart =;
const ShoppingCarts kEmptyExpected =;
#endif

std::unique_ptr<net::test_server::HttpResponse> BasicResponse(
    const net::test_server::HttpRequest& request) {}

// Tests CommerceHintAgent.
class CommerceHintAgentTest : public PlatformBrowserTest {};

IN_PROC_BROWSER_TEST_F(CommerceHintAgentTest, AddToCartByURL) {}

IN_PROC_BROWSER_TEST_F(CommerceHintAgentTest, AddToCartByForm) {}

IN_PROC_BROWSER_TEST_F(CommerceHintAgentTest, AddToCartByForm_WithLink) {}

#if !BUILDFLAG(IS_ANDROID)
IN_PROC_BROWSER_TEST_F(CommerceHintAgentTest, AddToCartByForm_WithWrongLink) {}
#endif

IN_PROC_BROWSER_TEST_F(CommerceHintAgentTest, AddToCartByURL_XHR) {}

IN_PROC_BROWSER_TEST_F(CommerceHintAgentTest, SkipAddToCart_FromComponent) {}

// TODO(https://crbug/1310497, https://crbug.com/1362442): This test is flaky
// on ChromeOS and Linux Asan.
#if BUILDFLAG(IS_CHROMEOS)
#define MAYBE_VisitCart
#elif BUILDFLAG(IS_LINUX) && defined(ADDRESS_SANITIZER)
#define MAYBE_VisitCart
#else
#define MAYBE_VisitCart
#endif

IN_PROC_BROWSER_TEST_F(CommerceHintAgentTest, MAYBE_VisitCart) {}

IN_PROC_BROWSER_TEST_F(CommerceHintAgentTest,
                       VisitCart_GeneralPattern_FromComponent) {}

IN_PROC_BROWSER_TEST_F(CommerceHintAgentTest,
                       VisitCart_PerDomain_FromComponent) {}

IN_PROC_BROWSER_TEST_F(CommerceHintAgentTest, ExtractCart_ScriptFromResource) {}

IN_PROC_BROWSER_TEST_F(CommerceHintAgentTest, ExtractCart_ScriptFromComponent) {}

#if !BUILDFLAG(IS_ANDROID)
IN_PROC_BROWSER_TEST_F(CommerceHintAgentTest,
                       ExtractCart_ProductIDFromComponent) {}

IN_PROC_BROWSER_TEST_F(CommerceHintAgentTest, AddCartFromComponent) {}

class CommerceHintNoRateControlTest : public CommerceHintAgentTest {};

// TODO(crbug.com/40194728): Add the rate control back for this test after
// figuring out why rate control makes this test flaky.
// Disabled due to failing tests. https://crbug.com/1254802
IN_PROC_BROWSER_TEST_F(CommerceHintNoRateControlTest, DISABLED_CartPriority) {}
#endif  // !BUILDFLAG(IS_ANDROID)

IN_PROC_BROWSER_TEST_F(CommerceHintAgentTest, VisitCheckout) {}

IN_PROC_BROWSER_TEST_F(CommerceHintAgentTest, PurchaseByURL) {}

IN_PROC_BROWSER_TEST_F(CommerceHintAgentTest, PurchaseByForm) {}

// TODO(crbug.com/40169871): CrOS multi-profiles implementation is different
// from the rest and below tests don't work on CrOS yet. Re-enable them on CrOS
// after figuring out the reason for failure. Signing out on Lacros is not
// possible.
// TODO(crbug.com/40227790): Intentionally skip below two tests for Android for
// now.
#if !BUILDFLAG(IS_CHROMEOS) && !BUILDFLAG(IS_ANDROID)
// TODO(crbug.com/40201179): Skip work on non-eligible profiles.
IN_PROC_BROWSER_TEST_F(CommerceHintAgentTest, NonSignInUser) {}

// TODO(crbug.com/40201179): Skip work on non-eligible profiles.
// Flaky on Linux Asan and Mac: https://crbug.com/1306908.
#if (BUILDFLAG(IS_LINUX) && defined(ADDRESS_SANITIZER)) || BUILDFLAG(IS_MAC)
#define MAYBE_MultipleProfiles
#else
#define MAYBE_MultipleProfiles
#endif
IN_PROC_BROWSER_TEST_F(CommerceHintAgentTest, MAYBE_MultipleProfiles) {}
#endif  // !BUILDFLAG(IS_CHROMEOS) && !BUILDFLAG(IS_ANDROID)

class CommerceHintCacaoTest : public CommerceHintAgentTest {};

IN_PROC_BROWSER_TEST_F(CommerceHintCacaoTest, Passed) {}

// If command line argument "optimization_guide_hints_override" is not given,
// nothing is specified in AddHintForTesting(), and the real hints are not
// downloaded, all the URLs are considered non-shopping.
IN_PROC_BROWSER_TEST_F(CommerceHintCacaoTest, Rejected) {}

#if !BUILDFLAG(IS_ANDROID)
class CommerceHintProductInfoTest : public CommerceHintAgentTest {};

IN_PROC_BROWSER_TEST_F(CommerceHintProductInfoTest, AddToCartByForm_CaptureId) {}

IN_PROC_BROWSER_TEST_F(CommerceHintProductInfoTest, AddToCartByURL_CaptureId) {}

IN_PROC_BROWSER_TEST_F(CommerceHintProductInfoTest,
                       ExtractCart_CaptureId_FromElement) {}

IN_PROC_BROWSER_TEST_F(CommerceHintProductInfoTest,
                       ExtractCart_CaptureId_FromImageURL) {}

IN_PROC_BROWSER_TEST_F(CommerceHintProductInfoTest,
                       ExtractCart_CaptureId_FromProductURL) {}

IN_PROC_BROWSER_TEST_F(CommerceHintProductInfoTest,
                       ExtractCart_CaptureId_CaptureGroupIndex) {}

IN_PROC_BROWSER_TEST_F(CommerceHintProductInfoTest,
                       ExtractCart_CaptureId_CouponPartnerMerchants) {}

IN_PROC_BROWSER_TEST_F(CommerceHintProductInfoTest,
                       RBDPartnerCartURLNotOverwrite) {}
#endif  // !BUILDFLAG(IS_ANDROID)

// Product extraction would always timeout and return empty results.
class CommerceHintTimeoutTest : public CommerceHintAgentTest {};

// Flaky on Linux, ChromeOS and Windows: https://crbug.com/1257964.
// Falky on Mac: https://crbug.com/1312849.
#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_WIN) || \
    BUILDFLAG(IS_MAC)
#define MAYBE_ExtractCart
#else
#define MAYBE_ExtractCart
#endif
IN_PROC_BROWSER_TEST_F(CommerceHintTimeoutTest, MAYBE_ExtractCart) {}

class CommerceHintMaxCountTest : public CommerceHintAgentTest {};

// Flaky on Linux: https://crbug.com/1257964.
// See definition of MAYBE_ExtractCart above.
IN_PROC_BROWSER_TEST_F(CommerceHintMaxCountTest, MAYBE_ExtractCart) {}

// Override add-to-cart pattern.
class CommerceHintAddToCartPatternTest : public CommerceHintAgentTest {};

IN_PROC_BROWSER_TEST_F(CommerceHintAddToCartPatternTest, AddToCartByURL) {}

IN_PROC_BROWSER_TEST_F(CommerceHintAddToCartPatternTest, AddToCartByForm) {}

// Override per-domain add-to-cart pattern.
class CommerceHintSkippAddToCartTest : public CommerceHintAgentTest {};

IN_PROC_BROWSER_TEST_F(CommerceHintSkippAddToCartTest, AddToCartByForm) {}

#if BUILDFLAG(IS_LINUX) && defined(ADDRESS_SANITIZER)
// Override per-domain and generic cart pattern.
class CommerceHintCartPatternTest : public CommerceHintAgentTest {
 public:
  void SetUpInProcessBrowserTestFixture() override {
    scoped_feature_list_.InitWithFeaturesAndParameters(
        {{
#if !BUILDFLAG(IS_ANDROID)
            ntp_features::kNtpChromeCartModule,
#else
            commerce::kCommerceHintAndroid,
#endif
            {{"cart-pattern", "chicken|egg"},
             {"cart-pattern-mapping",
              R"({"guitarcenter.com": "(special|text)lol"})"}}}},
        {optimization_guide::features::kOptimizationHints});
  }

 private:
  base::test::ScopedFeatureList scoped_feature_list_;
};

// TODO(crbug.com/40238349): Deflake this test.
IN_PROC_BROWSER_TEST_F(CommerceHintCartPatternTest, DISABLED_VisitCart) {
  // The test is flaky with same-site back/forward cache, presumably because it
  // doesn't expect a RenderView change on same-site navigations.
  // TODO(crbug.com/40217176): Investigate and fix this.
  content::DisableBackForwardCacheForTesting(
      web_contents(),
      content::BackForwardCache::TEST_ASSUMES_NO_RENDER_FRAME_CHANGE);

  NavigateToURL("https://www.guitarcenter.com/SpecialLoL");
  WaitForUmaCount("Commerce.Carts.VisitCart", 1);

  NavigateToURL("https://www.guitarcenter.com/cart.html");
  NavigateToURL("https://www.guitarcenter.com/chicken");
  NavigateToURL("https://www.guitarcenter.com/cart.html");
  WaitForUmaCount("Commerce.Carts.VisitCart", 1);

  NavigateToURL("https://www.guitarcenter.com/TextLoL");
  WaitForUmaCount("Commerce.Carts.VisitCart", 2);

  // Unspecified domains fall back to generic pattern.
  NavigateToURL("https://www.example.com/SpecialLoL");
  NavigateToURL("https://www.example.com/cart.html");
  NavigateToURL("https://www.example.com/TextLoL");
  WaitForUmaCount("Commerce.Carts.VisitCart", 2);

  NavigateToURL("https://www.example.com/Chicken");
  WaitForUmaCount("Commerce.Carts.VisitCart", 3);

  NavigateToURL("https://www.example.com/Egg");
  WaitForUmaCount("Commerce.Carts.VisitCart", 4);
}
#endif  // BUILDFLAG(IS_LINUX) && defined(ADDRESS_SANITIZER)

// Override per-domain and generic checkout pattern.
class CommerceHintCheckoutPatternTest : public CommerceHintAgentTest {};

IN_PROC_BROWSER_TEST_F(CommerceHintCheckoutPatternTest, VisitCheckout) {}

// Override per-domain and generic purchase button pattern.
class CommerceHintPurchaseButtonPatternTest : public CommerceHintAgentTest {};

IN_PROC_BROWSER_TEST_F(CommerceHintPurchaseButtonPatternTest, PurchaseByForm) {}

class CommerceHintPurchaseURLPatternTest : public CommerceHintAgentTest {};

IN_PROC_BROWSER_TEST_F(CommerceHintPurchaseURLPatternTest, PurchaseByURL) {}

class CommerceHintOptimizeRendererTest : public CommerceHintAgentTest {};

// Times out on multiple platforms. https://crbug.com/1258553
#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_MAC) || \
    BUILDFLAG(IS_ANDROID)
#define MAYBE_CartExtractionSkipped
#else
#define MAYBE_CartExtractionSkipped
#endif
IN_PROC_BROWSER_TEST_F(CommerceHintOptimizeRendererTest,
                       MAYBE_CartExtractionSkipped) {}

#if !BUILDFLAG(IS_CHROMEOS)
// TODO(crbug.com/40830409): This test is flaky on ChromeOS.
class CommerceHintAgentFencedFrameTest : public CommerceHintAgentTest {};

IN_PROC_BROWSER_TEST_F(CommerceHintAgentFencedFrameTest,
                       VisitCartInFencedFrame) {}

#endif  // !BUILDFLAG(IS_CHROMEOS)

#if !BUILDFLAG(IS_ANDROID)
class CommerceHintFeatureDefaultWithoutGeoTest : public CommerceHintAgentTest {};

IN_PROC_BROWSER_TEST_F(CommerceHintFeatureDefaultWithoutGeoTest,
                       DisableWithoutGeo) {}

class CommerceHintFeatureDefaultWithGeoTest : public CommerceHintAgentTest {};

IN_PROC_BROWSER_TEST_F(CommerceHintFeatureDefaultWithGeoTest, EnableWithGeo) {}
#endif

class CommerceHintDOMBasedHeuristicsTest : public CommerceHintAgentTest {};

IN_PROC_BROWSER_TEST_F(CommerceHintDOMBasedHeuristicsTest,
                       DetectionRequiresAddToCartActive) {}

IN_PROC_BROWSER_TEST_F(CommerceHintDOMBasedHeuristicsTest,
                       DetectionInactiveForWrongButton) {}

IN_PROC_BROWSER_TEST_F(CommerceHintDOMBasedHeuristicsTest,
                       AddToCartActiveExpires) {}

IN_PROC_BROWSER_TEST_F(CommerceHintDOMBasedHeuristicsTest,
                       TestAddToCartPattern) {}

class CommerceHintDOMBasedHeuristicsSkipTest : public CommerceHintAgentTest {};

IN_PROC_BROWSER_TEST_F(CommerceHintDOMBasedHeuristicsSkipTest,
                       SkipDOMBasedHeuristics) {}

class CommerceHintDOMBasedHeuristicsGapTimeTest : public CommerceHintAgentTest {};

IN_PROC_BROWSER_TEST_F(CommerceHintDOMBasedHeuristicsGapTimeTest,
                       EnforceExecutionTimeGap) {}

}  // namespace