blob: 2f7e4866e1263299db2e2aec926965076997b081 [file] [log] [blame]
// Copyright 2022 The Chromium Authors
// 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 "chrome/browser/printing/print_preview_dialog_controller.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/test/base/in_process_browser_test.h"
#include "chrome/test/base/interactive_test_utils.h"
#include "chrome/test/base/ui_test_utils.h"
#include "components/permissions/permission_request_manager.h"
#include "content/public/browser/web_contents.h"
#include "content/public/browser/web_contents_observer.h"
#include "content/public/test/browser_test.h"
#include "content/public/test/browser_test_utils.h"
#include "net/test/embedded_test_server/embedded_test_server.h"
#include "ui/display/screen_base.h"
#include "ui/display/test/test_screen.h"
#if BUILDFLAG(IS_CHROMEOS)
#include "ash/shell.h"
#include "ui/display/test/display_manager_test_api.h" // nogncheck
#endif // BUILDFLAG(IS_CHROMEOS)
class WindowManagementTest : public InProcessBrowserTest {
public:
void SetUp() override {
#if !BUILDFLAG(IS_CHROMEOS)
display::Screen::SetScreenInstance(&screen_);
screen_.display_list().AddDisplay({1, gfx::Rect(0, 0, 803, 600)},
display::DisplayList::Type::PRIMARY);
#endif
InProcessBrowserTest::SetUp();
}
void SetUpOnMainThread() override {
// Window management features are only available on secure contexts.
https_test_server_ = std::make_unique<net::EmbeddedTestServer>(
net::EmbeddedTestServer::TYPE_HTTPS);
https_test_server_->ServeFilesFromSourceDirectory(GetChromeTestDataDir());
ASSERT_TRUE(https_test_server_->Start());
}
void TearDown() override {
InProcessBrowserTest::TearDown();
#if !BUILDFLAG(IS_CHROMEOS)
display::Screen::SetScreenInstance(nullptr);
#endif
}
protected:
std::unique_ptr<net::EmbeddedTestServer> https_test_server_;
#if !BUILDFLAG(IS_CHROMEOS)
display::ScreenBase screen_;
#endif
};
// TODO(crbug.com/40115071): Windows crashes static casting to ScreenWin.
// TODO(crbug.com/433855037): Disabling on Mac due to flakiness.
#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC)
#define MAYBE_NoCrashOnEventsDuringHandlerPrint \
DISABLED_NoCrashOnEventsDuringHandlerPrint
#else
#define MAYBE_NoCrashOnEventsDuringHandlerPrint \
NoCrashOnEventsDuringHandlerPrint
#endif
// Test that screen change events occurring while an event handler is running
// a nested event loop (i.e. via window.print()) do not cause a crash.
// Regression test for crbug.com/1273841
IN_PROC_BROWSER_TEST_F(WindowManagementTest,
MAYBE_NoCrashOnEventsDuringHandlerPrint) {
// Update the display configuration to mock display changes.
#if BUILDFLAG(IS_CHROMEOS)
display::test::DisplayManagerTestApi(ash::Shell::Get()->display_manager())
.UpdateDisplay("0+0-803x600");
#endif // BUILDFLAG(IS_CHROMEOS)
ASSERT_EQ(1, display::Screen::Get()->GetNumDisplays());
// Navigate in a new tab to observe the test screen instance as needed.
const GURL url(https_test_server_->GetURL("/simple.html"));
ui_test_utils::NavigateToURLWithDisposition(
browser(), url, WindowOpenDisposition::NEW_FOREGROUND_TAB,
ui_test_utils::BROWSER_TEST_WAIT_FOR_TAB |
ui_test_utils::BROWSER_TEST_WAIT_FOR_LOAD_STOP);
// Auto-accept the Window Placement permission request.
auto* tab = browser()->tab_strip_model()->GetActiveWebContents();
permissions::PermissionRequestManager* permission_request_manager_tab =
permissions::PermissionRequestManager::FromWebContents(tab);
permission_request_manager_tab->set_auto_response_for_test(
permissions::PermissionRequestManager::ACCEPT_ALL);
// Add a currentscreenchange event handler that will freeze JS via print().
auto* script = R"(
function freezeJS(e) {
self.print();
screenDetails.removeEventListener('currentscreenchange', freezeJS);
}
let screenDetails;
self.getScreenDetails().then(s => {
screenDetails = s;
screenDetails.addEventListener('currentscreenchange', freezeJS);
});
)";
content::WebContentsAddedObserver web_contents_added_observer;
ASSERT_TRUE(EvalJs(tab, script).is_ok());
// Alter the display to trigger the currentscreenchange event and print().
#if BUILDFLAG(IS_CHROMEOS)
display::test::DisplayManagerTestApi(ash::Shell::Get()->display_manager())
.UpdateDisplay("0+0-807x600");
#else
screen_.display_list().UpdateDisplay({1, gfx::Rect(0, 0, 807, 600)},
display::DisplayList::Type::PRIMARY);
EXPECT_EQ(screen_.display_list().displays().size(), 1u);
#endif // BUILDFLAG(IS_CHROMEOS)
ASSERT_EQ(1, display::Screen::Get()->GetNumDisplays());
content::WebContents* print_preview =
web_contents_added_observer.GetWebContents();
EXPECT_EQ(print_preview, printing::PrintPreviewDialogController::GetInstance()
->GetPrintPreviewForContents(tab));
content::AwaitDocumentOnLoadCompleted(print_preview);
// Add a second display while the print preview dialog is showing.
#if BUILDFLAG(IS_CHROMEOS)
display::test::DisplayManagerTestApi(ash::Shell::Get()->display_manager())
.UpdateDisplay("0+0-807x600,1000+0-804x600");
#else
screen_.display_list().AddDisplay({2, gfx::Rect(1000, 0, 804, 600)},
display::DisplayList::Type::NOT_PRIMARY);
EXPECT_EQ(screen_.display_list().displays().size(), 2u);
#endif // BUILDFLAG(IS_CHROMEOS)
ASSERT_EQ(2, display::Screen::Get()->GetNumDisplays());
// Cancel print to unfreeze the tab's JS and check that no crash occurred.
content::WebContentsDestroyedWatcher destroyed_watcher(print_preview);
// Note: This could be a browser_test if cancelling the print preview dialog
// was more broadly possible without simulating a key press.
// PrintViewManager::PrintPreviewDone() worked on Linux, but not Chrome OS.
EXPECT_TRUE(ui_test_utils::SendKeyPressSync(browser(), ui::VKEY_ESCAPE, false,
false, false, false));
destroyed_watcher.Wait();
ASSERT_FALSE(tab->IsCrashed());
EXPECT_EQ(true, EvalJs(tab, "true"));
}