ktsu.ImGui.App.Testing 3.9.0

Prefix Reserved
dotnet add package ktsu.ImGui.App.Testing --version 3.9.0
                    
NuGet\Install-Package ktsu.ImGui.App.Testing -Version 3.9.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="ktsu.ImGui.App.Testing" Version="3.9.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="ktsu.ImGui.App.Testing" Version="3.9.0" />
                    
Directory.Packages.props
<PackageReference Include="ktsu.ImGui.App.Testing" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add ktsu.ImGui.App.Testing --version 3.9.0
                    
#r "nuget: ktsu.ImGui.App.Testing, 3.9.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package ktsu.ImGui.App.Testing@3.9.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=ktsu.ImGui.App.Testing&version=3.9.0
                    
Install as a Cake Addin
#tool nuget:?package=ktsu.ImGui.App.Testing&version=3.9.0
                    
Install as a Cake Tool

ktsu.ImGui.App.Testing

Headless test harness for ktsu.ImGui.App applications. Renders through a CPU rasterizer with no window, no GPU and no graphics driver, injects input directly into ImGui rather than through the operating system, and advances frames under the test's control.

Because nothing reaches the operating system, tests neither steal focus nor disturb anything else on the machine, and the same suite runs on a busy desktop and on a continuous integration runner with no display attached.

A Worked Example

using ImGuiAppHarness harness = ImGuiAppHarness.Start(app.BuildConfig(), new HarnessOptions
{
	Width = 1280,
	Height = 720,
});

harness.Click("file.open");
bool ready = harness.StepUntil(() => session.IsSettled, maxFrames: 300);
Assert.IsTrue(ready, "The application never settled.");

CapturedFrame frame = harness.Capture();
Rectangle? image = frame.FindBounds(p => p.A > 0);
Assert.IsNotNull(image, "Something should have been drawn.");
frame.SavePng("artifact.png");

Pass the same ImGuiAppConfig the application gives ImGuiApp.Start, so a test exercises the real configuration rather than one written for testing.

Driving the Application

Step() advances exactly one frame. StepUntil(predicate, maxFrames) advances until a condition holds or a frame budget runs out, returning false rather than throwing so the caller decides whether a timeout is a failure. The budget counts frames rather than milliseconds, so a loaded machine takes longer in real time without changing the outcome.

Input is injected into ImGui's event queue:

harness.Mouse.MoveTo(x, y);
harness.Mouse.Click(x, y);
harness.Mouse.Drag(fromX, fromY, toX, toY, steps: 24);
harness.Mouse.Wheel(x, y, clicks: 4);
harness.Keyboard.Press(ImGuiKey.Z, ctrl: true);
harness.Keyboard.Type("export.png");

The high-level helpers advance frames where the interaction requires it. ImGui activates a button on release and only notices a press that was visible during a completed frame, so a press and release inside one frame would do nothing.

Addressing Widgets by Name

Prefer names over coordinates. ktsu.ImGui.Widgets and ktsu.ImGui.Popups mark their interactive items automatically, and an application marks anything else through ImGuiProbes.MarkItem:

harness.Click("filesystem-browser/a.png");
Assert.IsNull(harness.Probe.Rect("filesystem-browser/notes.txt"), "The codec filter should exclude it.");

Names are recorded fully qualified, as the ImGui window followed by any pushed scopes and then the item's own name. Lookups match trailing segments, so a test writes the shortest name that identifies one item. A name matching several items, or one marked twice in a single frame, is reported as ambiguous with its candidates listed rather than resolving to whichever was drawn last. Clicking an item that was not drawn in the most recent frame fails as well, since its recorded position is stale and clicking it would hit whatever has since moved there.

Determinism

HarnessOptions pins everything that would otherwise vary between runs: display size, DPI scale, and a fixed frame delta independent of real elapsed time. Frame rate limiting is off and ImGui's layout file is never read or written, so one test cannot inherit state from another.

Two runs of the same scenario produce byte-identical frames. That property is what makes pixel measurements worth asserting on, and it is covered by a test.

Known Limitations

Rendering is a CPU rasterizer, not the OpenGL backend the application ships with. That is what makes results identical on every machine, and it is also why a defect confined to the GL renderer will not be caught here.

Only marked items can be addressed by name. Two identically labelled widgets in the same window with no scope between them collide, and are refused rather than guessed at. ImGui has the same limitation and the same remedy, which is to give them distinct identifiers.

Product Compatible and additional computed target framework versions.
.NET net10.0 is compatible.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
3.9.0 0 8/19/2026
3.8.1 0 8/19/2026
3.8.0 0 8/19/2026

## v3.9.0 (minor)

Changes since v3.8.0:

- docs: refer to the host in plain code so the iOS target compiles [patch] ([@matt-edmondson](https://github.com/matt-edmondson))
- feat: let a headless session install its own renderer backend [minor] ([@matt-edmondson](https://github.com/matt-edmondson))
- chore: refresh the API compatibility suppressions [patch] ([@matt-edmondson](https://github.com/matt-edmondson))