[go: nahoru, domu]

Add toggle UI for FloatingSso cookie sync

This CL adds an UI element for the users to be able to control the
Cookie sync behavior of the Floating SSO feature. The UI element is
only displayed when the Floating SSO feature flag is enabled and the
Floating SSO policy is enabled as well. The user's decision is
remembered in between policy changes.

This CL also registers the Cookies ModelTypeController that is needed
for the cookies UI showing up (cookiesRegistered).

Screenshot: https://screenshot.googleplex.com/7vbvJxpdwaWRQVi

Design doc(internal): go/floating-sso-dd

Bug: b:318391357, b:347263073
Change-Id: I0a46212f5fc7f3283811abe0e89bbfeabecce8b1
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5633427
Commit-Queue: Maria Petrisor <mpetrisor@chromium.org>
Reviewed-by: Marc Treib <treib@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1324187}
diff --git a/ash/constants/ash_features.cc b/ash/constants/ash_features.cc
index 8ce38a49..fb4c01e8 100644
--- a/ash/constants/ash_features.cc
+++ b/ash/constants/ash_features.cc
@@ -1173,9 +1173,9 @@
              base::FEATURE_DISABLED_BY_DEFAULT);
 
 // Controls Floating SSO feature which can move cookies between ChromeOS
-// enterprise devices. The feature is also guarded by an enterprise policy, this
-// flag controls if we are even allowed to launch the service observing that
-// policy.
+// enterprise devices. The feature is also guarded by an enterprise policy. This
+// flag controls if we are allowed to launch the service observing the policy
+// and if we show the user selectable UI when the policy is enabled.
 BASE_FEATURE(kFloatingSso, "FloatingSso", base::FEATURE_DISABLED_BY_DEFAULT);
 
 // Enables or disables Floating Workspace feature on ChromeOS
diff --git a/chrome/app/shared_settings_strings.grdp b/chrome/app/shared_settings_strings.grdp
index 1e8c254..a20d432 100644
--- a/chrome/app/shared_settings_strings.grdp
+++ b/chrome/app/shared_settings_strings.grdp
@@ -416,6 +416,9 @@
     <message name="IDS_BROWSER_SETTINGS_SYNC_FEATURE_LABEL" desc="Label describing the browser sync feature.">
       Your data will be synced across all Chrome browsers where you have turned on sync for this account. For ChromeOS sync options, go to <ph name="LINK_BEGIN">&lt;a&gt;</ph>ChromeOS settings<ph name="LINK_END">&lt;/a&gt;</ph>.
     </message>
+    <message name="IDS_SETTINGS_COOKIES_CHECKBOX_LABEL" desc="Label for the checkbox which enables or disables syncing cookies between multiple browser instances.">
+      Cookies
+    </message>
   </if>
 
   <!-- About Subpage-->
diff --git a/chrome/app/shared_settings_strings_grdp/IDS_SETTINGS_COOKIES_CHECKBOX_LABEL.png.sha1 b/chrome/app/shared_settings_strings_grdp/IDS_SETTINGS_COOKIES_CHECKBOX_LABEL.png.sha1
new file mode 100644
index 0000000..0799663
--- /dev/null
+++ b/chrome/app/shared_settings_strings_grdp/IDS_SETTINGS_COOKIES_CHECKBOX_LABEL.png.sha1
@@ -0,0 +1 @@
+96000bcab2c90e8ab861bd4b55ca51839ac42759
\ No newline at end of file
diff --git a/chrome/browser/ash/floating_sso/floating_sso_service.cc b/chrome/browser/ash/floating_sso/floating_sso_service.cc
index e697998..8cc4ee0 100644
--- a/chrome/browser/ash/floating_sso/floating_sso_service.cc
+++ b/chrome/browser/ash/floating_sso/floating_sso_service.cc
@@ -45,4 +45,9 @@
   prefs_ = nullptr;
 }
 
+base::WeakPtr<syncer::ModelTypeControllerDelegate>
+FloatingSsoService::GetControllerDelegate() {
+  return bridge_.change_processor()->GetControllerDelegate();
+}
+
 }  // namespace ash::floating_sso
