Browse Source

Add missing AutomationPeers from built-in Controls.

pull/21322/head
Jumar Macato 5 months ago
parent
commit
3ad3e5cf72
  1. 42
      src/Avalonia.Controls.ColorPicker/Automation/Peers/ColorSpectrumAutomationPeer.cs
  2. 6
      src/Avalonia.Controls.ColorPicker/ColorSpectrum/ColorSpectrum.cs
  3. 3
      src/Avalonia.Controls/AutoCompleteBox/AutoCompleteBox.cs
  4. 68
      src/Avalonia.Controls/Automation/Peers/AutoCompleteBoxAutomationPeer.cs
  5. 57
      src/Avalonia.Controls/Automation/Peers/CalendarAutomationPeer.cs
  6. 72
      src/Avalonia.Controls/Automation/Peers/CalendarDatePickerAutomationPeer.cs
  7. 35
      src/Avalonia.Controls/Automation/Peers/NativeMenuBarAutomationPeer.cs
  8. 73
      src/Avalonia.Controls/Automation/Peers/NumericUpDownAutomationPeer.cs
  9. 73
      src/Avalonia.Controls/Automation/Peers/SplitButtonAutomationPeer.cs
  10. 50
      src/Avalonia.Controls/Automation/Peers/ToggleSplitButtonAutomationPeer.cs
  11. 14
      src/Avalonia.Controls/Automation/Peers/ToolTipAutomationPeer.cs
  12. 2
      src/Avalonia.Controls/Calendar/Calendar.cs
  13. 3
      src/Avalonia.Controls/CalendarDatePicker/CalendarDatePicker.cs
  14. 3
      src/Avalonia.Controls/NativeMenuBar.cs
  15. 3
      src/Avalonia.Controls/NumericUpDown/NumericUpDown.cs
  16. 24
      src/Avalonia.Controls/SplitButton/SplitButton.cs
  17. 8
      src/Avalonia.Controls/SplitButton/ToggleSplitButton.cs
  18. 4
      src/Avalonia.Controls/ToolTip.cs
  19. 91
      tests/Avalonia.Controls.UnitTests/Automation/ColorSpectrumAutomationPeerTests.cs
  20. 292
      tests/Avalonia.Controls.UnitTests/Automation/ComplexControlAutomationPeerTests.cs
  21. 266
      tests/Avalonia.Controls.UnitTests/Automation/FoundationAutomationPeerTests.cs
  22. 73
      tests/Avalonia.Controls.UnitTests/Automation/NativeMenuBarAutomationPeerTests.cs
  23. 196
      tests/Avalonia.Controls.UnitTests/Automation/SplitButtonAutomationPeerTests.cs
  24. 1
      tests/Avalonia.Controls.UnitTests/Avalonia.Controls.UnitTests.csproj

42
src/Avalonia.Controls.ColorPicker/Automation/Peers/ColorSpectrumAutomationPeer.cs

@ -0,0 +1,42 @@
using Avalonia;
using Avalonia.Automation;
using Avalonia.Automation.Provider;
using Avalonia.Controls.Primitives;
using Avalonia.Media;
namespace Avalonia.Automation.Peers;
public class ColorSpectrumAutomationPeer : ControlAutomationPeer, IValueProvider
{
public ColorSpectrumAutomationPeer(ColorSpectrum owner)
: base(owner)
{
owner.PropertyChanged += OwnerPropertyChanged;
}
public bool IsReadOnly => false;
public new ColorSpectrum Owner => (ColorSpectrum)base.Owner;
public string? Value => Owner.Color.ToString();
public void SetValue(string? value)
{
if (!Color.TryParse(value, out var color))
{
throw new System.FormatException($"Invalid color string: '{value}'.");
}
Owner.Color = color;
}
protected override AutomationControlType GetAutomationControlTypeCore() => AutomationControlType.Custom;
protected override string GetClassNameCore() => nameof(ColorSpectrum);
private void OwnerPropertyChanged(object? sender, AvaloniaPropertyChangedEventArgs e)
{
if (e.Property == ColorSpectrum.ColorProperty)
{
RaisePropertyChangedEvent(ValuePatternIdentifiers.ValueProperty, e.OldValue?.ToString(), e.NewValue?.ToString());
}
}
}

6
src/Avalonia.Controls.ColorPicker/ColorSpectrum/ColorSpectrum.cs

@ -7,6 +7,7 @@ using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Avalonia.Collections.Pooled;
using Avalonia.Automation.Peers;
using Avalonia.Controls.Metadata;
using Avalonia.Controls.Shapes;
using Avalonia.Input;
@ -197,6 +198,11 @@ namespace Avalonia.Controls.Primitives
base.OnDetachedFromVisualTree(e);
}
protected override AutomationPeer OnCreateAutomationPeer()
{
return new ColorSpectrumAutomationPeer(this);
}
/// <summary>
/// Explicitly unregisters all events connected in OnApplyTemplate().
/// </summary>

3
src/Avalonia.Controls/AutoCompleteBox/AutoCompleteBox.cs

@ -15,6 +15,7 @@ using System.Threading;
using System.Threading.Tasks;
using Avalonia.Collections;
using Avalonia.Controls.Metadata;
using Avalonia.Automation.Peers;
using Avalonia.Controls.Primitives;
using Avalonia.Controls.Templates;
using Avalonia.Controls.Utils;
@ -774,6 +775,8 @@ namespace Avalonia.Controls
FocusChanged(HasFocus());
}
protected override AutomationPeer OnCreateAutomationPeer() => new AutoCompleteBoxAutomationPeer(this);
/// <summary>
/// Determines whether the text box or drop-down portion of the
/// <see cref="T:Avalonia.Controls.AutoCompleteBox" /> control has

68
src/Avalonia.Controls/Automation/Peers/AutoCompleteBoxAutomationPeer.cs

@ -0,0 +1,68 @@
using System;
using Avalonia.Automation;
using Avalonia.Automation.Provider;
using Avalonia.Controls;
namespace Avalonia.Automation.Peers
{
public class AutoCompleteBoxAutomationPeer : ControlAutomationPeer, IExpandCollapseProvider, IValueProvider
{
public AutoCompleteBoxAutomationPeer(AutoCompleteBox owner)
: base(owner)
{
owner.PropertyChanged += OwnerPropertyChanged;
}
public new AutoCompleteBox Owner => (AutoCompleteBox)base.Owner;
public ExpandCollapseState ExpandCollapseState => ToState(Owner.IsDropDownOpen);
public bool ShowsMenu => true;
public void Collapse() => Owner.IsDropDownOpen = false;
public void Expand() => Owner.IsDropDownOpen = true;
public bool IsReadOnly => false;
public string? Value
{
get => Owner.Text;
set
{
if (value == Owner.Text)
return;
Owner.Text = value;
}
}
void IValueProvider.SetValue(string? value) => Owner.Text = value;
protected override AutomationControlType GetAutomationControlTypeCore()
{
return AutomationControlType.Group;
}
protected override string GetClassNameCore() => nameof(AutoCompleteBox);
private void OwnerPropertyChanged(object? sender, AvaloniaPropertyChangedEventArgs e)
{
if (e.Property == AutoCompleteBox.IsDropDownOpenProperty)
{
RaisePropertyChangedEvent(
ExpandCollapsePatternIdentifiers.ExpandCollapseStateProperty,
ToState(e.GetOldValue<bool>()),
ToState(e.GetNewValue<bool>()));
}
else if (e.Property == AutoCompleteBox.TextProperty)
{
RaisePropertyChangedEvent(
ValuePatternIdentifiers.ValueProperty,
e.OldValue,
e.NewValue);
}
}
private static ExpandCollapseState ToState(bool value)
{
return value ? ExpandCollapseState.Expanded : ExpandCollapseState.Collapsed;
}
}
}

