// Copyright 2016 The Chromium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include <memory> #include "base/command_line.h" #include "base/containers/contains.h" #include "base/memory/raw_ptr.h" #include "base/run_loop.h" #include "base/strings/string_number_conversions.h" #include "base/strings/stringprintf.h" #include "base/task/single_thread_task_runner.h" #include "base/test/run_until.h" #include "base/test/scoped_feature_list.h" #include "base/test/test_timeouts.h" #include "build/build_config.h" #include "build/chromeos_buildflags.h" #include "chrome/browser/password_manager/chrome_password_manager_client.h" #include "chrome/browser/renderer_context_menu/render_view_context_menu_browsertest_util.h" #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/browser_window.h" #include "chrome/browser/ui/exclusive_access/exclusive_access_manager.h" #include "chrome/browser/ui/tabs/tab_strip_model.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/security_state/core/security_state.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/focused_node_details.h" #include "content/public/browser/navigation_handle.h" #include "content/public/browser/render_frame_host.h" #include "content/public/browser/render_widget_host.h" #include "content/public/browser/render_widget_host_iterator.h" #include "content/public/browser/render_widget_host_view.h" #include "content/public/browser/web_contents.h" #include "content/public/test/browser_test.h" #include "content/public/test/browser_test_utils.h" #include "content/public/test/content_browser_test_utils.h" #include "content/public/test/fenced_frame_test_util.h" #include "content/public/test/hit_test_region_observer.h" #include "content/public/test/test_navigation_observer.h" #include "content/public/test/test_utils.h" #include "extensions/browser/api/extensions_api_client.h" #include "extensions/common/constants.h" #include "net/dns/mock_host_resolver.h" #include "net/test/embedded_test_server/default_handlers.h" #include "net/test/embedded_test_server/embedded_test_server.h" #include "pdf/buildflags.h" #include "ui/base/test/ui_controls.h" #include "ui/display/display.h" #include "ui/display/screen.h" #include "ui/gfx/geometry/point.h" #include "ui/gfx/geometry/rect.h" #include "ui/gfx/geometry/vector2d.h" #include "url/gurl.h" #if BUILDFLAG(ENABLE_PDF) #include "base/test/with_feature_override.h" #include "chrome/browser/pdf/test_pdf_viewer_stream_manager.h" #include "components/guest_view/browser/guest_view_base.h" #include "components/guest_view/browser/guest_view_manager_delegate.h" #include "components/guest_view/browser/test_guest_view_manager.h" #include "extensions/browser/guest_view/mime_handler_view/test_mime_handler_view_guest.h" #include "pdf/pdf_features.h" #include "third_party/abseil-cpp/absl/types/variant.h" #endif // BUILDFLAG(ENABLE_PDF) namespace { // Counts and returns the number of RenderWidgetHosts in the browser process. size_t GetNumberOfRenderWidgetHosts() { … } // Waits and polls the current number of RenderWidgetHosts and stops when the // number reaches |target_count|. void WaitForRenderWidgetHostCount(size_t target_count) { … } } // namespace class SitePerProcessInteractiveBrowserTest : public InProcessBrowserTest { … }; class SitePerProcessInteractiveFencedFrameBrowserTest : public SitePerProcessInteractiveBrowserTest, public testing::WithParamInterface<const char*> { … }; // Check that document.hasFocus() works properly with out-of-process iframes. // The test builds a page with four cross-site frames and then focuses them one // by one, checking the value of document.hasFocus() in all frames. For any // given focused frame, document.hasFocus() should return true for that frame // and all its ancestor frames. IN_PROC_BROWSER_TEST_F(SitePerProcessInteractiveBrowserTest, DocumentHasFocus) { … } // Ensure that a cross-process subframe can receive keyboard events when in // focus. IN_PROC_BROWSER_TEST_F(SitePerProcessInteractiveBrowserTest, SubframeKeyboardEventRouting) { … } // Ensure that sequential focus navigation (advancing focused elements with // <tab> and <shift-tab>) works across cross-process subframes. This has 2 test // cases that check sequential focus navigation for both <iframe> and // <fencedframe> elements. // The test sets up six inputs fields in a page with two cross-process // subframes: // child1 child2 // /------------\ /------------\. // | 2. <input> | | 4. <input> | // 1. <input> | 3. <input> | | 5. <input> | 6. <input> // \------------/ \------------/. // // The test then presses <tab> six times to cycle through focused elements 1-6. // The test then repeats this with <shift-tab> to cycle in reverse order. IN_PROC_BROWSER_TEST_P(SitePerProcessInteractiveFencedFrameBrowserTest, SequentialFocusNavigation) { … } // Similar to the test above, but check that sequential focus navigation works // with <object> tags that contain OOPIFs. // // The test sets up four inputs fields in a page with a <object> that contains // an OOPIF: // <object> // /------------\. // | 2. <input> | // 1. <input> | 3. <input> | 4. <input> // \------------/. // // The test then presses <tab> 4 times to cycle through focused elements 1-4. // The test then repeats this with <shift-tab> to cycle in reverse order. IN_PROC_BROWSER_TEST_F(SitePerProcessInteractiveBrowserTest, SequentialFocusNavigationWithObject) { … } // Ensure that frames get focus when wrapping focus using <tab> or <shift-tab>. // This has 2 test cases that check sequential focus navigation for both // <iframe> and <fencedframe> elements. // The test sets up two input fields in a page with one cross-process subframe: // child // /------------\. // 1. <input> | 2. <input> | // \------------/. // // The test then presses <tab> to focus on elements 1, then <shift-tab> twice to // focus on the omnibox followed by element 2. This tests that focus works as // expected when wrapping through non-page UI elements. Specifically, this tests // that fenced frames can properly get and verify focus if its RenderWidgetHost // loses focus. IN_PROC_BROWSER_TEST_P(SitePerProcessInteractiveFencedFrameBrowserTest, SequentialFocusNavigationWrapAround) { … } // Ensure that frames can pass focus to subsequent frames if there is nothing // focusable left in their frame. The test sets up two input fields in a page // with three cross-process subframes: // child1 child3 // /------------\. /------------\. // 1. <input> | child2 | | 2. <input> | // | /--------\ | \------------/. // | \--------/ | // \------------/. // // The test then presses <tab> twice to focus on elements 1 and 2. // TODO(crbug.com/40276413): Re-enable this test once this bug is fixed. IN_PROC_BROWSER_TEST_P(SitePerProcessInteractiveFencedFrameBrowserTest, SequentialFocusNavigationPassThrough) { … } // Ensure that frames can pass focus to subsequent frames if there is nothing // focusable left in their frame. The test sets up two input fields in the last // subframe loaded into a page: // child1 child3 // /------------\. /-------------\. // | child2 | | 1. <input1> | // | /--------\ | \ 2. <input2> / // | \--------/ | \-------------/. // \------------/. // // The test then presses <tab> twice to focus on elements 1 and 2, <tab> to // move focus to the UI, and <tab> one more time to focus on element 1 again. // TODO(crbug.com/40276413): Re-enable this test once this bug is fixed. IN_PROC_BROWSER_TEST_P(SitePerProcessInteractiveFencedFrameBrowserTest, SequentialFocusWrapBackIntoChildFrame) { … } // TODO(crbug.com/40118868): Revisit the macro expression once build flag switch // of lacros-chrome is complete. #if (BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)) || BUILDFLAG(IS_WIN) // Ensures that renderers know to advance focus to sibling frames and parent // frames in the presence of mouse click initiated focus changes. // Verifies against regression of https://crbug.com/702330 IN_PROC_BROWSER_TEST_F(SitePerProcessInteractiveBrowserTest, TabAndMouseFocusNavigation) { … } #endif namespace { // Helper to retrieve the frame's (window.innerWidth, window.innerHeight). gfx::Size GetFrameSize(content::RenderFrameHost* frame) { … } // Helper to check |frame|'s document.webkitFullscreenElement and return its ID // if it's defined (which is the case when |frame| is in fullscreen mode), or // "none" otherwise. std::string GetFullscreenElementId(content::RenderFrameHost* frame) { … } // Helper to check if an element with ID |element_id| has the // :-webkit-full-screen style. bool ElementHasFullscreenStyle(content::RenderFrameHost* frame, const std::string& element_id) { … } // Helper to check if an element with ID |element_id| has the // :-webkit-full-screen-ancestor style. bool ElementHasFullscreenAncestorStyle(content::RenderFrameHost* host, const std::string& element_id) { … } // Add a listener that will send back a message whenever the (prefixed) // fullscreenchange event fires. The message will be "fullscreenchange", // followed by a space and the provided |id|. void AddFullscreenChangeListener(content::RenderFrameHost* frame, const std::string& id) { … } // Helper to add a listener that will send back a "resize" message when the // target |frame| is resized to |expected_size|. void AddResizeListener(content::RenderFrameHost* frame, const gfx::Size& expected_size) { … } // Helper to wait for a toggle fullscreen operation to complete in all affected // frames. This means waiting for: // 1. All fullscreenchange events with id's matching the list in // |expected_fullscreen_event_ids|. Typically the list will correspond to // events from the actual fullscreen element and all of its ancestor // <iframe> elements. // 2. A resize event. This will verify that the frame containing the // fullscreen element is properly resized. This assumes that the expected // size is already registered via AddResizeListener(). void WaitForMultipleFullscreenEvents( const std::set<std::string>& expected_fullscreen_event_ids, content::DOMMessageQueue& queue) { … } } // namespace // Check that an element in a cross-process subframe can enter and exit // fullscreen. The test will verify that: // - the subframe is properly resized // - the WebContents properly enters/exits fullscreen. // - document.webkitFullscreenElement is correctly updated in both frames. // - fullscreenchange events fire in both frames. // - fullscreen CSS is applied correctly in both frames. // #if BUILDFLAG(IS_MAC) // https://crbug.com/850594 #define MAYBE_FullscreenElementInSubframe … #else #define MAYBE_FullscreenElementInSubframe … #endif IN_PROC_BROWSER_TEST_F(SitePerProcessInteractiveBrowserTest, MAYBE_FullscreenElementInSubframe) { … } // Check that on a page with A-embed-B-embed-A frame hierarchy, an element in // the bottom frame can enter and exit fullscreen. |exit_method| specifies // whether to use browser-initiated vs. renderer-initiated fullscreen exit // (i.e., pressing escape vs. a JS call), since they trigger different code // paths on the Blink side. void SitePerProcessInteractiveBrowserTest::FullscreenElementInABA( FullscreenExitMethod exit_method) { … } // https://crbug.com/1087392: Flaky for ASAN and TSAN #if BUILDFLAG(IS_MAC) || defined(ADDRESS_SANITIZER) || defined(THREAD_SANITIZER) #define MAYBE_FullscreenElementInABAAndExitViaEscapeKey … #else #define MAYBE_FullscreenElementInABAAndExitViaEscapeKey … #endif IN_PROC_BROWSER_TEST_F(SitePerProcessInteractiveBrowserTest, MAYBE_FullscreenElementInABAAndExitViaEscapeKey) { … } // This test is flaky on Linux (crbug.com/851236) and also not working // on Mac (crbug.com/850594). IN_PROC_BROWSER_TEST_F(SitePerProcessInteractiveBrowserTest, DISABLED_FullscreenElementInABAAndExitViaJS) { … } // Check that fullscreen works on a more complex page hierarchy with multiple // local and remote ancestors. The test uses this frame tree: // // A (a_top) // | // A (a_bottom) // / \ . // (b_first) B B (b_second) // | // C (c_top) // | // C (c_middle) <- fullscreen target // | // C (c_bottom) // // The c_middle frame will trigger fullscreen for its <div> element. The test // verifies that its ancestor chain is properly updated for fullscreen, and // that the b_first node that's not on the chain is not affected. // // The test also exits fullscreen by simulating pressing ESC rather than using // document.webkitExitFullscreen(), which tests the browser-initiated // fullscreen exit path. // TODO(crbug.com/40535621): flaky on all platforms. IN_PROC_BROWSER_TEST_F(SitePerProcessInteractiveBrowserTest, DISABLED_FullscreenElementInMultipleSubframes) { … } // Test that deleting a RenderWidgetHost that holds the mouse lock won't cause a // crash. https://crbug.com/619571. // Flaky on multiple builders. https://crbug.com/1059632 IN_PROC_BROWSER_TEST_F(SitePerProcessInteractiveBrowserTest, DISABLED_RenderWidgetHostDeletedWhileMouseLocked) { … } #if BUILDFLAG(ENABLE_PDF) // Base test class for interactive tests which load and test PDF files. class SitePerProcessInteractivePDFTest : public base::test::WithFeatureOverride, public SitePerProcessInteractiveBrowserTest { … }; // This test loads a PDF inside an OOPIF and then verifies that context menu // shows up at the correct position. // TODO(crbug.com/1423184, crbug.com/327338993): Fix flaky test. #if BUILDFLAG(IS_WIN) || (BUILDFLAG(IS_LINUX) && defined(ADDRESS_SANITIZER)) #define MAYBE_ContextMenuPositionForEmbeddedPDFInCrossOriginFrame … #else #define MAYBE_ContextMenuPositionForEmbeddedPDFInCrossOriginFrame … #endif // BUILDFLAG(IS_WIN) || (BUILDFLAG(IS_LINUX) && // defined(ADDRESS_SANITIZER)) IN_PROC_BROWSER_TEST_P( SitePerProcessInteractivePDFTest, MAYBE_ContextMenuPositionForEmbeddedPDFInCrossOriginFrame) { … } IN_PROC_BROWSER_TEST_P(SitePerProcessInteractivePDFTest, LoadingPdfDoesNotStealFocus) { … } // TODO(crbug.com/40268279): Stop testing both modes after OOPIF PDF viewer // launches. INSTANTIATE_FEATURE_OVERRIDE_TEST_SUITE(…); #endif // BUILDFLAG(ENABLE_PDF) class SitePerProcessAutofillTest : public SitePerProcessInteractiveBrowserTest { … }; // Waits until transforming |sample_point| from |render_frame_host| coordinates // to its root frame's view's coordinates matches |transformed_point| within a // reasonable error margin less than or equal to |bound|. This method is used to // verify CSS changes on OOPIFs have been applied properly and the corresponding // compositor frame is updated as well. This way we can rest assured that the // future transformed and reported bounds for the elements inside // |render_frame_host| are correct. void WaitForFramePositionUpdated(content::RenderFrameHost* render_frame_host, const gfx::Point& sample_point, const gfx::Point& transformed_point, float bound) { … } // This test verifies that when clicking outside the bounds of a date picker // associated with an <input> inside an OOPIF, the RenderWidgetHostImpl // corresponding to the WebPagePopup is destroyed (see // https://crbug.com/671732). IN_PROC_BROWSER_TEST_F(SitePerProcessInteractiveBrowserTest, ShowAndHideDatePopupInOOPIFMultipleTimes) { … } // There is a problem of missing keyup events with the command key after // the NSEvent is sent to NSApplication in ui/base/test/ui_controls_mac.mm . // This test is disabled on only the Mac until the problem is resolved. // See http://crbug.com/425859 for more information. #if BUILDFLAG(IS_MAC) #define MAYBE_SubframeAnchorOpenedInBackgroundTab … #else #define MAYBE_SubframeAnchorOpenedInBackgroundTab … #endif // Tests that ctrl-click in a subframe results in a background, not a foreground // tab - see https://crbug.com/804838. This test is somewhat similar to // CtrlClickShouldEndUpIn*ProcessTest tests, but this test has to simulate an // actual mouse click. IN_PROC_BROWSER_TEST_F(SitePerProcessInteractiveBrowserTest, MAYBE_SubframeAnchorOpenedInBackgroundTab) { … } // Check that window.focus works for cross-process popups. // Flaky on ChromeOS debug and ASAN builds. https://crbug.com/1326293 // Flaky on Linux https://crbug.com/1336109. // Flaky on Win https://crbug.com/1337725. #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_WIN) || \ (BUILDFLAG(IS_CHROMEOS) && \ (!defined(NDEBUG) || defined(ADDRESS_SANITIZER))) #define MAYBE_PopupWindowFocus … #else #define MAYBE_PopupWindowFocus … #endif IN_PROC_BROWSER_TEST_F(SitePerProcessInteractiveBrowserTest, MAYBE_PopupWindowFocus) { … } INSTANTIATE_TEST_SUITE_P(…);