ocornut / imgui_test_engine

Dear ImGui Automation Engine & Test Suite
386 stars 40 forks source link

Unmangle child ids #48

Closed mgerhardy closed 2 months ago

mgerhardy commented 2 months ago

It looks like I really can't get this running.. The item ##_top_selector_neo is not found

I have the following path copied from Stack Tool

// /Animation###animationtimeline\/##neo-sequencer-child_EEF00089\/####neo-sequencer_child_wrapper_D29EAF74/##neo-sequencer/##_top_selector_neo
ctx->SetRef("Animation###animationtimeline");
ctx->SetRef(ctx->WindowInfo("##neo-sequencer-child")->ID);
ctx->SetRef(ctx->WindowInfo("####neo-sequencer_child_wrapper")->ID);
ctx->MouseMove("##neo-sequencer/##_top_selector_neo");
ctx->MouseDragWithDelta({10.0f, 0.0f});
ctx->ItemClick("###Add");

These are the logs

[0000] Test: 'animationtimeline' 'create keyframe'..
[0000] -- SetInputMode 1
[0001] -- ItemClick '###viewport0' > 00000000
[0016] -- WindowFocus('22585415 > 'NULL'')
[0017] -- SetRef ' Animation###animationtimeline' 22585415
[0017] OK AnimationTimelineTest.cpp:20 'focusWindow(ctx, title)'
[0017] -- WindowInfo: by path: '##neo-sequencer-child'
[0018] -- SetRef 'NULL' 4226E3F2
[0018] -- WindowInfo: by path: '####neo-sequencer_child_wrapper'
[0019] -- SetRef 'NULL' AAFE48E8
[0023] Error 'Unable to locate item: '/##neo-sequencer/##_top_selector_neo''
[0023] -- MouseMove to '##neo-sequencer/##_top_selector_neo' > 00000000
[0023] create keyframe test failed.

side note - the mentioned focusWindow function in the logs looks like this


bool Panel::focusWindow(ImGuiTestContext *ctx, const char *title) {
    IM_CHECK_SILENT_RETV(title != nullptr, false);
    ImGuiWindow* window = ImGui::FindWindowByName(title);
    if (window == nullptr) {
        ctx->LogError("Error: could not find window with title/id %s", title);
        IM_CHECK_SILENT_RETV(window != nullptr, false);
    }
    ctx->WindowFocus(window->ID);
    ctx->SetRef(window);
    return true;
}

As a sidenote - I've also tried to use //**/##neo-sequencer-child and //**/**/##neo-sequencer-child (up to 5 times **/ out of ignorance ;) )

And last but not least a screenshot of the "problem" ;)

Bildschirmfoto vom 2024-04-20 18-03-41

ocornut commented 2 months ago

Sorry I am confused by the issue as posted.

mgerhardy commented 2 months ago

I'll try to post an update here with the updated and cleaned-up id handing (also with one child less)

void AnimationTimeline::registerUITests(ImGuiTestEngine *engine, const char *title) {
    // Copied path: / Animation###animationtimeline\/##sequencer_child_wrapper_C173513F/sequencer/##_top_selector_neo
    //
    // ----logs
    // [0000] Test: 'animationtimeline' 'create keyframe'..
    // [0000] -- SetInputMode 1
    // [0001] -- ItemClick '###viewport0' > 00000000
    // [0001] --   MouseMove to '###viewport0' > 00000000
    // [0001] --     WindowBringToFront()->FocusWindow('Free SceneMode###viewport0')
    // [0003] --     MouseMoveToPos from (2358,858) to (947,654)
    // [0005] --     BringWindowToDisplayFront('Free SceneMode###viewport0') (window.back=##Combo_00)
    // [0010] --   MouseClick 0
    // [0014] -- WindowFocus('22585415')
    // [0015] -- SetRef ' Animation###animationtimeline' 22585415
    // [0015] OK AnimationTimelineTest.cpp:23 'focusWindow(ctx, title)'
    // [0015] -- WindowInfo: by path: '##sequencer_child_wrapper'
    // [0016] -- SetRef 'NULL' 7B448F59
    // [0020] Error 'Unable to locate item: '/sequencer/##_top_selector_neo''
    // [0020] -- MouseMove to 'sequencer/##_top_selector_neo' > 00000000
    // [0020] create keyframe test failed.

    IM_REGISTER_TEST(engine, testCategory(), "create keyframe")->TestFunc = [=](ImGuiTestContext *ctx) {
        const int viewportId = viewportSceneMode(ctx, _app);
        IM_CHECK_SILENT(viewportId != -1);
        const core::String id = Viewport::viewportId(viewportId);
        ctx->ItemClick(id.c_str());

        IM_CHECK(focusWindow(ctx, title)); // line 0015 in logs
        ctx->SetRef(ctx->WindowInfo("##sequencer_child_wrapper").ID);
                // even without "sequencer" id being pushed - a single "##_top_selector_neo" is not found here
        ctx->MouseMove("sequencer/##_top_selector_neo"); // sequencer is pushed via PushID(), ##_top_selector_neo is an ItemHoverable()
        [...]
    };
}