57
src/Avalonia.Controls/Automation/Peers/CalendarAutomationPeer.cs

@ -0,0 +1,57 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Avalonia.Automation;
using Avalonia.Automation.Provider;
using Avalonia.Controls;
using Avalonia.Controls.Primitives;
namespace Avalonia.Automation.Peers
{
public class CalendarAutomationPeer : ControlAutomationPeer, ISelectionProvider, IValueProvider
{
public CalendarAutomationPeer(Calendar owner)
: base(owner)
{
owner.SelectedDatesChanged += OwnerSelectedDatesChanged;
}
public new Calendar Owner => (Calendar)base.Owner;
public bool CanSelectMultiple =>
Owner.SelectionMode == CalendarSelectionMode.SingleRange ||
Owner.SelectionMode == CalendarSelectionMode.MultipleRange;
public bool IsSelectionRequired => false;
public IReadOnlyList<AutomationPeer> GetSelection()
{
return Owner.SelectedDates.Select(date => Owner.FindDayButtonFromDay(date))
.OfType<CalendarDayButton>().Select(GetOrCreate).ToList();
}
public bool IsReadOnly => true;
public string? Value => string.Join(
System.Globalization.CultureInfo.CurrentCulture.TextInfo.ListSeparator,
Owner.SelectedDates.Select(x => x.ToString(System.Globalization.CultureInfo.CurrentCulture)));
public void SetValue(string? value)
{
throw new NotSupportedException();
}
protected override AutomationControlType GetAutomationControlTypeCore()
{
return AutomationControlType.Calendar;
}
protected override string GetClassNameCore() => nameof(Calendar);
private void OwnerSelectedDatesChanged(object? sender, SelectionChangedEventArgs e)
{
RaisePropertyChangedEvent(SelectionPatternIdentifiers.SelectionProperty, null, null);
RaisePropertyChangedEvent(ValuePatternIdentifiers.ValueProperty, null, null);
}
}
}

72
src/Avalonia.Controls/Automation/Peers/CalendarDatePickerAutomationPeer.cs

@ -0,0 +1,72 @@
using System;
using Avalonia.Automation;
using Avalonia.Automation.Provider;
using Avalonia.Controls;
namespace Avalonia.Automation.Peers
{
public class CalendarDatePickerAutomationPeer : ControlAutomationPeer,
IInvokeProvider,
IExpandCollapseProvider,
IValueProvider
{
public CalendarDatePickerAutomationPeer(CalendarDatePicker owner)
: base(owner)
{
Owner.PropertyChanged += OwnerPropertyChanged;
}
public new CalendarDatePicker Owner => (CalendarDatePicker)base.Owner;
public ExpandCollapseState ExpandCollapseState => ToState(Owner.IsDropDownOpen);
public bool ShowsMenu => true;
public bool IsReadOnly => false;
public string? Value => Owner.Text;
public void Invoke()
{
EnsureEnabled();
Owner.IsDropDownOpen = true;
}
public void Expand() => Owner.IsDropDownOpen = true;
public void Collapse() => Owner.IsDropDownOpen = false;
public void SetValue(string? value) => Owner.Text = value;
protected override AutomationControlType GetAutomationControlTypeCore() => AutomationControlType.Button;
protected override string GetClassNameCore() => "CalendarDatePicker";
protected override bool IsContentElementCore() => true;
protected override bool IsControlElementCore() => true;
private void OwnerPropertyChanged(object? sender, AvaloniaPropertyChangedEventArgs e)
{
if (e.Property == CalendarDatePicker.TextProperty)
{
RaisePropertyChangedEvent(
ValuePatternIdentifiers.ValueProperty,
e.OldValue,
e.NewValue);
}
else if (e.Property == CalendarDatePicker.IsDropDownOpenProperty)
{
RaisePropertyChangedEvent(
ExpandCollapsePatternIdentifiers.ExpandCollapseStateProperty,
ToState(e.GetOldValue<bool>()),
ToState(e.GetNewValue<bool>()));
}
}
private static ExpandCollapseState ToState(bool isExpanded)
{
return isExpanded ? ExpandCollapseState.Expanded : ExpandCollapseState.Collapsed;
}
}
}

35
src/Avalonia.Controls/Automation/Peers/NativeMenuBarAutomationPeer.cs

@ -0,0 +1,35 @@
using System.Collections.Generic;
using System.Linq;
using Avalonia.Controls;
using Avalonia.LogicalTree;
using Avalonia.VisualTree;
namespace Avalonia.Automation.Peers
{
public class NativeMenuBarAutomationPeer(NativeMenuBar owner) : ControlAutomationPeer(owner)
{
protected override AutomationControlType GetAutomationControlTypeCore()
{
return AutomationControlType.MenuBar;
}
protected override IReadOnlyList<AutomationPeer>? GetChildrenCore()
{
var menu = Owner.VisualChildren.OfType<MenuBase>().FirstOrDefault() ??
Owner.GetVisualDescendants().OfType<MenuBase>().FirstOrDefault();
if (menu is null)
{
return base.GetChildrenCore();
}
var children = menu.GetLogicalChildren()
.OfType<Control>()
.Where(x => x.IsVisible)
.Select(GetOrCreate)
.ToList();
return children.Count > 0 ? children : base.GetChildrenCore();
}
}
}

73
src/Avalonia.Controls/Automation/Peers/NumericUpDownAutomationPeer.cs

