blob: 5f70f20dab7317cb687ec17f4ac11a0f53196fa3 [file] [log] [blame]
// 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