I hope that this might help a little bit more. If not, I don't want to waste your time any further - I'm sure the error is on my side and I'll fiddle it out.

Thanks a lot

ocornut commented 2 months ago

I'm not sure if you are proposing to do ctx->SetRef(ctx->WindowInfo(title + "/##sequencer_child_wrapper").ID); here?

Yes was suggesting that (or you can use .Window as well).

If not, I don't want to waste your time any further - I'm sure the error is on my side and I'll fiddle it out.

Dealing with child windows can get abnormally confusing or tricky. There are reasons for this but it shouldn't be an excuse (aka I should improve the system). I'd rather have you share your pain here so we can improve the situation.

(Although fuller wildcard support is difficult to support for widgets (e.g. "*world") it's technically more at reach for windows since we do carry retained representation of them along with their hierarchy. So perhaps adding support for those may be another good tool we can implement as well.)

mgerhardy commented 2 months ago

this works, too (only setting the reference - not getting the child item for ##_top_selector_neo)

core::String fullPathId = core::string::format("//%s/##sequencer_child_wrapper", title); // title is the full label of the window as given in the log output above
ctx->SetRef(ctx->WindowInfo(fullPathId.c_str()).ID);

but no matter which string path I give to ctx->ItemInfo() - I can't find that item - even by simple brute-forcing..:

ctx->SetRef(ctx->WindowInfo("//$FOCUSED/##sequencer_child_wrapper").ID); // works - according to the logs
ctx->ItemInfo("/sequencer/##_top_selector_neo");
ctx->TestOutput->Status = ImGuiTestStatus_Success;
ctx->ItemInfo("sequencer/##_top_selector_neo");
ctx->TestOutput->Status = ImGuiTestStatus_Success;
ctx->ItemInfo("//sequencer/##_top_selector_neo");
ctx->TestOutput->Status = ImGuiTestStatus_Success;
ctx->ItemInfo("//##_top_selector_neo");
ctx->TestOutput->Status = ImGuiTestStatus_Success;
ctx->ItemInfo("##_top_selector_neo");
ctx->TestOutput->Status = ImGuiTestStatus_Success;
ctx->ItemInfo("**/##_top_selector_neo");
ctx->TestOutput->Status = ImGuiTestStatus_Success;

And even after re-reading the code and https://github.com/ocornut/imgui_test_engine/wiki/Named-References I can't get it...


As a side-note: I wonder whether it would make sense to print the string from ItemInfoErrorLog() in trace log at least.

maybe an edge case - but useful when just brute forcing the different attempts

ctx->ItemInfo(fullItemPathId.c_str(),);
ctx->TestOutput->Status = ImGuiTestStatus_Success;
ctx->ItemInfo("##_top_selector_neo");
ctx->TestOutput->Status = ImGuiTestStatus_Success;
ctx->ItemInfo("**/##_top_selector_neo");

would be easier like this:

ctx->ItemInfo(fullItemPathId.c_str(), ImGuiTestOpFlags_NoError);
ctx->ItemInfo("##_top_selector_neo", ImGuiTestOpFlags_NoError);
ctx->ItemInfo("**/##_top_selector_neo", ImGuiTestOpFlags_NoError);
ocornut commented 2 months ago

I can’t really help you if i don’t know what the Begin/BeginChild code structure is.

ocornut commented 2 months ago

Just to clarify, I would really like to help, and I would really like to do anything I can to improve and simplify this. But I'm also overwhelmed in requests so it sometimes can be difficult to track bundled requests (many different ideas in a same thread) or if it's not obvious how to repro.

ocornut commented 2 months ago

would be easier like this: ctx->ItemInfo(fullItemPathId.c_str(), ImGuiTestOpFlags_NoError);

I'm not sure I understand what you are suggesting. This normally DOES work to be passing ImGuiTestOpFlags_NoError to make a failed lookup not alter status. So yeah you can do that. What are you suggesting?

ctx->TestOutput->Status = ImGuiTestStatus_Success;

Please don't do this :D

It's not easy to extract. ##_top_selector_neo is submitted like this ItemHoverable(pointerRect, GetCurrentWindow()->GetID("##_top_selector_neo"), 0);

It's been hard to help because you never submitted even pseudo-code about what those items were. But this line suggest that ##_top_selector_neo is a custom widget? For the item to be seen by test engine, you need to either call ItemAdd() or IMGUI_TEST_ENGINE_ITEM_ADD() (the later is called by ItemAdd).