blob: ace507f508108986d99b7e6303b9977e8ac3460c [file] [log] [blame]
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#import "ios/chrome/browser/overscroll_actions/overscroll_actions_tab_helper.h"
#import <UIKit/UIKit.h>
#import "base/test/ios/wait_util.h"
#include "ios/chrome/browser/browser_state/test_chrome_browser_state.h"
#import "ios/chrome/browser/ui/overscroll_actions/overscroll_actions_controller.h"
#import "ios/chrome/browser/ui/overscroll_actions/overscroll_actions_view.h"
#import "ios/chrome/common/colors/dynamic_color_util.h"
#import "ios/chrome/common/colors/semantic_color_names.h"
#import "ios/chrome/test/fakes/fake_overscroll_actions_controller_delegate.h"
#import "ios/web/public/test/fakes/test_web_state.h"
#include "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"
#include "testing/gtest/include/gtest/gtest.h"
#import "testing/gtest_mac.h"
#include "testing/platform_test.h"
#import "third_party/ocmock/OCMock/OCMock.h"
#include "third_party/ocmock/gtest_support.h"
#if !defined(__has_feature) || !__has_feature(objc_arc)
#error "This file requires ARC support."
#endif
// Test fixture for OverscrollActionsTabHelper class.
class OverscrollActionsTabHelperTest : public PlatformTest {
protected:
OverscrollActionsTabHelperTest()
: browser_state_(TestChromeBrowserState::Builder().Build()),
overscroll_delegate_(
[[FakeOverscrollActionsControllerDelegate alloc] init]),
scroll_view_proxy_([[CRWWebViewScrollViewProxy alloc] init]),
ui_scroll_view_([[UIScrollView alloc] init]) {
OverscrollActionsTabHelper::CreateForWebState(&web_state_);
[scroll_view_proxy_ setScrollView:ui_scroll_view_];
id web_view_proxy_mock = OCMProtocolMock(@protocol(CRWWebViewProxy));
[[[web_view_proxy_mock stub] andReturn:scroll_view_proxy_] scrollViewProxy];
web_state_.SetWebViewProxy(web_view_proxy_mock);
// Setting insets to imitate having omnibox & toolbar.
scroll_view_proxy_.contentInset = UIEdgeInsetsMake(40, 0, 82, 0);
}
OverscrollActionsTabHelper* overscroll_tab_helper() {
return OverscrollActionsTabHelper::FromWebState(&web_state_);
}
UIView* action_view() {
return overscroll_delegate_.headerView.subviews.firstObject;
}
// Simulates scroll on the |scroll_view_proxy_| view, which should trigger
// page refresh action.
void SimulatePullForRefreshAction() {
[scroll_view_proxy_ scrollViewWillBeginDragging:ui_scroll_view_];
// Wait until scroll action is allowed. There is no condition to wait, just
// a time period.
base::test::ios::SpinRunLoopWithMinDelay(base::TimeDelta::FromSecondsD(
kMinimumPullDurationToTransitionToReadyInSeconds));
[scroll_view_proxy_ scrollViewDidScroll:ui_scroll_view_];
scroll_view_proxy_.contentOffset = CGPointMake(0, -293);
CGPoint target_offset = CGPointMake(0, -92);
[scroll_view_proxy_ scrollViewWillEndDragging:ui_scroll_view_
withVelocity:CGPointMake(0, -1.5)
targetContentOffset:&target_offset];
[overscroll_delegate_.headerView layoutIfNeeded];
[scroll_view_proxy_ scrollViewDidEndDragging:ui_scroll_view_
willDecelerate:NO];
}
web::WebTaskEnvironment task_environment_;
std::unique_ptr<ios::ChromeBrowserState> browser_state_;
web::TestWebState web_state_;
FakeOverscrollActionsControllerDelegate* overscroll_delegate_;
CRWWebViewScrollViewProxy* scroll_view_proxy_;
UIScrollView* ui_scroll_view_;
};
// Tests that OverscrollActionsControllerDelegate is set correctly and triggered
// When there is a view pull.
// TODO(crbug.com/944599): Fails on device.
#if TARGET_IPHONE_SIMULATOR
#define MAYBE_TestDelegateTrigger TestDelegateTrigger
#else
#define MAYBE_TestDelegateTrigger DISABLED_TestDelegateTrigger
#endif
TEST_F(OverscrollActionsTabHelperTest, MAYBE_TestDelegateTrigger) {
web_state_.SetBrowserState(browser_state_.get());
overscroll_tab_helper()->SetDelegate(overscroll_delegate_);
// Start pull for page refresh action.
SimulatePullForRefreshAction();
// Wait for the layout calls and the delegate call.
using base::test::ios::WaitUntilConditionOrTimeout;
using base::test::ios::kWaitForUIElementTimeout;
EXPECT_TRUE(WaitUntilConditionOrTimeout(kWaitForUIElementTimeout, ^{
return overscroll_delegate_.selectedAction == OverscrollAction::REFRESH;
}));
}
// Tests that overscrolls actions view style is set correctly, for regular
// browsing browser state.
// TODO(crbug.com/944599): Fails on device.
#if TARGET_IPHONE_SIMULATOR
#define MAYBE_TestRegularBrowserStateStyle TestRegularBrowserStateStyle
#else
#define MAYBE_TestRegularBrowserStateStyle DISABLED_TestRegularBrowserStateStyle
#endif
TEST_F(OverscrollActionsTabHelperTest, MAYBE_TestRegularBrowserStateStyle) {
web_state_.SetBrowserState(browser_state_.get());
overscroll_tab_helper()->SetDelegate(overscroll_delegate_);
SimulatePullForRefreshAction();
UIColor* expected_color = [UIColor colorNamed:kBackgroundColor];
EXPECT_TRUE(action_view());
EXPECT_NSEQ(expected_color, action_view().backgroundColor);
}
// Tests that overscrolls actions view style is set correctly, for off the
// record browser state.
// TODO(crbug.com/944599): Fails on device.
#if TARGET_IPHONE_SIMULATOR
#define MAYBE_TestOffTheRecordBrowserStateStyle \
TestOffTheRecordBrowserStateStyle
#else
#define MAYBE_TestOffTheRecordBrowserStateStyle \
DISABLED_TestOffTheRecordBrowserStateStyle
#endif
TEST_F(OverscrollActionsTabHelperTest,
MAYBE_TestOffTheRecordBrowserStateStyle) {
web_state_.SetBrowserState(
browser_state_->GetOffTheRecordChromeBrowserState());
overscroll_tab_helper()->SetDelegate(overscroll_delegate_);
SimulatePullForRefreshAction();
// For iOS 13 and dark mode, the incognito overscroll actions view uses a
// dynamic color.
UIColor* expected_color =
color::DarkModeDynamicColor([UIColor colorNamed:kBackgroundColor], true,
[UIColor colorNamed:kBackgroundDarkColor]);
EXPECT_TRUE(action_view());
EXPECT_NSEQ(expected_color, action_view().backgroundColor);
}
// Tests that overscroll state is reset when Clear() is called.
TEST_F(OverscrollActionsTabHelperTest, TestClear) {
web_state_.SetBrowserState(browser_state_.get());
overscroll_tab_helper()->SetDelegate(overscroll_delegate_);
OverscrollActionsController* controller =
overscroll_tab_helper()->GetOverscrollActionsController();
EXPECT_EQ(OverscrollState::NO_PULL_STARTED, controller.overscrollState);
SimulatePullForRefreshAction();
EXPECT_EQ(OverscrollState::ACTION_READY, controller.overscrollState);
overscroll_tab_helper()->Clear();
EXPECT_EQ(OverscrollState::NO_PULL_STARTED, controller.overscrollState);
}