;; Hyperscript behavioral tests — auto-generated from upstream _hyperscript test suite ;; Source: spec/tests/hyperscript-upstream-tests.json (1496 tests, v0.9.14 + dev) ;; DO NOT EDIT — regenerate with: python3 tests/playwright/generate-sx-tests.py ;; ── Test helpers ────────────────────────────────────────────────── (define hs-test-el (fn (tag hs-src) (let ((el (dom-create-element tag))) (dom-set-attr el "_" hs-src) (dom-append (dom-body) el) (hs-activate! el) el))) (define hs-cleanup! (fn () (dom-set-inner-html (dom-body) ""))) ;; Evaluate a hyperscript expression and return either the expression ;; value or `it` (whichever is non-nil). Multi-statement scripts that ;; mutate `it` (e.g. `pick first 3 of arr; set $test to it`) get `it` back; ;; bare expressions (e.g. `foo.foo`) get the expression value back. (define _hs-wrap-body (fn (sx) (list (quote let) (list (list (quote it) nil) (list (quote event) nil)) (list (quote let) (list (list (quote _ret) sx)) (list (quote if) (list (quote nil?) (quote _ret)) (quote it) (quote _ret)))))) (define eval-hs (fn (src) (let ((sx (hs-to-sx (hs-compile src)))) (let ((handler (eval-expr-cek (list (quote fn) (list (quote me)) (list (quote let) (list (list (quote it) nil) (list (quote event) nil)) sx))))) (guard (_e (true (if (and (list? _e) (= (first _e) "hs-return")) (nth _e 1) (raise _e)))) (handler nil)))))) ;; Evaluate a hyperscript expression with locals. bindings = list of (symbol value). ;; Locals are injected as a `let` wrapping the compiled body, then evaluated ;; in a fresh CEK env. Avoids `apply` (whose JIT path can loop on some forms). (define eval-hs-locals (fn (src bindings) (let ((sx (hs-to-sx (hs-compile src)))) ;; Build (let ((name1 (quote val1)) ...) ) (let ((let-binds (map (fn (b) (list (first b) (list (quote quote) (nth b 1)))) bindings))) (let ((wrapped (list (quote let) let-binds (_hs-wrap-body sx)))) (let ((thunk (list (quote fn) (list (quote me)) wrapped))) (let ((handler (eval-expr-cek thunk))) (guard (_e (true (if (and (list? _e) (= (first _e) "hs-return")) (nth _e 1) (raise _e)))) (handler nil))))))))) ;; Evaluate with a specific me value (for "I am between" etc.) (define eval-hs-with-me (fn (src me-val) (let ((sx (hs-to-sx (hs-compile src)))) (let ((handler (eval-expr-cek (list (quote fn) (list (quote me)) (_hs-wrap-body sx))))) (guard (_e (true (if (and (list? _e) (= (first _e) "hs-return")) (nth _e 1) (raise _e)))) (handler me-val)))))) ;; ── add (19 tests) ── (defsuite "hs-upstream-add" (deftest "can add a value to a set" (hs-cleanup!) (let ((_el-div (dom-create-element "div"))) (dom-set-attr _el-div "_" "on click set :s to [] as Set then add 'a' to :s then add 'b' to :s then add 'a' to :s then put :s.size into me") (dom-append (dom-body) _el-div) (hs-activate! _el-div) (dom-dispatch _el-div "click" nil) (assert= (dom-text-content _el-div) "2") )) (deftest "can add a value to an array" (hs-cleanup!) (let ((_el-div (dom-create-element "div"))) (dom-set-attr _el-div "_" "on click set :arr to [1,2,3] then add 4 to :arr then put :arr as String into me") (dom-append (dom-body) _el-div) (hs-activate! _el-div) (dom-dispatch _el-div "click" nil) (assert= (dom-text-content _el-div) "1,2,3,4") )) (deftest "can add class ref on a single div" (hs-cleanup!) (let ((_el-div (dom-create-element "div"))) (dom-set-attr _el-div "_" "on click add .foo") (dom-append (dom-body) _el-div) (hs-activate! _el-div) (dom-dispatch _el-div "click" nil) (assert (dom-has-class? _el-div "foo")) )) (deftest "can add class ref on a single form" (hs-cleanup!) (let ((_el-form (dom-create-element "form"))) (dom-set-attr _el-form "_" "on click add .foo") (dom-append (dom-body) _el-form) (hs-activate! _el-form) (dom-dispatch _el-form "click" nil) (assert (dom-has-class? _el-form "foo")) )) (deftest "can add class ref w/ double dash on a single div" (hs-cleanup!) (let ((_el-div (dom-create-element "div"))) (dom-set-attr _el-div "_" "on click add .foo--bar") (dom-append (dom-body) _el-div) (hs-activate! _el-div) (dom-dispatch _el-div "click" nil) (assert (dom-has-class? _el-div "foo--bar")) )) (deftest "can add class refs w/ colons and dashes" (hs-cleanup!) (let ((_el-div (dom-create-element "div"))) (dom-set-attr _el-div "_" "on click add .foo:bar-doh") (dom-append (dom-body) _el-div) (hs-activate! _el-div) (dom-dispatch _el-div "click" nil) (assert (dom-has-class? _el-div "foo:bar-doh")) )) (deftest "can add css properties" (hs-cleanup!) (let ((_el-div (dom-create-element "div"))) (dom-set-attr _el-div "_" "on click add {color: red; font-family: monospace}") (dom-set-attr _el-div "style" "color: blue") (dom-append (dom-body) _el-div) (hs-activate! _el-div) (dom-dispatch _el-div "click" nil) (assert= (dom-get-style _el-div "color") "red") (assert= (dom-get-style _el-div "font-family") "monospace") )) (deftest "can add multiple class refs" (hs-cleanup!) (let ((_el-div (dom-create-element "div"))) (dom-set-attr _el-div "_" "on click add .foo .bar") (dom-append (dom-body) _el-div) (hs-activate! _el-div) (dom-dispatch _el-div "click" nil) (assert (dom-has-class? _el-div "foo")) (assert (dom-has-class? _el-div "bar")) )) (deftest "can add non-class attributes" (hs-cleanup!) (let ((_el-div (dom-create-element "div"))) (dom-set-attr _el-div "_" "on click add [@foo=\"bar\"]") (dom-append (dom-body) _el-div) (hs-activate! _el-div) (dom-dispatch _el-div "click" nil) (assert= (dom-get-attr _el-div "foo") "bar") )) (deftest "can add templated css properties" (hs-cleanup!) (let ((_el-div (dom-create-element "div"))) (dom-set-attr _el-div "_" "on click add {color: ${}{\"red\"};}") (dom-set-attr _el-div "style" "color: blue") (dom-append (dom-body) _el-div) (hs-activate! _el-div) (dom-dispatch _el-div "click" nil) (assert= (dom-get-style _el-div "color") "red") )) (deftest "can add to an HTMLCollection" (hs-cleanup!) (let ((_el-trigger (dom-create-element "div")) (_el-bar (dom-create-element "div")) (_el-c1 (dom-create-element "div")) (_el-c2 (dom-create-element "div"))) (dom-set-attr _el-trigger "id" "trigger") (dom-set-attr _el-trigger "_" "on click add .foo to the children of #bar") (dom-set-attr _el-bar "id" "bar") (dom-set-attr _el-c1 "id" "c1") (dom-set-attr _el-c2 "id" "c2") (dom-append (dom-body) _el-trigger) (dom-append (dom-body) _el-bar) (dom-append _el-bar _el-c1) (dom-append _el-bar _el-c2) (hs-activate! _el-trigger) (dom-dispatch (dom-query-by-id "trigger") "click" nil) (assert (dom-has-class? (dom-query-by-id "c1") "foo")) (assert (dom-has-class? (dom-query-by-id "c2") "foo")) )) (deftest "can add to children" (hs-cleanup!) (let ((_el-outer (dom-create-element "div")) (_el-p1 (dom-create-element "p"))) (dom-set-attr _el-outer "id" "outer") (dom-set-attr _el-outer "_" "on click add .foo to my children") (dom-set-attr _el-p1 "id" "p1") (dom-append (dom-body) _el-outer) (dom-append _el-outer _el-p1) (hs-activate! _el-outer) (dom-dispatch (dom-query-by-id "outer") "click" nil) (assert (dom-has-class? (dom-query-by-id "p1") "foo")) (assert (not (dom-has-class? (dom-query-by-id "outer") "foo"))) )) (deftest "can add to query in me" (hs-cleanup!) (let ((_el-outer (dom-create-element "div")) (_el-p1 (dom-create-element "p"))) (dom-set-attr _el-outer "id" "outer") (dom-set-attr _el-outer "_" "on click add .foo to

in me") (dom-set-attr _el-p1 "id" "p1") (dom-append (dom-body) _el-outer) (dom-append _el-outer _el-p1) (hs-activate! _el-outer) (dom-dispatch (dom-query-by-id "outer") "click" nil) (assert (dom-has-class? (dom-query-by-id "p1") "foo")) (assert (not (dom-has-class? (dom-query-by-id "outer") "foo"))) )) (deftest "can filter class addition via the when clause" (hs-cleanup!) (let ((_el-trigger (dom-create-element "div")) (_el-d2 (dom-create-element "div")) (_el-d3 (dom-create-element "div"))) (dom-set-attr _el-trigger "id" "trigger") (dom-set-attr _el-trigger "_" "on click add .rey to .bar when it matches .doh") (dom-set-attr _el-d2 "id" "d2") (dom-add-class _el-d2 "bar") (dom-set-attr _el-d3 "id" "d3") (dom-add-class _el-d3 "bar") (dom-add-class _el-d3 "doh") (dom-append (dom-body) _el-trigger) (dom-append (dom-body) _el-d2) (dom-append (dom-body) _el-d3) (hs-activate! _el-trigger) (dom-dispatch (dom-query-by-id "trigger") "click" nil) (assert (not (dom-has-class? (dom-query-by-id "d2") "rey"))) (assert (dom-has-class? (dom-query-by-id "d3") "rey")) )) (deftest "can filter property addition via the when clause" (hs-cleanup!) (let ((_el-trigger (dom-create-element "div")) (_el-d2 (dom-create-element "div")) (_el-d3 (dom-create-element "div"))) (dom-set-attr _el-trigger "id" "trigger") (dom-set-attr _el-trigger "_" "on click add @rey to .bar when it matches .doh") (dom-set-attr _el-d2 "id" "d2") (dom-add-class _el-d2 "bar") (dom-set-attr _el-d3 "id" "d3") (dom-add-class _el-d3 "bar") (dom-add-class _el-d3 "doh") (dom-append (dom-body) _el-trigger) (dom-append (dom-body) _el-d2) (dom-append (dom-body) _el-d3) (hs-activate! _el-trigger) (dom-dispatch (dom-query-by-id "trigger") "click" nil) (assert (not (dom-has-attr? (dom-query-by-id "d2") "rey"))) (assert (dom-has-attr? (dom-query-by-id "d3") "rey")) )) (deftest "can target another div for class ref" (hs-cleanup!) (let ((_el-bar (dom-create-element "div")) (_el-trigger (dom-create-element "div"))) (dom-set-attr _el-bar "id" "bar") (dom-set-attr _el-trigger "id" "trigger") (dom-set-attr _el-trigger "_" "on click add .foo to #bar") (dom-append (dom-body) _el-bar) (dom-append (dom-body) _el-trigger) (hs-activate! _el-trigger) (dom-dispatch (dom-query-by-id "trigger") "click" nil) (assert (dom-has-class? (dom-query-by-id "bar") "foo")) (assert (not (dom-has-class? (dom-query-by-id "trigger") "foo"))) )) (deftest "supports async expressions in when clause" (hs-cleanup!) (let ((_el-trigger (dom-create-element "div")) (_el-d2 (dom-create-element "div"))) (dom-set-attr _el-trigger "id" "trigger") (dom-set-attr _el-trigger "_" "on click add .foo to #d2 when asyncCheck()") (dom-set-attr _el-d2 "id" "d2") (dom-append (dom-body) _el-trigger) (dom-append (dom-body) _el-d2) (hs-activate! _el-trigger) (dom-dispatch (dom-query-by-id "trigger") "click" nil) (assert (dom-has-class? (dom-query-by-id "d2") "foo")) )) (deftest "when clause result is empty when nothing matches" (hs-cleanup!) (let ((_el-trigger (dom-create-element "div")) (_el-d1 (dom-create-element "div")) (_el-none (dom-create-element "div"))) (dom-set-attr _el-trigger "id" "trigger") (dom-set-attr _el-trigger "_" "on click add .foo to .item when it matches .nope then if the result is empty remove @hidden from #none") (dom-set-attr _el-d1 "id" "d1") (dom-add-class _el-d1 "item") (dom-set-attr _el-none "id" "none") (dom-set-attr _el-none "hidden" "") (dom-append (dom-body) _el-trigger) (dom-append (dom-body) _el-d1) (dom-append (dom-body) _el-none) (hs-activate! _el-trigger) (dom-dispatch (dom-query-by-id "trigger") "click" nil) (assert (not (dom-has-attr? (dom-query-by-id "none") "hidden"))) )) (deftest "when clause sets result to matched elements" (hs-cleanup!) (let ((_el-trigger (dom-create-element "div")) (_el-d1 (dom-create-element "div")) (_el-d2 (dom-create-element "div")) (_el-none (dom-create-element "div"))) (dom-set-attr _el-trigger "id" "trigger") (dom-set-attr _el-trigger "_" "on click add .foo to .item when it matches .yes then if the result is empty show #none else hide #none") (dom-set-attr _el-d1 "id" "d1") (dom-add-class _el-d1 "item") (dom-add-class _el-d1 "yes") (dom-set-attr _el-d2 "id" "d2") (dom-add-class _el-d2 "item") (dom-set-attr _el-none "id" "none") (dom-set-attr _el-none "style" "display:none") (dom-append (dom-body) _el-trigger) (dom-append (dom-body) _el-d1) (dom-append (dom-body) _el-d2) (dom-append (dom-body) _el-none) (hs-activate! _el-trigger) (dom-dispatch (dom-query-by-id "trigger") "click" nil) (assert (not (dom-visible? (dom-query-by-id "none")))) )) ) ;; ── append (13 tests) ── (defsuite "hs-upstream-append" (deftest "append preserves existing content rather than overwriting it" (hs-cleanup!) (let ((_el-div (dom-create-element "div")) (_el-btn1 (dom-create-element "button"))) (dom-set-attr _el-div "_" "on click append 'New Content' to me") (dom-set-attr _el-btn1 "id" "btn1") (dom-set-inner-html _el-btn1 "Click Me") (dom-append (dom-body) _el-div) (dom-append _el-div _el-btn1) (hs-activate! _el-div) (dom-dispatch _el-div "click" nil) )) (deftest "append to undefined ignores the undefined" (hs-cleanup!) (let ((_el-id (dom-create-element "div"))) (dom-set-attr _el-id "id" "id") (dom-set-attr _el-id "_" "on click append 'bar' then append it to me") (dom-append (dom-body) _el-id) (hs-activate! _el-id) (dom-dispatch _el-id "click" nil) (assert= (dom-text-content _el-id) "bar") )) (deftest "can append a string to another string" (hs-cleanup!) (let ((_el-div (dom-create-element "div"))) (dom-set-attr _el-div "_" "on click set value to 'Hello there.' then append ' General Kenobi.' to value then set my.innerHTML to value") (dom-append (dom-body) _el-div) (hs-activate! _el-div) (dom-dispatch _el-div "click" nil) (assert= (dom-text-content _el-div) "Hello there. General Kenobi.") )) (deftest "can append a value into an array" (hs-cleanup!) (let ((_el-div (dom-create-element "div"))) (dom-set-attr _el-div "_" "on click set value to [1,2,3] then append 4 to value then set my.innerHTML to value as String") (dom-append (dom-body) _el-div) (hs-activate! _el-div) (dom-dispatch _el-div "click" nil) (assert= (dom-text-content _el-div) "1,2,3,4") )) (deftest "can append a value to 'it'" (hs-cleanup!) (let ((_el-div (dom-create-element "div"))) (dom-set-attr _el-div "_" "on click set result to [1,2,3] then append 4 then put it as String into me") (dom-append (dom-body) _el-div) (hs-activate! _el-div) (dom-dispatch _el-div "click" nil) (assert= (dom-text-content _el-div) "1,2,3,4") )) (deftest "can append a value to I" (hs-cleanup!) (let ((_el-div (dom-create-element "div"))) (dom-set-attr _el-div "_" "on click append 'Content' to I") (dom-append (dom-body) _el-div) (hs-activate! _el-div) (dom-dispatch _el-div "click" nil) (assert= (dom-text-content _el-div) "Content") )) (deftest "can append a value to a DOM element" (hs-cleanup!) (let ((_el-content (dom-create-element "div"))) (dom-set-attr _el-content "id" "content") (dom-set-attr _el-content "_" "on click append 'Content' to #content") (dom-append (dom-body) _el-content) (hs-activate! _el-content) (dom-dispatch _el-content "click" nil) (assert= (dom-text-content _el-content) "Content") )) (deftest "can append a value to a DOM node" (hs-cleanup!) (let ((_el-div (dom-create-element "div"))) (dom-set-attr _el-div "_" "on click append 'This is my inner HTML' to me then append 'With Tags' to me") (dom-append (dom-body) _el-div) (hs-activate! _el-div) (dom-dispatch _el-div "click" nil) (assert= (dom-text-content _el-div) "This is my inner HTMLWith Tags") )) (deftest "can append a value to a set" (hs-cleanup!) (let ((_el-div (dom-create-element "div"))) (dom-set-attr _el-div "_" "on click set :s to [1,2] as Set then append 3 to :s then append 1 to :s then put :s.size into me") (dom-append (dom-body) _el-div) (hs-activate! _el-div) (dom-dispatch _el-div "click" nil) (assert= (dom-text-content _el-div) "3") )) (deftest "can append a value to an object property" (hs-cleanup!) (let ((_el-id (dom-create-element "div"))) (dom-set-attr _el-id "id" "id") (dom-set-attr _el-id "_" "on click append '_new' to my id") (dom-append (dom-body) _el-id) (hs-activate! _el-id) (dom-dispatch _el-id "click" nil) )) (deftest "multiple appends work" (hs-cleanup!) (let ((_el-id (dom-create-element "div"))) (dom-set-attr _el-id "id" "id") (dom-set-attr _el-id "_" "on click get 'foo' then append 'bar' then append 'doh' then append it to me") (dom-append (dom-body) _el-id) (hs-activate! _el-id) (dom-dispatch _el-id "click" nil) (assert= (dom-text-content _el-id) "foobardoh") )) (deftest "new DOM content added by append will be live" (hs-cleanup!) (let ((_el-div (dom-create-element "div"))) (dom-set-attr _el-div "_" "on click make a then append it to me") (dom-append (dom-body) _el-div) (hs-activate! _el-div) (dom-dispatch _el-div "click" nil) (assert (dom-has-class? (dom-query "span.topping") "topping")) )) (deftest "new content added by append will be live" (hs-cleanup!) (let ((_el-div (dom-create-element "div"))) (dom-set-attr _el-div "_" "on click append `` to me") (dom-append (dom-body) _el-div) (hs-activate! _el-div) (dom-dispatch _el-div "click" nil) (dom-dispatch (dom-query-by-id "b1") "click" nil) )) ) ;; ── askAnswer (5 tests) ── (defsuite "hs-upstream-askAnswer" (deftest "confirm returns first choice on OK" (hs-cleanup!) (let ((_el-button (dom-create-element "button")) (_el-out (dom-create-element "div"))) (dom-set-attr _el-button "_" "on click answer \"Save?\" with \"Yes\" or \"No\" then put it into #out") (dom-set-inner-html _el-button "Go") (dom-set-attr _el-out "id" "out") (dom-append (dom-body) _el-button) (dom-append (dom-body) _el-out) (hs-activate! _el-button) (dom-dispatch _el-button "click" nil) (assert= (dom-text-content (dom-query-by-id "out")) "Yes") )) (deftest "confirm returns second choice on cancel" (hs-cleanup!) (let ((_el-button (dom-create-element "button")) (_el-out (dom-create-element "div"))) (dom-set-attr _el-button "_" "on click answer \"Save?\" with \"Yes\" or \"No\" then put it into #out") (dom-set-inner-html _el-button "Go") (dom-set-attr _el-out "id" "out") (dom-append (dom-body) _el-button) (dom-append (dom-body) _el-out) (hs-activate! _el-button) (dom-dispatch _el-button "click" nil) (assert= (dom-text-content (dom-query-by-id "out")) "No") )) (deftest "prompts and puts result in it" (hs-cleanup!) (let ((_el-button (dom-create-element "button")) (_el-out (dom-create-element "div"))) (dom-set-attr _el-button "_" "on click ask \"What is your name?\" then put it into #out") (dom-set-inner-html _el-button "Ask") (dom-set-attr _el-out "id" "out") (dom-append (dom-body) _el-button) (dom-append (dom-body) _el-out) (hs-activate! _el-button) (dom-dispatch _el-button "click" nil) (assert= (dom-text-content (dom-query-by-id "out")) "Alice") )) (deftest "returns null on cancel" (hs-cleanup!) (let ((_el-button (dom-create-element "button")) (_el-out (dom-create-element "div"))) (dom-set-attr _el-button "_" "on click ask \"Name?\" then put it into #out") (dom-set-inner-html _el-button "Ask") (dom-set-attr _el-out "id" "out") (dom-append (dom-body) _el-button) (dom-append (dom-body) _el-out) (hs-activate! _el-button) (dom-dispatch _el-button "click" nil) (assert= (dom-text-content (dom-query-by-id "out")) "null") )) (deftest "shows an alert" (hs-cleanup!) (let ((_el-button (dom-create-element "button")) (_el-out (dom-create-element "div"))) (dom-set-attr _el-button "_" "on click answer \"Hello!\" then put \"done\" into #out") (dom-set-inner-html _el-button "Go") (dom-set-attr _el-out "id" "out") (dom-append (dom-body) _el-button) (dom-append (dom-body) _el-out) (hs-activate! _el-button) (dom-dispatch _el-button "click" nil) (assert= (dom-text-content (dom-query-by-id "out")) "done") )) ) ;; ── behavior (10 tests) ── (defsuite "hs-upstream-behavior" (deftest "can declare variables in init blocks" (hs-cleanup!) (let ((_el-script (dom-create-element "script")) (_el-div (dom-create-element "div"))) (dom-set-attr _el-script "type" "text/hyperscript") (dom-set-inner-html _el-script "behavior Behave init set element's foo to 1 set element's bar to {} end on click increment element's foo set element's bar[\"count\"] to element's foo put element's bar[\"count\"] into me end end") (dom-set-attr _el-div "_" "install Behave") (dom-append (dom-body) _el-script) (dom-append (dom-body) _el-div) (hs-activate! _el-div) (dom-dispatch _el-div "click" nil) (assert= (dom-text-content _el-div) "2") (dom-dispatch _el-div "click" nil) (assert= (dom-text-content _el-div) "3") )) (deftest "can define behaviors" (hs-cleanup!) (let ((_el-script (dom-create-element "script"))) (dom-set-attr _el-script "type" "text/hyperscript") (dom-set-inner-html _el-script "behavior TheBehaviorWeAreDefiningForHyperscriptTestingPurposes init log 'foo' end end") (dom-append (dom-body) _el-script) )) (deftest "can install behaviors" (hs-cleanup!) (let ((_el-script (dom-create-element "script")) (_el-div (dom-create-element "div"))) (dom-set-attr _el-script "type" "text/hyperscript") (dom-set-inner-html _el-script "behavior Behave on click add .foo end end") (dom-set-attr _el-div "_" "install Behave") (dom-append (dom-body) _el-script) (dom-append (dom-body) _el-div) (hs-activate! _el-div) (dom-dispatch _el-div "click" nil) (assert (dom-has-class? _el-div "foo")) )) (deftest "can pass arguments to behaviors" (hs-cleanup!) (let ((_el-script (dom-create-element "script")) (_el-div (dom-create-element "div"))) (dom-set-attr _el-script "type" "text/hyperscript") (dom-set-inner-html _el-script "behavior Behave(foo, bar) on click put foo + bar into me end end") (dom-set-attr _el-div "_" "install Behave(foo: 1, bar: 1)") (dom-append (dom-body) _el-script) (dom-append (dom-body) _el-div) (hs-activate! _el-div) (dom-dispatch _el-div "click" nil) (assert= (dom-text-content _el-div) "2") )) (deftest "can pass element arguments to listen to in behaviors" (hs-cleanup!) (let ((_el-script (dom-create-element "script")) (_el-b1 (dom-create-element "button")) (_el-div (dom-create-element "div"))) (dom-set-attr _el-script "type" "text/hyperscript") (dom-set-inner-html _el-script "behavior Behave(elt) on click from elt put 'foo' into me end end") (dom-set-attr _el-b1 "id" "b1") (dom-set-attr _el-div "_" "install Behave(elt: #b1)") (dom-append (dom-body) _el-script) (dom-append (dom-body) _el-b1) (dom-append (dom-body) _el-div) (hs-activate! _el-div) (dom-dispatch (dom-query-by-id "b1") "click" nil) (assert= (dom-text-content _el-div) "foo") )) (deftest "can refer to arguments in init blocks" (hs-cleanup!) (let ((_el-script (dom-create-element "script")) (_el-d1 (dom-create-element "div")) (_el-div (dom-create-element "div"))) (dom-set-attr _el-script "type" "text/hyperscript") (dom-set-inner-html _el-script "behavior Behave(elt) init put 'foo' into elt end end") (dom-set-attr _el-d1 "id" "d1") (dom-set-attr _el-div "_" "install Behave(elt: #d1)") (dom-append (dom-body) _el-script) (dom-append (dom-body) _el-d1) (dom-append (dom-body) _el-div) (hs-activate! _el-div) )) (deftest "install resolves namespaced behavior paths" (hs-cleanup!) (let ((_el-script (dom-create-element "script")) (_el-div (dom-create-element "div"))) (dom-set-attr _el-script "type" "text/hyperscript") (dom-set-inner-html _el-script "behavior App.Widgets.Clickable on click add .clicked end end") (dom-set-attr _el-div "_" "install App.Widgets.Clickable") (dom-append (dom-body) _el-script) (dom-append (dom-body) _el-div) (hs-activate! _el-div) (dom-dispatch _el-div "click" nil) (assert (dom-has-class? _el-div "clicked")) )) (deftest "install throws when the behavior path does not exist" (hs-cleanup!) (let ((_el-div (dom-create-element "div"))) (dom-set-attr _el-div "_" "install NoSuchBehavior") (dom-append (dom-body) _el-div) (hs-activate! _el-div) )) (deftest "install throws when the path resolves to a non-function" (hs-cleanup!) (let ((_el-div (dom-create-element "div"))) (dom-set-attr _el-div "_" "install NotABehavior") (dom-append (dom-body) _el-div) (hs-activate! _el-div) )) (deftest "supports init blocks in behaviors" (hs-cleanup!) (let ((_el-script (dom-create-element "script")) (_el-div (dom-create-element "div"))) (dom-set-attr _el-script "type" "text/hyperscript") (dom-set-inner-html _el-script "behavior Behave init add .foo to me end") (dom-set-attr _el-div "_" "install Behave") (dom-append (dom-body) _el-script) (dom-append (dom-body) _el-div) (hs-activate! _el-div) )) ) ;; ── bind (44 tests) ── (defsuite "hs-upstream-bind" (deftest "\"with\" is a synonym for \"and\"" (hs-cleanup!) (let ((_el-city-input (dom-create-element "input")) (_el-span (dom-create-element "span"))) (dom-set-attr _el-city-input "id" "city-input") (dom-set-attr _el-city-input "type" "text") (dom-set-attr _el-city-input "value" "Paris") (dom-set-attr _el-span "_" "bind $city to #city-input.value end when $city changes put it into me") (dom-append (dom-body) _el-city-input) (dom-append (dom-body) _el-span) (hs-activate! _el-span) )) (deftest "attribute bound to another element input value" (hs-cleanup!) (let ((_el-title-input (dom-create-element "input")) (_el-h1 (dom-create-element "h1"))) (dom-set-attr _el-title-input "id" "title-input") (dom-set-attr _el-title-input "type" "text") (dom-set-attr _el-title-input "value" "Hello") (dom-set-attr _el-h1 "_" "bind @data-title and #title-input's value") (dom-append (dom-body) _el-title-input) (dom-append (dom-body) _el-h1) (hs-activate! _el-h1) (dom-set-prop (dom-query-by-id "title-input") "value" "World") (dom-dispatch (dom-query-by-id "title-input") "input" nil) )) (deftest "bind element to element: both sides auto-detect" (hs-cleanup!) (let ((_el-range-slider (dom-create-element "input")) (_el-input (dom-create-element "input"))) (dom-set-attr _el-range-slider "id" "range-slider") (dom-set-attr _el-range-slider "type" "range") (dom-set-attr _el-range-slider "value" "50") (dom-set-attr _el-input "_" "bind me to #range-slider") (dom-set-attr _el-input "type" "number") (dom-append (dom-body) _el-range-slider) (dom-append (dom-body) _el-input) (hs-activate! _el-input) )) (deftest "bind to contenteditable element auto-detects textContent" (hs-cleanup!) (let ((_el-div (dom-create-element "div"))) (dom-set-attr _el-div "_" "bind $text to me") (dom-set-attr _el-div "contenteditable" "true") (dom-set-inner-html _el-div "initial") (dom-append (dom-body) _el-div) (hs-activate! _el-div) )) (deftest "bind to custom element with value property auto-detects value" (hs-cleanup!) (let ((_el-test-input (dom-create-element "test-input"))) (dom-set-attr _el-test-input "_" "bind $custom to me") (dom-append (dom-body) _el-test-input) (hs-activate! _el-test-input) )) (deftest "bind variable to checkbox by id auto-detects checked" (hs-cleanup!) (let ((_el-agree-cb (dom-create-element "input")) (_el-div (dom-create-element "div"))) (dom-set-attr _el-agree-cb "id" "agree-cb") (dom-set-attr _el-agree-cb "type" "checkbox") (dom-set-attr _el-div "_" "bind $agreed to #agree-cb") (dom-append (dom-body) _el-agree-cb) (dom-append (dom-body) _el-div) (hs-activate! _el-div) )) (deftest "bind variable to element by id auto-detects value" (hs-cleanup!) (let ((_el-name-field (dom-create-element "input")) (_el-div (dom-create-element "div"))) (dom-set-attr _el-name-field "id" "name-field") (dom-set-attr _el-name-field "type" "text") (dom-set-attr _el-name-field "value" "") (dom-set-attr _el-div "_" "bind $name to #name-field") (dom-append (dom-body) _el-name-field) (dom-append (dom-body) _el-div) (hs-activate! _el-div) )) (deftest "bind variable to number input by id auto-detects valueAsNumber" (hs-cleanup!) (let ((_el-qty-input (dom-create-element "input")) (_el-div (dom-create-element "div"))) (dom-set-attr _el-qty-input "id" "qty-input") (dom-set-attr _el-qty-input "type" "number") (dom-set-attr _el-div "_" "bind $qty to #qty-input") (dom-append (dom-body) _el-qty-input) (dom-append (dom-body) _el-div) (hs-activate! _el-div) )) (deftest "boolean bind to aria-* attribute uses \"true\"/\"false\" strings" (hs-cleanup!) (let ((_el-div (dom-create-element "div"))) (dom-set-attr _el-div "_" "bind $isHidden and @aria-hidden") (dom-append (dom-body) _el-div) (hs-activate! _el-div) )) (deftest "boolean bind to attribute uses presence/absence" (hs-cleanup!) (let ((_el-div (dom-create-element "div"))) (dom-set-attr _el-div "_" "bind $isEnabled and @data-active") (dom-append (dom-body) _el-div) (hs-activate! _el-div) )) (deftest "class bound to another element checkbox" (hs-cleanup!) (let ((_el-dark-toggle (dom-create-element "input")) (_el-div (dom-create-element "div"))) (dom-set-attr _el-dark-toggle "id" "dark-toggle") (dom-set-attr _el-dark-toggle "type" "checkbox") (dom-set-attr _el-div "_" "bind .dark and #dark-toggle's checked") (dom-set-inner-html _el-div "test") (dom-append (dom-body) _el-dark-toggle) (dom-append (dom-body) _el-div) (hs-activate! _el-div) (dom-set-prop (dom-query-by-id "dark-toggle") "checked" true) (dom-dispatch (dom-query-by-id "dark-toggle") "change" nil) (dom-set-prop (dom-query-by-id "dark-toggle") "checked" false) (dom-dispatch (dom-query-by-id "dark-toggle") "change" nil) )) (deftest "clicking a radio sets the variable to its value" (hs-cleanup!) (let ((_el-input (dom-create-element "input")) (_el-input1 (dom-create-element "input")) (_el-input2 (dom-create-element "input")) (_el-span (dom-create-element "span"))) (dom-set-attr _el-input "_" "bind $color to me") (dom-set-attr _el-input "type" "radio") (dom-set-attr _el-input "name" "color") (dom-set-attr _el-input "value" "red") (dom-set-attr _el-input1 "_" "bind $color to me") (dom-set-attr _el-input1 "type" "radio") (dom-set-attr _el-input1 "name" "color") (dom-set-attr _el-input1 "value" "blue") (dom-set-attr _el-input2 "_" "bind $color to me") (dom-set-attr _el-input2 "type" "radio") (dom-set-attr _el-input2 "name" "color") (dom-set-attr _el-input2 "value" "green") (dom-set-attr _el-span "_" "when $color changes put it into me") (dom-append (dom-body) _el-input) (dom-append (dom-body) _el-input1) (dom-append (dom-body) _el-input2) (dom-append (dom-body) _el-span) (hs-activate! _el-input) (hs-activate! _el-input1) (hs-activate! _el-input2) (hs-activate! _el-span) (dom-dispatch (dom-query "input[value="blue"]") "click" nil) (dom-dispatch (dom-query "input[value="green"]") "click" nil) )) (deftest "dedup prevents infinite loop in two-way bind" (hs-cleanup!) (let ((_el-div (dom-create-element "div"))) (dom-set-attr _el-div "_" "bind $color and @data-color") (dom-append (dom-body) _el-div) (hs-activate! _el-div) )) (deftest "external JS property write does not sync (known limitation)" (hs-cleanup!) (let ((_el-input (dom-create-element "input")) (_el-span (dom-create-element "span"))) (dom-set-attr _el-input "_" "bind $searchTerm to me") (dom-set-attr _el-input "type" "text") (dom-set-attr _el-input "value" "original") (dom-set-attr _el-span "_" "when $searchTerm changes put it into me") (dom-append (dom-body) _el-input) (dom-append (dom-body) _el-span) (hs-activate! _el-input) (hs-activate! _el-span) )) (deftest "external class change syncs back to variable" (hs-cleanup!) (let ((_el-div (dom-create-element "div"))) (dom-set-attr _el-div "_" "bind .dark and $darkMode") (dom-set-inner-html _el-div "test") (dom-append (dom-body) _el-div) (hs-activate! _el-div) )) (deftest "form reset listener is removed on cleanup" (hs-cleanup!) (let ((_el-form (dom-create-element "form")) (_el-binput (dom-create-element "input")) (_el-button (dom-create-element "button"))) (dom-set-attr _el-binput "id" "binput") (dom-set-attr _el-binput "_" "bind $val to me") (dom-set-attr _el-binput "type" "text") (dom-set-attr _el-binput "value" "initial") (dom-set-attr _el-button "type" "reset") (dom-set-inner-html _el-button "Reset") (dom-append (dom-body) _el-form) (dom-append _el-form _el-binput) (dom-append _el-form _el-button) (hs-activate! _el-binput) )) (deftest "form.reset() syncs variable back to default value" (hs-cleanup!) (let ((_el-test-form (dom-create-element "form")) (_el-input (dom-create-element "input")) (_el-span (dom-create-element "span"))) (dom-set-attr _el-test-form "id" "test-form") (dom-set-attr _el-input "_" "bind $formField to me") (dom-set-attr _el-input "type" "text") (dom-set-attr _el-input "value" "default") (dom-set-attr _el-span "_" "when $formField changes put it into me") (dom-append (dom-body) _el-test-form) (dom-append _el-test-form _el-input) (dom-append (dom-body) _el-span) (hs-activate! _el-input) (hs-activate! _el-span) (dom-set-prop _el-input "value" "user typed this") (dom-dispatch _el-input "input" nil) )) (deftest "init: right side wins - attribute (Y) initializes variable (X)" (hs-cleanup!) (let ((_el-div (dom-create-element "div"))) (dom-set-attr _el-div "_" "bind $color to @data-color") (dom-set-attr _el-div "data-color" "red") (dom-append (dom-body) _el-div) (hs-activate! _el-div) )) (deftest "init: right side wins - class (Y) drives variable (X)" (hs-cleanup!) (let ((_el-div (dom-create-element "div"))) (dom-add-class _el-div "dark") (dom-set-attr _el-div "_" "bind $isDark to .dark") (dom-append (dom-body) _el-div) (hs-activate! _el-div) )) (deftest "init: right side wins - input value (Y) overwrites variable (X)" (hs-cleanup!) (let ((_el-input (dom-create-element "input"))) (dom-set-attr _el-input "_" "bind $name to my value") (dom-set-attr _el-input "type" "text") (dom-set-attr _el-input "value" "Bob") (dom-append (dom-body) _el-input) (hs-activate! _el-input) )) (deftest "init: right side wins - variable (Y) drives class (X)" (hs-cleanup!) (let ((_el-div (dom-create-element "div"))) (dom-set-attr _el-div "_" "bind .dark to $isDark") (dom-append (dom-body) _el-div) (hs-activate! _el-div) )) (deftest "init: right side wins - variable (Y) initializes attribute (X)" (hs-cleanup!) (let ((_el-div (dom-create-element "div"))) (dom-set-attr _el-div "_" "bind @data-theme to $theme") (dom-append (dom-body) _el-div) (hs-activate! _el-div) )) (deftest "init: right side wins - variable (Y) overwrites input value (X)" (hs-cleanup!) (let ((_el-input (dom-create-element "input"))) (dom-set-attr _el-input "_" "bind my value to $name") (dom-set-attr _el-input "type" "text") (dom-set-attr _el-input "value" "Bob") (dom-append (dom-body) _el-input) (hs-activate! _el-input) )) (deftest "initial value checks the correct radio on load" (hs-cleanup!) (let ((_el-input (dom-create-element "input")) (_el-input1 (dom-create-element "input")) (_el-input2 (dom-create-element "input"))) (dom-set-attr _el-input "_" "bind $fruit to me") (dom-set-attr _el-input "type" "radio") (dom-set-attr _el-input "name" "fruit") (dom-set-attr _el-input "value" "apple") (dom-set-attr _el-input1 "_" "bind $fruit to me") (dom-set-attr _el-input1 "type" "radio") (dom-set-attr _el-input1 "name" "fruit") (dom-set-attr _el-input1 "value" "banana") (dom-set-attr _el-input2 "_" "bind $fruit to me") (dom-set-attr _el-input2 "type" "radio") (dom-set-attr _el-input2 "name" "fruit") (dom-set-attr _el-input2 "value" "cherry") (dom-append (dom-body) _el-input) (dom-append (dom-body) _el-input1) (dom-append (dom-body) _el-input2) (hs-activate! _el-input) (hs-activate! _el-input1) (hs-activate! _el-input2) )) (deftest "of-expression: bind $var to value of #input" (hs-cleanup!) (let ((_el-of-input (dom-create-element "input")) (_el-div (dom-create-element "div"))) (dom-set-attr _el-of-input "id" "of-input") (dom-set-attr _el-of-input "type" "text") (dom-set-attr _el-of-input "value" "initial") (dom-set-attr _el-div "_" "bind $search to value of #of-input") (dom-append (dom-body) _el-of-input) (dom-append (dom-body) _el-div) (hs-activate! _el-div) )) (deftest "possessive attribute: bind $var and my @data-label" (hs-cleanup!) (let ((_el-div (dom-create-element "div"))) (dom-set-attr _el-div "_" "bind $label and my @data-label") (dom-append (dom-body) _el-div) (hs-activate! _el-div) )) (deftest "possessive property: bind $var to my value" (hs-cleanup!) (let ((_el-input (dom-create-element "input"))) (dom-set-attr _el-input "_" "bind $myVal to my value") (dom-set-attr _el-input "type" "text") (dom-set-attr _el-input "value" "hello") (dom-append (dom-body) _el-input) (hs-activate! _el-input) (dom-set-prop _el-input "value" "world") (dom-dispatch _el-input "input" nil) )) (deftest "radio change listener is removed on cleanup" (hs-cleanup!) (let ((_el-input (dom-create-element "input")) (_el-input1 (dom-create-element "input"))) (dom-set-attr _el-input "_" "bind $color to me") (dom-set-attr _el-input "type" "radio") (dom-set-attr _el-input "name" "color") (dom-set-attr _el-input "value" "red") (dom-set-attr _el-input "checked" "") (dom-set-attr _el-input1 "_" "bind $color to me") (dom-set-attr _el-input1 "type" "radio") (dom-set-attr _el-input1 "name" "color") (dom-set-attr _el-input1 "value" "blue") (dom-append (dom-body) _el-input) (dom-append (dom-body) _el-input1) (hs-activate! _el-input) (hs-activate! _el-input1) )) (deftest "right side wins on class init" (hs-cleanup!) (let ((_el-div (dom-create-element "div"))) (dom-set-attr _el-div "_" "bind .highlight to $highlighted") (dom-set-inner-html _el-div "test") (dom-append (dom-body) _el-div) (hs-activate! _el-div) )) (deftest "right side wins on init: input (Y) initializes variable (X)" (hs-cleanup!) (let ((_el-input (dom-create-element "input"))) (dom-set-attr _el-input "_" "bind $name to me") (dom-set-attr _el-input "type" "text") (dom-set-attr _el-input "value" "Bob") (dom-append (dom-body) _el-input) (hs-activate! _el-input) )) (deftest "right side wins on init: variable (Y) initializes input (X)" (hs-cleanup!) (let ((_el-input (dom-create-element "input"))) (dom-set-attr _el-input "_" "bind me to $name") (dom-set-attr _el-input "type" "text") (dom-set-attr _el-input "value" "Bob") (dom-append (dom-body) _el-input) (hs-activate! _el-input) )) (deftest "same value does not re-set input (prevents cursor jump)" (hs-cleanup!) (let ((_el-input (dom-create-element "input"))) (dom-set-attr _el-input "_" "bind $message to me") (dom-set-attr _el-input "type" "text") (dom-set-attr _el-input "value" "hello") (dom-append (dom-body) _el-input) (hs-activate! _el-input) )) (deftest "setting variable programmatically checks the matching radio" (hs-cleanup!) (let ((_el-input (dom-create-element "input")) (_el-input1 (dom-create-element "input")) (_el-input2 (dom-create-element "input"))) (dom-set-attr _el-input "_" "bind $size to me") (dom-set-attr _el-input "type" "radio") (dom-set-attr _el-input "name" "size") (dom-set-attr _el-input "value" "small") (dom-set-attr _el-input1 "_" "bind $size to me") (dom-set-attr _el-input1 "type" "radio") (dom-set-attr _el-input1 "name" "size") (dom-set-attr _el-input1 "value" "medium") (dom-set-attr _el-input2 "_" "bind $size to me") (dom-set-attr _el-input2 "type" "radio") (dom-set-attr _el-input2 "name" "size") (dom-set-attr _el-input2 "value" "large") (dom-append (dom-body) _el-input) (dom-append (dom-body) _el-input1) (dom-append (dom-body) _el-input2) (hs-activate! _el-input) (hs-activate! _el-input1) (hs-activate! _el-input2) )) (deftest "shorthand on checkbox binds to checked" (hs-cleanup!) (let ((_el-input (dom-create-element "input")) (_el-span (dom-create-element "span"))) (dom-set-attr _el-input "_" "bind $isDarkMode to me") (dom-set-attr _el-input "type" "checkbox") (dom-set-attr _el-span "_" "when $isDarkMode changes put it into me") (dom-append (dom-body) _el-input) (dom-append (dom-body) _el-span) (hs-activate! _el-input) (hs-activate! _el-span) (dom-set-prop _el-input "checked" true) (dom-dispatch _el-input "change" nil) )) (deftest "shorthand on select binds to value" (hs-cleanup!) (let ((_el-select (dom-create-element "select")) (_el-option (dom-create-element "option")) (_el-option2 (dom-create-element "option")) (_el-option3 (dom-create-element "option")) (_el-span (dom-create-element "span"))) (dom-set-attr _el-select "_" "bind $country to me") (dom-set-attr _el-option "value" "us") (dom-set-inner-html _el-option "United States") (dom-set-attr _el-option2 "value" "uk") (dom-set-inner-html _el-option2 "United Kingdom") (dom-set-attr _el-option3 "value" "fr") (dom-set-inner-html _el-option3 "France") (dom-set-attr _el-span "_" "when $country changes put it into me") (dom-append (dom-body) _el-select) (dom-append _el-select _el-option) (dom-append _el-select _el-option2) (dom-append _el-select _el-option3) (dom-append (dom-body) _el-span) (hs-activate! _el-select) (hs-activate! _el-span) (dom-set-prop _el-select "value" "uk") (dom-dispatch _el-select "change" nil) )) (deftest "shorthand on text input binds to value" (hs-cleanup!) (let ((_el-input (dom-create-element "input")) (_el-span (dom-create-element "span"))) (dom-set-attr _el-input "_" "bind $greeting to me end when $greeting changes put it into next ") (dom-set-attr _el-input "type" "text") (dom-set-attr _el-input "value" "hello") (dom-append (dom-body) _el-input) (dom-append (dom-body) _el-span) (hs-activate! _el-input) (dom-set-prop _el-input "value" "goodbye") (dom-dispatch _el-input "input" nil) )) (deftest "shorthand on textarea binds to value" (hs-cleanup!) (let ((_el-textarea (dom-create-element "textarea")) (_el-span (dom-create-element "span"))) (dom-set-attr _el-textarea "_" "bind $bio to me") (dom-set-inner-html _el-textarea "Hello world") (dom-set-attr _el-span "_" "when $bio changes put it into me") (dom-append (dom-body) _el-textarea) (dom-append (dom-body) _el-span) (hs-activate! _el-textarea) (hs-activate! _el-span) (dom-set-prop _el-textarea "value" "New bio") (dom-dispatch _el-textarea "input" nil) )) (deftest "shorthand on type=number preserves number type" (hs-cleanup!) (let ((_el-input (dom-create-element "input")) (_el-span (dom-create-element "span"))) (dom-set-attr _el-input "_" "bind $price to me") (dom-set-attr _el-input "type" "number") (dom-set-attr _el-span "_" "when $price changes put it into me") (dom-append (dom-body) _el-input) (dom-append (dom-body) _el-span) (hs-activate! _el-input) (hs-activate! _el-span) )) (deftest "style bind is one-way: variable drives style, not vice versa" (hs-cleanup!) (let ((_el-div (dom-create-element "div"))) (dom-set-attr _el-div "_" "bind $opacity and *opacity") (dom-set-inner-html _el-div "visible") (dom-append (dom-body) _el-div) (hs-activate! _el-div) )) (deftest "syncs variable and attribute in both directions" (hs-cleanup!) (let ((_el-div (dom-create-element "div"))) (dom-set-attr _el-div "_" "bind $theme and @data-theme") (dom-append (dom-body) _el-div) (hs-activate! _el-div) )) (deftest "syncs variable and input value in both directions" (hs-cleanup!) (let ((_el-name-input (dom-create-element "input")) (_el-span (dom-create-element "span"))) (dom-set-attr _el-name-input "id" "name-input") (dom-set-attr _el-name-input "type" "text") (dom-set-attr _el-name-input "value" "Alice") (dom-set-attr _el-span "_" "bind $name and #name-input.value end when $name changes put it into me") (dom-append (dom-body) _el-name-input) (dom-append (dom-body) _el-span) (hs-activate! _el-span) )) (deftest "two inputs synced via bind" (hs-cleanup!) (let ((_el-slider (dom-create-element "input")) (_el-input (dom-create-element "input"))) (dom-set-attr _el-slider "id" "slider") (dom-set-attr _el-slider "type" "range") (dom-set-attr _el-slider "value" "50") (dom-set-attr _el-input "_" "bind my value and #slider's value") (dom-set-attr _el-input "type" "number") (dom-append (dom-body) _el-slider) (dom-append (dom-body) _el-input) (hs-activate! _el-input) )) (deftest "unsupported element: bind to plain div errors" (error "SKIP (untranslated): unsupported element: bind to plain div errors")) (deftest "variable drives class: setting variable adds/removes class" (hs-cleanup!) (let ((_el-div (dom-create-element "div"))) (dom-set-attr _el-div "_" "bind .dark and $darkMode") (dom-set-inner-html _el-div "test") (dom-append (dom-body) _el-div) (hs-activate! _el-div) )) ) ;; ── breakpoint (2 tests) ── (defsuite "hs-upstream-breakpoint" (deftest "parses as a top-level command" (error "SKIP (untranslated): parses as a top-level command")) (deftest "parses inside an event handler" (error "SKIP (untranslated): parses inside an event handler")) ) ;; ── call (6 tests) ── (defsuite "hs-upstream-call" (deftest "call functions that return promises are waited on" (hs-cleanup!) (let ((_el-div (dom-create-element "div"))) (dom-set-attr _el-div "_" "on click call promiseAnInt() then put it into my.innerHTML") (dom-append (dom-body) _el-div) (hs-activate! _el-div) (dom-dispatch _el-div "click" nil) (assert= (dom-text-content _el-div) "42") )) (deftest "can call functions w/ dollar signs" (hs-cleanup!) (let ((_el-div (dom-create-element "div"))) (dom-set-attr _el-div "_" "on click call $()") (dom-append (dom-body) _el-div) (hs-activate! _el-div) (dom-dispatch _el-div "click" nil) )) (deftest "can call functions w/ underscores" (hs-cleanup!) (let ((_el-div (dom-create-element "div"))) (dom-set-attr _el-div "_" "on click call global_function()") (dom-append (dom-body) _el-div) (hs-activate! _el-div) (dom-dispatch _el-div "click" nil) )) (deftest "can call global javascript functions" (hs-cleanup!) (let ((_el-div (dom-create-element "div"))) (dom-set-attr _el-div "_" "on click call globalFunction(\"foo\")") (dom-append (dom-body) _el-div) (hs-activate! _el-div) (dom-dispatch _el-div "click" nil) )) (deftest "can call javascript instance functions" (hs-cleanup!) (let ((_el-d1 (dom-create-element "div"))) (dom-set-attr _el-d1 "id" "d1") (dom-set-attr _el-d1 "_" "on click call document.getElementById(\"d1\") then put it into window.results") (dom-append (dom-body) _el-d1) (hs-activate! _el-d1) (dom-dispatch (dom-query-by-id "d1") "click" nil) )) (deftest "can call no argument functions" (hs-cleanup!) (let ((_el-div (dom-create-element "div"))) (dom-set-attr _el-div "_" "on click call globalFunction()") (dom-append (dom-body) _el-div) (hs-activate! _el-div) (dom-dispatch _el-div "click" nil) )) ) ;; ── core/api (1 tests) ── (defsuite "hs-upstream-core/api" (deftest "processNodes does not reinitialize a node already processed" (hs-cleanup!) (let ((_el-div (dom-create-element "div"))) (dom-set-attr _el-div "_" "on click set window.global_int to window.global_int + 1") (dom-append (dom-body) _el-div) (hs-activate! _el-div) (dom-dispatch _el-div "click" nil) (dom-dispatch _el-div "click" nil) )) ) ;; ── core/asyncError (2 tests) ── (defsuite "hs-upstream-core/asyncError" (deftest "rejected promise stops execution" (hs-cleanup!) (let ((_el-button (dom-create-element "button")) (_el-out (dom-create-element "div"))) (dom-set-attr _el-button "_" "on click call failAsync() then put 'should not reach' into #out then") (dom-set-inner-html _el-button "Go") (dom-set-attr _el-out "id" "out") (dom-set-inner-html _el-out "original") (dom-append (dom-body) _el-button) (dom-append (dom-body) _el-out) (hs-activate! _el-button) (dom-dispatch _el-button "click" nil) (assert= (dom-text-content (dom-query-by-id "out")) "original") )) (deftest "rejected promise triggers catch block" (hs-cleanup!) (let ((_el-button (dom-create-element "button")) (_el-out (dom-create-element "div"))) (dom-set-attr _el-button "_" "on click call failAsync() then put 'unreachable' into #out then catch e then put e.message into #out then") (dom-set-inner-html _el-button "Go") (dom-set-attr _el-out "id" "out") (dom-append (dom-body) _el-button) (dom-append (dom-body) _el-out) (hs-activate! _el-button) (dom-dispatch _el-button "click" nil) (assert= (dom-text-content (dom-query-by-id "out")) "boom") )) ) ;; ── core/bootstrap (26 tests) ── (defsuite "hs-upstream-core/bootstrap" (deftest "can call functions" (hs-cleanup!) (let ((_el-div (dom-create-element "div"))) (dom-set-attr _el-div "_" "on click call globalFunction(\"foo\")") (dom-append (dom-body) _el-div) (hs-activate! _el-div) (dom-dispatch _el-div "click" nil) )) (deftest "can change non-class properties" (hs-cleanup!) (let ((_el-div (dom-create-element "div"))) (dom-set-attr _el-div "_" "on click add [@foo=\"bar\"]") (dom-append (dom-body) _el-div) (hs-activate! _el-div) (dom-dispatch _el-div "click" nil) (assert= (dom-get-attr _el-div "foo") "bar") )) (deftest "can respond to events on other elements" (hs-cleanup!) (let ((_el-bar (dom-create-element "div")) (_el-div (dom-create-element "div"))) (dom-set-attr _el-bar "id" "bar") (dom-set-attr _el-div "_" "on click from #bar then add .clicked") (dom-append (dom-body) _el-bar) (dom-append (dom-body) _el-div) (hs-activate! _el-div) (dom-dispatch (dom-query-by-id "bar") "click" nil) (assert (dom-has-class? (dom-query "div:nth-of-type(2)") "clicked")) )) (deftest "can send events" (hs-cleanup!) (let ((_el-div (dom-create-element "div")) (_el-bar (dom-create-element "div"))) (dom-set-attr _el-div "_" "on click send foo to #bar") (dom-set-attr _el-bar "id" "bar") (dom-set-attr _el-bar "_" "on foo add .foo-sent") (dom-append (dom-body) _el-div) (dom-append (dom-body) _el-bar) (hs-activate! _el-div) (hs-activate! _el-bar) (dom-dispatch _el-div "click" nil) (assert (dom-has-class? (dom-query-by-id "bar") "foo-sent")) )) (deftest "can send events with args" (hs-cleanup!) (let ((_el-div (dom-create-element "div")) (_el-bar (dom-create-element "div"))) (dom-set-attr _el-div "_" "on click send foo(x:42) to #bar") (dom-set-attr _el-bar "id" "bar") (dom-set-attr _el-bar "_" "on foo put event.detail.x into my.innerHTML") (dom-append (dom-body) _el-div) (dom-append (dom-body) _el-bar) (hs-activate! _el-div) (hs-activate! _el-bar) (dom-dispatch _el-div "click" nil) (assert= (dom-text-content (dom-query-by-id "bar")) "42") )) (deftest "can set properties" (hs-cleanup!) (let ((_el-d1 (dom-create-element "div"))) (dom-set-attr _el-d1 "id" "d1") (dom-set-attr _el-d1 "_" "on click put \"foo\" into #d1.innerHTML") (dom-append (dom-body) _el-d1) (hs-activate! _el-d1) (dom-dispatch (dom-query-by-id "d1") "click" nil) (assert= (dom-text-content (dom-query-by-id "d1")) "foo") )) (deftest "can set styles" (hs-cleanup!) (let ((_el-div (dom-create-element "div"))) (dom-set-attr _el-div "_" "on click put \"red\" into my.style.color") (dom-set-inner-html _el-div "lolwat") (dom-append (dom-body) _el-div) (hs-activate! _el-div) (dom-dispatch _el-div "click" nil) (assert= (dom-get-style _el-div "color") "red") )) (deftest "can take a class from other elements" (hs-cleanup!) (let ((_el-div (dom-create-element "div")) (_el-div1 (dom-create-element "div")) (_el-div2 (dom-create-element "div"))) (dom-add-class _el-div "divs") (dom-add-class _el-div "foo") (dom-add-class _el-div1 "divs") (dom-set-attr _el-div1 "_" "on click take .foo from .divs") (dom-add-class _el-div2 "divs") (dom-append (dom-body) _el-div) (dom-append (dom-body) _el-div1) (dom-append (dom-body) _el-div2) (hs-activate! _el-div1) )) (deftest "can target another div" (hs-cleanup!) (let ((_el-bar (dom-create-element "div")) (_el-div (dom-create-element "div"))) (dom-set-attr _el-bar "id" "bar") (dom-set-attr _el-div "_" "on click add .foo to #bar") (dom-append (dom-body) _el-bar) (dom-append (dom-body) _el-div) (hs-activate! _el-div) (dom-dispatch (dom-query "div:nth-of-type(2)") "click" nil) (assert (dom-has-class? (dom-query-by-id "bar") "foo")) )) (deftest "can wait" (hs-cleanup!) (let ((_el-div (dom-create-element "div"))) (dom-set-attr _el-div "_" "on click add .foo then wait 20ms then add .bar") (dom-append (dom-body) _el-div) (hs-activate! _el-div) (dom-dispatch _el-div "click" nil) (assert (dom-has-class? _el-div "foo")) (assert (dom-has-class? _el-div "bar")) )) (deftest "cleanup clears elt._hyperscript" (hs-cleanup!) (let ((_el-div (dom-create-element "div"))) (dom-set-attr _el-div "_" "on click add .foo") (dom-append (dom-body) _el-div) (hs-activate! _el-div) )) (deftest "cleanup removes cross-element event listeners" (hs-cleanup!) (let ((_el-source (dom-create-element "div")) (_el-target (dom-create-element "div"))) (dom-set-attr _el-source "id" "source") (dom-set-attr _el-target "id" "target") (dom-set-attr _el-target "_" "on click from #source add .foo") (dom-append (dom-body) _el-source) (dom-append (dom-body) _el-target) (hs-activate! _el-target) (dom-dispatch (dom-query-by-id "source") "click" nil) (assert (dom-has-class? (dom-query-by-id "target") "foo")) )) (deftest "cleanup removes data-hyperscript-powered" (hs-cleanup!) (let ((_el-div (dom-create-element "div"))) (dom-set-attr _el-div "_" "on click add .foo") (dom-append (dom-body) _el-div) (hs-activate! _el-div) )) (deftest "cleanup removes event listeners on the element" (hs-cleanup!) (let ((_el-div (dom-create-element "div"))) (dom-set-attr _el-div "_" "on click add .foo") (dom-append (dom-body) _el-div) (hs-activate! _el-div) (dom-dispatch _el-div "click" nil) (assert (dom-has-class? _el-div "foo")) (assert (not (dom-has-class? _el-div "foo"))) )) (deftest "cleanup tracks listeners in elt._hyperscript" (hs-cleanup!) (let ((_el-div (dom-create-element "div"))) (dom-set-attr _el-div "_" "on click add .foo") (dom-append (dom-body) _el-div) (hs-activate! _el-div) )) (deftest "fires hyperscript:before:cleanup and hyperscript:after:cleanup" (hs-cleanup!) (let ((_el-div (dom-create-element "div"))) (dom-set-attr _el-div "_" "on click add .foo") (dom-append (dom-body) _el-div) (hs-activate! _el-div) )) (deftest "fires hyperscript:before:init and hyperscript:after:init" (error "SKIP (untranslated): fires hyperscript:before:init and hyperscript:after:init")) (deftest "hyperscript can have more than one action" (hs-cleanup!) (let ((_el-bar (dom-create-element "div")) (_el-div (dom-create-element "div"))) (dom-set-attr _el-bar "id" "bar") (dom-set-attr _el-div "_" "on click add .foo to #bar then add .blah") (dom-append (dom-body) _el-bar) (dom-append (dom-body) _el-div) (hs-activate! _el-div) (dom-dispatch (dom-query "div:nth-of-type(2)") "click" nil) (assert (dom-has-class? (dom-query-by-id "bar") "foo")) (assert (not (dom-has-class? (dom-query-by-id "bar") "blah"))) (assert (not (dom-has-class? (dom-query "div:nth-of-type(2)") "foo"))) (assert (dom-has-class? (dom-query "div:nth-of-type(2)") "blah")) )) (deftest "hyperscript:before:init can cancel initialization" (error "SKIP (untranslated): hyperscript:before:init can cancel initialization")) (deftest "logAll config logs events to console" (error "SKIP (untranslated): logAll config logs events to console")) (deftest "on a single div" (hs-cleanup!) (let ((_el-div (dom-create-element "div"))) (dom-set-attr _el-div "_" "on click add .foo") (dom-append (dom-body) _el-div) (hs-activate! _el-div) (dom-dispatch _el-div "click" nil) (assert (dom-has-class? _el-div "foo")) )) (deftest "reinitializes if script attribute changes" (hs-cleanup!) (let ((_el-div (dom-create-element "div"))) (dom-set-attr _el-div "_" "on click add .foo") (dom-append (dom-body) _el-div) (hs-activate! _el-div) (dom-dispatch _el-div "click" nil) (assert (dom-has-class? _el-div "foo")) (dom-dispatch _el-div "click" nil) (assert (dom-has-class? _el-div "bar")) )) (deftest "sets data-hyperscript-powered on initialized elements" (hs-cleanup!) (let ((_el-div (dom-create-element "div"))) (dom-set-attr _el-div "_" "on click add .foo") (dom-append (dom-body) _el-div) (hs-activate! _el-div) )) (deftest "skips reinitialization if script unchanged" (hs-cleanup!) (let ((_el-div (dom-create-element "div"))) (dom-set-attr _el-div "_" "on click add .foo") (dom-append (dom-body) _el-div) (hs-activate! _el-div) )) (deftest "stores state on elt._hyperscript" (hs-cleanup!) (let ((_el-div (dom-create-element "div"))) (dom-set-attr _el-div "_" "on click add .foo") (dom-append (dom-body) _el-div) (hs-activate! _el-div) )) (deftest "toggles" (hs-cleanup!) (let ((_el-div (dom-create-element "div"))) (dom-set-attr _el-div "_" "on click toggle .foo") (dom-append (dom-body) _el-div) (hs-activate! _el-div) (dom-dispatch _el-div "click" nil) (assert (dom-has-class? _el-div "foo")) (dom-dispatch _el-div "click" nil) (assert (not (dom-has-class? _el-div "foo"))) )) ) ;; ── core/dom-scope (5 tests) ── (defsuite "hs-upstream-core/dom-scope" (deftest "closest jumps to matching ancestor" (hs-cleanup!) (let ((_el-div (dom-create-element "div")) (_el-div1 (dom-create-element "div")) (_el-span (dom-create-element "span"))) (dom-add-class _el-div "outer") (dom-set-attr _el-div "_" "init set ^val to 'from-outer'") (dom-set-attr _el-div1 "_" "init set ^val to 'from-inner'") (dom-set-attr _el-div1 "dom-scope" "isolated") (dom-set-attr _el-span "_" "init put ^val into me") (dom-set-attr _el-span "dom-scope" "closest .outer") (dom-set-inner-html _el-span "none") (dom-append (dom-body) _el-div) (dom-append _el-div _el-div1) (dom-append _el-div1 _el-span) (hs-activate! _el-div) (hs-activate! _el-div1) (hs-activate! _el-span) )) (deftest "closest with no match stops resolution" (hs-cleanup!) (let ((_el-div (dom-create-element "div")) (_el-span (dom-create-element "span"))) (dom-set-attr _el-div "_" "init set ^val to 'found'") (dom-set-attr _el-span "_" "init if ^val is not undefined put 'leaked' into me else put 'blocked' into me") (dom-set-attr _el-span "dom-scope" "closest .nonexistent") (dom-set-inner-html _el-span "waiting") (dom-append (dom-body) _el-div) (dom-append _el-div _el-span) (hs-activate! _el-div) (hs-activate! _el-span) )) (deftest "isolated allows setting ^var on the isolated element itself" (hs-cleanup!) (let ((_el-div (dom-create-element "div")) (_el-div1 (dom-create-element "div")) (_el-span (dom-create-element "span"))) (dom-set-attr _el-div "_" "init set ^outer to 'leaked'") (dom-set-attr _el-div1 "_" "init set ^inner to 'contained'") (dom-set-attr _el-div1 "dom-scope" "isolated") (dom-set-attr _el-span "_" "init put ^inner into me") (dom-set-inner-html _el-span "none") (dom-append (dom-body) _el-div) (dom-append _el-div _el-div1) (dom-append _el-div1 _el-span) (hs-activate! _el-div) (hs-activate! _el-div1) (hs-activate! _el-span) )) (deftest "isolated stops ^var resolution" (hs-cleanup!) (let ((_el-div (dom-create-element "div")) (_el-div1 (dom-create-element "div")) (_el-span (dom-create-element "span"))) (dom-set-attr _el-div "_" "init set ^color to 'red'") (dom-set-attr _el-div1 "dom-scope" "isolated") (dom-set-attr _el-span "_" "init if ^color is not undefined put 'leaked' into me else put 'blocked' into me") (dom-set-inner-html _el-span "waiting") (dom-append (dom-body) _el-div) (dom-append _el-div _el-div1) (dom-append _el-div1 _el-span) (hs-activate! _el-div) (hs-activate! _el-span) )) (deftest "parent of jumps past matching ancestor to its parent" (hs-cleanup!) (let ((_el-div (dom-create-element "div")) (_el-div1 (dom-create-element "div")) (_el-span (dom-create-element "span"))) (dom-add-class _el-div "outer") (dom-set-attr _el-div "_" "init set ^val to 'from-outer'") (dom-add-class _el-div1 "middle") (dom-set-attr _el-div1 "_" "init set ^val to 'from-middle'") (dom-set-attr _el-div1 "dom-scope" "isolated") (dom-set-attr _el-span "_" "init put ^val into me") (dom-set-attr _el-span "dom-scope" "parent of .middle") (dom-set-inner-html _el-span "none") (dom-append (dom-body) _el-div) (dom-append _el-div _el-div1) (dom-append _el-div1 _el-span) (hs-activate! _el-div) (hs-activate! _el-div1) (hs-activate! _el-span) )) ) ;; ── core/evalStatically (8 tests) ── (defsuite "hs-upstream-core/evalStatically" (deftest "throws on math expressions" (error "SKIP (untranslated): throws on math expressions")) (deftest "throws on symbol references" (error "SKIP (untranslated): throws on symbol references")) (deftest "throws on template strings" (error "SKIP (untranslated): throws on template strings")) (deftest "works on boolean literals" (assert= (eval-hs "true") true) (assert= (eval-hs "false") false) ) (deftest "works on null literal" (assert= (eval-hs "null") nil) ) (deftest "works on number literals" (assert= (eval-hs "42") 42) (assert= (eval-hs "3.14") 3.14) ) (deftest "works on plain string literals" (assert= (eval-hs "\"hello\"") "hello") (assert= (eval-hs "'world'") "world") ) (deftest "works on time expressions" (assert= (eval-hs "200ms") 200) (assert= (eval-hs "2s") 2000) ) ) ;; ── core/liveTemplate (16 tests) ── (defsuite "hs-upstream-core/liveTemplate" (deftest "applies init script from _ attribute" (hs-cleanup!) (let ((_el-script (dom-create-element "script"))) (dom-set-attr _el-script "_" "init set ^msg to 'initialized'") (dom-set-attr _el-script "type" "text/hyperscript-template") (dom-set-inner-html _el-script "${}{^msg}") (dom-append (dom-body) _el-script) (hs-activate! _el-script) )) (deftest "loop index variable is captured alongside loop variable" (hs-cleanup!) (let ((_el-script (dom-create-element "script"))) (dom-set-attr _el-script "type" "text/hyperscript-template") (dom-set-inner-html _el-script "

") (dom-append (dom-body) _el-script) )) (deftest "loop variable capture works with remove for live list" (hs-cleanup!) (let ((_el-script (dom-create-element "script"))) (dom-set-attr _el-script "type" "text/hyperscript-template") (dom-set-inner-html _el-script "") (dom-append (dom-body) _el-script) (dom-dispatch (dom-query "[data-live-template] li').nth(1).locator('button") "click" nil) (assert= (dom-text-content (dom-query "[data-live-template] li').first().locator('span")) "A") (assert= (dom-text-content (dom-query "[data-live-template] li').last().locator('span")) "C") )) (deftest "loop variables are captured and available in _= handlers" (hs-cleanup!) (let ((_el-script (dom-create-element "script"))) (dom-set-attr _el-script "type" "text/hyperscript-template") (dom-set-inner-html _el-script "") (dom-append (dom-body) _el-script) )) (deftest "multiple live templates are independent" (hs-cleanup!) (let ((_el-script (dom-create-element "script")) (_el-script1 (dom-create-element "script"))) (dom-set-attr _el-script "_" "init set ^x to 'first'") (dom-set-attr _el-script "type" "text/hyperscript-template") (dom-set-inner-html _el-script "${}{^x}") (dom-set-attr _el-script1 "_" "init set ^x to 'second'") (dom-set-attr _el-script1 "type" "text/hyperscript-template") (dom-set-inner-html _el-script1 "${}{^x}") (dom-append (dom-body) _el-script) (dom-append (dom-body) _el-script1) (hs-activate! _el-script) (hs-activate! _el-script1) )) (deftest "processes hyperscript on inner elements" (hs-cleanup!) (let ((_el-script (dom-create-element "script"))) (dom-set-attr _el-script "_" "init set ^val to 0") (dom-set-attr _el-script "type" "text/hyperscript-template") (dom-set-inner-html _el-script " 0") (dom-append (dom-body) _el-script) (hs-activate! _el-script) (dom-dispatch (dom-query "[data-live-template] button") "click" nil) )) (deftest "reactively updates when dependencies change" (hs-cleanup!) (let ((_el-script (dom-create-element "script"))) (dom-set-attr _el-script "_" "init set ^count to 0") (dom-set-attr _el-script "type" "text/hyperscript-template") (dom-set-inner-html _el-script " Count: ${}{^count}") (dom-append (dom-body) _el-script) (hs-activate! _el-script) (dom-dispatch (dom-query "[data-live-template] button") "click" nil) )) (deftest "reacts to global state without init script" (hs-cleanup!) (let ((_el-script (dom-create-element "script"))) (dom-set-attr _el-script "type" "text/hyperscript-template") (dom-set-inner-html _el-script "

Hello, ${}{$ltGlobal}!

") (dom-append (dom-body) _el-script) )) (deftest "renders static content after the template" (hs-cleanup!) (let ((_el-script (dom-create-element "script"))) (dom-set-attr _el-script "type" "text/hyperscript-template") (dom-set-inner-html _el-script "Hello World") (dom-append (dom-body) _el-script) )) (deftest "renders template expressions" (hs-cleanup!) (let ((_el-script (dom-create-element "script"))) (dom-set-attr _el-script "type" "text/hyperscript-template") (dom-set-inner-html _el-script "Hello ${}{$ltName}!") (dom-append (dom-body) _el-script) )) (deftest "scope is refreshed after morph so surviving elements get updated indices" (hs-cleanup!) (let ((_el-script (dom-create-element "script"))) (dom-set-attr _el-script "type" "text/hyperscript-template") (dom-set-inner-html _el-script "") (dom-append (dom-body) _el-script) (dom-dispatch (dom-query "[data-live-template] li") "click" nil) (assert= (dom-text-content (dom-query "[data-live-template] li")) "2:C") (dom-dispatch (dom-query "[data-live-template] li") "click" nil) (assert= (dom-text-content (dom-query "[data-live-template] li")) "1:C") )) (deftest "script type=\"text/hyperscript-template\" works as a live template source" (hs-cleanup!) (let ((_el-script (dom-create-element "script"))) (dom-set-attr _el-script "_" "init set ^stMsg to 'from script'") (dom-set-attr _el-script "type" "text/hyperscript-template") (dom-set-inner-html _el-script "${}{^stMsg}") (dom-append (dom-body) _el-script) (hs-activate! _el-script) )) (deftest "script-based live template preserves ${} in bare attribute position" (hs-cleanup!) (let ((_el-script (dom-create-element "script"))) (dom-set-attr _el-script "_" "init set ^items to [{text:'A', done:true},{text:'B', done:false}]") (dom-set-attr _el-script "type" "text/hyperscript-template") (dom-set-inner-html _el-script "") (dom-append (dom-body) _el-script) (hs-activate! _el-script) )) (deftest "supports #for loops" (hs-cleanup!) (let ((_el-script (dom-create-element "script"))) (dom-set-attr _el-script "_" "init set ^items to ['a', 'b', 'c']") (dom-set-attr _el-script "type" "text/hyperscript-template") (dom-set-inner-html _el-script "") (dom-append (dom-body) _el-script) (hs-activate! _el-script) )) (deftest "supports #if conditionals" (hs-cleanup!) (let ((_el-script (dom-create-element "script"))) (dom-set-attr _el-script "_" "init set ^show to true") (dom-set-attr _el-script "type" "text/hyperscript-template") (dom-set-inner-html _el-script "#if ^show visible #end") (dom-append (dom-body) _el-script) (hs-activate! _el-script) )) (deftest "wrapper has display:contents" (hs-cleanup!) (let ((_el-script (dom-create-element "script"))) (dom-set-attr _el-script "type" "text/hyperscript-template") (dom-set-inner-html _el-script "test") (dom-append (dom-body) _el-script) )) ) ;; ── core/parser (14 tests) ── (defsuite "hs-upstream-core/parser" (deftest "_hyperscript() evaluate API still throws on first error" (error "SKIP (untranslated): _hyperscript() evaluate API still throws on first error")) (deftest "basic parse error messages work" (error "SKIP (untranslated): basic parse error messages work")) (deftest "can have alternate comments in attributes" (hs-cleanup!) (let ((_el-div (dom-create-element "div"))) (dom-set-attr _el-div "_" "on click put \"clicked\" into my.innerHTML // put some content into the div...") (dom-append (dom-body) _el-div) (hs-activate! _el-div) (dom-dispatch _el-div "click" nil) (assert= (dom-text-content _el-div) "clicked") )) (deftest "can have alternate comments in scripts" (hs-cleanup!) (guard (_e (true nil)) (eval-expr-cek (hs-to-sx (hs-compile "// this is a comment def foo() // this is another comment return \"foo\" end // end with a comment")))) ) (deftest "can have comments in attributes" (hs-cleanup!) (let ((_el-div (dom-create-element "div"))) (dom-set-attr _el-div "_" "on click put \"clicked\" into my.innerHTML -- put some content into the div...") (dom-append (dom-body) _el-div) (hs-activate! _el-div) (dom-dispatch _el-div "click" nil) (assert= (dom-text-content _el-div) "clicked") )) (deftest "can have comments in attributes (triple dash)" (hs-cleanup!) (let ((_el-div (dom-create-element "div"))) (dom-set-attr _el-div "_" "on click put \"clicked\" into my.innerHTML ---put some content into the div...") (dom-append (dom-body) _el-div) (hs-activate! _el-div) (dom-dispatch _el-div "click" nil) (assert= (dom-text-content _el-div) "clicked") )) (deftest "can have comments in scripts" (hs-cleanup!) (guard (_e (true nil)) (eval-expr-cek (hs-to-sx (hs-compile "-- this is a comment def foo() -- this is another comment return \"foo\" end -- end with a comment--- this is a comment ----this is a comment---- def bar() ---this is another comment return \"bar\" end --- end with a comment")))) ) (deftest "can support parenthesized commands and features" (hs-cleanup!) (let ((_el-div (dom-create-element "div"))) (dom-set-attr _el-div "_" "(on click (log me) (trigger foo)) (on foo (put \"clicked\" into my.innerHTML))") (dom-append (dom-body) _el-div) (hs-activate! _el-div) (dom-dispatch _el-div "click" nil) (assert= (dom-text-content _el-div) "clicked") )) (deftest "continues initializing elements in the presence of a parse error" (hs-cleanup!) (let ((_el-div (dom-create-element "div")) (_el-d1 (dom-create-element "div")) (_el-d2 (dom-create-element "div"))) (dom-set-attr _el-d1 "id" "d1") (dom-set-attr _el-d1 "_" "on click bad") (dom-set-attr _el-d2 "id" "d2") (dom-set-attr _el-d2 "_" "on click put \"clicked\" into my.innerHTML") (dom-append (dom-body) _el-div) (dom-append _el-div _el-d1) (dom-append _el-div _el-d2) (hs-activate! _el-d1) (hs-activate! _el-d2) (dom-dispatch (dom-query-by-id "d2") "click" nil) (assert= (dom-text-content (dom-query-by-id "d2")) "clicked") )) (deftest "element-level isolation still works with error recovery" (hs-cleanup!) (let ((_el-div (dom-create-element "div")) (_el-d1 (dom-create-element "div")) (_el-d2 (dom-create-element "div"))) (dom-set-attr _el-d1 "id" "d1") (dom-set-attr _el-d1 "_" "on click blargh end on mouseenter also_bad") (dom-set-attr _el-d2 "id" "d2") (dom-set-attr _el-d2 "_" "on click put \"clicked\" into my.innerHTML") (dom-append (dom-body) _el-div) (dom-append _el-div _el-d1) (dom-append _el-div _el-d2) (hs-activate! _el-d1) (hs-activate! _el-d2) (dom-dispatch (dom-query-by-id "d2") "click" nil) (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")) (deftest "parse error at EOF on trailing newline does not crash" (error "SKIP (untranslated): parse error at EOF on trailing newline does not crash")) (deftest "recovers across feature boundaries and reports all errors" (hs-cleanup!) (let ((_el-d1 (dom-create-element "div"))) (dom-set-attr _el-d1 "id" "d1") (dom-set-attr _el-d1 "_" "on click blargh end on mouseenter put \"hovered\" into my.innerHTML") (dom-append (dom-body) _el-d1) (hs-activate! _el-d1) )) (deftest "recovers across multiple feature errors" (hs-cleanup!) (let ((_el-d1 (dom-create-element "div"))) (dom-set-attr _el-d1 "id" "d1") (dom-set-attr _el-d1 "_" "on click blargh end on mouseenter also_bad end on focus put \"focused\" into my.innerHTML") (dom-append (dom-body) _el-d1) (hs-activate! _el-d1) )) ) ;; ── core/reactivity (8 tests) ── (defsuite "hs-upstream-core/reactivity" (deftest "NaN → NaN does not retrigger handlers (Object.is semantics)" (hs-cleanup!) (let ((_el-div (dom-create-element "div"))) (dom-set-attr _el-div "_" "when $rxNanVal changes increment $rxNanCount") (dom-append (dom-body) _el-div) (hs-activate! _el-div) )) (deftest "effect switches its dependencies based on control flow" (hs-cleanup!) (let ((_el-div (dom-create-element "div"))) (dom-set-attr _el-div "_" "live if $rxCond put $rxA into me else put $rxB into me end end") (dom-append (dom-body) _el-div) (hs-activate! _el-div) )) (deftest "effects fire in source registration order" (hs-cleanup!) (let ((_el-div (dom-create-element "div")) (_el-div1 (dom-create-element "div")) (_el-div2 (dom-create-element "div"))) (dom-set-attr _el-div "_" "when $rxTrigger changes call $rxOrder.push('first')") (dom-set-attr _el-div1 "_" "when $rxTrigger changes call $rxOrder.push('second')") (dom-set-attr _el-div2 "_" "when $rxTrigger changes call $rxOrder.push('third')") (dom-append (dom-body) _el-div) (dom-append (dom-body) _el-div1) (dom-append (dom-body) _el-div2) (hs-activate! _el-div) (hs-activate! _el-div1) (hs-activate! _el-div2) )) (deftest "effects on disconnected elements stop automatically" (hs-cleanup!) (let ((_el-persist (dom-create-element "div")) (_el-doomed (dom-create-element "div"))) (dom-set-attr _el-persist "id" "persist") (dom-set-attr _el-persist "_" "when $rxDcVal changes increment $rxDcCount then put $rxDcVal into me") (dom-set-attr _el-doomed "id" "doomed") (dom-set-attr _el-doomed "_" "when $rxDcVal changes increment $rxDcCount") (dom-append (dom-body) _el-persist) (dom-append (dom-body) _el-doomed) (hs-activate! _el-persist) (hs-activate! _el-doomed) )) (deftest "element-scoped writes only trigger effects on the same element" (hs-cleanup!) (let ((_el-a (dom-create-element "div")) (_el-b (dom-create-element "div"))) (dom-set-attr _el-a "id" "a") (dom-set-attr _el-a "_" "init set :count to 0 then on click increment :count then when :count changes put :count into me") (dom-set-attr _el-b "id" "b") (dom-set-attr _el-b "_" "init set :count to 0 then when :count changes put :count into me") (dom-append (dom-body) _el-a) (dom-append (dom-body) _el-b) (hs-activate! _el-a) (hs-activate! _el-b) (dom-dispatch (dom-query-by-id "a") "click" nil) (assert= (dom-text-content (dom-query-by-id "a")) "1") (assert= (dom-text-content (dom-query-by-id "b")) "0") )) (deftest "multiple effects on the same global fire once per write" (hs-cleanup!) (let ((_el-a (dom-create-element "div")) (_el-b (dom-create-element "div"))) (dom-set-attr _el-a "id" "a") (dom-set-attr _el-a "_" "when $rxVal changes increment $rxCount then put $rxVal into me") (dom-set-attr _el-b "id" "b") (dom-set-attr _el-b "_" "when $rxVal changes put $rxVal into me") (dom-append (dom-body) _el-a) (dom-append (dom-body) _el-b) (hs-activate! _el-a) (hs-activate! _el-b) )) (deftest "reactive loops are detected and stopped after 100 consecutive triggers" (hs-cleanup!) (let ((_el-div (dom-create-element "div"))) (dom-set-attr _el-div "_" "when $rxLoop changes increment $rxLoop") (dom-append (dom-body) _el-div) (hs-activate! _el-div) )) (deftest "setting same value does not retrigger handler" (hs-cleanup!) (let ((_el-div (dom-create-element "div"))) (dom-set-attr _el-div "_" "when $rxSameVal changes increment $rxSameCount") (dom-append (dom-body) _el-div) (hs-activate! _el-div) )) ) ;; ── core/regressions (16 tests) ── (defsuite "hs-upstream-core/regressions" (deftest "async exception" (hs-cleanup!) (let ((_el-div (dom-create-element "div"))) (dom-set-attr _el-div "_" "on click async transition opacity to 0 log \"hello!\"") (dom-append (dom-body) _el-div) (hs-activate! _el-div) (dom-dispatch _el-div "click" nil) )) (deftest "button query in form" (hs-cleanup!) (let ((_el-form (dom-create-element "form")) (_el-b1 (dom-create-element "button"))) (dom-set-attr _el-form "_" "on click get the