@ -0,0 +1,73 @@
using System;
using Avalonia.Automation;
using Avalonia.Automation.Provider;
using Avalonia.Controls;
namespace Avalonia.Automation.Peers
{
public class NumericUpDownAutomationPeer : ControlAutomationPeer, IRangeValueProvider
{
public NumericUpDownAutomationPeer(NumericUpDown owner)
: base(owner)
{
Owner.PropertyChanged += OwnerPropertyChanged;
}
public new NumericUpDown Owner => (NumericUpDown)base.Owner;
public bool IsReadOnly => Owner.IsReadOnly;
public double Maximum => (double)Owner.Maximum;
public double Minimum => (double)Owner.Minimum;
public double Value => Owner.Value.HasValue
? (double)Owner.Value.Value
: (double)Math.Clamp(0m, Owner.Minimum, Owner.Maximum);
public double SmallChange => (double)Owner.Increment;
public double LargeChange => (double)Owner.Increment;
public void SetValue(double value)
{
Owner.Value = (decimal)value;
}
protected override AutomationControlType GetAutomationControlTypeCore() => AutomationControlType.Spinner;
protected override string GetClassNameCore() => "NumericUpDown";
private void OwnerPropertyChanged(object? sender, AvaloniaPropertyChangedEventArgs e)
{
if (e.Property == NumericUpDown.MinimumProperty)
{
RaisePropertyChangedEvent(
RangeValuePatternIdentifiers.MinimumProperty,
e.OldValue,
e.NewValue);
}
else if (e.Property == NumericUpDown.MaximumProperty)
{
RaisePropertyChangedEvent(
RangeValuePatternIdentifiers.MaximumProperty,
e.OldValue,
e.NewValue);
}
else if (e.Property == NumericUpDown.ValueProperty)
{
RaisePropertyChangedEvent(
RangeValuePatternIdentifiers.ValueProperty,
e.OldValue,
e.NewValue);
}
else if (e.Property == NumericUpDown.IsReadOnlyProperty)
{
RaisePropertyChangedEvent(
RangeValuePatternIdentifiers.IsReadOnlyProperty,
e.OldValue,
e.NewValue);
}
}
}
}

73
src/Avalonia.Controls/Automation/Peers/SplitButtonAutomationPeer.cs

@ -0,0 +1,73 @@
using Avalonia.Automation;
using Avalonia.Automation.Provider;
using Avalonia.Controls;
namespace Avalonia.Automation.Peers
{
public class SplitButtonAutomationPeer : ContentControlAutomationPeer, IInvokeProvider, IExpandCollapseProvider
{
private ExpandCollapseState _expandCollapseState;
public SplitButtonAutomationPeer(SplitButton owner)
: base(owner)
{
_expandCollapseState = ToState(owner.IsFlyoutOpen);
owner.FlyoutStateChanged += OwnerFlyoutStateChanged;
}
public new SplitButton Owner => (SplitButton)base.Owner;
public ExpandCollapseState ExpandCollapseState => ToState(Owner.IsFlyoutOpen);
public bool ShowsMenu => true;
public void Collapse()
{
Owner.CloseFlyoutForAutomation();
}
public void Expand()
{
Owner.OpenFlyoutForAutomation();
}
void IInvokeProvider.Invoke()
{
EnsureEnabled();
Owner.InvokePrimary();
}
protected override AutomationControlType GetAutomationControlTypeCore()
{
return AutomationControlType.SplitButton;
}
protected override string GetClassNameCore()
{
return "SplitButton";
}
protected override bool IsContentElementCore() => true;
protected override bool IsControlElementCore() => true;
private void OwnerFlyoutStateChanged(object? sender, System.EventArgs e)
{
var oldState = _expandCollapseState;
var newState = ToState(Owner.IsFlyoutOpen);
if (oldState != newState)
{
_expandCollapseState = newState;
RaisePropertyChangedEvent(
ExpandCollapsePatternIdentifiers.ExpandCollapseStateProperty,
oldState,
newState);
}
}
private static ExpandCollapseState ToState(bool isOpen)
{
return isOpen ? ExpandCollapseState.Expanded : ExpandCollapseState.Collapsed;
}
}
}

50
src/Avalonia.Controls/Automation/Peers/ToggleSplitButtonAutomationPeer.cs

@ -0,0 +1,50 @@
using Avalonia.Automation.Provider;
using Avalonia.Controls;
namespace Avalonia.Automation.Peers
{
public class ToggleSplitButtonAutomationPeer : SplitButtonAutomationPeer, IToggleProvider
{
public ToggleSplitButtonAutomationPeer(ToggleSplitButton owner)
: base(owner)
{
owner.PropertyChanged += OwnerPropertyChanged;
}
public new ToggleSplitButton Owner => (ToggleSplitButton)base.Owner;
ToggleState IToggleProvider.ToggleState => ToState(Owner.IsChecked);
void IToggleProvider.Toggle()
{
EnsureEnabled();
Owner.ToggleForAutomation();
}
protected override AutomationControlType GetAutomationControlTypeCore()
{
return AutomationControlType.SplitButton;
}
protected override string GetClassNameCore()
{
return "ToggleSplitButton";
}
private void OwnerPropertyChanged(object? sender, AvaloniaPropertyChangedEventArgs e)
{
if (e.Property == ToggleSplitButton.IsCheckedProperty)
{
RaisePropertyChangedEvent(
TogglePatternIdentifiers.ToggleStateProperty,
ToState(e.GetOldValue<bool>()),
ToState(e.GetNewValue<bool>()));
}
}
private static ToggleState ToState(bool value)
{
return value ? ToggleState.On : ToggleState.Off;
}
}
}

14
src/Avalonia.Controls/Automation/Peers/ToolTipAutomationPeer.cs

@ -0,0 +1,14 @@
using Avalonia.Automation.Provider;
using Avalonia.Controls;
namespace Avalonia.Automation.Peers
{
public class ToolTipAutomationPeer(ToolTip owner) : ControlAutomationPeer(owner)
{
public new ToolTip Owner => (ToolTip)base.Owner;
protected override AutomationControlType GetAutomationControlTypeCore() => AutomationControlType.ToolTip;
protected override string GetClassNameCore() => "ToolTip";
}
}

2
src/Avalonia.Controls/Calendar/Calendar.cs

@ -6,6 +6,7 @@
using System;
using System.Collections.ObjectModel;
using System.Diagnostics;
using Avalonia.Automation.Peers;
using Avalonia.Controls.Metadata;
using Avalonia.Controls.Primitives;
using Avalonia.Data;
@ -2251,5 +2252,6 @@ namespace Avalonia.Controls
}
}
protected override AutomationPeer OnCreateAutomationPeer() => new CalendarAutomationPeer(this);
}
}

3
src/Avalonia.Controls/CalendarDatePicker/CalendarDatePicker.cs

@ -7,6 +7,7 @@ using System;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Globalization;
using Avalonia.Automation.Peers;
using Avalonia.Reactive;
using Avalonia.Controls.Metadata;
using Avalonia.Controls.Primitives;
@ -195,6 +196,8 @@ namespace Avalonia.Controls
UpdatePseudoClasses();
}
protected override AutomationPeer OnCreateAutomationPeer() => new CalendarDatePickerAutomationPeer(this);
/// <inheritdoc/>
protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change)
{

3
src/Avalonia.Controls/NativeMenuBar.cs

@ -1,4 +1,5 @@
using System;
using Avalonia.Automation.Peers;
using Avalonia.Controls.Metadata;
using Avalonia.Controls.Primitives;
using Avalonia.Controls.Templates;
@ -70,5 +71,7 @@ namespace Avalonia.Controls
menu.Bind(ItemsControl.ItemsSourceProperty, topLevel.GetBindingObservable(NativeMenu.MenuProperty)
.Select(v => v.GetValueOrDefault<NativeMenu>()?.Items)));
}
protected override AutomationPeer OnCreateAutomationPeer() => new NativeMenuBarAutomationPeer(this);
}
}

