chromium/ios/chrome/browser/browser_view/ui_bundled/browser_view_controller_unittest.mm

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

#import "ios/chrome/browser/browser_view/ui_bundled/browser_view_controller.h"

#import <Foundation/Foundation.h>
#import <PassKit/PassKit.h>

#import <memory>

#import "base/apple/foundation_util.h"
#import "base/memory/raw_ptr.h"
#import "components/content_settings/core/browser/host_content_settings_map.h"
#import "components/open_from_clipboard/fake_clipboard_recent_content.h"
#import "components/search_engines/template_url_service.h"
#import "components/supervised_user/core/common/features.h"
#import "ios/chrome/browser/bookmarks/model/bookmark_model_factory.h"
#import "ios/chrome/browser/bookmarks/ui_bundled/home/bookmarks_coordinator.h"
#import "ios/chrome/browser/browser_view/ui_bundled/browser_view_controller+private.h"
#import "ios/chrome/browser/browser_view/ui_bundled/key_commands_provider.h"
#import "ios/chrome/browser/browser_view/ui_bundled/safe_area_provider.h"
#import "ios/chrome/browser/browser_view/ui_bundled/tab_consumer.h"
#import "ios/chrome/browser/browser_view/ui_bundled/tab_events_mediator.h"
#import "ios/chrome/browser/favicon/model/favicon_service_factory.h"
#import "ios/chrome/browser/favicon/model/ios_chrome_favicon_loader_factory.h"
#import "ios/chrome/browser/favicon/model/ios_chrome_large_icon_service_factory.h"
#import "ios/chrome/browser/history/model/history_service_factory.h"
#import "ios/chrome/browser/incognito_reauth/ui_bundled/incognito_reauth_commands.h"
#import "ios/chrome/browser/lens/model/lens_browser_agent.h"
#import "ios/chrome/browser/metrics/model/tab_usage_recorder_browser_agent.h"
#import "ios/chrome/browser/ntp/model/new_tab_page_tab_helper.h"
#import "ios/chrome/browser/ntp/ui_bundled/new_tab_page_component_factory.h"
#import "ios/chrome/browser/ntp/ui_bundled/new_tab_page_coordinator.h"
#import "ios/chrome/browser/omnibox/model/omnibox_position_browser_agent.h"
#import "ios/chrome/browser/search_engines/model/template_url_service_factory.h"
#import "ios/chrome/browser/segmentation_platform/model/segmentation_platform_service_factory.h"
#import "ios/chrome/browser/sessions/model/ios_chrome_tab_restore_service_factory.h"
#import "ios/chrome/browser/shared/coordinator/layout_guide/layout_guide_util.h"
#import "ios/chrome/browser/shared/coordinator/scene/scene_state.h"
#import "ios/chrome/browser/shared/model/browser/test/test_browser.h"
#import "ios/chrome/browser/shared/model/profile/test/test_profile_ios.h"
#import "ios/chrome/browser/shared/model/profile/test/test_profile_manager_ios.h"
#import "ios/chrome/browser/shared/model/web_state_list/web_state_list.h"
#import "ios/chrome/browser/shared/model/web_state_list/web_state_opener.h"
#import "ios/chrome/browser/shared/public/commands/activity_service_commands.h"
#import "ios/chrome/browser/shared/public/commands/application_commands.h"
#import "ios/chrome/browser/shared/public/commands/command_dispatcher.h"
#import "ios/chrome/browser/shared/public/commands/find_in_page_commands.h"
#import "ios/chrome/browser/shared/public/commands/help_commands.h"
#import "ios/chrome/browser/shared/public/commands/lens_commands.h"
#import "ios/chrome/browser/shared/public/commands/page_info_commands.h"
#import "ios/chrome/browser/shared/public/commands/parcel_tracking_opt_in_commands.h"
#import "ios/chrome/browser/shared/public/commands/qr_scanner_commands.h"
#import "ios/chrome/browser/shared/public/commands/quick_delete_commands.h"
#import "ios/chrome/browser/shared/public/commands/settings_commands.h"
#import "ios/chrome/browser/shared/public/commands/snackbar_commands.h"
#import "ios/chrome/browser/shared/public/commands/text_zoom_commands.h"
#import "ios/chrome/browser/side_swipe/ui_bundled/side_swipe_mediator.h"
#import "ios/chrome/browser/signin/model/authentication_service_factory.h"
#import "ios/chrome/browser/signin/model/fake_authentication_service_delegate.h"
#import "ios/chrome/browser/start_surface/ui_bundled/start_surface_recent_tab_browser_agent.h"
#import "ios/chrome/browser/tabs/model/tab_helper_util.h"
#import "ios/chrome/browser/tabs/ui_bundled/foreground_tab_animation_view.h"
#import "ios/chrome/browser/tabs/ui_bundled/tab_strip_legacy_coordinator.h"
#import "ios/chrome/browser/ui/browser_container/browser_container_view_controller.h"
#import "ios/chrome/browser/ui/fullscreen/fullscreen_controller.h"
#import "ios/chrome/browser/ui/popup_menu/popup_menu_coordinator.h"
#import "ios/chrome/browser/ui/tab_switcher/tab_strip/coordinator/tab_strip_coordinator.h"
#import "ios/chrome/browser/ui/toolbar/toolbar_coordinator.h"
#import "ios/chrome/browser/url_loading/model/new_tab_animation_tab_helper.h"
#import "ios/chrome/browser/url_loading/model/url_loading_notifier_browser_agent.h"
#import "ios/chrome/browser/web/model/page_placeholder_browser_agent.h"
#import "ios/chrome/browser/web/model/web_navigation_browser_agent.h"
#import "ios/chrome/browser/web/model/web_state_update_browser_agent.h"
#import "ios/chrome/browser/web_state_list/model/web_usage_enabler/web_usage_enabler_browser_agent.h"
#import "ios/chrome/test/block_cleanup_test.h"
#import "ios/chrome/test/ios_chrome_scoped_testing_local_state.h"
#import "ios/web/public/test/fakes/fake_web_state.h"
#import "ios/web/public/test/web_task_environment.h"
#import "ios/web/public/web_state.h"
#import "testing/gmock/include/gmock/gmock.h"
#import "testing/gtest/include/gtest/gtest.h"
#import "testing/gtest_mac.h"
#import "third_party/ocmock/OCMock/OCMock.h"
#import "third_party/ocmock/gtest_support.h"
#import "ui/base/device_form_factor.h"

