HS: wip — parser every-fix, integration boot, test tooling expansion

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-05-06 18:51:32 +00:00
parent b0c135412a
commit c5d9a8b789
6 changed files with 442 additions and 64 deletions

View File

@@ -1891,7 +1891,20 @@
(assert= (dom-text-content (dom-query-by-id "d2")) "clicked")
))
(deftest "fires hyperscript:parse-error event with all errors"
(error "SKIP (untranslated): fires hyperscript:parse-error event with all errors"))
(hs-cleanup!)
(let ((_fired false) (_err-count 0))
(let ((_el (dom-create-element "div")))
(dom-listen _el "hyperscript:parse-error"
(fn (e)
(set! _fired true)
(let ((_errs (host-get (host-get e "detail") "errors")))
(set! _err-count (len _errs)))))
(dom-set-attr _el "_" "worker MyWorker end")
(dom-append (dom-body) _el)
(hs-activate! _el)
(assert _fired)
(assert (> _err-count 0))))
)
(deftest "parse error at EOF on trailing newline does not crash"
(let ((caught nil))
(guard (_e (true (set! caught (str _e))))
@@ -5712,17 +5725,34 @@
(assert= (eval-hs-locals "getObj().greet()" (list (list (quote getObj) (fn () {:greet (fn () "hi")})))) "hi")
)
(deftest "can invoke function on object"
(error "SKIP: JS this-binding not supported in SX lambdas")
(hs-cleanup!)
(hs-js-exec (list) "window.hsTestObj = {value: 'foo', getValue: function() { return this.value }}" (list))
(let ((_obj (host-get (host-global "window") "hsTestObj")))
(assert= (host-call _obj "getValue" (list)) "foo"))
)
(deftest "can invoke function on object w/ async arg"
(error "SKIP (untranslated): can invoke function on object w/ async arg"))
(hs-cleanup!)
(hs-js-exec (list) "window.asyncArgObj = {identity: function(x) { return x; }}" (list))
(let ((_obj (host-get (host-global "window") "asyncArgObj")))
(let ((_arg (hs-win-call "promiseAnIntIn" (list 10))))
(assert= (host-call _obj "identity" _arg) 42)))
)
(deftest "can invoke function on object w/ async root & arg"
(error "SKIP (untranslated): can invoke function on object w/ async root & arg"))
(hs-cleanup!)
(hs-js-exec (list) "window.asyncRootObj = {asyncId: function(x) { return Promise.resolve(x); }}" (list))
(let ((_obj (host-get (host-global "window") "asyncRootObj")))
(let ((_arg (hs-win-call "promiseAnIntIn" (list 10))))
(let ((_result (host-call _obj "asyncId" _arg)))
(let ((_state (host-promise-state _result)))
(assert= (if _state (host-get _state "value") _result) 42)))))
)
(deftest "can invoke global function"
(assert= (eval-hs-locals "identity(\"foo\")" (list (list (quote identity) (fn (x) x)))) "foo")
)
(deftest "can invoke global function w/ async arg"
(error "SKIP (untranslated): can invoke global function w/ async arg"))
(hs-cleanup!)
(assert= (eval-hs "identity(promiseAnIntIn(10))") 42)
)
(deftest "can pass an array literal as an argument"
(assert= (eval-hs-locals "sum([1, 2, 3, 4])" (list (list (quote sum) (fn (arr) (reduce (fn (a b) (+ a b)) 0 arr))))) 10)
)
@@ -5869,7 +5899,9 @@
;; ── expressions/logicalOperator (10 tests) ──
(defsuite "hs-upstream-expressions/logicalOperator"
(deftest "and short-circuits when lhs promise resolves to false"
(error "SKIP (untranslated): and short-circuits when lhs promise resolves to false"))
(hs-cleanup!)
(assert= (eval-hs "promiseValueBackIn(false, 0) and \"foo\"") false)
)
(deftest "and works"
(assert= (eval-hs "true and false") false)
)
@@ -5877,9 +5909,13 @@
(assert= (eval-hs "true and true and false") false)
)
(deftest "or evaluates rhs when lhs promise resolves to false"
(error "SKIP (untranslated): or evaluates rhs when lhs promise resolves to false"))
(hs-cleanup!)
(assert= (eval-hs "promiseValueBackIn(false, 0) or \"foo\"") "foo")
)
(deftest "or short-circuits when lhs promise resolves to true"
(error "SKIP (untranslated): or short-circuits when lhs promise resolves to true"))
(hs-cleanup!)
(assert (eval-hs "promiseValueBackIn(true, 0) or \"foo\""))
)
(deftest "or works"
(assert= (eval-hs "true or false") true)
)
@@ -5932,7 +5968,9 @@
(assert= (eval-hs "[1] + [2] + [3]") (list 1 2 3))
)
(deftest "can use mixed expressions"
(error "SKIP (untranslated): can use mixed expressions"))
(hs-cleanup!)
(assert= (eval-hs "1 + promiseAnIntIn(10)") 43)
)
(deftest "division works"
(assert= (eval-hs "1 / 2") 0.5)
)
@@ -7702,7 +7740,14 @@
(assert= (dom-text-content _el-div) "yay")
))
(deftest "can do a simple fetch w/ html"
(error "SKIP (skip-list): can do a simple fetch w/ html"))
(hs-cleanup!)
(let ((_el (dom-create-element "div")))
(dom-set-attr _el "_" "on click fetch /test as html then set my innerHTML to result.childElementCount")
(dom-append (dom-body) _el)
(hs-activate! _el)
(dom-dispatch _el "click" nil)
(assert= (dom-text-content _el) "1"))
)
(deftest "can do a simple fetch w/ json"
(hs-cleanup!)
(let ((_el-div (dom-create-element "div")))
@@ -9388,7 +9433,15 @@
(hs-activate! _el-button)
))
(deftest "can be in a top level script tag"
(error "SKIP (skip-list): can be in a top level script tag"))
(hs-cleanup!)
(let ((_demo (dom-create-element "div")))
(dom-set-attr _demo "id" "loadedDemo")
(dom-append (dom-body) _demo)
(let ((handler (hs-handler "on customEvent put 'Loaded' into #loadedDemo")))
(handler (dom-body)))
(dom-dispatch (dom-body) "customEvent" nil)
(assert= (dom-text-content _demo) "Loaded"))
)
(deftest "can catch async top-level exceptions"
(hs-cleanup!)
(let ((_el-button (dom-create-element "button")))
@@ -9397,9 +9450,23 @@
(hs-activate! _el-button)
))
(deftest "can catch exceptions thrown in hyperscript functions"
(error "SKIP (skip-list): can catch exceptions thrown in hyperscript functions"))
(hs-cleanup!)
(let ((_btn (dom-create-element "button")))
(dom-set-attr _btn "_" "on click throw 'bar' catch e put e into me")
(dom-append (dom-body) _btn)
(hs-activate! _btn)
(dom-dispatch _btn "click" nil)
(assert= (dom-text-content _btn) "bar"))
)
(deftest "can catch exceptions thrown in js functions"
(error "SKIP (skip-list): can catch exceptions thrown in js functions"))
(hs-cleanup!)
(let ((_btn (dom-create-element "button")))
(dom-set-attr _btn "_" "on click throwBar() catch e put e into me")
(dom-append (dom-body) _btn)
(hs-activate! _btn)
(dom-dispatch _btn "click" nil)
(assert= (dom-text-content _btn) "bar"))
)
(deftest "can catch top-level exceptions"
(hs-cleanup!)
(let ((_el-button (dom-create-element "button")))
@@ -9737,7 +9804,28 @@
(hs-activate! _el-d)
))
(deftest "each behavior installation has its own event queue"
(error "SKIP (skip-list): each behavior installation has its own event queue"))
(hs-cleanup!)
;; Define globally via eval-expr-cek so symbol lookup in install works
(eval-expr-cek (hs-to-sx (hs-compile "behavior DemoBehavior on foo wait 10ms then set my innerHTML to 'behavior' end")))
(let ((_el1 (dom-create-element "div"))
(_el2 (dom-create-element "div"))
(_el3 (dom-create-element "div")))
(dom-set-attr _el1 "_" "install DemoBehavior")
(dom-set-attr _el2 "_" "install DemoBehavior")
(dom-set-attr _el3 "_" "install DemoBehavior")
(dom-append (dom-body) _el1)
(dom-append (dom-body) _el2)
(dom-append (dom-body) _el3)
(hs-activate! _el1)
(hs-activate! _el2)
(hs-activate! _el3)
(dom-dispatch _el1 "foo" nil)
(dom-dispatch _el2 "foo" nil)
(dom-dispatch _el3 "foo" nil)
(assert= (dom-text-content _el1) "behavior")
(assert= (dom-text-content _el2) "behavior")
(assert= (dom-text-content _el3) "behavior"))
)
(deftest "exceptions in catch block don't kill the event queue"
(hs-cleanup!)
(let ((_el-button (dom-create-element "button")))
@@ -9792,11 +9880,43 @@
(hs-activate! _el-d1)
))
(deftest "listeners on other elements are removed when the registering element is removed"
(error "SKIP (skip-list): listeners on other elements are removed when the registering element is removed"))
(hs-cleanup!)
(let ((_target (dom-create-element "div"))
(_listener (dom-create-element "div")))
(dom-set-attr _target "id" "t7-target")
(dom-set-attr _listener "_" "on someEvent from #t7-target put \"fired\" into #t7-target")
(dom-append (dom-body) _target)
(dom-append (dom-body) _listener)
(hs-activate! _listener)
(dom-dispatch _target "someEvent" nil)
(assert= (dom-text-content _target) "fired")
(dom-remove _listener)
(dom-set-inner-html _target "before")
(dom-dispatch _target "someEvent" nil)
(assert= (dom-text-content _target) "before"))
)
(deftest "listeners on self are not removed when the element is removed"
(error "SKIP (skip-list): listeners on self are not removed when the element is removed"))
(hs-cleanup!)
(let ((_el (dom-create-element "div")))
(dom-set-attr _el "_" "on someCustomEvent put 1 into me")
(dom-append (dom-body) _el)
(hs-activate! _el)
(dom-remove _el)
(dom-dispatch _el "someCustomEvent" nil)
(assert= (dom-text-content _el) "1"))
)
(deftest "multiple event handlers at a time are allowed to execute with the every keyword"
(error "SKIP (skip-list): multiple event handlers at a time are allowed to execute with the every keyword"))
(hs-cleanup!)
(host-set! (host-global "window") "__evCnt" 0)
(let ((_el (dom-create-element "div")))
(dom-set-attr _el "_" "on click every set window.__evCnt to window.__evCnt + 1")
(dom-append (dom-body) _el)
(hs-activate! _el)
(dom-dispatch _el "click" nil)
(dom-dispatch _el "click" nil)
(dom-dispatch _el "click" nil)
(assert= (host-get (host-global "window") "__evCnt") 3))
)
(deftest "on first click fires only once"
(hs-cleanup!)
(let ((_el-div (dom-create-element "div")))
@@ -14123,7 +14243,17 @@ end")
(hs-activate! _el-span)
))
(deftest "attribute observers are persistent (not recreated on re-run)"
(error "SKIP (untranslated): attribute observers are persistent (not recreated on re-run)"))
(hs-cleanup!)
(let ((_el (dom-create-element "div")))
(dom-set-attr _el "data-val" "1")
(dom-set-attr _el "_" "when @data-val changes put it into me")
(dom-append (dom-body) _el)
(hs-activate! _el)
(dom-set-attr _el "data-val" "2")
(assert= (dom-text-content _el) "2")
(dom-set-attr _el "data-val" "3")
(assert= (dom-text-content _el) "3"))
)
(deftest "auto-tracks compound expressions"
(hs-cleanup!)
(let ((_el-div (dom-create-element "div")))