chromium/ios/chrome/browser/web/model/web_state_delegate_browser_agent_unittest.mm

// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#import "ios/chrome/browser/web/model/web_state_delegate_browser_agent.h"

#import "ios/chrome/browser/overlays/model/public/overlay_request.h"
#import "ios/chrome/browser/overlays/model/public/overlay_request_queue.h"
#import "ios/chrome/browser/overlays/model/public/web_content_area/http_auth_overlay.h"
#import "ios/chrome/browser/overlays/model/public/web_content_area/java_script_alert_dialog_overlay.h"
#import "ios/chrome/browser/shared/model/browser/browser.h"
#import "ios/chrome/browser/shared/model/browser/test/test_browser.h"
#import "ios/chrome/browser/shared/model/profile/profile_ios.h"
#import "ios/chrome/browser/shared/model/profile/test/test_profile_ios.h"
#import "ios/chrome/browser/shared/model/web_state_list/web_state_list.h"
#import "ios/chrome/browser/snapshots/model/snapshot_tab_helper.h"
#import "ios/chrome/browser/tab_insertion/model/tab_insertion_browser_agent.h"
#import "ios/chrome/browser/web/model/blocked_popup_tab_helper.h"
#import "ios/web/public/navigation/navigation_item.h"
#import "ios/web/public/test/web_task_environment.h"
#import "ios/web/public/ui/java_script_dialog_presenter.h"
#import "ios/web/public/web_state.h"
#import "testing/gtest/include/gtest/gtest.h"
#import "testing/gtest_mac.h"
#import "testing/platform_test.h"

const char kURL1[] = "https://www.some.url.com";
const char kURL2[] = "https://www.some.url2.com";

// Test fixture for WebStateDelegateTabHelper.
class WebStateDelegateBrowserAgentTest : public PlatformTest {
 public:
  WebStateDelegateBrowserAgentTest() {
    browser_state_ = TestChromeBrowserState::Builder().Build();
    browser_ = std::make_unique<TestBrowser>(browser_state_.get());
    TabInsertionBrowserAgent::CreateForBrowser(browser_.get());
    WebStateDelegateBrowserAgent::CreateForBrowser(
        browser_.get(), TabInsertionBrowserAgent::FromBrowser(browser_.get()));
  }
  ~WebStateDelegateBrowserAgentTest() override = default;

  web::WebStateDelegate* delegate() {
    return WebStateDelegateBrowserAgent::FromBrowser(browser_.get());
  }

  web::WebState* InsertNewWebState(const GURL& url) {
    web::NavigationManager::WebLoadParams load_params(url);
    load_params.transition_type = ui::PAGE_TRANSITION_TYPED;

    web::WebState::CreateParams create_params(browser_->GetBrowserState());
    create_params.created_with_opener = false;

    std::unique_ptr<web::WebState> web_state =
        web::WebState::Create(create_params);
    OverlayRequestQueue::CreateForWebState(web_state.get());
    BlockedPopupTabHelper::GetOrCreateForWebState(web_state.get());
    SnapshotTabHelper::CreateForWebState(web_state.get());
    web_state->GetNavigationManager()->LoadURLWithParams(load_params);

    WebStateList* web_state_list = browser_->GetWebStateList();
    web_state_list->InsertWebState(
        std::move(web_state),
        WebStateList::InsertionParams::Automatic().Activate());
    return web_state_list->GetActiveWebState();
  }

 protected:
  web::WebTaskEnvironment task_environment_;
  std::unique_ptr<TestChromeBrowserState> browser_state_;
  std::unique_ptr<TestBrowser> browser_;
};

// Test that CreateNewWebState() creates a new web state in the correct place.
TEST_F(WebStateDelegateBrowserAgentTest, CreateNewWebState) {
  web::WebState* web_state = InsertNewWebState(GURL(kURL1));
  web::WebState* web_state2 =
      delegate()->CreateNewWebState(web_state, GURL(kURL2), GURL(kURL1), true);
  EXPECT_NE(web_state2, nullptr);

  // Check that it was inserted correctly
  EXPECT_EQ(browser_->GetWebStateList()->GetIndexOfWebState(web_state2),
            browser_->GetWebStateList()->GetIndexOfWebState(web_state) + 1);
}

// Test that CreateNewWebState() doesn't create a popup if popups aren't
// enabled.
TEST_F(WebStateDelegateBrowserAgentTest, CreateNewWebStateAndPopup) {
  web::WebState* web_state = InsertNewWebState(GURL(kURL1));

  // Verify that this webstate's popups are blocked
  BlockedPopupTabHelper* popup_helper =
      BlockedPopupTabHelper::GetOrCreateForWebState(web_state);
  EXPECT_TRUE(popup_helper->ShouldBlockPopup(GURL(kURL1)));
  // Create a new webstate without user initiation.
  web::WebState* web_state2 =
      delegate()->CreateNewWebState(web_state, GURL(kURL2), GURL(kURL1), false);
  // Expect that the webstate isn't created, returned, or inserted into the\
  // web state list.
  EXPECT_EQ(web_state2, nullptr);
  EXPECT_EQ(browser_->GetWebStateList()->count(), 1);
}

