Merge pull request #536 from irihitech/tests

Add tests for AutoCompleteBox and Banner
This commit is contained in:
Dong Bin
2025-01-10 22:13:49 +08:00
committed by GitHub
9 changed files with 242 additions and 18 deletions

View File

@@ -65,4 +65,4 @@
</u:Form> </u:Form>
</StackPanel> </StackPanel>
</ScrollViewer> </ScrollViewer>
</UserControl> </UserControl>

View File

@@ -1,3 +1,5 @@
using System.Diagnostics;
using Avalonia;
using Avalonia.Controls; using Avalonia.Controls;
using Avalonia.Controls.Primitives; using Avalonia.Controls.Primitives;
using Avalonia.Input; using Avalonia.Input;
@@ -8,8 +10,6 @@ namespace Ursa.Controls;
public class AutoCompleteBox: Avalonia.Controls.AutoCompleteBox, IClearControl public class AutoCompleteBox: Avalonia.Controls.AutoCompleteBox, IClearControl
{ {
// protected override Type StyleKeyOverride { get; } = typeof(Avalonia.Controls.AutoCompleteBox);
private TextBox? _text;
static AutoCompleteBox() static AutoCompleteBox()
{ {
MinimumPrefixLengthProperty.OverrideDefaultValue<AutoCompleteBox>(0); MinimumPrefixLengthProperty.OverrideDefaultValue<AutoCompleteBox>(0);
@@ -17,15 +17,9 @@ public class AutoCompleteBox: Avalonia.Controls.AutoCompleteBox, IClearControl
public AutoCompleteBox() public AutoCompleteBox()
{ {
this.AddHandler(PointerPressedEvent, OnBoxPointerPressed, RoutingStrategies.Tunnel); AddHandler(PointerPressedEvent, OnBoxPointerPressed, RoutingStrategies.Tunnel);
} }
protected override void OnApplyTemplate(TemplateAppliedEventArgs e)
{
base.OnApplyTemplate(e);
_text = e.NameScope.Get<TextBox>("PART_TextBox");
}
private void OnBoxPointerPressed(object? sender, PointerPressedEventArgs e) private void OnBoxPointerPressed(object? sender, PointerPressedEventArgs e)
{ {
if (Equals(sender, this) && e.GetCurrentPoint(this).Properties.IsLeftButtonPressed) if (Equals(sender, this) && e.GetCurrentPoint(this).Properties.IsLeftButtonPressed)
@@ -37,6 +31,7 @@ public class AutoCompleteBox: Avalonia.Controls.AutoCompleteBox, IClearControl
protected override void OnGotFocus(GotFocusEventArgs e) protected override void OnGotFocus(GotFocusEventArgs e)
{ {
base.OnGotFocus(e); base.OnGotFocus(e);
if (IsDropDownOpen) return;
SetCurrentValue(IsDropDownOpenProperty, true); SetCurrentValue(IsDropDownOpenProperty, true);
} }

View File

@@ -1,4 +1,5 @@
using Avalonia; using System.Diagnostics.CodeAnalysis;
using Avalonia;
using Avalonia.Controls; using Avalonia.Controls;
using Avalonia.Media; using Avalonia.Media;
@@ -12,12 +13,14 @@ public class Avatar : Button
public static readonly StyledProperty<object?> HoverMaskProperty = AvaloniaProperty.Register<Avatar, object?>( public static readonly StyledProperty<object?> HoverMaskProperty = AvaloniaProperty.Register<Avatar, object?>(
nameof(HoverMask)); nameof(HoverMask));
[ExcludeFromCodeCoverage]
public IImage? Source public IImage? Source
{ {
get => GetValue(SourceProperty); get => GetValue(SourceProperty);
set => SetValue(SourceProperty, value); set => SetValue(SourceProperty, value);
} }
[ExcludeFromCodeCoverage]
public object? HoverMask public object? HoverMask
{ {
get => GetValue(HoverMaskProperty); get => GetValue(HoverMaskProperty);

View File

@@ -1,8 +1,10 @@
using System.Diagnostics.CodeAnalysis;
using Avalonia; using Avalonia;
using Avalonia.Controls; using Avalonia.Controls;
using Avalonia.Controls.Metadata; using Avalonia.Controls.Metadata;
using Avalonia.Controls.Notifications; using Avalonia.Controls.Notifications;
using Avalonia.Controls.Primitives; using Avalonia.Controls.Primitives;
using Avalonia.Input;
using Avalonia.Interactivity; using Avalonia.Interactivity;
using Irihi.Avalonia.Shared.Helpers; using Irihi.Avalonia.Shared.Helpers;
@@ -20,15 +22,17 @@ public class Banner: HeaderedContentControl
public static readonly StyledProperty<bool> CanCloseProperty = AvaloniaProperty.Register<Banner, bool>( public static readonly StyledProperty<bool> CanCloseProperty = AvaloniaProperty.Register<Banner, bool>(
nameof(CanClose)); nameof(CanClose));
[ExcludeFromCodeCoverage]
public bool CanClose public bool CanClose
{ {
get => GetValue(CanCloseProperty); get => GetValue(CanCloseProperty);
set => SetValue(CanCloseProperty, value); set => SetValue(CanCloseProperty, value);
} }
public static readonly StyledProperty<bool> ShowIconProperty = AvaloniaProperty.Register<Banner, bool>( public static readonly StyledProperty<bool> ShowIconProperty = AvaloniaProperty.Register<Banner, bool>(
nameof(ShowIcon), true); nameof(ShowIcon), true);
[ExcludeFromCodeCoverage]
public bool ShowIcon public bool ShowIcon
{ {
get => GetValue(ShowIconProperty); get => GetValue(ShowIconProperty);
@@ -38,6 +42,7 @@ public class Banner: HeaderedContentControl
public static readonly StyledProperty<object?> IconProperty = AvaloniaProperty.Register<Banner, object?>( public static readonly StyledProperty<object?> IconProperty = AvaloniaProperty.Register<Banner, object?>(
nameof(Icon)); nameof(Icon));
[ExcludeFromCodeCoverage]
public object? Icon public object? Icon
{ {
get => GetValue(IconProperty); get => GetValue(IconProperty);
@@ -47,6 +52,7 @@ public class Banner: HeaderedContentControl
public static readonly StyledProperty<NotificationType> TypeProperty = AvaloniaProperty.Register<Banner, NotificationType>( public static readonly StyledProperty<NotificationType> TypeProperty = AvaloniaProperty.Register<Banner, NotificationType>(
nameof(Type)); nameof(Type));
[ExcludeFromCodeCoverage]
public NotificationType Type public NotificationType Type
{ {
get => GetValue(TypeProperty); get => GetValue(TypeProperty);
@@ -63,6 +69,6 @@ public class Banner: HeaderedContentControl
private void OnCloseClick(object? sender, RoutedEventArgs args) private void OnCloseClick(object? sender, RoutedEventArgs args)
{ {
IsVisible = false; SetCurrentValue(IsVisibleProperty, false);
} }
} }

View File

@@ -0,0 +1,100 @@
using Avalonia;
using Avalonia.Controls;
using Avalonia.Headless;
using Avalonia.Headless.XUnit;
using Avalonia.Input;
using Avalonia.Layout;
using UrsaControl = Ursa.Controls;
namespace HeadlessTest.Ursa.Controls.AutoCompleteBoxTests;
public class Tests
{
[AvaloniaFact]
// Ideally Should not open popup when there is no items, but sub class have no access to this status.
public void AutoCompleteBox_Focus_And_LostFocus()
{
var window = new Window();
var autoCompleteBox = new UrsaControl.AutoCompleteBox()
{
HorizontalAlignment = HorizontalAlignment.Left,
VerticalAlignment = VerticalAlignment.Top,
Width = 100,
Height = 100,
};
var textBox = new TextBox()
{
Width = 100, Height = 100,
};
window.Content = new StackPanel()
{
Children = { autoCompleteBox, textBox }
};
window.Show();
Assert.False(autoCompleteBox.IsDropDownOpen);
autoCompleteBox.Focus();
Assert.True(autoCompleteBox.IsDropDownOpen);
textBox.Focus();
Assert.False(autoCompleteBox.IsDropDownOpen);
}
[AvaloniaFact]
public void Click_AutoCompleteBox_With_Mouse_Should_Open_Dropdown()
{
var window = new Window();
var autoCompleteBox = new UrsaControl.AutoCompleteBox()
{
HorizontalAlignment = HorizontalAlignment.Left,
VerticalAlignment = VerticalAlignment.Top,
Width = 100,
Height = 100,
ItemsSource = new List<string> {"Hello", "World"}
};
window.Content = autoCompleteBox;
window.Show();
Assert.False(autoCompleteBox.IsDropDownOpen);
window.MouseDown(new Point(10, 10), MouseButton.Left);
Assert.True(autoCompleteBox.IsDropDownOpen);
}
[AvaloniaFact]
public void Click_AutoCompleteBox_With_Mouse_Should_NotOpen_Dropdown_When_Empty()
{
var window = new Window();
var autoCompleteBox = new UrsaControl.AutoCompleteBox()
{
HorizontalAlignment = HorizontalAlignment.Left,
VerticalAlignment = VerticalAlignment.Top,
Width = 100,
Height = 100,
};
window.Content = autoCompleteBox;
window.Show();
Assert.False(autoCompleteBox.IsDropDownOpen);
window.MouseDown(new Point(10, 10), MouseButton.Left);
Assert.False(autoCompleteBox.IsDropDownOpen);
}
[AvaloniaFact]
public void Right_Click_AutoCompleteBox_With_Mouse_Should_NotOpen_Dropdown()
{
var window = new Window();
var autoCompleteBox = new UrsaControl.AutoCompleteBox()
{
HorizontalAlignment = HorizontalAlignment.Left,
VerticalAlignment = VerticalAlignment.Top,
Width = 100,
Height = 100,
ItemsSource = new List<string> {"Hello", "World"},
};
window.Content = autoCompleteBox;
window.Show();
Assert.False(autoCompleteBox.IsDropDownOpen);
window.MouseDown(new Point(10, 10), MouseButton.Right);
Assert.False(autoCompleteBox.IsDropDownOpen);
}
}

View File

@@ -0,0 +1,87 @@
using Avalonia;
using Avalonia.Controls;
using Avalonia.Controls.Shapes;
using Avalonia.Controls.Templates;
using Avalonia.Headless;
using Avalonia.Headless.XUnit;
using Avalonia.Input;
using Avalonia.Media;
using Avalonia.VisualTree;
using UrsaControls = Ursa.Controls;
namespace HeadlessTest.Ursa.Controls.BannerTests;
public class Tests
{
[AvaloniaFact]
public void Click_On_Banner_Close_Button_Should_Hide_Banner()
{
// Arrange
var window = new Window();
var banner = new UrsaControls.Banner()
{
HorizontalAlignment = Avalonia.Layout.HorizontalAlignment.Left,
VerticalAlignment = Avalonia.Layout.VerticalAlignment.Top,
Width = 300,
Height = 100,
CanClose = true
};
window.Content = banner;
window.Show();
Assert.True(banner.IsVisible);
var closeButton = banner.GetTemplateChildren().OfType<Button>()
.FirstOrDefault(a => a.Name == UrsaControls.Banner.PART_CloseButton);
Assert.NotNull(closeButton);
Assert.True(closeButton.IsVisible);
var clickPosition = closeButton.Bounds.Center;
clickPosition = new Point(clickPosition.X + 20, clickPosition.Y + 20);
// Act
window.MouseDown(clickPosition, MouseButton.Left);
window.MouseUp(clickPosition, MouseButton.Left);
// Assert
Assert.False(banner.IsVisible);
}
[AvaloniaFact]
public void Click_On_Banner_Does_Nothing_If_Cannot_Close()
{
// Arrange
var window = new Window();
var banner = new UrsaControls.Banner()
{
HorizontalAlignment = Avalonia.Layout.HorizontalAlignment.Left,
VerticalAlignment = Avalonia.Layout.VerticalAlignment.Top,
Width = 300,
Height = 100,
CanClose = false
};
window.Content = banner;
window.Show();
Assert.True(banner.IsVisible);
var closeButton = banner.GetTemplateChildren().OfType<Button>()
.FirstOrDefault(a => a.Name == UrsaControls.Banner.PART_CloseButton);
Assert.NotNull(closeButton);
Assert.False(closeButton.IsVisible);
var clickPosition = closeButton.Bounds.Center;
clickPosition = new Point(clickPosition.X + 20, clickPosition.Y + 20);
// Act
window.MouseDown(clickPosition, MouseButton.Left);
window.MouseUp(clickPosition, MouseButton.Left);
// Assert
Assert.True(banner.IsVisible);
}
}

View File

@@ -10,11 +10,12 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Avalonia.Headless.XUnit" Version="11.1.3" /> <PackageReference Include="Avalonia.Headless.XUnit" Version="11.2.3" />
<PackageReference Include="Avalonia.Skia" Version="11.2.3" />
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.2.0" /> <PackageReference Include="CommunityToolkit.Mvvm" Version="8.2.0" />
<PackageReference Include="coverlet.collector" Version="6.0.0"/> <PackageReference Include="coverlet.collector" Version="6.0.0"/>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.8.0"/> <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.8.0"/>
<PackageReference Include="Semi.Avalonia" Version="11.1.0.4" /> <PackageReference Include="Semi.Avalonia" Version="11.2.1.3" />
<PackageReference Include="xunit" Version="2.5.3"/> <PackageReference Include="xunit" Version="2.5.3"/>
<PackageReference Include="xunit.runner.visualstudio" Version="2.5.3"/> <PackageReference Include="xunit.runner.visualstudio" Version="2.5.3"/>
</ItemGroup> </ItemGroup>

View File

@@ -9,5 +9,17 @@ namespace HeadlessTest.Ursa;
public class TestAppBuilder public class TestAppBuilder
{ {
public static AppBuilder BuildAvaloniaApp() => public static AppBuilder BuildAvaloniaApp() =>
AppBuilder.Configure<App>().UseHeadless(new AvaloniaHeadlessPlatformOptions()); AppBuilder
} .Configure<App>()
.UseHeadless(new AvaloniaHeadlessPlatformOptions());
}
public class SkiaTestAppBuilder
{
public static AppBuilder BuildAvaloniaApp() =>
AppBuilder
.Configure<App>()
.UseSkia()
.UseHeadless(new AvaloniaHeadlessPlatformOptions(){ UseHeadlessDrawing = false});
}

View File

@@ -0,0 +1,20 @@
using Avalonia;
using Avalonia.Controls;
using Avalonia.Controls.Primitives;
using Avalonia.Input;
using Avalonia.Remote.Protocol.Input;
using AutoCompleteBox = Ursa.Controls.AutoCompleteBox;
namespace Test.Ursa.AutoCompleteBoxTests;
public class Tests
{
[Fact]
public void Clear_SetsSelectedItemToNull()
{
var autoCompleteBox = new AutoCompleteBox();
autoCompleteBox.SelectedItem = "TestItem";
autoCompleteBox.Clear();
Assert.Null(autoCompleteBox.SelectedItem);
}
}