diff --git a/samples/IntegrationTestApp/App.axaml.cs b/samples/IntegrationTestApp/App.axaml.cs index 022931366d..ed1eecb263 100644 --- a/samples/IntegrationTestApp/App.axaml.cs +++ b/samples/IntegrationTestApp/App.axaml.cs @@ -1,6 +1,7 @@ using Avalonia; using Avalonia.Controls.ApplicationLifetimes; using Avalonia.Markup.Xaml; +using MiniMvvm; namespace IntegrationTestApp { diff --git a/samples/IntegrationTestApp/IntegrationTestApp.csproj b/samples/IntegrationTestApp/IntegrationTestApp.csproj index 77bfa828a7..82a9d87b0a 100644 --- a/samples/IntegrationTestApp/IntegrationTestApp.csproj +++ b/samples/IntegrationTestApp/IntegrationTestApp.csproj @@ -27,6 +27,9 @@ + + + diff --git a/samples/IntegrationTestApp/MainWindow.axaml b/samples/IntegrationTestApp/MainWindow.axaml index 29a8a254e5..3f6d507866 100644 --- a/samples/IntegrationTestApp/MainWindow.axaml +++ b/samples/IntegrationTestApp/MainWindow.axaml @@ -2,13 +2,13 @@ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" - xmlns:integrationTestApp="using:IntegrationTestApp" + xmlns:vm="using:IntegrationTestApp.ViewModels" mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450" x:Class="IntegrationTestApp.MainWindow" Name="MainWindow" Icon="/Assets/icon.ico" Title="IntegrationTestApp" - x:DataType="integrationTestApp:MainWindow"> + x:DataType="vm:MainWindowViewModel"> @@ -19,7 +19,7 @@ - + @@ -28,185 +28,25 @@ WindowState: - + - - - - - TextBlockWithName - - TextBlockWithNameAndAutomationId - - Label for TextBox - - Foo - - - - - - - - - - - - - - - - - Sample RadioButton - - Three States: Option 1 - Three States: Option 2 - - - - - - - Unchecked - Checked - ThreeState - - - - - - - Item 0 - Item 1 - - Wrap Selection - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - None - - - - - - - - - - - - NonOwned - Owned - Modal - - - Manual - CenterScreen - CenterOwner - - - Normal - Minimized - Maximized - FullScreen - - - None - BorderOnly - Full - - ExtendClientAreaToDecorationsHint - Can Resize - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + diff --git a/samples/IntegrationTestApp/MainWindow.axaml.cs b/samples/IntegrationTestApp/MainWindow.axaml.cs index 986eb920a3..62ef970aa1 100644 --- a/samples/IntegrationTestApp/MainWindow.axaml.cs +++ b/samples/IntegrationTestApp/MainWindow.axaml.cs @@ -1,17 +1,8 @@ using System.Collections.Generic; -using System.Linq; -using Avalonia; -using Avalonia.Automation; using Avalonia.Controls; -using Avalonia.Controls.ApplicationLifetimes; -using Avalonia.Controls.Primitives; -using Avalonia.Controls.Primitives.PopupPositioning; -using Avalonia.Input; -using Avalonia.Interactivity; -using Avalonia.Markup.Xaml; -using Avalonia.Media; -using Avalonia.VisualTree; -using Microsoft.CodeAnalysis; +using IntegrationTestApp.Models; +using IntegrationTestApp.Pages; +using IntegrationTestApp.ViewModels; namespace IntegrationTestApp { @@ -20,270 +11,67 @@ namespace IntegrationTestApp public MainWindow() { InitializeComponent(); - InitializeViewMenu(); - InitializeGesturesTab(); - this.AttachDevTools(); - var overlayPopups = this.Get("AppOverlayPopups"); - overlayPopups.Text = Program.OverlayPopups ? "Overlay Popups" : "Native Popups"; + var viewModel = new MainWindowViewModel(CreatePages()); + InitializeViewMenu(viewModel.Pages); - AddHandler(Button.ClickEvent, OnButtonClick); - ListBoxItems = Enumerable.Range(0, 100).Select(x => "Item " + x).ToList(); - DataContext = this; + DataContext = viewModel; + AppOverlayPopups.Text = Program.OverlayPopups ? "Overlay Popups" : "Native Popups"; } - public List ListBoxItems { get; } + private MainWindowViewModel? ViewModel => (MainWindowViewModel?)DataContext; - private void InitializeComponent() - { - AvaloniaXamlLoader.Load(this); - } - - private void InitializeViewMenu() + private void InitializeViewMenu(IEnumerable pages) { var mainTabs = this.Get("MainTabs"); var viewMenu = (NativeMenuItem?)NativeMenu.GetMenu(this)?.Items[1]; - foreach (var tabItem in mainTabs.Items.Cast()) + foreach (var page in pages) { var menuItem = new NativeMenuItem { - Header = (string?)tabItem.Header, - ToolTip = $"Tip:{(string?)tabItem.Header}", - IsChecked = tabItem.IsSelected, + Header = (string?)page.Name, + ToolTip = $"Tip:{(string?)page.Name}", ToggleType = NativeMenuItemToggleType.Radio, }; - menuItem.Click += (_, _) => tabItem.IsSelected = true; - viewMenu?.Menu?.Items.Add(menuItem); - } - } - - private void ShowWindow() - { - var sizeTextBox = this.GetControl("ShowWindowSize"); - var modeComboBox = this.GetControl("ShowWindowMode"); - var locationComboBox = this.GetControl("ShowWindowLocation"); - var stateComboBox = this.GetControl("ShowWindowState"); - var size = !string.IsNullOrWhiteSpace(sizeTextBox.Text) ? Size.Parse(sizeTextBox.Text) : (Size?)null; - var systemDecorations = this.GetControl("ShowWindowSystemDecorations"); - var extendClientArea = this.GetControl("ShowWindowExtendClientAreaToDecorationsHint"); - var canResizeCheckBox = this.GetControl("ShowWindowCanResize"); - var owner = (Window)this.GetVisualRoot()!; - - var window = new ShowWindowTest - { - WindowStartupLocation = (WindowStartupLocation)locationComboBox.SelectedIndex, - CanResize = canResizeCheckBox.IsChecked ?? false, - }; - - if (Application.Current?.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime lifetime) - { - // Make sure the windows have unique names and AutomationIds. - var existing = lifetime.Windows.OfType().Count(); - if (existing > 0) + menuItem.Click += (_, _) => { - AutomationProperties.SetAutomationId(window, window.Name + (existing + 1)); - window.Title += $" {existing + 1}"; - } - } - - if (size.HasValue) - { - window.Width = size.Value.Width; - window.Height = size.Value.Height; - } - - sizeTextBox.Text = string.Empty; - window.ExtendClientAreaToDecorationsHint = extendClientArea.IsChecked ?? false; - window.SystemDecorations = (SystemDecorations)systemDecorations.SelectedIndex; - window.WindowState = (WindowState)stateComboBox.SelectedIndex; - - switch (modeComboBox.SelectedIndex) - { - case 0: - window.Show(); - break; - case 1: - window.Show(owner); - break; - case 2: - window.ShowDialog(owner); - break; - } - } - - private void ShowTransparentWindow() - { - // Show a background window to make sure the color behind the transparent window is - // a known color (green). - var backgroundWindow = new Window - { - Title = "Transparent Window Background", - Name = "TransparentWindowBackground", - Width = 300, - Height = 300, - Background = Brushes.Green, - WindowStartupLocation = WindowStartupLocation.CenterOwner, - }; - - // This is the transparent window with a red circle. - var window = new Window - { - Title = "Transparent Window", - Name = "TransparentWindow", - SystemDecorations = SystemDecorations.None, - Background = Brushes.Transparent, - TransparencyLevelHint = new[] { WindowTransparencyLevel.Transparent }, - WindowStartupLocation = WindowStartupLocation.CenterOwner, - Width = 200, - Height = 200, - Content = new Border - { - Background = Brushes.Red, - CornerRadius = new CornerRadius(100), - } - }; - - window.PointerPressed += (_, _) => - { - window.Close(); - backgroundWindow.Close(); - }; - - backgroundWindow.Show(this); - window.Show(backgroundWindow); - } - - private void ShowTransparentPopup() - { - var popup = new Popup - { - WindowManagerAddShadowHint = false, - Placement = PlacementMode.AnchorAndGravity, - PlacementAnchor = PopupAnchor.Top, - PlacementGravity = PopupGravity.Bottom, - Width= 200, - Height= 200, - Child = new Border - { - Background = Brushes.Red, - CornerRadius = new CornerRadius(100), - } - }; - - // Show a background window to make sure the color behind the transparent window is - // a known color (green). - var backgroundWindow = new Window - { - Title = "Transparent Popup Background", - Name = "TransparentPopupBackground", - Width = 200, - Height = 200, - Background = Brushes.Green, - WindowStartupLocation = WindowStartupLocation.CenterOwner, - Content = new Border - { - Name = "PopupContainer", - Child = popup, - [AutomationProperties.AccessibilityViewProperty] = AccessibilityView.Content, - } - }; - - backgroundWindow.PointerPressed += (_, _) => backgroundWindow.Close(); - backgroundWindow.Show(this); - - popup.Open(); - } - - private void SendToBack() - { - var lifetime = (ClassicDesktopStyleApplicationLifetime)Application.Current!.ApplicationLifetime!; - - foreach (var window in lifetime.Windows.ToArray()) - { - window.Activate(); - } - } - - private void RestoreAll() - { - var lifetime = (ClassicDesktopStyleApplicationLifetime)Application.Current!.ApplicationLifetime!; + if (ViewModel is { } viewModel) + viewModel.SelectedPage = page; + }; - foreach (var window in lifetime.Windows.ToArray()) - { - window.Show(); - if (window.WindowState == WindowState.Minimized) - window.WindowState = WindowState.Normal; + viewMenu?.Menu?.Items.Add(menuItem); } } - private void InitializeGesturesTab() + private void Pager_SelectionChanged(object? sender, SelectionChangedEventArgs e) { - var gestureBorder = this.GetControl("GestureBorder"); - var gestureBorder2 = this.GetControl("GestureBorder2"); - var lastGesture = this.GetControl("LastGesture"); - var resetGestures = this.GetControl + + + + + + diff --git a/samples/IntegrationTestApp/Pages/ButtonPage.axaml.cs b/samples/IntegrationTestApp/Pages/ButtonPage.axaml.cs new file mode 100644 index 0000000000..540ce839a3 --- /dev/null +++ b/samples/IntegrationTestApp/Pages/ButtonPage.axaml.cs @@ -0,0 +1,11 @@ +using Avalonia.Controls; + +namespace IntegrationTestApp.Pages; + +public partial class ButtonPage : UserControl +{ + public ButtonPage() + { + InitializeComponent(); + } +} diff --git a/samples/IntegrationTestApp/Pages/CheckBoxPage.axaml b/samples/IntegrationTestApp/Pages/CheckBoxPage.axaml new file mode 100644 index 0000000000..cdb61b53a4 --- /dev/null +++ b/samples/IntegrationTestApp/Pages/CheckBoxPage.axaml @@ -0,0 +1,12 @@ + + + Unchecked + Checked + ThreeState + + diff --git a/samples/IntegrationTestApp/Pages/CheckBoxPage.axaml.cs b/samples/IntegrationTestApp/Pages/CheckBoxPage.axaml.cs new file mode 100644 index 0000000000..6863f62387 --- /dev/null +++ b/samples/IntegrationTestApp/Pages/CheckBoxPage.axaml.cs @@ -0,0 +1,11 @@ +using Avalonia.Controls; + +namespace IntegrationTestApp.Pages; + +public partial class CheckBoxPage : UserControl +{ + public CheckBoxPage() + { + InitializeComponent(); + } +} diff --git a/samples/IntegrationTestApp/Pages/ComboBoxPage.axaml b/samples/IntegrationTestApp/Pages/ComboBoxPage.axaml new file mode 100644 index 0000000000..6068b06e85 --- /dev/null +++ b/samples/IntegrationTestApp/Pages/ComboBoxPage.axaml @@ -0,0 +1,16 @@ + + + + Item 0 + Item 1 + + Wrap Selection + + + + diff --git a/samples/IntegrationTestApp/Pages/ComboBoxPage.axaml.cs b/samples/IntegrationTestApp/Pages/ComboBoxPage.axaml.cs new file mode 100644 index 0000000000..eb9b66de76 --- /dev/null +++ b/samples/IntegrationTestApp/Pages/ComboBoxPage.axaml.cs @@ -0,0 +1,22 @@ +using Avalonia.Controls; +using Avalonia.Interactivity; + +namespace IntegrationTestApp.Pages; + +public partial class ComboBoxPage : UserControl +{ + public ComboBoxPage() + { + InitializeComponent(); + } + + private void ComboBoxSelectionClear_Click(object? sender, RoutedEventArgs e) + { + BasicComboBox.SelectedIndex = -1; + } + + private void ComboBoxSelectFirst_Click(object? sender, RoutedEventArgs e) + { + BasicComboBox.SelectedIndex = 0; + } +} diff --git a/samples/IntegrationTestApp/Pages/ContextMenuPage.axaml b/samples/IntegrationTestApp/Pages/ContextMenuPage.axaml new file mode 100644 index 0000000000..7d494bb277 --- /dev/null +++ b/samples/IntegrationTestApp/Pages/ContextMenuPage.axaml @@ -0,0 +1,17 @@ + + + + + diff --git a/samples/IntegrationTestApp/Pages/ContextMenuPage.axaml.cs b/samples/IntegrationTestApp/Pages/ContextMenuPage.axaml.cs new file mode 100644 index 0000000000..e42d9f232e --- /dev/null +++ b/samples/IntegrationTestApp/Pages/ContextMenuPage.axaml.cs @@ -0,0 +1,11 @@ +using Avalonia.Controls; + +namespace IntegrationTestApp.Pages; + +public partial class ContextMenuPage : UserControl +{ + public ContextMenuPage() + { + InitializeComponent(); + } +} diff --git a/samples/IntegrationTestApp/Pages/DesktopPage.axaml b/samples/IntegrationTestApp/Pages/DesktopPage.axaml new file mode 100644 index 0000000000..a5495bd347 --- /dev/null +++ b/samples/IntegrationTestApp/Pages/DesktopPage.axaml @@ -0,0 +1,14 @@ + + + Tray Icon Clicked + Tray Icon Menu Clicked + + + + + + + + + diff --git a/samples/IntegrationTestApp/Pages/GesturesPage.axaml.cs b/samples/IntegrationTestApp/Pages/GesturesPage.axaml.cs new file mode 100644 index 0000000000..907edb973c --- /dev/null +++ b/samples/IntegrationTestApp/Pages/GesturesPage.axaml.cs @@ -0,0 +1,44 @@ +using Avalonia.Controls; +using Avalonia.Input; +using Avalonia.Interactivity; + +namespace IntegrationTestApp.Pages; + +public partial class GesturesPage : UserControl +{ + public GesturesPage() + { + InitializeComponent(); + } + + private void GestureBorder_Tapped(object? sender, TappedEventArgs e) + { + LastGesture.Text = "Tapped"; + } + + private void GestureBorder_DoubleTapped(object? sender, TappedEventArgs e) + { + LastGesture.Text = "DoubleTapped"; + + // Testing #8733 + GestureBorder.IsVisible = false; + GestureBorder2.IsVisible = true; + } + + private void GestureBorder_RightTapped(object? sender, RoutedEventArgs e) + { + LastGesture.Text = "RightTapped"; + } + + private void GestureBorder2_DoubleTapped(object? sender, TappedEventArgs e) + { + LastGesture.Text = "DoubleTapped2"; + } + + private void ResetGestures_Click(object? sender, RoutedEventArgs e) + { + LastGesture.Text = string.Empty; + GestureBorder.IsVisible = true; + GestureBorder2.IsVisible = false; + } +} diff --git a/samples/IntegrationTestApp/Pages/ListBoxPage.axaml b/samples/IntegrationTestApp/Pages/ListBoxPage.axaml new file mode 100644 index 0000000000..4e23cd8e37 --- /dev/null +++ b/samples/IntegrationTestApp/Pages/ListBoxPage.axaml @@ -0,0 +1,15 @@ + + + + + + + + diff --git a/samples/IntegrationTestApp/Pages/ListBoxPage.axaml.cs b/samples/IntegrationTestApp/Pages/ListBoxPage.axaml.cs new file mode 100644 index 0000000000..3bff7d9231 --- /dev/null +++ b/samples/IntegrationTestApp/Pages/ListBoxPage.axaml.cs @@ -0,0 +1,23 @@ +using System.Collections.Generic; +using System.Linq; +using Avalonia.Controls; +using Avalonia.Interactivity; + +namespace IntegrationTestApp.Pages; + +public partial class ListBoxPage : UserControl +{ + public ListBoxPage() + { + InitializeComponent(); + ListBoxItems = Enumerable.Range(0, 100).Select(x => "Item " + x).ToList(); + DataContext = this; + } + + public List ListBoxItems { get; } + + private void ListBoxSelectionClear_Click(object? sender, RoutedEventArgs e) + { + BasicListBox.SelectedIndex = -1; + } +} diff --git a/samples/IntegrationTestApp/Pages/MenuPage.axaml b/samples/IntegrationTestApp/Pages/MenuPage.axaml new file mode 100644 index 0000000000..36c2636f3d --- /dev/null +++ b/samples/IntegrationTestApp/Pages/MenuPage.axaml @@ -0,0 +1,22 @@ + + + + + + + + + + + + None + + + + + diff --git a/samples/IntegrationTestApp/Pages/MenuPage.axaml.cs b/samples/IntegrationTestApp/Pages/MenuPage.axaml.cs new file mode 100644 index 0000000000..8be695f8ab --- /dev/null +++ b/samples/IntegrationTestApp/Pages/MenuPage.axaml.cs @@ -0,0 +1,24 @@ +using Avalonia.Controls; +using Avalonia.Interactivity; + +namespace IntegrationTestApp.Pages; + +public partial class MenuPage : UserControl +{ + public MenuPage() + { + InitializeComponent(); + } + + private void MenuClicked(object? sender, RoutedEventArgs e) + { + var clickedMenuItemTextBlock = ClickedMenuItem; + clickedMenuItemTextBlock.Text = (sender as MenuItem)?.Header?.ToString(); + } + + + private void MenuClickedMenuItemReset_Click(object? sender, RoutedEventArgs e) + { + ClickedMenuItem.Text = "None"; + } +} diff --git a/samples/IntegrationTestApp/Pages/PointerPage.axaml b/samples/IntegrationTestApp/Pages/PointerPage.axaml new file mode 100644 index 0000000000..ba6016c9b5 --- /dev/null +++ b/samples/IntegrationTestApp/Pages/PointerPage.axaml @@ -0,0 +1,19 @@ + + + + + Show Dialog + + + + diff --git a/samples/IntegrationTestApp/Pages/PointerPage.axaml.cs b/samples/IntegrationTestApp/Pages/PointerPage.axaml.cs new file mode 100644 index 0000000000..b34798be10 --- /dev/null +++ b/samples/IntegrationTestApp/Pages/PointerPage.axaml.cs @@ -0,0 +1,47 @@ +using Avalonia; +using Avalonia.Controls; +using Avalonia.Input; + +namespace IntegrationTestApp.Pages; + +public partial class PointerPage : UserControl +{ + public PointerPage() + { + InitializeComponent(); + } + + private void PointerPageShowDialog_PointerPressed(object? sender, PointerPressedEventArgs e) + { + void CaptureLost(object? sender, PointerCaptureLostEventArgs e) + { + PointerCaptureStatus.Text = "None"; + ((Control)sender!).PointerCaptureLost -= CaptureLost; + } + + var window = TopLevel.GetTopLevel(this) as Window ?? + throw new AvaloniaInternalException("PointerPage is not attached to a Window."); + var captured = e.Pointer.Captured as Control; + + if (captured is not null) + { + captured.PointerCaptureLost += CaptureLost; + } + + PointerCaptureStatus.Text = captured?.ToString() ?? "None"; + + var dialog = new Window + { + Width = 200, + Height = 200, + }; + + dialog.Content = new Button + { + Content = "Close", + Command = new DelegateCommand(() => dialog.Close()), + }; + + dialog.ShowDialog(window); + } +} diff --git a/samples/IntegrationTestApp/Pages/RadioButtonPage.axaml b/samples/IntegrationTestApp/Pages/RadioButtonPage.axaml new file mode 100644 index 0000000000..f66b9b9f7b --- /dev/null +++ b/samples/IntegrationTestApp/Pages/RadioButtonPage.axaml @@ -0,0 +1,14 @@ + + + Sample RadioButton + + Three States: Option 1 + Three States: Option 2 + + + diff --git a/samples/IntegrationTestApp/Pages/RadioButtonPage.axaml.cs b/samples/IntegrationTestApp/Pages/RadioButtonPage.axaml.cs new file mode 100644 index 0000000000..115ff6f2f0 --- /dev/null +++ b/samples/IntegrationTestApp/Pages/RadioButtonPage.axaml.cs @@ -0,0 +1,11 @@ +using Avalonia.Controls; + +namespace IntegrationTestApp.Pages; + +public partial class RadioButtonPage : UserControl +{ + public RadioButtonPage() + { + InitializeComponent(); + } +} diff --git a/samples/IntegrationTestApp/Pages/ScreensPage.axaml b/samples/IntegrationTestApp/Pages/ScreensPage.axaml new file mode 100644 index 0000000000..2d95c4719a --- /dev/null +++ b/samples/IntegrationTestApp/Pages/ScreensPage.axaml @@ -0,0 +1,19 @@ + + + + + diff --git a/samples/IntegrationTestApp/Pages/SliderPage.axaml.cs b/samples/IntegrationTestApp/Pages/SliderPage.axaml.cs new file mode 100644 index 0000000000..72f0174fed --- /dev/null +++ b/samples/IntegrationTestApp/Pages/SliderPage.axaml.cs @@ -0,0 +1,17 @@ +using Avalonia.Controls; +using Avalonia.Interactivity; + +namespace IntegrationTestApp.Pages; + +public partial class SliderPage : UserControl +{ + public SliderPage() + { + InitializeComponent(); + } + + private void ResetSliders_Click(object? sender, RoutedEventArgs e) + { + HorizontalSlider.Value = 50; + } +} diff --git a/samples/IntegrationTestApp/Pages/WindowDecorationsPage.axaml b/samples/IntegrationTestApp/Pages/WindowDecorationsPage.axaml new file mode 100644 index 0000000000..21a5b1d883 --- /dev/null +++ b/samples/IntegrationTestApp/Pages/WindowDecorationsPage.axaml @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/samples/IntegrationTestApp/Pages/WindowPage.axaml.cs b/samples/IntegrationTestApp/Pages/WindowPage.axaml.cs new file mode 100644 index 0000000000..5549e537d3 --- /dev/null +++ b/samples/IntegrationTestApp/Pages/WindowPage.axaml.cs @@ -0,0 +1,199 @@ +using System.Linq; +using Avalonia; +using Avalonia.Automation; +using Avalonia.Controls; +using Avalonia.Controls.ApplicationLifetimes; +using Avalonia.Controls.Primitives; +using Avalonia.Controls.Primitives.PopupPositioning; +using Avalonia.Interactivity; +using Avalonia.Media; + +namespace IntegrationTestApp.Pages; + +public partial class WindowPage : UserControl +{ + public WindowPage() + { + InitializeComponent(); + } + + private Window Window => TopLevel.GetTopLevel(this) as Window ?? + throw new AvaloniaInternalException("WindowPage is not attached to a Window."); + + private void ShowWindow_Click(object? sender, RoutedEventArgs e) + { + var size = !string.IsNullOrWhiteSpace(ShowWindowSize.Text) ? Size.Parse(ShowWindowSize.Text) : (Size?)null; + var window = new ShowWindowTest + { + WindowStartupLocation = (WindowStartupLocation)ShowWindowLocation.SelectedIndex, + CanResize = ShowWindowCanResize.IsChecked ?? false, + }; + + if (Application.Current?.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime lifetime) + { + // Make sure the windows have unique names and AutomationIds. + var existing = lifetime.Windows.OfType().Count(); + if (existing > 0) + { + AutomationProperties.SetAutomationId(window, window.Name + (existing + 1)); + window.Title += $" {existing + 1}"; + } + } + + if (size.HasValue) + { + window.Width = size.Value.Width; + window.Height = size.Value.Height; + } + + ShowWindowSize.Text = string.Empty; + window.ExtendClientAreaToDecorationsHint = ShowWindowExtendClientAreaToDecorationsHint.IsChecked ?? false; + window.SystemDecorations = (SystemDecorations)ShowWindowSystemDecorations.SelectedIndex; + window.WindowState = (WindowState)ShowWindowState.SelectedIndex; + + switch (ShowWindowMode.SelectedIndex) + { + case 0: + window.Show(); + break; + case 1: + window.Show(Window); + break; + case 2: + window.ShowDialog(Window); + break; + } + } + + private void ShowTransparentWindow_Click(object? sender, RoutedEventArgs e) + { + // Show a background window to make sure the color behind the transparent window is + // a known color (green). + var backgroundWindow = new Window + { + Title = "Transparent Window Background", + Name = "TransparentWindowBackground", + Width = 300, + Height = 300, + Background = Brushes.Green, + WindowStartupLocation = WindowStartupLocation.CenterOwner, + }; + + // This is the transparent window with a red circle. + var window = new Window + { + Title = "Transparent Window", + Name = "TransparentWindow", + SystemDecorations = SystemDecorations.None, + Background = Brushes.Transparent, + TransparencyLevelHint = new[] { WindowTransparencyLevel.Transparent }, + WindowStartupLocation = WindowStartupLocation.CenterOwner, + Width = 200, + Height = 200, + Content = new Border + { + Background = Brushes.Red, + CornerRadius = new CornerRadius(100), + } + }; + + window.PointerPressed += (_, _) => + { + window.Close(); + backgroundWindow.Close(); + }; + + backgroundWindow.Show(Window); + window.Show(backgroundWindow); + } + + private void ShowTransparentPopup_Click(object? sender, RoutedEventArgs e) + { + var popup = new Popup + { + WindowManagerAddShadowHint = false, + Placement = PlacementMode.AnchorAndGravity, + PlacementAnchor = PopupAnchor.Top, + PlacementGravity = PopupGravity.Bottom, + Width = 200, + Height = 200, + Child = new Border + { + Background = Brushes.Red, + CornerRadius = new CornerRadius(100), + } + }; + + // Show a background window to make sure the color behind the transparent window is + // a known color (green). + var backgroundWindow = new Window + { + Title = "Transparent Popup Background", + Name = "TransparentPopupBackground", + Width = 200, + Height = 200, + Background = Brushes.Green, + WindowStartupLocation = WindowStartupLocation.CenterOwner, + Content = new Border + { + Name = "PopupContainer", + Child = popup, + [AutomationProperties.AccessibilityViewProperty] = AccessibilityView.Content, + } + }; + + backgroundWindow.PointerPressed += (_, _) => backgroundWindow.Close(); + backgroundWindow.Show(Window); + + popup.Open(); + } + + private void SendToBack_Click(object? sender, RoutedEventArgs e) + { + var lifetime = (ClassicDesktopStyleApplicationLifetime)Application.Current!.ApplicationLifetime!; + + foreach (var window in lifetime.Windows.ToArray()) + { + window.Activate(); + } + } + + private void EnterFullscreen_Click(object? sender, RoutedEventArgs e) + { + Window.WindowState = WindowState.FullScreen; + } + + private void ExitFullscreen_Click(object? sender, RoutedEventArgs e) + { + Window.WindowState = WindowState.Normal; + } + + private void RestoreAll_Click(object? sender, RoutedEventArgs e) + { + var lifetime = (ClassicDesktopStyleApplicationLifetime)Application.Current!.ApplicationLifetime!; + + foreach (var window in lifetime.Windows.ToArray()) + { + window.Show(); + if (window.WindowState == WindowState.Minimized) + window.WindowState = WindowState.Normal; + } + } + + private void ShowTopmostWindow_Click(object? sender, RoutedEventArgs e) + { + var mainWindow = new TopmostWindowTest("OwnerWindow") + { + Topmost = true, + Title = "Owner Window" + }; + var ownedWindow = new TopmostWindowTest("OwnedWindow") + { + WindowStartupLocation = WindowStartupLocation.CenterOwner, + Title = "Owned Window" + }; + + mainWindow.Show(); + ownedWindow.Show(mainWindow); + } +} diff --git a/samples/IntegrationTestApp/ShowWindowTest.axaml.cs b/samples/IntegrationTestApp/ShowWindowTest.axaml.cs index f0be34fdaa..0c5774bf53 100644 --- a/samples/IntegrationTestApp/ShowWindowTest.axaml.cs +++ b/samples/IntegrationTestApp/ShowWindowTest.axaml.cs @@ -2,7 +2,6 @@ using System; using System.Runtime.InteropServices; using Avalonia; using Avalonia.Controls; -using Avalonia.Markup.Xaml; using Avalonia.Threading; namespace IntegrationTestApp diff --git a/samples/IntegrationTestApp/ViewModels/MainWindowViewModel.cs b/samples/IntegrationTestApp/ViewModels/MainWindowViewModel.cs new file mode 100644 index 0000000000..86eb13ec5a --- /dev/null +++ b/samples/IntegrationTestApp/ViewModels/MainWindowViewModel.cs @@ -0,0 +1,23 @@ +using System.Collections.Generic; +using System.Collections.ObjectModel; +using IntegrationTestApp.Models; + +namespace IntegrationTestApp.ViewModels; + +internal class MainWindowViewModel : ViewModelBase +{ + private Page? _selectedPage; + + public MainWindowViewModel(IEnumerable pages) + { + Pages = new(pages); + } + + public ObservableCollection Pages { get; } + + public Page? SelectedPage + { + get => _selectedPage; + set => RaiseAndSetIfChanged(ref _selectedPage, value); + } +} diff --git a/samples/IntegrationTestApp/ViewModels/ViewModelBase.cs b/samples/IntegrationTestApp/ViewModels/ViewModelBase.cs new file mode 100644 index 0000000000..521382b863 --- /dev/null +++ b/samples/IntegrationTestApp/ViewModels/ViewModelBase.cs @@ -0,0 +1,24 @@ +using System.Collections.Generic; +using System.ComponentModel; +using System.Runtime.CompilerServices; + +namespace IntegrationTestApp.ViewModels; + +internal class ViewModelBase : INotifyPropertyChanged +{ + public event PropertyChangedEventHandler? PropertyChanged; + + protected bool RaiseAndSetIfChanged(ref T field, T value, [CallerMemberName] string? propertyName = null) + { + if (!EqualityComparer.Default.Equals(field, value)) + { + field = value; + RaisePropertyChanged(propertyName); + return true; + } + return false; + } + + protected void RaisePropertyChanged([CallerMemberName] string? propertyName = null) + => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); +} diff --git a/src/Avalonia.Controls.DataGrid/DataGridCell.cs b/src/Avalonia.Controls.DataGrid/DataGridCell.cs index 852b85ff01..3518738485 100644 --- a/src/Avalonia.Controls.DataGrid/DataGridCell.cs +++ b/src/Avalonia.Controls.DataGrid/DataGridCell.cs @@ -3,6 +3,7 @@ // Please see http://go.microsoft.com/fwlink/?LinkID=131993 for details. // All other rights reserved. +using Avalonia.Automation; using Avalonia.Automation.Peers; using Avalonia.Controls.Automation.Peers; using Avalonia.Controls.Metadata; @@ -37,6 +38,7 @@ namespace Avalonia.Controls (x,e) => x.DataGridCell_PointerPressed(e), handledEventsToo: true); FocusableProperty.OverrideDefaultValue(true); IsTabStopProperty.OverrideDefaultValue(false); + AutomationProperties.IsOffscreenBehaviorProperty.OverrideDefaultValue(IsOffscreenBehavior.FromClip); } public DataGridCell() { } diff --git a/src/Avalonia.Controls.DataGrid/DataGridColumnHeader.cs b/src/Avalonia.Controls.DataGrid/DataGridColumnHeader.cs index 579c4d04ad..a3dcc433ee 100644 --- a/src/Avalonia.Controls.DataGrid/DataGridColumnHeader.cs +++ b/src/Avalonia.Controls.DataGrid/DataGridColumnHeader.cs @@ -6,6 +6,7 @@ using System; using System.ComponentModel; using System.Diagnostics; +using Avalonia.Automation; using Avalonia.Automation.Peers; using Avalonia.Collections; using Avalonia.Controls.Automation.Peers; @@ -74,6 +75,7 @@ namespace Avalonia.Controls AreSeparatorsVisibleProperty.Changed.AddClassHandler((x, e) => x.OnAreSeparatorsVisibleChanged(e)); PressedMixin.Attach(); IsTabStopProperty.OverrideDefaultValue(false); + AutomationProperties.IsOffscreenBehaviorProperty.OverrideDefaultValue(IsOffscreenBehavior.FromClip); } /// diff --git a/src/Avalonia.Controls.DataGrid/DataGridRow.cs b/src/Avalonia.Controls.DataGrid/DataGridRow.cs index 12dbd01d07..e94eecbb91 100644 --- a/src/Avalonia.Controls.DataGrid/DataGridRow.cs +++ b/src/Avalonia.Controls.DataGrid/DataGridRow.cs @@ -17,6 +17,7 @@ using System; using System.Diagnostics; using Avalonia.Automation.Peers; using Avalonia.Reactive; +using Avalonia.Automation; namespace Avalonia.Controls { @@ -143,6 +144,7 @@ namespace Avalonia.Controls AreDetailsVisibleProperty.Changed.AddClassHandler((x, e) => x.OnAreDetailsVisibleChanged(e)); PointerPressedEvent.AddClassHandler((x, e) => x.DataGridRow_PointerPressed(e), handledEventsToo: true); IsTabStopProperty.OverrideDefaultValue(false); + AutomationProperties.IsOffscreenBehaviorProperty.OverrideDefaultValue(IsOffscreenBehavior.FromClip); } /// diff --git a/src/Avalonia.Controls.DataGrid/DataGridRowHeader.cs b/src/Avalonia.Controls.DataGrid/DataGridRowHeader.cs index a480a7af15..ba6ad94777 100644 --- a/src/Avalonia.Controls.DataGrid/DataGridRowHeader.cs +++ b/src/Avalonia.Controls.DataGrid/DataGridRowHeader.cs @@ -3,6 +3,7 @@ // Please see http://go.microsoft.com/fwlink/?LinkID=131993 for details. // All other rights reserved. +using Avalonia.Automation; using Avalonia.Controls.Metadata; using Avalonia.Input; using Avalonia.Media; @@ -50,6 +51,11 @@ namespace Avalonia.Controls.Primitives AddHandler(PointerPressedEvent, DataGridRowHeader_PointerPressed, handledEventsToo: true); } + static DataGridRowHeader() + { + AutomationProperties.IsOffscreenBehaviorProperty.OverrideDefaultValue(IsOffscreenBehavior.FromClip); + } + internal Control Owner { get; diff --git a/src/Avalonia.Controls/Automation/Peers/AutomationPeer.cs b/src/Avalonia.Controls/Automation/Peers/AutomationPeer.cs index fb7cdd87ed..6a45ba4cea 100644 --- a/src/Avalonia.Controls/Automation/Peers/AutomationPeer.cs +++ b/src/Avalonia.Controls/Automation/Peers/AutomationPeer.cs @@ -153,6 +153,17 @@ namespace Avalonia.Automation.Peers /// public bool IsKeyboardFocusable() => IsKeyboardFocusableCore(); + /// + /// Gets a value that indicates whether an element is off the screen. + /// + /// + /// This property does not indicate whether the element is visible. In some circumstances, + /// an element is on the screen but is still not visible. For example, if the element is + /// on the screen but obscured by other elements, it might not be visible. In this case, + /// the method returns false. + /// + public bool IsOffscreen() => IsOffscreenCore(); + /// /// Sets the keyboard focus on the element that is associated with this automation peer. /// @@ -245,6 +256,7 @@ namespace Avalonia.Automation.Peers protected abstract bool IsControlElementCore(); protected abstract bool IsEnabledCore(); protected abstract bool IsKeyboardFocusableCore(); + protected virtual bool IsOffscreenCore() => false; protected abstract void SetFocusCore(); protected abstract bool ShowContextMenuCore(); diff --git a/src/Avalonia.Controls/Automation/Peers/ControlAutomationPeer.cs b/src/Avalonia.Controls/Automation/Peers/ControlAutomationPeer.cs index b0dd30a878..0c043e7577 100644 --- a/src/Avalonia.Controls/Automation/Peers/ControlAutomationPeer.cs +++ b/src/Avalonia.Controls/Automation/Peers/ControlAutomationPeer.cs @@ -2,6 +2,7 @@ using System; using System.Collections.Generic; using System.Linq; using Avalonia.Controls; +using Avalonia.Utilities; using Avalonia.VisualTree; namespace Avalonia.Automation.Peers @@ -201,6 +202,19 @@ namespace Avalonia.Automation.Peers return view == AccessibilityView.Default ? IsControlElementCore() : view >= AccessibilityView.Control; } + protected override bool IsOffscreenCore() + { + return AutomationProperties.GetIsOffscreenBehavior(Owner) switch + { + IsOffscreenBehavior.Onscreen => false, + IsOffscreenBehavior.Offscreen => true, + IsOffscreenBehavior.FromClip => Owner.GetTransformedBounds() is not { } bounds || + MathUtilities.IsZero(bounds.Clip.Width) || + MathUtilities.IsZero(bounds.Clip.Height), + _ => !Owner.IsVisible, + }; + } + private static Rect GetBounds(Control control) { var root = control.GetVisualRoot(); diff --git a/src/Avalonia.Controls/ListBoxItem.cs b/src/Avalonia.Controls/ListBoxItem.cs index 5ee4854554..55fc81653a 100644 --- a/src/Avalonia.Controls/ListBoxItem.cs +++ b/src/Avalonia.Controls/ListBoxItem.cs @@ -1,3 +1,4 @@ +using Avalonia.Automation; using Avalonia.Automation.Peers; using Avalonia.Controls.Metadata; using Avalonia.Controls.Mixins; @@ -30,6 +31,7 @@ namespace Avalonia.Controls SelectableMixin.Attach(IsSelectedProperty); PressedMixin.Attach(); FocusableProperty.OverrideDefaultValue(true); + AutomationProperties.IsOffscreenBehaviorProperty.OverrideDefaultValue(IsOffscreenBehavior.FromClip); } /// diff --git a/src/Avalonia.Controls/MenuItem.cs b/src/Avalonia.Controls/MenuItem.cs index a2a54d5550..13cd78f2fc 100644 --- a/src/Avalonia.Controls/MenuItem.cs +++ b/src/Avalonia.Controls/MenuItem.cs @@ -2,6 +2,7 @@ using System; using System.Collections.Generic; using System.Linq; using System.Windows.Input; +using Avalonia.Automation; using Avalonia.Automation.Peers; using Avalonia.Controls.Metadata; using Avalonia.Controls.Mixins; @@ -141,6 +142,7 @@ namespace Avalonia.Controls ItemsPanelProperty.OverrideDefaultValue(DefaultPanel); ClickEvent.AddClassHandler((x, e) => x.OnClick(e)); SubmenuOpenedEvent.AddClassHandler((x, e) => x.OnSubmenuOpened(e)); + AutomationProperties.IsOffscreenBehaviorProperty.OverrideDefaultValue(IsOffscreenBehavior.FromClip); } public MenuItem() diff --git a/src/Avalonia.Controls/TabItem.cs b/src/Avalonia.Controls/TabItem.cs index 9bffacd921..0a0c3f5fc5 100644 --- a/src/Avalonia.Controls/TabItem.cs +++ b/src/Avalonia.Controls/TabItem.cs @@ -39,6 +39,7 @@ namespace Avalonia.Controls FocusableProperty.OverrideDefaultValue(typeof(TabItem), true); DataContextProperty.Changed.AddClassHandler((x, e) => x.UpdateHeader(e)); AutomationProperties.ControlTypeOverrideProperty.OverrideDefaultValue(AutomationControlType.TabItem); + AutomationProperties.IsOffscreenBehaviorProperty.OverrideDefaultValue(IsOffscreenBehavior.FromClip); AccessKeyHandler.AccessKeyPressedEvent.AddClassHandler((tabItem, args) => tabItem.TabItemActivated(args)); } diff --git a/src/Avalonia.Controls/TreeViewItem.cs b/src/Avalonia.Controls/TreeViewItem.cs index a48706cb19..76a01fab35 100644 --- a/src/Avalonia.Controls/TreeViewItem.cs +++ b/src/Avalonia.Controls/TreeViewItem.cs @@ -2,6 +2,8 @@ using System; using System.Collections.Generic; using System.Collections.Specialized; using System.Linq; +using Avalonia.Automation; +using Avalonia.Automation.Peers; using Avalonia.Controls.Metadata; using Avalonia.Controls.Mixins; using Avalonia.Controls.Primitives; @@ -61,6 +63,7 @@ namespace Avalonia.Controls PressedMixin.Attach(); FocusableProperty.OverrideDefaultValue(true); ItemsPanelProperty.OverrideDefaultValue(DefaultPanel); + AutomationProperties.IsOffscreenBehaviorProperty.OverrideDefaultValue(IsOffscreenBehavior.FromClip); RequestBringIntoViewEvent.AddClassHandler((x, e) => x.OnRequestBringIntoView(e)); } diff --git a/src/Windows/Avalonia.Win32/Automation/AutomationNode.cs b/src/Windows/Avalonia.Win32/Automation/AutomationNode.cs index 569f7da738..8489e6ec29 100644 --- a/src/Windows/Avalonia.Win32/Automation/AutomationNode.cs +++ b/src/Windows/Avalonia.Win32/Automation/AutomationNode.cs @@ -118,6 +118,7 @@ namespace Avalonia.Win32.Automation UiaPropertyId.IsControlElement => InvokeSync(() => Peer.IsControlElement()), UiaPropertyId.IsEnabled => InvokeSync(() => Peer.IsEnabled()), UiaPropertyId.IsKeyboardFocusable => InvokeSync(() => Peer.IsKeyboardFocusable()), + UiaPropertyId.IsOffscreen => InvokeSync(() => Peer.IsOffscreen()), UiaPropertyId.LocalizedControlType => InvokeSync(() => Peer.GetLocalizedControlType()), UiaPropertyId.Name => InvokeSync(() => Peer.GetName()), UiaPropertyId.ProcessId => Process.GetCurrentProcess().Id, diff --git a/tests/Avalonia.IntegrationTests.Appium/AutomationTests.cs b/tests/Avalonia.IntegrationTests.Appium/AutomationTests.cs index ce6e10807d..1924e27fc6 100644 --- a/tests/Avalonia.IntegrationTests.Appium/AutomationTests.cs +++ b/tests/Avalonia.IntegrationTests.Appium/AutomationTests.cs @@ -1,20 +1,13 @@ -using OpenQA.Selenium.Appium; -using Xunit; +using Xunit; namespace Avalonia.IntegrationTests.Appium { [Collection("Default")] - public class AutomationTests + public class AutomationTests : TestBase { - private readonly AppiumDriver _session; - public AutomationTests(DefaultAppFixture fixture) + : base(fixture, "Automation") { - _session = fixture.Session; - - var tabs = _session.FindElementByAccessibilityId("MainTabs"); - var tab = tabs.FindElementByName("Automation"); - tab.Click(); } [Fact] @@ -22,15 +15,15 @@ namespace Avalonia.IntegrationTests.Appium { // AutomationID can be specified by the Name or AutomationProperties.AutomationId // properties, with the latter taking precedence. - var byName = _session.FindElementByAccessibilityId("TextBlockWithName"); - var byAutomationId = _session.FindElementByAccessibilityId("TextBlockWithNameAndAutomationId"); + var byName = Session.FindElementByAccessibilityId("TextBlockWithName"); + var byAutomationId = Session.FindElementByAccessibilityId("TextBlockWithNameAndAutomationId"); } [Fact] public void LabeledBy() { - var label = _session.FindElementByAccessibilityId("TextBlockAsLabel"); - var labeledTextBox = _session.FindElementByAccessibilityId("LabeledByTextBox"); + var label = Session.FindElementByAccessibilityId("TextBlockAsLabel"); + var labeledTextBox = Session.FindElementByAccessibilityId("LabeledByTextBox"); Assert.Equal("Label for TextBox", label.Text); Assert.Equal("Label for TextBox", labeledTextBox.GetName()); diff --git a/tests/Avalonia.IntegrationTests.Appium/ButtonTests.cs b/tests/Avalonia.IntegrationTests.Appium/ButtonTests.cs index 22b68732c7..e2af1eef14 100644 --- a/tests/Avalonia.IntegrationTests.Appium/ButtonTests.cs +++ b/tests/Avalonia.IntegrationTests.Appium/ButtonTests.cs @@ -1,27 +1,19 @@ -using System.Runtime.InteropServices; -using OpenQA.Selenium.Appium; -using Xunit; +using Xunit; namespace Avalonia.IntegrationTests.Appium { [Collection("Default")] - public class ButtonTests + public class ButtonTests : TestBase { - private readonly AppiumDriver _session; - public ButtonTests(DefaultAppFixture fixture) + : base(fixture, "Button") { - _session = fixture.Session; - - var tabs = _session.FindElementByAccessibilityId("MainTabs"); - var tab = tabs.FindElementByName("Button"); - tab.Click(); } [Fact] public void DisabledButton() { - var button = _session.FindElementByAccessibilityId("DisabledButton"); + var button = Session.FindElementByAccessibilityId("DisabledButton"); Assert.Equal("Disabled Button", button.Text); Assert.False(button.Enabled); @@ -30,7 +22,7 @@ namespace Avalonia.IntegrationTests.Appium [Fact] public void EffectivelyDisabledButton() { - var button = _session.FindElementByAccessibilityId("EffectivelyDisabledButton"); + var button = Session.FindElementByAccessibilityId("EffectivelyDisabledButton"); Assert.Equal("Effectively Disabled Button", button.Text); Assert.False(button.Enabled); @@ -39,7 +31,7 @@ namespace Avalonia.IntegrationTests.Appium [Fact] public void BasicButton() { - var button = _session.FindElementByAccessibilityId("BasicButton"); + var button = Session.FindElementByAccessibilityId("BasicButton"); Assert.Equal("Basic Button", button.Text); Assert.True(button.Enabled); @@ -48,7 +40,7 @@ namespace Avalonia.IntegrationTests.Appium [Fact] public void ButtonWithTextBlock() { - var button = _session.FindElementByAccessibilityId("ButtonWithTextBlock"); + var button = Session.FindElementByAccessibilityId("ButtonWithTextBlock"); Assert.Equal("Button with TextBlock", button.Text); } @@ -56,7 +48,7 @@ namespace Avalonia.IntegrationTests.Appium [PlatformFact(TestPlatforms.Windows)] public void ButtonWithAcceleratorKey() { - var button = _session.FindElementByAccessibilityId("ButtonWithAcceleratorKey"); + var button = Session.FindElementByAccessibilityId("ButtonWithAcceleratorKey"); Assert.Equal("Ctrl+B", button.GetAttribute("AcceleratorKey")); } diff --git a/tests/Avalonia.IntegrationTests.Appium/CheckBoxTests.cs b/tests/Avalonia.IntegrationTests.Appium/CheckBoxTests.cs index 490210ae31..ab15a59af3 100644 --- a/tests/Avalonia.IntegrationTests.Appium/CheckBoxTests.cs +++ b/tests/Avalonia.IntegrationTests.Appium/CheckBoxTests.cs @@ -1,26 +1,19 @@ -using OpenQA.Selenium.Appium; -using Xunit; +using Xunit; namespace Avalonia.IntegrationTests.Appium { [Collection("Default")] - public class CheckBoxTests + public class CheckBoxTests : TestBase { - private readonly AppiumDriver _session; - public CheckBoxTests(DefaultAppFixture fixture) + : base(fixture, "CheckBox") { - _session = fixture.Session; - - var tabs = _session.FindElementByAccessibilityId("MainTabs"); - var tab = tabs.FindElementByName("CheckBox"); - tab.Click(); } [Fact] public void UncheckedCheckBox() { - var checkBox = _session.FindElementByAccessibilityId("UncheckedCheckBox"); + var checkBox = Session.FindElementByAccessibilityId("UncheckedCheckBox"); Assert.Equal("Unchecked", checkBox.GetName()); Assert.Equal(false, checkBox.GetIsChecked()); @@ -32,7 +25,7 @@ namespace Avalonia.IntegrationTests.Appium [Fact] public void CheckedCheckBox() { - var checkBox = _session.FindElementByAccessibilityId("CheckedCheckBox"); + var checkBox = Session.FindElementByAccessibilityId("CheckedCheckBox"); Assert.Equal("Checked", checkBox.GetName()); Assert.Equal(true, checkBox.GetIsChecked()); @@ -44,7 +37,7 @@ namespace Avalonia.IntegrationTests.Appium [Fact] public void ThreeStateCheckBox() { - var checkBox = _session.FindElementByAccessibilityId("ThreeStateCheckBox"); + var checkBox = Session.FindElementByAccessibilityId("ThreeStateCheckBox"); Assert.Equal("ThreeState", checkBox.GetName()); Assert.Null(checkBox.GetIsChecked()); diff --git a/tests/Avalonia.IntegrationTests.Appium/ComboBoxTests.cs b/tests/Avalonia.IntegrationTests.Appium/ComboBoxTests.cs index 231a50c89b..78b00ba641 100644 --- a/tests/Avalonia.IntegrationTests.Appium/ComboBoxTests.cs +++ b/tests/Avalonia.IntegrationTests.Appium/ComboBoxTests.cs @@ -1,32 +1,25 @@ using OpenQA.Selenium; -using OpenQA.Selenium.Appium; using Xunit; namespace Avalonia.IntegrationTests.Appium { - public abstract class ComboBoxTests + public abstract class ComboBoxTests : TestBase { - private readonly AppiumDriver _session; - public ComboBoxTests(DefaultAppFixture fixture) + : base(fixture, "ComboBox") { - _session = fixture.Session; - - var tabs = _session.FindElementByAccessibilityId("MainTabs"); - var tab = tabs.FindElementByName("ComboBox"); - tab.Click(); } [Fact] public void Can_Change_Selection_Using_Mouse() { - var comboBox = _session.FindElementByAccessibilityId("BasicComboBox"); + var comboBox = Session.FindElementByAccessibilityId("BasicComboBox"); - _session.FindElementByAccessibilityId("ComboBoxSelectFirst").Click(); + Session.FindElementByAccessibilityId("ComboBoxSelectFirst").Click(); Assert.Equal("Item 0", comboBox.GetComboBoxValue()); comboBox.Click(); - _session.FindElementByName("Item 1").SendClick(); + Session.FindElementByName("Item 1").SendClick(); Assert.Equal("Item 1", comboBox.GetComboBoxValue()); } @@ -34,13 +27,13 @@ namespace Avalonia.IntegrationTests.Appium [Fact] public void Can_Change_Selection_From_Unselected_Using_Mouse() { - var comboBox = _session.FindElementByAccessibilityId("BasicComboBox"); + var comboBox = Session.FindElementByAccessibilityId("BasicComboBox"); - _session.FindElementByAccessibilityId("ComboBoxSelectionClear").Click(); + Session.FindElementByAccessibilityId("ComboBoxSelectionClear").Click(); Assert.Equal(string.Empty, comboBox.GetComboBoxValue()); comboBox.Click(); - _session.FindElementByName("Item 0").SendClick(); + Session.FindElementByName("Item 0").SendClick(); Assert.Equal("Item 0", comboBox.GetComboBoxValue()); } @@ -48,13 +41,13 @@ namespace Avalonia.IntegrationTests.Appium [PlatformFact(TestPlatforms.Windows)] public void Can_Change_Selection_With_Keyboard_When_Closed() { - var comboBox = _session.FindElementByAccessibilityId("BasicComboBox"); - var wrap = _session.FindElementByAccessibilityId("ComboBoxWrapSelection"); + var comboBox = Session.FindElementByAccessibilityId("BasicComboBox"); + var wrap = Session.FindElementByAccessibilityId("ComboBoxWrapSelection"); if (wrap.GetIsChecked() != false) wrap.Click(); - _session.FindElementByAccessibilityId("ComboBoxSelectionClear").Click(); + Session.FindElementByAccessibilityId("ComboBoxSelectionClear").Click(); comboBox.SendKeys(Keys.ArrowDown); Assert.Equal("Item 0", comboBox.GetComboBoxValue()); @@ -75,13 +68,13 @@ namespace Avalonia.IntegrationTests.Appium [PlatformFact(TestPlatforms.Windows)] public void Can_Change_Wrapping_Selection_With_Keyboard_When_Closed() { - var comboBox = _session.FindElementByAccessibilityId("BasicComboBox"); - var wrap = _session.FindElementByAccessibilityId("ComboBoxWrapSelection"); + var comboBox = Session.FindElementByAccessibilityId("BasicComboBox"); + var wrap = Session.FindElementByAccessibilityId("ComboBoxWrapSelection"); if (wrap.GetIsChecked() != true) wrap.Click(); - _session.FindElementByAccessibilityId("ComboBoxSelectionClear").Click(); + Session.FindElementByAccessibilityId("ComboBoxSelectionClear").Click(); comboBox.SendKeys(Keys.ArrowDown); Assert.Equal("Item 0", comboBox.GetComboBoxValue()); @@ -105,15 +98,15 @@ namespace Avalonia.IntegrationTests.Appium [PlatformFact(TestPlatforms.Windows)] public void Can_Change_Selection_When_Open_With_Keyboard() { - var comboBox = _session.FindElementByAccessibilityId("BasicComboBox"); + var comboBox = Session.FindElementByAccessibilityId("BasicComboBox"); - _session.FindElementByAccessibilityId("ComboBoxSelectFirst").Click(); + Session.FindElementByAccessibilityId("ComboBoxSelectFirst").Click(); Assert.Equal("Item 0", comboBox.GetComboBoxValue()); comboBox.SendKeys(Keys.LeftAlt + Keys.ArrowDown); comboBox.SendKeys(Keys.ArrowDown); - var item = _session.FindElementByName("Item 1"); + var item = Session.FindElementByName("Item 1"); item.SendKeys(Keys.Enter); Assert.Equal("Item 1", comboBox.GetComboBoxValue()); @@ -122,15 +115,15 @@ namespace Avalonia.IntegrationTests.Appium [PlatformFact(TestPlatforms.Windows)] public void Can_Change_Selection_When_Open_With_Keyboard_From_Unselected() { - var comboBox = _session.FindElementByAccessibilityId("BasicComboBox"); + var comboBox = Session.FindElementByAccessibilityId("BasicComboBox"); - _session.FindElementByAccessibilityId("ComboBoxSelectionClear").Click(); + Session.FindElementByAccessibilityId("ComboBoxSelectionClear").Click(); Assert.Equal(string.Empty, comboBox.GetComboBoxValue()); comboBox.SendKeys(Keys.LeftAlt + Keys.ArrowDown); comboBox.SendKeys(Keys.ArrowDown); - var item = _session.FindElementByName("Item 0"); + var item = Session.FindElementByName("Item 0"); item.SendKeys(Keys.Enter); Assert.Equal("Item 0", comboBox.GetComboBoxValue()); @@ -139,15 +132,15 @@ namespace Avalonia.IntegrationTests.Appium [PlatformFact(TestPlatforms.Windows)] public void Can_Cancel_Keyboard_Selection_With_Escape() { - var comboBox = _session.FindElementByAccessibilityId("BasicComboBox"); + var comboBox = Session.FindElementByAccessibilityId("BasicComboBox"); - _session.FindElementByAccessibilityId("ComboBoxSelectionClear").Click(); + Session.FindElementByAccessibilityId("ComboBoxSelectionClear").Click(); Assert.Equal(string.Empty, comboBox.GetComboBoxValue()); comboBox.SendKeys(Keys.LeftAlt + Keys.ArrowDown); comboBox.SendKeys(Keys.ArrowDown); - var item = _session.FindElementByName("Item 0"); + var item = Session.FindElementByName("Item 0"); item.SendKeys(Keys.Escape); Assert.Equal(string.Empty, comboBox.GetComboBoxValue()); diff --git a/tests/Avalonia.IntegrationTests.Appium/ContextMenuTests.cs b/tests/Avalonia.IntegrationTests.Appium/ContextMenuTests.cs index 2d4ef14f45..af468e6f10 100644 --- a/tests/Avalonia.IntegrationTests.Appium/ContextMenuTests.cs +++ b/tests/Avalonia.IntegrationTests.Appium/ContextMenuTests.cs @@ -6,30 +6,24 @@ using Xunit; namespace Avalonia.IntegrationTests.Appium { [Collection("Default")] - public class ContextMenuTests + public class ContextMenuTests : TestBase { - private readonly AppiumDriver _session; - public ContextMenuTests(DefaultAppFixture fixture) + : base(fixture, "ContextMenu") { - _session = fixture.Session; - - var tabs = _session.FindElementByAccessibilityId("MainTabs"); - var tab = tabs.FindElementByName("ContextMenu"); - tab.Click(); } [PlatformFact(TestPlatforms.Windows)] public void Select_First_Item_With_Down_Arrow_Key() { - var control = _session.FindElementByAccessibilityId("ShowContextMenu"); + var control = Session.FindElementByAccessibilityId("ShowContextMenu"); - new Actions(_session) + new Actions(Session) .ContextClick(control) .SendKeys(Keys.ArrowDown) .Perform(); - var clickedMenuItem = _session.FindElementByAccessibilityId("ContextMenuItem1"); + var clickedMenuItem = Session.FindElementByAccessibilityId("ContextMenuItem1"); Assert.True(clickedMenuItem.GetIsFocused()); } } diff --git a/tests/Avalonia.IntegrationTests.Appium/GestureTests.cs b/tests/Avalonia.IntegrationTests.Appium/GestureTests.cs index 0fc8a68f44..b2d06be28e 100644 --- a/tests/Avalonia.IntegrationTests.Appium/GestureTests.cs +++ b/tests/Avalonia.IntegrationTests.Appium/GestureTests.cs @@ -1,34 +1,27 @@ using System; using System.Threading; -using OpenQA.Selenium.Appium; using OpenQA.Selenium.Interactions; using Xunit; namespace Avalonia.IntegrationTests.Appium { [Collection("Default")] - public class GestureTests + public class GestureTests : TestBase { - private readonly AppiumDriver _session; - public GestureTests(DefaultAppFixture fixture) + : base(fixture, "Gestures") { - _session = fixture.Session; - - var tabs = _session.FindElementByAccessibilityId("MainTabs"); - var tab = tabs.FindElementByName("Gestures"); - tab.Click(); - var clear = _session.FindElementByAccessibilityId("ResetGestures"); + var clear = Session.FindElementByAccessibilityId("ResetGestures"); clear.Click(); } [Fact] public void Tapped_Is_Raised() { - var border = _session.FindElementByAccessibilityId("GestureBorder"); - var lastGesture = _session.FindElementByAccessibilityId("LastGesture"); + var border = Session.FindElementByAccessibilityId("GestureBorder"); + var lastGesture = Session.FindElementByAccessibilityId("LastGesture"); - new Actions(_session).Click(border).Perform(); + new Actions(Session).Click(border).Perform(); Assert.Equal("Tapped", lastGesture.Text); } @@ -36,14 +29,14 @@ namespace Avalonia.IntegrationTests.Appium [Fact] public void Tapped_Is_Raised_Slow() { - var border = _session.FindElementByAccessibilityId("GestureBorder"); - var lastGesture = _session.FindElementByAccessibilityId("LastGesture"); + var border = Session.FindElementByAccessibilityId("GestureBorder"); + var lastGesture = Session.FindElementByAccessibilityId("LastGesture"); - new Actions(_session).ClickAndHold(border).Perform(); + new Actions(Session).ClickAndHold(border).Perform(); Thread.Sleep(2000); - new Actions(_session).Release(border).Perform(); + new Actions(Session).Release(border).Perform(); Assert.Equal("Tapped", lastGesture.Text); } @@ -51,10 +44,10 @@ namespace Avalonia.IntegrationTests.Appium [Fact] public void Tapped_Is_Not_Raised_For_Drag() { - var border = _session.FindElementByAccessibilityId("GestureBorder"); - var lastGesture = _session.FindElementByAccessibilityId("LastGesture"); + var border = Session.FindElementByAccessibilityId("GestureBorder"); + var lastGesture = Session.FindElementByAccessibilityId("LastGesture"); - new Actions(_session) + new Actions(Session) .ClickAndHold(border) .MoveByOffset(50, 50) .Release() @@ -66,10 +59,10 @@ namespace Avalonia.IntegrationTests.Appium [Fact] public void DoubleTapped_Is_Raised() { - var border = _session.FindElementByAccessibilityId("GestureBorder"); - var lastGesture = _session.FindElementByAccessibilityId("LastGesture"); + var border = Session.FindElementByAccessibilityId("GestureBorder"); + var lastGesture = Session.FindElementByAccessibilityId("LastGesture"); - new Actions(_session).DoubleClick(border).Perform(); + new Actions(Session).DoubleClick(border).Perform(); Assert.Equal("DoubleTapped", lastGesture.Text); } @@ -77,15 +70,15 @@ namespace Avalonia.IntegrationTests.Appium [PlatformFact(TestPlatforms.Windows | TestPlatforms.Linux)] public void DoubleTapped_Is_Raised_2() { - var border = _session.FindElementByAccessibilityId("GestureBorder"); - var lastGesture = _session.FindElementByAccessibilityId("LastGesture"); + var border = Session.FindElementByAccessibilityId("GestureBorder"); + var lastGesture = Session.FindElementByAccessibilityId("LastGesture"); - new Actions(_session).ClickAndHold(border).Release().Perform(); + new Actions(Session).ClickAndHold(border).Release().Perform(); Thread.Sleep(50); // DoubleTapped is raised on second pointer press, not release. - new Actions(_session).ClickAndHold(border).Perform(); + new Actions(Session).ClickAndHold(border).Perform(); try { @@ -94,21 +87,21 @@ namespace Avalonia.IntegrationTests.Appium finally { - new Actions(_session).MoveToElement(lastGesture).Release().Perform(); + new Actions(Session).MoveToElement(lastGesture).Release().Perform(); } } [Fact] public void DoubleTapped_Is_Raised_Not_Raised_If_Too_Slow() { - var border = _session.FindElementByAccessibilityId("GestureBorder"); - var lastGesture = _session.FindElementByAccessibilityId("LastGesture"); + var border = Session.FindElementByAccessibilityId("GestureBorder"); + var lastGesture = Session.FindElementByAccessibilityId("LastGesture"); - new Actions(_session).ClickAndHold(border).Release().Perform(); + new Actions(Session).ClickAndHold(border).Release().Perform(); Thread.Sleep(2000); - new Actions(_session).ClickAndHold(border).Release().Perform(); + new Actions(Session).ClickAndHold(border).Release().Perform(); Assert.Equal("Tapped", lastGesture.Text); } @@ -117,17 +110,17 @@ namespace Avalonia.IntegrationTests.Appium public void DoubleTapped_Is_Raised_After_Control_Changes() { // #8733 - var border = _session.FindElementByAccessibilityId("GestureBorder"); - var lastGesture = _session.FindElementByAccessibilityId("LastGesture"); + var border = Session.FindElementByAccessibilityId("GestureBorder"); + var lastGesture = Session.FindElementByAccessibilityId("LastGesture"); - new Actions(_session) + new Actions(Session) .MoveToElement(border) .DoubleClick() .Perform(); Thread.Sleep(100); - new Actions(_session).MoveToElement(lastGesture, 200, 200).DoubleClick().Perform(); + new Actions(Session).MoveToElement(lastGesture, 200, 200).DoubleClick().Perform(); Assert.Equal("DoubleTapped2", lastGesture.Text); } @@ -135,10 +128,10 @@ namespace Avalonia.IntegrationTests.Appium [Fact] public void RightTapped_Is_Raised() { - var border = _session.FindElementByAccessibilityId("GestureBorder"); - var lastGesture = _session.FindElementByAccessibilityId("LastGesture"); + var border = Session.FindElementByAccessibilityId("GestureBorder"); + var lastGesture = Session.FindElementByAccessibilityId("LastGesture"); - new Actions(_session).ContextClick(border).Perform(); + new Actions(Session).ContextClick(border).Perform(); Assert.Equal("RightTapped", lastGesture.Text); } @@ -146,8 +139,8 @@ namespace Avalonia.IntegrationTests.Appium [PlatformFact(TestPlatforms.MacOS)] public void RightTapped_Is_Raised_2() { - var border = _session.FindElementByAccessibilityId("GestureBorder"); - var lastGesture = _session.FindElementByAccessibilityId("LastGesture"); + var border = Session.FindElementByAccessibilityId("GestureBorder"); + var lastGesture = Session.FindElementByAccessibilityId("LastGesture"); var device = new PointerInputDevice(PointerKind.Mouse); var b = new ActionBuilder(); @@ -155,7 +148,7 @@ namespace Avalonia.IntegrationTests.Appium b.AddAction(device.CreatePointerDown(MouseButton.Right)); b.AddAction(device.CreatePointerMove(border, 52, 52, TimeSpan.FromMilliseconds(50))); b.AddAction(device.CreatePointerUp(MouseButton.Right)); - _session.PerformActions(b.ToActionSequenceList()); + Session.PerformActions(b.ToActionSequenceList()); Assert.Equal("RightTapped", lastGesture.Text); } @@ -163,8 +156,8 @@ namespace Avalonia.IntegrationTests.Appium [PlatformFact(TestPlatforms.MacOS)] public void RightTapped_Is_Not_Raised_For_Drag() { - var border = _session.FindElementByAccessibilityId("GestureBorder"); - var lastGesture = _session.FindElementByAccessibilityId("LastGesture"); + var border = Session.FindElementByAccessibilityId("GestureBorder"); + var lastGesture = Session.FindElementByAccessibilityId("LastGesture"); var device = new PointerInputDevice(PointerKind.Mouse); var b = new ActionBuilder(); diff --git a/tests/Avalonia.IntegrationTests.Appium/ListBoxTests.cs b/tests/Avalonia.IntegrationTests.Appium/ListBoxTests.cs index 24a02a7844..2291bcd433 100644 --- a/tests/Avalonia.IntegrationTests.Appium/ListBoxTests.cs +++ b/tests/Avalonia.IntegrationTests.Appium/ListBoxTests.cs @@ -7,17 +7,11 @@ using Xunit; namespace Avalonia.IntegrationTests.Appium { [Collection("Default")] - public class ListBoxTests + public class ListBoxTests : TestBase { - private readonly AppiumDriver _session; - public ListBoxTests(DefaultAppFixture fixture) + : base(fixture, "ListBox") { - _session = fixture.Session; - - var tabs = _session.FindElementByAccessibilityId("MainTabs"); - var tab = tabs.FindElementByName("ListBox"); - tab.Click(); } [Fact] @@ -49,7 +43,7 @@ namespace Avalonia.IntegrationTests.Appium Assert.False(item2.Selected); Assert.False(item4.Selected); - new Actions(_session) + new Actions(Session) .Click(item2) .KeyDown(Keys.Control) .Click(item4) @@ -73,7 +67,7 @@ namespace Avalonia.IntegrationTests.Appium Assert.False(item3.Selected); Assert.False(item4.Selected); - new Actions(_session) + new Actions(Session) .Click(item2) .KeyDown(Keys.Shift) .Click(item4) @@ -96,8 +90,8 @@ namespace Avalonia.IntegrationTests.Appium private AppiumWebElement GetTarget() { - _session.FindElementByAccessibilityId("ListBoxSelectionClear").Click(); - return _session.FindElementByAccessibilityId("BasicListBox"); + Session.FindElementByAccessibilityId("ListBoxSelectionClear").Click(); + return Session.FindElementByAccessibilityId("BasicListBox"); } } } diff --git a/tests/Avalonia.IntegrationTests.Appium/MenuTests.cs b/tests/Avalonia.IntegrationTests.Appium/MenuTests.cs index f9fa9312ee..6fd9505583 100644 --- a/tests/Avalonia.IntegrationTests.Appium/MenuTests.cs +++ b/tests/Avalonia.IntegrationTests.Appium/MenuTests.cs @@ -1,59 +1,50 @@ -using System.Threading; -using OpenQA.Selenium; -using OpenQA.Selenium.Appium; +using OpenQA.Selenium; using OpenQA.Selenium.Interactions; using Xunit; namespace Avalonia.IntegrationTests.Appium { [Collection("Default")] - public abstract class MenuTests + public abstract class MenuTests : TestBase { - private readonly AppiumDriver _session; - public MenuTests(DefaultAppFixture fixture) + : base(fixture, "Menu") { - _session = fixture.Session; - - var tabs = _session.FindElementByAccessibilityId("MainTabs"); - var tab = tabs.FindElementByName("Menu"); - tab.Click(); - - var reset = _session.FindElementByAccessibilityId("MenuClickedMenuItemReset"); + var reset = Session.FindElementByAccessibilityId("MenuClickedMenuItemReset"); reset.Click(); - var clickedMenuItem = _session.FindElementByAccessibilityId("ClickedMenuItem"); + var clickedMenuItem = Session.FindElementByAccessibilityId("ClickedMenuItem"); Assert.Equal("None", clickedMenuItem.Text); } [Fact] public void Click_Child() { - var rootMenuItem = _session.FindElementByAccessibilityId("RootMenuItem"); + var rootMenuItem = Session.FindElementByAccessibilityId("RootMenuItem"); rootMenuItem.SendClick(); - var childMenuItem = _session.FindElementByAccessibilityId("Child1MenuItem"); + var childMenuItem = Session.FindElementByAccessibilityId("Child1MenuItem"); childMenuItem.SendClick(); - var clickedMenuItem = _session.FindElementByAccessibilityId("ClickedMenuItem"); + var clickedMenuItem = Session.FindElementByAccessibilityId("ClickedMenuItem"); Assert.Equal("_Child 1", clickedMenuItem.Text); } [Fact] public void Click_Grandchild() { - var rootMenuItem = _session.FindElementByAccessibilityId("RootMenuItem"); + var rootMenuItem = Session.FindElementByAccessibilityId("RootMenuItem"); rootMenuItem.SendClick(); - var childMenuItem = _session.FindElementByAccessibilityId("Child2MenuItem"); + var childMenuItem = Session.FindElementByAccessibilityId("Child2MenuItem"); childMenuItem.SendClick(); - var grandchildMenuItem = _session.FindElementByAccessibilityId("GrandchildMenuItem"); + var grandchildMenuItem = Session.FindElementByAccessibilityId("GrandchildMenuItem"); grandchildMenuItem.SendClick(); - var clickedMenuItem = _session.FindElementByAccessibilityId("ClickedMenuItem"); + var clickedMenuItem = Session.FindElementByAccessibilityId("ClickedMenuItem"); Assert.Equal("_Grandchild", clickedMenuItem.Text); } @@ -62,12 +53,12 @@ namespace Avalonia.IntegrationTests.Appium { MovePointerOutOfTheWay(); - new Actions(_session) + new Actions(Session) .KeyDown(Keys.Alt).KeyUp(Keys.Alt) .SendKeys(Keys.Down + Keys.Enter) .Perform(); - var clickedMenuItem = _session.FindElementByAccessibilityId("ClickedMenuItem"); + var clickedMenuItem = Session.FindElementByAccessibilityId("ClickedMenuItem"); Assert.Equal("_Child 1", clickedMenuItem.Text); } @@ -76,12 +67,12 @@ namespace Avalonia.IntegrationTests.Appium { MovePointerOutOfTheWay(); - new Actions(_session) + new Actions(Session) .KeyDown(Keys.Alt).KeyUp(Keys.Alt) .SendKeys(Keys.Down + Keys.Down + Keys.Right + Keys.Enter) .Perform(); - var clickedMenuItem = _session.FindElementByAccessibilityId("ClickedMenuItem"); + var clickedMenuItem = Session.FindElementByAccessibilityId("ClickedMenuItem"); Assert.Equal("_Grandchild", clickedMenuItem.Text); } @@ -90,12 +81,12 @@ namespace Avalonia.IntegrationTests.Appium { MovePointerOutOfTheWay(); - new Actions(_session) + new Actions(Session) .KeyDown(Keys.Alt).KeyUp(Keys.Alt) .SendKeys("rc") .Perform(); - var clickedMenuItem = _session.FindElementByAccessibilityId("ClickedMenuItem"); + var clickedMenuItem = Session.FindElementByAccessibilityId("ClickedMenuItem"); Assert.Equal("_Child 1", clickedMenuItem.Text); } @@ -104,55 +95,55 @@ namespace Avalonia.IntegrationTests.Appium { MovePointerOutOfTheWay(); - new Actions(_session) + new Actions(Session) .KeyDown(Keys.Alt).KeyUp(Keys.Alt) .SendKeys("rhg") .Perform(); - var clickedMenuItem = _session.FindElementByAccessibilityId("ClickedMenuItem"); + var clickedMenuItem = Session.FindElementByAccessibilityId("ClickedMenuItem"); Assert.Equal("_Grandchild", clickedMenuItem.Text); } [PlatformFact(TestPlatforms.Windows)] public void Select_Child_With_Click_Arrow_Keys() { - var rootMenuItem = _session.FindElementByAccessibilityId("RootMenuItem"); + var rootMenuItem = Session.FindElementByAccessibilityId("RootMenuItem"); rootMenuItem.SendClick(); MovePointerOutOfTheWay(); - new Actions(_session) + new Actions(Session) .SendKeys(Keys.Down + Keys.Enter) .Perform(); - var clickedMenuItem = _session.FindElementByAccessibilityId("ClickedMenuItem"); + var clickedMenuItem = Session.FindElementByAccessibilityId("ClickedMenuItem"); Assert.Equal("_Child 1", clickedMenuItem.Text); } [PlatformFact(TestPlatforms.Windows)] public void Select_Grandchild_With_Click_Arrow_Keys() { - var rootMenuItem = _session.FindElementByAccessibilityId("RootMenuItem"); + var rootMenuItem = Session.FindElementByAccessibilityId("RootMenuItem"); rootMenuItem.SendClick(); MovePointerOutOfTheWay(); - new Actions(_session) + new Actions(Session) .SendKeys(Keys.Down + Keys.Down + Keys.Right + Keys.Enter) .Perform(); - var clickedMenuItem = _session.FindElementByAccessibilityId("ClickedMenuItem"); + var clickedMenuItem = Session.FindElementByAccessibilityId("ClickedMenuItem"); Assert.Equal("_Grandchild", clickedMenuItem.Text); } [PlatformFact(TestPlatforms.Windows)] public void Child_AcceleratorKey() { - var rootMenuItem = _session.FindElementByAccessibilityId("RootMenuItem"); + var rootMenuItem = Session.FindElementByAccessibilityId("RootMenuItem"); rootMenuItem.SendClick(); - var childMenuItem = _session.FindElementByAccessibilityId("Child1MenuItem"); + var childMenuItem = Session.FindElementByAccessibilityId("Child1MenuItem"); Assert.Equal("Ctrl+O", childMenuItem.GetAttribute("AcceleratorKey")); } @@ -161,12 +152,12 @@ namespace Avalonia.IntegrationTests.Appium public void PointerOver_Does_Not_Steal_Focus() { // Issue #7906 - var textBox = _session.FindElementByAccessibilityId("MenuFocusTest"); + var textBox = Session.FindElementByAccessibilityId("MenuFocusTest"); textBox.Click(); Assert.True(textBox.GetIsFocused()); - var rootMenuItem = _session.FindElementByAccessibilityId("RootMenuItem"); + var rootMenuItem = Session.FindElementByAccessibilityId("RootMenuItem"); rootMenuItem.MovePointerOver(); Assert.True(textBox.GetIsFocused()); @@ -175,9 +166,9 @@ namespace Avalonia.IntegrationTests.Appium private void MovePointerOutOfTheWay() { // Move the pointer to the menu tab item so that it's not over the menu in preparation - // for key press tests. This prevents the mouse accidentially selecting the wrong item + // for key press tests. This prevents the mouse accidentally selecting the wrong item // by hovering. - var tabs = _session.FindElementByAccessibilityId("MainTabs"); + var tabs = Session.FindElementByAccessibilityId("Pager"); var tab = tabs.FindElementByName("Menu"); tab.MovePointerOver(); } diff --git a/tests/Avalonia.IntegrationTests.Appium/NativeMenuTests.cs b/tests/Avalonia.IntegrationTests.Appium/NativeMenuTests.cs index ec4f9d705d..2406ff5958 100644 --- a/tests/Avalonia.IntegrationTests.Appium/NativeMenuTests.cs +++ b/tests/Avalonia.IntegrationTests.Appium/NativeMenuTests.cs @@ -1,29 +1,22 @@ using System.Threading; -using OpenQA.Selenium.Appium; using Xunit; namespace Avalonia.IntegrationTests.Appium { [Collection("Default")] - public class NativeMenuTests + public class NativeMenuTests : TestBase { - private readonly AppiumDriver _session; - public NativeMenuTests(DefaultAppFixture fixture) + : base(fixture, "Automation") { - _session = fixture.Session; - - var tabs = _session.FindElementByAccessibilityId("MainTabs"); - var tab = tabs.FindElementByName("Automation"); - tab.Click(); } [PlatformFact(TestPlatforms.MacOS)] public void MacOS_View_Menu_Select_Button_Tab() { - var tabs = _session.FindElementByAccessibilityId("MainTabs"); + var tabs = Session.FindElementByAccessibilityId("Pager"); var buttonTab = tabs.FindElementByName("Button"); - var menuBar = _session.FindElementByXPath("/XCUIElementTypeApplication/XCUIElementTypeMenuBar"); + var menuBar = Session.FindElementByXPath("/XCUIElementTypeApplication/XCUIElementTypeMenuBar"); var viewMenu = menuBar.FindElementByName("View"); Assert.False(buttonTab.Selected); @@ -38,9 +31,9 @@ namespace Avalonia.IntegrationTests.Appium [PlatformFact(TestPlatforms.Windows)] public void Win32_View_Menu_Select_Button_Tab() { - var tabs = _session.FindElementByAccessibilityId("MainTabs"); + var tabs = Session.FindElementByAccessibilityId("Pager"); var buttonTab = tabs.FindElementByName("Button"); - var viewMenu = _session.FindElementByXPath("//MenuItem[@Name='View']"); + var viewMenu = Session.FindElementByXPath("//MenuItem[@Name='View']"); Assert.False(buttonTab.Selected); @@ -54,7 +47,7 @@ namespace Avalonia.IntegrationTests.Appium [PlatformFact(TestPlatforms.MacOS)] public void MacOS_Sanitizes_Access_Key_Markers_When_Included_In_Menu_Title() { - var menuBar = _session.FindElementByXPath("/XCUIElementTypeApplication/XCUIElementTypeMenuBar"); + var menuBar = Session.FindElementByXPath("/XCUIElementTypeApplication/XCUIElementTypeMenuBar"); Assert.True(menuBar.FindElementsByName("_Options").Count == 0); Assert.True(menuBar.FindElementsByName("Options").Count == 1); @@ -63,7 +56,7 @@ namespace Avalonia.IntegrationTests.Appium [PlatformFact(TestPlatforms.Windows)] public void Win32_Avalonia_Menu_Has_ToolTip_If_Defined() { - var viewMenu = _session.FindElementByXPath("//MenuItem[@Name='View']"); + var viewMenu = Session.FindElementByXPath("//MenuItem[@Name='View']"); viewMenu.Click(); var buttonMenuItem = viewMenu.FindElementByName("Button"); @@ -72,14 +65,14 @@ namespace Avalonia.IntegrationTests.Appium // Wait for tooltip to open. Thread.Sleep(2000); - var toolTipCandidates = _session.FindElementsByClassName("TextBlock"); + var toolTipCandidates = Session.FindElementsByClassName("TextBlock"); Assert.Contains(toolTipCandidates, x => x.Text == "Tip:Button"); } [PlatformFact(TestPlatforms.MacOS, Skip = "Flaky test")] public void MacOS_Native_Menu_Has_ToolTip_If_Defined() { - var menuBar = _session.FindElementByXPath("/XCUIElementTypeApplication/XCUIElementTypeMenuBar"); + var menuBar = Session.FindElementByXPath("/XCUIElementTypeApplication/XCUIElementTypeMenuBar"); var viewMenu = menuBar.FindElementByName("View"); viewMenu.Click(); @@ -89,7 +82,7 @@ namespace Avalonia.IntegrationTests.Appium // Wait for tooltip to open. Thread.Sleep(4000); - var toolTipCandidates = _session.FindElementsByClassName("XCUIElementTypeStaticText"); + var toolTipCandidates = Session.FindElementsByClassName("XCUIElementTypeStaticText"); Assert.Contains(toolTipCandidates, x => x.Text == "Tip:Button"); } } diff --git a/tests/Avalonia.IntegrationTests.Appium/RadioButtonTests.cs b/tests/Avalonia.IntegrationTests.Appium/RadioButtonTests.cs index c58c57bddc..d949eb635d 100644 --- a/tests/Avalonia.IntegrationTests.Appium/RadioButtonTests.cs +++ b/tests/Avalonia.IntegrationTests.Appium/RadioButtonTests.cs @@ -4,23 +4,17 @@ using Xunit; namespace Avalonia.IntegrationTests.Appium { [Collection("Default")] - public class RadioButtonTests + public class RadioButtonTests : TestBase { - private readonly AppiumDriver _session; - public RadioButtonTests(DefaultAppFixture fixture) + : base(fixture, "RadioButton") { - _session = fixture.Session; - - var tabs = _session.FindElementByAccessibilityId("MainTabs"); - tabs.FindElementByName("RadioButton").Click(); } - [Fact] public void RadioButton_IsChecked_True_When_Clicked() { - var button = _session.FindElementByAccessibilityId("BasicRadioButton"); + var button = Session.FindElementByAccessibilityId("BasicRadioButton"); Assert.False(button.GetIsChecked()); button.Click(); Assert.True(button.GetIsChecked()); @@ -29,8 +23,8 @@ namespace Avalonia.IntegrationTests.Appium [Fact] public void ThreeState_RadioButton_IsChecked_False_When_Other_ThreeState_RadioButton_Checked() { - var button1 = _session.FindElementByAccessibilityId("ThreeStatesRadioButton1"); - var button2 = _session.FindElementByAccessibilityId("ThreeStatesRadioButton2"); + var button1 = Session.FindElementByAccessibilityId("ThreeStatesRadioButton1"); + var button2 = Session.FindElementByAccessibilityId("ThreeStatesRadioButton2"); Assert.True(button1.GetIsChecked()); Assert.False(button2.GetIsChecked()); button2.Click(); diff --git a/tests/Avalonia.IntegrationTests.Appium/ScrollBarTests.cs b/tests/Avalonia.IntegrationTests.Appium/ScrollBarTests.cs index 1a285c5ce6..1e1748facf 100644 --- a/tests/Avalonia.IntegrationTests.Appium/ScrollBarTests.cs +++ b/tests/Avalonia.IntegrationTests.Appium/ScrollBarTests.cs @@ -4,23 +4,17 @@ using Xunit; namespace Avalonia.IntegrationTests.Appium { [Collection("Default")] - public class ScrollBarTests + public class ScrollBarTests : TestBase { - private readonly AppiumDriver _session; - public ScrollBarTests(DefaultAppFixture fixture) + : base(fixture, "ScrollBar") { - _session = fixture.Session; - - var tabs = _session.FindElementByAccessibilityId("MainTabs"); - var tab = tabs.FindElementByName("ScrollBar"); - tab.Click(); } [Fact] public void ScrollBar_Increases_Value_By_LargeChange_When_IncreaseButton_Is_Clicked() { - var button = _session.FindElementByAccessibilityId("MyScrollBar"); + var button = Session.FindElementByAccessibilityId("MyScrollBar"); Assert.True(double.Parse(button.Text) == 20); button.Click(); diff --git a/tests/Avalonia.IntegrationTests.Appium/SliderTests.cs b/tests/Avalonia.IntegrationTests.Appium/SliderTests.cs index 1eede63aae..0cec55ad63 100644 --- a/tests/Avalonia.IntegrationTests.Appium/SliderTests.cs +++ b/tests/Avalonia.IntegrationTests.Appium/SliderTests.cs @@ -7,34 +7,27 @@ using Xunit; namespace Avalonia.IntegrationTests.Appium { [Collection("Default")] - public class SliderTests + public class SliderTests : TestBase { - private readonly AppiumDriver _session; - public SliderTests(DefaultAppFixture fixture) + : base(fixture, "Slider") { - _session = fixture.Session; - - var tabs = _session.FindElementByAccessibilityId("MainTabs"); - var tab = tabs.FindElementByName("Slider"); - tab.Click(); - - var reset = _session.FindElementByAccessibilityId("ResetSliders"); + var reset = Session.FindElementByAccessibilityId("ResetSliders"); reset.Click(); } [Fact] public void Horizontal_Changes_Value_Dragging_Thumb_Right() { - var slider = _session.FindElementByAccessibilityId("HorizontalSlider"); + var slider = Session.FindElementByAccessibilityId("HorizontalSlider"); var thumb = slider.FindElementByAccessibilityId("thumb"); var initialThumbRect = thumb.Rect; - new Actions(_session).ClickAndHold(thumb).MoveByOffset(100, 0).Release().Perform(); + new Actions(Session).ClickAndHold(thumb).MoveByOffset(100, 0).Release().Perform(); var value = Math.Round(double.Parse(slider.Text, CultureInfo.InvariantCulture)); var boundValue = double.Parse( - _session.FindElementByAccessibilityId("HorizontalSliderValue").Text, + Session.FindElementByAccessibilityId("HorizontalSliderValue").Text, CultureInfo.InvariantCulture); Assert.True(value > 50); @@ -47,15 +40,15 @@ namespace Avalonia.IntegrationTests.Appium [Fact] public void Horizontal_Changes_Value_Dragging_Thumb_Left() { - var slider = _session.FindElementByAccessibilityId("HorizontalSlider"); + var slider = Session.FindElementByAccessibilityId("HorizontalSlider"); var thumb = slider.FindElementByAccessibilityId("thumb"); var initialThumbRect = thumb.Rect; - new Actions(_session).ClickAndHold(thumb).MoveByOffset(-100, 0).Release().Perform(); + new Actions(Session).ClickAndHold(thumb).MoveByOffset(-100, 0).Release().Perform(); var value = Math.Round(double.Parse(slider.Text, CultureInfo.InvariantCulture)); var boundValue = double.Parse( - _session.FindElementByAccessibilityId("HorizontalSliderValue").Text, + Session.FindElementByAccessibilityId("HorizontalSliderValue").Text, CultureInfo.InvariantCulture); Assert.True(value < 50); @@ -68,15 +61,15 @@ namespace Avalonia.IntegrationTests.Appium [Fact] public void Horizontal_Changes_Value_When_Clicking_Increase_Button() { - var slider = _session.FindElementByAccessibilityId("HorizontalSlider"); + var slider = Session.FindElementByAccessibilityId("HorizontalSlider"); var thumb = slider.FindElementByAccessibilityId("thumb"); var initialThumbRect = thumb.Rect; - new Actions(_session).MoveToElementCenter(slider, 100, 0).Click().Perform(); + new Actions(Session).MoveToElementCenter(slider, 100, 0).Click().Perform(); var value = Math.Round(double.Parse(slider.Text, CultureInfo.InvariantCulture)); var boundValue = double.Parse( - _session.FindElementByAccessibilityId("HorizontalSliderValue").Text, + Session.FindElementByAccessibilityId("HorizontalSliderValue").Text, CultureInfo.InvariantCulture); Assert.True(value > 50); @@ -89,15 +82,15 @@ namespace Avalonia.IntegrationTests.Appium [Fact] public void Horizontal_Changes_Value_When_Clicking_Decrease_Button() { - var slider = _session.FindElementByAccessibilityId("HorizontalSlider"); + var slider = Session.FindElementByAccessibilityId("HorizontalSlider"); var thumb = slider.FindElementByAccessibilityId("thumb"); var initialThumbRect = thumb.Rect; - new Actions(_session).MoveToElementCenter(slider, -100, 0).Click().Perform(); + new Actions(Session).MoveToElementCenter(slider, -100, 0).Click().Perform(); var value = Math.Round(double.Parse(slider.Text, CultureInfo.InvariantCulture)); var boundValue = double.Parse( - _session.FindElementByAccessibilityId("HorizontalSliderValue").Text, + Session.FindElementByAccessibilityId("HorizontalSliderValue").Text, CultureInfo.InvariantCulture); Assert.True(value < 50); diff --git a/tests/Avalonia.IntegrationTests.Appium/TestBase.cs b/tests/Avalonia.IntegrationTests.Appium/TestBase.cs new file mode 100644 index 0000000000..5306d71c8f --- /dev/null +++ b/tests/Avalonia.IntegrationTests.Appium/TestBase.cs @@ -0,0 +1,33 @@ +using OpenQA.Selenium; +using System.Threading; + +namespace Avalonia.IntegrationTests.Appium; + +public class TestBase +{ + protected TestBase(DefaultAppFixture fixture, string pageName) + { + Session = fixture.Session; + + var retry = 0; + + for (;;) + { + try + { + var pager = Session.FindElementByAccessibilityId("Pager"); + var page = pager.FindElementByName(pageName); + page.Click(); + break; + } + catch (WebDriverException) when (retry++ < 3) + { + // MacOS sometimes seems to need a bit of time to get itself back in order after switching out + // of fullscreen. + Thread.Sleep(1000); + } + } + } + + protected AppiumDriver Session { get; } +} diff --git a/tests/Avalonia.IntegrationTests.Appium/WindowTests.cs b/tests/Avalonia.IntegrationTests.Appium/WindowTests.cs index e172980981..67ac84b2a6 100644 --- a/tests/Avalonia.IntegrationTests.Appium/WindowTests.cs +++ b/tests/Avalonia.IntegrationTests.Appium/WindowTests.cs @@ -13,17 +13,11 @@ using Xunit.Sdk; namespace Avalonia.IntegrationTests.Appium { [Collection("Default")] - public class WindowTests + public class WindowTests : TestBase { - private readonly AppiumDriver _session; - public WindowTests(DefaultAppFixture fixture) + : base(fixture, "Window") { - _session = fixture.Session; - - var tabs = _session.FindElementByAccessibilityId("MainTabs"); - var tab = tabs.FindElementByName("Window"); - tab.Click(); } [Theory] @@ -90,8 +84,8 @@ namespace Avalonia.IntegrationTests.Appium { try { - _session.FindElementByAccessibilityId("CurrentWindowState").SendClick(); - _session.FindElementByAccessibilityId("WindowStateNormal").SendClick(); + Session.FindElementByAccessibilityId("CurrentWindowState").SendClick(); + Session.FindElementByAccessibilityId("WindowStateNormal").SendClick(); // Wait for animations to run. if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) @@ -110,14 +104,14 @@ namespace Avalonia.IntegrationTests.Appium { using (OpenWindow(new Size(400, 400), ShowWindowMode.NonOwned, WindowStartupLocation.Manual)) { - var windowState = _session.FindElementByAccessibilityId("CurrentWindowState"); + var windowState = Session.FindElementByAccessibilityId("CurrentWindowState"); Assert.Equal("Normal", windowState.GetComboBoxValue()); - var window = _session.FindElements(By.XPath("//Window")).First(); + var window = Session.FindElements(By.XPath("//Window")).First(); - new Actions(_session) + new Actions(Session) .KeyDown(Keys.Meta) .SendKeys(Keys.Left) .KeyUp(Keys.Meta) @@ -126,9 +120,9 @@ namespace Avalonia.IntegrationTests.Appium var original = GetWindowInfo(); windowState.Click(); - _session.FindElementByName("Minimized").SendClick(); + Session.FindElementByName("Minimized").SendClick(); - new Actions(_session) + new Actions(Session) .KeyDown(Keys.Alt) .SendKeys(Keys.Tab) .KeyUp(Keys.Alt) @@ -147,8 +141,8 @@ namespace Avalonia.IntegrationTests.Appium { using (OpenWindow(new Size(4000, 2200), ShowWindowMode.NonOwned, WindowStartupLocation.Manual)) { - var screenRectTextBox = _session.FindElementByAccessibilityId("CurrentClientSize"); - var measuredWithTextBlock = _session.FindElementByAccessibilityId("CurrentMeasuredWithText"); + var screenRectTextBox = Session.FindElementByAccessibilityId("CurrentClientSize"); + var measuredWithTextBlock = Session.FindElementByAccessibilityId("CurrentMeasuredWithText"); var measuredWithString = measuredWithTextBlock.Text; var workingAreaString = screenRectTextBox.Text; @@ -167,17 +161,17 @@ namespace Avalonia.IntegrationTests.Appium public void ShowMode(ShowWindowMode mode) { using var window = OpenWindow(null, mode, WindowStartupLocation.Manual); - var windowState = _session.FindElementByAccessibilityId("CurrentWindowState"); + var windowState = Session.FindElementByAccessibilityId("CurrentWindowState"); var original = GetWindowInfo(); Assert.Equal("Normal", windowState.GetComboBoxValue()); windowState.Click(); - _session.FindElementByAccessibilityId("WindowStateMaximized").SendClick(); + Session.FindElementByAccessibilityId("WindowStateMaximized").SendClick(); Assert.Equal("Maximized", windowState.GetComboBoxValue()); windowState.Click(); - _session.FindElementByAccessibilityId("WindowStateNormal").SendClick(); + Session.FindElementByAccessibilityId("WindowStateNormal").SendClick(); var current = GetWindowInfo(); Assert.Equal(original.Position, current.Position); @@ -187,7 +181,7 @@ namespace Avalonia.IntegrationTests.Appium if (!RuntimeInformation.IsOSPlatform(OSPlatform.OSX) || mode == ShowWindowMode.NonOwned) { windowState.Click(); - _session.FindElementByAccessibilityId("WindowStateFullScreen").SendClick(); + Session.FindElementByAccessibilityId("WindowStateFullScreen").SendClick(); Assert.Equal("FullScreen", windowState.GetComboBoxValue()); current = GetWindowInfo(); @@ -197,7 +191,7 @@ namespace Avalonia.IntegrationTests.Appium windowState.SendClick(); - _session.FindElementByAccessibilityId("WindowStateNormal").SendClick(); + Session.FindElementByAccessibilityId("WindowStateNormal").SendClick(); current = GetWindowInfo(); Assert.Equal(original.Position, current.Position); @@ -210,7 +204,7 @@ namespace Avalonia.IntegrationTests.Appium { var clientSize = new Size(400, 400); using var window = OpenWindow(clientSize, ShowWindowMode.NonOwned, WindowStartupLocation.CenterScreen, extendClientArea: true); - var windowState = _session.FindElementByAccessibilityId("CurrentWindowState"); + var windowState = Session.FindElementByAccessibilityId("CurrentWindowState"); var current = GetWindowInfo(); Assert.Equal(current.ClientSize, clientSize); @@ -219,11 +213,11 @@ namespace Avalonia.IntegrationTests.Appium [Fact] public void TransparentWindow() { - var showTransparentWindow = _session.FindElementByAccessibilityId("ShowTransparentWindow"); + var showTransparentWindow = Session.FindElementByAccessibilityId("ShowTransparentWindow"); showTransparentWindow.Click(); Thread.Sleep(1000); - var window = _session.FindElementByAccessibilityId("TransparentWindow"); + var window = Session.FindElementByAccessibilityId("TransparentWindow"); var screenshot = window.GetScreenshot(); window.Click(); @@ -239,11 +233,11 @@ namespace Avalonia.IntegrationTests.Appium [Fact] public void TransparentPopup() { - var showTransparentWindow = _session.FindElementByAccessibilityId("ShowTransparentPopup"); + var showTransparentWindow = Session.FindElementByAccessibilityId("ShowTransparentPopup"); showTransparentWindow.Click(); Thread.Sleep(1000); - var window = _session.FindElementByAccessibilityId("TransparentPopupBackground"); + var window = Session.FindElementByAccessibilityId("TransparentPopupBackground"); var container = window.FindElementByAccessibilityId("PopupContainer"); var screenshot = container.GetScreenshot(); @@ -268,7 +262,7 @@ namespace Avalonia.IntegrationTests.Appium { using (OpenWindow(null, mode, WindowStartupLocation.Manual, canResize: false, extendClientArea: extendClientArea)) { - var secondaryWindow = GetWindow("SecondaryWindow"); + var secondaryWindow = Session.GetWindowById("SecondaryWindow"); AppiumWebElement? maximizeButton; if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) @@ -375,13 +369,13 @@ namespace Avalonia.IntegrationTests.Appium bool canResize = true, bool extendClientArea = false) { - var sizeTextBox = _session.FindElementByAccessibilityId("ShowWindowSize"); - var modeComboBox = _session.FindElementByAccessibilityId("ShowWindowMode"); - var locationComboBox = _session.FindElementByAccessibilityId("ShowWindowLocation"); - var stateComboBox = _session.FindElementByAccessibilityId("ShowWindowState"); - var canResizeCheckBox = _session.FindElementByAccessibilityId("ShowWindowCanResize"); - var showButton = _session.FindElementByAccessibilityId("ShowWindow"); - var extendClientAreaCheckBox = _session.FindElementByAccessibilityId("ShowWindowExtendClientAreaToDecorationsHint"); + var sizeTextBox = Session.FindElementByAccessibilityId("ShowWindowSize"); + var modeComboBox = Session.FindElementByAccessibilityId("ShowWindowMode"); + var locationComboBox = Session.FindElementByAccessibilityId("ShowWindowLocation"); + var stateComboBox = Session.FindElementByAccessibilityId("ShowWindowState"); + var canResizeCheckBox = Session.FindElementByAccessibilityId("ShowWindowCanResize"); + var showButton = Session.FindElementByAccessibilityId("ShowWindow"); + var extendClientAreaCheckBox = Session.FindElementByAccessibilityId("ShowWindowExtendClientAreaToDecorationsHint"); if (size.HasValue) sizeTextBox.SendKeys($"{size.Value.Width}, {size.Value.Height}"); @@ -389,19 +383,19 @@ namespace Avalonia.IntegrationTests.Appium if (modeComboBox.GetComboBoxValue() != mode.ToString()) { modeComboBox.Click(); - _session.FindElementByName(mode.ToString()).SendClick(); + Session.FindElementByName(mode.ToString()).SendClick(); } if (locationComboBox.GetComboBoxValue() != location.ToString()) { locationComboBox.Click(); - _session.FindElementByName(location.ToString()).SendClick(); + Session.FindElementByName(location.ToString()).SendClick(); } if (stateComboBox.GetComboBoxValue() != state.ToString()) { stateComboBox.Click(); - _session.FindElementByAccessibilityId($"ShowWindowState{state}").SendClick(); + Session.FindElementByAccessibilityId($"ShowWindowState{state}").SendClick(); } if (canResizeCheckBox.GetIsChecked() != canResize) @@ -432,7 +426,7 @@ namespace Avalonia.IntegrationTests.Appium { PixelRect? ReadOwnerRect() { - var text = _session.FindElementByAccessibilityId("CurrentOwnerRect").Text; + var text = Session.FindElementByAccessibilityId("CurrentOwnerRect").Text; return !string.IsNullOrWhiteSpace(text) ? PixelRect.Parse(text) : null; } @@ -443,13 +437,13 @@ namespace Avalonia.IntegrationTests.Appium try { return new( - Size.Parse(_session.FindElementByAccessibilityId("CurrentClientSize").Text), - Size.Parse(_session.FindElementByAccessibilityId("CurrentFrameSize").Text), - PixelPoint.Parse(_session.FindElementByAccessibilityId("CurrentPosition").Text), + Size.Parse(Session.FindElementByAccessibilityId("CurrentClientSize").Text), + Size.Parse(Session.FindElementByAccessibilityId("CurrentFrameSize").Text), + PixelPoint.Parse(Session.FindElementByAccessibilityId("CurrentPosition").Text), ReadOwnerRect(), - PixelRect.Parse(_session.FindElementByAccessibilityId("CurrentScreenRect").Text), - double.Parse(_session.FindElementByAccessibilityId("CurrentScaling").Text), - Enum.Parse(_session.FindElementByAccessibilityId("CurrentWindowState").Text)); + PixelRect.Parse(Session.FindElementByAccessibilityId("CurrentScreenRect").Text), + double.Parse(Session.FindElementByAccessibilityId("CurrentScaling").Text), + Enum.Parse(Session.FindElementByAccessibilityId("CurrentWindowState").Text)); } catch (OpenQA.Selenium.NoSuchElementException) when (retry++ < 3) { diff --git a/tests/Avalonia.IntegrationTests.Appium/WindowTests_MacOS.cs b/tests/Avalonia.IntegrationTests.Appium/WindowTests_MacOS.cs index 53a41f5d46..ed57f9bed1 100644 --- a/tests/Avalonia.IntegrationTests.Appium/WindowTests_MacOS.cs +++ b/tests/Avalonia.IntegrationTests.Appium/WindowTests_MacOS.cs @@ -1,10 +1,7 @@ using System; -using System.Collections.Generic; using System.Linq; using System.Threading; using Avalonia.Controls; -using Avalonia.Utilities; -using OpenQA.Selenium; using OpenQA.Selenium.Appium; using OpenQA.Selenium.Interactions; using Xunit; @@ -12,39 +9,17 @@ using Xunit; namespace Avalonia.IntegrationTests.Appium { [Collection("Default")] - public class WindowTests_MacOS + public class WindowTests_MacOS : TestBase { - private readonly AppiumDriver _session; - public WindowTests_MacOS(DefaultAppFixture fixture) + : base(fixture, "Window") { - var retry = 0; - - _session = fixture.Session; - - for (;;) - { - try - { - var tabs = _session.FindElementByAccessibilityId("MainTabs"); - var tab = tabs.FindElementByName("Window"); - tab.Click(); - return; - } - catch (WebDriverException) when (retry++ < 3) - { - // MacOS sometimes seems to need a bit of time to get itself back in order after switching out - // of fullscreen. - Thread.Sleep(1000); - } - } - } [PlatformFact(TestPlatforms.MacOS)] public void WindowOrder_Modal_Dialog_Stays_InFront_Of_Parent() { - var mainWindow = _session.FindElementByAccessibilityId("MainWindow"); + var mainWindow = Session.FindElementByAccessibilityId("MainWindow"); using (OpenWindow(new PixelSize(200, 100), ShowWindowMode.Modal, WindowStartupLocation.Manual)) { @@ -63,14 +38,14 @@ namespace Avalonia.IntegrationTests.Appium using (OpenWindow(new PixelSize(200, 100), ShowWindowMode.Modal, WindowStartupLocation.Manual)) { - new Actions(_session) + new Actions(Session) .MoveToElement(mainWindow, 100, 1) .ClickAndHold() .Perform(); var secondaryWindowIndex = GetWindowOrder("SecondaryWindow"); - new Actions(_session) + new Actions(Session) .MoveToElement(mainWindow, 100, 1) .Release() .Perform(); @@ -99,14 +74,14 @@ namespace Avalonia.IntegrationTests.Appium } finally { - _session.FindElementByAccessibilityId("ExitFullscreen").Click(); + Session.FindElementByAccessibilityId("ExitFullscreen").Click(); } } [PlatformFact(TestPlatforms.MacOS)] public void WindowOrder_Owned_Dialog_Stays_InFront_Of_Parent() { - var mainWindow = _session.FindElementByAccessibilityId("MainWindow"); + var mainWindow = Session.FindElementByAccessibilityId("MainWindow"); using (OpenWindow(new PixelSize(200, 100), ShowWindowMode.Owned, WindowStartupLocation.Manual)) { @@ -119,7 +94,7 @@ namespace Avalonia.IntegrationTests.Appium [PlatformFact(TestPlatforms.MacOS)] public void WindowOrder_Owned_Dialog_Stays_InFront_Of_FullScreen_Parent() { - var mainWindow = _session.FindElementByAccessibilityId("MainWindow"); + var mainWindow = Session.FindElementByAccessibilityId("MainWindow"); // Enter fullscreen mainWindow.FindElementByAccessibilityId("EnterFullscreen").Click(); @@ -146,7 +121,7 @@ namespace Avalonia.IntegrationTests.Appium Thread.Sleep(1000); // Make sure we exited fullscreen. - mainWindow = _session.FindElementByAccessibilityId("MainWindow"); + mainWindow = Session.FindElementByAccessibilityId("MainWindow"); windowState = mainWindow.FindElementByAccessibilityId("MainWindowState"); Assert.Equal("Normal", windowState.Text); } @@ -167,7 +142,7 @@ namespace Avalonia.IntegrationTests.Appium public void Does_Not_Switch_Space_From_FullScreen_To_Main_Desktop_When_FullScreen_Window_Clicked() { // Issue #9565 - var mainWindow = _session.FindElementByAccessibilityId("MainWindow"); + var mainWindow = Session.FindElementByAccessibilityId("MainWindow"); AppiumWebElement windowState; // Open child window. @@ -180,7 +155,7 @@ namespace Avalonia.IntegrationTests.Appium Thread.Sleep(1000); // Make sure we entered fullscreen. - mainWindow = _session.FindElementByAccessibilityId("MainWindow"); + mainWindow = Session.FindElementByAccessibilityId("MainWindow"); windowState = mainWindow.FindElementByAccessibilityId("MainWindowState"); Assert.Equal("FullScreen", windowState.Text); @@ -196,7 +171,7 @@ namespace Avalonia.IntegrationTests.Appium } // Make sure we exited fullscreen. - mainWindow = _session.FindElementByAccessibilityId("MainWindow"); + mainWindow = Session.FindElementByAccessibilityId("MainWindow"); windowState = mainWindow.FindElementByAccessibilityId("MainWindowState"); Assert.Equal("Normal", windowState.Text); } @@ -204,7 +179,7 @@ namespace Avalonia.IntegrationTests.Appium [PlatformFact(TestPlatforms.MacOS)] public void WindowOrder_NonOwned_Window_Does_Not_Stay_InFront_Of_Parent() { - var mainWindow = _session.FindElementByAccessibilityId("MainWindow"); + var mainWindow = Session.FindElementByAccessibilityId("MainWindow"); using (OpenWindow(new PixelSize(800, 100), ShowWindowMode.NonOwned, WindowStartupLocation.Manual)) { @@ -214,7 +189,7 @@ namespace Avalonia.IntegrationTests.Appium Assert.Equal(2, secondaryWindowIndex); - var sendToBack = _session.FindElementByAccessibilityId("SendToBack"); + var sendToBack = Session.FindElementByAccessibilityId("SendToBack"); sendToBack.Click(); } } @@ -294,14 +269,14 @@ namespace Avalonia.IntegrationTests.Appium miniaturizeButton.Click(); Thread.Sleep(1000); - var hittable = _session.FindElementsByXPath("/XCUIElementTypeApplication/XCUIElementTypeWindow") + var hittable = Session.FindElementsByXPath("/XCUIElementTypeApplication/XCUIElementTypeWindow") .Select(x => x.GetAttribute("hittable")).ToList(); Assert.Equal(new[] { "true", "false" }, hittable); - _session.FindElementByAccessibilityId("RestoreAll").Click(); + Session.FindElementByAccessibilityId("RestoreAll").Click(); Thread.Sleep(1000); - hittable = _session.FindElementsByXPath("/XCUIElementTypeApplication/XCUIElementTypeWindow") + hittable = Session.FindElementsByXPath("/XCUIElementTypeApplication/XCUIElementTypeWindow") .Select(x => x.GetAttribute("hittable")).ToList(); Assert.Equal(new[] { "true", "true" }, hittable); } @@ -310,7 +285,7 @@ namespace Avalonia.IntegrationTests.Appium [PlatformFact(TestPlatforms.MacOS)] public void Hidden_Child_Window_Is_Not_Reshown_When_Parent_Clicked() { - var mainWindow = _session.FindElementByAccessibilityId("MainWindow"); + var mainWindow = Session.FindElementByAccessibilityId("MainWindow"); // We don't use dispose to close the window here, because it seems that hiding and re-showing a window // causes Appium to think it's a different window. @@ -321,15 +296,15 @@ namespace Avalonia.IntegrationTests.Appium hideButton.Click(); - var windows = _session.FindElementsByXPath("XCUIElementTypeWindow"); + var windows = Session.FindElementsByXPath("XCUIElementTypeWindow"); Assert.Single(windows); mainWindow.Click(); - windows = _session.FindElementsByXPath("XCUIElementTypeWindow"); + windows = Session.FindElementsByXPath("XCUIElementTypeWindow"); Assert.Single(windows); - _session.FindElementByAccessibilityId("RestoreAll").Click(); + Session.FindElementByAccessibilityId("RestoreAll").Click(); // Close the window manually. secondaryWindow = GetWindow("SecondaryWindow"); @@ -352,9 +327,9 @@ namespace Avalonia.IntegrationTests.Appium Assert.Equal(0, titleBar); secondaryWindow.FindElementByAccessibilityId("CurrentSystemDecorations").Click(); - _session.FindElementByAccessibilityId("SystemDecorationsNone").SendClick(); + Session.FindElementByAccessibilityId("SystemDecorationsNone").SendClick(); secondaryWindow.FindElementByAccessibilityId("CurrentSystemDecorations").Click(); - _session.FindElementByAccessibilityId("SystemDecorationsFull").SendClick(); + Session.FindElementByAccessibilityId("SystemDecorationsFull").SendClick(); titleBar = secondaryWindow.FindElementsByXPath("/*/XCUIElementTypeStaticText").Count; Assert.Equal(0, titleBar); @@ -394,7 +369,7 @@ namespace Avalonia.IntegrationTests.Appium if (decorations != SystemDecorations.Full) { secondaryWindow.FindElementByAccessibilityId("CurrentSystemDecorations").Click(); - _session.FindElementByAccessibilityId("SystemDecorationsFull").SendClick(); + Session.FindElementByAccessibilityId("SystemDecorationsFull").SendClick(); } } } @@ -408,13 +383,13 @@ namespace Avalonia.IntegrationTests.Appium SystemDecorations systemDecorations = SystemDecorations.Full, bool extendClientArea = false) { - var sizeTextBox = _session.FindElementByAccessibilityId("ShowWindowSize"); - var modeComboBox = _session.FindElementByAccessibilityId("ShowWindowMode"); - var locationComboBox = _session.FindElementByAccessibilityId("ShowWindowLocation"); - var canResizeCheckBox = _session.FindElementByAccessibilityId("ShowWindowCanResize"); - var showButton = _session.FindElementByAccessibilityId("ShowWindow"); - var systemDecorationsComboBox = _session.FindElementByAccessibilityId("ShowWindowSystemDecorations"); - var extendClientAreaCheckBox = _session.FindElementByAccessibilityId("ShowWindowExtendClientAreaToDecorationsHint"); + var sizeTextBox = Session.FindElementByAccessibilityId("ShowWindowSize"); + var modeComboBox = Session.FindElementByAccessibilityId("ShowWindowMode"); + var locationComboBox = Session.FindElementByAccessibilityId("ShowWindowLocation"); + var canResizeCheckBox = Session.FindElementByAccessibilityId("ShowWindowCanResize"); + var showButton = Session.FindElementByAccessibilityId("ShowWindow"); + var systemDecorationsComboBox = Session.FindElementByAccessibilityId("ShowWindowSystemDecorations"); + var extendClientAreaCheckBox = Session.FindElementByAccessibilityId("ShowWindowExtendClientAreaToDecorationsHint"); if (size.HasValue) sizeTextBox.SendKeys($"{size.Value.Width}, {size.Value.Height}"); @@ -422,13 +397,13 @@ namespace Avalonia.IntegrationTests.Appium if (modeComboBox.GetComboBoxValue() != mode.ToString()) { modeComboBox.Click(); - _session.FindElementByName(mode.ToString()).SendClick(); + Session.FindElementByName(mode.ToString()).SendClick(); } if (locationComboBox.GetComboBoxValue() != location.ToString()) { locationComboBox.Click(); - _session.FindElementByName(location.ToString()).SendClick(); + Session.FindElementByName(location.ToString()).SendClick(); } if (canResizeCheckBox.GetIsChecked() != canResize) @@ -437,7 +412,7 @@ namespace Avalonia.IntegrationTests.Appium if (systemDecorationsComboBox.GetComboBoxValue() != systemDecorations.ToString()) { systemDecorationsComboBox.Click(); - _session.FindElementByName(systemDecorations.ToString()).SendClick(); + Session.FindElementByName(systemDecorations.ToString()).SendClick(); } if (extendClientAreaCheckBox.GetIsChecked() != extendClientArea) @@ -448,10 +423,7 @@ namespace Avalonia.IntegrationTests.Appium private AppiumWebElement GetWindow(string identifier) { - // The Avalonia a11y tree currently exposes two nested Window elements, this is a bug and should be fixed - // but in the meantime use the `parent::' selector to return the parent "real" window. - return _session.FindElementByXPath( - $"XCUIElementTypeWindow//*[@identifier='{identifier}']/parent::XCUIElementTypeWindow"); + return Session.GetWindowById(identifier); } private int GetWindowOrder(string identifier)