diff --git a/spec/tests/test-signals-advanced.sx b/spec/tests/test-signals-advanced.sx index 07a8cac..cda2e2a 100644 --- a/spec/tests/test-signals-advanced.sx +++ b/spec/tests/test-signals-advanced.sx @@ -294,3 +294,55 @@ (swap! acc + 5) (swap! acc - 3) (assert-equal 12 (deref acc))))) + + +;; -------------------------------------------------------------------------- +;; call-lambda + trampoline — event handler pattern +;; -------------------------------------------------------------------------- +;; +;; Regression: dom-on wraps Lambda event handlers in JS functions that +;; call callLambda. callLambda returns a Thunk (TCO), but the wrapper +;; never trampolined it, so the handler body (swap!, reset!, etc.) +;; never executed. Buttons rendered but clicks had no effect. +;; +;; These tests verify the pattern that dom-on uses: +;; (trampoline (call-lambda handler (list arg))) +;; must resolve thunks and execute side effects. + +(defsuite "call-lambda-trampoline-handlers" + (deftest "call-lambda + trampoline executes signal mutation" + (let ((count (signal 0)) + (handler (fn () (swap! count + 1)))) + (trampoline (call-lambda handler (list))) + (assert-equal 1 (deref count)))) + + (deftest "call-lambda + trampoline with event arg" + (let ((last-val (signal nil)) + (handler (fn (e) (reset! last-val e)))) + (trampoline (call-lambda handler (list "click-event"))) + (assert-equal "click-event" (deref last-val)))) + + (deftest "call-lambda + trampoline executes multi-statement body" + (let ((a (signal 0)) + (b (signal 0)) + (handler (fn () + (reset! a 10) + (reset! b 20)))) + (trampoline (call-lambda handler (list))) + (assert-equal 10 (deref a)) + (assert-equal 20 (deref b)))) + + (deftest "repeated call-lambda accumulates side effects" + (let ((count (signal 0)) + (handler (fn () (swap! count + 1)))) + (trampoline (call-lambda handler (list))) + (trampoline (call-lambda handler (list))) + (trampoline (call-lambda handler (list))) + (assert-equal 3 (deref count)))) + + (deftest "call-lambda handler calling another lambda" + (let ((log (signal (list))) + (inner (fn (msg) (reset! log (append (deref log) (list msg))))) + (outer (fn () (inner "hello") (inner "world")))) + (trampoline (call-lambda outer (list))) + (assert-equal (list "hello" "world") (deref log)))))