1// Copyright 2017 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#import "ios/web/navigation/wk_based_navigation_manager_impl.h" 6 7#include <WebKit/WebKit.h> 8#include <memory> 9 10#include "base/strings/stringprintf.h" 11#include "base/strings/sys_string_conversions.h" 12#include "base/strings/utf_string_conversions.h" 13#include "base/test/metrics/histogram_tester.h" 14#include "ios/web/common/features.h" 15#import "ios/web/navigation/navigation_manager_delegate.h" 16#import "ios/web/navigation/navigation_manager_impl.h" 17#import "ios/web/navigation/wk_navigation_util.h" 18#include "ios/web/public/navigation/navigation_item.h" 19#include "ios/web/public/navigation/reload_type.h" 20#include "ios/web/public/test/fakes/test_browser_state.h" 21#import "ios/web/public/web_client.h" 22#import "ios/web/test/fakes/crw_fake_back_forward_list.h" 23#include "ios/web/test/test_url_constants.h" 24#include "net/base/escape.h" 25#import "net/base/mac/url_conversions.h" 26#include "testing/gmock/include/gmock/gmock.h" 27#include "testing/gtest/include/gtest/gtest.h" 28#include "testing/platform_test.h" 29#include "third_party/ocmock/OCMock/OCMock.h" 30#include "ui/base/page_transition_types.h" 31#include "url/scheme_host_port.h" 32#include "url/url_util.h" 33 34#if !defined(__has_feature) || !__has_feature(objc_arc) 35#error "This file requires ARC support." 36#endif 37 38namespace web { 39 40// Query parameter that will be appended by AppendingUrlRewriter if it is 41// installed into NavigationManager by a test case. 42const char kRewrittenQueryParam[] = "wknavigationmanagerrewrittenquery"; 43 44// Appends |kRewrittenQueryParam| to |url|. 45bool AppendingUrlRewriter(GURL* url, BrowserState* browser_state) { 46 GURL::Replacements query_replacements; 47 query_replacements.SetQueryStr(kRewrittenQueryParam); 48 *url = url->ReplaceComponents(query_replacements); 49 return false; 50} 51 52// URL scheme that will be rewritten by WebUIUrlRewriter. 53const char kSchemeToRewrite[] = "wknavigationmanagerschemetorewrite"; 54 55// Replaces |kSchemeToRewrite| scheme with |kTestWebUIScheme|. 56bool WebUIUrlRewriter(GURL* url, BrowserState* browser_state) { 57 if (url->scheme() == kSchemeToRewrite) { 58 GURL::Replacements scheme_replacements; 59 scheme_replacements.SetSchemeStr(kTestWebUIScheme); 60 *url = url->ReplaceComponents(scheme_replacements); 61 return true; 62 } 63 return false; 64} 65 66class MockNavigationManagerDelegate : public NavigationManagerDelegate { 67 public: 68 void SetWebViewNavigationProxy(id web_view) { mock_web_view_ = web_view; } 69 void RemoveWebView() override { 70 // Simulate removing the web view. 71 mock_web_view_ = nil; 72 } 73 74 MOCK_METHOD0(ClearTransientContent, void()); 75 MOCK_METHOD0(ClearDialogs, void()); 76 MOCK_METHOD0(RecordPageStateInNavigationItem, void()); 77 MOCK_METHOD2(OnGoToIndexSameDocumentNavigation, 78 void(NavigationInitiationType type, bool has_user_gesture)); 79 MOCK_METHOD1(LoadCurrentItem, void(NavigationInitiationType type)); 80 MOCK_METHOD0(LoadIfNecessary, void()); 81 MOCK_METHOD0(Reload, void()); 82 MOCK_METHOD1(OnNavigationItemsPruned, void(size_t)); 83 MOCK_METHOD1(OnNavigationItemCommitted, void(NavigationItem* item)); 84 MOCK_METHOD1(SetWebStateUserAgent, void(UserAgentType user_agent_type)); 85 MOCK_METHOD4(GoToBackForwardListItem, 86 void(WKBackForwardListItem*, 87 NavigationItem*, 88 NavigationInitiationType, 89 bool)); 90 MOCK_METHOD0(GetPendingItem, NavigationItemImpl*()); 91 92 private: 93 WebState* GetWebState() override { return nullptr; } 94 95 id<CRWWebViewNavigationProxy> GetWebViewNavigationProxy() const override { 96 return mock_web_view_; 97 } 98 99 id mock_web_view_; 100}; 101 102// Test fixture for WKBasedNavigationManagerImpl. 103class WKBasedNavigationManagerTest : public PlatformTest { 104 protected: 105 WKBasedNavigationManagerTest() : manager_(new WKBasedNavigationManagerImpl) { 106 mock_web_view_ = OCMClassMock([WKWebView class]); 107 mock_wk_list_ = [[CRWFakeBackForwardList alloc] init]; 108 OCMStub([mock_web_view_ backForwardList]).andReturn(mock_wk_list_); 109 delegate_.SetWebViewNavigationProxy(mock_web_view_); 110 111 manager_->SetDelegate(&delegate_); 112 manager_->SetBrowserState(&browser_state_); 113 114 BrowserURLRewriter::GetInstance()->AddURLRewriter(WebUIUrlRewriter); 115 url::AddStandardScheme(kSchemeToRewrite, url::SCHEME_WITH_HOST); 116 } 117 118 // Returns the value of the "#session=" URL hash component from |url|. 119 static std::string ExtractRestoredSession(const GURL& url) { 120 std::string decoded = net::UnescapeBinaryURLComponent(url.ref()); 121 return decoded.substr( 122 strlen(wk_navigation_util::kRestoreSessionSessionHashPrefix)); 123 } 124 125 std::unique_ptr<NavigationManagerImpl> manager_; 126 CRWFakeBackForwardList* mock_wk_list_; 127 id mock_web_view_; 128 MockNavigationManagerDelegate delegate_; 129 base::HistogramTester histogram_tester_; 130 131 private: 132 TestBrowserState browser_state_; 133 url::ScopedSchemeRegistryForTests scoped_registry_; 134}; 135 136// Tests that GetItemAtIndex() on an empty manager will sync navigation items to 137// WKBackForwardList using default properties. 138TEST_F(WKBasedNavigationManagerTest, SyncAfterItemAtIndex) { 139 EXPECT_EQ(0, manager_->GetItemCount()); 140 EXPECT_EQ(nullptr, manager_->GetItemAtIndex(0)); 141 142 [mock_wk_list_ setCurrentURL:@"http://www.0.com"]; 143 EXPECT_EQ(1, manager_->GetItemCount()); 144 EXPECT_EQ(0, manager_->GetLastCommittedItemIndex()); 145 146 NavigationItem* item = manager_->GetItemAtIndex(0); 147 ASSERT_NE(item, nullptr); 148 EXPECT_EQ(GURL("http://www.0.com"), item->GetURL()); 149 EXPECT_TRUE(ui::PageTransitionCoreTypeIs(ui::PAGE_TRANSITION_LINK, 150 item->GetTransitionType())); 151 EXPECT_EQ(UserAgentType::NONE, item->GetUserAgentType()); 152 EXPECT_FALSE(item->GetTimestamp().is_null()); 153} 154 155// Tests that Referrer is inferred from the previous WKBackForwardListItem. 156TEST_F(WKBasedNavigationManagerTest, SyncAfterItemAtIndexWithPreviousItem) { 157 [mock_wk_list_ setCurrentURL:@"http://www.1.com" 158 backListURLs:@[ @"http://www.0.com" ] 159 forwardListURLs:@[ @"http://www.2.com" ]]; 160 EXPECT_EQ(3, manager_->GetItemCount()); 161 EXPECT_EQ(1, manager_->GetLastCommittedItemIndex()); 162 163 // The out-of-order access is intentionall to test that syncing doesn't rely 164 // on the previous WKBackForwardListItem having an associated NavigationItem. 165 NavigationItem* item2 = manager_->GetItemAtIndex(2); 166 ASSERT_NE(item2, nullptr); 167 EXPECT_EQ(GURL("http://www.2.com"), item2->GetURL()); 168 EXPECT_TRUE(ui::PageTransitionCoreTypeIs(ui::PAGE_TRANSITION_LINK, 169 item2->GetTransitionType())); 170 EXPECT_EQ(UserAgentType::NONE, item2->GetUserAgentType()); 171 EXPECT_EQ(GURL("http://www.1.com"), item2->GetReferrer().url); 172 EXPECT_FALSE(item2->GetTimestamp().is_null()); 173 174 NavigationItem* item1 = manager_->GetItemAtIndex(1); 175 ASSERT_NE(item1, nullptr); 176 EXPECT_EQ(GURL("http://www.1.com"), item1->GetURL()); 177 EXPECT_TRUE(ui::PageTransitionCoreTypeIs(ui::PAGE_TRANSITION_LINK, 178 item1->GetTransitionType())); 179 EXPECT_EQ(UserAgentType::NONE, item1->GetUserAgentType()); 180 EXPECT_EQ(GURL("http://www.0.com"), item1->GetReferrer().url); 181 EXPECT_FALSE(item1->GetTimestamp().is_null()); 182 183 NavigationItem* item0 = manager_->GetItemAtIndex(0); 184 ASSERT_NE(item0, nullptr); 185 EXPECT_EQ(GURL("http://www.0.com"), item0->GetURL()); 186 EXPECT_TRUE(ui::PageTransitionCoreTypeIs(ui::PAGE_TRANSITION_LINK, 187 item0->GetTransitionType())); 188 EXPECT_EQ(UserAgentType::NONE, item0->GetUserAgentType()); 189 EXPECT_FALSE(item0->GetTimestamp().is_null()); 190} 191 192// Tests that GetLastCommittedItem() creates a default NavigationItem when the 193// last committed item in WKWebView does not have a linked entry. 194TEST_F(WKBasedNavigationManagerTest, SyncInGetLastCommittedItem) { 195 [mock_wk_list_ setCurrentURL:@"http://www.0.com"]; 196 EXPECT_EQ(1, manager_->GetItemCount()); 197 198 NavigationItem* item = manager_->GetLastCommittedItem(); 199 ASSERT_NE(item, nullptr); 200 EXPECT_EQ("http://www.0.com/", item->GetURL().spec()); 201 EXPECT_FALSE(item->GetTimestamp().is_null()); 202} 203 204// Tests that GetLastCommittedItem() creates a default NavigationItem when the 205// last committed item in WKWebView is an app-specific URL. 206TEST_F(WKBasedNavigationManagerTest, 207 SyncInGetLastCommittedItemForAppSpecificURL) { 208 GURL url(url::SchemeHostPort(kSchemeToRewrite, "test", 0).Serialize()); 209 210 // Verifies that the test URL is rewritten into an app-specific URL. 211 manager_->AddPendingItem(url, Referrer(), ui::PAGE_TRANSITION_TYPED, 212 web::NavigationInitiationType::BROWSER_INITIATED); 213 NavigationItem* pending_item = manager_->GetPendingItem(); 214 ASSERT_TRUE(pending_item); 215 ASSERT_TRUE(web::GetWebClient()->IsAppSpecificURL(pending_item->GetURL())); 216 217 [mock_wk_list_ setCurrentURL:base::SysUTF8ToNSString(url.spec())]; 218 NavigationItem* item = manager_->GetLastCommittedItem(); 219 220 ASSERT_NE(item, nullptr); 221 EXPECT_EQ(url, item->GetURL()); 222 EXPECT_EQ(1, manager_->GetItemCount()); 223} 224 225// Tests that CommitPendingItem() will sync navigation items to 226// WKBackForwardList and the pending item NavigationItemImpl will be used. 227TEST_F(WKBasedNavigationManagerTest, GetItemAtIndexAfterCommitPending) { 228 // Simulate a main frame navigation. 229 manager_->AddPendingItem(GURL("http://www.0.com"), Referrer(), 230 ui::PAGE_TRANSITION_TYPED, 231 web::NavigationInitiationType::BROWSER_INITIATED); 232 NavigationItem* pending_item0 = manager_->GetPendingItem(); 233 234 [mock_wk_list_ setCurrentURL:@"http://www.0.com"]; 235 manager_->CommitPendingItem(); 236 237 EXPECT_EQ(1, manager_->GetItemCount()); 238 NavigationItem* item = manager_->GetLastCommittedItem(); 239 EXPECT_EQ(pending_item0, item); 240 EXPECT_EQ(GURL("http://www.0.com"), item->GetURL()); 241 EXPECT_TRUE(ui::PageTransitionCoreTypeIs(ui::PAGE_TRANSITION_TYPED, 242 item->GetTransitionType())); 243 244 // Simulate a second main frame navigation. 245 manager_->AddPendingItem(GURL("http://www.2.com"), Referrer(), 246 ui::PAGE_TRANSITION_TYPED, 247 web::NavigationInitiationType::BROWSER_INITIATED); 248 NavigationItem* pending_item2 = manager_->GetPendingItem(); 249 250 // Simulate an iframe navigation between the two main frame navigations. 251 [mock_wk_list_ setCurrentURL:@"http://www.2.com" 252 backListURLs:@[ @"http://www.0.com", @"http://www.1.com" ] 253 forwardListURLs:nil]; 254 manager_->CommitPendingItem(); 255 256 EXPECT_EQ(3, manager_->GetItemCount()); 257 EXPECT_EQ(2, manager_->GetLastCommittedItemIndex()); 258 259 // This item is created by syncing. 260 NavigationItem* item1 = manager_->GetItemAtIndex(1); 261 EXPECT_EQ(GURL("http://www.1.com"), item1->GetURL()); 262 EXPECT_TRUE(ui::PageTransitionCoreTypeIs(ui::PAGE_TRANSITION_LINK, 263 item1->GetTransitionType())); 264 EXPECT_EQ(GURL("http://www.0.com"), item1->GetReferrer().url); 265 266 // This item is created by CommitPendingItem. 267 NavigationItem* item2 = manager_->GetItemAtIndex(2); 268 EXPECT_EQ(pending_item2, item2); 269 EXPECT_EQ(GURL("http://www.2.com"), item2->GetURL()); 270 EXPECT_TRUE(ui::PageTransitionCoreTypeIs(ui::PAGE_TRANSITION_TYPED, 271 item2->GetTransitionType())); 272 EXPECT_EQ(GURL(""), item2->GetReferrer().url); 273} 274 275// Tests that AddPendingItem does not create a new NavigationItem if the new 276// pending item is a back forward navigation or when reloading a redirect page. 277TEST_F(WKBasedNavigationManagerTest, ReusePendingItemForHistoryNavigation) { 278 // Simulate two regular navigations. 279 [mock_wk_list_ setCurrentURL:@"http://www.1.com" 280 backListURLs:@[ @"http://www.0.com" ] 281 forwardListURLs:nil]; 282 283 // Force sync NavigationItems. 284 NavigationItem* original_item0 = manager_->GetItemAtIndex(0); 285 manager_->GetItemAtIndex(1); 286 287 // Simulate a back-forward navigation. Manually shuffle the objects in 288 // mock_wk_list_ to avoid creating new WKBackForwardListItem mocks and 289 // preserve existing NavigationItem associations. 290 WKBackForwardListItem* wk_item0 = [mock_wk_list_ itemAtIndex:-1]; 291 WKBackForwardListItem* wk_item1 = [mock_wk_list_ itemAtIndex:0]; 292 mock_wk_list_.currentItem = wk_item0; 293 mock_wk_list_.backList = nil; 294 mock_wk_list_.forwardList = @[ wk_item1 ]; 295 OCMStub([mock_web_view_ URL]) 296 .andReturn([[NSURL alloc] initWithString:@"http://www.0.com"]); 297 manager_->AddPendingItem(GURL("http://www.0.com"), Referrer(), 298 ui::PAGE_TRANSITION_TYPED, 299 web::NavigationInitiationType::BROWSER_INITIATED); 300 301 EXPECT_EQ(original_item0, manager_->GetPendingItem()); 302 303 // Simulate reloading a redirect url. This happens when one restores while 304 // offline. 305 GURL redirect_url = wk_navigation_util::CreateRedirectUrl( 306 manager_->GetPendingItem()->GetURL()); 307 [mock_wk_list_ setCurrentURL:base::SysUTF8ToNSString(redirect_url.spec()) 308 backListURLs:nil 309 forwardListURLs:nil]; 310 original_item0 = manager_->GetItemAtIndex(0); 311 manager_->AddPendingItem(GURL("http://www.0.com"), Referrer(), 312 ui::PAGE_TRANSITION_RELOAD, 313 web::NavigationInitiationType::BROWSER_INITIATED); 314 EXPECT_EQ(original_item0, manager_->GetPendingItem()); 315} 316 317// Tests that AddPendingItem does not create a new NavigationItem if the new 318// pending item is a reload of app-specific URL. 319TEST_F(WKBasedNavigationManagerTest, ReusePendingItemForReloadAppSpecificURL) { 320 // Simulate a previous app-specific navigation. 321 NSString* url = @"about:blank?for=chrome%3A%2F%2Fnewtab"; 322 [mock_wk_list_ setCurrentURL:url]; 323 NavigationItem* original_item = manager_->GetItemAtIndex(0); 324 325 OCMExpect([mock_web_view_ URL]).andReturn([[NSURL alloc] initWithString:url]); 326 327 manager_->AddPendingItem(GURL("chrome://newtab"), Referrer(), 328 ui::PAGE_TRANSITION_RELOAD, 329 web::NavigationInitiationType::BROWSER_INITIATED); 330 331 EXPECT_EQ(original_item, manager_->GetPendingItem()); 332} 333 334// Tests that transient URL rewriters are only applied to a new pending item. 335TEST_F(WKBasedNavigationManagerTest, 336 TransientURLRewritersOnlyUsedForPendingItem) { 337 manager_->AddPendingItem(GURL("http://www.0.com"), Referrer(), 338 ui::PAGE_TRANSITION_TYPED, 339 NavigationInitiationType::BROWSER_INITIATED); 340 341 // Install transient URL rewriters. 342 manager_->AddTransientURLRewriter(&AppendingUrlRewriter); 343 [mock_wk_list_ setCurrentURL:@"http://www.0.com"]; 344 345 // Transient URL rewriters do not apply to lazily synced items. 346 NavigationItem* item0 = manager_->GetItemAtIndex(0); 347 EXPECT_EQ(GURL("http://www.0.com"), item0->GetURL()); 348 349 // Transient URL rewriters do not apply to transient items. 350 manager_->AddTransientItem(GURL("http://www.1.com")); 351 EXPECT_EQ(GURL("http://www.1.com"), manager_->GetTransientItem()->GetURL()); 352 353 // Transient URL rewriters are applied to a new pending item. 354 manager_->AddPendingItem(GURL("http://www.2.com"), Referrer(), 355 ui::PAGE_TRANSITION_TYPED, 356 NavigationInitiationType::BROWSER_INITIATED); 357 EXPECT_EQ(kRewrittenQueryParam, manager_->GetPendingItem()->GetURL().query()); 358} 359 360// Tests DiscardNonCommittedItems discards both pending and transient items. 361TEST_F(WKBasedNavigationManagerTest, DiscardNonCommittedItems) { 362 manager_->AddPendingItem(GURL("http://www.0.com"), Referrer(), 363 ui::PAGE_TRANSITION_TYPED, 364 web::NavigationInitiationType::BROWSER_INITIATED); 365 manager_->AddTransientItem(GURL("http://www.1.com")); 366 367 EXPECT_NE(nullptr, manager_->GetPendingItem()); 368 EXPECT_NE(nullptr, manager_->GetTransientItem()); 369 370 manager_->DiscardNonCommittedItems(); 371 EXPECT_EQ(nullptr, manager_->GetPendingItem()); 372 EXPECT_EQ(nullptr, manager_->GetTransientItem()); 373} 374 375// Tests that in the absence of a transient item, going back is delegated to the 376// underlying WKWebView. 377TEST_F(WKBasedNavigationManagerTest, GoBackWithoutTransientItem) { 378 ASSERT_FALSE(manager_->CanGoBack()); 379 380 manager_->AddPendingItem(GURL("http://www.0.com"), Referrer(), 381 ui::PAGE_TRANSITION_TYPED, 382 web::NavigationInitiationType::BROWSER_INITIATED); 383 [mock_wk_list_ setCurrentURL:@"http://www.0.com"]; 384 385 manager_->AddPendingItem(GURL("http://www.1.com"), Referrer(), 386 ui::PAGE_TRANSITION_TYPED, 387 web::NavigationInitiationType::BROWSER_INITIATED); 388 [mock_wk_list_ setCurrentURL:@"http://www.1.com" 389 backListURLs:@[ @"http://www.0.com" ] 390 forwardListURLs:nil]; 391 392 ASSERT_TRUE(manager_->CanGoBack()); 393 394 EXPECT_CALL(delegate_, 395 GoToBackForwardListItem( 396 mock_wk_list_.backList[0], manager_->GetItemAtIndex(0), 397 NavigationInitiationType::BROWSER_INITIATED, 398 /*has_user_gesture=*/true)); 399 manager_->GoBack(); 400 [mock_web_view_ verify]; 401} 402 403// Tests that going back from a transient item will discard the transient item 404// and the pending item associated with it. 405TEST_F(WKBasedNavigationManagerTest, GoBackFromTransientItem) { 406 manager_->AddPendingItem(GURL("http://www.0.com"), Referrer(), 407 ui::PAGE_TRANSITION_TYPED, 408 web::NavigationInitiationType::BROWSER_INITIATED); 409 [mock_wk_list_ setCurrentURL:@"http://www.0.com"]; 410 manager_->CommitPendingItem(); 411 412 manager_->AddPendingItem(GURL("http://www.1.com"), Referrer(), 413 ui::PAGE_TRANSITION_TYPED, 414 web::NavigationInitiationType::BROWSER_INITIATED); 415 manager_->AddTransientItem(GURL("http://www.1.com/transient")); 416 417 ASSERT_TRUE(manager_->CanGoBack()); 418 EXPECT_CALL(delegate_, 419 GoToBackForwardListItem( 420 mock_wk_list_.currentItem, manager_->GetItemAtIndex(0), 421 NavigationInitiationType::BROWSER_INITIATED, 422 /*has_user_gesture=*/true)); 423 manager_->GoBack(); 424 [mock_web_view_ verify]; 425 426 EXPECT_EQ(nullptr, manager_->GetPendingItem()); 427 EXPECT_EQ(nullptr, manager_->GetTransientItem()); 428} 429 430// Tests that going forward is always delegated to the underlying WKWebView 431// without any sanity checks such as whether any forward history exists. 432TEST_F(WKBasedNavigationManagerTest, GoForward) { 433 manager_->AddPendingItem(GURL("http://www.0.com"), Referrer(), 434 ui::PAGE_TRANSITION_TYPED, 435 web::NavigationInitiationType::BROWSER_INITIATED); 436 [mock_wk_list_ setCurrentURL:@"http://www.0.com"]; 437 manager_->CommitPendingItem(); 438 439 manager_->AddPendingItem(GURL("http://www.1.com"), Referrer(), 440 ui::PAGE_TRANSITION_TYPED, 441 web::NavigationInitiationType::BROWSER_INITIATED); 442 [mock_wk_list_ setCurrentURL:@"http://www.1.com" 443 backListURLs:@[ @"http://www.0.com" ] 444 forwardListURLs:nil]; 445 446 [mock_wk_list_ moveCurrentToIndex:0]; 447 ASSERT_TRUE(manager_->CanGoForward()); 448 449 EXPECT_CALL(delegate_, 450 GoToBackForwardListItem( 451 mock_wk_list_.forwardList[0], manager_->GetItemAtIndex(1), 452 NavigationInitiationType::BROWSER_INITIATED, 453 /*has_user_gesture=*/true)); 454 manager_->GoForward(); 455 [mock_web_view_ verify]; 456} 457 458// Tests that going forward clears uncommitted items. 459TEST_F(WKBasedNavigationManagerTest, GoForwardShouldDiscardsUncommittedItems) { 460 manager_->AddPendingItem(GURL("http://www.0.com"), Referrer(), 461 ui::PAGE_TRANSITION_TYPED, 462 web::NavigationInitiationType::BROWSER_INITIATED); 463 [mock_wk_list_ setCurrentURL:@"http://www.0.com"]; 464 manager_->CommitPendingItem(); 465 466 manager_->AddPendingItem(GURL("http://www.1.com"), Referrer(), 467 ui::PAGE_TRANSITION_TYPED, 468 web::NavigationInitiationType::BROWSER_INITIATED); 469 [mock_wk_list_ setCurrentURL:@"http://www.1.com" 470 backListURLs:@[ @"http://www.0.com" ] 471 forwardListURLs:nil]; 472 473 [mock_wk_list_ moveCurrentToIndex:0]; 474 ASSERT_TRUE(manager_->CanGoForward()); 475 476 manager_->AddPendingItem(GURL("http://www.0.com"), Referrer(), 477 ui::PAGE_TRANSITION_TYPED, 478 web::NavigationInitiationType::BROWSER_INITIATED); 479 manager_->AddTransientItem(GURL("http://www.1.com")); 480 481 EXPECT_NE(nullptr, manager_->GetPendingItem()); 482 EXPECT_NE(nullptr, manager_->GetTransientItem()); 483 484 EXPECT_CALL(delegate_, 485 GoToBackForwardListItem( 486 mock_wk_list_.forwardList[0], manager_->GetItemAtIndex(1), 487 NavigationInitiationType::BROWSER_INITIATED, 488 /*has_user_gesture=*/true)); 489 manager_->GoForward(); 490 [mock_web_view_ verify]; 491 492 EXPECT_EQ(nullptr, manager_->GetPendingItem()); 493 EXPECT_EQ(nullptr, manager_->GetTransientItem()); 494} 495 496// Tests CanGoToOffset API for positive, negative and zero delta. 497TEST_F(WKBasedNavigationManagerTest, CanGoToOffset) { 498 manager_->AddPendingItem(GURL("http://www.url.com/0"), Referrer(), 499 ui::PAGE_TRANSITION_LINK, 500 web::NavigationInitiationType::BROWSER_INITIATED); 501 502 [mock_wk_list_ setCurrentURL:@"http://www.url.com/0"]; 503 manager_->CommitPendingItem(); 504 505 manager_->AddPendingItem(GURL("http://www.url.com/1"), Referrer(), 506 ui::PAGE_TRANSITION_LINK, 507 web::NavigationInitiationType::BROWSER_INITIATED); 508 509 [mock_wk_list_ setCurrentURL:@"http://www.url.com/1" 510 backListURLs:@[ @"http://www.url.com/0" ] 511 forwardListURLs:nil]; 512 manager_->CommitPendingItem(); 513 514 manager_->AddPendingItem(GURL("http://www.url.com/2"), Referrer(), 515 ui::PAGE_TRANSITION_LINK, 516 web::NavigationInitiationType::BROWSER_INITIATED); 517 518 [mock_wk_list_ 519 setCurrentURL:@"http://www.url.com/2" 520 backListURLs:@[ @"http://www.url.com/0", @"http://www.url.com/1" ] 521 forwardListURLs:nil]; 522 manager_->CommitPendingItem(); 523 524 ASSERT_EQ(3, manager_->GetItemCount()); 525 ASSERT_EQ(2, manager_->GetLastCommittedItemIndex()); 526 527 // Go to entry at index 1 and test API from that state. 528 [mock_wk_list_ moveCurrentToIndex:1]; 529 ASSERT_EQ(1, manager_->GetLastCommittedItemIndex()); 530 ASSERT_EQ(-1, manager_->GetPendingItemIndex()); 531 EXPECT_TRUE(manager_->CanGoToOffset(-1)); 532 EXPECT_EQ(0, manager_->GetIndexForOffset(-1)); 533 EXPECT_FALSE(manager_->CanGoToOffset(-2)); 534 EXPECT_TRUE(manager_->CanGoToOffset(1)); 535 EXPECT_EQ(2, manager_->GetIndexForOffset(1)); 536 EXPECT_FALSE(manager_->CanGoToOffset(2)); 537 // Test with large values 538 EXPECT_FALSE(manager_->CanGoToOffset(INT_MAX)); 539 EXPECT_FALSE(manager_->CanGoToOffset(INT_MIN)); 540 541 // Go to entry at index 0 and test API from that state. 542 [mock_wk_list_ moveCurrentToIndex:0]; 543 ASSERT_EQ(0, manager_->GetLastCommittedItemIndex()); 544 ASSERT_EQ(-1, manager_->GetPendingItemIndex()); 545 EXPECT_FALSE(manager_->CanGoToOffset(-1)); 546 EXPECT_TRUE(manager_->CanGoToOffset(1)); 547 EXPECT_EQ(1, manager_->GetIndexForOffset(1)); 548 EXPECT_TRUE(manager_->CanGoToOffset(2)); 549 EXPECT_EQ(2, manager_->GetIndexForOffset(2)); 550 EXPECT_FALSE(manager_->CanGoToOffset(3)); 551 // Test with large values 552 EXPECT_FALSE(manager_->CanGoToOffset(INT_MAX)); 553 EXPECT_FALSE(manager_->CanGoToOffset(INT_MIN)); 554 555 // Go to entry at index 2 and test API from that state. 556 [mock_wk_list_ moveCurrentToIndex:2]; 557 ASSERT_EQ(2, manager_->GetLastCommittedItemIndex()); 558 ASSERT_EQ(-1, manager_->GetPendingItemIndex()); 559 EXPECT_TRUE(manager_->CanGoToOffset(-1)); 560 EXPECT_EQ(1, manager_->GetIndexForOffset(-1)); 561 EXPECT_TRUE(manager_->CanGoToOffset(-2)); 562 EXPECT_EQ(0, manager_->GetIndexForOffset(-2)); 563 EXPECT_FALSE(manager_->CanGoToOffset(1)); 564 // Test with large values 565 EXPECT_FALSE(manager_->CanGoToOffset(INT_MAX)); 566 EXPECT_FALSE(manager_->CanGoToOffset(INT_MIN)); 567 568 // Test with transient entry. 569 manager_->AddPendingItem(GURL("http://www.url.com/3"), Referrer(), 570 ui::PAGE_TRANSITION_LINK, 571 web::NavigationInitiationType::BROWSER_INITIATED); 572 manager_->AddTransientItem(GURL("http://www.url.com/3")); 573 ASSERT_EQ(3, manager_->GetItemCount()); 574 ASSERT_EQ(2, manager_->GetLastCommittedItemIndex()); 575 EXPECT_TRUE(manager_->CanGoToOffset(-1)); 576 EXPECT_EQ(2, manager_->GetIndexForOffset(-1)); 577 EXPECT_TRUE(manager_->CanGoToOffset(-3)); 578 EXPECT_EQ(0, manager_->GetIndexForOffset(-3)); 579 EXPECT_FALSE(manager_->CanGoToOffset(-4)); 580 EXPECT_FALSE(manager_->CanGoToOffset(1)); 581 582 // Simulate a history navigation pending item. 583 [mock_wk_list_ moveCurrentToIndex:1]; 584 OCMExpect([mock_web_view_ URL]) 585 .andReturn([[NSURL alloc] initWithString:@"http://www.url.com/1"]); 586 manager_->AddPendingItem(GURL("http://www.url.com/1"), Referrer(), 587 ui::PAGE_TRANSITION_LINK, 588 web::NavigationInitiationType::BROWSER_INITIATED); 589 590 EXPECT_EQ(3, manager_->GetItemCount()); 591 EXPECT_EQ(2, manager_->GetLastCommittedItemIndex()); 592 EXPECT_EQ(1, manager_->GetPendingItemIndex()); 593 EXPECT_TRUE(manager_->CanGoToOffset(-1)); 594 EXPECT_EQ(0, manager_->GetIndexForOffset(-1)); 595 EXPECT_FALSE(manager_->CanGoToOffset(-2)); 596 EXPECT_TRUE(manager_->CanGoToOffset(1)); 597 EXPECT_EQ(2, manager_->GetIndexForOffset(1)); 598 EXPECT_FALSE(manager_->CanGoToOffset(2)); 599} 600 601// Tests that non-empty session history can be restored, and are re-written if 602// necessary. 603TEST_F(WKBasedNavigationManagerTest, RestoreSessionWithHistory) { 604 manager_->AddTransientURLRewriter(&WebUIUrlRewriter); 605 auto item0 = std::make_unique<NavigationItemImpl>(); 606 GURL url(url::SchemeHostPort(kSchemeToRewrite, "test", 0).Serialize()); 607 item0->SetURL(url); 608 item0->SetTitle(base::ASCIIToUTF16("Test Website 0")); 609 auto item1 = std::make_unique<NavigationItemImpl>(); 610 item1->SetURL(GURL("http://www.1.com")); 611 612 std::vector<std::unique_ptr<NavigationItem>> items; 613 items.push_back(std::move(item0)); 614 items.push_back(std::move(item1)); 615 616 ASSERT_FALSE(manager_->IsRestoreSessionInProgress()); 617 manager_->Restore(1 /* last_committed_item_index */, std::move(items)); 618 EXPECT_TRUE(manager_->IsRestoreSessionInProgress()); 619 620 ASSERT_FALSE(manager_->GetPendingItem()); 621 NavigationItem* pending_item = 622 manager_->GetPendingItemInCurrentOrRestoredSession(); 623 ASSERT_TRUE(pending_item); 624 GURL pending_url = pending_item->GetURL(); 625 EXPECT_TRUE(pending_url.SchemeIsFile()); 626 EXPECT_EQ("restore_session.html", pending_url.ExtractFileName()); 627 EXPECT_EQ(url.spec(), pending_item->GetVirtualURL()); 628 EXPECT_EQ("Test Website 0", base::UTF16ToUTF8(pending_item->GetTitle())); 629 630 EXPECT_EQ("{\"offset\":0,\"titles\":[\"Test Website 0\",\"\"]," 631 "\"urls\":[\"testwebui://test/\"," 632 "\"http://www.1.com/\"]}", 633 ExtractRestoredSession(pending_url)); 634 635 // Check that cached visible item is returned. 636 EXPECT_EQ("http://www.1.com/", manager_->GetVisibleItem()->GetURL()); 637 638 histogram_tester_.ExpectTotalCount(kRestoreNavigationItemCount, 1); 639 histogram_tester_.ExpectBucketCount(kRestoreNavigationItemCount, 2, 1); 640} 641 642// Tests that restoring session replaces existing history in navigation manager. 643TEST_F(WKBasedNavigationManagerTest, RestoreSessionResetsHistory) { 644 EXPECT_EQ(-1, manager_->GetPendingItemIndex()); 645 EXPECT_EQ(-1, manager_->GetLastCommittedItemIndex()); 646 647 // Sets up the navigation history with 2 entries, and a pending back-forward 648 // navigation so that last_committed_item_index is 1, pending_item_index is 0, 649 // and previous_item_index is 0. Basically, none of them is -1. 650 manager_->AddPendingItem(GURL("http://www.url.com/0"), Referrer(), 651 ui::PAGE_TRANSITION_TYPED, 652 web::NavigationInitiationType::BROWSER_INITIATED); 653 [mock_wk_list_ setCurrentURL:@"http://www.url.com/0"]; 654 manager_->CommitPendingItem(); 655 656 manager_->AddPendingItem(GURL("http://www.url.com/1"), Referrer(), 657 ui::PAGE_TRANSITION_TYPED, 658 web::NavigationInitiationType::BROWSER_INITIATED); 659 [mock_wk_list_ setCurrentURL:@"http://www.url.com/1" 660 backListURLs:@[ @"http://www.url.com/0" ] 661 forwardListURLs:nil]; 662 manager_->CommitPendingItem(); 663 664 [mock_wk_list_ moveCurrentToIndex:0]; 665 OCMStub([mock_web_view_ URL]) 666 .andReturn([NSURL URLWithString:@"http://www.url.com/0"]); 667 manager_->AddPendingItem(GURL("http://www.url.com/0"), Referrer(), 668 ui::PAGE_TRANSITION_TYPED, 669 web::NavigationInitiationType::BROWSER_INITIATED); 670 671 EXPECT_EQ(1, manager_->GetLastCommittedItemIndex()); 672 EXPECT_EQ(0, manager_->GetPendingItemIndex()); 673 EXPECT_TRUE(manager_->GetPendingItem() != nullptr); 674 675 // Restores a fake session. 676 auto restored_item = std::make_unique<NavigationItemImpl>(); 677 restored_item->SetURL(GURL("http://restored.com")); 678 std::vector<std::unique_ptr<NavigationItem>> items; 679 items.push_back(std::move(restored_item)); 680 ASSERT_FALSE(manager_->IsRestoreSessionInProgress()); 681 manager_->Restore(0 /* last_committed_item_index */, std::move(items)); 682 EXPECT_TRUE(manager_->IsRestoreSessionInProgress()); 683 684 // Check that last_committed_index, previous_item_index and pending_item_index 685 // are all reset to -1. Note that last_committed_item_index will change to the 686 // value in the restored session (i.e. 0) once restore_session.html finishes 687 // loading in the web view. This is not tested here because this test doesn't 688 // use real WKWebView. 689 EXPECT_EQ(-1, manager_->GetLastCommittedItemIndex()); 690 EXPECT_EQ(-1, manager_->GetPendingItemIndex()); 691 692 // Check that the only pending item is restore_session.html. 693 ASSERT_FALSE(manager_->GetPendingItem()); 694 NavigationItem* pending_item = 695 manager_->GetPendingItemInCurrentOrRestoredSession(); 696 ASSERT_TRUE(pending_item != nullptr); 697 GURL pending_url = pending_item->GetURL(); 698 EXPECT_TRUE(pending_url.SchemeIsFile()); 699 EXPECT_EQ("restore_session.html", pending_url.ExtractFileName()); 700 701 // Check that cached visible item is returned. 702 EXPECT_EQ("http://restored.com/", manager_->GetVisibleItem()->GetURL()); 703} 704 705// Tests that Restore() accepts empty session history and performs no-op. 706TEST_F(WKBasedNavigationManagerTest, RestoreSessionWithEmptyHistory) { 707 manager_->Restore(-1 /* last_committed_item_index */, 708 std::vector<std::unique_ptr<NavigationItem>>()); 709 710 ASSERT_EQ(nullptr, manager_->GetPendingItem()); 711} 712 713// Tests that the virtual URL of a restore_session redirect item is updated to 714// the target URL. 715TEST_F(WKBasedNavigationManagerTest, HideInternalRedirectUrl) { 716 GURL target_url = GURL("http://www.1.com?query=special%26chars"); 717 GURL url = wk_navigation_util::CreateRedirectUrl(target_url); 718 NSString* url_spec = base::SysUTF8ToNSString(url.spec()); 719 [mock_wk_list_ setCurrentURL:url_spec]; 720 NavigationItem* item = manager_->GetItemAtIndex(0); 721 ASSERT_TRUE(item); 722 EXPECT_EQ(target_url, item->GetVirtualURL()); 723 EXPECT_EQ(url, item->GetURL()); 724} 725 726// Tests that the virtual URL of a placeholder item is updated to the original 727// URL. 728TEST_F(WKBasedNavigationManagerTest, HideInternalPlaceholderUrl) { 729 if (base::FeatureList::IsEnabled(web::features::kUseJSForErrorPage)) 730 return; 731 732 GURL original_url = GURL("http://www.1.com?query=special%26chars"); 733 GURL url = wk_navigation_util::CreatePlaceholderUrlForUrl(original_url); 734 NSString* url_spec = base::SysUTF8ToNSString(url.spec()); 735 [mock_wk_list_ setCurrentURL:url_spec]; 736 NavigationItem* item = manager_->GetItemAtIndex(0); 737 ASSERT_TRUE(item); 738 EXPECT_EQ(original_url, item->GetVirtualURL()); 739 EXPECT_EQ(url, item->GetURL()); 740} 741 742// Tests that all NavigationManager APIs return reasonable values in the Empty 743// Window Open Navigation edge case. See comments in header file for details. 744TEST_F(WKBasedNavigationManagerTest, EmptyWindowOpenNavigation) { 745 // Set up the precondition for an empty window open item. 746 OCMExpect([mock_web_view_ URL]) 747 .andReturn(net::NSURLWithGURL(GURL(url::kAboutBlankURL))); 748 mock_wk_list_.currentItem = nil; 749 750 manager_->AddPendingItem(GURL(url::kAboutBlankURL), Referrer(), 751 ui::PAGE_TRANSITION_LINK, 752 web::NavigationInitiationType::RENDERER_INITIATED); 753 754 const NavigationItem* pending_item = manager_->GetPendingItem(); 755 ASSERT_TRUE(pending_item); 756 EXPECT_EQ(-1, manager_->GetPendingItemIndex()); 757 EXPECT_EQ(url::kAboutBlankURL, pending_item->GetURL().spec()); 758 759 manager_->CommitPendingItem(); 760 761 const NavigationItem* last_committed_item = manager_->GetLastCommittedItem(); 762 ASSERT_EQ(pending_item, last_committed_item); 763 EXPECT_EQ(last_committed_item, manager_->GetVisibleItem()); 764 765 EXPECT_EQ(0, manager_->GetIndexForOffset(0)); 766 EXPECT_EQ(1, manager_->GetIndexForOffset(1)); 767 EXPECT_EQ(-1, manager_->GetIndexForOffset(-1)); 768 769 EXPECT_EQ(1, manager_->GetItemCount()); 770 EXPECT_EQ(last_committed_item, manager_->GetItemAtIndex(0)); 771 EXPECT_FALSE(manager_->GetItemAtIndex(1)); 772 773 EXPECT_EQ(0, manager_->GetIndexOfItem(last_committed_item)); 774 EXPECT_EQ(-1, manager_->GetPendingItemIndex()); 775 EXPECT_EQ(0, manager_->GetLastCommittedItemIndex()); 776 777 EXPECT_FALSE(manager_->CanGoBack()); 778 EXPECT_FALSE(manager_->CanGoForward()); 779 EXPECT_TRUE(manager_->CanGoToOffset(0)); 780 EXPECT_FALSE(manager_->CanGoToOffset(-1)); 781 EXPECT_FALSE(manager_->CanGoToOffset(1)); 782 783 // This is allowed on an empty window open item. 784 manager_->GoToIndex(0); 785 786 // Add another navigation and verify that it replaces the empty window open 787 // item. 788 manager_->AddPendingItem(GURL("http://www.2.com"), Referrer(), 789 ui::PAGE_TRANSITION_TYPED, 790 web::NavigationInitiationType::BROWSER_INITIATED); 791 792 const NavigationItem* pending_item_2 = manager_->GetPendingItem(); 793 ASSERT_TRUE(pending_item_2); 794 EXPECT_EQ("http://www.2.com/", pending_item_2->GetURL().spec()); 795 796 [mock_wk_list_ setCurrentURL:@"http://www.2.com"]; 797 manager_->CommitPendingItem(); 798 OCMExpect([mock_web_view_ URL]) 799 .andReturn([[NSURL alloc] initWithString:@"http://www.2.com"]); 800 801 const NavigationItem* last_committed_item_2 = 802 manager_->GetLastCommittedItem(); 803 ASSERT_EQ(pending_item_2, last_committed_item_2); 804 EXPECT_EQ(last_committed_item_2, manager_->GetVisibleItem()); 805 806 EXPECT_EQ(0, manager_->GetIndexForOffset(0)); 807 EXPECT_EQ(1, manager_->GetIndexForOffset(1)); 808 EXPECT_EQ(-1, manager_->GetIndexForOffset(-1)); 809 810 EXPECT_EQ(1, manager_->GetItemCount()); 811 EXPECT_EQ(last_committed_item_2, manager_->GetItemAtIndex(0)); 812 EXPECT_FALSE(manager_->GetItemAtIndex(1)); 813 814 EXPECT_EQ(-1, manager_->GetIndexOfItem(last_committed_item)); 815 EXPECT_EQ(0, manager_->GetIndexOfItem(last_committed_item_2)); 816 EXPECT_EQ(-1, manager_->GetPendingItemIndex()); 817 EXPECT_EQ(0, manager_->GetLastCommittedItemIndex()); 818 819 EXPECT_FALSE(manager_->CanGoBack()); 820 EXPECT_FALSE(manager_->CanGoForward()); 821 EXPECT_TRUE(manager_->CanGoToOffset(0)); 822 EXPECT_FALSE(manager_->CanGoToOffset(-1)); 823 EXPECT_FALSE(manager_->CanGoToOffset(1)); 824 825 // This is still allowed on a length-1 navigation history. 826 manager_->GoToIndex(0); 827} 828 829// Test fixture for detach from web view mode for WKBasedNavigationManagerImpl. 830class WKBasedNavigationManagerDetachedModeTest 831 : public WKBasedNavigationManagerTest { 832 protected: 833 void SetUp() override { 834 // Sets up each test case with a session history of 3 items. The middle item 835 // is the current item. 836 url0_ = GURL("http://www.0.com"); 837 url1_ = GURL("http://www.1.com"); 838 url2_ = GURL("http://www.2.com"); 839 840 [mock_wk_list_ setCurrentURL:@"http://www.1.com" 841 backListURLs:@[ @"http://www.0.com" ] 842 forwardListURLs:@[ @"http://www.2.com" ]]; 843 844 ASSERT_EQ(url0_, manager_->GetItemAtIndex(0)->GetURL()); 845 ASSERT_EQ(url1_, manager_->GetItemAtIndex(1)->GetURL()); 846 ASSERT_EQ(url2_, manager_->GetItemAtIndex(2)->GetURL()); 847 } 848 849 NSString* CreateRedirectUrlForWKList(GURL url) { 850 GURL redirect_url = wk_navigation_util::CreateRedirectUrl(url); 851 return base::SysUTF8ToNSString(redirect_url.spec()); 852 } 853 854 GURL url0_; 855 GURL url1_; 856 GURL url2_; 857}; 858 859// Tests that all getters return the expected value in detached mode. 860TEST_F(WKBasedNavigationManagerDetachedModeTest, CachedSessionHistory) { 861 manager_->DetachFromWebView(); 862 delegate_.RemoveWebView(); 863 864 EXPECT_EQ(url1_, manager_->GetVisibleItem()->GetURL()); 865 EXPECT_EQ(3, manager_->GetItemCount()); 866 867 EXPECT_EQ(url0_, manager_->GetItemAtIndex(0)->GetURL()); 868 EXPECT_EQ(url1_, manager_->GetItemAtIndex(1)->GetURL()); 869 EXPECT_EQ(url2_, manager_->GetItemAtIndex(2)->GetURL()); 870 871 EXPECT_EQ(0, manager_->GetIndexOfItem(manager_->GetItemAtIndex(0))); 872 EXPECT_EQ(1, manager_->GetIndexOfItem(manager_->GetItemAtIndex(1))); 873 EXPECT_EQ(2, manager_->GetIndexOfItem(manager_->GetItemAtIndex(2))); 874 875 EXPECT_EQ(-1, manager_->GetPendingItemIndex()); 876 EXPECT_EQ(nullptr, manager_->GetPendingItem()); 877 878 EXPECT_EQ(1, manager_->GetLastCommittedItemIndex()); 879 EXPECT_EQ(url1_, manager_->GetLastCommittedItem()->GetURL()); 880 881 EXPECT_TRUE(manager_->CanGoBack()); 882 EXPECT_TRUE(manager_->CanGoForward()); 883 EXPECT_TRUE(manager_->CanGoToOffset(0)); 884 EXPECT_TRUE(manager_->CanGoToOffset(-1)); 885 EXPECT_TRUE(manager_->CanGoToOffset(1)); 886 887 EXPECT_EQ(0, manager_->GetIndexForOffset(-1)); 888 EXPECT_EQ(1, manager_->GetIndexForOffset(0)); 889 EXPECT_EQ(2, manager_->GetIndexForOffset(1)); 890 891 NavigationItemList backward_items = manager_->GetBackwardItems(); 892 EXPECT_EQ(1UL, backward_items.size()); 893 EXPECT_EQ(url0_, backward_items[0]->GetURL()); 894 895 NavigationItemList forward_items = manager_->GetForwardItems(); 896 EXPECT_EQ(1UL, forward_items.size()); 897 EXPECT_EQ(url2_, forward_items[0]->GetURL()); 898} 899 900// Tests that detaching from an empty WKWebView works. 901TEST_F(WKBasedNavigationManagerDetachedModeTest, NothingToCache) { 902 delegate_.RemoveWebView(); 903 manager_->DetachFromWebView(); 904 905 EXPECT_EQ(0, manager_->GetItemCount()); 906 EXPECT_EQ(nullptr, manager_->GetVisibleItem()); 907 EXPECT_EQ(nullptr, manager_->GetItemAtIndex(0)); 908 EXPECT_EQ(nullptr, manager_->GetPendingItem()); 909 EXPECT_EQ(-1, manager_->GetLastCommittedItemIndex()); 910 911 manager_->Reload(web::ReloadType::NORMAL, false /* check_for_repost */); 912 EXPECT_EQ(nullptr, manager_->GetPendingItem()); 913} 914 915// Tests that Reload from detached mode restores cached history. 916TEST_F(WKBasedNavigationManagerDetachedModeTest, Reload) { 917 manager_->DetachFromWebView(); 918 delegate_.RemoveWebView(); 919 920 manager_->Reload(web::ReloadType::NORMAL, false /* check_for_repost */); 921 NavigationItem* pending_item = 922 manager_->GetPendingItemInCurrentOrRestoredSession(); 923 EXPECT_EQ( 924 "{\"offset\":-1,\"titles\":[\"\",\"\",\"\"],\"urls\":[\"http://www.0.com/" 925 "\",\"http://www.1.com/\",\"http://www.2.com/\"]}", 926 ExtractRestoredSession(pending_item->GetURL())); 927 928 EXPECT_EQ(url0_, pending_item->GetVirtualURL()); 929 EXPECT_EQ(url1_, manager_->GetVisibleItem()->GetURL()); 930 931 histogram_tester_.ExpectTotalCount(kRestoreNavigationItemCount, 1); 932 histogram_tester_.ExpectBucketCount(kRestoreNavigationItemCount, 3, 1); 933} 934 935// Tests that GoToIndex from detached mode restores cached history with updated 936// current item offset. 937TEST_F(WKBasedNavigationManagerDetachedModeTest, GoToIndex) { 938 manager_->DetachFromWebView(); 939 delegate_.RemoveWebView(); 940 941 manager_->GoToIndex(0); 942 NavigationItem* pending_item = 943 manager_->GetPendingItemInCurrentOrRestoredSession(); 944 945 EXPECT_EQ( 946 "{\"offset\":-2,\"titles\":[\"\",\"\",\"\"],\"urls\":[\"http://www.0.com/" 947 "\",\"http://www.1.com/\",\"http://www.2.com/\"]}", 948 ExtractRestoredSession(pending_item->GetURL())); 949 EXPECT_EQ(url0_, pending_item->GetVirtualURL()); 950 EXPECT_EQ(url0_, manager_->GetVisibleItem()->GetURL()); 951 952 histogram_tester_.ExpectTotalCount(kRestoreNavigationItemCount, 1); 953 histogram_tester_.ExpectBucketCount(kRestoreNavigationItemCount, 3, 1); 954} 955 956// Tests that LoadIfNecessary from detached mode restores cached history. 957TEST_F(WKBasedNavigationManagerDetachedModeTest, LoadIfNecessary) { 958 manager_->DetachFromWebView(); 959 delegate_.RemoveWebView(); 960 961 manager_->LoadIfNecessary(); 962 NavigationItem* pending_item = 963 manager_->GetPendingItemInCurrentOrRestoredSession(); 964 965 EXPECT_EQ( 966 "{\"offset\":-1,\"titles\":[\"\",\"\",\"\"],\"urls\":[\"http://www.0.com/" 967 "\",\"http://www.1.com/\",\"http://www.2.com/\"]}", 968 ExtractRestoredSession(pending_item->GetURL())); 969 EXPECT_EQ(url0_, pending_item->GetVirtualURL()); 970 EXPECT_EQ(url1_, manager_->GetVisibleItem()->GetURL()); 971 972 histogram_tester_.ExpectTotalCount(kRestoreNavigationItemCount, 1); 973 histogram_tester_.ExpectBucketCount(kRestoreNavigationItemCount, 3, 1); 974} 975 976// Tests that LoadURLWithParams from detached mode restores backward history and 977// adds the new item at the end. 978TEST_F(WKBasedNavigationManagerDetachedModeTest, LoadURLWithParams) { 979 manager_->DetachFromWebView(); 980 delegate_.RemoveWebView(); 981 982 GURL url("http://www.3.com"); 983 NavigationManager::WebLoadParams params(url); 984 manager_->LoadURLWithParams(params); 985 NavigationItem* pending_item = 986 manager_->GetPendingItemInCurrentOrRestoredSession(); 987 EXPECT_EQ( 988 "{\"offset\":0,\"titles\":[\"\",\"\",\"\"],\"urls\":[\"http://www.0.com/" 989 "\",\"http://www.1.com/\",\"http://www.3.com/\"]}", 990 ExtractRestoredSession(pending_item->GetURL())); 991 EXPECT_EQ(url0_, pending_item->GetVirtualURL()); 992 EXPECT_EQ(url, manager_->GetVisibleItem()->GetURL()); 993 994 histogram_tester_.ExpectTotalCount(kRestoreNavigationItemCount, 1); 995 histogram_tester_.ExpectBucketCount(kRestoreNavigationItemCount, 3, 1); 996} 997 998// Tests that detaching placeholder urls are cleaned before being cached. 999TEST_F(WKBasedNavigationManagerDetachedModeTest, CachedPlaceholders) { 1000 [mock_wk_list_ setCurrentURL:CreateRedirectUrlForWKList(url1_) 1001 backListURLs:@[ CreateRedirectUrlForWKList(url0_) ] 1002 forwardListURLs:@[ CreateRedirectUrlForWKList(url2_) ]]; 1003 manager_->DetachFromWebView(); 1004 1005 EXPECT_EQ(url0_, manager_->GetNavigationItemImplAtIndex(0)->GetURL()); 1006 EXPECT_EQ(url1_, manager_->GetNavigationItemImplAtIndex(1)->GetURL()); 1007 EXPECT_EQ(url2_, manager_->GetNavigationItemImplAtIndex(2)->GetURL()); 1008} 1009 1010// Tests that pending item is set to serializable when appropriate. 1011TEST_F(WKBasedNavigationManagerDetachedModeTest, NotSerializable) { 1012 manager_->AddPendingItem(GURL("http://www.0.com"), Referrer(), 1013 ui::PAGE_TRANSITION_TYPED, 1014 web::NavigationInitiationType::BROWSER_INITIATED); 1015 EXPECT_FALSE(manager_->GetPendingItemInCurrentOrRestoredSession() 1016 ->ShouldSkipSerialization()); 1017 1018 manager_->SetWKWebViewNextPendingUrlNotSerializable(GURL("http://www.1.com")); 1019 manager_->AddPendingItem(GURL("http://www.1.com"), Referrer(), 1020 ui::PAGE_TRANSITION_TYPED, 1021 web::NavigationInitiationType::BROWSER_INITIATED); 1022 EXPECT_TRUE(manager_->GetPendingItemInCurrentOrRestoredSession() 1023 ->ShouldSkipSerialization()); 1024 1025 manager_->AddPendingItem(GURL("http://www.1.com"), Referrer(), 1026 ui::PAGE_TRANSITION_TYPED, 1027 web::NavigationInitiationType::BROWSER_INITIATED); 1028 EXPECT_FALSE(manager_->GetPendingItemInCurrentOrRestoredSession() 1029 ->ShouldSkipSerialization()); 1030} 1031 1032} // namespace web 1033