Communitygithub.com

Windows-Desktop-E2E

E2E-Tests für native Windows-Desktop-Apps (WPF, WinForms, Win32/MFC, Qt) mit pywinauto und Windows UI Automation. Verwenden Sie dieses Skill, wenn Sie E2E-Tests für eine native Windows-Desktop-App mit pywinauto oder UI Automation schreiben.

Was ist Windows-Desktop-E2E?

Dieses Skill bietet eine umfassende Anleitung für End-to-End-Tests von nativen Windows-Desktop-Anwendungen mit pywinauto und der Windows UI Automation (UIA)-API. Es deckt die wichtigsten Frameworks wie WPF, WinForms, Win32/MFC und Qt (5.x/6.x) ab und bietet framework-spezifische Ratschläge zur Verbesserung der Testbarkeit durch stabile AutomationId-Werte. Das Skill beinhaltet eine vollständige Page-Object-Modell-Implementierung mit Hilfsklassen für Locators, Wartezeiten, Aktionen und Screenshots sowie eine Strategie für die Behandlung flaky Tests durch Tracing und gezielte Ausnahmen. Es unterstützt die Integration in CI/CD-Pipelines (z.B. GitHub Actions auf `windows-latest`) und empfiehlt Tools wie Accessibility Insights for Windows zur Inspektion der UIA-Elementstruktur. Die Anleitung ist besonders wertvoll für Entwickler, die zuverlässige und wartbare GUI-Tests für Windows-Apps erstellen möchten, und bietet erweiterte Funktionen wie Schritt-für-Schritt-Tracing, Screenshot-Verwaltung und Failover-Mechanismen für Qt 5.x.

Funktioniert mit✓Claude Code~Codex CLI~Cursor
npx skills add https://github.com/affaan-m/ECC/tree/main/skills/windows-desktop-e2e

In Ihrer bevorzugten KI fragen

Öffnet einen neuen Chat, in dem dieser Agent-Skill bereits geladen ist.

Dokumentation

Windows Desktop E2E-Testing

End-to-End-Testing für native Windows-Desktop-Anwendungen mit pywinauto auf Basis der Windows UI Automation (UIA). Deckt WPF, WinForms, Win32/MFC und Qt (5.x / 6.x) ab – mit Qt-spezifischen Hinweisen in einem eigenen Abschnitt.

Wann aktivieren

  • Schreiben oder Ausführen von E2E-Tests für eine native Windows-Desktop-Anwendung
  • Einrichten einer Desktop-GUI-Testsuite von Grund auf
  • Diagnose von flaky oder fehlschlagenden Desktop-Automatisierungstests
  • Hinzufügen von Testbarkeit (AutomationId, zugängliche Namen) zu einer bestehenden App
  • Integration von Desktop-E2E in eine CI/CD-Pipeline (GitHub Actions windows-latest)

Wann NICHT verwenden

  • Webanwendungen → verwenden Sie das Skill e2e-testing (Playwright)
  • Electron / CEF / WebView2-Apps → die HTML-Ebene benötigt Browser-Automatisierung, nicht UIA
  • Mobile Apps → verwenden Sie plattformspezifische Tools (UIAutomator, XCUITest)
  • Reine Unit- oder Integrationstests, die keine laufende GUI benötigen

Kernkonzepte

Alle Windows-Desktop-Automatisierung basiert auf UI Automation (UIA), einer in Windows integrierten API für Barrierefreiheit. Jedes unterstützte Framework stellt einen Baum von UIA-Elementen mit Eigenschaften bereit, die Claude lesen und bearbeiten kann:

Ihr Test (Python)
    └── pywinauto (UIA-Backend)
        └── Windows UI Automation API   ← in Windows integriert, framework-agnostisch
            └── UIA-Provider der App    ← jedes Framework liefert seinen eigenen
                └── Ausführende .exe

UIA-Qualität nach Framework:

FrameworkAutomationIdZuverlässigkeitHinweise
WPF5/5Ausgezeichnetx:Name wird direkt auf AutomationId abgebildet
WinForms4/5GutAccessibleName = AutomationId
UWP / WinUI 35/5AusgezeichnetVolle Microsoft-Unterstützung
Qt 6.x5/5AusgezeichnetBarrierefreiheit standardmäßig aktiviert; Klassennamen ändern sich zu Qt6*
Qt 5.15+4/5GutVerbessertes Accessibility-Modul
Qt 5.7–5.143/5MittelBenötigt QT_ACCESSIBILITY=1; objectName manuell
Win32 / MFC3/5MittelSteuerelement-IDs zugänglich; Textabgleich üblich

Einrichtung und Voraussetzungen

# Python 3.8+, nur Windows
pip install pywinauto pytest pytest-html Pillow pytest-timeout
# Optional: Bildschirmaufzeichnung
# Installieren Sie ffmpeg und fügen Sie es zum PATH hinzu: https://ffmpeg.org/download.html

Überprüfen Sie, ob UIA erreichbar ist:

from pywinauto import Desktop
Desktop(backend="uia").windows()  # listet alle Fenster der obersten Ebene

Installieren Sie Accessibility Insights for Windows (kostenlos, von Microsoft) – Ihr DevTools-Äquivalent zur Inspektion des UIA-Elementbaums vor dem Schreiben von Tests.

Testbarkeitseinrichtung (nach Framework)

Das Wichtigste, was Sie tun können, ist, jedem interaktiven Steuerelement vor dem Schreiben von Tests eine stabile AutomationId zu geben.

WPF

<!-- XAML: x:Name wird automatisch zur AutomationId -->
<TextBox x:Name="usernameInput" />
<PasswordBox x:Name="passwordInput" />
<Button x:Name="btnLogin" Content="Login" />
<TextBlock x:Name="lblError" />

WinForms

// Im Designer oder Code setzen
usernameInput.AccessibleName = "usernameInput";
passwordInput.AccessibleName = "passwordInput";
btnLogin.AccessibleName = "btnLogin";
lblError.AccessibleName = "lblError";

Win32 / MFC

// Steuerelement-Ressourcen-IDs in der .rc-Datei werden als AutomationId-Zeichenfolgen bereitgestellt
// IDC_EDIT_USERNAME -> AutomationId "1001"
// Bevorzugen Sie SetWindowText für den Namen; fügen Sie IAccessible für umfangreichere Unterstützung hinzu

Qt – siehe eigenen Abschnitt unten


Page-Object-Modell

tests/
├── conftest.py          # App-Start-Fixture, Fehler-Screenshot
├── pytest.ini
├── config.py
├── pages/
│   ├── __init__.py      # für Imports erforderlich
│   ├── base_page.py     # Locators, Wartezeiten, Screenshot-Hilfen
│   ├── login_page.py
│   └── main_page.py
├── tests/
│   ├── __init__.py
│   ├── test_login.py
│   └── test_main_flow.py
└── artifacts/           # Screenshots, Videos, Logs

base_page.py

import os, time
from pywinauto import Desktop
from config import ACTION_TIMEOUT, ARTIFACT_DIR

