본문으로 건너뛰기
cccskills
무료GitHub에 공개

flaui-tests

Authors and runs FlaUI-based Windows UI tests - the .NET-native wrapper around Microsoft UI Automation (UIA2 + UIA3). Covers the `FlaUI.Core` / `FlaUI.UIA2` / `FlaUI.UIA3` NuGet packages, `Application.Launch` / `Application.Attach` lifecycles, `ConditionFactory` + `FindFirstDescendant` locator patterns, `Retry` waits, and xUnit / NUnit / MSTest harness integration. Use when the test stack is C# / .NET-first and the team wants idiomatic in-process UIA calls rather than the HTTP/JSON wire protocol of `winappdriver` (direct or Appium-wrapped).

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

testland/qa스타 13(GitHub 13 + cccskills 0)

실행 점수 미검증

설치 방법 보기

포함된 파일(3)

  • SKILL.md14.6 KB
  • .tessl-plugin/plugin.json674 B
  • references/flaui-api.md2.5 KB

SKILL.md(원문)

설치하기 전에 에이전트에게 전달되는 지시 내용을 확인할 수 있습니다.

flaui-tests

Overview

FlaUI is a .NET library for automated UI testing of Windows applications (flaui) that wraps Microsoft UI Automation (UIA) - the Windows accessibility tree covered in desktop-test-strategy-reference - behind an idiomatic C# API. It supports "Win32, WinForms, WPF, and Store Apps" via two bindings: UIA2 (managed System.Windows.Automation, Microsoft Learn - UI Automation Overview) and UIA3 (COM interop). v5.0.0 released February 2025; MIT-licensed and actively maintained (flaui).

Disambiguation - FlaUI vs winappdriver

FlaUI is a .NET library that links into the test process and calls UIA directly. By contrast, winappdriver is an HTTP/JSON service that exposes a W3C-WebDriver endpoint on 127.0.0.1:4723; tests speak Selenium-style protocol over the wire, the driver is language-agnostic, and it can be invoked either directly or through the Appium 2.x wrapper (gestures / multi-window helpers / PowerShell hooks - both paths in that skill).

Pick FlaUI when the test stack is already C# / .NET-first and you want in-process UIA calls without an HTTP hop. Pick winappdriver when you need a Selenium client in another language or the Appium feature surface.

When to use

  • Test code lives in a C# / .NET project alongside the application (a dotnet test solution).
  • Application under test is WPF, WinForms, Win32, or a Windows Store app - the four classes FlaUI documents support for (flaui).
  • The team prefers strongly-typed control wrappers (AsButton(), AsTextBox()) over WebDriver's stringly-typed locators.
  • No HTTP wire protocol required between test and driver (in-process testing minimises a moving part).

For cross-language test stacks (Java / Python / Ruby clients), use winappdriver instead.

Authoring

NuGet packages

Per flaui, three packages cover the surface:

PackagePurpose
FlaUI.CoreBase library - element abstractions, Application, ConditionFactory, Retry, control patterns
FlaUI.UIA3COM-based UIA binding - recommended for WPF and Store Apps (flaui)
FlaUI.UIA2Managed UIA binding using System.Windows.Automation (msuia2) - better legacy WinForms compatibility (flaui)

Reference both FlaUI.Core and one of UIA2 / UIA3 from the test project. Mixed-mode authoring (UIA2 and UIA3 in the same process) is unsupported - see FlaUInspect which requires the inspector mode to be picked at startup.

Launching the application under test

Per the FlaUI wiki - Application page:

using FlaUI.Core;
using FlaUI.UIA3;

// Launch a fresh process
var app = Application.Launch(@"C:\Path\To\MyApp.exe");

// Attach to an already-running process by name or PID
var existing = Application.Attach("MyApp");

// Best-effort: attach if running, launch otherwise
var aol = Application.AttachOrLaunch(new ProcessStartInfo(@"C:\Path\To\MyApp.exe"));

// For a Windows Store app, pass the AUMID
var store = Application.LaunchStoreApp("Microsoft.WindowsCalculator_8wekyb3d8bbwe!App");

using var automation = new UIA3Automation();
var window = app.GetMainWindow(automation);

Per flauiapp: "When the application object is disposed, the application itself is closed as well." Pair the Application lifecycle with the test harness's fixture scope so child processes are cleaned up after each test class.

Finding elements with ConditionFactory

The lambda form is the shortest and is the upstream convention (flauisearch):

var loginButton = window.FindFirstDescendant(cf => cf.ByAutomationId("LoginButton"));

Prefer ByAutomationId (developer-set, locale- and theme-independent per msuia2); fall back to ByControlType + a nested condition, then ByName as a last resort. The equivalent ConditionFactory / PropertyCondition forms, the FindFirst* / FindAll* families, and the full condition-constructor list are in references/flaui-api.md.

