chromium/ios/chrome/browser/plus_addresses/coordinator/plus_address_bottom_sheet_mediator_unittest.mm

// Copyright 2023 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/plus_addresses/coordinator/plus_address_bottom_sheet_mediator.h"

#import "base/functional/bind.h"
#import "base/strings/sys_string_conversions.h"
#import "base/test/scoped_feature_list.h"
#import "base/test/task_environment.h"
#import "base/types/expected.h"
#import "components/plus_addresses/fake_plus_address_service.h"
#import "components/plus_addresses/features.h"
#import "components/plus_addresses/metrics/plus_address_metrics.h"
#import "components/plus_addresses/plus_address_service.h"
#import "components/plus_addresses/plus_address_types.h"
#import "components/plus_addresses/settings/mock_plus_address_setting_service.h"
#import "ios/chrome/browser/plus_addresses/ui/plus_address_bottom_sheet_constants.h"
#import "ios/chrome/browser/plus_addresses/ui/plus_address_bottom_sheet_consumer.h"
#import "ios/chrome/browser/shared/model/browser/test/test_browser.h"
#import "ios/chrome/browser/shared/model/profile/test/test_profile_ios.h"
#import "ios/chrome/browser/signin/model/identity_manager_factory.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 "testing/gmock/include/gmock/gmock.h"
#import "testing/platform_test.h"
#import "third_party/ocmock/OCMock/OCMock.h"
#import "third_party/ocmock/gtest_support.h"
#import "url/gurl.h"
#import "url/origin.h"

namespace {

using plus_addresses::FakePlusAddressService;
using plus_addresses::MockPlusAddressSettingService;
using ::testing::Return;

}  // namespace

class PlusAddressBottomSheetMediatorTest : public PlatformTest {
 protected:
  PlusAddressBottomSheetMediatorTest()
      : consumer_(OCMProtocolMock(@protocol(PlusAddressBottomSheetConsumer))),
        browser_state_(TestChromeBrowserState::Builder().Build()),
        browser_(browser_state_.get()),
        service_(
            browser_state_->GetPrefs(),
            IdentityManagerFactory::GetForBrowserState(browser_state_.get()),
            &plus_address_setting_service_) {
    UrlLoadingNotifierBrowserAgent::CreateForBrowser(&browser_);
    FakeUrlLoadingBrowserAgent::InjectForBrowser(&browser_);
    url_loader_ = FakeUrlLoadingBrowserAgent::FromUrlLoadingBrowserAgent(
        UrlLoadingBrowserAgent::FromBrowser(&browser_));
    BOOL incognito = browser_state_.get()->IsOffTheRecord();
    mediator_ = [[PlusAddressBottomSheetMediator alloc]
        initWithPlusAddressService:&service()
         plusAddressSettingService:&plus_address_setting_service_
                         activeUrl:GURL(FakePlusAddressService::kFacet)
                  autofillCallback:base::DoNothing()
                         urlLoader:url_loader_
                         incognito:incognito];
    mediator_.consumer = consumer_;
  }

  FakePlusAddressService& service() { return service_; }
  MockPlusAddressSettingService& plus_address_setting_service() {
    return plus_address_setting_service_;
  }
  PlusAddressBottomSheetMediator* mediator() { return mediator_; }
  FakeUrlLoadingBrowserAgent* url_loader() { return url_loader_.get(); }

  id consumer_;

 private:
  base::test::TaskEnvironment task_environment_;
  std::unique_ptr<TestChromeBrowserState> browser_state_;
  TestBrowser browser_;
  FakePlusAddressService service_;
  MockPlusAddressSettingService plus_address_setting_service_;
  raw_ptr<FakeUrlLoadingBrowserAgent> url_loader_;
  PlusAddressBottomSheetMediator* mediator_ = nil;
};

// Ensure that the consumer is notified when a plus address is successfully
// reserved.
TEST_F(PlusAddressBottomSheetMediatorTest, ReservePlusAddress) {
  OCMExpect([consumer_
      didReservePlusAddress:base::SysUTF8ToNSString(
                                FakePlusAddressService::kFakePlusAddress)]);
  [mediator() reservePlusAddress];
  EXPECT_OCMOCK_VERIFY(consumer_);
}

// Ensure that the consumer is notified when errors are observed by the
// mediator.
TEST_F(PlusAddressBottomSheetMediatorTest, ReservePlusAddressError) {
  service().set_should_fail_to_reserve(true);
  OCMExpect([consumer_
      notifyError:plus_addresses::metrics::PlusAddressModalCompletionStatus::
                      kReservePlusAddressError]);
  [mediator() reservePlusAddress];
  EXPECT_OCMOCK_VERIFY(consumer_);
}