diff --git a/chrome/browser/ash/floating_sso/floating_sso_service.h b/chrome/browser/ash/floating_sso/floating_sso_service.h
index 33a8c2d3..f9b3715 100644
--- a/chrome/browser/ash/floating_sso/floating_sso_service.h
+++ b/chrome/browser/ash/floating_sso/floating_sso_service.h
@@ -14,6 +14,7 @@
 
 namespace syncer {
 class ModelTypeChangeProcessor;
+class ModelTypeControllerDelegate;
 }  // namespace syncer
 
 class PrefService;
@@ -33,6 +34,8 @@
   // KeyedService:
   void Shutdown() override;
 
+  base::WeakPtr<syncer::ModelTypeControllerDelegate> GetControllerDelegate();
+
   // TODO: b/346354327 - temporary flag used for testing. Remove after
   // actual behavior is implemented.
   bool is_enabled_for_testing_ = false;
diff --git a/chrome/browser/resources/settings/people_page/sync_controls.html b/chrome/browser/resources/settings/people_page/sync_controls.html
index 9a6ccdf28..0cd5421 100644
--- a/chrome/browser/resources/settings/people_page/sync_controls.html
+++ b/chrome/browser/resources/settings/people_page/sync_controls.html
@@ -255,6 +255,23 @@
       </div>
 
 <if expr="chromeos_ash">
+      <div class="list-item" id="cookiesSyncItem" hidden="[[hideCookieItem_(
+        syncStatus.syncCookiesSupported, syncPrefs.cookiesRegistered)]]">
+        <div>
+          $i18n{cookiesCheckboxLabel}
+        </div>
+        <cr-policy-indicator indicator-type="userPolicy"
+            hidden="[[!syncPrefs.cookiesManaged]]">
+        </cr-policy-indicator>
+        <cr-toggle id="cookiesCheckbox"
+            checked="{{syncPrefs.cookiesSynced}}"
+            on-change="onSingleSyncDataTypeChanged_"
+            disabled="[[disableTypeCheckBox_(
+                syncPrefs.syncAllDataTypes, syncPrefs.cookiesManaged)]]"
+            aria-label="$i18n{cookiesCheckboxLabel}">
+        </cr-toggle>
+      </div>
+
       <div class="list-item"
            hidden="[[!syncPrefs.wifiConfigurationsRegistered]]">
         <div id="wifiConfigurationsCheckboxLabel">
diff --git a/chrome/browser/resources/settings/people_page/sync_controls.ts b/chrome/browser/resources/settings/people_page/sync_controls.ts
index 0d67851..6227bb9 100644
--- a/chrome/browser/resources/settings/people_page/sync_controls.ts
+++ b/chrome/browser/resources/settings/people_page/sync_controls.ts
@@ -208,6 +208,13 @@
     return syncAllDataTypes || dataTypeManaged;
   }
 
+  // <if expr="chromeos_ash">
+  private hideCookieItem_(
+      syncCookiesSupported: boolean, cookiesRegistered: boolean): boolean {
+    return !syncCookiesSupported || !cookiesRegistered;
+  }
+  // </if>
+
   private syncStatusChanged_() {
     const router = Router.getInstance();
     const routes = router.getRoutes() as {SYNC: Route, SYNC_ADVANCED: Route};
diff --git a/chrome/browser/resources/settings_shared/people_page/sync_browser_proxy.ts b/chrome/browser/resources/settings_shared/people_page/sync_browser_proxy.ts
index fdf1533..96402c12 100644
--- a/chrome/browser/resources/settings_shared/people_page/sync_browser_proxy.ts
+++ b/chrome/browser/resources/settings_shared/people_page/sync_browser_proxy.ts
@@ -47,6 +47,7 @@
   statusActionText?: string;
   statusText?: string;
   supervisedUser?: boolean;
+  syncCookiesSupported?: boolean;
   syncSystemEnabled?: boolean;
 }
 
@@ -81,6 +82,9 @@
   bookmarksManaged: boolean;
   bookmarksRegistered: boolean;
   bookmarksSynced: boolean;
