Skip to main content

Interaction recipes

These examples use standard Avalonia controls and work with either ProTest xUnit adapter. Start with the xUnit setup and load your application's theme for template-dependent controls such as TextBox. Each test closes its window during cleanup.

Find a control and enter text​

Use the driver when a test should describe a sequence of user interactions. Tree queries can then verify that a locator selected the intended control.

using System.Linq;
using Avalonia.Controls;
using Avalonia.Headless.XUnit;
using Avalonia.HeadlessTestingFramework;
using Avalonia.HeadlessTestingFramework.Appium;
using Xunit;

public class EditorInteractionTests
{
[AvaloniaFact]
public void Typing_updates_the_named_editor()
{
var editor = new TextBox { Name = "editor" };
var window = new Window { Content = editor, Width = 240, Height = 80 };
try
{
window.Show();
using var driver = new AvaloniaDriver(window);
driver.FindElement(By.Id("editor")).SendKeys("ProTest helpers");

Assert.Equal("ProTest helpers", editor.Text);
Assert.Same(editor, window.Find<TextBox>().FindFirst<TextBox>());
Assert.Same(editor,
new TreeXPath(window)
.Select<TextBox>("//TextBox[@Name='editor']")
.Single());
}
finally
{
window.Close();
}
}
}

See driver and elements for additional locators and actions, or control finder for fluent tree filters.

Verify a complete touch drag​

Observe the pointer events delivered to a control, including the final position and release of capture. This helps test controls that implement their own dragging behavior.

using System.Collections.Generic;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Headless.XUnit;
using Avalonia.HeadlessTestingFramework;
using Avalonia.Media;
using Xunit;

public class TouchInteractionTests
{
[AvaloniaFact]
public void Drag_delivers_press_moves_and_release()
{
var target = new Border { Background = Brushes.White };
var window = new Window { Content = target, Width = 200, Height = 100 };
var pressed = 0;
var positions = new List<Point>();
var released = 0;

target.PointerPressed += (_, _) => pressed++;
target.PointerMoved += (_, e) => positions.Add(e.GetPosition(target));
target.PointerReleased += (_, _) => released++;

try
{
window.Show();
var touch = new GestureRecognizerTestHelper();
touch.Drag(target, new Point(10, 10), new Point(90, 50), steps: 4);

Assert.Equal(1, pressed);
Assert.Equal(4, positions.Count);
Assert.Equal(new Point(90, 50), positions[^1]);
Assert.Equal(1, released);
Assert.Null(touch.Captured);
}
finally
{
window.Close();
}
}
}

For pinch, scroll, or other recognizer-driven gestures, register gesture handlers before showing the window. Use multi-touch helpers when the test needs several independent pointers.

Record and inspect a rendered frame​

Configure Skia rendering before running this test. It records a PNG sequence and decodes the resulting image to check its dimensions. PNG capture does not require FFmpeg.

using System;
using System.IO;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Headless.XUnit;
using Avalonia.HeadlessTestingFramework.Recording;
using Avalonia.Media;
using Avalonia.Media.Imaging;
using Xunit;

public class RecordingInteractionTests
{
[AvaloniaFact]
public void Recording_writes_a_rendered_image()
{
var output = Path.Combine(
Path.GetTempPath(), "ProTest-recording-" + Guid.NewGuid().ToString("N"));
var window = new Window
{
Width = 120,
Height = 80,
Content = new Border { Background = Brushes.CornflowerBlue }
};

try
{
window.Show();
using var recorder = new HeadlessScreenRecorder();
recorder.StartRecording(window,
new RecordingOptions { Format = RecordingFormat.PngSequence }, output);

Assert.True(recorder.CaptureFrame(), recorder.LastCaptureFailureReason);
var statistics = recorder.StopRecording();

Assert.True(statistics.FramesCaptured > 0);
var frames = Directory.GetFiles(output, "*.png");
Assert.NotEmpty(frames);
using var image = new Bitmap(frames[0]);
Assert.Equal(new PixelSize(120, 80), image.PixelSize);
}
finally
{
window.Close();
if (Directory.Exists(output))
Directory.Delete(output, recursive: true);
}
}
}

For diagnostic recordings in CI, retain the output directory as a build artifact instead of deleting it. Recorded input combines capture with scripted interactions; video conversion explains the optional FFmpeg workflow.