Every QuickApp has that moment: a handful of buttons and selects, each with a callback, and "did I break any of them with that change?" means clicking through the whole UI by hand. With 44 possible actions, that is an afternoon you never get back. flua can do it in one run, one exit code — the QA is the test.
Two ready-made examples ship with flua; run them from the repo root:
flua --api local examples/ui-interaction-test.lua # one action, end to end flua --api local examples/ui-interaction-suite.lua # the whole UI, data-driven
ui-interaction-test.lua loads a JSON fixture, injects a
button release and a select change the way the HC3 UI would deliver them,
waits for each asynchronous callback, and asserts both the rendered view
(self:getView()) and the simulator state
(api.get / self.properties). The verdict is the
exit code:
flua --api local examples/ui-interaction-test.lua echo $? # 0 = every check passed
The one detail that trips people up: _FLUA.uiEvent(...)
returns before the callback runs — it delivers the event like the HC3 UI
does. So the test polls for the callback's effect and then asserts,
instead of asserting immediately. The example's waitUntil
helper is the whole trick, and it works in every clock mode
(--instant included).
ui-interaction-suite.lua scales it: a table of cases, one
loop:
local cases = {
{element="btnA", event="onReleased", expect="A"},
{element="btnB", event="onReleased", expect="B"},
{element="btnC", event="onReleased", expect="C"},
}
Each row injects the event, waits for the callback's effect on the
view, checks it, and moves to the next — printing PASS/FAIL per element
and exiting with the failure count. For your real QA, the
expect check becomes an assertion on the actual state: the
view text, a property, a variable, an API read. One run covers the whole
surface; the exit code feeds CI.
PASS btnA -> A PASS btnB -> B PASS btnC -> C VERDICT: all passed
Two flags turn the pattern into a trustworthy pipeline step:
flua --api local --strict-tests --result-json result.json qa.lua
--strict-tests — an unhandled callback error fails the
run (exit 1) even if a later callback exits 0. Sticky: your UI callback
crashing can never look green.--result-json — one machine-readable verdict
(passed/failed/timeout, the failure records with the callback kind, clock
mode, timings). Your agent or CI reads that instead of grepping logs.Add rows as the UI grows — the suite is a living regression test, and "did I break a button?" becomes a 10-second answer instead of an afternoon of clicking.