+  cookiesManaged: boolean;
+  cookiesRegistered: boolean;
+  cookiesSynced: boolean;
   customPassphraseAllowed: boolean;
   encryptAllData: boolean;
   extensionsManaged: boolean;
@@ -127,6 +131,7 @@
   'appsSynced',
   'autofillSynced',
   'bookmarksSynced',
+  'cookiesSynced',
   'extensionsSynced',
   'readingListSynced',
   'passwordsSynced',
diff --git a/chrome/browser/sync/BUILD.gn b/chrome/browser/sync/BUILD.gn
index bb6c3b3..75af3dd 100644
--- a/chrome/browser/sync/BUILD.gn
+++ b/chrome/browser/sync/BUILD.gn
@@ -165,6 +165,7 @@
       "//chrome/browser/ash/arc",
       "//chrome/browser/ash/arc/tracing",
       "//chrome/browser/ash/crosapi:browser_util",
+      "//chrome/browser/ash/floating_sso",
       "//chrome/browser/ash/guest_os",
       "//chrome/browser/ash/printing/oauth2",
       "//chromeos/ash/components/network",
diff --git a/chrome/browser/sync/chrome_sync_client.cc b/chrome/browser/sync/chrome_sync_client.cc
index ff7d9fc..65cdf63 100644
--- a/chrome/browser/sync/chrome_sync_client.cc
+++ b/chrome/browser/sync/chrome_sync_client.cc
@@ -138,6 +138,8 @@
 #include "chrome/browser/ash/app_list/arc/arc_package_syncable_service.h"
 #include "chrome/browser/ash/arc/arc_util.h"
 #include "chrome/browser/ash/crosapi/browser_util.h"
+#include "chrome/browser/ash/floating_sso/floating_sso_service.h"
+#include "chrome/browser/ash/floating_sso/floating_sso_service_factory.h"
 #include "chrome/browser/ash/printing/oauth2/authorization_zones_manager.h"
 #include "chrome/browser/ash/printing/oauth2/authorization_zones_manager_factory.h"
 #include "chrome/browser/ash/printing/printers_sync_bridge.h"
@@ -671,6 +673,19 @@
             printers_authorization_servers_delegate),
         /*delegate_for_transport_mode=*/nullptr));
   }
+
+  if (ash::features::IsFloatingSsoAllowed()) {
+    syncer::ModelTypeControllerDelegate* cookies_delegate =
+        ash::floating_sso::FloatingSsoServiceFactory::GetForProfile(profile_)
+            ->GetControllerDelegate()
+            .get();
+    controllers.push_back(std::make_unique<syncer::ModelTypeController>(
+        syncer::COOKIES,
+        /*delegate_for_full_sync_mode=*/
+        std::make_unique<syncer::ForwardingModelTypeControllerDelegate>(
+            cookies_delegate),
+        /*delegate_for_transport_mode=*/nullptr));
+  }
 #endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
   return controllers;
diff --git a/chrome/browser/ui/webui/settings/people_handler.cc b/chrome/browser/ui/webui/settings/people_handler.cc
index ebee41e..54531eb 100644
--- a/chrome/browser/ui/webui/settings/people_handler.cc
+++ b/chrome/browser/ui/webui/settings/people_handler.cc
@@ -42,6 +42,7 @@
 #include "chrome/browser/ui/singleton_tabs.h"
 #include "chrome/browser/ui/webui/signin/login_ui_service.h"
 #include "chrome/browser/ui/webui/signin/login_ui_service_factory.h"
+#include "chrome/common/pref_names.h"
 #include "chrome/common/url_constants.h"
 #include "chrome/common/webui_url_constants.h"
 #include "chrome/grit/generated_resources.h"
@@ -73,6 +74,10 @@
 #include "ui/base/webui/web_ui_util.h"
 #include "ui/gfx/image/image.h"
 
+#if BUILDFLAG(IS_CHROMEOS_ASH)
+#include "ash/constants/ash_features.h"
+#endif
+
 #if !BUILDFLAG(IS_CHROMEOS_ASH)
 #include "chrome/browser/ui/webui/profile_helper.h"
 #endif