class BasePage:
    def __init__(self, window):
        self.window = window

    # --- Locators (Prioritätsreihenfolge) ---

    def by_id(self, auto_id, **kw):
        """AutomationId – am stabilsten. Erste Wahl."""
        return self.window.child_window(auto_id=auto_id, **kw)

    def by_name(self, name, **kw):
        """Sichtbarer Text / zugänglicher Name."""
        return self.window.child_window(title=name, **kw)

    def by_class(self, cls, index=0, **kw):
        """Steuerelement-Klasse + Index – fragil, wenn möglich vermeiden."""
        return self.window.child_window(class_name=cls, found_index=index, **kw)

    # --- Wartevorgänge ---

    def wait_visible(self, spec, timeout=ACTION_TIMEOUT):
        spec.wait("visible", timeout=timeout)
        return spec

    def wait_gone(self, spec, timeout=ACTION_TIMEOUT):
        spec.wait_not("visible", timeout=timeout)
        return spec

    def wait_window(self, title, timeout=ACTION_TIMEOUT):
        """Warten auf ein neues Fenster der obersten Ebene (Dialoge, Unterfenster)."""
        dlg = Desktop(backend="uia").window(title=title)
        dlg.wait("visible", timeout=timeout)
        return dlg

    def wait_until(self, fn, timeout=ACTION_TIMEOUT, interval=0.3):
        """Beliebige Bedingung abfragen – verwenden, wenn UIA-Ereignisse unzuverlässig sind."""
        deadline = time.time() + timeout
        while time.time() < deadline:
            try:
                if fn():
                    return True
            except Exception:
                pass
            time.sleep(interval)
        raise TimeoutError(f"Bedingung innerhalb von {timeout}s nicht erfüllt")

    # --- Aktionen ---

    def click(self, spec):
        self.wait_visible(spec)
        spec.click_input()

    def type_text(self, spec, text):
        self.wait_visible(spec)
        ctrl = spec.wrapper_object()
        try:
            ctrl.set_edit_text(text)
        except Exception as e:
            # Qt 5.x Fallback: UIA-Wertmuster kann unvollständig sein
            import sys, pywinauto.keyboard as kb
            print(f"[windows-desktop-e2e] set_edit_text fehlgeschlagen ({e}), verwende Tastatur-Fallback", file=sys.stderr)
            ctrl.click_input()
            kb.send_keys("^a")
            kb.send_keys(text, with_spaces=True)

    def get_text(self, spec):
        ctrl = spec.wrapper_object()
        for attr in ("window_text", "get_value"):
            try:
                v = getattr(ctrl, attr)()
                if v:
                    return v
            except Exception:
                pass
        return ""

    # --- Artefakte ---

    def screenshot(self, name):
        os.makedirs(ARTIFACT_DIR, exist_ok=True)
        path = os.path.join(ARTIFACT_DIR, f"{name}.png")
        self.window.capture_as_image().save(path)
        return path

login_page.py

from pages.base_page import BasePage

class LoginPage(BasePage):
    @property
    def username(self): return self.by_id("usernameInput")

    @property
    def password(self): return self.by_id("passwordInput")

    @property
    def btn_login(self): return self.by_id("btnLogin")

    @property
    def error_label(self): return self.by_id("lblError")

    def login(self, user, pwd):
        self.type_text(self.username, user)
        self.type_text(self.password, pwd)
        self.click(self.btn_login)

    def login_ok(self, user, pwd, main_title="Main Window"):
        self.login(user, pwd)
        return self.wait_window(main_title)

    def login_fail(self, user, pwd):
        self.login(user, pwd)
        self.wait_visible(self.error_label)
        return self.get_text(self.error_label)

conftest.py

Für neue Projekte bevorzugen Sie die Tier-1-Sandbox-Fixture (siehe unten) – sie fügt Dateisystem-Isolation ohne zusätzliche Kosten hinzu. Diese einfache Fixture ist nur für minimale/ Legacy-Setups gedacht.

import os, pytest
os.environ["QT_ACCESSIBILITY"] = "1"  # Erforderlich für Qt 5.x UIA-Unterstützung

from pywinauto import Application
from config import APP_PATH, MAIN_WINDOW_TITLE, LAUNCH_TIMEOUT, ARTIFACT_DIR

@pytest.fixture
def app(request):
    if not APP_PATH:
        pytest.exit("APP_PATH-Umgebungsvariable ist nicht gesetzt", returncode=1)
    proc = Application(backend="uia").start(APP_PATH, timeout=LAUNCH_TIMEOUT)
    win  = proc.window(title=MAIN_WINDOW_TITLE)
    win.wait("visible", timeout=LAUNCH_TIMEOUT)
    yield win
    # Screenshot bei Fehler
    if getattr(getattr(request.node, "rep_call", None), "failed", False):
        os.makedirs(ARTIFACT_DIR, exist_ok=True)
        try:
            win.capture_as_image().save(
                os.path.join(ARTIFACT_DIR, f"FAIL_{request.node.name}.png")
            )
        except Exception:
            pass
    # Zuerst ordentliches Beenden, als Fallback erzwungenes Beenden
    # proc ist eine pywinauto.Application – verwenden Sie wait_for_process_exit(), nicht wait_for_process()
    try:
        win.close()
        proc.wait_for_process_exit(timeout=5)
    except Exception:
        proc.kill()