3
src/Avalonia.Controls/NumericUpDown/NumericUpDown.cs

@ -2,6 +2,7 @@ using System;
using System.Globalization;
using System.IO;
using System.Linq;
using Avalonia.Automation.Peers;
using Avalonia.Controls.Metadata;
using Avalonia.Controls.Primitives;
using Avalonia.Data;
@ -488,6 +489,8 @@ namespace Avalonia.Controls
SetValidSpinDirection();
}
protected override AutomationPeer OnCreateAutomationPeer() => new NumericUpDownAutomationPeer(this);
/// <inheritdoc />
protected override void OnKeyDown(KeyEventArgs e)
{

24
src/Avalonia.Controls/SplitButton/SplitButton.cs

@ -1,6 +1,7 @@
using System;
using System.Windows.Input;
using Avalonia.Controls.Metadata;
using Avalonia.Automation.Peers;
using Avalonia.Controls.Primitives;
using Avalonia.Input;
using Avalonia.Interactivity;
@ -74,6 +75,8 @@ namespace Avalonia.Controls
private IDisposable? _flyoutPropertyChangedDisposable;
internal event EventHandler? FlyoutStateChanged;
/// <summary>
/// Initializes a new instance of the <see cref="SplitButton"/> class.
/// </summary>
@ -256,6 +259,8 @@ namespace Avalonia.Controls
UpdatePseudoClasses();
}
protected override AutomationPeer OnCreateAutomationPeer() => new SplitButtonAutomationPeer(this);
/// <inheritdoc/>
protected override void OnAttachedToLogicalTree(LogicalTreeAttachmentEventArgs e)
{
@ -418,6 +423,23 @@ namespace Avalonia.Controls
}
}
internal void InvokePrimary()
{
OnClickPrimary(null);
}
internal bool IsFlyoutOpen => _isFlyoutOpen;
internal void OpenFlyoutForAutomation()
{
OpenFlyout();
}
internal void CloseFlyoutForAutomation()
{
CloseFlyout();
}
/// <summary>
/// Invoked when the secondary button part is clicked.
/// </summary>
@ -516,6 +538,7 @@ namespace Avalonia.Controls
{
_isFlyoutOpen = true;
UpdatePseudoClasses();
FlyoutStateChanged?.Invoke(this, EventArgs.Empty);
OnFlyoutOpened();
}
@ -533,6 +556,7 @@ namespace Avalonia.Controls
{
_isFlyoutOpen = false;
UpdatePseudoClasses();
FlyoutStateChanged?.Invoke(this, EventArgs.Empty);
OnFlyoutClosed();
}

8
src/Avalonia.Controls/SplitButton/ToggleSplitButton.cs

@ -1,5 +1,6 @@
using System;
using Avalonia.Automation.Peers;
using Avalonia.Controls.Metadata;
using Avalonia.Controls.Primitives;
using Avalonia.Data;
@ -65,6 +66,8 @@ namespace Avalonia.Controls
/// </remarks>
protected override Type StyleKeyOverride => typeof(SplitButton);
protected override AutomationPeer OnCreateAutomationPeer() => new ToggleSplitButtonAutomationPeer(this);
/// <summary>
/// Toggles the <see cref="IsChecked"/> property between true and false.
/// </summary>
@ -73,6 +76,11 @@ namespace Avalonia.Controls
SetCurrentValue(IsCheckedProperty, !IsChecked);
}
internal void ToggleForAutomation()
{
OnClickPrimary(null);
}
/// <inheritdoc/>
protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs e)
{

4
src/Avalonia.Controls/ToolTip.cs

@ -1,5 +1,6 @@
using System;
using System.ComponentModel;
using Avalonia.Automation.Peers;
using Avalonia.Controls.Diagnostics;
using Avalonia.Controls.Metadata;
using Avalonia.Controls.Primitives;
@ -472,5 +473,8 @@ namespace Avalonia.Controls
{
PseudoClasses.Set(":open", newValue);
}
protected override AutomationPeer OnCreateAutomationPeer()
=> new ToolTipAutomationPeer(this);
}
}

91
tests/Avalonia.Controls.UnitTests/Automation/ColorSpectrumAutomationPeerTests.cs

@ -0,0 +1,91 @@
using System;
using Avalonia.Automation;
using Avalonia.Automation.Peers;
using Avalonia.Automation.Provider;
using Avalonia.Controls.Primitives;
using Avalonia.Media;
using Avalonia.UnitTests;
using Xunit;
namespace Avalonia.Controls.UnitTests.Automation;
public class ColorSpectrumAutomationPeerTests
{
public class AutomationPeerTests : ScopedTestBase
{
[Fact]
public void Creates_ColorSpectrumAutomationPeer()
{
var spectrum = new ColorSpectrum();
var peer = ControlAutomationPeer.CreatePeerForElement(spectrum);
Assert.IsType<ColorSpectrumAutomationPeer>(peer);
}
[Fact]
public void ControlType_Is_Custom()
{
var spectrum = new ColorSpectrum();
var peer = (ColorSpectrumAutomationPeer)ControlAutomationPeer.CreatePeerForElement(spectrum);
Assert.Equal(AutomationControlType.Custom, peer.GetAutomationControlType());
}
[Fact]
public void ClassName_Is_ColorSpectrum()
{
var spectrum = new ColorSpectrum();
var peer = (ColorSpectrumAutomationPeer)ControlAutomationPeer.CreatePeerForElement(spectrum);
Assert.Equal("ColorSpectrum", peer.GetClassName());
}
[Fact]
public void Implements_IValueProvider()
{
var spectrum = new ColorSpectrum();
var peer = (ColorSpectrumAutomationPeer)ControlAutomationPeer.CreatePeerForElement(spectrum);
Assert.Equal(Colors.White.ToString(), peer.Value);
var valueProvider = Assert.IsAssignableFrom<IValueProvider>(peer);
valueProvider.SetValue("#00FF00");
Assert.Equal(Colors.Lime.ToString(), peer.Value);
Assert.Equal(Colors.Lime, spectrum.Color);
}
[Fact]
public void SetValue_Uses_Color_Parse_And_Throws_FormatException_On_Invalid_Input()
{
var spectrum = new ColorSpectrum();
var peer = (ColorSpectrumAutomationPeer)ControlAutomationPeer.CreatePeerForElement(spectrum);
var valueProvider = Assert.IsAssignableFrom<IValueProvider>(peer);
Assert.Throws<FormatException>(() => valueProvider.SetValue("not-a-color"));
}
[Fact]
public void ValueProperty_Raises_AutomationPropertyChangedEvent_On_Color_Change()
{
var spectrum = new ColorSpectrum();
var peer = (ColorSpectrumAutomationPeer)ControlAutomationPeer.CreatePeerForElement(spectrum);
AutomationPropertyChangedEventArgs? changed = null;
peer.PropertyChanged += (_, e) =>
{
if (e.Property == ValuePatternIdentifiers.ValueProperty)
{
changed = e;
}
};
spectrum.Color = Colors.Black;
Assert.NotNull(changed);
Assert.Equal(ValuePatternIdentifiers.ValueProperty, changed!.Property);
Assert.Equal(Colors.White.ToString(), changed.OldValue);
Assert.Equal(Colors.Black.ToString(), changed.NewValue);
}
}
}

