chromium/ios/chrome/browser/side_swipe/ui_bundled/side_swipe_mediator_unittest.mm

// Copyright 2015 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/side_swipe/ui_bundled/side_swipe_mediator.h"

#import <WebKit/WebKit.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/url/chrome_url_constants.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/side_swipe/ui_bundled/side_swipe_mediator+Testing.h"
#import "ios/chrome/browser/ui/fullscreen/fullscreen_controller.h"
#import "ios/chrome/test/scoped_key_window.h"
#import "ios/web/common/crw_web_view_content_view.h"
#import "ios/web/common/features.h"
#import "ios/web/public/navigation/navigation_item.h"
#import "ios/web/public/test/fakes/fake_navigation_context.h"
#import "ios/web/public/test/fakes/fake_navigation_manager.h"
#import "ios/web/public/test/fakes/fake_web_state.h"
#import "ios/web/public/test/web_task_environment.h"
#import "ios/web/public/ui/crw_web_view_proxy.h"
#import "ios/web/public/ui/crw_web_view_scroll_view_proxy.h"
#import "testing/platform_test.h"
#import "third_party/ocmock/OCMock/OCMock.h"
#import "third_party/ocmock/gtest_support.h"
#import "third_party/ocmock/ocmock_extensions.h"

namespace {

class SideSwipeMediatorTest : public PlatformTest {
 public:
  SideSwipeMediatorTest()
      : web_view_([[WKWebView alloc]
            initWithFrame:scoped_window_.Get().bounds
            configuration:[[WKWebViewConfiguration alloc] init]]),
        content_view_([[CRWWebViewContentView alloc]
            initWithWebView:web_view_
                 scrollView:web_view_.scrollView
            fullscreenState:CrFullscreenState::kNotInFullScreen]) {
    auto original_web_state(std::make_unique<web::FakeWebState>());
    original_web_state->SetView(content_view_);
    CRWWebViewScrollViewProxy* scroll_view_proxy =
        [[CRWWebViewScrollViewProxy alloc] init];
    UIScrollView* scroll_view = [[UIScrollView alloc] init];
    [scroll_view_proxy setScrollView:scroll_view];
    id web_view_proxy_mock = OCMProtocolMock(@protocol(CRWWebViewProxy));
    [[[web_view_proxy_mock stub] andReturn:scroll_view_proxy] scrollViewProxy];
    original_web_state->SetWebViewProxy(web_view_proxy_mock);

    browser_state_ = TestChromeBrowserState::Builder().Build();
    browser_ = std::make_unique<TestBrowser>(browser_state_.get());

    browser_->GetWebStateList()->InsertWebState(std::move(original_web_state));

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

    view_ = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 320, 240)];

    [side_swipe_mediator_ addHorizontalGesturesToView:view_];
  }

  ~SideSwipeMediatorTest() override { [side_swipe_mediator_ disconnect]; }

  web::WebTaskEnvironment task_environment_;
  std::unique_ptr<TestChromeBrowserState> browser_state_;
  std::unique_ptr<Browser> browser_;
  UIView* view_;
  SideSwipeMediator* side_swipe_mediator_;
  ScopedKeyWindow scoped_window_;
  WKWebView* web_view_ = nil;
  CRWWebViewContentView* content_view_ = nil;
};

TEST_F(SideSwipeMediatorTest, TestConstructor) {
  EXPECT_TRUE(side_swipe_mediator_);
}