class BrowserViewControllerTest : public BlockCleanupTest {
 public:
 protected:

  void SetUp() override {
    BlockCleanupTest::SetUp();

    scene_state_ = [[SceneState alloc] initWithAppState:nil];

    // Set up a TestChromeBrowserState instance.
    TestChromeBrowserState::Builder test_cbs_builder;

    test_cbs_builder.AddTestingFactory(
        IOSChromeTabRestoreServiceFactory::GetInstance(),
        IOSChromeTabRestoreServiceFactory::GetDefaultFactory());
    test_cbs_builder.AddTestingFactory(
        ios::TemplateURLServiceFactory::GetInstance(),
        ios::TemplateURLServiceFactory::GetDefaultFactory());
    test_cbs_builder.AddTestingFactory(
        IOSChromeLargeIconServiceFactory::GetInstance(),
        IOSChromeLargeIconServiceFactory::GetDefaultFactory());
    test_cbs_builder.AddTestingFactory(
        IOSChromeFaviconLoaderFactory::GetInstance(),
        IOSChromeFaviconLoaderFactory::GetDefaultFactory());
    test_cbs_builder.AddTestingFactory(
        ios::FaviconServiceFactory::GetInstance(),
        ios::FaviconServiceFactory::GetDefaultFactory());
    test_cbs_builder.AddTestingFactory(
        ios::HistoryServiceFactory::GetInstance(),
        ios::HistoryServiceFactory::GetDefaultFactory());
    test_cbs_builder.AddTestingFactory(
        ios::BookmarkModelFactory::GetInstance(),
        ios::BookmarkModelFactory::GetDefaultFactory());
    test_cbs_builder.AddTestingFactory(
        AuthenticationServiceFactory::GetInstance(),
        AuthenticationServiceFactory::GetDefaultFactory());
    test_cbs_builder.AddTestingFactory(
        segmentation_platform::SegmentationPlatformServiceFactory::
            GetInstance(),
        segmentation_platform::SegmentationPlatformServiceFactory::
            GetDefaultFactory());

    browser_state_ =
        profile_manager_.AddProfileWithBuilder(std::move(test_cbs_builder));

    AuthenticationServiceFactory::CreateAndInitializeForBrowserState(
        GetBrowserState(),
        std::make_unique<FakeAuthenticationServiceDelegate>());

    browser_ = std::make_unique<TestBrowser>(GetBrowserState(), scene_state_);
    WebUsageEnablerBrowserAgent::CreateForBrowser(browser_.get());
    UrlLoadingNotifierBrowserAgent::CreateForBrowser(browser_.get());
    LensBrowserAgent::CreateForBrowser(browser_.get());
    WebNavigationBrowserAgent::CreateForBrowser(browser_.get());
    TabUsageRecorderBrowserAgent::CreateForBrowser(browser_.get());
    PagePlaceholderBrowserAgent::CreateForBrowser(browser_.get());
    StartSurfaceRecentTabBrowserAgent::CreateForBrowser(browser_.get());
    OmniboxPositionBrowserAgent::CreateForBrowser(browser_.get());

    WebUsageEnablerBrowserAgent::FromBrowser(browser_.get())
        ->SetWebUsageEnabled(true);

    WebStateUpdateBrowserAgent::CreateForBrowser(browser_.get());

    CommandDispatcher* dispatcher = browser_->GetCommandDispatcher();

    id mockActivityServiceCommandHandler =
        OCMProtocolMock(@protocol(ActivityServiceCommands));
    [dispatcher startDispatchingToTarget:mockActivityServiceCommandHandler
                             forProtocol:@protocol(ActivityServiceCommands)];
    id mockFindInPageCommandHandler =
        OCMProtocolMock(@protocol(FindInPageCommands));
    [dispatcher startDispatchingToTarget:mockFindInPageCommandHandler
                             forProtocol:@protocol(FindInPageCommands)];
    id mockLensCommandHandler = OCMProtocolMock(@protocol(LensCommands));
    [dispatcher startDispatchingToTarget:mockLensCommandHandler
                             forProtocol:@protocol(LensCommands)];
    id mockTextZoomCommandHandler =
        OCMProtocolMock(@protocol(TextZoomCommands));
    [dispatcher startDispatchingToTarget:mockTextZoomCommandHandler
                             forProtocol:@protocol(TextZoomCommands)];
    id mockPageInfoCommandHandler =
        OCMProtocolMock(@protocol(PageInfoCommands));
    [dispatcher startDispatchingToTarget:mockPageInfoCommandHandler
                             forProtocol:@protocol(PageInfoCommands)];
    id mockQrScannerCommandHandler =
        OCMProtocolMock(@protocol(QRScannerCommands));
    [dispatcher startDispatchingToTarget:mockQrScannerCommandHandler
                             forProtocol:@protocol(QRScannerCommands)];
    id mockSnackbarCommandHandler =
        OCMProtocolMock(@protocol(SnackbarCommands));
    [dispatcher startDispatchingToTarget:mockSnackbarCommandHandler
                             forProtocol:@protocol(SnackbarCommands)];
    id mockParcelTrackingCommandHandler =
        OCMProtocolMock(@protocol(ParcelTrackingOptInCommands));
    [dispatcher
        startDispatchingToTarget:mockParcelTrackingCommandHandler
                     forProtocol:@protocol(ParcelTrackingOptInCommands)];

    id mockHelpHandler = OCMProtocolMock(@protocol(HelpCommands));
    [dispatcher startDispatchingToTarget:mockHelpHandler
                             forProtocol:@protocol(HelpCommands)];

    // Set up Applicationhander and SettingsHandler mocks.
    mock_application_handler_ = OCMProtocolMock(@protocol(ApplicationCommands));
    id mock_settings_handler = OCMProtocolMock(@protocol(SettingsCommands));
    [dispatcher startDispatchingToTarget:mock_application_handler_
                             forProtocol:@protocol(ApplicationCommands)];
    [dispatcher startDispatchingToTarget:mock_settings_handler
                             forProtocol:@protocol(SettingsCommands)];

    id mock_quick_delete_handler =
        OCMProtocolMock(@protocol(QuickDeleteCommands));
    [dispatcher startDispatchingToTarget:mock_quick_delete_handler
                             forProtocol:@protocol(QuickDeleteCommands)];

    // Create three web states.
    for (int i = 0; i < 3; i++) {
      web::WebState::CreateParams params(GetBrowserState());
      std::unique_ptr<web::WebState> webState = web::WebState::Create(params);
      AttachTabHelpers(webState.get());
      browser_->GetWebStateList()->InsertWebState(std::move(webState));
      browser_->GetWebStateList()->ActivateWebStateAt(0);
    }

    // Load TemplateURLService.
    TemplateURLService* template_url_service =
        ios::TemplateURLServiceFactory::GetForBrowserState(GetBrowserState());
    template_url_service->Load();

    ClipboardRecentContent::SetInstance(
        std::make_unique<FakeClipboardRecentContent>());

    container_ = [[BrowserContainerViewController alloc] init];
    key_commands_provider_ =
        [[KeyCommandsProvider alloc] initWithBrowser:browser_.get()];
    safe_area_provider_ =
        [[SafeAreaProvider alloc] initWithBrowser:browser_.get()];

    popup_menu_coordinator_ =
        [[PopupMenuCoordinator alloc] initWithBrowser:browser_.get()];
    [popup_menu_coordinator_ start];

    toolbar_coordinator_ =
        [[ToolbarCoordinator alloc] initWithBrowser:browser_.get()];
    [toolbar_coordinator_ start];

    tab_strip_coordinator_ =
        [[TabStripCoordinator alloc] initWithBrowser:browser_.get()];

    legacy_tab_strip_coordinator_ =
        [[TabStripLegacyCoordinator alloc] initWithBrowser:browser_.get()];

    fullscreen_controller_ = FullscreenController::FromBrowser(browser_.get());
    side_swipe_mediator_ = [[SideSwipeMediator alloc]
        initWithFullscreenController:fullscreen_controller_
                        webStateList:browser_->GetWebStateList()];

    bookmarks_coordinator_ =
        [[BookmarksCoordinator alloc] initWithBrowser:browser_.get()];

    tab_usage_recorder_browser_agent_ =
        TabUsageRecorderBrowserAgent::FromBrowser(browser_.get());
    page_placeholder_browser_agent_ =
        PagePlaceholderBrowserAgent::FromBrowser(browser_.get());
    NTPCoordinator_ = [[NewTabPageCoordinator alloc]
         initWithBrowser:browser_.get()
        componentFactory:[[NewTabPageComponentFactory alloc] init]];
    NTPCoordinator_.toolbarDelegate =
        OCMProtocolMock(@protocol(NewTabPageControllerDelegate));

    BrowserViewControllerDependencies dependencies;
    dependencies.popupMenuCoordinator = popup_menu_coordinator_;
    dependencies.toolbarCoordinator = toolbar_coordinator_;
    dependencies.tabStripCoordinator = tab_strip_coordinator_;
    dependencies.legacyTabStripCoordinator = legacy_tab_strip_coordinator_;
    dependencies.sideSwipeMediator = side_swipe_mediator_;
    dependencies.bookmarksCoordinator = bookmarks_coordinator_;
    dependencies.fullscreenController = fullscreen_controller_;
    dependencies.tabUsageRecorderBrowserAgent =
        tab_usage_recorder_browser_agent_;
    dependencies.layoutGuideCenter =
        LayoutGuideCenterForBrowser(browser_.get());
    dependencies.webStateList = browser_->GetWebStateList()->AsWeakPtr();
    dependencies.safeAreaProvider = safe_area_provider_;
    dependencies.pagePlaceholderBrowserAgent = page_placeholder_browser_agent_;
    dependencies.applicationCommandsHandler = mock_application_handler_;
    dependencies.ntpCoordinator = NTPCoordinator_;

    bvc_ = [[BrowserViewController alloc]
        initWithBrowserContainerViewController:container_
                           keyCommandsProvider:key_commands_provider_
                                  dependencies:dependencies];
    bvc_.webUsageEnabled = YES;

    id mockReauthHandler = OCMProtocolMock(@protocol(IncognitoReauthCommands));
    bvc_.reauthHandler = mockReauthHandler;

    UrlLoadingNotifierBrowserAgent* url_loading_notifier =
        UrlLoadingNotifierBrowserAgent::FromBrowser(browser_.get());
    tab_events_mediator_ = [[TabEventsMediator alloc]
        initWithWebStateList:browser_.get()->GetWebStateList()
              ntpCoordinator:NTPCoordinator_
                browserState:GetBrowserState()
             loadingNotifier:url_loading_notifier];
    tab_events_mediator_.consumer = bvc_;

    // Force the view to load.
    UIWindow* window = [[UIWindow alloc] initWithFrame:CGRectZero];
    window.rootViewController = bvc_;
    [window makeKeyAndVisible];
    window_ = window;
  }