292
tests/Avalonia.Controls.UnitTests/Automation/ComplexControlAutomationPeerTests.cs

@ -0,0 +1,292 @@
using System;
using System.Globalization;
using System.Linq;
using Avalonia;
using Avalonia.Automation;
using Avalonia.Automation.Peers;
using Avalonia.Automation.Provider;
using Avalonia.Controls;
using Avalonia.Controls.Primitives;
using Avalonia.UnitTests;
using Xunit;
namespace Avalonia.Controls.UnitTests.Automation;
public class AutoCompleteBoxAutomationPeerTests : ScopedTestBase
{
[Fact]
public void Creates_AutoCompleteBoxAutomationPeer()
{
var target = new AutoCompleteBox();
var peer = ControlAutomationPeer.CreatePeerForElement(target);
Assert.IsType<AutoCompleteBoxAutomationPeer>(peer);
}
[Fact]
public void Implements_IExpandCollapse_And_IValue_Providers()
{
var target = new AutoCompleteBox();
var peer = ControlAutomationPeer.CreatePeerForElement(target);
Assert.IsAssignableFrom<IExpandCollapseProvider>(peer);
Assert.IsAssignableFrom<IValueProvider>(peer);
Assert.False(peer is IInvokeProvider);
}
[Fact]
public void ControlType_Is_Group_And_ClassName_Is_AutoCompleteBox()
{
var target = new AutoCompleteBox();
var peer = (AutoCompleteBoxAutomationPeer)ControlAutomationPeer.CreatePeerForElement(target);
Assert.Equal(AutomationControlType.Group, peer.GetAutomationControlType());
Assert.Equal(nameof(AutoCompleteBox), peer.GetClassName());
}
[Fact]
public void ExpandCollapse_Tracks_IsDropDownOpen()
{
var target = new AutoCompleteBox
{
ItemsSource = new[] { "alpha" },
Text = "a"
};
var peer = (IExpandCollapseProvider)ControlAutomationPeer.CreatePeerForElement(target);
Assert.True(peer.ShowsMenu);
target.IsDropDownOpen = false;
Assert.False(target.IsDropDownOpen);
peer.Expand();
Assert.True(target.IsDropDownOpen);
Assert.Equal(ExpandCollapseState.Expanded, peer.ExpandCollapseState);
peer.Collapse();
Assert.False(target.IsDropDownOpen);
Assert.Equal(ExpandCollapseState.Collapsed, peer.ExpandCollapseState);
}
[Fact]
public void Value_Tracks_And_Sets_Text()
{
var target = new AutoCompleteBox { Text = "one" };
var peer = (IValueProvider)ControlAutomationPeer.CreatePeerForElement(target);
Assert.Equal("one", peer.Value);
peer.SetValue("two");
Assert.Equal("two", target.Text);
Assert.Equal("two", ((IValueProvider)peer).Value);
}
[Fact]
public void ValueProvider_IsMutable()
{
var target = new AutoCompleteBox();
var peer = (IValueProvider)ControlAutomationPeer.CreatePeerForElement(target);
Assert.False(peer.IsReadOnly);
}
[Fact]
public void Property_Change_Events_Raise_For_DropDown_And_Text()
{
var target = new AutoCompleteBox();
var peer = (AutoCompleteBoxAutomationPeer)ControlAutomationPeer.CreatePeerForElement(target);
AutomationPropertyChangedEventArgs? expandCollapseChanged = null;
AutomationPropertyChangedEventArgs? valueChanged = null;
peer.PropertyChanged += (_, e) =>
{
if (e.Property == ExpandCollapsePatternIdentifiers.ExpandCollapseStateProperty)
{
expandCollapseChanged = e;
}
else if (e.Property == ValuePatternIdentifiers.ValueProperty)
{
valueChanged = e;
}
};
target.IsDropDownOpen = true;
Assert.NotNull(expandCollapseChanged);
Assert.Equal(ExpandCollapsePatternIdentifiers.ExpandCollapseStateProperty, expandCollapseChanged!.Property);
Assert.Equal(ExpandCollapseState.Collapsed, expandCollapseChanged.OldValue);
Assert.Equal(ExpandCollapseState.Expanded, expandCollapseChanged.NewValue);
target.Text = "query";
Assert.NotNull(valueChanged);
Assert.Equal(ValuePatternIdentifiers.ValueProperty, valueChanged!.Property);
Assert.Equal(string.Empty, valueChanged.OldValue);
Assert.Equal("query", valueChanged.NewValue);
}
}
public class CalendarAutomationPeerTests : ScopedTestBase
{
[Fact]
public void Creates_CalendarAutomationPeer()
{
var target = new Calendar();
var peer = ControlAutomationPeer.CreatePeerForElement(target);
Assert.IsType<CalendarAutomationPeer>(peer);
}
[Fact]
public void Implements_ISelection_And_IValue_Providers()
{
var target = new Calendar();
var peer = ControlAutomationPeer.CreatePeerForElement(target);
Assert.IsAssignableFrom<ISelectionProvider>(peer);
Assert.IsAssignableFrom<IValueProvider>(peer);
}
[Fact]
public void ControlType_Is_Calendar_And_ClassName_Is_Calendar()
{
var target = new Calendar();
var peer = (CalendarAutomationPeer)ControlAutomationPeer.CreatePeerForElement(target);
Assert.Equal(AutomationControlType.Calendar, peer.GetAutomationControlType());
Assert.Equal(nameof(Calendar), peer.GetClassName());
}
[Theory]
[InlineData(CalendarSelectionMode.SingleDate, false)]
[InlineData(CalendarSelectionMode.SingleRange, true)]
[InlineData(CalendarSelectionMode.MultipleRange, true)]
[InlineData(CalendarSelectionMode.None, false)]
public void CanSelectMultiple_Reflects_SelectionMode(CalendarSelectionMode selectionMode, bool canSelectMultiple)
{
var target = new Calendar { SelectionMode = selectionMode };
var peer = (ISelectionProvider)ControlAutomationPeer.CreatePeerForElement(target);
Assert.Equal(canSelectMultiple, peer.CanSelectMultiple);
Assert.False(peer.IsSelectionRequired);
}
[Fact]
public void Selection_Events_Include_Selection_And_Value_Properties()
{
var target = new Calendar { SelectionMode = CalendarSelectionMode.SingleDate };
var peer = (CalendarAutomationPeer)ControlAutomationPeer.CreatePeerForElement(target);
AutomationPropertyChangedEventArgs? selectionChanged = null;
AutomationPropertyChangedEventArgs? valueChanged = null;
peer.PropertyChanged += (_, e) =>
{
if (e.Property == SelectionPatternIdentifiers.SelectionProperty)
{
selectionChanged = e;
}
else if (e.Property == ValuePatternIdentifiers.ValueProperty)
{
valueChanged = e;
}
};
target.SelectedDate = new DateTime(2010, 1, 1);
Assert.NotNull(selectionChanged);
Assert.NotNull(valueChanged);
Assert.Equal(SelectionPatternIdentifiers.SelectionProperty, selectionChanged!.Property);
Assert.Equal(ValuePatternIdentifiers.ValueProperty, valueChanged!.Property);
}
[Fact]
public void Value_Joins_Selected_Dates_With_CurrentCulture()
{
var previousCulture = CultureInfo.CurrentCulture;
try
{
CultureInfo.CurrentCulture = CultureInfo.GetCultureInfo("en-GB");
var selectedDates = new[] { new DateTime(2026, 5, 7), new DateTime(2026, 5, 8) };
var target = new Calendar
{
SelectionMode = CalendarSelectionMode.MultipleRange
};
var peer = (CalendarAutomationPeer)ControlAutomationPeer.CreatePeerForElement(target);
foreach (var date in selectedDates)
{
target.SelectedDates.Add(date);
}
Assert.Equal(
string.Join(CultureInfo.CurrentCulture.TextInfo.ListSeparator, selectedDates.Select(x => x.ToString(CultureInfo.CurrentCulture))),
peer.Value);
}
finally
{
CultureInfo.CurrentCulture = previousCulture;
}
}
[Fact]
public void SetValue_Throws_NotSupported()
{
var peer = (IValueProvider)ControlAutomationPeer.CreatePeerForElement(new Calendar());
Assert.Throws<NotSupportedException>(() => peer.SetValue("2026-01-01"));
}
[Fact]
public void Value_Is_ReadOnly()
{
var peer = (IValueProvider)ControlAutomationPeer.CreatePeerForElement(new Calendar());
Assert.True(peer.IsReadOnly);
}
[Fact]
public void GetSelection_Returns_Empty_When_DayButton_Not_Realized()
{
var target = new Calendar { SelectionMode = CalendarSelectionMode.SingleDate, SelectedDate = new DateTime(2026, 5, 7) };
var peer = (CalendarAutomationPeer)ControlAutomationPeer.CreatePeerForElement(target);
var selection = peer.GetSelection();
Assert.Empty(selection);
}
[Fact]
public void GetSelection_Returns_Realized_DayButton_Peers()
{
var selectedDate = new DateTime(2026, 5, 7);
var target = new Calendar
{
SelectionMode = CalendarSelectionMode.SingleDate,
DisplayDate = new DateTime(2026, 5, 1),
SelectedDate = selectedDate,
};
var monthView = new Grid();
var calendarItem = new CalendarItem
{
Owner = target,
MonthView = monthView
};
target.Root = new Panel { Children = { calendarItem } };
for (var i = 0; i < Calendar.ColumnsPerMonth; i++)
{
monthView.Children.Add(new TextBlock());
}
for (var i = 0; i < Calendar.RowsPerMonth * Calendar.ColumnsPerMonth - Calendar.ColumnsPerMonth; i++)
{
monthView.Children.Add(new CalendarDayButton
{
Owner = target,
DataContext = i == 0 ? selectedDate : selectedDate.AddDays(i + 1)
});
}
var peer = (CalendarAutomationPeer)ControlAutomationPeer.CreatePeerForElement(target);
var selection = peer.GetSelection();
Assert.Single(selection);
}
}

