Index: content/browser/frame_host/render_frame_host_impl_browsertest.cc |
diff --git a/content/browser/frame_host/render_frame_host_impl_browsertest.cc b/content/browser/frame_host/render_frame_host_impl_browsertest.cc |
index f975aa9981412c1962460d20e0290ca201c6878f..0200d46af4aadc3a7acde981a7c7b4ae20df07b7 100644 |
--- a/content/browser/frame_host/render_frame_host_impl_browsertest.cc |
+++ b/content/browser/frame_host/render_frame_host_impl_browsertest.cc |
@@ -247,7 +247,10 @@ IN_PROC_BROWSER_TEST_F(RenderFrameHostImplBrowserTest, |
"document.body.appendChild(iframe);" |
"iframe.contentWindow.onbeforeunload=function(e){return 'x'};"; |
EXPECT_TRUE(content::ExecuteScript(wc, script)); |
- EXPECT_TRUE(WaitForLoadStop(shell()->web_contents())); |
+ EXPECT_TRUE(WaitForLoadStop(wc)); |
+ // JavaScript onbeforeunload dialogs require a user gesture. |
+ for (auto* frame : wc->GetAllFrames()) |
+ frame->ExecuteJavaScriptWithUserGestureForTests(base::string16()); |
// Force a process switch by going to a privileged page. The beforeunload |
// timer will be started on the top-level frame but will be paused while the |
@@ -280,4 +283,43 @@ IN_PROC_BROWSER_TEST_F(RenderFrameHostImplBrowserTest, |
wc->SetJavaScriptDialogManagerForTesting(nullptr); |
} |
+// Tests that a gesture is required in a frame before it can request a |
+// beforeunload dialog. |
+IN_PROC_BROWSER_TEST_F(RenderFrameHostImplBrowserTest, |
+ BeforeUnloadDialogRequiresGesture) { |
+ WebContentsImpl* wc = static_cast<WebContentsImpl*>(shell()->web_contents()); |
+ TestJavaScriptDialogManager dialog_manager; |
+ wc->SetDelegate(&dialog_manager); |
+ |
+ EXPECT_TRUE(NavigateToURL( |
+ shell(), GetTestUrl("render_frame_host", "beforeunload.html"))); |
+ // Disable the hang monitor, otherwise there will be a race between the |
+ // beforeunload dialog and the beforeunload hang timer. |
+ wc->GetMainFrame()->DisableBeforeUnloadHangMonitorForTesting(); |
+ |
+ // Reload. There should be no beforeunload dialog because there was no gesture |
+ // on the page. If there was, this WaitForLoadStop call will hang. |
+ wc->GetController().Reload(ReloadType::NORMAL, false); |
+ EXPECT_TRUE(WaitForLoadStop(wc)); |
+ |
+ // Give the page a user gesture and try reloading again. This time there |
+ // should be a dialog. If there is no dialog, the call to Wait will hang. |
+ wc->GetMainFrame()->ExecuteJavaScriptWithUserGestureForTests( |
+ base::string16()); |
+ wc->GetController().Reload(ReloadType::NORMAL, false); |
+ dialog_manager.Wait(); |
+ |
+ // Answer the dialog. |
+ dialog_manager.callback().Run(true, base::string16()); |
+ EXPECT_TRUE(WaitForLoadStop(wc)); |
+ |
+ // The reload should have cleared the user gesture bit, so upon leaving again |
+ // there should be no beforeunload dialog. |
+ shell()->LoadURL(GURL("about:blank")); |
+ EXPECT_TRUE(WaitForLoadStop(wc)); |
+ |
+ wc->SetDelegate(nullptr); |
+ wc->SetJavaScriptDialogManagerForTesting(nullptr); |
+} |
+ |
} // namespace content |