| // Copyright 2018 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #import "ios/web/public/test/web_test_with_web_state.h" |
| |
| #include "base/ios/ios_util.h" |
| #include "base/test/scoped_feature_list.h" |
| #include "ios/web/common/features.h" |
| #import "ios/web/public/js_messaging/web_frame.h" |
| #import "ios/web/public/js_messaging/web_frames_manager.h" |
| #import "ios/web/public/web_state/web_state.h" |
| #import "ios/web/public/web_state/web_state_observer.h" |
| #include "testing/gmock/include/gmock/gmock.h" |
| |
| #if !defined(__has_feature) || !__has_feature(objc_arc) |
| #error "This file requires ARC support." |
| #endif |
| |
| using testing::Truly; |
| |
| namespace { |
| |
| // WebFrameWebStateObserverInttest is parameterized on this enum to test both |
| // LegacyNavigationManager and WKBasedNavigationManager. |
| enum class NavigationManagerChoice { |
| LEGACY, |
| WK_BASED, |
| }; |
| |
| // Mocks WebStateObserver navigation callbacks. |
| class WebStateObserverMock : public web::WebStateObserver { |
| public: |
| WebStateObserverMock() = default; |
| |
| MOCK_METHOD2(WebFrameDidBecomeAvailable, |
| void(web::WebState*, web::WebFrame*)); |
| MOCK_METHOD2(WebFrameWillBecomeUnavailable, |
| void(web::WebState*, web::WebFrame*)); |
| void WebStateDestroyed(web::WebState* web_state) override { NOTREACHED(); } |
| |
| private: |
| DISALLOW_COPY_AND_ASSIGN(WebStateObserverMock); |
| }; |
| |
| // A predicate that returns true if |frame| is a main frame. |
| bool IsMainFrame(web::WebFrame* frame) { |
| return frame->IsMainFrame(); |
| } |
| |
| // Verifies that the web frame passed to the observer is the main frame. |
| ACTION_P(VerifyMainWebFrame, web_state) { |
| EXPECT_EQ(web_state, arg0); |
| EXPECT_EQ(web_state->GetWebFramesManager()->GetMainWebFrame(), arg1); |
| } |
| |
| // Verifies that the web frame passed to the observer is a child frame. |
| ACTION_P(VerifyChildWebFrame, web_state) { |
| EXPECT_EQ(web_state, arg0); |
| |
| web::WebFramesManager* manager = web_state->GetWebFramesManager(); |
| auto frames = manager->GetAllWebFrames(); |
| EXPECT_TRUE(frames.end() != std::find(frames.begin(), frames.end(), arg1)); |
| EXPECT_NE(manager->GetMainWebFrame(), arg1); |
| } |
| } |
| |
| namespace web { |
| |
| class WebFrameWebStateObserverInttest |
| : public WebTestWithWebState, |
| public ::testing::WithParamInterface<NavigationManagerChoice> { |
| protected: |
| void SetUp() override { |
| if (GetParam() == NavigationManagerChoice::LEGACY) { |
| scoped_feature_list_.InitAndDisableFeature( |
| web::features::kSlimNavigationManager); |
| } else { |
| scoped_feature_list_.InitAndEnableFeature( |
| web::features::kSlimNavigationManager); |
| } |
| |
| WebTestWithWebState::SetUp(); |
| } |
| |
| private: |
| base::test::ScopedFeatureList scoped_feature_list_; |
| }; |
| |
| // Web frame events should be registered on HTTP navigation. |
| TEST_P(WebFrameWebStateObserverInttest, SingleWebFrameHTTP) { |
| testing::StrictMock<WebStateObserverMock> observer; |
| web_state()->AddObserver(&observer); |
| EXPECT_CALL(observer, WebFrameDidBecomeAvailable(web_state(), testing::_)) |
| .WillOnce(VerifyMainWebFrame(web_state())); |
| LoadHtml(@"<p></p>", GURL("http://testurl1")); |
| EXPECT_CALL(observer, WebFrameDidBecomeAvailable(web_state(), testing::_)) |
| .WillOnce(VerifyMainWebFrame(web_state())); |
| EXPECT_CALL(observer, WebFrameWillBecomeUnavailable(web_state(), testing::_)) |
| .WillOnce(VerifyMainWebFrame(web_state())); |
| LoadHtml(@"<p></p>", GURL("http://testurl2")); |
| web_state()->RemoveObserver(&observer); |
| } |
| |
| // Web frame events should be registered on HTTPS navigation. |
| TEST_P(WebFrameWebStateObserverInttest, SingleWebFrameHTTPS) { |
| testing::StrictMock<WebStateObserverMock> observer; |
| web_state()->AddObserver(&observer); |
| EXPECT_CALL(observer, WebFrameDidBecomeAvailable(web_state(), testing::_)) |
| .WillOnce(VerifyMainWebFrame(web_state())); |
| LoadHtml(@"<p></p>", GURL("https://testurl1")); |
| EXPECT_CALL(observer, WebFrameDidBecomeAvailable(web_state(), testing::_)) |
| .WillOnce(VerifyMainWebFrame(web_state())); |
| EXPECT_CALL(observer, WebFrameWillBecomeUnavailable(web_state(), testing::_)) |
| .WillOnce(VerifyMainWebFrame(web_state())); |
| LoadHtml(@"<p></p>", GURL("https://testurl2")); |
| web_state()->RemoveObserver(&observer); |
| } |
| |
| // Web frame event should be registered on HTTPS navigation with iframe. |
| TEST_P(WebFrameWebStateObserverInttest, TwoWebFrameHTTPS) { |
| testing::StrictMock<WebStateObserverMock> observer; |
| web_state()->AddObserver(&observer); |
| |
| // The order in which the main and child frames become available is not |
| // guaranteed due to the async nature of messaging. The following expectations |
| // use separate matchers to identify main and child frames so that they can |
| // be matched in any order. |
| EXPECT_CALL(observer, |
| WebFrameDidBecomeAvailable(web_state(), Truly(IsMainFrame))) |
| .WillOnce(VerifyMainWebFrame(web_state())); |
| EXPECT_CALL(observer, |
| WebFrameDidBecomeAvailable(web_state(), Not(Truly(IsMainFrame)))) |
| .WillOnce(VerifyChildWebFrame(web_state())); |
| LoadHtml(@"<p><iframe/></p>", GURL("https://testurl1")); |
| |
| EXPECT_CALL(observer, |
| WebFrameDidBecomeAvailable(web_state(), Truly(IsMainFrame))) |
| .WillOnce(VerifyMainWebFrame(web_state())); |
| EXPECT_CALL(observer, |
| WebFrameDidBecomeAvailable(web_state(), Not(Truly(IsMainFrame)))) |
| .WillOnce(VerifyChildWebFrame(web_state())); |
| EXPECT_CALL(observer, |
| WebFrameWillBecomeUnavailable(web_state(), Truly(IsMainFrame))) |
| .WillOnce(VerifyMainWebFrame(web_state())); |
| EXPECT_CALL(observer, WebFrameWillBecomeUnavailable(web_state(), |
| Not(Truly(IsMainFrame)))) |
| .WillOnce(VerifyChildWebFrame(web_state())); |
| LoadHtml(@"<p><iframe/></p>", GURL("https://testurl2")); |
| |
| web_state()->RemoveObserver(&observer); |
| } |
| |
| INSTANTIATE_TEST_SUITE_P(ProgrammaticWebFrameWebStateObserverInttest, |
| WebFrameWebStateObserverInttest, |
| ::testing::Values(NavigationManagerChoice::LEGACY, |
| NavigationManagerChoice::WK_BASED)); |
| |
| } // namespace web |