chromium/chrome/test/base/ash/interactive/cellular/apn_ui_interactive_uitest.cc

// 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.

#include <string>

#include "ash/constants/ash_features.h"
#include "base/test/scoped_feature_list.h"
#include "chrome/test/base/ash/interactive/cellular/esim_interactive_uitest_base.h"
#include "chrome/test/base/ash/interactive/cellular/wait_for_service_connected_observer.h"
#include "chrome/test/base/ash/interactive/settings/interactive_uitest_elements.h"
#include "chromeos/ash/components/dbus/hermes/fake_hermes_euicc_client.h"
#include "chromeos/ash/components/dbus/shill/fake_shill_service_client.h"
#include "chromeos/strings/grit/chromeos_strings.h"
#include "dbus/object_path.h"
#include "ui/base/interaction/element_identifier.h"
#include "ui/base/l10n/l10n_util.h"

namespace ash {
namespace {

const char kDefaultCustomApnName[] = "default_only_apn";
const char kAttachCustomApnName[] = "attach_only_apn";

DEFINE_LOCAL_ELEMENT_IDENTIFIER_VALUE(kOSSettingsId);

class ApnUiInteractiveUiTest : public EsimInteractiveUiTestBase {
 protected:
  ApnUiInteractiveUiTest() {
    scoped_feature_list_.InitAndEnableFeature(ash::features::kApnRevamp);
  }

  // InteractiveAshTest:
  void SetUpOnMainThread() override {
    EsimInteractiveUiTestBase::SetUpOnMainThread();

    esim_info_ = std::make_unique<SimInfo>(/*id=*/0);
    ConfigureEsimProfile(euicc_info(), *esim_info_, /*connected=*/true);

    default_modb_apn_name_ = *ShillServiceClient::Get()
                                  ->GetTestInterface()
                                  ->GetFakeDefaultModbApnDict()
                                  .FindString(shill::kApnNameProperty);
  }

  const SimInfo& esim_info() const { return *esim_info_; }
  const std::string& default_modb_apn_name() const {
    return default_modb_apn_name_;
  }

  void VerifyNoCustomApnsInShill() {
    const base::Value::Dict* cellular_properties =
        ShillServiceClient::Get()->GetTestInterface()->GetServiceProperties(
            esim_info().service_path());
    ASSERT_TRUE(cellular_properties);
    const base::Value::List* shill_custom_apns =
        cellular_properties->FindList(shill::kCellularCustomApnListProperty);
    ASSERT_TRUE(shill_custom_apns);
    EXPECT_EQ(0u, shill_custom_apns->size());
  }

  void VerifyCustomApnInShill(bool expect_exists,
                              const std::string& expected_apn_name,
                              const std::string& expected_apn_type) {
    const base::Value::Dict* cellular_properties =
        ShillServiceClient::Get()->GetTestInterface()->GetServiceProperties(
            esim_info().service_path());
    ASSERT_TRUE(cellular_properties);
    const base::Value::List* shill_custom_apns =
        cellular_properties->FindList(shill::kCellularCustomApnListProperty);
    ASSERT_TRUE(shill_custom_apns);

    bool found_matching_apn_name = false;
    for (const auto& custom_apn : *shill_custom_apns) {
      CHECK(custom_apn.is_dict());

      const std::string* apn_name =
          custom_apn.GetDict().FindString(shill::kApnProperty);
      if (!apn_name || *apn_name != expected_apn_name) {
        continue;
      }
      found_matching_apn_name = true;
      const std::string* apn_type =
          custom_apn.GetDict().FindString(shill::kApnTypesProperty);
      ASSERT_TRUE(apn_type);
      EXPECT_EQ(expected_apn_type, *apn_type);
    }
    EXPECT_EQ(expect_exists, found_matching_apn_name);
  }

  void VerifyLastGoodApn(const std::string expected_apn_name) {
    const base::Value::Dict* cellular_properties =
        ShillServiceClient::Get()->GetTestInterface()->GetServiceProperties(
            esim_info().service_path());
    ASSERT_TRUE(cellular_properties);
    const base::Value::Dict* last_good_apn =
        cellular_properties->FindDict(shill::kCellularLastGoodApnProperty);
    ASSERT_TRUE(last_good_apn);
    const std::string* apn_name =
        last_good_apn->FindString(shill::kApnProperty);
    ASSERT_TRUE(apn_name);
    EXPECT_EQ(expected_apn_name, *apn_name);
  }