// Tests that pages that need to use Chromium native swipe
TEST_F(SideSwipeMediatorTest, TestEdgeNavigationEnabled) {
  auto fake_web_state = std::make_unique<web::FakeWebState>();
  auto fake_navigation_manager = std::make_unique<web::FakeNavigationManager>();
  std::unique_ptr<web::NavigationItem> item = web::NavigationItem::Create();
  fake_navigation_manager->SetVisibleItem(item.get());
  fake_web_state->SetNavigationManager(std::move(fake_navigation_manager));

  // The NTP and chrome://crash should use native swipe.
  item->SetURL(GURL(kChromeUINewTabURL));
  [side_swipe_mediator_
      updateNavigationEdgeSwipeForWebState:fake_web_state.get()];
  EXPECT_TRUE(side_swipe_mediator_.leadingEdgeNavigationEnabled);
  EXPECT_TRUE(side_swipe_mediator_.trailingEdgeNavigationEnabled);

  item->SetURL(GURL("chrome://crash"));
  [side_swipe_mediator_
      updateNavigationEdgeSwipeForWebState:fake_web_state.get()];
  EXPECT_TRUE(side_swipe_mediator_.leadingEdgeNavigationEnabled);
  EXPECT_TRUE(side_swipe_mediator_.trailingEdgeNavigationEnabled);

  item->SetURL(GURL("http://wwww.test.com"));
  [side_swipe_mediator_
      updateNavigationEdgeSwipeForWebState:fake_web_state.get()];
  EXPECT_FALSE(side_swipe_mediator_.leadingEdgeNavigationEnabled);
  EXPECT_FALSE(side_swipe_mediator_.trailingEdgeNavigationEnabled);

  item->SetURL(GURL("chrome://foo"));
  [side_swipe_mediator_
      updateNavigationEdgeSwipeForWebState:fake_web_state.get()];
  EXPECT_FALSE(side_swipe_mediator_.leadingEdgeNavigationEnabled);
  EXPECT_FALSE(side_swipe_mediator_.trailingEdgeNavigationEnabled);

  item->SetURL(GURL("chrome://version"));
  [side_swipe_mediator_
      updateNavigationEdgeSwipeForWebState:fake_web_state.get()];
  EXPECT_FALSE(side_swipe_mediator_.leadingEdgeNavigationEnabled);
  EXPECT_FALSE(side_swipe_mediator_.trailingEdgeNavigationEnabled);

  // Tests that when webstate is nil calling
  // updateNavigationEdgeSwipeForWebState doesn't change the edge navigation
  // state.
  item->SetURL(GURL("http://wwww.test.com"));
  [side_swipe_mediator_ updateNavigationEdgeSwipeForWebState:nil];
  EXPECT_FALSE(side_swipe_mediator_.leadingEdgeNavigationEnabled);
  EXPECT_FALSE(side_swipe_mediator_.trailingEdgeNavigationEnabled);
  side_swipe_mediator_.leadingEdgeNavigationEnabled = YES;
  side_swipe_mediator_.trailingEdgeNavigationEnabled = YES;
  [side_swipe_mediator_ updateNavigationEdgeSwipeForWebState:nil];
  EXPECT_TRUE(side_swipe_mediator_.leadingEdgeNavigationEnabled);
  EXPECT_TRUE(side_swipe_mediator_.trailingEdgeNavigationEnabled);
}

// Tests that when the active webState is changed or when the active webState
// finishes navigation, the edge state will be updated accordingly.
TEST_F(SideSwipeMediatorTest, ObserversTriggerStateUpdate) {
  ASSERT_FALSE(side_swipe_mediator_.leadingEdgeNavigationEnabled);
  ASSERT_FALSE(side_swipe_mediator_.trailingEdgeNavigationEnabled);

  auto fake_web_state = std::make_unique<web::FakeWebState>();
  fake_web_state->SetView(content_view_);
  CRWWebViewScrollViewProxy* scroll_view_proxy =
      [[CRWWebViewScrollViewProxy alloc] init];
  UIScrollView* scroll_view = [[UIScrollView alloc] init];
  [scroll_view_proxy setScrollView:scroll_view];
  id web_view_proxy_mock = OCMProtocolMock(@protocol(CRWWebViewProxy));
  [[[web_view_proxy_mock stub] andReturn:scroll_view_proxy] scrollViewProxy];
  fake_web_state->SetWebViewProxy(web_view_proxy_mock);
  web::FakeWebState* fake_web_state_ptr = fake_web_state.get();
  auto fake_navigation_manager = std::make_unique<web::FakeNavigationManager>();
  std::unique_ptr<web::NavigationItem> item = web::NavigationItem::Create();
  fake_navigation_manager->SetVisibleItem(item.get());
  fake_navigation_manager->SetLastCommittedItem(item.get());
  fake_web_state->SetNavigationManager(std::move(fake_navigation_manager));

  // The NTP and chrome://crash should use native swipe.
  item->SetURL(GURL(kChromeUINewTabURL));
  // Insert the WebState and make sure it's active. This should trigger
  // the activation WebState change and update edge navigation state.
  browser_->GetWebStateList()->InsertWebState(
      std::move(fake_web_state),
      WebStateList::InsertionParams::AtIndex(1).Activate());
  EXPECT_TRUE(side_swipe_mediator_.leadingEdgeNavigationEnabled);
  EXPECT_TRUE(side_swipe_mediator_.trailingEdgeNavigationEnabled);

  // Non native URL should have shouldn't be handled by SideSwipeMediator.
  item->SetURL(GURL("http://wwww.test.test"));
  web::FakeNavigationContext context;
  context.SetHasCommitted(true);
  // Navigation finish should also update the edge navigation state.
  fake_web_state_ptr->OnNavigationFinished(&context);
  EXPECT_FALSE(side_swipe_mediator_.leadingEdgeNavigationEnabled);
  EXPECT_FALSE(side_swipe_mediator_.trailingEdgeNavigationEnabled);
}

}  // anonymous namespace