|  | // Copyright 2017 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/web/page_placeholder_tab_helper.h" | 
|  |  | 
|  | #import <Foundation/Foundation.h> | 
|  |  | 
|  | #include <memory> | 
|  |  | 
|  | #import "base/test/ios/wait_util.h" | 
|  | #include "ios/chrome/browser/browser_state/test_chrome_browser_state.h" | 
|  | #import "ios/chrome/browser/snapshots/snapshot_tab_helper.h" | 
|  | #import "ios/web/public/test/fakes/test_web_state.h" | 
|  | #include "ios/web/public/test/test_web_thread_bundle.h" | 
|  | #include "testing/gtest/include/gtest/gtest.h" | 
|  | #include "testing/platform_test.h" | 
|  |  | 
|  | #if !defined(__has_feature) || !__has_feature(objc_arc) | 
|  | #error "This file requires ARC support." | 
|  | #endif | 
|  |  | 
|  | using base::test::ios::kWaitForUIElementTimeout; | 
|  | using base::test::ios::WaitUntilConditionOrTimeout; | 
|  |  | 
|  | // Test fixture for PagePlaceholderTabHelper class. | 
|  | class PagePlaceholderTabHelperTest : public PlatformTest { | 
|  | protected: | 
|  | PagePlaceholderTabHelperTest() { | 
|  | browser_state_ = TestChromeBrowserState::Builder().Build(); | 
|  | web_state_ = std::make_unique<web::TestWebState>(); | 
|  | web_state_->SetBrowserState(browser_state_.get()); | 
|  |  | 
|  | CGRect frame = {CGPointZero, CGSizeMake(400, 300)}; | 
|  | web_state_view_ = [[UIView alloc] initWithFrame:frame]; | 
|  | web_state_view_.backgroundColor = [UIColor blueColor]; | 
|  | web_state_->SetView(web_state_view_); | 
|  |  | 
|  | // PagePlaceholderTabHelper uses SnapshotTabHelper, so ensure it has been | 
|  | // created. | 
|  | SnapshotTabHelper::CreateForWebState(web_state_.get(), | 
|  | [[NSUUID UUID] UUIDString]); | 
|  | PagePlaceholderTabHelper::CreateForWebState(web_state_.get()); | 
|  | } | 
|  |  | 
|  | PagePlaceholderTabHelper* tab_helper() { | 
|  | return PagePlaceholderTabHelper::FromWebState(web_state_.get()); | 
|  | } | 
|  |  | 
|  | web::TestWebThreadBundle thread_bundle_; | 
|  | std::unique_ptr<ios::ChromeBrowserState> browser_state_; | 
|  | std::unique_ptr<web::TestWebState> web_state_; | 
|  | UIView* web_state_view_ = nil; | 
|  | }; | 
|  |  | 
|  | // Tests that placeholder is not shown after DidStartNavigation if it was not | 
|  | // requested. | 
|  | TEST_F(PagePlaceholderTabHelperTest, NotShown) { | 
|  | ASSERT_FALSE(tab_helper()->displaying_placeholder()); | 
|  | ASSERT_FALSE(tab_helper()->will_add_placeholder_for_next_navigation()); | 
|  | web_state_->OnNavigationStarted(nullptr); | 
|  | EXPECT_FALSE(tab_helper()->displaying_placeholder()); | 
|  | EXPECT_FALSE(tab_helper()->will_add_placeholder_for_next_navigation()); | 
|  | } | 
|  |  | 
|  | // Tests that placehold is not shown after DidStartNavigation if it was | 
|  | // cancelled before the navigation. | 
|  | TEST_F(PagePlaceholderTabHelperTest, NotShownIfCancelled) { | 
|  | ASSERT_FALSE(tab_helper()->will_add_placeholder_for_next_navigation()); | 
|  | tab_helper()->AddPlaceholderForNextNavigation(); | 
|  | ASSERT_FALSE(tab_helper()->displaying_placeholder()); | 
|  | EXPECT_TRUE(tab_helper()->will_add_placeholder_for_next_navigation()); | 
|  | tab_helper()->CancelPlaceholderForNextNavigation(); | 
|  | ASSERT_FALSE(tab_helper()->displaying_placeholder()); | 
|  | EXPECT_FALSE(tab_helper()->will_add_placeholder_for_next_navigation()); | 
|  | web_state_->OnNavigationStarted(nullptr); | 
|  | EXPECT_FALSE(tab_helper()->displaying_placeholder()); | 
|  | EXPECT_FALSE(tab_helper()->will_add_placeholder_for_next_navigation()); | 
|  | } | 
|  |  | 
|  | // Tests that placeholder is shown between DidStartNavigation/PageLoaded | 
|  | // WebStateObserver callbacks. | 
|  | TEST_F(PagePlaceholderTabHelperTest, Shown) { | 
|  | ASSERT_FALSE(tab_helper()->will_add_placeholder_for_next_navigation()); | 
|  | tab_helper()->AddPlaceholderForNextNavigation(); | 
|  | ASSERT_FALSE(tab_helper()->displaying_placeholder()); | 
|  | EXPECT_TRUE(tab_helper()->will_add_placeholder_for_next_navigation()); | 
|  |  | 
|  | web_state_->OnNavigationStarted(nullptr); | 
|  | EXPECT_TRUE(tab_helper()->displaying_placeholder()); | 
|  | EXPECT_FALSE(tab_helper()->will_add_placeholder_for_next_navigation()); | 
|  |  | 
|  | web_state_->OnPageLoaded(web::PageLoadCompletionStatus::SUCCESS); | 
|  | EXPECT_FALSE(tab_helper()->displaying_placeholder()); | 
|  | EXPECT_FALSE(tab_helper()->will_add_placeholder_for_next_navigation()); | 
|  | } | 
|  |  | 
|  | // Tests that placeholder is removed if cancelled while presented. | 
|  | TEST_F(PagePlaceholderTabHelperTest, RemovedIfCancelledWhileShown) { | 
|  | ASSERT_FALSE(tab_helper()->will_add_placeholder_for_next_navigation()); | 
|  | tab_helper()->AddPlaceholderForNextNavigation(); | 
|  | ASSERT_FALSE(tab_helper()->displaying_placeholder()); | 
|  | EXPECT_TRUE(tab_helper()->will_add_placeholder_for_next_navigation()); | 
|  | web_state_->OnNavigationStarted(nullptr); | 
|  | EXPECT_TRUE(tab_helper()->displaying_placeholder()); | 
|  | EXPECT_FALSE(tab_helper()->will_add_placeholder_for_next_navigation()); | 
|  |  | 
|  | tab_helper()->CancelPlaceholderForNextNavigation(); | 
|  | EXPECT_FALSE(tab_helper()->displaying_placeholder()); | 
|  | EXPECT_FALSE(tab_helper()->will_add_placeholder_for_next_navigation()); | 
|  | } | 
|  |  | 
|  | // Tests that destructing WebState removes the placeholder. | 
|  | TEST_F(PagePlaceholderTabHelperTest, DestructWebStateWhenShowingPlaceholder) { | 
|  | ASSERT_FALSE(tab_helper()->will_add_placeholder_for_next_navigation()); | 
|  | tab_helper()->AddPlaceholderForNextNavigation(); | 
|  | ASSERT_FALSE(tab_helper()->displaying_placeholder()); | 
|  |  | 
|  | EXPECT_TRUE(tab_helper()->will_add_placeholder_for_next_navigation()); | 
|  | web_state_->OnNavigationStarted(nullptr); | 
|  |  | 
|  | EXPECT_TRUE(tab_helper()->displaying_placeholder()); | 
|  | EXPECT_FALSE(tab_helper()->will_add_placeholder_for_next_navigation()); | 
|  | EXPECT_TRUE([[web_state_view_ subviews] count] != 0); | 
|  | web_state_.reset(); | 
|  |  | 
|  | // The tab helper has been deleted at this point, so do not check the value | 
|  | // of displaying_placeholder(). Check that the view has no subviews (i.e. no | 
|  | // placeholder is presented) after some time (since the placeholder view is | 
|  | // removed with an animation). | 
|  | EXPECT_TRUE(WaitUntilConditionOrTimeout(kWaitForUIElementTimeout, ^{ | 
|  | return [[web_state_view_ subviews] count] == 0; | 
|  | })); | 
|  | } |