Uh oh!
There was an error while loading. Please reload this page.
Add per-widget isolation UI tests for ktsu.ImGui.Widgets - #337
Merged
Conversation
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
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
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
Uh oh!
There was an error while loading. Please reload this page.
This was referenced Aug 27, 2026
This was referenced Aug 28, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for freeto join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.



What
Adds
tests/ImGui.Widgets.UITests, a headless UI test project covering every widget inktsu.ImGui.Widgetsin isolation: one test class per widget, each starting anImGuiAppHarnesswhose 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>.UITestsprojects drive an example's realBuildConfig()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 bytests/ImGui.Widgets.Testsrather than being duplicated here.Shared plumbing
WidgetTestis the base class: harness lifecycle, name-addressed input (Click,ClickFraction,DragAcross,Hover),IsVisible/RectOf/CenterOf,Mark/MarkSpanfor 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.mdand at the call sites:clicked |= ...), since a click is reported for one frame andClickrenders a further frame after the release.DismissOpenDialogs()from a cleanup.Behavior recorded along the way
OpenFolderDialogreports the folder it was browsing on Cancel, even thoughFolderDialogOutcome.Pathdocuments itself as null when nothing was chosen: the wrapper passes Hexa'sSelectedFolderthrough 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
ImGui.slnunder the Tests folder.CLAUDE.md, and adds the step to the "New Widget" checklist.Verification
dotnet build -c Release ImGui.slnsucceeds, and the suite passes 322/322 across repeated runs, with no order dependence between suites.Generated by Claude Code