chromium/chrome/browser/ui/views/profiles/profile_picker_view_browsertest.cc

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

#include "chrome/browser/ui/views/profiles/profile_picker_view.h"

#include <optional>
#include <set>

#include "base/barrier_closure.h"
#include "base/cfi_buildflags.h"
#include "base/files/file_path.h"
#include "base/json/values_util.h"
#include "base/memory/raw_ptr.h"
#include "base/run_loop.h"
#include "base/test/bind.h"
#include "base/test/metrics/histogram_tester.h"
#include "base/test/metrics/user_action_tester.h"
#include "base/test/mock_callback.h"
#include "base/test/scoped_feature_list.h"
#include "base/test/test_future.h"
#include "base/time/time.h"
#include "base/values.h"
#include "build/build_config.h"
#include "build/chromeos_buildflags.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/chrome_browser_main.h"
#include "chrome/browser/chrome_browser_main_extra_parts.h"
#include "chrome/browser/enterprise/util/managed_browser_utils.h"
#include "chrome/browser/feature_engagement/tracker_factory.h"
#include "chrome/browser/interstitials/chrome_settings_page_helper.h"
#include "chrome/browser/lifetime/browser_shutdown.h"
#include "chrome/browser/metrics/first_web_contents_profiler_base.h"
#include "chrome/browser/policy/cloud/user_policy_signin_service.h"
#include "chrome/browser/policy/cloud/user_policy_signin_service_factory.h"
#include "chrome/browser/policy/cloud/user_policy_signin_service_test_util.h"
#include "chrome/browser/policy/profile_policy_connector.h"
#include "chrome/browser/policy/profile_policy_connector_builder.h"
#include "chrome/browser/profiles/keep_alive/profile_keep_alive_types.h"
#include "chrome/browser/profiles/nuke_profile_directory_utils.h"
#include "chrome/browser/profiles/profile_attributes_entry.h"
#include "chrome/browser/profiles/profile_attributes_storage.h"
#include "chrome/browser/profiles/profile_manager.h"
#include "chrome/browser/profiles/profile_test_util.h"
#include "chrome/browser/profiles/profiles_state.h"
#include "chrome/browser/signin/chrome_signin_client_factory.h"
#include "chrome/browser/signin/chrome_signin_client_test_util.h"
#include "chrome/browser/signin/identity_manager_factory.h"
#include "chrome/browser/signin/signin_promo.h"
#include "chrome/browser/signin/signin_util.h"
#include "chrome/browser/sync/sync_service_factory.h"
#include "chrome/browser/sync/sync_startup_tracker.h"
#include "chrome/browser/themes/theme_service.h"
#include "chrome/browser/themes/theme_service_factory.h"
#include "chrome/browser/trusted_vault/trusted_vault_encryption_keys_tab_helper.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_commands.h"
#include "chrome/browser/ui/browser_finder.h"
#include "chrome/browser/ui/browser_list.h"
#include "chrome/browser/ui/profiles/profile_customization_util.h"
#include "chrome/browser/ui/profiles/profile_ui_test_utils.h"
#include "chrome/browser/ui/startup/first_run_service.h"
#include "chrome/browser/ui/tab_dialogs.h"
#include "chrome/browser/ui/views/profiles/avatar_toolbar_button.h"
#include "chrome/browser/ui/views/profiles/profile_picker_dice_reauth_provider.h"
#include "chrome/browser/ui/views/profiles/profile_picker_test_base.h"
#include "chrome/browser/ui/views/user_education/browser_feature_promo_controller.h"
#include "chrome/browser/ui/webui/signin/login_ui_service.h"
#include "chrome/browser/ui/webui/signin/login_ui_service_factory.h"
#include "chrome/browser/ui/webui/signin/managed_user_profile_notice_handler.h"
#include "chrome/browser/ui/webui/signin/managed_user_profile_notice_ui.h"
#include "chrome/browser/ui/webui/signin/profile_customization_handler.h"
#include "chrome/browser/ui/webui/signin/profile_customization_ui.h"
#include "chrome/browser/ui/webui/signin/profile_picker_handler.h"
#include "chrome/browser/ui/webui/signin/profile_picker_ui.h"
#include "chrome/browser/ui/webui/signin/signin_url_utils.h"
#include "chrome/browser/ui/webui/signin/signin_utils.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/pref_names.h"
#include "chrome/common/webui_url_constants.h"
#include "chrome/test/base/in_process_browser_test.h"
#include "chrome/test/base/profile_deletion_observer.h"
#include "chrome/test/base/profile_destruction_waiter.h"
#include "chrome/test/base/ui_test_utils.h"
#include "chrome/test/user_education/interactive_feature_promo_test.h"
#include "components/feature_engagement/public/feature_constants.h"
#include "components/feature_engagement/public/tracker.h"
#include "components/keyed_service/content/browser_context_dependency_manager.h"
#include "components/policy/core/browser/browser_policy_connector.h"
#include "components/policy/core/common/mock_configuration_policy_provider.h"
#include "components/policy/policy_constants.h"
#include "components/prefs/pref_service.h"
#include "components/signin/public/base/signin_buildflags.h"
#include "components/signin/public/base/signin_metrics.h"
#include "components/signin/public/base/signin_switches.h"
#include "components/signin/public/identity_manager/account_info.h"
#include "components/signin/public/identity_manager/identity_manager.h"
#include "components/signin/public/identity_manager/identity_test_utils.h"
#include "components/signin/public/identity_manager/primary_account_mutator.h"
#include "components/sync/base/pref_names.h"
#include "components/sync/service/sync_service.h"
#include "components/sync/service/sync_user_settings.h"
#include "components/sync/test/test_sync_service.h"
#include "content/public/browser/web_contents.h"
#include "content/public/test/browser_test.h"
#include "content/public/test/browser_test_utils.h"
#include "content/public/test/test_launcher.h"
#include "content/public/test/test_navigation_observer.h"
#include "extensions/common/extension_id.h"
#include "google_apis/gaia/gaia_urls.h"
#include "google_apis/gaia/google_service_auth_error.h"
#include "services/network/test/test_url_loader_factory.h"
#include "third_party/skia/include/core/SkColor.h"
#include "ui/base/accelerators/accelerator.h"
#include "ui/events/event_constants.h"
#include "ui/views/widget/widget_delegate.h"
#include "url/gurl.h"

#if BUILDFLAG(IS_MAC)
#include "chrome/browser/enterprise/browser_management/management_service_factory.h"
#include "components/policy/core/common/management/management_service.h"
#include "components/policy/core/common/management/scoped_management_service_override_for_testing.h"
#elif BUILDFLAG(IS_CHROMEOS_LACROS)
#include "chrome/browser/lacros/account_manager/fake_account_manager_ui_dialog_waiter.h"
#include "components/account_manager_core/chromeos/account_manager.h"
#include "components/account_manager_core/chromeos/account_manager_facade_factory.h"
#include "components/account_manager_core/chromeos/account_manager_mojo_service.h"
#endif  // BUILDFLAG(IS_CHROMEOS_LACROS)

#if BUILDFLAG(ENABLE_DICE_SUPPORT)
#include "chrome/browser/signin/dice_tab_helper.h"
#include "chrome/browser/signin/process_dice_header_delegate_impl.h"
#endif

