| // Copyright 2020 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 "build/build_config.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| #include "third_party/blink/renderer/core/frame/frame_test_helpers.h" |
| #include "third_party/blink/renderer/core/frame/local_frame.h" |
| #include "third_party/blink/renderer/core/frame/web_frame_widget_base.h" |
| #include "third_party/blink/renderer/core/html/html_anchor_element.h" |
| #include "third_party/blink/renderer/core/page/chrome_client_impl.h" |
| #include "third_party/blink/renderer/core/testing/sim/sim_request.h" |
| #include "third_party/blink/renderer/core/testing/sim/sim_test.h" |
| #include "third_party/blink/renderer/platform/testing/unit_test_helpers.h" |
| #include "third_party/blink/renderer/platform/testing/url_test_helpers.h" |
| |
| namespace blink { |
| |
| class FrameLoaderSimTest : public SimTest { |
| public: |
| FrameLoaderSimTest() = default; |
| |
| void SetUp() override { |
| SimTest::SetUp(); |
| WebView().MainFrameWidgetBase()->UpdateAllLifecyclePhases( |
| DocumentUpdateReason::kTest); |
| } |
| }; |
| |
| // Ensure that the load event progress is progressed through BeforeUnload only |
| // if the event is uncanceled. |
| TEST_F(FrameLoaderSimTest, LoadEventProgressBeforeUnloadCanceled) { |
| SimRequest request("https://example.com/test.html", "text/html"); |
| SimRequest request_a("https://example.com/subframe-a.html", "text/html"); |
| SimRequest request_b("https://example.com/subframe-b.html", "text/html"); |
| SimRequest request_c("https://example.com/subframe-c.html", "text/html"); |
| SimRequest request_unload("https://example.com/next-page.html", "text/html"); |
| LoadURL("https://example.com/test.html"); |
| request.Complete(R"HTML( |
| <!DOCTYPE html> |
| <iframe src="subframe-a.html"></iframe> |
| )HTML"); |
| |
| request_a.Complete(R"HTML( |
| <!DOCTYPE html> |
| <iframe src="subframe-b.html"></iframe> |
| <a id="link" href="next-page.html">Next Page</a> |
| )HTML"); |
| request_b.Complete(R"HTML( |
| <!DOCTYPE html> |
| <script> |
| window.onbeforeunload = (e) => { |
| e.returnValue = ''; |
| e.preventDefault(); |
| }; |
| </script> |
| <iframe src="subframe-c.html"></iframe> |
| )HTML"); |
| request_c.Complete(R"HTML( |
| <!DOCTYPE html> |
| )HTML"); |
| Compositor().BeginFrame(); |
| |
| auto* main_frame = To<LocalFrame>(GetDocument().GetPage()->MainFrame()); |
| auto* frame_a = To<LocalFrame>(main_frame->Tree().FirstChild()); |
| auto* frame_b = To<LocalFrame>(frame_a->Tree().FirstChild()); |
| auto* frame_c = To<LocalFrame>(frame_b->Tree().FirstChild()); |
| |
| ASSERT_FALSE(main_frame->GetDocument()->BeforeUnloadStarted()); |
| ASSERT_FALSE(frame_a->GetDocument()->BeforeUnloadStarted()); |
| ASSERT_FALSE(frame_b->GetDocument()->BeforeUnloadStarted()); |
| ASSERT_FALSE(frame_c->GetDocument()->BeforeUnloadStarted()); |
| |
| // We'll only allow canceling a beforeunload if there's a sticky user |
| // activation present so simulate a user gesture. |
| frame_b->NotifyUserActivationInLocalTree( |
| mojom::UserActivationNotificationType::kTest); |
| |
| auto& chrome_client = |
| To<ChromeClientImpl>(WebView().GetPage()->GetChromeClient()); |
| |
| // Simulate the user canceling the navigation away. Since the navigation was |
| // "canceled", we expect that each of the frames should remain in their state |
| // before the beforeunload was dispatched. |
| { |
| chrome_client.SetBeforeUnloadConfirmPanelResultForTesting(false); |
| |
| // Note: We can't perform a navigation to check this because the |
| // beforeunload event is dispatched from content's RenderFrameImpl, Blink |
| // tests mock this out using a WebFrameTestProxy which doesn't check |
| // beforeunload before navigating. |
| ASSERT_FALSE(frame_a->Loader().ShouldClose()); |
| |
| EXPECT_FALSE(main_frame->GetDocument()->BeforeUnloadStarted()); |
| EXPECT_FALSE(frame_a->GetDocument()->BeforeUnloadStarted()); |
| EXPECT_FALSE(frame_b->GetDocument()->BeforeUnloadStarted()); |
| EXPECT_FALSE(frame_c->GetDocument()->BeforeUnloadStarted()); |
| } |
| |
| // Now test the opposite, the user allowing the navigation away. |
| { |
| chrome_client.SetBeforeUnloadConfirmPanelResultForTesting(true); |
| ASSERT_TRUE(frame_a->Loader().ShouldClose()); |
| |
| // The navigation was in frame a so it shouldn't affect the parent. |
| EXPECT_FALSE(main_frame->GetDocument()->BeforeUnloadStarted()); |
| EXPECT_TRUE(frame_a->GetDocument()->BeforeUnloadStarted()); |
| EXPECT_TRUE(frame_b->GetDocument()->BeforeUnloadStarted()); |
| EXPECT_TRUE(frame_c->GetDocument()->BeforeUnloadStarted()); |
| } |
| } |
| |
| } // namespace blink |