Add call-lambda + trampoline handler tests for dom-on pattern
Regression tests for the silent failure where callLambda returns a Thunk (TCO) that must be trampolined for side effects to execute. Without trampoline, event handlers (swap!, reset!) silently did nothing. 5 tests covering: single mutation, event arg passing, multi-statement body, repeated accumulation, and nested lambda calls — all through the (trampoline (call-lambda handler args)) pattern that dom-on uses. Tests: 1322 JS (full), 1114 OCaml Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -294,3 +294,55 @@
|
|||||||
(swap! acc + 5)
|
(swap! acc + 5)
|
||||||
(swap! acc - 3)
|
(swap! acc - 3)
|
||||||
(assert-equal 12 (deref acc)))))
|
(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)))))
|
||||||
|
|||||||
Reference in New Issue
Block a user