namespace {
const SkColor kProfileColor =;

// State of the the ForceEphemeralProfiles policy.
enum class ForceEphemeralProfilesPolicy {};

const char16_t kOriginalProfileName[] =;
const char kGaiaId[] =;

#if !BUILDFLAG(IS_CHROMEOS_LACROS)
const char16_t kWork[] =;
#endif  // !BUILDFLAG(IS_CHROMEOS_LACROS)

#if !BUILDFLAG(IS_LINUX) && !BUILDFLAG(IS_CHROMEOS)
const char kReauthResultHistogramName[] = "ProfilePicker.ReauthResult";
#endif

AccountInfo FillAccountInfo(
    const CoreAccountInfo& core_info,
    const std::string& given_name,
    const std::string& hosted_domain = kNoHostedDomainFound) {}

GURL GetSyncConfirmationURL() {}

class BrowserAddedWaiter : public BrowserListObserver {};

class TestTabDialogs : public TabDialogs {};

class PageNonEmptyPaintObserver : public content::WebContentsObserver {};

// Waits for a first non empty paint for `target` and expects that it will load
// the given `url`.
void WaitForFirstNonEmptyPaint(const GURL& url, content::WebContents* target) {}

}  // namespace

class ProfilePickerViewBrowserTest : public ProfilePickerTestBase {};

// Regression test for crbug.com/1442159.
IN_PROC_BROWSER_TEST_F(ProfilePickerViewBrowserTest,
                       ShowScreen_DoesNotFinishForErrorOnInternalNavigation) {}

// Regression test for crbug.com/1442159.
IN_PROC_BROWSER_TEST_F(ProfilePickerViewBrowserTest,
                       ShowScreen_FinishesForErrorOnStandardNavigation) {}

class ProfilePickerCreationFlowBrowserTest
    : public InteractiveFeaturePromoTestT<ProfilePickerTestBase> {};

IN_PROC_BROWSER_TEST_F(ProfilePickerCreationFlowBrowserTest, ShowPicker) {}

IN_PROC_BROWSER_TEST_F(ProfilePickerCreationFlowBrowserTest, ShowChoice) {}

IN_PROC_BROWSER_TEST_F(ProfilePickerCreationFlowBrowserTest,
                       CreateSignedInProfile) {}

// Regression test for https://crbug.com/1431342
IN_PROC_BROWSER_TEST_F(ProfilePickerCreationFlowBrowserTest,
                       CreateSignedInProfileClosePicker) {}

#if !BUILDFLAG(IS_CHROMEOS_LACROS)
// TODO(crbug.com/40868761): Test is flaky on Linux and Windows.
#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_WIN)
#define MAYBE_CreateForceSignedInProfile
#else
#define MAYBE_CreateForceSignedInProfile
#endif
IN_PROC_BROWSER_TEST_F(ProfilePickerCreationFlowBrowserTest,
                       MAYBE_CreateForceSignedInProfile) {}

// Force signin is disabled on Linux and ChromeOS.
// TODO(crbug.com/40235093): enable this test when enabling force sign in
// on Linux.
#if !BUILDFLAG(IS_LINUX) && !BUILDFLAG(IS_CHROMEOS)
class ForceSigninProfilePickerCreationFlowBrowserTest
    : public ProfilePickerCreationFlowBrowserTest {
 public:
  explicit ForceSigninProfilePickerCreationFlowBrowserTest(
      bool force_signin_enabled = true)
      : force_signin_setter_(force_signin_enabled) {}

  void SimulateSuccesfulSignin(signin::IdentityManager* identity_manager,
                               const std::string& email) {
    // Simulate a successful reauth by making the account available.
    signin::MakeAccountAvailable(identity_manager, email);
  }

  bool IsForceSigninErrorDialogShown() {
    // Make sure the profile picker is opened, with the main profile picker view
    // (where the dialog can be shown), and the page is fully loaded.
    EXPECT_TRUE(ProfilePicker::IsOpen());
    const GURL main_profile_picker_url("chrome://profile-picker");
    EXPECT_EQ(web_contents()->GetURL().GetWithEmptyPath(),
              main_profile_picker_url);
    WaitForLoadStop(main_profile_picker_url);

    return content::EvalJs(
               web_contents(),
               // Get down to the `forceSigninErrorDialog` cr-dialog node and
               // check the `open` field.
               "document.body.getElementsByTagName('profile-picker-app')[0]."
               "shadowRoot.getElementById('mainView').shadowRoot."
               "getElementById(\""
               "forceSigninErrorDialog\").open")
        .ExtractBool();
  }

  base::HistogramTester* histogram_tester() { return &histogram_tester_; }

 private:
  signin_util::ScopedForceSigninSetterForTesting force_signin_setter_;
  base::HistogramTester histogram_tester_;
};

IN_PROC_BROWSER_TEST_F(ForceSigninProfilePickerCreationFlowBrowserTest,
                       ForceSigninSuccessful) {
  size_t initial_browser_count = BrowserList::GetInstance()->size();
  // Create a new signin flow, sign-in, and wait for the Sync Comfirmation
  // promo.
  Profile* force_sign_in_profile =
      SignInForNewProfile(GetSyncConfirmationURL(), "[email protected]",
                          "Joe", kNoHostedDomainFound, true);
  // No browser for the created profile exist yet.
  ASSERT_EQ(chrome::GetBrowserCount(force_sign_in_profile), 0u);
  ASSERT_TRUE(ProfilePicker::IsOpen());

  ProfileAttributesEntry* entry =
      g_browser_process->profile_manager()
          ->GetProfileAttributesStorage()
          .GetProfileAttributesWithPath(force_sign_in_profile->GetPath());
  // Profile is still locked and ephemeral at this point.
  EXPECT_EQ(entry->IsSigninRequired(), true);
  EXPECT_EQ(entry->IsEphemeral(), true);

  // Simulate the "Yes, I'm in" button clicked.
  LoginUIServiceFactory::GetForProfile(force_sign_in_profile)
      ->SyncConfirmationUIClosed(LoginUIService::SYNC_WITH_DEFAULT_SETTINGS);

  // A browser should open up and the picker should be closed.
  Browser* new_browser = BrowserAddedWaiter(initial_browser_count + 1u).Wait();
  WaitForPickerClosed();

  // The browser is for the newly created profile.
  EXPECT_EQ(new_browser->profile(), force_sign_in_profile);
  // Profile is unlocked and ready to be used.
  EXPECT_EQ(entry->IsSigninRequired(), false);
  EXPECT_EQ(entry->IsEphemeral(), false);
}