  void TearDown() override {
    [tab_events_mediator_ disconnect];
    [[bvc_ view] removeFromSuperview];
    [bvc_ shutdown];
    [bookmarks_coordinator_ stop];
    [tab_strip_coordinator_ stop];
    [legacy_tab_strip_coordinator_ stop];
    [toolbar_coordinator_ stop];
    [popup_menu_coordinator_ stop];
    [NTPCoordinator_ stop];
    [side_swipe_mediator_ disconnect];
    ClipboardRecentContent::SetInstance(nullptr);

    BlockCleanupTest::TearDown();
  }

  TestChromeBrowserState* GetBrowserState() { return browser_state_.get(); }

  web::WebState* ActiveWebState() {
    return browser_->GetWebStateList()->GetActiveWebState();
  }

  void InsertWebState(std::unique_ptr<web::WebState> web_state) {
    WebStateList* web_state_list = browser_->GetWebStateList();
    web_state_list->InsertWebState(
        std::move(web_state),
        WebStateList::InsertionParams::Automatic().Activate());
  }

  std::unique_ptr<web::WebState> CreateWebState() {
    web::WebState::CreateParams params(GetBrowserState());
    auto web_state = web::WebState::Create(params);
    AttachTabHelpers(web_state.get());
    return web_state;
  }