Interacting with elements

Per flaui:

// Strongly-typed wrappers
var button = window.FindFirstDescendant(cf => cf.ByAutomationId("Submit")).AsButton();
button.Invoke();

var textbox = window.FindFirstDescendant(cf => cf.ByAutomationId("Username")).AsTextBox();
textbox.Enter("alice@example.com");

var listbox = window.FindFirstDescendant(cf => cf.ByControlType(ControlType.List)).AsListBox();
listbox.Select(2);

AsButton().Invoke() calls the UIA InvokePattern on the element - the accessibility-canonical "press" action, distinct from a synthetic mouse click (msuia2 §Control Patterns).

Waits with the Retry class

Before v2.0.0 some Find methods auto-retried; that responsibility now falls to the caller (flauiretry):

// Wait until the element appears
var found = Retry.WhileNull(
    () => window.FindFirstDescendant(cf => cf.ByAutomationId("StatusLabel")),
    timeout: TimeSpan.FromSeconds(10),
    interval: TimeSpan.FromMilliseconds(200),
    throwOnTimeout: true,
    ignoreException: true).Result;

// Wait until the element disappears
Retry.WhileTrue(
    () => window.FindFirstDescendant(cf => cf.ByAutomationId("Spinner")) is not null,
    timeout: TimeSpan.FromSeconds(30));

Retry.WhileNull / Retry.WhileTrue / Retry.WhileFalse / Retry.WhileException are the four variants (flauiretry). Each returns a RetryResult carrying iteration count, duration, and the last value - the test can assert on those metrics when diagnosing slow-loading screens.

Waits with Application.WaitWhileBusy

WaitWhileBusy blocks while the target process is busy; a null timeout means infinite, and it returns true if the application went idle (flauiappsrc):

public bool WaitWhileBusy(TimeSpan? waitTimeout = null)

Use it after a launch or a window-level action (menu open, modal dismiss, dialog confirm) before driving the next element - it blocks on the Win32 message-pump-idle signal of the target process. Pair with WaitWhileMainHandleIsMissing right after Launch so the test doesn't race the splash screen:

var app = Application.Launch(@"C:\Path\To\InvoiceApp.exe");
app.WaitWhileMainHandleIsMissing(TimeSpan.FromSeconds(10));
app.WaitWhileBusy(TimeSpan.FromSeconds(10));

var window = app.GetMainWindow(automation);
window.FindFirstDescendant(cf => cf.ByAutomationId("Save")).AsButton().Invoke();
app.WaitWhileBusy(TimeSpan.FromSeconds(5)); // wait for save handler

Retry.* waits on element-level conditions (descendant appears / disappears / matches a predicate); WaitWhileBusy waits on the process-level idle signal. Both belong in the same test - pick by what you can actually observe.

Running

Test framework integration

FlaUI integrates with any .NET test runner - xUnit, NUnit, MSTest:

// xUnit collection fixture for one-time app launch per test class
public class LoginAppFixture : IDisposable
{
    public Application App { get; }
    public UIA3Automation Automation { get; }
    public LoginAppFixture()
    {
        App = Application.Launch(@"C:\Path\To\LoginApp.exe");
        Automation = new UIA3Automation();
    }
    public void Dispose()
    {
        Automation.Dispose();
        App.Close();
        App.Dispose();
    }
}

public class LoginTests : IClassFixture<LoginAppFixture>
{
    private readonly LoginAppFixture _fx;
    public LoginTests(LoginAppFixture fx) => _fx = fx;

    [Fact]
    public void Logs_in_with_valid_credentials()
    {
        var window = _fx.App.GetMainWindow(_fx.Automation);
        window.FindFirstDescendant(cf => cf.ByAutomationId("User")).AsTextBox().Enter("alice");
        window.FindFirstDescendant(cf => cf.ByAutomationId("Pass")).AsTextBox().Enter("secret");
        window.FindFirstDescendant(cf => cf.ByAutomationId("Login")).AsButton().Invoke();
        Assert.NotNull(window.FindFirstDescendant(cf => cf.ByAutomationId("Welcome")));
    }
}

For per-test app launch (slower but isolates state), put Launch / Close in the test method itself; for per-class launch (faster but shared state), use IClassFixture (xUnit) / [OneTimeSetUp] (NUnit) / [ClassInitialize] (MSTest). Pair authoring conventions with dotnet-unit-tests (in the qa-unit-tests-net plugin) for the matching harness idioms.

STA threading

UIA3 (COM interop) requires an STA thread (msuia2); xUnit defaults to MTA, so set the apartment via the runner attribute:

// xUnit - install Xunit.StaFact and use [StaFact]
[StaFact]
public void Fact_running_on_sta_thread() { /* ... */ }

// NUnit - use [Apartment]
[Test, Apartment(ApartmentState.STA)]
public void Test_running_on_sta_thread() { /* ... */ }

// MSTest - STA is default; no attribute needed for sync tests

UIA2 (managed) is more permissive, but keeping all UIA work on STA makes threading bugs easier to debug.

dotnet test invocation

:: Build + run
dotnet test --logger "trx;LogFileName=results.trx"

:: With a filter on the FlaUI smoke suite
dotnet test --filter "Category=Smoke" --logger "trx;LogFileName=smoke.trx"

Verify: run the suite and confirm it launches the app and passes. If a test fails with a NullReference or Retry timeout, the locator or wait is wrong - open FlaUInspect to recheck the AutomationId, fix the FindFirstDescendant / Retry call, then re-run before adding more cases.

Parsing results

xUnit / NUnit / MSTest emit standard TRX / JUnit XML output via the test logger flag. Pair with junit-xml-analysis (in the qa-test-reporting plugin) for cross-runner aggregation.

For interactive selector discovery during authoring, use FlaUInspect - per its README it is "based on FlaUI" and presents the UIA tree with AutomationId, Name, ControlType, and XPath fields. Pre-built FlaUInspect.UIA2 and FlaUInspect.UIA3 binaries are downloadable from the releases page; pick the build matching the UIA mode used by the test project.

CI integration

Windows runner required (UIA is Windows-only per msuia2); use windows-latest for an interactive desktop, since UIA cannot drive Session-0. Full windows-latest workflow: references/flaui-api.md.

UIA2 vs UIA3 selection

Per flaui:

ChooseWhen
UIA3WPF / Store Apps / new code - COM-based, fewer compatibility gaps with modern controls
UIA2Legacy WinForms / older Win32 - managed System.Windows.Automation (msuia2) handles some legacy controls UIA3 misses

For new projects, UIA3 is the default recommendation (flaui). UIA2 remains supported as a peer binding; FlaUI itself ships both packages.

Anti-patterns

Anti-patternWhy it failsFix
Thread.Sleep(2000) between actionsTest runtime balloons; still flaky on slow CIUse Retry.WhileNull / Retry.WhileTrue with explicit timeout per flauiretry
FindFirstByXPath("//Button[@Name='Save']")Brittle to UI tree restructuringUse ByAutomationId first; XPath only as last resort per flauisearch
Finding solely by visible Name (ByName)Localised apps fail across languagesAutomationId is locale-independent per msuia2
Sharing one Application across all test classesUI state leaks between tests; one slow test halts the restUse one fixture per class (xUnit IClassFixture)
Forgetting app.Dispose() / automation.Dispose()Orphaned processes accumulate on CI runnerusing declaration or IDisposable fixture
Mouse-coordinate clicks (Mouse.Click(x, y))DPI / multi-monitor / theme changes breakResolve element via UIA, call Invoke()
Asserting on raw bitmap screenshotsBrittle to font / theme / DPIUIA tree is the assertion surface; screenshots only for canvas-rendered surfaces
Mixing UIA2 and UIA3 in one processUnsupported per FlaUInspect inspector constraintPick one binding per test project