IN_PROC_BROWSER_TEST_F(ForceSigninProfilePickerCreationFlowBrowserTest,
                       ForceSigninAbortedBySyncDeclined_ThenSigninAgain) {
  ProfileManager* profile_manager = g_browser_process->profile_manager();
  // Only the default profile exists at this point.
  size_t initial_profile_count = 1u;
  ASSERT_EQ(profile_manager->GetNumberOfProfiles(), initial_profile_count);

  // Create a new signin flow, sign-in, and wait for the Sync Comfirmation
  // promo.
  Profile* force_sign_in_profile =
      SignInForNewProfile(GetSyncConfirmationURL(), "[email protected]",
                          "Joe", kNoHostedDomainFound, true);
  base::FilePath force_sign_in_profile_path = force_sign_in_profile->GetPath();
  // No browser for the created profile exist yet.
  ASSERT_EQ(chrome::GetBrowserCount(force_sign_in_profile), 0u);
  ASSERT_TRUE(ProfilePicker::IsOpen());

  ProfileAttributesStorage& storage =
      profile_manager->GetProfileAttributesStorage();
  ProfileAttributesEntry* entry =
      storage.GetProfileAttributesWithPath(force_sign_in_profile_path);
  ASSERT_NE(entry, nullptr);

  EXPECT_EQ(profile_manager->GetNumberOfProfiles(), initial_profile_count + 1);
  // Profile is still locked and ephemeral at this point.
  EXPECT_EQ(entry->IsSigninRequired(), true);
  EXPECT_EQ(entry->IsEphemeral(), true);

  ProfileDeletionObserver deletion_observer;
  // Simulate the "No thanks" button clicked.
  LoginUIServiceFactory::GetForProfile(force_sign_in_profile)
      ->SyncConfirmationUIClosed(LoginUIService::ABORT_SYNC);

  // Expect the profile to be deleted.
  deletion_observer.Wait();

  // Expect a redirect to the initial page of the profile picker.
  WaitForLoadStop(GURL("chrome://profile-picker"));
  EXPECT_TRUE(ProfilePicker::IsOpen());

  // The created profile path entry is now deletec.
  EXPECT_EQ(storage.GetProfileAttributesWithPath(force_sign_in_profile_path),
            nullptr);
  // Makes sure that the only profile that exist is the default one and not the
  // one we attempted to create.
  EXPECT_EQ(profile_manager->GetNumberOfProfiles(), initial_profile_count);

  // ---------------------------------------------------------------------------
  // This part of the test is to make sure we can safely instantiate a new sign
  // in flow after declining the first one.
  // ---------------------------------------------------------------------------

  size_t initial_browser_count = BrowserList::GetInstance()->size();

  // Create a second signin flow as part of the same session.
  Profile* force_sign_in_profile_2 =
      SignInForNewProfile(GetSyncConfirmationURL(), "[email protected]",
                          "Joe", kNoHostedDomainFound, true);

  LoginUIServiceFactory::GetForProfile(force_sign_in_profile_2)
      ->SyncConfirmationUIClosed(LoginUIService::SYNC_WITH_DEFAULT_SETTINGS);

  Browser* new_browser = BrowserAddedWaiter(initial_browser_count + 1u).Wait();
  WaitForPickerClosed();

  // The browser is for the newly created profile.
  EXPECT_EQ(new_browser->profile(), force_sign_in_profile_2);
}

IN_PROC_BROWSER_TEST_F(ForceSigninProfilePickerCreationFlowBrowserTest,
                       ForceSigninReauthSuccessful) {
  size_t initial_browser_count = BrowserList::GetInstance()->size();
  ASSERT_EQ(initial_browser_count, 0u);

  const std::vector<Profile*> profiles =
      g_browser_process->profile_manager()->GetLoadedProfiles();
  ASSERT_GE(profiles.size(), 1u);
  Profile* profile = profiles[0];
  ProfileAttributesEntry* entry =
      g_browser_process->profile_manager()
          ->GetProfileAttributesStorage()
          .GetProfileAttributesWithPath(profile->GetPath());

  ASSERT_TRUE(entry->IsSigninRequired());
  ASSERT_TRUE(ProfilePicker::IsOpen());

  signin::IdentityManager* identity_manager =
      IdentityManagerFactory::GetForProfile(profile);

  const std::string email("[email protected]");
  signin::MakePrimaryAccountAvailable(identity_manager, email,
                                      signin::ConsentLevel::kSignin);
  // Only managed accounts are allowed to reauth.
  entry->SetUserAcceptedAccountManagement(true);

  CoreAccountId primary_account =
      identity_manager->GetPrimaryAccountId(signin::ConsentLevel::kSignin);
  ASSERT_FALSE(primary_account.empty());

  // Simulate an invalid account.
  signin::SetInvalidRefreshTokenForPrimaryAccount(identity_manager);

  // Opening the locked profile from the profile picker should trigger the
  // reauth.
  OpenProfileFromPicker(entry->GetPath(), false);
  WaitForLoadStop(GetChromeReauthURL(email));

  // Simulate a successful reauth with the existing email.
  SimulateSuccesfulSignin(identity_manager, email);

  // A browser should open and the profile should now be unlocked.
  Browser* new_browser = BrowserAddedWaiter(initial_browser_count + 1u).Wait();
  EXPECT_TRUE(new_browser);
  EXPECT_EQ(new_browser->profile(), profile);
  EXPECT_FALSE(entry->IsSigninRequired());
  histogram_tester()->ExpectUniqueSample(
      kReauthResultHistogramName, ProfilePickerReauthResult::kSuccess, 1);
}

IN_PROC_BROWSER_TEST_F(ForceSigninProfilePickerCreationFlowBrowserTest,
                       ForceSigninReauthWithAnotherAccount) {
  size_t initial_browser_count = BrowserList::GetInstance()->size();
  ASSERT_EQ(initial_browser_count, 0u);

  const std::vector<Profile*> profiles =
      g_browser_process->profile_manager()->GetLoadedProfiles();
  ASSERT_GE(profiles.size(), 1u);
  Profile* profile = profiles[0];
  ProfileAttributesEntry* entry =
      g_browser_process->profile_manager()
          ->GetProfileAttributesStorage()
          .GetProfileAttributesWithPath(profile->GetPath());

  ASSERT_TRUE(entry->IsSigninRequired());
  ASSERT_TRUE(ProfilePicker::IsOpen());
  ASSERT_FALSE(IsForceSigninErrorDialogShown());

  signin::IdentityManager* identity_manager =
      IdentityManagerFactory::GetForProfile(profile);

  const std::string email("[email protected]");
  signin::MakePrimaryAccountAvailable(identity_manager, email,
                                      signin::ConsentLevel::kSignin);
  // Only managed accounts are allowed to reauth.
  entry->SetUserAcceptedAccountManagement(true);

  CoreAccountId primary_account =
      identity_manager->GetPrimaryAccountId(signin::ConsentLevel::kSignin);
  ASSERT_FALSE(primary_account.empty());

  // Simulate an invalid account.
  signin::SetInvalidRefreshTokenForPrimaryAccount(identity_manager);

  // Opening the locked profile from the profile picker should trigger the
  // reauth.
  OpenProfileFromPicker(entry->GetPath(), false);
  WaitForLoadStop(GetChromeReauthURL(email));

  // Simulate a successful sign in with another email address.
  const std::string different_email("[email protected]");
  ASSERT_NE(email, different_email);
  SimulateSuccesfulSignin(identity_manager, different_email);

  // Expect the profile picker to be opened instead of a browser, and the
  // profile to be still locked.
  WaitForLoadStop(GURL("chrome://profile-picker"));
  EXPECT_TRUE(ProfilePicker::IsOpen());
  EXPECT_TRUE(IsForceSigninErrorDialogShown());
  EXPECT_EQ(BrowserList::GetInstance()->size(), initial_browser_count);
  EXPECT_TRUE(entry->IsSigninRequired());
  histogram_tester()->ExpectUniqueSample(
      kReauthResultHistogramName, ProfilePickerReauthResult::kErrorUsedNewEmail,
      1);
}

