chromium/ios/chrome/browser/ui/content_suggestions/parcel_tracking/parcel_tracking_mediator_unittest.mm

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

#import "ios/chrome/browser/ui/content_suggestions/parcel_tracking/parcel_tracking_mediator.h"

#import "base/run_loop.h"
#import "base/test/ios/wait_util.h"
#import "base/test/test_timeouts.h"
#import "base/time/time.h"
#import "components/commerce/core/mock_shopping_service.h"
#import "ios/chrome/browser/parcel_tracking/parcel_tracking_prefs.h"
#import "ios/chrome/browser/shared/model/application_context/application_context.h"
#import "ios/chrome/browser/shared/model/browser/test/test_browser.h"
#import "ios/chrome/browser/shared/model/prefs/pref_names.h"
#import "ios/chrome/browser/shared/model/profile/test/test_profile_ios.h"
#import "ios/chrome/browser/ui/content_suggestions/parcel_tracking/parcel_tracking_item.h"
#import "ios/chrome/browser/url_loading/model/fake_url_loading_browser_agent.h"
#import "ios/chrome/browser/url_loading/model/url_loading_notifier_browser_agent.h"
#import "ios/chrome/test/ios_chrome_scoped_testing_local_state.h"
#import "ios/web/public/test/web_task_environment.h"
#import "testing/platform_test.h"
#import "third_party/ocmock/OCMock/OCMock.h"
#import "third_party/ocmock/gtest_support.h"

// Tests the ParcelTrackingMediator's functionality.
class ParcelTrackingMediatorTest : public PlatformTest {
 public:
  ParcelTrackingMediatorTest() {
    browser_state_ = TestChromeBrowserState::Builder().Build();
    browser_ = std::make_unique<TestBrowser>(browser_state_.get());

    shopping_service_ = std::make_unique<commerce::MockShoppingService>();
    std::vector<commerce::ParcelTrackingStatus> parcels;
    commerce::ParcelTrackingStatus out_for_delivery;
    out_for_delivery.carrier = commerce::ParcelIdentifier::UPS;
    out_for_delivery.state = commerce::ParcelStatus::OUT_FOR_DELIVERY;
    out_for_delivery.tracking_id = "abc";
    out_for_delivery.estimated_delivery_time =
        base::Time::Now() + base::Hours(3);
    parcels.emplace_back(out_for_delivery);

    commerce::ParcelTrackingStatus delivered_status;
    delivered_status.carrier = commerce::ParcelIdentifier::USPS;
    delivered_status.state = commerce::ParcelStatus::FINISHED;
    delivered_status.tracking_id = "def";
    delivered_status.estimated_delivery_time =
        base::Time::Now() - base::Days(3);
    parcels.emplace_back(delivered_status);

    commerce::ParcelTrackingStatus in_progress;
    in_progress.carrier = commerce::ParcelIdentifier::UPS;
    in_progress.state = commerce::ParcelStatus::WITH_CARRIER;
    in_progress.tracking_id = "abc";
    in_progress.estimated_delivery_time = base::Time::Now() + base::Days(3);
    parcels.emplace_back(in_progress);

    shopping_service_->SetGetAllParcelStatusesCallbackValue(parcels);

    UrlLoadingNotifierBrowserAgent::CreateForBrowser(browser_.get());
    FakeUrlLoadingBrowserAgent::InjectForBrowser(browser_.get());
    url_loader_ = FakeUrlLoadingBrowserAgent::FromUrlLoadingBrowserAgent(
        UrlLoadingBrowserAgent::FromBrowser(browser_.get()));
  }

  ~ParcelTrackingMediatorTest() override { [mediator_ disconnect]; }

  PrefService* local_state() {
    return GetApplicationContext()->GetLocalState();
  }

 protected:
  void SetupMediator() {
    mediator_ = [[ParcelTrackingMediator alloc]
        initWithShoppingService:shopping_service_.get()
         URLLoadingBrowserAgent:url_loader_
                    prefService:local_state()];
    delegate_ = OCMProtocolMock(@protocol(ParcelTrackingMediatorDelegate));
    mediator_.delegate = delegate_;
  }

  web::WebTaskEnvironment task_environment_;
  IOSChromeScopedTestingLocalState scoped_testing_local_state_;
  std::unique_ptr<TestChromeBrowserState> browser_state_;
  std::unique_ptr<TestBrowser> browser_;
  FakeUrlLoadingBrowserAgent* url_loader_;
  std::unique_ptr<commerce::MockShoppingService> shopping_service_;
  ParcelTrackingMediator* mediator_;
  id delegate_;
};

// Tests that the mediator handles the parcels returned from
// ShoppingService::GetAllParcelStatuses by sending up the parcels to the
// consumer and includes the parcel tracking module type correctly in the magic
// stack order.
TEST_F(ParcelTrackingMediatorTest, TestParcelTrackingReceived) {
  int parcel_tracking_freshness_impression_count = local_state()->GetInteger(
      prefs::kIosMagicStackSegmentationParcelTrackingImpressionsSinceFreshness);
  EXPECT_EQ(parcel_tracking_freshness_impression_count, -1);

  // One of the parcels should be untracked since it was delivered more than two
  // days ago.
  EXPECT_CALL(*shopping_service_, StopTrackingParcel(testing::_, testing::_))
      .Times(1);
  SetupMediator();

  EXPECT_TRUE(base::test::ios::WaitUntilConditionOrTimeout(
      TestTimeouts::action_timeout(), true, ^bool() {
        base::RunLoop().RunUntilIdle();
        return [[mediator_ allParcelTrackingItems] count] == 3;
      }));

  ParcelTrackingItem* item = [mediator_ parcelTrackingItemToShow];
  ParcelTrackingItem* outForDeliveryItem = item;
  EXPECT_EQ(outForDeliveryItem.parcelType, ParcelType::kUPS);
  EXPECT_EQ(outForDeliveryItem.status, ParcelState::kOutForDelivery);
  EXPECT_TRUE(outForDeliveryItem.shouldShowSeeMore);

  parcel_tracking_freshness_impression_count = local_state()->GetInteger(
      prefs::kIosMagicStackSegmentationParcelTrackingImpressionsSinceFreshness);
  EXPECT_EQ(parcel_tracking_freshness_impression_count, 0);
}

// Tests that the -loadParcelTrackingPage ParcelTrackingCommands
// implementation logs the correct metric and loads the passed URL.
TEST_F(ParcelTrackingMediatorTest, TestParcelTracking) {
  SetupMediator();
  GURL parcelTrackingURL = GURL("http://chromium.org");
  [mediator_ loadParcelTrackingPage:parcelTrackingURL];
  EXPECT_EQ(parcelTrackingURL, url_loader_->last_params.web_params.url);
}

TEST_F(ParcelTrackingMediatorTest, TestModuleDisabled) {
  SetupMediator();

  // Set up expectations.
  EXPECT_CALL(*shopping_service_, StopTrackingAllParcels(testing::_)).Times(1);
  OCMExpect([delegate_ parcelTrackingDisabled]);

  // Disable the pref.
  DisableParcelTracking(local_state());

  // Verify the delegate callback.
  EXPECT_OCMOCK_VERIFY(delegate_);
}