Getting Started
Prerequisites
Operating system
Windows 10 version 1903 or later. UI Automation (UIA3) is a Windows-only technology. Running in a Linux or macOS container will not work; the test runner must execute on a machine with a live desktop session.
Runtime
.NET 10.0 SDK or later. Download from dotnet.microsoft.com.
FlaUI requirements
Flawright wraps FlaUI, which in turn wraps Microsoft's UI Automation (UIA3) APIs. No additional installation is required — FlaUI ships as NuGet packages and is pulled in transitively. However, the target application must:
- Expose its controls via UIA. Most Win32, WinForms, WPF, and WinUI3 applications do. Legacy applications using custom-drawn UI may not.
- Not run at a higher integrity level than the test process. If the application requires elevation (UAC prompt), the test runner must also run as administrator.
Inspect tool
Before writing selectors, use an inspection tool to browse the UIA tree of your application:
- Accessibility Insights for Windows — accessibilityinsights.io (recommended)
- inspect.exe — ships with the Windows SDK at
C:\Program Files (x86)\Windows Kits\10\bin\<version>\x64\inspect.exe
These tools show AutomationId, Name, ControlType, and other properties for each element, which map directly to Flawright selectors.
Installing
Add the package to your test project:
dotnet add package Flawright
Or via the Directory.Packages.props / .csproj pattern:
<PackageReference Include="Flawright" />
Flawright targets net10.0-windows. Your test project must target a Windows TFM (e.g., net10.0-windows).
First Test: Notepad
The following is a complete, runnable xUnit test that launches Notepad, types text, and asserts visibility.
Project file
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net10.0-windows</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Flawright" Version="*" />
<PackageReference Include="xunit" Version="2.*" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.*" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.*" />
</ItemGroup>
</Project>
Test file
using Flawright;
using Xunit;
public class NotepadTests : IAsyncLifetime
{
private Flawright? _fw;
public async Task InitializeAsync()
{
// Configure DismissDialogCloseBehavior so CloseAsync handles the
// "save changes?" dialog that Notepad shows when exiting with unsaved content.
_fw = await Flawright.LaunchAsync(
new LaunchOptions { ApplicationPath = "notepad.exe" },
new FlawrightOptions
{
CloseBehavior = new DismissDialogCloseBehavior() // handles Win10 + Win11 Notepad
});
}
[Fact]
public async Task TypeText_AppearsInEditor()
{
var page = await _fw!.Browser.NewPageAsync();
// Win11 Notepad (WinUI3) uses AutomationId "RichEditBox" for the editor.
// On classic Win10 Notepad use "class:Edit" instead (the Win32 ClassName is
// "Edit", but its UIA ControlType is Document — so class:Edit, not controltype:Edit).
await page.FillAsync("#RichEditBox", "Hello from Flawright!");
var text = await page.Locator("#RichEditBox").InnerTextAsync();
Assert.Equal("Hello from Flawright!", text);
}
[Fact]
public async Task MenuBar_IsVisible()
{
var page = await _fw!.Browser.NewPageAsync();
await page.Locator("controltype:MenuBar").Expect().ToBeVisibleAsync();
}
[Fact]
public async Task Screenshot_ReturnsPngBytes()
{
var page = await _fw!.Browser.NewPageAsync();
var png = await page.ScreenshotAsync();
Assert.NotNull(png);
Assert.True(png.Length > 0);
}
public async Task DisposeAsync()
{
if (_fw != null)
{
// Runs the configured DismissDialogCloseBehavior — dismisses the
// "save changes?" dialog if it appears, then waits for exit.
await _fw.Browser.CloseAsync();
await _fw.DisposeAsync();
}
}
}
Windows 10 vs Windows 11 selector differences
Version Editor selector Notes Windows 11 Notepad (WinUI3) #RichEditBoxAutomationId-based; reliable across Win11 builds Classic Windows 10 Notepad (Win32) class:EditClassName-based; use class:notcontroltype:— the UIA ControlType for this multi-line edit isDocument, notEditWhen in doubt, use Accessibility Insights for Windows or
inspect.exeto browse the live UIA tree and find the right selector.
Run the tests
dotnet test
The test runner launches Notepad, drives it, and closes it. Tests run sequentially by default in xUnit. For parallel execution with UI automation, pin each test class to a single thread using [Collection] or a custom ITestCollectionOrderer.
What just happened
Flawright.LaunchAsync(options)is a single static call that startsnotepad.exe. On Windows 11, Flawright detects thatnotepad.exeis a packaged WinUI3 app and automatically callsApplication.LaunchStoreApp("Microsoft.WindowsNotepad_8wekyb3d8bbwe!App")so FlaUI binds to the real application instead of the short-lived alias stub.Browser.NewPageAsync()callsGetMainWindowon the FlaUIApplicationand wraps the resultingWindowin aFlawrightPage.FillAsync("#RichEditBox", ...)finds the element withAutomationId = "RichEditBox"(the Win11 WinUI3 editor), auto-waiting up to 5 seconds, and sets its value viaValuePattern.SetValue.Expect().ToBeVisibleAsync()resolves the locator and polls until the element is not offscreen, or throwsFlawrightTimeoutExceptionafter the timeout.IAsyncLifetime.DisposeAsync()callsFlawright.DisposeAsync(), which closes the Notepad process and releases UIA resources.
Where to go next
- Selectors — learn the full selector grammar
- Assertions — reference for all
Expect()assertions - Auto-Waiting — understand timing and retries
- Examples — Calculator, File Explorer, installer wizard
- Troubleshooting — if something is not working