IN_PROC_BROWSER_TEST_F(ForceSigninProfilePickerCreationFlowBrowserTest,
                       ForceSigninReauthNavigateBackShouldAbort) {
  size_t initial_browser_count = BrowserList::GetInstance()->size();
  ASSERT_EQ(initial_browser_count, 0u);

  const std::vector<Profile*> profiles =
      g_browser_process->profile_manager()->GetLoadedProfiles();
  ASSERT_GE(profiles.size(), 1u);
  Profile* profile = profiles[0];
  ProfileAttributesEntry* entry =
      g_browser_process->profile_manager()
          ->GetProfileAttributesStorage()
          .GetProfileAttributesWithPath(profile->GetPath());

  ASSERT_TRUE(entry->IsSigninRequired());
  ASSERT_TRUE(ProfilePicker::IsOpen());

  signin::IdentityManager* identity_manager =
      IdentityManagerFactory::GetForProfile(profile);

  const std::string email("[email protected]");
  signin::MakePrimaryAccountAvailable(identity_manager, email,
                                      signin::ConsentLevel::kSignin);
  // Only managed accounts are allowed to reauth.
  entry->SetUserAcceptedAccountManagement(true);

  CoreAccountId primary_account =
      identity_manager->GetPrimaryAccountId(signin::ConsentLevel::kSignin);
  ASSERT_FALSE(primary_account.empty());

  // Simulate an invalid account.
  signin::SetInvalidRefreshTokenForPrimaryAccount(identity_manager);

  // Opening the locked profile from the profile picker should trigger the
  // reauth, and the back button toolbar should be visible.
  OpenProfileFromPicker(entry->GetPath(), false);
  WaitForLoadStop(GetChromeReauthURL(email));
  EXPECT_TRUE(IsNativeToolbarVisible());

  // Simulate a redirect within the reauth page (requesting a password for
  // example), the actual URL is not important for the testing purposes.
  GURL redirect_url("https://www.google.com/");
  web_contents()->GetController().LoadURL(redirect_url, content::Referrer(),
                                          ui::PAGE_TRANSITION_AUTO_TOPLEVEL,
                                          std::string());
  WaitForLoadStop(redirect_url);

  // Simulate a back navigation within the reauth redirect.
  SimulateNavigateBack();

  // Expect it to take us back to the initial reauth page.
  WaitForLoadStop(GetChromeReauthURL(email));

  // Simulate a back navigation within the reauth page.
  SimulateNavigateBack();

  // Expect the profile picker to be opened since it was the last step before
  // reauth, toolbar should be hidden, and the profile to be still locked.
  WaitForLoadStop(GURL("chrome://profile-picker"));
  EXPECT_TRUE(ProfilePicker::IsOpen());
  EXPECT_FALSE(IsNativeToolbarVisible());
  EXPECT_EQ(BrowserList::GetInstance()->size(), initial_browser_count);
  EXPECT_TRUE(entry->IsSigninRequired());
}

IN_PROC_BROWSER_TEST_F(ForceSigninProfilePickerCreationFlowBrowserTest,
                       ForceSigninLaunchInactiveDefaultProfile) {
  size_t initial_browser_count = BrowserList::GetInstance()->size();
  ASSERT_EQ(initial_browser_count, 0u);

  ProfileManager* profile_manager = g_browser_process->profile_manager();
  const std::vector<Profile*> profiles = profile_manager->GetLoadedProfiles();
  ASSERT_GE(profiles.size(), 1u);
  Profile* default_profile = profiles[0];
  ProfileAttributesEntry* default_profile_entry =
      profile_manager->GetProfileAttributesStorage()
          .GetProfileAttributesWithPath(default_profile->GetPath());

  ASSERT_TRUE(ProfilePicker::IsOpen());
  // Make sure that this is the default profile. Also this profile is not yet
  // active/used which makes a valid candidate to sign in.
  ASSERT_EQ(default_profile_entry->GetPath(),
            profiles::GetDefaultProfileDir(profile_manager->user_data_dir()));
  ASSERT_EQ(default_profile_entry->GetActiveTime(), base::Time());
  ASSERT_TRUE(default_profile_entry->IsSigninRequired());

  // Opening the default profile for the first time is allowed, it is expected
  // to open the sign in screen.
  OpenProfileFromPicker(default_profile_entry->GetPath(), false);
  WaitForLoadStop(GetSigninChromeSyncDiceUrl());

  // Finish the signin that was started from opening the default profile.
  FinishDiceSignIn(default_profile, "[email protected]", "Joe");
  WaitForLoadStop(GetSyncConfirmationURL());

  // Accept Sync.
  LoginUIServiceFactory::GetForProfile(default_profile)
      ->SyncConfirmationUIClosed(LoginUIService::SYNC_WITH_DEFAULT_SETTINGS);

  // A browser should open and the profile should now be unlocked.
  Browser* new_browser = BrowserAddedWaiter(initial_browser_count + 1u).Wait();
  EXPECT_TRUE(new_browser);
  EXPECT_EQ(new_browser->profile(), default_profile);
  EXPECT_FALSE(default_profile_entry->IsSigninRequired());

  // Default profile is now active.
  EXPECT_NE(default_profile_entry->GetActiveTime(), base::Time());
}

class ForceSigninProfilePickerCreationFlowBrowserTestWithPRE
    : public ForceSigninProfilePickerCreationFlowBrowserTest {
 public:
  ForceSigninProfilePickerCreationFlowBrowserTestWithPRE()
      : ForceSigninProfilePickerCreationFlowBrowserTest(
            /*force_signin_enabled=*/!content::IsPreTest()) {}
};

IN_PROC_BROWSER_TEST_F(ForceSigninProfilePickerCreationFlowBrowserTestWithPRE,
                       PRE_ProfileThatCannotBeManagedCannotBeOpened) {
  ASSERT_FALSE(signin_util::IsForceSigninEnabled());

  ProfileManager* profile_manager = g_browser_process->profile_manager();
  // Only default profile exists.
  ASSERT_EQ(1u, profile_manager->GetNumberOfProfiles());

  // Activate this profile then close the session.
  CreateBrowser(profile_manager->GetLoadedProfiles()[0]);
}

IN_PROC_BROWSER_TEST_F(ForceSigninProfilePickerCreationFlowBrowserTestWithPRE,
                       ProfileThatCannotBeManagedCannotBeOpened) {
  ASSERT_TRUE(signin_util::IsForceSigninEnabled());

  size_t initial_browser_count = BrowserList::GetInstance()->size();
  ASSERT_EQ(0u, initial_browser_count);

  ProfileManager* profile_manager = g_browser_process->profile_manager();
  std::vector<ProfileAttributesEntry*> entries =
      profile_manager->GetProfileAttributesStorage().GetAllProfilesAttributes();
  ASSERT_EQ(1u, entries.size());
  // Use the same (only) profile as in PRE.
  ProfileAttributesEntry* existing_entry = entries[0];

  // Profile has been used and is now locked.
  ASSERT_NE(existing_entry->GetActiveTime(), base::Time());
  ASSERT_TRUE(existing_entry->IsSigninRequired());
  ASSERT_FALSE(existing_entry->CanBeManaged());

  ASSERT_TRUE(ProfilePicker::IsOpen());
  ASSERT_FALSE(IsForceSigninErrorDialogShown());

  // Attempting to open this profile, profile was previously active and not
  // syncing/managed.
  OpenProfileFromPicker(existing_entry->GetPath(), false);

  // Should not succeed.
  EXPECT_EQ(initial_browser_count, BrowserList::GetInstance()->size());
  // Error dialog is shown on top of the ProfilePicker.
  EXPECT_TRUE(IsForceSigninErrorDialogShown());
  // Profile is still locked.
  EXPECT_TRUE(existing_entry->IsSigninRequired());
}

