Megjegyzés
Az oldalhoz való hozzáféréshez engedély szükséges. Megpróbálhat bejelentkezni vagy módosítani a címtárat.
Az oldalhoz való hozzáféréshez engedély szükséges. Megpróbálhatja módosítani a címtárat.
Vizsgálja meg és használja a parancssorból futó Windows alkalmazásokat. Az AI-ügynökök és fejlesztők használják a felhasználói felület teszteléséhez, hibakereséséhez és automatizálásához.
Áttekintés
winapp ui parancsokat biztosít Windows alkalmazás felhasználói felületeinek vizsgálatához és azokkal való interakcióhoz.
Windows UI-automatizálás (UIA) használata. Bármilyen Windows alkalmazással használható – WPF, WinForms, Win32, Electron és WinUI 3.
A legtöbb parancs UIA-mintákon keresztül vezeti az alkalmazást (nincs bemeneti injektálás); ui click ez a kivétel, és valós egérszimulációt használ a nem támogatott InvokePatternvezérlőkhöz.
gyorskonfigurálás
# Connect to any app and see its UI tree
winapp ui inspect -a notepad
# Find specific elements
winapp ui search Button -a notepad
# Activate an element
winapp ui invoke Close -a notepad
# Take a screenshot
winapp ui screenshot -a notepad
Alkalmazások célzása
Folyamatnév alapján
winapp ui inspect -a notepad
winapp ui inspect -a slack # auto-picks visible window for multi-process apps
winapp ui inspect -a imageresizer # partial match: finds PowerToys.ImageResizer
Ablak címe szerint
winapp ui inspect -a "LICENSE - Notepad"
winapp ui inspect -a "Fix WinApp" # partial title match
Készítette: PID
winapp ui inspect -a 12345
HWND szerint (stabil – túléli a lap/cím változásait)
# Discover HWNDs
winapp ui list-windows -a Terminal
→ HWND 985238: "🤖 Testing" (WindowsTerminal, PID 21228)
→ HWND 131906: "Fix WinApp" (WindowsTerminal, PID 21228)
# Target specific window
winapp ui inspect -w 131906
winapp ui screenshot -w 131906
Felderítéshez, -a-w stabil célzáshoz használható. Ha -a több ablaknak felel meg, a parancs felsorolja őket a kiválasztandó HWND-kkel.
Szelektorok
Célelemek az ellenőrzés/keresés kimenetében [brackets] látható választóval.
A választóknak három típusa van:
| Selector | Értelmezés | Example |
|---|---|---|
MinimizeButton |
AutomationId (egyedi – stabil, előnyben részesített) | winapp ui invoke MinimizeButton -a myapp |
btn-close-d1a0 |
Szemantikai csiga (akkor jelenik meg, ha nincs egyedi AutomationId) | winapp ui invoke btn-close-d1a0 -a myapp |
Submit |
Egyszerű szöveges keresés név/AutomationId (kis- és nagybetűk megkülönböztetése) alapján | winapp ui invoke Submit -a myapp |
Az AutomationId-választók fejlesztői azonosítók (AutomationProperties.AutomationId XAML-ben).
Ha egy AutomationId egyedi a teljes felhasználói felületi fán, inspect és search közvetlenül választóként jeleníti meg – ezek túlélik az elrendezés változásait, a honosítást és a fa szerkezetátalakítását.
A slug selectorok (például) akkor jönnek létre, btn-close-d1a0ha nincs egyedi AutomationId.
Formátum: prefix-name-hash. A kivonat ellenőrzi az elemidentitást, de a felhasználói felület módosítása után elavult lehet.
Kimeneti formátum vizsgálata
A inspect parancs színes kimenettel jeleníti meg az elemfát (kijelölő ciánban, név zöldben, metaadatok szürkében):
TabView Tab (0,-1 1200x48)
TabListView List (4,-1 1100x48)
tab-newtab-5f5b TabItem "New Tab" (14,-1 200x48)
NewTabButton SplitButton "New Tab" [collapsed] (1104,5 96x36)
Found 10 elements (--depth 3). Use the first token as selector, e.g.: winapp ui invoke TabView -a terminal
Minden sorban az első szó a választó – használja más ui parancsokkal.
Ha egy elem egyedi AutomationId azonosítóval rendelkezik, az közvetlenül (például TabView, ). NewTabButton
Ha nem létezik egyedi AutomationId, a rendszer létrehoz egy létrehozott csigákat (pl. tab-newtab-5f5b).
Szemantikus csigák
A csigák a következő formátumot használják: prefix-normalizedname-hash
- előtag – 3 betűs rövidítés (btn, txt, chk, cmb, itm, tab, img, lbl, pn, win, grp, lnk, mnu stb.)
- normalizedname – kisbetűs alfanumerikus az AutomationId (előnyben részesített) vagy a Name (legfeljebb 15 karakter) karakterből
- kivonat – Az elem futtatókörnyezetazonosítójának 4 karakteres hexa kivonata (ellenőrzi az elemidentitást)
A csigák héjbiztosak (nincsenek speciális karakterek), egyediek, és közvetlenül argumentumként használhatók. A kivonat elavultsági észlelést biztosít – ha az elemet lecserélték, a következőt kapja: "Előfordulhat, hogy az elem módosult. Újrafuttathatja az ellenőrzést."
A névvel vagy AutomationId azonosítóval nem rendelkező elemek csak az előtagot és a kivonatot jelenítik meg (pl. pn-c8a3).
Több találat egyértelműsítője
A kimenetből származó inspect/search csigák egyediek, de az elrendezés változásai között változhatnak – egyszerű típusneveken vagy szövegen keresztül használhatják őket, ha több egyezés is van. Ha egy választó nem egyértelmű, a parancssori felület az összes egyezést kinyomtatja a csigákkal, így kiválaszthatja a megfelelőt, és újra futtathatja az adott golyót.
winapp ui search Button -a myapp # shows: btn-ok-a1b2 "OK", btn-cancel-c3d4 "Cancel"
winapp ui invoke btn-ok-a1b2 -a myapp # invoke using slug (preferred)
winapp ui invoke btn-cancel-c3d4 -a myapp # invoke the other Button by its slug
Egyszerű szöveges keresés
Egyszerű szöveg használata elemek kereséséhez – nincs szükség speciális szintaxisra:
winapp ui search Minimize -a notepad # finds elements with "Minimize" in Name or AutomationId
winapp ui search Close -a notepad # case-insensitive substring match
winapp ui invoke Minimize -a notepad # search + invoke in one step (disambiguates if needed)
winapp ui search "Save" -a notepad # find elements containing "Save"
winapp ui search "error" -a myapp # case-insensitive match
Ha egy szöveges keresés több elemnek felel meg (például a SettingsExpander, ahol a Csoport, a Gomb és a Szöveg azonos néven szerepel), a parancssori felület automatikusan kiválasztja az egyetlen kimondható elemet. Ha több is invokable, akkor felsorolja az összes egyezést a csigákkal.
A nem invokálható keresési eredmények (például egy Gombon belüli TextBlock) esetén a keresés automatikusan megjeleníti a legközelebbi invokálható elődöt – a szülőelemet, amellyel invokehasználhatja.
Ez az összes keresőválasztó esetében működik:
lbl-savechanges-a1b2 "Save changes" (120,40 80x20)
^ invoke via: btn-save-c3d4 "Save"
A felületi választó közvetlenül használható:
winapp ui invoke btn-save-c3d4 -a myapp # invoke the parent Button
Parancsok
állapot
Csatlakozzon egy alkalmazáshoz, és jelenítse meg a kapcsolat adatait.
winapp ui status -a notepad
winapp ui status -a notepad --json
Ellenőrizni
Tekintse meg a felhasználói felület elemfáját. A kimenet szemantikai csigákat jelenít meg, 2 szóköz behúzással a hierarchia számára:
winapp ui inspect -a notepad # full window tree, depth 3
winapp ui inspect -a notepad --depth 5 # deeper tree
winapp ui inspect txt-searchbox-e5f6 -a notepad # subtree rooted at element
winapp ui inspect --ancestors btn-close-d1a2 -a notepad # walk up from element to root
winapp ui inspect -a myapp --interactive # invokable elements only, auto-depth 8
winapp ui inspect -a myapp --hide-disabled # hide disabled elements
winapp ui inspect -a myapp --hide-offscreen # hide offscreen elements
Példakimenet (alapértelmezett):
win-aidevgalleryp-f1a3 "AI Dev Gallery Preview" (94,206 1280x1023)
pn-c8a3 (102,207 1264x1014)
btn-minimize-d1a0 "Minimize" (1222,206 48x48)
btn-maximize-e2b1 "Maximize" (1270,206 48x48)
itm-samples-3f2c "Samples" (102,330 72x62)
Példakimenet (--interactive — csak invokable elements, flat list):
btn-minimize-d1a0 "Minimize" (1222,206 48x48)
btn-maximize-e2b1 "Maximize" (1270,206 48x48)
btn-close-d1a2 "Close" (1318,206 48x48)
itm-home-7b3e "Home" (102,268 72x62)
itm-samples-3f2c "Samples" (102,330 72x62)
itm-models-9a4f "Models" (102,392 72x62)
Az elemek a következő állapotjelölőket jeleníthetik meg:
-
[on]/[off]/[indeterminate]— kapcsoló/jelölőnégyzet állapota -
[collapsed]/[expanded]— fák, kombinált listák, menüelemek kibontása/összecsukása -
[scroll:v]/[scroll:h]/[scroll:vh]— görgethető tároló (függőleges, vízszintes vagy mindkettő) -
[offscreen]— az elem nem látható a képernyőn -
[disabled]— az elem nincs engedélyezve -
value="..."— a szerkeszthető elemek aktuális szöveges tartalma (ha eltér a névtől)
keres
A választónak megfelelő elemek keresése. A kimenet szemantikai csigákat jelenít meg:
winapp ui search Button -a notepad # all buttons
winapp ui search Close -a notepad # finds elements with "Close" in name
winapp ui search SearchBox -a notepad # finds elements with "SearchBox" in name or AutomationId
winapp ui search Button --max 10 -a notepad # limit results
A kimenet példája:
btn-minimize-d1a0 "Minimize" (1222,206 48x48)
btn-maximize-e2b1 "Maximize" (1270,206 48x48)
btn-close-d1a2 "Close" (1318,206 48x48)
A kimenetben látható csigák (pl. btn-minimize-d1a0) közvetlenül használhatók más parancsokkal:
winapp ui invoke btn-minimize-d1a0 -a notepad
get-property
Tulajdonságértékek olvasása elemből. Mintaspecifikus állapotot tartalmaz (ToggleState, Value, IsSelected stb.).
winapp ui get-property btn-submit-7a90 -a myapp # all properties
winapp ui get-property chk-checkbox-b2c3 -p ToggleState -a myapp # checkbox state
winapp ui get-property txt-textbox-a4b1 -p Value -a myapp # current text value
winapp ui get-property cmb-combobox-d5e6 -p ExpandCollapseState -a myapp # expanded or collapsed
képernyőkép
Ablak vagy elem rögzítése PNG-ként. Ha több ablak is létezik (például alkalmazás + megnyitott párbeszédpanel), a rendszer egyetlen PNG-be alakítja őket, amelyben minden ablak össze van fűzve.
winapp ui screenshot -a notepad # saves screenshot.png in cwd
winapp ui screenshot -a notepad --output my.png # custom filename
winapp ui screenshot -a notepad --json # returns file path as JSON
winapp ui screenshot -w 131906 # target specific HWND (+ its dialogs)
winapp ui screenshot txt-searchbox-e5f6 -a myapp # crop to element bounds
winapp ui screenshot -a myapp --capture-screen # capture from screen (includes popups/overlays)
Amikor a párbeszédpanelek vagy előugró ablakok meg vannak nyitva, a rendszer az összes ablakot egyetlen PNG-re alakítja, így egyetlen képen láthatja a teljes felhasználói felületi állapotot.
Akkor használható --capture-screen , ha előugró menüket, legördülő listákat, úszó paneleket vagy elemleírás-átfedéseket kell rögzítenie. Módban --capture-screen (és az üres keret észlelése után újrapróbálkozáskor) a célablak először az előtérbe kerül; a normál ablakrögzítések nem mozgatják az ablakot.
hív
Programozott módon aktiválhat egy elemet (kattintson a gombra, jelölje be a jelölőnégyzetet, bontsa ki a kombinált listát).
winapp ui invoke btn-submit-7a90 -a myapp # by slug from inspect
winapp ui invoke btn-submit-a1b2 -a myapp # by slug from inspect/search
winapp ui invoke cmb-sizecombobox-b4c5 -a myapp # expand combo box
Minták sorrendbe rendezése: InvokePattern → TogglePattern → SelectionItemPattern → ExpandCollapsePattern.
click
Kattintson a képernyő koordinátáinak egyik elemére egérszimulációval. Használja ezt a nem támogatott InvokePattern vezérlőkhöz (például oszlopfejlécekhez, listaelemekhez).
winapp ui click btn-column1-a3f2 -a myapp # single click by slug
winapp ui click "Column1" -a myapp # single click by text search
winapp ui click btn-column1-a3f2 -a myapp --double # double-click
winapp ui click btn-column1-a3f2 -a myapp --right # right-click
set-value
Állítson be egy értéket egy szerkeszthető elemen (szöveg a TextBox/ComboBox esetében, a csúszka száma).
winapp ui set-value txt-textbox-a4b1 "Hello world" -a notepad
winapp ui set-value sld-volume-b2c3 75 -a myapp
get-value
Olvassa el az aktuális értéket egy elemből. Intelligens tartalékláncot használ: TextPattern (RichEditBox, Document) → ValuePattern (TextBox, Slider) → SelectionPattern (ComboBox, RadioButton, TabView) → név (címkék).
winapp ui get-value doc-texteditor-53ad -a notepad # read full document text
winapp ui get-value SearchBox -a myapp # read TextBox content
winapp ui get-value CmbTheme -a myapp # read ComboBox selected item
winapp ui get-value sld-volume-b2c3 -a myapp # read Slider value
winapp ui get-value lbl-title-a1b2 -a myapp --json # JSON: { "elementId": "...", "text": "..." }
fókusz
A billentyűzetfókusz áthelyezése egy elemre.
winapp ui focus txt-textbox-a4b1 -a notepad
görgetés nézetbe
Görgessen egy elemet a látható területre.
winapp ui scroll-into-view itm-targetitem-c3d4 -a myapp
várakozási idő
Várjon, amíg egy elem megjelenik, eltűnik, vagy egy érték eléri a célt.
winapp ui wait-for Button -a myapp --timeout 5000 # wait for any button
winapp ui wait-for btn-submit-7a90 -a myapp --timeout 5000 # wait for specific element
winapp ui wait-for CounterDisplay -a myapp --value "5" --timeout 5000 # wait for element value (smart fallback)
winapp ui wait-for lbl-status -a myapp --property Name --value "Done" --timeout 5000 # wait for specific property
winapp ui wait-for btn-submit-a1b2 --gone -a myapp --timeout 2000 # wait for element to disappear
winapp ui wait-for lbl-status -a myapp --value "Done" --contains # substring match instead of exact equality
Lapozzunk
Tárolóelem görgetése. Keresse meg a search scroll görgethető tárolókat a ( [scroll:v] függőleges) vagy [scroll:h] a (vízszintes) jelölőkkel.
# Find which elements are scrollable and in which direction
winapp ui search scroll -a myapp
# pn-scrollview-bfef Pane "scrollView" [scroll:v] (main content, vertical)
# pn-scrollviewer-bfb1 Pane "scrollViewer" [scroll:h] (horizontal list)
# Scroll the main content down
winapp ui scroll pn-scrollview-bfef --direction down -a myapp
# Jump to top/bottom
winapp ui scroll pn-scrollview-bfef --to bottom -a myapp
# If you target an element that's not scrollable, scroll walks up to find the nearest scrollable parent
winapp ui scroll itm-someitem-a1b2 --direction down -a myapp
összpontosítás
Az aktuális billentyűzetfókuszú elem megjelenítése.
winapp ui get-focused -a myapp
list-windows
Az alkalmazás összes látható ablakának listázása, beleértve az előugró ablakokat és a párbeszédpaneleket.
winapp ui list-windows -a imageresizer
winapp ui list-windows -a Terminal
winapp ui list-windows # all windows (no filter)
Keretrendszer támogatása
| Keretrendszer | Ellenőrizni | keres | hív | set-value | képernyőkép |
|---|---|---|---|---|---|
| WPF | ✅ Teljes fa | ✅ Minden tulajdonság | ✅ Minden minta | ✅ | ✅ |
| WinForms | ✅ | ✅ | ✅ | ✅ | ✅ |
| Win32 | ✅ | ✅ | ✅ | ✅ | ✅ |
| WinUI 3 | ✅ | ✅ | ✅ | ✅ | ✅ |
| Elektron | ⚠️ Krómfa | ⚠️ Korlátozott | ⚠️ Változó | ⚠️ Változó | ✅ |
| Flutter | ⚠️ Alapszintű | ⚠️ Alapszintű | ❌ Minimális | ❌ | ✅ |
Hibaelhárítás
| Error | A probléma oka | Solution |
|---|---|---|
| "Nem található futó alkalmazás" | Az alkalmazás nem fut, vagy a néveltérés nem egyezik | Folyamat nevének ellenőrzése vagy a PID használata |
| "Több ablak egyezés" | Nem egyértelmű -a érték |
Használat -w <HWND> a felsorolt lehetőségek közül |
| "több ablaka van" | A folyamat több ablakból áll | Adott cél célként való használata -w <HWND> |
| "Választó egyező N elemekkel" | Nem egyértelmű örökölt választó | A kimenetből származó inspect vagy hozzáfűző [0][1] csigák használata régi választókhoz |
| "Előfordulhat, hogy az elem megváltozott" | A lassú kivonat nem felel meg az aktuális elemnek | Újrafuttatás inspect vagy search friss csigák lekérése |
| "nem támogatja a meghívási mintát" | Az elem nem hívható meg | Az elem használata inspect invokálható gyermek megkereséséhez |
| "Nincs UIA-ablak" | Az UIA nem látja a folyamatot | A list-windows HWND megkereséséhez használja, majd -w |
| "Az ablak mérete nulla" | Az ablak kis méretű | Az alkalmazás automatikusan vissza lesz állítva |
| Előugró/legördülő lista nem a képernyőképen | A PrintWindow nem rögzíti az átfedéseket | Jelölő használata --capture-screen |
Gyakori minták
Navigálás és ellenőrzés
winapp ui invoke btn-settings-a1b2 -a myapp # click a button
winapp ui wait-for pn-settingspage-c3d4 -a myapp # wait for page to load
winapp ui screenshot -a myapp --output settings.png # verify visually
Szöveg keresése és a szülő meghívása
# Search shows invokable ancestor; invoke auto-walks to it
winapp ui invoke 'Save changes' -a myapp
# Or search first to see what matches, then invoke
winapp ui search "Save changes" -a myapp; winapp ui invoke btn-save-c3d4 -a myapp
Ismétlődő elemek egyértelműsítése
winapp ui search '#Image' -a myapp; winapp ui invoke itm-image-a2b3 -a myapp
Képernyőkép előugró átfedésekkel
winapp ui set-value txt-searchbox-e5f6 "query" -a myapp; winapp ui screenshot -a myapp --capture-screen
Navigálás, várakozás és ellenőrzés (egyetlen lánc)
winapp ui invoke btn-settings-a1b2 -a myapp; winapp ui wait-for pn-settingspage-c3d4 -a myapp --timeout 3000; winapp ui screenshot -a myapp -o settings.png
Felfedezés, kattintás és ellenőrzés
winapp ui inspect -a myapp --interactive; winapp ui invoke btn-submit-7a90 -a myapp; winapp ui screenshot -a myapp
Fájl párbeszédpanel-interakció
A fájlmegnyitási/mentési párbeszédpanelek szabványos Windows párbeszédpanelek az UIA támogatásával:
# Trigger the dialog, find it, type the path, confirm
winapp ui invoke btn-openfilebtn-a2b3 -a myapp
winapp ui list-windows -a myapp # find dialog HWND
winapp ui set-value txt-1148-c4d5 "C:\path\to\file.png" -w <dialog-hwnd>
winapp ui invoke btn-open-e6f7 -w <dialog-hwnd>
Egy inspect -w <dialog-hwnd> --interactive adott párbeszédpanel tényleges meztelencsomóit derítheti fel.
Miért ; a láncolás (nem &&)
A PowerShell operátora && lefagyhat, ha egy natív parancssori felület ír a stderrbe, vagy ANSI-feloldási sorozatokat használ. Használja ; inkább – feltétel nélkül futtatja az egyes parancsokat, és elkerüli ezt a holtpontot. Ez az ügynök-munkafolyamatok esetében is jobb: általában azt szeretné, hogy a képernyőkép akkor is fusson, ha a meghívás nem nulla kimenetű volt.
CI-tesztelési minták
A ci-folyamatokban (GitHub Actions, Azure DevOps) winapp ui parancsok használata füsttesztekhez és felhasználói felületi ellenőrzéshez.
wait-for
--value és --property helyességként működik – az 1. kilépési kódot adja vissza időtúllépéskor, és automatikusan meghiúsul a CI-lépés.
Indítás és tesztelés a GitHub Actions
steps:
- name: Build
run: dotnet build MyApp.csproj -c Debug -p:Platform=x64
- name: Launch and test
run: |
$result = winapp run .\bin\x64\Debug\net8.0-windows10.0.26100.0\win-x64 --detach --json | ConvertFrom-Json
$appPid = $result.ProcessId
# Wait for window to initialize
winapp ui wait-for "Main Window" -a $appPid --timeout 30000
# Run tests — each wait-for exits non-zero on failure
winapp ui invoke "Login" -a $appPid
winapp ui wait-for "Dashboard" -a $appPid --timeout 10000
winapp ui screenshot -a $appPid -o dashboard.png
Elemállapot érvényesítése a wait-for
wait-for --value lekérdezi, amíg egy elem értéke meg nem egyezik a várt sztringgel, és ugyanazt az intelligens tartalékot használja, mint get-value (TextPattern → ValuePattern → SelectionPattern → Name). A 0-s kilépési kódot adja vissza egyezéskor, az 1-es kilépési kódot időtúllépéskor – így CI-barát állítás. Ehelyett egy adott UIA-tulajdonság ellenőrzésére használható --property .
# Assert: button click updated the counter (smart value fallback — works for TextBlock, TextBox, etc.)
winapp ui invoke "Counter Button" -a $pid
winapp ui wait-for "Counter Display" -a $pid --value "Count: 1" -t 5000
# Assert: text input was accepted
winapp ui set-value "Search Box" "hello world" -a $pid
winapp ui wait-for "Search Box" -a $pid --value "hello world" -t 3000
# Assert: checkbox was toggled (use --property for specific UIA properties)
winapp ui invoke "Dark Mode" -a $pid
winapp ui wait-for "Dark Mode" -a $pid --property ToggleState --value "On" -t 3000
# Assert: navigation happened (new page appeared)
winapp ui invoke "Settings" -a $pid
winapp ui wait-for "Settings Page" -a $pid -t 10000
# Assert: dialog was dismissed (element disappeared)
winapp ui invoke "Close" -a $pid
winapp ui wait-for "Dialog Title" -a $pid --gone -t 5000
Igény érvényesítése JSON-kimenettel
Összetettebb állítások esetén használja --json a PowerShellt vagy a jq-t:
Kilépési kód szerződése
searchéswait-for--jsonmódban: ha egyetlen elem sem egyezik (search) vagy a várakozási idő (wait-for), a parancs egy teljesen elemezhető eredményborítékot ír a stdout ({ "matchCount": 0, ... }vagy{ "found": false, "timedOut": true, ... }) értékre, és visszaadja az 1. kilépési kódot. A Stderr üres--jsonmódban van (a naplózó kimenete le van tiltva). Elágaztatás a borítékmezőkön vagy attól$LASTEXITCODEfüggően, hogy melyik ergonomikusabb.
# Assert: search found exactly one match
$result = winapp ui search "Submit" -a $pid --json | ConvertFrom-Json
if ($result.matchCount -ne 1) { throw "Expected 1 Submit button, found $($result.matchCount)" }
# Assert: element has expected properties
# inspect --json returns { windows: [{ hwnd, title, elements: [...] }] };
# each window's elements[] is the nested tree (children rendered via .children).
$tree = winapp ui inspect "Counter Display" -a $pid --json | ConvertFrom-Json
$counter = $tree.windows[0].elements[0]
if ($counter.name -ne "Count: 3") { throw "Counter value wrong: $($counter.name)" }
Példa a teljes füsttesztre
# Launch
$app = winapp run .\build-output --detach --json | ConvertFrom-Json
# Verify app loaded
winapp ui wait-for "Main Page" -a $app.ProcessId -t 30000
# Interact and assert
winapp ui invoke "Add Item" -a $app.ProcessId
winapp ui set-value "Item Name" "Test Item" -a $app.ProcessId
winapp ui invoke "Save" -a $app.ProcessId
winapp ui wait-for "Test Item" -a $app.ProcessId -t 5000 # assert item appeared in list
winapp ui wait-for "Save" -a $app.ProcessId --gone -t 3000 # assert save dialog closed
# Visual verification
winapp ui screenshot -a $app.ProcessId -o smoke-test.png
Windows developer