Skip to content
omar edited this page Jan 20, 2025 · 15 revisions

Index


Once the Test Engine is setup, most interactions are done via the ImGuiTextContext interface. Refer to imgui_te_context.h for API and comments.

You may refer to app_minimal_tests.cpp as a reference for basic tests. You may refer to our test suite imgui_test_suite/ for a larger amount of reference code. Please note that our test suite is written primarily with the intent of testing Dear ImGui, not with the intent of providing examples for using the API.


Registering and Queuing Tests

See Setting Up -> Registering and Queuing Tests section.


Check Macros

  • A failed check will:
    • Output an error and set the test status accordingly.
    • Optionally break in debugger (if test_io.ConfigBreakOnError is set).
    • Return from the function (unless _NORET() is used).
  • The main macro is IM_CHECK(), e.g. IM_CHECK(result == true);
  • Operator macros are preferred as they will display the VALUE of both operands in the log: IM_CHECK_EQ(), IM_CHECK_NE(), IM_CHECK_LT(), IM_CHECK_LE(), IM_CHECK_GT(), IM_CHECK_GE().
  • Add suffix _NORET e.g. IM_CHECK_NO_RET(result == true); to prevent the macro from returning from function on failure (which is the default).
  • Add suffix _RETV e.g. IM_CHECK_RETV(result == true, -1); to return a specific error is running from sub-functions.
  • Add suffix _SILENT e.g. IM_CHECK_SILENT(window != NULL); to omit appending to log on lower verbose levels (reduce spam).
  • Specialized checks for strings: IM_CHECK_STR_EQ(), IM_CHECK_STR_NE().
  • Specialized checks for floating point values: IM_CHECK_FLOAT_EQ_EPS(), IM_CHECK_FLOAT_NEAR().
t = IM_REGISTER_TEST(e, "demo_tests", "always_fail");
t->TestFunc = [](ImGuiTestContext* ctx)
{
    int value = 1;
    IM_CHECK_EQ(value, 2);
};

image


Accessing your Data

(1) One solution is to set the void* UserData field of the structure ImGuiTest:

t = IM_REGISTER_TEST(e, "myapp_tests", "test1"); 
t->UserData = (void*)my_app; // Associate application pointer when registering
t->TestFunc = [](ImGuiTestContext* ctx)
{
    MyApp* my_app = (MyApp*)ctx->Test->UserData; // Retrieve application pointer when running.
    [....]
    // access your data however you need, e.g.
    IM_CHECK_EQ(my_app.GetSettings()->GridEnabled, true);
};

(2) You can access common widget states via ctx->ItemIsChecked("my_checkbox"), ctx->ItemIsOpened("my_tree_node") and other status flags emitted by ctx->ItemInfo(). You can use ctx->ItemReadAsInt(), ctx->ItemReadAsFloat(), ctx->ItemReadAsString(), etc functions to extract data from a SliderXXX/DragXXX/InputXXX item:

const char* str = ctx->ItemReadAsString("MyTextField");
IM_CHECK_STR_EQ(str, "expected value");

int v = ctx->ItemReadAsInt("MySlider", &v);
IM_CHECK_EQ(v, 42);

(3) Depending on the nature of your tests, you may want to share variables between your application or your GuiFunc and your TestFunc. This is mostly only ever useful if you are using a GuiFunc (e.g. for testing your own widgets or dialogs independently from your main application). To do this, you can request the test engine to instantiate a custom structure during the duration of a test running:

struct TestVars { int MyInt = 42; };
t = IM_REGISTER_TEST(e, "demo_tests", "test2");
t->SetVarsDataType<TestVars2>();
t->GuiFunc = [](ImGuiTestContext* ctx)
{
    auto& vars = ctx->GetVars<TestVars>();
    ImGui::Begin("Test Window", NULL, ImGuiWindowFlags_NoSavedSettings);
    ImGui::SliderInt("Slider", &vars.MyInt, 0, 1000);
    ImGui::End();
};
t->TestFunc = [](ImGuiTestContext* ctx)
{
    auto& vars = ctx->GetVars<auto>();
    ctx->SetRef("Test Window");

    IM_CHECK_EQ(vars.MyInt, 42); // Check default value
    ctx->ItemInputValue("Slider", 123);
    IM_CHECK_EQ(vars.MyInt, 123); // Check value after our action
};

As a convenience, we also provide a structure called ImGuiTestGenericVars and always available in ctx->GenericVars. The structure hold variety of ready-to-use named fields.

(4) We are working on a "screen reader" tool to read text and shapes emitted by widgets, so a future possibility would be to read data from the visual output.


Named References

See Named References page where all nice uses of ImGuiTestRef are explained:

ctx->SetRef("Window");                      // Set Base Reference
ctx->ItemClick("Button");                   // Relative path
ctx->ItemClick("Node/Item");                // Relative path (composite)
ctx->ItemClick("//Window/Button");          // Absolute path
ctx->ItemClick("//$FOCUSED/Button");        // Relative to focused window
ctx->ItemClick("//Window/List/$$0/Button"); // Encode literal integer in string, for PushID(int)
ctx->ItemClick("//Window/**/Button");       // Wildcard search by full label
ctx->WindowInfo("//Window/Child/SubChild"); // Find child window by short name

ImGuiTestContext API

Refer to imgui_te_context.h

(TODO)