HS test generator: fix toHaveCSS, locals, and \"-escapes — +28 tests

Generator changes (tests/playwright/generate-sx-tests.py):
- toHaveCSS regex: balance parens so `'rgb(255, 0, 0)'` is captured intact
  (was truncating at first `)`)
- Map browser-computed colors `rgb(R,G,B)` back to CSS keywords
  (red/green/blue/black/white) — our DOM mock returns the inline value
- js_val_to_sx now handles object literals `{a: 1, b: {c: 2}}` → `{:a 1 :b {:c 2}}`
- Pattern 2 (`var x = await run(...)`) now captures locals via balanced-brace
  scan and emits `eval-hs-locals` instead of `eval-hs`
- Pattern 1 with locals: emit `eval-hs-locals` (was wrapping in `let`, which
  doesn't reach the inner HS env)
- Stop collapsing `\"` → `"` in raw HTML (line 218): the backslash escapes
  are legitimate in single-quoted `_='...'` HS attribute values containing
  nested HS scripts

Test-framework changes (regenerated into spec/tests/test-hyperscript-behavioral.sx):
- `_hs-wrap-body`: returns expression value if non-nil, else `it`. Lets bare
  expressions (`foo.foo`) and `it`-mutating scripts (`pick first 3 of arr;
  set $test to it`) both round-trip through the same wrapper
- `eval-hs-locals` now injects locals via `(let ((name (quote val)) ...) sx)`
  rather than `apply handler (cons nil vals)` — works around a JIT loop on
  some compiled forms (e.g. `bar.doh of foo` with undefined `bar`)

Also synced lib/hyperscript/*.sx → shared/static/wasm/sx/hs-*.sx (the WASM
test runner reads from the wasm/sx/ copies).

Net per-cluster pass counts (vs prior baseline):
- put: 23 → 29 (+6)
- set: 21 → 28 (+7)
- show: 7 → 15 (+8)
- expressions/propertyAccess: 3 → 9 (+6)
- expressions/possessiveExpression: 17 → 18 (+1)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-23 09:18:21 +00:00
parent 0515295317
commit a11d0941e9
7 changed files with 451 additions and 194 deletions

View File

@@ -16,13 +16,24 @@
(fn ()
(dom-set-inner-html (dom-body) "")))
;; Evaluate a hyperscript expression and return the last-expression value.
;; Compiles the expression, wraps in a thunk, evaluates, returns result.
;; 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)))))
(list (quote fn) (list (quote me))
(list (quote let) (list (list (quote it) nil) (list (quote event) nil)) sx)))))
(guard
(_e
(true
@@ -33,18 +44,16 @@
(handler nil))))))
;; Evaluate a hyperscript expression with locals. bindings = list of (symbol value).
;; The locals are injected as fn params so they resolve in the handler body.
;; 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))))
(let ((names (map (fn (b) (first b)) bindings))
(vals (map (fn (b) (nth b 1)) bindings)))
(let ((param-list (cons (quote me) names)))
(let ((wrapper (list (quote fn) param-list
(list (quote let)
(list (list (quote it) nil) (list (quote event) nil))
sx (quote it)))))
(let ((handler (eval-expr-cek wrapper)))
;; Build (let ((name1 (quote val1)) ...) <wrap-body>)
(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
@@ -52,14 +61,14 @@
(and (list? _e) (= (first _e) "hs-return"))
(nth _e 1)
(raise _e))))
(apply handler (cons nil vals))))))))))
(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)) (list (quote let) (list (list (quote it) nil) (list (quote event) nil)) sx)))))
(list (quote fn) (list (quote me)) (_hs-wrap-body sx)))))
(guard
(_e
(true
@@ -133,7 +142,7 @@
(dom-append (dom-body) _el-div)
(hs-activate! _el-div)
(dom-dispatch _el-div "click" nil)
(assert= (dom-get-style _el-div "color") "")
(assert= (dom-get-style _el-div "color") "red")
(assert= (dom-get-style _el-div "font-family") "monospace")
))
(deftest "can add multiple class refs"
@@ -163,7 +172,7 @@
(dom-append (dom-body) _el-div)
(hs-activate! _el-div)
(dom-dispatch _el-div "click" nil)
(assert= (dom-get-style _el-div "color") "")
(assert= (dom-get-style _el-div "color") "red")
))
(deftest "can add to an HTMLCollection"
(hs-cleanup!)
@@ -1287,7 +1296,7 @@
(dom-append (dom-body) _el-div)
(hs-activate! _el-div)
(dom-dispatch _el-div "click" nil)
(assert= (dom-get-style _el-div "color") "")
(assert= (dom-get-style _el-div "color") "red")
))
(deftest "can take a class from other elements"
(hs-cleanup!)
@@ -2693,7 +2702,7 @@
(dom-append (dom-body) _el-div)
(hs-activate! _el-div)
(dom-dispatch _el-div "click" nil)
(assert= (dom-get-style _el-div "background-color") "")
(assert= (dom-get-style _el-div "background-color") "red")
))
(deftest "can default variables"
(hs-cleanup!)
@@ -2770,7 +2779,7 @@
(dom-append (dom-body) _el-div)
(hs-activate! _el-div)
(dom-dispatch _el-div "click" nil)
(assert= (dom-get-style _el-div "color") "")
(assert= (dom-get-style _el-div "color") "blue")
))
(deftest "default variables respect existing values"
(hs-cleanup!)
@@ -3286,7 +3295,7 @@
(assert= (eval-hs "[1 + 1, 2 * 3, 10 - 5]") (list 2 6 5))
)
(deftest "arrays containing objects work"
(assert= (eval-hs "[{a: 1}, {b: 2}]") (list "{a: 1}" "{b: 2}"))
(assert= (eval-hs "[{a: 1}, {b: 2}]") (list {:a 1} {:b 2}))
)
(deftest "deeply nested array literals work"
(assert= (eval-hs "[[[1]], [[2, 3]]]") (list (list (list 1)) (list (list 2 3))))
@@ -3359,7 +3368,7 @@
(dom-dispatch (dom-query-by-id "qsdiv") "click" nil)
))
(deftest "converts an array into HTML"
(assert= (eval-hs "d as HTML") "`this-is-html`")
(assert= (eval-hs-locals "d as HTML" (list (list (quote d) (list "this-" "is-" "html")))) "`this-is-html`")
)
(deftest "converts an element into HTML"
(error "SKIP (untranslated): converts an element into HTML"))
@@ -3389,7 +3398,7 @@
(deftest "converts null as null"
(error "SKIP (untranslated): converts null as null"))
(deftest "converts numbers things 'HTML'"
(assert= (eval-hs "value as HTML") "123")
(assert= (eval-hs-locals "value as HTML" (list (list (quote value) 123))) "123")
)
(deftest "converts object as Entries"
(assert= (eval-hs "{a:1} as Entries") (list (list "a" 1)))
@@ -3434,7 +3443,7 @@
(assert= (eval-hs "'10' as Number") 10.4)
)
(deftest "converts value as Object"
(assert= (host-get (eval-hs "x as Object") "foo") "bar")
(assert= (host-get (eval-hs-locals "x as Object" (list (list (quote x) {:foo "bar"}))) "foo") "bar")
)
(deftest "converts value as String"
(assert= (eval-hs "10 as String") "10")
@@ -4160,7 +4169,7 @@
(dom-append _el-container _el-span3)
))
(deftest "where binds after property access"
(assert= (eval-hs "obj.items where it > 2") (list 3 4))
(assert= (eval-hs-locals "obj.items where it > 2" (list (list (quote obj) {:items (list 1 2 3 4)}))) (list 3 4))
)
(deftest "where in component init followed by on feature"
(hs-cleanup!)
@@ -4332,8 +4341,8 @@
(assert= (eval-hs "'Hello World' contains 'missing' ignoring case") false)
)
(deftest "contains works with arrays"
(let ((that 1)) (assert= (eval-hs "I contain that") true))
(let ((that "[1")) (assert= (eval-hs "that contains me") true))
(assert= (eval-hs-locals "I contain that" (list (list (quote that) 1))) true)
(assert= (eval-hs-locals "that contains me" (list (list (quote that) "[1"))) true)
)
(deftest "contains works with css literals"
(hs-cleanup!)
@@ -4486,14 +4495,14 @@
(assert= (eval-hs "2 > 2") false)
)
(deftest "include works"
(let ((foo "foo") (foobar "foobar")) (assert= (eval-hs "foo includes foobar") false))
(let ((foo "foo") (foobar "foobar")) (assert= (eval-hs "foobar includes foo") true))
(let ((foo "foo") (foobar "foobar")) (assert= (eval-hs "foo does not include foobar") true))
(let ((foo "foo") (foobar "foobar")) (assert= (eval-hs "foobar does not include foo") false))
(assert= (eval-hs-locals "foo includes foobar" (list (list (quote foo) "foo") (list (quote foobar) "foobar"))) false)
(assert= (eval-hs-locals "foobar includes foo" (list (list (quote foo) "foo") (list (quote foobar) "foobar"))) true)
(assert= (eval-hs-locals "foo does not include foobar" (list (list (quote foo) "foo") (list (quote foobar) "foobar"))) true)
(assert= (eval-hs-locals "foobar does not include foo" (list (list (quote foo) "foo") (list (quote foobar) "foobar"))) false)
)
(deftest "includes works with arrays"
(let ((that 1)) (assert= (eval-hs "I include that") true))
(let ((that "[1")) (assert= (eval-hs "that includes me") true))
(assert= (eval-hs-locals "I include that" (list (list (quote that) 1))) true)
(assert= (eval-hs-locals "that includes me" (list (list (quote that) "[1"))) true)
)
(deftest "includes works with css literals"
(hs-cleanup!)
@@ -4706,8 +4715,8 @@
(assert= (eval-hs "2 is really '2'") false)
)
(deftest "is still does equality when rhs variable exists"
(let ((x 5) (y 5)) (assert= (eval-hs "x is y") true))
(let ((x 5) (y 6)) (assert= (eval-hs "x is y") false))
(assert= (eval-hs-locals "x is y" (list (list (quote x) 5) (list (quote y) 5))) true)
(assert= (eval-hs-locals "x is y" (list (list (quote x) 5) (list (quote y) 6))) false)
)
(deftest "is works"
(assert= (eval-hs "1 is 2") false)
@@ -5658,7 +5667,7 @@
(dom-append (dom-body) _el-pDiv)
))
(deftest "can access basic properties"
(assert= (eval-hs "foo's foo") "foo")
(assert= (eval-hs-locals "foo's foo" (list (list (quote foo) {:foo "foo"}))) "foo")
)
(deftest "can access basic style"
(hs-cleanup!)
@@ -5805,32 +5814,32 @@
;; ── expressions/propertyAccess (12 tests) ──
(defsuite "hs-upstream-expressions/propertyAccess"
(deftest "can access basic properties"
(assert= (eval-hs "foo.foo") "foo")
(assert= (eval-hs-locals "foo.foo" (list (list (quote foo) {:foo "foo"}))) "foo")
)
(deftest "chained property access (four levels)"
(assert= (eval-hs "a.b.c.d") 42)
(assert= (eval-hs-locals "a.b.c.d" (list (list (quote a) {:b {:c {:d 42}}}))) 42)
)
(deftest "chained property access (three levels)"
(assert= (eval-hs "a.b.c") "deep")
(assert= (eval-hs-locals "a.b.c" (list (list (quote a) {:b {:c "deep"}}))) "deep")
)
(deftest "is null safe"
(error "SKIP (untranslated): is null safe"))
(deftest "mixing dot and of forms"
(assert= (eval-hs "c of a.b") "mixed")
(assert= (eval-hs-locals "c of a.b" (list (list (quote a) {:b {:c "mixed"}}))) "mixed")
)
(deftest "null-safe access through an undefined intermediate"
(error "SKIP (untranslated): null-safe access through an undefined intermediate"))
(deftest "of form chains through multiple levels"
(assert= (eval-hs "c of b of a") "deep")
(assert= (eval-hs-locals "c of b of a" (list (list (quote a) {:b {:c "deep"}}))) "deep")
)
(deftest "of form works"
(assert= (eval-hs "foo of foo") "foo")
(assert= (eval-hs-locals "foo of foo" (list (list (quote foo) {:foo "foo"}))) "foo")
)
(deftest "of form works w/ complex left side"
(assert= (eval-hs "bar.doh of foo") "foo")
(assert= (eval-hs-locals "bar.doh of foo" (list (list (quote foo) {:bar {:doh "foo"}}))) "foo")
)
(deftest "of form works w/ complex right side"
(assert= (eval-hs "doh of foo.bar") "foo")
(assert= (eval-hs-locals "doh of foo.bar" (list (list (quote foo) {:bar {:doh "foo"}}))) "foo")
)
(deftest "property access on function result"
(assert= (eval-hs "makeObj().name") "hi")
@@ -6350,7 +6359,7 @@
(assert= (eval-hs "\"foo\"") "foo")
)
(deftest "should handle back slashes in non-template content"
(assert= (eval-hs "`https://${foo}`") "https://bar")
(assert= (eval-hs-locals "`https://${foo}`" (list (list (quote foo) "bar"))) "https://bar")
)
(deftest "should handle strings with tags and quotes"
(error "SKIP (untranslated): should handle strings with tags and quotes"))
@@ -6425,7 +6434,7 @@
(deftest "resolves global context properly"
(error "SKIP (untranslated): resolves global context properly"))
(deftest "resolves local context properly"
(assert= (eval-hs "foo") 42)
(assert= (eval-hs-locals "foo" (list (list (quote foo) 42))) 42)
)
)
@@ -9348,7 +9357,7 @@
(dom-append (dom-body) _el-div)
(hs-activate! _el-div)
(dom-dispatch _el-div "click" nil)
(assert= (dom-get-style _el-div "color") "")
(assert= (dom-get-style _el-div "color") "red")
))
(deftest "can put array vals w/ array access syntax and var"
(hs-cleanup!)
@@ -9358,7 +9367,7 @@
(dom-append (dom-body) _el-div)
(hs-activate! _el-div)
(dom-dispatch _el-div "click" nil)
(assert= (dom-get-style _el-div "color") "")
(assert= (dom-get-style _el-div "color") "red")
))
(deftest "can put at end of an array"
(hs-cleanup!)
@@ -9416,7 +9425,7 @@
(dom-append (dom-body) _el-div)
(hs-activate! _el-div)
(dom-dispatch _el-div "click" nil)
(assert= (dom-get-style _el-div "color") "")
(assert= (dom-get-style _el-div "color") "red")
))
(deftest "can put properties w/ array access syntax and var"
(hs-cleanup!)
@@ -9426,7 +9435,7 @@
(dom-append (dom-body) _el-div)
(hs-activate! _el-div)
(dom-dispatch _el-div "click" nil)
(assert= (dom-get-style _el-div "color") "")
(assert= (dom-get-style _el-div "color") "red")
))
(deftest "can set into attribute ref"
(hs-cleanup!)
@@ -9526,7 +9535,7 @@
(dom-append (dom-body) _el-div)
(hs-activate! _el-div)
(dom-dispatch _el-div "click" nil)
(assert= (dom-get-style _el-div "color") "")
(assert= (dom-get-style _el-div "color") "red")
))
(deftest "can set into indirect style ref 2"
(hs-cleanup!)
@@ -9538,7 +9547,7 @@
(dom-append (dom-body) _el-div2)
(hs-activate! _el-div)
(dom-dispatch _el-div "click" nil)
(assert= (dom-get-style (dom-query-by-id "div2") "color") "")
(assert= (dom-get-style (dom-query-by-id "div2") "color") "red")
))
(deftest "can set into indirect style ref 3"
(hs-cleanup!)
@@ -9550,7 +9559,7 @@
(dom-append (dom-body) _el-div2)
(hs-activate! _el-div)
(dom-dispatch _el-div "click" nil)
(assert= (dom-get-style (dom-query-by-id "div2") "color") "")
(assert= (dom-get-style (dom-query-by-id "div2") "color") "red")
))
(deftest "can set into style ref"
(hs-cleanup!)
@@ -9560,7 +9569,7 @@
(dom-append (dom-body) _el-div)
(hs-activate! _el-div)
(dom-dispatch _el-div "click" nil)
(assert= (dom-get-style _el-div "color") "")
(assert= (dom-get-style _el-div "color") "red")
))
(deftest "can set javascript globals"
(hs-cleanup!)
@@ -9599,7 +9608,7 @@
(dom-append (dom-body) _el-div)
(hs-activate! _el-div)
(dom-dispatch _el-div "click" nil)
(assert= (dom-get-style _el-div "color") "")
(assert= (dom-get-style _el-div "color") "red")
))
(deftest "is null tolerant"
(hs-cleanup!)
@@ -9623,7 +9632,7 @@
(hs-cleanup!)
(let ((_el-d1 (dom-create-element "div")))
(dom-set-attr _el-d1 "id" "d1")
(dom-set-attr _el-d1 "_" "on click put \"<button id=\"b1\" _=\"on click put 42 into me\">40</button>\" after me")
(dom-set-attr _el-d1 "_" "on click put \"<button id=\\\"b1\\\" _=\\\"on click put 42 into me\\\">40</button>\" after me")
(dom-append (dom-body) _el-d1)
(hs-activate! _el-d1)
(dom-dispatch (dom-query-by-id "d1") "click" nil)
@@ -9635,7 +9644,7 @@
(hs-cleanup!)
(let ((_el-d1 (dom-create-element "div")))
(dom-set-attr _el-d1 "id" "d1")
(dom-set-attr _el-d1 "_" "on click put \"<button id=\"b1\" _=\"on click put 42 into me\">40</button>\" at the end of me")
(dom-set-attr _el-d1 "_" "on click put \"<button id=\\\"b1\\\" _=\\\"on click put 42 into me\\\">40</button>\" at the end of me")
(dom-append (dom-body) _el-d1)
(hs-activate! _el-d1)
(dom-dispatch (dom-query-by-id "d1") "click" nil)
@@ -9646,7 +9655,7 @@
(hs-cleanup!)
(let ((_el-d1 (dom-create-element "div")))
(dom-set-attr _el-d1 "id" "d1")
(dom-set-attr _el-d1 "_" "on click put \"<button id=\"b1\" _=\"on click put 42 into me\">40</button>\" at the start of me")
(dom-set-attr _el-d1 "_" "on click put \"<button id=\\\"b1\\\" _=\\\"on click put 42 into me\\\">40</button>\" at the start of me")
(dom-append (dom-body) _el-d1)
(hs-activate! _el-d1)
(dom-dispatch (dom-query-by-id "d1") "click" nil)
@@ -9657,7 +9666,7 @@
(hs-cleanup!)
(let ((_el-d1 (dom-create-element "div")))
(dom-set-attr _el-d1 "id" "d1")
(dom-set-attr _el-d1 "_" "on click put \"<button id=\"b1\" _=\"on click put 42 into me\">40</button>\" before me")
(dom-set-attr _el-d1 "_" "on click put \"<button id=\\\"b1\\\" _=\\\"on click put 42 into me\\\">40</button>\" before me")
(dom-append (dom-body) _el-d1)
(hs-activate! _el-d1)
(dom-dispatch (dom-query-by-id "d1") "click" nil)
@@ -9669,7 +9678,7 @@
(hs-cleanup!)
(let ((_el-d1 (dom-create-element "div")))
(dom-set-attr _el-d1 "id" "d1")
(dom-set-attr _el-d1 "_" "on click put \"<button id=\"b1\" _=\"on click put 42 into me\">40</button>\" into <div#d1/>")
(dom-set-attr _el-d1 "_" "on click put \"<button id=\\\"b1\\\" _=\\\"on click put 42 into me\\\">40</button>\" into <div#d1/>")
(dom-append (dom-body) _el-d1)
(hs-activate! _el-d1)
(dom-dispatch (dom-query-by-id "d1") "click" nil)
@@ -9679,7 +9688,7 @@
(deftest "properly processes hyperscript in new content in a symbol write"
(hs-cleanup!)
(let ((_el-div (dom-create-element "div")))
(dom-set-attr _el-div "_" "on click put \"<button id=\"b1\" _=\"on click put 42 into me\">40</button>\" into me")
(dom-set-attr _el-div "_" "on click put \"<button id=\\\"b1\\\" _=\\\"on click put 42 into me\\\">40</button>\" into me")
(dom-append (dom-body) _el-div)
(hs-activate! _el-div)
(dom-dispatch _el-div "click" nil)
@@ -10736,7 +10745,7 @@
(dom-append (dom-body) _el-div)
(hs-activate! _el-div)
(dom-dispatch _el-div "click" nil)
(assert= (dom-get-style _el-div "color") "")
(assert= (dom-get-style _el-div "color") "red")
))
(deftest "can set arrays w/ array access syntax and var"
(hs-cleanup!)
@@ -10746,7 +10755,7 @@
(dom-append (dom-body) _el-div)
(hs-activate! _el-div)
(dom-dispatch _el-div "click" nil)
(assert= (dom-get-style _el-div "color") "")
(assert= (dom-get-style _el-div "color") "red")
))
(deftest "can set chained indirect properties"
(hs-cleanup!)
@@ -10869,7 +10878,7 @@
(dom-append (dom-body) _el-div2)
(hs-activate! _el-div)
(dom-dispatch _el-div "click" nil)
(assert= (dom-get-style (dom-query-by-id "div2") "color") "")
(assert= (dom-get-style (dom-query-by-id "div2") "color") "red")
))
(deftest "can set into indirect style ref 2"
(hs-cleanup!)
@@ -10881,7 +10890,7 @@
(dom-append (dom-body) _el-div2)
(hs-activate! _el-div)
(dom-dispatch _el-div "click" nil)
(assert= (dom-get-style (dom-query-by-id "div2") "color") "")
(assert= (dom-get-style (dom-query-by-id "div2") "color") "red")
))
(deftest "can set into indirect style ref 3"
(hs-cleanup!)
@@ -10893,7 +10902,7 @@
(dom-append (dom-body) _el-div2)
(hs-activate! _el-div)
(dom-dispatch _el-div "click" nil)
(assert= (dom-get-style (dom-query-by-id "div2") "color") "")
(assert= (dom-get-style (dom-query-by-id "div2") "color") "red")
))
(deftest "can set into style ref"
(hs-cleanup!)
@@ -10903,7 +10912,7 @@
(dom-append (dom-body) _el-div)
(hs-activate! _el-div)
(dom-dispatch _el-div "click" nil)
(assert= (dom-get-style _el-div "color") "")
(assert= (dom-get-style _el-div "color") "red")
))
(deftest "can set javascript globals"
(hs-cleanup!)
@@ -10950,7 +10959,7 @@
(dom-append (dom-body) _el-div)
(hs-activate! _el-div)
(dom-dispatch _el-div "click" nil)
(assert= (dom-get-style _el-div "color") "")
(assert= (dom-get-style _el-div "color") "red")
))
(deftest "can set props w/ array access syntax and var"
(hs-cleanup!)
@@ -10960,7 +10969,7 @@
(dom-append (dom-body) _el-div)
(hs-activate! _el-div)
(dom-dispatch _el-div "click" nil)
(assert= (dom-get-style _el-div "color") "")
(assert= (dom-get-style _el-div "color") "red")
))
(deftest "can set styles"
(hs-cleanup!)
@@ -10970,7 +10979,7 @@
(dom-append (dom-body) _el-div)
(hs-activate! _el-div)
(dom-dispatch _el-div "click" nil)
(assert= (dom-get-style _el-div "color") "")
(assert= (dom-get-style _el-div "color") "red")
))
(deftest "global ($) variables are allowed at the feature level"
(hs-cleanup!)