@@ -1127,6 +1132,12 @@
                   signin_ui_util::GetAuthenticatedUsername(profile_));
   sync_status.Set("hasUnrecoverableError",
                   service && service->HasUnrecoverableError());
+#if BUILDFLAG(IS_CHROMEOS_ASH)
+  if (ash::features::IsFloatingSsoAllowed()) {
+    sync_status.Set("syncCookiesSupported", profile_->GetPrefs()->GetBoolean(
+                                                prefs::kFloatingSsoEnabled));
+  }
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
   return sync_status;
 }
 
diff --git a/chrome/browser/ui/webui/settings/people_handler.h b/chrome/browser/ui/webui/settings/people_handler.h
index 7130691a..73d9d292 100644
--- a/chrome/browser/ui/webui/settings/people_handler.h
+++ b/chrome/browser/ui/webui/settings/people_handler.h
@@ -121,6 +121,7 @@
                            DashboardClearWhileSettingsOpen_ConfirmLater);
   FRIEND_TEST_ALL_PREFIXES(PeopleHandlerDiceTest, StoredAccountsList);
   FRIEND_TEST_ALL_PREFIXES(PeopleHandlerGuestModeTest, GetStoredAccountsList);
+  FRIEND_TEST_ALL_PREFIXES(PeopleHandlerTest, SyncCookiesDisabled);
   FRIEND_TEST_ALL_PREFIXES(PeopleHandlerTest, TurnOffSync);
   FRIEND_TEST_ALL_PREFIXES(PeopleHandlerTest, GetStoredAccountsList);
   FRIEND_TEST_ALL_PREFIXES(PeopleHandlerMainProfile, Signout);
@@ -130,6 +131,8 @@
                            GetStoredAccountsList);
   FRIEND_TEST_ALL_PREFIXES(PeopleHandlerWebOnlySigninTest,
                            ChromeSigninUserAvailableOnWebSignin);
+  FRIEND_TEST_ALL_PREFIXES(PeopleHandlerWithCookiesSyncTest,
+                           SyncCookiesSupported);
 #if DCHECK_IS_ON()
   FRIEND_TEST_ALL_PREFIXES(PeopleHandlerMainProfile, DeleteProfileCrashes);
 #endif
diff --git a/chrome/browser/ui/webui/settings/people_handler_unittest.cc b/chrome/browser/ui/webui/settings/people_handler_unittest.cc
index b046e2d89..e0ba5dde 100644
--- a/chrome/browser/ui/webui/settings/people_handler_unittest.cc
+++ b/chrome/browser/ui/webui/settings/people_handler_unittest.cc
@@ -71,6 +71,10 @@
 #include "services/network/test/test_url_loader_factory.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
+#if BUILDFLAG(IS_CHROMEOS_ASH)
+#include "ash/constants/ash_features.h"
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
+
 namespace {
 
 using signin::ConsentLevel;
@@ -168,6 +172,8 @@
                    types.Has(syncer::UserSelectableType::kAutofill));
   ExpectHasBoolKey(dictionary, "bookmarksSynced",
                    types.Has(syncer::UserSelectableType::kBookmarks));
+  ExpectHasBoolKey(dictionary, "cookiesSynced",
+                   types.Has(syncer::UserSelectableType::kCookies));
   ExpectHasBoolKey(dictionary, "extensionsSynced",
                    types.Has(syncer::UserSelectableType::kExtensions));
   ExpectHasBoolKey(dictionary, "passwordsSynced",
@@ -369,6 +375,7 @@
   TestWebUIProvider test_provider_;
   std::unique_ptr<TestChromeWebUIControllerFactory> test_factory_;
   std::unique_ptr<TestingPeopleHandler> handler_;
+  base::test::ScopedFeatureList feature_list_;
 };
 
 #if !BUILDFLAG(IS_CHROMEOS_ASH)
@@ -754,6 +761,7 @@
   ExpectHasBoolKey(dictionary, "appsRegistered", true);
   ExpectHasBoolKey(dictionary, "autofillRegistered", true);
   ExpectHasBoolKey(dictionary, "bookmarksRegistered", true);
