blob: 3fcefeb1fa17bec67bfce2fa08764f0824a15bcc [file] [log] [blame]
// 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.
#include <memory>
#include <string>
#include "base/scoped_observer.h"
#include "base/strings/stringprintf.h"
#import "ios/testing/wait_util.h"
#import "ios/web/public/navigation_item.h"
#import "ios/web/public/navigation_manager.h"
#import "ios/web/public/test/fakes/test_native_content.h"
#import "ios/web/public/test/fakes/test_native_content_provider.h"
#import "ios/web/public/test/http_server/html_response_provider.h"
#import "ios/web/public/test/http_server/html_response_provider_impl.h"
#import "ios/web/public/test/http_server/http_server.h"
#include "ios/web/public/test/http_server/http_server_util.h"
#import "ios/web/public/test/navigation_test_util.h"
#import "ios/web/public/test/web_view_content_test_util.h"
#import "ios/web/public/test/web_view_interaction_test_util.h"
#import "ios/web/public/web_client.h"
#import "ios/web/public/web_state/navigation_context.h"
#include "ios/web/public/web_state/web_state_observer.h"
#import "ios/web/public/web_state/web_state_policy_decider.h"
#include "ios/web/test/test_url_constants.h"
#import "ios/web/test/web_int_test.h"
#import "ios/web/web_state/ui/crw_web_controller.h"
#import "ios/web/web_state/web_state_impl.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/base/page_transition_types.h"
#include "url/gurl.h"
#include "url/scheme_host_port.h"
#if !defined(__has_feature) || !__has_feature(objc_arc)
#error "This file requires ARC support."
#endif
namespace web {
namespace {
const char kTestPageText[] = "landing!";
const char kExpectedMimeType[] = "text/html";
// Verifies correctness of |NavigationContext| (|arg1|) for new page navigation
// passed to |DidStartNavigation|. Stores |NavigationContext| in |context|
// pointer.
ACTION_P3(VerifyNewPageStartedContext, web_state, url, context) {
*context = arg1;
ASSERT_TRUE(*context);
EXPECT_EQ(web_state, arg0);
EXPECT_EQ(web_state, (*context)->GetWebState());
EXPECT_EQ(url, (*context)->GetUrl());
EXPECT_TRUE(
PageTransitionCoreTypeIs(ui::PageTransition::PAGE_TRANSITION_TYPED,
(*context)->GetPageTransition()));
EXPECT_FALSE((*context)->IsSameDocument());
EXPECT_FALSE((*context)->IsPost());
EXPECT_FALSE((*context)->GetError());
EXPECT_FALSE((*context)->IsRendererInitiated());
ASSERT_FALSE((*context)->GetResponseHeaders());
ASSERT_TRUE(web_state->IsLoading());
NavigationManager* navigation_manager = web_state->GetNavigationManager();
NavigationItem* item = navigation_manager->GetPendingItem();
EXPECT_EQ(url, item->GetURL());
}
// Verifies correctness of |NavigationContext| (|arg1|) for new page navigation
// passed to |DidFinishNavigation|. Asserts that |NavigationContext| the same as
// |context|.
ACTION_P3(VerifyNewPageFinishedContext, web_state, url, context) {
ASSERT_EQ(*context, arg1);
EXPECT_EQ(web_state, arg0);
EXPECT_EQ(web_state, (*context)->GetWebState());
ASSERT_TRUE((*context));
EXPECT_EQ(web_state, (*context)->GetWebState());
EXPECT_EQ(url, (*context)->GetUrl());
EXPECT_TRUE(
PageTransitionCoreTypeIs(ui::PageTransition::PAGE_TRANSITION_TYPED,
(*context)->GetPageTransition()));
EXPECT_FALSE((*context)->IsSameDocument());
EXPECT_FALSE((*context)->IsPost());
EXPECT_FALSE((*context)->GetError());
EXPECT_FALSE((*context)->IsRendererInitiated());
ASSERT_TRUE((*context)->GetResponseHeaders());
std::string mime_type;
(*context)->GetResponseHeaders()->GetMimeType(&mime_type);
ASSERT_TRUE(web_state->IsLoading());
EXPECT_EQ(kExpectedMimeType, mime_type);
NavigationManager* navigation_manager = web_state->GetNavigationManager();
NavigationItem* item = navigation_manager->GetLastCommittedItem();
EXPECT_TRUE(!item->GetTimestamp().is_null());
EXPECT_EQ(url, item->GetURL());
}
// Verifies correctness of |NavigationContext| (|arg1|) for failed navigation
// passed to |DidFinishNavigation|. Asserts that |NavigationContext| the same as
// |context|.
ACTION_P3(VerifyErrorFinishedContext, web_state, url, context) {
ASSERT_EQ(*context, arg1);
EXPECT_EQ(web_state, arg0);
ASSERT_TRUE((*context));
EXPECT_EQ(web_state, (*context)->GetWebState());
EXPECT_EQ(url, (*context)->GetUrl());
EXPECT_TRUE(
PageTransitionCoreTypeIs(ui::PageTransition::PAGE_TRANSITION_TYPED,
(*context)->GetPageTransition()));
EXPECT_FALSE((*context)->IsSameDocument());
EXPECT_FALSE((*context)->IsPost());
// The error code will be different on bots and for local runs. Allow both.
NSInteger error_code = (*context)->GetError().code;
EXPECT_TRUE(error_code == NSURLErrorCannotFindHost ||
error_code == NSURLErrorNotConnectedToInternet);
EXPECT_FALSE((*context)->IsRendererInitiated());
EXPECT_FALSE((*context)->GetResponseHeaders());
ASSERT_FALSE(web_state->IsLoading());
NavigationManager* navigation_manager = web_state->GetNavigationManager();
NavigationItem* item = navigation_manager->GetLastCommittedItem();
EXPECT_FALSE(item->GetTimestamp().is_null());
EXPECT_EQ(url, item->GetURL());
}
// Verifies correctness of |NavigationContext| (|arg1|) for navigations via POST
// HTTP methods passed to |DidStartNavigation|. Stores |NavigationContext| in
// |context| pointer.
ACTION_P4(VerifyPostStartedContext,
web_state,
url,
context,
renderer_initiated) {
*context = arg1;
ASSERT_TRUE(*context);
EXPECT_EQ(web_state, arg0);
EXPECT_EQ(web_state, (*context)->GetWebState());
EXPECT_EQ(url, (*context)->GetUrl());
EXPECT_FALSE((*context)->IsSameDocument());
EXPECT_TRUE((*context)->IsPost());
EXPECT_FALSE((*context)->GetError());
EXPECT_EQ(renderer_initiated, (*context)->IsRendererInitiated());
ASSERT_FALSE((*context)->GetResponseHeaders());
ASSERT_TRUE(web_state->IsLoading());
// TODO(crbug.com/676129): Reload does not create a pending item. Remove this
// workaround once the bug is fixed. The slim navigation manager fixes this
// bug.
if (web::GetWebClient()->IsSlimNavigationManagerEnabled() ||
!ui::PageTransitionTypeIncludingQualifiersIs(
ui::PageTransition::PAGE_TRANSITION_RELOAD,
(*context)->GetPageTransition())) {
NavigationManager* navigation_manager = web_state->GetNavigationManager();
NavigationItem* item = navigation_manager->GetPendingItem();
EXPECT_EQ(url, item->GetURL());
}
}
// Verifies correctness of |NavigationContext| (|arg1|) for navigations via POST
// HTTP methods passed to |DidFinishNavigation|. Stores |NavigationContext| in
// |context| pointer.
ACTION_P4(VerifyPostFinishedContext,
web_state,
url,
context,
renderer_initiated) {
ASSERT_EQ(*context, arg1);
EXPECT_EQ(web_state, arg0);
EXPECT_EQ(web_state, (*context)->GetWebState());
ASSERT_TRUE((*context));
EXPECT_EQ(web_state, (*context)->GetWebState());
EXPECT_EQ(url, (*context)->GetUrl());
EXPECT_FALSE((*context)->IsSameDocument());
EXPECT_TRUE((*context)->IsPost());
EXPECT_FALSE((*context)->GetError());
EXPECT_EQ(renderer_initiated, (*context)->IsRendererInitiated());
ASSERT_TRUE(web_state->IsLoading());
NavigationManager* navigation_manager = web_state->GetNavigationManager();
NavigationItem* item = navigation_manager->GetLastCommittedItem();
EXPECT_TRUE(!item->GetTimestamp().is_null());
EXPECT_EQ(url, item->GetURL());
}
// Verifies correctness of |NavigationContext| (|arg1|) for same page navigation
// passed to |DidFinishNavigation|. Stores |NavigationContext| in |context|
// pointer.
ACTION_P5(VerifySameDocumentStartedContext,
web_state,
url,
context,
page_transition,
renderer_initiated) {
*context = arg1;
ASSERT_TRUE(*context);
EXPECT_EQ(web_state, arg0);
EXPECT_EQ(web_state, (*context)->GetWebState());
EXPECT_EQ(url, (*context)->GetUrl());
EXPECT_TRUE(PageTransitionTypeIncludingQualifiersIs(
page_transition, (*context)->GetPageTransition()));
EXPECT_TRUE((*context)->IsSameDocument());
EXPECT_FALSE((*context)->IsPost());
EXPECT_FALSE((*context)->GetError());
EXPECT_FALSE((*context)->GetResponseHeaders());
}
// Verifies correctness of |NavigationContext| (|arg1|) for same page navigation
// passed to |DidFinishNavigation|. Asserts that |NavigationContext| the same as
// |context|.
ACTION_P5(VerifySameDocumentFinishedContext,
web_state,
url,
context,
page_transition,
renderer_initiated) {
ASSERT_EQ(*context, arg1);
ASSERT_TRUE(*context);
EXPECT_EQ(web_state, arg0);
EXPECT_EQ(web_state, (*context)->GetWebState());
EXPECT_EQ(url, (*context)->GetUrl());
EXPECT_TRUE(PageTransitionTypeIncludingQualifiersIs(
page_transition, (*context)->GetPageTransition()));
EXPECT_TRUE((*context)->IsSameDocument());
EXPECT_FALSE((*context)->IsPost());
EXPECT_FALSE((*context)->GetError());
EXPECT_FALSE((*context)->GetResponseHeaders());
NavigationManager* navigation_manager = web_state->GetNavigationManager();
NavigationItem* item = navigation_manager->GetLastCommittedItem();
EXPECT_TRUE(!item->GetTimestamp().is_null());
EXPECT_EQ(url, item->GetURL());
}
// Verifies correctness of |NavigationContext| (|arg1|) for new page navigation
// to native URLs passed to |DidStartNavigation|. Stores |NavigationContext| in
// |context| pointer.
ACTION_P3(VerifyNewNativePageStartedContext, web_state, url, context) {
*context = arg1;
ASSERT_TRUE(*context);
EXPECT_EQ(web_state, arg0);
EXPECT_EQ(web_state, (*context)->GetWebState());
EXPECT_EQ(url, (*context)->GetUrl());
EXPECT_TRUE(
PageTransitionCoreTypeIs(ui::PageTransition::PAGE_TRANSITION_TYPED,
(*context)->GetPageTransition()));
EXPECT_FALSE((*context)->IsSameDocument());
EXPECT_FALSE((*context)->IsPost());
EXPECT_FALSE((*context)->GetError());
EXPECT_FALSE((*context)->IsRendererInitiated());
EXPECT_FALSE((*context)->GetResponseHeaders());
ASSERT_TRUE(web_state->IsLoading());
NavigationManager* navigation_manager = web_state->GetNavigationManager();
NavigationItem* item = navigation_manager->GetPendingItem();
EXPECT_EQ(url, item->GetURL());
}
// Verifies correctness of |NavigationContext| (|arg1|) for new page navigation
// to native URLs passed to |DidFinishNavigation|. Asserts that
// |NavigationContext| the same as |context|.
ACTION_P3(VerifyNewNativePageFinishedContext, web_state, url, context) {
ASSERT_EQ(*context, arg1);
ASSERT_TRUE(*context);
EXPECT_EQ(web_state, arg0);
EXPECT_EQ(web_state, (*context)->GetWebState());
EXPECT_EQ(url, (*context)->GetUrl());
EXPECT_TRUE(
PageTransitionCoreTypeIs(ui::PageTransition::PAGE_TRANSITION_TYPED,
(*context)->GetPageTransition()));
EXPECT_FALSE((*context)->IsSameDocument());
EXPECT_FALSE((*context)->IsPost());
EXPECT_FALSE((*context)->GetError());
EXPECT_FALSE((*context)->IsRendererInitiated());
EXPECT_FALSE((*context)->GetResponseHeaders());
NavigationManager* navigation_manager = web_state->GetNavigationManager();
NavigationItem* item = navigation_manager->GetLastCommittedItem();
EXPECT_TRUE(!item->GetTimestamp().is_null());
EXPECT_EQ(url, item->GetURL());
}
// Verifies correctness of |NavigationContext| (|arg1|) for reload navigation
// passed to |DidStartNavigation|. Stores |NavigationContext| in |context|
// pointer.
ACTION_P3(VerifyReloadStartedContext, web_state, url, context) {
*context = arg1;
ASSERT_TRUE(*context);
EXPECT_EQ(web_state, arg0);
EXPECT_EQ(web_state, (*context)->GetWebState());
EXPECT_EQ(url, (*context)->GetUrl());
EXPECT_TRUE(
PageTransitionCoreTypeIs(ui::PageTransition::PAGE_TRANSITION_RELOAD,
(*context)->GetPageTransition()));
EXPECT_FALSE((*context)->IsSameDocument());
EXPECT_FALSE((*context)->GetError());
EXPECT_TRUE((*context)->IsRendererInitiated());
EXPECT_FALSE((*context)->GetResponseHeaders());
// TODO(crbug.com/676129): Reload does not create a pending item. Check
// pending item once the bug is fixed. The slim navigation manager fixes this
// bug.
if (web::GetWebClient()->IsSlimNavigationManagerEnabled()) {
NavigationManager* navigation_manager = web_state->GetNavigationManager();
NavigationItem* item = navigation_manager->GetPendingItem();
EXPECT_EQ(url, item->GetURL());
} else {
EXPECT_FALSE(web_state->GetNavigationManager()->GetPendingItem());
}
}
// Verifies correctness of |NavigationContext| (|arg1|) for reload navigation
// passed to |DidFinishNavigation|. Asserts that |NavigationContext| the same as
// |context|.
ACTION_P4(VerifyReloadFinishedContext, web_state, url, context, is_web_page) {
ASSERT_EQ(*context, arg1);
ASSERT_TRUE(*context);
EXPECT_EQ(web_state, arg0);
EXPECT_EQ(web_state, (*context)->GetWebState());
EXPECT_EQ(url, (*context)->GetUrl());
EXPECT_TRUE(
PageTransitionCoreTypeIs(ui::PageTransition::PAGE_TRANSITION_RELOAD,
(*context)->GetPageTransition()));
EXPECT_FALSE((*context)->IsSameDocument());
EXPECT_FALSE((*context)->GetError());
EXPECT_TRUE((*context)->IsRendererInitiated());
if (is_web_page) {
ASSERT_TRUE((*context)->GetResponseHeaders());
std::string mime_type;
(*context)->GetResponseHeaders()->GetMimeType(&mime_type);
EXPECT_EQ(kExpectedMimeType, mime_type);
} else {
EXPECT_FALSE((*context)->GetResponseHeaders());
}
NavigationManager* navigation_manager = web_state->GetNavigationManager();
NavigationItem* item = navigation_manager->GetLastCommittedItem();
EXPECT_TRUE(!item->GetTimestamp().is_null());
EXPECT_EQ(url, item->GetURL());
}
// Mocks WebStateObserver navigation callbacks.
class WebStateObserverMock : public WebStateObserver {
public:
WebStateObserverMock() = default;
MOCK_METHOD2(DidStartNavigation, void(WebState*, NavigationContext*));
MOCK_METHOD2(DidFinishNavigation, void(WebState*, NavigationContext*));
MOCK_METHOD1(DidStartLoading, void(WebState*));
MOCK_METHOD1(DidStopLoading, void(WebState*));
MOCK_METHOD2(PageLoaded, void(WebState*, PageLoadCompletionStatus));
void WebStateDestroyed(WebState* web_state) override { NOTREACHED(); }
private:
DISALLOW_COPY_AND_ASSIGN(WebStateObserverMock);
};
// Mocks WebStatePolicyDecider decision callbacks.
class PolicyDeciderMock : public WebStatePolicyDecider {
public:
PolicyDeciderMock(WebState* web_state) : WebStatePolicyDecider(web_state) {}
MOCK_METHOD2(ShouldAllowRequest, bool(NSURLRequest*, ui::PageTransition));
MOCK_METHOD2(ShouldAllowResponse, bool(NSURLResponse*, bool for_main_frame));
};
} // namespace
using test::HttpServer;
using testing::Return;
using testing::StrictMock;
using testing::_;
using testing::WaitUntilConditionOrTimeout;
using web::test::WaitForWebViewContainingText;
// Test fixture for WebStateDelegate::ProvisionalNavigationStarted,
// WebStateDelegate::DidFinishNavigation, WebStateDelegate::DidStartLoading and
// WebStateDelegate::DidStopLoading integration tests.
class NavigationAndLoadCallbacksTest : public WebIntTest {
public:
NavigationAndLoadCallbacksTest() : scoped_observer_(&observer_) {}
void SetUp() override {
WebIntTest::SetUp();
decider_ = std::make_unique<StrictMock<PolicyDeciderMock>>(web_state());
scoped_observer_.Add(web_state());
// Stub out NativeContent objects.
provider_ = [[TestNativeContentProvider alloc] init];
content_ = [[TestNativeContent alloc] initWithURL:GURL::EmptyGURL()
virtualURL:GURL::EmptyGURL()];
WebStateImpl* web_state_impl = reinterpret_cast<WebStateImpl*>(web_state());
web_state_impl->GetWebController().nativeProvider = provider_;
}
void TearDown() override {
scoped_observer_.RemoveAll();
WebIntTest::TearDown();
}
protected:
TestNativeContentProvider* provider_;
std::unique_ptr<StrictMock<PolicyDeciderMock>> decider_;
TestNativeContent* content_;
StrictMock<WebStateObserverMock> observer_;
ScopedObserver<WebState, WebStateObserver> scoped_observer_;
testing::InSequence callbacks_sequence_checker_;
DISALLOW_COPY_AND_ASSIGN(NavigationAndLoadCallbacksTest);
};
// Tests successful navigation to a new page.
TEST_F(NavigationAndLoadCallbacksTest, NewPageNavigation) {
const GURL url = HttpServer::MakeUrl("http://chromium.test");
std::map<GURL, std::string> responses;
responses[url] = "Chromium Test";
web::test::SetUpSimpleHttpServer(responses);
// Perform new page navigation.
NavigationContext* context = nullptr;
EXPECT_CALL(observer_, DidStartLoading(web_state()));
EXPECT_CALL(*decider_, ShouldAllowRequest(_, _)).WillOnce(Return(true));
EXPECT_CALL(observer_, DidStartNavigation(web_state(), _))
.WillOnce(VerifyNewPageStartedContext(web_state(), url, &context));
EXPECT_CALL(*decider_, ShouldAllowResponse(_, /*for_main_frame=*/true))
.WillOnce(Return(true));
EXPECT_CALL(observer_, DidFinishNavigation(web_state(), _))
.WillOnce(VerifyNewPageFinishedContext(web_state(), url, &context));
EXPECT_CALL(observer_, DidStopLoading(web_state()));
EXPECT_CALL(observer_,
PageLoaded(web_state(), PageLoadCompletionStatus::SUCCESS));
LoadUrl(url);
}
// Tests that if web usage is already enabled, enabling it again would not cause
// any page loads (related to restoring cached session). This is a regression
// test for crbug.com/781916.
TEST_F(NavigationAndLoadCallbacksTest, EnableWebUsageTwice) {
const GURL url = HttpServer::MakeUrl("http://chromium.test");
std::map<GURL, std::string> responses;
responses[url] = "Chromium Test";
web::test::SetUpSimpleHttpServer(responses);
// Only expect one set of load events from the first LoadUrl(), not subsequent
// SetWebUsageEnabled(true) calls. Web usage is already enabled, so the
// subsequent calls should be noops.
NavigationContext* context = nullptr;
EXPECT_CALL(observer_, DidStartLoading(web_state()));
EXPECT_CALL(*decider_, ShouldAllowRequest(_, _)).WillOnce(Return(true));
EXPECT_CALL(observer_, DidStartNavigation(web_state(), _))
.WillOnce(VerifyNewPageStartedContext(web_state(), url, &context));
EXPECT_CALL(*decider_, ShouldAllowResponse(_, /*for_main_frame=*/true))
.WillOnce(Return(true));
EXPECT_CALL(observer_, DidFinishNavigation(web_state(), _))
.WillOnce(VerifyNewPageFinishedContext(web_state(), url, &context));
EXPECT_CALL(observer_, DidStopLoading(web_state()));
EXPECT_CALL(observer_,
PageLoaded(web_state(), PageLoadCompletionStatus::SUCCESS));
LoadUrl(url);
web_state()->SetWebUsageEnabled(true);
web_state()->SetWebUsageEnabled(true);
}
// Tests failed navigation to a new page.
TEST_F(NavigationAndLoadCallbacksTest, FailedNavigation) {
const GURL url = HttpServer::MakeUrl("unsupported://chromium.test");
// Perform a navigation to url with unsupported scheme, which will fail.
NavigationContext* context = nullptr;
EXPECT_CALL(observer_, DidStartLoading(web_state()));
EXPECT_CALL(*decider_, ShouldAllowRequest(_, _)).WillOnce(Return(true));
EXPECT_CALL(observer_, DidStartNavigation(web_state(), _))
.WillOnce(VerifyNewPageStartedContext(web_state(), url, &context));
EXPECT_CALL(observer_, DidStopLoading(web_state()));
// TODO(crbug.com/803232): PageLoaded() should be called after
// DidFinishNavigation().
EXPECT_CALL(observer_,
PageLoaded(web_state(), PageLoadCompletionStatus::FAILURE));
EXPECT_CALL(observer_, DidFinishNavigation(web_state(), _))
.WillOnce(VerifyErrorFinishedContext(web_state(), url, &context));
// LoadUrl() expects sucessfull load and can not be used here.
web::test::LoadUrl(web_state(), url);
EXPECT_TRUE(WaitUntilConditionOrTimeout(testing::kWaitForPageLoadTimeout, ^{
return !web_state()->IsLoading();
}));
}
// Tests web page reload navigation.
TEST_F(NavigationAndLoadCallbacksTest, WebPageReloadNavigation) {
const GURL url = HttpServer::MakeUrl("http://chromium.test");
std::map<GURL, std::string> responses;
responses[url] = "Chromium Test";
web::test::SetUpSimpleHttpServer(responses);
// Perform new page navigation.
EXPECT_CALL(observer_, DidStartLoading(web_state()));
EXPECT_CALL(*decider_, ShouldAllowRequest(_, _)).WillOnce(Return(true));
EXPECT_CALL(observer_, DidStartNavigation(web_state(), _));
EXPECT_CALL(*decider_, ShouldAllowResponse(_, /*for_main_frame=*/true))
.WillOnce(Return(true));
EXPECT_CALL(observer_, DidFinishNavigation(web_state(), _));
EXPECT_CALL(observer_, DidStopLoading(web_state()));
EXPECT_CALL(observer_,
PageLoaded(web_state(), PageLoadCompletionStatus::SUCCESS));
LoadUrl(url);
// Reload web page.
NavigationContext* context = nullptr;
EXPECT_CALL(observer_, DidStartLoading(web_state()));
EXPECT_CALL(*decider_, ShouldAllowRequest(_, _)).WillOnce(Return(true));
EXPECT_CALL(observer_, DidStartNavigation(web_state(), _))
.WillOnce(VerifyReloadStartedContext(web_state(), url, &context));
EXPECT_CALL(*decider_, ShouldAllowResponse(_, /*for_main_frame=*/true))
.WillOnce(Return(true));
EXPECT_CALL(observer_, DidFinishNavigation(web_state(), _))
.WillOnce(VerifyReloadFinishedContext(web_state(), url, &context,
true /* is_web_page */));
EXPECT_CALL(observer_, DidStopLoading(web_state()));
EXPECT_CALL(observer_,
PageLoaded(web_state(), PageLoadCompletionStatus::SUCCESS));
// TODO(crbug.com/700958): ios/web ignores |check_for_repost| flag and current
// delegate does not run callback for ShowRepostFormWarningDialog. Clearing
// the delegate will allow form resubmission. Remove this workaround (clearing
// the delegate, once |check_for_repost| is supported).
web_state()->SetDelegate(nullptr);
ExecuteBlockAndWaitForLoad(url, ^{
navigation_manager()->Reload(ReloadType::NORMAL,
false /*check_for_repost*/);
});
}
// Tests user-initiated hash change.
TEST_F(NavigationAndLoadCallbacksTest, UserInitiatedHashChangeNavigation) {
const GURL url = HttpServer::MakeUrl("http://chromium.test");
std::map<GURL, std::string> responses;
responses[url] = "Chromium Test";
web::test::SetUpSimpleHttpServer(responses);
// Perform new page navigation.
NavigationContext* context = nullptr;
EXPECT_CALL(observer_, DidStartLoading(web_state()));
EXPECT_CALL(*decider_, ShouldAllowRequest(_, _)).WillOnce(Return(true));
EXPECT_CALL(observer_, DidStartNavigation(web_state(), _))
.WillOnce(VerifyNewPageStartedContext(web_state(), url, &context));
EXPECT_CALL(*decider_, ShouldAllowResponse(_, /*for_main_frame=*/true))
.WillOnce(Return(true));
EXPECT_CALL(observer_, DidFinishNavigation(web_state(), _))
.WillOnce(VerifyNewPageFinishedContext(web_state(), url, &context));
EXPECT_CALL(observer_, DidStopLoading(web_state()));
EXPECT_CALL(observer_,
PageLoaded(web_state(), PageLoadCompletionStatus::SUCCESS));
LoadUrl(url);
// Perform same-document navigation.
const GURL hash_url = HttpServer::MakeUrl("http://chromium.test#1");
EXPECT_CALL(observer_, DidStartLoading(web_state()));
EXPECT_CALL(*decider_, ShouldAllowRequest(_, _)).WillOnce(Return(true));
EXPECT_CALL(observer_, DidStartNavigation(web_state(), _))
.WillOnce(VerifySameDocumentStartedContext(
web_state(), hash_url, &context,
ui::PageTransition::PAGE_TRANSITION_TYPED,
/*renderer_initiated=*/false));
// No ShouldAllowResponse callback for same-document navigations.
EXPECT_CALL(observer_, DidFinishNavigation(web_state(), _))
.WillOnce(VerifySameDocumentFinishedContext(
web_state(), hash_url, &context,
ui::PageTransition::PAGE_TRANSITION_TYPED,
/*renderer_initiated=*/false));
EXPECT_CALL(observer_, DidStopLoading(web_state()));
EXPECT_CALL(observer_,
PageLoaded(web_state(), PageLoadCompletionStatus::SUCCESS));
LoadUrl(hash_url);
// Perform same-document navigation by going back.
// No ShouldAllowRequest callback for same-document back-forward navigations.
EXPECT_CALL(observer_, DidStartLoading(web_state()));
EXPECT_CALL(observer_, DidStartNavigation(web_state(), _))
.WillOnce(VerifySameDocumentStartedContext(
web_state(), url, &context,
ui::PageTransition::PAGE_TRANSITION_FORWARD_BACK,
/*renderer_initiated=*/false));
// No ShouldAllowResponse callbacks for same-document back-forward
// navigations.
EXPECT_CALL(observer_, DidFinishNavigation(web_state(), _))
.WillOnce(VerifySameDocumentFinishedContext(
web_state(), url, &context,
ui::PageTransition::PAGE_TRANSITION_FORWARD_BACK,
/*renderer_initiated=*/false));
EXPECT_CALL(observer_, DidStopLoading(web_state()));
EXPECT_CALL(observer_,
PageLoaded(web_state(), PageLoadCompletionStatus::SUCCESS));
ExecuteBlockAndWaitForLoad(url, ^{
navigation_manager()->GoBack();
});
}
// Tests renderer-initiated hash change.
TEST_F(NavigationAndLoadCallbacksTest, RendererInitiatedHashChangeNavigation) {
const GURL url = HttpServer::MakeUrl("http://chromium.test");
std::map<GURL, std::string> responses;
responses[url] = "Chromium Test";
web::test::SetUpSimpleHttpServer(responses);
// Perform new page navigation.
NavigationContext* context = nullptr;
EXPECT_CALL(observer_, DidStartLoading(web_state()));
EXPECT_CALL(*decider_, ShouldAllowRequest(_, _)).WillOnce(Return(true));
EXPECT_CALL(observer_, DidStartNavigation(web_state(), _))
.WillOnce(VerifyNewPageStartedContext(web_state(), url, &context));
EXPECT_CALL(*decider_, ShouldAllowResponse(_, /*for_main_frame=*/true))
.WillOnce(Return(true));
EXPECT_CALL(observer_, DidFinishNavigation(web_state(), _))
.WillOnce(VerifyNewPageFinishedContext(web_state(), url, &context));
EXPECT_CALL(observer_, DidStopLoading(web_state()));
EXPECT_CALL(observer_,
PageLoaded(web_state(), PageLoadCompletionStatus::SUCCESS));
LoadUrl(url);
// Perform same-page navigation using JavaScript.
const GURL hash_url = HttpServer::MakeUrl("http://chromium.test#1");
EXPECT_CALL(*decider_, ShouldAllowRequest(_, _)).WillOnce(Return(true));
EXPECT_CALL(observer_, DidStartLoading(web_state()));
EXPECT_CALL(observer_, DidStartNavigation(web_state(), _))
.WillOnce(VerifySameDocumentStartedContext(
web_state(), hash_url, &context,
ui::PageTransition::PAGE_TRANSITION_CLIENT_REDIRECT,
/*renderer_initiated=*/true));
// No ShouldAllowResponse callback for same-document navigations.
EXPECT_CALL(observer_, DidFinishNavigation(web_state(), _))
.WillOnce(VerifySameDocumentFinishedContext(
web_state(), hash_url, &context,
ui::PageTransition::PAGE_TRANSITION_CLIENT_REDIRECT,
/*renderer_initiated=*/true));
EXPECT_CALL(observer_, DidStopLoading(web_state()));
EXPECT_CALL(observer_,
PageLoaded(web_state(), PageLoadCompletionStatus::SUCCESS));
ExecuteJavaScript(@"window.location.hash = '#1'");
}
// Tests state change.
TEST_F(NavigationAndLoadCallbacksTest, StateNavigation) {
const GURL url = HttpServer::MakeUrl("http://chromium.test");
std::map<GURL, std::string> responses;
responses[url] = "Chromium Test";
web::test::SetUpSimpleHttpServer(responses);
// Perform new page navigation.
NavigationContext* context = nullptr;
EXPECT_CALL(observer_, DidStartLoading(web_state()));
EXPECT_CALL(*decider_, ShouldAllowRequest(_, _)).WillOnce(Return(true));
EXPECT_CALL(observer_, DidStartNavigation(web_state(), _))
.WillOnce(VerifyNewPageStartedContext(web_state(), url, &context));
EXPECT_CALL(*decider_, ShouldAllowResponse(_, /*for_main_frame=*/true))
.WillOnce(Return(true));
EXPECT_CALL(observer_, DidFinishNavigation(web_state(), _))
.WillOnce(VerifyNewPageFinishedContext(web_state(), url, &context));
EXPECT_CALL(observer_, DidStopLoading(web_state()));
EXPECT_CALL(observer_,
PageLoaded(web_state(), PageLoadCompletionStatus::SUCCESS));
LoadUrl(url);
// Perform push state using JavaScript.
const GURL push_url = HttpServer::MakeUrl("http://chromium.test/test.html");
EXPECT_CALL(observer_, DidStartNavigation(web_state(), _))
.WillOnce(VerifySameDocumentStartedContext(
web_state(), push_url, &context,
ui::PageTransition::PAGE_TRANSITION_CLIENT_REDIRECT,
/*renderer_initiated=*/true));
// No ShouldAllowRequest/ShouldAllowResponse callbacks for same-document push
// state navigations.
EXPECT_CALL(observer_, DidFinishNavigation(web_state(), _))
.WillOnce(VerifySameDocumentFinishedContext(
web_state(), push_url, &context,
ui::PageTransition::PAGE_TRANSITION_CLIENT_REDIRECT,
/*renderer_initiated=*/true));
ExecuteJavaScript(@"window.history.pushState('', 'Test', 'test.html')");
// Perform replace state using JavaScript.
const GURL replace_url = HttpServer::MakeUrl("http://chromium.test/1.html");
// No ShouldAllowRequest callbacks for same-document push state navigations.
EXPECT_CALL(observer_, DidStartNavigation(web_state(), _))
.WillOnce(VerifySameDocumentStartedContext(
web_state(), replace_url, &context,
ui::PageTransition::PAGE_TRANSITION_CLIENT_REDIRECT,
/*renderer_initiated=*/true));
// No ShouldAllowResponse callbacks for same-document push state navigations.
EXPECT_CALL(observer_, DidFinishNavigation(web_state(), _))
.WillOnce(VerifySameDocumentFinishedContext(
web_state(), replace_url, &context,
ui::PageTransition::PAGE_TRANSITION_CLIENT_REDIRECT,
/*renderer_initiated=*/true));
ExecuteJavaScript(@"window.history.replaceState('', 'Test', '1.html')");
}
// Tests native content navigation.
TEST_F(NavigationAndLoadCallbacksTest, NativeContentNavigation) {
GURL url(url::SchemeHostPort(kTestNativeContentScheme, "ui", 0).Serialize());
NavigationContext* context = nullptr;
EXPECT_CALL(observer_, DidStartLoading(web_state()));
EXPECT_CALL(observer_, DidStartNavigation(web_state(), _))
.WillOnce(VerifyNewNativePageStartedContext(web_state(), url, &context));
// No ShouldAllowRequest/ShouldAllowResponse callbacks for native content
// navigations.
EXPECT_CALL(observer_, DidFinishNavigation(web_state(), _))
.WillOnce(VerifyNewNativePageFinishedContext(web_state(), url, &context));
EXPECT_CALL(observer_, DidStopLoading(web_state()));
EXPECT_CALL(observer_,
PageLoaded(web_state(), PageLoadCompletionStatus::SUCCESS));
[provider_ setController:content_ forURL:url];
LoadUrl(url);
}
// Tests native content reload navigation.
TEST_F(NavigationAndLoadCallbacksTest, NativeContentReload) {
GURL url(url::SchemeHostPort(kTestNativeContentScheme, "ui", 0).Serialize());
EXPECT_CALL(observer_, DidStartLoading(web_state()));
EXPECT_CALL(observer_, DidStartNavigation(web_state(), _));
// No ShouldAllowRequest/ShouldAllowResponse callbacks for native content
// navigations.
EXPECT_CALL(observer_, DidFinishNavigation(web_state(), _));
EXPECT_CALL(observer_, DidStopLoading(web_state()));
EXPECT_CALL(observer_,
PageLoaded(web_state(), PageLoadCompletionStatus::SUCCESS));
[provider_ setController:content_ forURL:url];
LoadUrl(url);
// Reload native content.
NavigationContext* context = nullptr;
EXPECT_CALL(observer_, DidStartLoading(web_state()));
// No ShouldAllowRequest callbacks for native content navigations.
EXPECT_CALL(observer_, DidStartNavigation(web_state(), _))
.WillOnce(VerifyReloadStartedContext(web_state(), url, &context));
// No ShouldAllowResponse callbacks for native content navigations.
EXPECT_CALL(observer_, DidFinishNavigation(web_state(), _))
.WillOnce(VerifyReloadFinishedContext(web_state(), url, &context,
false /* is_web_page */));
EXPECT_CALL(observer_, DidStopLoading(web_state()));
EXPECT_CALL(observer_,
PageLoaded(web_state(), PageLoadCompletionStatus::SUCCESS));
navigation_manager()->Reload(ReloadType::NORMAL, false /*check_for_repost*/);
}
// Tests successful navigation to a new page with post HTTP method.
TEST_F(NavigationAndLoadCallbacksTest, UserInitiatedPostNavigation) {
const GURL url = HttpServer::MakeUrl("http://chromium.test");
std::map<GURL, std::string> responses;
responses[url] = kTestPageText;
web::test::SetUpSimpleHttpServer(responses);
// Perform new page navigation.
NavigationContext* context = nullptr;
EXPECT_CALL(observer_, DidStartLoading(web_state()));
EXPECT_CALL(*decider_, ShouldAllowRequest(_, _)).WillOnce(Return(true));
EXPECT_CALL(observer_, DidStartNavigation(web_state(), _))
.WillOnce(VerifyPostStartedContext(web_state(), url, &context,
/*renderer_initiated=*/false));
if (@available(iOS 11, *)) {
EXPECT_CALL(*decider_, ShouldAllowResponse(_, /*for_main_frame=*/true))
.WillOnce(Return(true));
}
EXPECT_CALL(observer_, DidFinishNavigation(web_state(), _))
.WillOnce(VerifyPostFinishedContext(web_state(), url, &context,
/*renderer_initiated=*/false));
EXPECT_CALL(observer_, DidStopLoading(web_state()));
EXPECT_CALL(observer_,
PageLoaded(web_state(), PageLoadCompletionStatus::SUCCESS));
// Load request using POST HTTP method.
web::NavigationManager::WebLoadParams params(url);
params.post_data = [@"foo" dataUsingEncoding:NSUTF8StringEncoding];
params.extra_headers = @{@"Content-Type" : @"text/html"};
LoadWithParams(params);
ASSERT_TRUE(WaitForWebViewContainingText(web_state(), kTestPageText));
}
// Tests successful navigation to a new page with post HTTP method.
TEST_F(NavigationAndLoadCallbacksTest, RendererInitiatedPostNavigation) {
const GURL url = HttpServer::MakeUrl("http://chromium.test");
const GURL action = HttpServer::MakeUrl("http://action.test");
std::map<GURL, std::string> responses;
responses[url] =
base::StringPrintf("<form method='post' id='form' action='%s'></form>%s",
action.spec().c_str(), kTestPageText);
responses[action] = "arrived!";
web::test::SetUpSimpleHttpServer(responses);
// Perform new page navigation.
EXPECT_CALL(observer_, DidStartLoading(web_state()));
EXPECT_CALL(*decider_, ShouldAllowRequest(_, _)).WillOnce(Return(true));
EXPECT_CALL(observer_, DidStartNavigation(web_state(), _));
EXPECT_CALL(*decider_, ShouldAllowResponse(_, /*for_main_frame=*/true))
.WillOnce(Return(true));
EXPECT_CALL(observer_, DidFinishNavigation(web_state(), _));
EXPECT_CALL(observer_, DidStopLoading(web_state()));
EXPECT_CALL(observer_,
PageLoaded(web_state(), PageLoadCompletionStatus::SUCCESS));
LoadUrl(url);
ASSERT_TRUE(WaitForWebViewContainingText(web_state(), kTestPageText));
// Submit the form using JavaScript.
NavigationContext* context = nullptr;
EXPECT_CALL(*decider_, ShouldAllowRequest(_, _)).WillOnce(Return(true));
EXPECT_CALL(observer_, DidStartLoading(web_state()));
EXPECT_CALL(observer_, DidStartNavigation(web_state(), _))
.WillOnce(VerifyPostStartedContext(web_state(), action, &context,
/*renderer_initiated=*/true));
EXPECT_CALL(*decider_, ShouldAllowResponse(_, /*for_main_frame=*/true))
.WillOnce(Return(true));
EXPECT_CALL(observer_, DidFinishNavigation(web_state(), _))
.WillOnce(VerifyPostFinishedContext(web_state(), action, &context,
/*renderer_initiated=*/true));
EXPECT_CALL(observer_, DidStopLoading(web_state()));
EXPECT_CALL(observer_,
PageLoaded(web_state(), PageLoadCompletionStatus::SUCCESS));
ExecuteJavaScript(@"document.getElementById('form').submit();");
ASSERT_TRUE(WaitForWebViewContainingText(web_state(), responses[action]));
}
// Tests successful reload of a page returned for post request.
TEST_F(NavigationAndLoadCallbacksTest, ReloadPostNavigation) {
const GURL url = HttpServer::MakeUrl("http://chromium.test");
std::map<GURL, std::string> responses;
const GURL action = HttpServer::MakeUrl("http://action.test");
responses[url] =
base::StringPrintf("<form method='post' id='form' action='%s'></form>%s",
action.spec().c_str(), kTestPageText);
responses[action] = "arrived!";
web::test::SetUpSimpleHttpServer(responses);
// Perform new page navigation.
EXPECT_CALL(observer_, DidStartLoading(web_state()));
EXPECT_CALL(*decider_, ShouldAllowRequest(_, _)).WillOnce(Return(true));
EXPECT_CALL(observer_, DidStartNavigation(web_state(), _));
EXPECT_CALL(*decider_, ShouldAllowResponse(_, /*for_main_frame=*/true))
.WillOnce(Return(true));
EXPECT_CALL(observer_, DidFinishNavigation(web_state(), _));
EXPECT_CALL(observer_, DidStopLoading(web_state()));
EXPECT_CALL(observer_,
PageLoaded(web_state(), PageLoadCompletionStatus::SUCCESS));
LoadUrl(url);
ASSERT_TRUE(WaitForWebViewContainingText(web_state(), kTestPageText));
// Submit the form using JavaScript.
EXPECT_CALL(*decider_, ShouldAllowRequest(_, _)).WillOnce(Return(true));
EXPECT_CALL(observer_, DidStartLoading(web_state()));
EXPECT_CALL(observer_, DidStartNavigation(web_state(), _));
EXPECT_CALL(*decider_, ShouldAllowResponse(_, /*for_main_frame=*/true))
.WillOnce(Return(true));
EXPECT_CALL(observer_, DidFinishNavigation(web_state(), _));
EXPECT_CALL(observer_, DidStopLoading(web_state()));
EXPECT_CALL(observer_,
PageLoaded(web_state(), PageLoadCompletionStatus::SUCCESS));
ExecuteJavaScript(@"window.document.getElementById('form').submit();");
ASSERT_TRUE(WaitForWebViewContainingText(web_state(), responses[action]));
// Reload the page.
NavigationContext* context = nullptr;
EXPECT_CALL(observer_, DidStartLoading(web_state()));
EXPECT_CALL(*decider_, ShouldAllowRequest(_, _)).WillOnce(Return(true));
EXPECT_CALL(observer_, DidStartNavigation(web_state(), _))
.WillOnce(VerifyPostStartedContext(web_state(), action, &context,
/*renderer_initiated=*/true));
EXPECT_CALL(*decider_, ShouldAllowResponse(_, /*for_main_frame=*/true))
.WillOnce(Return(true));
EXPECT_CALL(observer_, DidFinishNavigation(web_state(), _))
.WillOnce(VerifyPostFinishedContext(web_state(), action, &context,
/*renderer_initiated=*/true));
EXPECT_CALL(observer_, DidStopLoading(web_state()));
EXPECT_CALL(observer_,
PageLoaded(web_state(), PageLoadCompletionStatus::SUCCESS));
// TODO(crbug.com/700958): ios/web ignores |check_for_repost| flag and current
// delegate does not run callback for ShowRepostFormWarningDialog. Clearing
// the delegate will allow form resubmission. Remove this workaround (clearing
// the delegate, once |check_for_repost| is supported).
web_state()->SetDelegate(nullptr);
ExecuteBlockAndWaitForLoad(action, ^{
navigation_manager()->Reload(ReloadType::NORMAL,
false /*check_for_repost*/);
});
}
// Tests going forward to a page rendered from post response.
TEST_F(NavigationAndLoadCallbacksTest, ForwardPostNavigation) {
const GURL url = HttpServer::MakeUrl("http://chromium.test");
std::map<GURL, std::string> responses;
const GURL action = HttpServer::MakeUrl("http://action.test");
responses[url] =
base::StringPrintf("<form method='post' id='form' action='%s'></form>%s",
action.spec().c_str(), kTestPageText);
responses[action] = "arrived!";
web::test::SetUpSimpleHttpServer(responses);
// Perform new page navigation.
EXPECT_CALL(observer_, DidStartLoading(web_state()));
EXPECT_CALL(*decider_, ShouldAllowRequest(_, _)).WillOnce(Return(true));
EXPECT_CALL(observer_, DidStartNavigation(web_state(), _));
EXPECT_CALL(*decider_, ShouldAllowResponse(_, /*for_main_frame=*/true))
.WillOnce(Return(true));
EXPECT_CALL(observer_, DidFinishNavigation(web_state(), _));
EXPECT_CALL(observer_, DidStopLoading(web_state()));
EXPECT_CALL(observer_,
PageLoaded(web_state(), PageLoadCompletionStatus::SUCCESS));
LoadUrl(url);
ASSERT_TRUE(WaitForWebViewContainingText(web_state(), kTestPageText));
// Submit the form using JavaScript.
EXPECT_CALL(*decider_, ShouldAllowRequest(_, _)).WillOnce(Return(true));
EXPECT_CALL(observer_, DidStartLoading(web_state()));
EXPECT_CALL(observer_, DidStartNavigation(web_state(), _));
EXPECT_CALL(*decider_, ShouldAllowResponse(_, /*for_main_frame=*/true))
.WillOnce(Return(true));
EXPECT_CALL(observer_, DidFinishNavigation(web_state(), _));
EXPECT_CALL(observer_, DidStopLoading(web_state()));
EXPECT_CALL(observer_,
PageLoaded(web_state(), PageLoadCompletionStatus::SUCCESS));
ExecuteJavaScript(@"window.document.getElementById('form').submit();");
ASSERT_TRUE(WaitForWebViewContainingText(web_state(), responses[action]));
// Go Back.
if (web::GetWebClient()->IsSlimNavigationManagerEnabled()) {
EXPECT_CALL(*decider_, ShouldAllowRequest(_, _)).WillOnce(Return(true));
EXPECT_CALL(observer_, DidStartLoading(web_state()));
} else {
EXPECT_CALL(observer_, DidStartLoading(web_state()));
EXPECT_CALL(*decider_, ShouldAllowRequest(_, _)).WillOnce(Return(true));
}
EXPECT_CALL(observer_, DidStartNavigation(web_state(), _));
if (@available(iOS 10, *)) {
// Starting from iOS10, ShouldAllowResponse is not called when going back
// after form submission.
} else {
EXPECT_CALL(*decider_, ShouldAllowResponse(_, /*for_main_frame=*/true))
.WillOnce(Return(true));
}
EXPECT_CALL(observer_, DidFinishNavigation(web_state(), _));
EXPECT_CALL(observer_, DidStopLoading(web_state()));
EXPECT_CALL(observer_,
PageLoaded(web_state(), PageLoadCompletionStatus::SUCCESS));
ExecuteBlockAndWaitForLoad(url, ^{
navigation_manager()->GoBack();
});
// Go forward.
NavigationContext* context = nullptr;
if (web::GetWebClient()->IsSlimNavigationManagerEnabled()) {
EXPECT_CALL(*decider_, ShouldAllowRequest(_, _)).WillOnce(Return(true));
EXPECT_CALL(observer_, DidStartLoading(web_state()));
} else {
EXPECT_CALL(observer_, DidStartLoading(web_state()));
EXPECT_CALL(*decider_, ShouldAllowRequest(_, _)).WillOnce(Return(true));
}
EXPECT_CALL(observer_, DidStartNavigation(web_state(), _))
.WillOnce(VerifyPostStartedContext(web_state(), action, &context,
/*renderer_initiated=*/false));
EXPECT_CALL(observer_, DidFinishNavigation(web_state(), _))
.WillOnce(VerifyPostFinishedContext(web_state(), action, &context,
/*renderer_initiated=*/false));
EXPECT_CALL(observer_, DidStopLoading(web_state()));
EXPECT_CALL(observer_,
PageLoaded(web_state(), PageLoadCompletionStatus::SUCCESS));
// TODO(crbug.com/700958): ios/web ignores |check_for_repost| flag and current
// delegate does not run callback for ShowRepostFormWarningDialog. Clearing
// the delegate will allow form resubmission. Remove this workaround (clearing
// the delegate, once |check_for_repost| is supported).
web_state()->SetDelegate(nullptr);
ExecuteBlockAndWaitForLoad(action, ^{
navigation_manager()->GoForward();
});
}
// Tests server redirect navigation.
TEST_F(NavigationAndLoadCallbacksTest, RedirectNavigation) {
const GURL url = HttpServer::MakeUrl("http://chromium.test");
std::map<GURL, HtmlResponseProviderImpl::Response> responses;
const GURL redirect_url = HttpServer::MakeUrl("http://chromium2.test");
responses[url] = HtmlResponseProviderImpl::GetRedirectResponse(
redirect_url, net::HTTP_MOVED_PERMANENTLY);
responses[redirect_url] = HtmlResponseProviderImpl::GetSimpleResponse("here");
std::unique_ptr<web::DataResponseProvider> provider(
new HtmlResponseProvider(responses));
web::test::SetUpHttpServer(std::move(provider));
// Load url which replies with redirect.
NavigationContext* context = nullptr;
EXPECT_CALL(observer_, DidStartLoading(web_state()));
EXPECT_CALL(*decider_, ShouldAllowRequest(_, _)).WillOnce(Return(true));
EXPECT_CALL(observer_, DidStartNavigation(web_state(), _))
.WillOnce(VerifyNewPageStartedContext(web_state(), url, &context));
// Second ShouldAllowRequest call is for redirect_url.
EXPECT_CALL(*decider_, ShouldAllowRequest(_, _)).WillOnce(Return(true));
EXPECT_CALL(*decider_, ShouldAllowResponse(_, /*for_main_frame=*/true))
.WillOnce(Return(true));
EXPECT_CALL(observer_, DidFinishNavigation(web_state(), _))
.WillOnce(
VerifyNewPageFinishedContext(web_state(), redirect_url, &context));
EXPECT_CALL(observer_, DidStopLoading(web_state()));
EXPECT_CALL(observer_,
PageLoaded(web_state(), PageLoadCompletionStatus::SUCCESS));
LoadUrl(url);
}
} // namespace web