| // Copyright 2021 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "chrome/browser/cart/cart_handler.h" |
| |
| #include "base/memory/raw_ptr.h" |
| #include "base/test/metrics/histogram_tester.h" |
| #include "build/build_config.h" |
| #include "chrome/browser/cart/cart_db_content.pb.h" |
| #include "chrome/browser/cart/cart_service.h" |
| #include "chrome/browser/cart/cart_service_factory.h" |
| #include "chrome/browser/history/history_service_factory.h" |
| #include "chrome/browser/persisted_state_db/profile_proto_db.h" |
| #include "chrome/common/pref_names.h" |
| #include "chrome/test/base/testing_profile.h" |
| #include "components/commerce/core/commerce_feature_list.h" |
| #include "components/prefs/pref_service.h" |
| #include "components/search/ntp_features.h" |
| #include "content/public/test/browser_task_environment.h" |
| #include "content/public/test/test_web_contents_factory.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| #include "third_party/abseil-cpp/absl/types/optional.h" |
| |
| namespace { |
| void GetEvaluationMerchantCarts( |
| base::OnceClosure closure, |
| std::vector<chrome_cart::mojom::MerchantCartPtr> expected, |
| std::vector<chrome_cart::mojom::MerchantCartPtr> found) { |
| ASSERT_EQ(expected.size(), found.size()); |
| for (size_t i = 0; i < expected.size(); i++) { |
| ASSERT_EQ(expected[i]->merchant, found[i]->merchant); |
| ASSERT_EQ(expected[i]->cart_url, found[i]->cart_url); |
| ASSERT_EQ(expected[i]->discount_text, found[i]->discount_text); |
| ASSERT_EQ(expected[i]->product_image_urls.size(), |
| found[i]->product_image_urls.size()); |
| for (size_t j = 0; j < expected[i]->product_image_urls.size(); j++) { |
| ASSERT_EQ(expected[i]->product_image_urls[i], |
| found[i]->product_image_urls[i]); |
| } |
| } |
| std::move(closure).Run(); |
| } |
| |
| void GetEvaluationMerchantCartWithUtmSource( |
| base::OnceClosure closure, |
| bool expected_has_utm_source, |
| const std::string& expected_utm_source_tag_and_value, |
| std::vector<chrome_cart::mojom::MerchantCartPtr> found) { |
| EXPECT_EQ(1U, found.size()); |
| EXPECT_EQ(expected_has_utm_source, |
| found[0]->cart_url.spec().find("utm_source") != std::string::npos); |
| if (expected_has_utm_source) { |
| EXPECT_EQ(expected_has_utm_source, |
| found[0]->cart_url.spec().find( |
| expected_utm_source_tag_and_value) != std::string::npos); |
| } |
| std::move(closure).Run(); |
| } |
| |
| cart_db::ChromeCartContentProto BuildProto(const char* key, |
| const char* domain, |
| const char* merchant_url) { |
| cart_db::ChromeCartContentProto proto; |
| proto.set_key(domain); |
| proto.set_merchant(domain); |
| proto.set_merchant_cart_url(merchant_url); |
| proto.set_timestamp(base::Time::Now().ToDoubleT()); |
| return proto; |
| } |
| |
| const char kFakeMerchantKey[] = "Fake:foo.com"; |
| const char kFakeMerchant[] = "foo.com"; |
| const char kFakeMerchantURL[] = "https://www.foo.com"; |
| const char kMockMerchantBKey[] = "bar.com"; |
| const char kMockMerchantB[] = "bar.com"; |
| const char kMockMerchantURLB[] = "https://www.bar.com"; |
| const cart_db::ChromeCartContentProto kFakeProto = |
| BuildProto(kFakeMerchantKey, kFakeMerchant, kFakeMerchantURL); |
| const cart_db::ChromeCartContentProto kMockProtoB = |
| BuildProto(kMockMerchantBKey, kMockMerchantB, kMockMerchantURLB); |
| const std::vector<ProfileProtoDB<cart_db::ChromeCartContentProto>::KeyAndValue> |
| kExpectedFake = {{kFakeMerchant, kFakeProto}}; |
| const std::vector<ProfileProtoDB<cart_db::ChromeCartContentProto>::KeyAndValue> |
| kExpectedAllData = { |
| {kFakeMerchant, kFakeProto}, |
| {kMockMerchantB, kMockProtoB}, |
| }; |
| const std::vector<ProfileProtoDB<cart_db::ChromeCartContentProto>::KeyAndValue> |
| kEmptyExpected = {}; |
| } // namespace |
| |
| class CartHandlerTest : public testing::Test { |
| public: |
| CartHandlerTest() |
| : task_environment_(content::BrowserTaskEnvironment::IO_MAINLOOP) { |
| feature_list_.InitAndEnableFeatureWithParameters( |
| ntp_features::kNtpChromeCartModule, |
| {{ntp_features::kNtpChromeCartModuleAbandonedCartDiscountUseUtmParam, |
| "false"}}); |
| } |
| |
| void SetUp() override { |
| testing::Test::SetUp(); |
| TestingProfile::Builder profile_builder; |
| profile_builder.AddTestingFactory( |
| HistoryServiceFactory::GetInstance(), |
| HistoryServiceFactory::GetDefaultFactory()); |
| profile_ = profile_builder.Build(); |
| web_contents_ = web_contents_factory_.CreateWebContents(profile_.get()); |
| |
| handler_ = std::make_unique<CartHandler>( |
| mojo::PendingReceiver<chrome_cart::mojom::CartHandler>(), |
| profile_.get(), web_contents_); |
| service_ = CartServiceFactory::GetForProfile(profile_.get()); |
| } |
| |
| void OperationEvaluation(base::OnceClosure closure, |
| bool expected_success, |
| bool actual_success) { |
| EXPECT_EQ(expected_success, actual_success); |
| std::move(closure).Run(); |
| } |
| |
| void GetEvaluationCartHiddenStatus( |
| base::OnceClosure closure, |
| bool isHidden, |
| bool result, |
| std::vector<ProfileProtoDB<cart_db::ChromeCartContentProto>::KeyAndValue> |
| found) { |
| EXPECT_EQ(1U, found.size()); |
| EXPECT_EQ(isHidden, found[0].second.is_hidden()); |
| std::move(closure).Run(); |
| } |
| |
| void GetEvaluationCartRemovedStatus( |
| base::OnceClosure closure, |
| bool isRemoved, |
| bool result, |
| std::vector<ProfileProtoDB<cart_db::ChromeCartContentProto>::KeyAndValue> |
| found) { |
| EXPECT_EQ(1U, found.size()); |
| EXPECT_EQ(isRemoved, found[0].second.is_removed()); |
| std::move(closure).Run(); |
| } |
| |
| void GetEvaluationBoolResult(base::OnceClosure closure, |
| bool expected_show, |
| bool actual_show) { |
| EXPECT_EQ(expected_show, actual_show); |
| std::move(closure).Run(); |
| } |
| |
| void TearDown() override {} |
| |
| protected: |
| // This needs to be declared before |task_environment_|, so that it will be |
| // destroyed after |task_environment_| has run all the tasks on other threads |
| // that might check if a feature is enabled. |
| base::test::ScopedFeatureList feature_list_; |
| // Required to run tests from UI thread. |
| content::BrowserTaskEnvironment task_environment_; |
| std::unique_ptr<TestingProfile> profile_; |
| content::TestWebContentsFactory web_contents_factory_; |
| raw_ptr<content::WebContents> web_contents_; // Weak. Owned by factory_. |
| std::unique_ptr<CartHandler> handler_; |
| raw_ptr<CartService> service_; |
| base::HistogramTester histogram_tester_; |
| }; |
| |
| // Verifies the hide status is flipped by hiding and restoring. |
| TEST_F(CartHandlerTest, TestHideStatusChange) { |
| ASSERT_FALSE(service_->IsHidden()); |
| |
| handler_->HideCartModule(); |
| ASSERT_TRUE(service_->IsHidden()); |
| |
| handler_->RestoreHiddenCartModule(); |
| ASSERT_FALSE(service_->IsHidden()); |
| } |
| |
| // Tests hiding a single cart and undoing the hide. |
| TEST_F(CartHandlerTest, TestHideCart) { |
| CartDB* cart_db_ = service_->GetDB(); |
| base::RunLoop run_loop[6]; |
| cart_db_->AddCart( |
| kMockMerchantBKey, kMockProtoB, |
| base::BindOnce(&CartHandlerTest::OperationEvaluation, |
| base::Unretained(this), run_loop[0].QuitClosure(), true)); |
| run_loop[0].Run(); |
| |
| service_->LoadCart( |
| kMockMerchantB, |
| base::BindOnce(&CartHandlerTest::GetEvaluationCartHiddenStatus, |
| base::Unretained(this), run_loop[1].QuitClosure(), false)); |
| run_loop[1].Run(); |
| |
| handler_->HideCart( |
| GURL(kMockMerchantURLB), |
| base::BindOnce(&CartHandlerTest::OperationEvaluation, |
| base::Unretained(this), run_loop[2].QuitClosure(), true)); |
| run_loop[2].Run(); |
| |
| service_->LoadCart( |
| kMockMerchantB, |
| base::BindOnce(&CartHandlerTest::GetEvaluationCartHiddenStatus, |
| base::Unretained(this), run_loop[3].QuitClosure(), true)); |
| run_loop[3].Run(); |
| |
| handler_->RestoreHiddenCart( |
| GURL(kMockMerchantURLB), |
| base::BindOnce(&CartHandlerTest::OperationEvaluation, |
| base::Unretained(this), run_loop[4].QuitClosure(), true)); |
| run_loop[4].Run(); |
| |
| service_->LoadCart( |
| kMockMerchantB, |
| base::BindOnce(&CartHandlerTest::GetEvaluationCartHiddenStatus, |
| base::Unretained(this), run_loop[5].QuitClosure(), false)); |
| run_loop[5].Run(); |
| } |
| |
| // Tests removing a single cart and undoing the remove. |
| TEST_F(CartHandlerTest, TestRemoveCart) { |
| CartDB* cart_db_ = service_->GetDB(); |
| base::RunLoop run_loop[6]; |
| cart_db_->AddCart( |
| kMockMerchantB, kMockProtoB, |
| base::BindOnce(&CartHandlerTest::OperationEvaluation, |
| base::Unretained(this), run_loop[0].QuitClosure(), true)); |
| run_loop[0].Run(); |
| |
| service_->LoadCart( |
| kMockMerchantB, |
| base::BindOnce(&CartHandlerTest::GetEvaluationCartRemovedStatus, |
| base::Unretained(this), run_loop[1].QuitClosure(), false)); |
| run_loop[1].Run(); |
| |
| handler_->RemoveCart( |
| GURL(kMockMerchantURLB), |
| base::BindOnce(&CartHandlerTest::OperationEvaluation, |
| base::Unretained(this), run_loop[2].QuitClosure(), true)); |
| run_loop[2].Run(); |
| |
| service_->LoadCart( |
| kMockMerchantB, |
| base::BindOnce(&CartHandlerTest::GetEvaluationCartRemovedStatus, |
| base::Unretained(this), run_loop[3].QuitClosure(), true)); |
| run_loop[3].Run(); |
| |
| handler_->RestoreRemovedCart( |
| GURL(kMockMerchantURLB), |
| base::BindOnce(&CartHandlerTest::OperationEvaluation, |
| base::Unretained(this), run_loop[4].QuitClosure(), true)); |
| run_loop[4].Run(); |
| |
| service_->LoadCart( |
| kMockMerchantB, |
| base::BindOnce(&CartHandlerTest::GetEvaluationCartRemovedStatus, |
| base::Unretained(this), run_loop[5].QuitClosure(), false)); |
| run_loop[5].Run(); |
| } |
| |
| // Verifies GetMerchantCarts loads real data without fake data parameter. |
| // Flaky, see crbug.com/1185497. |
| TEST_F(CartHandlerTest, DISABLED_TestDisableFakeData) { |
| base::RunLoop run_loop; |
| service_->AddCart(kFakeMerchantKey, absl::nullopt, kFakeProto); |
| service_->AddCart(kMockMerchantBKey, absl::nullopt, kMockProtoB); |
| task_environment_.RunUntilIdle(); |
| |
| std::vector<chrome_cart::mojom::MerchantCartPtr> carts; |
| auto dummy_cart1 = chrome_cart::mojom::MerchantCart::New(); |
| dummy_cart1->merchant = kFakeMerchant; |
| dummy_cart1->cart_url = GURL(kFakeMerchantURL); |
| auto dummy_cart2 = chrome_cart::mojom::MerchantCart::New(); |
| dummy_cart2->merchant = kMockMerchantB; |
| dummy_cart2->cart_url = GURL(kMockMerchantURLB); |
| carts.push_back(std::move(dummy_cart2)); |
| carts.push_back(std::move(dummy_cart1)); |
| |
| handler_->GetMerchantCarts(base::BindOnce( |
| &GetEvaluationMerchantCarts, run_loop.QuitClosure(), std::move(carts))); |
| run_loop.Run(); |
| } |
| |
| // Tests show welcome surface for first three appearances of cart module. |
| TEST_F(CartHandlerTest, TestShowWelcomeSurface) { |
| base::RunLoop run_loop[4 * CartService::kWelcomSurfaceShowLimit + 5]; |
| int run_loop_index = 0; |
| |
| // Never increase appearance count for welcome surface when there is no cart. |
| for (int i = 0; i < CartService::kWelcomSurfaceShowLimit + 1; i++) { |
| std::vector<chrome_cart::mojom::MerchantCartPtr> empty_carts; |
| handler_->GetWarmWelcomeVisible(base::BindOnce( |
| &CartHandlerTest::GetEvaluationBoolResult, base::Unretained(this), |
| run_loop[run_loop_index].QuitClosure(), true)); |
| run_loop[run_loop_index++].Run(); |
| handler_->GetMerchantCarts(base::BindOnce( |
| &GetEvaluationMerchantCarts, run_loop[run_loop_index].QuitClosure(), |
| std::move(empty_carts))); |
| run_loop[run_loop_index++].Run(); |
| } |
| |
| // Add a cart with product image. |
| CartDB* cart_db_ = service_->GetDB(); |
| const char image_url[] = "www.image1.com"; |
| cart_db::ChromeCartContentProto merchant_proto = |
| BuildProto(kMockMerchantBKey, kMockMerchantB, kMockMerchantURLB); |
| merchant_proto.add_product_image_urls(image_url); |
| cart_db_->AddCart( |
| kMockMerchantBKey, merchant_proto, |
| base::BindOnce(&CartHandlerTest::OperationEvaluation, |
| base::Unretained(this), |
| run_loop[run_loop_index].QuitClosure(), true)); |
| run_loop[run_loop_index++].Run(); |
| |
| // Show welcome surface for the first three appearances. |
| for (int i = 0; i < CartService::kWelcomSurfaceShowLimit; i++) { |
| // Build a callback result without product image. |
| auto dummy_cart1 = chrome_cart::mojom::MerchantCart::New(); |
| dummy_cart1->merchant = kMockMerchantB; |
| dummy_cart1->cart_url = GURL(kMockMerchantURLB); |
| std::vector<chrome_cart::mojom::MerchantCartPtr> carts_without_product; |
| carts_without_product.push_back(std::move(dummy_cart1)); |
| |
| handler_->GetWarmWelcomeVisible(base::BindOnce( |
| &CartHandlerTest::GetEvaluationBoolResult, base::Unretained(this), |
| run_loop[run_loop_index].QuitClosure(), true)); |
| run_loop[run_loop_index++].Run(); |
| handler_->GetMerchantCarts(base::BindOnce( |
| &GetEvaluationMerchantCarts, run_loop[run_loop_index].QuitClosure(), |
| std::move(carts_without_product))); |
| run_loop[run_loop_index++].Run(); |
| } |
| |
| // Build a callback result with product image. |
| auto dummy_cart2 = chrome_cart::mojom::MerchantCart::New(); |
| dummy_cart2->merchant = kMockMerchantB; |
| dummy_cart2->cart_url = GURL(kMockMerchantURLB); |
| dummy_cart2->product_image_urls.emplace_back(image_url); |
| std::vector<chrome_cart::mojom::MerchantCartPtr> carts_with_product; |
| carts_with_product.push_back(std::move(dummy_cart2)); |
| |
| // Not show welcome surface afterwards. |
| handler_->GetWarmWelcomeVisible(base::BindOnce( |
| &CartHandlerTest::GetEvaluationBoolResult, base::Unretained(this), |
| run_loop[run_loop_index].QuitClosure(), false)); |
| run_loop[run_loop_index++].Run(); |
| handler_->GetMerchantCarts(base::BindOnce( |
| &GetEvaluationMerchantCarts, run_loop[run_loop_index].QuitClosure(), |
| std::move(carts_with_product))); |
| run_loop[run_loop_index++].Run(); |
| } |
| |
| // Verifies discount data not showing with RBD disabled. |
| TEST_F(CartHandlerTest, TestDiscountDataWithoutFeature) { |
| base::RunLoop run_loop[7]; |
| int run_loop_index = 0; |
| // Add a cart with discount. |
| cart_db::ChromeCartContentProto merchant_proto = |
| BuildProto(kMockMerchantBKey, kMockMerchantB, kMockMerchantURLB); |
| merchant_proto.mutable_discount_info()->set_discount_text("15% off"); |
| service_->AddCart(kMockMerchantBKey, absl::nullopt, merchant_proto); |
| task_environment_.RunUntilIdle(); |
| |
| // Skip the welcome surface stage as discount is not showing for welcome |
| // surface. |
| for (int i = 0; i < CartService::kWelcomSurfaceShowLimit; i++) { |
| service_->IncreaseWelcomeSurfaceCounter(); |
| } |
| ASSERT_FALSE(service_->ShouldShowWelcomeSurface()); |
| |
| // Discount should not show in normal cart module with RBD disabled. |
| auto expect_cart = chrome_cart::mojom::MerchantCart::New(); |
| expect_cart->merchant = kMockMerchantB; |
| expect_cart->cart_url = GURL(kMockMerchantURLB); |
| std::vector<chrome_cart::mojom::MerchantCartPtr> carts; |
| carts.push_back(std::move(expect_cart)); |
| handler_->GetMerchantCarts( |
| base::BindOnce(&GetEvaluationMerchantCarts, |
| run_loop[run_loop_index].QuitClosure(), std::move(carts))); |
| run_loop[run_loop_index++].Run(); |
| } |
| |
| // Override CartHandlerTest so that we can initialize feature_list_ in our |
| // constructor, before CartHandlerTest::SetUp is called. |
| class CartHandlerNtpModuleFakeDataTest : public CartHandlerTest { |
| public: |
| CartHandlerNtpModuleFakeDataTest() { |
| // This needs to be called before any tasks that run on other threads check |
| // if a feature is enabled. |
| feature_list_.InitAndEnableFeatureWithParameters( |
| ntp_features::kNtpChromeCartModule, |
| {{"NtpChromeCartModuleDataParam", "fake"}, |
| {ntp_features::kNtpChromeCartModuleAbandonedCartDiscountUseUtmParam, |
| "false"}}); |
| } |
| |
| private: |
| base::test::ScopedFeatureList feature_list_; |
| }; |
| |
| // Verifies GetMerchantCarts loads fake data with feature parameter. |
| TEST_F(CartHandlerNtpModuleFakeDataTest, TestEnableFakeData) { |
| // Remove fake data loaded by CartService::CartService. |
| service_->DeleteCartsWithFakeData(); |
| |
| service_->AddCart(kFakeMerchantKey, absl::nullopt, kFakeProto); |
| service_->AddCart(kMockMerchantBKey, absl::nullopt, kMockProtoB); |
| task_environment_.RunUntilIdle(); |
| |
| std::vector<chrome_cart::mojom::MerchantCartPtr> carts; |
| auto dummy_cart1 = chrome_cart::mojom::MerchantCart::New(); |
| dummy_cart1->merchant = kFakeMerchant; |
| dummy_cart1->cart_url = GURL(kFakeMerchantURL); |
| carts.push_back(std::move(dummy_cart1)); |
| |
| base::RunLoop run_loop; |
| handler_->GetMerchantCarts(base::BindOnce( |
| &GetEvaluationMerchantCarts, run_loop.QuitClosure(), std::move(carts))); |
| run_loop.Run(); |
| } |
| |
| // Override CartHandlerTest so that we can initialize feature_list_ in our |
| // constructor, before CartHandlerTest::SetUp is called. |
| class CartHandlerNtpModuleDiscountTest : public CartHandlerTest { |
| public: |
| CartHandlerNtpModuleDiscountTest() { |
| // This needs to be called before any tasks that run on other threads check |
| // if a feature is enabled. |
| feature_list_.InitAndEnableFeatureWithParameters( |
| ntp_features::kNtpChromeCartModule, |
| {{"NtpChromeCartModuleAbandonedCartDiscountParam", "true"}, |
| {"partner-merchant-pattern", "(foo.com)"}, |
| {ntp_features::kNtpChromeCartModuleAbandonedCartDiscountUseUtmParam, |
| "false"}}); |
| } |
| |
| void SetUp() override { |
| CartHandlerTest::SetUp(); |
| |
| // Mock that welcome surface has already finished showing. |
| for (int i = 0; i < CartService::kWelcomSurfaceShowLimit; i++) { |
| service_->IncreaseWelcomeSurfaceCounter(); |
| } |
| ASSERT_FALSE(service_->ShouldShowWelcomeSurface()); |
| } |
| |
| private: |
| base::test::ScopedFeatureList feature_list_; |
| }; |
| |
| // Test discount consent card visibility aligns with CartService. |
| // Flaky on multiple platforms: crbug.com/1256745 |
| TEST_F(CartHandlerNtpModuleDiscountTest, |
| DISABLED_TestGetDiscountConsentCardVisible) { |
| CartDB* cart_db = service_->GetDB(); |
| base::RunLoop run_loop[5]; |
| service_->ShouldShowDiscountConsent( |
| base::BindOnce(&CartHandlerTest::GetEvaluationBoolResult, |
| base::Unretained(this), run_loop[0].QuitClosure(), false)); |
| run_loop[0].Run(); |
| handler_->GetDiscountConsentCardVisible( |
| base::BindOnce(&CartHandlerTest::GetEvaluationBoolResult, |
| base::Unretained(this), run_loop[1].QuitClosure(), false)); |
| run_loop[1].Run(); |
| |
| // Add a partner cart. |
| cart_db->AddCart( |
| kFakeMerchant, kFakeProto, |
| base::BindOnce(&CartHandlerTest::OperationEvaluation, |
| base::Unretained(this), run_loop[2].QuitClosure(), true)); |
| run_loop[2].Run(); |
| |
| service_->ShouldShowDiscountConsent( |
| base::BindOnce(&CartHandlerTest::GetEvaluationBoolResult, |
| base::Unretained(this), run_loop[3].QuitClosure(), true)); |
| run_loop[3].Run(); |
| handler_->GetDiscountConsentCardVisible( |
| base::BindOnce(&CartHandlerTest::GetEvaluationBoolResult, |
| base::Unretained(this), run_loop[4].QuitClosure(), true)); |
| run_loop[4].Run(); |
| } |
| |
| // Test OnDiscountConsentAcknowledged can update status in CartService. |
| // Flaky on multiple platforms: crbug.com/1256745 |
| TEST_F(CartHandlerNtpModuleDiscountTest, |
| DISABLED_TestOnDiscountConsentAcknowledged) { |
| // Update fetch timestamp to avoid fetching triggered by consent |
| // acknowledgement. |
| profile_->GetPrefs()->SetTime(prefs::kCartDiscountLastFetchedTime, |
| base::Time::Now()); |
| CartDB* cart_db = service_->GetDB(); |
| base::RunLoop run_loop[4]; |
| // Add a partner cart. |
| cart_db->AddCart( |
| kFakeMerchant, kFakeProto, |
| base::BindOnce(&CartHandlerTest::OperationEvaluation, |
| base::Unretained(this), run_loop[0].QuitClosure(), true)); |
| run_loop[0].Run(); |
| |
| service_->ShouldShowDiscountConsent( |
| base::BindOnce(&CartHandlerTest::GetEvaluationBoolResult, |
| base::Unretained(this), run_loop[1].QuitClosure(), true)); |
| run_loop[1].Run(); |
| ASSERT_FALSE(service_->IsCartDiscountEnabled()); |
| |
| handler_->OnDiscountConsentAcknowledged(true); |
| service_->ShouldShowDiscountConsent( |
| base::BindOnce(&CartHandlerTest::GetEvaluationBoolResult, |
| base::Unretained(this), run_loop[2].QuitClosure(), false)); |
| run_loop[2].Run(); |
| ASSERT_TRUE(service_->IsCartDiscountEnabled()); |
| |
| handler_->OnDiscountConsentAcknowledged(false); |
| service_->ShouldShowDiscountConsent( |
| base::BindOnce(&CartHandlerTest::GetEvaluationBoolResult, |
| base::Unretained(this), run_loop[3].QuitClosure(), false)); |
| run_loop[3].Run(); |
| ASSERT_FALSE(service_->IsCartDiscountEnabled()); |
| } |
| |
| // Test GetDiscountEnabled returns whether rule-based discount feature is |
| // enabled. |
| TEST_F(CartHandlerNtpModuleDiscountTest, TestGetDiscountEnabled) { |
| base::RunLoop run_loop[2]; |
| profile_->GetPrefs()->SetBoolean(prefs::kCartDiscountEnabled, true); |
| ASSERT_TRUE(service_->IsCartDiscountEnabled()); |
| handler_->GetDiscountEnabled( |
| base::BindOnce(&CartHandlerTest::GetEvaluationBoolResult, |
| base::Unretained(this), run_loop[0].QuitClosure(), true)); |
| run_loop[0].Run(); |
| |
| profile_->GetPrefs()->SetBoolean(prefs::kCartDiscountEnabled, false); |
| ASSERT_FALSE(service_->IsCartDiscountEnabled()); |
| handler_->GetDiscountEnabled( |
| base::BindOnce(&CartHandlerTest::GetEvaluationBoolResult, |
| base::Unretained(this), run_loop[1].QuitClosure(), false)); |
| run_loop[1].Run(); |
| } |
| |
| // Test SetDiscountEnabled updates whether rule-based discount is enabled. |
| TEST_F(CartHandlerNtpModuleDiscountTest, TestSetDiscountEnabled) { |
| ASSERT_FALSE(service_->IsCartDiscountEnabled()); |
| handler_->SetDiscountEnabled(true); |
| ASSERT_TRUE(service_->IsCartDiscountEnabled()); |
| handler_->SetDiscountEnabled(false); |
| ASSERT_FALSE(service_->IsCartDiscountEnabled()); |
| } |
| |
| // Verifies discount data showing with RBD enabled. |
| TEST_F(CartHandlerNtpModuleDiscountTest, TestDiscountDataWithFeature) { |
| base::RunLoop run_loop[7]; |
| int run_loop_index = 0; |
| // Add a cart with discount. Mock that welcome surface hasn't shown and RBD is |
| // enabled. |
| cart_db::ChromeCartContentProto merchant_proto = |
| BuildProto(kMockMerchantBKey, kMockMerchantB, kMockMerchantURLB); |
| merchant_proto.mutable_discount_info()->set_discount_text("15% off"); |
| cart_db::RuleDiscountInfoProto* rule_discount_info = |
| merchant_proto.mutable_discount_info()->add_rule_discount_info(); |
| rule_discount_info->set_rule_id("123"); |
| service_->AddCart(kMockMerchantBKey, absl::nullopt, merchant_proto); |
| task_environment_.RunUntilIdle(); |
| profile_->GetPrefs()->SetInteger(prefs::kCartModuleWelcomeSurfaceShownTimes, |
| 0); |
| profile_->GetPrefs()->SetBoolean(prefs::kCartDiscountEnabled, true); |
| |
| // Discount should not show in welcome surface. |
| for (int i = 0; i < CartService::kWelcomSurfaceShowLimit; i++) { |
| // Build a callback result without discount. |
| auto expect_cart = chrome_cart::mojom::MerchantCart::New(); |
| expect_cart->merchant = kMockMerchantB; |
| expect_cart->cart_url = GURL(kMockMerchantURLB); |
| std::vector<chrome_cart::mojom::MerchantCartPtr> carts; |
| carts.push_back(std::move(expect_cart)); |
| handler_->GetWarmWelcomeVisible(base::BindOnce( |
| &CartHandlerTest::GetEvaluationBoolResult, base::Unretained(this), |
| run_loop[run_loop_index].QuitClosure(), true)); |
| run_loop[run_loop_index++].Run(); |
| handler_->GetMerchantCarts(base::BindOnce( |
| &GetEvaluationMerchantCarts, run_loop[run_loop_index].QuitClosure(), |
| std::move(carts))); |
| run_loop[run_loop_index++].Run(); |
| } |
| |
| // Discount should show in normal cart module with RBD enabled. |
| auto expect_cart = chrome_cart::mojom::MerchantCart::New(); |
| expect_cart->merchant = kMockMerchantB; |
| expect_cart->cart_url = GURL(kMockMerchantURLB); |
| expect_cart->discount_text = "15% off"; |
| std::vector<chrome_cart::mojom::MerchantCartPtr> carts; |
| carts.push_back(std::move(expect_cart)); |
| handler_->GetMerchantCarts( |
| base::BindOnce(&GetEvaluationMerchantCarts, |
| run_loop[run_loop_index].QuitClosure(), std::move(carts))); |
| run_loop[run_loop_index++].Run(); |
| } |
| |
| // Verifies discount data showing when coupons is available. |
| TEST_F(CartHandlerNtpModuleDiscountTest, TestDiscountDataShows) { |
| profile_->GetPrefs()->SetInteger(prefs::kCartModuleWelcomeSurfaceShownTimes, |
| 3); |
| profile_->GetPrefs()->SetBoolean(prefs::kCartDiscountEnabled, true); |
| |
| base::RunLoop run_loop; |
| |
| // Add a cart with discount. |
| cart_db::ChromeCartContentProto merchant_proto = |
| BuildProto(kMockMerchantBKey, kMockMerchantB, kMockMerchantURLB); |
| merchant_proto.mutable_discount_info()->set_discount_text("15% off"); |
| merchant_proto.mutable_discount_info()->set_has_coupons(true); |
| service_->AddCart(kMockMerchantBKey, absl::nullopt, merchant_proto); |
| task_environment_.RunUntilIdle(); |
| |
| // Discount should show. |
| auto expect_cart = chrome_cart::mojom::MerchantCart::New(); |
| expect_cart->merchant = kMockMerchantB; |
| expect_cart->cart_url = GURL(kMockMerchantURLB); |
| expect_cart->discount_text = "15% off"; |
| std::vector<chrome_cart::mojom::MerchantCartPtr> carts; |
| carts.push_back(std::move(expect_cart)); |
| handler_->GetMerchantCarts(base::BindOnce( |
| &GetEvaluationMerchantCarts, run_loop.QuitClosure(), std::move(carts))); |
| run_loop.Run(); |
| } |
| |
| // Override CartHandlerTest so that we can initialize feature_list_ in our |
| // constructor, before CartHandlerTest::SetUp is called. |
| class CartHandlerCartURLUTMTest : public CartHandlerTest { |
| public: |
| CartHandlerCartURLUTMTest() { |
| // This needs to be called before any tasks that run on other threads check |
| // if a feature is enabled. |
| feature_list_.InitAndEnableFeatureWithParameters( |
| ntp_features::kNtpChromeCartModule, |
| {{"NtpChromeCartModuleAbandonedCartDiscountParam", "true"}, |
| {"partner-merchant-pattern", "(foo.com)"}, |
| {ntp_features::kNtpChromeCartModuleAbandonedCartDiscountUseUtmParam, |
| "true"}}); |
| } |
| |
| private: |
| base::test::ScopedFeatureList feature_list_; |
| }; |
| |
| // Verifies UTM tags are correctly appended to partner merchant's cart. |
| TEST_F(CartHandlerCartURLUTMTest, TestAppendUTMToPartnerMerchant) { |
| base::RunLoop run_loop[2]; |
| service_->AddCart(kFakeMerchantKey, absl::nullopt, kFakeProto); |
| task_environment_.RunUntilIdle(); |
| |
| // Verifies UTM tags for when discount is disabled. |
| ASSERT_FALSE(service_->IsCartDiscountEnabled()); |
| handler_->GetMerchantCarts(base::BindOnce( |
| &GetEvaluationMerchantCartWithUtmSource, run_loop[0].QuitClosure(), true, |
| "utm_source=chrome&utm_medium=app&utm_campaign=chrome-cart-discount-" |
| "off")); |
| run_loop[0].Run(); |
| |
| // Verifies UTM tags for when discount is enabled. |
| profile_->GetPrefs()->SetBoolean(prefs::kCartDiscountEnabled, true); |
| ASSERT_TRUE(service_->IsCartDiscountEnabled()); |
| handler_->GetMerchantCarts(base::BindOnce( |
| &GetEvaluationMerchantCartWithUtmSource, run_loop[1].QuitClosure(), true, |
| "utm_source=chrome&utm_medium=app&utm_campaign=chrome-cart-discount-on")); |
| run_loop[1].Run(); |
| } |
| |
| // Verifies UTM tags are correctly appended to non-partner merchant's cart. |
| TEST_F(CartHandlerCartURLUTMTest, TestAppendUTMToNonPartnerMerchant) { |
| base::RunLoop run_loop[2]; |
| service_->AddCart(kMockMerchantBKey, absl::nullopt, kMockProtoB); |
| task_environment_.RunUntilIdle(); |
| |
| // UTM tags are the same for non-partner merchants regardless of discount |
| // status. |
| ASSERT_FALSE(service_->IsCartDiscountEnabled()); |
| handler_->GetMerchantCarts(base::BindOnce( |
| &GetEvaluationMerchantCartWithUtmSource, run_loop[0].QuitClosure(), true, |
| "utm_source=chrome&utm_medium=app&utm_campaign=chrome-cart")); |
| run_loop[0].Run(); |
| |
| handler_->SetDiscountEnabled(true); |
| ASSERT_TRUE(service_->IsCartDiscountEnabled()); |
| handler_->GetMerchantCarts(base::BindOnce( |
| &GetEvaluationMerchantCartWithUtmSource, run_loop[1].QuitClosure(), true, |
| "utm_source=chrome&utm_medium=app&utm_campaign=chrome-cart")); |
| run_loop[1].Run(); |
| } |
| |
| class CartHandlerNtpModuleDiscountConsentV2Test : public CartHandlerTest { |
| public: |
| CartHandlerNtpModuleDiscountConsentV2Test() { |
| std::vector<base::test::ScopedFeatureList::FeatureAndParams> |
| enabled_features; |
| base::FieldTrialParams consent_v2_params, cart_params; |
| cart_params["NtpChromeCartModuleAbandonedCartDiscountParam"] = "true"; |
| cart_params["partner-merchant-pattern"] = "(foo.com)"; |
| enabled_features.emplace_back(ntp_features::kNtpChromeCartModule, |
| cart_params); |
| consent_v2_params["discount-consent-ntp-reshow-time"] = "1m"; |
| consent_v2_params["discount-consent-ntp-max-dismiss-count"] = "2"; |
| enabled_features.emplace_back(commerce::kDiscountConsentV2, |
| consent_v2_params); |
| feature_list_.InitWithFeaturesAndParameters(enabled_features, |
| /*disabled_features*/ {}); |
| } |
| |
| void SetUp() override { |
| CartHandlerTest::SetUp(); |
| // Simulate that the welcome surface has been shown. |
| profile_->GetPrefs()->SetInteger(prefs::kCartModuleWelcomeSurfaceShownTimes, |
| CartService::kWelcomSurfaceShowLimit); |
| } |
| |
| private: |
| base::test::ScopedFeatureList feature_list_; |
| }; |
| |
| TEST_F(CartHandlerNtpModuleDiscountConsentV2Test, |
| TestOnDiscountConsentDismissed) { |
| CartDB* cart_db = service_->GetDB(); |
| { |
| base::RunLoop run_loop; |
| // Add a partner cart. |
| cart_db->AddCart( |
| kFakeMerchant, kFakeProto, |
| base::BindOnce(&CartHandlerTest::OperationEvaluation, |
| base::Unretained(this), run_loop.QuitClosure(), true)); |
| run_loop.Run(); |
| } |
| { |
| base::RunLoop run_loop; |
| service_->ShouldShowDiscountConsent( |
| base::BindOnce(&CartHandlerTest::GetEvaluationBoolResult, |
| base::Unretained(this), run_loop.QuitClosure(), true)); |
| run_loop.Run(); |
| } |
| |
| handler_->OnDiscountConsentDismissed(); |
| { |
| base::RunLoop run_loop; |
| service_->ShouldShowDiscountConsent( |
| base::BindOnce(&CartHandlerTest::GetEvaluationBoolResult, |
| base::Unretained(this), run_loop.QuitClosure(), false)); |
| run_loop.Run(); |
| } |
| } |