using AcDream.Core.Chat; using AcDream.UI.Abstractions.Panels.Chat; namespace AcDream.UI.Abstractions.Tests.Panels.Chat; /// /// Phase K.2 — Tab fires , /// which calls . The chat panel honors /// the request on the very next by emitting /// a SetKeyboardFocusHere immediately before the input field. After /// it fires once, subsequent renders without another FocusInput /// call must not re-fire (one-shot semantics) — otherwise the chat field /// would steal focus on every frame and the user could never click out. /// public sealed class ChatPanelFocusTests { private sealed class NullBus : AcDream.UI.Abstractions.ICommandBus { public void Publish(T command) where T : notnull { } } [Fact] public void FocusInput_NextRender_EmitsSetKeyboardFocusHereBeforeInput() { var panel = new ChatPanel(new ChatVM(new ChatLog())); var renderer = new FakePanelRenderer(); panel.FocusInput(); panel.Render(new PanelContext(0.016f, new NullBus()), renderer); // Find the SetKeyboardFocusHere call; it must come before the // InputTextSubmit call so ImGui applies the focus to that widget. int focusIdx = -1, inputIdx = -1; for (int i = 0; i < renderer.Calls.Count; i++) { if (renderer.Calls[i].Method == "SetKeyboardFocusHere") focusIdx = i; else if (renderer.Calls[i].Method == "InputTextSubmit") inputIdx = i; } Assert.True(focusIdx >= 0, "ChatPanel must call SetKeyboardFocusHere when FocusInput requested."); Assert.True(inputIdx >= 0, "ChatPanel must still render the InputTextSubmit field."); Assert.True(focusIdx < inputIdx, "SetKeyboardFocusHere must precede the InputTextSubmit it targets."); } [Fact] public void Render_WithoutFocusInputCall_DoesNotEmitSetKeyboardFocusHere() { var panel = new ChatPanel(new ChatVM(new ChatLog())); var renderer = new FakePanelRenderer(); panel.Render(new PanelContext(0.016f, new NullBus()), renderer); Assert.DoesNotContain(renderer.Calls, c => c.Method == "SetKeyboardFocusHere"); } [Fact] public void FocusInput_OnlyAffectsTheNextRender_OneShot() { var panel = new ChatPanel(new ChatVM(new ChatLog())); // Frame 1 — FocusInput requested → expect a SetKeyboardFocusHere. var r1 = new FakePanelRenderer(); panel.FocusInput(); panel.Render(new PanelContext(0.016f, new NullBus()), r1); Assert.Contains(r1.Calls, c => c.Method == "SetKeyboardFocusHere"); // Frame 2 — no further FocusInput call → must NOT re-fire. var r2 = new FakePanelRenderer(); panel.Render(new PanelContext(0.016f, new NullBus()), r2); Assert.DoesNotContain(r2.Calls, c => c.Method == "SetKeyboardFocusHere"); } }