// Ensure the consumer is notified when plus addresses are confirmed.
TEST_F(PlusAddressBottomSheetMediatorTest, ConfirmPlusAddress) {
  OCMExpect([consumer_
      didReservePlusAddress:base::SysUTF8ToNSString(
                                FakePlusAddressService::kFakePlusAddress)]);
  [mediator() reservePlusAddress];
  EXPECT_OCMOCK_VERIFY(consumer_);
  OCMExpect([consumer_ didConfirmPlusAddress]);
  [mediator() confirmPlusAddress];
  EXPECT_OCMOCK_VERIFY(consumer_);
}

// Tests that the settings service is informed that the notice was accepted.
TEST_F(PlusAddressBottomSheetMediatorTest, AcceptNoticeNotifiesService) {
  base::test::ScopedFeatureList features_{
      plus_addresses::features::kPlusAddressUserOnboardingEnabled};

  ON_CALL(plus_address_setting_service(), GetHasAcceptedNotice())
      .WillByDefault(Return(false));
  EXPECT_CALL(plus_address_setting_service(), SetHasAcceptedNotice());

  [mediator() reservePlusAddress];
  [mediator() confirmPlusAddress];
}

// Tests that the settings service is not informed when the bottomsheet was
// accepted if the notice has already been accepted before.
TEST_F(PlusAddressBottomSheetMediatorTest, NoticeAlreadyAccepted) {
  base::test::ScopedFeatureList features_{
      plus_addresses::features::kPlusAddressUserOnboardingEnabled};

  ON_CALL(plus_address_setting_service(), GetHasAcceptedNotice())
      .WillByDefault(Return(true));
  EXPECT_CALL(plus_address_setting_service(), SetHasAcceptedNotice()).Times(0);

  [mediator() reservePlusAddress];
  [mediator() confirmPlusAddress];
}

// Ensure the consumer is notified when plus addresses confirmation fails.
TEST_F(PlusAddressBottomSheetMediatorTest, ConfirmPlusAddressError) {
  OCMExpect([consumer_
      didReservePlusAddress:base::SysUTF8ToNSString(
                                FakePlusAddressService::kFakePlusAddress)]);
  [mediator() reservePlusAddress];
  EXPECT_OCMOCK_VERIFY(consumer_);
  OCMExpect([consumer_
      notifyError:plus_addresses::metrics::PlusAddressModalCompletionStatus::
                      kConfirmPlusAddressError]);
  service().set_should_fail_to_confirm(true);
  [mediator() confirmPlusAddress];
  EXPECT_OCMOCK_VERIFY(consumer_);
}

TEST_F(PlusAddressBottomSheetMediatorTest, OpenManagementUrlOnNewTab) {
  [mediator() openNewTab:PlusAddressURLType::kManagement];

  EXPECT_EQ(GURL(plus_addresses::features::kPlusAddressManagementUrl.Get()),
            url_loader()->last_params.web_params.url);
  // Ensure one new tab is opened.
  EXPECT_EQ(1, url_loader()->load_new_tab_call_count);
}

// Ensure that `openNewTab` opens errorReportUrl.
TEST_F(PlusAddressBottomSheetMediatorTest, OpenErrorReportUrlOnNewTab) {
  [mediator() openNewTab:PlusAddressURLType::kErrorReport];

  EXPECT_EQ(GURL(plus_addresses::features::kPlusAddressErrorReportUrl.Get()),
            url_loader()->last_params.web_params.url);
  // Ensure one new tab is opened.
  EXPECT_EQ(1, url_loader()->load_new_tab_call_count);
}

TEST_F(PlusAddressBottomSheetMediatorTest, OpenLearnMoreUrlOnNewTab) {
  [mediator() openNewTab:PlusAddressURLType::kLearnMore];

  EXPECT_EQ(GURL(plus_addresses::features::kPlusAddressLearnMoreUrl.Get()),
            url_loader()->last_params.web_params.url);
  // Ensure one new tab is opened.
  EXPECT_EQ(1, url_loader()->load_new_tab_call_count);
}

// Ensure the consumer is notified when plus addresses are refreshed.
TEST_F(PlusAddressBottomSheetMediatorTest, DidTapRefresh) {
  OCMExpect([consumer_
      didReservePlusAddress:base::SysUTF8ToNSString(
                                FakePlusAddressService::kFakePlusAddress)]);
  [mediator() didTapRefreshButton];
  EXPECT_OCMOCK_VERIFY(consumer_);
  OCMExpect([consumer_ didConfirmPlusAddress]);
  [mediator() confirmPlusAddress];
  EXPECT_OCMOCK_VERIFY(consumer_);
}