#endif

// Regression test for crbug.com/1266415.
IN_PROC_BROWSER_TEST_F(ProfilePickerCreationFlowBrowserTest,
                       CreateSignedInProfileWithSyncEncryptionKeys) {}

// Regression test for crbug.com/1196290. Makes no sense for lacros because you
// cannot sign-in twice in the same way on lacros.
IN_PROC_BROWSER_TEST_F(ProfilePickerCreationFlowBrowserTest,
                       CreateSignedInProfileAfterCancellingFirstAttempt) {}

IN_PROC_BROWSER_TEST_F(ProfilePickerCreationFlowBrowserTest,
                       CancelWhileSigningIn) {}

// Regression test for crbug.com/1278726.
IN_PROC_BROWSER_TEST_F(ProfilePickerCreationFlowBrowserTest,
                       CancelWhileSigningInBeforeProfileCreated) {}

IN_PROC_BROWSER_TEST_F(ProfilePickerCreationFlowBrowserTest,
                       PRE_CancelWhileSigningInWithNoOtherWindow) {}

IN_PROC_BROWSER_TEST_F(ProfilePickerCreationFlowBrowserTest,
                       CancelWhileSigningInWithNoOtherWindow) {}

// Tests dice-specific logic for keeping track of the new profile color.
IN_PROC_BROWSER_TEST_F(ProfilePickerCreationFlowBrowserTest,
                       CreateSignedInProfileDiceReenter) {}
#endif  // !BUILDFLAG(IS_CHROMEOS_LACROS)

// TODO(crbug.com/40817459) Test is flaky on Linux CFI, Linux dbg, Mac ASan
#if ((BUILDFLAG(CFI_ICALL_CHECK) || !defined(NDEBUG)) && \
     BUILDFLAG(IS_LINUX)) ||                             \
    (BUILDFLAG(IS_MAC) && defined(ADDRESS_SANITIZER))
#define MAYBE_CreateSignedInProfileSettings
#else
#define MAYBE_CreateSignedInProfileSettings
#endif
IN_PROC_BROWSER_TEST_F(ProfilePickerCreationFlowBrowserTest,
                       MAYBE_CreateSignedInProfileSettings) {}

// The following tests rely on dice specific logic. Some of them could be
// extended to cover lacros as well.
#if !BUILDFLAG(IS_CHROMEOS_LACROS)
IN_PROC_BROWSER_TEST_F(ProfilePickerCreationFlowBrowserTest,
                       CreateSignedInProfileOpenLink) {}

// Regression test for crbug.com/1219980.
// TODO(crbug.com/40772284): Re-implement the test bases on the final fix.
IN_PROC_BROWSER_TEST_F(ProfilePickerCreationFlowBrowserTest,
                       CreateSignedInProfileSecurityInterstitials) {}

// TODO(crbug.com/40197099): Extend this test to support lacros.
IN_PROC_BROWSER_TEST_F(ProfilePickerCreationFlowBrowserTest,
                       CreateSignedInProfileExtendedInfoTimeout) {}

// TODO(crbug.com/40197099): Extend this test to support lacros.
// TODO(crbug.com/41496960): Flaky on Linux MSan.
#if BUILDFLAG(IS_LINUX) && defined(MEMORY_SANITIZER)
#define MAYBE_CreateSignedInProfileExtendedInfoDelayed
#else
#define MAYBE_CreateSignedInProfileExtendedInfoDelayed
#endif
IN_PROC_BROWSER_TEST_F(ProfilePickerCreationFlowBrowserTest,
                       MAYBE_CreateSignedInProfileExtendedInfoDelayed) {}

IN_PROC_BROWSER_TEST_F(ProfilePickerCreationFlowBrowserTest,
                       CreateSignedInProfileWithSAML) {}

// TODO(crbug.com/40197099): Extend this test to support lacros.
// Regression test for crash https://crbug.com/1195784.
// Crash requires specific conditions to be reproduced. Browser should have 2
// profiles with the same GAIA account name and the first profile should use
// default local name. This is set up specifically in order to trigger
// ProfileAttributesStorage::NotifyIfProfileNamesHaveChanged() when a new third
// profile is added.
IN_PROC_BROWSER_TEST_F(ProfilePickerCreationFlowBrowserTest,
                       PRE_ProfileNameChangesOnProfileAdded) {}

IN_PROC_BROWSER_TEST_F(ProfilePickerCreationFlowBrowserTest,
                       ProfileNameChangesOnProfileAdded) {}

// Regression test for https://crbug.com/1467483
IN_PROC_BROWSER_TEST_F(ProfilePickerCreationFlowBrowserTest,
                       DiceSigninFailure) {}
#endif  // !BUILDFLAG(IS_CHROMEOS_LACROS)

IN_PROC_BROWSER_TEST_F(ProfilePickerCreationFlowBrowserTest,
                       OpenPickerAndClose) {}

// Regression test for https://crbug.com/1205147.
IN_PROC_BROWSER_TEST_F(ProfilePickerCreationFlowBrowserTest,
                       OpenPickerWhileClosing) {}

IN_PROC_BROWSER_TEST_F(ProfilePickerCreationFlowBrowserTest, ReShow) {}

// TODO(crbug.com/325310963): Re-enable this flaky test on macOS.
#if BUILDFLAG(IS_MAC)
#define MAYBE_OpenProfile
#else
#define MAYBE_OpenProfile
#endif
IN_PROC_BROWSER_TEST_F(ProfilePickerCreationFlowBrowserTest,
                       MAYBE_OpenProfile) {}

IN_PROC_BROWSER_TEST_F(ProfilePickerCreationFlowBrowserTest,
                       OpenProfileFromStartup) {}

// TODO(crbug.com/40817459) Test is flaky on Linux CFI, Linux dbg, Mac ASan
#if ((BUILDFLAG(CFI_ICALL_CHECK) || !defined(NDEBUG)) && \
     BUILDFLAG(IS_LINUX)) ||                             \
    (BUILDFLAG(IS_MAC) && defined(ADDRESS_SANITIZER))
#define MAYBE_OpenProfile_Settings
#else
#define MAYBE_OpenProfile_Settings
#endif
IN_PROC_BROWSER_TEST_F(ProfilePickerCreationFlowBrowserTest,
                       MAYBE_OpenProfile_Settings) {}

IN_PROC_BROWSER_TEST_F(ProfilePickerCreationFlowBrowserTest,
                       OpenURL_PickerClosed) {}

// Regression test for https://crbug.com/1199035
IN_PROC_BROWSER_TEST_F(ProfilePickerCreationFlowBrowserTest,
                       OpenProfile_Guest) {}

// Closes the default browser window before creating a new profile in the
// profile picker.
// Regression test for https://crbug.com/1144092.
IN_PROC_BROWSER_TEST_F(ProfilePickerCreationFlowBrowserTest,
                       CloseBrowserBeforeCreatingNewProfile) {}

