Skip to content

Add per-widget isolation UI tests for ktsu.ImGui.Widgets - #337

Merged
matt-edmondson merged 2 commits into
mainfrom
claude/uitests-imgui-widgets-mkib4b
Aug 27, 2026
Merged

Add per-widget isolation UI tests for ktsu.ImGui.Widgets#337
matt-edmondson merged 2 commits into
mainfrom
claude/uitests-imgui-widgets-mkib4b

Conversation

@matt-edmondson

Copy link
Copy Markdown
Contributor

What

Adds tests/ImGui.Widgets.UITests, a headless UI test project covering every widget in ktsu.ImGui.Widgetsin isolation: one test class per widget, each starting an ImGuiAppHarness whose entire render callback is that widget and nothing else.

322 tests across 50 widget suites, all passing in about 65 seconds in Release.

Why this is separate from the demo suites

The existing tests/<Demo>.UITests projects drive an example's real BuildConfig() end to end, which proves the examples work. These cover each widget whether or not an example happens to use it, and a failure names the widget rather than a demo page that contains it.

What is covered

Form controls (Switch, Stepper, Rating, SegmentedControl, Chip/ChipGroup, RangeSlider, XYPad, Knob, PinInput, SearchBox, Combo, EnumCombo, HandleTrack, PageIndicator, HexaButtons, DatePicker/YearPicker, GestureDetector), display widgets (Avatar, Badge, ColorIndicator, Text and the alignment helpers, Tooltip, Icon, Image, ImageCanvas, Histogram, DbMeter, Scope, FlameGraph, RadialProgressBar, Spinner, BufferingBar, SkeletonLoader), containers (Card, Grid, Tree, IconTreeNode, TabPanel, DividerContainer, Splitter, ScopedDisable, ScopedId, OverlayHost, FileTreeView), the editors (CurveData and CurveSource curve editors, BezierEditor, Sequencer), and the deferred-drawing surface (both pumps, DockedWindow, message boxes, RenameDialog, the three file pickers).

Pure logic with no draw path — Easing, Spring, Tween, InertialScroll, GestureMachine, HandleTrackState, ImageCanvasState — stays covered by tests/ImGui.Widgets.Tests rather than being duplicated here.

Shared plumbing

WidgetTest is the base class: harness lifecycle, name-addressed input (Click, ClickFraction, DragAcross, Hover), IsVisible/RectOf/CenterOf, Mark/MarkSpan for widgets that mark nothing, pixel comparison (Snapshot, PixelsChangedSince, BoundsOfDifference), generated textures, and helpers for reaching Hexa's dialogs.

Notes worth knowing, all documented in CLAUDE.md and at the call sites:

  • The alignment helpers leave a zero-width spacer as the last submitted item, so where they drew is measured from the pixels rather than from the probe.
  • Immediate-mode return values are latched (clicked |= ...), since a click is reported for one frame and Click renders a further frame after the release.
  • Hexa's dialog managers are process-static, so a dialog left unanswered outlives its harness and is drawn over the next test; suites that open one call DismissOpenDialogs() from a cleanup.
  • Hexa's dialogs mark nothing, so a message box's buttons are located by finding the lowest run of theme-blue pixels, and the file pickers are cancelled at a fixed offset from the picker window's corner.
  • Click targets that are not where you would guess — the flame graph's bars, the sequencer's clip rows, the page indicator's dots — were measured and are commented where they appear.

Behavior recorded along the way

OpenFolderDialog reports the folder it was browsing on Cancel, even though FolderDialogOutcome.Path documents itself as null when nothing was chosen: the wrapper passes Hexa's SelectedFolder through without consulting the result. The test records the current behavior with a comment rather than asserting the documented one; worth deciding separately whether the wrapper or the doc should change.

Also

  • Registers the project in ImGui.sln under the Tests folder.
  • Documents the suite in CLAUDE.md, and adds the step to the "New Widget" checklist.

Verification

dotnet build -c Release ImGui.sln succeeds, and the suite passes 322/322 across repeated runs, with no order dependence between suites.


Generated by Claude Code

Adds tests/ImGui.Widgets.UITests, a headless UI suite covering every widget in
ktsu.ImGui.Widgets on its own: one test class per widget, each starting a harness
whose entire render callback is that widget. The existing per-demo suites prove
the examples work; these cover a widget whether or not any example uses it, and a
failure names the widget rather than the demo page containing it.
322 tests across 50 widget suites, ~65s in Release. Shared plumbing lives in
WidgetTest: harness lifecycle, name-addressed input, pixel diffing for widgets
whose probe mark is not what they drew, generated textures, and helpers for
reaching Hexa's dialogs, which mark nothing and are located by geometry.
[minor]
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012LpmkkkYgP7gp1gkawJAkq
Comment threadtests/ImGui.Widgets.UITests/TabPanelTests.cs Fixed
Comment threadtests/ImGui.Widgets.UITests/FileTreeViewTests.cs Fixed
Comment threadtests/ImGui.Widgets.UITests/FileTreeViewTests.cs Fixed
Comment threadtests/ImGui.Widgets.UITests/FileDialogTests.cs Fixed
Comment threadtests/ImGui.Widgets.UITests/FileTreeViewTests.cs Fixed
Comment threadtests/ImGui.Widgets.UITests/FileTreeViewTests.cs Fixed
Comment threadtests/ImGui.Widgets.UITests/FileDialogTests.cs Fixed
Comment threadtests/ImGui.Widgets.UITests/FileDialogTests.cs Fixed
Comment threadtests/ImGui.Widgets.UITests/RenameDialogTests.cs Fixed
Comment threadtests/ImGui.Widgets.UITests/RenameDialogTests.cs Fixed
Path.Join rather than Path.Combine when appending a known child name to a
temp directory, so a rooted later segment cannot silently drop the base, and
drop the redundant per-iteration copy of the tab label: the loop variable is
already per-iteration, so the closure captures the right one without it.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012LpmkkkYgP7gp1gkawJAkq
@sonarqubecloud

Copy link
Copy Markdown

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@matt-edmondson@claude