+  ExpectHasBoolKey(dictionary, "cookiesRegistered", true);
   ExpectHasBoolKey(dictionary, "extensionsRegistered", true);
   ExpectHasBoolKey(dictionary, "passwordsRegistered", true);
   ExpectHasBoolKey(dictionary, "paymentsRegistered", true);
@@ -1268,6 +1276,23 @@
   ASSERT_EQ(1u, accounts.size());
   EXPECT_EQ("user@gmail.com", *accounts[0].GetDict().FindString("email"));
 }
+
+TEST_F(PeopleHandlerTest, SyncCookiesDisabled) {
+  base::test::ScopedFeatureList features;
+  // Disable Floating SSO feature flag.
+  features.InitWithFeatures(
+      /*enabled_features=*/{},
+      /*disabled_features=*/{ash::features::kFloatingSso});
+
+  SigninUserAndTurnSyncFeatureOn();
+  CreatePeopleHandler();
+
+  const base::Value::Dict& sync_status_values =
+      handler_->GetSyncStatusDictionary();
+  std::optional<bool> sync_cookies_supported =
+      sync_status_values.FindBool("syncCookiesSupported");
+  EXPECT_FALSE(sync_cookies_supported.has_value());
+}
 #endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
 #if BUILDFLAG(ENABLE_DICE_SUPPORT)
@@ -2064,4 +2089,51 @@
   EXPECT_FALSE(identity_manager()->HasPrimaryAccount(ConsentLevel::kSignin));
 }
 #endif  // BUILDFLAG(ENABLE_DICE_SUPPORT)
+
+#if BUILDFLAG(IS_CHROMEOS_ASH)
+class PeopleHandlerWithCookiesSyncTest : public PeopleHandlerTest {
+ private:
+  // Enable Floating SSO feature flag.
+  base::test::ScopedFeatureList features_{ash::features::kFloatingSso};
+};
+
+TEST_F(PeopleHandlerWithCookiesSyncTest, SyncCookiesSupported) {
+  SigninUserAndTurnSyncFeatureOn();
+  CreatePeopleHandler();
+
+  // Feature flag enabled, policy unset.
+  {
+    const base::Value::Dict& sync_status_values =
+        handler_->GetSyncStatusDictionary();
+    std::optional<bool> sync_cookies_supported =
+        sync_status_values.FindBool("syncCookiesSupported");
+    ASSERT_TRUE(sync_cookies_supported.has_value());
+    EXPECT_FALSE(sync_cookies_supported.value());
+  }
+
+  // Feature flag enabled, policy set to false.
+  {
+    profile()->GetPrefs()->SetBoolean(prefs::kFloatingSsoEnabled, false);
+
+    const base::Value::Dict& sync_status_values =
+        handler_->GetSyncStatusDictionary();
+    std::optional<bool> sync_cookies_supported =
+        sync_status_values.FindBool("syncCookiesSupported");
+    ASSERT_TRUE(sync_cookies_supported.has_value());
+    EXPECT_FALSE(sync_cookies_supported.value());
+  }
+
+  // Feature flag enabled, policy set to true.
+  {
+    profile()->GetPrefs()->SetBoolean(prefs::kFloatingSsoEnabled, true);
+
+    const base::Value::Dict& sync_status_values =
+        handler_->GetSyncStatusDictionary();
+    std::optional<bool> sync_cookies_supported =
+        sync_status_values.FindBool("syncCookiesSupported");
+    ASSERT_TRUE(sync_cookies_supported.has_value());
+    EXPECT_TRUE(sync_cookies_supported.value());
+  }
+}
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 }  // namespace settings
diff --git a/chrome/browser/ui/webui/settings/settings_localized_strings_provider.cc b/chrome/browser/ui/webui/settings/settings_localized_strings_provider.cc
index 5d0a0a9..99825fe 100644
--- a/chrome/browser/ui/webui/settings/settings_localized_strings_provider.cc
+++ b/chrome/browser/ui/webui/settings/settings_localized_strings_provider.cc
@@ -1549,6 +1549,9 @@
 #if BUILDFLAG(IS_CHROMEOS)
       {"browserSyncFeatureLabel", IDS_BROWSER_SETTINGS_SYNC_FEATURE_LABEL},
 #endif