  std::unique_ptr<web::WebState> CreateOffTheRecordWebState() {
    web::WebState::CreateParams params(
        GetBrowserState()
            ->CreateOffTheRecordBrowserStateWithTestingFactories());
    auto web_state = web::WebState::Create(params);
    AttachTabHelpers(web_state.get());
    return web_state;
  }

  // Fakes loading the NTP for a given `web_state`.
  void LoadNTP(web::WebState* web_state) {
    web::FakeWebState fake_web_state;
    fake_web_state.SetVisibleURL(GURL("chrome://newtab/"));
    web::WebStateObserver* NTPHelper =
        (web::WebStateObserver*)NewTabPageTabHelper::FromWebState(web_state);
    // Use the fake_web_state to fake the NTPHelper into believing that the NTP
    // has been loaded.
    NTPHelper->PageLoaded(&fake_web_state,
                          web::PageLoadCompletionStatus::SUCCESS);
  }

  void ExpectNewTabInsertionAnimation(bool animated, ProceduralBlock block) {
    id mock_animation_view_class =
        OCMClassMock([ForegroundTabAnimationView class]);

    if (animated) {
      OCMExpect([mock_animation_view_class alloc]).andReturn(nil);
    } else {
      [[mock_animation_view_class reject] alloc];
    }

    block();

    [mock_animation_view_class verify];
  }