// Test that CloseWebState() removed the web state from the web state list.
TEST_F(WebStateDelegateBrowserAgentTest, CloseWebState) {
  web::WebState* web_state = InsertNewWebState(GURL(kURL1));
  delegate()->CloseWebState(web_state);
  EXPECT_EQ(browser_->GetWebStateList()->count(), 0);
}

// Test that the new tab options for OpenURLFromWebState() creates new web
// states and activates them appropriately.
TEST_F(WebStateDelegateBrowserAgentTest, OpenURLNewTabs) {
  web::WebState* web_state = InsertNewWebState(GURL(kURL1));
  web::WebState::OpenURLParams fg_open_params(
      GURL(kURL2), web::Referrer(), WindowOpenDisposition::NEW_FOREGROUND_TAB,
      ui::PAGE_TRANSITION_LINK, false);
  web::WebState* web_state2 =
      delegate()->OpenURLFromWebState(web_state, fg_open_params);
  EXPECT_EQ(browser_->GetWebStateList()->count(), 2);
  // NEW_FOREGROUND_TAB should activate the newly added webstate.
  EXPECT_EQ(browser_->GetWebStateList()->GetActiveWebState(), web_state2);

  web::WebState::OpenURLParams bg_open_params(
      GURL(kURL2), web::Referrer(), WindowOpenDisposition::NEW_BACKGROUND_TAB,
      ui::PAGE_TRANSITION_LINK, false);
  delegate()->OpenURLFromWebState(web_state, bg_open_params);
  EXPECT_EQ(browser_->GetWebStateList()->count(), 3);
  // NEW_BACKGROUND_TAB should *not* activate the newly added webstate, so
  // web_state2 should still be active.
  EXPECT_EQ(browser_->GetWebStateList()->GetActiveWebState(), web_state2);
}

// Tests that OpenURLFromWebState() doesn't create a new tab with the
// CURRENT_TAB option.
TEST_F(WebStateDelegateBrowserAgentTest, OpenURLCurrentTab) {
  InsertNewWebState(GURL(kURL1));
  web::WebState::OpenURLParams open_params(GURL(kURL2), web::Referrer(),
                                           WindowOpenDisposition::CURRENT_TAB,
                                           ui::PAGE_TRANSITION_LINK, false);
  EXPECT_EQ(browser_->GetWebStateList()->count(), 1);
}

// Tests that OnAuthRequired() adds an HTTP authentication overlay request to
// the WebState's OverlayRequestQueue at OverlayModality::kWebContentArea.
TEST_F(WebStateDelegateBrowserAgentTest, OnAuthRequired) {
  NSURLProtectionSpace* protection_space =
      [[NSURLProtectionSpace alloc] initWithProxyHost:@"http://chromium.test"
                                                 port:0
                                                 type:nil
                                                realm:nil
                                 authenticationMethod:nil];
  NSURLCredential* credential =
      [[NSURLCredential alloc] initWithUser:@""
                                   password:@""
                                persistence:NSURLCredentialPersistenceNone];
  web::WebStateDelegate::AuthCallback callback =
      base::BindOnce(^(NSString* user, NSString* password){
      });
  web::WebState* web_state = InsertNewWebState(GURL(kURL1));
  delegate()->OnAuthRequired(web_state, protection_space, credential,
                             std::move(callback));

  // Verify that an HTTP auth overlay request has been created for the WebState.
  OverlayRequestQueue* queue = OverlayRequestQueue::FromWebState(
      web_state, OverlayModality::kWebContentArea);
  ASSERT_TRUE(queue);
  OverlayRequest* request = queue->front_request();
  EXPECT_TRUE(request);
  EXPECT_TRUE(request->GetConfig<HTTPAuthOverlayRequestConfig>());
}

// Tests that GetJavaScriptDialogPresenter() returns an overlay-based JavaScript
// dialog presenter.
TEST_F(WebStateDelegateBrowserAgentTest, GetJavaScriptDialogPresenter) {
  // Verify that the delegate returns a non-null presenter.
  web::WebState* web_state = InsertNewWebState(GURL(kURL1));
  web::JavaScriptDialogPresenter* presenter =
      delegate()->GetJavaScriptDialogPresenter(web_state);
  EXPECT_TRUE(presenter);

  // Present a JavaScript alert.
  GURL kOriginUrl("http://chromium.test");
  presenter->RunJavaScriptAlertDialog(web_state, kOriginUrl, @"",
                                      base::DoNothing());

  // Verify that JavaScript alert OverlayRequest has been added to the
  // WebState's queue.
  OverlayRequestQueue* queue = OverlayRequestQueue::FromWebState(
      web_state, OverlayModality::kWebContentArea);
  ASSERT_TRUE(queue);
  OverlayRequest* request = queue->front_request();
  EXPECT_TRUE(request);
  EXPECT_TRUE(request->GetConfig<JavaScriptAlertDialogRequest>());
}