266
tests/Avalonia.Controls.UnitTests/Automation/FoundationAutomationPeerTests.cs

@ -0,0 +1,266 @@
using System;
using Avalonia.Automation;
using Avalonia.Automation.Peers;
using Avalonia.Automation.Provider;
using Avalonia.Controls;
using Avalonia.UnitTests;
using Xunit;
#nullable enable
namespace Avalonia.Controls.UnitTests.Automation;
public class FoundationAutomationPeerTests
{
public class ToolTipPeer : ScopedTestBase
{
[Fact]
public void Creates_ToolTipAutomationPeer()
{
var control = new ToolTip();
var peer = ControlAutomationPeer.CreatePeerForElement(control);
Assert.IsType<ToolTipAutomationPeer>(peer);
}
[Fact]
public void ControlType_Is_ToolTip()
{
var control = new ToolTip();
var peer = (ToolTipAutomationPeer)ControlAutomationPeer.CreatePeerForElement(control);
Assert.Equal(AutomationControlType.ToolTip, peer.GetAutomationControlType());
Assert.Equal("ToolTip", peer.GetClassName());
}
}
public class CalendarDatePickerPeer : ScopedTestBase
{
[Fact]
public void Creates_CalendarDatePickerAutomationPeer()
{
var control = new CalendarDatePicker();
var peer = ControlAutomationPeer.CreatePeerForElement(control);
Assert.IsType<CalendarDatePickerAutomationPeer>(peer);
}
[Fact]
public void Implements_IInvoke_And_IValue_Providers()
{
var control = new CalendarDatePicker();
var peer = ControlAutomationPeer.CreatePeerForElement(control);
Assert.IsAssignableFrom<IInvokeProvider>(peer);
Assert.IsAssignableFrom<IExpandCollapseProvider>(peer);
Assert.IsAssignableFrom<IValueProvider>(peer);
}
[Fact]
public void Has_Button_ControlType()
{
var control = new CalendarDatePicker();
var peer = (CalendarDatePickerAutomationPeer)ControlAutomationPeer.CreatePeerForElement(control);
Assert.Equal(AutomationControlType.Button, peer.GetAutomationControlType());
Assert.Equal("CalendarDatePicker", peer.GetClassName());
}
[Fact]
public void Invoke_Opens_DropDown()
{
var control = new CalendarDatePicker();
var peer = (IInvokeProvider)ControlAutomationPeer.CreatePeerForElement(control);
peer.Invoke();
Assert.True(control.IsDropDownOpen);
}
[Fact]
public void ExpandCollapse_Tracks_IsDropDownOpen()
{
var control = new CalendarDatePicker();
var peer = (IExpandCollapseProvider)ControlAutomationPeer.CreatePeerForElement(control);
Assert.True(peer.ShowsMenu);
Assert.Equal(ExpandCollapseState.Collapsed, peer.ExpandCollapseState);
peer.Expand();
Assert.True(control.IsDropDownOpen);
Assert.Equal(ExpandCollapseState.Expanded, peer.ExpandCollapseState);
peer.Collapse();
Assert.False(control.IsDropDownOpen);
Assert.Equal(ExpandCollapseState.Collapsed, peer.ExpandCollapseState);
}
[Fact]
public void Value_Mirrors_Owner_Text()
{
var control = new CalendarDatePicker { Text = "typed value" };
var peer = (CalendarDatePickerAutomationPeer)ControlAutomationPeer.CreatePeerForElement(control);
Assert.Equal("typed value", peer.Value);
control.Text = "updated typed value";
Assert.Equal("updated typed value", peer.Value);
}
[Fact]
public void SetValue_Updates_Text()
{
var control = new CalendarDatePicker();
var peer = (IValueProvider)ControlAutomationPeer.CreatePeerForElement(control);
Assert.False(peer.IsReadOnly);
peer.SetValue("automation text");
Assert.Equal("automation text", control.Text);
}
[Fact]
public void PropertyChanged_Raises_Value_When_Text_Changes()
{
var control = new CalendarDatePicker();
var peer = (CalendarDatePickerAutomationPeer)ControlAutomationPeer.CreatePeerForElement(control);
AutomationPropertyChangedEventArgs? changed = null;
peer.PropertyChanged += (_, e) =>
{
if (e.Property == ValuePatternIdentifiers.ValueProperty)
changed = e;
};
control.Text = "January";
Assert.NotNull(changed);
Assert.Equal(ValuePatternIdentifiers.ValueProperty, changed!.Property);
Assert.Null(changed.OldValue);
Assert.Equal("January", changed.NewValue);
}
[Fact]
public void PropertyChanged_Raises_ExpandCollapseState_When_DropDown_Open_Changes()
{
var control = new CalendarDatePicker();
var peer = (CalendarDatePickerAutomationPeer)ControlAutomationPeer.CreatePeerForElement(control);
AutomationPropertyChangedEventArgs? changed = null;
peer.PropertyChanged += (_, e) =>
{
if (e.Property == ExpandCollapsePatternIdentifiers.ExpandCollapseStateProperty)
changed = e;
};
control.IsDropDownOpen = true;
Assert.NotNull(changed);
Assert.Equal(ExpandCollapsePatternIdentifiers.ExpandCollapseStateProperty, changed!.Property);
Assert.Equal(ExpandCollapseState.Collapsed, changed.OldValue);
Assert.Equal(ExpandCollapseState.Expanded, changed.NewValue);
}
}
public class NumericUpDownPeer : ScopedTestBase
{
[Fact]
public void Creates_NumericUpDownAutomationPeer()
{
var control = new NumericUpDown();
var peer = ControlAutomationPeer.CreatePeerForElement(control);
Assert.IsType<NumericUpDownAutomationPeer>(peer);
}
[Fact]
public void Is_Spinner_ControlType()
{
var control = new NumericUpDown();
var peer = (NumericUpDownAutomationPeer)ControlAutomationPeer.CreatePeerForElement(control);
Assert.Equal(AutomationControlType.Spinner, peer.GetAutomationControlType());
Assert.Equal("NumericUpDown", peer.GetClassName());
}
[Fact]
public void Implements_IRangeValueProvider()
{
var control = new NumericUpDown();
var peer = ControlAutomationPeer.CreatePeerForElement(control);
Assert.IsAssignableFrom<IRangeValueProvider>(peer);
}
[Fact]
public void Range_Values_Reflect_Owner()
{
var control = new NumericUpDown
{
Minimum = 10,
Maximum = 20,
Increment = 3,
IsReadOnly = true,
Value = 14,
};
var peer = (IRangeValueProvider)ControlAutomationPeer.CreatePeerForElement(control);
Assert.Equal(10d, peer.Minimum);
Assert.Equal(20d, peer.Maximum);
Assert.Equal(14d, peer.Value);
Assert.Equal(3d, peer.SmallChange);
Assert.Equal(3d, peer.LargeChange);
Assert.True(peer.IsReadOnly);
}
[Fact]
public void Null_Value_Reports_Default_Clamped_To_Range()
{
var control = new NumericUpDown
{
Minimum = 10,
Maximum = 20,
Value = null,
};
var peer = (IRangeValueProvider)ControlAutomationPeer.CreatePeerForElement(control);
Assert.Equal(10d, peer.Value);
}
[Fact]
public void SetValue_Updates_Owner_Value()
{
var control = new NumericUpDown();
var peer = (IRangeValueProvider)ControlAutomationPeer.CreatePeerForElement(control);
peer.SetValue(42.5);
Assert.Equal(42.5m, control.Value);
}
[Fact]
public void PropertyChanged_Raises_Range_When_Value_Changes()
{
var control = new NumericUpDown();
var peer = (NumericUpDownAutomationPeer)ControlAutomationPeer.CreatePeerForElement(control);
AutomationPropertyChangedEventArgs? changed = null;
peer.PropertyChanged += (_, e) =>
{
if (e.Property == RangeValuePatternIdentifiers.ValueProperty)
changed = e;
};
control.Value = 7.5m;
Assert.NotNull(changed);
Assert.Equal(RangeValuePatternIdentifiers.ValueProperty, changed!.Property);
Assert.Null(changed.OldValue);
Assert.Equal(7.5m, changed.NewValue);
}
}
}