  // Used as an OCMArg to check that the argument's `contentView` matches the
  // return value of the given `expected_view` block.
  id OCMArgWithContentView(UIView* (^expected_view)()) {
    return [OCMArg checkWithBlock:^(UIView* view) {
      UIView* content_view =
          base::apple::ObjCCast<ForegroundTabAnimationView>(view).contentView;
      return content_view == expected_view();
    }];
  }

  MOCK_METHOD0(OnCompletionCalled, void());

  web::WebTaskEnvironment task_environment_;
  IOSChromeScopedTestingLocalState scoped_testing_local_state_;
  TestProfileManagerIOS profile_manager_;
  raw_ptr<TestChromeBrowserState> browser_state_;
  std::unique_ptr<Browser> browser_;
  KeyCommandsProvider* key_commands_provider_;
  BrowserContainerViewController* container_;
  BrowserViewController* bvc_;
  UIWindow* window_;
  SceneState* scene_state_;
  PopupMenuCoordinator* popup_menu_coordinator_;
  ToolbarCoordinator* toolbar_coordinator_;
  TabStripCoordinator* tab_strip_coordinator_;
  TabStripLegacyCoordinator* legacy_tab_strip_coordinator_;
  SideSwipeMediator* side_swipe_mediator_;
  BookmarksCoordinator* bookmarks_coordinator_;
  raw_ptr<FullscreenController> fullscreen_controller_;
  TabEventsMediator* tab_events_mediator_;
  NewTabPageCoordinator* NTPCoordinator_;
  raw_ptr<TabUsageRecorderBrowserAgent> tab_usage_recorder_browser_agent_;
  SafeAreaProvider* safe_area_provider_;
  raw_ptr<PagePlaceholderBrowserAgent> page_placeholder_browser_agent_;
  id mock_application_handler_;
};

