magogi/prod/: mgf-uitest-desktop-0.1.2 metadata and description

Simple index

Shared observable-behavior UI testing for the Magogi PySide6/Qt desktop apps — drives each app's real widget tree in an offscreen QApplication and asserts the pillars an in-process handler call can't see: layout integrity (nothing squeezed below its own minimum, no elided text, no child escaping its parent), accessibility (accessible-name coverage + focus-chain reachability), runtime health (no QtWarning/QtCritical, no unraisable exception), plus real input events, modal-dialog auto-answer and a screenshot gallery, across a viewport x theme matrix. The desktop half of the mgf-uitest family (web sibling: mgf-uitest-web). Sibling under the mgf.* namespace.

author Bassam Alsanie, mgf-uitest-desktop contributors
classifiers
  • Development Status :: 2 - Pre-Alpha
  • Environment :: X11 Applications :: Qt
  • Framework :: Pytest
  • Intended Audience :: Developers
  • License :: OSI Approved :: Apache Software License
  • Operating System :: OS Independent
  • Programming Language :: Python :: 3
  • Programming Language :: Python :: 3.11
  • Programming Language :: Python :: 3.12
  • Programming Language :: Python :: 3.13
  • Topic :: Software Development :: Testing
  • Typing :: Typed
description_content_type text/markdown
keywords accessibility,desktop,magogi,pyside6,pytest-qt,qt,ui-testing
license Apache-2.0
license_file
  • LICENSE
  • NOTICE
project_urls
  • Homepage, https://codeberg.org/magogi-admin/mgf-uitest-desktop
  • Issues, https://codeberg.org/magogi-admin/mgf-uitest-desktop/issues
  • Feedback, https://codeberg.org/magogi-admin/mgf-uitest-desktop/src/branch/main/FEEDBACK.md
requires_dist
  • pyside6<7,>=6.7
  • pytest-qt<5,>=4.4
  • pytest<10,>=8.0
  • coverage[toml]>=7.10; extra == 'dev'
  • import-linter<3.0,>=2.0; extra == 'dev'
  • mgf-standard<0.2,>=0.1.57; extra == 'dev'
  • mgf-test-supervisor<0.2,>=0.1.20; extra == 'dev'
  • mypy>=1.10; extra == 'dev'
  • pytest-cov>=5.0; extra == 'dev'
  • pytest-timeout<3,>=2.3; extra == 'dev'
  • ruff<0.16,>=0.4; extra == 'dev'
  • mgf-common[standards]<1.0,>=0.50; extra == 'standards'
requires_python >=3.11

Because this project isn't in the mirror_whitelist, no releases from root/pypi are included.

File Tox results History
mgf_uitest_desktop-0.1.2-py3-none-any.whl
Size
46 KB
Type
Python Wheel
Python
3

mgf-uitest-desktop

Observable-behavior UI testing for the Magogi PySide6/Qt desktop apps — the missing tier.

Every Magogi desktop app is a PySide6 application whose GUI suite, today, calls its handlers directly:

window._retry_connection()          # the current shape
assert window._status_label.text() == "Retrying…"

That proves the handler works. It proves nothing about the button. Disconnect retry_button.clicked and the suite stays green — which is not a hypothetical: hrb-app shipped a visibly-broken button past a green suite on 2026-07-16, and the audit that followed found zero real input events in the whole suite, four objectNames, and no setAccessibleName anywhere.

This package closes that gap. It drives each app's real widget tree in an offscreen QApplication, with real posted input events, and asserts the pillars a handler call cannot see.

def test_greeting(console):
    console.click("#greet-button")                    # a real mouse event
    assert "Hello, world" in console.text("#greeting")
    console.assert_ok()                               # layout + a11y + health
    console.snapshot("greeting")

§1. The pillars

  1. Layout integrity — reads Qt's real geometry to catch what an operator notices: text elided because QFontMetrics says it never fitted, a child whose rect escapes its parent, a window squeezed below its own minimumSizeHint(). Deterministic; no image baseline to bless.
  2. Functional — drive the real golden paths through real input events, and assert the observable outcome.
  3. Accessibility — every interactive widget has an accessible name and is reachable by Tab. Honest scope: this is not axe — see §4.
  4. Runtime health — zero Qt warnings/criticals, zero unraisable exceptions. Qt fails quietly; this is what makes it audible.
  5. Responsive — the above across a viewport × theme (× DPI scale) matrix.
  6. Visual gallery — PNGs per matrix cell, for human eyeballing.

Plus the two things a Qt suite cannot do without: bounded waits instead of wall-clock sleeps, and modal-dialog auto-answer — because QMessageBox.exec() blocks inside C++, so a click on a button that asks "are you sure?" does not fail a test today, it hangs it. That is why the fleet's destructive verbs are untested, and expect_dialog is the way in.

§2. How it drives an app

In-process, through the app's own window factory. The consumer provides exactly one fixture — app_launch, returning an AppLaunch that says how to build its real top-level window — and the plugin supplies the rest:

app_launch  →  ui_app (offscreen QApplication, session)  →  ui_window
               (built · sized · themed · exposed · ready) →  console

The harness never imports mgf-hrb, mgf-common, mgf-brand-qt, or any app's domain stack — mechanically pinned by an import-linter contract. Its runtime dependencies are PySide6, pytest and pytest-qt, and nothing mgf-* at all.

§3. Family

The desktop half of the mgf-uitest family. mgf-uitest-web is the web half, and the shared vocabulary is deliberate: same fixture name (console), same *_launch override contract, same seven pillar names, same describe()-as- assertion-message discipline, same {slug}__{cell}.png gallery convention. The two share names, not codePUBLIC_API.md §5 maps every name web→desktop and records where the two genuinely differ. Genuinely shared plumbing gets extracted into an mgf-uitest-core only if a third consumer ever needs it — not on speculation.

§4. What this is not — read before trusting a green run

§5. Setup

uv venv --python 3.13
uv pip install -e ".[dev]"

Qt needs no browser install, but it does need a platform plugin: the pytest plugin sets QT_QPA_PLATFORM=offscreen for you (with setdefault, so QT_QPA_PLATFORM=xcb pytest -k clipping still shows you the window when you are debugging a finding).

§6. Running the suite

pytest --cov --cov-report=term-missing

Run the gates unpiped and read the real exit code. This is not style: a Qt suite can print 61 passed and then die of SIGSEGV, and pytest | tail reports the pipe's exit status, turning 139 into 0. That is how a real intermittent segfault stayed invisible in this fleet for weeks (LESSON_LEARNED.md).

Screenshots land in tests/_artifacts/gallery/ ({name}__{viewport}__{theme}__{scale}x.png). See tests/integration/conftest.py for a worked app_launch.

The app specs live in the apps, not here. This repo's own suite proves the library against a tiny in-repo sample window — including a test that seeds the sample's button unwired and asserts the gate fires. A harness that claims to catch dead buttons should have to prove it on one.

§7. Standards conformance

mgf-uitest-desktop declares L2 — Standard (CFM-02): conform to every MUST rule, evidenced by a per-rule audit — docs/inprogress/MGF_STANDARDS_CONFORMANCE.md. As a 0.1.0 founding, that ledger is declared provisional: the mechanical gates are green and the DOC-01 root set is complete, but the per-rule fresh-eyes audit across the full corpus has not been run yet, and the ledger says so rather than claiming a number it has not earned.

The public contract is PUBLIC_API.md (every name, its stability tier); the boundary is SCOPE.md.