# Automating Dear ImGui Testing Using the Test Engine: A Complete Integration Guide

> Automate Dear ImGui testing with the built-in Test Engine. Integrate seamlessly for efficient UI testing without affecting production builds. Learn how now.

- Repository: [omar/imgui](https://github.com/ocornut/imgui)
- Tags: how-to-guide
- Published: 2026-07-14

---

**Dear ImGui provides a built-in Test Engine framework that hooks into the ImGui context through extension points in [`imgui_internal.h`](https://github.com/ocornut/imgui/blob/main/imgui_internal.h), enabling automated UI testing via item registration macros and runtime flags without impacting production binaries.**

Dear ImGui (ocornut/imgui) includes a lightweight, pluggable Test Engine architecture designed specifically for automating UI testing. By leveraging hook points defined in the internal headers and a companion repository, developers can implement regression testing, CI validation, and scripted gameplay interactions while keeping the test infrastructure entirely optional. This guide explains how the Test Engine integrates with ImGui's core to capture widget data and drive automated interactions.

## How the Test Engine Hooks into the ImGui Context

The Test Engine integrates directly with Dear ImGui's core through a series of extension points defined in [`imgui_internal.h`](https://github.com/ocornut/imgui/blob/main/imgui_internal.h). Rather than existing as a separate binary, the engine hooks into the existing ImGui context using callback structures and global flags that remain dormant until explicitly activated.

### The ImGuiContextHook Structure

At the heart of the integration lies the **`ImGuiContextHook`** structure (defined in [`imgui_internal.h`](https://github.com/ocornut/imgui/blob/main/imgui_internal.h) at line 155). This structure allows external modules to register callbacks that ImGui invokes during key lifecycle events. When the Test Engine initializes, it registers a hook that receives notifications for item creation, information queries, and custom log entries.

The hook mechanism ensures that the Test Engine remains decoupled from ImGui's rendering logic while maintaining real-time visibility into UI state changes.

### Runtime Flags and Activation

Two critical runtime flags control the Test Engine's data capture:

- **`ImGuiDebugLogFlags_OutputToTestEngine`** (line 2149): Directs ImGui's internal debug log stream to the Test Engine for centralized logging.
- **`g.TestEngineHookItems`** (line 2253): Enables the per-item callbacks that power automated testing.

These flags are toggled either by user code or automatically during the engine's initialization sequence. When disabled, the Test Engine macros compile to no-ops, ensuring zero overhead in production builds.

## Item Registration and Data Capture

Every time ImGui renders a widget, the Test Engine captures metadata through conditional macros that expand only when testing is enabled. This instrumentation allows the engine to build a searchable representation of the active UI.

### The IMGUI_TEST_ENGINE_ITEM_ADD Macro

Whenever an ImGui widget renders, the **`IMGUI_TEST_ENGINE_ITEM_ADD`** macro expands to a conditional call to `ImGuiTestEngineHook_ItemAdd`. This function records the widget's **ID**, **bounding box**, and optional **`ImGuiLastItemData`**. The macro is gated by the `g.TestEngineHookItems` flag, ensuring that the overhead of item tracking only occurs during test execution.

Similarly, **`IMGUI_TEST_ENGINE_ITEM_INFO`** captures additional metadata about the item's status, while **`IMGUI_TEST_ENGINE_LOG`** handles debug output. All three macros reside in [`imgui_internal.h`](https://github.com/ocornut/imgui/blob/main/imgui_internal.h) and provide the raw data that the Test Engine uses to locate and interact with widgets programmatically.

### Capturing Data in Custom Widgets

For custom widgets not covered by standard ImGui macros, you can manually register items with the Test Engine:

```cpp
bool MyCustomButton(const char* label)
{
    ImGuiWindow* window = ImGui::GetCurrentWindow();
    ImGuiID id = window->GetID(label);
    ImRect bb = ImGui::GetItemRect();

    // Register the item with the test engine (if enabled)
    IMGUI_TEST_ENGINE_ITEM_ADD(id, bb, nullptr);
    IMGUI_TEST_ENGINE_ITEM_INFO(id, label, ImGuiItemStatusFlags_None);

    // Normal button rendering
    return ImGui::Button(label);
}

```

## Locating Widgets for Automated Interaction

The Test Engine relies on human-readable identifiers to locate specific widgets during test execution. The helper function **`ImGuiTestEngine_FindItemDebugLabel`** (defined at line 4093 in [`imgui_internal.h`](https://github.com/ocornut/imgui/blob/main/imgui_internal.h)) resolves a widget's debug label from its ID and state.

This resolution mechanism enables the engine to generate descriptive logs and allows test scripts to reference UI elements by meaningful names rather than internal handles. When combined with the bounding box data captured during item registration, the engine can simulate precise mouse clicks and keyboard inputs at the correct screen coordinates.

## Engine Data Store and Separation of Concerns

ImGui maintains a pointer to the Test Engine's state through **`g.TestEngine`** (line 2273), declared as a `void*` in the internal context structure. This opaque pointer stores the engine's complete state without requiring ImGui to know the implementation details.

The actual Test Engine implementation resides in the separate **imgui_test_engine** repository, which provides the scripting language, test runner, and UI snapshot validation logic. This architectural separation allows developers to include the engine only in test builds, preventing binary bloat or performance degradation in shipping applications.

## Setting Up the Test Engine in Your Application

Integrating the Test Engine requires linking the companion repository and activating the hooks during ImGui initialization.

### Initialization Example

```cpp
// Include the engine header (provided by imgui_test_engine)
#include "imgui_test_engine.h"

int main()
{
    // Initialize ImGui first
    ImGui::CreateContext();
    ImGuiIO& io = ImGui::GetIO();

    // Create the test engine instance
    ImGuiTestEngine* engine = ImGuiTestEngine_Create();
    ImGui::GetCurrentContext()->TestEngine = engine;          // Store pointer in ImGui context
    ImGui::GetCurrentContext()->TestEngineHookItems = true;  // Enable item callbacks

    // Load a test script (example: my_test.imt)
    ImGuiTestEngine_AddTestFromFile(engine, "my_test.imt");

    // Run the engine each frame
    while (!done)
    {
        // ... ImGui frame start/end ...

        ImGuiTestEngine_Run(engine);  // Executes pending test steps
    }

    // Cleanup
    ImGuiTestEngine_Destroy(engine);
    ImGui::DestroyContext();
}

```

### Writing Test Scripts

Test scripts use a domain-specific language to describe interactions. Save the following as `my_test.imt`:

```text

# Simple click test

TEST MyWindowTest
{
    # Find the window titled "Demo"

    FIND_WINDOW "Demo"

    # Click the button labelled "OK"

    FIND_ITEM "OK"
    CLICK

    # Verify that a label "Success" appears

    FIND_ITEM "Success"
    ASSERT_VISIBLE
}

```

## Key Files in the Test Engine Architecture

Understanding the file structure helps navigate the integration between ImGui core and the Test Engine:

- **[`imgui_internal.h`](https://github.com/ocornut/imgui/blob/main/imgui_internal.h)**: Defines the `ImGuiContextHook` structure and the `IMGUI_TEST_ENGINE_*` macros (lines 155, 2253, 4093).
- **[`imgui.cpp`](https://github.com/ocornut/imgui/blob/main/imgui.cpp)**: Contains the runtime toggles for `TestEngineHookItems` and the `TestEngine` pointer storage.
- **[`imgui_widgets.cpp`](https://github.com/ocornut/imgui/blob/main/imgui_widgets.cpp)**: Widget implementations showing conditional compilation of Test Engine data.
- **[`imgui_tables.cpp`](https://github.com/ocornut/imgui/blob/main/imgui_tables.cpp)**: Table widget code with Test Engine integration points.
- **imgui_test_engine repository**: Complete implementation including the scripting language and test runner.

## Summary

- **Dear ImGui's Test Engine** hooks into the core library via `ImGuiContextHook` structures and runtime flags defined in [`imgui_internal.h`](https://github.com/ocornut/imgui/blob/main/imgui_internal.h).
- **Item registration macros** (`IMGUI_TEST_ENGINE_ITEM_ADD`, `IMGUI_TEST_ENGINE_ITEM_INFO`) capture widget metadata only when `g.TestEngineHookItems` is enabled.
- **The `g.TestEngine` void pointer** maintains the engine's state while keeping the implementation separate in the imgui_test_engine repository.
- **Debug label resolution** via `ImGuiTestEngine_FindItemDebugLabel` enables human-readable test scripts.
- **Zero overhead in production** is achieved through conditional compilation and runtime flags that disable all test infrastructure when not needed.

## Frequently Asked Questions

### How do I enable the Test Engine without modifying ImGui source code?

Enable the Test Engine by setting the `TestEngineHookItems` flag on your ImGui context after creating the engine instance. According to the source code in [`imgui_internal.h`](https://github.com/ocornut/imgui/blob/main/imgui_internal.h) (line 2253), this flag gates all `IMGUI_TEST_ENGINE_*` macros, allowing you to toggle testing at runtime without recompiling ImGui. Simply link against the imgui_test_engine repository and assign the engine pointer to `ImGui::GetCurrentContext()->TestEngine`.

### What performance impact does the Test Engine have on my application?

The Test Engine imposes **zero overhead** when disabled. All item registration macros expand to no-ops unless `g.TestEngineHookItems` is true, and the `g.TestEngine` pointer remains unused in standard builds. When enabled, the impact is limited to the cost of recording item IDs and bounding boxes via `ImGuiTestEngineHook_ItemAdd`, which is typically negligible for CI and testing scenarios.

### Can I use the Test Engine with custom widgets that don't use standard ImGui functions?

Yes. Custom widgets can integrate with the Test Engine by manually calling `IMGUI_TEST_ENGINE_ITEM_ADD` with the widget's ID and bounding box, followed by `IMGUI_TEST_ENGINE_ITEM_INFO` to provide the label and status flags. As shown in [`imgui_internal.h`](https://github.com/ocornut/imgui/blob/main/imgui_internal.h), these macros accept the same parameters ImGui uses internally, ensuring your custom widgets are fully discoverable by test scripts.

### Where is the actual Test Engine implementation located?

The Test Engine implementation resides in the **imgui_test_engine** companion repository, not in the main ocornut/imgui repository. The core ImGui library only provides the instrumentation hooks (the `ImGuiContextHook` structure and registration macros) and the `g.TestEngine` void pointer for storage. This separation allows you to include the full engine only in test builds, keeping production binaries lean.