73
tests/Avalonia.Controls.UnitTests/Automation/NativeMenuBarAutomationPeerTests.cs

@ -0,0 +1,73 @@
using System.Linq;
using Avalonia;
using Avalonia.Automation;
using Avalonia.Automation.Peers;
using Avalonia.Controls;
using Avalonia.Controls.Templates;
using Avalonia.UnitTests;
using Avalonia.VisualTree;
using Xunit;
namespace Avalonia.Controls.UnitTests.Automation;
public class NativeMenuBarAutomationPeerTests
{
public class PeerCreation : ScopedTestBase
{
[Fact]
public void Creates_NativeMenuBarAutomationPeer()
{
var control = new NativeMenuBar { Template = CreateTemplate() };
var peer = ControlAutomationPeer.CreatePeerForElement(control);
Assert.IsType<NativeMenuBarAutomationPeer>(peer);
}
[Fact]
public void ControlType_Is_MenuBar()
{
var control = new NativeMenuBar { Template = CreateTemplate() };
var peer = (NativeMenuBarAutomationPeer)ControlAutomationPeer.CreatePeerForElement(control);
Assert.Equal(AutomationControlType.MenuBar, peer.GetAutomationControlType());
}
}
public class Children : ScopedTestBase
{
[Fact]
public void Exposes_Realized_MenuItems_Via_VisualChildren()
{
var control = new NativeMenuBar { Template = CreateTemplate() };
control.ApplyTemplate();
var menu = Assert.IsType<Menu>(control.GetVisualChildren().Single());
menu.ApplyTemplate();
menu.Measure(Size.Infinity);
menu.Arrange(new Rect(0, 0, 300, 30));
control.Measure(Size.Infinity);
control.Arrange(new Rect(0, 0, 300, 30));
var peer = (NativeMenuBarAutomationPeer)ControlAutomationPeer.CreatePeerForElement(control);
var presenterChildren = peer.GetChildren();
Assert.Equal(2, presenterChildren.Count);
Assert.All(presenterChildren, x => Assert.IsType<MenuItemAutomationPeer>(x));
Assert.Equal("File", presenterChildren[0].GetName());
Assert.Equal("Edit", presenterChildren[1].GetName());
}
}
private static FuncControlTemplate CreateTemplate()
{
return new FuncControlTemplate((_, ns) =>
new Menu
{
Name = "PART_NativeMenuPresenter",
Items =
{
new MenuItem { Header = "File" },
new MenuItem { Header = "Edit" },
},
}.RegisterInNameScope(ns));
}
}

