Element
An Element
represents a WPF element within the current application visual tree. It can be interacted with and queried in all expected ways. An element is accessible via GetElement(s)
on the AppDriver
class.
The properties of an Element
are automatically updated whenever there is a change in the application's state. For example, if additional text is entered into a field, the value of input["Text"]
will be updated accordingly.
Methods
Element Click()
Issues a full Click
event using the left mouse button on the underlying WPF element, including PreviewMouseDown
, MouseDown
and then PreviewMouseUp
and MouseUp
. The MouseDevice
will be properly hooked to read correct mouse down and mouse up values, as well as the IsMouseOver
property on each element in the visual tree.
⚠️ The mouse position cannot be hooked and should not be relied on to calculate IsMouseOver
. You may need to refactor your code to use the IsMouseOver
property directly instead.
The current element is returned to allow chaining methods.
Usage
element.Click();
Element RightClick()
Issues a full Click
event using the right mouse button on the underlying WPF element including PreviewMouseDown
, MouseDown
and then PreviewMouseUp
and MouseUp
. The MouseDevice
will be properly hooked to read correct mouse down and mouse up values, as well as the IsMouseOver
property on each element in the visual tree.
⚠️ The mouse position cannot be hooked and should not be relied on to calculate IsMouseOver
. You may need to refactor your code to use the IsMouseOver
property directly instead.
The current element is returned to allow chaining methods.
Usage
element.RightClick();
Element DoubleClick()
Raises a MouseDoubleClickEvent
on the underlying WPF element using the left mouse button. The MouseDevice
will be properly hooked to read correct mouse down and mouse up values, as well as the IsMouseOver
property on each element in the visual tree.
⚠️ The mouse position cannot be hooked and should not be relied on to calculate IsMouseOver
. You may need to refactor your code to use the IsMouseOver
property directly instead.
The current element is returned to allow chaining methods.
Usage
element.DoubleClick();
Element Focus()
Invokes Focus()
on the underlying WPF element.
The current element is returned to allow chaining methods.
Usage
element.Focus();
Element Select()
Sets the IsSelected
property on the underlying WPF element to true
. If the element is a ListBoxItem
or the like, a subsequent selected event will be raised.
The current element is returned to allow chaining methods.
Usage
element.Select();
Element Expand()
Sets the IsExpanded
property on the underlying WPF element to true
. If the element is a Expander
or the like, a subsequent expanded event will be raised.
The current element is returned to allow chaining methods.
Usage
element.Expand();
Element Collapse()
Sets the IsExpanded
property on the underlying WPF element to false
. If the element is a Expander
or the like, a subsequent collapsed event will be raised.
The current element is returned to allow chaining methods.
Usage
element.Collapse();
Element SelectText(string text)
Finds the given text
on the underlying WPF element and sets the SelectionStart
and the SelectionLength
to match. If the text
cannot be found, SelectedText
is set instead, which appends the given text
on the control and then selects it. If the element is a TextBox
or the like, subsequent selection changed events will be raised.
The current element is returned to allow chaining methods.
Usage
element.SelectText("Hello world");
Element Check()
Sets the IsChecked
property on the underlying WPF element to true
. If the element is a CheckBox
or the like, a subsequent checked event will be raised.
The current element is returned to allow chaining methods.
Usage
element.Check();
Element Uncheck()
Sets the IsChecked
property on the underlying WPF element to false
. If the element is a CheckBox
or the like, a subsequent unchecked event will be raised.
The current element is returned to allow chaining methods.
Usage
element.Uncheck();
Element ScrollIntoView()
Invokes BringIntoView()
on the underlying WPF element.
The current element is returned to allow chaining methods.
Usage
element.ScrollIntoView();
Element Type(string text)
Invokes Focus()
and then PreviewTextInputEvent
on the underlying WPF element with the given text
. For most controls, this will simulate typing.
The current element is returned to allow chaining methods.
Usage
element.Type("My New Username");
Element Screenshot(string fileOutputPath)
Takes a screenshot of the underlying WPF element and saves it to fileOutputPath
. The code will briefly wait for the element to be visually stable before taking a screenshot.
The current element is returned to allow chaining methods.
Usage
element.Screenshot(@"C:\images\element.png");
element.Screenshot(@"%TEMP%\result.jpg");
Element Screenshot(out byte[] screenshotBytes, ImageFormat format = ImageFormat.Jpeg)
Takes a screenshot of the underlying WPF element as screenshotBytes
. The code will briefly wait for the element to be visually stable before taking a screenshot.
The current element is returned to allow chaining methods.
Usage
// jpg
element.Screenshot(out var bytes);
File.WriteAllBytes(@"C:\test-pic.jpg", bytes);
// png
element.Screenshot(out var bytes, ImageFormat.Png);
File.WriteAllBytes(@"C:\result.png", bytes);
byte[] Screenshot(ImageFormat format = ImageFormat.Jpeg)
Takes a screenshot of the underlying WPF element and returns it as an array of bytes
. The code will briefly wait for the element to be visually stable before taking a screenshot.
Usage
var bytes = element.Screenshot();
File.WriteAllBytes(@"%TEMP%\output.jpg", bytes);
Element RaiseEvent<TInput>(Expression<Func<TInput, RoutedEventArgs>> code)
Invokes RaiseEvent
on the underlying WPF element using the given code
expression to generate the input RoutedEventArgs
. If the underlying WPF element does not have any handlers for the given event, and it is a direct
routed event, it will iterate up the visual tree for a more appropriate target. If it cannot find one, the original element is used. The MouseDevice
and IsMouseOver
properties will be properly hooked if a mouse event is raised.
TInput
specifies the type of the underlying WPF element. UIElement
can be used if it is irrelevant.
The current element is returned to allow chaining methods.
Usage
// Raise event with `MouseButtonEventArgs`
element.RaiseEvent<UIElement>(_ => new MouseButtonEventArgs(
Mouse.PrimaryDevice,
Environment.TickCount,
MouseButton.Left)
{
RoutedEvent = Control.MouseDoubleClickEvent,
});
// Raise event with `TextCompositionEventArgs` on the underlying `TextBox`.
element.RaiseEvent<TextBox>(x => new TextCompositionEventArgs(
Keyboard.PrimaryDevice,
new TextComposition(InputManager.Current, x, x.Text + " Append some text!"))
{
RoutedEvent = UIElement.PreviewTextInputEvent,
Source = Keyboard.PrimaryDevice.FocusedElement,
});
TOutput Invoke<TInput, TOutput>(Expression<Func<TInput, TOutput>> code)
Invokes the given code
expression on the underlying WPF element and returns the result if it is serializable, or null
if it is not.
TInput
specifies the type of the underlying WPF element.
TOutput
specifies the type of the result.
Usage
var formId = element.Invoke<MyCustomControl, Guid>(x => x.GetFormId());
var richText = element.Invoke<RichTextEditor, string>(x => x.NormalizedRichText);
// Execute a private method on the underlying WPF element.
// `Invoke` is a WPF Pilot convenience extension method for executing private methods.
// There is also `Field` and `Property` for private fields and properties.
var registrationDate = element.Invoke<Calendar, DateTime>(x => x.Invoke<DateTime>("GetRegistrationDate"));
Element Invoke<TInput, TOutput>(Expression<Func<TInput, TOutput>> code, out TOutput? result)
Invokes the given code
expression on the underlying WPF element and returns the result to result
if it is serializable, or null
if it is not.
TInput
specifies the type of the underlying WPF element.
TOutput
specifies the type of the result.
The current element is returned to allow chaining methods.
Usage
element.Invoke<MyCustomControl, Guid>(x => x.GetFormId(), out var result);
Element Invoke(Expression<Action<UIElement>> code)
Invokes the given code
expression on the underlying WPF element.
The current element is returned to allow chaining methods.
Usage
element.Invoke(x => x.Focus());
Element Invoke<TInput>(Expression<Action<TInput>> code)
Invokes the given code
expression on the underlying WPF element.
TInput
specifies the type of the underlying WPF element.
The current element is returned to allow chaining methods.
Usage
element.Invoke<MyCoolControl>(x => x.ResetState());
TOutput InvokeAsync<TInput, TOutput>(Expression<Func<TInput, Task<TOutput>>> code)
Invokes the given async code
expression on the underlying WPF element and returns the awaited result if it is serializable, or null
if it is not.
TInput
specifies the type of the underlying WPF element.
TOutput
specifies the type of the result.
It is not possible to call await
within an expression, it will be handled by the Element
for you.
Usage
var formId = element.InvokeAsync<MyCustomControl, Guid>(x => x.GetFormIdAsync());
var richText = element.InvokeAsync<RichTextEditor, string>(x => x.FetchInitialAsync());
Element InvokeAsync<TInput, TOutput>(Expression<Func<TInput, Task<TOutput>>> code, out TOutput? result)
Invokes the given async code
expression on the underlying WPF element and returns the awaited result to result
if it is serializable, or null
if it is not.
TInput
specifies the type of the underlying WPF element.
TOutput
specifies the type of the result.
It is not possible to call await
within an expression, it will be handled by the Element
for you.
The current element is returned to allow chaining methods.
Usage
element.InvokeAsync<MyCustomControl, Guid>(x => x.GetFormIdAsync(), out var formId);
Element InvokeAsync(Expression<Func<UIElement, Task>> code)
Invokes the given async code
expression on the underlying WPF element.
It is not possible to call await
within an expression, it will be handled by the Element
for you.
The current element is returned to allow chaining methods.
Usage
element.InvokeAsync(x => x.ResetControlDataAsync());
Element InvokeAsync<TInput>(Expression<Func<TInput, Task>> code)
Invokes the given async code
expression on the underlying WPF element.
TInput
specifies the type of the underlying WPF element.
It is not possible to call await
within an expression, it will be handled by the Element
for you.
The current element is returned to allow chaining methods.
Usage
element.InvokeAsync<MyCustomControl>(x => x.MyCoolMethodAsync());
Element SetProperty(string propertyName, object? value)
Sets the given propertyName
to the given value
on the underlying WPF element. The value
must be serializable.
The current element is returned to allow chaining methods.
Usage
element.SetProperty("IsPressed", true);
element.SetProperty("Text", "Hello world!");
Element SetProperty<TInput, TOutput>(string propertyName, Expression<Func<TInput, TOutput>> getValue)
Sets the given propertyName
to the result of getValue
on the underlying WPF element.
TInput
specifies the type of the underlying WPF element.
TOutput
specifies the type of the result.
The current element is returned to allow chaining methods.
Usage
// Toggle the check box.
element.SetProperty<CheckBox, bool>("IsChecked", x => !x.IsChecked);
Element Assert(Expression<Func<Element, bool?>> predicateExpression)
Executes the given predicateExpression
and throws a test framework specific assertion exception if the condition is not met. For example, if the test is run using NUnit
, an NUNit
assertion exception will be thrown. If the test is run using XUnit
, an XUnit
assertion exception will be thrown.
If the condition is not met, detailed exception info will be generated, including what the values were and what the expected output was.
The current element is returned to allow chaining methods.
Usage
// Simple `Assert`.
element.Click().Assert(x => x["Text"] == "I was clicked!");
bool HasProperty(string propName)
Returns whether the underlying WPF element has a given property. Note the result is still true
even if the value is null
.
Usage
// False.
var hasProp = element.HasProperty("NonExistentProp");
// True.
var hasProp = element.HasProperty("Text");
Primitive this[string propName]
Returns a Primitive
representing the underlying property.
Usage
var text = element["Text"];
var isChecked = element["IsChecked"];
Assert.AreEqual("Hello world", text);
Assert.AreEqual(true, isChecked);
string TypeName
Returns the name of the underlying WPF element type.
Usage
// True.
Assert.AreEqual(nameof(Button), buttonElement.TypeName);
// True.
Assert.AreEqual(nameof(CustomControl), customControlElement.TypeName);
Element? Parent
Returns the Parent
element, or null
if it is the root element.
Usage
var parentTypeName = element.Parent.TypeName;
element.Parent.Click();
IReadOnlyList<Element> Child
Returns a list of child elements, or an empty list if there are none.
Usage
element.Child[0].Click();
element.Child[1].Assert(x => x.TypeName == nameof(Border));