  ui::test::internal::InteractiveTestPrivate::MultiStep CreateCustomApn(
      const std::string& apn_name,
      bool is_default,
      bool is_attach) {
    return Steps(
        Log("Open add custom APN dialog"),

        OpenAddCustomApnDetailsDialog(kOSSettingsId),

        Log("Type in custom APN name in APN dialog"),

        WaitForElementExists(kOSSettingsId,
                             settings::cellular::ApnDialogApnInput()),
        WaitForElementEnabled(kOSSettingsId,
                              settings::cellular::ApnDialogApnInput()),
        ClickElement(kOSSettingsId, settings::cellular::ApnDialogApnInput()),
        SendTextAsKeyEvents(kOSSettingsId, apn_name),

        Log("Expand advanced settings"),

        WaitForElementEnabled(
            kOSSettingsId,
            settings::cellular::ApnDialogAdvancedSettingsButton()),
        ClickElement(kOSSettingsId,
                     settings::cellular::ApnDialogAdvancedSettingsButton()),
        WaitForElementOpened(
            kOSSettingsId,
            settings::cellular::ApnDialogAdvancedSettingsGroup()),

        Log("Check APN type defaults to 'Default'"),

        WaitForElementChecked(kOSSettingsId,
                              settings::cellular::ApnDialogDefaultCheckbox()),
        WaitForElementUnchecked(kOSSettingsId,
                                settings::cellular::ApnDialogAttachCheckbox()),

        Log(base::StringPrintf("Select APN type: Default: %s, Attach: %s",
                               is_default ? "true" : "false",
                               is_attach ? "true" : "false")),

        SelectApnTypeInDialog(is_default, is_attach),

        Log("Save the custom APN"),

        WaitForElementEnabled(kOSSettingsId,
                              settings::cellular::ApnDialogAddActionButton()),
        ClickElement(kOSSettingsId,
                     settings::cellular::ApnDialogAddActionButton()),
        WaitForElementDoesNotExist(kOSSettingsId,
                                   settings::cellular::ApnDialog()));
  }

  ui::test::internal::InteractiveTestPrivate::MultiStep DisableNthApnInList(
      int n) {
    return ClickButtonInDotsMenuOfNthApnInList(
        n, settings::cellular::ApnListNthItemDisableButton(n));
  }

  ui::test::internal::InteractiveTestPrivate::MultiStep RemoveNthApnInList(
      int n) {
    return ClickButtonInDotsMenuOfNthApnInList(
        n, settings::cellular::ApnListNthItemRemoveButton(n));
  }

  ui::test::internal::InteractiveTestPrivate::MultiStep EnableNthApnInList(
      int n) {
    return ClickButtonInDotsMenuOfNthApnInList(
        n, settings::cellular::ApnListNthItemEnableButton(n));
  }

  ui::test::internal::InteractiveTestPrivate::MultiStep WaitForApnConnected(
      const std::string& apn_name) {
    return Steps(
        WaitForElementTextContains(kOSSettingsId,
                                   settings::cellular::ApnListFirstItemName(),
                                   /*text=*/apn_name),
        WaitForElementTextContains(
            kOSSettingsId, settings::cellular::ApnListFirstItemSublabel(),
            /*text=*/l10n_util::GetStringUTF8(IDS_ONC_CONNECTED).c_str()),
        Do([&]() { VerifyLastGoodApn(apn_name); }));
  }

  ui::test::internal::InteractiveTestPrivate::MultiStep
  WaitForAutoDetectedApnConnected() {
    return Steps(
        WaitForApnConnected(default_modb_apn_name()),
        WaitForElementTextContains(
            kOSSettingsId, settings::cellular::ApnListItemAutoDetectedDiv(),
            /*text=*/
            l10n_util::GetStringUTF8(IDS_SETTINGS_APN_AUTO_DETECTED).c_str()));
  }