+#if BUILDFLAG(IS_CHROMEOS_ASH)
+      {"cookiesCheckboxLabel", IDS_SETTINGS_COOKIES_CHECKBOX_LABEL},
+#endif
   };
   html_source->AddLocalizedStrings(kLocalizedStrings);
 
diff --git a/chrome/test/data/webui/chromeos/settings/os_people_page/os_people_page_test.ts b/chrome/test/data/webui/chromeos/settings/os_people_page/os_people_page_test.ts
index 3b7cc0a..735c742 100644
--- a/chrome/test/data/webui/chromeos/settings/os_people_page/os_people_page_test.ts
+++ b/chrome/test/data/webui/chromeos/settings/os_people_page/os_people_page_test.ts
@@ -170,6 +170,9 @@
         bookmarksManaged: false,
         bookmarksRegistered: false,
         bookmarksSynced: false,
+        cookiesManaged: false,
+        cookiesRegistered: false,
+        cookiesSynced: false,
         encryptAllData: false,
         extensionsManaged: false,
         extensionsRegistered: false,
diff --git a/chrome/test/data/webui/chromeos/settings/os_privacy_page/os_privacy_page_test.ts b/chrome/test/data/webui/chromeos/settings/os_privacy_page/os_privacy_page_test.ts
index 096961f..0a2d08b 100644
--- a/chrome/test/data/webui/chromeos/settings/os_privacy_page/os_privacy_page_test.ts
+++ b/chrome/test/data/webui/chromeos/settings/os_privacy_page/os_privacy_page_test.ts
@@ -81,6 +81,9 @@
       bookmarksManaged: false,
       bookmarksRegistered: false,
       bookmarksSynced: false,
+      cookiesManaged: false,
+      cookiesRegistered: false,
+      cookiesSynced: false,
       encryptAllData: false,
       extensionsManaged: false,
       extensionsRegistered: false,
diff --git a/chrome/test/data/webui/settings/people_page_sync_controls_test.ts b/chrome/test/data/webui/settings/people_page_sync_controls_test.ts
index d9aa4c5d..bc24579e 100644
--- a/chrome/test/data/webui/settings/people_page_sync_controls_test.ts
+++ b/chrome/test/data/webui/settings/people_page_sync_controls_test.ts
@@ -181,6 +181,52 @@
     // Controls are available when there is a passphrase error.
     assertFalse(syncControls.hidden);
   });