IN_PROC_BROWSER_TEST_F(ProfilePickerCreationFlowBrowserTest,
                       CreateLocalProfile) {}

#if BUILDFLAG(IS_MAC)
#define MAYBE_CancelLocalProfileCreation
#else
#define MAYBE_CancelLocalProfileCreation
#endif  // BUILDFLAG(IS_MAC)
IN_PROC_BROWSER_TEST_F(ProfilePickerCreationFlowBrowserTest,
                       MAYBE_CancelLocalProfileCreation) {}

IN_PROC_BROWSER_TEST_F(ProfilePickerCreationFlowBrowserTest, DeleteProfile) {}

// Regression test for https://crbug.com/1488267
IN_PROC_BROWSER_TEST_F(ProfilePickerCreationFlowBrowserTest,
                       DeleteProfileFromOwnTab) {}

class ProfilePickerEnterpriseCreationFlowBrowserTest
    : public ProfilePickerCreationFlowBrowserTest {};

IN_PROC_BROWSER_TEST_F(ProfilePickerEnterpriseCreationFlowBrowserTest,
                       CreateSignedInProfile) {}

#if !BUILDFLAG(IS_CHROMEOS_LACROS)
IN_PROC_BROWSER_TEST_F(ProfilePickerEnterpriseCreationFlowBrowserTest,
                       CreateSignedInProfileWithSuggestedTwoFactorAuthSetup) {}

// TODO(crbug.com/40197102): Extend this test to support mirror.
IN_PROC_BROWSER_TEST_F(ProfilePickerEnterpriseCreationFlowBrowserTest,
                       CreateSignedInProfileWithSyncDisabled) {}
#endif  // !BUILDFLAG(IS_CHROMEOS_LACROS)

// TODO(crbug.com/40817459) Test is flaky on Linux CFI
// TODO(crbug.com/40885685) Test is also flaky on Linux (dbg)
#if BUILDFLAG(IS_LINUX)
#define MAYBE_CreateSignedInEnterpriseProfileSettings
#else
#define MAYBE_CreateSignedInEnterpriseProfileSettings
#endif
IN_PROC_BROWSER_TEST_F(ProfilePickerEnterpriseCreationFlowBrowserTest,
                       MAYBE_CreateSignedInEnterpriseProfileSettings) {}

IN_PROC_BROWSER_TEST_F(ProfilePickerEnterpriseCreationFlowBrowserTest, Cancel) {}

IN_PROC_BROWSER_TEST_F(ProfilePickerEnterpriseCreationFlowBrowserTest,
                       CancelFromPicker) {}

IN_PROC_BROWSER_TEST_F(ProfilePickerEnterpriseCreationFlowBrowserTest,
                       CreateSignedInProfileSigninAlreadyExists_ConfirmSwitch) {}

IN_PROC_BROWSER_TEST_F(ProfilePickerEnterpriseCreationFlowBrowserTest,
                       CreateSignedInProfileSigninAlreadyExists_CancelSwitch) {}

class ProfilePickerCreationFlowEphemeralProfileBrowserTest
    : public ProfilePickerCreationFlowBrowserTest,
      public testing::WithParamInterface<ForceEphemeralProfilesPolicy> {};

// Flaky on Windows: https://crbug.com/1247530.
#if BUILDFLAG(IS_WIN)
#define MAYBE_PRE_Signin
#define MAYBE_Signin
#else
#define MAYBE_PRE_Signin
#define MAYBE_Signin
#endif
// Checks that the new profile is no longer ephemeral at the end of the flow and
// still exists after restart.
IN_PROC_BROWSER_TEST_P(ProfilePickerCreationFlowEphemeralProfileBrowserTest,
                       MAYBE_PRE_Signin) {}

IN_PROC_BROWSER_TEST_P(ProfilePickerCreationFlowEphemeralProfileBrowserTest,
                       MAYBE_Signin) {}

#if !BUILDFLAG(IS_CHROMEOS_LACROS)
// Flaky on Windows: https://crbug.com/1247530.
#if BUILDFLAG(IS_WIN)
#define MAYBE_PRE_ExitDuringSignin
#define MAYBE_ExitDuringSignin
#else
#define MAYBE_PRE_ExitDuringSignin
#define MAYBE_ExitDuringSignin
#endif
// Checks that the new profile is deleted on next startup if Chrome exits during
// the signin flow.
IN_PROC_BROWSER_TEST_P(ProfilePickerCreationFlowEphemeralProfileBrowserTest,
                       MAYBE_PRE_ExitDuringSignin) {}

IN_PROC_BROWSER_TEST_P(ProfilePickerCreationFlowEphemeralProfileBrowserTest,
                       MAYBE_ExitDuringSignin) {}
#endif

INSTANTIATE_TEST_SUITE_P();

// Only MacOS has a keyboard shortcut to exit Chrome.
#if BUILDFLAG(IS_MAC)
IN_PROC_BROWSER_TEST_F(ProfilePickerCreationFlowBrowserTest,
                       SyncConfirmationExitChromeTest) {
  // Simulate a successful sign-in and wait for the sign-in to propagate to the
  // flow, resulting in sync confirmation screen getting displayed.
  SignInForNewProfile(GetSyncConfirmationURL(), "[email protected]",
                      "Joe");
  EXPECT_TRUE(ProfilePicker::IsOpen());

  // Exit the sync confirmation view (Cmd-Q).
  view()->AcceleratorPressed(ui::Accelerator(ui::VKEY_Q, ui::EF_COMMAND_DOWN));
  WaitForPickerClosed();
  EXPECT_TRUE(browser_shutdown::IsTryingToQuit());
}
#endif

IN_PROC_BROWSER_TEST_F(ProfilePickerCreationFlowBrowserTest,
                       SyncConfirmationNavigateBackTest) {}

#if BUILDFLAG(IS_CHROMEOS_LACROS)