 private:
  ui::test::internal::InteractiveTestPrivate::MultiStep
  ClickButtonInDotsMenuOfNthApnInList(
      int n,
      const WebContentsInteractionTestUtil::DeepQuery& action_button) {
    return Steps(
        WaitForElementEnabled(kOSSettingsId,
                              settings::cellular::ApnListNthItemMenuButton(n)),
        ClickElement(kOSSettingsId,
                     settings::cellular::ApnListNthItemMenuButton(n)),
        WaitForElementOpened(kOSSettingsId,
                             settings::cellular::ApnListNthItemDotsMenu(n)),
        WaitForElementEnabled(kOSSettingsId, action_button),
        ClickElement(kOSSettingsId, action_button),
        WaitForElementUnopened(kOSSettingsId,
                               settings::cellular::ApnListNthItemDotsMenu(n)));
  }

  ui::test::internal::InteractiveTestPrivate::MultiStep SelectApnTypeInDialog(
      bool select_default_type,
      bool select_attach_type) {
    if (select_default_type && !select_attach_type) {
      return Steps();
    }
    if (select_default_type && select_attach_type) {
      return Steps(
          SelectCheckbox(settings::cellular::ApnDialogAttachCheckbox()));
    }
    if (!select_default_type && select_attach_type) {
      return Steps(
          UnselectCheckbox(settings::cellular::ApnDialogDefaultCheckbox()),
          SelectCheckbox(settings::cellular::ApnDialogAttachCheckbox()));
    }
    // APN type is required.
    NOTREACHED();
  }

  ui::test::internal::InteractiveTestPrivate::MultiStep SelectCheckbox(
      const WebContentsInteractionTestUtil::DeepQuery& checkbox) {
    return Steps(WaitForElementUnchecked(kOSSettingsId, checkbox),
                 ClickElement(kOSSettingsId, checkbox),
                 WaitForElementChecked(kOSSettingsId, checkbox));
  }

  ui::test::internal::InteractiveTestPrivate::MultiStep UnselectCheckbox(
      const WebContentsInteractionTestUtil::DeepQuery& checkbox) {
    return Steps(WaitForElementChecked(kOSSettingsId, checkbox),
                 ClickElement(kOSSettingsId, checkbox),
                 WaitForElementUnchecked(kOSSettingsId, checkbox));
  }

  std::unique_ptr<SimInfo> esim_info_;
  std::string default_modb_apn_name_;