TEST_F(BrowserViewControllerTest, TestWebStateSelected) {
  [bvc_ webStateSelected];
  EXPECT_EQ(ActiveWebState()->GetView().superview, container_.view);
  EXPECT_TRUE(ActiveWebState()->IsVisible());
}

TEST_F(BrowserViewControllerTest, TestClearPresentedState) {
  EXPECT_CALL(*this, OnCompletionCalled());
  [bvc_
      clearPresentedStateWithCompletion:^{
        this->OnCompletionCalled();
      }
                         dismissOmnibox:YES];
}

// Tests that WebState::WasShown() and WebState::WasHidden() is properly called
// for WebState activations in the BrowserViewController's WebStateList.
TEST_F(BrowserViewControllerTest, UpdateWebStateVisibility) {
  WebStateList* web_state_list = browser_->GetWebStateList();
  ASSERT_EQ(3, web_state_list->count());

  // Activate each WebState in the list and check the visibility.
  web_state_list->ActivateWebStateAt(0);
  EXPECT_EQ(web_state_list->GetWebStateAt(0)->IsVisible(), true);
  EXPECT_EQ(web_state_list->GetWebStateAt(1)->IsVisible(), false);
  EXPECT_EQ(web_state_list->GetWebStateAt(2)->IsVisible(), false);
  web_state_list->ActivateWebStateAt(1);
  EXPECT_EQ(web_state_list->GetWebStateAt(0)->IsVisible(), false);
  EXPECT_EQ(web_state_list->GetWebStateAt(1)->IsVisible(), true);
  EXPECT_EQ(web_state_list->GetWebStateAt(2)->IsVisible(), false);
  web_state_list->ActivateWebStateAt(2);
  EXPECT_EQ(web_state_list->GetWebStateAt(0)->IsVisible(), false);
  EXPECT_EQ(web_state_list->GetWebStateAt(1)->IsVisible(), false);
  EXPECT_EQ(web_state_list->GetWebStateAt(2)->IsVisible(), true);
}

TEST_F(BrowserViewControllerTest, didInsertWebStateWithAnimation) {
  // Animation is only expected on iPhone, not iPad.
  bool animation_expected =
      ui::GetDeviceFormFactor() == ui::DEVICE_FORM_FACTOR_PHONE;
  ExpectNewTabInsertionAnimation(animation_expected, ^{
    auto web_state = CreateWebState();
    InsertWebState(std::move(web_state));
  });
}

