| // 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 "ios/testing/embedded_test_server_handlers.h" |
| #import "ios/web/public/js_messaging/web_frame.h" |
| #import "ios/web/public/js_messaging/web_frames_manager.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/web_state.h" |
| #include "ios/web/public/web_state_observer.h" |
| #include "net/test/embedded_test_server/embedded_test_server.h" |
| #include "net/test/embedded_test_server/request_handler_util.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 { |
| |
| // 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 { |
| protected: |
| void SetUp() override { |
| WebTestWithWebState::SetUp(); |
| test_server_.RegisterRequestHandler(base::BindRepeating( |
| &net::test_server::HandlePrefixedRequest, "/echo-query", |
| base::BindRepeating(&testing::HandlePageWithContents))); |
| ASSERT_TRUE(test_server_.Start()); |
| } |
| |
| net::EmbeddedTestServer test_server_; |
| }; |
| |
| // Web frame events should be registered on HTTP navigation. |
| TEST_F(WebFrameWebStateObserverInttest, SingleWebFrameHTTP) { |
| testing::StrictMock<WebStateObserverMock> observer; |
| web_state()->AddObserver(&observer); |
| EXPECT_CALL(observer, WebFrameDidBecomeAvailable(web_state(), testing::_)) |
| .WillOnce(VerifyMainWebFrame(web_state())); |
| |
| test::LoadUrl(web_state(), test_server_.GetURL("/echo-query?test")); |
| ASSERT_TRUE(test::WaitForWebViewContainingText(web_state(), "test")); |
| |
| EXPECT_CALL(observer, WebFrameDidBecomeAvailable(web_state(), testing::_)) |
| .WillOnce(VerifyMainWebFrame(web_state())); |
| EXPECT_CALL(observer, WebFrameWillBecomeUnavailable(web_state(), testing::_)) |
| .WillOnce(VerifyMainWebFrame(web_state())); |
| |
| test::LoadUrl(web_state(), test_server_.GetURL("/echo-query?secondPage")); |
| ASSERT_TRUE(test::WaitForWebViewContainingText(web_state(), "secondPage")); |
| |
| web_state()->RemoveObserver(&observer); |
| } |
| |
| // Web frame events should be registered on HTTPS navigation. |
| TEST_F(WebFrameWebStateObserverInttest, SingleWebFrameHTTPS) { |
| testing::StrictMock<WebStateObserverMock> observer; |
| web_state()->AddObserver(&observer); |
| |
| EXPECT_CALL(observer, WebFrameDidBecomeAvailable(web_state(), testing::_)) |
| .WillOnce(VerifyMainWebFrame(web_state())); |
| |
| // Load a first page to avoid having an item inserted during the |LoadHtml|. |
| test::LoadUrl(web_state(), test_server_.GetURL("/echo-query?test")); |
| ASSERT_TRUE(test::WaitForWebViewContainingText(web_state(), "test")); |
| |
| 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://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_F(WebFrameWebStateObserverInttest, TwoWebFrameHTTPS) { |
| testing::StrictMock<WebStateObserverMock> observer; |
| web_state()->AddObserver(&observer); |
| |
| EXPECT_CALL(observer, WebFrameDidBecomeAvailable(web_state(), testing::_)) |
| .WillOnce(VerifyMainWebFrame(web_state())); |
| |
| // Load a first page to avoid having an item inserted during the |LoadHtml|. |
| test::LoadUrl(web_state(), test_server_.GetURL("/echo-query?test")); |
| ASSERT_TRUE(test::WaitForWebViewContainingText(web_state(), "test")); |
| |
| // 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())); |
| EXPECT_CALL(observer, WebFrameWillBecomeUnavailable(web_state(), testing::_)) |
| .WillOnce(VerifyMainWebFrame(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); |
| } |
| |
| } // namespace web |