class ProfilePickerLacrosFirstRunBrowserTestBase
    : public ProfilePickerTestBase {
 public:
  void SetUpInProcessBrowserTestFixture() override {
    ProfilePickerTestBase::SetUpInProcessBrowserTestFixture();
    create_services_subscription_ =
        BrowserContextDependencyManager::GetInstance()
            ->RegisterCreateServicesCallbackForTesting(base::BindRepeating(
                &ProfilePickerLacrosFirstRunBrowserTestBase::
                    OnWillCreateBrowserContextServices,
                base::Unretained(this)));
  }

  virtual void OnWillCreateBrowserContextServices(
      content::BrowserContext* context) {
    SyncServiceFactory::GetInstance()->SetTestingFactory(
        context, base::BindRepeating([](content::BrowserContext* context)
                                         -> std::unique_ptr<KeyedService> {
          auto sync_service = std::make_unique<syncer::TestSyncService>();

          // The FRE will be paused, waiting for the state to change
          // before either showing or exiting it.
          // `GoThroughFirstRunFlow()` will do this, or the test
          // should call `sync_service()` to do this manually.
          sync_service->SetMaxTransportState(
              syncer::SyncService::TransportState::INITIALIZING);

          return sync_service;
        }));
  }

  void SetUpDefaultCommandLine(base::CommandLine* command_line) override {
    ProfilePickerTestBase::SetUpDefaultCommandLine(command_line);

    if (GetTestPreCount() <= 1) {
      // Show the FRE in these tests. We only disable the FRE for PRE_PRE_ tests
      // (with GetTestPreCount() == 2) as we need the general set up to run
      // and finish registering a signed in account with the primary profile. It
      // will then be available to the subsequent steps of the test.
      // TODO(crbug.com/40833358): Find a simpler way to set this up.
      command_line->RemoveSwitch(switches::kNoFirstRun);
    }
  }

  // Helper to obtain the primary profile from the `ProfileManager` instead of
  // going through the `Browser`, which we don't open in many tests here.
  Profile* GetPrimaryProfile() {
    ProfileManager* profile_manager = g_browser_process->profile_manager();
    return profile_manager->GetProfile(
        profile_manager->GetPrimaryUserProfilePath());
  }

  // Helper to walk through the FRE. Performs a few assertions, and performs the
  // specified choices when prompted.
  void GoThroughFirstRunFlow(bool quit_on_welcome,
                             std::optional<bool> quit_on_sync) {
    Profile* profile = GetPrimaryProfile();
    EXPECT_TRUE(ShouldOpenFirstRun(profile));

    // The profile picker should be open on start to show the FRE.
    EXPECT_EQ(0u, BrowserList::GetInstance()->size());
    EXPECT_TRUE(ProfilePicker::IsOpen());

    // Unblock the sync service.
    sync_service()->SetMaxTransportState(
        syncer::SyncService::TransportState::ACTIVE);
    sync_service()->FireStateChanged();

    // A welcome page should be displayed.
    WaitForPickerWidgetCreated();

    WaitForLoadStop(GURL(chrome::kChromeUIIntroURL));
    content::WebContents* contents = web_contents();
    EXPECT_TRUE(contents);
    base::OnceClosure complete_welcome =
        base::BindLambdaForTesting([contents]() {
          contents->GetWebUI()->ProcessWebUIMessage(
              contents->GetURL(), "continueWithAccount", base::Value::List());
        });

    if (quit_on_welcome) {
      // Do nothing for now, we will exit the flow below.
      ASSERT_FALSE(quit_on_sync.has_value());
    } else {
      // Proceed to the sync confirmation page.
      std::move(complete_welcome).Run();
      WaitForLoadStop(GetSyncConfirmationURL());
    }
    if (quit_on_welcome || quit_on_sync.value()) {
      // Exit the flow.
      ProfilePicker::Hide();
    } else {
      // Opt-in to sync.
      LoginUIServiceFactory::GetForProfile(profile)->SyncConfirmationUIClosed(
          LoginUIService::SYNC_WITH_DEFAULT_SETTINGS);
    }

    // Wait for the FRE closure to settle before the caller can proceed with
    // assertions.
    WaitForPickerClosed();
  }

  const base::HistogramTester& histogram_tester() { return histogram_tester_; }

  syncer::TestSyncService* sync_service() {
    return static_cast<syncer::TestSyncService*>(
        SyncServiceFactory::GetForProfile(GetPrimaryProfile()));
  }

 private:
  // Start tracking the logged histograms from the beginning, since the FRE can
  // be triggered and completed before we enter the test body.
  base::HistogramTester histogram_tester_;

  base::CallbackListSubscription create_services_subscription_;

  // Lifts the timeout to make sure it is not hiding errors where we don't get
  // the signal that the sync service started.
  // TODO(crbug.com/40839518): Find a better way to safely work around
  // the sync service stalling issue.
  testing::ScopedSyncStartupTimeoutOverride sync_startup_timeout_{
      std::optional<base::TimeDelta>()};
};

class ProfilePickerLacrosFirstRunBrowserTest
    : public ProfilePickerLacrosFirstRunBrowserTestBase {
 private:
  profiles::testing::ScopedNonEnterpriseDomainSetterForTesting
      non_enterprise_domain_setter_;
};

// Overall sequence for QuitEarly:
// Start browser => Show FRE => Quit on welcome step.
IN_PROC_BROWSER_TEST_F(ProfilePickerLacrosFirstRunBrowserTest,
                       PRE_PRE_QuitEarly) {}
IN_PROC_BROWSER_TEST_F(ProfilePickerLacrosFirstRunBrowserTest, PRE_QuitEarly) {
  GoThroughFirstRunFlow(
      /*quit_on_welcome=*/true,
      /*quit_on_sync=*/std::nullopt);

  // No browser window should open because we closed the FRE UI early.
  EXPECT_EQ(0u, BrowserList::GetInstance()->size());
  EXPECT_TRUE(ShouldOpenFirstRun(GetPrimaryProfile()));
}
IN_PROC_BROWSER_TEST_F(ProfilePickerLacrosFirstRunBrowserTest, QuitEarly) {
  // On the second run, the FRE is still not marked finished and we should
  // reopen it.
  EXPECT_TRUE(ShouldOpenFirstRun(GetPrimaryProfile()));
  EXPECT_TRUE(ProfilePicker::IsOpen());
}

// Overall sequence for QuitAtEnd:
// Start browser => Show FRE => Advance to sync consent step => Quit.
IN_PROC_BROWSER_TEST_F(ProfilePickerLacrosFirstRunBrowserTest,
                       PRE_PRE_QuitAtEnd) {
  // Dummy case to set up the primary profile.
}
IN_PROC_BROWSER_TEST_F(ProfilePickerLacrosFirstRunBrowserTest, PRE_QuitAtEnd) {
  Profile* profile = GetPrimaryProfile();

  GoThroughFirstRunFlow(
      /*quit_on_welcome=*/false,
      /*quit_on_sync=*/true);

  // Because we quit, we should also quit chrome, but mark the FRE finished.
  EXPECT_FALSE(ShouldOpenFirstRun(profile));
  EXPECT_EQ(0u, BrowserList::GetInstance()->size());
  EXPECT_FALSE(enterprise_util::UserAcceptedAccountManagement(profile));
}
IN_PROC_BROWSER_TEST_F(ProfilePickerLacrosFirstRunBrowserTest, QuitAtEnd) {
  Profile* profile = GetPrimaryProfile();

  // On the second run, the FRE is marked finished and we should skip it.
  EXPECT_FALSE(ShouldOpenFirstRun(profile));
  EXPECT_FALSE(enterprise_util::UserAcceptedAccountManagement(profile));
  EXPECT_FALSE(ProfilePicker::IsOpen());
  EXPECT_EQ(1u, BrowserList::GetInstance()->size());
}

// Overall sequence for OptIn:
// Start browser => Show FRE => Advance to sync consent step => Opt-in.
IN_PROC_BROWSER_TEST_F(ProfilePickerLacrosFirstRunBrowserTest, PRE_PRE_OptIn) {}
IN_PROC_BROWSER_TEST_F(ProfilePickerLacrosFirstRunBrowserTest, PRE_OptIn) {
  GoThroughFirstRunFlow(
      /*quit_on_welcome=*/false,
      /*quit_on_sync=*/false);

  // A browser should open.
  EXPECT_FALSE(ShouldOpenFirstRun(GetPrimaryProfile()));
  EXPECT_EQ(1u, BrowserList::GetInstance()->size());
}