@pytest.hookimpl(tryfirst=True, hookwrapper=True)
def pytest_runtest_makereport(item, call):
    outcome = yield
    setattr(item, f"rep_{outcome.get_result().when}", outcome.get_result())

config.py

import os
APP_PATH          = os.environ.get("APP_PATH", "")           # via env gesetzt – kein Standardpfad
MAIN_WINDOW_TITLE = os.environ.get("APP_TITLE", "")
LAUNCH_TIMEOUT    = int(os.environ.get("LAUNCH_TIMEOUT", "15"))
ACTION_TIMEOUT    = int(os.environ.get("ACTION_TIMEOUT", "10"))
ARTIFACT_DIR      = os.path.join(os.path.dirname(__file__), "artifacts")

pytest.ini

[pytest]
testpaths = tests
markers =
    smoke: schnelle Rauchtests für kritische Pfade
    flaky: bekanntermaßen instabile Tests
addopts = -v --tb=short --html=artifacts/report.html --self-contained-html

Locator-Strategie

AutomationId  >  Name (Text)  >  ClassName + Index  >  XPath
  (stabil)         (lesbar)        (fragil)            (letzter Ausweg)

Inspizieren Sie mit Accessibility Insights → Bereich Eigenschaften → suchen Sie zuerst nach AutomationId.

# Zur Laufzeit inspizieren – in ein REPL einfügen, um den Baum zu erkunden
win.print_control_identifiers()
# oder den Bereich eingrenzen:
win.child_window(auto_id="groupBox1").print_control_identifiers()

Wartemuster

# Warten, bis ein Steuerelement erscheint
page.wait_visible(page.by_id("statusLabel"))

# Warten, bis ein Steuerelement verschwindet (z. B. Lade-Spinner)
page.wait_gone(page.by_id("spinnerOverlay"))

# Warten auf ein Dialogfenster
dlg = page.wait_window("Löschen bestätigen")

# Benutzerdefinierte Bedingung (z. B. Textänderungen)
page.wait_until(lambda: page.get_text(page.by_id("lblStatus")) == "Bereit")

Verwenden Sie niemals time.sleep() als primäre Synchronisierung – verwenden Sie wait() oder wait_until().

Artefaktverwaltung

# Screenshot auf Anfrage
page.screenshot("after_login")

# Vollbildaufnahme (wenn das Fenster ausgeblendet oder minimiert ist)
import pyautogui
pyautogui.screenshot("artifacts/fullscreen.png")

# Bildschirmaufzeichnung mit ffmpeg (vor dem Test starten, nach dem Test beenden)
import subprocess

def start_recording(name):
    return subprocess.Popen([
        "ffmpeg", "-f", "gdigrab", "-framerate", "10",
        "-i", "desktop", "-y", f"artifacts/videos/{name}.mp4"
    ], stdin=subprocess.PIPE, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)

def stop_recording(proc):
    proc.stdin.write(b"q"); proc.stdin.flush(); proc.wait(timeout=10)

Schritt-für-Schritt-Trace (Opt-in)

Der standardmäßige Fehler-Screenshot ist oft zu dünn für die Diagnose flaky Tests. Das schrittweise Trace unten ist standardmäßig deaktiviert – aktivieren Sie es nur, wenn Sie einen flaky Fall reproduzieren.

Aktivieren

E2E_TRACE=1 pytest tests/test_login.py -v
# Eingegebenen Text in das JSONL-Log aufnehmen (NICHT für Tests verwenden, die Anmeldedaten/PII eingeben):
E2E_TRACE=1 E2E_TRACE_INCLUDE_TEXT=1 pytest ...

In BasePage integrieren

import os, json, time
TRACE_ENABLED      = os.environ.get("E2E_TRACE") == "1"
TRACE_INCLUDE_TEXT = os.environ.get("E2E_TRACE_INCLUDE_TEXT") == "1"

