From 557730390585fef06a7c6aaee043ec6d26cccb16 Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 16 Oct 2026 03:23:43 +0000 Subject: [PATCH] fix(modern): a store's window never builds the stress panel The stress panel (vtmodern --stress) was built in every window and only hidden, so keeping a store's screen still depended on each of its bindings remembering there was no stress test; the last fix guarded one timer. Main.qml now loads the panel only while a stress test is attached (a Loader, like the setup guide), so a store has no panel, no hidden controls and no tour timer at all. The timer's duplicate stress check and the duplicate objectName on the instance go. The regression test asserts the panel and its tour timer do not exist in a store's window, then attaches an unstarted stress runner as a control: the panel appears with the tour running and leaves when it is detached, so the names it checks are proven live. It no longer waits 200 ms on a 15-second timer, uses findChild instead of a hand-rolled finder, and is tagged [flow][ui] rather than a look-alike of the hidden [.stress] run. Co-Authored-By: Claude Fable 5.1 Claude-Session: https://claude.ai/code/session_018nW8B6ZSc3vRSbdE1Vk358 --- modern/tests/test_pos_flow.cpp | 38 ++++++++++++++++------------------ modern/ui/qml/Main.qml | 14 ++++++++----- modern/ui/qml/StressPanel.qml | 6 +++--- 3 files changed, 30 insertions(+), 28 deletions(-) diff --git a/modern/tests/test_pos_flow.cpp b/modern/tests/test_pos_flow.cpp index 36279aaf..fc48612f 100644 --- a/modern/tests/test_pos_flow.cpp +++ b/modern/tests/test_pos_flow.cpp @@ -2,6 +2,7 @@ #include #include "net/build_info.hh" +#include "net/stress.hh" #include "layout_fixture.hh" #include "layoutcontroller.hh" #include "print/raster.hh" @@ -2234,29 +2235,26 @@ TEST_CASE("UI: ring items in by number (keyboard, or Find)", "[flow][ui][plu]") } } -TEST_CASE("UI: no stress test, no page tour: the screen stays where it is", "[flow][ui][stress]") +TEST_CASE("UI: no stress test, no stress panel: the screen stays where it is", "[flow][ui]") { Screen s; - // The stress panel is always there (hidden); its tour of the pages must - // not run without a stress test, or a store's screen changes by itself. - // Hidden (no stress test), so looked for among hidden items too. - const std::function find = [&find](QQuickItem *root) -> QQuickItem * { - for (QQuickItem *item : root->childItems()) { - if (item->objectName() == u"stressPanel"_s) - return item; - if (QQuickItem *hit = find(item)) - return hit; - } - return nullptr; - }; - QQuickItem *panel = find(s.window->contentItem()); - REQUIRE(panel); - QObject *tour = panel->findChild(u"stressPageTour"_s); + // A store's window never builds the stress panel (Main.qml loads it only + // for a stress test), so there is no tour of the pages to move its screen. + CHECK_FALSE(s.window->findChild(u"stressPanel"_s)); + CHECK_FALSE(s.window->findChild(u"stressPageTour"_s)); + + // The control: a stress test on the window brings the panel, tour running, + // so the two names above are live rather than stale. + net::StressRunner stress(s.pos.shared(), nullptr, {}); // never started: just something to show + s.window->setProperty("stress", QVariant::fromValue(static_cast(&stress))); + QTest::qWait(20); + QObject *tour = s.window->findChild(u"stressPageTour"_s); REQUIRE(tour); - CHECK_FALSE(tour->property("running").toBool()); - const QString page = s.c.pageId(); - QTest::qWait(200); - CHECK(s.c.pageId() == page); + REQUIRE(tour->inherits("QQmlTimer")); + CHECK(tour->property("running").toBool()); + s.window->setProperty("stress", QVariant::fromValue(static_cast(nullptr))); // before `stress` dies + QTest::qWait(20); // the Loader deletes its item with deleteLater(); qWait flushes DeferredDelete + CHECK_FALSE(s.window->findChild(u"stressPanel"_s)); } TEST_CASE("UI: the manager's dashboard: today so far", "[flow][ui][dashboard]") diff --git a/modern/ui/qml/Main.qml b/modern/ui/qml/Main.qml index 0d998f94..8c18ca29 100644 --- a/modern/ui/qml/Main.qml +++ b/modern/ui/qml/Main.qml @@ -1257,10 +1257,14 @@ ApplicationWindow { function onNoticeChanged() { root.toast(root.editor.notice) } } - StressPanel { - objectName: "stressPanel" - visible: root.stress !== null - stress: root.stress - controller: root.controller + // The stress test's numbers (vtmodern --stress). Only built then: a + // store's window has no panel, and no tour of the pages. + Loader { + anchors.fill: parent + z: 95 + active: root.stress !== null + sourceComponent: Item { + StressPanel { stress: root.stress; controller: root.controller } + } } } diff --git a/modern/ui/qml/StressPanel.qml b/modern/ui/qml/StressPanel.qml index 6e2aa303..8166ce45 100644 --- a/modern/ui/qml/StressPanel.qml +++ b/modern/ui/qml/StressPanel.qml @@ -31,15 +31,15 @@ Rectangle { border.color: done ? (st.passed ? "#2fa35a" : "#d64545") : "#3a4250" border.width: done ? 3 : 1 - // Around the restaurant: a page every 15 seconds (only in a stress test: - // the panel is always there, hidden). + // Around the restaurant: a page every 15 seconds. (Main.qml builds this + // panel only during a stress test: a store's screen is never toured.) Timer { objectName: "stressPageTour" readonly property var pages: ["tables", "seating", "kitchen", "expo", "dashboard", "deliveries"] property int at: 0 interval: 15000 repeat: true - running: panel.stress !== null && panel.autoPages && !panel.done && panel.controller !== null + running: panel.autoPages && !panel.done && panel.controller !== null onTriggered: { at = (at + 1) % pages.length; panel.controller.jumpTo(pages[at]) } }