+
+  // <if expr="chromeos_ash">
+  test('SyncCookiesSupported', async function() {
+    // Sync everything enabled.
+    assertTrue(syncEverything.checked);
+    assertFalse(customizeSync.checked);
+
+    // The cookies element is not visible when syncCookiesSupported is disabled
+    // (default).
+    let cookieListItem = syncControls.shadowRoot!.querySelector(
+        '#cookiesSyncItem:not([hidden])');
+    assertFalse(!!cookieListItem);
+
+    // Enable syncCookiesSupported.
+    syncControls.syncStatus = {
+      disabled: false,
+      hasError: false,
+      signedInState: SignedInState.SYNCING,
+      statusAction: StatusAction.NO_ACTION,
+      syncCookiesSupported: true,
+    };
+    // The cookies element is now visible.
+    cookieListItem = syncControls.shadowRoot!.querySelector(
+        '#cookiesSyncItem:not([hidden])');
+    assertTrue(!!cookieListItem);
+    // Cookies checkbox is disabled.
+    let cookiesCheckbox: CrToggleElement =
+        syncControls.shadowRoot!.querySelector('#cookiesCheckbox')!;
+    assertTrue(!!cookiesCheckbox);
+    assertTrue(cookiesCheckbox.disabled);
+    assertTrue(cookiesCheckbox.checked);
+
+    // Customize sync enabled.
+    customizeSync.click();
+    await eventToPromise('selected-changed', radioGroup);
+    assertFalse(syncEverything.checked);
+    assertTrue(customizeSync.checked);
+
+    // Cookies checkbox is enabled.
+    cookiesCheckbox =
+        syncControls.shadowRoot!.querySelector('#cookiesCheckbox')!;
+    assertTrue(!!cookiesCheckbox);
+    assertFalse(cookiesCheckbox.disabled);
+    assertTrue(cookiesCheckbox.checked);
+  });
+  // </if>
 });
 
 suite('SyncControlsSubpageTest', function() {
@@ -247,7 +293,7 @@
 // Test to check that toggles are disabled when sync types are managed by
 // policy.
 suite('SyncControlsManagedTest', async function() {
-  let syncControls: HTMLElement;
+  let syncControls: SettingsSyncControlsElement;
   let browserProxy: TestSyncBrowserProxy;
   let syncEverything: CrRadioButtonElement;
   let customizeSync: CrRadioButtonElement;
@@ -263,6 +309,14 @@
 
     // Start with all prefs managed.
     webUIListenerCallback('sync-prefs-changed', getSyncAllPrefsManaged());
+    // Enable Cookie sync.
+    syncControls.syncStatus = {
+      disabled: false,
+      hasError: false,
+      signedInState: SignedInState.SYNCING,
+      statusAction: StatusAction.NO_ACTION,
+      syncCookiesSupported: true,
+    };
     flush();
 
     await waitBeforeNextRender(syncControls);
diff --git a/chrome/test/data/webui/settings/sync_test_util.ts b/chrome/test/data/webui/settings/sync_test_util.ts
index 1c8b912..699a455 100644
--- a/chrome/test/data/webui/settings/sync_test_util.ts
+++ b/chrome/test/data/webui/settings/sync_test_util.ts
@@ -22,6 +22,9 @@
     bookmarksManaged: false,
     bookmarksRegistered: true,
     bookmarksSynced: true,
+    cookiesManaged: false,
+    cookiesRegistered: true,
+    cookiesSynced: true,
     encryptAllData: false,
     customPassphraseAllowed: true,
     extensionsManaged: false,
@@ -69,6 +72,8 @@
     autofillSynced: false,
     bookmarksManaged: true,
     bookmarksSynced: false,
+    cookiesManaged: true,
+    cookiesSynced: false,
     extensionsManaged: true,
     extensionsSynced: false,
     passwordsManaged: true,
diff --git a/components/sync/base/user_selectable_type.cc b/components/sync/base/user_selectable_type.cc
index 83f0b3d..94c418e0 100644
--- a/components/sync/base/user_selectable_type.cc
+++ b/components/sync/base/user_selectable_type.cc
@@ -190,6 +190,9 @@
   if (type == kProductComparisonTypeName) {
     return UserSelectableType::kProductComparison;
   }
+  if (type == kCookiesTypeName) {
+    return UserSelectableType::kCookies;
+  }
   return std::nullopt;
 }
 
diff --git a/components/sync/service/model_type_controller.cc b/components/sync/service/model_type_controller.cc
index 8263106..ff4ceca1 100644
--- a/components/sync/service/model_type_controller.cc
+++ b/components/sync/service/model_type_controller.cc
@@ -114,7 +114,8 @@
     // full-sync mode, never transport-mode. So for data types that only exist
     // on this platform, it doesn't matter if they support transport mode or not
     // (this includes PRINTERS, WIFI_CONFIGURATIONS, OS_PREFERENCES,
-    // OS_PRIORITY_PREFERENCES, WORKSPACE_DESK, PRINTERS_AUTHORIZATION_SERVERS).
+    // OS_PRIORITY_PREFERENCES, WORKSPACE_DESK, PRINTERS_AUTHORIZATION_SERVERS,
+    // COOKIES).
     //
     // All other data types listed here will likely have to be migrated.
     static constexpr ModelTypeSet kLegacyTypes = {
@@ -146,7 +147,8 @@
         HISTORY,
         PRINTERS_AUTHORIZATION_SERVERS,
         POWER_BOOKMARK,
-        NIGORI};
+        NIGORI,
+        COOKIES};
     CHECK(kLegacyTypes.Has(type()))
         << ModelTypeToDebugString(type())
         << " must support running in transport mode!";