196
tests/Avalonia.Controls.UnitTests/Automation/SplitButtonAutomationPeerTests.cs

@ -0,0 +1,196 @@
using Avalonia.Automation;
using Avalonia.Automation.Peers;
using Avalonia.Automation.Provider;
using Avalonia.Controls;
using Avalonia.UnitTests;
using Xunit;
namespace Avalonia.Controls.UnitTests.Automation;
public class SplitButtonAutomationPeerTests : ScopedTestBase
{
[Fact]
public void Creates_SplitButtonAutomationPeer()
{
var target = new SplitButton();
var peer = ControlAutomationPeer.CreatePeerForElement(target);
Assert.IsType<SplitButtonAutomationPeer>(peer);
}
[Fact]
public void Implements_IExpandCollapseProvider()
{
var target = new SplitButton();
var peer = ControlAutomationPeer.CreatePeerForElement(target);
Assert.IsAssignableFrom<IExpandCollapseProvider>(peer);
}
[Fact]
public void Implements_IInvokeProvider()
{
var target = new SplitButton();
var peer = ControlAutomationPeer.CreatePeerForElement(target);
Assert.IsAssignableFrom<IInvokeProvider>(peer);
}
[Fact]
public void ControlType_Is_SplitButton()
{
var target = new SplitButton();
var peer = (SplitButtonAutomationPeer)ControlAutomationPeer.CreatePeerForElement(target);
Assert.Equal(AutomationControlType.SplitButton, peer.GetAutomationControlType());
}
[Fact]
public void ClassName_Is_SplitButton()
{
var target = new SplitButton();
var peer = (SplitButtonAutomationPeer)ControlAutomationPeer.CreatePeerForElement(target);
Assert.Equal("SplitButton", peer.GetClassName());
}
[Fact]
public void ShowsMenu_Is_True()
{
var target = new SplitButton();
var peer = (IExpandCollapseProvider)ControlAutomationPeer.CreatePeerForElement(target);
Assert.True(peer.ShowsMenu);
}
[Fact]
public void Invoke_Triggers_Click()
{
var clicked = 0;
var target = new SplitButton();
var peer = (IInvokeProvider)ControlAutomationPeer.CreatePeerForElement(target);
target.Click += (_, _) => clicked++;
peer.Invoke();
Assert.Equal(1, clicked);
}
[Fact]
public void ExpandCollapse_State_Tracks_Flyout()
{
using (UnitTestApplication.Start(TestServices.StyledWindow))
{
var target = new SplitButton
{
Flyout = new Flyout()
};
var window = new Window
{
Content = target,
};
window.Show();
var peer = (SplitButtonAutomationPeer)ControlAutomationPeer.CreatePeerForElement(target);
Assert.Equal(ExpandCollapseState.Collapsed, peer.ExpandCollapseState);
peer.Expand();
Assert.Equal(ExpandCollapseState.Expanded, peer.ExpandCollapseState);
Assert.True(target.Flyout?.IsOpen);
peer.Collapse();
Assert.Equal(ExpandCollapseState.Collapsed, peer.ExpandCollapseState);
Assert.False(target.Flyout!.IsOpen);
}
}
[Fact]
public void ExpandCollapse_Raises_PropertyChanged()
{
using (UnitTestApplication.Start(TestServices.StyledWindow))
{
var target = new SplitButton
{
Flyout = new Flyout()
};
var window = new Window
{
Content = target,
};
window.Show();
var peer = (SplitButtonAutomationPeer)ControlAutomationPeer.CreatePeerForElement(target);
AutomationPropertyChangedEventArgs? changed = null;
peer.PropertyChanged += (_, e) =>
{
if (e.Property == ExpandCollapsePatternIdentifiers.ExpandCollapseStateProperty)
{
changed = e;
}
};
peer.Expand();
Assert.NotNull(changed);
Assert.Equal(ExpandCollapseState.Collapsed, changed!.OldValue);
Assert.Equal(ExpandCollapseState.Expanded, changed.NewValue);
}
}
}
public class ToggleSplitButtonAutomationPeerTests : ScopedTestBase
{
[Fact]
public void Creates_ToggleSplitButtonAutomationPeer()
{
var target = new ToggleSplitButton();
var peer = ControlAutomationPeer.CreatePeerForElement(target);
Assert.IsType<ToggleSplitButtonAutomationPeer>(peer);
}
[Fact]
public void Implements_IToggleProvider()
{
var target = new ToggleSplitButton();
var peer = ControlAutomationPeer.CreatePeerForElement(target);
Assert.IsAssignableFrom<IToggleProvider>(peer);
}
[Fact]
public void ControlType_Is_SplitButton()
{
var target = new ToggleSplitButton();
var peer = (SplitButtonAutomationPeer)ControlAutomationPeer.CreatePeerForElement(target);
Assert.Equal(AutomationControlType.SplitButton, peer.GetAutomationControlType());
}
[Fact]
public void ClassName_Is_ToggleSplitButton()
{
var target = new ToggleSplitButton();
var peer = (ToggleSplitButtonAutomationPeer)ControlAutomationPeer.CreatePeerForElement(target);
Assert.Equal("ToggleSplitButton", peer.GetClassName());
}
[Fact]
public void Toggle_Changes_IsChecked_And_Fires_Click()
{
var clicked = 0;
var target = new ToggleSplitButton();
var peer = (IToggleProvider)ControlAutomationPeer.CreatePeerForElement(target);
Assert.Equal(ToggleState.Off, peer.ToggleState);
target.Click += (_, _) => clicked++;
peer.Toggle();
Assert.True(target.IsChecked);
Assert.Equal(ToggleState.On, peer.ToggleState);
Assert.Equal(1, clicked);
}
}

1
tests/Avalonia.Controls.UnitTests/Avalonia.Controls.UnitTests.csproj

@ -21,6 +21,7 @@
<ProjectReference Include="..\..\src\Markup\Avalonia.Markup.Xaml.Loader\Avalonia.Markup.Xaml.Loader.csproj" />
<ProjectReference Include="..\..\src\Markup\Avalonia.Markup.Xaml\Avalonia.Markup.Xaml.csproj" />
<ProjectReference Include="..\..\src\Markup\Avalonia.Markup\Avalonia.Markup.csproj" />
<ProjectReference Include="..\..\src\Avalonia.Controls.ColorPicker\Avalonia.Controls.ColorPicker.csproj" />
<ProjectReference Include="..\..\src\Avalonia.Base\Avalonia.Base.csproj" />
<ProjectReference Include="..\..\src\Avalonia.Controls\Avalonia.Controls.csproj" />
<ProjectReference Include="..\Avalonia.UnitTests\Avalonia.UnitTests.csproj" />

Loading…
Cancel
Save