class BasePage:
    _step = 0

    def _trace(self, action, spec=None, text=None):
        if not TRACE_ENABLED:
            return
        BasePage._step += 1
        idx = f"{BasePage._step:03d}"
        os.makedirs(ARTIFACT_DIR, exist_ok=True)
        try:
            self.window.capture_as_image().save(
                os.path.join(ARTIFACT_DIR, f"step_{idx}_{action}.png"))
        except Exception:
            pass  # Fehler bei der Aufnahme darf den Test nicht unterbrechen
        rec = {
            "ts": time.time(), "step": BasePage._step, "action": action,
            "locator": getattr(spec, "criteria", None),
            "text": text if TRACE_INCLUDE_TEXT else ("<redacted>" if text else None),
        }
        with open(os.path.join(ARTIFACT_DIR, "trace.jsonl"), "a") as f:
            f.write(json.dumps(rec) + "\n")

    def click(self, spec):
        self.wait_visible(spec); self._trace("click_before", spec)
        spec.click_input();      self._trace("click_after",  spec)

    def type_text(self, spec, text):
        self.wait_visible(spec); self._trace("type_before", spec, text)
        # ... bestehender set_edit_text / Tastatur-Fallback ...
        self._trace("type_after", spec)

Einschränkungen

  • PII / Anmeldedaten: Der Inhalt von type_text wird standardmäßig als <redacted> angezeigt. Setzen Sie E2E_TRACE_INCLUDE_TEXT=1 niemals bei Anmelde- oder Zahlungsabläufen.
  • Overhead: ~50–200ms pro Aktion + ein PNG pro Schritt auf der Festplatte. Nicht in der Standard-CI-Matrix aktivieren – nur in einem dedizierten Auftrag zur Reproduktion von Flakes.
  • Artefakt-Aufblähung: Ein langer Ablauf produziert Dutzende MB; passen Sie retention-days entsprechend an.
  • Parallel-Wiederholungs-Hygiene: Dieses einfache Beispiel hängt an trace.jsonl an und verwendet einen Klassen-zähler. Löschen Sie das Artefakt-Verzeichnis vor Wiederholungen und verwenden Sie pro-Worker-Artefaktverzeichnisse für parallele Tests.
  • Abdeckungslücke: Aktionen, die außerhalb von BasePage ausgeführt werden (rohe pywinauto-Aufrufe im Testcode), werden nicht getrackt.

Behandlung flaky Tests

# Quarantäne – entspricht Playwrights test.fixme()
@pytest.mark.skip(reason="Flaky: Animationswettlauf auf langsamer CI. Issue #42")
def test_animated_transition(self, app): ...

# Überspringen, wenn der Fehler bereits gemeldet wurde

## Qt-spezifische Testanleitung

Qt-Anwendungen können getestet werden, benötigen aber besondere Sorgfalt. Die UIA-Unterstützung variiert je nach Qt-Version und -Konfiguration erheblich.

### Qt-Versionsunterstützung

| Version | Status | Anforderungen |
|---------|--------|---------------|
| Qt 6.2+ | ✅ **Ausgezeichnet** | UIA standardmäßig aktiviert; Klassennamen sind `Qt6QListView`, `Qt6QLineEdit` usw. |
| Qt 5.15+ | ✅ **Gut** | UIA-Standardtreiber; setzen Sie `QT_ACCESSIBILITY=1` für zusätzliche Sicherheit |
| Qt 5.7–5.14 | ⚠️ **Okay** | Erfordert `QT_ACCESSIBILITY=1`, begrenztes `objectName`-Mapping |
| Qt 5.6 und älter | ❌ **Nicht empfohlen** | UIA nicht vollständig unterstützt; verwenden Sie WinForms als Alternative oder erwägen Sie ein Upgrade |

### Kritische Umgebungsvariable

