chromium/chrome/browser/ui/views/menu_interactive_uitest.cc

// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ui/views/controls/menu/menu_controller.h"

#include <utility>

#include "base/memory/raw_ptr.h"
#include "base/run_loop.h"
#include "base/strings/utf_string_conversions.h"
#include "build/build_config.h"
#include "build/chromeos_buildflags.h"
#include "chrome/browser/ui/browser_commands.h"
#include "chrome/browser/ui/views/native_widget_factory.h"
#include "chrome/test/base/in_process_browser_test.h"
#include "chrome/test/base/interactive_test_utils.h"
#include "chrome/test/base/test_browser_window.h"
#include "content/public/test/browser_test.h"
#include "content/public/test/scoped_accessibility_mode_override.h"
#include "ui/accessibility/ax_node_data.h"
#include "ui/base/metadata/metadata_header_macros.h"
#include "ui/base/metadata/metadata_impl_macros.h"
#include "ui/base/test/ui_controls.h"
#include "ui/gfx/geometry/point.h"
#include "ui/views/accessibility/view_accessibility.h"
#include "ui/views/controls/button/button.h"
#include "ui/views/controls/menu/menu_item_view.h"
#include "ui/views/controls/menu/submenu_view.h"
#include "ui/views/focus/focus_manager.h"
#include "ui/views/test/ax_event_counter.h"
#include "ui/views/test/widget_activation_waiter.h"
#include "ui/views/test/widget_test.h"
#include "ui/views/widget/widget.h"

#if !BUILDFLAG(IS_CHROMEOS_ASH)
#include "ui/accessibility/platform/ax_platform_node.h"
#endif

#if BUILDFLAG(IS_WIN)
#include "base/win/windows_version.h"
#endif

namespace views {
namespace test {

namespace {

class TestButton : public Button {};

BEGIN_METADATA()

}  // namespace

class MenuControllerUITest : public InProcessBrowserTest {};

// TODO(crbug.com/40765889): Re-enable this test
IN_PROC_BROWSER_TEST_F(MenuControllerUITest, DISABLED_TestMouseOverShownMenu) {}

// This test creates a menu without a parent widget, and tests that it
// can receive keyboard events.
// TODO(davidbienvenu): If possible, get test working for linux and
// mac. Only status_icon_win runs a menu with a null parent widget
// currently.
#if BUILDFLAG(IS_WIN)
IN_PROC_BROWSER_TEST_F(MenuControllerUITest, FocusOnOrphanMenu) {
  // This test is extremely flaky on WIN10_20H2, so disable.
  // TODO(crbug.com/40188371) Investigate why it's so flaky on that version of
  // Windows.
  if (base::win::OSInfo::GetInstance()->version() >=
      base::win::Version::WIN10_20H2) {
    GTEST_SKIP() << "Skipping test for WIN10_20H2 and greater";
  }
  // Going into full screen mode prevents pre-test focus and mouse position
  // state from affecting test, and helps ui_controls function correctly.
  chrome::ToggleFullscreenMode(browser());
  content::ScopedAccessibilityModeOverride ax_mode_override(
      ui::kAXModeComplete);
  MenuDelegate menu_delegate;
  auto menu_item_owning = std::make_unique<MenuItemView>(&menu_delegate);
  MenuItemView* menu_item = menu_item_owning.get();
  AXEventCounter ax_counter(views::AXEventManager::Get());
  EXPECT_EQ(ax_counter.GetCount(ax::mojom::Event::kMenuStart), 0);
  EXPECT_EQ(ax_counter.GetCount(ax::mojom::Event::kMenuPopupStart), 0);
  EXPECT_EQ(ax_counter.GetCount(ax::mojom::Event::kMenuPopupEnd), 0);
  EXPECT_EQ(ax_counter.GetCount(ax::mojom::Event::kMenuEnd), 0);
  std::unique_ptr<MenuRunner> menu_runner(std::make_unique<MenuRunner>(
      std::move(menu_item_owning), views::MenuRunner::CONTEXT_MENU));
  MenuItemView* first_item = menu_item->AppendMenuItem(1, u"One");
  menu_item->AppendMenuItem(2, u"Two");
  menu_runner->RunMenuAt(nullptr, nullptr, gfx::Rect(),
                         views::MenuAnchorPosition::kTopLeft,
                         ui::MENU_SOURCE_NONE);
  EXPECT_EQ(ax_counter.GetCount(ax::mojom::Event::kMenuStart), 1);
  EXPECT_EQ(ax_counter.GetCount(ax::mojom::Event::kMenuPopupStart), 1);
  EXPECT_EQ(ax_counter.GetCount(ax::mojom::Event::kMenuPopupEnd), 0);
  EXPECT_EQ(ax_counter.GetCount(ax::mojom::Event::kMenuEnd), 0);
  base::RunLoop loop;
  // SendKeyPress fails if the window doesn't have focus.
  ASSERT_TRUE(ui_controls::SendKeyPressNotifyWhenDone(
      menu_item->GetSubmenu()->GetWidget()->GetNativeWindow(), ui::VKEY_DOWN,
      false, false, false, false, loop.QuitClosure()));
  loop.Run();
  EXPECT_TRUE(first_item->IsSelected());
  EXPECT_TRUE(first_item->GetViewAccessibility().IsFocusedForTesting());
  menu_runner->Cancel();
  EXPECT_FALSE(first_item->GetViewAccessibility().IsFocusedForTesting());
  EXPECT_EQ(ax_counter.GetCount(ax::mojom::Event::kMenuStart), 1);
  EXPECT_EQ(ax_counter.GetCount(ax::mojom::Event::kMenuPopupStart), 1);
  EXPECT_EQ(ax_counter.GetCount(ax::mojom::Event::kMenuPopupEnd), 1);
  EXPECT_EQ(ax_counter.GetCount(ax::mojom::Event::kMenuEnd), 1);
}
#endif  // BUILDFLAG(IS_WIN)

}  // namespace test
}  // namespace views