  base::test::ScopedFeatureList scoped_feature_list_;
};

IN_PROC_BROWSER_TEST_F(ApnUiInteractiveUiTest,
                       NonConnectedCellularHasNoApn) {
  ui::ElementContext context =
      LaunchSystemWebApp(SystemWebAppType::SETTINGS, kOSSettingsId);

  // Run the following steps with the OS Settings context set as the default.
  RunTestSequenceInContext(
      context,

      Log("Navigating to the internet page"),

      NavigateToInternetDetailsPage(kOSSettingsId,
                                    NetworkTypePattern::Cellular(),
                                    esim_info().nickname()),

      Log("Navigate to the APN revamp details page"),

      NavigateToApnRevampDetailsPage(kOSSettingsId),

      Log("Verify it connects to the auto detected APN"),

      WaitForAutoDetectedApnConnected(),

      Log("Disconnect cellular network"),

      Do([&]() { esim_info().Disconnect(); }),

      Log("Verify Zero state message shows and no APN shows in the list when "
          "not connected"),

      WaitForElementExists(kOSSettingsId,
                           settings::cellular::ApnSubpageZeroStateContent()),
      WaitForElementHasAttribute(
          kOSSettingsId, settings::cellular::ApnListFirstItem(), "hidden"),

      Log("Test complete"));
}

IN_PROC_BROWSER_TEST_F(ApnUiInteractiveUiTest, MultipleNetworksDefaultApn) {
  DEFINE_LOCAL_STATE_IDENTIFIER_VALUE(WaitForServiceConnectedObserver,
                                      kConnectedToCellularService);
  SimInfo esim_info1(/*id=*/1);
  ConfigureEsimProfile(euicc_info(), esim_info1, /*connected=*/false);

  ui::ElementContext context =
      LaunchSystemWebApp(SystemWebAppType::SETTINGS, kOSSettingsId);

  // Run the following steps with the OS Settings context set as the default.
  RunTestSequenceInContext(
      context,

      Log("Navigating to the internet page"),

      NavigateToInternetDetailsPage(kOSSettingsId,
                                    NetworkTypePattern::Cellular(),
                                    esim_info().nickname()),

      Log("Navigate to the APN revamp details page"),

      NavigateToApnRevampDetailsPage(kOSSettingsId),

      Log("Verify it connects to the auto detected APN"),

      WaitForAutoDetectedApnConnected(),

      Log("Navigate to the second cellular network"),

      NavigateToInternetDetailsPage(
          kOSSettingsId, NetworkTypePattern::Cellular(), esim_info1.nickname()),

      Log("Connect to the second network"),

      ObserveState(kConnectedToCellularService,
                   std::make_unique<WaitForServiceConnectedObserver>(
                       esim_info1.iccid())),
      Do([&]() { esim_info1.Connect(); }),
      WaitForState(kConnectedToCellularService, true),

      Log("Wait for the UI shows connected"),

      WaitForElementTextContains(
          kOSSettingsId, settings::SettingsSubpageNetworkState(),
          /*text=*/l10n_util::GetStringUTF8(IDS_ONC_CONNECTED).c_str()),

      Log("Navigate to the second APN revamp details page"),

      NavigateToApnRevampDetailsPage(kOSSettingsId),

      Log("Verify it connects to the auto detected APN"),

      WaitForAutoDetectedApnConnected(),

      Log("Test complete"));
}

IN_PROC_BROWSER_TEST_F(ApnUiInteractiveUiTest, CreateDefaultCustomApn) {
  ui::ElementContext context =
      LaunchSystemWebApp(SystemWebAppType::SETTINGS, kOSSettingsId);

  // Run the following steps with the OS Settings context set as the default.
  RunTestSequenceInContext(
      context,

      Log("Verify no custom APNs before start testing"),

      Do([&]() { VerifyNoCustomApnsInShill(); }),

      Log("Navigating to the internet page"),

      NavigateToInternetDetailsPage(kOSSettingsId,
                                    NetworkTypePattern::Cellular(),
                                    esim_info().nickname()),

      Log("Navigate to the APN revamp details page"),

      NavigateToApnRevampDetailsPage(kOSSettingsId),

      Log("Create default custom APN from the dialog"),

      CreateCustomApn(kDefaultCustomApnName, /*is_default=*/true,
                      /*is_attach=*/false),

      Log("Wait for the newly created custom APN appear at the top of the "
          "list"),

      WaitForElementExists(kOSSettingsId,
                           settings::cellular::ApnListFirstItem()),
      WaitForElementTextContains(kOSSettingsId,
                                 settings::cellular::ApnListFirstItemName(),
                                 /*text=*/kDefaultCustomApnName),

      Log("Verify the custom APN saved in Shill"),

      Do([&]() {
        VerifyCustomApnInShill(/*expect_exists=*/true, kDefaultCustomApnName,
                               shill::kApnTypeDefault);
      }),

      Log("Test complete"));
}

IN_PROC_BROWSER_TEST_F(ApnUiInteractiveUiTest,
                       CreateDefaultAndAttachCustomApn) {
  ui::ElementContext context =
      LaunchSystemWebApp(SystemWebAppType::SETTINGS, kOSSettingsId);

  // Run the following steps with the OS Settings context set as the default.
  RunTestSequenceInContext(
      context,

      Log("Verify no custom APNs before start testing"),

      Do([&]() { VerifyNoCustomApnsInShill(); }),

      Log("Navigating to the internet page"),

      NavigateToInternetDetailsPage(kOSSettingsId,
                                    NetworkTypePattern::Cellular(),
                                    esim_info().nickname()),

      Log("Navigate to the APN revamp details page"),

      NavigateToApnRevampDetailsPage(kOSSettingsId),

      Log("Open add custom APN dialog"),

      OpenAddCustomApnDetailsDialog(kOSSettingsId),

      Log("Type in custom APN name in APN dialog"),

      WaitForElementExists(kOSSettingsId,
                           settings::cellular::ApnDialogApnInput()),
      WaitForElementEnabled(kOSSettingsId,
                            settings::cellular::ApnDialogApnInput()),
      ClickElement(kOSSettingsId, settings::cellular::ApnDialogApnInput()),
      SendTextAsKeyEvents(kOSSettingsId, kDefaultCustomApnName),

      Log("Expand advanced settings"),

      WaitForElementEnabled(
          kOSSettingsId, settings::cellular::ApnDialogAdvancedSettingsButton()),
      ClickElement(kOSSettingsId,
                   settings::cellular::ApnDialogAdvancedSettingsButton()),
      WaitForElementOpened(
          kOSSettingsId, settings::cellular::ApnDialogAdvancedSettingsGroup()),

      Log("Check APN type defaults to 'Default'"),

      WaitForElementChecked(kOSSettingsId,
                            settings::cellular::ApnDialogDefaultCheckbox()),

      Log("Uncheck 'Default' type"),

      ClickElement(kOSSettingsId,
                   settings::cellular::ApnDialogDefaultCheckbox()),
      WaitForElementUnchecked(kOSSettingsId,
                              settings::cellular::ApnDialogDefaultCheckbox()),

      Log("Check 'Attach' type"),

      WaitForElementUnchecked(kOSSettingsId,
                              settings::cellular::ApnDialogAttachCheckbox()),
      ClickElement(kOSSettingsId,
                   settings::cellular::ApnDialogAttachCheckbox()),
      WaitForElementChecked(kOSSettingsId,
                            settings::cellular::ApnDialogAttachCheckbox()),

      Log("Check for the warning message"),

      WaitForElementExists(
          kOSSettingsId, settings::cellular::ApnDialogDefaultApnRequiredInfo()),

      Log("Check for the 'Add' button disabled"),

      WaitForElementDisabled(kOSSettingsId,
                             settings::cellular::ApnDialogAddActionButton()),

      Log("Re-check the 'Default' type"),

      ClickElement(kOSSettingsId,
                   settings::cellular::ApnDialogDefaultCheckbox()),
      WaitForElementChecked(kOSSettingsId,
                            settings::cellular::ApnDialogDefaultCheckbox()),

      Log("Save the custom APN"),

      WaitForElementEnabled(kOSSettingsId,
                            settings::cellular::ApnDialogAddActionButton()),
      ClickElement(kOSSettingsId,
                   settings::cellular::ApnDialogAddActionButton()),

      Log("Wait for the newly created custom APN appear at the top of the "
          "list"),

      WaitForElementExists(kOSSettingsId,
                           settings::cellular::ApnListFirstItem()),
      WaitForElementTextContains(kOSSettingsId,
                                 settings::cellular::ApnListFirstItemName(),
                                 /*text=*/kDefaultCustomApnName),

      Log("Wait for the custom APN connected"),

      WaitForElementTextContains(
          kOSSettingsId, settings::cellular::ApnListFirstItemSublabel(),
          /*text=*/l10n_util::GetStringUTF8(IDS_ONC_CONNECTED).c_str()),

      Log("Wait for the custom APN connected"),

      WaitForElementTextContains(
          kOSSettingsId, settings::cellular::ApnListFirstItemSublabel(),
          /*text=*/l10n_util::GetStringUTF8(IDS_ONC_CONNECTED).c_str()),

      Log("Verify the custom APN saved in Shill"),

      Do([&]() {
        VerifyCustomApnInShill(
            /*expect_exists*/ true, kDefaultCustomApnName,
            base::StringPrintf("%s,%s", shill::kApnTypeDefault,
                               shill::kApnTypeIA));
      }),

      Log("Test complete"));
}

IN_PROC_BROWSER_TEST_F(ApnUiInteractiveUiTest, DiscoverApns) {
  ui::ElementContext context =
      LaunchSystemWebApp(SystemWebAppType::SETTINGS, kOSSettingsId);

  // Run the following steps with the OS Settings context set as the default.
  RunTestSequenceInContext(
      context,

      Log("Verify no custom APNs before start testing"),

      Do([&]() { VerifyNoCustomApnsInShill(); }),

      Log("Navigating to the internet page"),

      NavigateToInternetDetailsPage(kOSSettingsId,
                                    NetworkTypePattern::Cellular(),
                                    esim_info().nickname()),

      Log("Navigate to the APN revamp details page"),

      NavigateToApnRevampDetailsPage(kOSSettingsId),

      Log("Create default custom APN from the dialog"),

      CreateCustomApn(kDefaultCustomApnName, /*is_default=*/true,
                      /*is_attach=*/false),

      Log("Wait for the newly created custom APN appear at the top of the "
          "list"),

      WaitForElementTextContains(kOSSettingsId,
                                 settings::cellular::ApnListFirstItemName(),
                                 /*text=*/kDefaultCustomApnName),

      Log("Wait for the custom APN connected"),

      WaitForApnConnected(kDefaultCustomApnName),

      Log("Open 'Show known APNs' dialog"),

      OpenApnSelectionDialog(kOSSettingsId),

      Log("Checking the name of the first APN item"),

      WaitForElementTextContains(
          kOSSettingsId, settings::cellular::ApnSelectionFirstItemName(),
          /*text=*/default_modb_apn_name()),

      Log("Select default APNs"),

      WaitForElementDisabled(kOSSettingsId,
                             settings::cellular::ApnSelectionConfirmButton()),
      ClickElement(kOSSettingsId, settings::cellular::ApnSelectionFirstItem()),
      WaitForElementEnabled(kOSSettingsId,
                            settings::cellular::ApnSelectionConfirmButton()),
      ClickElement(kOSSettingsId,
                   settings::cellular::ApnSelectionConfirmButton()),

      Log("Checking for the APN selection dialog close"),

      WaitForElementDoesNotExist(kOSSettingsId,
                                 settings::cellular::ApnSelectionDialog()),

      Log("Wait for the default APN connected"),

      WaitForApnConnected(default_modb_apn_name()),

      Log("Check the custom APN re-ordered to second APN"),

      WaitForElementTextContains(kOSSettingsId,
                                 settings::cellular::ApnListNthItemName(2),
                                 /*text=*/kDefaultCustomApnName),

      Log("Check custom APN disabled"),

      WaitForElementHasAttribute(
          kOSSettingsId, settings::cellular::ApnListNthItem(2), "is-disabled_"),

      Log("Test complete"));
}

IN_PROC_BROWSER_TEST_F(ApnUiInteractiveUiTest, EnableDisableRemoveApns) {
  ui::ElementContext context =
      LaunchSystemWebApp(SystemWebAppType::SETTINGS, kOSSettingsId);

  // Run the following steps with the OS Settings context set as the default.
  RunTestSequenceInContext(
      context,

      Log("Verify no custom APNs before start testing"),

      Do([&]() { VerifyNoCustomApnsInShill(); }),

      Log("Navigating to the internet page"),

      NavigateToInternetDetailsPage(kOSSettingsId,
                                    NetworkTypePattern::Cellular(),
                                    esim_info().nickname()),

      Log("Navigate to the APN revamp details page"),

      NavigateToApnRevampDetailsPage(kOSSettingsId),

      Log("Create a default custom APN from the dialog"),

      CreateCustomApn(kDefaultCustomApnName, /*is_default=*/true,
                      /*is_attach=*/false),

      Log("Wait for the newly created custom APN appear at the top of the "
          "list"),

      WaitForElementTextContains(kOSSettingsId,
                                 settings::cellular::ApnListFirstItemName(),
                                 /*text=*/kDefaultCustomApnName),

      Log("Wait for the default custom APN connected"),

      WaitForApnConnected(kDefaultCustomApnName),

      Log("Create a attach custom APN from the dialog"),

      CreateCustomApn(kAttachCustomApnName, /*is_default=*/false,
                      /*is_attach=*/true),

      Log("Checking for the default custom APN still connected"),

      WaitForApnConnected(kDefaultCustomApnName),

      Log("Attempt to disable Default APN"),

      DisableNthApnInList(1),

      Log("Checking for a warning toast and default APN not disabled in Shill"),

      WaitForElementTextContains(
          kOSSettingsId, settings::InternetPageErrorToastMessage(),
          l10n_util::GetStringUTF8(
              IDS_SETTINGS_APN_WARNING_PROMPT_FOR_DISABLE_REMOVE)
              .c_str()),
      Do([&]() {
        VerifyCustomApnInShill(/*expect_exists=*/true, kDefaultCustomApnName,
                               shill::kApnTypeDefault);
      }),

      Log("Attempt to remove Default APN"),

      RemoveNthApnInList(1),

      Log("Checking for a warning toast and default APN not removed in Shill"),

      WaitForElementTextContains(
          kOSSettingsId, settings::InternetPageErrorToastMessage(),
          l10n_util::GetStringUTF8(
              IDS_SETTINGS_APN_WARNING_PROMPT_FOR_DISABLE_REMOVE)
              .c_str()),
      Do([&]() {
        VerifyCustomApnInShill(/*expect_exists=*/true, kDefaultCustomApnName,
                               shill::kApnTypeDefault);
      }),

      Log("Disable Attach APN"),

      DisableNthApnInList(2),
      WaitForElementHasAttribute(
          kOSSettingsId, settings::cellular::ApnListNthItem(2), "is-disabled_"),
      Do([&]() {
        VerifyCustomApnInShill(/*expect_exists=*/false, kAttachCustomApnName,
                               shill::kApnTypeIA);
      }),

      Log("Disable Default APN"),

      DisableNthApnInList(1),

      Log("Checking for auto-detected APN popped up in the APN list"),

      WaitForAutoDetectedApnConnected(),

      Log("Checking for Default custom APN removed and Modb APN connected in "
          "Shill"),

      Do([&]() { VerifyLastGoodApn(default_modb_apn_name()); }),

      Log("Checking for both Default and Attach APNs disabled"),

      WaitForElementHasAttribute(
          kOSSettingsId, settings::cellular::ApnListNthItem(2), "is-disabled_"),
      WaitForElementHasAttribute(
          kOSSettingsId, settings::cellular::ApnListNthItem(3), "is-disabled_"),
      Do([&]() { VerifyNoCustomApnsInShill(); }),

      Log("Attempt to enable Attach APN"),

      EnableNthApnInList(2),

      Log("Checking for a warning toast"),

      WaitForElementTextContains(
          kOSSettingsId, settings::InternetPageErrorToastMessage(),
          l10n_util::GetStringUTF8(IDS_SETTINGS_APN_WARNING_PROMPT_FOR_ENABLE)
              .c_str()),
      Do([&]() {
        VerifyCustomApnInShill(/*expect_exists=*/false, kAttachCustomApnName,
                               shill::kApnTypeIA);
      }),

      Log("Enable Default APN"),

      EnableNthApnInList(3), WaitForApnConnected(kDefaultCustomApnName),
      Do([&]() {
        VerifyCustomApnInShill(/*expect_exists=*/true, kDefaultCustomApnName,
                               shill::kApnTypeDefault);
      }),

      Log("Remove Attach APN"),

      RemoveNthApnInList(2),

      Log("Remove Default APN"),

      RemoveNthApnInList(1),

      Log("Checking for auto-detected APN popped up in the APN list when "
          "there is no custom APN"),

      WaitForElementTextContains(kOSSettingsId,
                                 settings::cellular::ApnListFirstItemName(),
                                 /*text=*/default_modb_apn_name()),
      WaitForElementTextContains(
          kOSSettingsId, settings::cellular::ApnListFirstItemSublabel(),
          /*text=*/l10n_util::GetStringUTF8(IDS_ONC_CONNECTED).c_str()),
      Do([&]() { VerifyLastGoodApn(default_modb_apn_name()); }),

      Log("Checking for both custom APNs removed in Shill"),

      Do([&]() { VerifyNoCustomApnsInShill(); }),

      Log("Test complete"));
}

}  // namespace
}  // namespace ash