IN_PROC_BROWSER_TEST_F(ProfilePickerLacrosFirstRunBrowserTest, OptIn) {
  // On the second run, the FRE is marked finished and we should skip it.
  EXPECT_FALSE(ShouldOpenFirstRun(GetPrimaryProfile()));
  EXPECT_FALSE(ProfilePicker::IsOpen());
  EXPECT_EQ(1u, BrowserList::GetInstance()->size());
}

class ManagedProfileSetUpHelper : public ChromeBrowserMainExtraParts {
 public:
  void PostProfileInit(Profile* profile, bool is_initial_profile) override {
    // Only one profile, the primary one, should be initialized in this test.
    EXPECT_EQ(
        profile->GetPath(),
        g_browser_process->profile_manager()->GetPrimaryUserProfilePath());
    profile->GetProfilePolicyConnector()->OverrideIsManagedForTesting(true);
  }
};

class ProfilePickerLacrosManagedFirstRunBrowserTest
    : public ProfilePickerLacrosFirstRunBrowserTestBase {
 public:
  void CreatedBrowserMainParts(content::BrowserMainParts* parts) override {
    ProfilePickerLacrosFirstRunBrowserTestBase::CreatedBrowserMainParts(parts);
    static_cast<ChromeBrowserMainParts*>(parts)->AddParts(
        std::make_unique<ManagedProfileSetUpHelper>());
  }

  const base::UserActionTester& user_action_tester() {
    return user_action_tester_;
  }

 private:
  base::UserActionTester user_action_tester_;
};

// Overall sequence for QuitEarly:
// Start browser => Show FRE => Quit on welcome step.
IN_PROC_BROWSER_TEST_F(ProfilePickerLacrosManagedFirstRunBrowserTest,
                       PRE_PRE_QuitEarly) {}
IN_PROC_BROWSER_TEST_F(ProfilePickerLacrosManagedFirstRunBrowserTest,
                       PRE_QuitEarly) {
  Profile* profile = GetPrimaryProfile();
  // TODO(crbug.com/40224163): This is a bug, the flag should not be set.
  EXPECT_TRUE(enterprise_util::UserAcceptedAccountManagement(profile));
  EXPECT_EQ(1, user_action_tester().GetActionCount(
                   "Signin_EnterpriseAccountPrompt_ImportData"));

  GoThroughFirstRunFlow(
      /*quit_on_welcome=*/true,
      /*quit_on_sync=*/std::nullopt);

  // No browser window should open because we closed the FRE UI early.
  EXPECT_EQ(0u, BrowserList::GetInstance()->size());
  EXPECT_TRUE(ShouldOpenFirstRun(profile));
}
IN_PROC_BROWSER_TEST_F(ProfilePickerLacrosManagedFirstRunBrowserTest,
                       QuitEarly) {
  Profile* profile = GetPrimaryProfile();

  // TODO(crbug.com/40224163): This is a bug, the flag should not be set.
  EXPECT_TRUE(enterprise_util::UserAcceptedAccountManagement(profile));
  EXPECT_EQ(0, user_action_tester().GetActionCount(
                   "Signin_EnterpriseAccountPrompt_ImportData"));

  // On the second run, the FRE is still not marked finished and we should
  // reopen it.
  GoThroughFirstRunFlow(
      /*quit_on_welcome=*/true,
      /*quit_on_sync=*/std::nullopt);
}

// Overall sequence for QuitAtEnd:
// Start browser => Show FRE => Advance to sync consent step => Quit.
IN_PROC_BROWSER_TEST_F(ProfilePickerLacrosManagedFirstRunBrowserTest,
                       PRE_PRE_QuitAtEnd) {}
IN_PROC_BROWSER_TEST_F(ProfilePickerLacrosManagedFirstRunBrowserTest,
                       PRE_QuitAtEnd) {
  Profile* profile = GetPrimaryProfile();
  // TODO(crbug.com/40224163): This is a bug, the flag is set too early
  EXPECT_TRUE(enterprise_util::UserAcceptedAccountManagement(profile));
  EXPECT_EQ(1, user_action_tester().GetActionCount(
                   "Signin_EnterpriseAccountPrompt_ImportData"));

  GoThroughFirstRunFlow(
      /*quit_on_welcome=*/false,
      /*quit_on_sync=*/true);

  // The user went past the welcome step, management should be marked accepted.
  EXPECT_TRUE(enterprise_util::UserAcceptedAccountManagement(profile));
  EXPECT_EQ(1, user_action_tester().GetActionCount(
                   "Signin_EnterpriseAccountPrompt_ImportData"));

  // No browser window should open because we closed the FRE UI early.
  EXPECT_EQ(0u, BrowserList::GetInstance()->size());
  EXPECT_FALSE(ShouldOpenFirstRun(profile));
}
IN_PROC_BROWSER_TEST_F(ProfilePickerLacrosManagedFirstRunBrowserTest,
                       QuitAtEnd) {
  Profile* profile = GetPrimaryProfile();

  // On the second run, the FRE is marked finished and we should skip it.
  EXPECT_FALSE(ShouldOpenFirstRun(profile));
  EXPECT_TRUE(enterprise_util::UserAcceptedAccountManagement(profile));
  EXPECT_FALSE(ProfilePicker::IsOpen());
  EXPECT_EQ(1u, BrowserList::GetInstance()->size());
}

// Overall sequence for SyncDisabled:
// Start browser => FRE Skipped => Browser opens.
IN_PROC_BROWSER_TEST_F(ProfilePickerLacrosManagedFirstRunBrowserTest,
                       PRE_PRE_SyncDisabled) {}
IN_PROC_BROWSER_TEST_F(ProfilePickerLacrosManagedFirstRunBrowserTest,
                       PRE_SyncDisabled) {
  Profile* profile = GetPrimaryProfile();

  // The profile picker is created but is waiting for the
  // sync service to complete its initialization to
  // determine whether to show the FRE or not.
  EXPECT_TRUE(enterprise_util::UserAcceptedAccountManagement(profile));
  EXPECT_EQ(1, user_action_tester().GetActionCount(
                   "Signin_EnterpriseAccountPrompt_ImportData"));
  EXPECT_TRUE(ProfilePicker::IsOpen());
  EXPECT_EQ(0u, BrowserList::GetInstance()->size());
  EXPECT_EQ(ProfilePickerView::State::kInitializing,
            view()->state_for_testing());

  // Unblock the sync service and simulate the server-side
  // being disabled.
  sync_service()->SetAllowedByEnterprisePolicy(false);
  sync_service()->FireStateChanged();

  // The pending state should resolve by skipping the FRE.
  EXPECT_FALSE(ShouldOpenFirstRun(profile));
  WaitForPickerClosed();
  EXPECT_FALSE(ProfilePicker::IsOpen());
  EXPECT_EQ(1u, BrowserList::GetInstance()->size());
}
IN_PROC_BROWSER_TEST_F(ProfilePickerLacrosManagedFirstRunBrowserTest,
                       SyncDisabled) {
  Profile* profile = GetPrimaryProfile();

  // On the second run, the FRE is marked finished and we should skip it.
  EXPECT_FALSE(ShouldOpenFirstRun(profile));
  EXPECT_TRUE(enterprise_util::UserAcceptedAccountManagement(profile));
  EXPECT_FALSE(ProfilePicker::IsOpen());
  EXPECT_EQ(1u, BrowserList::GetInstance()->size());
}

#endif  // BUILDFLAG(IS_CHROMEOS_LACROS)