TEST_F(BrowserViewControllerTest, didInsertWebStateWithoutAnimation) {
  ExpectNewTabInsertionAnimation(false, ^{
    auto web_state = CreateWebState();
    NewTabAnimationTabHelper::CreateForWebState(web_state.get());
    NewTabAnimationTabHelper::FromWebState(web_state.get())
        ->DisableNewTabAnimation();
    InsertWebState(std::move(web_state));
  });
}

TEST_F(BrowserViewControllerTest,
       presentIncognitoReauthDismissesPresentedState) {
  // Add a presented VC so dismiss modal dialogs is dispatched.
  [bvc_ presentViewController:[[UIViewController alloc] init]
                     animated:NO
                   completion:nil];

  OCMExpect([mock_application_handler_ dismissModalDialogsWithCompletion:nil]);

  // Present incognito authentication must dismiss presented state.
  [bvc_ setItemsRequireAuthentication:YES];

  // Verify that the command was dispatched.
  EXPECT_OCMOCK_VERIFY(mock_application_handler_);
}

// Tests that an off-the-record web state can be created and inserted in the
// browser view controller.
TEST_F(BrowserViewControllerTest, didInsertOffTheRecordWebState) {
  // The animation being tested only runs on the phone form factor.
  if (ui::GetDeviceFormFactor() == ui::DEVICE_FORM_FACTOR_TABLET) {
    return;
  }
  id container_view_mock = OCMPartialMock(container_.view);

  // Add an off-the-record web state with supported tab helpers.
  std::unique_ptr<web::WebState> web_state = CreateOffTheRecordWebState();
  UIView* web_state_view = web_state->GetView();

  // Insert in browser web state list.
  [[container_view_mock expect] addSubview:OCMArgWithContentView(^{
                                  return web_state_view;
                                })];
  InsertWebState(std::move(web_state));
  EXPECT_OCMOCK_VERIFY(container_view_mock);
}

// Tests that when a webstate is inserted, the correct view is used during
// the animation.
// TODO(crbug.com/344849341): This test fails when run as part of the entire
// test suite. Retries seem to pass.
TEST_F(BrowserViewControllerTest, ViewOnInsert) {
  // The animation being tested only runs on the phone form factor.
  if (ui::GetDeviceFormFactor() == ui::DEVICE_FORM_FACTOR_TABLET) {
    return;
  }

  id container_view_mock = OCMPartialMock(container_.view);

  // When inserting a non-ntp WebState, the WebState's view should be animated.
  std::unique_ptr<web::WebState> web_state = CreateWebState();
  UIView* web_state_view = web_state->GetView();
  [[container_view_mock expect] addSubview:OCMArgWithContentView(^{
                                  return web_state_view;
                                })];
  InsertWebState(std::move(web_state));
  EXPECT_OCMOCK_VERIFY(container_view_mock);

  // When inserting an NTP WebState, the NTP's view should be animated.
  std::unique_ptr<web::WebState> ntp_web_state = CreateWebState();
  LoadNTP(ntp_web_state.get());
  [[container_view_mock expect] addSubview:OCMArgWithContentView(^{
                                  return NTPCoordinator_.viewController.view;
                                })];
  InsertWebState(std::move(ntp_web_state));
  EXPECT_OCMOCK_VERIFY(container_view_mock);

  // When inserting a second NTP WebState, the NTP's view should be animated.
  // In this case the NTP is already started, so we want to ensure that the
  // correct view is used in this case too.
  std::unique_ptr<web::WebState> ntp_web_state2 = CreateWebState();
  LoadNTP(ntp_web_state2.get());
  [[container_view_mock expect] addSubview:OCMArgWithContentView(^{
                                  return NTPCoordinator_.viewController.view;
                                })];
  InsertWebState(std::move(ntp_web_state2));
  EXPECT_OCMOCK_VERIFY(container_view_mock);
}