Files
rose-ash/spec/tests/test-perform-chain.sx
giles 5c42f4842b Tests: cek-try-seq / htmx / hs-diag / perform-chain + node HS runners
New spec tests: test-cek-try-seq (CEK try/seq), test-htmx (htmx
directive coverage, 292L), test-hs-diag, test-perform-chain (IO
suspension chains).

tests/hs-*.js: Node.js-side hyperscript runners for browser-mode
testing (hs-behavioral-node, hs-behavioral-runner, hs-parse-audit,
hs-run-timed).

Vendors shared/static/scripts/htmx.min.js.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-22 09:09:27 +00:00

63 lines
3.0 KiB
Plaintext

;; Tests for perform/IO suspension chaining through for-each
;; Bug: after resume from first perform inside for-each,
;; subsequent iterations' performs don't suspend — they complete
;; synchronously, breaking multi-step async sequences like test runners.
(defsuite
"perform-for-each-chain"
(deftest
"for-each with perform suspends on each iteration"
(let
((state1 (cek-step-loop (make-cek-state (quote (let ((results (list))) (for-each (fn (item) (let ((val (perform {:op "fetch" :key item}))) (append! results val))) (list "a" "b" "c")) results)) (make-env) (list)))))
(assert-true (cek-suspended? state1))
(assert= "a" (get (cek-io-request state1) :key))
(let
((state2 (cek-resume state1 "result-a")))
(assert-true (cek-suspended? state2))
(assert= "b" (get (cek-io-request state2) :key))
(let
((state3 (cek-resume state2 "result-b")))
(assert-true (cek-suspended? state3))
(assert= "c" (get (cek-io-request state3) :key))
(let
((final (cek-resume state3 "result-c")))
(assert-true (cek-terminal? final))
(assert= 3 (len (cek-value final))))))))
(deftest
"for-each with guard and perform chains correctly"
(let
((state1 (cek-step-loop (make-cek-state (quote (let ((results (list))) (for-each (fn (item) (guard (e (true (append! results (str "fail:" item)))) (let ((val (perform {:op "fetch" :key item}))) (append! results (str "ok:" val))))) (list "x" "y")) results)) (make-env) (list)))))
(assert-true (cek-suspended? state1))
(let
((state2 (cek-resume state1 "X")))
(assert-true (cek-suspended? state2))
(let
((final (cek-resume state2 "Y")))
(assert-true (cek-terminal? final))
(let
((results (cek-value final)))
(assert= 2 (len results))
(assert= "ok:X" (nth results 0))
(assert= "ok:Y" (nth results 1)))))))
(deftest
"nested performs in for-each — reload + wait pattern"
(let
((state1 (cek-step-loop (make-cek-state (quote (let ((log (list))) (for-each (fn (name) (perform {:op "wait" :ms 1000}) (append! log (str "reloaded:" name)) (perform {:op "wait" :ms 500}) (append! log (str "done:" name))) (list "t1" "t2")) log)) (make-env) (list)))))
(assert-true (cek-suspended? state1))
(assert= 1000 (get (cek-io-request state1) :ms))
(let
((s2 (cek-resume state1 nil)))
(assert-true (cek-suspended? s2))
(assert= 500 (get (cek-io-request s2) :ms))
(let
((s3 (cek-resume s2 nil)))
(assert-true (cek-suspended? s3))
(assert= 1000 (get (cek-io-request s3) :ms))
(let
((s4 (cek-resume s3 nil)))
(assert-true (cek-suspended? s4))
(assert= 500 (get (cek-io-request s4) :ms))
(let
((final (cek-resume s4 nil)))
(assert-true (cek-terminal? final))
(assert= 4 (len (cek-value final))))))))))