```bash
# Fügen Sie dies zu Ihrem CI-Skript oder pytest.ini hinzu (wird zu pytest.giconft.py hinzugefügt)
export QT_ACCESSIBILITY=1
# Für Qt 6.2+ optional – standardmäßig aktiviert

Locators für Qt

# Standard (stabil, ein Objektname = ein Steuerelement)
page.by_id("usernameInput")                 # objectName: usernameInput
page.by_name("Anmelden")                     # Sichtbarer Text „Anmelden"

# Fallback (verwenden Sie print_control_identifiers(), um Runtime-Klassennamen zu finden)
page.by_class("Qt6QLineEdit", index=0)       # Erstes Texteingabefeld
page.by_class("Qt6QPushButton", index=0)     # Erste Schaltfläche

Wichtig: In Qt 6.x sind alle Klassennamen mit Qt6 (nicht QPushButton) präfigiert. Verwenden Sie print_control_identifiers(), um die genauen Namen zur Laufzeit zu erhalten.

Qt 5.x-Text-Fallback

In Qt 5.x kann das UIA-Wertmusters (benötigt für set_edit_text()) manchmal unvollständig sein. pywinautos type_text() in base_page.py verwendet automatisch einen Tastatur-Fallback, wenn set_edit_text() fehlschlägt. Sie müssen dafür nichts weiter tun – der Code behandelt dies transparent.

Tastatur-Fallback erklärt

# Dies geschieht automatisch in type_text() – hier für Referenz:
ctrl.click_input()
kb.send_keys("^a")            # Alles auswählen
text = "meinBenutzername"
kb.send_keys(text, with_spaces=True)  # Text eingeben (Leerzeichen werden korrekt behandelt)

CI/CD-Integration (GitHub Actions)

name: Desktop E2E
on: [push, pull_request]

jobs:
  e2e:
    runs-on: windows-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-python@v5
        with:
          python-version: '3.11'
      - name: Abhängigkeiten installieren
        run: |
          pip install pywinauto pytest pytest-html Pillow pytest-timeout
          # Optional: ffmpeg installieren
          # choco install ffmpeg
      - name: E2E-Tests ausführen
        env:
          APP_PATH: ${{ github.workspace }}\Deploy\MeineApp.exe
          APP_TITLE: Hauptfenster
          QT_ACCESSIBILITY: 1   # Erforderlich für Qt 5.x
        run: |
          pytest tests/ -v --html=artifacts/report.html --self-contained-html
      - name: Artefakte hochladen
        uses: actions/upload-artifact@v4
        if: always()
        with:
          name: test-artifacts
          path: artifacts/

Wichtige CI-Erwägungen

  1. App-Bereitstellung: Stellen Sie sicher, dass die App vor dem Start der Tests erstellt/bereitgestellt wird (z. B. mit msbuild oder einem Installationsprogramm).
  2. Umgebungsvariablen: APP_PATH muss auf die ausführbare Datei verweisen. APP_TITLE muss dem Fenstertitel der obersten Ebene entsprechen.
  3. CI-Timeout: Setzen Sie ein angemessenes pytest-Timeout (pytest-timeout), um zu verhindern, dass hängende Tests die gesamte CI-Pipeline blockieren.
  4. Artefakt-Lebensdauer: Konfigurieren Sie retention-days im Schritt upload-artifact, um die Speichernutzung zu verwalten.
  5. Bildschirmauflösung: Der standardmäßige windows-latest-Runner verwendet die Auflösung 1024x768. Wenn Ihre App mehr benötigt, konfigurieren Sie sie vor dem Start des Testläufers.

Zugänglichkeitsprüfung mit Accessibility Insights

Accessibility Insights for Windows ist unverzichtbar für die Erstellung zuverlässiger Tests:

  1. Starten Sie die App unter Test.
  2. Öffnen Sie Accessibility Insights → Live-Inspect.
  3. Zeigen Sie auf ein Steuerelement → der rechte Bereich zeigt alle UIA-Eigenschaften an.
  4. Suchen Sie nach AutomationId – wenn vorhanden, ist dies Ihr stabilster Locator.
  5. Notieren Sie sich den AutomationId-Wert und verwenden Sie ihn in by_id().

Pro-Tipp: Wenn AutomationId leer ist, suchen Sie nach Name (Text) oder ClassName – diese sind weniger stabil, aber als Fallback akzeptabel.

Verbesserung der Testbarkeit

Wenn die App kein AutomationId bereitstellt, haben Sie zwei Möglichkeiten:

1. App-Code ändern (bevorzugt)

Fügen Sie AutomationId für jedes interaktive Steuerelement in der App hinzu:

  • WPF: x:Name wird automatisch zur AutomationId.
  • WinForms: Setzen Sie AccessibleName.
  • Win32/MFC: Setzen Sie IAccessible und legen Sie Name fest.
  • Qt: Setzen Sie setObjectName().

2. UIA überbrücken (falls keine Codeänderung möglich)

# Verwenden Sie print_control_identifiers(), um Runtime-ID-Muster zu finden
win.print_control_identifiers()
# Suchen Sie nach konsistenten Klassennamen oder Textmustern
page.by_name("OK").click()  # Verwenden Sie sichtbaren Text, wenn AutomationId nicht verfügbar ist

Fehlerbehebung

Häufige Probleme

ProblemUrsacheLösung
ElementNotEnabledExceptionSteuerelement deaktiviert/anfangs ausgeblendetWarten Sie auf Sichtbarkeit, bevor Sie Maßnahmen ergreifen
ElementNotVisibleExceptionSteuerelement nicht im Ansichtsfenster oder überlagertScrollen oder verwenden Sie click_input() (simuliert Mausbewegung)
NoSuchWindowExceptionFenster wurde nicht gefunden oder geschlossenÜberprüfen Sie MAIN_WINDOW_TITLE; verwenden Sie wait_window()
TimeoutErrorSteuerelement erscheint nicht innerhalb des TimeoutsErhöhen Sie ACTION_TIMEOUT oder prüfen Sie auf Ausnahmen/UI-Änderungen
Flaky-TestsZeitprobleme, UIA-Eigenschaften ändern sich zwischen LäufenVerwenden Sie wait_until() und Accessibility Insights, um die Locator-Quelle zu überprüfen

Protokollierung

# Ausführliche pywinauto-Protokollierung aktivieren
import logging
logging.basicConfig(level=logging.DEBUG)
# Odere auf pywinauto beschränken:
logging.getLogger("pywinauto").setLevel(logging.DEBUG)

Best Practices-Zusammenfassung

  1. Priorisieren Sie AutomationId – es ist der stabilste Locator.
  2. Vermeiden Sie time.sleep() – verwenden Sie wait_visible(), wait_gone() oder wait_until().
  3. Stellen Sie Bereinigung bei Fehlern sicher – die Fixture in conftest.py macht automatisch einen Screenshot und beendet die App sauber.
  4. Isolieren Sie die App – verwenden Sie Sandbox-Umgebungen (Tier 1) für Dateisystem-Isolation, wann immer möglich.
  5. Überprüfen Sie vor dem Testen – verwenden Sie Accessibility Insights, um Locators zu überprüfen, bevor Sie Code schreiben.
  6. Setzen Sie Timeouts – setzen Sie ACTION_TIMEOUT und LAUNCH_TIMEOUT für jede Testsuite.
  7. Gruppieren Sie Artefakte – Screenshots und Videoaufnahmen helfen bei der Diagnose von Fehlern in CI.
  8. Qt-spezifische Aufmerksamkeit – setzen Sie QT_ACCESSIBILITY=1 und überprüfen Sie die UIA-Eigenschaften mit Accessibility Insights, bevor Sie Tests schreiben.

Individual skills in this repo

This repo contains 20 individual skills — each has its own dedicated page.

accessibility

Design, implement, and audit inclusive digital products using WCAG 2.2 Level AA. Use when building or auditing UI that must meet WCAG 2.2 Level AA, or when reviewing a change for keyboard, contrast, or screen-reader support.

affaan-m/content-engine

Create platform-native content systems for X, LinkedIn, TikTok, YouTube, newsletters, and repurposed multi-platform campaigns. Use when the user wants social posts, threads, scripts, content calendars, or one source asset adapted cleanly across platforms.

affaan-m/ECC

Multi-platform content distribution across X, LinkedIn, Threads, and Bluesky. Adapts content per platform using content-engine patterns. Never posts identical content cross-platform. Use when the user wants to distribute content across social platforms.

affaan-m/fal-ai-media

Unified media generation via fal.ai MCP — image, video, and audio. Covers text-to-image (Nano Banana), text/image-to-video (Seedance, Kling, Veo 3), text-to-speech (CSM-1B), and video-to-audio (ThinkSound). Use when the user wants to generate images, videos, or audio with AI.

affaan-m/manim-video

日本語翻訳:このファイルは manim-video 用の日本語翻訳が必要です

affaan-m/remotion-video-creation

Remotion のベストプラクティス - React で動画を作成する。3D、アニメーション、音声、字幕、チャート、トランジションなどをカバーするドメイン固有の29のルール。

affaan-m/video-editing

AI-assisted video editing workflows for cutting, structuring, and augmenting real footage. Covers the full pipeline from raw capture through FFmpeg, Remotion, ElevenLabs, fal.ai, and final polish in Descript or CapCut. Use when the user wants to edit video, cut footage, create vlogs, or build video content.

agent-architecture-audit

Full-stack diagnostic for agent and LLM applications. Audits the 12-layer agent stack for wrapper regression, memory pollution, tool discipline failures, hidden repair loops, and rendering corruption. Produces severity-ranked findings with code-first fixes. Essential for developers building agent applications, autonomous loops, or any LLM-powered feature. Use when an agent or LLM feature misbehaves and the failing layer is unknown, or before shipping an agent stack.

agent-eval

Head-to-head comparison of coding agents (Claude Code, Aider, Codex, etc.) on custom tasks with pass rate, cost, time, and consistency metrics. Use when choosing between coding agents, or when a change to an agent setup needs measured pass rate, cost, and time rather than an impression.

agent-harness-construction

Design and optimize AI agent action spaces, tool definitions, and observation formatting for higher completion rates. Use when defining or revising an agent

agentic-engineering

Operate as an agentic engineer using eval-first execution, decomposition, and cost-aware model routing. Use when planning or executing engineering work that agents will carry out end to end.

agentic-os

Build persistent multi-agent operating systems on Claude Code. Covers kernel architecture, specialist agents, slash commands, file-based memory, scheduled automation, and state management without external databases. Use when building a persistent multi-agent system on Claude Code with its own memory, commands, and scheduling.

agent-introspection-debugging

Structured self-debugging workflow for AI agent failures using capture, diagnosis, contained recovery, and introspection reports. Use when an agent run fails and you need a reproducible diagnosis instead of a retry.

agent-payment-x402

Add x402 payment execution to AI agents with per-task budgets, spending controls, and non-custodial wallets. Supports Base through agentwallet-sdk and X Layer through OKX Payments / OKX Agent Payments Protocol. Use when an agent must pay for something itself and needs per-task budgets, spending controls, and a non-custodial wallet.

agent-self-evaluation

Use after completing any non-trivial task. The agent self-rates its output on 5 axes — accuracy, completeness, clarity, actionability, conciseness — with concrete evidence per criterion. Produces a structured 1-5 scorecard with specific improvement suggestions.

agent-sort

Build an evidence-backed ECC install plan for a specific repo by sorting skills, commands, rules, hooks, and extras into DAILY vs LIBRARY buckets using parallel repo-aware review passes. Use when ECC should be trimmed to what a project actually needs instead of loading the full bundle.

ai-first-engineering

Engineering operating model for teams where AI agents generate a large share of implementation output. Use when setting team process, review gates, or ownership rules for a codebase largely written by agents.

ai-regression-testing

Regression testing strategies for AI-assisted development. Sandbox-mode API testing without database dependencies, automated bug-check workflows, and patterns to catch AI blind spots where the same model writes and reviews code. Use when adding regression coverage to AI-assisted code, or when the same model both wrote and reviewed a change.

android-clean-architecture

Clean Architecture patterns for Android and Kotlin Multiplatform projects — module structure, dependency rules, UseCases, Repositories, and data layer patterns. Use when structuring modules, layers, or data flow in an Android or KMP project.

angular-developer

Generates Angular code and provides architectural guidance. Trigger when creating projects, components, or services, or for best practices on reactivity (signals, linkedSignal, resource), forms, dependency injection, routing, SSR, accessibility (ARIA), animations, styling (component styles, Tailwind CSS), testing, or CLI tooling.

Verwandte Skills