Limitations

  • Windows-only. UIA is a Windows-specific API per msuia2. No macOS / Linux equivalent - for those OSes see the desktop-test-strategy-reference matrix (XCTest via qa-mobile's xcuitest-suite; AT-SPI on Linux).
  • Requires an interactive desktop session. UIA cannot drive Session-0 / headless Windows containers. windows-latest GitHub runners are interactive by default; self-hosted containers need Auto-Login + an unlocked desktop.
  • UIA2 vs UIA3 picked once per process. Mixed-mode authoring is unsupported (flauinspect). New code should prefer UIA3 (flaui); UIA2 is retained for legacy WinForms compatibility but no hard deprecation date is published - pin the decision per project.
  • GPU / DirectComposition surfaces. Some WPF + WinUI 3 controls rendered via DirectX may not expose a UIA tree. Inspect with FlaUInspect; fall back to image matching for those surfaces.
  • App must publish UIA. Custom-painted Win32 windows that don't implement IRawElementProviderSimple are opaque to FlaUI (and to every other UIA-backed driver). Add UIA support in the application or fall back to image matching for those screens.

References

  • FlaUI repository (README) - flaui.
  • FlaUI wiki - Application, Searching, Retry.
  • FlaUInspect inspector tool - flauinspect.
  • Microsoft Learn - UI Automation Overview - msuia2.
  • Sibling skills: winappdriver, desktop-test-strategy-reference.
  • Composing harness: dotnet-unit-tests (qa-unit-tests-net).

리뷰

아직 리뷰가 없습니다. 사용해 본 소감을 남겨 주세요.

댓글

로그인 없이 쓸 수 있습니다. 사용 후기, 질문, 작동하지 않은 환경 등을 편하게 남겨 주세요.

아직 댓글이 없습니다. 첫 댓글을 남겨 보세요.

보내면 바로 공개됩니다. 이메일 주소나 전화번호 같은 개인 정보는 쓰지 마세요. URL은 2개까지입니다.

0 / 1,000자

이 양식은 reCAPTCHA로 보호되며 Google 개인정보처리방침 및 서비스 약관이 적용됩니다.

같은 저장소의 스킬

Builds a CI gate that fails the build on **new** WCAG / a11y violations introduced by a PR while grandfathering pre-existing violations on a per-rule / per-page baseline. Aggregates verdicts from axe-core / pa11y / Lighthouse a11y / WAVE / IBM Equal Access scans. Use when a project has accumulated a11y debt and a strict "zero violations" gate would block every PR - the ratchet pattern lets the team ship while preventing regressions.

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

testland/qa132026년 10월 20일 업데이트

Workflow skill that builds an A/B-test validity checklist from an experiment proposal, walking the canonical design-correctness gates - pre-registered OEC/power/guardrails, randomization unit + SRM check, assignment integrity, telemetry, peeking discipline, novelty/primacy, post-experiment SRM re-check - into a per-experiment checklist + sign-off form. Use when launching, auditing, or governing an experiment. For pitfall mechanics (guardrails, peeking) see experiment-results-interpreter's references; to read an already-valid result use experiment-results-interpreter; for per-SDK harness tests use experiment-sdk-testing - this gates DESIGN, not SDK code.

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

testland/qa132026년 10월 20일 업데이트

The single install-flow skill: the reference contract for the PWA install flow (installability gate fields, `beforeinstallprompt` handshake, per-platform paths - Android WebAPK / iOS Share menu / Firefox no-op - and the `display-mode` post-install signal, in references/install-flow-reference.md) plus the build-an-X workflow that emits the Add-to-Home-Screen suite. Walks the four-stage timeline, emitting one test per gate cell per [web.dev/articles/install-criteria][install-criteria], the deferred-prompt → `prompt()` → `userChoice` chain per [web.dev/articles/customize-install][customize-install], the iOS Safari manual-metadata branch (`apple-touch-icon`) per [web.dev/learn/pwa/installation][learn-pwa], and the post-install `(display-mode: standalone)` MQ assertion. Output: a Playwright spec with per-stage cells plus a coverage matrix. Use when a PWA's manifest, icons, or install handler change, when install conversion drops at an unknown stage, or when triaging a flaky install assertion.

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

testland/qa132026년 10월 20일 업데이트

Build-an-X workflow that uses an LLM to map existing tests to spec sections - given a spec doc + the test suite, the LLM identifies which tests cover which sections, surfaces uncovered sections (gap), and recommends specific tests to add. Output is a coverage matrix per spec ID. Scope is mapping tests that already exist and naming the gaps, not authoring tests for new acceptance criteria. Use when a spec doc and a test suite both exist but nobody can say which requirements are actually covered - before a release sign-off, an audit, or a decision about where to spend the next round of test effort.

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

testland/qa132026년 10월 20일 업데이트

Generates tests from natural-language specs (acceptance criteria, user stories, requirements) using an LLM, with confidence scoring per test case (LLM self-assessment plus heuristics: assertion quality, naming, completeness), batching uncertain cases for human review, and integration with the team's existing test framework. Use when the user asks to generate unit tests from acceptance criteria, convert user stories to test cases, automate test creation from requirements, or augment a spec-driven test suite with AI-generated stubs that are then curated before merge.

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

testland/qa132026년 10월 20일 업데이트

Configures Allure Report (test-runner adapter install, `allure-results` directory wiring, `categories.json` for failure classification, `history-trend.json` retention via the copy-history-between-runs pattern), runs the Allure CLI to convert `allure-results` to a static HTML site, and uploads the report as a CI artifact. Use when the team needs richer test reporting than JUnit XML - step-level attachments, per-test history, retry tracking, and severity / epic / feature labeling across framework-agnostic adapters (pytest, Jest, JUnit, TestNG, NUnit, Mocha). As a rich static HTML report generator, it is the open-source alternative to the sunset ExtentReports (JVM/.NET per-test HTML narrative); for hosted cross-run flakiness analytics rather than a static per-run report use currents-integration.

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

testland/qa132026년 10월 20일 업데이트

testland의 스킬 모두 보기

이 스킬의 문제 신고