avalonia-testing
Skill50 starsChanged 7 days agoMITView on GitHub
Use when writing tests for Avalonia apps — headless UI testing, ViewModel unit tests, UI automation, or setting up the Avalonia test infrastructure.
In this repository23 other files it gives its agents.
- avalonia-app-developmentSkill
- avalonia-controlsSkill
- avalonia-custom-controlsSkill
- avalonia-data-bindingSkill
- avalonia-data-templatesSkill
- avalonia-deploymentSkill
- avalonia-eventsSkill
- avalonia-graphics-animationSkill
- avalonia-input-interactionSkill
- avalonia-interop-renderingSkill
- avalonia-layoutSkill
- avalonia-mobileSkill
- avalonia-mvvmSkill
- avalonia-performanceSkill
- avalonia-pro-maxSkill
- avalonia-property-systemSkill
- avalonia-servicesSkill
- avalonia-stylingSkill
- avalonia-threadingSkill
- avalonia-versionsSkill
- avalonia-wpf-migrationSkill
- avalonia-xamlSkill
- avaloniaSkill
The file
We split this skill into the rules it gives an agent
2 rules. About 0 are common, 1 is distinctive, and 1 is very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈1
Distinctive · estimate
This author's own choices. Worth a look.
1
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 11
No special setup needed — ViewModels are plain C# classes:
- Very specific: line 42
Test framework: 12.0+ requires xUnit v3 / NUnit 4 (Avalonia.Headless.XUnit 12.1.4 depends on xunit.v3.extensibility.core).
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Avalonia Testing
Overview
Two testing approaches: ViewModel unit tests (no Avalonia needed, plain xUnit/NUnit), and headless UI tests using Avalonia.Headless (renders without a display).
ViewModel Unit Tests (No UI)
No special setup needed — ViewModels are plain C# classes:
[Fact]
public void Name_Change_RaisesPropertyChanged()
{
var vm = new MainViewModel();
var raised = new List<string?>();
vm.PropertyChanged += (_, e) => raised.Add(e.PropertyName);
vm.Name = "Alice";
Assert.Contains(nameof(vm.Name), raised);
Assert.Equal("Alice", vm.Name);
}
[Fact]
public async Task SaveCommand_WhenNameEmpty_CannotExecute()
{
var vm = new MainViewModel { Name = "" };
Assert.False(vm.SaveCommand.CanExecute(null));
}Headless Testing Setup
NuGet packages (same version as Avalonia):
Avalonia.HeadlessAvalonia.Headless.XUnit(orAvalonia.Headless.NUnit)Avalonia.Themes.Fluent(controls need a theme)Avalonia.Skia(real rendering for screenshots)Avalonia.HarfBuzz(12.0+; omit on 11.x)
Test framework: 12.0+ requires xUnit v3 / NUnit 4 (Avalonia.Headless.XUnit 12.1.4 depends on xunit.v3.extensibility.core). (11.x) xUnit v2 / NUnit 3.
// Assembly-level attribute (AssemblyInfo.cs or top of test file)
[assembly: AvaloniaTestApplication(typeof(TestAppBuilder))]
public class TestAppBuilder
{
public static AppBuilder BuildAvaloniaApp()
=> AppBuilder.Configure<App>()
.UseSkia()
.UseHarfBuzz() // 12.0+; omit on 11.x
.UseHeadless(new AvaloniaHeadlessPlatformOptions { UseHeadlessDrawing = false });
}CaptureRenderedFrame() requires Skia with UseHeadlessDrawing = false. The lightweight UseHeadlessDrawing = true backend is suitable for tests that do not capture screenshots. Avalonia 12 also requires UseHarfBuzz() when configuring Skia explicitly. On Avalonia 11.x, omit both the Avalonia.HarfBuzz package and the .UseHarfBuzz() call.
Optional isolation: [assembly: AvaloniaTestIsolation(AvaloniaTestIsolationLevel.PerAssembly)] (default PerTest recreates Application + Dispatcher; PerAssembly shares state, no concurrent tests). Use [AvaloniaTheory] instead of [Theory].
Writing Headless Tests (xUnit)
public class MainWindowTests
{
[AvaloniaFact]
public void Button_Click_UpdatesViewModel()
{
var window = new MainWindow();
var vm = new MainViewModel();
window.DataContext = vm;
window.Show();
var button = window.FindControl<Button>("SaveButton")!;
button.RaiseEvent(new RoutedEventArgs(Button.ClickEvent));
Assert.True(vm.SaveWasCalled);
}
[AvaloniaFact]
public async Task TextBox_Input_UpdatesBinding()
{
var window = new MainWindow();
window.DataContext = new MainViewModel();
window.Show();
var textBox = window.FindControl<TextBox>("NameBox")!;
textBox.RaiseTextInput("Hello");
await Task.Delay(50); // allow binding to propagate
Assert.Equal("Hello", ((MainViewModel)window.DataContext!).Name);
}
}Finding Controls
// By name (x:Name)
var btn = window.FindControl<Button>("MyButton");
// By type (first match)
var textBox = window.FindDescendantOfType<TextBox>();
// All of type
var allButtons = window.GetVisualDescendants().OfType<Button>();Simulating Input
// Keyboard
window.KeyPressQwerty(PhysicalKey.Enter, RawInputModifiers.None);
window.KeyTextInput("Hello");
// Mouse/Pointer
window.MouseDown(new Point(100, 50), MouseButton.Left);
window.MouseMove(new Point(150, 50));
window.MouseUp(new Point(150, 50), MouseButton.Left);
// DPI / render scaling (12.0+)
window.SetRenderScaling(2.0);Screenshot Testing
[AvaloniaFact]
public void Window_RendersCorrectly()
{
var window = new MainWindow();
window.Show();
// Capture frame as bitmap
var bitmap = window.CaptureRenderedFrame()!;
// Compare or save for regression
bitmap.Save("snapshot.png");
}Testing with NUnit
[TestFixture]
public class Tests
{
[AvaloniaTest] // instead of [Test]
public void MyTest() { }
}Community Testing Libraries
| Library | NuGet | Purpose |
| Verify.Avalonia | Verify.Avalonia | Extends Verify for snapshot/approval testing of Avalonia UI |
Snapshot Testing with Verify.Avalonia
[AvaloniaFact]
public async Task Window_MatchesSnapshot()
{
var window = new MainWindow();
window.Show();
await Verify(window); // saves .verified.png on first run, diffs on subsequent
}Requires: Verify.Avalonia + Verify.Xunit (or NUnit variant).
On first run, creates a .verified.png baseline. Subsequent runs diff against it — fails on visual regression.
Common Mistakes
- 12.x project still on xUnit v2 / NUnit 3 — Headless packages need xUnit v3 / NUnit 4
- Missing
[assembly: AvaloniaTestApplication]— headless renderer not initialized, NullReferenceException - Using
[Fact]instead of[AvaloniaFact]for UI tests — no Avalonia dispatcher, random failures - Forgetting
window.Show()before interacting — controls not attached to visual tree - Testing bindings synchronously — bindings may be async, add small delay or use
Dispatcher.UIThread.RunJobs()
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

