Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 48s
Three-part fix for hs-upstream-core/asyncError test 2/2:
1. runtime.sx hs-win-call: when an async call returns a rejected promise,
store the error value in window.__hs_async_error (side-channel) and
raise the sentinel "__hs_async_error__" so the value survives the
raise boundary intact.
2. compiler.sx catch clause: inject `(let ((var (host-hs-normalize-exc var))) ...)`
around the catch body so the sentinel gets swapped for the real error
object before user code runs. Uses let (not set!) so shadowing works
correctly for guard catch variables.
3. tests/hs-run-filtered.js:
- host-promise-state wraps JS Error objects as plain {message:...} dicts
before they cross the WASM boundary (Error.toString() was producing
"Error: boom" strings instead of accessible objects)
- host-hs-normalize-exc native retrieves the side-channel value when
the sentinel arrives in a catch variable
- host-get coercion restricted to El instances — plain JS objects with
a "value" key were being stringified to "[object Object]"
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
14077 lines
619 KiB
Plaintext
14077 lines
619 KiB
Plaintext
;; 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 ──────────────────────────────────────────────────
|
|
|
|
;; Bind `window` and `document` as plain SX symbols so HS code that
|
|
;; references them (e.g. `window.tmp`) can resolve through the host.
|
|
(define window (host-global "window"))
|
|
(define document (host-global "document"))
|
|
(define cookies (host-global "cookies"))
|
|
|
|
(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 ()
|
|
(begin
|
|
(dom-set-inner-html (dom-body) "")
|
|
;; Reset global runtime state that prior tests may have set.
|
|
(hs-set-default-hide-strategy! nil)
|
|
(hs-set-log-all! false))))
|
|
|
|
;; 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)
|
|
;; Wrap body to capture return via `it`. `event` default is always nil.
|
|
;; `it` is NOT shadowed here — callers (eval-hs-locals) may pre-bind it.
|
|
(list (quote let)
|
|
(list (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)
|
|
;; Also expose bindings on the `window` global so tests that reference
|
|
;; window.X (common in upstream tests) can resolve them.
|
|
(for-each (fn (b) (host-set! (host-global "window") (str (first b)) (nth b 1))) bindings)
|
|
(let ((sx (hs-to-sx (hs-compile src))))
|
|
;; 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
|
|
(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))))))
|
|
|
|
;; Evaluate a HS expression using evalStatically semantics:
|
|
;; only literal values (numbers, strings, booleans, null, time units)
|
|
;; succeed — any other expression raises "cannot be evaluated statically".
|
|
(define hs-eval-statically
|
|
(fn (src)
|
|
(let ((ast (hs-compile src)))
|
|
(if (or (number? ast) (string? ast) (boolean? ast)
|
|
(and (list? ast) (= (first ast) (quote null-literal))))
|
|
(eval-hs src)
|
|
(raise "cannot be evaluated statically")))))
|
|
|
|
;; ── 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)
|
|
(assert (not (dom-has-class? _el-div "foo")))
|
|
(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)
|
|
(assert (not (dom-has-class? _el-form "foo")))
|
|
(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)
|
|
(assert (not (dom-has-class? _el-div "foo--bar")))
|
|
(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)
|
|
(assert= (dom-get-style _el-div "color") "blue")
|
|
(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)
|
|
(assert (not (dom-has-class? _el-div "foo")))
|
|
(assert (not (dom-has-class? _el-div "bar")))
|
|
(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)
|
|
(assert (not (dom-has-attr? _el-div "foo")))
|
|
(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)
|
|
(assert= (dom-get-style _el-div "color") "blue")
|
|
(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)
|
|
(assert (not (dom-has-class? (dom-query-by-id "c1") "foo")))
|
|
(assert (not (dom-has-class? (dom-query-by-id "c2") "foo")))
|
|
(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)
|
|
(assert (not (dom-has-class? (dom-query-by-id "p1") "foo")))
|
|
(assert (not (dom-has-class? (dom-query-by-id "outer") "foo")))
|
|
(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 <p/> 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)
|
|
(assert (not (dom-has-class? (dom-query-by-id "p1") "foo")))
|
|
(assert (not (dom-has-class? (dom-query-by-id "outer") "foo")))
|
|
(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)
|
|
(assert (not (dom-has-class? (dom-query-by-id "bar") "foo")))
|
|
(assert (not (dom-has-class? (dom-query-by-id "trigger") "foo")))
|
|
(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 '<a>New Content</a>' 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)
|
|
(host-set! (host-global "window") "clicks" 0)
|
|
(dom-dispatch (dom-query-by-id "btn1") "click" nil)
|
|
(dom-dispatch _el-div "click" nil)
|
|
(dom-dispatch (dom-query-by-id "btn1") "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 '<span>This is my inner HTML</span>' to me then append '<b>With Tags</b>' 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 <span.topping/> 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 `<button id='b1' _='on click increment window.temp'>Test</button>` 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)
|
|
))
|
|
(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)
|
|
))
|
|
(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)
|
|
))
|
|
(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)
|
|
))
|
|
(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)
|
|
))
|
|
(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)
|
|
))
|
|
(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)
|
|
))
|
|
(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)
|
|
))
|
|
(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)
|
|
))
|
|
(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)
|
|
))
|
|
(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)
|
|
))
|
|
(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)
|
|
))
|
|
(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 <span/>")
|
|
(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)
|
|
))
|
|
(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)
|
|
))
|
|
(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"
|
|
(hs-compile "breakpoint")
|
|
)
|
|
(deftest "parses inside an event handler"
|
|
(hs-compile "on click breakpoint end")
|
|
)
|
|
)
|
|
|
|
;; ── 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!)
|
|
(host-set! (host-global "window") "called" false)
|
|
(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!)
|
|
(host-set! (host-global "window") "called" false)
|
|
(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!)
|
|
(host-set! (host-global "window") "calledWith" null)
|
|
(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!)
|
|
(host-set! (host-global "window") "called" false)
|
|
(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!)
|
|
(host-set! (host-global "window") "global_int" 0)
|
|
(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 catch e 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!)
|
|
(host-set! (host-global "window") "calledWith" nil)
|
|
(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)
|
|
(assert (not (dom-has-attr? _el-div "foo")))
|
|
(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)
|
|
(assert (not (dom-has-class? (dom-query "div:nth-of-type(2)") "clicked")))
|
|
(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)
|
|
(assert (not (dom-has-class? (dom-query-by-id "bar") "foo-sent")))
|
|
(dom-dispatch (nth (dom-query-all (dom-body) "div") 0) "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 (nth (dom-query-all (dom-body) "div") 0) "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)
|
|
(dom-dispatch (nth (dom-query-all (dom-body) ".divs") 1) "click" nil)
|
|
(assert (not (dom-has-class? (nth (dom-query-all (dom-body) ".divs") 0) "foo")))
|
|
(assert (dom-has-class? (nth (dom-query-all (dom-body) ".divs") 1) "foo"))
|
|
(assert (not (dom-has-class? (nth (dom-query-all (dom-body) ".divs") 2) "foo")))
|
|
))
|
|
(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)
|
|
(assert (not (dom-has-class? (dom-query-by-id "bar") "foo")))
|
|
(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)
|
|
(assert= (dom-get-attr _el-div "data-hyperscript-powered") "true")
|
|
))
|
|
(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"))
|
|
(hs-deactivate! _el-div)
|
|
(dom-remove-class _el-div "foo")
|
|
(dom-dispatch _el-div "click" nil)
|
|
(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"
|
|
(hs-cleanup!)
|
|
(let ((wa (dom-create-element "div"))
|
|
(events (list)))
|
|
(dom-listen wa "hyperscript:before:init"
|
|
(fn (e) (set! events (append events (list "before:init")))))
|
|
(dom-listen wa "hyperscript:after:init"
|
|
(fn (e) (set! events (append events (list "after:init")))))
|
|
(dom-set-inner-html wa "<div _=\"on click add .foo\"></div>")
|
|
(hs-boot-subtree! wa)
|
|
(assert= events (list "before:init" "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"
|
|
(hs-cleanup!)
|
|
(let ((wa (dom-create-element "div")))
|
|
(dom-listen wa "hyperscript:before:init"
|
|
(fn (e) (host-call e "preventDefault")))
|
|
(dom-set-inner-html wa "<div _=\"on click add .foo\"></div>")
|
|
(hs-boot-subtree! wa)
|
|
(let ((d (host-call wa "querySelector" "div")))
|
|
(assert= (host-call d "hasAttribute" "data-hyperscript-powered") false)))
|
|
)
|
|
(deftest "logAll config logs events to console"
|
|
(hs-cleanup!)
|
|
(hs-clear-log-captured!)
|
|
(hs-set-log-all! true)
|
|
(let ((wa (dom-create-element "div")))
|
|
(dom-set-inner-html wa "<div _=\"on click add .foo\"></div>")
|
|
(hs-boot-subtree! wa))
|
|
(hs-set-log-all! false)
|
|
(assert= (some (fn (l) (string-contains? l "hyperscript:"))
|
|
(hs-get-log-captured))
|
|
true)
|
|
)
|
|
(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)
|
|
(assert (not (dom-has-class? _el-div "foo")))
|
|
(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-set-attr _el-div "_" "on click add .bar")
|
|
(hs-activate! _el-div)
|
|
(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)
|
|
(assert= (dom-get-attr _el-div "data-hyperscript-powered") "true")
|
|
))
|
|
(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)
|
|
(assert (not (dom-has-class? _el-div "foo")))
|
|
(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"
|
|
(guard (_e (true nil)) (hs-eval-statically "1 + 2") (error "hs-eval-statically did not throw for: 1 + 2"))
|
|
)
|
|
(deftest "throws on symbol references"
|
|
(guard (_e (true nil)) (hs-eval-statically "x") (error "hs-eval-statically did not throw for: x"))
|
|
)
|
|
(deftest "throws on template strings"
|
|
(guard (_e (true nil)) (hs-eval-statically "`hello ${name}`") (error "hs-eval-statically did not throw for: `hello ${name}`"))
|
|
)
|
|
(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 "<span>${}{^msg}</span>")
|
|
(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 "<ul>
|
|
#for item in $idxItems index i
|
|
<li _=\"on click put i + ':' + item into me\">${}{item}</li>
|
|
#end
|
|
</ul>")
|
|
(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 "<ul>
|
|
#for item in $removeItems
|
|
<li><span>${}{item.name}</span><button _=\"on click remove item from $removeItems\">x</button></li>
|
|
#end
|
|
</ul>")
|
|
(dom-append (dom-body) _el-script)
|
|
))
|
|
(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 "<ul>
|
|
#for item in $captureItems index i
|
|
<li _=\"on click put item.name into me\">${}{item.name}</li>
|
|
#end
|
|
</ul>")
|
|
(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 "<span class=\"a\">${}{^x}</span>")
|
|
(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 "<span class=\"b\">${}{^x}</span>")
|
|
(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 "<button _=\"on click increment ^val then put ^val into the next <output/>\">+</button>
|
|
<output>0</output>")
|
|
(dom-append (dom-body) _el-script)
|
|
(hs-activate! _el-script)
|
|
))
|
|
(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 "<button _=\"on click increment ^count\">+</button>
|
|
<span>Count: ${}{^count}</span>")
|
|
(dom-append (dom-body) _el-script)
|
|
(hs-activate! _el-script)
|
|
))
|
|
(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 "<p>Hello, ${}{$ltGlobal}!</p>")
|
|
(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 "<span>Hello World</span>")
|
|
(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 "<span>Hello ${}{$ltName}!</span>")
|
|
(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 "<ul>
|
|
#for item in $morphItems index i
|
|
<li _=\"on click put i + ':' + item.name into me\">${}{item.name}</li>
|
|
#end
|
|
</ul>")
|
|
(dom-append (dom-body) _el-script)
|
|
))
|
|
(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 "<span>${}{^stMsg}</span>")
|
|
(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 "<ul>
|
|
#for item in ^items
|
|
<li class=\"${}{'done' if item.done}\" data-text=\"${}{item.text}\">
|
|
<input type=\"checkbox\" ${}{'checked' if item.done}>
|
|
<span>${}{item.text}</span>
|
|
</li>
|
|
#end
|
|
</ul>")
|
|
(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 "<ul>
|
|
#for item in ^items
|
|
<li>${}{item}</li>
|
|
#end
|
|
</ul>")
|
|
(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
|
|
<span>visible</span>
|
|
#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 "<span>test</span>")
|
|
(dom-append (dom-body) _el-script)
|
|
))
|
|
)
|
|
|
|
;; ── core/parser (14 tests) ──
|
|
(defsuite "hs-upstream-core/parser"
|
|
(deftest "_hyperscript() evaluate API still throws on first error"
|
|
(assert-throws (fn () (eval-hs "add - to")))
|
|
)
|
|
(deftest "basic parse error messages work"
|
|
(assert-throws (fn () (eval-hs "add - to")))
|
|
)
|
|
(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")
|
|
(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")
|
|
(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")
|
|
(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)
|
|
))
|
|
(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 <button/> in me set it @disabled to true")
|
|
(dom-set-attr _el-b1 "id" "b1")
|
|
(dom-set-inner-html _el-b1 "Button")
|
|
(dom-append (dom-body) _el-form)
|
|
(dom-append _el-form _el-b1)
|
|
(hs-activate! _el-form)
|
|
(dom-dispatch _el-form "click" nil)
|
|
))
|
|
(deftest "can create a paragraph tag"
|
|
(hs-cleanup!)
|
|
(let ((_el-i1 (dom-create-element "input")) (_el-d2 (dom-create-element "div")) (_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-i1 "id" "i1")
|
|
(dom-set-attr _el-i1 "value" "foo")
|
|
(dom-set-attr _el-d2 "id" "d2")
|
|
(dom-set-attr _el-div "_" "on click make a <p/> then put #i1.value into its textContent put it.outerHTML at end of #d2")
|
|
(dom-append (dom-body) _el-i1)
|
|
(dom-append (dom-body) _el-d2)
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
(dom-dispatch (dom-query "div:nth-of-type(2)") "click" nil)
|
|
))
|
|
(deftest "can invoke functions w/ numbers in name"
|
|
(hs-cleanup!)
|
|
(host-set! (host-global "window") "select2" (fn () "select2"))
|
|
(let ((_el-button (dom-create-element "button")))
|
|
(dom-set-attr _el-button "_" "on click put select2() into me")
|
|
(dom-append (dom-body) _el-button)
|
|
(hs-activate! _el-button)
|
|
(dom-dispatch _el-button "click" nil)
|
|
(assert= (dom-text-content _el-button) "select2")
|
|
))
|
|
(deftest "can pick detail fields out by name"
|
|
(hs-cleanup!)
|
|
(let ((_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 send custom(foo:\"fromBar\") to #d2")
|
|
(dom-set-attr _el-d2 "id" "d2")
|
|
(dom-set-attr _el-d2 "_" "on custom(foo) call me.classList.add(foo)")
|
|
(dom-append (dom-body) _el-d1)
|
|
(dom-append (dom-body) _el-d2)
|
|
(hs-activate! _el-d1)
|
|
(hs-activate! _el-d2)
|
|
(assert (not (dom-has-class? _el-d2 "fromBar")))
|
|
(dom-dispatch _el-d1 "click" nil)
|
|
(assert (dom-has-class? _el-d2 "fromBar")))
|
|
)
|
|
(deftest "can refer to function in init blocks"
|
|
(hs-cleanup!)
|
|
(let ((_el-d1 (dom-create-element "div")))
|
|
(dom-set-attr _el-d1 "id" "d1")
|
|
(dom-append (dom-body) _el-d1)
|
|
(guard (_e (true nil)) (eval-expr-cek (hs-to-sx (hs-compile "init call foo() end def foo() put \"here\" into #d1's innerHTML end"))))
|
|
(assert= (dom-text-content (dom-query-by-id "d1")) "here"))
|
|
)
|
|
(deftest "can remove by clicks elsewhere"
|
|
(hs-cleanup!)
|
|
(let ((_el-target (dom-create-element "div")) (_el-other (dom-create-element "div")))
|
|
(dom-set-attr _el-target "id" "target")
|
|
(dom-set-attr _el-target "_" "on click elsewhere remove me")
|
|
(dom-set-attr _el-other "id" "other")
|
|
(dom-append (dom-body) _el-target)
|
|
(dom-append (dom-body) _el-other)
|
|
(hs-activate! _el-target)
|
|
(dom-dispatch (dom-query-by-id "other") "click" nil)
|
|
))
|
|
(deftest "can remove class by id"
|
|
(hs-cleanup!)
|
|
(let ((_el-email-form (dom-create-element "form")) (_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-email-form "id" "email-form")
|
|
(dom-add-class _el-email-form "hideme")
|
|
(dom-set-attr _el-div "_" "on click remove .hideme from #email-form")
|
|
(dom-append (dom-body) _el-email-form)
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
(assert (dom-has-class? (dom-query-by-id "email-form") "hideme"))
|
|
(dom-dispatch _el-div "click" nil)
|
|
(assert (not (dom-has-class? (dom-query-by-id "email-form") "hideme")))
|
|
))
|
|
(deftest "can trigger htmx events"
|
|
(hs-cleanup!)
|
|
(let ((_el-div1 (dom-create-element "div")) (_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div1 "id" "div1")
|
|
(dom-set-attr _el-div1 "_" "on htmx:foo put \"foo\" into my.innerHTML")
|
|
(dom-set-attr _el-div "_" "on click send htmx:foo to #div1")
|
|
(dom-append (dom-body) _el-div1)
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div1)
|
|
(hs-activate! _el-div)
|
|
(dom-dispatch (dom-query "div:nth-of-type(2)") "click" nil)
|
|
(assert= (dom-text-content (dom-query-by-id "div1")) "foo")
|
|
))
|
|
(deftest "extra chars cause error when evaling"
|
|
(assert-throws (fn () (eval-hs "1!")))
|
|
)
|
|
(deftest "listen for event on form"
|
|
(hs-cleanup!)
|
|
(let ((_el-form (dom-create-element "form")) (_el-b1 (dom-create-element "button")))
|
|
(dom-set-attr _el-b1 "id" "b1")
|
|
(dom-set-attr _el-b1 "_" "on click from closest <form/> put \"clicked\" into me")
|
|
(dom-set-inner-html _el-b1 "Button")
|
|
(dom-append (dom-body) _el-form)
|
|
(dom-append _el-form _el-b1)
|
|
(hs-activate! _el-b1)
|
|
(dom-dispatch _el-form "click" nil)
|
|
(assert= (dom-text-content (dom-query-by-id "b1")) "clicked")
|
|
))
|
|
(deftest "me and it is properly set when responding to events"
|
|
(hs-cleanup!)
|
|
(let ((_el-name (dom-create-element "div")) (_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-name "id" "name")
|
|
(dom-set-attr _el-div "_" "on click from #name set window.me to me set window.it to it")
|
|
(dom-append (dom-body) _el-name)
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
(dom-dispatch (dom-query-by-id "name") "click" nil)
|
|
))
|
|
(deftest "me symbol works in from expressions"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")) (_el-d1 (dom-create-element "div")))
|
|
(dom-set-attr _el-d1 "id" "d1")
|
|
(dom-set-attr _el-d1 "_" "on click from closest parent <div/> put \"Foo\" into me")
|
|
(dom-append (dom-body) _el-div)
|
|
(dom-append _el-div _el-d1)
|
|
(hs-activate! _el-d1)
|
|
(assert= (dom-text-content (dom-query-by-id "d1")) "")
|
|
(dom-dispatch (nth (dom-query-all (dom-body) "div") 0) "click" nil)
|
|
(assert= (dom-text-content (dom-query-by-id "d1")) "Foo")
|
|
))
|
|
(deftest "properly interpolates values"
|
|
(hs-cleanup!)
|
|
(let ((_el-button (dom-create-element "button")))
|
|
(dom-set-attr _el-button "_" "on click set count to 1 then set optName to `options_${count}_value` then put optName into me")
|
|
(dom-append (dom-body) _el-button)
|
|
(hs-activate! _el-button)
|
|
(dom-dispatch _el-button "click" nil)
|
|
(assert= (dom-text-content _el-button) "options_1_value")
|
|
))
|
|
(deftest "properly interpolates values 2"
|
|
(hs-cleanup!)
|
|
(let ((_el-button (dom-create-element "button")))
|
|
(dom-set-attr _el-button "_" "on click set trackingcode to `AB123456789KK` then set pdfurl to `https://yyy.xxxxxx.com/path/out/${trackingcode}.pdf` then put pdfurl into me")
|
|
(dom-append (dom-body) _el-button)
|
|
(hs-activate! _el-button)
|
|
(dom-dispatch _el-button "click" nil)
|
|
(assert= (dom-text-content _el-button) "https://yyy.xxxxxx.com/path/out/AB123456789KK.pdf")
|
|
))
|
|
(deftest "string literals can dot-invoked against"
|
|
(assert= (eval-hs "'foo'.length") 3)
|
|
(assert= (eval-hs "`foo`.length") 3)
|
|
(assert= (eval-hs "\"foo\".length") 3)
|
|
)
|
|
)
|
|
|
|
;; ── core/runtime (7 tests) ──
|
|
(defsuite "hs-upstream-core/runtime"
|
|
(deftest "arrays args are handled properly wrt Promises"
|
|
(hs-cleanup!)
|
|
(guard (_e (true nil)) (eval-expr-cek (hs-to-sx (hs-compile "def invokesArrayPromise() return { foo: stringPromise(), bar: stringPromise(), baz: stringPromise() }end def stringPromise() wait 20ms return 'foo' end"))))
|
|
)
|
|
(deftest "async hypertrace is reasonable"
|
|
(hs-cleanup!)
|
|
(guard (_e (true nil)) (eval-expr-cek (hs-to-sx (hs-compile "def bar() call baz('nope') end def baz(str) wait 20ms throw str end"))))
|
|
(guard (_e (true nil)) (eval-expr-cek (hs-to-sx (hs-compile "def bar() call baz('nope') end def baz(str) wait 20ms throw str end"))))
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click call bar()")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
(dom-dispatch _el-div "click" nil)
|
|
))
|
|
(deftest "has proper stack"
|
|
(hs-cleanup!)
|
|
(guard (_e (true nil)) (eval-expr-cek (hs-to-sx (hs-compile "def foo() return bar() end def bar() return meta.caller end"))))
|
|
)
|
|
(deftest "has proper stack from event handler"
|
|
(hs-cleanup!)
|
|
(guard (_e (true nil)) (eval-expr-cek (hs-to-sx (hs-compile "def bar() log meta.caller return meta.caller end"))))
|
|
(guard (_e (true nil)) (eval-expr-cek (hs-to-sx (hs-compile "def bar() log meta.caller return meta.caller end"))))
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click put bar().meta.feature.type 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) "onFeature")
|
|
))
|
|
(deftest "hypertrace from javascript is reasonable"
|
|
(hs-cleanup!)
|
|
(guard (_e (true nil)) (eval-expr-cek (hs-to-sx (hs-compile "def bar() call baz('nope') end"))))
|
|
(guard (_e (true nil)) (eval-expr-cek (hs-to-sx (hs-compile "def bar() call baz('nope') end"))))
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click call bar()")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
(dom-dispatch _el-div "click" nil)
|
|
))
|
|
(deftest "hypertrace is reasonable"
|
|
(hs-cleanup!)
|
|
(guard (_e (true nil)) (eval-expr-cek (hs-to-sx (hs-compile "def bar() call baz('nope') end def baz(str) throw str end"))))
|
|
(guard (_e (true nil)) (eval-expr-cek (hs-to-sx (hs-compile "def bar() call baz('nope') end def baz(str) throw str end"))))
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click call bar()")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
(dom-dispatch _el-div "click" nil)
|
|
))
|
|
(deftest "scalar args are handled properly wrt Promises"
|
|
(hs-cleanup!)
|
|
(guard (_e (true nil)) (eval-expr-cek (hs-to-sx (hs-compile "def invokesScalarPromise() return stringPromise()end def stringPromise() wait 20ms return 'foo' end"))))
|
|
)
|
|
)
|
|
|
|
;; ── core/runtimeErrors (18 tests) ──
|
|
(defsuite "hs-upstream-core/runtimeErrors"
|
|
(deftest "reports basic function invocation null errors properly"
|
|
(hs-cleanup!)
|
|
(assert= (eval-hs-error "x()") "'x' is null")
|
|
(assert= (eval-hs-error "x.y()") "'x' is null")
|
|
(assert= (eval-hs-error "x.y.z()") "'x.y' is null"))
|
|
(deftest "reports basic function invocation null errors properly w/ of"
|
|
(hs-cleanup!)
|
|
(assert= (eval-hs-error "z() of y of x") "'z' is null"))
|
|
(deftest "reports basic function invocation null errors properly w/ possessives"
|
|
(hs-cleanup!)
|
|
(assert= (eval-hs-error "x's y()") "'x' is null")
|
|
(assert= (eval-hs-error "x's y's z()") "'x's y' is null"))
|
|
(deftest "reports null errors on add command properly"
|
|
(hs-cleanup!)
|
|
(assert= (eval-hs-error "add .foo to #doesntExist") "'#doesntExist' is null")
|
|
(assert= (eval-hs-error "add @foo to #doesntExist") "'#doesntExist' is null")
|
|
(assert= (eval-hs-error "add {display:none} to #doesntExist") "'#doesntExist' is null"))
|
|
(deftest "reports null errors on decrement command properly"
|
|
(hs-cleanup!)
|
|
(assert= (eval-hs-error "decrement #doesntExist's innerHTML") "'#doesntExist' is null"))
|
|
(deftest "reports null errors on default command properly"
|
|
(hs-cleanup!)
|
|
(assert= (eval-hs-error "default #doesntExist's innerHTML to 'foo'") "'#doesntExist' is null"))
|
|
(deftest "reports null errors on hide command properly"
|
|
(hs-cleanup!)
|
|
(assert= (eval-hs-error "hide #doesntExist") "'#doesntExist' is null"))
|
|
(deftest "reports null errors on increment command properly"
|
|
(hs-cleanup!)
|
|
(assert= (eval-hs-error "increment #doesntExist's innerHTML") "'#doesntExist' is null"))
|
|
(deftest "reports null errors on measure command properly"
|
|
(hs-cleanup!)
|
|
(assert= (eval-hs-error "measure #doesntExist") "'#doesntExist' is null"))
|
|
(deftest "reports null errors on put command properly"
|
|
(hs-cleanup!)
|
|
(assert= (eval-hs-error "put 'foo' into #doesntExist") "'#doesntExist' is null")
|
|
(assert= (eval-hs-error "put 'foo' into #doesntExist's innerHTML") "'#doesntExist' is null")
|
|
(assert= (eval-hs-error "put 'foo' into #doesntExist.innerHTML") "'#doesntExist' is null")
|
|
(assert= (eval-hs-error "put 'foo' before #doesntExist") "'#doesntExist' is null")
|
|
(assert= (eval-hs-error "put 'foo' after #doesntExist") "'#doesntExist' is null")
|
|
(assert= (eval-hs-error "put 'foo' at the start of #doesntExist") "'#doesntExist' is null")
|
|
(assert= (eval-hs-error "put 'foo' at the end of #doesntExist") "'#doesntExist' is null"))
|
|
(deftest "reports null errors on remove command properly"
|
|
(hs-cleanup!)
|
|
(assert= (eval-hs-error "remove .foo from #doesntExist") "'#doesntExist' is null")
|
|
(assert= (eval-hs-error "remove @foo from #doesntExist") "'#doesntExist' is null")
|
|
(assert= (eval-hs-error "remove #doesntExist from #doesntExist") "'#doesntExist' is null"))
|
|
(deftest "reports null errors on send command properly"
|
|
(hs-cleanup!)
|
|
(assert= (eval-hs-error "send 'foo' to #doesntExist") "'#doesntExist' is null"))
|
|
(deftest "reports null errors on sets properly"
|
|
(hs-cleanup!)
|
|
(assert= (eval-hs-error "set x's y to true") "'x' is null")
|
|
(assert= (eval-hs-error "set x's @y to true") "'x' is null"))
|
|
(deftest "reports null errors on settle command properly"
|
|
(hs-cleanup!)
|
|
(assert= (eval-hs-error "settle #doesntExist") "'#doesntExist' is null"))
|
|
(deftest "reports null errors on show command properly"
|
|
(hs-cleanup!)
|
|
(assert= (eval-hs-error "show #doesntExist") "'#doesntExist' is null"))
|
|
(deftest "reports null errors on toggle command properly"
|
|
(hs-cleanup!)
|
|
(assert= (eval-hs-error "toggle .foo on #doesntExist") "'#doesntExist' is null")
|
|
(assert= (eval-hs-error "toggle between .foo and .bar on #doesntExist") "'#doesntExist' is null")
|
|
(assert= (eval-hs-error "toggle @foo on #doesntExist") "'#doesntExist' is null"))
|
|
(deftest "reports null errors on transition command properly"
|
|
(hs-cleanup!)
|
|
(assert= (eval-hs-error "transition #doesntExist's *visibility to 0") "'#doesntExist' is null"))
|
|
(deftest "reports null errors on trigger command properly"
|
|
(hs-cleanup!)
|
|
(assert= (eval-hs-error "trigger 'foo' on #doesntExist") "'#doesntExist' is null"))
|
|
)
|
|
|
|
;; ── core/scoping (20 tests) ──
|
|
(defsuite "hs-upstream-core/scoping"
|
|
(deftest "basic behavior scoping works"
|
|
(hs-cleanup!)
|
|
(let ((_el-script (dom-create-element "script")) (_el-d1 (dom-create-element "div")))
|
|
(dom-set-attr _el-script "type" "text/hyperscript")
|
|
(dom-set-inner-html _el-script "behavior Behave(foo) on click set @out to foo")
|
|
(dom-set-attr _el-d1 "id" "d1")
|
|
(dom-set-attr _el-d1 "_" "install Behave(foo:10)")
|
|
(dom-append (dom-body) _el-script)
|
|
(dom-append (dom-body) _el-d1)
|
|
(hs-activate! _el-d1)
|
|
(dom-dispatch (dom-query-by-id "d1") "click" nil)
|
|
(assert= (dom-get-attr (dom-query-by-id "d1") "out") "10")
|
|
))
|
|
(deftest "behavior scoping is at the element level"
|
|
(hs-cleanup!)
|
|
(let ((_el-script (dom-create-element "script")) (_el-d1 (dom-create-element "div")))
|
|
(dom-set-attr _el-script "type" "text/hyperscript")
|
|
(dom-set-inner-html _el-script "behavior Behave(foo) on click 1 set foo to foo + 10 on click 2 set @out to foo")
|
|
(dom-set-attr _el-d1 "id" "d1")
|
|
(dom-set-attr _el-d1 "_" "install Behave(foo:10)")
|
|
(dom-append (dom-body) _el-script)
|
|
(dom-append (dom-body) _el-d1)
|
|
(hs-activate! _el-d1)
|
|
(dom-dispatch (dom-query-by-id "d1") "click" nil)
|
|
(dom-dispatch (dom-query-by-id "d1") "click" nil)
|
|
(assert= (dom-get-attr (dom-query-by-id "d1") "out") "20")
|
|
))
|
|
(deftest "behavior scoping is isolated from other behaviors"
|
|
(hs-cleanup!)
|
|
(let ((_el-script (dom-create-element "script")) (_el-d1 (dom-create-element "div")))
|
|
(dom-set-attr _el-script "type" "text/hyperscript")
|
|
(dom-set-inner-html _el-script "behavior Behave(foo) on click 1 set foo to foo + 10 on click 3 set @out to foo behavior BehaveTwo(foo) on click 2 set element foo to 1 on click 4 set @out2 to foo")
|
|
(dom-set-attr _el-d1 "id" "d1")
|
|
(dom-set-attr _el-d1 "_" "install Behave(foo:10) install BehaveTwo(foo:42)")
|
|
(dom-append (dom-body) _el-script)
|
|
(dom-append (dom-body) _el-d1)
|
|
(hs-activate! _el-d1)
|
|
(dom-dispatch (dom-query-by-id "d1") "click" nil)
|
|
(dom-dispatch (dom-query-by-id "d1") "click" nil)
|
|
(dom-dispatch (dom-query-by-id "d1") "click" nil)
|
|
(dom-dispatch (dom-query-by-id "d1") "click" nil)
|
|
(assert= (dom-get-attr (dom-query-by-id "d1") "out") "20")
|
|
(assert= (dom-get-attr (dom-query-by-id "d1") "out2") "1")
|
|
))
|
|
(deftest "behavior scoping is isolated from the core element scope"
|
|
(hs-cleanup!)
|
|
(let ((_el-script (dom-create-element "script")) (_el-d1 (dom-create-element "div")))
|
|
(dom-set-attr _el-script "type" "text/hyperscript")
|
|
(dom-set-inner-html _el-script "behavior Behave(foo) on click 1 set foo to foo + 10 on click 3 set @out to foo")
|
|
(dom-set-attr _el-d1 "id" "d1")
|
|
(dom-set-attr _el-d1 "_" "install Behave(foo:10) on click 2 set element foo to 1 on click 4 set @out2 to foo")
|
|
(dom-append (dom-body) _el-script)
|
|
(dom-append (dom-body) _el-d1)
|
|
(hs-activate! _el-d1)
|
|
(dom-dispatch (dom-query-by-id "d1") "click" nil)
|
|
(dom-dispatch (dom-query-by-id "d1") "click" nil)
|
|
(dom-dispatch (dom-query-by-id "d1") "click" nil)
|
|
(dom-dispatch (dom-query-by-id "d1") "click" nil)
|
|
(assert= (dom-get-attr (dom-query-by-id "d1") "out") "20")
|
|
(assert= (dom-get-attr (dom-query-by-id "d1") "out2") "1")
|
|
))
|
|
(deftest "element scoped variables are local only to element"
|
|
(hs-cleanup!)
|
|
(let ((_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 set element x to 10")
|
|
(dom-set-attr _el-d2 "id" "d2")
|
|
(dom-set-attr _el-d2 "_" "on click set @out to x")
|
|
(dom-append (dom-body) _el-d1)
|
|
(dom-append _el-d1 _el-d2)
|
|
(hs-activate! _el-d1)
|
|
(hs-activate! _el-d2)
|
|
(dom-dispatch (dom-query-by-id "d1") "click" nil)
|
|
(dom-dispatch (dom-query-by-id "d2") "click" nil)
|
|
))
|
|
(deftest "element scoped variables span features"
|
|
(hs-cleanup!)
|
|
(let ((_el-d1 (dom-create-element "div")))
|
|
(dom-set-attr _el-d1 "id" "d1")
|
|
(dom-set-attr _el-d1 "_" "on click 1 set element x to 10 on click 2 set @out to x")
|
|
(dom-append (dom-body) _el-d1)
|
|
(hs-activate! _el-d1)
|
|
(dom-dispatch (dom-query-by-id "d1") "click" nil)
|
|
(dom-dispatch (dom-query-by-id "d1") "click" nil)
|
|
(assert= (dom-get-attr (dom-query-by-id "d1") "out") "10")
|
|
))
|
|
(deftest "element scoped variables span features w/short syntax"
|
|
(hs-cleanup!)
|
|
(let ((_el-d1 (dom-create-element "div")))
|
|
(dom-set-attr _el-d1 "id" "d1")
|
|
(dom-set-attr _el-d1 "_" "on click 1 set :x to 10 on click 2 set @out to :x")
|
|
(dom-append (dom-body) _el-d1)
|
|
(hs-activate! _el-d1)
|
|
(dom-dispatch (dom-query-by-id "d1") "click" nil)
|
|
(dom-dispatch (dom-query-by-id "d1") "click" nil)
|
|
(assert= (dom-get-attr (dom-query-by-id "d1") "out") "10")
|
|
))
|
|
(deftest "element scoped variables support pseudo-possessive syntax"
|
|
(hs-cleanup!)
|
|
(let ((_el-d1 (dom-create-element "div")))
|
|
(dom-set-attr _el-d1 "id" "d1")
|
|
(dom-set-attr _el-d1 "_" "on click set the element's x to 10 then set @out to the element's x")
|
|
(dom-append (dom-body) _el-d1)
|
|
(hs-activate! _el-d1)
|
|
(dom-dispatch (dom-query-by-id "d1") "click" nil)
|
|
(assert= (dom-get-attr (dom-query-by-id "d1") "out") "10")
|
|
))
|
|
(deftest "element scoped variables work"
|
|
(hs-cleanup!)
|
|
(let ((_el-d1 (dom-create-element "div")))
|
|
(dom-set-attr _el-d1 "id" "d1")
|
|
(dom-set-attr _el-d1 "_" "on click set element x to 10 then set @out to x")
|
|
(dom-append (dom-body) _el-d1)
|
|
(hs-activate! _el-d1)
|
|
(dom-dispatch (dom-query-by-id "d1") "click" nil)
|
|
(assert= (dom-get-attr (dom-query-by-id "d1") "out") "10")
|
|
))
|
|
(deftest "element scoped variables work w/short syntax"
|
|
(hs-cleanup!)
|
|
(let ((_el-d1 (dom-create-element "div")))
|
|
(dom-set-attr _el-d1 "id" "d1")
|
|
(dom-set-attr _el-d1 "_" "on click set :x to 10 then set @out to :x")
|
|
(dom-append (dom-body) _el-d1)
|
|
(hs-activate! _el-d1)
|
|
(dom-dispatch (dom-query-by-id "d1") "click" nil)
|
|
(assert= (dom-get-attr (dom-query-by-id "d1") "out") "10")
|
|
))
|
|
(deftest "global scoped variables span features"
|
|
(hs-cleanup!)
|
|
(let ((_el-d1 (dom-create-element "div")))
|
|
(dom-set-attr _el-d1 "id" "d1")
|
|
(dom-set-attr _el-d1 "_" "on click 1 set $x to 10 on click 2 set @out to $x")
|
|
(dom-append (dom-body) _el-d1)
|
|
(hs-activate! _el-d1)
|
|
(dom-dispatch (dom-query-by-id "d1") "click" nil)
|
|
(dom-dispatch (dom-query-by-id "d1") "click" nil)
|
|
(assert= (dom-get-attr (dom-query-by-id "d1") "out") "10")
|
|
))
|
|
(deftest "global scoped variables work"
|
|
(hs-cleanup!)
|
|
(let ((_el-d1 (dom-create-element "div")))
|
|
(dom-set-attr _el-d1 "id" "d1")
|
|
(dom-set-attr _el-d1 "_" "on click set global x to 10 then set @out to x")
|
|
(dom-append (dom-body) _el-d1)
|
|
(hs-activate! _el-d1)
|
|
(dom-dispatch (dom-query-by-id "d1") "click" nil)
|
|
(assert= (dom-get-attr (dom-query-by-id "d1") "out") "10")
|
|
))
|
|
(deftest "global scoped variables work w/ short syntax"
|
|
(hs-cleanup!)
|
|
(let ((_el-d1 (dom-create-element "div")))
|
|
(dom-set-attr _el-d1 "id" "d1")
|
|
(dom-set-attr _el-d1 "_" "on click set $x to 10 then set @out to $x")
|
|
(dom-append (dom-body) _el-d1)
|
|
(hs-activate! _el-d1)
|
|
(dom-dispatch (dom-query-by-id "d1") "click" nil)
|
|
(assert= (dom-get-attr (dom-query-by-id "d1") "out") "10")
|
|
))
|
|
(deftest "locally scoped variables do not span features"
|
|
(hs-cleanup!)
|
|
(let ((_el-d1 (dom-create-element "div")))
|
|
(dom-set-attr _el-d1 "id" "d1")
|
|
(dom-set-attr _el-d1 "_" "on click 1 set x to 10 on click 2 set @out to x")
|
|
(dom-append (dom-body) _el-d1)
|
|
(hs-activate! _el-d1)
|
|
(dom-dispatch (dom-query-by-id "d1") "click" nil)
|
|
(dom-dispatch (dom-query-by-id "d1") "click" nil)
|
|
))
|
|
(deftest "locally scoped variables don't clash with built-in variables"
|
|
(hs-cleanup!)
|
|
(let ((_el-d1 (dom-create-element "div")))
|
|
(dom-set-attr _el-d1 "id" "d1")
|
|
(dom-set-attr _el-d1 "_" "on click repeat for meta in [1, 2, 3] set @out to meta end")
|
|
(dom-append (dom-body) _el-d1)
|
|
(hs-activate! _el-d1)
|
|
(dom-dispatch (dom-query-by-id "d1") "click" nil)
|
|
(assert= (dom-get-attr (dom-query-by-id "d1") "out") "[object Object]")
|
|
))
|
|
(deftest "locally scoped variables work"
|
|
(hs-cleanup!)
|
|
(let ((_el-d1 (dom-create-element "div")))
|
|
(dom-set-attr _el-d1 "id" "d1")
|
|
(dom-set-attr _el-d1 "_" "on click set x to 10 then set @out to x")
|
|
(dom-append (dom-body) _el-d1)
|
|
(hs-activate! _el-d1)
|
|
(dom-dispatch (dom-query-by-id "d1") "click" nil)
|
|
(assert= (dom-get-attr (dom-query-by-id "d1") "out") "10")
|
|
))
|
|
(deftest "set favors local variables over global variables"
|
|
(hs-cleanup!)
|
|
(host-set! (host-global "window") "foo" 12)
|
|
(let ((_el-d1 (dom-create-element "div")))
|
|
(dom-set-attr _el-d1 "id" "d1")
|
|
(dom-set-attr _el-d1 "_" "on click 1 set foo to 20 then set @out to foo")
|
|
(dom-append (dom-body) _el-d1)
|
|
(hs-activate! _el-d1)
|
|
(dom-dispatch (dom-query-by-id "d1") "click" nil)
|
|
(assert= (dom-get-attr (dom-query-by-id "d1") "out") "20")
|
|
))
|
|
(deftest "setting a global scoped variable spans features"
|
|
(hs-cleanup!)
|
|
(let ((_el-d1 (dom-create-element "div")))
|
|
(dom-set-attr _el-d1 "id" "d1")
|
|
(dom-set-attr _el-d1 "_" "on click 1 default global x to 0 on click 2 set global x to 10 on click 3 set @out to x")
|
|
(dom-append (dom-body) _el-d1)
|
|
(hs-activate! _el-d1)
|
|
(dom-dispatch (dom-query-by-id "d1") "click" nil)
|
|
(dom-dispatch (dom-query-by-id "d1") "click" nil)
|
|
(dom-dispatch (dom-query-by-id "d1") "click" nil)
|
|
(assert= (dom-get-attr (dom-query-by-id "d1") "out") "10")
|
|
))
|
|
(deftest "setting an element scoped variable spans features"
|
|
(hs-cleanup!)
|
|
(let ((_el-d1 (dom-create-element "div")))
|
|
(dom-set-attr _el-d1 "id" "d1")
|
|
(dom-set-attr _el-d1 "_" "on click 1 default element x to 0 on click 2 set element x to 10 on click 3 set @out to x")
|
|
(dom-append (dom-body) _el-d1)
|
|
(hs-activate! _el-d1)
|
|
(dom-dispatch (dom-query-by-id "d1") "click" nil)
|
|
(dom-dispatch (dom-query-by-id "d1") "click" nil)
|
|
(dom-dispatch (dom-query-by-id "d1") "click" nil)
|
|
(assert= (dom-get-attr (dom-query-by-id "d1") "out") "10")
|
|
))
|
|
(deftest "variables are hoisted"
|
|
(hs-cleanup!)
|
|
(let ((_el-d1 (dom-create-element "div")))
|
|
(dom-set-attr _el-d1 "id" "d1")
|
|
(dom-set-attr _el-d1 "_" "on click if true set foo to 10 end set @out to foo")
|
|
(dom-append (dom-body) _el-d1)
|
|
(hs-activate! _el-d1)
|
|
(dom-dispatch (dom-query-by-id "d1") "click" nil)
|
|
(assert= (dom-get-attr (dom-query-by-id "d1") "out") "10")
|
|
))
|
|
)
|
|
|
|
;; ── core/security (1 tests) ──
|
|
(defsuite "hs-upstream-core/security"
|
|
(deftest "on a single div"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")) (_el-d1 (dom-create-element "div")))
|
|
(dom-set-attr _el-d1 "id" "d1")
|
|
(dom-set-attr _el-d1 "_" "on click add .foo")
|
|
(dom-append (dom-body) _el-div)
|
|
(dom-append _el-div _el-d1)
|
|
(hs-activate! _el-d1)
|
|
(dom-dispatch (dom-query-by-id "d1") "click" nil)
|
|
(assert (not (dom-has-class? (dom-query-by-id "d1") "foo")))
|
|
))
|
|
)
|
|
|
|
;; ── core/sourceInfo (4 tests) ──
|
|
(defsuite "hs-upstream-core/sourceInfo"
|
|
(deftest "debug"
|
|
(assert= (hs-src "<button.foo/>") "<button.foo/>"))
|
|
(deftest "get line works for statements"
|
|
(assert= (hs-line-at "if true\n log 'it was true'\n log 'it was true'" (list)) "if true")
|
|
(assert= (hs-line-at "if true\n log 'it was true'\n log 'it was true'" (list :true-branch)) " log 'it was true'")
|
|
(assert= (hs-line-at "if true\n log 'it was true'\n log 'it was true'" (list :true-branch :next)) " log 'it was true'"))
|
|
(deftest "get source works for expressions"
|
|
(assert= (hs-src "1") "1")
|
|
(assert= (hs-src "a.b") "a.b")
|
|
(assert= (hs-src-at "a.b" (list :root)) "a")
|
|
(assert= (hs-src "a.b()") "a.b()")
|
|
(assert= (hs-src-at "a.b()" (list :root)) "a.b")
|
|
(assert= (hs-src-at "a.b()" (list :root :root)) "a")
|
|
(assert= (hs-src "<button.foo/>") "<button.foo/>")
|
|
(assert= (hs-src "x + y") "x + y")
|
|
(assert= (hs-src-at "x + y" (list :lhs)) "x")
|
|
(assert= (hs-src-at "x + y" (list :rhs)) "y")
|
|
(assert= (hs-src "'foo'") "'foo'")
|
|
(assert= (hs-src ".foo") ".foo")
|
|
(assert= (hs-src "#bar") "#bar"))
|
|
(deftest "get source works for statements"
|
|
(assert= (hs-src "if true log 'it was true'") "if true log 'it was true'")
|
|
(assert= (hs-src "for x in [1, 2, 3] log x then log x end") "for x in [1, 2, 3] log x then log x end"))
|
|
)
|
|
|
|
;; ── core/tokenizer (17 tests) ──
|
|
(defsuite "hs-upstream-core/tokenizer"
|
|
(deftest "handles $ in template properly"
|
|
(assert= (hs-token-value (hs-stream-token (hs-tokens-of "\"" :template) 0)) "\"")
|
|
)
|
|
(deftest "handles all special escapes properly"
|
|
(assert= (hs-token-value (hs-stream-consume (hs-tokens-of "\"\\b\""))) (char-from-code 8))
|
|
(assert= (hs-token-value (hs-stream-consume (hs-tokens-of "\"\\f\""))) (char-from-code 12))
|
|
(assert= (hs-token-value (hs-stream-consume (hs-tokens-of "\"\\n\""))) "\n")
|
|
(assert= (hs-token-value (hs-stream-consume (hs-tokens-of "\"\\r\""))) "\r")
|
|
(assert= (hs-token-value (hs-stream-consume (hs-tokens-of "\"\\t\""))) "\t")
|
|
(assert= (hs-token-value (hs-stream-consume (hs-tokens-of "\"\\v\""))) (char-from-code 11))
|
|
)
|
|
(deftest "handles basic token types"
|
|
(assert= (hs-token-type (hs-stream-consume (hs-tokens-of "foo"))) "IDENTIFIER")
|
|
(assert= (hs-token-type (hs-stream-consume (hs-tokens-of "1"))) "NUMBER")
|
|
(let ((s (hs-tokens-of "1.1")))
|
|
(let ((tok (hs-stream-consume s)))
|
|
(assert= (hs-token-type tok) "NUMBER")
|
|
(assert= (hs-stream-has-more s) false)))
|
|
(let ((s (hs-tokens-of "1e6")))
|
|
(let ((tok (hs-stream-consume s)))
|
|
(assert= (hs-token-type tok) "NUMBER")
|
|
(assert= (hs-stream-has-more s) false)))
|
|
(let ((s (hs-tokens-of "1e-6")))
|
|
(let ((tok (hs-stream-consume s)))
|
|
(assert= (hs-token-type tok) "NUMBER")
|
|
(assert= (hs-stream-has-more s) false)))
|
|
(let ((s (hs-tokens-of "1.1e6")))
|
|
(let ((tok (hs-stream-consume s)))
|
|
(assert= (hs-token-type tok) "NUMBER")
|
|
(assert= (hs-stream-has-more s) false)))
|
|
(let ((s (hs-tokens-of "1.1e-6")))
|
|
(let ((tok (hs-stream-consume s)))
|
|
(assert= (hs-token-type tok) "NUMBER")
|
|
(assert= (hs-stream-has-more s) false)))
|
|
(assert= (hs-token-type (hs-stream-consume (hs-tokens-of ".a"))) "CLASS_REF")
|
|
(assert= (hs-token-type (hs-stream-consume (hs-tokens-of "#a"))) "ID_REF")
|
|
(assert= (hs-token-type (hs-stream-consume (hs-tokens-of "\"asdf\""))) "STRING")
|
|
)
|
|
(deftest "handles class identifiers properly"
|
|
(assert= (hs-token-type (hs-stream-consume (hs-tokens-of ".a"))) "CLASS_REF")
|
|
(assert= (hs-token-value (hs-stream-consume (hs-tokens-of ".a"))) ".a")
|
|
(assert= (hs-token-type (hs-stream-consume (hs-tokens-of " .a"))) "CLASS_REF")
|
|
(assert= (hs-token-value (hs-stream-consume (hs-tokens-of " .a"))) ".a")
|
|
(assert= (hs-token-type (hs-stream-consume (hs-tokens-of "a.a"))) "IDENTIFIER")
|
|
(assert= (hs-token-value (hs-stream-consume (hs-tokens-of "a.a"))) "a")
|
|
(assert= (hs-token-type (nth (get (hs-tokens-of "(a).a") "list") 4)) "IDENTIFIER")
|
|
(assert= (hs-token-value (nth (get (hs-tokens-of "(a).a") "list") 4)) "a")
|
|
(assert= (hs-token-type (nth (get (hs-tokens-of "{a}.a") "list") 4)) "IDENTIFIER")
|
|
(assert= (hs-token-value (nth (get (hs-tokens-of "{a}.a") "list") 4)) "a")
|
|
(assert= (hs-token-type (nth (get (hs-tokens-of "[a].a") "list") 4)) "IDENTIFIER")
|
|
(assert= (hs-token-value (nth (get (hs-tokens-of "[a].a") "list") 4)) "a")
|
|
(assert= (hs-token-type (nth (get (hs-tokens-of "(a(.a") "list") 3)) "CLASS_REF")
|
|
(assert= (hs-token-value (nth (get (hs-tokens-of "(a(.a") "list") 3)) ".a")
|
|
(assert= (hs-token-type (nth (get (hs-tokens-of "{a{.a") "list") 3)) "CLASS_REF")
|
|
(assert= (hs-token-value (nth (get (hs-tokens-of "{a{.a") "list") 3)) ".a")
|
|
(assert= (hs-token-type (nth (get (hs-tokens-of "[a[.a") "list") 3)) "CLASS_REF")
|
|
(assert= (hs-token-value (nth (get (hs-tokens-of "[a[.a") "list") 3)) ".a")
|
|
)
|
|
(deftest "handles comments properly"
|
|
(assert= (len (get (hs-tokens-of "--") "list")) 0)
|
|
(assert= (len (get (hs-tokens-of "asdf--") "list")) 1)
|
|
(assert= (len (get (hs-tokens-of "-- asdf") "list")) 0)
|
|
(assert= (len (get (hs-tokens-of "--\nasdf") "list")) 1)
|
|
(assert= (len (get (hs-tokens-of "--\nasdf--") "list")) 1)
|
|
(assert= (len (get (hs-tokens-of "---asdf") "list")) 0)
|
|
(assert= (len (get (hs-tokens-of "----\n---asdf") "list")) 0)
|
|
(assert= (len (get (hs-tokens-of "----asdf----") "list")) 0)
|
|
(assert= (len (get (hs-tokens-of "---\nasdf---") "list")) 1)
|
|
(assert= (len (get (hs-tokens-of "// asdf") "list")) 0)
|
|
(assert= (len (get (hs-tokens-of "///asdf") "list")) 0)
|
|
(assert= (len (get (hs-tokens-of "asdf//") "list")) 1)
|
|
(assert= (len (get (hs-tokens-of "asdf\n//") "list")) 2)
|
|
)
|
|
(deftest "handles hex escapes properly"
|
|
(assert= (hs-token-value (hs-stream-consume (hs-tokens-of "\"\\x1f\""))) (char-from-code 31))
|
|
(assert= (hs-token-value (hs-stream-consume (hs-tokens-of "\"\\x41\""))) "A")
|
|
(assert= (hs-token-value (hs-stream-consume (hs-tokens-of "\"\\x41\\x61\""))) "Aa")
|
|
(let ((threw false))
|
|
(guard (e (true (set! threw true))) (hs-stream-consume (hs-tokens-of "\"\\x\"")))
|
|
(assert threw))
|
|
(let ((threw false))
|
|
(guard (e (true (set! threw true))) (hs-stream-consume (hs-tokens-of "\"\\xGG\"")))
|
|
(assert threw))
|
|
(let ((threw false))
|
|
(guard (e (true (set! threw true))) (hs-stream-consume (hs-tokens-of "\"\\x4\"")))
|
|
(assert threw))
|
|
)
|
|
(deftest "handles id references properly"
|
|
(assert= (hs-token-type (hs-stream-consume (hs-tokens-of "#a"))) "ID_REF")
|
|
(assert= (hs-token-value (hs-stream-consume (hs-tokens-of "#a"))) "#a")
|
|
(assert= (hs-token-type (hs-stream-consume (hs-tokens-of " #a"))) "ID_REF")
|
|
(assert= (hs-token-value (hs-stream-consume (hs-tokens-of " #a"))) "#a")
|
|
(assert= (hs-token-type (hs-stream-consume (hs-tokens-of "a#a"))) "IDENTIFIER")
|
|
(assert= (hs-token-value (hs-stream-consume (hs-tokens-of "a#a"))) "a")
|
|
(assert= (hs-token-type (nth (get (hs-tokens-of "(a)#a") "list") 4)) "IDENTIFIER")
|
|
(assert= (hs-token-value (nth (get (hs-tokens-of "(a)#a") "list") 4)) "a")
|
|
(assert= (hs-token-type (nth (get (hs-tokens-of "{a}#a") "list") 4)) "IDENTIFIER")
|
|
(assert= (hs-token-value (nth (get (hs-tokens-of "{a}#a") "list") 4)) "a")
|
|
(assert= (hs-token-type (nth (get (hs-tokens-of "[a]#a") "list") 4)) "IDENTIFIER")
|
|
(assert= (hs-token-value (nth (get (hs-tokens-of "[a]#a") "list") 4)) "a")
|
|
(assert= (hs-token-type (nth (get (hs-tokens-of "(a(#a") "list") 3)) "ID_REF")
|
|
(assert= (hs-token-value (nth (get (hs-tokens-of "(a(#a") "list") 3)) "#a")
|
|
(assert= (hs-token-type (nth (get (hs-tokens-of "{a{#a") "list") 3)) "ID_REF")
|
|
(assert= (hs-token-value (nth (get (hs-tokens-of "{a{#a") "list") 3)) "#a")
|
|
(assert= (hs-token-type (nth (get (hs-tokens-of "[a[#a") "list") 3)) "ID_REF")
|
|
(assert= (hs-token-value (nth (get (hs-tokens-of "[a[#a") "list") 3)) "#a")
|
|
)
|
|
(deftest "handles identifiers properly"
|
|
(assert= (hs-token-type (hs-stream-consume (hs-tokens-of "foo"))) "IDENTIFIER")
|
|
(assert= (hs-token-value (hs-stream-consume (hs-tokens-of "foo"))) "foo")
|
|
(assert= (hs-token-type (hs-stream-consume (hs-tokens-of " foo "))) "IDENTIFIER")
|
|
(assert= (hs-token-value (hs-stream-consume (hs-tokens-of " foo "))) "foo")
|
|
(let ((s (hs-tokens-of " foo bar")))
|
|
(let ((tok1 (hs-stream-consume s)))
|
|
(assert= (hs-token-type tok1) "IDENTIFIER")
|
|
(assert= (hs-token-value tok1) "foo")
|
|
(let ((tok2 (hs-stream-consume s)))
|
|
(assert= (hs-token-type tok2) "IDENTIFIER")
|
|
(assert= (hs-token-value tok2) "bar"))))
|
|
(let ((s (hs-tokens-of " foo\n-- a comment\n bar")))
|
|
(let ((tok1 (hs-stream-consume s)))
|
|
(assert= (hs-token-type tok1) "IDENTIFIER")
|
|
(assert= (hs-token-value tok1) "foo")
|
|
(let ((tok2 (hs-stream-consume s)))
|
|
(assert= (hs-token-type tok2) "IDENTIFIER")
|
|
(assert= (hs-token-value tok2) "bar"))))
|
|
)
|
|
(deftest "handles identifiers with numbers properly"
|
|
(assert= (hs-token-type (hs-stream-consume (hs-tokens-of "f1oo"))) "IDENTIFIER")
|
|
(assert= (hs-token-value (hs-stream-consume (hs-tokens-of "f1oo"))) "f1oo")
|
|
(assert= (hs-token-type (hs-stream-consume (hs-tokens-of "fo1o"))) "IDENTIFIER")
|
|
(assert= (hs-token-value (hs-stream-consume (hs-tokens-of "fo1o"))) "fo1o")
|
|
(assert= (hs-token-type (hs-stream-consume (hs-tokens-of "foo1"))) "IDENTIFIER")
|
|
(assert= (hs-token-value (hs-stream-consume (hs-tokens-of "foo1"))) "foo1")
|
|
)
|
|
(deftest "handles look ahead property"
|
|
(assert= (hs-token-value (hs-stream-token (hs-tokens-of "a 1 + 1") 0)) "a")
|
|
(assert= (hs-token-value (hs-stream-token (hs-tokens-of "a 1 + 1") 1)) "1")
|
|
(assert= (hs-token-value (hs-stream-token (hs-tokens-of "a 1 + 1") 2)) "+")
|
|
(assert= (hs-token-value (hs-stream-token (hs-tokens-of "a 1 + 1") 3)) "1")
|
|
(assert= (hs-token-value (hs-stream-token (hs-tokens-of "a 1 + 1") 4)) "<<<EOF>>>")
|
|
)
|
|
(deftest "handles numbers properly"
|
|
(assert= (hs-token-type (hs-stream-consume (hs-tokens-of "1"))) "NUMBER")
|
|
(assert= (hs-token-value (hs-stream-consume (hs-tokens-of "1"))) "1")
|
|
(assert= (hs-token-type (hs-stream-consume (hs-tokens-of "1.1"))) "NUMBER")
|
|
(assert= (hs-token-value (hs-stream-consume (hs-tokens-of "1.1"))) "1.1")
|
|
(assert= (hs-token-type (hs-stream-consume (hs-tokens-of "1234567890.1234567890"))) "NUMBER")
|
|
(assert= (hs-token-value (hs-stream-consume (hs-tokens-of "1234567890.1234567890"))) "1234567890.1234567890")
|
|
(assert= (hs-token-type (hs-stream-consume (hs-tokens-of "1e6"))) "NUMBER")
|
|
(assert= (hs-token-value (hs-stream-consume (hs-tokens-of "1e6"))) "1e6")
|
|
(assert= (hs-token-type (hs-stream-consume (hs-tokens-of "1e-6"))) "NUMBER")
|
|
(assert= (hs-token-value (hs-stream-consume (hs-tokens-of "1e-6"))) "1e-6")
|
|
(assert= (hs-token-type (hs-stream-consume (hs-tokens-of "1.1e6"))) "NUMBER")
|
|
(assert= (hs-token-value (hs-stream-consume (hs-tokens-of "1.1e6"))) "1.1e6")
|
|
(assert= (hs-token-type (hs-stream-consume (hs-tokens-of "1.1e-6"))) "NUMBER")
|
|
(assert= (hs-token-value (hs-stream-consume (hs-tokens-of "1.1e-6"))) "1.1e-6")
|
|
(assert= (hs-token-type (nth (get (hs-tokens-of "1.1.1") "list") 0)) "NUMBER")
|
|
(assert= (hs-token-type (nth (get (hs-tokens-of "1.1.1") "list") 1)) "PERIOD")
|
|
(assert= (hs-token-type (nth (get (hs-tokens-of "1.1.1") "list") 2)) "NUMBER")
|
|
(assert= (len (get (hs-tokens-of "1.1.1") "list")) 3)
|
|
)
|
|
(deftest "handles operators properly"
|
|
(assert= (hs-token-op? (hs-stream-consume (hs-tokens-of "+"))) true)
|
|
(assert= (hs-token-value (hs-stream-consume (hs-tokens-of "+"))) "+")
|
|
(assert= (hs-token-op? (hs-stream-consume (hs-tokens-of "-"))) true)
|
|
(assert= (hs-token-value (hs-stream-consume (hs-tokens-of "-"))) "-")
|
|
(assert= (hs-token-op? (hs-stream-consume (hs-tokens-of "*"))) true)
|
|
(assert= (hs-token-value (hs-stream-consume (hs-tokens-of "*"))) "*")
|
|
(assert= (hs-token-op? (hs-stream-consume (hs-tokens-of "."))) true)
|
|
(assert= (hs-token-value (hs-stream-consume (hs-tokens-of "."))) ".")
|
|
(assert= (hs-token-op? (hs-stream-consume (hs-tokens-of "\\"))) true)
|
|
(assert= (hs-token-value (hs-stream-consume (hs-tokens-of "\\"))) "\\")
|
|
(assert= (hs-token-op? (hs-stream-consume (hs-tokens-of ":"))) true)
|
|
(assert= (hs-token-value (hs-stream-consume (hs-tokens-of ":"))) ":")
|
|
(assert= (hs-token-op? (hs-stream-consume (hs-tokens-of "%"))) true)
|
|
(assert= (hs-token-value (hs-stream-consume (hs-tokens-of "%"))) "%")
|
|
(assert= (hs-token-op? (hs-stream-consume (hs-tokens-of "|"))) true)
|
|
(assert= (hs-token-value (hs-stream-consume (hs-tokens-of "|"))) "|")
|
|
(assert= (hs-token-op? (hs-stream-consume (hs-tokens-of "!"))) true)
|
|
(assert= (hs-token-value (hs-stream-consume (hs-tokens-of "!"))) "!")
|
|
(assert= (hs-token-op? (hs-stream-consume (hs-tokens-of "?"))) true)
|
|
(assert= (hs-token-value (hs-stream-consume (hs-tokens-of "?"))) "?")
|
|
(assert= (hs-token-op? (hs-stream-consume (hs-tokens-of "#"))) true)
|
|
(assert= (hs-token-value (hs-stream-consume (hs-tokens-of "#"))) "#")
|
|
(assert= (hs-token-op? (hs-stream-consume (hs-tokens-of "&"))) true)
|
|
(assert= (hs-token-value (hs-stream-consume (hs-tokens-of "&"))) "&")
|
|
(assert= (hs-token-op? (hs-stream-consume (hs-tokens-of ";"))) true)
|
|
(assert= (hs-token-value (hs-stream-consume (hs-tokens-of ";"))) ";")
|
|
(assert= (hs-token-op? (hs-stream-consume (hs-tokens-of ","))) true)
|
|
(assert= (hs-token-value (hs-stream-consume (hs-tokens-of ","))) ",")
|
|
(assert= (hs-token-op? (hs-stream-consume (hs-tokens-of "("))) true)
|
|
(assert= (hs-token-value (hs-stream-consume (hs-tokens-of "("))) "(")
|
|
(assert= (hs-token-op? (hs-stream-consume (hs-tokens-of ")"))) true)
|
|
(assert= (hs-token-value (hs-stream-consume (hs-tokens-of ")"))) ")")
|
|
(assert= (hs-token-op? (hs-stream-consume (hs-tokens-of "<"))) true)
|
|
(assert= (hs-token-value (hs-stream-consume (hs-tokens-of "<"))) "<")
|
|
(assert= (hs-token-op? (hs-stream-consume (hs-tokens-of ">"))) true)
|
|
(assert= (hs-token-value (hs-stream-consume (hs-tokens-of ">"))) ">")
|
|
(assert= (hs-token-op? (hs-stream-consume (hs-tokens-of "{"))) true)
|
|
(assert= (hs-token-value (hs-stream-consume (hs-tokens-of "{"))) "{")
|
|
(assert= (hs-token-op? (hs-stream-consume (hs-tokens-of "}"))) true)
|
|
(assert= (hs-token-value (hs-stream-consume (hs-tokens-of "}"))) "}")
|
|
(assert= (hs-token-op? (hs-stream-consume (hs-tokens-of "["))) true)
|
|
(assert= (hs-token-value (hs-stream-consume (hs-tokens-of "["))) "[")
|
|
(assert= (hs-token-op? (hs-stream-consume (hs-tokens-of "]"))) true)
|
|
(assert= (hs-token-value (hs-stream-consume (hs-tokens-of "]"))) "]")
|
|
(assert= (hs-token-op? (hs-stream-consume (hs-tokens-of "="))) true)
|
|
(assert= (hs-token-value (hs-stream-consume (hs-tokens-of "="))) "=")
|
|
(assert= (hs-token-op? (hs-stream-consume (hs-tokens-of "<="))) true)
|
|
(assert= (hs-token-value (hs-stream-consume (hs-tokens-of "<="))) "<=")
|
|
(assert= (hs-token-op? (hs-stream-consume (hs-tokens-of ">="))) true)
|
|
(assert= (hs-token-value (hs-stream-consume (hs-tokens-of ">="))) ">=")
|
|
(assert= (hs-token-op? (hs-stream-consume (hs-tokens-of "=="))) true)
|
|
(assert= (hs-token-value (hs-stream-consume (hs-tokens-of "=="))) "==")
|
|
(assert= (hs-token-op? (hs-stream-consume (hs-tokens-of "==="))) true)
|
|
(assert= (hs-token-value (hs-stream-consume (hs-tokens-of "==="))) "===")
|
|
)
|
|
(deftest "handles strings properly"
|
|
(assert= (hs-token-type (hs-stream-consume (hs-tokens-of "\"foo\""))) "STRING")
|
|
(assert= (hs-token-value (hs-stream-consume (hs-tokens-of "\"foo\""))) "foo")
|
|
(assert= (hs-token-type (hs-stream-consume (hs-tokens-of "\"fo'o\""))) "STRING")
|
|
(assert= (hs-token-value (hs-stream-consume (hs-tokens-of "\"fo'o\""))) "fo'o")
|
|
(assert= (hs-token-type (hs-stream-consume (hs-tokens-of "\"fo\\\"o\""))) "STRING")
|
|
(assert= (hs-token-value (hs-stream-consume (hs-tokens-of "\"fo\\\"o\""))) "fo\"o")
|
|
(assert= (hs-token-type (hs-stream-consume (hs-tokens-of "'foo'"))) "STRING")
|
|
(assert= (hs-token-value (hs-stream-consume (hs-tokens-of "'foo'"))) "foo")
|
|
(assert= (hs-token-type (hs-stream-consume (hs-tokens-of "'fo\"o'"))) "STRING")
|
|
(assert= (hs-token-value (hs-stream-consume (hs-tokens-of "'fo\"o'"))) "fo\"o")
|
|
(assert= (hs-token-type (hs-stream-consume (hs-tokens-of "'fo\\'o'"))) "STRING")
|
|
(assert= (hs-token-value (hs-stream-consume (hs-tokens-of "'fo\\'o'"))) "fo'o")
|
|
(let ((threw false))
|
|
(guard (e (true (set! threw true))) (hs-stream-consume (hs-tokens-of "'")))
|
|
(assert threw))
|
|
(let ((threw false))
|
|
(guard (e (true (set! threw true))) (hs-stream-consume (hs-tokens-of "\"")))
|
|
(assert threw))
|
|
)
|
|
(deftest "handles strings properly 2"
|
|
(assert= (hs-token-type (hs-stream-consume (hs-tokens-of "'foo'"))) "STRING")
|
|
(assert= (hs-token-value (hs-stream-consume (hs-tokens-of "'foo'"))) "foo")
|
|
)
|
|
(deftest "handles template bootstrap properly"
|
|
(assert= (hs-token-value (hs-stream-token (hs-tokens-of "\"" :template) 0)) "\"")
|
|
(assert= (hs-token-value (hs-stream-token (hs-tokens-of "\"$" :template) 0)) "\"")
|
|
(assert= (hs-token-value (hs-stream-token (hs-tokens-of "\"$" :template) 1)) "$")
|
|
(assert= (hs-token-value (hs-stream-token (hs-tokens-of "\"${" :template) 0)) "\"")
|
|
(assert= (hs-token-value (hs-stream-token (hs-tokens-of "\"${" :template) 1)) "$")
|
|
(assert= (hs-token-value (hs-stream-token (hs-tokens-of "\"${" :template) 2)) "{")
|
|
(assert= (hs-token-value (hs-stream-token (hs-tokens-of "\"${\"asdf\"" :template) 0)) "\"")
|
|
(assert= (hs-token-value (hs-stream-token (hs-tokens-of "\"${\"asdf\"" :template) 1)) "$")
|
|
(assert= (hs-token-value (hs-stream-token (hs-tokens-of "\"${\"asdf\"" :template) 2)) "{")
|
|
(assert= (hs-token-value (hs-stream-token (hs-tokens-of "\"${\"asdf\"" :template) 3)) "asdf")
|
|
(assert= (hs-token-value (hs-stream-token (hs-tokens-of "\"${\"asdf\"}\"" :template) 0)) "\"")
|
|
(assert= (hs-token-value (hs-stream-token (hs-tokens-of "\"${\"asdf\"}\"" :template) 1)) "$")
|
|
(assert= (hs-token-value (hs-stream-token (hs-tokens-of "\"${\"asdf\"}\"" :template) 2)) "{")
|
|
(assert= (hs-token-value (hs-stream-token (hs-tokens-of "\"${\"asdf\"}\"" :template) 3)) "asdf")
|
|
(assert= (hs-token-value (hs-stream-token (hs-tokens-of "\"${\"asdf\"}\"" :template) 4)) "}")
|
|
(assert= (hs-token-value (hs-stream-token (hs-tokens-of "\"${\"asdf\"}\"" :template) 5)) "\"")
|
|
)
|
|
(deftest "handles whitespace properly"
|
|
(assert= (len (get (hs-tokens-of " ") "list")) 0)
|
|
(assert= (len (get (hs-tokens-of " asdf") "list")) 1)
|
|
(assert= (len (get (hs-tokens-of " asdf ") "list")) 2)
|
|
(assert= (len (get (hs-tokens-of "asdf ") "list")) 2)
|
|
(assert= (len (get (hs-tokens-of "\n") "list")) 0)
|
|
(assert= (len (get (hs-tokens-of "\nasdf") "list")) 1)
|
|
(assert= (len (get (hs-tokens-of "\nasdf\n") "list")) 2)
|
|
(assert= (len (get (hs-tokens-of "asdf\n") "list")) 2)
|
|
(assert= (len (get (hs-tokens-of "\r") "list")) 0)
|
|
(assert= (len (get (hs-tokens-of "\rasdf") "list")) 1)
|
|
(assert= (len (get (hs-tokens-of "\rasdf\r") "list")) 2)
|
|
(assert= (len (get (hs-tokens-of "asdf\r") "list")) 2)
|
|
(assert= (len (get (hs-tokens-of "\t") "list")) 0)
|
|
(assert= (len (get (hs-tokens-of "\tasdf") "list")) 1)
|
|
(assert= (len (get (hs-tokens-of "\tasdf\t") "list")) 2)
|
|
(assert= (len (get (hs-tokens-of "asdf\t") "list")) 2)
|
|
)
|
|
(deftest "string interpolation isnt surprising"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click set x to 42 then put `test\\${x} test ${x} test\\$x test $x test \\$x test \\${x} test$x test_$x test_${x} test-$x test.$x` 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) "test${x} test 42 test$x test 42 test $x test ${x} test42 test_42 test_42 test-42 test.42")
|
|
))
|
|
)
|
|
|
|
;; ── def (27 tests) ──
|
|
(defsuite "hs-upstream-def"
|
|
(deftest "async finally blocks run normally"
|
|
(hs-cleanup!)
|
|
(guard (_e (true nil)) (eval-expr-cek (hs-to-sx (hs-compile "def foo() wait a tick then set window.bar to 10 finally set window.bar to 20 end"))))
|
|
)
|
|
(deftest "async finally blocks run when an exception occurs"
|
|
(hs-cleanup!)
|
|
(guard (_e (true nil)) (eval-expr-cek (hs-to-sx (hs-compile "def foo() wait a tick then set window.bar to 10 throw \"foo\" finally set window.bar to 20 end"))))
|
|
)
|
|
(deftest "can call asynchronously"
|
|
(hs-cleanup!)
|
|
(guard (_e (true nil)) (eval-expr-cek (hs-to-sx (hs-compile "def foo() wait 1ms log me end"))))
|
|
(guard (_e (true nil)) (eval-expr-cek (hs-to-sx (hs-compile "def foo() wait 1ms log me end"))))
|
|
(let ((_el-div (dom-create-element "div")) (_el-d1 (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click call foo() then add .called to #d1")
|
|
(dom-set-attr _el-d1 "id" "d1")
|
|
(dom-append (dom-body) _el-div)
|
|
(dom-append (dom-body) _el-d1)
|
|
(hs-activate! _el-div)
|
|
))
|
|
(deftest "can catch async exceptions"
|
|
(hs-cleanup!)
|
|
(guard (_e (true nil)) (eval-expr-cek (hs-to-sx (hs-compile "def doh() wait 10ms throw \"bar\" end def foo() call doh() catch e set window.bar to e end"))))
|
|
)
|
|
(deftest "can catch exceptions"
|
|
(hs-cleanup!)
|
|
(guard (_e (true nil)) (eval-expr-cek (hs-to-sx (hs-compile "def foo() throw \"bar\" catch e set window.bar to e end"))))
|
|
)
|
|
(deftest "can catch nested async exceptions"
|
|
(hs-cleanup!)
|
|
(guard (_e (true nil)) (eval-expr-cek (hs-to-sx (hs-compile "def doh() wait 10ms throw \"bar\" end def foo() call doh() catch e set window.bar to e end"))))
|
|
)
|
|
(deftest "can define a basic no arg function"
|
|
(hs-cleanup!)
|
|
(guard (_e (true nil)) (eval-expr-cek (hs-to-sx (hs-compile "def foo() add .called to #d1 end"))))
|
|
(guard (_e (true nil)) (eval-expr-cek (hs-to-sx (hs-compile "def foo() add .called to #d1 end"))))
|
|
(let ((_el-div (dom-create-element "div")) (_el-d1 (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click call foo()")
|
|
(dom-set-attr _el-d1 "id" "d1")
|
|
(dom-append (dom-body) _el-div)
|
|
(dom-append (dom-body) _el-d1)
|
|
(hs-activate! _el-div)
|
|
))
|
|
(deftest "can define a basic one arg function"
|
|
(hs-cleanup!)
|
|
(guard (_e (true nil)) (eval-expr-cek (hs-to-sx (hs-compile "def foo(str) put str into #d1.innerHTML end"))))
|
|
(guard (_e (true nil)) (eval-expr-cek (hs-to-sx (hs-compile "def foo(str) put str into #d1.innerHTML end"))))
|
|
(let ((_el-div (dom-create-element "div")) (_el-d1 (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click call foo(\"called\")")
|
|
(dom-set-attr _el-d1 "id" "d1")
|
|
(dom-append (dom-body) _el-div)
|
|
(dom-append (dom-body) _el-d1)
|
|
(hs-activate! _el-div)
|
|
))
|
|
(deftest "can exit"
|
|
(hs-cleanup!)
|
|
(guard (_e (true nil)) (eval-expr-cek (hs-to-sx (hs-compile "def foo() exit end"))))
|
|
)
|
|
(deftest "can install a function on an element and use in children w/ no leak"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")) (_el-d1 (dom-create-element "div")) (_el-d2 (dom-create-element "div")) (_el-d3 (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "def func() put 42 into #d3")
|
|
(dom-set-attr _el-d1 "id" "d1")
|
|
(dom-set-attr _el-d1 "_" "on click call func()")
|
|
(dom-set-attr _el-d2 "id" "d2")
|
|
(dom-set-attr _el-d3 "id" "d3")
|
|
(dom-append (dom-body) _el-div)
|
|
(dom-append _el-div _el-d1)
|
|
(dom-append _el-div _el-d2)
|
|
(dom-append _el-div _el-d3)
|
|
(hs-activate! _el-div)
|
|
(hs-activate! _el-d1)
|
|
))
|
|
(deftest "can install a function on an element and use in children w/ return value"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")) (_el-d1 (dom-create-element "div")) (_el-d2 (dom-create-element "div")) (_el-d3 (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "def func() return 42")
|
|
(dom-set-attr _el-d1 "id" "d1")
|
|
(dom-set-attr _el-d1 "_" "on click put func() into me")
|
|
(dom-set-attr _el-d2 "id" "d2")
|
|
(dom-set-attr _el-d3 "id" "d3")
|
|
(dom-append (dom-body) _el-div)
|
|
(dom-append _el-div _el-d1)
|
|
(dom-append _el-div _el-d2)
|
|
(dom-append _el-div _el-d3)
|
|
(hs-activate! _el-div)
|
|
(hs-activate! _el-d1)
|
|
))
|
|
(deftest "can install a function on an element and use me symbol correctly"
|
|
(hs-cleanup!)
|
|
(let ((_el-outer (dom-create-element "div")) (_el-d1 (dom-create-element "div")) (_el-d2 (dom-create-element "div")) (_el-d3 (dom-create-element "div")))
|
|
(dom-set-attr _el-outer "id" "outer")
|
|
(dom-set-attr _el-outer "_" "def func() put 42 into me")
|
|
(dom-set-attr _el-d1 "id" "d1")
|
|
(dom-set-attr _el-d1 "_" "on click call func()")
|
|
(dom-set-attr _el-d2 "id" "d2")
|
|
(dom-set-attr _el-d3 "id" "d3")
|
|
(dom-append (dom-body) _el-outer)
|
|
(dom-append _el-outer _el-d1)
|
|
(dom-append _el-outer _el-d2)
|
|
(dom-append _el-outer _el-d3)
|
|
(hs-activate! _el-outer)
|
|
(hs-activate! _el-d1)
|
|
))
|
|
(deftest "can interop with javascript"
|
|
(hs-cleanup!)
|
|
(guard (_e (true nil)) (eval-expr-cek (hs-to-sx (hs-compile "def foo() return \"foo\" end"))))
|
|
)
|
|
(deftest "can interop with javascript asynchronously"
|
|
(hs-cleanup!)
|
|
(guard (_e (true nil)) (eval-expr-cek (hs-to-sx (hs-compile "def foo() wait 1ms return \"foo\" end"))))
|
|
)
|
|
(deftest "can rethrow in async catch blocks"
|
|
(hs-cleanup!)
|
|
(guard (_e (true nil)) (eval-expr-cek (hs-to-sx (hs-compile "def foo() throw \"bar\" catch e wait 10ms throw e end"))))
|
|
)
|
|
(deftest "can rethrow in catch blocks"
|
|
(hs-cleanup!)
|
|
(guard (_e (true nil)) (eval-expr-cek (hs-to-sx (hs-compile "def foo() throw \"bar\" catch e throw e end"))))
|
|
)
|
|
(deftest "can return a value asynchronously"
|
|
(hs-cleanup!)
|
|
(guard (_e (true nil)) (eval-expr-cek (hs-to-sx (hs-compile "def foo() wait 1ms return \"foo\" end"))))
|
|
(guard (_e (true nil)) (eval-expr-cek (hs-to-sx (hs-compile "def foo() wait 1ms return \\\"foo\\\" end"))))
|
|
(let ((_el-div (dom-create-element "div")) (_el-d1 (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click call foo() then put it into #d1.innerText")
|
|
(dom-set-attr _el-d1 "id" "d1")
|
|
(dom-append (dom-body) _el-div)
|
|
(dom-append (dom-body) _el-d1)
|
|
(hs-activate! _el-div)
|
|
))
|
|
(deftest "can return a value synchronously"
|
|
(hs-cleanup!)
|
|
(guard (_e (true nil)) (eval-expr-cek (hs-to-sx (hs-compile "def foo() return \"foo\" end"))))
|
|
(guard (_e (true nil)) (eval-expr-cek (hs-to-sx (hs-compile "def foo() return \\\"foo\\\" end"))))
|
|
(let ((_el-div (dom-create-element "div")) (_el-d1 (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click call foo() then put it into #d1.innerText")
|
|
(dom-set-attr _el-d1 "id" "d1")
|
|
(dom-append (dom-body) _el-div)
|
|
(dom-append (dom-body) _el-d1)
|
|
(hs-activate! _el-div)
|
|
))
|
|
(deftest "can return in async catch blocks"
|
|
(hs-cleanup!)
|
|
(guard (_e (true nil)) (eval-expr-cek (hs-to-sx (hs-compile "def foo() throw \"bar\" catch e wait 10ms return 42 end"))))
|
|
)
|
|
(deftest "can return in catch blocks"
|
|
(hs-cleanup!)
|
|
(guard (_e (true nil)) (eval-expr-cek (hs-to-sx (hs-compile "def foo() throw \"bar\" catch e return 42 end"))))
|
|
)
|
|
(deftest "can return without a value"
|
|
(hs-cleanup!)
|
|
(guard (_e (true nil)) (eval-expr-cek (hs-to-sx (hs-compile "def foo() return end"))))
|
|
)
|
|
(deftest "exit stops execution mid-function"
|
|
(hs-cleanup!)
|
|
(guard (_e (true nil)) (eval-expr-cek (hs-to-sx (hs-compile "def foo() set x to 1 then exit then set x to 2 then return x end"))))
|
|
)
|
|
(deftest "finally blocks run normally"
|
|
(hs-cleanup!)
|
|
(guard (_e (true nil)) (eval-expr-cek (hs-to-sx (hs-compile "def foo() set window.bar to 10 finally set window.bar to 20 end"))))
|
|
)
|
|
(deftest "finally blocks run when an exception expr occurs"
|
|
(hs-cleanup!)
|
|
(guard (_e (true nil)) (eval-expr-cek (hs-to-sx (hs-compile "def foo() set window.bar to 10 call throwsAsyncException() finally set window.bar to 20 end"))))
|
|
)
|
|
(deftest "finally blocks run when an exception occurs"
|
|
(hs-cleanup!)
|
|
(guard (_e (true nil)) (eval-expr-cek (hs-to-sx (hs-compile "def foo() set window.bar to 10 throw \"foo\" finally set window.bar to 20 end"))))
|
|
)
|
|
(deftest "functions can be namespaced"
|
|
(hs-cleanup!)
|
|
(guard (_e (true nil)) (eval-expr-cek (hs-to-sx (hs-compile "def utils.foo() add .called to #d1 end"))))
|
|
(guard (_e (true nil)) (eval-expr-cek (hs-to-sx (hs-compile "def utils.foo() add .called to #d1 end"))))
|
|
(let ((_el-div (dom-create-element "div")) (_el-d1 (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click call utils.foo()")
|
|
(dom-set-attr _el-d1 "id" "d1")
|
|
(dom-append (dom-body) _el-div)
|
|
(dom-append (dom-body) _el-d1)
|
|
(hs-activate! _el-div)
|
|
))
|
|
(deftest "is called synchronously"
|
|
(hs-cleanup!)
|
|
(guard (_e (true nil)) (eval-expr-cek (hs-to-sx (hs-compile "def foo() log me end"))))
|
|
(guard (_e (true nil)) (eval-expr-cek (hs-to-sx (hs-compile "def foo() log me end"))))
|
|
(let ((_el-div (dom-create-element "div")) (_el-d1 (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click call foo() then add .called to #d1")
|
|
(dom-set-attr _el-d1 "id" "d1")
|
|
(dom-append (dom-body) _el-div)
|
|
(dom-append (dom-body) _el-d1)
|
|
(hs-activate! _el-div)
|
|
))
|
|
)
|
|
|
|
;; ── default (15 tests) ──
|
|
(defsuite "hs-upstream-default"
|
|
(deftest "can default array elements"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click set arr to [null, null] then default arr[0] to 'yes' then put arr[0] into me")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
(dom-dispatch _el-div "click" nil)
|
|
(assert= (dom-text-content _el-div) "yes")
|
|
))
|
|
(deftest "can default attributes"
|
|
(hs-cleanup!)
|
|
(let ((_el-d1 (dom-create-element "div")))
|
|
(dom-set-attr _el-d1 "id" "d1")
|
|
(dom-set-attr _el-d1 "_" "on click default @foo to \"foo\" then put @foo into me")
|
|
(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 default of-expression properties"
|
|
(hs-cleanup!)
|
|
(let ((_el-d1 (dom-create-element "div")))
|
|
(dom-set-attr _el-d1 "id" "d1")
|
|
(dom-set-attr _el-d1 "_" "on click default foo of me to 'bar' then put my foo into me")
|
|
(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")) "bar")
|
|
))
|
|
(deftest "can default possessive properties"
|
|
(hs-cleanup!)
|
|
(let ((_el-d1 (dom-create-element "div")))
|
|
(dom-set-attr _el-d1 "id" "d1")
|
|
(dom-set-attr _el-d1 "_" "on click default #d1's foo to 'bar' then put #d1's foo into me")
|
|
(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")) "bar")
|
|
))
|
|
(deftest "can default properties"
|
|
(hs-cleanup!)
|
|
(let ((_el-d1 (dom-create-element "div")))
|
|
(dom-set-attr _el-d1 "id" "d1")
|
|
(dom-set-attr _el-d1 "_" "on click default me.foo to \"foo\" then put me.foo into me")
|
|
(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 default style ref when unset"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click default *background-color to 'red'")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
(dom-dispatch _el-div "click" nil)
|
|
(assert= (dom-get-style _el-div "background-color") "red")
|
|
))
|
|
(deftest "can default variables"
|
|
(hs-cleanup!)
|
|
(let ((_el-d1 (dom-create-element "div")))
|
|
(dom-set-attr _el-d1 "id" "d1")
|
|
(dom-set-attr _el-d1 "_" "on click default x to \"foo\" then put x into me")
|
|
(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 "default array element respects existing value"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click set arr to ['existing', null] then default arr[0] to 'new' then put arr[0] into me")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
(dom-dispatch _el-div "click" nil)
|
|
(assert= (dom-text-content _el-div) "existing")
|
|
))
|
|
(deftest "default attributes respect existing values"
|
|
(hs-cleanup!)
|
|
(let ((_el-d1 (dom-create-element "div")))
|
|
(dom-set-attr _el-d1 "id" "d1")
|
|
(dom-set-attr _el-d1 "_" "on click default @foo to \"foo\" then put @foo into me")
|
|
(dom-set-attr _el-d1 "foo" "bar")
|
|
(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")) "bar")
|
|
))
|
|
(deftest "default overwrites empty string"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click set x to \"\" then default x to \"fallback\" then put x into me")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
(dom-dispatch _el-div "click" nil)
|
|
(assert= (dom-text-content _el-div) "fallback")
|
|
))
|
|
(deftest "default preserves false"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click set x to false then default x to true then put x into me")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
(dom-dispatch _el-div "click" nil)
|
|
(assert= (dom-text-content _el-div) "false")
|
|
))
|
|
(deftest "default preserves zero"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click set x to 0 then default x to 10 then put x into me")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
(dom-dispatch _el-div "click" nil)
|
|
(assert= (dom-text-content _el-div) "0")
|
|
))
|
|
(deftest "default properties respect existing values"
|
|
(hs-cleanup!)
|
|
(let ((_el-d1 (dom-create-element "div")))
|
|
(dom-set-attr _el-d1 "id" "d1")
|
|
(dom-set-attr _el-d1 "_" "on click set me.foo to \"bar\" then default me.foo to \"foo\" then put me.foo into me")
|
|
(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")) "bar")
|
|
))
|
|
(deftest "default style ref preserves existing value"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click default *color to '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") "blue")
|
|
))
|
|
(deftest "default variables respect existing values"
|
|
(hs-cleanup!)
|
|
(let ((_el-d1 (dom-create-element "div")))
|
|
(dom-set-attr _el-d1 "id" "d1")
|
|
(dom-set-attr _el-d1 "_" "on click set x to \"bar\" then default x to \"foo\" then put x into me")
|
|
(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")) "bar")
|
|
))
|
|
)
|
|
|
|
;; ── dialog (12 tests) ──
|
|
(defsuite "hs-upstream-dialog"
|
|
(deftest "close closes a details element"
|
|
(hs-cleanup!)
|
|
(let ((_el-d (dom-create-element "details")) (_el-summary (dom-create-element "summary")) (_el-p (dom-create-element "p")) (_el-button (dom-create-element "button")))
|
|
(dom-set-attr _el-d "id" "d")
|
|
(dom-set-attr _el-d "open" "")
|
|
(dom-set-inner-html _el-summary "More")
|
|
(dom-set-inner-html _el-p "Content")
|
|
(dom-set-attr _el-button "_" "on click close #d")
|
|
(dom-set-inner-html _el-button "Close")
|
|
(dom-append (dom-body) _el-d)
|
|
(dom-append _el-d _el-summary)
|
|
(dom-append _el-d _el-p)
|
|
(dom-append (dom-body) _el-button)
|
|
(hs-activate! _el-button)
|
|
(assert (dom-has-attr? (dom-query-by-id "d") "open"))
|
|
(dom-dispatch _el-button "click" nil)
|
|
(assert (not (dom-has-attr? (dom-query-by-id "d") "open")))
|
|
))
|
|
(deftest "close closes a dialog"
|
|
(hs-cleanup!)
|
|
(let ((_el-d (dom-create-element "dialog")) (_el-p (dom-create-element "p")) (_el-close (dom-create-element "button")))
|
|
(dom-set-attr _el-d "id" "d")
|
|
(dom-set-inner-html _el-p "Hello")
|
|
(dom-set-attr _el-close "id" "close")
|
|
(dom-set-attr _el-close "_" "on click close #d")
|
|
(dom-set-inner-html _el-close "Close")
|
|
(dom-append (dom-body) _el-d)
|
|
(dom-append _el-d _el-p)
|
|
(dom-append _el-d _el-close)
|
|
(hs-activate! _el-close)
|
|
(host-call (dom-query-by-id "d") "showModal")
|
|
(assert (dom-has-attr? (dom-query-by-id "d") "open"))
|
|
(dom-dispatch (dom-query-by-id "close") "click" nil)
|
|
(assert (not (dom-has-attr? (dom-query-by-id "d") "open")))
|
|
))
|
|
(deftest "close hides a popover"
|
|
(hs-cleanup!)
|
|
(let ((_el-p (dom-create-element "div")) (_el-p1 (dom-create-element "p")) (_el-close (dom-create-element "button")))
|
|
(dom-set-attr _el-p "id" "p")
|
|
(dom-set-inner-html _el-p1 "Popover content")
|
|
(dom-set-attr _el-close "id" "close")
|
|
(dom-set-attr _el-close "_" "on click close #p")
|
|
(dom-set-inner-html _el-close "Close")
|
|
(dom-append (dom-body) _el-p)
|
|
(dom-append _el-p _el-p1)
|
|
(dom-append _el-p _el-close)
|
|
(hs-activate! _el-close)
|
|
(dom-dispatch (dom-query-by-id "close") "click" nil)
|
|
))
|
|
(deftest "hide closes a dialog"
|
|
(hs-cleanup!)
|
|
(let ((_el-d (dom-create-element "dialog")) (_el-p (dom-create-element "p")) (_el-close (dom-create-element "button")))
|
|
(dom-set-attr _el-d "id" "d")
|
|
(dom-set-inner-html _el-p "Hello")
|
|
(dom-set-attr _el-close "id" "close")
|
|
(dom-set-attr _el-close "_" "on click hide #d")
|
|
(dom-set-inner-html _el-close "Close")
|
|
(dom-append (dom-body) _el-d)
|
|
(dom-append _el-d _el-p)
|
|
(dom-append _el-d _el-close)
|
|
(hs-activate! _el-close)
|
|
(host-call (dom-query-by-id "d") "showModal")
|
|
(assert (dom-has-attr? (dom-query-by-id "d") "open"))
|
|
(dom-dispatch (dom-query-by-id "close") "click" nil)
|
|
(assert (not (dom-has-attr? (dom-query-by-id "d") "open")))
|
|
))
|
|
(deftest "open on implicit me"
|
|
(hs-cleanup!)
|
|
(let ((_el-d (dom-create-element "dialog")) (_el-button (dom-create-element "button")))
|
|
(dom-set-attr _el-d "id" "d")
|
|
(dom-set-attr _el-d "_" "on myOpen open")
|
|
(dom-set-attr _el-button "_" "on click send myOpen to #d")
|
|
(dom-set-inner-html _el-button "Open")
|
|
(dom-append (dom-body) _el-d)
|
|
(dom-append (dom-body) _el-button)
|
|
(hs-activate! _el-d)
|
|
(hs-activate! _el-button)
|
|
(dom-dispatch _el-button "click" nil)
|
|
(assert (dom-has-attr? (dom-query-by-id "d") "open"))
|
|
))
|
|
(deftest "open opens a details element"
|
|
(hs-cleanup!)
|
|
(let ((_el-d (dom-create-element "details")) (_el-summary (dom-create-element "summary")) (_el-p (dom-create-element "p")) (_el-button (dom-create-element "button")))
|
|
(dom-set-attr _el-d "id" "d")
|
|
(dom-set-inner-html _el-summary "More")
|
|
(dom-set-inner-html _el-p "Content")
|
|
(dom-set-attr _el-button "_" "on click open #d")
|
|
(dom-set-inner-html _el-button "Open")
|
|
(dom-append (dom-body) _el-d)
|
|
(dom-append _el-d _el-summary)
|
|
(dom-append _el-d _el-p)
|
|
(dom-append (dom-body) _el-button)
|
|
(hs-activate! _el-button)
|
|
(assert (not (dom-has-attr? (dom-query-by-id "d") "open")))
|
|
(dom-dispatch _el-button "click" nil)
|
|
(assert (dom-has-attr? (dom-query-by-id "d") "open"))
|
|
))
|
|
(deftest "open opens a dialog"
|
|
(hs-cleanup!)
|
|
(let ((_el-d (dom-create-element "dialog")) (_el-p (dom-create-element "p")) (_el-button (dom-create-element "button")))
|
|
(dom-set-attr _el-d "id" "d")
|
|
(dom-set-inner-html _el-p "Hello")
|
|
(dom-set-attr _el-button "_" "on click open #d")
|
|
(dom-set-inner-html _el-button "Open")
|
|
(dom-append (dom-body) _el-d)
|
|
(dom-append _el-d _el-p)
|
|
(dom-append (dom-body) _el-button)
|
|
(hs-activate! _el-button)
|
|
(assert (not (dom-has-attr? (dom-query-by-id "d") "open")))
|
|
(dom-dispatch _el-button "click" nil)
|
|
(assert (dom-has-attr? (dom-query-by-id "d") "open"))
|
|
))
|
|
(deftest "open opens a modal dialog (matches :modal)"
|
|
(hs-cleanup!)
|
|
(let ((_el-d (dom-create-element "dialog")) (_el-p (dom-create-element "p")) (_el-button (dom-create-element "button")))
|
|
(dom-set-attr _el-d "id" "d")
|
|
(dom-set-inner-html _el-p "Hello")
|
|
(dom-set-attr _el-button "_" "on click open #d")
|
|
(dom-set-inner-html _el-button "Open")
|
|
(dom-append (dom-body) _el-d)
|
|
(dom-append _el-d _el-p)
|
|
(dom-append (dom-body) _el-button)
|
|
(hs-activate! _el-button)
|
|
(dom-dispatch _el-button "click" nil)
|
|
))
|
|
(deftest "open shows a popover"
|
|
(hs-cleanup!)
|
|
(let ((_el-p (dom-create-element "div")) (_el-p1 (dom-create-element "p")) (_el-button (dom-create-element "button")))
|
|
(dom-set-attr _el-p "id" "p")
|
|
(dom-set-inner-html _el-p1 "Popover content")
|
|
(dom-set-attr _el-button "_" "on click open #p")
|
|
(dom-set-inner-html _el-button "Open")
|
|
(dom-append (dom-body) _el-p)
|
|
(dom-append _el-p _el-p1)
|
|
(dom-append (dom-body) _el-button)
|
|
(hs-activate! _el-button)
|
|
(dom-dispatch _el-button "click" nil)
|
|
))
|
|
(deftest "show on already-open dialog is a no-op"
|
|
(hs-cleanup!)
|
|
(let ((_el-d (dom-create-element "dialog")) (_el-p (dom-create-element "p")) (_el-button (dom-create-element "button")))
|
|
(dom-set-attr _el-d "id" "d")
|
|
(dom-set-inner-html _el-p "Hello")
|
|
(dom-set-attr _el-button "_" "on click show #d")
|
|
(dom-set-inner-html _el-button "Show Again")
|
|
(dom-append (dom-body) _el-d)
|
|
(dom-append _el-d _el-p)
|
|
(dom-append _el-d _el-button)
|
|
(hs-activate! _el-button)
|
|
(host-call (dom-query-by-id "d") "showModal")
|
|
(assert (dom-has-attr? (dom-query-by-id "d") "open"))
|
|
(dom-dispatch _el-button "click" nil)
|
|
(assert (dom-has-attr? (dom-query-by-id "d") "open"))
|
|
))
|
|
(deftest "show opens a dialog (non-modal)"
|
|
(hs-cleanup!)
|
|
(let ((_el-d (dom-create-element "dialog")) (_el-p (dom-create-element "p")) (_el-button (dom-create-element "button")))
|
|
(dom-set-attr _el-d "id" "d")
|
|
(dom-set-inner-html _el-p "Hello")
|
|
(dom-set-attr _el-button "_" "on click show #d")
|
|
(dom-set-inner-html _el-button "Open")
|
|
(dom-append (dom-body) _el-d)
|
|
(dom-append _el-d _el-p)
|
|
(dom-append (dom-body) _el-button)
|
|
(hs-activate! _el-button)
|
|
(assert (not (dom-has-attr? (dom-query-by-id "d") "open")))
|
|
(dom-dispatch _el-button "click" nil)
|
|
(assert (dom-has-attr? (dom-query-by-id "d") "open"))
|
|
))
|
|
(deftest "show opens a non-modal dialog (no ::backdrop)"
|
|
(hs-cleanup!)
|
|
(let ((_el-d (dom-create-element "dialog")) (_el-p (dom-create-element "p")) (_el-button (dom-create-element "button")))
|
|
(dom-set-attr _el-d "id" "d")
|
|
(dom-set-inner-html _el-p "Hello")
|
|
(dom-set-attr _el-button "_" "on click show #d")
|
|
(dom-set-inner-html _el-button "Open")
|
|
(dom-append (dom-body) _el-d)
|
|
(dom-append _el-d _el-p)
|
|
(dom-append (dom-body) _el-button)
|
|
(hs-activate! _el-button)
|
|
(dom-dispatch _el-button "click" nil)
|
|
))
|
|
)
|
|
|
|
;; ── empty (13 tests) ──
|
|
(defsuite "hs-upstream-empty"
|
|
(deftest "can empty a checkbox"
|
|
(hs-cleanup!)
|
|
(let ((_el-cb1 (dom-create-element "input")) (_el-button (dom-create-element "button")))
|
|
(dom-set-attr _el-cb1 "id" "cb1")
|
|
(dom-set-attr _el-cb1 "type" "checkbox")
|
|
(dom-set-attr _el-cb1 "checked" "")
|
|
(dom-set-attr _el-button "_" "on click empty #cb1")
|
|
(dom-set-inner-html _el-button "Empty")
|
|
(dom-append (dom-body) _el-cb1)
|
|
(dom-append (dom-body) _el-button)
|
|
(hs-activate! _el-button)
|
|
(assert (dom-get-prop (dom-query-by-id "cb1") "checked"))
|
|
(dom-dispatch _el-button "click" nil)
|
|
(assert (not (dom-get-prop (dom-query-by-id "cb1") "checked")))
|
|
))
|
|
(deftest "can empty a form (clears all inputs)"
|
|
(hs-cleanup!)
|
|
(let ((_el-f1 (dom-create-element "form")) (_el-t2 (dom-create-element "input")) (_el-ta2 (dom-create-element "textarea")) (_el-cb2 (dom-create-element "input")) (_el-button (dom-create-element "button")))
|
|
(dom-set-attr _el-f1 "id" "f1")
|
|
(dom-set-attr _el-t2 "id" "t2")
|
|
(dom-set-attr _el-t2 "type" "text")
|
|
(dom-set-attr _el-t2 "value" "val")
|
|
(dom-set-attr _el-ta2 "id" "ta2")
|
|
(dom-set-inner-html _el-ta2 "text")
|
|
(dom-set-attr _el-cb2 "id" "cb2")
|
|
(dom-set-attr _el-cb2 "type" "checkbox")
|
|
(dom-set-attr _el-cb2 "checked" "")
|
|
(dom-set-attr _el-button "_" "on click empty #f1")
|
|
(dom-set-inner-html _el-button "Empty")
|
|
(dom-append (dom-body) _el-f1)
|
|
(dom-append _el-f1 _el-t2)
|
|
(dom-append _el-f1 _el-ta2)
|
|
(dom-append _el-f1 _el-cb2)
|
|
(dom-append (dom-body) _el-button)
|
|
(hs-activate! _el-button)
|
|
(dom-dispatch _el-button "click" nil)
|
|
(assert= (dom-get-prop (dom-query-by-id "t2") "value") "")
|
|
(assert= (dom-get-prop (dom-query-by-id "ta2") "value") "")
|
|
(assert (not (dom-get-prop (dom-query-by-id "cb2") "checked")))
|
|
))
|
|
(deftest "can empty a map"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click set :m to {a:1, b:2} as Map then empty :m then put :m.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) "0")
|
|
))
|
|
(deftest "can empty a select"
|
|
(hs-cleanup!)
|
|
(let ((_el-sel1 (dom-create-element "select")) (_el-option (dom-create-element "option")) (_el-option2 (dom-create-element "option")) (_el-button (dom-create-element "button")))
|
|
(dom-set-attr _el-sel1 "id" "sel1")
|
|
(dom-set-attr _el-option "value" "a")
|
|
(dom-set-inner-html _el-option "A")
|
|
(dom-set-attr _el-option2 "value" "b")
|
|
(dom-set-attr _el-option2 "selected" "")
|
|
(dom-set-inner-html _el-option2 "B")
|
|
(dom-set-attr _el-button "_" "on click empty #sel1")
|
|
(dom-set-inner-html _el-button "Empty")
|
|
(dom-append (dom-body) _el-sel1)
|
|
(dom-append _el-sel1 _el-option)
|
|
(dom-append _el-sel1 _el-option2)
|
|
(dom-append (dom-body) _el-button)
|
|
(hs-activate! _el-button)
|
|
(dom-dispatch _el-button "click" nil)
|
|
))
|
|
(deftest "can empty a set"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click set :s to [1,2,3] as Set then empty :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) "0")
|
|
))
|
|
(deftest "can empty a text input"
|
|
(hs-cleanup!)
|
|
(let ((_el-t1 (dom-create-element "input")) (_el-button (dom-create-element "button")))
|
|
(dom-set-attr _el-t1 "id" "t1")
|
|
(dom-set-attr _el-t1 "type" "text")
|
|
(dom-set-attr _el-t1 "value" "hello")
|
|
(dom-set-attr _el-button "_" "on click empty #t1")
|
|
(dom-set-inner-html _el-button "Empty")
|
|
(dom-append (dom-body) _el-t1)
|
|
(dom-append (dom-body) _el-button)
|
|
(hs-activate! _el-button)
|
|
(assert= (dom-get-prop (dom-query-by-id "t1") "value") "hello")
|
|
(dom-dispatch _el-button "click" nil)
|
|
(assert= (dom-get-prop (dom-query-by-id "t1") "value") "")
|
|
))
|
|
(deftest "can empty a textarea"
|
|
(hs-cleanup!)
|
|
(let ((_el-ta1 (dom-create-element "textarea")) (_el-button (dom-create-element "button")))
|
|
(dom-set-attr _el-ta1 "id" "ta1")
|
|
(dom-set-inner-html _el-ta1 "some text")
|
|
(dom-set-attr _el-button "_" "on click empty #ta1")
|
|
(dom-set-inner-html _el-button "Empty")
|
|
(dom-append (dom-body) _el-ta1)
|
|
(dom-append (dom-body) _el-button)
|
|
(hs-activate! _el-button)
|
|
(dom-dispatch _el-button "click" nil)
|
|
(assert= (dom-get-prop (dom-query-by-id "ta1") "value") "")
|
|
))
|
|
(deftest "can empty 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 empty :arr then put :arr.length into me")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
(dom-dispatch _el-div "click" nil)
|
|
(assert= (dom-text-content _el-div) "0")
|
|
))
|
|
(deftest "can empty an element"
|
|
(hs-cleanup!)
|
|
(let ((_el-d1 (dom-create-element "div")) (_el-p (dom-create-element "p")) (_el-p2 (dom-create-element "p")) (_el-button (dom-create-element "button")))
|
|
(dom-set-attr _el-d1 "id" "d1")
|
|
(dom-set-inner-html _el-p "hello")
|
|
(dom-set-inner-html _el-p2 "world")
|
|
(dom-set-attr _el-button "_" "on click empty #d1")
|
|
(dom-append (dom-body) _el-d1)
|
|
(dom-append _el-d1 _el-p)
|
|
(dom-append _el-d1 _el-p2)
|
|
(dom-append (dom-body) _el-button)
|
|
(hs-activate! _el-button)
|
|
(assert= (dom-text-content (dom-query-by-id "d1")) "helloworld")
|
|
(dom-dispatch _el-button "click" nil)
|
|
(assert= (dom-text-content (dom-query-by-id "d1")) "")
|
|
))
|
|
(deftest "can empty multiple elements"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")) (_el-p (dom-create-element "p")) (_el-div2 (dom-create-element "div")) (_el-p3 (dom-create-element "p")) (_el-button (dom-create-element "button")))
|
|
(dom-add-class _el-div "clearme")
|
|
(dom-set-inner-html _el-p "a")
|
|
(dom-add-class _el-div2 "clearme")
|
|
(dom-set-inner-html _el-p3 "b")
|
|
(dom-set-attr _el-button "_" "on click empty .clearme")
|
|
(dom-append (dom-body) _el-div)
|
|
(dom-append _el-div _el-p)
|
|
(dom-append (dom-body) _el-div2)
|
|
(dom-append _el-div2 _el-p3)
|
|
(dom-append (dom-body) _el-button)
|
|
(hs-activate! _el-button)
|
|
(dom-dispatch _el-button "click" nil)
|
|
(assert= (dom-text-content (nth (dom-query-all (dom-body) ".clearme") 0)) "")
|
|
(assert= (dom-text-content (let ((_all (dom-query-all (dom-body) ".clearme"))) (nth _all (- (len _all) 1)))) "")
|
|
))
|
|
(deftest "clear is an alias for empty"
|
|
(hs-cleanup!)
|
|
(let ((_el-t3 (dom-create-element "input")) (_el-button (dom-create-element "button")))
|
|
(dom-set-attr _el-t3 "id" "t3")
|
|
(dom-set-attr _el-t3 "type" "text")
|
|
(dom-set-attr _el-t3 "value" "hello")
|
|
(dom-set-attr _el-button "_" "on click clear #t3")
|
|
(dom-set-inner-html _el-button "Clear")
|
|
(dom-append (dom-body) _el-t3)
|
|
(dom-append (dom-body) _el-button)
|
|
(hs-activate! _el-button)
|
|
(assert= (dom-get-prop (dom-query-by-id "t3") "value") "hello")
|
|
(dom-dispatch _el-button "click" nil)
|
|
(assert= (dom-get-prop (dom-query-by-id "t3") "value") "")
|
|
))
|
|
(deftest "clear works on elements"
|
|
(hs-cleanup!)
|
|
(let ((_el-d2 (dom-create-element "div")) (_el-p (dom-create-element "p")) (_el-button (dom-create-element "button")))
|
|
(dom-set-attr _el-d2 "id" "d2")
|
|
(dom-set-inner-html _el-p "content")
|
|
(dom-set-attr _el-button "_" "on click clear #d2")
|
|
(dom-append (dom-body) _el-d2)
|
|
(dom-append _el-d2 _el-p)
|
|
(dom-append (dom-body) _el-button)
|
|
(hs-activate! _el-button)
|
|
(assert= (dom-text-content (dom-query-by-id "d2")) "content")
|
|
(dom-dispatch _el-button "click" nil)
|
|
(assert= (dom-text-content (dom-query-by-id "d2")) "")
|
|
))
|
|
(deftest "empty with no target empties me"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click empty")
|
|
(dom-set-inner-html _el-div "content")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
(assert= (dom-text-content _el-div) "content")
|
|
(dom-dispatch _el-div "click" nil)
|
|
(assert= (dom-text-content _el-div) "")
|
|
))
|
|
)
|
|
|
|
;; ── expressions/arrayIndex (14 tests) ──
|
|
(defsuite "hs-upstream-expressions/arrayIndex"
|
|
(deftest "can create an array literal"
|
|
(assert= (eval-hs "[1, 2, 3]") (list 1 2 3))
|
|
)
|
|
(deftest "can get the range of first values in an array"
|
|
(hs-cleanup!)
|
|
(let ((_el-d1 (dom-create-element "div")))
|
|
(dom-set-attr _el-d1 "id" "d1")
|
|
(dom-set-attr _el-d1 "_" "on click set var to [0,1,2,3,4,5] then put var[..3] as String into #d1")
|
|
(dom-append (dom-body) _el-d1)
|
|
(hs-activate! _el-d1)
|
|
))
|
|
(deftest "can get the range of last values in an array"
|
|
(hs-cleanup!)
|
|
(let ((_el-d1 (dom-create-element "div")))
|
|
(dom-set-attr _el-d1 "id" "d1")
|
|
(dom-set-attr _el-d1 "_" "on click set var to [0,1,2,3,4,5] then put var[3 ..] as String into #d1")
|
|
(dom-append (dom-body) _el-d1)
|
|
(hs-activate! _el-d1)
|
|
))
|
|
(deftest "can get the range of last values in an array WITHOUT EXTRA SPACES"
|
|
(hs-cleanup!)
|
|
(let ((_el-d1 (dom-create-element "div")))
|
|
(dom-set-attr _el-d1 "id" "d1")
|
|
(dom-set-attr _el-d1 "_" "on click set var to [0,1,2,3,4,5] then put var[3..] as String into #d1")
|
|
(dom-append (dom-body) _el-d1)
|
|
(hs-activate! _el-d1)
|
|
))
|
|
(deftest "can get the range of middle values in an array"
|
|
(hs-cleanup!)
|
|
(let ((_el-d1 (dom-create-element "div")))
|
|
(dom-set-attr _el-d1 "id" "d1")
|
|
(dom-set-attr _el-d1 "_" "on click set var to [0,1,2,3,4,5] then put var[2 .. 3] as String into #d1")
|
|
(dom-append (dom-body) _el-d1)
|
|
(hs-activate! _el-d1)
|
|
))
|
|
(deftest "can get the range of middle values in an array WITHOUT EXTRA SPACES"
|
|
(hs-cleanup!)
|
|
(let ((_el-d1 (dom-create-element "div")))
|
|
(dom-set-attr _el-d1 "id" "d1")
|
|
(dom-set-attr _el-d1 "_" "on click set var to [0,1,2,3,4,5] then put var[2..3] as String into #d1")
|
|
(dom-append (dom-body) _el-d1)
|
|
(hs-activate! _el-d1)
|
|
))
|
|
(deftest "can get the range of middle values in an array using an expression"
|
|
(hs-cleanup!)
|
|
(let ((_el-d1 (dom-create-element "div")))
|
|
(dom-set-attr _el-d1 "id" "d1")
|
|
(dom-set-attr _el-d1 "_" "on click set index to 3 then set var to [0,1,2,3,4,5] then put var[(index-1)..(index+1)] as String into #d1")
|
|
(dom-append (dom-body) _el-d1)
|
|
(hs-activate! _el-d1)
|
|
))
|
|
(deftest "can index an array value"
|
|
(hs-cleanup!)
|
|
(let ((_el-d1 (dom-create-element "div")))
|
|
(dom-set-attr _el-d1 "id" "d1")
|
|
(dom-set-attr _el-d1 "_" "on click set newVar to [10, 20, 30] then put newVar[0] into #d1.innerHTML")
|
|
(dom-append (dom-body) _el-d1)
|
|
(hs-activate! _el-d1)
|
|
))
|
|
(deftest "can index an array value at the beginning of the array"
|
|
(hs-cleanup!)
|
|
(let ((_el-d1 (dom-create-element "div")))
|
|
(dom-set-attr _el-d1 "id" "d1")
|
|
(dom-set-attr _el-d1 "_" "on click set newVar to [10, 20, 30] then put newVar[0] into #d1.innerHTML")
|
|
(dom-append (dom-body) _el-d1)
|
|
(hs-activate! _el-d1)
|
|
))
|
|
(deftest "can index an array value at the end of the array"
|
|
(hs-cleanup!)
|
|
(let ((_el-d1 (dom-create-element "div")))
|
|
(dom-set-attr _el-d1 "id" "d1")
|
|
(dom-set-attr _el-d1 "_" "on click set newVar to [10, 20, 30] then put newVar[2] into #d1.innerHTML")
|
|
(dom-append (dom-body) _el-d1)
|
|
(hs-activate! _el-d1)
|
|
))
|
|
(deftest "can index an array value in the middle of the array"
|
|
(hs-cleanup!)
|
|
(let ((_el-d1 (dom-create-element "div")))
|
|
(dom-set-attr _el-d1 "id" "d1")
|
|
(dom-set-attr _el-d1 "_" "on click set newVar to [10, 20, 30] then put newVar[1] into #d1.innerHTML")
|
|
(dom-append (dom-body) _el-d1)
|
|
(hs-activate! _el-d1)
|
|
))
|
|
(deftest "can index an array value with an expression"
|
|
(hs-cleanup!)
|
|
(let ((_el-d1 (dom-create-element "div")))
|
|
(dom-set-attr _el-d1 "id" "d1")
|
|
(dom-set-attr _el-d1 "_" "on click set newVar to [\"A\", \"B\", \"C\"] then put newVar[1+1] into #d1.innerHTML")
|
|
(dom-append (dom-body) _el-d1)
|
|
(hs-activate! _el-d1)
|
|
))
|
|
(deftest "errors when index exceeds array length"
|
|
(hs-cleanup!)
|
|
(let ((_el-d1 (dom-create-element "div")))
|
|
(dom-set-attr _el-d1 "id" "d1")
|
|
(dom-set-attr _el-d1 "_" "on click set newVar to [10, 20, 30] then put newVar[10] into #d1.innerHTML")
|
|
(dom-append (dom-body) _el-d1)
|
|
(hs-activate! _el-d1)
|
|
(dom-dispatch (dom-query-by-id "d1") "click" nil)
|
|
))
|
|
(deftest "errors when indexed value is not an array"
|
|
(hs-cleanup!)
|
|
(let ((_el-d1 (dom-create-element "div")))
|
|
(dom-set-attr _el-d1 "id" "d1")
|
|
(dom-set-attr _el-d1 "_" "on click set newVar to \"not-an-array\" then put newVar[0] into #d1.innerHTML")
|
|
(dom-append (dom-body) _el-d1)
|
|
(hs-activate! _el-d1)
|
|
(dom-dispatch (dom-query-by-id "d1") "click" nil)
|
|
))
|
|
)
|
|
|
|
;; ── expressions/arrayLiteral (8 tests) ──
|
|
(defsuite "hs-upstream-expressions/arrayLiteral"
|
|
(deftest "arrays can contain expressions"
|
|
(assert= (eval-hs "[1 + 1, 2 * 3, 10 - 5]") (list 2 6 5))
|
|
)
|
|
(deftest "arrays containing objects work"
|
|
(assert-equal (list {:a 1} {:b 2}) (eval-hs "[{a: 1}, {b: 2}]"))
|
|
)
|
|
(deftest "deeply nested array literals work"
|
|
(assert= (eval-hs "[[[1]], [[2, 3]]]") (list (list (list 1)) (list (list 2 3))))
|
|
)
|
|
(deftest "empty array literals work"
|
|
(assert= (eval-hs "[]") (list))
|
|
)
|
|
(deftest "mixed-type array literal works"
|
|
(assert= (eval-hs "[1, 'two', true, null]") (list 1 "two" true nil))
|
|
)
|
|
(deftest "multi element array literal works"
|
|
(assert= (eval-hs "[true, false]") (list true false))
|
|
)
|
|
(deftest "nested array literals work"
|
|
(assert= (eval-hs "[[1, 2], [3, 4]]") (list (list 1 2) (list 3 4)))
|
|
)
|
|
(deftest "one element array literal works"
|
|
(assert= (eval-hs "[true]") (list true))
|
|
)
|
|
)
|
|
|
|
;; ── expressions/asExpression (42 tests) ──
|
|
(defsuite "hs-upstream-expressions/asExpression"
|
|
(deftest "can accept custom conversions"
|
|
(error "SKIP (untranslated): can accept custom conversions"))
|
|
(deftest "can accept custom dynamic conversions"
|
|
(error "SKIP (untranslated): can accept custom dynamic conversions"))
|
|
(deftest "can use the a modifier if you like"
|
|
(error "SKIP (untranslated): can use the a modifier if you like"))
|
|
(deftest "can use the an modifier if you'd like"
|
|
(assert= (host-get (eval-hs "'{\"foo\":\"bar\"}' as an Object") "foo") "bar")
|
|
)
|
|
(deftest "collects duplicate text inputs into an array"
|
|
(let ((_node (dom-create-element "form")))
|
|
(dom-set-inner-html _node "<input name=\"tag\" value=\"alpha\"> <input name=\"tag\" value=\"beta\"> <input name=\"tag\" value=\"gamma\">")
|
|
(let ((_result (eval-hs-locals "x as Values" (list (list (quote x) _node)))))
|
|
(assert= (host-get _result "tag") (list "alpha" "beta" "gamma"))
|
|
(assert= (host-get _result "tag") (list "alpha" "beta" "gamma"))
|
|
))
|
|
)
|
|
(deftest "converts a NodeList into HTML"
|
|
(error "SKIP (untranslated): converts a NodeList into HTML"))
|
|
(deftest "converts a complete form into Values"
|
|
(let ((_node (dom-create-element "form")))
|
|
(dom-set-inner-html _node "<div><span><b> Catches elements nested deeply within the DOM tree <input name=\"firstName\" value=\"John\"><br> <input name=\"lastName\" value=\"Connor\"><br> <input name=\"phone\" value=\"555-1212\"> </b></span></div> Works with Textareas <textarea name=\"aboutMe\">It began on a warm summer day in 1969...</textarea> Works with Single Select Boxes <select name=\"animal\"> <option value=\"dog\" selected>Doggo</option> <option value=\"cat\">Kitteh</option> <option value=\"raccoon\">Trash Panda</option> <option value=\"possum\">Sleepy Boi</option> </select> Works with Multi-Select Boxes <select name=\"spiritAnimal\" multiple> <option value=\"dog\" selected>Doggo</option> <option value=\"cat\">Kitteh</option> <option value=\"raccoon\" selected>Trash Panda</option> <option value=\"possum\">Sleepy Boi</option> </select> Works with Radio Buttons <input type=\"radio\" name=\"coolOrNaw\" value=\"Cool\" checked> <input type=\"radio\" name=\"coolOrNaw\" value=\"Naw Bruh\"> Works with Checkboxes <input type=\"checkbox\" name=\"gender\" value=\"Male\" checked> <input type=\"checkbox\" name=\"gender\" value=\"Female\" checked> <input type=\"checkbox\" name=\"gender\" value=\"Other\" checked>")
|
|
(let ((_result (eval-hs-locals "x as Values" (list (list (quote x) _node)))))
|
|
(assert= (host-get _result "firstName") "John")
|
|
(assert= (host-get _result "lastName") "Connor")
|
|
(assert= (host-get _result "phone") "555-1212")
|
|
(assert= (host-get _result "aboutMe") "It began on a warm summer day in 1969...")
|
|
(assert= (host-get _result "animal") "dog")
|
|
(assert= (nth (host-get _result "spiritAnimal") 0) "dog")
|
|
(assert= (nth (host-get _result "spiritAnimal") 1) "raccoon")
|
|
(assert= (host-get _result "coolOrNaw") "Cool")
|
|
(assert= (nth (host-get _result "gender") 0) "Male")
|
|
(assert= (nth (host-get _result "gender") 1) "Female")
|
|
(assert= (nth (host-get _result "gender") 2) "Other")
|
|
))
|
|
)
|
|
(deftest "converts a form element into Values"
|
|
(let ((_node (dom-create-element "form")))
|
|
(dom-set-inner-html _node "<input name=\"firstName\" value=\"John\"><br> <input name=\"lastName\" value=\"Connor\"><br> <div> <input name=\"areaCode\" value=\"213\"> <input name=\"phone\" value=\"555-1212\"> </div>")
|
|
(let ((_result (eval-hs-locals "x as Values" (list (list (quote x) _node)))))
|
|
(assert= (host-get _result "firstName") "John")
|
|
(assert= (host-get _result "lastName") "Connor")
|
|
(assert= (host-get _result "areaCode") "213")
|
|
(assert= (host-get _result "phone") "555-1212")
|
|
))
|
|
)
|
|
(deftest "converts a form element into Values | FormEncoded"
|
|
(let ((_node (dom-create-element "form")))
|
|
(dom-set-inner-html _node "<input name=\"firstName\" value=\"John\"><br> <input name=\"lastName\" value=\"Connor\"><br> <div> <input name=\"areaCode\" value=\"213\"> <input name=\"phone\" value=\"555-1212\"> </div>")
|
|
(let ((_result (eval-hs-locals "x as Values | FormEncoded" (list (list (quote x) _node)))))
|
|
(assert= _result "firstName=John&lastName=Connor&areaCode=213&phone=555-1212")
|
|
))
|
|
)
|
|
(deftest "converts a form element into Values | JSONString"
|
|
(let ((_node (dom-create-element "form")))
|
|
(dom-set-inner-html _node "<input name=\"firstName\" value=\"John\"><br> <input name=\"lastName\" value=\"Connor\"><br> <div> <input name=\"areaCode\" value=\"213\"> <input name=\"phone\" value=\"555-1212\"> </div>")
|
|
(let ((_result (eval-hs-locals "x as Values | JSONString" (list (list (quote x) _node)))))
|
|
(assert= _result "{\"firstName\":\"John\",\"lastName\":\"Connor\",\"areaCode\":\"213\",\"phone\":\"555-1212\"}")
|
|
))
|
|
)
|
|
(deftest "converts a query selector into Values"
|
|
(hs-cleanup!)
|
|
(let ((_el-qsdiv (dom-create-element "div")) (_el-input (dom-create-element "input")) (_el-br (dom-create-element "br")) (_el-input3 (dom-create-element "input")) (_el-br4 (dom-create-element "br")) (_el-input5 (dom-create-element "input")) (_el-input6 (dom-create-element "input")))
|
|
(dom-set-attr _el-qsdiv "id" "qsdiv")
|
|
(dom-set-attr _el-qsdiv "_" "on click put <input.include/> as Values into my.customData")
|
|
(dom-add-class _el-input "include")
|
|
(dom-set-attr _el-input "name" "firstName")
|
|
(dom-set-attr _el-input "value" "John")
|
|
(dom-add-class _el-input3 "include")
|
|
(dom-set-attr _el-input3 "name" "lastName")
|
|
(dom-set-attr _el-input3 "value" "Connor")
|
|
(dom-add-class _el-input5 "include")
|
|
(dom-set-attr _el-input5 "name" "areaCode")
|
|
(dom-set-attr _el-input5 "value" "213")
|
|
(dom-add-class _el-input6 "dont-include")
|
|
(dom-set-attr _el-input6 "name" "phone")
|
|
(dom-set-attr _el-input6 "value" "555-1212")
|
|
(dom-append (dom-body) _el-qsdiv)
|
|
(dom-append _el-qsdiv _el-input)
|
|
(dom-append _el-qsdiv _el-br)
|
|
(dom-append _el-qsdiv _el-input3)
|
|
(dom-append _el-qsdiv _el-br4)
|
|
(dom-append _el-qsdiv _el-input5)
|
|
(dom-append _el-qsdiv _el-input6)
|
|
(hs-activate! _el-qsdiv)
|
|
))
|
|
(deftest "converts an array into 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"
|
|
(let ((_node (dom-create-element "div")))
|
|
(host-set! _node "id" "myDiv")
|
|
(host-set! _node "innerText" "With Text")
|
|
(let ((_result (eval-hs-locals "d as HTML" (list (list (quote d) _node)))))
|
|
(assert= _result "<div id=\"myDiv\">With Text</div>")
|
|
))
|
|
)
|
|
(deftest "converts an input element into Values"
|
|
(let ((_node (dom-create-element "input")))
|
|
(host-set! _node "name" "test-name")
|
|
(host-set! _node "value" "test-value")
|
|
(let ((_result (eval-hs-locals "x as Values" (list (list (quote x) _node)))))
|
|
(assert= (host-get _result "test-name") "test-value")
|
|
))
|
|
)
|
|
(deftest "converts array as Reversed"
|
|
(assert= (eval-hs "[1,2,3] as Reversed") (list 3 2 1))
|
|
)
|
|
(deftest "converts array as Set"
|
|
(error "SKIP (untranslated): converts array as Set"))
|
|
(deftest "converts array as Unique"
|
|
(assert= (eval-hs "[1,2,2,3,3] as Unique") (list 1 2 3))
|
|
)
|
|
(deftest "converts arrays into fragments"
|
|
(error "SKIP (untranslated): converts arrays into fragments"))
|
|
(deftest "converts checkboxes into a Value correctly"
|
|
(let ((_node (dom-create-element "form")))
|
|
(dom-set-inner-html _node "<div> <input type=\"checkbox\" name=\"gender\" value=\"Male\" checked> <input type=\"checkbox\" name=\"gender\" value=\"Female\" checked> <input type=\"checkbox\" name=\"gender\" value=\"Other\" checked> </div>")
|
|
(let ((_result (eval-hs-locals "x as Values" (list (list (quote x) _node)))))
|
|
(assert= (nth (host-get _result "gender") 0) "Male")
|
|
(assert= (nth (host-get _result "gender") 1) "Female")
|
|
(assert= (nth (host-get _result "gender") 2) "Other")
|
|
))
|
|
)
|
|
(deftest "converts elements into fragments"
|
|
(error "SKIP (untranslated): converts elements into fragments"))
|
|
(deftest "converts multiple selects into a Value correctly"
|
|
(let ((_node (dom-create-element "form")))
|
|
(dom-set-inner-html _node "<select name=\"animal\" multiple> <option value=\"dog\" selected>Doggo</option> <option value=\"cat\">Kitteh</option> <option value=\"raccoon\" selected>Trash Panda</option> <option value=\"possum\">Sleepy Boi</option> </select>")
|
|
(let ((_result (eval-hs-locals "x as Values" (list (list (quote x) _node)))))
|
|
(assert= (nth (host-get _result "animal") 0) "dog")
|
|
(assert= (nth (host-get _result "animal") 1) "raccoon")
|
|
))
|
|
)
|
|
(deftest "converts multiple selects with programmatically changed selections"
|
|
(let ((_node (dom-create-element "form")))
|
|
(dom-set-inner-html _node "<select name=\"animal\" multiple> <option value=\"dog\" selected>Doggo</option> <option value=\"cat\">Kitteh</option> <option value=\"raccoon\" selected>Trash Panda</option> <option value=\"possum\">Sleepy Boi</option> </select>")
|
|
(let ((_sel (dom-query _node "select")))
|
|
(let ((_opts (host-get _sel "options")))
|
|
(host-set! (nth _opts 0) "selected" false)
|
|
(host-set! (nth _opts 1) "selected" true)
|
|
(let ((_result (eval-hs-locals "x as Values" (list (list (quote x) _node)))))
|
|
(assert= (nth (host-get _result "animal") 0) "cat")
|
|
(assert= (nth (host-get _result "animal") 1) "raccoon")
|
|
))))
|
|
)
|
|
(deftest "converts nested array as Flat"
|
|
(assert= (eval-hs "[[1,2],[3,4]] as Flat") (list 1 2 3 4))
|
|
)
|
|
(deftest "converts null as null"
|
|
(eval-hs "null as String")
|
|
)
|
|
(deftest "converts numbers things 'HTML'"
|
|
(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)))
|
|
)
|
|
(deftest "converts object as Keys"
|
|
(assert= (eval-hs "{a:1, b:2} as Keys") (list "a" "b"))
|
|
)
|
|
(deftest "converts object as Map"
|
|
(error "SKIP (untranslated): converts object as Map"))
|
|
(deftest "converts radio buttons into a Value correctly"
|
|
(let ((_node (dom-create-element "form")))
|
|
(dom-set-inner-html _node "<div> <input type=\"radio\" name=\"gender\" value=\"Male\" checked> <input type=\"radio\" name=\"gender\" value=\"Female\"> <input type=\"radio\" name=\"gender\" value=\"Other\"> </div>")
|
|
(let ((_result (eval-hs-locals "x as Values" (list (list (quote x) _node)))))
|
|
(assert= (host-get _result "gender") "Male")
|
|
))
|
|
)
|
|
(deftest "converts string as Object"
|
|
(assert= (host-get (eval-hs "'{\"foo\":\"bar\"}' as Object") "foo") "bar")
|
|
)
|
|
(deftest "converts strings into fragments"
|
|
(error "SKIP (untranslated): converts strings into fragments"))
|
|
(deftest "converts value as Boolean"
|
|
(assert= (eval-hs "1 as Boolean") true)
|
|
(assert= (eval-hs "0 as Boolean") false)
|
|
(assert= (eval-hs "'' as Boolean") false)
|
|
(assert= (eval-hs "'hello' as Boolean") true)
|
|
)
|
|
(deftest "converts value as Date"
|
|
(error "SKIP (untranslated): converts value as Date"))
|
|
(deftest "converts value as Fixed"
|
|
(assert= (eval-hs "'10.4' as Fixed") "10")
|
|
(assert= (eval-hs "'10.4899' as Fixed:2") "10.49")
|
|
)
|
|
(deftest "converts value as Float"
|
|
(assert= (eval-hs "'10' as Float") 10)
|
|
(assert= (eval-hs "'10.4' as Float") 10.4)
|
|
)
|
|
(deftest "converts value as Int"
|
|
(assert= (eval-hs "'10' as Int") 10)
|
|
(assert= (eval-hs "'10.4' as Int") 10)
|
|
)
|
|
(deftest "converts value as JSONString"
|
|
(assert= (eval-hs "{foo:'bar'} as JSONString") "{\"foo\":\"bar\"}")
|
|
)
|
|
(deftest "converts value as Number"
|
|
(assert= (eval-hs "'10' as Number") 10)
|
|
(assert= (eval-hs "'10.4' as Number") 10.4)
|
|
)
|
|
(deftest "converts value as Object"
|
|
(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")
|
|
(assert= (eval-hs "true as String") "true")
|
|
)
|
|
(deftest "parses string as JSON to object"
|
|
(assert= (host-get (eval-hs "'{\"foo\":\"bar\"}' as JSON") "foo") "bar")
|
|
)
|
|
(deftest "pipe operator chains conversions"
|
|
(assert= (host-get (eval-hs "{foo:'bar'} as JSONString | JSON") "foo") "bar")
|
|
)
|
|
)
|
|
|
|
;; ── expressions/assignableElements (8 tests) ──
|
|
(defsuite "hs-upstream-expressions/assignableElements"
|
|
(deftest "hyperscript in replacement content is initialized"
|
|
(hs-cleanup!)
|
|
(let ((_el-target (dom-create-element "div")) (_el-go (dom-create-element "button")))
|
|
(dom-set-attr _el-target "id" "target")
|
|
(dom-set-inner-html _el-target "old")
|
|
(dom-set-attr _el-go "id" "go")
|
|
(dom-set-attr _el-go "_" "on click set #target to '<div id=target _=\"on click put `clicked` into me\">new</div>'")
|
|
(dom-set-inner-html _el-go "go")
|
|
(dom-append (dom-body) _el-target)
|
|
(dom-append (dom-body) _el-go)
|
|
(hs-activate! _el-go)
|
|
(dom-dispatch (dom-query-by-id "go") "click" nil)
|
|
(assert= (dom-text-content (dom-query-by-id "target")) "new")
|
|
(dom-dispatch (dom-query-by-id "target") "click" nil)
|
|
(assert= (dom-text-content (dom-query-by-id "target")) "clicked")
|
|
))
|
|
(deftest "put into still works as innerHTML"
|
|
(hs-cleanup!)
|
|
(let ((_el-target (dom-create-element "div")) (_el-button (dom-create-element "button")))
|
|
(dom-set-attr _el-target "id" "target")
|
|
(dom-set-inner-html _el-target "old")
|
|
(dom-set-attr _el-button "_" "on click put \"new\" into #target")
|
|
(dom-set-inner-html _el-button "go")
|
|
(dom-append (dom-body) _el-target)
|
|
(dom-append (dom-body) _el-button)
|
|
(hs-activate! _el-button)
|
|
(dom-dispatch _el-button "click" nil)
|
|
(assert= (dom-text-content (dom-query-by-id "target")) "new")
|
|
))
|
|
(deftest "set #id replaces element with HTML string"
|
|
(hs-cleanup!)
|
|
(let ((_el-target (dom-create-element "div")) (_el-button (dom-create-element "button")))
|
|
(dom-set-attr _el-target "id" "target")
|
|
(dom-set-inner-html _el-target "old")
|
|
(dom-set-attr _el-button "_" "on click set #target to \"<span id=target>new</span>\"")
|
|
(dom-set-inner-html _el-button "go")
|
|
(dom-append (dom-body) _el-target)
|
|
(dom-append (dom-body) _el-button)
|
|
(hs-activate! _el-button)
|
|
(dom-dispatch _el-button "click" nil)
|
|
(assert= (dom-text-content (dom-query-by-id "target")) "new")
|
|
))
|
|
(deftest "set #id replaces element with another element"
|
|
(hs-cleanup!)
|
|
(let ((_el-target (dom-create-element "div")) (_el-button (dom-create-element "button")))
|
|
(dom-set-attr _el-target "id" "target")
|
|
(dom-set-inner-html _el-target "old")
|
|
(dom-set-attr _el-button "_" "on click make a <span.replaced/> then put \"moved\" into it then set #target to it")
|
|
(dom-set-inner-html _el-button "go")
|
|
(dom-append (dom-body) _el-target)
|
|
(dom-append (dom-body) _el-button)
|
|
(hs-activate! _el-button)
|
|
(dom-dispatch _el-button "click" nil)
|
|
))
|
|
(deftest "set .class replaces all matching elements"
|
|
(hs-cleanup!)
|
|
(let ((_el-list (dom-create-element "ul")) (_el-li (dom-create-element "li")) (_el-li2 (dom-create-element "li")) (_el-li3 (dom-create-element "li")) (_el-button (dom-create-element "button")))
|
|
(dom-set-attr _el-list "id" "list")
|
|
(dom-add-class _el-li "item")
|
|
(dom-set-inner-html _el-li "a")
|
|
(dom-add-class _el-li2 "item")
|
|
(dom-set-inner-html _el-li2 "b")
|
|
(dom-add-class _el-li3 "item")
|
|
(dom-set-inner-html _el-li3 "c")
|
|
(dom-set-attr _el-button "_" "on click set .item to \"<li class=item>replaced</li>\"")
|
|
(dom-set-inner-html _el-button "go")
|
|
(dom-append (dom-body) _el-list)
|
|
(dom-append _el-list _el-li)
|
|
(dom-append _el-list _el-li2)
|
|
(dom-append _el-list _el-li3)
|
|
(dom-append (dom-body) _el-button)
|
|
(hs-activate! _el-button)
|
|
(dom-dispatch _el-button "click" nil)
|
|
))
|
|
(deftest "set <query/> replaces all matching elements"
|
|
(hs-cleanup!)
|
|
(let ((_el-box (dom-create-element "div")) (_el-p (dom-create-element "p")) (_el-p2 (dom-create-element "p")) (_el-button (dom-create-element "button")))
|
|
(dom-set-attr _el-box "id" "box")
|
|
(dom-set-inner-html _el-p "one")
|
|
(dom-set-inner-html _el-p2 "two")
|
|
(dom-set-attr _el-button "_" "on click set <p/> in #box to \"<p>done</p>\"")
|
|
(dom-set-inner-html _el-button "go")
|
|
(dom-append (dom-body) _el-box)
|
|
(dom-append _el-box _el-p)
|
|
(dom-append _el-box _el-p2)
|
|
(dom-append (dom-body) _el-button)
|
|
(hs-activate! _el-button)
|
|
(dom-dispatch _el-button "click" nil)
|
|
))
|
|
(deftest "set closest replaces ancestor"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")) (_el-button (dom-create-element "button")))
|
|
(dom-add-class _el-div "wrapper")
|
|
(dom-set-attr _el-button "_" "on click set (closest <div/>) to \"<div class=wrapper>replaced</div>\"")
|
|
(dom-set-inner-html _el-button "go")
|
|
(dom-append (dom-body) _el-div)
|
|
(dom-append _el-div _el-button)
|
|
(hs-activate! _el-button)
|
|
(dom-dispatch _el-button "click" nil)
|
|
(assert= (dom-text-content (dom-query ".wrapper")) "replaced")
|
|
))
|
|
(deftest "swap #a with #b swaps DOM positions"
|
|
(hs-cleanup!)
|
|
(let ((_el-container (dom-create-element "div")) (_el-a (dom-create-element "div")) (_el-b (dom-create-element "div")) (_el-button (dom-create-element "button")))
|
|
(dom-set-attr _el-container "id" "container")
|
|
(dom-set-attr _el-a "id" "a")
|
|
(dom-set-inner-html _el-a "A")
|
|
(dom-set-attr _el-b "id" "b")
|
|
(dom-set-inner-html _el-b "B")
|
|
(dom-set-attr _el-button "_" "on click swap #a with #b")
|
|
(dom-set-inner-html _el-button "go")
|
|
(dom-append (dom-body) _el-container)
|
|
(dom-append _el-container _el-a)
|
|
(dom-append _el-container _el-b)
|
|
(dom-append (dom-body) _el-button)
|
|
(hs-activate! _el-button)
|
|
(dom-dispatch _el-button "click" nil)
|
|
))
|
|
)
|
|
|
|
;; ── expressions/attributeRef (22 tests) ──
|
|
(defsuite "hs-upstream-expressions/attributeRef"
|
|
(deftest "attributeRef can be put as symbol"
|
|
(hs-cleanup!)
|
|
(let ((_el-arDiv (dom-create-element "div")))
|
|
(dom-set-attr _el-arDiv "id" "arDiv")
|
|
(dom-set-attr _el-arDiv "_" "on click put \"blue\" into [@data-foo]")
|
|
(dom-set-attr _el-arDiv "data-foo" "red")
|
|
(dom-append (dom-body) _el-arDiv)
|
|
(hs-activate! _el-arDiv)
|
|
))
|
|
(deftest "attributeRef can be put as symbol w/ short syntax"
|
|
(hs-cleanup!)
|
|
(let ((_el-arDiv (dom-create-element "div")))
|
|
(dom-set-attr _el-arDiv "id" "arDiv")
|
|
(dom-set-attr _el-arDiv "_" "on click put \"blue\" into @data-foo")
|
|
(dom-set-attr _el-arDiv "data-foo" "red")
|
|
(dom-append (dom-body) _el-arDiv)
|
|
(hs-activate! _el-arDiv)
|
|
))
|
|
(deftest "attributeRef can be put indirectly"
|
|
(hs-cleanup!)
|
|
(let ((_el-arDiv (dom-create-element "div")))
|
|
(dom-set-attr _el-arDiv "id" "arDiv")
|
|
(dom-set-attr _el-arDiv "data-foo" "red")
|
|
(dom-append (dom-body) _el-arDiv)
|
|
))
|
|
(deftest "attributeRef can be put indirectly w/ short syntax"
|
|
(hs-cleanup!)
|
|
(let ((_el-arDiv (dom-create-element "div")))
|
|
(dom-set-attr _el-arDiv "id" "arDiv")
|
|
(dom-set-attr _el-arDiv "data-foo" "red")
|
|
(dom-append (dom-body) _el-arDiv)
|
|
))
|
|
(deftest "attributeRef can be set as prop"
|
|
(hs-cleanup!)
|
|
(let ((_el-arDiv (dom-create-element "div")))
|
|
(dom-set-attr _el-arDiv "id" "arDiv")
|
|
(dom-set-attr _el-arDiv "data-foo" "red")
|
|
(dom-append (dom-body) _el-arDiv)
|
|
))
|
|
(deftest "attributeRef can be set as prop w/ short syntax"
|
|
(hs-cleanup!)
|
|
(let ((_el-arDiv (dom-create-element "div")))
|
|
(dom-set-attr _el-arDiv "id" "arDiv")
|
|
(dom-set-attr _el-arDiv "data-foo" "red")
|
|
(dom-append (dom-body) _el-arDiv)
|
|
))
|
|
(deftest "attributeRef can be set as symbol"
|
|
(hs-cleanup!)
|
|
(let ((_el-arDiv (dom-create-element "div")))
|
|
(dom-set-attr _el-arDiv "id" "arDiv")
|
|
(dom-set-attr _el-arDiv "_" "on click set [@data-foo] to \"blue\"")
|
|
(dom-set-attr _el-arDiv "data-foo" "red")
|
|
(dom-append (dom-body) _el-arDiv)
|
|
(hs-activate! _el-arDiv)
|
|
))
|
|
(deftest "attributeRef can be set as symbol w/ short syntax"
|
|
(hs-cleanup!)
|
|
(let ((_el-arDiv (dom-create-element "div")))
|
|
(dom-set-attr _el-arDiv "id" "arDiv")
|
|
(dom-set-attr _el-arDiv "_" "on click set @data-foo to \"blue\"")
|
|
(dom-set-attr _el-arDiv "data-foo" "red")
|
|
(dom-append (dom-body) _el-arDiv)
|
|
(hs-activate! _el-arDiv)
|
|
))
|
|
(deftest "attributeRef can be set indirectly"
|
|
(hs-cleanup!)
|
|
(let ((_el-arDiv (dom-create-element "div")))
|
|
(dom-set-attr _el-arDiv "id" "arDiv")
|
|
(dom-set-attr _el-arDiv "data-foo" "red")
|
|
(dom-append (dom-body) _el-arDiv)
|
|
))
|
|
(deftest "attributeRef can be set indirectly w/ short syntax"
|
|
(hs-cleanup!)
|
|
(let ((_el-arDiv (dom-create-element "div")))
|
|
(dom-set-attr _el-arDiv "id" "arDiv")
|
|
(dom-set-attr _el-arDiv "data-foo" "red")
|
|
(dom-append (dom-body) _el-arDiv)
|
|
))
|
|
(deftest "attributeRef can be set through possessive"
|
|
(hs-cleanup!)
|
|
(let ((_el-arDiv (dom-create-element "div")))
|
|
(dom-set-attr _el-arDiv "id" "arDiv")
|
|
(dom-set-attr _el-arDiv "_" "on click set my [@data-foo] to \"blue\"")
|
|
(dom-set-attr _el-arDiv "data-foo" "red")
|
|
(dom-append (dom-body) _el-arDiv)
|
|
(hs-activate! _el-arDiv)
|
|
))
|
|
(deftest "attributeRef can be set through possessive w/ short syntax"
|
|
(hs-cleanup!)
|
|
(let ((_el-arDiv (dom-create-element "div")))
|
|
(dom-set-attr _el-arDiv "id" "arDiv")
|
|
(dom-set-attr _el-arDiv "_" "on click set my @data-foo to \"blue\"")
|
|
(dom-set-attr _el-arDiv "data-foo" "red")
|
|
(dom-append (dom-body) _el-arDiv)
|
|
(hs-activate! _el-arDiv)
|
|
))
|
|
(deftest "attributeRef can have value in quotes used in add commands"
|
|
(hs-cleanup!)
|
|
(let ((_el-arDiv (dom-create-element "div")))
|
|
(dom-set-attr _el-arDiv "id" "arDiv")
|
|
(dom-set-attr _el-arDiv "_" "on click add [@data-foo=\"blue\"]")
|
|
(dom-set-attr _el-arDiv "data-foo" "red")
|
|
(dom-append (dom-body) _el-arDiv)
|
|
(hs-activate! _el-arDiv)
|
|
))
|
|
(deftest "attributeRef can have value in quotes used in add commands w/ short syntax"
|
|
(hs-cleanup!)
|
|
(let ((_el-arDiv (dom-create-element "div")))
|
|
(dom-set-attr _el-arDiv "id" "arDiv")
|
|
(dom-set-attr _el-arDiv "_" "on click add @data-foo=\"blue\"")
|
|
(dom-set-attr _el-arDiv "data-foo" "red")
|
|
(dom-append (dom-body) _el-arDiv)
|
|
(hs-activate! _el-arDiv)
|
|
))
|
|
(deftest "attributeRef can have value in quotes with spaces used in add commands"
|
|
(hs-cleanup!)
|
|
(let ((_el-arDiv (dom-create-element "div")))
|
|
(dom-set-attr _el-arDiv "id" "arDiv")
|
|
(dom-set-attr _el-arDiv "_" "on click add [@data-foo=\"blue green\"]")
|
|
(dom-set-attr _el-arDiv "data-foo" "red")
|
|
(dom-append (dom-body) _el-arDiv)
|
|
(hs-activate! _el-arDiv)
|
|
))
|
|
(deftest "attributeRef can have value in quotes with spaces used in add commands w/ short syntax"
|
|
(hs-cleanup!)
|
|
(let ((_el-arDiv (dom-create-element "div")))
|
|
(dom-set-attr _el-arDiv "id" "arDiv")
|
|
(dom-set-attr _el-arDiv "_" "on click add @data-foo=\"blue green\"")
|
|
(dom-set-attr _el-arDiv "data-foo" "red")
|
|
(dom-append (dom-body) _el-arDiv)
|
|
(hs-activate! _el-arDiv)
|
|
))
|
|
(deftest "attributeRef can have value used in add commands"
|
|
(hs-cleanup!)
|
|
(let ((_el-arDiv (dom-create-element "div")))
|
|
(dom-set-attr _el-arDiv "id" "arDiv")
|
|
(dom-set-attr _el-arDiv "_" "on click add [@data-foo=blue]")
|
|
(dom-set-attr _el-arDiv "data-foo" "red")
|
|
(dom-append (dom-body) _el-arDiv)
|
|
(hs-activate! _el-arDiv)
|
|
))
|
|
(deftest "attributeRef can have value used in add commands w/ short syntax"
|
|
(hs-cleanup!)
|
|
(let ((_el-arDiv (dom-create-element "div")))
|
|
(dom-set-attr _el-arDiv "id" "arDiv")
|
|
(dom-set-attr _el-arDiv "_" "on click add @data-foo=blue")
|
|
(dom-set-attr _el-arDiv "data-foo" "red")
|
|
(dom-append (dom-body) _el-arDiv)
|
|
(hs-activate! _el-arDiv)
|
|
))
|
|
(deftest "attributeRef with dashes name works"
|
|
(hs-cleanup!)
|
|
(let ((_el-arDiv (dom-create-element "div")))
|
|
(dom-set-attr _el-arDiv "id" "arDiv")
|
|
(dom-set-attr _el-arDiv "data-foo" "c1")
|
|
(dom-append (dom-body) _el-arDiv)
|
|
))
|
|
(deftest "attributeRef with dashes name works w/ short syntax"
|
|
(hs-cleanup!)
|
|
(let ((_el-arDiv (dom-create-element "div")))
|
|
(dom-set-attr _el-arDiv "id" "arDiv")
|
|
(dom-set-attr _el-arDiv "data-foo" "c1")
|
|
(dom-append (dom-body) _el-arDiv)
|
|
))
|
|
(deftest "attributeRef with no value works"
|
|
(hs-cleanup!)
|
|
(let ((_el-arDiv (dom-create-element "div")))
|
|
(dom-set-attr _el-arDiv "id" "arDiv")
|
|
(dom-set-attr _el-arDiv "foo" "c1")
|
|
(dom-append (dom-body) _el-arDiv)
|
|
))
|
|
(deftest "attributeRef with no value works w/ short syntax"
|
|
(hs-cleanup!)
|
|
(let ((_el-arDiv (dom-create-element "div")))
|
|
(dom-set-attr _el-arDiv "id" "arDiv")
|
|
(dom-set-attr _el-arDiv "foo" "c1")
|
|
(dom-append (dom-body) _el-arDiv)
|
|
))
|
|
)
|
|
|
|
;; ── expressions/beep! (6 tests) ──
|
|
(defsuite "hs-upstream-expressions/beep!"
|
|
(deftest "beeps a basic value"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click get beep! 10")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
))
|
|
(deftest "beeps a formatted string value"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click get beep! \"foo\"")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
))
|
|
(deftest "beeps a null value"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click get beep! null")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
))
|
|
(deftest "beeps the result of an ElementCollection"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-add-class _el-div "foo")
|
|
(dom-set-attr _el-div "_" "on click get beep! .foo")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
))
|
|
(deftest "can be cancelled"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on hyperscript:beep halt on click get beep! \"foo\"")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
))
|
|
(deftest "can capture information from event"
|
|
(hs-cleanup!)
|
|
(let ((_el-beepDiv (dom-create-element "div")))
|
|
(dom-set-attr _el-beepDiv "id" "beepDiv")
|
|
(dom-set-attr _el-beepDiv "_" "on hyperscript:beep(value) set my @data-value to the value on click get beep! \"foo\"")
|
|
(dom-append (dom-body) _el-beepDiv)
|
|
(hs-activate! _el-beepDiv)
|
|
))
|
|
)
|
|
|
|
;; ── expressions/blockLiteral (4 tests) ──
|
|
(defsuite "hs-upstream-expressions/blockLiteral"
|
|
(deftest "basic block literals work"
|
|
(assert= (apply (eval-expr-cek (hs-to-sx (hs-compile "\\ -> true"))) (list)) true)
|
|
)
|
|
(deftest "basic identity works"
|
|
(assert= (apply (eval-expr-cek (hs-to-sx (hs-compile "\\ x -> x"))) (list true)) true)
|
|
)
|
|
(deftest "basic two arg identity works"
|
|
(assert= (apply (eval-expr-cek (hs-to-sx (hs-compile "\\ x, y -> y"))) (list false true)) true)
|
|
)
|
|
(deftest "can map an array"
|
|
(assert= (map (eval-expr-cek (hs-to-sx (hs-compile "\\ s -> s.length"))) (list "a" "ab" "abc")) (list 1 2 3))
|
|
)
|
|
)
|
|
|
|
;; ── expressions/boolean (2 tests) ──
|
|
(defsuite "hs-upstream-expressions/boolean"
|
|
(deftest "false boolean literals work"
|
|
(assert= (eval-hs "false") false)
|
|
)
|
|
(deftest "true boolean literals work"
|
|
(assert= (eval-hs "true") true)
|
|
)
|
|
)
|
|
|
|
;; ── expressions/classRef (9 tests) ──
|
|
(defsuite "hs-upstream-expressions/classRef"
|
|
(deftest "basic classRef works"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-add-class _el-div "c1")
|
|
(dom-append (dom-body) _el-div)
|
|
))
|
|
(deftest "basic classRef works w no match"
|
|
(error "SKIP (untranslated): basic classRef works w no match"))
|
|
(deftest "colon class ref works"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-add-class _el-div "c1:foo")
|
|
(dom-append (dom-body) _el-div)
|
|
))
|
|
(deftest "dashed class ref works"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-add-class _el-div "c1-foo")
|
|
(dom-append (dom-body) _el-div)
|
|
))
|
|
(deftest "leading minus class ref works"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-add-class _el-div "-c1")
|
|
(dom-append (dom-body) _el-div)
|
|
))
|
|
(deftest "multiple colon class ref works"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-add-class _el-div "c1:foo:bar")
|
|
(dom-append (dom-body) _el-div)
|
|
))
|
|
(deftest "slashes in class references work"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-add-class _el-div "-c1/22")
|
|
(dom-append (dom-body) _el-div)
|
|
))
|
|
(deftest "tailwind insanity in class references work"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-add-class _el-div "group-[:nth-of-type(3)_&]:block")
|
|
(dom-append (dom-body) _el-div)
|
|
))
|
|
(deftest "template classRef works"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-add-class _el-div "c1")
|
|
(dom-append (dom-body) _el-div)
|
|
))
|
|
)
|
|
|
|
;; ── expressions/closest (10 tests) ──
|
|
(defsuite "hs-upstream-expressions/closest"
|
|
(deftest "attributes can be looked up and referred to in same expression"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")) (_el-d1 (dom-create-element "div")))
|
|
(dom-set-attr _el-div "foo" "bar")
|
|
(dom-set-attr _el-d1 "id" "d1")
|
|
(dom-set-attr _el-d1 "_" "on click put closest @foo into me")
|
|
(dom-append (dom-body) _el-div)
|
|
(dom-append _el-div _el-d1)
|
|
(hs-activate! _el-d1)
|
|
))
|
|
(deftest "attributes can be set via the closest expression"
|
|
(hs-cleanup!)
|
|
(let ((_el-outerDiv (dom-create-element "div")) (_el-d1 (dom-create-element "div")))
|
|
(dom-set-attr _el-outerDiv "id" "outerDiv")
|
|
(dom-set-attr _el-outerDiv "foo" "bar")
|
|
(dom-set-attr _el-d1 "id" "d1")
|
|
(dom-set-attr _el-d1 "_" "on click set closest @foo to \"doh\"")
|
|
(dom-append (dom-body) _el-outerDiv)
|
|
(dom-append _el-outerDiv _el-d1)
|
|
(hs-activate! _el-d1)
|
|
))
|
|
(deftest "attributes can be set via the closest expression 2"
|
|
(hs-cleanup!)
|
|
(let ((_el-outerDiv2 (dom-create-element "div")) (_el-d1b (dom-create-element "div")))
|
|
(dom-set-attr _el-outerDiv2 "id" "outerDiv2")
|
|
(dom-set-attr _el-outerDiv2 "foo" "bar")
|
|
(dom-set-attr _el-d1b "id" "d1b")
|
|
(dom-set-attr _el-d1b "_" "on click set closest @foo to \"doh\"")
|
|
(dom-append (dom-body) _el-outerDiv2)
|
|
(dom-append _el-outerDiv2 _el-d1b)
|
|
(hs-activate! _el-d1b)
|
|
))
|
|
(deftest "attributes resolve as attributes"
|
|
(hs-cleanup!)
|
|
(let ((_el-d3 (dom-create-element "div")) (_el-d1 (dom-create-element "div")) (_el-d2 (dom-create-element "div")))
|
|
(dom-set-attr _el-d3 "id" "d3")
|
|
(dom-set-attr _el-d3 "foo" "bar")
|
|
(dom-set-attr _el-d1 "id" "d1")
|
|
(dom-set-attr _el-d2 "id" "d2")
|
|
(dom-append (dom-body) _el-d3)
|
|
(dom-append _el-d3 _el-d1)
|
|
(dom-append _el-d3 _el-d2)
|
|
))
|
|
(deftest "basic query return values"
|
|
(hs-cleanup!)
|
|
(let ((_el-d3 (dom-create-element "div")) (_el-d1 (dom-create-element "div")) (_el-d2 (dom-create-element "div")))
|
|
(dom-set-attr _el-d3 "id" "d3")
|
|
(dom-set-attr _el-d1 "id" "d1")
|
|
(dom-set-attr _el-d2 "id" "d2")
|
|
(dom-append (dom-body) _el-d3)
|
|
(dom-append _el-d3 _el-d1)
|
|
(dom-append _el-d3 _el-d2)
|
|
))
|
|
(deftest "closest does not consume a following where clause"
|
|
(hs-cleanup!)
|
|
(let ((_el-table (dom-create-element "table")) (_el-tr (dom-create-element "tr")) (_el-td (dom-create-element "td")) (_el-input (dom-create-element "input")) (_el-input4 (dom-create-element "input")) (_el-master (dom-create-element "input")) (_el-out (dom-create-element "div")))
|
|
(dom-add-class _el-input "cb")
|
|
(dom-set-attr _el-input "type" "checkbox")
|
|
(dom-add-class _el-input4 "cb")
|
|
(dom-set-attr _el-input4 "type" "checkbox")
|
|
(dom-set-attr _el-master "id" "master")
|
|
(dom-set-attr _el-master "_" "set :others to <input[type=checkbox]/> in the closest <table/> where it is not me on click put :others.length into #out")
|
|
(dom-set-attr _el-master "type" "checkbox")
|
|
(dom-set-attr _el-out "id" "out")
|
|
(dom-append (dom-body) _el-table)
|
|
(dom-append _el-table _el-tr)
|
|
(dom-append _el-tr _el-td)
|
|
(dom-append _el-td _el-input)
|
|
(dom-append _el-td _el-input4)
|
|
(dom-append _el-td _el-master)
|
|
(dom-append (dom-body) _el-out)
|
|
(hs-activate! _el-master)
|
|
(dom-dispatch (dom-query-by-id "master") "click" nil)
|
|
(assert= (dom-text-content (dom-query-by-id "out")) "2")
|
|
))
|
|
(deftest "closest with to modifier still works after parse change"
|
|
(hs-cleanup!)
|
|
(let ((_el-outer (dom-create-element "div")) (_el-inner (dom-create-element "div")))
|
|
(dom-set-attr _el-outer "id" "outer")
|
|
(dom-set-attr _el-inner "id" "inner")
|
|
(dom-append (dom-body) _el-outer)
|
|
(dom-append _el-outer _el-inner)
|
|
))
|
|
(deftest "parent modifier works"
|
|
(hs-cleanup!)
|
|
(let ((_el-d3 (dom-create-element "div")) (_el-d1 (dom-create-element "div")) (_el-d2 (dom-create-element "div")))
|
|
(dom-set-attr _el-d3 "id" "d3")
|
|
(dom-set-attr _el-d1 "id" "d1")
|
|
(dom-set-attr _el-d2 "id" "d2")
|
|
(dom-append (dom-body) _el-d3)
|
|
(dom-append _el-d3 _el-d1)
|
|
(dom-append _el-d3 _el-d2)
|
|
))
|
|
(deftest "parenthesizing allows you to nest to modifiers properly"
|
|
(hs-cleanup!)
|
|
(let ((_el-outerDiv (dom-create-element "div")) (_el-d1 (dom-create-element "div")) (_el-div2 (dom-create-element "div")))
|
|
(dom-set-attr _el-outerDiv "id" "outerDiv")
|
|
(dom-set-attr _el-outerDiv "foo" "bar")
|
|
(dom-set-attr _el-d1 "id" "d1")
|
|
(dom-set-attr _el-div2 "id" "div2")
|
|
(dom-set-attr _el-div2 "_" "on click set (closest @foo to #d1) to \"doh\"")
|
|
(dom-append (dom-body) _el-outerDiv)
|
|
(dom-append _el-outerDiv _el-d1)
|
|
(dom-append (dom-body) _el-div2)
|
|
(hs-activate! _el-div2)
|
|
))
|
|
(deftest "returns an array where appropriate"
|
|
(hs-cleanup!)
|
|
(let ((_el-d2 (dom-create-element "div")) (_el-d1 (dom-create-element "div")) (_el-d3 (dom-create-element "div")) (_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-d2 "id" "d2")
|
|
(dom-add-class _el-d2 "bar")
|
|
(dom-set-attr _el-d1 "id" "d1")
|
|
(dom-add-class _el-d1 "foo")
|
|
(dom-set-attr _el-d1 "_" "on click add .doh to closest .bar to .foo")
|
|
(dom-set-attr _el-d3 "id" "d3")
|
|
(dom-add-class _el-d3 "bar")
|
|
(dom-add-class _el-div "foo")
|
|
(dom-append (dom-body) _el-d2)
|
|
(dom-append _el-d2 _el-d1)
|
|
(dom-append (dom-body) _el-d3)
|
|
(dom-append _el-d3 _el-div)
|
|
(hs-activate! _el-d1)
|
|
))
|
|
)
|
|
|
|
;; ── expressions/collectionExpressions (28 tests) ──
|
|
(defsuite "hs-upstream-expressions/collectionExpressions"
|
|
(deftest "filters an array by condition"
|
|
(assert= (map (fn (x) (get x "name")) (eval-hs "set arr to [{name: \"a\", active: true}, {name: \"b\", active: false}, {name: \"c\", active: true}] then return arr where its active")) (list "a" "c"))
|
|
)
|
|
(deftest "filters with comparison"
|
|
(assert= (eval-hs "set arr to [1, 2, 3, 4, 5] then return arr where it > 3") (list 4 5))
|
|
)
|
|
(deftest "full select-all pattern with multiple on features"
|
|
(hs-cleanup!)
|
|
(let ((_el-table (dom-create-element "table")) (_el-tr (dom-create-element "tr")) (_el-td (dom-create-element "td")) (_el-input (dom-create-element "input")) (_el-tr4 (dom-create-element "tr")) (_el-td5 (dom-create-element "td")) (_el-input6 (dom-create-element "input")) (_el-tr7 (dom-create-element "tr")) (_el-td8 (dom-create-element "td")) (_el-input9 (dom-create-element "input")) (_el-tr10 (dom-create-element "tr")) (_el-td11 (dom-create-element "td")) (_el-master (dom-create-element "input")))
|
|
(dom-add-class _el-input "cb")
|
|
(dom-set-attr _el-input "type" "checkbox")
|
|
(dom-set-attr _el-input "checked" "")
|
|
(dom-add-class _el-input6 "cb")
|
|
(dom-set-attr _el-input6 "type" "checkbox")
|
|
(dom-add-class _el-input9 "cb")
|
|
(dom-set-attr _el-input9 "type" "checkbox")
|
|
(dom-set-attr _el-input9 "checked" "")
|
|
(dom-set-attr _el-master "id" "master")
|
|
(dom-set-attr _el-master "_" "set :checkboxes to <input[type=checkbox]/> in the closest <table/> where it is not me then on change set checked of the :checkboxes to my checked then on change from the closest <table/> then if no :checkboxes where it is checked then set my indeterminate to false then set my checked to false else if no :checkboxes where it is not checked then set my indeterminate to false then set my checked to true else set my indeterminate to true end")
|
|
(dom-set-attr _el-master "type" "checkbox")
|
|
(dom-append (dom-body) _el-table)
|
|
(dom-append _el-table _el-tr)
|
|
(dom-append _el-tr _el-td)
|
|
(dom-append _el-td _el-input)
|
|
(dom-append _el-table _el-tr4)
|
|
(dom-append _el-tr4 _el-td5)
|
|
(dom-append _el-td5 _el-input6)
|
|
(dom-append _el-table _el-tr7)
|
|
(dom-append _el-tr7 _el-td8)
|
|
(dom-append _el-td8 _el-input9)
|
|
(dom-append _el-table _el-tr10)
|
|
(dom-append _el-tr10 _el-td11)
|
|
(dom-append _el-td11 _el-master)
|
|
(hs-activate! _el-master)
|
|
(dom-dispatch (dom-query-by-id "master") "click" nil)
|
|
(dom-dispatch (nth (dom-query-all (dom-body) ".cb") 0) "click" nil)
|
|
))
|
|
(deftest "joined by on null returns null"
|
|
(eval-hs "set x to null then return x joined by ','")
|
|
)
|
|
(deftest "mapped to on null returns null"
|
|
(eval-hs "set x to null then return x mapped to (it * 2)")
|
|
)
|
|
(deftest "maps to a property"
|
|
(assert= (eval-hs "set arr to [{name: \"Alice\"}, {name: \"Bob\"}] then return arr mapped to its name") (list "Alice" "Bob"))
|
|
)
|
|
(deftest "maps with an expression"
|
|
(assert= (eval-hs "set arr to [1, 2, 3] then return arr mapped to (it * 2)") (list 2 4 6))
|
|
)
|
|
(deftest "sorted by binds after in without parens"
|
|
(hs-cleanup!)
|
|
(let ((_el-list (dom-create-element "ul")) (_el-li (dom-create-element "li")) (_el-li2 (dom-create-element "li")) (_el-li3 (dom-create-element "li")))
|
|
(dom-set-attr _el-list "id" "list")
|
|
(dom-set-inner-html _el-li "C")
|
|
(dom-set-inner-html _el-li2 "A")
|
|
(dom-set-inner-html _el-li3 "B")
|
|
(dom-append (dom-body) _el-list)
|
|
(dom-append _el-list _el-li)
|
|
(dom-append _el-list _el-li2)
|
|
(dom-append _el-list _el-li3)
|
|
))
|
|
(deftest "sorted by on null returns null"
|
|
(eval-hs "set x to null then return x sorted by it")
|
|
)
|
|
(deftest "sorted by then mapped to"
|
|
(assert= (eval-hs "set arr to [{name: \"Charlie\", age: 30}, {name: \"Alice\", age: 20}] then return arr sorted by its age mapped to its name") (list "Alice" "Charlie"))
|
|
)
|
|
(deftest "sorts by a property"
|
|
(assert= (map (fn (x) (get x "name")) (eval-hs "set arr to [{name: \"Charlie\"}, {name: \"Alice\"}, {name: \"Bob\"}] then return arr sorted by its name")) (list "Alice" "Bob" "Charlie"))
|
|
)
|
|
(deftest "sorts descending"
|
|
(assert= (eval-hs "set arr to [3, 1, 2] then return arr sorted by it descending") (list 3 2 1))
|
|
)
|
|
(deftest "sorts numbers by a computed key"
|
|
(assert= (map (fn (x) (get x "name")) (eval-hs "set arr to [{name: \"b\", age: 30}, {name: \"a\", age: 20}, {name: \"c\", age: 25}] then return arr sorted by its age")) (list "a" "c" "b"))
|
|
)
|
|
(deftest "split by on null returns null"
|
|
(eval-hs "set x to null then return x split by ','\\n")
|
|
)
|
|
(deftest "the result inside where refers to previous command result, not current element"
|
|
(assert= (eval-hs "get 3 then set arr to [1, 2, 3, 4, 5] then return arr where it > the result") (list 4 5))
|
|
)
|
|
(deftest "where after in with mapped to"
|
|
(hs-cleanup!)
|
|
(let ((_el-items (dom-create-element "ul")) (_el-li (dom-create-element "li")) (_el-li2 (dom-create-element "li")) (_el-li3 (dom-create-element "li")))
|
|
(dom-set-attr _el-items "id" "items")
|
|
(dom-add-class _el-li "yes")
|
|
(dom-set-inner-html _el-li "A")
|
|
(dom-set-inner-html _el-li2 "B")
|
|
(dom-add-class _el-li3 "yes")
|
|
(dom-set-inner-html _el-li3 "C")
|
|
(dom-append (dom-body) _el-items)
|
|
(dom-append _el-items _el-li)
|
|
(dom-append _el-items _el-li2)
|
|
(dom-append _el-items _el-li3)
|
|
))
|
|
(deftest "where binds after in on closest"
|
|
(hs-cleanup!)
|
|
(let ((_el-box (dom-create-element "div")) (_el-span (dom-create-element "span")) (_el-span2 (dom-create-element "span")) (_el-span3 (dom-create-element "span")) (_el-button (dom-create-element "button")) (_el-b2 (dom-create-element "button")))
|
|
(dom-set-attr _el-box "id" "box")
|
|
(dom-add-class _el-span "a")
|
|
(dom-set-inner-html _el-span "A")
|
|
(dom-add-class _el-span2 "b")
|
|
(dom-set-inner-html _el-span2 "B")
|
|
(dom-add-class _el-span3 "a")
|
|
(dom-set-inner-html _el-span3 "C")
|
|
(dom-set-attr _el-button "_" "on click set result to (<span/> in #box) where it matches .a then put result.length into me")
|
|
(dom-set-inner-html _el-button "go (parens)")
|
|
(dom-set-attr _el-b2 "id" "b2")
|
|
(dom-set-attr _el-b2 "_" "on click set result to <span/> in #box where it matches .a then put result.length into me")
|
|
(dom-set-inner-html _el-b2 "go")
|
|
(dom-append (dom-body) _el-box)
|
|
(dom-append _el-box _el-span)
|
|
(dom-append _el-box _el-span2)
|
|
(dom-append _el-box _el-span3)
|
|
(dom-append (dom-body) _el-button)
|
|
(dom-append (dom-body) _el-b2)
|
|
(hs-activate! _el-button)
|
|
(hs-activate! _el-b2)
|
|
(dom-dispatch (nth (dom-query-all (dom-body) "button") 0) "click" nil)
|
|
(assert= (dom-text-content (nth (dom-query-all (dom-body) "button") 0)) "2")
|
|
(dom-dispatch (dom-query-by-id "b2") "click" nil)
|
|
(assert= (dom-text-content (dom-query-by-id "b2")) "2")
|
|
))
|
|
(deftest "where binds after in without parens"
|
|
(hs-cleanup!)
|
|
(let ((_el-container (dom-create-element "div")) (_el-span (dom-create-element "span")) (_el-span2 (dom-create-element "span")) (_el-span3 (dom-create-element "span")))
|
|
(dom-set-attr _el-container "id" "container")
|
|
(dom-add-class _el-span "a")
|
|
(dom-set-inner-html _el-span "A")
|
|
(dom-add-class _el-span2 "b")
|
|
(dom-set-inner-html _el-span2 "B")
|
|
(dom-add-class _el-span3 "a")
|
|
(dom-set-inner-html _el-span3 "C")
|
|
(dom-append (dom-body) _el-container)
|
|
(dom-append _el-container _el-span)
|
|
(dom-append _el-container _el-span2)
|
|
(dom-append _el-container _el-span3)
|
|
))
|
|
(deftest "where binds after property access"
|
|
(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!)
|
|
(let ((_el-box (dom-create-element "div")) (_el-span (dom-create-element "span")) (_el-span2 (dom-create-element "span")) (_el-script (dom-create-element "script")) (_el-test-where-comp (dom-create-element "test-where-comp")))
|
|
(dom-set-attr _el-box "id" "box")
|
|
(dom-add-class _el-span "a")
|
|
(dom-set-inner-html _el-span "A")
|
|
(dom-add-class _el-span2 "b")
|
|
(dom-set-inner-html _el-span2 "B")
|
|
(dom-set-attr _el-script "_" "set :items to <span/> in #box where it matches .a then on click put :items.length into me")
|
|
(dom-set-attr _el-script "type" "text/hyperscript-template")
|
|
(dom-set-attr _el-script "component" "test-where-comp")
|
|
(dom-set-inner-html _el-script "<slot/>")
|
|
(dom-set-inner-html _el-test-where-comp "go")
|
|
(dom-append (dom-body) _el-box)
|
|
(dom-append _el-box _el-span)
|
|
(dom-append _el-box _el-span2)
|
|
(dom-append (dom-body) _el-script)
|
|
(dom-append (dom-body) _el-test-where-comp)
|
|
(hs-activate! _el-script)
|
|
(dom-dispatch _el-test-where-comp "click" nil)
|
|
(assert= (dom-text-content _el-test-where-comp) "1")
|
|
))
|
|
(deftest "where in init followed by on feature"
|
|
(hs-cleanup!)
|
|
(let ((_el-box (dom-create-element "div")) (_el-span (dom-create-element "span")) (_el-span2 (dom-create-element "span")) (_el-button (dom-create-element "button")))
|
|
(dom-set-attr _el-box "id" "box")
|
|
(dom-add-class _el-span "a")
|
|
(dom-set-inner-html _el-span "A")
|
|
(dom-add-class _el-span2 "b")
|
|
(dom-set-inner-html _el-span2 "B")
|
|
(dom-set-attr _el-button "_" "set :items to <span/> in #box where it matches .a on click put :items.length into me")
|
|
(dom-set-inner-html _el-button "go")
|
|
(dom-append (dom-body) _el-box)
|
|
(dom-append _el-box _el-span)
|
|
(dom-append _el-box _el-span2)
|
|
(dom-append (dom-body) _el-button)
|
|
(hs-activate! _el-button)
|
|
(dom-dispatch _el-button "click" nil)
|
|
(assert= (dom-text-content _el-button) "1")
|
|
))
|
|
(deftest "where on null returns null"
|
|
(eval-hs "set x to null then return x where it > 1")
|
|
)
|
|
(deftest "where on undefined returns undefined"
|
|
(eval-hs "return doesNotExist where it > 1")
|
|
)
|
|
(deftest "where then mapped to"
|
|
(assert= (eval-hs "set arr to [{name: \"Alice\", active: true}, {name: \"Bob\", active: false}, {name: \"Charlie\", active: true}] then return arr where its active mapped to its name") (list "Alice" "Charlie"))
|
|
)
|
|
(deftest "where then sorted by then mapped to"
|
|
(assert= (eval-hs "set arr to [{name: \"Charlie\", active: true, age: 30}, {name: \"Alice\", active: false, age: 20}, {name: \"Bob\", active: true, age: 25}] then return arr where its active sorted by its age mapped to its name") (list "Bob" "Charlie"))
|
|
)
|
|
(deftest "where with is not me followed by on feature"
|
|
(hs-cleanup!)
|
|
(let ((_el-table (dom-create-element "table")) (_el-tr (dom-create-element "tr")) (_el-td (dom-create-element "td")) (_el-input (dom-create-element "input")) (_el-tr4 (dom-create-element "tr")) (_el-td5 (dom-create-element "td")) (_el-input6 (dom-create-element "input")) (_el-tr7 (dom-create-element "tr")) (_el-td8 (dom-create-element "td")) (_el-input9 (dom-create-element "input")) (_el-tr10 (dom-create-element "tr")) (_el-td11 (dom-create-element "td")) (_el-master (dom-create-element "input")))
|
|
(dom-add-class _el-input "cb")
|
|
(dom-set-attr _el-input "type" "checkbox")
|
|
(dom-set-attr _el-input "checked" "")
|
|
(dom-add-class _el-input6 "cb")
|
|
(dom-set-attr _el-input6 "type" "checkbox")
|
|
(dom-add-class _el-input9 "cb")
|
|
(dom-set-attr _el-input9 "type" "checkbox")
|
|
(dom-set-attr _el-input9 "checked" "")
|
|
(dom-set-attr _el-master "id" "master")
|
|
(dom-set-attr _el-master "_" "set :checkboxes to <input[type=checkbox]/> in the closest <table/> where it is not me then on change set checked of the :checkboxes to my checked")
|
|
(dom-set-attr _el-master "type" "checkbox")
|
|
(dom-append (dom-body) _el-table)
|
|
(dom-append _el-table _el-tr)
|
|
(dom-append _el-tr _el-td)
|
|
(dom-append _el-td _el-input)
|
|
(dom-append _el-table _el-tr4)
|
|
(dom-append _el-tr4 _el-td5)
|
|
(dom-append _el-td5 _el-input6)
|
|
(dom-append _el-table _el-tr7)
|
|
(dom-append _el-tr7 _el-td8)
|
|
(dom-append _el-td8 _el-input9)
|
|
(dom-append _el-table _el-tr10)
|
|
(dom-append _el-tr10 _el-td11)
|
|
(dom-append _el-td11 _el-master)
|
|
(hs-activate! _el-master)
|
|
(dom-dispatch (dom-query-by-id "master") "click" nil)
|
|
))
|
|
(deftest "where with is not me in component template"
|
|
(hs-cleanup!)
|
|
(let ((_el-box (dom-create-element "div")) (_el-input (dom-create-element "input")) (_el-input2 (dom-create-element "input")) (_el-script (dom-create-element "script")) (_el-test-where-me (dom-create-element "test-where-me")))
|
|
(dom-set-attr _el-box "id" "box")
|
|
(dom-add-class _el-input "cb")
|
|
(dom-set-attr _el-input "type" "checkbox")
|
|
(dom-add-class _el-input2 "cb")
|
|
(dom-set-attr _el-input2 "type" "checkbox")
|
|
(dom-set-attr _el-script "type" "text/hyperscript-template")
|
|
(dom-set-attr _el-script "component" "test-where-me")
|
|
(dom-set-inner-html _el-script "<input type=\"checkbox\" _=\"set :checkboxes to <input[type=checkbox]/> in #box where it is not me on change set checked of the :checkboxes to my checked\">")
|
|
(dom-append (dom-body) _el-box)
|
|
(dom-append _el-box _el-input)
|
|
(dom-append _el-box _el-input2)
|
|
(dom-append (dom-body) _el-script)
|
|
(dom-append (dom-body) _el-test-where-me)
|
|
(dom-dispatch (dom-query "test-where-me input") "click" nil)
|
|
))
|
|
(deftest "works with DOM elements"
|
|
(hs-cleanup!)
|
|
(let ((_el-list (dom-create-element "ul")) (_el-li (dom-create-element "li")) (_el-li2 (dom-create-element "li")) (_el-li3 (dom-create-element "li")) (_el-button (dom-create-element "button")) (_el-out (dom-create-element "div")))
|
|
(dom-set-attr _el-list "id" "list")
|
|
(dom-add-class _el-li "yes")
|
|
(dom-set-inner-html _el-li "A")
|
|
(dom-set-inner-html _el-li2 "B")
|
|
(dom-add-class _el-li3 "yes")
|
|
(dom-set-inner-html _el-li3 "C")
|
|
(dom-set-attr _el-button "_" "on click set items to <li/> in #list set matches to items where it matches .yes then put matches mapped to its textContent into #out")
|
|
(dom-set-inner-html _el-button "Go")
|
|
(dom-set-attr _el-out "id" "out")
|
|
(dom-append (dom-body) _el-list)
|
|
(dom-append _el-list _el-li)
|
|
(dom-append _el-list _el-li2)
|
|
(dom-append _el-list _el-li3)
|
|
(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")) "AC")
|
|
))
|
|
)
|
|
|
|
;; ── expressions/comparisonOperator (83 tests) ──
|
|
(defsuite "hs-upstream-expressions/comparisonOperator"
|
|
(deftest "I am between works"
|
|
(assert= (eval-hs-with-me "I am between 1 and 10" 5) true)
|
|
(assert= (eval-hs-with-me "I am between 1 and 10" 0) false)
|
|
)
|
|
(deftest "I am in works"
|
|
(assert= (eval-hs-with-me "I am in [1, 2]" 1) true)
|
|
(assert= (eval-hs-with-me "I am in [1, 2]" 2) true)
|
|
(assert= (eval-hs-with-me "I am in [1, 2]" 3) false)
|
|
(assert= (eval-hs "I am in null") false)
|
|
)
|
|
(deftest "I am not between works"
|
|
(assert= (eval-hs-with-me "I am not between 1 and 10" 5) false)
|
|
(assert= (eval-hs-with-me "I am not between 1 and 10" 0) true)
|
|
)
|
|
(deftest "I am not in works"
|
|
(assert= (eval-hs-with-me "I am not in [1, 2]" 1) false)
|
|
(assert= (eval-hs-with-me "I am not in [1, 2]" 2) false)
|
|
(assert= (eval-hs-with-me "I am not in [1, 2]" 3) true)
|
|
(assert= (eval-hs "I am not in null") true)
|
|
)
|
|
(deftest "I precede works"
|
|
(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 "_" "on click if I precede #b put 'yes' into me")
|
|
(dom-set-attr _el-b "id" "b")
|
|
(dom-append (dom-body) _el-a)
|
|
(dom-append (dom-body) _el-b)
|
|
(hs-activate! _el-a)
|
|
))
|
|
(deftest "am works as alias for is"
|
|
(assert= (eval-hs "2 am 2") true)
|
|
(assert= (eval-hs "2 am 1") false)
|
|
)
|
|
(deftest "between works with strings"
|
|
(assert= (eval-hs "'b' is between 'a' and 'c'") true)
|
|
(assert= (eval-hs "'d' is between 'a' and 'c'") false)
|
|
)
|
|
(deftest "contains ignoring case works"
|
|
(assert= (eval-hs "'Hello World' contains 'hello' ignoring case") true)
|
|
(assert= (eval-hs "'Hello World' contains 'WORLD' ignoring case") true)
|
|
(assert= (eval-hs "'Hello World' contains 'missing' ignoring case") false)
|
|
)
|
|
(deftest "contains works with arrays"
|
|
(assert= (eval-hs-locals "I contain that" (list (list (quote that) 1) (list (quote me) (list 1 2 3)))) true)
|
|
(assert= (eval-hs-locals "that contains me" (list (list (quote that) (list 1 2 3)) (list (quote me) 1))) true)
|
|
)
|
|
(deftest "contains works with css literals"
|
|
(hs-cleanup!)
|
|
(let ((_el-d1 (dom-create-element "div")) (_el-d2 (dom-create-element "div")))
|
|
(dom-set-attr _el-d1 "id" "d1")
|
|
(dom-add-class _el-d1 "outer")
|
|
(dom-set-attr _el-d2 "id" "d2")
|
|
(dom-append (dom-body) _el-d1)
|
|
(dom-append _el-d1 _el-d2)
|
|
))
|
|
(deftest "contains works with elts"
|
|
(hs-cleanup!)
|
|
(let ((_el-outer (dom-create-element "div")) (_el-inner (dom-create-element "div")))
|
|
(dom-set-attr _el-outer "id" "outer")
|
|
(dom-set-attr _el-inner "id" "inner")
|
|
(dom-append (dom-body) _el-outer)
|
|
(dom-append _el-outer _el-inner)
|
|
))
|
|
(deftest "does not contain works"
|
|
(hs-cleanup!)
|
|
(let ((_el-outer (dom-create-element "div")) (_el-inner (dom-create-element "div")))
|
|
(dom-set-attr _el-outer "id" "outer")
|
|
(dom-set-attr _el-inner "id" "inner")
|
|
(dom-append (dom-body) _el-outer)
|
|
(dom-append _el-outer _el-inner)
|
|
))
|
|
(deftest "does not end with works"
|
|
(assert= (eval-hs "'hello world' does not end with 'world'") false)
|
|
(assert= (eval-hs "'hello world' does not end with 'hello'") true)
|
|
)
|
|
(deftest "does not exist works"
|
|
(assert= (eval-hs "undefined does not exist") true)
|
|
(assert= (eval-hs "null does not exist") true)
|
|
(assert= (eval-hs "#doesNotExist does not exist") true)
|
|
(assert= (eval-hs ".aClassThatDoesNotExist does not exist") true)
|
|
(assert= (eval-hs "<.aClassThatDoesNotExist/> does not exist") true)
|
|
(assert= (eval-hs "<body/> does not exist") false)
|
|
)
|
|
(deftest "does not follow works"
|
|
(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-b "id" "b")
|
|
(dom-append (dom-body) _el-a)
|
|
(dom-append (dom-body) _el-b)
|
|
))
|
|
(deftest "does not match works"
|
|
(hs-cleanup!)
|
|
(let ((_el-mDiv (dom-create-element "div")))
|
|
(dom-set-attr _el-mDiv "id" "mDiv")
|
|
(dom-add-class _el-mDiv "foo")
|
|
(dom-append (dom-body) _el-mDiv)
|
|
))
|
|
(deftest "does not match works w/ strings"
|
|
(assert= (eval-hs "'a' does not match '.*'") false)
|
|
(assert= (eval-hs "'a' does not match 'b'") true)
|
|
)
|
|
(deftest "does not precede works"
|
|
(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-b "id" "b")
|
|
(dom-append (dom-body) _el-a)
|
|
(dom-append (dom-body) _el-b)
|
|
))
|
|
(deftest "does not start with works"
|
|
(assert= (eval-hs "'hello world' does not start with 'hello'") false)
|
|
(assert= (eval-hs "'hello world' does not start with 'world'") true)
|
|
)
|
|
(deftest "ends with coerces to string"
|
|
(assert= (eval-hs "123 ends with '23'") true)
|
|
(assert= (eval-hs "123 ends with '12'") false)
|
|
)
|
|
(deftest "ends with ignoring case works"
|
|
(assert= (eval-hs "'Hello World' ends with 'world' ignoring case") true)
|
|
(assert= (eval-hs "'Hello World' ends with 'WORLD' ignoring case") true)
|
|
(assert= (eval-hs "'Hello World' ends with 'hello' ignoring case") false)
|
|
)
|
|
(deftest "ends with null is false"
|
|
(assert= (eval-hs "null ends with 'x'") false)
|
|
(assert= (eval-hs "null does not end with 'x'") true)
|
|
)
|
|
(deftest "ends with works"
|
|
(assert= (eval-hs "'hello world' ends with 'world'") true)
|
|
(assert= (eval-hs "'hello world' ends with 'hello'") false)
|
|
(assert= (eval-hs "'hello' ends with 'hello'") true)
|
|
(assert= (eval-hs "'' ends with 'x'") false)
|
|
)
|
|
(deftest "english greater than or equal works"
|
|
(assert= (eval-hs "1 is greater than or equal to 2") false)
|
|
(assert= (eval-hs "2 is greater than or equal to 1") true)
|
|
(assert= (eval-hs "2 is greater than or equal to 2") true)
|
|
)
|
|
(deftest "english greater than works"
|
|
(assert= (eval-hs "1 is greater than 2") false)
|
|
(assert= (eval-hs "2 is greater than 1") true)
|
|
(assert= (eval-hs "2 is greater than 2") false)
|
|
)
|
|
(deftest "english less than or equal works"
|
|
(assert= (eval-hs "1 is less than or equal to 2") true)
|
|
(assert= (eval-hs "2 is less than or equal to 1") false)
|
|
(assert= (eval-hs "2 is less than or equal to 2") true)
|
|
)
|
|
(deftest "english less than works"
|
|
(assert= (eval-hs "1 is less than 2") true)
|
|
(assert= (eval-hs "2 is less than 1") false)
|
|
(assert= (eval-hs "2 is less than 2") false)
|
|
)
|
|
(deftest "equal works"
|
|
(assert= (eval-hs "1 == 2") false)
|
|
(assert= (eval-hs "2 == 1") false)
|
|
(assert= (eval-hs "2 == 2") true)
|
|
)
|
|
(deftest "equals works"
|
|
(assert= (eval-hs "1 equals 2") false)
|
|
(assert= (eval-hs "2 equals 1") false)
|
|
(assert= (eval-hs "2 equals 2") true)
|
|
)
|
|
(deftest "exists works"
|
|
(hs-cleanup!)
|
|
(let ((_el-d1 (dom-create-element "div")) (_el-d2 (dom-create-element "div")) (_el-d3 (dom-create-element "div")))
|
|
(dom-set-attr _el-d1 "id" "d1")
|
|
(dom-add-class _el-d1 "c1")
|
|
(dom-set-attr _el-d2 "id" "d2")
|
|
(dom-add-class _el-d2 "c1")
|
|
(dom-set-attr _el-d3 "id" "d3")
|
|
(dom-add-class _el-d3 "c1")
|
|
(dom-append (dom-body) _el-d1)
|
|
(dom-append (dom-body) _el-d2)
|
|
(dom-append (dom-body) _el-d3)
|
|
))
|
|
(deftest "follows works"
|
|
(hs-cleanup!)
|
|
(let ((_el-a (dom-create-element "div")) (_el-b (dom-create-element "div")) (_el-c (dom-create-element "div")))
|
|
(dom-set-attr _el-a "id" "a")
|
|
(dom-set-attr _el-b "id" "b")
|
|
(dom-set-attr _el-c "id" "c")
|
|
(dom-append (dom-body) _el-a)
|
|
(dom-append (dom-body) _el-b)
|
|
(dom-append (dom-body) _el-c)
|
|
))
|
|
(deftest "greater than or equal works"
|
|
(assert= (eval-hs "1 >= 2") false)
|
|
(assert= (eval-hs "2 >= 1") true)
|
|
(assert= (eval-hs "2 >= 2") true)
|
|
)
|
|
(deftest "greater than works"
|
|
(assert= (eval-hs "1 > 2") false)
|
|
(assert= (eval-hs "2 > 1") true)
|
|
(assert= (eval-hs "2 > 2") false)
|
|
)
|
|
(deftest "include works"
|
|
(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"
|
|
(assert= (eval-hs-locals "I include that" (list (list (quote that) 1) (list (quote me) (list 1 2 3)))) true)
|
|
(assert= (eval-hs-locals "that includes me" (list (list (quote that) (list 1 2 3)) (list (quote me) 1))) true)
|
|
)
|
|
(deftest "includes works with css literals"
|
|
(hs-cleanup!)
|
|
(let ((_el-d1 (dom-create-element "div")) (_el-d2 (dom-create-element "div")))
|
|
(dom-set-attr _el-d1 "id" "d1")
|
|
(dom-add-class _el-d1 "outer")
|
|
(dom-set-attr _el-d2 "id" "d2")
|
|
(dom-append (dom-body) _el-d1)
|
|
(dom-append _el-d1 _el-d2)
|
|
))
|
|
(deftest "is a Node works via instanceof"
|
|
(hs-cleanup!)
|
|
(let ((_el-d1 (dom-create-element "div")))
|
|
(dom-set-attr _el-d1 "id" "d1")
|
|
(dom-set-attr _el-d1 "_" "on click if I am a Node put \"yes\" into me")
|
|
(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")) "yes")
|
|
))
|
|
(deftest "is a works"
|
|
(assert= (eval-hs "null is a String") true)
|
|
(assert= (eval-hs "null is a String!") false)
|
|
(assert= (eval-hs "'' is a String!") true)
|
|
)
|
|
(deftest "is a works with instanceof fallback"
|
|
(hs-cleanup!)
|
|
(let ((_el-d1 (dom-create-element "div")))
|
|
(dom-set-attr _el-d1 "id" "d1")
|
|
(dom-set-attr _el-d1 "_" "on click if I am a Element put \"yes\" into me")
|
|
(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")) "yes")
|
|
))
|
|
(deftest "is an works"
|
|
(assert= (eval-hs "null is an String") true)
|
|
(assert= (eval-hs "null is an String!") false)
|
|
(assert= (eval-hs "'' is an String!") true)
|
|
)
|
|
(deftest "is between works"
|
|
(assert= (eval-hs "5 is between 1 and 10") true)
|
|
(assert= (eval-hs "1 is between 1 and 10") true)
|
|
(assert= (eval-hs "10 is between 1 and 10") true)
|
|
(assert= (eval-hs "0 is between 1 and 10") false)
|
|
(assert= (eval-hs "11 is between 1 and 10") false)
|
|
)
|
|
(deftest "is boolean property works in where clause"
|
|
(hs-cleanup!)
|
|
(let ((_el-input (dom-create-element "input")) (_el-input1 (dom-create-element "input")) (_el-input2 (dom-create-element "input")))
|
|
(dom-add-class _el-input "cb")
|
|
(dom-set-attr _el-input "type" "checkbox")
|
|
(dom-set-attr _el-input "checked" "checked")
|
|
(dom-add-class _el-input1 "cb")
|
|
(dom-set-attr _el-input1 "type" "checkbox")
|
|
(dom-add-class _el-input2 "cb")
|
|
(dom-set-attr _el-input2 "type" "checkbox")
|
|
(dom-set-attr _el-input2 "checked" "checked")
|
|
(dom-append (dom-body) _el-input)
|
|
(dom-append (dom-body) _el-input1)
|
|
(dom-append (dom-body) _el-input2)
|
|
))
|
|
(deftest "is boolean property works with disabled"
|
|
(hs-cleanup!)
|
|
(let ((_el-b1 (dom-create-element "button")) (_el-b2 (dom-create-element "button")))
|
|
(dom-set-attr _el-b1 "id" "b1")
|
|
(dom-set-attr _el-b1 "disabled" "")
|
|
(dom-set-inner-html _el-b1 "Disabled")
|
|
(dom-set-attr _el-b2 "id" "b2")
|
|
(dom-set-inner-html _el-b2 "Enabled")
|
|
(dom-append (dom-body) _el-b1)
|
|
(dom-append (dom-body) _el-b2)
|
|
))
|
|
(deftest "is empty works"
|
|
(assert= (eval-hs "undefined is empty") true)
|
|
(assert= (eval-hs "'' is empty") true)
|
|
(assert= (eval-hs "[] is empty") true)
|
|
(assert= (eval-hs "'not empty' is empty") false)
|
|
(assert= (eval-hs "1000 is empty") false)
|
|
(assert= (eval-hs "[1,2,3] is empty") false)
|
|
(assert= (eval-hs ".aClassThatDoesNotExist is empty") true)
|
|
)
|
|
(deftest "is equal to works"
|
|
(assert= (eval-hs "1 is equal to 2") false)
|
|
(assert= (eval-hs "2 is equal to 1") false)
|
|
(assert= (eval-hs "2 is equal to 2") true)
|
|
)
|
|
(deftest "is equal works without to"
|
|
(assert= (eval-hs "2 is equal 2") true)
|
|
(assert= (eval-hs "2 is equal 1") false)
|
|
)
|
|
(deftest "is falls back to boolean property when rhs is undefined"
|
|
(hs-cleanup!)
|
|
(let ((_el-c1 (dom-create-element "input")) (_el-c2 (dom-create-element "input")))
|
|
(dom-set-attr _el-c1 "id" "c1")
|
|
(dom-set-attr _el-c1 "type" "checkbox")
|
|
(dom-set-attr _el-c1 "checked" "checked")
|
|
(dom-set-attr _el-c2 "id" "c2")
|
|
(dom-set-attr _el-c2 "type" "checkbox")
|
|
(dom-append (dom-body) _el-c1)
|
|
(dom-append (dom-body) _el-c2)
|
|
))
|
|
(deftest "is ignoring case works"
|
|
(assert= (eval-hs "'Hello' is 'hello' ignoring case") true)
|
|
(assert= (eval-hs "'Hello' is 'HELLO' ignoring case") true)
|
|
(assert= (eval-hs "'Hello' is 'world' ignoring case") false)
|
|
)
|
|
(deftest "is in works"
|
|
(assert= (eval-hs "1 is in [1, 2]") true)
|
|
(assert= (eval-hs "2 is in [1, 2]") true)
|
|
(assert= (eval-hs "3 is in [1, 2]") false)
|
|
(assert= (eval-hs "3 is in null") false)
|
|
)
|
|
(deftest "is not a works"
|
|
(assert= (eval-hs "null is not a String") false)
|
|
(assert= (eval-hs "null is not a String!") true)
|
|
(assert= (eval-hs "'' is not a String!") false)
|
|
)
|
|
(deftest "is not a works with instanceof fallback"
|
|
(hs-cleanup!)
|
|
(let ((_el-d1 (dom-create-element "div")))
|
|
(dom-set-attr _el-d1 "id" "d1")
|
|
(dom-set-attr _el-d1 "_" "on click if \"hello\" is not a Element put \"yes\" into me")
|
|
(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")) "yes")
|
|
))
|
|
(deftest "is not an works"
|
|
(assert= (eval-hs "null is not an String") false)
|
|
(assert= (eval-hs "null is not an String!") true)
|
|
(assert= (eval-hs "'' is not an String!") false)
|
|
)
|
|
(deftest "is not between works"
|
|
(assert= (eval-hs "5 is not between 1 and 10") false)
|
|
(assert= (eval-hs "0 is not between 1 and 10") true)
|
|
(assert= (eval-hs "11 is not between 1 and 10") true)
|
|
(assert= (eval-hs "1 is not between 1 and 10") false)
|
|
(assert= (eval-hs "10 is not between 1 and 10") false)
|
|
)
|
|
(deftest "is not empty works"
|
|
(assert= (eval-hs "undefined is not empty") false)
|
|
(assert= (eval-hs "'' is not empty") false)
|
|
(assert= (eval-hs "[] is not empty") false)
|
|
(assert= (eval-hs "'not empty' is not empty") true)
|
|
(assert= (eval-hs "1000 is not empty") true)
|
|
(assert= (eval-hs "[1,2,3] is not empty") true)
|
|
)
|
|
(deftest "is not equal to works"
|
|
(assert= (eval-hs "1 is not equal to 2") true)
|
|
(assert= (eval-hs "2 is not equal to 1") true)
|
|
(assert= (eval-hs "2 is not equal to 2") false)
|
|
)
|
|
(deftest "is not equal works without to"
|
|
(assert= (eval-hs "2 is not equal 2") false)
|
|
(assert= (eval-hs "2 is not equal 1") true)
|
|
)
|
|
(deftest "is not falls back to boolean property when rhs is undefined"
|
|
(hs-cleanup!)
|
|
(let ((_el-c1 (dom-create-element "input")) (_el-c2 (dom-create-element "input")))
|
|
(dom-set-attr _el-c1 "id" "c1")
|
|
(dom-set-attr _el-c1 "type" "checkbox")
|
|
(dom-set-attr _el-c1 "checked" "checked")
|
|
(dom-set-attr _el-c2 "id" "c2")
|
|
(dom-set-attr _el-c2 "type" "checkbox")
|
|
(dom-append (dom-body) _el-c1)
|
|
(dom-append (dom-body) _el-c2)
|
|
))
|
|
(deftest "is not ignoring case works"
|
|
(assert= (eval-hs "'Hello' is not 'world' ignoring case") true)
|
|
(assert= (eval-hs "'Hello' is not 'hello' ignoring case") false)
|
|
)
|
|
(deftest "is not in works"
|
|
(assert= (eval-hs "1 is not in [1, 2]") false)
|
|
(assert= (eval-hs "2 is not in [1, 2]") false)
|
|
(assert= (eval-hs "3 is not in [1, 2]") true)
|
|
(assert= (eval-hs "3 is not in null") true)
|
|
)
|
|
(deftest "is not null still works as equality"
|
|
(assert= (eval-hs "5 is not null") true)
|
|
(assert= (eval-hs "null is not null") false)
|
|
)
|
|
(deftest "is not really equal to works"
|
|
(assert= (eval-hs "1 is not really equal to 2") true)
|
|
(assert= (eval-hs "2 is not really equal to 1") true)
|
|
(assert= (eval-hs "2 is not really equal to '2'") true)
|
|
(assert= (eval-hs "2 is not really equal to 2") false)
|
|
)
|
|
(deftest "is not really works without equal to"
|
|
(assert= (eval-hs "2 is not really '2'") true)
|
|
(assert= (eval-hs "2 is not really 2") false)
|
|
)
|
|
(deftest "is not undefined still works as equality"
|
|
(assert= (eval-hs "5 is not undefined") true)
|
|
(assert= (eval-hs "null is not undefined") false)
|
|
)
|
|
(deftest "is not works"
|
|
(assert= (eval-hs "1 is not 2") true)
|
|
(assert= (eval-hs "2 is not 1") true)
|
|
(assert= (eval-hs "2 is not 2") false)
|
|
)
|
|
(deftest "is really equal to works"
|
|
(assert= (eval-hs "1 is really equal to 2") false)
|
|
(assert= (eval-hs "2 is really equal to 1") false)
|
|
(assert= (eval-hs "2 is really equal to '2'") false)
|
|
(assert= (eval-hs "2 is really equal to 2") true)
|
|
)
|
|
(deftest "is really works without equal to"
|
|
(assert= (eval-hs "2 is really 2") true)
|
|
(assert= (eval-hs "2 is really '2'") false)
|
|
)
|
|
(deftest "is still does equality when rhs variable exists"
|
|
(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)
|
|
(assert= (eval-hs "2 is 1") false)
|
|
(assert= (eval-hs "2 is 2") true)
|
|
)
|
|
(deftest "less than or equal works"
|
|
(assert= (eval-hs "1 <= 2") true)
|
|
(assert= (eval-hs "2 <= 1") false)
|
|
(assert= (eval-hs "2 <= 2") true)
|
|
)
|
|
(deftest "less than works"
|
|
(assert= (eval-hs "1 < 2") true)
|
|
(assert= (eval-hs "2 < 1") false)
|
|
(assert= (eval-hs "2 < 2") false)
|
|
)
|
|
(deftest "match works"
|
|
(hs-cleanup!)
|
|
(let ((_el-mDiv (dom-create-element "div")))
|
|
(dom-set-attr _el-mDiv "id" "mDiv")
|
|
(dom-add-class _el-mDiv "foo")
|
|
(dom-append (dom-body) _el-mDiv)
|
|
))
|
|
(deftest "match works w/ strings"
|
|
(assert= (eval-hs "'a' matches '.*'") true)
|
|
(assert= (eval-hs "'a' matches 'b'") false)
|
|
)
|
|
(deftest "matches ignoring case works"
|
|
(assert= (eval-hs "'Hello' matches 'hello' ignoring case") true)
|
|
(assert= (eval-hs "'Hello' matches 'HELLO' ignoring case") true)
|
|
)
|
|
(deftest "not equal works"
|
|
(assert= (eval-hs "1 != 2") true)
|
|
(assert= (eval-hs "2 != 1") true)
|
|
(assert= (eval-hs "2 != 2") false)
|
|
)
|
|
(deftest "precedes with null is false"
|
|
(assert= (eval-hs "null precedes null") false)
|
|
(assert= (eval-hs "null does not precede null") true)
|
|
)
|
|
(deftest "precedes works"
|
|
(hs-cleanup!)
|
|
(let ((_el-a (dom-create-element "div")) (_el-b (dom-create-element "div")) (_el-c (dom-create-element "div")))
|
|
(dom-set-attr _el-a "id" "a")
|
|
(dom-set-attr _el-b "id" "b")
|
|
(dom-set-attr _el-c "id" "c")
|
|
(dom-append (dom-body) _el-a)
|
|
(dom-append (dom-body) _el-b)
|
|
(dom-append (dom-body) _el-c)
|
|
))
|
|
(deftest "really equals works"
|
|
(assert= (eval-hs "1 really equals 2") false)
|
|
(assert= (eval-hs "2 really equals 1") false)
|
|
(assert= (eval-hs "2 really equals 2") true)
|
|
)
|
|
(deftest "starts with coerces to string"
|
|
(assert= (eval-hs "123 starts with '12'") true)
|
|
(assert= (eval-hs "123 starts with '23'") false)
|
|
)
|
|
(deftest "starts with ignoring case works"
|
|
(assert= (eval-hs "'Hello World' starts with 'hello' ignoring case") true)
|
|
(assert= (eval-hs "'Hello World' starts with 'HELLO' ignoring case") true)
|
|
(assert= (eval-hs "'Hello World' starts with 'world' ignoring case") false)
|
|
)
|
|
(deftest "starts with null is false"
|
|
(assert= (eval-hs "null starts with 'x'") false)
|
|
(assert= (eval-hs "null does not start with 'x'") true)
|
|
)
|
|
(deftest "starts with works"
|
|
(assert= (eval-hs "'hello world' starts with 'hello'") true)
|
|
(assert= (eval-hs "'hello world' starts with 'world'") false)
|
|
(assert= (eval-hs "'hello' starts with 'hello'") true)
|
|
(assert= (eval-hs "'' starts with 'x'") false)
|
|
)
|
|
(deftest "triple equal works"
|
|
(assert= (eval-hs "1 === 2") false)
|
|
(assert= (eval-hs "2 === 1") false)
|
|
(assert= (eval-hs "2 === 2") true)
|
|
)
|
|
(deftest "triple not equal works"
|
|
(assert= (eval-hs "1 !== 2") true)
|
|
(assert= (eval-hs "2 !== 1") true)
|
|
(assert= (eval-hs "2 !== 2") false)
|
|
)
|
|
)
|
|
|
|
;; ── expressions/cookies (5 tests) ──
|
|
(defsuite "hs-upstream-expressions/cookies"
|
|
(deftest "basic clear cookie values work"
|
|
(hs-cleanup!)
|
|
(eval-hs "set cookies.foo to 'bar'")
|
|
(assert= (eval-hs "cookies.foo") "bar")
|
|
(eval-hs "call cookies.clear('foo')")
|
|
(assert (nil? (eval-hs "cookies.foo"))))
|
|
(deftest "basic set cookie values work"
|
|
(hs-cleanup!)
|
|
(assert (nil? (eval-hs "cookies.foo")))
|
|
(eval-hs "set cookies.foo to 'bar'")
|
|
(assert= (eval-hs "cookies.foo") "bar"))
|
|
(deftest "iterate cookies values work"
|
|
(hs-cleanup!)
|
|
(host-set! (host-global "cookies") "foo" "bar")
|
|
(let ((_names (list)) (_values (list)))
|
|
(hs-for-each
|
|
(fn (x)
|
|
(append! _names (host-get x "name"))
|
|
(append! _values (host-get x "value")))
|
|
(host-global "cookies"))
|
|
(assert-contains "foo" _names)
|
|
(assert-contains "bar" _values))
|
|
)
|
|
(deftest "length is 0 when no cookies are set"
|
|
(hs-cleanup!)
|
|
(assert= (eval-hs "cookies.length") 0))
|
|
(deftest "update cookie values work"
|
|
(hs-cleanup!)
|
|
(eval-hs "set cookies.foo to 'bar'")
|
|
(assert= (eval-hs "cookies.foo") "bar")
|
|
(eval-hs "set cookies.foo to 'doh'")
|
|
(assert= (eval-hs "cookies.foo") "doh"))
|
|
)
|
|
|
|
;; ── expressions/dom-scope (20 tests) ──
|
|
(defsuite "hs-upstream-expressions/dom-scope"
|
|
(deftest "always reacts to ^var changes"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")) (_el-button (dom-create-element "button")) (_el-output (dom-create-element "output")))
|
|
(dom-set-attr _el-div "_" "init set ^name to 'alice'")
|
|
(dom-set-attr _el-button "_" "on click set ^name to 'bob'")
|
|
(dom-set-inner-html _el-button "rename")
|
|
(dom-set-attr _el-output "_" "live put 'Hello ' + ^name into me")
|
|
(dom-set-inner-html _el-output "loading")
|
|
(dom-append (dom-body) _el-div)
|
|
(dom-append _el-div _el-button)
|
|
(dom-append _el-div _el-output)
|
|
(hs-activate! _el-div)
|
|
(hs-activate! _el-button)
|
|
(hs-activate! _el-output)
|
|
))
|
|
(deftest "bind works with ^var"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")) (_el-input (dom-create-element "input")) (_el-output (dom-create-element "output")))
|
|
(dom-set-attr _el-div "_" "init set ^search to ''")
|
|
(dom-set-attr _el-input "_" "bind ^search and my value")
|
|
(dom-set-attr _el-input "type" "text")
|
|
(dom-set-attr _el-output "_" "when ^search changes put it into me")
|
|
(dom-append (dom-body) _el-div)
|
|
(dom-append _el-div _el-input)
|
|
(dom-append _el-div _el-output)
|
|
(hs-activate! _el-div)
|
|
(hs-activate! _el-input)
|
|
(hs-activate! _el-output)
|
|
))
|
|
(deftest "child reads ^var set by parent"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")) (_el-span (dom-create-element "span")))
|
|
(dom-set-attr _el-div "_" "init set ^count to 42")
|
|
(dom-set-attr _el-span "_" "on click put ^count into me")
|
|
(dom-set-inner-html _el-span "0")
|
|
(dom-append (dom-body) _el-div)
|
|
(dom-append _el-div _el-span)
|
|
(hs-activate! _el-div)
|
|
(hs-activate! _el-span)
|
|
))
|
|
(deftest "child write updates the ancestor, not a local copy"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")) (_el-button (dom-create-element "button")) (_el-span (dom-create-element "span")))
|
|
(dom-set-attr _el-div "_" "init set ^shared to 0")
|
|
(dom-set-attr _el-button "_" "on click set ^shared to 10")
|
|
(dom-set-inner-html _el-button "set")
|
|
(dom-set-attr _el-span "_" "on click put ^shared into me")
|
|
(dom-set-inner-html _el-span "0")
|
|
(dom-append (dom-body) _el-div)
|
|
(dom-append _el-div _el-button)
|
|
(dom-append _el-div _el-span)
|
|
(hs-activate! _el-div)
|
|
(hs-activate! _el-button)
|
|
(hs-activate! _el-span)
|
|
))
|
|
(deftest "child writes ^var and parent sees it"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")) (_el-button (dom-create-element "button")) (_el-span (dom-create-element "span")))
|
|
(dom-set-attr _el-div "_" "init set ^count to 0")
|
|
(dom-set-attr _el-button "_" "on click set ^count to 99")
|
|
(dom-set-inner-html _el-button "set")
|
|
(dom-set-attr _el-span "_" "on click put ^count into me")
|
|
(dom-set-inner-html _el-span "0")
|
|
(dom-append (dom-body) _el-div)
|
|
(dom-append _el-div _el-button)
|
|
(dom-append _el-div _el-span)
|
|
(hs-activate! _el-div)
|
|
(hs-activate! _el-button)
|
|
(hs-activate! _el-span)
|
|
))
|
|
(deftest "closest ancestor wins (shadowing)"
|
|
(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 "_" "init set ^color to 'blue'")
|
|
(dom-set-attr _el-span "_" "on click put ^color into me")
|
|
(dom-set-inner-html _el-span "empty")
|
|
(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 "dedup prevents re-fire on same ^var value"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")) (_el-output (dom-create-element "output")) (_el-button (dom-create-element "button")) (_el-diff (dom-create-element "button")))
|
|
(dom-set-attr _el-div "_" "init set ^val to 'same'")
|
|
(dom-set-attr _el-output "_" "when ^val changes increment :runs then put :runs into me")
|
|
(dom-set-attr _el-button "_" "on click set ^val to 'same'")
|
|
(dom-set-inner-html _el-button "same")
|
|
(dom-set-attr _el-diff "id" "diff")
|
|
(dom-set-attr _el-diff "_" "on click set ^val to 'different'")
|
|
(dom-set-inner-html _el-diff "diff")
|
|
(dom-append (dom-body) _el-div)
|
|
(dom-append _el-div _el-output)
|
|
(dom-append _el-div _el-button)
|
|
(dom-append _el-div _el-diff)
|
|
(hs-activate! _el-div)
|
|
(hs-activate! _el-output)
|
|
(hs-activate! _el-button)
|
|
(hs-activate! _el-diff)
|
|
))
|
|
(deftest "deeply nested child reads ^var from grandparent"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")) (_el-div1 (dom-create-element "div")) (_el-div2 (dom-create-element "div")) (_el-span (dom-create-element "span")))
|
|
(dom-set-attr _el-div "_" "init set ^name to 'alice'")
|
|
(dom-set-attr _el-span "_" "on click put ^name into me")
|
|
(dom-set-inner-html _el-span "empty")
|
|
(dom-append (dom-body) _el-div)
|
|
(dom-append _el-div _el-div1)
|
|
(dom-append _el-div1 _el-div2)
|
|
(dom-append _el-div2 _el-span)
|
|
(hs-activate! _el-div)
|
|
(hs-activate! _el-span)
|
|
))
|
|
(deftest "derived ^var chains reactively"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")) (_el-span (dom-create-element "span")) (_el-span2 (dom-create-element "span")) (_el-output (dom-create-element "output")) (_el-price-btn (dom-create-element "button")) (_el-qty-btn (dom-create-element "button")))
|
|
(dom-set-attr _el-div "_" "init set ^price to 10 then set ^qty to 2 then set ^total to 20")
|
|
(dom-set-attr _el-span "_" "when ^price changes set ^total to (^price * ^qty)")
|
|
(dom-set-attr _el-span2 "_" "when ^qty changes set ^total to (^price * ^qty)")
|
|
(dom-set-attr _el-output "_" "when ^total changes put it into me")
|
|
(dom-set-attr _el-price-btn "id" "price-btn")
|
|
(dom-set-attr _el-price-btn "_" "on click set ^price to 25")
|
|
(dom-set-inner-html _el-price-btn "set price")
|
|
(dom-set-attr _el-qty-btn "id" "qty-btn")
|
|
(dom-set-attr _el-qty-btn "_" "on click set ^qty to 5")
|
|
(dom-set-inner-html _el-qty-btn "set qty")
|
|
(dom-append (dom-body) _el-div)
|
|
(dom-append _el-div _el-span)
|
|
(dom-append _el-div _el-span2)
|
|
(dom-append _el-div _el-output)
|
|
(dom-append _el-div _el-price-btn)
|
|
(dom-append _el-div _el-qty-btn)
|
|
(hs-activate! _el-div)
|
|
(hs-activate! _el-span)
|
|
(hs-activate! _el-span2)
|
|
(hs-activate! _el-output)
|
|
(hs-activate! _el-price-btn)
|
|
(hs-activate! _el-qty-btn)
|
|
))
|
|
(deftest "dom keyword works as scope modifier"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")) (_el-span (dom-create-element "span")))
|
|
(dom-set-attr _el-div "_" "init set dom count to 42")
|
|
(dom-set-attr _el-span "_" "on click put dom count into me")
|
|
(dom-set-inner-html _el-span "0")
|
|
(dom-append (dom-body) _el-div)
|
|
(dom-append _el-div _el-span)
|
|
(hs-activate! _el-div)
|
|
(hs-activate! _el-span)
|
|
))
|
|
(deftest "effect stops when element is removed"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")) (_el-output (dom-create-element "output")) (_el-button (dom-create-element "button")))
|
|
(dom-set-attr _el-div "_" "init set ^msg to 'hello'")
|
|
(dom-set-attr _el-output "_" "when ^msg changes put it into me")
|
|
(dom-set-attr _el-button "_" "on click set ^msg to 'updated'")
|
|
(dom-set-inner-html _el-button "update")
|
|
(dom-append (dom-body) _el-div)
|
|
(dom-append _el-div _el-output)
|
|
(dom-append _el-div _el-button)
|
|
(hs-activate! _el-div)
|
|
(hs-activate! _el-output)
|
|
(hs-activate! _el-button)
|
|
))
|
|
(deftest "increment works on inherited var"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")) (_el-button (dom-create-element "button")) (_el-span (dom-create-element "span")))
|
|
(dom-set-attr _el-div "_" "init set ^count to 0")
|
|
(dom-set-attr _el-button "_" "on click increment ^count")
|
|
(dom-set-inner-html _el-button "+1")
|
|
(dom-set-attr _el-span "_" "on click put ^count into me")
|
|
(dom-set-inner-html _el-span "0")
|
|
(dom-append (dom-body) _el-div)
|
|
(dom-append _el-div _el-button)
|
|
(dom-append _el-div _el-span)
|
|
(hs-activate! _el-div)
|
|
(hs-activate! _el-button)
|
|
(hs-activate! _el-span)
|
|
))
|
|
(deftest "multiple children react to same ^var"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")) (_el-button (dom-create-element "button")) (_el-a (dom-create-element "span")) (_el-b (dom-create-element "span")))
|
|
(dom-set-attr _el-div "_" "init set ^color to 'red'")
|
|
(dom-set-attr _el-button "_" "on click set ^color to 'blue'")
|
|
(dom-set-inner-html _el-button "change")
|
|
(dom-set-attr _el-a "id" "a")
|
|
(dom-set-attr _el-a "_" "when ^color changes put it into me")
|
|
(dom-set-attr _el-b "id" "b")
|
|
(dom-set-attr _el-b "_" "when ^color changes put it into me")
|
|
(dom-append (dom-body) _el-div)
|
|
(dom-append _el-div _el-button)
|
|
(dom-append _el-div _el-a)
|
|
(dom-append _el-div _el-b)
|
|
(hs-activate! _el-div)
|
|
(hs-activate! _el-button)
|
|
(hs-activate! _el-a)
|
|
(hs-activate! _el-b)
|
|
))
|
|
(deftest "on clause targets a specific 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 ^outerVal to 'outer'")
|
|
(dom-add-class _el-div1 "inner")
|
|
(dom-set-attr _el-div1 "_" "init set ^innerVal to 'inner'")
|
|
(dom-set-attr _el-span "_" "on click put ^outerVal on closest .outer into me")
|
|
(dom-set-inner-html _el-span "read")
|
|
(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 "on clause with id reference"
|
|
(hs-cleanup!)
|
|
(let ((_el-state-holder (dom-create-element "div")) (_el-button (dom-create-element "button")) (_el-span (dom-create-element "span")))
|
|
(dom-set-attr _el-state-holder "id" "state-holder")
|
|
(dom-set-attr _el-button "_" "on click set ^count on #state-holder to 99")
|
|
(dom-set-inner-html _el-button "set")
|
|
(dom-set-attr _el-span "_" "on click put ^count on #state-holder into me")
|
|
(dom-set-inner-html _el-span "read")
|
|
(dom-append (dom-body) _el-state-holder)
|
|
(dom-append (dom-body) _el-button)
|
|
(dom-append (dom-body) _el-span)
|
|
(hs-activate! _el-button)
|
|
(hs-activate! _el-span)
|
|
))
|
|
(deftest "set ^var on explicit element"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")) (_el-button (dom-create-element "button")) (_el-span (dom-create-element "span")))
|
|
(dom-add-class _el-div "store")
|
|
(dom-set-attr _el-button "_" "on click set ^data on closest .store to 'hello'")
|
|
(dom-set-inner-html _el-button "set")
|
|
(dom-set-attr _el-span "_" "on click put ^data on closest .store into me")
|
|
(dom-set-inner-html _el-span "read")
|
|
(dom-append (dom-body) _el-div)
|
|
(dom-append _el-div _el-button)
|
|
(dom-append _el-div _el-span)
|
|
(hs-activate! _el-button)
|
|
(hs-activate! _el-span)
|
|
))
|
|
(deftest "sibling subtrees have independent ^vars"
|
|
(hs-cleanup!)
|
|
(let ((_el-a (dom-create-element "div")) (_el-span (dom-create-element "span")) (_el-b (dom-create-element "div")) (_el-span3 (dom-create-element "span")))
|
|
(dom-set-attr _el-a "id" "a")
|
|
(dom-set-attr _el-a "_" "init set ^val to 'A'")
|
|
(dom-set-attr _el-span "_" "on click put ^val into me")
|
|
(dom-set-inner-html _el-span "empty")
|
|
(dom-set-attr _el-b "id" "b")
|
|
(dom-set-attr _el-b "_" "init set ^val to 'B'")
|
|
(dom-set-attr _el-span3 "_" "on click put ^val into me")
|
|
(dom-set-inner-html _el-span3 "empty")
|
|
(dom-append (dom-body) _el-a)
|
|
(dom-append _el-a _el-span)
|
|
(dom-append (dom-body) _el-b)
|
|
(dom-append _el-b _el-span3)
|
|
(hs-activate! _el-a)
|
|
(hs-activate! _el-span)
|
|
(hs-activate! _el-b)
|
|
(hs-activate! _el-span3)
|
|
))
|
|
(deftest "sibling subtrees react independently with ^var"
|
|
(hs-cleanup!)
|
|
(let ((_el-a (dom-create-element "div")) (_el-button (dom-create-element "button")) (_el-output (dom-create-element "output")) (_el-b (dom-create-element "div")) (_el-button4 (dom-create-element "button")) (_el-output5 (dom-create-element "output")))
|
|
(dom-set-attr _el-a "id" "a")
|
|
(dom-set-attr _el-a "_" "init set ^val to 0")
|
|
(dom-set-attr _el-button "_" "on click increment ^val")
|
|
(dom-set-inner-html _el-button "+1")
|
|
(dom-set-attr _el-output "_" "when ^val changes put it into me")
|
|
(dom-set-inner-html _el-output "0")
|
|
(dom-set-attr _el-b "id" "b")
|
|
(dom-set-attr _el-b "_" "init set ^val to 0")
|
|
(dom-set-attr _el-button4 "_" "on click increment ^val")
|
|
(dom-set-inner-html _el-button4 "+1")
|
|
(dom-set-attr _el-output5 "_" "when ^val changes put it into me")
|
|
(dom-set-inner-html _el-output5 "0")
|
|
(dom-append (dom-body) _el-a)
|
|
(dom-append _el-a _el-button)
|
|
(dom-append _el-a _el-output)
|
|
(dom-append (dom-body) _el-b)
|
|
(dom-append _el-b _el-button4)
|
|
(dom-append _el-b _el-output5)
|
|
(hs-activate! _el-a)
|
|
(hs-activate! _el-button)
|
|
(hs-activate! _el-output)
|
|
(hs-activate! _el-b)
|
|
(hs-activate! _el-button4)
|
|
(hs-activate! _el-output5)
|
|
))
|
|
(deftest "when reacts to ^var changes"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")) (_el-button (dom-create-element "button")) (_el-output (dom-create-element "output")))
|
|
(dom-set-attr _el-div "_" "init set ^count to 0")
|
|
(dom-set-attr _el-button "_" "on click increment ^count")
|
|
(dom-set-inner-html _el-button "+1")
|
|
(dom-set-attr _el-output "_" "when ^count changes put it into me")
|
|
(dom-set-inner-html _el-output "0")
|
|
(dom-append (dom-body) _el-div)
|
|
(dom-append _el-div _el-button)
|
|
(dom-append _el-div _el-output)
|
|
(hs-activate! _el-div)
|
|
(hs-activate! _el-button)
|
|
(hs-activate! _el-output)
|
|
))
|
|
(deftest "write to ^var not found anywhere creates on current element"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")) (_el-button (dom-create-element "button")) (_el-span (dom-create-element "span")))
|
|
(dom-set-attr _el-button "_" "on click set ^newvar to 'created' then put ^newvar into next <span/>")
|
|
(dom-set-inner-html _el-button "go")
|
|
(dom-set-inner-html _el-span "empty")
|
|
(dom-append (dom-body) _el-div)
|
|
(dom-append _el-div _el-button)
|
|
(dom-append _el-div _el-span)
|
|
(hs-activate! _el-button)
|
|
))
|
|
)
|
|
|
|
;; ── expressions/functionCalls (12 tests) ──
|
|
(defsuite "hs-upstream-expressions/functionCalls"
|
|
(deftest "can access a property of a call's result"
|
|
(assert= (eval-hs-locals "makePoint(3, 4).x" (list (list (quote makePoint) (fn (x y) {:x x :y y})))) 3)
|
|
(assert= (eval-hs-locals "makePoint(3, 4).y" (list (list (quote makePoint) (fn (x y) {:x x :y y})))) 4)
|
|
)
|
|
(deftest "can chain calls on the result of a call"
|
|
(assert= (eval-hs-locals "getObj().greet()" (list (list (quote getObj) (fn () {:greet (fn () "hi")})))) "hi")
|
|
)
|
|
(deftest "can invoke function on object"
|
|
(assert= (eval-hs-locals "obj.getValue()" (list (list (quote obj) {:value "foo" :getValue (fn () (host-get this "value"))}))) "foo")
|
|
)
|
|
(deftest "can invoke function on object w/ async arg"
|
|
(error "SKIP (untranslated): can invoke function on object w/ async arg"))
|
|
(deftest "can invoke function on object w/ async root & arg"
|
|
(error "SKIP (untranslated): can invoke function on object w/ async root & arg"))
|
|
(deftest "can invoke global function"
|
|
(assert= (eval-hs-locals "identity(\"foo\")" (list (list (quote identity) (fn (x) x)))) "foo")
|
|
)
|
|
(deftest "can invoke global function w/ async arg"
|
|
(error "SKIP (untranslated): can invoke global function w/ async arg"))
|
|
(deftest "can pass an array literal as an argument"
|
|
(assert= (eval-hs-locals "sum([1, 2, 3, 4])" (list (list (quote sum) (fn (arr) (reduce (fn (a b) (+ a b)) 0 arr))))) 10)
|
|
)
|
|
(deftest "can pass an expression as an argument"
|
|
(assert= (eval-hs-locals "double(3 + 4)" (list (list (quote double) (fn (n) (* n 2))))) 14)
|
|
)
|
|
(deftest "can pass an object literal as an argument"
|
|
(assert= (eval-hs-locals "getName({name: 'Alice'})" (list (list (quote getName) (fn (o) (host-get o "name"))))) "Alice")
|
|
)
|
|
(deftest "can pass multiple arguments"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click put add(1, 2, 3) into me")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
))
|
|
(deftest "can pass no arguments"
|
|
(assert= (eval-hs-locals "getFortyTwo()" (list (list (quote getFortyTwo) (fn () 42)))) 42)
|
|
)
|
|
)
|
|
|
|
;; ── expressions/idRef (4 tests) ──
|
|
(defsuite "hs-upstream-expressions/idRef"
|
|
(deftest "basic id ref works"
|
|
(hs-cleanup!)
|
|
(let ((_el-d1 (dom-create-element "div")))
|
|
(dom-set-attr _el-d1 "id" "d1")
|
|
(dom-append (dom-body) _el-d1)
|
|
))
|
|
(deftest "basic id ref works w no match"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-append (dom-body) _el-div)
|
|
))
|
|
(deftest "id ref works from a disconnected element"
|
|
(hs-cleanup!)
|
|
(let ((_el-d1 (dom-create-element "div")))
|
|
(dom-set-attr _el-d1 "id" "d1")
|
|
(dom-append (dom-body) _el-d1)
|
|
))
|
|
(deftest "template id ref works"
|
|
(hs-cleanup!)
|
|
(let ((_el-d1 (dom-create-element "div")))
|
|
(dom-set-attr _el-d1 "id" "d1")
|
|
(dom-append (dom-body) _el-d1)
|
|
))
|
|
)
|
|
|
|
;; ── expressions/in (10 tests) ──
|
|
(defsuite "hs-upstream-expressions/in"
|
|
(deftest "basic no query return values"
|
|
(assert= (eval-hs "1 in [1, 2, 3]") (list 1))
|
|
(assert= (eval-hs "[1, 3] in [1, 2, 3]") (list 1 3))
|
|
(assert= (eval-hs "[1, 3, 4] in [1, 2, 3]") (list 1 3))
|
|
(assert= (eval-hs "[4, 5, 6] in [1, 2, 3]") (list))
|
|
)
|
|
(deftest "basic query return values"
|
|
(hs-cleanup!)
|
|
(let ((_el-d1 (dom-create-element "div")) (_el-p (dom-create-element "p")) (_el-p2 (dom-create-element "p")))
|
|
(dom-set-attr _el-d1 "id" "d1")
|
|
(dom-append (dom-body) _el-d1)
|
|
(dom-append _el-d1 _el-p)
|
|
(dom-append _el-d1 _el-p2)
|
|
))
|
|
(deftest "class returns values"
|
|
(hs-cleanup!)
|
|
(let ((_el-inDiv (dom-create-element "div")) (_el-p1 (dom-create-element "p")))
|
|
(dom-set-attr _el-inDiv "id" "inDiv")
|
|
(dom-set-attr _el-inDiv "_" "on click get the first .p1 in me put its id into @result")
|
|
(dom-set-attr _el-p1 "id" "p1")
|
|
(dom-add-class _el-p1 "p1")
|
|
(dom-append (dom-body) _el-inDiv)
|
|
(dom-append _el-inDiv _el-p1)
|
|
(hs-activate! _el-inDiv)
|
|
))
|
|
(deftest "class template returns values"
|
|
(hs-cleanup!)
|
|
(let ((_el-inDiv (dom-create-element "div")) (_el-p1 (dom-create-element "p")))
|
|
(dom-set-attr _el-inDiv "id" "inDiv")
|
|
(dom-set-attr _el-inDiv "_" "on click get the first .{\"p1\"} in me put its id into @result")
|
|
(dom-set-attr _el-p1 "id" "p1")
|
|
(dom-add-class _el-p1 "p1")
|
|
(dom-append (dom-body) _el-inDiv)
|
|
(dom-append _el-inDiv _el-p1)
|
|
(hs-activate! _el-inDiv)
|
|
))
|
|
(deftest "id returns values"
|
|
(hs-cleanup!)
|
|
(let ((_el-inDiv (dom-create-element "div")) (_el-p1 (dom-create-element "p")))
|
|
(dom-set-attr _el-inDiv "id" "inDiv")
|
|
(dom-set-attr _el-inDiv "_" "on click get #p1 in me put its id into @result")
|
|
(dom-set-attr _el-p1 "id" "p1")
|
|
(dom-append (dom-body) _el-inDiv)
|
|
(dom-append _el-inDiv _el-p1)
|
|
(hs-activate! _el-inDiv)
|
|
))
|
|
(deftest "id template returns values"
|
|
(hs-cleanup!)
|
|
(let ((_el-inDiv (dom-create-element "div")) (_el-p1 (dom-create-element "p")))
|
|
(dom-set-attr _el-inDiv "id" "inDiv")
|
|
(dom-set-attr _el-inDiv "_" "on click get #{\"p1\"} in me put its id into @result")
|
|
(dom-set-attr _el-p1 "id" "p1")
|
|
(dom-append (dom-body) _el-inDiv)
|
|
(dom-append _el-inDiv _el-p1)
|
|
(hs-activate! _el-inDiv)
|
|
))
|
|
(deftest "in expression binds to unaryOperators"
|
|
(hs-cleanup!)
|
|
(let ((_el-d2 (dom-create-element "div")) (_el-p (dom-create-element "p")) (_el-p2 (dom-create-element "p")))
|
|
(dom-set-attr _el-d2 "id" "d2")
|
|
(dom-add-class _el-p "foo")
|
|
(dom-set-inner-html _el-p "bar")
|
|
(dom-append (dom-body) _el-d2)
|
|
(dom-append _el-d2 _el-p)
|
|
(dom-append _el-d2 _el-p2)
|
|
))
|
|
(deftest "null value in array returns empty"
|
|
(assert= (eval-hs "null in [1, 2, 3]") (list))
|
|
)
|
|
(deftest "query returns values"
|
|
(hs-cleanup!)
|
|
(let ((_el-inDiv (dom-create-element "div")) (_el-p1 (dom-create-element "p")))
|
|
(dom-set-attr _el-inDiv "id" "inDiv")
|
|
(dom-set-attr _el-inDiv "_" "on click get the first <p/> in me put its id into @result")
|
|
(dom-set-attr _el-p1 "id" "p1")
|
|
(dom-add-class _el-p1 "p1")
|
|
(dom-append (dom-body) _el-inDiv)
|
|
(dom-append _el-inDiv _el-p1)
|
|
(hs-activate! _el-inDiv)
|
|
))
|
|
(deftest "query template returns values"
|
|
(hs-cleanup!)
|
|
(let ((_el-inDiv (dom-create-element "div")) (_el-p1 (dom-create-element "p")))
|
|
(dom-set-attr _el-inDiv "id" "inDiv")
|
|
(dom-set-attr _el-inDiv "_" "on click get the first <${\"p\"}/> in me put its id into @result")
|
|
(dom-set-attr _el-p1 "id" "p1")
|
|
(dom-add-class _el-p1 "p1")
|
|
(dom-append (dom-body) _el-inDiv)
|
|
(dom-append _el-inDiv _el-p1)
|
|
(hs-activate! _el-inDiv)
|
|
))
|
|
)
|
|
|
|
;; ── expressions/logicalOperator (10 tests) ──
|
|
(defsuite "hs-upstream-expressions/logicalOperator"
|
|
(deftest "and short-circuits when lhs promise resolves to false"
|
|
(error "SKIP (untranslated): and short-circuits when lhs promise resolves to false"))
|
|
(deftest "and works"
|
|
(assert= (eval-hs "true and false") false)
|
|
)
|
|
(deftest "and works w/ more than one value"
|
|
(assert= (eval-hs "true and true and false") false)
|
|
)
|
|
(deftest "or evaluates rhs when lhs promise resolves to false"
|
|
(error "SKIP (untranslated): or evaluates rhs when lhs promise resolves to false"))
|
|
(deftest "or short-circuits when lhs promise resolves to true"
|
|
(error "SKIP (untranslated): or short-circuits when lhs promise resolves to true"))
|
|
(deftest "or works"
|
|
(assert= (eval-hs "true or false") true)
|
|
)
|
|
(deftest "parenthesized expressions with multiple operators work"
|
|
(assert= (eval-hs "true and (false or true)") true)
|
|
)
|
|
(deftest "should short circuit with and expression"
|
|
(let ((func1-called false) (func2-called false))
|
|
(let ((func1 (fn () (let ((dummy (set! func1-called true))) false)))
|
|
(func2 (fn () (let ((dummy (set! func2-called true))) false))))
|
|
(let ((result (eval-hs-locals "func1() and func2()"
|
|
(list (list (quote func1) func1) (list (quote func2) func2)))))
|
|
(assert= result false)
|
|
(assert func1-called)
|
|
(assert (not func2-called)))))
|
|
)
|
|
(deftest "should short circuit with or expression"
|
|
(let ((func1-called false) (func2-called false))
|
|
(let ((func1 (fn () (let ((dummy (set! func1-called true))) true)))
|
|
(func2 (fn () (let ((dummy (set! func2-called true))) true))))
|
|
(let ((result (eval-hs-locals "func1() or func2()"
|
|
(list (list (quote func1) func1) (list (quote func2) func2)))))
|
|
(assert result)
|
|
(assert func1-called)
|
|
(assert (not func2-called)))))
|
|
)
|
|
(deftest "unparenthesized expressions with multiple operators cause an error"
|
|
(assert-throws (fn () (eval-hs "true and false or true")))
|
|
)
|
|
)
|
|
|
|
;; ── expressions/mathOperator (15 tests) ──
|
|
(defsuite "hs-upstream-expressions/mathOperator"
|
|
(deftest "addition works"
|
|
(assert= (eval-hs "1 + 1") 2)
|
|
)
|
|
(deftest "addition works w/ more than one value"
|
|
(assert= (eval-hs "1 + 2 + 3") 6)
|
|
)
|
|
(deftest "array + array concats"
|
|
(assert= (eval-hs "[1, 2] + [3, 4]") (list 1 2 3 4))
|
|
)
|
|
(deftest "array + array does not mutate original"
|
|
(assert= (eval-hs "set a to [1, 2] then set b to a + [3] then return a") (list 1 2))
|
|
)
|
|
(deftest "array + single value appends"
|
|
(assert= (eval-hs "[1, 2] + 3") (list 1 2 3))
|
|
)
|
|
(deftest "array concat chains"
|
|
(assert= (eval-hs "[1] + [2] + [3]") (list 1 2 3))
|
|
)
|
|
(deftest "can use mixed expressions"
|
|
(error "SKIP (untranslated): can use mixed expressions"))
|
|
(deftest "division works"
|
|
(assert= (eval-hs "1 / 2") 0.5)
|
|
)
|
|
(deftest "empty array + array works"
|
|
(assert= (eval-hs "[] + [1, 2]") (list 1 2))
|
|
)
|
|
(deftest "mod works"
|
|
(assert= (eval-hs "3 mod 2") 1)
|
|
)
|
|
(deftest "multiplication works"
|
|
(assert= (eval-hs "1 * 2") 2)
|
|
)
|
|
(deftest "parenthesized expressions with multiple operators work"
|
|
(assert= (eval-hs "1 + (2 * 3)") 7)
|
|
)
|
|
(deftest "string concat works"
|
|
(assert= (eval-hs "'a' + 'b'") "ab")
|
|
)
|
|
(deftest "subtraction works"
|
|
(assert= (eval-hs "1 - 1") 0)
|
|
)
|
|
(deftest "unparenthesized expressions with multiple operators cause an error"
|
|
(assert-throws (fn () (eval-hs "1 + 2 * 3")))
|
|
)
|
|
)
|
|
|
|
;; ── expressions/no (9 tests) ──
|
|
(defsuite "hs-upstream-expressions/no"
|
|
(deftest "no returns false for non-empty array"
|
|
(assert= (eval-hs "no ['thing']") false)
|
|
)
|
|
(deftest "no returns false for non-null"
|
|
(assert= (eval-hs "no 'thing'") false)
|
|
)
|
|
(deftest "no returns true for empty array"
|
|
(assert= (eval-hs "no []") true)
|
|
)
|
|
(deftest "no returns true for empty selector"
|
|
(assert= (eval-hs "no .aClassThatDoesNotExist") true)
|
|
)
|
|
(deftest "no returns true for null"
|
|
(assert= (eval-hs "no null") true)
|
|
)
|
|
(deftest "no with where and is not"
|
|
(assert= (eval-hs "no [1, 2, 3] where it is not 2") false)
|
|
)
|
|
(deftest "no with where filters then checks emptiness"
|
|
(assert= (eval-hs "no [1, 2, 3] where it > 5") true)
|
|
)
|
|
(deftest "no with where on DOM elements"
|
|
(hs-cleanup!)
|
|
(let ((_el-box (dom-create-element "div")) (_el-span (dom-create-element "span")) (_el-span2 (dom-create-element "span")) (_el-button (dom-create-element "button")) (_el-out (dom-create-element "div")))
|
|
(dom-set-attr _el-box "id" "box")
|
|
(dom-add-class _el-span "a")
|
|
(dom-set-inner-html _el-span "A")
|
|
(dom-add-class _el-span2 "b")
|
|
(dom-set-inner-html _el-span2 "B")
|
|
(dom-set-attr _el-button "_" "on click if no <span/> in #box where it matches .c then put 'none' into #out else put 'found' into #out")
|
|
(dom-set-inner-html _el-button "go")
|
|
(dom-set-attr _el-out "id" "out")
|
|
(dom-append (dom-body) _el-box)
|
|
(dom-append _el-box _el-span)
|
|
(dom-append _el-box _el-span2)
|
|
(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")) "none")
|
|
))
|
|
(deftest "no with where returns false when matches exist"
|
|
(assert= (eval-hs "no [1, 2, 3] where it > 1") false)
|
|
)
|
|
)
|
|
|
|
;; ── expressions/not (9 tests) ──
|
|
(defsuite "hs-upstream-expressions/not"
|
|
(deftest "not has higher precedence than and"
|
|
(assert= (eval-hs "not false and true") true)
|
|
(assert= (eval-hs "not true and true") false)
|
|
)
|
|
(deftest "not has higher precedence than or"
|
|
(assert= (eval-hs "not true or true") true)
|
|
(assert= (eval-hs "not false or false") true)
|
|
)
|
|
(deftest "not inverts equality comparisons"
|
|
(assert= (eval-hs "not (1 is 2)") true)
|
|
(assert= (eval-hs "not (1 is 1)") false)
|
|
)
|
|
(deftest "not inverts false"
|
|
(assert= (eval-hs "not false") true)
|
|
)
|
|
(deftest "not inverts true"
|
|
(assert= (eval-hs "not true") false)
|
|
)
|
|
(deftest "not null and not undefined"
|
|
(assert= (eval-hs "not null") true)
|
|
(assert= (eval-hs "not undefined") true)
|
|
)
|
|
(deftest "not with numeric truthy/falsy values"
|
|
(assert= (eval-hs "not 0") true)
|
|
(assert= (eval-hs "not 1") false)
|
|
(assert= (eval-hs "not 42") false)
|
|
)
|
|
(deftest "not with string truthy/falsy values"
|
|
(assert= (eval-hs "not ''") true)
|
|
(assert= (eval-hs "not 'hello'") false)
|
|
)
|
|
(deftest "two nots make a true"
|
|
(assert= (eval-hs "not not true") true)
|
|
)
|
|
)
|
|
|
|
;; ── expressions/null (1 tests) ──
|
|
(defsuite "hs-upstream-expressions/null"
|
|
(deftest "null literal work"
|
|
(eval-hs "null")
|
|
)
|
|
)
|
|
|
|
;; ── expressions/numbers (1 tests) ──
|
|
(defsuite "hs-upstream-expressions/numbers"
|
|
(deftest "handles numbers properly"
|
|
(assert= (eval-hs "-1") -1)
|
|
(assert= (eval-hs "1") 1)
|
|
(assert= (eval-hs "1.1") 1.1)
|
|
(assert= (eval-hs "1e6") 1e6)
|
|
(assert= (eval-hs "1e-6") 1e-6)
|
|
(assert= (eval-hs "1.1e6") 1.1e6)
|
|
(assert= (eval-hs "1.1e-6") 1.1e-6)
|
|
(assert= (eval-hs "1234567890.1234567890") 1234567890.123456789)
|
|
)
|
|
)
|
|
|
|
;; ── expressions/objectLiteral (12 tests) ──
|
|
(defsuite "hs-upstream-expressions/objectLiteral"
|
|
(deftest "allows trailing commas"
|
|
;; TODO: assert= (eval-hs "{foo:true, bar-baz:false,}") against { "foo": true, "bar-baz": false }
|
|
)
|
|
(deftest "deeply nested object literals work"
|
|
;; TODO: assert= (eval-hs "{a: {b: {c: 'deep'}}}") against { a: { b: { c: 'deep' } } }
|
|
)
|
|
(deftest "empty object literals work"
|
|
;; TODO: assert= (eval-hs "{}") against {}
|
|
)
|
|
(deftest "expressions work in object literal field names"
|
|
(error "SKIP (untranslated): expressions work in object literal field names"))
|
|
(deftest "hyphens work in object literal field names"
|
|
;; TODO: assert= (eval-hs "{-foo:true, bar-baz:false}") against { "-foo": true, "bar-baz": false }
|
|
)
|
|
(deftest "mixed field name styles in one literal"
|
|
;; TODO: assert= (eval-hs "{plain: 1, \"quoted\": 2, -dashed: 3}") against { plain: 1, quoted: 2, "-dashed": 3 }
|
|
)
|
|
(deftest "multi-field object literal works"
|
|
;; TODO: assert= (eval-hs "{foo:true, bar:false}") against { foo: true, bar: false }
|
|
)
|
|
(deftest "nested object literals work"
|
|
;; TODO: assert= (eval-hs "{outer: {inner: 1}}") against { outer: { inner: 1 } }
|
|
)
|
|
(deftest "object literal values can be expressions"
|
|
;; TODO: assert= (eval-hs "{sum: 1 + 2, product: 3 * 4}") against { sum: 3, product: 12 }
|
|
)
|
|
(deftest "object literals can contain arrays"
|
|
;; TODO: assert= (eval-hs "{items: [1, 2, 3], count: 3}") against { items: [1, 2, 3], count: 3 }
|
|
)
|
|
(deftest "one field object literal works"
|
|
;; TODO: assert= (eval-hs "{foo:true}") against { foo: true }
|
|
)
|
|
(deftest "strings work in object literal field names"
|
|
;; TODO: assert= (eval-hs "{\"foo\":true, \"bar\":false}") against { foo: true, bar: false }
|
|
)
|
|
)
|
|
|
|
;; ── expressions/positionalExpression (7 tests) ──
|
|
(defsuite "hs-upstream-expressions/positionalExpression"
|
|
(deftest "first works"
|
|
(assert= (eval-hs "the first of [1, 2, 3]") 1)
|
|
)
|
|
(deftest "first works w/ array-like"
|
|
(hs-cleanup!)
|
|
(let ((_el-d1 (dom-create-element "div")) (_el-d2 (dom-create-element "div")) (_el-d3 (dom-create-element "div")))
|
|
(dom-set-attr _el-d1 "id" "d1")
|
|
(dom-add-class _el-d1 "c1")
|
|
(dom-set-attr _el-d2 "id" "d2")
|
|
(dom-add-class _el-d2 "c1")
|
|
(dom-set-attr _el-d3 "id" "d3")
|
|
(dom-add-class _el-d3 "c1")
|
|
(dom-append (dom-body) _el-d1)
|
|
(dom-append (dom-body) _el-d2)
|
|
(dom-append (dom-body) _el-d3)
|
|
))
|
|
(deftest "first works w/ node"
|
|
(hs-cleanup!)
|
|
(let ((_el-outerDiv (dom-create-element "div")) (_el-d1 (dom-create-element "div")) (_el-d2 (dom-create-element "div")) (_el-d3 (dom-create-element "div")))
|
|
(dom-set-attr _el-outerDiv "id" "outerDiv")
|
|
(dom-set-attr _el-d1 "id" "d1")
|
|
(dom-add-class _el-d1 "c1")
|
|
(dom-set-attr _el-d2 "id" "d2")
|
|
(dom-add-class _el-d2 "c1")
|
|
(dom-set-attr _el-d3 "id" "d3")
|
|
(dom-add-class _el-d3 "c1")
|
|
(dom-append (dom-body) _el-outerDiv)
|
|
(dom-append _el-outerDiv _el-d1)
|
|
(dom-append _el-outerDiv _el-d2)
|
|
(dom-append _el-outerDiv _el-d3)
|
|
))
|
|
(deftest "is null safe"
|
|
(eval-hs "the first of null")
|
|
)
|
|
(deftest "last works"
|
|
(assert= (eval-hs "the last of [1, 2, 3]") 3)
|
|
)
|
|
(deftest "last works w/ array-like"
|
|
(hs-cleanup!)
|
|
(let ((_el-d1 (dom-create-element "div")) (_el-d2 (dom-create-element "div")) (_el-d3 (dom-create-element "div")))
|
|
(dom-set-attr _el-d1 "id" "d1")
|
|
(dom-add-class _el-d1 "c1")
|
|
(dom-set-attr _el-d2 "id" "d2")
|
|
(dom-add-class _el-d2 "c1")
|
|
(dom-set-attr _el-d3 "id" "d3")
|
|
(dom-add-class _el-d3 "c1")
|
|
(dom-append (dom-body) _el-d1)
|
|
(dom-append (dom-body) _el-d2)
|
|
(dom-append (dom-body) _el-d3)
|
|
))
|
|
(deftest "last works w/ node"
|
|
(hs-cleanup!)
|
|
(let ((_el-outerDiv (dom-create-element "div")) (_el-d1 (dom-create-element "div")) (_el-d2 (dom-create-element "div")) (_el-d3 (dom-create-element "div")))
|
|
(dom-set-attr _el-outerDiv "id" "outerDiv")
|
|
(dom-set-attr _el-d1 "id" "d1")
|
|
(dom-add-class _el-d1 "c1")
|
|
(dom-set-attr _el-d2 "id" "d2")
|
|
(dom-add-class _el-d2 "c1")
|
|
(dom-set-attr _el-d3 "id" "d3")
|
|
(dom-add-class _el-d3 "c1")
|
|
(dom-append (dom-body) _el-outerDiv)
|
|
(dom-append _el-outerDiv _el-d1)
|
|
(dom-append _el-outerDiv _el-d2)
|
|
(dom-append _el-outerDiv _el-d3)
|
|
))
|
|
)
|
|
|
|
;; ── expressions/possessiveExpression (23 tests) ──
|
|
(defsuite "hs-upstream-expressions/possessiveExpression"
|
|
(deftest "can access basic attribute"
|
|
(hs-cleanup!)
|
|
(let ((_el-pDiv (dom-create-element "div")))
|
|
(dom-set-attr _el-pDiv "id" "pDiv")
|
|
(dom-set-attr _el-pDiv "data-foo" "bar")
|
|
(dom-append (dom-body) _el-pDiv)
|
|
))
|
|
(deftest "can access basic properties"
|
|
(assert= (eval-hs-locals "foo's foo" (list (list (quote foo) {:foo "foo"}))) "foo")
|
|
)
|
|
(deftest "can access basic style"
|
|
(hs-cleanup!)
|
|
(let ((_el-pDiv (dom-create-element "div")))
|
|
(dom-set-attr _el-pDiv "id" "pDiv")
|
|
(dom-set-attr _el-pDiv "style" "color:red")
|
|
(dom-append (dom-body) _el-pDiv)
|
|
))
|
|
(deftest "can access its properties"
|
|
(assert= (eval-hs-locals "its foo" (list (list (quote it) {:foo "foo"}))) "foo")
|
|
)
|
|
(deftest "can access multiple basic attributes"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")) (_el-div1 (dom-create-element "div")))
|
|
(dom-add-class _el-div "c1")
|
|
(dom-set-attr _el-div "data-foo" "bar")
|
|
(dom-add-class _el-div1 "c1")
|
|
(dom-set-attr _el-div1 "data-foo" "bar")
|
|
(dom-append (dom-body) _el-div)
|
|
(dom-append (dom-body) _el-div1)
|
|
))
|
|
(deftest "can access multiple basic styles"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")) (_el-div1 (dom-create-element "div")))
|
|
(dom-add-class _el-div "c1")
|
|
(dom-set-attr _el-div "style" "color:red")
|
|
(dom-add-class _el-div1 "c1")
|
|
(dom-set-attr _el-div1 "style" "color:red")
|
|
(dom-append (dom-body) _el-div)
|
|
(dom-append (dom-body) _el-div1)
|
|
))
|
|
(deftest "can access my attribute"
|
|
(hs-cleanup!)
|
|
(let ((_el-pDiv (dom-create-element "div")))
|
|
(dom-set-attr _el-pDiv "id" "pDiv")
|
|
(dom-set-attr _el-pDiv "data-foo" "bar")
|
|
(dom-append (dom-body) _el-pDiv)
|
|
))
|
|
(deftest "can access my properties"
|
|
(assert= (eval-hs-locals "my foo" (list (list (quote me) {:foo "foo"}))) "foo")
|
|
)
|
|
(deftest "can access my style"
|
|
(hs-cleanup!)
|
|
(let ((_el-pDiv (dom-create-element "div")))
|
|
(dom-set-attr _el-pDiv "id" "pDiv")
|
|
(dom-set-attr _el-pDiv "style" "color:red")
|
|
(dom-append (dom-body) _el-pDiv)
|
|
))
|
|
(deftest "can access properties on classrefs"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-add-class _el-div "foo")
|
|
(dom-set-attr _el-div "style" "display: inline")
|
|
(dom-append (dom-body) _el-div)
|
|
))
|
|
(deftest "can access properties on classrefs 2"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-add-class _el-div "foo")
|
|
(dom-set-attr _el-div "style" "display: inline")
|
|
(dom-append (dom-body) _el-div)
|
|
))
|
|
(deftest "can access properties on idrefs"
|
|
(hs-cleanup!)
|
|
(let ((_el-foo (dom-create-element "div")))
|
|
(dom-set-attr _el-foo "id" "foo")
|
|
(dom-set-attr _el-foo "style" "display: inline")
|
|
(dom-append (dom-body) _el-foo)
|
|
))
|
|
(deftest "can access properties on idrefs 2"
|
|
(hs-cleanup!)
|
|
(let ((_el-foo (dom-create-element "div")))
|
|
(dom-set-attr _el-foo "id" "foo")
|
|
(dom-set-attr _el-foo "style" "display: inline")
|
|
(dom-append (dom-body) _el-foo)
|
|
))
|
|
(deftest "can access properties on queryrefs"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-add-class _el-div "foo")
|
|
(dom-set-attr _el-div "style" "display: inline")
|
|
(dom-append (dom-body) _el-div)
|
|
))
|
|
(deftest "can access properties on queryrefs 2"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-add-class _el-div "foo")
|
|
(dom-set-attr _el-div "style" "display: inline")
|
|
(dom-append (dom-body) _el-div)
|
|
))
|
|
(deftest "can set basic attributes"
|
|
(hs-cleanup!)
|
|
(let ((_el-pDiv (dom-create-element "div")))
|
|
(dom-set-attr _el-pDiv "id" "pDiv")
|
|
(dom-set-attr _el-pDiv "data-foo" "bar")
|
|
(dom-append (dom-body) _el-pDiv)
|
|
))
|
|
(deftest "can set basic styles"
|
|
(hs-cleanup!)
|
|
(let ((_el-pDiv (dom-create-element "div")))
|
|
(dom-set-attr _el-pDiv "id" "pDiv")
|
|
(dom-set-attr _el-pDiv "style" "color:red")
|
|
(dom-append (dom-body) _el-pDiv)
|
|
))
|
|
(deftest "can set multiple basic attributes"
|
|
(hs-cleanup!)
|
|
(let ((_el-d1 (dom-create-element "div")) (_el-d2 (dom-create-element "div")))
|
|
(dom-set-attr _el-d1 "id" "d1")
|
|
(dom-add-class _el-d1 "c1")
|
|
(dom-set-attr _el-d1 "data-foo" "bar")
|
|
(dom-set-attr _el-d2 "id" "d2")
|
|
(dom-add-class _el-d2 "c1")
|
|
(dom-set-attr _el-d2 "data-foo" "bar")
|
|
(dom-append (dom-body) _el-d1)
|
|
(dom-append (dom-body) _el-d2)
|
|
))
|
|
(deftest "can set multiple basic styles"
|
|
(hs-cleanup!)
|
|
(let ((_el-d1 (dom-create-element "div")) (_el-d2 (dom-create-element "div")))
|
|
(dom-set-attr _el-d1 "id" "d1")
|
|
(dom-add-class _el-d1 "c1")
|
|
(dom-set-attr _el-d1 "style" "color:red")
|
|
(dom-set-attr _el-d2 "id" "d2")
|
|
(dom-add-class _el-d2 "c1")
|
|
(dom-set-attr _el-d2 "style" "color:red")
|
|
(dom-append (dom-body) _el-d1)
|
|
(dom-append (dom-body) _el-d2)
|
|
))
|
|
(deftest "can set root styles"
|
|
(hs-cleanup!)
|
|
(let ((_el-pDiv (dom-create-element "div")))
|
|
(dom-set-attr _el-pDiv "id" "pDiv")
|
|
(dom-set-attr _el-pDiv "style" "color:red")
|
|
(dom-append (dom-body) _el-pDiv)
|
|
))
|
|
(deftest "is null safe"
|
|
(eval-hs "foo's foo")
|
|
)
|
|
(deftest "its property is null safe"
|
|
(eval-hs "its foo")
|
|
)
|
|
(deftest "my property is null safe"
|
|
(eval-hs "my foo")
|
|
)
|
|
)
|
|
|
|
;; ── expressions/propertyAccess (12 tests) ──
|
|
(defsuite "hs-upstream-expressions/propertyAccess"
|
|
(deftest "can access basic properties"
|
|
(assert= (eval-hs-locals "foo.foo" (list (list (quote foo) {:foo "foo"}))) "foo")
|
|
)
|
|
(deftest "chained property access (four levels)"
|
|
(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-locals "a.b.c" (list (list (quote a) {:b {:c "deep"}}))) "deep")
|
|
)
|
|
(deftest "is null safe"
|
|
(eval-hs "foo.foo")
|
|
)
|
|
(deftest "mixing dot and of forms"
|
|
(assert= (eval-hs-locals "c of a.b" (list (list (quote a) {:b {:c "mixed"}}))) "mixed")
|
|
)
|
|
(deftest "null-safe access through an undefined intermediate"
|
|
(eval-hs "a.b.c")
|
|
)
|
|
(deftest "of form chains through multiple levels"
|
|
(assert= (eval-hs-locals "c of b of a" (list (list (quote a) {:b {:c "deep"}}))) "deep")
|
|
)
|
|
(deftest "of form works"
|
|
(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-locals "bar.doh of foo" (list (list (quote foo) {:bar {:doh "foo"}}))) "foo")
|
|
)
|
|
(deftest "of form works w/ complex right side"
|
|
(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-locals "makeObj().name" (list (list (quote makeObj) (fn () {:name "hi"})))) "hi")
|
|
)
|
|
(deftest "works properly w/ boolean properties"
|
|
(hs-cleanup!)
|
|
(let ((_el-input (dom-create-element "input")) (_el-input1 (dom-create-element "input")))
|
|
(dom-add-class _el-input "cb")
|
|
(dom-set-attr _el-input "type" "checkbox")
|
|
(dom-set-attr _el-input "checked" "checked")
|
|
(dom-add-class _el-input1 "cb")
|
|
(dom-set-attr _el-input1 "type" "checkbox")
|
|
(dom-append (dom-body) _el-input)
|
|
(dom-append (dom-body) _el-input1)
|
|
))
|
|
)
|
|
|
|
;; ── expressions/queryRef (13 tests) ──
|
|
(defsuite "hs-upstream-expressions/queryRef"
|
|
(deftest "basic queryRef works"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-add-class _el-div "c1")
|
|
(dom-append (dom-body) _el-div)
|
|
))
|
|
(deftest "basic queryRef works w no match"
|
|
(error "SKIP (untranslated): basic queryRef works w no match"))
|
|
(deftest "basic queryRef works w properties w/ strings"
|
|
(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 "c1")
|
|
(dom-add-class _el-div1 "c2")
|
|
(dom-set-attr _el-div1 "foo" "bar")
|
|
(dom-add-class _el-div2 "c3")
|
|
(dom-append (dom-body) _el-div)
|
|
(dom-append (dom-body) _el-div1)
|
|
(dom-append (dom-body) _el-div2)
|
|
))
|
|
(deftest "basic queryRef works w/ div selector"
|
|
(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 "c1")
|
|
(dom-add-class _el-div1 "c2")
|
|
(dom-add-class _el-div2 "c3")
|
|
(dom-append (dom-body) _el-div)
|
|
(dom-append (dom-body) _el-div1)
|
|
(dom-append (dom-body) _el-div2)
|
|
))
|
|
(deftest "basic queryRef works w/ funny selector"
|
|
(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 "title" "t1")
|
|
(dom-set-attr _el-div1 "title" "t2")
|
|
(dom-set-attr _el-div2 "title" "t3")
|
|
(dom-append (dom-body) _el-div)
|
|
(dom-append (dom-body) _el-div1)
|
|
(dom-append (dom-body) _el-div2)
|
|
))
|
|
(deftest "basic queryRef works w/ multiple matches"
|
|
(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 "c1")
|
|
(dom-add-class _el-div1 "c1")
|
|
(dom-add-class _el-div2 "c1")
|
|
(dom-append (dom-body) _el-div)
|
|
(dom-append (dom-body) _el-div1)
|
|
(dom-append (dom-body) _el-div2)
|
|
))
|
|
(deftest "basic queryRef works w/ properties"
|
|
(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 "title" "t1")
|
|
(dom-set-attr _el-div1 "title" "t2")
|
|
(dom-set-attr _el-div2 "title" "t3")
|
|
(dom-append (dom-body) _el-div)
|
|
(dom-append (dom-body) _el-div1)
|
|
(dom-append (dom-body) _el-div2)
|
|
))
|
|
(deftest "can interpolate elements into queries"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")) (_el-div1 (dom-create-element "div")))
|
|
(dom-add-class _el-div "a")
|
|
(dom-add-class _el-div1 "b")
|
|
(dom-append (dom-body) _el-div)
|
|
(dom-append (dom-body) _el-div1)
|
|
))
|
|
(deftest "queryRef w/ $ no curlies works"
|
|
(hs-cleanup!)
|
|
(let ((_el-t1 (dom-create-element "div")) (_el-t2 (dom-create-element "div")) (_el-t3 (dom-create-element "div")))
|
|
(dom-set-attr _el-t1 "id" "t1")
|
|
(dom-set-attr _el-t2 "id" "t2")
|
|
(dom-set-attr _el-t3 "id" "t3")
|
|
(dom-append (dom-body) _el-t1)
|
|
(dom-append (dom-body) _el-t2)
|
|
(dom-append (dom-body) _el-t3)
|
|
))
|
|
(deftest "queryRef w/ $ works"
|
|
(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 "c1")
|
|
(dom-add-class _el-div1 "c2")
|
|
(dom-set-attr _el-div1 "foo" "bar")
|
|
(dom-add-class _el-div2 "c3")
|
|
(dom-append (dom-body) _el-div)
|
|
(dom-append (dom-body) _el-div1)
|
|
(dom-append (dom-body) _el-div2)
|
|
))
|
|
(deftest "queryRefs support colons properly"
|
|
(hs-cleanup!)
|
|
(let ((_el-input (dom-create-element "input")))
|
|
(dom-add-class _el-input "foo")
|
|
(dom-set-attr _el-input "type" "checkbox")
|
|
(dom-set-attr _el-input "checked" "checked")
|
|
(dom-append (dom-body) _el-input)
|
|
))
|
|
(deftest "queryRefs support dollar properly"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "title" "little flower")
|
|
(dom-append (dom-body) _el-div)
|
|
))
|
|
(deftest "queryRefs support tildes properly"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "title" "little flower")
|
|
(dom-append (dom-body) _el-div)
|
|
))
|
|
)
|
|
|
|
;; ── expressions/relativePositionalExpression (23 tests) ──
|
|
(defsuite "hs-upstream-expressions/relativePositionalExpression"
|
|
(deftest "can access property of next element with possessive"
|
|
(hs-cleanup!)
|
|
(let ((_el-d1 (dom-create-element "div")) (_el-d2 (dom-create-element "div")))
|
|
(dom-set-attr _el-d1 "id" "d1")
|
|
(dom-set-attr _el-d2 "id" "d2")
|
|
(dom-set-inner-html _el-d2 "hello")
|
|
(dom-append (dom-body) _el-d1)
|
|
(dom-append (dom-body) _el-d2)
|
|
))
|
|
(deftest "can access property of previous element with possessive"
|
|
(hs-cleanup!)
|
|
(let ((_el-d1 (dom-create-element "div")) (_el-d2 (dom-create-element "div")))
|
|
(dom-set-attr _el-d1 "id" "d1")
|
|
(dom-set-inner-html _el-d1 "world")
|
|
(dom-set-attr _el-d2 "id" "d2")
|
|
(dom-append (dom-body) _el-d1)
|
|
(dom-append (dom-body) _el-d2)
|
|
))
|
|
(deftest "can access style of next element with possessive"
|
|
(hs-cleanup!)
|
|
(let ((_el-d1 (dom-create-element "div")) (_el-d2 (dom-create-element "div")))
|
|
(dom-set-attr _el-d1 "id" "d1")
|
|
(dom-set-attr _el-d2 "id" "d2")
|
|
(dom-set-attr _el-d2 "style" "color: red")
|
|
(dom-append (dom-body) _el-d1)
|
|
(dom-append (dom-body) _el-d2)
|
|
))
|
|
(deftest "can write to next element with put command"
|
|
(error "SKIP (untranslated): can write to next element with put command"))
|
|
(deftest "next works properly among siblings"
|
|
(hs-cleanup!)
|
|
(let ((_el-d1 (dom-create-element "div")) (_el-d2 (dom-create-element "div")) (_el-d3 (dom-create-element "div")))
|
|
(dom-set-attr _el-d1 "id" "d1")
|
|
(dom-add-class _el-d1 "c1")
|
|
(dom-set-attr _el-d2 "id" "d2")
|
|
(dom-add-class _el-d2 "c1")
|
|
(dom-set-attr _el-d3 "id" "d3")
|
|
(dom-add-class _el-d3 "c1")
|
|
(dom-append (dom-body) _el-d1)
|
|
(dom-append (dom-body) _el-d2)
|
|
(dom-append (dom-body) _el-d3)
|
|
))
|
|
(deftest "next works properly among siblings with wrapping"
|
|
(hs-cleanup!)
|
|
(let ((_el-d1 (dom-create-element "div")) (_el-d2 (dom-create-element "div")) (_el-d3 (dom-create-element "div")))
|
|
(dom-set-attr _el-d1 "id" "d1")
|
|
(dom-add-class _el-d1 "c1")
|
|
(dom-set-attr _el-d2 "id" "d2")
|
|
(dom-add-class _el-d2 "c1")
|
|
(dom-set-attr _el-d3 "id" "d3")
|
|
(dom-add-class _el-d3 "c1")
|
|
(dom-append (dom-body) _el-d1)
|
|
(dom-append (dom-body) _el-d2)
|
|
(dom-append (dom-body) _el-d3)
|
|
))
|
|
(deftest "next works properly with array-like"
|
|
(hs-cleanup!)
|
|
(let ((_el-d1 (dom-create-element "div")) (_el-p (dom-create-element "p")) (_el-d2 (dom-create-element "div")) (_el-p3 (dom-create-element "p")) (_el-d3 (dom-create-element "div")))
|
|
(dom-set-attr _el-d1 "id" "d1")
|
|
(dom-add-class _el-d1 "c1")
|
|
(dom-add-class _el-p "c1")
|
|
(dom-set-attr _el-d2 "id" "d2")
|
|
(dom-add-class _el-d2 "c1")
|
|
(dom-add-class _el-p3 "c1")
|
|
(dom-set-attr _el-d3 "id" "d3")
|
|
(dom-add-class _el-d3 "c1")
|
|
(dom-append (dom-body) _el-d1)
|
|
(dom-append (dom-body) _el-p)
|
|
(dom-append (dom-body) _el-d2)
|
|
(dom-append (dom-body) _el-p3)
|
|
(dom-append (dom-body) _el-d3)
|
|
))
|
|
(deftest "next works properly with array-like and wrap"
|
|
(hs-cleanup!)
|
|
(let ((_el-d1 (dom-create-element "div")) (_el-p (dom-create-element "p")) (_el-d2 (dom-create-element "div")) (_el-p3 (dom-create-element "p")) (_el-d3 (dom-create-element "div")))
|
|
(dom-set-attr _el-d1 "id" "d1")
|
|
(dom-add-class _el-d1 "c1")
|
|
(dom-add-class _el-p "c1")
|
|
(dom-set-attr _el-d2 "id" "d2")
|
|
(dom-add-class _el-d2 "c1")
|
|
(dom-add-class _el-p3 "c1")
|
|
(dom-set-attr _el-d3 "id" "d3")
|
|
(dom-add-class _el-d3 "c1")
|
|
(dom-append (dom-body) _el-d1)
|
|
(dom-append (dom-body) _el-p)
|
|
(dom-append (dom-body) _el-d2)
|
|
(dom-append (dom-body) _el-p3)
|
|
(dom-append (dom-body) _el-d3)
|
|
))
|
|
(deftest "next works properly with array-like no match"
|
|
(hs-cleanup!)
|
|
(let ((_el-d1 (dom-create-element "div")) (_el-p (dom-create-element "p")) (_el-d2 (dom-create-element "div")) (_el-p3 (dom-create-element "p")) (_el-d3 (dom-create-element "div")))
|
|
(dom-set-attr _el-d1 "id" "d1")
|
|
(dom-add-class _el-d1 "c1")
|
|
(dom-add-class _el-p "c1")
|
|
(dom-set-attr _el-d2 "id" "d2")
|
|
(dom-add-class _el-d2 "c1")
|
|
(dom-add-class _el-p3 "c1")
|
|
(dom-set-attr _el-d3 "id" "d3")
|
|
(dom-add-class _el-d3 "c1")
|
|
(dom-append (dom-body) _el-d1)
|
|
(dom-append (dom-body) _el-p)
|
|
(dom-append (dom-body) _el-d2)
|
|
(dom-append (dom-body) _el-p3)
|
|
(dom-append (dom-body) _el-d3)
|
|
))
|
|
(deftest "next works properly with array-like no match and wrap"
|
|
(hs-cleanup!)
|
|
(let ((_el-d1 (dom-create-element "div")) (_el-p (dom-create-element "p")) (_el-d2 (dom-create-element "div")) (_el-p3 (dom-create-element "p")) (_el-d3 (dom-create-element "div")))
|
|
(dom-set-attr _el-d1 "id" "d1")
|
|
(dom-add-class _el-d1 "c1")
|
|
(dom-add-class _el-p "c1")
|
|
(dom-set-attr _el-d2 "id" "d2")
|
|
(dom-add-class _el-d2 "c1")
|
|
(dom-add-class _el-p3 "c1")
|
|
(dom-set-attr _el-d3 "id" "d3")
|
|
(dom-add-class _el-d3 "c1")
|
|
(dom-append (dom-body) _el-d1)
|
|
(dom-append (dom-body) _el-p)
|
|
(dom-append (dom-body) _el-d2)
|
|
(dom-append (dom-body) _el-p3)
|
|
(dom-append (dom-body) _el-d3)
|
|
))
|
|
(deftest "previous works properly among siblings"
|
|
(hs-cleanup!)
|
|
(let ((_el-d1 (dom-create-element "div")) (_el-d2 (dom-create-element "div")) (_el-d3 (dom-create-element "div")))
|
|
(dom-set-attr _el-d1 "id" "d1")
|
|
(dom-add-class _el-d1 "c1")
|
|
(dom-set-attr _el-d2 "id" "d2")
|
|
(dom-add-class _el-d2 "c1")
|
|
(dom-set-attr _el-d3 "id" "d3")
|
|
(dom-add-class _el-d3 "c1")
|
|
(dom-append (dom-body) _el-d1)
|
|
(dom-append (dom-body) _el-d2)
|
|
(dom-append (dom-body) _el-d3)
|
|
))
|
|
(deftest "previous works properly among siblings with wrapping"
|
|
(hs-cleanup!)
|
|
(let ((_el-d1 (dom-create-element "div")) (_el-d2 (dom-create-element "div")) (_el-d3 (dom-create-element "div")))
|
|
(dom-set-attr _el-d1 "id" "d1")
|
|
(dom-add-class _el-d1 "c1")
|
|
(dom-set-attr _el-d2 "id" "d2")
|
|
(dom-add-class _el-d2 "c1")
|
|
(dom-set-attr _el-d3 "id" "d3")
|
|
(dom-add-class _el-d3 "c1")
|
|
(dom-append (dom-body) _el-d1)
|
|
(dom-append (dom-body) _el-d2)
|
|
(dom-append (dom-body) _el-d3)
|
|
))
|
|
(deftest "previous works properly with array-like"
|
|
(hs-cleanup!)
|
|
(let ((_el-d1 (dom-create-element "div")) (_el-p (dom-create-element "p")) (_el-d2 (dom-create-element "div")) (_el-p3 (dom-create-element "p")) (_el-d3 (dom-create-element "div")))
|
|
(dom-set-attr _el-d1 "id" "d1")
|
|
(dom-add-class _el-d1 "c1")
|
|
(dom-add-class _el-p "c1")
|
|
(dom-set-attr _el-d2 "id" "d2")
|
|
(dom-add-class _el-d2 "c1")
|
|
(dom-add-class _el-p3 "c1")
|
|
(dom-set-attr _el-d3 "id" "d3")
|
|
(dom-add-class _el-d3 "c1")
|
|
(dom-append (dom-body) _el-d1)
|
|
(dom-append (dom-body) _el-p)
|
|
(dom-append (dom-body) _el-d2)
|
|
(dom-append (dom-body) _el-p3)
|
|
(dom-append (dom-body) _el-d3)
|
|
))
|
|
(deftest "previous works properly with array-like and wrap"
|
|
(hs-cleanup!)
|
|
(let ((_el-d1 (dom-create-element "div")) (_el-p (dom-create-element "p")) (_el-d2 (dom-create-element "div")) (_el-p3 (dom-create-element "p")) (_el-d3 (dom-create-element "div")))
|
|
(dom-set-attr _el-d1 "id" "d1")
|
|
(dom-add-class _el-d1 "c1")
|
|
(dom-add-class _el-p "c1")
|
|
(dom-set-attr _el-d2 "id" "d2")
|
|
(dom-add-class _el-d2 "c1")
|
|
(dom-add-class _el-p3 "c1")
|
|
(dom-set-attr _el-d3 "id" "d3")
|
|
(dom-add-class _el-d3 "c1")
|
|
(dom-append (dom-body) _el-d1)
|
|
(dom-append (dom-body) _el-p)
|
|
(dom-append (dom-body) _el-d2)
|
|
(dom-append (dom-body) _el-p3)
|
|
(dom-append (dom-body) _el-d3)
|
|
))
|
|
(deftest "previous works properly with array-like no match"
|
|
(hs-cleanup!)
|
|
(let ((_el-d1 (dom-create-element "div")) (_el-p (dom-create-element "p")) (_el-d2 (dom-create-element "div")) (_el-p3 (dom-create-element "p")) (_el-d3 (dom-create-element "div")))
|
|
(dom-set-attr _el-d1 "id" "d1")
|
|
(dom-add-class _el-d1 "c1")
|
|
(dom-add-class _el-p "c1")
|
|
(dom-set-attr _el-d2 "id" "d2")
|
|
(dom-add-class _el-d2 "c1")
|
|
(dom-add-class _el-p3 "c1")
|
|
(dom-set-attr _el-d3 "id" "d3")
|
|
(dom-add-class _el-d3 "c1")
|
|
(dom-append (dom-body) _el-d1)
|
|
(dom-append (dom-body) _el-p)
|
|
(dom-append (dom-body) _el-d2)
|
|
(dom-append (dom-body) _el-p3)
|
|
(dom-append (dom-body) _el-d3)
|
|
))
|
|
(deftest "previous works properly with array-like no match and wrap"
|
|
(hs-cleanup!)
|
|
(let ((_el-d1 (dom-create-element "div")) (_el-p (dom-create-element "p")) (_el-d2 (dom-create-element "div")) (_el-p3 (dom-create-element "p")) (_el-d3 (dom-create-element "div")))
|
|
(dom-set-attr _el-d1 "id" "d1")
|
|
(dom-add-class _el-d1 "c1")
|
|
(dom-add-class _el-p "c1")
|
|
(dom-set-attr _el-d2 "id" "d2")
|
|
(dom-add-class _el-d2 "c1")
|
|
(dom-add-class _el-p3 "c1")
|
|
(dom-set-attr _el-d3 "id" "d3")
|
|
(dom-add-class _el-d3 "c1")
|
|
(dom-append (dom-body) _el-d1)
|
|
(dom-append (dom-body) _el-p)
|
|
(dom-append (dom-body) _el-d2)
|
|
(dom-append (dom-body) _el-p3)
|
|
(dom-append (dom-body) _el-d3)
|
|
))
|
|
(deftest "properly constrains via the within modifier"
|
|
(hs-cleanup!)
|
|
(let ((_el-d1 (dom-create-element "div")) (_el-d2 (dom-create-element "div")) (_el-d3 (dom-create-element "div")) (_el-d4 (dom-create-element "div")))
|
|
(dom-set-attr _el-d1 "id" "d1")
|
|
(dom-add-class _el-d1 "c1")
|
|
(dom-set-attr _el-d2 "id" "d2")
|
|
(dom-add-class _el-d2 "c1")
|
|
(dom-set-attr _el-d3 "id" "d3")
|
|
(dom-add-class _el-d3 "c1")
|
|
(dom-set-attr _el-d4 "id" "d4")
|
|
(dom-add-class _el-d4 "c1")
|
|
(dom-append (dom-body) _el-d1)
|
|
(dom-append _el-d1 _el-d2)
|
|
(dom-append _el-d1 _el-d3)
|
|
(dom-append (dom-body) _el-d4)
|
|
))
|
|
(deftest "relative next works properly among siblings w/ class"
|
|
(hs-cleanup!)
|
|
(let ((_el-d1 (dom-create-element "div")) (_el-d2 (dom-create-element "div")))
|
|
(dom-set-attr _el-d1 "id" "d1")
|
|
(dom-add-class _el-d1 "c1")
|
|
(dom-set-attr _el-d1 "_" "on click add .foo to next .c1")
|
|
(dom-set-attr _el-d2 "id" "d2")
|
|
(dom-add-class _el-d2 "c1")
|
|
(dom-append (dom-body) _el-d1)
|
|
(dom-append (dom-body) _el-d2)
|
|
(hs-activate! _el-d1)
|
|
))
|
|
(deftest "relative next works properly among siblings w/ query"
|
|
(hs-cleanup!)
|
|
(let ((_el-d1 (dom-create-element "div")) (_el-d2 (dom-create-element "div")))
|
|
(dom-set-attr _el-d1 "id" "d1")
|
|
(dom-add-class _el-d1 "c1")
|
|
(dom-set-attr _el-d1 "_" "on click add .foo to next <div/>")
|
|
(dom-set-attr _el-d2 "id" "d2")
|
|
(dom-add-class _el-d2 "c1")
|
|
(dom-append (dom-body) _el-d1)
|
|
(dom-append (dom-body) _el-d2)
|
|
(hs-activate! _el-d1)
|
|
))
|
|
(deftest "relative next works properly among siblings w/ query & class"
|
|
(hs-cleanup!)
|
|
(let ((_el-d1 (dom-create-element "div")) (_el-d2 (dom-create-element "div")))
|
|
(dom-set-attr _el-d1 "id" "d1")
|
|
(dom-add-class _el-d1 "c1")
|
|
(dom-set-attr _el-d1 "_" "on click add .foo to next <div.c1/>")
|
|
(dom-set-attr _el-d2 "id" "d2")
|
|
(dom-add-class _el-d2 "c1")
|
|
(dom-append (dom-body) _el-d1)
|
|
(dom-append (dom-body) _el-d2)
|
|
(hs-activate! _el-d1)
|
|
))
|
|
(deftest "relative previous works properly among siblings w/ class"
|
|
(hs-cleanup!)
|
|
(let ((_el-d1 (dom-create-element "div")) (_el-d2 (dom-create-element "div")))
|
|
(dom-set-attr _el-d1 "id" "d1")
|
|
(dom-add-class _el-d1 "c1")
|
|
(dom-set-attr _el-d2 "id" "d2")
|
|
(dom-add-class _el-d2 "c1")
|
|
(dom-set-attr _el-d2 "_" "on click add .foo to previous .c1")
|
|
(dom-append (dom-body) _el-d1)
|
|
(dom-append (dom-body) _el-d2)
|
|
(hs-activate! _el-d2)
|
|
))
|
|
(deftest "relative previous works properly among siblings w/ query"
|
|
(hs-cleanup!)
|
|
(let ((_el-d1 (dom-create-element "div")) (_el-d2 (dom-create-element "div")))
|
|
(dom-set-attr _el-d1 "id" "d1")
|
|
(dom-add-class _el-d1 "c1")
|
|
(dom-set-attr _el-d2 "id" "d2")
|
|
(dom-add-class _el-d2 "c1")
|
|
(dom-set-attr _el-d2 "_" "on click add .foo to previous <div/>")
|
|
(dom-append (dom-body) _el-d1)
|
|
(dom-append (dom-body) _el-d2)
|
|
(hs-activate! _el-d2)
|
|
))
|
|
(deftest "relative previous works properly among siblings w/ query & class"
|
|
(hs-cleanup!)
|
|
(let ((_el-d1 (dom-create-element "div")) (_el-d2 (dom-create-element "div")))
|
|
(dom-set-attr _el-d1 "id" "d1")
|
|
(dom-add-class _el-d1 "c1")
|
|
(dom-set-attr _el-d2 "id" "d2")
|
|
(dom-add-class _el-d2 "c1")
|
|
(dom-set-attr _el-d2 "_" "on click add .foo to previous <div.c1/>")
|
|
(dom-append (dom-body) _el-d1)
|
|
(dom-append (dom-body) _el-d2)
|
|
(hs-activate! _el-d2)
|
|
))
|
|
)
|
|
|
|
;; ── expressions/some (6 tests) ──
|
|
(defsuite "hs-upstream-expressions/some"
|
|
(deftest "some returns false for empty array"
|
|
(assert= (eval-hs "some []") false)
|
|
)
|
|
(deftest "some returns false for empty selector"
|
|
(assert= (eval-hs "some .aClassThatDoesNotExist") false)
|
|
)
|
|
(deftest "some returns false for null"
|
|
(assert= (eval-hs "some null") false)
|
|
)
|
|
(deftest "some returns true for filled array"
|
|
(assert= (eval-hs "some ['thing']") true)
|
|
)
|
|
(deftest "some returns true for non-null"
|
|
(assert= (eval-hs "some 'thing'") true)
|
|
)
|
|
(deftest "some returns true for nonempty selector"
|
|
(assert= (eval-hs "some <html/>") true)
|
|
)
|
|
)
|
|
|
|
;; ── expressions/splitJoin (7 tests) ──
|
|
(defsuite "hs-upstream-expressions/splitJoin"
|
|
(deftest "joins an array with delimiter"
|
|
(assert= (eval-hs "return [\"a\", \"b\", \"c\"] joined by \", \"") "a, b, c")
|
|
)
|
|
(deftest "joins with empty string"
|
|
(assert= (eval-hs "return [\"x\", \"y\", \"z\"] joined by \"\"") "xyz")
|
|
)
|
|
(deftest "split then mapped then joined"
|
|
(assert= (eval-hs "return \"hello world\" split by \" \" mapped to its length joined by \",\"") "5,5")
|
|
)
|
|
(deftest "split then sorted then joined"
|
|
(assert= (eval-hs "return \"banana,apple,cherry\" split by \",\" sorted by it joined by \", \"") "apple, banana, cherry")
|
|
)
|
|
(deftest "split then where then joined"
|
|
(assert= (eval-hs "return \"a,,b,,c\" split by \",\" where it is not \"\" joined by \"-\"") "a-b-c")
|
|
)
|
|
(deftest "splits a string by delimiter"
|
|
(assert= (eval-hs "return \"a,b,c\" split by \",\"") (list "a" "b" "c"))
|
|
)
|
|
(deftest "splits by whitespace"
|
|
(assert= (eval-hs "return \"hello world\" split by \" \"") (list "hello" "world"))
|
|
)
|
|
)
|
|
|
|
;; ── expressions/stringPostfix (3 tests) ──
|
|
(defsuite "hs-upstream-expressions/stringPostfix"
|
|
(deftest "handles basic postfix strings properly"
|
|
(assert= (eval-hs "1em") "1em")
|
|
(assert= (eval-hs "1px") "1px")
|
|
(assert= (eval-hs "-1px") "-1px")
|
|
(assert= (eval-hs "100%") "100%")
|
|
)
|
|
(deftest "handles basic postfix strings with spaces properly"
|
|
(assert= (eval-hs "1 em") "1em")
|
|
(assert= (eval-hs "1 px") "1px")
|
|
(assert= (eval-hs "100 %") "100%")
|
|
)
|
|
(deftest "handles expression roots properly"
|
|
(assert= (eval-hs "(0 + 1) em") "1em")
|
|
(assert= (eval-hs "(0 + 1) px") "1px")
|
|
(assert= (eval-hs "(100 + 0) %") "100%")
|
|
)
|
|
)
|
|
|
|
;; ── expressions/strings (8 tests) ──
|
|
(defsuite "hs-upstream-expressions/strings"
|
|
(deftest "handles strings properly"
|
|
(assert= (eval-hs "\"foo\"") "foo")
|
|
(assert= (eval-hs "\"fo'o\"") "fo'o")
|
|
(assert= (eval-hs "'foo'") "foo")
|
|
)
|
|
(deftest "should handle back slashes in non-template content"
|
|
(assert= (eval-hs-locals "`https://${foo}`" (list (list (quote foo) "bar"))) "https://bar")
|
|
)
|
|
(deftest "should handle strings with tags and quotes"
|
|
(let ((record {:name "John Connor" :age 21 :favouriteColour "bleaux"}))
|
|
(assert= (eval-hs-locals
|
|
"`<div age=\"${record.age}\" style=\"color:${record.favouriteColour}\">${record.name}</div>`"
|
|
(list (list (quote record) record)))
|
|
"<div age=\"21\" style=\"color:bleaux\">John Connor</div>"))
|
|
)
|
|
(deftest "string templates preserve white space"
|
|
(assert= (eval-hs "` ${1 + 2} ${1 + 2} `") " 3 3 ")
|
|
(assert= (eval-hs "`${1 + 2} ${1 + 2} `") "3 3 ")
|
|
(assert= (eval-hs "`${1 + 2}${1 + 2} `") "33 ")
|
|
(assert= (eval-hs "`${1 + 2} ${1 + 2}`") "3 3")
|
|
)
|
|
(deftest "string templates work properly"
|
|
(assert= (eval-hs "`$1`") "1")
|
|
)
|
|
(deftest "string templates work properly w braces"
|
|
(assert= (eval-hs "`${1 + 2}`") "3")
|
|
)
|
|
(deftest "string templates work w/ props"
|
|
(assert= (eval-hs-locals "`$window.foo`" (list (list (quote foo) "foo"))) "foo")
|
|
)
|
|
(deftest "string templates work w/ props w/ braces"
|
|
(assert= (eval-hs-locals "`${window.foo}`" (list (list (quote foo) "foo"))) "foo")
|
|
)
|
|
)
|
|
|
|
;; ── expressions/styleRef (6 tests) ──
|
|
(defsuite "hs-upstream-expressions/styleRef"
|
|
(deftest "basic style ref works"
|
|
(hs-cleanup!)
|
|
(let ((_el-sDiv (dom-create-element "div")))
|
|
(dom-set-attr _el-sDiv "id" "sDiv")
|
|
(dom-set-attr _el-sDiv "style" "color: red; text-align: center; width: 10px")
|
|
(dom-append (dom-body) _el-sDiv)
|
|
))
|
|
(deftest "calculated of style ref works"
|
|
(hs-cleanup!)
|
|
(let ((_el-sDiv (dom-create-element "div")))
|
|
(dom-set-attr _el-sDiv "id" "sDiv")
|
|
(dom-set-attr _el-sDiv "style" "color: red; text-align: center; width: 10px")
|
|
(dom-append (dom-body) _el-sDiv)
|
|
))
|
|
(deftest "calculated possessive style ref works"
|
|
(hs-cleanup!)
|
|
(let ((_el-sDiv (dom-create-element "div")))
|
|
(dom-set-attr _el-sDiv "id" "sDiv")
|
|
(dom-set-attr _el-sDiv "style" "color: red; text-align: center; width: 10px")
|
|
(dom-append (dom-body) _el-sDiv)
|
|
))
|
|
(deftest "calculated style ref works"
|
|
(hs-cleanup!)
|
|
(let ((_el-sDiv (dom-create-element "div")))
|
|
(dom-set-attr _el-sDiv "id" "sDiv")
|
|
(dom-set-attr _el-sDiv "style" "color: red; text-align: center; width: 10px")
|
|
(dom-append (dom-body) _el-sDiv)
|
|
))
|
|
(deftest "of style ref works"
|
|
(hs-cleanup!)
|
|
(let ((_el-sDiv (dom-create-element "div")))
|
|
(dom-set-attr _el-sDiv "id" "sDiv")
|
|
(dom-set-attr _el-sDiv "style" "color: red; text-align: center; width: 10px")
|
|
(dom-append (dom-body) _el-sDiv)
|
|
))
|
|
(deftest "possessive style ref works"
|
|
(hs-cleanup!)
|
|
(let ((_el-sDiv (dom-create-element "div")))
|
|
(dom-set-attr _el-sDiv "id" "sDiv")
|
|
(dom-set-attr _el-sDiv "style" "color: red; text-align: center; width: 10px")
|
|
(dom-append (dom-body) _el-sDiv)
|
|
))
|
|
)
|
|
|
|
;; ── expressions/symbol (2 tests) ──
|
|
(defsuite "hs-upstream-expressions/symbol"
|
|
(deftest "resolves global context properly"
|
|
(error "SKIP (untranslated): resolves global context properly"))
|
|
(deftest "resolves local context properly"
|
|
(assert= (eval-hs-locals "foo" (list (list (quote foo) 42))) 42)
|
|
)
|
|
)
|
|
|
|
;; ── expressions/typecheck (5 tests) ──
|
|
(defsuite "hs-upstream-expressions/typecheck"
|
|
(deftest "can do basic non-string typecheck failure"
|
|
(assert-throws (fn () (hs-type-assert true "String")))
|
|
)
|
|
(deftest "can do basic string non-null typecheck"
|
|
(assert= (eval-hs "'foo' : String!") "foo")
|
|
)
|
|
(deftest "can do basic string typecheck"
|
|
(assert= (eval-hs "'foo' : String") "foo")
|
|
)
|
|
(deftest "can do null as string typecheck"
|
|
(eval-hs "null : String")
|
|
)
|
|
(deftest "null causes null safe string check to fail"
|
|
(assert-throws (fn () (hs-type-assert-strict nil "String")))
|
|
)
|
|
)
|
|
|
|
;; ── ext/component (20 tests) ──
|
|
(defsuite "hs-upstream-ext/component"
|
|
(deftest "applies _ hyperscript to component instance"
|
|
(hs-cleanup!)
|
|
(let ((_el-script (dom-create-element "script")) (_el-test-init (dom-create-element "test-init")))
|
|
(dom-set-attr _el-script "_" "init set ^msg to 'initialized'")
|
|
(dom-set-attr _el-script "type" "text/hyperscript-template")
|
|
(dom-set-attr _el-script "component" "test-init")
|
|
(dom-set-inner-html _el-script "<span>${}{^msg}</span>")
|
|
(dom-append (dom-body) _el-script)
|
|
(dom-append (dom-body) _el-test-init)
|
|
(hs-activate! _el-script)
|
|
))
|
|
(deftest "attrs bind is bidirectional - inner changes flow outward"
|
|
(hs-cleanup!)
|
|
(let ((_el-script (dom-create-element "script")) (_el-test-args-bidir (dom-create-element "test-args-bidir")) (_el-p (dom-create-element "p")))
|
|
(dom-set-attr _el-script "_" "bind ^count to attrs.count")
|
|
(dom-set-attr _el-script "type" "text/hyperscript-template")
|
|
(dom-set-attr _el-script "component" "test-args-bidir")
|
|
(dom-set-inner-html _el-script "<span>${}{^count}</span>
|
|
<button _=\"on click increment ^count\">+</button>")
|
|
(dom-set-attr _el-test-args-bidir "count" "$count")
|
|
(dom-set-attr _el-p "_" "live put $count into me")
|
|
(dom-append (dom-body) _el-script)
|
|
(dom-append (dom-body) _el-test-args-bidir)
|
|
(dom-append (dom-body) _el-p)
|
|
(hs-activate! _el-script)
|
|
(hs-activate! _el-p)
|
|
))
|
|
(deftest "attrs evaluates attribute as hyperscript in parent scope"
|
|
(hs-cleanup!)
|
|
(let ((_el-script (dom-create-element "script")) (_el-test-args (dom-create-element "test-args")))
|
|
(dom-set-attr _el-script "_" "init set ^list to attrs.items")
|
|
(dom-set-attr _el-script "type" "text/hyperscript-template")
|
|
(dom-set-attr _el-script "component" "test-args")
|
|
(dom-set-inner-html _el-script "<ul>
|
|
#for item in ^list
|
|
<li>${}{item}</li>
|
|
#end
|
|
</ul>")
|
|
(dom-set-attr _el-test-args "items" "$stuff")
|
|
(dom-append (dom-body) _el-script)
|
|
(dom-append (dom-body) _el-test-args)
|
|
(hs-activate! _el-script)
|
|
))
|
|
(deftest "attrs works with bind for reactive pass-through"
|
|
(hs-cleanup!)
|
|
(let ((_el-script (dom-create-element "script")) (_el-test-args-bind (dom-create-element "test-args-bind")) (_el-button (dom-create-element "button")))
|
|
(dom-set-attr _el-script "_" "bind ^val to attrs.count")
|
|
(dom-set-attr _el-script "type" "text/hyperscript-template")
|
|
(dom-set-attr _el-script "component" "test-args-bind")
|
|
(dom-set-inner-html _el-script "<span>${}{^val}</span>")
|
|
(dom-set-attr _el-test-args-bind "count" "$count")
|
|
(dom-set-attr _el-button "_" "on click increment $count")
|
|
(dom-set-inner-html _el-button "+")
|
|
(dom-append (dom-body) _el-script)
|
|
(dom-append (dom-body) _el-test-args-bind)
|
|
(dom-append (dom-body) _el-button)
|
|
(hs-activate! _el-script)
|
|
(hs-activate! _el-button)
|
|
))
|
|
(deftest "bind keeps ^var in sync with attribute changes"
|
|
(hs-cleanup!)
|
|
(let ((_el-script (dom-create-element "script")) (_el-test-bind-attr (dom-create-element "test-bind-attr")))
|
|
(dom-set-attr _el-script "_" "bind ^count to @data-count")
|
|
(dom-set-attr _el-script "type" "text/hyperscript-template")
|
|
(dom-set-attr _el-script "component" "test-bind-attr")
|
|
(dom-set-inner-html _el-script "<span>${}{^count}</span>")
|
|
(dom-set-attr _el-test-bind-attr "data-count" "5")
|
|
(dom-append (dom-body) _el-script)
|
|
(dom-append (dom-body) _el-test-bind-attr)
|
|
(hs-activate! _el-script)
|
|
))
|
|
(deftest "blocks processing of inner hyperscript until render"
|
|
(hs-cleanup!)
|
|
(let ((_el-script (dom-create-element "script")) (_el-test-block (dom-create-element "test-block")))
|
|
(dom-set-attr _el-script "_" "init set ^msg to 'ready'")
|
|
(dom-set-attr _el-script "type" "text/hyperscript-template")
|
|
(dom-set-attr _el-script "component" "test-block")
|
|
(dom-set-inner-html _el-script "<span _=\"on click put ^msg into me\">click me</span>")
|
|
(dom-append (dom-body) _el-script)
|
|
(dom-append (dom-body) _el-test-block)
|
|
(hs-activate! _el-script)
|
|
))
|
|
(deftest "component isolation prevents ^var leaking inward"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")) (_el-script (dom-create-element "script")) (_el-test-isolated (dom-create-element "test-isolated")))
|
|
(dom-set-attr _el-div "_" "init set ^leaked to 'should-not-see'")
|
|
(dom-set-attr _el-script "_" "init set ^internal to 'component-only'")
|
|
(dom-set-attr _el-script "type" "text/hyperscript-template")
|
|
(dom-set-attr _el-script "component" "test-isolated")
|
|
(dom-set-inner-html _el-script "<span _=\"init if ^leaked is not undefined put 'leaked!' into me else put ^internal into me\">waiting</span>")
|
|
(dom-append (dom-body) _el-div)
|
|
(dom-append _el-div _el-script)
|
|
(dom-append _el-div _el-test-isolated)
|
|
(hs-activate! _el-div)
|
|
(hs-activate! _el-script)
|
|
))
|
|
(deftest "does not process slotted _ attributes prematurely"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")) (_el-script (dom-create-element "script")) (_el-test-slot-hs (dom-create-element "test-slot-hs")) (_el-span (dom-create-element "span")))
|
|
(dom-set-attr _el-div "_" "init set ^x to 42")
|
|
(dom-set-attr _el-script "type" "text/hyperscript-template")
|
|
(dom-set-attr _el-script "component" "test-slot-hs")
|
|
(dom-set-inner-html _el-script "<div class=\"wrap\"><slot/></div>")
|
|
(dom-set-attr _el-span "_" "on click put ^x into me")
|
|
(dom-set-inner-html _el-span "before")
|
|
(dom-append (dom-body) _el-div)
|
|
(dom-append _el-div _el-script)
|
|
(dom-append _el-div _el-test-slot-hs)
|
|
(dom-append _el-test-slot-hs _el-span)
|
|
(hs-activate! _el-div)
|
|
(hs-activate! _el-span)
|
|
))
|
|
(deftest "extracts <style> blocks and wraps them in @scope"
|
|
(hs-cleanup!)
|
|
(let ((_el-script (dom-create-element "script")) (_el-test-styled (dom-create-element "test-styled")))
|
|
(dom-set-attr _el-script "type" "text/hyperscript-template")
|
|
(dom-set-attr _el-script "component" "test-styled")
|
|
(dom-set-inner-html _el-script "<style>
|
|
:scope { display: block; }
|
|
.inner { color: rgb(11, 22, 33); }
|
|
</style>
|
|
<span class=\"inner\">styled</span>")
|
|
(dom-append (dom-body) _el-script)
|
|
(dom-append (dom-body) _el-test-styled)
|
|
))
|
|
(deftest "processes _ on inner elements"
|
|
(hs-cleanup!)
|
|
(let ((_el-script (dom-create-element "script")) (_el-test-inner (dom-create-element "test-inner")))
|
|
(dom-set-attr _el-script "_" "init set ^count to 0")
|
|
(dom-set-attr _el-script "type" "text/hyperscript-template")
|
|
(dom-set-attr _el-script "component" "test-inner")
|
|
(dom-set-inner-html _el-script "<button _=\"on click increment ^count then put ^count into the next <span/>\">+</button>
|
|
<span>0</span>")
|
|
(dom-append (dom-body) _el-script)
|
|
(dom-append (dom-body) _el-test-inner)
|
|
(hs-activate! _el-script)
|
|
))
|
|
(deftest "reactively updates template expressions"
|
|
(hs-cleanup!)
|
|
(let ((_el-script (dom-create-element "script")) (_el-test-reactive (dom-create-element "test-reactive")))
|
|
(dom-set-attr _el-script "_" "init set ^count to 0")
|
|
(dom-set-attr _el-script "type" "text/hyperscript-template")
|
|
(dom-set-attr _el-script "component" "test-reactive")
|
|
(dom-set-inner-html _el-script "<button _=\"on click increment ^count\">+</button>
|
|
<span>Count: ${}{^count}</span>")
|
|
(dom-append (dom-body) _el-script)
|
|
(dom-append (dom-body) _el-test-reactive)
|
|
(hs-activate! _el-script)
|
|
))
|
|
(deftest "reads attributes via @"
|
|
(hs-cleanup!)
|
|
(let ((_el-script (dom-create-element "script")) (_el-test-attrs (dom-create-element "test-attrs")))
|
|
(dom-set-attr _el-script "_" "init set ^val to @data-start as Int")
|
|
(dom-set-attr _el-script "type" "text/hyperscript-template")
|
|
(dom-set-attr _el-script "component" "test-attrs")
|
|
(dom-set-inner-html _el-script "<span>${}{^val}</span>")
|
|
(dom-set-attr _el-test-attrs "data-start" "42")
|
|
(dom-append (dom-body) _el-script)
|
|
(dom-append (dom-body) _el-test-attrs)
|
|
(hs-activate! _el-script)
|
|
))
|
|
(deftest "registers a custom element from a template"
|
|
(hs-cleanup!)
|
|
(let ((_el-script (dom-create-element "script")) (_el-test-hello (dom-create-element "test-hello")))
|
|
(dom-set-attr _el-script "type" "text/hyperscript-template")
|
|
(dom-set-attr _el-script "component" "test-hello")
|
|
(dom-set-inner-html _el-script "<span>Hello World</span>")
|
|
(dom-append (dom-body) _el-script)
|
|
(dom-append (dom-body) _el-test-hello)
|
|
))
|
|
(deftest "renders template expressions"
|
|
(hs-cleanup!)
|
|
(let ((_el-script (dom-create-element "script")) (_el-test-greet (dom-create-element "test-greet")))
|
|
(dom-set-attr _el-script "type" "text/hyperscript-template")
|
|
(dom-set-attr _el-script "component" "test-greet")
|
|
(dom-set-inner-html _el-script "<span>Hello ${}{$name}!</span>")
|
|
(dom-append (dom-body) _el-script)
|
|
(dom-append (dom-body) _el-test-greet)
|
|
))
|
|
(deftest "slotted content resolves ^var from outer scope, not component scope"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")) (_el-script (dom-create-element "script")) (_el-test-scope-slot (dom-create-element "test-scope-slot")) (_el-span (dom-create-element "span")))
|
|
(dom-set-attr _el-div "_" "init set ^outer to 'from-outside'")
|
|
(dom-set-attr _el-script "_" "init set ^outer to 'from-component'")
|
|
(dom-set-attr _el-script "type" "text/hyperscript-template")
|
|
(dom-set-attr _el-script "component" "test-scope-slot")
|
|
(dom-set-inner-html _el-script "<div class=\"inner\"><slot/></div>")
|
|
(dom-set-attr _el-span "_" "init put ^outer into me")
|
|
(dom-set-inner-html _el-span "waiting")
|
|
(dom-append (dom-body) _el-div)
|
|
(dom-append _el-div _el-script)
|
|
(dom-append _el-div _el-test-scope-slot)
|
|
(dom-append _el-test-scope-slot _el-span)
|
|
(hs-activate! _el-div)
|
|
(hs-activate! _el-script)
|
|
(hs-activate! _el-span)
|
|
))
|
|
(deftest "substitutes slot content into template"
|
|
(hs-cleanup!)
|
|
(let ((_el-script (dom-create-element "script")) (_el-test-card (dom-create-element "test-card")) (_el-p (dom-create-element "p")))
|
|
(dom-set-attr _el-script "type" "text/hyperscript-template")
|
|
(dom-set-attr _el-script "component" "test-card")
|
|
(dom-set-inner-html _el-script "<div class=\"card\"><slot/></div>")
|
|
(dom-set-inner-html _el-p "Hello from slot")
|
|
(dom-append (dom-body) _el-script)
|
|
(dom-append (dom-body) _el-test-card)
|
|
(dom-append _el-test-card _el-p)
|
|
))
|
|
(deftest "supports #for loops in template"
|
|
(hs-cleanup!)
|
|
(let ((_el-script (dom-create-element "script")) (_el-test-loop (dom-create-element "test-loop")))
|
|
(dom-set-attr _el-script "_" "init set ^items to ['a', 'b', 'c']")
|
|
(dom-set-attr _el-script "type" "text/hyperscript-template")
|
|
(dom-set-attr _el-script "component" "test-loop")
|
|
(dom-set-inner-html _el-script "<ul>
|
|
#for item in ^items
|
|
<li>${}{item}</li>
|
|
#end
|
|
</ul>")
|
|
(dom-append (dom-body) _el-script)
|
|
(dom-append (dom-body) _el-test-loop)
|
|
(hs-activate! _el-script)
|
|
))
|
|
(deftest "supports #if conditionals in template"
|
|
(hs-cleanup!)
|
|
(let ((_el-script (dom-create-element "script")) (_el-test-cond (dom-create-element "test-cond")))
|
|
(dom-set-attr _el-script "_" "init set ^show to true")
|
|
(dom-set-attr _el-script "type" "text/hyperscript-template")
|
|
(dom-set-attr _el-script "component" "test-cond")
|
|
(dom-set-inner-html _el-script "#if ^show
|
|
<span>visible</span>
|
|
#end")
|
|
(dom-append (dom-body) _el-script)
|
|
(dom-append (dom-body) _el-test-cond)
|
|
(hs-activate! _el-script)
|
|
))
|
|
(deftest "supports multiple independent instances"
|
|
(hs-cleanup!)
|
|
(let ((_el-script (dom-create-element "script")) (_el-a (dom-create-element "test-multi")) (_el-b (dom-create-element "test-multi")))
|
|
(dom-set-attr _el-script "_" "init set ^count to 0")
|
|
(dom-set-attr _el-script "type" "text/hyperscript-template")
|
|
(dom-set-attr _el-script "component" "test-multi")
|
|
(dom-set-inner-html _el-script "<button _=\"on click increment ^count then put ^count into the next <span/>\">+</button>
|
|
<span>0</span>")
|
|
(dom-set-attr _el-a "id" "a")
|
|
(dom-set-attr _el-b "id" "b")
|
|
(dom-append (dom-body) _el-script)
|
|
(dom-append (dom-body) _el-a)
|
|
(dom-append (dom-body) _el-b)
|
|
(hs-activate! _el-script)
|
|
))
|
|
(deftest "supports named slots"
|
|
(hs-cleanup!)
|
|
(let ((_el-script (dom-create-element "script")) (_el-test-named-slot (dom-create-element "test-named-slot")) (_el-h1 (dom-create-element "h1")) (_el-p (dom-create-element "p")) (_el-span (dom-create-element "span")))
|
|
(dom-set-attr _el-script "type" "text/hyperscript-template")
|
|
(dom-set-attr _el-script "component" "test-named-slot")
|
|
(dom-set-inner-html _el-script "<header><slot name=\"title\"></slot></header>
|
|
<main><slot/></main>
|
|
<footer><slot name=\"footer\"></slot></footer>")
|
|
(dom-set-attr _el-h1 "slot" "title")
|
|
(dom-set-inner-html _el-h1 "My Title")
|
|
(dom-set-inner-html _el-p "Default content")
|
|
(dom-set-attr _el-span "slot" "footer")
|
|
(dom-set-inner-html _el-span "Footer text")
|
|
(dom-append (dom-body) _el-script)
|
|
(dom-append (dom-body) _el-test-named-slot)
|
|
(dom-append _el-test-named-slot _el-h1)
|
|
(dom-append _el-test-named-slot _el-p)
|
|
(dom-append _el-test-named-slot _el-span)
|
|
))
|
|
)
|
|
|
|
;; ── ext/eventsource (13 tests) ──
|
|
(defsuite "hs-upstream-ext/eventsource"
|
|
(deftest "as json decodes data"
|
|
(hs-cleanup!)
|
|
(guard (_e (true nil)) (eval-expr-cek (hs-to-sx (hs-compile "eventsource JsonSSE from \"/sse\" on \"update\" as json put it.name into #name put it.age into #age end end"))))
|
|
(guard (_e (true nil)) (eval-expr-cek (hs-to-sx (hs-compile "eventsource JsonSSE from \"/sse\" on \"update\" as json put it.name into #name put it.age into #age end end"))))
|
|
(let ((_el-name (dom-create-element "div")) (_el-age (dom-create-element "div")))
|
|
(dom-set-attr _el-name "id" "name")
|
|
(dom-set-attr _el-age "id" "age")
|
|
(dom-append (dom-body) _el-name)
|
|
(dom-append (dom-body) _el-age)
|
|
))
|
|
(deftest "catch-all * matches every event"
|
|
(hs-cleanup!)
|
|
(guard (_e (true nil)) (eval-expr-cek (hs-to-sx (hs-compile "eventsource CatchAllSSE from \"/sse\" on \"*\" as string put (event.type + \",\" + #out's innerHTML) into #out end end"))))
|
|
(guard (_e (true nil)) (eval-expr-cek (hs-to-sx (hs-compile "eventsource CatchAllSSE from \"/sse\" on \"*\" as string put (event.type + \",\" + #out's innerHTML) into #out end end"))))
|
|
(let ((_el-out (dom-create-element "div")))
|
|
(dom-set-attr _el-out "id" "out")
|
|
(dom-append (dom-body) _el-out)
|
|
))
|
|
(deftest "close() stops the connection"
|
|
(hs-cleanup!)
|
|
(guard (_e (true nil)) (eval-expr-cek (hs-to-sx (hs-compile "eventsource CloseSSE from \"/sse\" on \"message\" as string put it into #out if it is \"1\" call CloseSSE.close() end end end"))))
|
|
(guard (_e (true nil)) (eval-expr-cek (hs-to-sx (hs-compile "eventsource CloseSSE from \"/sse\" on \"message\" as string put it into #out if it is \"1\" call CloseSSE.close() end end end"))))
|
|
(let ((_el-out (dom-create-element "div")))
|
|
(dom-set-attr _el-out "id" "out")
|
|
(dom-set-inner-html _el-out "0")
|
|
(dom-append (dom-body) _el-out)
|
|
))
|
|
(deftest "dispatches named SSE events on the element"
|
|
(hs-cleanup!)
|
|
(let ((_el-out (dom-create-element "div")) (_el-button (dom-create-element "button")))
|
|
(dom-set-attr _el-out "id" "out")
|
|
(dom-set-attr _el-button "_" "on click fetch /stream-named as Stream then on status from me then put event.detail.data into #out end")
|
|
(dom-set-inner-html _el-button "go")
|
|
(dom-append (dom-body) _el-out)
|
|
(dom-append (dom-body) _el-button)
|
|
(hs-activate! _el-button)
|
|
(dom-dispatch _el-button "click" nil)
|
|
))
|
|
(deftest "dynamic open with new URL"
|
|
(hs-cleanup!)
|
|
(guard (_e (true nil)) (eval-expr-cek (hs-to-sx (hs-compile "eventsource DynSSE on \"msg\" as string put it into #out end end"))))
|
|
(guard (_e (true nil)) (eval-expr-cek (hs-to-sx (hs-compile "eventsource DynSSE on \"msg\" as string put it into #out end end"))))
|
|
(let ((_el-out (dom-create-element "div")))
|
|
(dom-set-attr _el-out "id" "out")
|
|
(dom-append (dom-body) _el-out)
|
|
))
|
|
(deftest "fires streamEnd when the stream closes"
|
|
(hs-cleanup!)
|
|
(let ((_el-out (dom-create-element "div")) (_el-button (dom-create-element "button")))
|
|
(dom-set-attr _el-out "id" "out")
|
|
(dom-set-attr _el-button "_" "on click fetch /streamEnd as Stream then wait for streamEnd from me then put 'finished' into #out")
|
|
(dom-set-inner-html _el-button "go")
|
|
(dom-append (dom-body) _el-out)
|
|
(dom-append (dom-body) _el-button)
|
|
(hs-activate! _el-button)
|
|
(dom-dispatch _el-button "click" nil)
|
|
))
|
|
(deftest "iterates plain messages with for loop"
|
|
(hs-cleanup!)
|
|
(let ((_el-out (dom-create-element "div")) (_el-button (dom-create-element "button")))
|
|
(dom-set-attr _el-out "id" "out")
|
|
(dom-set-attr _el-button "_" "on click fetch /stream-iter as Stream then for message in the result then put message + ' ' at end of #out end")
|
|
(dom-set-inner-html _el-button "go")
|
|
(dom-append (dom-body) _el-out)
|
|
(dom-append (dom-body) _el-button)
|
|
(hs-activate! _el-button)
|
|
(dom-dispatch _el-button "click" nil)
|
|
))
|
|
(deftest "open and close lifecycle events fire"
|
|
(hs-cleanup!)
|
|
(guard (_e (true nil)) (eval-expr-cek (hs-to-sx (hs-compile "eventsource LifecycleSSE from \"/sse\" on \"open\" put \"yes\" into #opened end on \"message\" as string call LifecycleSSE.close() end end"))))
|
|
(guard (_e (true nil)) (eval-expr-cek (hs-to-sx (hs-compile "eventsource LifecycleSSE from \"/sse\" on \"open\" put \"yes\" into #opened end on \"message\" as string call LifecycleSSE.close() end end"))))
|
|
(let ((_el-opened (dom-create-element "div")))
|
|
(dom-set-attr _el-opened "id" "opened")
|
|
(dom-append (dom-body) _el-opened)
|
|
))
|
|
(deftest "receives named events"
|
|
(hs-cleanup!)
|
|
(guard (_e (true nil)) (eval-expr-cek (hs-to-sx (hs-compile "eventsource NamedSSE from \"/sse\" on \"greeting\" as json put it.msg into #greet end on \"farewell\" as json put it.msg into #bye end end"))))
|
|
(guard (_e (true nil)) (eval-expr-cek (hs-to-sx (hs-compile "eventsource NamedSSE from \"/sse\" on \"greeting\" as json put it.msg into #greet end on \"farewell\" as json put it.msg into #bye end end"))))
|
|
(let ((_el-greet (dom-create-element "div")) (_el-bye (dom-create-element "div")))
|
|
(dom-set-attr _el-greet "id" "greet")
|
|
(dom-set-attr _el-bye "id" "bye")
|
|
(dom-append (dom-body) _el-greet)
|
|
(dom-append (dom-body) _el-bye)
|
|
))
|
|
(deftest "receives unnamed messages"
|
|
(hs-cleanup!)
|
|
(guard (_e (true nil)) (eval-expr-cek (hs-to-sx (hs-compile "eventsource TestSSE from \"/sse\" on \"message\" as string put it into #out end end"))))
|
|
(guard (_e (true nil)) (eval-expr-cek (hs-to-sx (hs-compile "eventsource TestSSE from \"/sse\" on \"message\" as string put it into #out end end"))))
|
|
(let ((_el-out (dom-create-element "div")))
|
|
(dom-set-attr _el-out "id" "out")
|
|
(dom-append (dom-body) _el-out)
|
|
))
|
|
(deftest "wildcard pattern matches multiple events"
|
|
(hs-cleanup!)
|
|
(guard (_e (true nil)) (eval-expr-cek (hs-to-sx (hs-compile "eventsource WildSSE from \"/sse\" on \"user.*\" as json set c to #count's innerHTML as Int put (c + 1) into #count end end"))))
|
|
(guard (_e (true nil)) (eval-expr-cek (hs-to-sx (hs-compile "eventsource WildSSE from \"/sse\" on \"user.*\" as json set c to #count's innerHTML as Int put (c + 1) into #count end end"))))
|
|
(let ((_el-count (dom-create-element "div")))
|
|
(dom-set-attr _el-count "id" "count")
|
|
(dom-set-inner-html _el-count "0")
|
|
(dom-append (dom-body) _el-count)
|
|
))
|
|
(deftest "with headers sends custom headers"
|
|
(hs-cleanup!)
|
|
(guard (_e (true nil)) (eval-expr-cek (hs-to-sx (hs-compile "eventsource HeaderSSE from \"/sse\" with headers {\"X-Custom\": \"test123\"} on \"ack\" as string put it into #out end end"))))
|
|
(guard (_e (true nil)) (eval-expr-cek (hs-to-sx (hs-compile "eventsource HeaderSSE from \"/sse\" with headers {\"X-Custom\": \"test123\"} on \"ack\" as string put it into #out end end"))))
|
|
(let ((_el-out (dom-create-element "div")))
|
|
(dom-set-attr _el-out "id" "out")
|
|
(dom-append (dom-body) _el-out)
|
|
))
|
|
(deftest "with method sends POST"
|
|
(hs-cleanup!)
|
|
(guard (_e (true nil)) (eval-expr-cek (hs-to-sx (hs-compile "eventsource PostSSE from \"/sse\" with method \"POST\" on \"ack\" as string put it into #out end end"))))
|
|
(guard (_e (true nil)) (eval-expr-cek (hs-to-sx (hs-compile "eventsource PostSSE from \"/sse\" with method \"POST\" on \"ack\" as string put it into #out end end"))))
|
|
(let ((_el-out (dom-create-element "div")))
|
|
(dom-set-attr _el-out "id" "out")
|
|
(dom-append (dom-body) _el-out)
|
|
))
|
|
)
|
|
|
|
;; ── ext/hs-include (10 tests) ──
|
|
(defsuite "hs-upstream-ext/hs-include"
|
|
(deftest "JSON-serializes object values"
|
|
(hs-cleanup!)
|
|
(let ((_el-button (dom-create-element "button")) (_el-out (dom-create-element "div")))
|
|
(dom-set-attr _el-button "_" "init set :obj to {name: 'Alice', age: 30}")
|
|
(dom-set-attr _el-button "hs-include" ":obj")
|
|
(dom-set-attr _el-button "hx-post" "/api")
|
|
(dom-set-attr _el-button "hx-target" "#out")
|
|
(dom-set-inner-html _el-button "Send")
|
|
(dom-set-attr _el-out "id" "out")
|
|
(dom-append (dom-body) _el-button)
|
|
(dom-append (dom-body) _el-out)
|
|
(hs-activate! _el-button)
|
|
))
|
|
(deftest "direct hs-include takes precedence over inherited"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")) (_el-button (dom-create-element "button")) (_el-out (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "init set :parent to 1")
|
|
(dom-set-attr _el-div "hs-include:inherited" ":parent")
|
|
(dom-set-attr _el-button "_" "init set :child to 2")
|
|
(dom-set-attr _el-button "hs-include" ":child")
|
|
(dom-set-attr _el-button "hx-post" "/api")
|
|
(dom-set-attr _el-button "hx-target" "#out")
|
|
(dom-set-inner-html _el-button "Send")
|
|
(dom-set-attr _el-out "id" "out")
|
|
(dom-append (dom-body) _el-div)
|
|
(dom-append _el-div _el-button)
|
|
(dom-append (dom-body) _el-out)
|
|
(hs-activate! _el-div)
|
|
(hs-activate! _el-button)
|
|
))
|
|
(deftest "elements without hs-include are unaffected"
|
|
(hs-cleanup!)
|
|
(let ((_el-button (dom-create-element "button")) (_el-out (dom-create-element "div")))
|
|
(dom-set-attr _el-button "_" "init set :secret to 42")
|
|
(dom-set-attr _el-button "hx-post" "/api")
|
|
(dom-set-attr _el-button "hx-target" "#out")
|
|
(dom-set-inner-html _el-button "Send")
|
|
(dom-set-attr _el-out "id" "out")
|
|
(dom-append (dom-body) _el-button)
|
|
(dom-append (dom-body) _el-out)
|
|
(hs-activate! _el-button)
|
|
))
|
|
(deftest "hs-include:inherited applies to descendant triggers"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")) (_el-button (dom-create-element "button")) (_el-out (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "init set :ctx to 'parent-val'")
|
|
(dom-set-attr _el-div "hs-include:inherited" ":ctx")
|
|
(dom-set-attr _el-button "hx-post" "/api")
|
|
(dom-set-attr _el-button "hx-target" "#out")
|
|
(dom-set-inner-html _el-button "Send")
|
|
(dom-set-attr _el-out "id" "out")
|
|
(dom-append (dom-body) _el-div)
|
|
(dom-append _el-div _el-button)
|
|
(dom-append (dom-body) _el-out)
|
|
(hs-activate! _el-div)
|
|
))
|
|
(deftest "includes a named element-scoped variable"
|
|
(hs-cleanup!)
|
|
(let ((_el-button (dom-create-element "button")) (_el-out (dom-create-element "div")))
|
|
(dom-set-attr _el-button "_" "init set :userId to 42")
|
|
(dom-set-attr _el-button "hs-include" ":userId")
|
|
(dom-set-attr _el-button "hx-post" "/api")
|
|
(dom-set-attr _el-button "hx-target" "#out")
|
|
(dom-set-inner-html _el-button "Send")
|
|
(dom-set-attr _el-out "id" "out")
|
|
(dom-append (dom-body) _el-button)
|
|
(dom-append (dom-body) _el-out)
|
|
(hs-activate! _el-button)
|
|
))
|
|
(deftest "includes multiple named variables"
|
|
(hs-cleanup!)
|
|
(let ((_el-button (dom-create-element "button")) (_el-out (dom-create-element "div")))
|
|
(dom-set-attr _el-button "_" "init set :a to 1 then set :b to 2")
|
|
(dom-set-attr _el-button "hs-include" ":a, :b")
|
|
(dom-set-attr _el-button "hx-post" "/api")
|
|
(dom-set-attr _el-button "hx-target" "#out")
|
|
(dom-set-inner-html _el-button "Send")
|
|
(dom-set-attr _el-out "id" "out")
|
|
(dom-append (dom-body) _el-button)
|
|
(dom-append (dom-body) _el-out)
|
|
(hs-activate! _el-button)
|
|
))
|
|
(deftest "missing variables are silently skipped"
|
|
(hs-cleanup!)
|
|
(let ((_el-button (dom-create-element "button")) (_el-out (dom-create-element "div")))
|
|
(dom-set-attr _el-button "hs-include" ":nonexistent")
|
|
(dom-set-attr _el-button "hx-post" "/api")
|
|
(dom-set-attr _el-button "hx-target" "#out")
|
|
(dom-set-inner-html _el-button "Send")
|
|
(dom-set-attr _el-out "id" "out")
|
|
(dom-append (dom-body) _el-button)
|
|
(dom-append (dom-body) _el-out)
|
|
))
|
|
(deftest "resolves inherited var via ^"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")) (_el-button (dom-create-element "button")) (_el-out (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "init set :shared to 99")
|
|
(dom-set-attr _el-button "hs-include" "^shared")
|
|
(dom-set-attr _el-button "hx-post" "/api")
|
|
(dom-set-attr _el-button "hx-target" "#out")
|
|
(dom-set-inner-html _el-button "Send")
|
|
(dom-set-attr _el-out "id" "out")
|
|
(dom-append (dom-body) _el-div)
|
|
(dom-append _el-div _el-button)
|
|
(dom-append (dom-body) _el-out)
|
|
(hs-activate! _el-div)
|
|
))
|
|
(deftest "resolves var from another element via #selector"
|
|
(hs-cleanup!)
|
|
(let ((_el-source (dom-create-element "div")) (_el-button (dom-create-element "button")) (_el-out (dom-create-element "div")))
|
|
(dom-set-attr _el-source "id" "source")
|
|
(dom-set-attr _el-source "_" "init set :data to 'hello'")
|
|
(dom-set-attr _el-button "hs-include" "#source:data")
|
|
(dom-set-attr _el-button "hx-post" "/api")
|
|
(dom-set-attr _el-button "hx-target" "#out")
|
|
(dom-set-inner-html _el-button "Send")
|
|
(dom-set-attr _el-out "id" "out")
|
|
(dom-append (dom-body) _el-source)
|
|
(dom-append (dom-body) _el-button)
|
|
(dom-append (dom-body) _el-out)
|
|
(hs-activate! _el-source)
|
|
))
|
|
(deftest "wildcard includes all element-scoped vars"
|
|
(hs-cleanup!)
|
|
(let ((_el-button (dom-create-element "button")) (_el-out (dom-create-element "div")))
|
|
(dom-set-attr _el-button "_" "init set :x to 10 then set :y to 20")
|
|
(dom-set-attr _el-button "hs-include" "*")
|
|
(dom-set-attr _el-button "hx-post" "/api")
|
|
(dom-set-attr _el-button "hx-target" "#out")
|
|
(dom-set-inner-html _el-button "Send")
|
|
(dom-set-attr _el-out "id" "out")
|
|
(dom-append (dom-body) _el-button)
|
|
(dom-append (dom-body) _el-out)
|
|
(hs-activate! _el-button)
|
|
))
|
|
)
|
|
|
|
;; ── ext/tailwind (12 tests) ──
|
|
(defsuite "hs-upstream-ext/tailwind"
|
|
(deftest "can hide element, with tailwindcss hidden class"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click hide with twDisplay")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
))
|
|
(deftest "can hide element, with tailwindcss hidden class default strategy"
|
|
(hs-cleanup!)
|
|
(hs-set-default-hide-strategy! "twDisplay")
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click hide")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
))
|
|
(deftest "can hide element, with tailwindcss invisible class"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click hide with twVisibility")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
))
|
|
(deftest "can hide element, with tailwindcss invisible class default strategy"
|
|
(hs-cleanup!)
|
|
(hs-set-default-hide-strategy! "twVisibility")
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click hide")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
))
|
|
(deftest "can hide element, with tailwindcss opacity-0 class"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click hide with twOpacity")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
))
|
|
(deftest "can hide element, with tailwindcss opacity-0 class default strategy"
|
|
(hs-cleanup!)
|
|
(hs-set-default-hide-strategy! "twOpacity")
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click hide")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
))
|
|
(deftest "can show element, with tailwindcss removing hidden class"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-add-class _el-div "hidden")
|
|
(dom-set-attr _el-div "_" "on click show with twDisplay")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
))
|
|
(deftest "can show element, with tailwindcss removing hidden class default strategy"
|
|
(hs-cleanup!)
|
|
(hs-set-default-hide-strategy! "twDisplay")
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-add-class _el-div "hidden")
|
|
(dom-set-attr _el-div "_" "on click show")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
))
|
|
(deftest "can show element, with tailwindcss removing invisible class"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-add-class _el-div "invisible")
|
|
(dom-set-attr _el-div "_" "on click show with twVisibility")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
))
|
|
(deftest "can show element, with tailwindcss removing invisible class default strategy"
|
|
(hs-cleanup!)
|
|
(hs-set-default-hide-strategy! "twVisibility")
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-add-class _el-div "invisible")
|
|
(dom-set-attr _el-div "_" "on click show")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
))
|
|
(deftest "can show element, with tailwindcss removing opacity-0 class"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-add-class _el-div "opacity-0")
|
|
(dom-set-attr _el-div "_" "on click show with twOpacity")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
))
|
|
(deftest "can show element, with tailwindcss removing opacity-0 class default strategy"
|
|
(hs-cleanup!)
|
|
(hs-set-default-hide-strategy! "twOpacity")
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-add-class _el-div "opacity-0")
|
|
(dom-set-attr _el-div "_" "on click show")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
))
|
|
)
|
|
|
|
;; ── fetch (23 tests) ──
|
|
(defsuite "hs-upstream-fetch"
|
|
(deftest "Response can be converted to JSON via as JSON"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click fetch /test as Response then put (it as JSON).name into me")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
(dom-dispatch _el-div "click" nil)
|
|
(assert= (dom-text-content _el-div) "Joe")
|
|
))
|
|
(deftest "allows the event handler to change the fetch parameters"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click fetch \"/test\" then put it into my.innerHTML end")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
(dom-dispatch _el-div "click" nil)
|
|
(assert= (dom-text-content _el-div) "yay")
|
|
))
|
|
(deftest "as response does not throw on 404"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click fetch /test as response then put it.status into me")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
(dom-dispatch _el-div "click" nil)
|
|
(assert= (dom-text-content _el-div) "404")
|
|
))
|
|
(deftest "can catch an error that occurs when using fetch"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click fetch /test catch e log e put \"yay\" into me")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
(dom-dispatch _el-div "click" nil)
|
|
(assert= (dom-text-content _el-div) "yay")
|
|
))
|
|
(deftest "can do a simple fetch"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click fetch \"/test\" 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) "yay")
|
|
))
|
|
(deftest "can do a simple fetch w/ a custom conversion"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click fetch /test as Number 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) "1.2")
|
|
))
|
|
(deftest "can do a simple fetch w/ a naked URL"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click fetch /test 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) "yay")
|
|
))
|
|
(deftest "can do a simple fetch w/ html"
|
|
(error "SKIP (skip-list): can do a simple fetch w/ html"))
|
|
(deftest "can do a simple fetch w/ json"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click fetch /test as json then get result as JSONString 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) "{\"foo\":1}")
|
|
))
|
|
(deftest "can do a simple fetch w/ json using JSON syntax"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click fetch /test as JSON then get result as JSONString 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) "{\"foo\":1}")
|
|
))
|
|
(deftest "can do a simple fetch w/ json using Object syntax"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click fetch /test as Object then get result as JSONString 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) "{\"foo\":1}")
|
|
))
|
|
(deftest "can do a simple fetch w/ json using Object syntax and an 'an' prefix"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click fetch /test as an Object then get result as JSONString 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) "{\"foo\":1}")
|
|
))
|
|
(deftest "can do a simple fetch with a response object"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click fetch /test as response then if its.ok put \"yep\" 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) "yep")
|
|
))
|
|
(deftest "can do a simple post"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click fetch /test {method:\"POST\"} 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) "yay")
|
|
))
|
|
(deftest "can do a simple post alt syntax w/ curlies"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click fetch /test with {method:\"POST\"} 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) "yay")
|
|
))
|
|
(deftest "can do a simple post alt syntax without curlies"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click fetch /test with method:\"POST\" 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) "yay")
|
|
))
|
|
(deftest "can put response conversion after with"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click fetch /test with {method:\"POST\"} as text 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) "yay")
|
|
))
|
|
(deftest "can put response conversion before with"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click fetch /test as text with {method:\"POST\"} 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) "yay")
|
|
))
|
|
(deftest "do not throw passes through 404 response"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click fetch /test do not throw then put it into me")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
(dom-dispatch _el-div "click" nil)
|
|
(assert= (dom-text-content _el-div) "the body")
|
|
))
|
|
(deftest "don't throw passes through 404 response"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click fetch /test don't throw then put it into me")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
(dom-dispatch _el-div "click" nil)
|
|
(assert= (dom-text-content _el-div) "the body")
|
|
))
|
|
(deftest "submits the fetch parameters to the event handler"
|
|
(hs-cleanup!)
|
|
(host-set! (host-global "window") "headerCheckPassed" false)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click fetch \"/test\" {headers: {\"X-CustomHeader\": \"foo\"}} then put it into my.innerHTML end")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
(dom-dispatch _el-div "click" nil)
|
|
(assert= (dom-text-content _el-div) "yay")
|
|
))
|
|
(deftest "throws on non-2xx response by default"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click fetch /test catch e put \"caught\" into me")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
(dom-dispatch _el-div "click" nil)
|
|
(assert= (dom-text-content _el-div) "caught")
|
|
))
|
|
(deftest "triggers an event just before fetching"
|
|
(hs-cleanup!)
|
|
(host-call (host-global "window") "addEventListener" "hyperscript:beforeFetch" (fn (_event) (dom-set-attr (host-get _event "target") "class" "foo-set")))
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click fetch \"/test\" then put it into my.innerHTML end")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
(assert (not (dom-has-class? _el-div "foo-set")))
|
|
(dom-dispatch _el-div "click" nil)
|
|
(assert (dom-has-class? _el-div "foo-set"))
|
|
(assert= (dom-text-content _el-div) "yay")
|
|
))
|
|
)
|
|
|
|
;; ── focus (3 tests) ──
|
|
(defsuite "hs-upstream-focus"
|
|
(deftest "can blur an element"
|
|
(hs-cleanup!)
|
|
(let ((_el-i1 (dom-create-element "input")))
|
|
(dom-set-attr _el-i1 "id" "i1")
|
|
(dom-set-attr _el-i1 "_" "on focus wait 10ms then blur me")
|
|
(dom-append (dom-body) _el-i1)
|
|
(hs-activate! _el-i1)
|
|
(dom-focus (dom-query-by-id "i1"))
|
|
))
|
|
(deftest "can focus an element"
|
|
(hs-cleanup!)
|
|
(let ((_el-i1 (dom-create-element "input")) (_el-button (dom-create-element "button")))
|
|
(dom-set-attr _el-i1 "id" "i1")
|
|
(dom-set-attr _el-button "_" "on click focus #i1")
|
|
(dom-append (dom-body) _el-i1)
|
|
(dom-append (dom-body) _el-button)
|
|
(hs-activate! _el-button)
|
|
(dom-dispatch _el-button "click" nil)
|
|
))
|
|
(deftest "focus with no target focuses me"
|
|
(hs-cleanup!)
|
|
(let ((_el-i1 (dom-create-element "input")))
|
|
(dom-set-attr _el-i1 "id" "i1")
|
|
(dom-set-attr _el-i1 "_" "on click focus")
|
|
(dom-append (dom-body) _el-i1)
|
|
(hs-activate! _el-i1)
|
|
(dom-dispatch (dom-query-by-id "i1") "click" nil)
|
|
))
|
|
)
|
|
|
|
;; ── go (5 tests) ──
|
|
(defsuite "hs-upstream-go"
|
|
(deftest "can parse go to with string URL"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click go to \"#test-hash\"")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
))
|
|
(deftest "deprecated scroll form still works"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")) (_el-target (dom-create-element "div")) (_el-div2 (dom-create-element "div")))
|
|
(dom-set-attr _el-div "style" "height: 2000px")
|
|
(dom-set-attr _el-target "id" "target")
|
|
(dom-set-inner-html _el-target "Target")
|
|
(dom-set-attr _el-div2 "_" "on click go to the top of #target")
|
|
(dom-append (dom-body) _el-div)
|
|
(dom-append (dom-body) _el-target)
|
|
(dom-append (dom-body) _el-div2)
|
|
(hs-activate! _el-div2)
|
|
(dom-dispatch (dom-query "div:nth-of-type(3)") "click" nil)
|
|
))
|
|
(deftest "deprecated url keyword still parses"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click go to url /test")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
))
|
|
(deftest "go to element scrolls"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")) (_el-target (dom-create-element "div")) (_el-div2 (dom-create-element "div")))
|
|
(dom-set-attr _el-div "style" "height: 2000px")
|
|
(dom-set-attr _el-target "id" "target")
|
|
(dom-set-inner-html _el-target "Target")
|
|
(dom-set-attr _el-div2 "_" "on click go to #target")
|
|
(dom-append (dom-body) _el-div)
|
|
(dom-append (dom-body) _el-target)
|
|
(dom-append (dom-body) _el-div2)
|
|
(hs-activate! _el-div2)
|
|
(dom-dispatch (dom-query "div:nth-of-type(3)") "click" nil)
|
|
))
|
|
(deftest "go to naked URL starting with / parses"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click go to /test/path")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
))
|
|
)
|
|
|
|
;; ── halt (7 tests) ──
|
|
(defsuite "hs-upstream-halt"
|
|
(deftest "halt bubbling only stops propagation, not default"
|
|
(hs-cleanup!)
|
|
(let ((_el-outer (dom-create-element "div")) (_el-inner (dom-create-element "div")))
|
|
(dom-set-attr _el-outer "id" "outer")
|
|
(dom-set-attr _el-outer "_" "on click add .outer-clicked")
|
|
(dom-set-attr _el-inner "id" "inner")
|
|
(dom-set-attr _el-inner "_" "on click halt bubbling then add .continued")
|
|
(dom-set-inner-html _el-inner "click me")
|
|
(dom-append (dom-body) _el-outer)
|
|
(dom-append _el-outer _el-inner)
|
|
(hs-activate! _el-outer)
|
|
(hs-activate! _el-inner)
|
|
(dom-dispatch (dom-query-by-id "inner") "click" nil)
|
|
(assert (not (dom-has-class? (dom-query-by-id "outer") "outer-clicked")))
|
|
(assert (not (dom-has-class? (dom-query-by-id "inner") "continued")))
|
|
))
|
|
(deftest "halt default only prevents default, not propagation"
|
|
(hs-cleanup!)
|
|
(let ((_el-outer (dom-create-element "div")) (_el-inner (dom-create-element "div")))
|
|
(dom-set-attr _el-outer "id" "outer")
|
|
(dom-set-attr _el-outer "_" "on click add .outer-clicked")
|
|
(dom-set-attr _el-inner "id" "inner")
|
|
(dom-set-attr _el-inner "_" "on click halt default")
|
|
(dom-set-inner-html _el-inner "click me")
|
|
(dom-append (dom-body) _el-outer)
|
|
(dom-append _el-outer _el-inner)
|
|
(hs-activate! _el-outer)
|
|
(hs-activate! _el-inner)
|
|
(dom-dispatch (dom-query-by-id "inner") "click" nil)
|
|
(assert (dom-has-class? (dom-query-by-id "outer") "outer-clicked"))
|
|
))
|
|
(deftest "halt stops execution after the halt"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click halt then add .should-not-happen")
|
|
(dom-set-inner-html _el-div "test")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
(dom-dispatch _el-div "click" nil)
|
|
(assert (not (dom-has-class? _el-div "should-not-happen")))
|
|
))
|
|
(deftest "halt the event stops propagation but continues execution"
|
|
(hs-cleanup!)
|
|
(let ((_el-outer (dom-create-element "div")) (_el-inner (dom-create-element "div")))
|
|
(dom-set-attr _el-outer "id" "outer")
|
|
(dom-set-attr _el-outer "_" "on click add .outer-clicked")
|
|
(dom-set-attr _el-inner "id" "inner")
|
|
(dom-set-attr _el-inner "_" "on click halt the event then add .continued")
|
|
(dom-set-inner-html _el-inner "click me")
|
|
(dom-append (dom-body) _el-outer)
|
|
(dom-append _el-outer _el-inner)
|
|
(hs-activate! _el-outer)
|
|
(hs-activate! _el-inner)
|
|
(dom-dispatch (dom-query-by-id "inner") "click" nil)
|
|
(assert (not (dom-has-class? (dom-query-by-id "outer") "outer-clicked")))
|
|
(assert (dom-has-class? (dom-query-by-id "inner") "continued"))
|
|
))
|
|
(deftest "halt the event's stops propagation but continues execution"
|
|
(hs-cleanup!)
|
|
(let ((_el-outer (dom-create-element "div")) (_el-inner (dom-create-element "div")))
|
|
(dom-set-attr _el-outer "id" "outer")
|
|
(dom-set-attr _el-outer "_" "on click add .outer-clicked")
|
|
(dom-set-attr _el-inner "id" "inner")
|
|
(dom-set-attr _el-inner "_" "on click halt the event's then add .continued")
|
|
(dom-set-inner-html _el-inner "click me")
|
|
(dom-append (dom-body) _el-outer)
|
|
(dom-append _el-outer _el-inner)
|
|
(hs-activate! _el-outer)
|
|
(hs-activate! _el-inner)
|
|
(dom-dispatch (dom-query-by-id "inner") "click" nil)
|
|
(assert (not (dom-has-class? (dom-query-by-id "outer") "outer-clicked")))
|
|
(assert (dom-has-class? (dom-query-by-id "inner") "continued"))
|
|
))
|
|
(deftest "halt works outside of event context"
|
|
(error "SKIP (untranslated): halt works outside of event context"))
|
|
(deftest "halts event propagation and default"
|
|
(hs-cleanup!)
|
|
(let ((_el-outer (dom-create-element "div")) (_el-inner (dom-create-element "a")))
|
|
(dom-set-attr _el-outer "id" "outer")
|
|
(dom-set-attr _el-outer "_" "on click add .outer-clicked")
|
|
(dom-set-attr _el-inner "id" "inner")
|
|
(dom-set-attr _el-inner "_" "on click halt")
|
|
(dom-set-attr _el-inner "href" "#shouldnot")
|
|
(dom-set-inner-html _el-inner "click me")
|
|
(dom-append (dom-body) _el-outer)
|
|
(dom-append _el-outer _el-inner)
|
|
(hs-activate! _el-outer)
|
|
(hs-activate! _el-inner)
|
|
(dom-dispatch (dom-query-by-id "inner") "click" nil)
|
|
(assert (not (dom-has-class? (dom-query-by-id "outer") "outer-clicked")))
|
|
))
|
|
)
|
|
|
|
;; ── hide (16 tests) ──
|
|
(defsuite "hs-upstream-hide"
|
|
(deftest "can configure hidden as the default hide strategy"
|
|
(hs-cleanup!)
|
|
(hs-set-default-hide-strategy! "hidden")
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click hide")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
(assert (!= (dom-get-attr _el-div "hidden") ""))
|
|
(dom-dispatch _el-div "click" nil)
|
|
(assert= (dom-get-attr _el-div "hidden") "")
|
|
(hs-set-default-hide-strategy! nil)
|
|
))
|
|
(deftest "can filter hide via the when clause"
|
|
(hs-cleanup!)
|
|
(let ((_el-trigger (dom-create-element "div")) (_el-d1 (dom-create-element "div")) (_el-d2 (dom-create-element "div")))
|
|
(dom-set-attr _el-trigger "id" "trigger")
|
|
(dom-set-attr _el-trigger "_" "on click hide <div/> in me when it matches .hideable")
|
|
(dom-set-attr _el-d1 "id" "d1")
|
|
(dom-add-class _el-d1 "hideable")
|
|
(dom-set-attr _el-d2 "id" "d2")
|
|
(dom-append (dom-body) _el-trigger)
|
|
(dom-append _el-trigger _el-d1)
|
|
(dom-append _el-trigger _el-d2)
|
|
(hs-activate! _el-trigger)
|
|
(dom-dispatch (dom-query-by-id "trigger") "click" nil)
|
|
(assert= (dom-get-style (dom-query-by-id "d1") "display") "none")
|
|
(assert= (dom-get-style (dom-query-by-id "d2") "display") "block")
|
|
))
|
|
(deftest "can hide element with display:none explicitly"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click hide me with display")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
(assert= (dom-get-style _el-div "display") "block")
|
|
(dom-dispatch _el-div "click" nil)
|
|
(assert= (dom-get-style _el-div "display") "none")
|
|
))
|
|
(deftest "can hide element with no target"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click hide")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
(dom-dispatch _el-div "click" nil)
|
|
(assert (not (dom-visible? _el-div)))
|
|
))
|
|
(deftest "can hide element with no target followed by command"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click hide add .foo")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
(assert= (dom-get-style _el-div "display") "block")
|
|
(assert (not (dom-has-class? _el-div "foo")))
|
|
(dom-dispatch _el-div "click" nil)
|
|
(assert= (dom-get-style _el-div "display") "none")
|
|
(assert (dom-has-class? _el-div "foo"))
|
|
))
|
|
(deftest "can hide element with no target followed by then"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click hide then add .foo")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
(assert= (dom-get-style _el-div "display") "block")
|
|
(assert (not (dom-has-class? _el-div "foo")))
|
|
(dom-dispatch _el-div "click" nil)
|
|
(assert= (dom-get-style _el-div "display") "none")
|
|
(assert (dom-has-class? _el-div "foo"))
|
|
))
|
|
(deftest "can hide element with no target with a with"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click hide with display then add .foo")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
(assert= (dom-get-style _el-div "display") "block")
|
|
(assert (not (dom-has-class? _el-div "foo")))
|
|
(dom-dispatch _el-div "click" nil)
|
|
(assert= (dom-get-style _el-div "display") "none")
|
|
(assert (dom-has-class? _el-div "foo"))
|
|
))
|
|
(deftest "can hide element with opacity style literal"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click hide me with *opacity")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
(assert= (dom-get-style _el-div "opacity") "1")
|
|
(dom-dispatch _el-div "click" nil)
|
|
(assert= (dom-get-style _el-div "opacity") "0")
|
|
))
|
|
(deftest "can hide element with opacity:0"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click hide me with opacity")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
(assert= (dom-get-style _el-div "opacity") "1")
|
|
(dom-dispatch _el-div "click" nil)
|
|
(assert= (dom-get-style _el-div "opacity") "0")
|
|
))
|
|
(deftest "can hide element, with display:none by default"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click hide me")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
(assert= (dom-get-style _el-div "display") "block")
|
|
(dom-dispatch _el-div "click" nil)
|
|
(assert= (dom-get-style _el-div "display") "none")
|
|
))
|
|
(deftest "can hide element, with visibility:hidden"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click hide me with visibility")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
(assert= (dom-get-style _el-div "visibility") "visible")
|
|
(dom-dispatch _el-div "click" nil)
|
|
(assert= (dom-get-style _el-div "visibility") "hidden")
|
|
))
|
|
(deftest "can hide other elements"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")) (_el-div1 (dom-create-element "div")))
|
|
(dom-add-class _el-div "hideme")
|
|
(dom-set-attr _el-div1 "_" "on click hide .hideme")
|
|
(dom-append (dom-body) _el-div)
|
|
(dom-append (dom-body) _el-div1)
|
|
(hs-activate! _el-div1)
|
|
(assert= (dom-get-style (dom-query ".hideme") "display") "block")
|
|
(dom-dispatch (dom-query "div:nth-of-type(2)") "click" nil)
|
|
(assert= (dom-get-style (dom-query ".hideme") "display") "none")
|
|
))
|
|
(deftest "can hide via the hidden attribute strategy"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click hide me with hidden")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
(assert (!= (dom-get-attr _el-div "hidden") ""))
|
|
(dom-dispatch _el-div "click" nil)
|
|
(assert= (dom-get-attr _el-div "hidden") "")
|
|
))
|
|
(deftest "can hide with custom strategy"
|
|
(hs-cleanup!)
|
|
(hs-set-hide-strategies! {:myHide (fn (op el arg) (if (= op "hide") (dom-add-class el "foo") (dom-remove-class el "foo")))})
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click hide with myHide")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
(assert (not (dom-has-class? _el-div "foo")))
|
|
(dom-dispatch _el-div "click" nil)
|
|
(assert (dom-has-class? _el-div "foo"))
|
|
))
|
|
(deftest "can set default to custom strategy"
|
|
(hs-cleanup!)
|
|
(hs-set-default-hide-strategy! "myHide")
|
|
(hs-set-hide-strategies! {:myHide (fn (op el arg) (if (= op "hide") (dom-add-class el "foo") (dom-remove-class el "foo")))})
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click hide")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
(assert (not (dom-has-class? _el-div "foo")))
|
|
(dom-dispatch _el-div "click" nil)
|
|
(assert (dom-has-class? _el-div "foo"))
|
|
))
|
|
(deftest "hide element then show element retains original display"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click 1 hide on click 2 show")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
(dom-dispatch _el-div "click" nil)
|
|
(assert= (dom-get-style _el-div "display") "none")
|
|
(dom-dispatch _el-div "click" nil)
|
|
(assert= (dom-get-style _el-div "display") "block")
|
|
))
|
|
)
|
|
|
|
;; ── if (19 tests) ──
|
|
(defsuite "hs-upstream-if"
|
|
(deftest "basic else branch works"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click if false else put \"foo\" into me.innerHTML")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
(dom-dispatch _el-div "click" nil)
|
|
(assert= (dom-text-content _el-div) "foo")
|
|
))
|
|
(deftest "basic else branch works with end"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click if false else put \"foo\" into me.innerHTML end")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
(dom-dispatch _el-div "click" nil)
|
|
(assert= (dom-text-content _el-div) "foo")
|
|
))
|
|
(deftest "basic else branch works with multiple commands"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click if false put \"bar\" into me.innerHTML else log me then put \"foo\" into me.innerHTML")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
(dom-dispatch _el-div "click" nil)
|
|
(assert= (dom-text-content _el-div) "foo")
|
|
))
|
|
(deftest "basic else if branch works"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click if false else if true put \"foo\" into me.innerHTML")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
(dom-dispatch _el-div "click" nil)
|
|
(assert= (dom-text-content _el-div) "foo")
|
|
))
|
|
(deftest "basic else if branch works with end"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click if false else if true put \"foo\" into me.innerHTML end")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
(dom-dispatch _el-div "click" nil)
|
|
(assert= (dom-text-content _el-div) "foo")
|
|
))
|
|
(deftest "basic true branch works"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click if true put \"foo\" into me.innerHTML")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
(dom-dispatch _el-div "click" nil)
|
|
(assert= (dom-text-content _el-div) "foo")
|
|
))
|
|
(deftest "basic true branch works with end"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click if true put \"foo\" into me.innerHTML end")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
(dom-dispatch _el-div "click" nil)
|
|
(assert= (dom-text-content _el-div) "foo")
|
|
))
|
|
(deftest "basic true branch works with multiple commands"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click if true log me then put \"foo\" into me.innerHTML")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
(dom-dispatch _el-div "click" nil)
|
|
(assert= (dom-text-content _el-div) "foo")
|
|
))
|
|
(deftest "basic true branch works with naked else"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click if true put \"foo\" into me.innerHTML else")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
(dom-dispatch _el-div "click" nil)
|
|
(assert= (dom-text-content _el-div) "foo")
|
|
))
|
|
(deftest "basic true branch works with naked else end"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click if true put \"foo\" into me.innerHTML else end")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
(dom-dispatch _el-div "click" nil)
|
|
(assert= (dom-text-content _el-div) "foo")
|
|
))
|
|
(deftest "false branch with a wait works"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click if false else wait 10 ms then put \"foo\" into me.innerHTML")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
(dom-dispatch _el-div "click" nil)
|
|
(assert= (dom-text-content _el-div) "foo")
|
|
))
|
|
(deftest "if on new line does not join w/ else"
|
|
(hs-cleanup!)
|
|
(host-set! (host-global "window") "tmp" false)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click if window.tmp else if window.tmp end put \"foo\" into me end")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
(dom-dispatch _el-div "click" nil)
|
|
(assert= (dom-text-content _el-div) "foo")
|
|
(host-set! (host-global "window") "tmp" true)
|
|
(dom-set-inner-html _el-div "")
|
|
(dom-dispatch _el-div "click" nil)
|
|
(assert= (dom-text-content _el-div) "")
|
|
))
|
|
(deftest "if properly passes execution along if child is not executed"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click if false end put \"foo\" into me.innerHTML")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
(dom-dispatch _el-div "click" nil)
|
|
(assert= (dom-text-content _el-div) "foo")
|
|
))
|
|
(deftest "if properly supports nested if statements and end block"
|
|
(hs-cleanup!)
|
|
(host-set! (host-global "window") "tmp" false)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click if window.tmp then put \"foo\" into me else if not window.tmp end catch e")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
(dom-dispatch _el-div "click" nil)
|
|
(assert= (dom-text-content _el-div) "")
|
|
(host-set! (host-global "window") "tmp" true)
|
|
(dom-dispatch _el-div "click" nil)
|
|
(assert= (dom-text-content _el-div) "foo")
|
|
))
|
|
(deftest "otherwise alias works"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click if false otherwise put \"foo\" into me.innerHTML")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
(dom-dispatch _el-div "click" nil)
|
|
(assert= (dom-text-content _el-div) "foo")
|
|
))
|
|
(deftest "passes the sieve test"
|
|
(error "SKIP (untranslated): passes the sieve test"))
|
|
(deftest "triple else if branch works"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click if false else if false else put \"foo\" into me.innerHTML")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
(dom-dispatch _el-div "click" nil)
|
|
(assert= (dom-text-content _el-div) "foo")
|
|
))
|
|
(deftest "triple else if branch works with end"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click if false else if false else put \"foo\" into me.innerHTML end")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
(dom-dispatch _el-div "click" nil)
|
|
(assert= (dom-text-content _el-div) "foo")
|
|
))
|
|
(deftest "true branch with a wait works"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click if true wait 10 ms then put \"foo\" into me.innerHTML")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
(dom-dispatch _el-div "click" nil)
|
|
(assert= (dom-text-content _el-div) "foo")
|
|
))
|
|
)
|
|
|
|
;; ── increment (20 tests) ──
|
|
(defsuite "hs-upstream-increment"
|
|
(deftest "can decrement a property"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click decrement my.innerHTML")
|
|
(dom-set-inner-html _el-div "3")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
(dom-dispatch _el-div "click" nil)
|
|
(dom-dispatch _el-div "click" nil)
|
|
(dom-dispatch _el-div "click" nil)
|
|
(assert= (dom-text-content _el-div) "0")
|
|
))
|
|
(deftest "can decrement a value multiple times"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click decrement my.innerHTML")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
(dom-dispatch _el-div "click" nil)
|
|
(dom-dispatch _el-div "click" nil)
|
|
(dom-dispatch _el-div "click" nil)
|
|
(dom-dispatch _el-div "click" nil)
|
|
(dom-dispatch _el-div "click" nil)
|
|
(assert= (dom-text-content _el-div) "-5")
|
|
))
|
|
(deftest "can decrement a variable"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click set value to 20 then decrement value by 2 then put value into me")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
(dom-dispatch _el-div "click" nil)
|
|
(assert= (dom-text-content _el-div) "18")
|
|
))
|
|
(deftest "can decrement an array element"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click set arr to [10, 20, 30] then decrement arr[1] then put arr[1] into me")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
(dom-dispatch _el-div "click" nil)
|
|
(assert= (dom-text-content _el-div) "19")
|
|
))
|
|
(deftest "can decrement an attribute"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click decrement @value then put @value into me")
|
|
(dom-set-attr _el-div "value" "5")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
(dom-dispatch _el-div "click" nil)
|
|
(dom-dispatch _el-div "click" nil)
|
|
(dom-dispatch _el-div "click" nil)
|
|
(assert= (dom-text-content _el-div) "2")
|
|
))
|
|
(deftest "can decrement an empty variable"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click decrement value then put value 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")
|
|
))
|
|
(deftest "can decrement an floating point numbers"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click set value to 6.1 then decrement value by 5.1 then put value into me")
|
|
(dom-set-attr _el-div "value" "5")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
(dom-dispatch _el-div "click" nil)
|
|
(assert= (dom-text-content _el-div) "1")
|
|
))
|
|
(deftest "can decrement by zero"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click set value to 20 then decrement value by 0 then put value into me")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
(dom-dispatch _el-div "click" nil)
|
|
(assert= (dom-text-content _el-div) "20")
|
|
))
|
|
(deftest "can increment a possessive property"
|
|
(hs-cleanup!)
|
|
(let ((_el-d1 (dom-create-element "div")))
|
|
(dom-set-attr _el-d1 "id" "d1")
|
|
(dom-set-attr _el-d1 "_" "on click increment #d1's innerHTML")
|
|
(dom-set-inner-html _el-d1 "5")
|
|
(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")) "6")
|
|
))
|
|
(deftest "can increment a property"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click increment my.innerHTML")
|
|
(dom-set-inner-html _el-div "3")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
(dom-dispatch _el-div "click" nil)
|
|
(dom-dispatch _el-div "click" nil)
|
|
(dom-dispatch _el-div "click" nil)
|
|
(assert= (dom-text-content _el-div) "6")
|
|
))
|
|
(deftest "can increment a property of expression"
|
|
(hs-cleanup!)
|
|
(let ((_el-d1 (dom-create-element "div")))
|
|
(dom-set-attr _el-d1 "id" "d1")
|
|
(dom-set-attr _el-d1 "_" "on click increment innerHTML of #d1")
|
|
(dom-set-inner-html _el-d1 "5")
|
|
(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")) "6")
|
|
))
|
|
(deftest "can increment a style ref"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click set my *opacity to 0.5 then increment *opacity by 0.25 then put *opacity into me")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
(dom-dispatch _el-div "click" nil)
|
|
(assert= (dom-text-content _el-div) "0.75")
|
|
))
|
|
(deftest "can increment a value multiple times"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click increment my.innerHTML")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
(dom-dispatch _el-div "click" nil)
|
|
(dom-dispatch _el-div "click" nil)
|
|
(dom-dispatch _el-div "click" nil)
|
|
(dom-dispatch _el-div "click" nil)
|
|
(dom-dispatch _el-div "click" nil)
|
|
(assert= (dom-text-content _el-div) "5")
|
|
))
|
|
(deftest "can increment a variable"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click set value to 20 then increment value by 2 then put value into me")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
(dom-dispatch _el-div "click" nil)
|
|
(assert= (dom-text-content _el-div) "22")
|
|
))
|
|
(deftest "can increment an array element"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click set arr to [10, 20, 30] then increment arr[1] then put arr[1] into me")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
(dom-dispatch _el-div "click" nil)
|
|
(assert= (dom-text-content _el-div) "21")
|
|
))
|
|
(deftest "can increment an attribute"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click increment @value then put @value into me")
|
|
(dom-set-attr _el-div "value" "5")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
(dom-dispatch _el-div "click" nil)
|
|
(dom-dispatch _el-div "click" nil)
|
|
(dom-dispatch _el-div "click" nil)
|
|
(assert= (dom-text-content _el-div) "8")
|
|
))
|
|
(deftest "can increment an empty variable"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click increment value then put value 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")
|
|
))
|
|
(deftest "can increment an floating point numbers"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click set value to 5.2 then increment value by 6.1 then put value into me")
|
|
(dom-set-attr _el-div "value" "5")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
(dom-dispatch _el-div "click" nil)
|
|
(assert= (dom-text-content _el-div) "11.3")
|
|
))
|
|
(deftest "can increment by zero"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click set value to 20 then increment value by 0 then put value into me")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
(dom-dispatch _el-div "click" nil)
|
|
(assert= (dom-text-content _el-div) "20")
|
|
))
|
|
(deftest "can increment refer to result"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click increment value by 2 then put it 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")
|
|
))
|
|
)
|
|
|
|
;; ── init (3 tests) ──
|
|
(defsuite "hs-upstream-init"
|
|
(deftest "can define an init block in a script"
|
|
(hs-cleanup!)
|
|
(guard (_e (true nil)) (eval-expr-cek (hs-to-sx (hs-compile "init set window.foo to 42 end"))))
|
|
)
|
|
(deftest "can define an init block inline"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "init then set my.foo to 42 end on click put my.foo into my.innerHTML")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
))
|
|
(deftest "can initialize immediately"
|
|
(hs-cleanup!)
|
|
(guard (_e (true nil)) (eval-expr-cek (hs-to-sx (hs-compile "init immediately set window.bar to 42 end"))))
|
|
)
|
|
)
|
|
|
|
;; ── integration/htmx (9 tests) ──
|
|
(defsuite "hs-upstream-integration/htmx"
|
|
(deftest "htmx content added by hyperscript is processed and can issue requests"
|
|
(hs-cleanup!)
|
|
(let ((_el-button (dom-create-element "button")) (_el-result9 (dom-create-element "div")))
|
|
(dom-set-attr _el-button "_" "on click put '<div id=\"injected\" hx-get=\"/test9\" hx-trigger=\"click\" hx-target=\"#result9\">Click me</div>' after me")
|
|
(dom-set-inner-html _el-button "Inject")
|
|
(dom-set-attr _el-result9 "id" "result9")
|
|
(dom-append (dom-body) _el-button)
|
|
(dom-append (dom-body) _el-result9)
|
|
(hs-activate! _el-button)
|
|
))
|
|
(deftest "hyperscript can cancel htmx request via halt"
|
|
(hs-cleanup!)
|
|
(let ((_el-button (dom-create-element "button")) (_el-out5 (dom-create-element "div")))
|
|
(dom-set-attr _el-button "_" "on htmx:before:request halt the event")
|
|
(dom-set-attr _el-button "hx-get" "/test5")
|
|
(dom-set-attr _el-button "hx-target" "#out5")
|
|
(dom-set-inner-html _el-button "Load")
|
|
(dom-set-attr _el-out5 "id" "out5")
|
|
(dom-set-inner-html _el-out5 "original")
|
|
(dom-append (dom-body) _el-button)
|
|
(dom-append (dom-body) _el-out5)
|
|
(hs-activate! _el-button)
|
|
))
|
|
(deftest "hyperscript can modify form values before htmx submit"
|
|
(hs-cleanup!)
|
|
(let ((_el-form (dom-create-element "form")) (_el-hidden4 (dom-create-element "input")) (_el-button (dom-create-element "button")) (_el-result4 (dom-create-element "div")))
|
|
(dom-set-attr _el-form "_" "on submit set #hidden4's value to 'injected'")
|
|
(dom-set-attr _el-form "hx-post" "/test4")
|
|
(dom-set-attr _el-form "hx-target" "#result4")
|
|
(dom-set-attr _el-hidden4 "id" "hidden4")
|
|
(dom-set-attr _el-hidden4 "type" "hidden")
|
|
(dom-set-attr _el-hidden4 "name" "data")
|
|
(dom-set-attr _el-hidden4 "value" "")
|
|
(dom-set-attr _el-button "type" "submit")
|
|
(dom-set-inner-html _el-button "Submit")
|
|
(dom-set-attr _el-result4 "id" "result4")
|
|
(dom-append (dom-body) _el-form)
|
|
(dom-append _el-form _el-hidden4)
|
|
(dom-append _el-form _el-button)
|
|
(dom-append (dom-body) _el-result4)
|
|
(hs-activate! _el-form)
|
|
))
|
|
(deftest "hyperscript can react to htmx:after:request"
|
|
(hs-cleanup!)
|
|
(let ((_el-button (dom-create-element "button")) (_el-out8 (dom-create-element "div")) (_el-status8 (dom-create-element "span")))
|
|
(dom-set-attr _el-button "_" "on htmx:after:request put 'finished' into #status8")
|
|
(dom-set-attr _el-button "hx-get" "/test8")
|
|
(dom-set-attr _el-button "hx-target" "#out8")
|
|
(dom-set-inner-html _el-button "Send")
|
|
(dom-set-attr _el-out8 "id" "out8")
|
|
(dom-set-attr _el-status8 "id" "status8")
|
|
(dom-append (dom-body) _el-button)
|
|
(dom-append (dom-body) _el-out8)
|
|
(dom-append (dom-body) _el-status8)
|
|
(hs-activate! _el-button)
|
|
))
|
|
(deftest "hyperscript can trigger htmx requests via send"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")) (_el-button (dom-create-element "button")) (_el-out2 (dom-create-element "div")))
|
|
(dom-set-attr _el-div "hx-get" "/test2")
|
|
(dom-set-attr _el-div "hx-trigger" "doLoad")
|
|
(dom-set-attr _el-div "hx-target" "#out2")
|
|
(dom-set-inner-html _el-div "waiting")
|
|
(dom-set-attr _el-button "_" "on click send doLoad to the previous <div/>")
|
|
(dom-set-inner-html _el-button "Go")
|
|
(dom-set-attr _el-out2 "id" "out2")
|
|
(dom-append (dom-body) _el-div)
|
|
(dom-append (dom-body) _el-button)
|
|
(dom-append (dom-body) _el-out2)
|
|
(hs-activate! _el-button)
|
|
))
|
|
(deftest "hyperscript element-scoped vars persist across htmx swaps"
|
|
(hs-cleanup!)
|
|
(let ((_el-outer7 (dom-create-element "div")) (_el-clicker7 (dom-create-element "button")) (_el-swapper7 (dom-create-element "button")) (_el-target7 (dom-create-element "div")) (_el-count7 (dom-create-element "span")))
|
|
(dom-set-attr _el-outer7 "id" "outer7")
|
|
(dom-set-attr _el-outer7 "_" "set :counter to 0 then on click from #clicker7 increment :counter then put :counter into #count7")
|
|
(dom-set-attr _el-clicker7 "id" "clicker7")
|
|
(dom-set-inner-html _el-clicker7 "Count")
|
|
(dom-set-attr _el-swapper7 "id" "swapper7")
|
|
(dom-set-attr _el-swapper7 "hx-get" "/test7")
|
|
(dom-set-attr _el-swapper7 "hx-target" "#target7")
|
|
(dom-set-attr _el-swapper7 "hx-swap" "innerHTML")
|
|
(dom-set-inner-html _el-swapper7 "Swap")
|
|
(dom-set-attr _el-target7 "id" "target7")
|
|
(dom-set-inner-html _el-target7 "original")
|
|
(dom-set-attr _el-count7 "id" "count7")
|
|
(dom-set-inner-html _el-count7 "0")
|
|
(dom-append (dom-body) _el-outer7)
|
|
(dom-append _el-outer7 _el-clicker7)
|
|
(dom-append _el-outer7 _el-swapper7)
|
|
(dom-append _el-outer7 _el-target7)
|
|
(dom-append _el-outer7 _el-count7)
|
|
(hs-activate! _el-outer7)
|
|
))
|
|
(deftest "hyperscript responds to htmx swap events"
|
|
(hs-cleanup!)
|
|
(let ((_el-button (dom-create-element "button")) (_el-target1 (dom-create-element "div")) (_el-status1 (dom-create-element "span")))
|
|
(dom-set-attr _el-button "_" "on htmx:after:swap put 'swapped!' into #status1")
|
|
(dom-set-attr _el-button "hx-get" "/test1")
|
|
(dom-set-attr _el-button "hx-target" "#target1")
|
|
(dom-set-inner-html _el-button "Load")
|
|
(dom-set-attr _el-target1 "id" "target1")
|
|
(dom-set-attr _el-status1 "id" "status1")
|
|
(dom-append (dom-body) _el-button)
|
|
(dom-append (dom-body) _el-target1)
|
|
(dom-append (dom-body) _el-status1)
|
|
(hs-activate! _el-button)
|
|
))
|
|
(deftest "hyperscript responds to htmx:after:settle on target"
|
|
(hs-cleanup!)
|
|
(let ((_el-button (dom-create-element "button")) (_el-target6 (dom-create-element "div")))
|
|
(dom-set-attr _el-button "hx-get" "/test6")
|
|
(dom-set-attr _el-button "hx-target" "#target6")
|
|
(dom-set-inner-html _el-button "Load")
|
|
(dom-set-attr _el-target6 "id" "target6")
|
|
(dom-set-attr _el-target6 "_" "on htmx:after:settle add .done to me")
|
|
(dom-append (dom-body) _el-button)
|
|
(dom-append (dom-body) _el-target6)
|
|
(hs-activate! _el-target6)
|
|
))
|
|
(deftest "hyperscript works on htmx-swapped content"
|
|
(hs-cleanup!)
|
|
(let ((_el-button (dom-create-element "button")) (_el-container3 (dom-create-element "div")))
|
|
(dom-set-attr _el-button "hx-get" "/test3")
|
|
(dom-set-attr _el-button "hx-target" "#container3")
|
|
(dom-set-inner-html _el-button "Load")
|
|
(dom-set-attr _el-container3 "id" "container3")
|
|
(dom-append (dom-body) _el-button)
|
|
(dom-append (dom-body) _el-container3)
|
|
))
|
|
)
|
|
|
|
;; ── js (11 tests) ──
|
|
(defsuite "hs-upstream-js"
|
|
(deftest "can access values from _hyperscript"
|
|
(hs-cleanup!)
|
|
(host-set! (host-global "window") "testSuccess" false)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click set t to true then js(t) window.testSuccess = t end")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
(dom-dispatch _el-div "click" nil)
|
|
))
|
|
(deftest "can deal with empty input list"
|
|
(hs-cleanup!)
|
|
(host-set! (host-global "window") "testSuccess" false)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click js() window.testSuccess = true end")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
(dom-dispatch _el-div "click" nil)
|
|
))
|
|
(deftest "can do both of the above"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click set a to 1 then js(a) return a + 1 end 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) "2")
|
|
))
|
|
(deftest "can expose functions"
|
|
(hs-cleanup!)
|
|
(let ((_el-script (dom-create-element "script")))
|
|
(dom-set-attr _el-script "type" "text/hyperscript")
|
|
(dom-append (dom-body) _el-script)
|
|
))
|
|
(deftest "can expose globals"
|
|
(hs-cleanup!)
|
|
(let ((_el-script (dom-create-element "script")))
|
|
(dom-set-attr _el-script "type" "text/hyperscript")
|
|
(dom-append (dom-body) _el-script)
|
|
))
|
|
(deftest "can hide functions"
|
|
(hs-cleanup!)
|
|
(let ((_el-script (dom-create-element "script")))
|
|
(dom-set-attr _el-script "type" "text/hyperscript")
|
|
(dom-append (dom-body) _el-script)
|
|
))
|
|
(deftest "can return values to _hyperscript"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click js return 'test success' end 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) "test success")
|
|
))
|
|
(deftest "can run js"
|
|
(hs-cleanup!)
|
|
(host-set! (host-global "window") "testSuccess" false)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click js window.testSuccess = true end")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
(dom-dispatch _el-div "click" nil)
|
|
))
|
|
(deftest "can run js at the top level"
|
|
(hs-cleanup!)
|
|
(let ((_el-script (dom-create-element "script")))
|
|
(dom-set-attr _el-script "type" "text/hyperscript")
|
|
(dom-append (dom-body) _el-script)
|
|
))
|
|
(deftest "does not expose variables"
|
|
(hs-cleanup!)
|
|
(let ((_el-script (dom-create-element "script")))
|
|
(dom-set-attr _el-script "type" "text/hyperscript")
|
|
(dom-append (dom-body) _el-script)
|
|
))
|
|
(deftest "handles rejected promises without hanging"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click js return Promise.reject(\"boom\") end catch e put e 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) "boom")
|
|
))
|
|
)
|
|
|
|
;; ── live (23 tests) ──
|
|
(defsuite "hs-upstream-live"
|
|
(deftest "append triggers live block"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "live put $items.join(', ') into me")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
))
|
|
(deftest "array + still works with live"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "live put $items.join(', ') into me")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
))
|
|
(deftest "bind and live on same element do not interfere"
|
|
(hs-cleanup!)
|
|
(let ((_el-input (dom-create-element "input")) (_el-span (dom-create-element "span")))
|
|
(dom-set-attr _el-input "_" "bind $username to me end live set my @data-mirror to $username")
|
|
(dom-set-attr _el-input "type" "text")
|
|
(dom-set-attr _el-input "value" "alice")
|
|
(dom-set-attr _el-span "_" "when $username 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 "block form cascades inter-dependent commands"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "live then set $subtotal to ($price * $qty) then set $total to ($subtotal + $tax) end when $total changes put it into me")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
))
|
|
(deftest "block form re-runs all commands when any dependency changes"
|
|
(hs-cleanup!)
|
|
(let ((_el-w (dom-create-element "span")) (_el-h (dom-create-element "span")) (_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-w "id" "w")
|
|
(dom-set-attr _el-w "_" "when $doubleWidth changes put it into me")
|
|
(dom-set-attr _el-h "id" "h")
|
|
(dom-set-attr _el-h "_" "when $doubleHeight changes put it into me")
|
|
(dom-set-attr _el-div "_" "live then set $doubleWidth to ($width * 2) then set $doubleHeight to ($height * 2) end")
|
|
(dom-append (dom-body) _el-w)
|
|
(dom-append (dom-body) _el-h)
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-w)
|
|
(hs-activate! _el-h)
|
|
(hs-activate! _el-div)
|
|
))
|
|
(deftest "conditional branch only tracks the active dependency"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "live then if $showFirst put $firstName into me else put $lastName into me end end")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
))
|
|
(deftest "derives a variable from a computed expression"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "live set $total to ($price * $qty) end when $total changes put it into me")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
))
|
|
(deftest "effects stop when element is removed from DOM"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "live put $message into me")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
))
|
|
(deftest "live and when on same element do not interfere"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "live set my @data-status to $status end when $status changes put 'Status: ' + it into me")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
))
|
|
(deftest "multiple live on same element work independently"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "live set my @data-name to $firstName end live set my @data-age to $age")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
))
|
|
(deftest "property change on object in array triggers live re-render"
|
|
(hs-cleanup!)
|
|
(let ((_el-people-tmpl (dom-create-element "script")) (_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-people-tmpl "id" "people-tmpl")
|
|
(dom-set-attr _el-people-tmpl "type" "text/hyperscript-template")
|
|
(dom-set-inner-html _el-people-tmpl "#for p in people
|
|
<span>${p.name}</span>
|
|
#end")
|
|
(dom-set-attr _el-div "_" "live render #people-tmpl with people: $people then put it into my.innerHTML end")
|
|
(dom-append (dom-body) _el-people-tmpl)
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
))
|
|
(deftest "push object then modify its property both trigger live"
|
|
(hs-cleanup!)
|
|
(let ((_el-items-tmpl (dom-create-element "script")) (_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-items-tmpl "id" "items-tmpl")
|
|
(dom-set-attr _el-items-tmpl "type" "text/hyperscript-template")
|
|
(dom-set-inner-html _el-items-tmpl "#for item in items
|
|
<span>${item.label}</span>
|
|
#end")
|
|
(dom-set-attr _el-div "_" "live render #items-tmpl with items: $items then put it into my.innerHTML end")
|
|
(dom-append (dom-body) _el-items-tmpl)
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
))
|
|
(deftest "push via call triggers live block"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "live put $items.join(', ') into me")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
))
|
|
(deftest "push via pseudo-command triggers live block"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "live put $items.join(', ') into me")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
))
|
|
(deftest "puts a computed dollar amount into the DOM"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "live put '$' + ($price * $qty) into me")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
))
|
|
(deftest "reactive effects are stopped on cleanup"
|
|
(hs-cleanup!)
|
|
(let ((_el-d1 (dom-create-element "div")))
|
|
(dom-set-attr _el-d1 "id" "d1")
|
|
(dom-set-attr _el-d1 "_" "live put $count into me")
|
|
(dom-append (dom-body) _el-d1)
|
|
(hs-activate! _el-d1)
|
|
))
|
|
(deftest "separate live statements create independent effects"
|
|
(hs-cleanup!)
|
|
(let ((_el-w (dom-create-element "span")) (_el-h (dom-create-element "span")) (_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-w "id" "w")
|
|
(dom-set-attr _el-w "_" "when $doubleWidth changes put it into me")
|
|
(dom-set-attr _el-h "id" "h")
|
|
(dom-set-attr _el-h "_" "when $doubleHeight changes put it into me")
|
|
(dom-set-attr _el-div "_" "live set $doubleWidth to ($width * 2) end live set $doubleHeight to ($height * 2)")
|
|
(dom-append (dom-body) _el-w)
|
|
(dom-append (dom-body) _el-h)
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-w)
|
|
(hs-activate! _el-h)
|
|
(hs-activate! _el-div)
|
|
))
|
|
(deftest "set property still works with live"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "live put $obj.name into me")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
))
|
|
(deftest "sets a style reactively"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "live set *opacity to $opacity")
|
|
(dom-set-inner-html _el-div "visible")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
))
|
|
(deftest "sets an attribute reactively"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "live set my @data-theme to $theme")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
))
|
|
(deftest "toggles a class based on a boolean variable"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "live then if $isActive add .active to me else remove .active from me end end")
|
|
(dom-set-inner-html _el-div "test")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
))
|
|
(deftest "toggles display style based on a boolean variable"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "live then if $isVisible set *display to 'block' else set *display to 'none' end end")
|
|
(dom-set-inner-html _el-div "content")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
))
|
|
(deftest "updates DOM text reactively with put"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "live put 'hello ' + $greeting into me")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
))
|
|
)
|
|
|
|
;; ── log (4 tests) ──
|
|
(defsuite "hs-upstream-log"
|
|
(deftest "can log multiple items"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click log me, my")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
(dom-dispatch _el-div "click" nil)
|
|
))
|
|
(deftest "can log multiple items with debug"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click log me, my with console.debug")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
(dom-dispatch _el-div "click" nil)
|
|
))
|
|
(deftest "can log multiple items with error"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click log me, my with console.error")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
(dom-dispatch _el-div "click" nil)
|
|
))
|
|
(deftest "can log single item"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click log me")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
(dom-dispatch _el-div "click" nil)
|
|
))
|
|
)
|
|
|
|
;; ── make (8 tests) ──
|
|
(defsuite "hs-upstream-make"
|
|
(deftest "can make elements"
|
|
(eval-hs "make a <p/> set window.obj to it")
|
|
(assert= (host-get (host-get (host-global "window") "obj") "tagName") "P")
|
|
)
|
|
(deftest "can make elements with id and classes"
|
|
(eval-hs "make a <p.a#id.b.c/> set window.obj to it")
|
|
(assert= (host-get (host-get (host-global "window") "obj") "tagName") "P")
|
|
(assert= (host-get (host-get (host-global "window") "obj") "id") "id")
|
|
(assert= (dom-has-class? (host-get (host-global "window") "obj") "a") true)
|
|
(assert= (dom-has-class? (host-get (host-global "window") "obj") "b") true)
|
|
(assert= (dom-has-class? (host-get (host-global "window") "obj") "c") true)
|
|
)
|
|
(deftest "can make named objects"
|
|
(eval-hs "make a WeakMap called wm then set window.obj to wm")
|
|
(assert= (not (nil? (host-get (host-global "window") "obj"))) true)
|
|
)
|
|
(deftest "can make named objects w/ global scope"
|
|
(eval-hs "make a WeakMap called $wm")
|
|
(assert= (not (nil? (host-get (host-global "window") "$wm"))) true)
|
|
)
|
|
(deftest "can make named objects with arguments"
|
|
(eval-hs "make a URL from \"/playground/\", \"https://hyperscript.org/\" called u set window.obj to u")
|
|
(assert= (not (nil? (host-get (host-global "window") "obj"))) true)
|
|
(assert= (host-get (host-get (host-global "window") "obj") "href") "https://hyperscript.org/playground/")
|
|
)
|
|
(deftest "can make objects"
|
|
(eval-hs "make a WeakMap then set window.obj to it")
|
|
(assert= (not (nil? (host-get (host-global "window") "obj"))) true)
|
|
)
|
|
(deftest "can make objects with arguments"
|
|
(eval-hs "make a URL from \"/playground/\", \"https://hyperscript.org/\" set window.obj to it")
|
|
(assert= (not (nil? (host-get (host-global "window") "obj"))) true)
|
|
(assert= (host-get (host-get (host-global "window") "obj") "href") "https://hyperscript.org/playground/")
|
|
)
|
|
(deftest "creates a div by default"
|
|
(eval-hs "make a <.a/> set window.obj to it")
|
|
(assert= (host-get (host-get (host-global "window") "obj") "tagName") "DIV")
|
|
(assert= (dom-has-class? (host-get (host-global "window") "obj") "a") true)
|
|
)
|
|
)
|
|
|
|
;; ── measure (6 tests) ──
|
|
(defsuite "hs-upstream-measure"
|
|
(deftest "can assign measurements to locals"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click measure my x,y,left,top,right,bottom then set window.measurement to {left:left,top:top,right:right,bottom:bottom}")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
(dom-dispatch _el-div "click" nil)
|
|
))
|
|
(deftest "can measure all the supported properties"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click measure x,y,left,top,right,bottom,width,height,bounds,scrollLeft,scrollTop,scrollLeftMax,scrollTopMax,scrollWidth,scrollHeight,scroll")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
(dom-dispatch _el-div "click" nil)
|
|
))
|
|
(deftest "can measure another element"
|
|
(hs-cleanup!)
|
|
(let ((_el-other (dom-create-element "div")) (_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-other "id" "other")
|
|
(dom-set-attr _el-other "style" "all: initial; position: fixed; top: 89px")
|
|
(dom-set-attr _el-div "_" "on click measure #other then set window.measurement to it")
|
|
(dom-append (dom-body) _el-other)
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
(dom-dispatch (dom-query "div:nth-of-type(2)") "click" nil)
|
|
))
|
|
(deftest "can measure me"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click measure me then set window.measurement to it")
|
|
(dom-set-attr _el-div "style" "all: initial; position: fixed; top: 89px")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
(dom-dispatch _el-div "click" nil)
|
|
))
|
|
(deftest "can measure with of syntax"
|
|
(hs-cleanup!)
|
|
(let ((_el-other (dom-create-element "div")) (_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-other "id" "other")
|
|
(dom-set-attr _el-other "style" "all: initial; position: fixed; top: 89px")
|
|
(dom-set-attr _el-div "_" "on click measure top of #other then set window.measurement to {top: top}")
|
|
(dom-append (dom-body) _el-other)
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
(dom-dispatch (dom-query "div:nth-of-type(2)") "click" nil)
|
|
))
|
|
(deftest "can measure with possessive syntax"
|
|
(hs-cleanup!)
|
|
(let ((_el-other (dom-create-element "div")) (_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-other "id" "other")
|
|
(dom-set-attr _el-other "style" "all: initial; position: fixed; top: 89px")
|
|
(dom-set-attr _el-div "_" "on click measure #other's top then set window.measurement to {top: top}")
|
|
(dom-append (dom-body) _el-other)
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
(dom-dispatch (dom-query "div:nth-of-type(2)") "click" nil)
|
|
))
|
|
)
|
|
|
|
;; ── morph (10 tests) ──
|
|
(defsuite "hs-upstream-morph"
|
|
(deftest "basic morph updates content"
|
|
(hs-cleanup!)
|
|
(let ((_el-target (dom-create-element "div")) (_el-button (dom-create-element "button")))
|
|
(dom-set-attr _el-target "id" "target")
|
|
(dom-set-inner-html _el-target "old")
|
|
(dom-set-attr _el-button "_" "on click morph #target to \"<div id=target>new</div>\"")
|
|
(dom-set-inner-html _el-button "go")
|
|
(dom-append (dom-body) _el-target)
|
|
(dom-append (dom-body) _el-button)
|
|
(hs-activate! _el-button)
|
|
(dom-dispatch _el-button "click" nil)
|
|
(assert= (dom-text-content (dom-query-by-id "target")) "new")
|
|
))
|
|
(deftest "morph adds new children"
|
|
(hs-cleanup!)
|
|
(let ((_el-target (dom-create-element "div")) (_el-span (dom-create-element "span")) (_el-go (dom-create-element "button")))
|
|
(dom-set-attr _el-target "id" "target")
|
|
(dom-set-inner-html _el-span "first")
|
|
(dom-set-attr _el-go "id" "go")
|
|
(dom-set-attr _el-go "_" "on click morph #target to '<div id=target><span>first</span><span>second</span></div>'")
|
|
(dom-set-inner-html _el-go "go")
|
|
(dom-append (dom-body) _el-target)
|
|
(dom-append _el-target _el-span)
|
|
(dom-append (dom-body) _el-go)
|
|
(hs-activate! _el-go)
|
|
(dom-dispatch (dom-query-by-id "go") "click" nil)
|
|
))
|
|
(deftest "morph cleans up removed hyperscript elements"
|
|
(hs-cleanup!)
|
|
(let ((_el-target (dom-create-element "div")) (_el-child (dom-create-element "div")) (_el-button (dom-create-element "button")))
|
|
(dom-set-attr _el-target "id" "target")
|
|
(dom-set-attr _el-child "id" "child")
|
|
(dom-set-attr _el-child "_" "on click put \"alive\" into me")
|
|
(dom-set-inner-html _el-child "child")
|
|
(dom-set-attr _el-button "_" "on click morph #target to \"<div id=target><p>replaced</p></div>\"")
|
|
(dom-set-inner-html _el-button "go")
|
|
(dom-append (dom-body) _el-target)
|
|
(dom-append _el-target _el-child)
|
|
(dom-append (dom-body) _el-button)
|
|
(hs-activate! _el-child)
|
|
(hs-activate! _el-button)
|
|
(dom-dispatch _el-button "click" nil)
|
|
))
|
|
(deftest "morph initializes hyperscript on new elements"
|
|
(hs-cleanup!)
|
|
(let ((_el-target (dom-create-element "div")) (_el-p (dom-create-element "p")) (_el-go (dom-create-element "button")))
|
|
(dom-set-attr _el-target "id" "target")
|
|
(dom-set-inner-html _el-p "old")
|
|
(dom-set-attr _el-go "id" "go")
|
|
(dom-set-attr _el-go "_" "on click morph #target to '<div id=target><p id=inner _=\"on click put `clicked` into me\">new</p></div>'")
|
|
(dom-set-inner-html _el-go "go")
|
|
(dom-append (dom-body) _el-target)
|
|
(dom-append _el-target _el-p)
|
|
(dom-append (dom-body) _el-go)
|
|
(hs-activate! _el-go)
|
|
(dom-dispatch (dom-query-by-id "go") "click" nil)
|
|
(assert= (dom-text-content (dom-query-by-id "inner")) "new")
|
|
(dom-dispatch (dom-query-by-id "inner") "click" nil)
|
|
(assert= (dom-text-content (dom-query-by-id "inner")) "clicked")
|
|
))
|
|
(deftest "morph preserves element identity"
|
|
(hs-cleanup!)
|
|
(let ((_el-target (dom-create-element "div")) (_el-go (dom-create-element "button")))
|
|
(dom-set-attr _el-target "id" "target")
|
|
(dom-set-inner-html _el-target "old")
|
|
(dom-set-attr _el-go "id" "go")
|
|
(dom-set-attr _el-go "_" "on click morph #target to \"<div id=target>new</div>\"")
|
|
(dom-set-inner-html _el-go "go")
|
|
(dom-append (dom-body) _el-target)
|
|
(dom-append (dom-body) _el-go)
|
|
(hs-activate! _el-go)
|
|
(dom-dispatch (dom-query-by-id "go") "click" nil)
|
|
(assert= (dom-text-content (dom-query-by-id "target")) "new")
|
|
))
|
|
(deftest "morph preserves matched child identity"
|
|
(hs-cleanup!)
|
|
(let ((_el-target (dom-create-element "div")) (_el-child (dom-create-element "div")) (_el-go (dom-create-element "button")))
|
|
(dom-set-attr _el-target "id" "target")
|
|
(dom-set-attr _el-child "id" "child")
|
|
(dom-set-inner-html _el-child "old")
|
|
(dom-set-attr _el-go "id" "go")
|
|
(dom-set-attr _el-go "_" "on click morph #target to \"<div id=target><div id=child>new</div></div>\"")
|
|
(dom-set-inner-html _el-go "go")
|
|
(dom-append (dom-body) _el-target)
|
|
(dom-append _el-target _el-child)
|
|
(dom-append (dom-body) _el-go)
|
|
(hs-activate! _el-go)
|
|
(host-set! (host-global "window") "_savedChild" (host-call document "querySelector" "#child"))
|
|
(dom-dispatch (dom-query-by-id "go") "click" nil)
|
|
))
|
|
(deftest "morph removes old children"
|
|
(hs-cleanup!)
|
|
(let ((_el-target (dom-create-element "div")) (_el-span (dom-create-element "span")) (_el-span2 (dom-create-element "span")) (_el-go (dom-create-element "button")))
|
|
(dom-set-attr _el-target "id" "target")
|
|
(dom-set-inner-html _el-span "first")
|
|
(dom-set-inner-html _el-span2 "second")
|
|
(dom-set-attr _el-go "id" "go")
|
|
(dom-set-attr _el-go "_" "on click morph #target to '<div id=target><span>first</span></div>'")
|
|
(dom-set-inner-html _el-go "go")
|
|
(dom-append (dom-body) _el-target)
|
|
(dom-append _el-target _el-span)
|
|
(dom-append _el-target _el-span2)
|
|
(dom-append (dom-body) _el-go)
|
|
(hs-activate! _el-go)
|
|
(dom-dispatch (dom-query-by-id "go") "click" nil)
|
|
))
|
|
(deftest "morph reorders children by id"
|
|
(hs-cleanup!)
|
|
(let ((_el-target (dom-create-element "div")) (_el-a (dom-create-element "div")) (_el-b (dom-create-element "div")) (_el-button (dom-create-element "button")))
|
|
(dom-set-attr _el-target "id" "target")
|
|
(dom-set-attr _el-a "id" "a")
|
|
(dom-set-inner-html _el-a "A")
|
|
(dom-set-attr _el-b "id" "b")
|
|
(dom-set-inner-html _el-b "B")
|
|
(dom-set-attr _el-button "_" "on click morph #target to \"<div id=target><div id=b>B2</div><div id=a>A2</div></div>\"")
|
|
(dom-set-inner-html _el-button "go")
|
|
(dom-append (dom-body) _el-target)
|
|
(dom-append _el-target _el-a)
|
|
(dom-append _el-target _el-b)
|
|
(dom-append (dom-body) _el-button)
|
|
(hs-activate! _el-button)
|
|
(dom-dispatch _el-button "click" nil)
|
|
))
|
|
(deftest "morph updates attributes"
|
|
(hs-cleanup!)
|
|
(let ((_el-target (dom-create-element "div")) (_el-button (dom-create-element "button")))
|
|
(dom-set-attr _el-target "id" "target")
|
|
(dom-add-class _el-target "old")
|
|
(dom-set-inner-html _el-target "content")
|
|
(dom-set-attr _el-button "_" "on click morph #target to \"<div id=target class=new>content</div>\"")
|
|
(dom-set-inner-html _el-button "go")
|
|
(dom-append (dom-body) _el-target)
|
|
(dom-append (dom-body) _el-button)
|
|
(hs-activate! _el-button)
|
|
(dom-dispatch _el-button "click" nil)
|
|
(assert (dom-has-class? (dom-query-by-id "target") "new"))
|
|
))
|
|
(deftest "morph with variable content"
|
|
(hs-cleanup!)
|
|
(let ((_el-target (dom-create-element "div")) (_el-go (dom-create-element "button")))
|
|
(dom-set-attr _el-target "id" "target")
|
|
(dom-set-inner-html _el-target "original")
|
|
(dom-set-attr _el-go "id" "go")
|
|
(dom-set-attr _el-go "_" "on click set content to \"<div id=target>morphed</div>\" then morph #target to content")
|
|
(dom-set-inner-html _el-go "go")
|
|
(dom-append (dom-body) _el-target)
|
|
(dom-append (dom-body) _el-go)
|
|
(hs-activate! _el-go)
|
|
(dom-dispatch (dom-query-by-id "go") "click" nil)
|
|
(assert= (dom-text-content (dom-query-by-id "target")) "morphed")
|
|
))
|
|
)
|
|
|
|
;; ── on (70 tests) ──
|
|
(defsuite "hs-upstream-on"
|
|
(deftest "async basic finally blocks work"
|
|
(error "SKIP (skip-list): async basic finally blocks work"))
|
|
(deftest "async exceptions don't kill the event queue"
|
|
(hs-cleanup!)
|
|
(let ((_el-button (dom-create-element "button")))
|
|
(dom-set-attr _el-button "_" "on click increment :x then if :x is 1 then wait 1ms then throw \"bar\" otherwise then put \"success\" into me end catch e put e into me")
|
|
(dom-append (dom-body) _el-button)
|
|
(hs-activate! _el-button)
|
|
))
|
|
(deftest "async exceptions in finally block don't kill the event queue"
|
|
(error "SKIP (skip-list): async exceptions in finally block don't kill the event queue"))
|
|
(deftest "async finally blocks work when exception thrown in catch"
|
|
(error "SKIP (skip-list): async finally blocks work when exception thrown in catch"))
|
|
(deftest "basic finally blocks work"
|
|
(error "SKIP (skip-list): basic finally blocks work"))
|
|
(deftest "can be in a top level script tag"
|
|
(error "SKIP (skip-list): can be in a top level script tag"))
|
|
(deftest "can catch async top-level exceptions"
|
|
(hs-cleanup!)
|
|
(let ((_el-button (dom-create-element "button")))
|
|
(dom-set-attr _el-button "_" "on click wait 1ms then throw \"bar\" catch e put e into me")
|
|
(dom-append (dom-body) _el-button)
|
|
(hs-activate! _el-button)
|
|
))
|
|
(deftest "can catch exceptions thrown in hyperscript functions"
|
|
(error "SKIP (skip-list): can catch exceptions thrown in hyperscript functions"))
|
|
(deftest "can catch exceptions thrown in js functions"
|
|
(error "SKIP (skip-list): can catch exceptions thrown in js functions"))
|
|
(deftest "can catch top-level exceptions"
|
|
(hs-cleanup!)
|
|
(let ((_el-button (dom-create-element "button")))
|
|
(dom-set-attr _el-button "_" "on click throw \"bar\" catch e put e into me")
|
|
(dom-append (dom-body) _el-button)
|
|
(hs-activate! _el-button)
|
|
))
|
|
(deftest "can click after a positive event filter"
|
|
(hs-cleanup!)
|
|
(let ((_el-pf (dom-create-element "div")))
|
|
(dom-set-attr _el-pf "id" "pf")
|
|
(dom-set-attr _el-pf "_" "on foo(bar)[bar] put \"triggered\" into my.innerHTML")
|
|
(dom-append (dom-body) _el-pf)
|
|
(hs-activate! _el-pf)
|
|
))
|
|
(deftest "can filter events based on count"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click 1 put 1 + my.innerHTML as Int into my.innerHTML")
|
|
(dom-set-inner-html _el-div "0")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
))
|
|
(deftest "can filter events based on count range"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click 1 to 2 put 1 + my.innerHTML as Int into my.innerHTML")
|
|
(dom-set-inner-html _el-div "0")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
))
|
|
(deftest "can filter events based on unbounded count range"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click 2 and on put 1 + my.innerHTML as Int into my.innerHTML")
|
|
(dom-set-inner-html _el-div "0")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
))
|
|
(deftest "can fire an event on load"
|
|
(hs-cleanup!)
|
|
(let ((_el-d1 (dom-create-element "div")))
|
|
(dom-set-attr _el-d1 "id" "d1")
|
|
(dom-set-attr _el-d1 "_" "on load put \"Loaded\" into my.innerHTML")
|
|
(dom-append (dom-body) _el-d1)
|
|
(hs-activate! _el-d1)
|
|
))
|
|
(deftest "can handle an or after a from clause"
|
|
(error "SKIP (skip-list): can handle an or after a from clause"))
|
|
(deftest "can have a simple event filter"
|
|
(hs-cleanup!)
|
|
(let ((_el-d1 (dom-create-element "div")))
|
|
(dom-set-attr _el-d1 "id" "d1")
|
|
(dom-set-attr _el-d1 "_" "on click[false] log event then put \"Clicked\" into my.innerHTML")
|
|
(dom-append (dom-body) _el-d1)
|
|
(hs-activate! _el-d1)
|
|
))
|
|
(deftest "can have multiple event handlers"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on foo put increment() into my.innerHTML end on bar put increment() into my.innerHTML")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
))
|
|
(deftest "can have multiple event handlers, no end"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on foo put increment() into my.innerHTML on bar put increment() into my.innerHTML")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
))
|
|
(deftest "can ignore when target doesn't exist"
|
|
(error "SKIP (skip-list): can ignore when target doesn't exist"))
|
|
(deftest "can invoke on multiple events"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click or foo call increment()")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
))
|
|
(deftest "can listen for attribute mutations"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on mutation of attributes put \"Mutated\" into me")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
))
|
|
(deftest "can listen for attribute mutations on other elements"
|
|
(hs-cleanup!)
|
|
(let ((_el-d1 (dom-create-element "div")) (_el-d2 (dom-create-element "div")))
|
|
(dom-set-attr _el-d1 "id" "d1")
|
|
(dom-set-attr _el-d2 "id" "d2")
|
|
(dom-set-attr _el-d2 "_" "on mutation of attributes from #d1 put \"Mutated\" into me")
|
|
(dom-append (dom-body) _el-d1)
|
|
(dom-append (dom-body) _el-d2)
|
|
(hs-activate! _el-d2)
|
|
))
|
|
(deftest "can listen for characterData mutation filter out other mutations"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on mutation of characterData put \"Mutated\" into me")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
))
|
|
(deftest "can listen for childList mutation filter out other mutations"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on mutation of childList put \"Mutated\" into me")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
))
|
|
(deftest "can listen for childList mutations"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on mutation of childList put \"Mutated\" into me then wait for hyperscript:mutation")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
))
|
|
(deftest "can listen for events in another element (lazy)"
|
|
(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-div "_" "on click in #d1 put it into window.tmp")
|
|
(dom-set-attr _el-d1 "id" "d1")
|
|
(dom-set-attr _el-d2 "id" "d2")
|
|
(dom-append (dom-body) _el-div)
|
|
(dom-append _el-div _el-d1)
|
|
(dom-append _el-div _el-d2)
|
|
(hs-activate! _el-div)
|
|
))
|
|
(deftest "can listen for general mutations"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on mutation put \"Mutated\" into me then wait for hyperscript:mutation")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
))
|
|
(deftest "can listen for multiple mutations"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on mutation of @foo or @bar put \"Mutated\" into me")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
))
|
|
(deftest "can listen for multiple mutations 2"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on mutation of @foo or @bar put \"Mutated\" into me")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
))
|
|
(deftest "can listen for specific attribute mutations"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on mutation of @foo put \"Mutated\" into me")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
))
|
|
(deftest "can listen for specific attribute mutations and filter out other attribute mutations"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on mutation of @bar put \"Mutated\" into me")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
))
|
|
(deftest "can mix ranges"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click 1 put \"one\" into my.innerHTML on click 3 put \"three\" into my.innerHTML on click 2 put \"two\" into my.innerHTML")
|
|
(dom-set-inner-html _el-div "0")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
))
|
|
(deftest "can pick detail fields out by name"
|
|
(hs-cleanup!)
|
|
(let ((_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 send custom(foo:\"fromBar\") to #d2")
|
|
(dom-set-attr _el-d2 "id" "d2")
|
|
(dom-set-attr _el-d2 "_" "on custom(foo) call me.classList.add(foo)")
|
|
(dom-append (dom-body) _el-d1)
|
|
(dom-append (dom-body) _el-d2)
|
|
(hs-activate! _el-d1)
|
|
(hs-activate! _el-d2)
|
|
(assert (not (dom-has-class? _el-d2 "fromBar")))
|
|
(dom-dispatch _el-d1 "click" nil)
|
|
(assert (dom-has-class? _el-d2 "fromBar")))
|
|
)
|
|
(deftest "can pick event properties out by name"
|
|
(hs-cleanup!)
|
|
(let ((_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 send fromBar to #d2")
|
|
(dom-set-attr _el-d2 "id" "d2")
|
|
(dom-set-attr _el-d2 "_" "on fromBar(type) call me.classList.add(type)")
|
|
(dom-append (dom-body) _el-d1)
|
|
(dom-append (dom-body) _el-d2)
|
|
(hs-activate! _el-d1)
|
|
(hs-activate! _el-d2)
|
|
(assert (not (dom-has-class? _el-d2 "fromBar")))
|
|
(dom-dispatch _el-d1 "click" nil)
|
|
(assert (dom-has-class? _el-d2 "fromBar")))
|
|
)
|
|
(deftest "can queue all events"
|
|
(hs-cleanup!)
|
|
(let ((_el-qa (dom-create-element "div")))
|
|
(dom-set-attr _el-qa "id" "qa")
|
|
(dom-set-attr _el-qa "_" "on foo queue all wait for bar then call increment()")
|
|
(dom-append (dom-body) _el-qa)
|
|
(hs-activate! _el-qa)
|
|
))
|
|
(deftest "can queue events"
|
|
(hs-cleanup!)
|
|
(let ((_el-qe (dom-create-element "div")))
|
|
(dom-set-attr _el-qe "id" "qe")
|
|
(dom-set-attr _el-qe "_" "on foo wait for bar then call increment()")
|
|
(dom-append (dom-body) _el-qe)
|
|
(hs-activate! _el-qe)
|
|
))
|
|
(deftest "can queue first event"
|
|
(hs-cleanup!)
|
|
(let ((_el-qf (dom-create-element "div")))
|
|
(dom-set-attr _el-qf "id" "qf")
|
|
(dom-set-attr _el-qf "_" "on foo queue first wait for bar then call increment()")
|
|
(dom-append (dom-body) _el-qf)
|
|
(hs-activate! _el-qf)
|
|
))
|
|
(deftest "can queue last event"
|
|
(hs-cleanup!)
|
|
(let ((_el-ql (dom-create-element "div")))
|
|
(dom-set-attr _el-ql "id" "ql")
|
|
(dom-set-attr _el-ql "_" "on foo queue last wait for bar then call increment()")
|
|
(dom-append (dom-body) _el-ql)
|
|
(hs-activate! _el-ql)
|
|
))
|
|
(deftest "can refer to event detail properties directly in filter"
|
|
(hs-cleanup!)
|
|
(let ((_el-fd (dom-create-element "div")))
|
|
(dom-set-attr _el-fd "id" "fd")
|
|
(dom-set-attr _el-fd "_" "on example[foo] increment @count then put it into me")
|
|
(dom-append (dom-body) _el-fd)
|
|
(hs-activate! _el-fd)
|
|
))
|
|
(deftest "can refer to event properties directly in filter"
|
|
(hs-cleanup!)
|
|
(let ((_el-t1 (dom-create-element "div")))
|
|
(dom-set-attr _el-t1 "id" "t1")
|
|
(dom-set-attr _el-t1 "_" "on click[buttons==0] log event then put \"Clicked\" into my.innerHTML")
|
|
(dom-append (dom-body) _el-t1)
|
|
(hs-activate! _el-t1)
|
|
))
|
|
(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 add .clicked")
|
|
(dom-append (dom-body) _el-bar)
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
))
|
|
(deftest "can respond to events with colons in names"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")) (_el-d1 (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click send example:event to #d1")
|
|
(dom-set-attr _el-d1 "id" "d1")
|
|
(dom-set-attr _el-d1 "_" "on example:event add .called")
|
|
(dom-append (dom-body) _el-div)
|
|
(dom-append (dom-body) _el-d1)
|
|
(hs-activate! _el-div)
|
|
(hs-activate! _el-d1)
|
|
))
|
|
(deftest "can respond to events with dots in names"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")) (_el-d1 (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click send example.event to #d1")
|
|
(dom-set-attr _el-d1 "id" "d1")
|
|
(dom-set-attr _el-d1 "_" "on example.event add .called")
|
|
(dom-append (dom-body) _el-div)
|
|
(dom-append (dom-body) _el-d1)
|
|
(hs-activate! _el-div)
|
|
(hs-activate! _el-d1)
|
|
))
|
|
(deftest "can respond to events with minus in names"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")) (_el-d1 (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click send \"a-b\" to #d1")
|
|
(dom-set-attr _el-d1 "id" "d1")
|
|
(dom-set-attr _el-d1 "_" "on \"a-b\" add .called")
|
|
(dom-append (dom-body) _el-div)
|
|
(dom-append (dom-body) _el-d1)
|
|
(hs-activate! _el-div)
|
|
(hs-activate! _el-d1)
|
|
))
|
|
(deftest "caught exceptions do not trigger 'exception' event"
|
|
(hs-cleanup!)
|
|
(let ((_el-button (dom-create-element "button")))
|
|
(dom-set-attr _el-button "_" "on click put \"foo\" into me then throw \"bar\" catch e log e on exception(error) put error into me")
|
|
(dom-append (dom-body) _el-button)
|
|
(hs-activate! _el-button)
|
|
))
|
|
(deftest "debounced at <time> collapses rapid events to the last one"
|
|
(hs-cleanup!)
|
|
(let ((_el-d (dom-create-element "div")))
|
|
(dom-set-attr _el-d "id" "d")
|
|
(dom-set-attr _el-d "_" "on click debounced at 80ms then increment @n then put @n into me")
|
|
(dom-append (dom-body) _el-d)
|
|
(hs-activate! _el-d)
|
|
))
|
|
(deftest "debounced at <time> resets the timer on each event"
|
|
(hs-cleanup!)
|
|
(let ((_el-d (dom-create-element "div")))
|
|
(dom-set-attr _el-d "id" "d")
|
|
(dom-set-attr _el-d "_" "on click debounced at 80ms then increment @n then put @n into me")
|
|
(dom-append (dom-body) _el-d)
|
|
(hs-activate! _el-d)
|
|
))
|
|
(deftest "each behavior installation has its own event queue"
|
|
(error "SKIP (skip-list): each behavior installation has its own event queue"))
|
|
(deftest "exceptions in catch block don't kill the event queue"
|
|
(hs-cleanup!)
|
|
(let ((_el-button (dom-create-element "button")))
|
|
(dom-set-attr _el-button "_" "on click increment :x then if :x is 1 then throw \"bar\" otherwise then put \"success\" into me end catch e put e into me then throw e")
|
|
(dom-append (dom-body) _el-button)
|
|
(hs-activate! _el-button)
|
|
))
|
|
(deftest "exceptions in finally block don't kill the event queue"
|
|
(error "SKIP (skip-list): exceptions in finally block don't kill the event queue"))
|
|
(deftest "finally blocks work when exception thrown in catch"
|
|
(error "SKIP (skip-list): finally blocks work when exception thrown in catch"))
|
|
(deftest "halt the event stops propagation to ancestors"
|
|
(hs-cleanup!)
|
|
(let ((_el-outer (dom-create-element "div")) (_el-inner (dom-create-element "button")))
|
|
(dom-set-attr _el-outer "id" "outer")
|
|
(dom-set-attr _el-outer "_" "on click add .outer-clicked")
|
|
(dom-set-attr _el-inner "id" "inner")
|
|
(dom-set-attr _el-inner "_" "on click halt the event")
|
|
(dom-append (dom-body) _el-outer)
|
|
(dom-append _el-outer _el-inner)
|
|
(hs-activate! _el-outer)
|
|
(hs-activate! _el-inner)
|
|
))
|
|
(deftest "halt the event's bubbling stops propagation"
|
|
(hs-cleanup!)
|
|
(let ((_el-outer (dom-create-element "div")) (_el-inner (dom-create-element "button")))
|
|
(dom-set-attr _el-outer "id" "outer")
|
|
(dom-set-attr _el-outer "_" "on click add .outer-clicked")
|
|
(dom-set-attr _el-inner "id" "inner")
|
|
(dom-set-attr _el-inner "_" "on click halt the event's bubbling")
|
|
(dom-append (dom-body) _el-outer)
|
|
(dom-append _el-outer _el-inner)
|
|
(hs-activate! _el-outer)
|
|
(hs-activate! _el-inner)
|
|
))
|
|
(deftest "handles custom events with null detail"
|
|
(hs-cleanup!)
|
|
(let ((_el-d1 (dom-create-element "div")))
|
|
(dom-set-attr _el-d1 "id" "d1")
|
|
(dom-set-attr _el-d1 "_" "on myEvent(foo) if foo put foo into me else put \"no-detail\" into me")
|
|
(dom-append (dom-body) _el-d1)
|
|
(hs-activate! _el-d1)
|
|
))
|
|
(deftest "listeners on other elements are removed when the registering element is removed"
|
|
(error "SKIP (skip-list): listeners on other elements are removed when the registering element is removed"))
|
|
(deftest "listeners on self are not removed when the element is removed"
|
|
(error "SKIP (skip-list): listeners on self are not removed when the element is removed"))
|
|
(deftest "multiple event handlers at a time are allowed to execute with the every keyword"
|
|
(error "SKIP (skip-list): multiple event handlers at a time are allowed to execute with the every keyword"))
|
|
(deftest "on first click fires only once"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on first click put 1 + my.innerHTML as Int into my.innerHTML")
|
|
(dom-set-inner-html _el-div "0")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
))
|
|
(deftest "on intersection fires when the element is in the viewport"
|
|
(hs-cleanup!)
|
|
(let ((_el-d (dom-create-element "div")))
|
|
(dom-set-attr _el-d "id" "d")
|
|
(dom-set-attr _el-d "_" "on intersection(intersecting) then if intersecting put \"seen\" into me end")
|
|
(dom-append (dom-body) _el-d)
|
|
(hs-activate! _el-d)
|
|
(assert= (dom-text-content (dom-query-by-id "d")) "seen")
|
|
))
|
|
(deftest "on intersection having margin parses and fires"
|
|
(hs-cleanup!)
|
|
(let ((_el-d (dom-create-element "div")))
|
|
(dom-set-attr _el-d "id" "d")
|
|
(dom-set-attr _el-d "_" "on intersection(intersecting) having margin \"10px\" then if intersecting put \"seen\" into me end")
|
|
(dom-set-attr _el-d "style" "width:100px;height:100px")
|
|
(dom-append (dom-body) _el-d)
|
|
(hs-activate! _el-d)
|
|
))
|
|
(deftest "on intersection having threshold parses and fires"
|
|
(hs-cleanup!)
|
|
(let ((_el-d (dom-create-element "div")))
|
|
(dom-set-attr _el-d "id" "d")
|
|
(dom-set-attr _el-d "_" "on intersection(intersecting) having threshold 0.1 then if intersecting put \"seen\" into me end")
|
|
(dom-set-attr _el-d "style" "width:100px;height:100px")
|
|
(dom-append (dom-body) _el-d)
|
|
(hs-activate! _el-d)
|
|
))
|
|
(deftest "on load from window responds to window load events"
|
|
(hs-cleanup!)
|
|
(let ((_el-d (dom-create-element "div")))
|
|
(dom-set-attr _el-d "id" "d")
|
|
(dom-set-attr _el-d "_" "on customload from window put \"loaded\" into me")
|
|
(dom-append (dom-body) _el-d)
|
|
(hs-activate! _el-d)
|
|
))
|
|
(deftest "queue none does not allow future queued events"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click queue none put increment() into my.innerHTML then wait for a customEvent")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
))
|
|
(deftest "rethrown exceptions trigger 'exception' event"
|
|
(hs-cleanup!)
|
|
(let ((_el-button (dom-create-element "button")))
|
|
(dom-set-attr _el-button "_"
|
|
"on click put \"foo\" into me then throw \"bar\" catch e throw e on exception(error) put error into me")
|
|
(dom-append (dom-body) _el-button)
|
|
(hs-activate! _el-button)
|
|
(dom-dispatch _el-button "click" nil)
|
|
(assert= (dom-text-content _el-button) "bar"))
|
|
)
|
|
(deftest "supports \"elsewhere\" modifier"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click elsewhere add .clicked")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
))
|
|
(deftest "supports \"from elsewhere\" modifier"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click from elsewhere add .clicked")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
))
|
|
(deftest "throttled at <time> allows events after the window elapses"
|
|
(hs-cleanup!)
|
|
(let ((_el-d (dom-create-element "div")))
|
|
(dom-set-attr _el-d "id" "d")
|
|
(dom-set-attr _el-d "_" "on click throttled at 60ms then increment @n then put @n into me")
|
|
(dom-append (dom-body) _el-d)
|
|
(hs-activate! _el-d)
|
|
))
|
|
(deftest "throttled at <time> drops events within the window"
|
|
(hs-cleanup!)
|
|
(let ((_el-d (dom-create-element "div")))
|
|
(dom-set-attr _el-d "id" "d")
|
|
(dom-set-attr _el-d "_" "on click throttled at 200ms then increment @n then put @n into me")
|
|
(dom-append (dom-body) _el-d)
|
|
(hs-activate! _el-d)
|
|
(assert= (dom-text-content (dom-query-by-id "d")) "1")
|
|
))
|
|
(deftest "uncaught exceptions trigger 'exception' event"
|
|
(hs-cleanup!)
|
|
(let ((_el-button (dom-create-element "button")))
|
|
(dom-set-attr _el-button "_"
|
|
"on click put \"foo\" into me then throw \"bar\" on exception(error) put error into me")
|
|
(dom-append (dom-body) _el-button)
|
|
(hs-activate! _el-button)
|
|
(dom-dispatch _el-button "click" nil)
|
|
(assert= (dom-text-content _el-button) "bar"))
|
|
)
|
|
)
|
|
|
|
;; ── pick (24 tests) ──
|
|
(defsuite "hs-upstream-pick"
|
|
(deftest "can pick a single item from a string"
|
|
(assert= (eval-hs-locals "pick item 2 from str set $test to it" (list (list (quote str) "abcdefghijklmnopqrstuvwxyz"))) "c")
|
|
)
|
|
(deftest "can pick a single item from an array"
|
|
(assert= (eval-hs-locals "pick item 2 from arr set $test to it" (list (list (quote arr) (list 10 11 12 13 14 15 16)))) (list 12))
|
|
)
|
|
(deftest "can pick a single regex match"
|
|
(assert= (eval-hs-locals "pick match of \"\\d+\" from haystack set window.test to it" (list (list (quote haystack) "The 32 quick brown foxes jumped 12 times over the 149 lazy dogs"))) (list "32"))
|
|
)
|
|
(deftest "can pick a single regex match w/ a flag"
|
|
(assert= (eval-hs-locals "pick match of \"t.e\" | i from haystack set window.test to it" (list (list (quote haystack) "The 32 quick brown foxes jumped 12 times over the 149 lazy dogs"))) (list "The"))
|
|
)
|
|
(deftest "can pick all regex matches"
|
|
(assert= (eval-hs-locals "pick matches of \"\\d+\" from haystack set window.test to it" (list (list (quote haystack) "The 32 quick brown foxes jumped 12 times over the 149 lazy dogs"))) (list (list "32") (list "12") (list "149")))
|
|
)
|
|
(deftest "can pick first n items"
|
|
(assert= (eval-hs-locals "pick first 3 of arr set $test to it" (list (list (quote arr) (list 10 20 30 40 50)))) (list 10 20 30))
|
|
)
|
|
(deftest "can pick items from a string"
|
|
(assert= (eval-hs-locals "pick items 1 to 3 from str set $test to it" (list (list (quote str) "abcdefghijklmnopqrstuvwxyz"))) "bc")
|
|
)
|
|
(deftest "can pick items from an array"
|
|
(assert= (eval-hs-locals "pick items 1 to 3 from arr set $test to it" (list (list (quote arr) (list 10 11 12 13 14 15 16)))) (list 11 12))
|
|
)
|
|
(deftest "can pick items using 'of' syntax"
|
|
(assert= (eval-hs-locals "pick items 1 to 3 of arr set $test to it" (list (list (quote arr) (list 10 11 12 13 14 15 16)))) (list 11 12))
|
|
)
|
|
(deftest "can pick last n items"
|
|
(assert= (eval-hs-locals "pick last 2 of arr set $test to it" (list (list (quote arr) (list 10 20 30 40 50)))) (list 40 50))
|
|
)
|
|
(deftest "can pick match using 'of' syntax"
|
|
(assert= (eval-hs-locals "pick match of \"\\d+\" of haystack set window.test to it" (list (list (quote haystack) "The 32 quick brown foxes"))) (list "32"))
|
|
)
|
|
(deftest "can pick random item"
|
|
(assert (not (nil? (eval-hs-locals "pick random of arr set $test to it" (list (list (quote arr) (list 10 20 30)))))))
|
|
)
|
|
(deftest "can pick random n items"
|
|
(assert= (len (eval-hs-locals "pick random 2 of arr set $test to it" (list (list (quote arr) (list 10 20 30 40 50))))) 2)
|
|
)
|
|
(deftest "can use 'end' when picking items from a string"
|
|
(assert= (eval-hs-locals "pick item 4 to end from str set $test to it" (list (list (quote str) "abcdefghijklmnopqrstuvwxyz"))) "efghijklmnopqrstuvwxyz")
|
|
)
|
|
(deftest "can use 'end' when picking items from an array"
|
|
(assert= (eval-hs-locals "pick item 4 to end from arr set $test to it" (list (list (quote arr) (list 10 11 12 13 14 15 16)))) (list 14 15 16))
|
|
)
|
|
(deftest "can use 'start' when picking items from a string"
|
|
(assert= (eval-hs-locals "pick items start to 3 from str set $test to it" (list (list (quote str) "abcdefghijklmnopqrstuvwxyz"))) "abc")
|
|
)
|
|
(deftest "can use 'start' when picking items from an array"
|
|
(assert= (eval-hs-locals "pick items start to 3 from arr set $test to it" (list (list (quote arr) (list 10 11 12 13 14 15 16)))) (list 10 11 12))
|
|
)
|
|
(deftest "can use negative indices when picking items from a string"
|
|
(assert= (eval-hs-locals "pick items 0 to -4 from str set $test to it" (list (list (quote str) "abcdefghijklmnopqrstuvwxyz"))) "abcdefghijklmnopqrstuv")
|
|
)
|
|
(deftest "can use negative indices when picking items from an array"
|
|
(assert= (eval-hs-locals "pick items 0 to -4 from arr set $test to it" (list (list (quote arr) (list 10 11 12 13 14 15 16)))) (list 10 11 12))
|
|
)
|
|
(deftest "does not hang on zero-length regex matches"
|
|
(assert (not (nil? (eval-hs-locals "pick matches of \"\\d*\" from haystack set window.test to it" (list (list (quote haystack) "a1b"))))))
|
|
)
|
|
(deftest "pick first from null returns null"
|
|
(eval-hs "set x to null then pick first 3 from x then return it")
|
|
)
|
|
(deftest "pick last from null returns null"
|
|
(eval-hs "set x to null then pick last 2 from x then return it")
|
|
)
|
|
(deftest "pick match from null returns null"
|
|
(eval-hs "set x to null then pick match of \"\\d+\" from x then return it")
|
|
)
|
|
(deftest "pick random from null returns null"
|
|
(eval-hs "set x to null then pick random from x then return it")
|
|
)
|
|
)
|
|
|
|
;; ── pseudoCommand (11 tests) ──
|
|
(defsuite "hs-upstream-pseudoCommand"
|
|
(deftest "Basic instance function with expression"
|
|
(hs-cleanup!)
|
|
(let ((_el-d1 (dom-create-element "div")))
|
|
(dom-set-attr _el-d1 "id" "d1")
|
|
(dom-set-attr _el-d1 "_" "on click getElementById(\"d1\") from the document then put the result into window.results")
|
|
(dom-append (dom-body) _el-d1)
|
|
(hs-activate! _el-d1)
|
|
(dom-dispatch (dom-query-by-id "d1") "click" nil)
|
|
))
|
|
(deftest "Basic instance function with expression and on"
|
|
(hs-cleanup!)
|
|
(let ((_el-d1 (dom-create-element "div")))
|
|
(dom-set-attr _el-d1 "id" "d1")
|
|
(dom-set-attr _el-d1 "_" "on click getElementById(\"d1\") on the document then put result into window.results")
|
|
(dom-append (dom-body) _el-d1)
|
|
(hs-activate! _el-d1)
|
|
(dom-dispatch (dom-query-by-id "d1") "click" nil)
|
|
))
|
|
(deftest "Basic instance function with expression and with"
|
|
(hs-cleanup!)
|
|
(let ((_el-d1 (dom-create-element "div")))
|
|
(dom-set-attr _el-d1 "id" "d1")
|
|
(dom-set-attr _el-d1 "_" "on click getElementById(\"d1\") with the document then put result into window.results")
|
|
(dom-append (dom-body) _el-d1)
|
|
(hs-activate! _el-d1)
|
|
(dom-dispatch (dom-query-by-id "d1") "click" nil)
|
|
))
|
|
(deftest "Basic instance function with me target"
|
|
(hs-cleanup!)
|
|
(let ((_el-d1 (dom-create-element "div")))
|
|
(dom-set-attr _el-d1 "id" "d1")
|
|
(dom-set-attr _el-d1 "_" "on click foo() on me put result into my bar")
|
|
(dom-append (dom-body) _el-d1)
|
|
(hs-activate! _el-d1)
|
|
(dom-dispatch (dom-query-by-id "d1") "click" nil)
|
|
))
|
|
(deftest "Basic instance function with me target no preposition"
|
|
(hs-cleanup!)
|
|
(let ((_el-d1 (dom-create-element "div")))
|
|
(dom-set-attr _el-d1 "id" "d1")
|
|
(dom-set-attr _el-d1 "_" "on click foo() me then put result into my bar")
|
|
(dom-append (dom-body) _el-d1)
|
|
(hs-activate! _el-d1)
|
|
(dom-dispatch (dom-query-by-id "d1") "click" nil)
|
|
))
|
|
(deftest "Can use functions defined outside of the current element"
|
|
(hs-cleanup!)
|
|
(host-set! (host-global "window") "foo" (fn () "foo"))
|
|
(let ((_el-d1 (dom-create-element "div")))
|
|
(dom-set-attr _el-d1 "id" "d1")
|
|
(dom-set-attr _el-d1 "_" "on click foo() then put result into my bar")
|
|
(dom-append (dom-body) _el-d1)
|
|
(hs-activate! _el-d1)
|
|
(dom-dispatch (dom-query-by-id "d1") "click" nil)
|
|
))
|
|
(deftest "Can use indirect functions with a function root"
|
|
(hs-cleanup!)
|
|
(host-set! (host-global "window") "bar" (fn () {:foo (fn () "foo")}))
|
|
(let ((_el-d1 (dom-create-element "div")))
|
|
(dom-set-attr _el-d1 "id" "d1")
|
|
(dom-set-attr _el-d1 "_" "on click bar().foo() then put the result into my bar")
|
|
(dom-append (dom-body) _el-d1)
|
|
(hs-activate! _el-d1)
|
|
(dom-dispatch (dom-query-by-id "d1") "click" nil)
|
|
))
|
|
(deftest "Can use indirect functions with a symbol root"
|
|
(hs-cleanup!)
|
|
(host-set! (host-global "window") "bar" {:foo (fn () "foo")})
|
|
(let ((_el-d1 (dom-create-element "div")))
|
|
(dom-set-attr _el-d1 "id" "d1")
|
|
(dom-set-attr _el-d1 "_" "on click bar.foo() then put the result into my bar")
|
|
(dom-append (dom-body) _el-d1)
|
|
(hs-activate! _el-d1)
|
|
(dom-dispatch (dom-query-by-id "d1") "click" nil)
|
|
))
|
|
(deftest "Can use nested indirect functions with a symbol root"
|
|
(hs-cleanup!)
|
|
(host-set! (host-global "window") "bar" (fn () {:foo (fn () "foo")}))
|
|
(let ((_el-d1 (dom-create-element "div")))
|
|
(dom-set-attr _el-d1 "id" "d1")
|
|
(dom-set-attr _el-d1 "_" "on click window.bar().foo() then put the result into my bar")
|
|
(dom-append (dom-body) _el-d1)
|
|
(hs-activate! _el-d1)
|
|
(dom-dispatch (dom-query-by-id "d1") "click" nil)
|
|
))
|
|
(deftest "functions defined alongside can be invoked"
|
|
(hs-cleanup!)
|
|
(let ((_el-d1 (dom-create-element "div")))
|
|
(dom-set-attr _el-d1 "id" "d1")
|
|
(dom-set-attr _el-d1 "_" "def foo() return \"foo\" end on click foo() then put result into my bar")
|
|
(dom-append (dom-body) _el-d1)
|
|
(hs-activate! _el-d1)
|
|
(dom-dispatch (dom-query-by-id "d1") "click" nil)
|
|
))
|
|
(deftest "non-function pseudo-command is an error"
|
|
(assert-throws (fn () (eval-hs "on click log me then foo.bar + bar")))
|
|
)
|
|
)
|
|
|
|
;; ── put (38 tests) ──
|
|
(defsuite "hs-upstream-put"
|
|
(deftest "can insert after"
|
|
(hs-cleanup!)
|
|
(let ((_el-d1 (dom-create-element "div")) (_el-d2 (dom-create-element "div")))
|
|
(dom-set-attr _el-d1 "id" "d1")
|
|
(dom-set-inner-html _el-d1 "foo")
|
|
(dom-set-attr _el-d2 "id" "d2")
|
|
(dom-set-attr _el-d2 "_" "on click put #d1 after #d2")
|
|
(dom-append (dom-body) _el-d1)
|
|
(dom-append (dom-body) _el-d2)
|
|
(hs-activate! _el-d2)
|
|
(dom-dispatch (dom-query-by-id "d2") "click" nil)
|
|
))
|
|
(deftest "can insert after beginning"
|
|
(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\" at start of #d1")
|
|
(dom-set-inner-html _el-d1 "*")
|
|
(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 insert before"
|
|
(hs-cleanup!)
|
|
(let ((_el-d2 (dom-create-element "div")) (_el-d1 (dom-create-element "div")))
|
|
(dom-set-attr _el-d2 "id" "d2")
|
|
(dom-set-attr _el-d2 "_" "on click put #d1 before #d2")
|
|
(dom-set-attr _el-d1 "id" "d1")
|
|
(dom-set-inner-html _el-d1 "foo")
|
|
(dom-append (dom-body) _el-d2)
|
|
(dom-append (dom-body) _el-d1)
|
|
(hs-activate! _el-d2)
|
|
(dom-dispatch (dom-query-by-id "d2") "click" nil)
|
|
))
|
|
(deftest "can insert before end"
|
|
(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\" at end of #d1")
|
|
(dom-set-inner-html _el-d1 "*")
|
|
(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 put array vals w/ array access syntax"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click set arr to [1, 2, 3] put \"red\" into arr[0] put arr[0] into my *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 put array vals w/ array access syntax and var"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click set arr to [1, 2, 3] set idx to 0 put \"red\" into arr[idx] put arr[0] into my *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 put at end of an array"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click set :arr to [1,2] then put 3 at end of :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")
|
|
))
|
|
(deftest "can put at start of an array"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click set :arr to [2,3] then put 1 at start of :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")
|
|
))
|
|
(deftest "can put directly into nodes"
|
|
(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")
|
|
(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 put directly into symbols"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click put \"foo\" into me")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
(dom-dispatch _el-div "click" nil)
|
|
(assert= (dom-text-content _el-div) "foo")
|
|
))
|
|
(deftest "can put nodes into nodes"
|
|
(hs-cleanup!)
|
|
(let ((_el-d1 (dom-create-element "div")) (_el-d2 (dom-create-element "div")))
|
|
(dom-set-attr _el-d1 "id" "d1")
|
|
(dom-set-attr _el-d2 "id" "d2")
|
|
(dom-set-attr _el-d2 "_" "on click put #d1 into #d2")
|
|
(dom-append (dom-body) _el-d1)
|
|
(dom-append (dom-body) _el-d2)
|
|
(hs-activate! _el-d2)
|
|
(dom-dispatch (dom-query-by-id "d2") "click" nil)
|
|
))
|
|
(deftest "can put properties w/ array access syntax"
|
|
(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 put properties w/ array access syntax and var"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click set foo to \"color\" then put \"red\" into my style[foo]")
|
|
(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 set into attribute ref"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-add-class _el-div "divs")
|
|
(dom-set-attr _el-div "_" "on click put \"foo\" into @bar")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
(dom-dispatch _el-div "click" nil)
|
|
(assert= (dom-get-attr _el-div "bar") "foo")
|
|
))
|
|
(deftest "can set into class ref w/ flatmapped property"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")) (_el-d1 (dom-create-element "div")) (_el-div2 (dom-create-element "div")) (_el-d2 (dom-create-element "div")) (_el-div4 (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click put \"foo\" into .divs.parentElement.innerHTML")
|
|
(dom-set-attr _el-d1 "id" "d1")
|
|
(dom-add-class _el-div2 "divs")
|
|
(dom-set-attr _el-d2 "id" "d2")
|
|
(dom-add-class _el-div4 "divs")
|
|
(dom-append (dom-body) _el-div)
|
|
(dom-append (dom-body) _el-d1)
|
|
(dom-append _el-d1 _el-div2)
|
|
(dom-append (dom-body) _el-d2)
|
|
(dom-append _el-d2 _el-div4)
|
|
(hs-activate! _el-div)
|
|
(dom-dispatch (nth (dom-query-all (dom-body) "div") 0) "click" nil)
|
|
(assert= (dom-text-content (dom-query-by-id "d1")) "foo")
|
|
(assert= (dom-text-content (dom-query-by-id "d2")) "foo")
|
|
))
|
|
(deftest "can set into class ref w/ flatmapped property using of"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")) (_el-d1 (dom-create-element "div")) (_el-div2 (dom-create-element "div")) (_el-d2 (dom-create-element "div")) (_el-div4 (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click put \"foo\" into innerHTML of parentElement of .divs")
|
|
(dom-set-attr _el-d1 "id" "d1")
|
|
(dom-add-class _el-div2 "divs")
|
|
(dom-set-attr _el-d2 "id" "d2")
|
|
(dom-add-class _el-div4 "divs")
|
|
(dom-append (dom-body) _el-div)
|
|
(dom-append (dom-body) _el-d1)
|
|
(dom-append _el-d1 _el-div2)
|
|
(dom-append (dom-body) _el-d2)
|
|
(dom-append _el-d2 _el-div4)
|
|
(hs-activate! _el-div)
|
|
(dom-dispatch (nth (dom-query-all (dom-body) "div") 0) "click" nil)
|
|
(assert= (dom-text-content (dom-query-by-id "d1")) "foo")
|
|
(assert= (dom-text-content (dom-query-by-id "d2")) "foo")
|
|
))
|
|
(deftest "can set into id ref"
|
|
(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 into indirect attribute ref"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-add-class _el-div "divs")
|
|
(dom-set-attr _el-div "_" "on click put \"foo\" into my @bar")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
(dom-dispatch _el-div "click" nil)
|
|
(assert= (dom-get-attr _el-div "bar") "foo")
|
|
))
|
|
(deftest "can set into indirect attribute ref 2"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")) (_el-div2 (dom-create-element "div")))
|
|
(dom-add-class _el-div "divs")
|
|
(dom-set-attr _el-div "_" "on click put 'foo' into #div2's @bar")
|
|
(dom-set-attr _el-div2 "id" "div2")
|
|
(dom-append (dom-body) _el-div)
|
|
(dom-append (dom-body) _el-div2)
|
|
(hs-activate! _el-div)
|
|
(dom-dispatch (nth (dom-query-all (dom-body) "div") 0) "click" nil)
|
|
(assert= (dom-get-attr (dom-query-by-id "div2") "bar") "foo")
|
|
))
|
|
(deftest "can set into indirect attribute ref 3"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")) (_el-div2 (dom-create-element "div")))
|
|
(dom-add-class _el-div "divs")
|
|
(dom-set-attr _el-div "_" "on click put 'foo' into @bar of #div2")
|
|
(dom-set-attr _el-div2 "id" "div2")
|
|
(dom-append (dom-body) _el-div)
|
|
(dom-append (dom-body) _el-div2)
|
|
(hs-activate! _el-div)
|
|
(dom-dispatch (nth (dom-query-all (dom-body) "div") 0) "click" nil)
|
|
(assert= (dom-get-attr (dom-query-by-id "div2") "bar") "foo")
|
|
))
|
|
(deftest "can set into indirect style ref"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-add-class _el-div "divs")
|
|
(dom-set-attr _el-div "_" "on click put \"red\" into my *color")
|
|
(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 set into indirect style ref 2"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")) (_el-div2 (dom-create-element "div")))
|
|
(dom-add-class _el-div "divs")
|
|
(dom-set-attr _el-div "_" "on click put 'red' into #div2's *color")
|
|
(dom-set-attr _el-div2 "id" "div2")
|
|
(dom-append (dom-body) _el-div)
|
|
(dom-append (dom-body) _el-div2)
|
|
(hs-activate! _el-div)
|
|
(dom-dispatch (nth (dom-query-all (dom-body) "div") 0) "click" nil)
|
|
(assert= (dom-get-style (dom-query-by-id "div2") "color") "red")
|
|
))
|
|
(deftest "can set into indirect style ref 3"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")) (_el-div2 (dom-create-element "div")))
|
|
(dom-add-class _el-div "divs")
|
|
(dom-set-attr _el-div "_" "on click put 'red' into the *color of #div2")
|
|
(dom-set-attr _el-div2 "id" "div2")
|
|
(dom-append (dom-body) _el-div)
|
|
(dom-append (dom-body) _el-div2)
|
|
(hs-activate! _el-div)
|
|
(dom-dispatch (nth (dom-query-all (dom-body) "div") 0) "click" nil)
|
|
(assert= (dom-get-style (dom-query-by-id "div2") "color") "red")
|
|
))
|
|
(deftest "can set into style ref"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-add-class _el-div "divs")
|
|
(dom-set-attr _el-div "_" "on click put \"red\" into *color")
|
|
(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 set javascript globals"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click put \"red\" into window.temp")
|
|
(dom-set-inner-html _el-div "lolwat")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
(dom-dispatch _el-div "click" nil)
|
|
))
|
|
(deftest "can set local variables"
|
|
(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 newVar then put newVar 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 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 "is null tolerant"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-add-class _el-div "divs")
|
|
(dom-set-attr _el-div "_" "on click put \"red\" into #a-bad-id-that-does-not-exist")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
(dom-dispatch _el-div "click" nil)
|
|
))
|
|
(deftest "me symbol doesn't get stomped on direct write"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click put \"foo\" into me then put \"bar\" into me")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
(dom-dispatch _el-div "click" nil)
|
|
(assert= (dom-text-content _el-div) "bar")
|
|
))
|
|
(deftest "properly processes hyperscript after"
|
|
(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-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 "b1")) "40")
|
|
(dom-dispatch (dom-query-by-id "b1") "click" nil)
|
|
(assert= (dom-text-content (dom-query-by-id "b1")) "42")
|
|
))
|
|
(deftest "properly processes hyperscript at end of"
|
|
(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-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 "b1")) "40")
|
|
(dom-dispatch (dom-query-by-id "b1") "click" nil)
|
|
(assert= (dom-text-content (dom-query-by-id "b1")) "42")
|
|
))
|
|
(deftest "properly processes hyperscript at start of"
|
|
(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-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 "b1")) "40")
|
|
(dom-dispatch (dom-query-by-id "b1") "click" nil)
|
|
(assert= (dom-text-content (dom-query-by-id "b1")) "42")
|
|
))
|
|
(deftest "properly processes hyperscript in before"
|
|
(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-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 "b1")) "40")
|
|
(dom-dispatch (dom-query-by-id "b1") "click" nil)
|
|
(assert= (dom-text-content (dom-query-by-id "b1")) "42")
|
|
))
|
|
(deftest "properly processes hyperscript in new content in a element target"
|
|
(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-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 "b1")) "40")
|
|
(dom-dispatch (dom-query-by-id "b1") "click" nil)
|
|
(assert= (dom-text-content (dom-query-by-id "b1")) "42")
|
|
))
|
|
(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-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
(dom-dispatch _el-div "click" nil)
|
|
(assert= (dom-text-content (dom-query-by-id "b1")) "40")
|
|
(dom-dispatch (dom-query-by-id "b1") "click" nil)
|
|
(assert= (dom-text-content (dom-query-by-id "b1")) "42")
|
|
))
|
|
(deftest "put null into attribute removes it"
|
|
(hs-cleanup!)
|
|
(let ((_el-d1 (dom-create-element "div")))
|
|
(dom-set-attr _el-d1 "id" "d1")
|
|
(dom-set-attr _el-d1 "_" "on click put null into @foo")
|
|
(dom-set-attr _el-d1 "foo" "bar")
|
|
(dom-append (dom-body) _el-d1)
|
|
(hs-activate! _el-d1)
|
|
(assert= (dom-get-attr (dom-query-by-id "d1") "foo") "bar")
|
|
(dom-dispatch (dom-query-by-id "d1") "click" nil)
|
|
(assert (not (dom-has-attr? (dom-query-by-id "d1") "foo")))
|
|
))
|
|
(deftest "waits on promises"
|
|
(hs-cleanup!)
|
|
(let ((_el-d1 (dom-create-element "div")))
|
|
(dom-set-attr _el-d1 "id" "d1")
|
|
(dom-set-attr _el-d1 "_" "on click put promiseAString() 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")
|
|
))
|
|
)
|
|
|
|
;; ── reactive-properties (4 tests) ──
|
|
(defsuite "hs-upstream-reactive-properties"
|
|
(deftest "live block tracks property reads on plain objects"
|
|
(hs-cleanup!)
|
|
(let ((_el-output (dom-create-element "output")))
|
|
(dom-set-attr _el-output "_" "live put $config's label into me")
|
|
(dom-append (dom-body) _el-output)
|
|
(hs-activate! _el-output)
|
|
))
|
|
(deftest "nested property chain triggers on intermediate reassignment"
|
|
(hs-cleanup!)
|
|
(let ((_el-output (dom-create-element "output")))
|
|
(dom-set-attr _el-output "_" "when $data's inner's val changes put it into me")
|
|
(dom-append (dom-body) _el-output)
|
|
(hs-activate! _el-output)
|
|
))
|
|
(deftest "property change on DOM element triggers reactivity via setProperty"
|
|
(hs-cleanup!)
|
|
(let ((_el-prop-input (dom-create-element "input")) (_el-output (dom-create-element "output")))
|
|
(dom-set-attr _el-prop-input "id" "prop-input")
|
|
(dom-set-attr _el-prop-input "type" "text")
|
|
(dom-set-attr _el-prop-input "value" "start")
|
|
(dom-set-attr _el-output "_" "when #prop-input's value changes put it into me")
|
|
(dom-append (dom-body) _el-prop-input)
|
|
(dom-append (dom-body) _el-output)
|
|
(hs-activate! _el-output)
|
|
))
|
|
(deftest "setting a property on a plain object triggers reactivity"
|
|
(hs-cleanup!)
|
|
(let ((_el-output (dom-create-element "output")))
|
|
(dom-set-attr _el-output "_" "when ($obj's x + $obj's y) changes put it into me")
|
|
(dom-append (dom-body) _el-output)
|
|
(hs-activate! _el-output)
|
|
))
|
|
)
|
|
|
|
;; ── remove (19 tests) ──
|
|
(defsuite "hs-upstream-remove"
|
|
(deftest "can delete a property via 'of' form"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click set :obj to { a: 1, b: 2, c: 3 } then remove b of :obj then put :obj.a + ',' + (:obj.b is undefined) + ',' + :obj.c 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,true,3")
|
|
))
|
|
(deftest "can delete a property via dot notation"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click set :obj to { a: 1, b: 2, c: 3 } then remove :obj.b then put :obj.a + ',' + (:obj.b is undefined) + ',' + :obj.c 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,true,3")
|
|
))
|
|
(deftest "can filter class removal via the when clause"
|
|
(hs-cleanup!)
|
|
(let ((_el-trigger (dom-create-element "div")) (_el-d1 (dom-create-element "div")) (_el-d2 (dom-create-element "div")))
|
|
(dom-set-attr _el-trigger "id" "trigger")
|
|
(dom-set-attr _el-trigger "_" "on click remove .highlight from .item when it matches .old")
|
|
(dom-set-attr _el-d1 "id" "d1")
|
|
(dom-add-class _el-d1 "item")
|
|
(dom-add-class _el-d1 "old")
|
|
(dom-add-class _el-d1 "highlight")
|
|
(dom-set-attr _el-d2 "id" "d2")
|
|
(dom-add-class _el-d2 "item")
|
|
(dom-add-class _el-d2 "highlight")
|
|
(dom-append (dom-body) _el-trigger)
|
|
(dom-append (dom-body) _el-d1)
|
|
(dom-append (dom-body) _el-d2)
|
|
(hs-activate! _el-trigger)
|
|
(dom-dispatch (dom-query-by-id "trigger") "click" nil)
|
|
(assert (not (dom-has-class? (dom-query-by-id "d1") "highlight")))
|
|
(assert (dom-has-class? (dom-query-by-id "d2") "highlight"))
|
|
))
|
|
(deftest "can remove CSS properties"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click remove {color} from me")
|
|
(dom-set-attr _el-div "style" "color: red; font-weight: bold;")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
(dom-dispatch _el-div "click" nil)
|
|
))
|
|
(deftest "can remove a value from a set"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click set :s to ['a','b','c'] as Set then remove 'b' from :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 remove a value from an array"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click set :arr to [1,2,3,4] then remove 3 from :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,4")
|
|
))
|
|
(deftest "can remove class ref on a single div"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-add-class _el-div "foo")
|
|
(dom-set-attr _el-div "_" "on click remove .foo")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
(assert (dom-has-class? _el-div "foo"))
|
|
(dom-dispatch _el-div "click" nil)
|
|
(assert (not (dom-has-class? _el-div "foo")))
|
|
))
|
|
(deftest "can remove class ref on a single form"
|
|
(hs-cleanup!)
|
|
(let ((_el-form (dom-create-element "form")))
|
|
(dom-add-class _el-form "foo")
|
|
(dom-set-attr _el-form "_" "on click remove .foo")
|
|
(dom-append (dom-body) _el-form)
|
|
(hs-activate! _el-form)
|
|
(assert (dom-has-class? _el-form "foo"))
|
|
(dom-dispatch _el-form "click" nil)
|
|
(assert (not (dom-has-class? _el-form "foo")))
|
|
))
|
|
(deftest "can remove elements"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click remove me")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
(dom-dispatch _el-div "click" nil)
|
|
))
|
|
(deftest "can remove multiple CSS properties"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click remove {color; font-weight} from me")
|
|
(dom-set-attr _el-div "style" "color: red; font-weight: bold; opacity: 0.5;")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
(dom-dispatch _el-div "click" nil)
|
|
))
|
|
(deftest "can remove multiple class refs"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-add-class _el-div "foo")
|
|
(dom-add-class _el-div "bar")
|
|
(dom-add-class _el-div "doh")
|
|
(dom-set-attr _el-div "_" "on click remove .foo .bar")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
(assert (dom-has-class? _el-div "foo"))
|
|
(assert (dom-has-class? _el-div "bar"))
|
|
(assert (dom-has-class? _el-div "doh"))
|
|
(dom-dispatch _el-div "click" nil)
|
|
(assert (not (dom-has-class? _el-div "foo")))
|
|
(assert (not (dom-has-class? _el-div "bar")))
|
|
(assert (dom-has-class? _el-div "doh"))
|
|
))
|
|
(deftest "can remove non-class attributes"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click remove [@foo]")
|
|
(dom-set-attr _el-div "foo" "bar")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
(assert= (dom-get-attr _el-div "foo") "bar")
|
|
(dom-dispatch _el-div "click" nil)
|
|
(assert (not (dom-has-attr? _el-div "foo")))
|
|
))
|
|
(deftest "can remove other elements"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")) (_el-that (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click remove #that")
|
|
(dom-set-attr _el-that "id" "that")
|
|
(dom-append (dom-body) _el-div)
|
|
(dom-append (dom-body) _el-that)
|
|
(hs-activate! _el-div)
|
|
(dom-dispatch (nth (dom-query-all (dom-body) "div") 0) "click" nil)
|
|
))
|
|
(deftest "can remove parent element"
|
|
(hs-cleanup!)
|
|
(let ((_el-p1 (dom-create-element "div")) (_el-b1 (dom-create-element "button")))
|
|
(dom-set-attr _el-p1 "id" "p1")
|
|
(dom-set-attr _el-b1 "id" "b1")
|
|
(dom-set-attr _el-b1 "_" "on click remove my.parentElement")
|
|
(dom-append (dom-body) _el-p1)
|
|
(dom-append _el-p1 _el-b1)
|
|
(hs-activate! _el-b1)
|
|
(dom-dispatch (dom-query-by-id "b1") "click" nil)
|
|
))
|
|
(deftest "can remove query refs from specific things"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")) (_el-d1 (dom-create-element "div")) (_el-p (dom-create-element "p")) (_el-p3 (dom-create-element "p")))
|
|
(dom-set-attr _el-d1 "id" "d1")
|
|
(dom-set-attr _el-d1 "_" "on click remove <p/> from me")
|
|
(dom-set-inner-html _el-p "foo")
|
|
(dom-set-inner-html _el-p3 "doh")
|
|
(dom-append (dom-body) _el-div)
|
|
(dom-append _el-div _el-d1)
|
|
(dom-append _el-d1 _el-p)
|
|
(dom-append _el-div _el-p3)
|
|
(hs-activate! _el-d1)
|
|
(dom-dispatch (dom-query-by-id "d1") "click" nil)
|
|
))
|
|
(deftest "can splice an array element by index"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click set :arr to [1,2,3,4] then remove :arr[1] 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,3,4")
|
|
))
|
|
(deftest "can splice an array with a negative index"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click set :arr to [1,2,3,4] then remove :arr[-1] 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")
|
|
))
|
|
(deftest "can target another div for class ref"
|
|
(hs-cleanup!)
|
|
(let ((_el-bar (dom-create-element "div")) (_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-bar "id" "bar")
|
|
(dom-add-class _el-bar "foo")
|
|
(dom-set-attr _el-div "_" "on click remove .foo from #bar")
|
|
(dom-append (dom-body) _el-bar)
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
(assert (dom-has-class? (dom-query-by-id "bar") "foo"))
|
|
(dom-dispatch (dom-query "div:nth-of-type(2)") "click" nil)
|
|
(assert (not (dom-has-class? (dom-query-by-id "bar") "foo")))
|
|
))
|
|
(deftest "remove on a property whose value is a DOM node still detaches the node"
|
|
(hs-cleanup!)
|
|
(let ((_el-parent (dom-create-element "div")) (_el-child (dom-create-element "span")) (_el-button (dom-create-element "button")))
|
|
(dom-set-attr _el-parent "id" "parent")
|
|
(dom-set-attr _el-child "id" "child")
|
|
(dom-set-inner-html _el-child "kept")
|
|
(dom-set-attr _el-button "_" "on click set :wrapper to { el: #child } then remove :wrapper.el")
|
|
(dom-set-inner-html _el-button "go")
|
|
(dom-append (dom-body) _el-parent)
|
|
(dom-append _el-parent _el-child)
|
|
(dom-append (dom-body) _el-button)
|
|
(hs-activate! _el-button)
|
|
(dom-dispatch _el-button "click" nil)
|
|
))
|
|
)
|
|
|
|
;; ── repeat (30 tests) ──
|
|
(defsuite "hs-upstream-repeat"
|
|
(deftest "basic for loop with null works"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click repeat for x in null put x at end of me end")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
(dom-dispatch _el-div "click" nil)
|
|
(assert= (dom-text-content _el-div) "")
|
|
))
|
|
(deftest "basic for loop works"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click repeat for x in [1, 2, 3] put x at end of me end")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
(dom-dispatch _el-div "click" nil)
|
|
(assert= (dom-text-content _el-div) "123")
|
|
))
|
|
(deftest "basic in loop works"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click repeat in [1, 2, 3] put it at end of me end")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
(dom-dispatch _el-div "click" nil)
|
|
(assert= (dom-text-content _el-div) "123")
|
|
))
|
|
(deftest "basic property for loop works"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click set x to {foo:1, bar:2, baz:3} then for prop in x put x[prop] at end of me end")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
(dom-dispatch _el-div "click" nil)
|
|
(assert= (dom-text-content _el-div) "123")
|
|
))
|
|
(deftest "basic raw for loop with null works"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click for x in null put x at end of me end")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
(dom-dispatch _el-div "click" nil)
|
|
(assert= (dom-text-content _el-div) "")
|
|
))
|
|
(deftest "basic raw for loop works"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click for x in [1, 2, 3] put x at end of me end")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
(dom-dispatch _el-div "click" nil)
|
|
(assert= (dom-text-content _el-div) "123")
|
|
))
|
|
(deftest "basic times loop works"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click repeat 3 times put \"a\" at end of me end")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
(dom-dispatch _el-div "click" nil)
|
|
(assert= (dom-text-content _el-div) "aaa")
|
|
))
|
|
(deftest "bottom-tested loop always runs at least once"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click set x to 0 then repeat then set x to x + 1 until true end put x 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")
|
|
))
|
|
(deftest "bottom-tested repeat until"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click set x to 0 then repeat then set x to x + 1 until x is 3 end put x 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 "bottom-tested repeat while"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click set x to 0 then repeat then set x to x + 1 while x < 3 end put x 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 "break exits a for-in loop"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click repeat for x in [1, 2, 3, 4, 5] if x is 4 break end put x at end of me end")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
(dom-dispatch _el-div "click" nil)
|
|
(assert= (dom-text-content _el-div) "123")
|
|
))
|
|
(deftest "break exits a simple repeat loop"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click set x to 0 then repeat 10 times set x to x + 1 then if x is 3 break end end put x into me then")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
(dom-dispatch _el-div "click" nil)
|
|
(assert= (dom-text-content _el-div) "3")
|
|
))
|
|
(deftest "break exits a while loop"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click set x to 0 then repeat while x < 100 then set x to x + 1 then if x is 5 break end end put x into me then")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
(dom-dispatch _el-div "click" nil)
|
|
(assert= (dom-text-content _el-div) "5")
|
|
))
|
|
(deftest "can nest loops"
|
|
(hs-cleanup!)
|
|
(guard (_e (true nil)) (eval-expr-cek (hs-to-sx (hs-compile "def sprayInto(elt) for x in [1, 2, 3] for y in [1, 2, 3] put x * y at end of elt end end end"))))
|
|
(guard (_e (true nil)) (eval-expr-cek (hs-to-sx (hs-compile "def sprayInto(elt) for x in [1, 2, 3] for y in [1, 2, 3] put x * y at end of elt end end end"))))
|
|
(let ((_el-d1 (dom-create-element "div")))
|
|
(dom-set-attr _el-d1 "id" "d1")
|
|
(dom-set-attr _el-d1 "_" "on click call sprayInto(me)")
|
|
(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")) "123246369")
|
|
))
|
|
(deftest "continue skips rest of iteration in simple repeat loop"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click repeat for x in [1, 2, 3, 4, 5] if x is 3 continue end put x at end of me end")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
(dom-dispatch _el-div "click" nil)
|
|
(assert= (dom-text-content _el-div) "1245")
|
|
))
|
|
(deftest "for loop over undefined skips without error"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click repeat for x in doesNotExist put x at end of me end put \"done\" into me")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
(dom-dispatch _el-div "click" nil)
|
|
(assert= (dom-text-content _el-div) "done")
|
|
))
|
|
(deftest "index syntax works"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click repeat for x in [\"a\", \"ab\", \"abc\"] index i then put x + i at end of me end")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
(dom-dispatch _el-div "click" nil)
|
|
(assert= (dom-text-content _el-div) "a0ab1abc2")
|
|
))
|
|
(deftest "indexed by syntax works"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click repeat for x in [\"a\", \"ab\", \"abc\"] indexed by i then put x + i at end of me end")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
(dom-dispatch _el-div "click" nil)
|
|
(assert= (dom-text-content _el-div) "a0ab1abc2")
|
|
))
|
|
(deftest "loop break works"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click repeat 2 times for x in ['A', 'B', 'C', 'D'] if x is 'C' then break end put x at end of me end end")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
(dom-dispatch _el-div "click" nil)
|
|
(assert= (dom-text-content _el-div) "ABAB")
|
|
))
|
|
(deftest "loop continue works"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click repeat 2 times for x in ['A', 'B', 'C', 'D'] if (x != 'D') then put 'success ' + x + '. ' at end of me then continue then put 'FAIL!!. ' at end of me end put 'expected D. ' at end of me end end")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
(dom-dispatch _el-div "click" nil)
|
|
(assert= (dom-text-content _el-div) "success A. success B. success C. expected D. success A. success B. success C. expected D. ")
|
|
))
|
|
(deftest "only executes the init expression once"
|
|
(hs-cleanup!)
|
|
(guard (_e (true nil)) (eval-expr-cek (hs-to-sx (hs-compile "def getArray() set window.called to (window.called or 0) + 1 return [1, 2, 3] end"))))
|
|
(guard (_e (true nil)) (eval-expr-cek (hs-to-sx (hs-compile "def getArray() set window.called to (window.called or 0) + 1 return [1, 2, 3] end"))))
|
|
(let ((_el-d1 (dom-create-element "div")))
|
|
(dom-set-attr _el-d1 "id" "d1")
|
|
(dom-set-attr _el-d1 "_" "on click for x in getArray() put x into my.innerHTML end")
|
|
(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")) "3")
|
|
))
|
|
(deftest "repeat forever works"
|
|
(hs-cleanup!)
|
|
(guard (_e (true nil)) (eval-expr-cek (hs-to-sx (hs-compile "def repeatForeverWithReturn() set retVal to 0 repeat forever set retVal to retVal + 1 if retVal == 5 then return retVal end end end"))))
|
|
(guard (_e (true nil)) (eval-expr-cek (hs-to-sx (hs-compile "def repeatForeverWithReturn() set retVal to 0 repeat forever set retVal to retVal + 1 if retVal == 5 then return retVal end end end"))))
|
|
(let ((_el-d1 (dom-create-element "div")))
|
|
(dom-set-attr _el-d1 "id" "d1")
|
|
(dom-set-attr _el-d1 "_" "on click put repeatForeverWithReturn() into my.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")) "5")
|
|
))
|
|
(deftest "repeat forever works w/o keyword"
|
|
(hs-cleanup!)
|
|
(guard (_e (true nil)) (eval-expr-cek (hs-to-sx (hs-compile "def repeatForeverWithReturn() set retVal to 0 repeat set retVal to retVal + 1 if retVal == 5 then return retVal end end end"))))
|
|
(guard (_e (true nil)) (eval-expr-cek (hs-to-sx (hs-compile "def repeatForeverWithReturn() set retVal to 0 repeat set retVal to retVal + 1 if retVal == 5 then return retVal end end end"))))
|
|
(let ((_el-d1 (dom-create-element "div")))
|
|
(dom-set-attr _el-d1 "id" "d1")
|
|
(dom-set-attr _el-d1 "_" "on click put repeatForeverWithReturn() into my.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")) "5")
|
|
))
|
|
(deftest "times loop with expression works"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click repeat 3 + 3 times put \"a\" at end of me end")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
(dom-dispatch _el-div "click" nil)
|
|
(assert= (dom-text-content _el-div) "aaaaaa")
|
|
))
|
|
(deftest "until event keyword works"
|
|
(hs-cleanup!)
|
|
(guard (_e (true nil)) (eval-expr-cek (hs-to-sx (hs-compile "def repeatUntilTest() repeat until event click from #untilTest wait 2ms end return 42 end"))))
|
|
(guard (_e (true nil)) (eval-expr-cek (hs-to-sx (hs-compile "def repeatUntilTest() repeat until event click from #untilTest wait 2ms end return 42 end"))))
|
|
(let ((_el-untilTest (dom-create-element "div")))
|
|
(dom-set-attr _el-untilTest "id" "untilTest")
|
|
(dom-append (dom-body) _el-untilTest)
|
|
(dom-dispatch (dom-query-by-id "untilTest") "click" nil)
|
|
))
|
|
(deftest "until keyword works"
|
|
(hs-cleanup!)
|
|
(guard (_e (true nil)) (eval-expr-cek (hs-to-sx (hs-compile "def repeatUntilTest() set retVal to 0 repeat until retVal == 5 set retVal to retVal + 1 end return retVal end"))))
|
|
(guard (_e (true nil)) (eval-expr-cek (hs-to-sx (hs-compile "def repeatUntilTest() set retVal to 0 repeat until retVal == 5 set retVal to retVal + 1 end return retVal end"))))
|
|
(let ((_el-d1 (dom-create-element "div")))
|
|
(dom-set-attr _el-d1 "id" "d1")
|
|
(dom-set-attr _el-d1 "_" "on click put repeatUntilTest() into my.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")) "5")
|
|
))
|
|
(deftest "waiting in for loop works"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click repeat for x in [1, 2, 3] log me then put x at end of me then wait 1ms end")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
(dom-dispatch _el-div "click" nil)
|
|
(assert= (dom-text-content _el-div) "123")
|
|
))
|
|
(deftest "waiting in raw for loop works"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click for x in [1, 2, 3] put x at end of me then wait 1ms end")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
(dom-dispatch _el-div "click" nil)
|
|
(assert= (dom-text-content _el-div) "123")
|
|
))
|
|
(deftest "where clause can use the for loop variable name"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click set :items to [{name:'a', val:5}, {name:'b', val:15}, {name:'c', val:25}] then repeat for x in :items where x.val > 10 then put x.name at end of me end")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
(dom-dispatch _el-div "click" nil)
|
|
(assert= (dom-text-content _el-div) "bc")
|
|
))
|
|
(deftest "while keyword works"
|
|
(hs-cleanup!)
|
|
(guard (_e (true nil)) (eval-expr-cek (hs-to-sx (hs-compile "def repeatWhileTest() set retVal to 0 repeat while retVal < 5 set retVal to retVal + 1 end return retVal end"))))
|
|
(guard (_e (true nil)) (eval-expr-cek (hs-to-sx (hs-compile "def repeatWhileTest() set retVal to 0 repeat while retVal < 5 set retVal to retVal + 1 end return retVal end"))))
|
|
(let ((_el-d1 (dom-create-element "div")))
|
|
(dom-set-attr _el-d1 "id" "d1")
|
|
(dom-set-attr _el-d1 "_" "on click put repeatWhileTest() into my.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")) "5")
|
|
))
|
|
)
|
|
|
|
;; ── reset (8 tests) ──
|
|
(defsuite "hs-upstream-reset"
|
|
(deftest "can reset a checkbox"
|
|
(hs-cleanup!)
|
|
(let ((_el-cb1 (dom-create-element "input")) (_el-button (dom-create-element "button")))
|
|
(dom-set-attr _el-cb1 "id" "cb1")
|
|
(dom-set-attr _el-cb1 "type" "checkbox")
|
|
(dom-set-attr _el-cb1 "checked" "")
|
|
(dom-set-attr _el-button "_" "on click reset #cb1")
|
|
(dom-set-inner-html _el-button "Reset")
|
|
(dom-append (dom-body) _el-cb1)
|
|
(dom-append (dom-body) _el-button)
|
|
(hs-activate! _el-button)
|
|
(dom-set-prop (dom-query-by-id "cb1") "checked" false)
|
|
(dom-dispatch (dom-query-by-id "cb1") "change" nil)
|
|
(assert (not (dom-get-prop (dom-query-by-id "cb1") "checked")))
|
|
(dom-dispatch _el-button "click" nil)
|
|
(assert (dom-get-prop (dom-query-by-id "cb1") "checked"))
|
|
))
|
|
(deftest "can reset a form"
|
|
(hs-cleanup!)
|
|
(let ((_el-f1 (dom-create-element "form")) (_el-t1 (dom-create-element "input")) (_el-button (dom-create-element "button")) (_el-rst (dom-create-element "button")))
|
|
(dom-set-attr _el-f1 "id" "f1")
|
|
(dom-set-attr _el-t1 "id" "t1")
|
|
(dom-set-attr _el-t1 "type" "text")
|
|
(dom-set-attr _el-t1 "value" "original")
|
|
(dom-set-attr _el-button "_" "on click set #t1's value to 'changed'")
|
|
(dom-set-attr _el-button "type" "button")
|
|
(dom-set-inner-html _el-button "Change")
|
|
(dom-set-attr _el-rst "id" "rst")
|
|
(dom-set-attr _el-rst "_" "on click reset #f1")
|
|
(dom-set-attr _el-rst "type" "button")
|
|
(dom-set-inner-html _el-rst "Reset")
|
|
(dom-append (dom-body) _el-f1)
|
|
(dom-append _el-f1 _el-t1)
|
|
(dom-append _el-f1 _el-button)
|
|
(dom-append _el-f1 _el-rst)
|
|
(hs-activate! _el-button)
|
|
(hs-activate! _el-rst)
|
|
(dom-set-prop (dom-query-by-id "t1") "value" "changed")
|
|
(dom-dispatch (dom-query-by-id "t1") "input" nil)
|
|
(assert= (dom-get-prop (dom-query-by-id "t1") "value") "changed")
|
|
(dom-dispatch (dom-query-by-id "rst") "click" nil)
|
|
(assert= (dom-get-prop (dom-query-by-id "t1") "value") "original")
|
|
))
|
|
(deftest "can reset a select"
|
|
(hs-cleanup!)
|
|
(let ((_el-sel1 (dom-create-element "select")) (_el-option (dom-create-element "option")) (_el-option2 (dom-create-element "option")) (_el-option3 (dom-create-element "option")) (_el-button (dom-create-element "button")))
|
|
(dom-set-attr _el-sel1 "id" "sel1")
|
|
(dom-set-attr _el-option "value" "a")
|
|
(dom-set-inner-html _el-option "A")
|
|
(dom-set-attr _el-option2 "value" "b")
|
|
(dom-set-attr _el-option2 "selected" "")
|
|
(dom-set-inner-html _el-option2 "B")
|
|
(dom-set-attr _el-option3 "value" "c")
|
|
(dom-set-inner-html _el-option3 "C")
|
|
(dom-set-attr _el-button "_" "on click reset #sel1")
|
|
(dom-set-inner-html _el-button "Reset")
|
|
(dom-append (dom-body) _el-sel1)
|
|
(dom-append _el-sel1 _el-option)
|
|
(dom-append _el-sel1 _el-option2)
|
|
(dom-append _el-sel1 _el-option3)
|
|
(dom-append (dom-body) _el-button)
|
|
(hs-activate! _el-button)
|
|
(dom-set-prop (dom-query-by-id "sel1") "value" "c")
|
|
(dom-dispatch (dom-query-by-id "sel1") "change" nil)
|
|
(assert= (dom-get-prop (dom-query-by-id "sel1") "value") "c")
|
|
(dom-dispatch _el-button "click" nil)
|
|
(assert= (dom-get-prop (dom-query-by-id "sel1") "value") "b")
|
|
))
|
|
(deftest "can reset a text input to defaultValue"
|
|
(hs-cleanup!)
|
|
(let ((_el-t3 (dom-create-element "input")) (_el-button (dom-create-element "button")))
|
|
(dom-set-attr _el-t3 "id" "t3")
|
|
(dom-set-attr _el-t3 "type" "text")
|
|
(dom-set-attr _el-t3 "value" "hello")
|
|
(dom-set-attr _el-button "_" "on click reset #t3")
|
|
(dom-set-inner-html _el-button "Reset")
|
|
(dom-append (dom-body) _el-t3)
|
|
(dom-append (dom-body) _el-button)
|
|
(hs-activate! _el-button)
|
|
(dom-set-prop (dom-query-by-id "t3") "value" "goodbye")
|
|
(dom-dispatch (dom-query-by-id "t3") "input" nil)
|
|
(assert= (dom-get-prop (dom-query-by-id "t3") "value") "goodbye")
|
|
(dom-dispatch _el-button "click" nil)
|
|
(assert= (dom-get-prop (dom-query-by-id "t3") "value") "hello")
|
|
))
|
|
(deftest "can reset a textarea"
|
|
(hs-cleanup!)
|
|
(let ((_el-ta1 (dom-create-element "textarea")) (_el-button (dom-create-element "button")))
|
|
(dom-set-attr _el-ta1 "id" "ta1")
|
|
(dom-set-inner-html _el-ta1 "original text")
|
|
(dom-set-attr _el-button "_" "on click reset #ta1")
|
|
(dom-set-inner-html _el-button "Reset")
|
|
(dom-append (dom-body) _el-ta1)
|
|
(dom-append (dom-body) _el-button)
|
|
(hs-activate! _el-button)
|
|
(dom-set-prop (dom-query-by-id "ta1") "value" "new text")
|
|
(dom-dispatch (dom-query-by-id "ta1") "input" nil)
|
|
(assert= (dom-get-prop (dom-query-by-id "ta1") "value") "new text")
|
|
(dom-dispatch _el-button "click" nil)
|
|
(assert= (dom-get-prop (dom-query-by-id "ta1") "value") "original text")
|
|
))
|
|
(deftest "can reset an unchecked checkbox"
|
|
(hs-cleanup!)
|
|
(let ((_el-cb2 (dom-create-element "input")) (_el-button (dom-create-element "button")))
|
|
(dom-set-attr _el-cb2 "id" "cb2")
|
|
(dom-set-attr _el-cb2 "type" "checkbox")
|
|
(dom-set-attr _el-button "_" "on click reset #cb2")
|
|
(dom-set-inner-html _el-button "Reset")
|
|
(dom-append (dom-body) _el-cb2)
|
|
(dom-append (dom-body) _el-button)
|
|
(hs-activate! _el-button)
|
|
(dom-set-prop (dom-query-by-id "cb2") "checked" true)
|
|
(dom-dispatch (dom-query-by-id "cb2") "change" nil)
|
|
(assert (dom-get-prop (dom-query-by-id "cb2") "checked"))
|
|
(dom-dispatch _el-button "click" nil)
|
|
(assert (not (dom-get-prop (dom-query-by-id "cb2") "checked")))
|
|
))
|
|
(deftest "can reset multiple inputs"
|
|
(hs-cleanup!)
|
|
(let ((_el-input (dom-create-element "input")) (_el-input1 (dom-create-element "input")) (_el-button (dom-create-element "button")))
|
|
(dom-add-class _el-input "resettable")
|
|
(dom-set-attr _el-input "type" "text")
|
|
(dom-set-attr _el-input "value" "one")
|
|
(dom-add-class _el-input1 "resettable")
|
|
(dom-set-attr _el-input1 "type" "text")
|
|
(dom-set-attr _el-input1 "value" "two")
|
|
(dom-set-attr _el-button "_" "on click reset .resettable")
|
|
(dom-set-inner-html _el-button "Reset")
|
|
(dom-append (dom-body) _el-input)
|
|
(dom-append (dom-body) _el-input1)
|
|
(dom-append (dom-body) _el-button)
|
|
(hs-activate! _el-button)
|
|
(dom-set-prop (nth (dom-query-all (dom-body) ".resettable") 0) "value" "changed1")
|
|
(dom-dispatch (nth (dom-query-all (dom-body) ".resettable") 0) "input" nil)
|
|
(dom-set-prop (let ((_all (dom-query-all (dom-body) ".resettable"))) (nth _all (- (len _all) 1))) "value" "changed2")
|
|
(dom-dispatch (let ((_all (dom-query-all (dom-body) ".resettable"))) (nth _all (- (len _all) 1))) "input" nil)
|
|
(dom-dispatch _el-button "click" nil)
|
|
(assert= (dom-get-prop (nth (dom-query-all (dom-body) ".resettable") 0) "value") "one")
|
|
(assert= (dom-get-prop (let ((_all (dom-query-all (dom-body) ".resettable"))) (nth _all (- (len _all) 1))) "value") "two")
|
|
))
|
|
(deftest "reset with no target resets me (form)"
|
|
(hs-cleanup!)
|
|
(let ((_el-form (dom-create-element "form")) (_el-t2 (dom-create-element "input")))
|
|
(dom-set-attr _el-form "_" "on custom reset")
|
|
(dom-set-attr _el-t2 "id" "t2")
|
|
(dom-set-attr _el-t2 "type" "text")
|
|
(dom-set-attr _el-t2 "value" "default")
|
|
(dom-append (dom-body) _el-form)
|
|
(dom-append _el-form _el-t2)
|
|
(hs-activate! _el-form)
|
|
(dom-set-prop (dom-query-by-id "t2") "value" "modified")
|
|
(dom-dispatch (dom-query-by-id "t2") "input" nil)
|
|
(assert= (dom-get-prop (dom-query-by-id "t2") "value") "modified")
|
|
(dom-dispatch _el-form "custom" nil)
|
|
(assert= (dom-get-prop (dom-query-by-id "t2") "value") "default")
|
|
))
|
|
)
|
|
|
|
;; ── resize (3 tests) ──
|
|
(defsuite "hs-upstream-resize"
|
|
(deftest "fires when element is resized"
|
|
(hs-cleanup!)
|
|
(let ((_el-box (dom-create-element "div")) (_el-out (dom-create-element "div")))
|
|
(dom-set-attr _el-box "id" "box")
|
|
(dom-set-attr _el-box "_" "on resize put detail.width into #out")
|
|
(dom-set-attr _el-box "style" "width:100px; height:100px")
|
|
(dom-set-attr _el-out "id" "out")
|
|
(dom-append (dom-body) _el-box)
|
|
(dom-append (dom-body) _el-out)
|
|
(hs-activate! _el-box)
|
|
(host-set! (host-get (dom-query-by-id "box") "style") "width" "200px")
|
|
(assert= (dom-text-content (dom-query-by-id "out")) "200")
|
|
))
|
|
(deftest "provides height in detail"
|
|
(hs-cleanup!)
|
|
(let ((_el-box (dom-create-element "div")) (_el-out (dom-create-element "div")))
|
|
(dom-set-attr _el-box "id" "box")
|
|
(dom-set-attr _el-box "_" "on resize put detail.height into #out")
|
|
(dom-set-attr _el-box "style" "width:100px; height:100px")
|
|
(dom-set-attr _el-out "id" "out")
|
|
(dom-append (dom-body) _el-box)
|
|
(dom-append (dom-body) _el-out)
|
|
(hs-activate! _el-box)
|
|
(host-set! (host-get (dom-query-by-id "box") "style") "height" "300px")
|
|
(assert= (dom-text-content (dom-query-by-id "out")) "300")
|
|
))
|
|
(deftest "works with from clause"
|
|
(hs-cleanup!)
|
|
(let ((_el-box (dom-create-element "div")) (_el-out (dom-create-element "div")))
|
|
(dom-set-attr _el-box "id" "box")
|
|
(dom-set-attr _el-box "style" "width:100px; height:100px")
|
|
(dom-set-attr _el-out "id" "out")
|
|
(dom-set-attr _el-out "_" "on resize from #box put detail.width into me")
|
|
(dom-append (dom-body) _el-box)
|
|
(dom-append (dom-body) _el-out)
|
|
(hs-activate! _el-out)
|
|
(host-set! (host-get (dom-query-by-id "box") "style") "width" "150px")
|
|
(assert= (dom-text-content (dom-query-by-id "out")) "150")
|
|
))
|
|
)
|
|
|
|
;; ── scroll (8 tests) ──
|
|
(defsuite "hs-upstream-scroll"
|
|
(deftest "can scroll by without direction (defaults to down)"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")) (_el-div1 (dom-create-element "div")))
|
|
(dom-set-attr _el-div "style" "height: 5000px")
|
|
(dom-set-attr _el-div1 "_" "on click scroll by 200px")
|
|
(dom-append (dom-body) _el-div)
|
|
(dom-append (dom-body) _el-div1)
|
|
(hs-activate! _el-div1)
|
|
(dom-dispatch (dom-query "div:nth-of-type(2)") "click" nil)
|
|
))
|
|
(deftest "can scroll container by amount"
|
|
(hs-cleanup!)
|
|
(let ((_el-box (dom-create-element "div")) (_el-div (dom-create-element "div")) (_el-go (dom-create-element "button")))
|
|
(dom-set-attr _el-box "id" "box")
|
|
(dom-set-attr _el-box "style" "height: 100px; overflow: auto")
|
|
(dom-set-attr _el-div "style" "height: 1000px")
|
|
(dom-set-inner-html _el-div "tall")
|
|
(dom-set-attr _el-go "id" "go")
|
|
(dom-set-attr _el-go "_" "on click scroll #box down by 200px")
|
|
(dom-set-inner-html _el-go "go")
|
|
(dom-append (dom-body) _el-box)
|
|
(dom-append _el-box _el-div)
|
|
(dom-append (dom-body) _el-go)
|
|
(hs-activate! _el-go)
|
|
(dom-dispatch (dom-query-by-id "go") "click" nil)
|
|
))
|
|
(deftest "can scroll down by amount"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")) (_el-div1 (dom-create-element "div")))
|
|
(dom-set-attr _el-div "style" "height: 5000px")
|
|
(dom-set-attr _el-div1 "_" "on click scroll down by 300px")
|
|
(dom-append (dom-body) _el-div)
|
|
(dom-append (dom-body) _el-div1)
|
|
(hs-activate! _el-div1)
|
|
(dom-dispatch (dom-query "div:nth-of-type(2)") "click" nil)
|
|
))
|
|
(deftest "can scroll left by amount"
|
|
(hs-cleanup!)
|
|
(let ((_el-box (dom-create-element "div")) (_el-div (dom-create-element "div")) (_el-go (dom-create-element "button")))
|
|
(dom-set-attr _el-box "id" "box")
|
|
(dom-set-attr _el-box "style" "width: 100px; overflow: auto; white-space: nowrap")
|
|
(dom-set-attr _el-div "style" "width: 5000px; height: 50px")
|
|
(dom-set-inner-html _el-div "wide")
|
|
(dom-set-attr _el-go "id" "go")
|
|
(dom-set-attr _el-go "_" "on click scroll #box right by 300px")
|
|
(dom-set-inner-html _el-go "go")
|
|
(dom-append (dom-body) _el-box)
|
|
(dom-append _el-box _el-div)
|
|
(dom-append (dom-body) _el-go)
|
|
(hs-activate! _el-go)
|
|
(dom-dispatch (dom-query-by-id "go") "click" nil)
|
|
))
|
|
(deftest "can scroll to an element"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")) (_el-target (dom-create-element "div")) (_el-div2 (dom-create-element "div")))
|
|
(dom-set-attr _el-div "style" "height: 2000px")
|
|
(dom-set-attr _el-target "id" "target")
|
|
(dom-set-inner-html _el-target "Target")
|
|
(dom-set-attr _el-div2 "_" "on click scroll to #target")
|
|
(dom-append (dom-body) _el-div)
|
|
(dom-append (dom-body) _el-target)
|
|
(dom-append (dom-body) _el-div2)
|
|
(hs-activate! _el-div2)
|
|
(dom-dispatch (dom-query "div:nth-of-type(3)") "click" nil)
|
|
))
|
|
(deftest "can scroll to element in container"
|
|
(hs-cleanup!)
|
|
(let ((_el-box (dom-create-element "div")) (_el-div (dom-create-element "div")) (_el-item (dom-create-element "div")) (_el-go (dom-create-element "button")))
|
|
(dom-set-attr _el-box "id" "box")
|
|
(dom-set-attr _el-box "style" "height: 100px; overflow: auto")
|
|
(dom-set-attr _el-div "style" "height: 500px")
|
|
(dom-set-inner-html _el-div "spacer")
|
|
(dom-set-attr _el-item "id" "item")
|
|
(dom-set-inner-html _el-item "target")
|
|
(dom-set-attr _el-go "id" "go")
|
|
(dom-set-attr _el-go "_" "on click scroll to #item in #box")
|
|
(dom-set-inner-html _el-go "go")
|
|
(dom-append (dom-body) _el-box)
|
|
(dom-append _el-box _el-div)
|
|
(dom-append _el-box _el-item)
|
|
(dom-append (dom-body) _el-go)
|
|
(hs-activate! _el-go)
|
|
(dom-dispatch (dom-query-by-id "go") "click" nil)
|
|
))
|
|
(deftest "can scroll to top of element"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")) (_el-target (dom-create-element "div")) (_el-div2 (dom-create-element "div")))
|
|
(dom-set-attr _el-div "style" "height: 2000px")
|
|
(dom-set-attr _el-target "id" "target")
|
|
(dom-set-attr _el-target "style" "height: 200px")
|
|
(dom-set-inner-html _el-target "Target")
|
|
(dom-set-attr _el-div2 "_" "on click scroll to the top of #target")
|
|
(dom-append (dom-body) _el-div)
|
|
(dom-append (dom-body) _el-target)
|
|
(dom-append (dom-body) _el-div2)
|
|
(hs-activate! _el-div2)
|
|
(dom-dispatch (dom-query "div:nth-of-type(3)") "click" nil)
|
|
))
|
|
(deftest "can scroll up by amount"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")) (_el-div1 (dom-create-element "div")))
|
|
(dom-set-attr _el-div "style" "height: 5000px")
|
|
(dom-set-attr _el-div1 "_" "on click scroll up by 100px")
|
|
(dom-append (dom-body) _el-div)
|
|
(dom-append (dom-body) _el-div1)
|
|
(hs-activate! _el-div1)
|
|
(dom-dispatch (dom-query "div:nth-of-type(2)") "click" nil)
|
|
))
|
|
)
|
|
|
|
;; ── select (4 tests) ──
|
|
(defsuite "hs-upstream-select"
|
|
(deftest "returns selected text"
|
|
(hs-cleanup!)
|
|
(let ((_el-text (dom-create-element "p")) (_el-button (dom-create-element "button")) (_el-out (dom-create-element "div")))
|
|
(dom-set-attr _el-text "id" "text")
|
|
(dom-set-inner-html _el-text "Hello World")
|
|
(dom-set-attr _el-button "_" "on click put the selection into #out")
|
|
(dom-set-inner-html _el-button "Get")
|
|
(dom-set-attr _el-out "id" "out")
|
|
(dom-append (dom-body) _el-text)
|
|
(dom-append (dom-body) _el-button)
|
|
(dom-append (dom-body) _el-out)
|
|
(hs-activate! _el-button)
|
|
(host-set! (host-global "window") "__test_selection" "Hello")
|
|
(dom-dispatch _el-button "click" nil)
|
|
(assert= (dom-text-content (dom-query-by-id "out")) "Hello")
|
|
))
|
|
(deftest "selects implicit me"
|
|
(hs-cleanup!)
|
|
(let ((_el-inp (dom-create-element "input")))
|
|
(dom-set-attr _el-inp "id" "inp")
|
|
(dom-set-attr _el-inp "_" "on click select")
|
|
(dom-set-attr _el-inp "value" "test")
|
|
(dom-append (dom-body) _el-inp)
|
|
(hs-activate! _el-inp)
|
|
(dom-dispatch (dom-query-by-id "inp") "click" nil)
|
|
))
|
|
(deftest "selects text in a textarea"
|
|
(hs-cleanup!)
|
|
(let ((_el-ta (dom-create-element "textarea")) (_el-button (dom-create-element "button")))
|
|
(dom-set-attr _el-ta "id" "ta")
|
|
(dom-set-inner-html _el-ta "some text")
|
|
(dom-set-attr _el-button "_" "on click select #ta")
|
|
(dom-set-inner-html _el-button "Select")
|
|
(dom-append (dom-body) _el-ta)
|
|
(dom-append (dom-body) _el-button)
|
|
(hs-activate! _el-button)
|
|
(dom-dispatch _el-button "click" nil)
|
|
))
|
|
(deftest "selects text in an input"
|
|
(hs-cleanup!)
|
|
(let ((_el-inp (dom-create-element "input")) (_el-button (dom-create-element "button")))
|
|
(dom-set-attr _el-inp "id" "inp")
|
|
(dom-set-attr _el-inp "value" "hello world")
|
|
(dom-set-attr _el-button "_" "on click select #inp")
|
|
(dom-set-inner-html _el-button "Select")
|
|
(dom-append (dom-body) _el-inp)
|
|
(dom-append (dom-body) _el-button)
|
|
(hs-activate! _el-button)
|
|
(dom-dispatch _el-button "click" nil)
|
|
))
|
|
)
|
|
|
|
;; ── send (8 tests) ──
|
|
(defsuite "hs-upstream-send"
|
|
(deftest "can reference sender in events"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")) (_el-bar (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click log 0 send foo to #bar log 3")
|
|
(dom-set-attr _el-bar "id" "bar")
|
|
(dom-set-attr _el-bar "_" "on foo add .foo-sent to sender log 1, me, sender")
|
|
(dom-append (dom-body) _el-div)
|
|
(dom-append (dom-body) _el-bar)
|
|
(hs-activate! _el-div)
|
|
(hs-activate! _el-bar)
|
|
(dom-dispatch (nth (dom-query-all (dom-body) "div") 0) "click" nil)
|
|
(assert (dom-has-class? (nth (dom-query-all (dom-body) "div") 0) "foo-sent"))
|
|
))
|
|
(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)
|
|
(assert (not (dom-has-class? (dom-query-by-id "bar") "foo-sent")))
|
|
(dom-dispatch (nth (dom-query-all (dom-body) "div") 0) "click" nil)
|
|
(assert (dom-has-class? (dom-query-by-id "bar") "foo-sent"))
|
|
))
|
|
(deftest "can send events to any expression"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")) (_el-bar (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "def bar return #bar 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)
|
|
(assert (not (dom-has-class? (dom-query-by-id "bar") "foo-sent")))
|
|
(dom-dispatch (nth (dom-query-all (dom-body) "div") 0) "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 (nth (dom-query-all (dom-body) "div") 0) "click" nil)
|
|
(assert= (dom-text-content (dom-query-by-id "bar")) "42")
|
|
))
|
|
(deftest "can send events with colons"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")) (_el-bar (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click send foo:bar to #bar")
|
|
(dom-set-attr _el-bar "id" "bar")
|
|
(dom-set-attr _el-bar "_" "on foo:bar add .foo-sent")
|
|
(dom-append (dom-body) _el-div)
|
|
(dom-append (dom-body) _el-bar)
|
|
(hs-activate! _el-div)
|
|
(hs-activate! _el-bar)
|
|
(assert (not (dom-has-class? (dom-query-by-id "bar") "foo-sent")))
|
|
(dom-dispatch (nth (dom-query-all (dom-body) "div") 0) "click" nil)
|
|
(assert (dom-has-class? (dom-query-by-id "bar") "foo-sent"))
|
|
))
|
|
(deftest "can send events with colons 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:bar(x:42) to #bar")
|
|
(dom-set-attr _el-bar "id" "bar")
|
|
(dom-set-attr _el-bar "_" "on foo:bar 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 (nth (dom-query-all (dom-body) "div") 0) "click" nil)
|
|
(assert= (dom-text-content (dom-query-by-id "bar")) "42")
|
|
))
|
|
(deftest "can send events with dots"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")) (_el-bar (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click send foo.bar to #bar")
|
|
(dom-set-attr _el-bar "id" "bar")
|
|
(dom-set-attr _el-bar "_" "on foo.bar add .foo-sent")
|
|
(dom-append (dom-body) _el-div)
|
|
(dom-append (dom-body) _el-bar)
|
|
(hs-activate! _el-div)
|
|
(hs-activate! _el-bar)
|
|
(assert (not (dom-has-class? (dom-query-by-id "bar") "foo-sent")))
|
|
(dom-dispatch (nth (dom-query-all (dom-body) "div") 0) "click" nil)
|
|
(assert (dom-has-class? (dom-query-by-id "bar") "foo-sent"))
|
|
))
|
|
(deftest "can send events with dots 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.bar(x:42) to #bar")
|
|
(dom-set-attr _el-bar "id" "bar")
|
|
(dom-set-attr _el-bar "_" "on foo.bar 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 (nth (dom-query-all (dom-body) "div") 0) "click" nil)
|
|
(assert= (dom-text-content (dom-query-by-id "bar")) "42")
|
|
))
|
|
)
|
|
|
|
;; ── set (31 tests) ──
|
|
(defsuite "hs-upstream-set"
|
|
(deftest "can define variables with let at the element level"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "set :foo to 42 on click put :foo into my innerHTML")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
))
|
|
(deftest "can set an attribute at the feature level"
|
|
(hs-cleanup!)
|
|
(let ((_el-d1 (dom-create-element "div")))
|
|
(dom-set-attr _el-d1 "id" "d1")
|
|
(dom-set-attr _el-d1 "_" "set @data-foo to \"bar\"")
|
|
(dom-append (dom-body) _el-d1)
|
|
(hs-activate! _el-d1)
|
|
))
|
|
(deftest "can set an attribute from inside a behavior"
|
|
(hs-cleanup!)
|
|
(guard (_e (true nil)) (eval-expr-cek (hs-to-sx (hs-compile "behavior MarkIt set @data-marked to 'yes' end"))))
|
|
(guard (_e (true nil)) (eval-expr-cek (hs-to-sx (hs-compile "behavior MarkIt set @data-marked to 'yes' end"))))
|
|
(let ((_el-d2 (dom-create-element "div")))
|
|
(dom-set-attr _el-d2 "id" "d2")
|
|
(dom-set-attr _el-d2 "_" "install MarkIt")
|
|
(dom-append (dom-body) _el-d2)
|
|
(hs-activate! _el-d2)
|
|
))
|
|
(deftest "can set arrays w/ array access syntax"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click set arr to [1, 2, 3] set arr[0] to \"red\" set my *color to arr[0]")
|
|
(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 set arrays w/ array access syntax and var"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click set arr to [1, 2, 3] set idx to 0 set arr[idx] to \"red\" set my *color to arr[0]")
|
|
(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 set chained indirect properties"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")) (_el-d1 (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click set the innerHTML of the parentNode of #d1 to \"foo\"")
|
|
(dom-set-attr _el-d1 "id" "d1")
|
|
(dom-append (dom-body) _el-div)
|
|
(dom-append _el-div _el-d1)
|
|
(hs-activate! _el-div)
|
|
(dom-dispatch (nth (dom-query-all (dom-body) "div") 0) "click" nil)
|
|
(assert= (dom-text-content (nth (dom-query-all (dom-body) "div") 0)) "foo")
|
|
))
|
|
(deftest "can set complex indirect properties lhs"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")) (_el-d1 (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click set parentNode.innerHTML of #d1 to \"foo\"")
|
|
(dom-set-attr _el-d1 "id" "d1")
|
|
(dom-append (dom-body) _el-div)
|
|
(dom-append _el-div _el-d1)
|
|
(hs-activate! _el-div)
|
|
(dom-dispatch (nth (dom-query-all (dom-body) "div") 0) "click" nil)
|
|
(assert= (dom-text-content (nth (dom-query-all (dom-body) "div") 0)) "foo")
|
|
))
|
|
(deftest "can set complex indirect properties rhs"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")) (_el-d1 (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click set innerHTML of #d1.parentNode to \"foo\"")
|
|
(dom-set-attr _el-d1 "id" "d1")
|
|
(dom-append (dom-body) _el-div)
|
|
(dom-append _el-div _el-d1)
|
|
(hs-activate! _el-div)
|
|
(dom-dispatch (nth (dom-query-all (dom-body) "div") 0) "click" nil)
|
|
(assert= (dom-text-content (nth (dom-query-all (dom-body) "div") 0)) "foo")
|
|
))
|
|
(deftest "can set indirect properties"
|
|
(hs-cleanup!)
|
|
(let ((_el-d1 (dom-create-element "div")))
|
|
(dom-set-attr _el-d1 "id" "d1")
|
|
(dom-set-attr _el-d1 "_" "on click set innerHTML of #d1 to \"foo\"")
|
|
(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 into attribute ref"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-add-class _el-div "divs")
|
|
(dom-set-attr _el-div "_" "on click set @bar to \"foo\"")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
(dom-dispatch _el-div "click" nil)
|
|
(assert= (dom-get-attr _el-div "bar") "foo")
|
|
))
|
|
(deftest "can set into class ref"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")) (_el-div1 (dom-create-element "div")))
|
|
(dom-add-class _el-div "divs")
|
|
(dom-set-attr _el-div "_" "on click set .divs.innerHTML to \"foo\"")
|
|
(dom-add-class _el-div1 "divs")
|
|
(dom-append (dom-body) _el-div)
|
|
(dom-append (dom-body) _el-div1)
|
|
(hs-activate! _el-div)
|
|
(dom-dispatch (nth (dom-query-all (dom-body) ".divs") 0) "click" nil)
|
|
(assert= (dom-text-content (nth (dom-query-all (dom-body) ".divs") 0)) "foo")
|
|
(assert= (dom-text-content (nth (dom-query-all (dom-body) ".divs") 1)) "foo")
|
|
))
|
|
(deftest "can set into id ref"
|
|
(hs-cleanup!)
|
|
(let ((_el-d1 (dom-create-element "div")))
|
|
(dom-set-attr _el-d1 "id" "d1")
|
|
(dom-set-attr _el-d1 "_" "on click set #d1.innerHTML to \"foo\"")
|
|
(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 into indirect attribute ref"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")) (_el-div2 (dom-create-element "div")))
|
|
(dom-add-class _el-div "divs")
|
|
(dom-set-attr _el-div "_" "on click set #div2's @bar to 'foo'")
|
|
(dom-set-attr _el-div2 "id" "div2")
|
|
(dom-append (dom-body) _el-div)
|
|
(dom-append (dom-body) _el-div2)
|
|
(hs-activate! _el-div)
|
|
(dom-dispatch (nth (dom-query-all (dom-body) "div") 0) "click" nil)
|
|
(assert= (dom-get-attr (dom-query-by-id "div2") "bar") "foo")
|
|
))
|
|
(deftest "can set into indirect attribute ref 2"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")) (_el-div2 (dom-create-element "div")))
|
|
(dom-add-class _el-div "divs")
|
|
(dom-set-attr _el-div "_" "on click set #div2's @bar to 'foo'")
|
|
(dom-set-attr _el-div2 "id" "div2")
|
|
(dom-append (dom-body) _el-div)
|
|
(dom-append (dom-body) _el-div2)
|
|
(hs-activate! _el-div)
|
|
(dom-dispatch (nth (dom-query-all (dom-body) "div") 0) "click" nil)
|
|
(assert= (dom-get-attr (dom-query-by-id "div2") "bar") "foo")
|
|
))
|
|
(deftest "can set into indirect attribute ref 3"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")) (_el-div2 (dom-create-element "div")))
|
|
(dom-add-class _el-div "divs")
|
|
(dom-set-attr _el-div "_" "on click set @bar of #div2 to 'foo'")
|
|
(dom-set-attr _el-div2 "id" "div2")
|
|
(dom-append (dom-body) _el-div)
|
|
(dom-append (dom-body) _el-div2)
|
|
(hs-activate! _el-div)
|
|
(dom-dispatch (nth (dom-query-all (dom-body) "div") 0) "click" nil)
|
|
(assert= (dom-get-attr (dom-query-by-id "div2") "bar") "foo")
|
|
))
|
|
(deftest "can set into indirect style ref"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")) (_el-div2 (dom-create-element "div")))
|
|
(dom-add-class _el-div "divs")
|
|
(dom-set-attr _el-div "_" "on click set #div2's *color to 'red'")
|
|
(dom-set-attr _el-div2 "id" "div2")
|
|
(dom-append (dom-body) _el-div)
|
|
(dom-append (dom-body) _el-div2)
|
|
(hs-activate! _el-div)
|
|
(dom-dispatch (nth (dom-query-all (dom-body) "div") 0) "click" nil)
|
|
(assert= (dom-get-style (dom-query-by-id "div2") "color") "red")
|
|
))
|
|
(deftest "can set into indirect style ref 2"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")) (_el-div2 (dom-create-element "div")))
|
|
(dom-add-class _el-div "divs")
|
|
(dom-set-attr _el-div "_" "on click set #div2's *color to 'red'")
|
|
(dom-set-attr _el-div2 "id" "div2")
|
|
(dom-append (dom-body) _el-div)
|
|
(dom-append (dom-body) _el-div2)
|
|
(hs-activate! _el-div)
|
|
(dom-dispatch (nth (dom-query-all (dom-body) "div") 0) "click" nil)
|
|
(assert= (dom-get-style (dom-query-by-id "div2") "color") "red")
|
|
))
|
|
(deftest "can set into indirect style ref 3"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")) (_el-div2 (dom-create-element "div")))
|
|
(dom-add-class _el-div "divs")
|
|
(dom-set-attr _el-div "_" "on click set *color of #div2 to 'red'")
|
|
(dom-set-attr _el-div2 "id" "div2")
|
|
(dom-append (dom-body) _el-div)
|
|
(dom-append (dom-body) _el-div2)
|
|
(hs-activate! _el-div)
|
|
(dom-dispatch (nth (dom-query-all (dom-body) "div") 0) "click" nil)
|
|
(assert= (dom-get-style (dom-query-by-id "div2") "color") "red")
|
|
))
|
|
(deftest "can set into style ref"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-add-class _el-div "divs")
|
|
(dom-set-attr _el-div "_" "on click set *color to \"red\"")
|
|
(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 set javascript globals"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click set window.temp to \"red\"")
|
|
(dom-set-inner-html _el-div "lolwat")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
(dom-dispatch _el-div "click" nil)
|
|
))
|
|
(deftest "can set local variables"
|
|
(hs-cleanup!)
|
|
(let ((_el-d1 (dom-create-element "div")))
|
|
(dom-set-attr _el-d1 "id" "d1")
|
|
(dom-set-attr _el-d1 "_" "on click set newVar to \"foo\" then put newVar 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 many properties at once with object literal"
|
|
(hs-cleanup!)
|
|
(host-set! (host-global "window") "obj" {:foo 1})
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click set {bar: 2, baz: 3} on obj")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
(dom-dispatch _el-div "click" nil)
|
|
))
|
|
(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 set #d1.innerHTML to \"foo\"")
|
|
(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 props w/ array access syntax"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click set my style[\"color\"] to \"red\"")
|
|
(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 set props w/ array access syntax and var"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click set foo to \"color\" then set my style[foo] to \"red\"")
|
|
(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 set styles"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click set my.style.color to \"red\"")
|
|
(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 "global ($) variables are allowed at the feature level"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "set $globalAtFeature to 99")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
))
|
|
(deftest "handles set url regression properly"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click set trackingcode to `foo` then set pdfurl to `https://yyy.xxxxxx.com/path/out/${trackingcode}.pdf` then put pdfurl into me")
|
|
(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-text-content _el-div) "https://yyy.xxxxxx.com/path/out/foo.pdf")
|
|
))
|
|
(deftest "rejects bare (local) variables at the feature level"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "set localAtFeature to 42")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
))
|
|
(deftest "set waits on promises"
|
|
(hs-cleanup!)
|
|
(let ((_el-d1 (dom-create-element "div")))
|
|
(dom-set-attr _el-d1 "id" "d1")
|
|
(dom-set-attr _el-d1 "_" "on click set #d1.innerHTML to promiseAString()")
|
|
(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 "supports DOM-scoped (^) variables at the element level"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "set ^foo to 42 on click put ^foo into me")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
))
|
|
)
|
|
|
|
;; ── settle (3 tests) ──
|
|
(defsuite "hs-upstream-settle"
|
|
(deftest "can settle a collection of elements"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")) (_el-div1 (dom-create-element "div")) (_el-trigger (dom-create-element "div")))
|
|
(dom-add-class _el-div "item")
|
|
(dom-add-class _el-div1 "item")
|
|
(dom-set-attr _el-trigger "id" "trigger")
|
|
(dom-set-attr _el-trigger "_" "on click settle <.item/> then add .done to <.item/>")
|
|
(dom-append (dom-body) _el-div)
|
|
(dom-append (dom-body) _el-div1)
|
|
(dom-append (dom-body) _el-trigger)
|
|
(hs-activate! _el-trigger)
|
|
(dom-dispatch (dom-query-by-id "trigger") "click" nil)
|
|
(assert (dom-has-class? (nth (dom-query-all (dom-body) ".item") 0) "done"))
|
|
(assert (dom-has-class? (nth (dom-query-all (dom-body) ".item") 1) "done"))
|
|
))
|
|
(deftest "can settle me no transition"
|
|
(hs-cleanup!)
|
|
(let ((_el-d1 (dom-create-element "div")))
|
|
(dom-set-attr _el-d1 "id" "d1")
|
|
(dom-set-attr _el-d1 "_" "on click settle then add .foo")
|
|
(dom-append (dom-body) _el-d1)
|
|
(hs-activate! _el-d1)
|
|
(dom-dispatch (dom-query-by-id "d1") "click" nil)
|
|
(assert (dom-has-class? (dom-query-by-id "d1") "foo"))
|
|
))
|
|
(deftest "can settle target no transition"
|
|
(hs-cleanup!)
|
|
(let ((_el-d1 (dom-create-element "div")) (_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-d1 "id" "d1")
|
|
(dom-set-attr _el-div "_" "on click settle #d1 then add .foo to #d1")
|
|
(dom-append (dom-body) _el-d1)
|
|
(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 "d1") "foo"))
|
|
))
|
|
)
|
|
|
|
;; ── show (18 tests) ──
|
|
(defsuite "hs-upstream-show"
|
|
(deftest "can filter over a set of elements using the its symbol"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")) (_el-p1 (dom-create-element "p")) (_el-p2 (dom-create-element "p")) (_el-p3 (dom-create-element "p")) (_el-p4 (dom-create-element "p")))
|
|
(dom-set-attr _el-div "_" "on click show <p/> in me when its innerText contains \"foo\"")
|
|
(dom-set-attr _el-p1 "id" "p1")
|
|
(dom-set-inner-html _el-p1 "foo")
|
|
(dom-set-attr _el-p2 "id" "p2")
|
|
(dom-set-inner-html _el-p2 "bar")
|
|
(dom-set-attr _el-p3 "id" "p3")
|
|
(dom-set-inner-html _el-p3 "foo")
|
|
(dom-set-attr _el-p4 "id" "p4")
|
|
(dom-set-inner-html _el-p4 "doh")
|
|
(dom-append (dom-body) _el-div)
|
|
(dom-append _el-div _el-p1)
|
|
(dom-append _el-div _el-p2)
|
|
(dom-append _el-div _el-p3)
|
|
(dom-append _el-div _el-p4)
|
|
(hs-activate! _el-div)
|
|
(dom-dispatch _el-div "click" nil)
|
|
(assert (dom-visible? (dom-query-by-id "p1")))
|
|
(assert (not (dom-visible? (dom-query-by-id "p2"))))
|
|
(assert (dom-visible? (dom-query-by-id "p3")))
|
|
(assert (not (dom-visible? (dom-query-by-id "p4"))))
|
|
))
|
|
(deftest "can show element via the hidden attribute strategy"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click show me with hidden")
|
|
(dom-set-attr _el-div "hidden" "")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
(assert= (dom-get-attr _el-div "hidden") "")
|
|
(dom-dispatch _el-div "click" nil)
|
|
(assert (!= (dom-get-attr _el-div "hidden") ""))
|
|
))
|
|
(deftest "can show element with custom display value"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click show me with display: flex")
|
|
(dom-set-attr _el-div "style" "display:none")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
(assert= (dom-get-style _el-div "display") "none")
|
|
(dom-dispatch _el-div "click" nil)
|
|
(assert= (dom-get-style _el-div "display") "flex")
|
|
))
|
|
(deftest "can show element with display:block explicitly"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click show me with display")
|
|
(dom-set-attr _el-div "style" "display:none")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
(assert= (dom-get-style _el-div "display") "none")
|
|
(dom-dispatch _el-div "click" nil)
|
|
(assert= (dom-get-style _el-div "display") "block")
|
|
))
|
|
(deftest "can show element with inline-block display value"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click show me with display: inline-block")
|
|
(dom-set-attr _el-div "style" "display:none")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
(assert= (dom-get-style _el-div "display") "none")
|
|
(dom-dispatch _el-div "click" nil)
|
|
(assert= (dom-get-style _el-div "display") "inline-block")
|
|
))
|
|
(deftest "can show element with opacity style literal"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click show me with *opacity")
|
|
(dom-set-attr _el-div "style" "opacity:0")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
(assert= (dom-get-style _el-div "opacity") "0")
|
|
(dom-dispatch _el-div "click" nil)
|
|
(assert= (dom-get-style _el-div "opacity") "1")
|
|
))
|
|
(deftest "can show element with opacity:1"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click show me with opacity")
|
|
(dom-set-attr _el-div "style" "opacity:0")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
(assert= (dom-get-style _el-div "opacity") "0")
|
|
(dom-dispatch _el-div "click" nil)
|
|
(assert= (dom-get-style _el-div "opacity") "1")
|
|
))
|
|
(deftest "can show element, with display:block by default"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click show me")
|
|
(dom-set-attr _el-div "style" "display:none")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
(assert= (dom-get-style _el-div "display") "none")
|
|
(dom-dispatch _el-div "click" nil)
|
|
(assert= (dom-get-style _el-div "display") "block")
|
|
))
|
|
(deftest "can show element, with visibility:visible"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click show me with visibility")
|
|
(dom-set-attr _el-div "style" "visibility:hidden")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
(assert= (dom-get-style _el-div "visibility") "hidden")
|
|
(dom-dispatch _el-div "click" nil)
|
|
(assert= (dom-get-style _el-div "visibility") "visible")
|
|
))
|
|
(deftest "can show form, with display:block by default"
|
|
(hs-cleanup!)
|
|
(let ((_el-form (dom-create-element "form")))
|
|
(dom-set-attr _el-form "_" "on click show me")
|
|
(dom-set-attr _el-form "style" "display:none")
|
|
(dom-append (dom-body) _el-form)
|
|
(hs-activate! _el-form)
|
|
(assert= (dom-get-style _el-form "display") "none")
|
|
(dom-dispatch _el-form "click" nil)
|
|
(assert= (dom-get-style _el-form "display") "block")
|
|
))
|
|
(deftest "can show multiple elements as class with inline-block display value"
|
|
(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-div "_" "on click show .c1 with display:inline-block")
|
|
(dom-set-attr _el-d1 "id" "d1")
|
|
(dom-add-class _el-d1 "c1")
|
|
(dom-set-attr _el-d1 "style" "display: none")
|
|
(dom-set-attr _el-d2 "id" "d2")
|
|
(dom-add-class _el-d2 "c1")
|
|
(dom-set-attr _el-d2 "style" "display: none")
|
|
(dom-append (dom-body) _el-div)
|
|
(dom-append (dom-body) _el-d1)
|
|
(dom-append (dom-body) _el-d2)
|
|
(hs-activate! _el-div)
|
|
(assert (not (dom-visible? (dom-query-by-id "d1"))))
|
|
(assert (not (dom-visible? (dom-query-by-id "d2"))))
|
|
(dom-dispatch (nth (dom-query-all (dom-body) "div") 0) "click" nil)
|
|
(assert= (dom-get-style (dom-query-by-id "d1") "display") "inline-block")
|
|
(assert= (dom-get-style (dom-query-by-id "d2") "display") "inline-block")
|
|
))
|
|
(deftest "can show multiple elements with inline-block display value"
|
|
(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-div "_" "on click show <#d1, #d2/> with display: inline-block")
|
|
(dom-set-attr _el-d1 "id" "d1")
|
|
(dom-set-attr _el-d1 "style" "display: none")
|
|
(dom-set-attr _el-d2 "id" "d2")
|
|
(dom-set-attr _el-d2 "style" "display: none")
|
|
(dom-append (dom-body) _el-div)
|
|
(dom-append (dom-body) _el-d1)
|
|
(dom-append (dom-body) _el-d2)
|
|
(hs-activate! _el-div)
|
|
(assert (not (dom-visible? (dom-query-by-id "d1"))))
|
|
(assert (not (dom-visible? (dom-query-by-id "d2"))))
|
|
(dom-dispatch (nth (dom-query-all (dom-body) "div") 0) "click" nil)
|
|
(assert= (dom-get-style (dom-query-by-id "d1") "display") "inline-block")
|
|
(assert= (dom-get-style (dom-query-by-id "d2") "display") "inline-block")
|
|
))
|
|
(deftest "can show other elements"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")) (_el-div1 (dom-create-element "div")))
|
|
(dom-add-class _el-div "showme")
|
|
(dom-set-attr _el-div "style" "display:none")
|
|
(dom-set-attr _el-div1 "_" "on click show .showme")
|
|
(dom-append (dom-body) _el-div)
|
|
(dom-append (dom-body) _el-div1)
|
|
(hs-activate! _el-div1)
|
|
(assert= (dom-get-style (dom-query ".showme") "display") "none")
|
|
(dom-dispatch (dom-query "div:nth-of-type(2)") "click" nil)
|
|
(assert= (dom-get-style (dom-query ".showme") "display") "block")
|
|
))
|
|
(deftest "can use a when clause and a with clause to show or hide an element"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click toggle .foo then show with opacity when I match .foo")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
(assert (not (dom-has-class? _el-div "foo")))
|
|
(dom-dispatch _el-div "click" nil)
|
|
(assert (dom-has-class? _el-div "foo"))
|
|
(assert= (dom-get-style _el-div "opacity") "1")
|
|
(dom-dispatch _el-div "click" nil)
|
|
(assert (not (dom-has-class? _el-div "foo")))
|
|
(assert= (dom-get-style _el-div "opacity") "0")
|
|
(dom-dispatch _el-div "click" nil)
|
|
(assert (dom-has-class? _el-div "foo"))
|
|
(assert= (dom-get-style _el-div "opacity") "1")
|
|
))
|
|
(deftest "can use a when clause to show or hide an element"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click toggle .foo then show when I match .foo")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
(assert (not (dom-has-class? _el-div "foo")))
|
|
(dom-dispatch _el-div "click" nil)
|
|
(assert (dom-has-class? _el-div "foo"))
|
|
(assert= (dom-get-style _el-div "display") "block")
|
|
(dom-dispatch _el-div "click" nil)
|
|
(assert (not (dom-has-class? _el-div "foo")))
|
|
(assert= (dom-get-style _el-div "display") "none")
|
|
(dom-dispatch _el-div "click" nil)
|
|
(assert (dom-has-class? _el-div "foo"))
|
|
(assert= (dom-get-style _el-div "display") "block")
|
|
))
|
|
(deftest "starting off with display none does not stick"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click toggle .foo show when I match .foo")
|
|
(dom-set-attr _el-div "style" "display: none")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
(assert= (dom-get-style _el-div "display") "none")
|
|
(dom-dispatch _el-div "click" nil)
|
|
(assert= (dom-get-style _el-div "display") "block")
|
|
(dom-dispatch _el-div "click" nil)
|
|
(assert= (dom-get-style _el-div "display") "none")
|
|
))
|
|
(deftest "the result after show...when is the matched elements"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")) (_el-p (dom-create-element "p")) (_el-p2 (dom-create-element "p")) (_el-out (dom-create-element "span")))
|
|
(dom-set-attr _el-div "_" "on click show <p/> in me when its textContent is 'yes' then if the result is empty put 'none' into #out else put 'some' into #out")
|
|
(dom-set-attr _el-p "style" "display:none")
|
|
(dom-set-inner-html _el-p "yes")
|
|
(dom-set-attr _el-p2 "style" "display:none")
|
|
(dom-set-inner-html _el-p2 "no")
|
|
(dom-set-attr _el-out "id" "out")
|
|
(dom-set-inner-html _el-out "--")
|
|
(dom-append (dom-body) _el-div)
|
|
(dom-append _el-div _el-p)
|
|
(dom-append _el-div _el-p2)
|
|
(dom-append _el-div _el-out)
|
|
(hs-activate! _el-div)
|
|
(dom-dispatch _el-div "click" nil)
|
|
(assert= (dom-text-content (dom-query-by-id "out")) "some")
|
|
))
|
|
(deftest "the result in a when clause refers to previous command result, not element being tested"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")) (_el-s1 (dom-create-element "span")) (_el-s2 (dom-create-element "span")))
|
|
(dom-set-attr _el-div "_" "on click get 'found' then show <span/> in me when the result is 'found'")
|
|
(dom-set-attr _el-s1 "id" "s1")
|
|
(dom-set-attr _el-s1 "style" "display:none")
|
|
(dom-set-inner-html _el-s1 "A")
|
|
(dom-set-attr _el-s2 "id" "s2")
|
|
(dom-set-attr _el-s2 "style" "display:none")
|
|
(dom-set-inner-html _el-s2 "B")
|
|
(dom-append (dom-body) _el-div)
|
|
(dom-append _el-div _el-s1)
|
|
(dom-append _el-div _el-s2)
|
|
(hs-activate! _el-div)
|
|
(dom-dispatch _el-div "click" nil)
|
|
(assert (dom-visible? (dom-query-by-id "s1")))
|
|
(assert (dom-visible? (dom-query-by-id "s2")))
|
|
))
|
|
)
|
|
|
|
;; ── socket (16 tests) ──
|
|
(defsuite "hs-upstream-socket"
|
|
(deftest "converts relative URL to ws:// on http pages"
|
|
(error "SKIP (untranslated): converts relative URL to ws:// on http pages"))
|
|
(deftest "converts relative URL to wss:// on https pages"
|
|
(error "SKIP (untranslated): converts relative URL to wss:// on https pages"))
|
|
(deftest "dispatchEvent sends JSON-encoded event over the socket"
|
|
(error "SKIP (untranslated): dispatchEvent sends JSON-encoded event over the socket"))
|
|
(deftest "namespaced sockets work"
|
|
(error "SKIP (untranslated): namespaced sockets work"))
|
|
(deftest "on message as JSON handler decodes JSON payload"
|
|
(error "SKIP (untranslated): on message as JSON handler decodes JSON payload"))
|
|
(deftest "on message as JSON throws on non-JSON payload"
|
|
(error "SKIP (untranslated): on message as JSON throws on non-JSON payload"))
|
|
(deftest "on message handler fires on incoming text message"
|
|
(error "SKIP (untranslated): on message handler fires on incoming text message"))
|
|
(deftest "parses socket with absolute ws:// URL"
|
|
(error "SKIP (untranslated): parses socket with absolute ws:// URL"))
|
|
(deftest "rpc proxy blacklists then/catch/length/toJSON"
|
|
(error "SKIP (untranslated): rpc proxy blacklists then/catch/length/toJSON"))
|
|
(deftest "rpc proxy default timeout rejects the promise"
|
|
(error "SKIP (untranslated): rpc proxy default timeout rejects the promise"))
|
|
(deftest "rpc proxy noTimeout avoids timeout rejection"
|
|
(error "SKIP (untranslated): rpc proxy noTimeout avoids timeout rejection"))
|
|
(deftest "rpc proxy reply with throw rejects the promise"
|
|
(error "SKIP (untranslated): rpc proxy reply with throw rejects the promise"))
|
|
(deftest "rpc proxy sends a message and resolves the reply"
|
|
(error "SKIP (untranslated): rpc proxy sends a message and resolves the reply"))
|
|
(deftest "rpc proxy timeout(n) rejects after a custom window"
|
|
(error "SKIP (untranslated): rpc proxy timeout(n) rejects after a custom window"))
|
|
(deftest "rpc reconnects after the underlying socket closes"
|
|
(error "SKIP (untranslated): rpc reconnects after the underlying socket closes"))
|
|
(deftest "with timeout parses and uses the configured timeout"
|
|
(error "SKIP (untranslated): with timeout parses and uses the configured timeout"))
|
|
)
|
|
|
|
;; ── swap (4 tests) ──
|
|
(defsuite "hs-upstream-swap"
|
|
(deftest "can swap a variable with a property"
|
|
(hs-cleanup!)
|
|
(let ((_el-d1 (dom-create-element "div")) (_el-target (dom-create-element "span")))
|
|
(dom-set-attr _el-d1 "id" "d1")
|
|
(dom-set-attr _el-d1 "_" "on click set x to \"old\" then set #target.dataset.val to \"new\" then swap x with #target.dataset.val then put x into me")
|
|
(dom-set-attr _el-target "id" "target")
|
|
(dom-set-attr _el-target "data-val" "x")
|
|
(dom-append (dom-body) _el-d1)
|
|
(dom-append (dom-body) _el-target)
|
|
(hs-activate! _el-d1)
|
|
(dom-dispatch (dom-query-by-id "d1") "click" nil)
|
|
(assert= (dom-text-content (dom-query-by-id "d1")) "new")
|
|
(assert= (dom-get-attr (dom-query-by-id "target") "data-val") "old")
|
|
))
|
|
(deftest "can swap array elements"
|
|
(hs-cleanup!)
|
|
(let ((_el-d1 (dom-create-element "div")))
|
|
(dom-set-attr _el-d1 "id" "d1")
|
|
(dom-set-attr _el-d1 "_" "on click set arr to [1,2,3] then swap arr[0] with arr[2] then put arr as String into me")
|
|
(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")) "3,2,1")
|
|
))
|
|
(deftest "can swap two properties"
|
|
(hs-cleanup!)
|
|
(let ((_el-d1 (dom-create-element "div")) (_el-a (dom-create-element "span")) (_el-b (dom-create-element "span")))
|
|
(dom-set-attr _el-d1 "id" "d1")
|
|
(dom-set-attr _el-d1 "_" "on click set #a.textContent to \"hello\" then set #b.textContent to \"world\" then swap #a.textContent with #b.textContent")
|
|
(dom-set-attr _el-a "id" "a")
|
|
(dom-set-inner-html _el-a "x")
|
|
(dom-set-attr _el-b "id" "b")
|
|
(dom-set-inner-html _el-b "y")
|
|
(dom-append (dom-body) _el-d1)
|
|
(dom-append (dom-body) _el-a)
|
|
(dom-append (dom-body) _el-b)
|
|
(hs-activate! _el-d1)
|
|
(dom-dispatch (dom-query-by-id "d1") "click" nil)
|
|
(assert= (dom-text-content (dom-query-by-id "a")) "world")
|
|
(assert= (dom-text-content (dom-query-by-id "b")) "hello")
|
|
))
|
|
(deftest "can swap two variables"
|
|
(hs-cleanup!)
|
|
(let ((_el-d1 (dom-create-element "div")))
|
|
(dom-set-attr _el-d1 "id" "d1")
|
|
(dom-set-attr _el-d1 "_" "on click set x to \"a\" then set y to \"b\" then swap x with y then put x + y into me")
|
|
(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")) "ba")
|
|
))
|
|
)
|
|
|
|
;; ── take (15 tests) ──
|
|
(defsuite "hs-upstream-take"
|
|
(deftest "a parent can take a class for other elements"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")) (_el-d1 (dom-create-element "div")) (_el-d2 (dom-create-element "div")) (_el-d3 (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click take .foo from .div for event.target")
|
|
(dom-set-attr _el-d1 "id" "d1")
|
|
(dom-add-class _el-d1 "div")
|
|
(dom-add-class _el-d1 "foo")
|
|
(dom-set-attr _el-d2 "id" "d2")
|
|
(dom-add-class _el-d2 "div")
|
|
(dom-set-attr _el-d3 "id" "d3")
|
|
(dom-add-class _el-d3 "div")
|
|
(dom-append (dom-body) _el-div)
|
|
(dom-append _el-div _el-d1)
|
|
(dom-append _el-div _el-d2)
|
|
(dom-append _el-div _el-d3)
|
|
(hs-activate! _el-div)
|
|
(dom-dispatch (dom-query-by-id "d2") "click" nil)
|
|
(assert (not (dom-has-class? (dom-query-by-id "d1") "foo")))
|
|
(assert (dom-has-class? (dom-query-by-id "d2") "foo"))
|
|
(assert (not (dom-has-class? (dom-query-by-id "d3") "foo")))
|
|
))
|
|
(deftest "a parent can take an attribute for other elements"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")) (_el-d1 (dom-create-element "div")) (_el-d2 (dom-create-element "div")) (_el-d3 (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click take @data-foo from .div for event.target")
|
|
(dom-set-attr _el-d1 "id" "d1")
|
|
(dom-add-class _el-d1 "div")
|
|
(dom-set-attr _el-d1 "data-foo" "bar")
|
|
(dom-set-attr _el-d2 "id" "d2")
|
|
(dom-add-class _el-d2 "div")
|
|
(dom-set-attr _el-d3 "id" "d3")
|
|
(dom-add-class _el-d3 "div")
|
|
(dom-append (dom-body) _el-div)
|
|
(dom-append _el-div _el-d1)
|
|
(dom-append _el-div _el-d2)
|
|
(dom-append _el-div _el-d3)
|
|
(hs-activate! _el-div)
|
|
(dom-dispatch (dom-query-by-id "d2") "click" nil)
|
|
(assert (not (dom-has-attr? (dom-query-by-id "d1") "data-foo")))
|
|
(assert= (dom-get-attr (dom-query-by-id "d2") "data-foo") "")
|
|
(assert (not (dom-has-attr? (dom-query-by-id "d3") "data-foo")))
|
|
))
|
|
(deftest "can take a class and swap it with another via giving"
|
|
(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 "item")
|
|
(dom-add-class _el-div "selected")
|
|
(dom-add-class _el-div1 "item")
|
|
(dom-add-class _el-div1 "unselected")
|
|
(dom-set-attr _el-div1 "_" "on click take .selected from .item giving .unselected")
|
|
(dom-add-class _el-div2 "item")
|
|
(dom-add-class _el-div2 "unselected")
|
|
(dom-append (dom-body) _el-div)
|
|
(dom-append (dom-body) _el-div1)
|
|
(dom-append (dom-body) _el-div2)
|
|
(hs-activate! _el-div1)
|
|
(dom-dispatch (nth (dom-query-all (dom-body) "div") 1) "click" nil)
|
|
(assert (dom-has-class? (nth (dom-query-all (dom-body) "div") 0) "unselected"))
|
|
(assert (not (dom-has-class? (nth (dom-query-all (dom-body) "div") 0) "selected")))
|
|
(assert (dom-has-class? (nth (dom-query-all (dom-body) "div") 1) "selected"))
|
|
(assert (not (dom-has-class? (nth (dom-query-all (dom-body) "div") 1) "unselected")))
|
|
(assert (dom-has-class? (nth (dom-query-all (dom-body) "div") 2) "unselected"))
|
|
))
|
|
(deftest "can take a class and swap it with another via with"
|
|
(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 "item")
|
|
(dom-add-class _el-div "selected")
|
|
(dom-add-class _el-div1 "item")
|
|
(dom-set-attr _el-div1 "_" "on click take .selected with .unselected from .item")
|
|
(dom-add-class _el-div2 "item")
|
|
(dom-append (dom-body) _el-div)
|
|
(dom-append (dom-body) _el-div1)
|
|
(dom-append (dom-body) _el-div2)
|
|
(hs-activate! _el-div1)
|
|
(dom-dispatch (nth (dom-query-all (dom-body) "div") 1) "click" nil)
|
|
(assert (not (dom-has-class? (nth (dom-query-all (dom-body) "div") 0) "selected")))
|
|
(assert (dom-has-class? (nth (dom-query-all (dom-body) "div") 0) "unselected"))
|
|
(assert (dom-has-class? (nth (dom-query-all (dom-body) "div") 1) "selected"))
|
|
(assert (not (dom-has-class? (nth (dom-query-all (dom-body) "div") 1) "unselected")))
|
|
(assert (dom-has-class? (nth (dom-query-all (dom-body) "div") 2) "unselected"))
|
|
))
|
|
(deftest "can take a class for other elements"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")) (_el-div1 (dom-create-element "div")) (_el-d3 (dom-create-element "div")))
|
|
(dom-add-class _el-div "div")
|
|
(dom-add-class _el-div "foo")
|
|
(dom-add-class _el-div1 "div")
|
|
(dom-set-attr _el-div1 "_" "on click take .foo from .div for #d3")
|
|
(dom-set-attr _el-d3 "id" "d3")
|
|
(dom-add-class _el-d3 "div")
|
|
(dom-append (dom-body) _el-div)
|
|
(dom-append (dom-body) _el-div1)
|
|
(dom-append (dom-body) _el-d3)
|
|
(hs-activate! _el-div1)
|
|
(dom-dispatch (nth (dom-query-all (dom-body) "div") 1) "click" nil)
|
|
(assert (not (dom-has-class? (nth (dom-query-all (dom-body) "div") 0) "foo")))
|
|
(assert (not (dom-has-class? (nth (dom-query-all (dom-body) "div") 1) "foo")))
|
|
(assert (dom-has-class? (dom-query-by-id "d3") "foo"))
|
|
))
|
|
(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 "div")
|
|
(dom-add-class _el-div "foo")
|
|
(dom-add-class _el-div1 "div")
|
|
(dom-set-attr _el-div1 "_" "on click take .foo from .div")
|
|
(dom-add-class _el-div2 "div")
|
|
(dom-append (dom-body) _el-div)
|
|
(dom-append (dom-body) _el-div1)
|
|
(dom-append (dom-body) _el-div2)
|
|
(hs-activate! _el-div1)
|
|
(dom-dispatch (nth (dom-query-all (dom-body) "div") 1) "click" nil)
|
|
(assert (not (dom-has-class? (nth (dom-query-all (dom-body) "div") 0) "foo")))
|
|
(assert (dom-has-class? (nth (dom-query-all (dom-body) "div") 1) "foo"))
|
|
(assert (not (dom-has-class? (nth (dom-query-all (dom-body) "div") 2) "foo")))
|
|
))
|
|
(deftest "can take a class from other forms"
|
|
(hs-cleanup!)
|
|
(let ((_el-form (dom-create-element "form")) (_el-form1 (dom-create-element "form")) (_el-form2 (dom-create-element "form")))
|
|
(dom-add-class _el-form "div")
|
|
(dom-add-class _el-form "foo")
|
|
(dom-add-class _el-form1 "div")
|
|
(dom-set-attr _el-form1 "_" "on click take .foo from .div")
|
|
(dom-add-class _el-form2 "div")
|
|
(dom-append (dom-body) _el-form)
|
|
(dom-append (dom-body) _el-form1)
|
|
(dom-append (dom-body) _el-form2)
|
|
(hs-activate! _el-form1)
|
|
(dom-dispatch (nth (dom-query-all (dom-body) "form") 1) "click" nil)
|
|
(assert (not (dom-has-class? (nth (dom-query-all (dom-body) "form") 0) "foo")))
|
|
(assert (dom-has-class? (nth (dom-query-all (dom-body) "form") 1) "foo"))
|
|
(assert (not (dom-has-class? (nth (dom-query-all (dom-body) "form") 2) "foo")))
|
|
))
|
|
(deftest "can take an attribute for other elements"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")) (_el-div1 (dom-create-element "div")) (_el-d3 (dom-create-element "div")))
|
|
(dom-add-class _el-div "div")
|
|
(dom-set-attr _el-div "data-foo" "bar")
|
|
(dom-add-class _el-div1 "div")
|
|
(dom-set-attr _el-div1 "_" "on click take @data-foo from .div for #d3")
|
|
(dom-set-attr _el-d3 "id" "d3")
|
|
(dom-add-class _el-d3 "div")
|
|
(dom-append (dom-body) _el-div)
|
|
(dom-append (dom-body) _el-div1)
|
|
(dom-append (dom-body) _el-d3)
|
|
(hs-activate! _el-div1)
|
|
(dom-dispatch (nth (dom-query-all (dom-body) "div") 1) "click" nil)
|
|
(assert (not (dom-has-attr? (nth (dom-query-all (dom-body) "div") 0) "data-foo")))
|
|
(assert (not (dom-has-attr? (nth (dom-query-all (dom-body) "div") 1) "data-foo")))
|
|
(assert= (dom-get-attr (dom-query-by-id "d3") "data-foo") "")
|
|
))
|
|
(deftest "can take an attribute 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 "div")
|
|
(dom-set-attr _el-div "data-foo" "bar")
|
|
(dom-add-class _el-div1 "div")
|
|
(dom-set-attr _el-div1 "_" "on click take @data-foo from .div")
|
|
(dom-add-class _el-div2 "div")
|
|
(dom-append (dom-body) _el-div)
|
|
(dom-append (dom-body) _el-div1)
|
|
(dom-append (dom-body) _el-div2)
|
|
(hs-activate! _el-div1)
|
|
(assert= (dom-get-attr (nth (dom-query-all (dom-body) "div") 0) "data-foo") "bar")
|
|
(dom-dispatch (nth (dom-query-all (dom-body) "div") 1) "click" nil)
|
|
(assert (not (dom-has-attr? (nth (dom-query-all (dom-body) "div") 0) "data-foo")))
|
|
(assert= (dom-get-attr (nth (dom-query-all (dom-body) "div") 1) "data-foo") "")
|
|
(assert (not (dom-has-attr? (nth (dom-query-all (dom-body) "div") 2) "data-foo")))
|
|
))
|
|
(deftest "can take an attribute value from other elements and set specific values instead"
|
|
(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 "div")
|
|
(dom-set-attr _el-div "data-foo" "bar")
|
|
(dom-add-class _el-div1 "div")
|
|
(dom-set-attr _el-div1 "_" "on click take @data-foo=baz with \"qux\" from .div")
|
|
(dom-add-class _el-div2 "div")
|
|
(dom-append (dom-body) _el-div)
|
|
(dom-append (dom-body) _el-div1)
|
|
(dom-append (dom-body) _el-div2)
|
|
(hs-activate! _el-div1)
|
|
(dom-dispatch (nth (dom-query-all (dom-body) "div") 1) "click" nil)
|
|
(assert= (dom-get-attr (nth (dom-query-all (dom-body) "div") 0) "data-foo") "qux")
|
|
(assert= (dom-get-attr (nth (dom-query-all (dom-body) "div") 1) "data-foo") "baz")
|
|
(assert= (dom-get-attr (nth (dom-query-all (dom-body) "div") 2) "data-foo") "qux")
|
|
))
|
|
(deftest "can take an attribute value from other elements and set value from an expression instead"
|
|
(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 "div")
|
|
(dom-set-attr _el-div "data-foo" "bar")
|
|
(dom-add-class _el-div1 "div")
|
|
(dom-set-attr _el-div1 "_" "on click take @data-foo=baz with my @data-foo from .div")
|
|
(dom-set-attr _el-div1 "data-foo" "qux")
|
|
(dom-add-class _el-div2 "div")
|
|
(dom-append (dom-body) _el-div)
|
|
(dom-append (dom-body) _el-div1)
|
|
(dom-append (dom-body) _el-div2)
|
|
(hs-activate! _el-div1)
|
|
(dom-dispatch (nth (dom-query-all (dom-body) "div") 1) "click" nil)
|
|
(assert= (dom-get-attr (nth (dom-query-all (dom-body) "div") 0) "data-foo") "qux")
|
|
(assert= (dom-get-attr (nth (dom-query-all (dom-body) "div") 1) "data-foo") "baz")
|
|
(assert= (dom-get-attr (nth (dom-query-all (dom-body) "div") 2) "data-foo") "qux")
|
|
))
|
|
(deftest "can take an attribute with specific value 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 "div")
|
|
(dom-set-attr _el-div "data-foo" "bar")
|
|
(dom-add-class _el-div1 "div")
|
|
(dom-set-attr _el-div1 "_" "on click take @data-foo=baz from .div")
|
|
(dom-add-class _el-div2 "div")
|
|
(dom-append (dom-body) _el-div)
|
|
(dom-append (dom-body) _el-div1)
|
|
(dom-append (dom-body) _el-div2)
|
|
(hs-activate! _el-div1)
|
|
(assert= (dom-get-attr (nth (dom-query-all (dom-body) "div") 0) "data-foo") "bar")
|
|
(dom-dispatch (nth (dom-query-all (dom-body) "div") 1) "click" nil)
|
|
(assert (not (dom-has-attr? (nth (dom-query-all (dom-body) "div") 0) "data-foo")))
|
|
(assert= (dom-get-attr (nth (dom-query-all (dom-body) "div") 1) "data-foo") "baz")
|
|
(assert (not (dom-has-attr? (nth (dom-query-all (dom-body) "div") 2) "data-foo")))
|
|
))
|
|
(deftest "can take multiple classes 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 "div")
|
|
(dom-add-class _el-div "foo")
|
|
(dom-add-class _el-div1 "div")
|
|
(dom-set-attr _el-div1 "_" "on click take .foo .bar")
|
|
(dom-add-class _el-div2 "div")
|
|
(dom-add-class _el-div2 "bar")
|
|
(dom-append (dom-body) _el-div)
|
|
(dom-append (dom-body) _el-div1)
|
|
(dom-append (dom-body) _el-div2)
|
|
(hs-activate! _el-div1)
|
|
(dom-dispatch (nth (dom-query-all (dom-body) "div") 1) "click" nil)
|
|
(assert (not (dom-has-class? (nth (dom-query-all (dom-body) "div") 0) "foo")))
|
|
(assert (dom-has-class? (nth (dom-query-all (dom-body) "div") 1) "foo"))
|
|
(assert (dom-has-class? (nth (dom-query-all (dom-body) "div") 1) "bar"))
|
|
(assert (not (dom-has-class? (nth (dom-query-all (dom-body) "div") 2) "bar")))
|
|
))
|
|
(deftest "can take multiple classes from specific element"
|
|
(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 "div1")
|
|
(dom-add-class _el-div "foo")
|
|
(dom-add-class _el-div "bar")
|
|
(dom-add-class _el-div1 "div")
|
|
(dom-set-attr _el-div1 "_" "on click take .foo .bar from .div1")
|
|
(dom-add-class _el-div2 "div")
|
|
(dom-add-class _el-div2 "bar")
|
|
(dom-append (dom-body) _el-div)
|
|
(dom-append (dom-body) _el-div1)
|
|
(dom-append (dom-body) _el-div2)
|
|
(hs-activate! _el-div1)
|
|
(dom-dispatch (nth (dom-query-all (dom-body) "div") 1) "click" nil)
|
|
(assert (not (dom-has-class? (nth (dom-query-all (dom-body) "div") 0) "foo")))
|
|
(assert (not (dom-has-class? (nth (dom-query-all (dom-body) "div") 0) "bar")))
|
|
(assert (dom-has-class? (nth (dom-query-all (dom-body) "div") 1) "foo"))
|
|
(assert (dom-has-class? (nth (dom-query-all (dom-body) "div") 1) "bar"))
|
|
(assert (dom-has-class? (nth (dom-query-all (dom-body) "div") 2) "bar"))
|
|
))
|
|
(deftest "giving may follow the from clause as an alternative to with"
|
|
(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 "div")
|
|
(dom-set-attr _el-div "data-foo" "bar")
|
|
(dom-add-class _el-div1 "div")
|
|
(dom-set-attr _el-div1 "_" "on click take @data-foo=baz from .div giving \"qux\"")
|
|
(dom-add-class _el-div2 "div")
|
|
(dom-append (dom-body) _el-div)
|
|
(dom-append (dom-body) _el-div1)
|
|
(dom-append (dom-body) _el-div2)
|
|
(hs-activate! _el-div1)
|
|
(dom-dispatch (nth (dom-query-all (dom-body) "div") 1) "click" nil)
|
|
(assert= (dom-get-attr (nth (dom-query-all (dom-body) "div") 0) "data-foo") "qux")
|
|
(assert= (dom-get-attr (nth (dom-query-all (dom-body) "div") 1) "data-foo") "baz")
|
|
(assert= (dom-get-attr (nth (dom-query-all (dom-body) "div") 2) "data-foo") "qux")
|
|
))
|
|
)
|
|
|
|
;; ── tell (10 tests) ──
|
|
(defsuite "hs-upstream-tell"
|
|
(deftest "attributes refer to the thing being told"
|
|
(hs-cleanup!)
|
|
(let ((_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 tell #d2 then put @foo into me")
|
|
(dom-set-attr _el-d2 "id" "d2")
|
|
(dom-set-attr _el-d2 "foo" "bar")
|
|
(dom-append (dom-body) _el-d1)
|
|
(dom-append (dom-body) _el-d2)
|
|
(hs-activate! _el-d1)
|
|
(dom-dispatch (dom-query-by-id "d1") "click" nil)
|
|
(assert= (dom-text-content (dom-query-by-id "d1")) "bar")
|
|
))
|
|
(deftest "does not overwrite the me symbol"
|
|
(hs-cleanup!)
|
|
(let ((_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 add .foo then tell #d2 then add .bar to me")
|
|
(dom-set-attr _el-d2 "id" "d2")
|
|
(dom-append (dom-body) _el-d1)
|
|
(dom-append (dom-body) _el-d2)
|
|
(hs-activate! _el-d1)
|
|
(dom-dispatch (dom-query-by-id "d1") "click" nil)
|
|
(assert (dom-has-class? (dom-query-by-id "d1") "bar"))
|
|
(assert (dom-has-class? (dom-query-by-id "d1") "foo"))
|
|
(assert (not (dom-has-class? (dom-query-by-id "d2") "bar")))
|
|
(assert (not (dom-has-class? (dom-query-by-id "d2") "foo")))
|
|
))
|
|
(deftest "establishes a proper beingTold symbol"
|
|
(hs-cleanup!)
|
|
(let ((_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 add .foo then tell #d2 then add .bar")
|
|
(dom-set-attr _el-d2 "id" "d2")
|
|
(dom-append (dom-body) _el-d1)
|
|
(dom-append (dom-body) _el-d2)
|
|
(hs-activate! _el-d1)
|
|
(dom-dispatch (dom-query-by-id "d1") "click" nil)
|
|
(assert (not (dom-has-class? (dom-query-by-id "d1") "bar")))
|
|
(assert (dom-has-class? (dom-query-by-id "d1") "foo"))
|
|
(assert (dom-has-class? (dom-query-by-id "d2") "bar"))
|
|
(assert (not (dom-has-class? (dom-query-by-id "d2") "foo")))
|
|
))
|
|
(deftest "ignores null"
|
|
(hs-cleanup!)
|
|
(let ((_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 tell null then add .bar end add .foo")
|
|
(dom-set-attr _el-d2 "id" "d2")
|
|
(dom-append (dom-body) _el-d1)
|
|
(dom-append (dom-body) _el-d2)
|
|
(hs-activate! _el-d1)
|
|
(dom-dispatch (dom-query-by-id "d1") "click" nil)
|
|
(assert (not (dom-has-class? (dom-query-by-id "d1") "bar")))
|
|
(assert (dom-has-class? (dom-query-by-id "d1") "foo"))
|
|
(assert (not (dom-has-class? (dom-query-by-id "d2") "bar")))
|
|
))
|
|
(deftest "restores a proper implicit me symbol"
|
|
(hs-cleanup!)
|
|
(let ((_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 tell #d2 then add .bar end add .foo")
|
|
(dom-set-attr _el-d2 "id" "d2")
|
|
(dom-append (dom-body) _el-d1)
|
|
(dom-append (dom-body) _el-d2)
|
|
(hs-activate! _el-d1)
|
|
(dom-dispatch (dom-query-by-id "d1") "click" nil)
|
|
(assert (not (dom-has-class? (dom-query-by-id "d1") "bar")))
|
|
(assert (dom-has-class? (dom-query-by-id "d1") "foo"))
|
|
(assert (dom-has-class? (dom-query-by-id "d2") "bar"))
|
|
(assert (not (dom-has-class? (dom-query-by-id "d2") "foo")))
|
|
))
|
|
(deftest "tell terminates with a feature"
|
|
(hs-cleanup!)
|
|
(let ((_el-d1 (dom-create-element "div")) (_el-d2 (dom-create-element "div")) (_el-d3 (dom-create-element "div")))
|
|
(dom-set-attr _el-d1 "id" "d1")
|
|
(dom-set-attr _el-d1 "_" "on click tell #d2 remove yourself on click tell #d3 remove yourself")
|
|
(dom-set-attr _el-d2 "id" "d2")
|
|
(dom-set-attr _el-d3 "id" "d3")
|
|
(dom-append (dom-body) _el-d1)
|
|
(dom-append _el-d1 _el-d2)
|
|
(dom-append _el-d1 _el-d3)
|
|
(hs-activate! _el-d1)
|
|
(dom-dispatch (dom-query-by-id "d1") "click" nil)
|
|
))
|
|
(deftest "works with an array"
|
|
(hs-cleanup!)
|
|
(let ((_el-d1 (dom-create-element "div")) (_el-p1 (dom-create-element "p")) (_el-p2 (dom-create-element "p")) (_el-d2 (dom-create-element "div")))
|
|
(dom-set-attr _el-d1 "id" "d1")
|
|
(dom-set-attr _el-d1 "_" "on click add .foo then tell <p/> in me add .bar")
|
|
(dom-set-attr _el-p1 "id" "p1")
|
|
(dom-set-attr _el-p2 "id" "p2")
|
|
(dom-set-attr _el-d2 "id" "d2")
|
|
(dom-append (dom-body) _el-d1)
|
|
(dom-append _el-d1 _el-p1)
|
|
(dom-append _el-d1 _el-p2)
|
|
(dom-append _el-d1 _el-d2)
|
|
(hs-activate! _el-d1)
|
|
(dom-dispatch (dom-query-by-id "d1") "click" nil)
|
|
(assert (dom-has-class? (dom-query-by-id "d1") "foo"))
|
|
(assert (not (dom-has-class? (dom-query-by-id "d1") "bar")))
|
|
(assert (not (dom-has-class? (dom-query-by-id "d2") "bar")))
|
|
(assert (dom-has-class? (dom-query-by-id "p1") "bar"))
|
|
(assert (dom-has-class? (dom-query-by-id "p2") "bar"))
|
|
))
|
|
(deftest "you symbol represents the thing being told"
|
|
(hs-cleanup!)
|
|
(let ((_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 tell #d2 then add .bar to you")
|
|
(dom-set-attr _el-d2 "id" "d2")
|
|
(dom-append (dom-body) _el-d1)
|
|
(dom-append (dom-body) _el-d2)
|
|
(hs-activate! _el-d1)
|
|
(dom-dispatch (dom-query-by-id "d1") "click" nil)
|
|
(assert (not (dom-has-class? (dom-query-by-id "d1") "bar")))
|
|
(assert (dom-has-class? (dom-query-by-id "d2") "bar"))
|
|
))
|
|
(deftest "your symbol represents the thing being told"
|
|
(hs-cleanup!)
|
|
(let ((_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 tell #d2 then put your innerText into me")
|
|
(dom-set-attr _el-d2 "id" "d2")
|
|
(dom-set-inner-html _el-d2 "foo")
|
|
(dom-append (dom-body) _el-d1)
|
|
(dom-append (dom-body) _el-d2)
|
|
(hs-activate! _el-d1)
|
|
(dom-dispatch (dom-query-by-id "d1") "click" nil)
|
|
(assert= (dom-text-content (dom-query-by-id "d1")) "foo")
|
|
))
|
|
(deftest "yourself attribute also works"
|
|
(hs-cleanup!)
|
|
(let ((_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 tell #d2 remove yourself")
|
|
(dom-set-attr _el-d2 "id" "d2")
|
|
(dom-append (dom-body) _el-d1)
|
|
(dom-append _el-d1 _el-d2)
|
|
(hs-activate! _el-d1)
|
|
(dom-dispatch (dom-query-by-id "d1") "click" nil)
|
|
))
|
|
)
|
|
|
|
;; ── templates/templates (48 tests) ──
|
|
(defsuite "hs-upstream-templates/templates"
|
|
(deftest "all html entities escaped"
|
|
(hs-cleanup!)
|
|
(let ((_el-script (dom-create-element "script")))
|
|
(dom-set-attr _el-script "type" "text/hyperscript-template")
|
|
(dom-set-inner-html _el-script "${x}")
|
|
(dom-append (dom-body) _el-script)
|
|
))
|
|
(deftest "async expressions in a loop resolve correctly"
|
|
(hs-cleanup!)
|
|
(let ((_el-script (dom-create-element "script")))
|
|
(dom-set-attr _el-script "type" "text/hyperscript-template")
|
|
(dom-set-inner-html _el-script "#for x in items
|
|
${asyncFn(x)}
|
|
#end")
|
|
(dom-append (dom-body) _el-script)
|
|
))
|
|
(deftest "blank lines are consumed as whitespace"
|
|
(hs-cleanup!)
|
|
(let ((_el-script (dom-create-element "script")))
|
|
(dom-set-attr _el-script "type" "text/hyperscript-template")
|
|
(dom-set-inner-html _el-script "a
|
|
|
|
b")
|
|
(dom-append (dom-body) _el-script)
|
|
))
|
|
(deftest "break prevents else clause from executing"
|
|
(hs-cleanup!)
|
|
(let ((_el-script (dom-create-element "script")))
|
|
(dom-set-attr _el-script "type" "text/hyperscript-template")
|
|
(dom-set-inner-html _el-script "#for item in items
|
|
#if item === 2
|
|
#break
|
|
#end
|
|
${item}
|
|
#else
|
|
No items
|
|
#end")
|
|
(dom-append (dom-body) _el-script)
|
|
))
|
|
(deftest "can render"
|
|
(hs-cleanup!)
|
|
(let ((_el-script (dom-create-element "script")))
|
|
(dom-set-attr _el-script "type" "text/hyperscript-template")
|
|
(dom-set-inner-html _el-script "render ${x}")
|
|
(dom-append (dom-body) _el-script)
|
|
))
|
|
(deftest "can render correctly"
|
|
(hs-cleanup!)
|
|
(let ((_el-script (dom-create-element "script")))
|
|
(dom-set-attr _el-script "type" "text/hyperscript-template")
|
|
(dom-set-inner-html _el-script "#for x in stuff
|
|
<p>Hello ${x}</p>
|
|
#end")
|
|
(dom-append (dom-body) _el-script)
|
|
))
|
|
(deftest "conditional with nested parens in value does not false-trigger on inner if"
|
|
(hs-cleanup!)
|
|
(let ((_el-script (dom-create-element "script")))
|
|
(dom-set-attr _el-script "type" "text/hyperscript-template")
|
|
(dom-set-inner-html _el-script "${fn(x) if condition}")
|
|
(dom-append (dom-body) _el-script)
|
|
))
|
|
(deftest "content after for...else still renders"
|
|
(hs-cleanup!)
|
|
(let ((_el-script (dom-create-element "script")))
|
|
(dom-set-attr _el-script "type" "text/hyperscript-template")
|
|
(dom-set-inner-html _el-script "#for item in items
|
|
${item}
|
|
#else
|
|
nothing
|
|
#end
|
|
after")
|
|
(dom-append (dom-body) _el-script)
|
|
))
|
|
(deftest "empty template renders empty string"
|
|
(hs-cleanup!)
|
|
(let ((_el-script (dom-create-element "script")))
|
|
(dom-set-attr _el-script "type" "text/hyperscript-template")
|
|
(dom-append (dom-body) _el-script)
|
|
))
|
|
(deftest "error in conditional expression is reported"
|
|
(hs-cleanup!)
|
|
(let ((_el-script (dom-create-element "script")))
|
|
(dom-set-attr _el-script "type" "text/hyperscript-template")
|
|
(dom-set-inner-html _el-script "${value if !!!}")
|
|
(dom-append (dom-body) _el-script)
|
|
))
|
|
(deftest "error in top-level expression is reported"
|
|
(hs-cleanup!)
|
|
(let ((_el-script (dom-create-element "script")))
|
|
(dom-set-attr _el-script "type" "text/hyperscript-template")
|
|
(dom-set-inner-html _el-script "before ${!!!} after")
|
|
(dom-append (dom-body) _el-script)
|
|
))
|
|
(deftest "error inside for body is reported"
|
|
(hs-cleanup!)
|
|
(let ((_el-script (dom-create-element "script")))
|
|
(dom-set-attr _el-script "type" "text/hyperscript-template")
|
|
(dom-set-inner-html _el-script "#for x in items
|
|
${!!!}
|
|
#end")
|
|
(dom-append (dom-body) _el-script)
|
|
))
|
|
(deftest "escapes html, with opt-out"
|
|
(hs-cleanup!)
|
|
(let ((_el-script (dom-create-element "script")))
|
|
(dom-set-attr _el-script "type" "text/hyperscript-template")
|
|
(dom-set-inner-html _el-script "render ${x} ${unescaped x}")
|
|
(dom-append (dom-body) _el-script)
|
|
))
|
|
(deftest "expression with function call"
|
|
(hs-cleanup!)
|
|
(let ((_el-script (dom-create-element "script")))
|
|
(dom-set-attr _el-script "type" "text/hyperscript-template")
|
|
(dom-set-inner-html _el-script "${fn()}")
|
|
(dom-append (dom-body) _el-script)
|
|
))
|
|
(deftest "expression with math"
|
|
(hs-cleanup!)
|
|
(let ((_el-script (dom-create-element "script")))
|
|
(dom-set-attr _el-script "type" "text/hyperscript-template")
|
|
(dom-set-inner-html _el-script "${x + y}")
|
|
(dom-append (dom-body) _el-script)
|
|
))
|
|
(deftest "expression with nested braces"
|
|
(hs-cleanup!)
|
|
(let ((_el-script (dom-create-element "script")))
|
|
(dom-set-attr _el-script "type" "text/hyperscript-template")
|
|
(dom-set-inner-html _el-script "${obj[\"key\"]}")
|
|
(dom-append (dom-body) _el-script)
|
|
))
|
|
(deftest "for loop over empty array"
|
|
(hs-cleanup!)
|
|
(let ((_el-script (dom-create-element "script")))
|
|
(dom-set-attr _el-script "type" "text/hyperscript-template")
|
|
(dom-set-inner-html _el-script "before
|
|
#for x in items
|
|
${x}
|
|
#end
|
|
after")
|
|
(dom-append (dom-body) _el-script)
|
|
))
|
|
(deftest "for loop with index"
|
|
(hs-cleanup!)
|
|
(let ((_el-script (dom-create-element "script")))
|
|
(dom-set-attr _el-script "type" "text/hyperscript-template")
|
|
(dom-set-inner-html _el-script "#for x in items
|
|
${x}
|
|
#end")
|
|
(dom-append (dom-body) _el-script)
|
|
))
|
|
(deftest "good expressions render despite errors in other 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 "good: ${value} bad: ${!!!}")
|
|
(dom-append (dom-body) _el-script)
|
|
))
|
|
(deftest "good expressions still render alongside bad ones"
|
|
(hs-cleanup!)
|
|
(let ((_el-script (dom-create-element "script")))
|
|
(dom-set-attr _el-script "type" "text/hyperscript-template")
|
|
(dom-set-inner-html _el-script "${x} ${!!!} ${y}")
|
|
(dom-append (dom-body) _el-script)
|
|
))
|
|
(deftest "handles async 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 "result: ${asyncFn()}")
|
|
(dom-append (dom-body) _el-script)
|
|
))
|
|
(deftest "if false takes else branch"
|
|
(hs-cleanup!)
|
|
(let ((_el-script (dom-create-element "script")))
|
|
(dom-set-attr _el-script "type" "text/hyperscript-template")
|
|
(dom-set-inner-html _el-script "#if false
|
|
yes
|
|
#else
|
|
no
|
|
#end")
|
|
(dom-append (dom-body) _el-script)
|
|
))
|
|
(deftest "if with expression condition"
|
|
(hs-cleanup!)
|
|
(let ((_el-script (dom-create-element "script")))
|
|
(dom-set-attr _el-script "type" "text/hyperscript-template")
|
|
(dom-set-inner-html _el-script "#if x is greater than 5
|
|
big
|
|
#else
|
|
small
|
|
#end")
|
|
(dom-append (dom-body) _el-script)
|
|
))
|
|
(deftest "multiple errors in one template are all reported"
|
|
(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 expressions on one line"
|
|
(hs-cleanup!)
|
|
(let ((_el-script (dom-create-element "script")))
|
|
(dom-set-attr _el-script "type" "text/hyperscript-template")
|
|
(dom-set-inner-html _el-script "${a} + ${b} = ${c}")
|
|
(dom-append (dom-body) _el-script)
|
|
))
|
|
(deftest "null and undefined render as empty"
|
|
(hs-cleanup!)
|
|
(let ((_el-script (dom-create-element "script")))
|
|
(dom-set-attr _el-script "type" "text/hyperscript-template")
|
|
(dom-set-inner-html _el-script "[${x}][${y}]")
|
|
(dom-append (dom-body) _el-script)
|
|
))
|
|
(deftest "null values render as empty string, not \"null\""
|
|
(hs-cleanup!)
|
|
(let ((_el-script (dom-create-element "script")))
|
|
(dom-set-attr _el-script "type" "text/hyperscript-template")
|
|
(dom-set-inner-html _el-script "[${x}]")
|
|
(dom-append (dom-body) _el-script)
|
|
))
|
|
(deftest "plain text with no 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 "just plain text")
|
|
(dom-append (dom-body) _el-script)
|
|
))
|
|
(deftest "recovers from bad expression in ${}"
|
|
(hs-cleanup!)
|
|
(let ((_el-script (dom-create-element "script")))
|
|
(dom-set-attr _el-script "type" "text/hyperscript-template")
|
|
(dom-set-inner-html _el-script "before ${!!!} after")
|
|
(dom-append (dom-body) _el-script)
|
|
))
|
|
(deftest "recovers from unterminated ${}"
|
|
(hs-cleanup!)
|
|
(let ((_el-script (dom-create-element "script")))
|
|
(dom-set-attr _el-script "type" "text/hyperscript-template")
|
|
(dom-set-inner-html _el-script "before ${x after")
|
|
(dom-append (dom-body) _el-script)
|
|
))
|
|
(deftest "render here sets innerHTML of me"
|
|
(hs-cleanup!)
|
|
(let ((_el-target (dom-create-element "div")) (_el-tmpl (dom-create-element "script")))
|
|
(dom-set-attr _el-target "id" "target")
|
|
(dom-set-attr _el-target "_" "on click render #tmpl here")
|
|
(dom-set-attr _el-tmpl "id" "tmpl")
|
|
(dom-set-attr _el-tmpl "type" "text/hyperscript-template")
|
|
(dom-set-inner-html _el-tmpl "<b>hello</b>")
|
|
(dom-append (dom-body) _el-target)
|
|
(dom-append _el-target _el-tmpl)
|
|
(hs-activate! _el-target)
|
|
))
|
|
(deftest "render here with args"
|
|
(hs-cleanup!)
|
|
(let ((_el-target (dom-create-element "div")) (_el-tmpl (dom-create-element "script")))
|
|
(dom-set-attr _el-target "id" "target")
|
|
(dom-set-attr _el-target "_" "on click render #tmpl with x: 'world' here")
|
|
(dom-set-attr _el-tmpl "id" "tmpl")
|
|
(dom-set-attr _el-tmpl "type" "text/hyperscript-template")
|
|
(dom-set-inner-html _el-tmpl "<b>${x}</b>")
|
|
(dom-append (dom-body) _el-target)
|
|
(dom-append _el-target _el-tmpl)
|
|
(hs-activate! _el-target)
|
|
))
|
|
(deftest "render into sets innerHTML of target element"
|
|
(hs-cleanup!)
|
|
(let ((_el-tmpl (dom-create-element "script")) (_el-target (dom-create-element "div")) (_el-button (dom-create-element "button")))
|
|
(dom-set-attr _el-tmpl "id" "tmpl")
|
|
(dom-set-attr _el-tmpl "type" "text/hyperscript-template")
|
|
(dom-set-inner-html _el-tmpl "<b>hello</b>")
|
|
(dom-set-attr _el-target "id" "target")
|
|
(dom-set-attr _el-button "_" "on click render #tmpl into #target")
|
|
(dom-set-inner-html _el-button "go")
|
|
(dom-append (dom-body) _el-tmpl)
|
|
(dom-append (dom-body) _el-target)
|
|
(dom-append (dom-body) _el-button)
|
|
(hs-activate! _el-button)
|
|
))
|
|
(deftest "render into with args"
|
|
(hs-cleanup!)
|
|
(let ((_el-tmpl (dom-create-element "script")) (_el-target (dom-create-element "div")) (_el-button (dom-create-element "button")))
|
|
(dom-set-attr _el-tmpl "id" "tmpl")
|
|
(dom-set-attr _el-tmpl "type" "text/hyperscript-template")
|
|
(dom-set-inner-html _el-tmpl "<b>${x}</b>")
|
|
(dom-set-attr _el-target "id" "target")
|
|
(dom-set-attr _el-button "_" "on click render #tmpl with x: 'world' into #target")
|
|
(dom-set-inner-html _el-button "go")
|
|
(dom-append (dom-body) _el-tmpl)
|
|
(dom-append (dom-body) _el-target)
|
|
(dom-append (dom-body) _el-button)
|
|
(hs-activate! _el-button)
|
|
))
|
|
(deftest "renders into DOM element"
|
|
(hs-cleanup!)
|
|
(let ((_el-script (dom-create-element "script")) (_el-target (dom-create-element "div")))
|
|
(dom-set-attr _el-script "type" "text/hyperscript-template")
|
|
(dom-set-inner-html _el-script "<b>${x}</b>")
|
|
(dom-set-attr _el-target "id" "target")
|
|
(dom-append (dom-body) _el-script)
|
|
(dom-append (dom-body) _el-target)
|
|
))
|
|
(deftest "supports break in template for loops"
|
|
(hs-cleanup!)
|
|
(let ((_el-script (dom-create-element "script")))
|
|
(dom-set-attr _el-script "type" "text/hyperscript-template")
|
|
(dom-set-inner-html _el-script "#for item in items
|
|
#if item === 3
|
|
#break
|
|
#end
|
|
${item}
|
|
#end")
|
|
(dom-append (dom-body) _el-script)
|
|
))
|
|
(deftest "supports conditional expressions in loops"
|
|
(hs-cleanup!)
|
|
(let ((_el-script (dom-create-element "script")))
|
|
(dom-set-attr _el-script "type" "text/hyperscript-template")
|
|
(dom-set-inner-html _el-script "#for item in items
|
|
${item.name if item.show else \"Hidden\"}
|
|
#end")
|
|
(dom-append (dom-body) _el-script)
|
|
))
|
|
(deftest "supports conditional expressions with complex 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 "Status: ${user.name if user.active else \"Inactive\"}")
|
|
(dom-append (dom-body) _el-script)
|
|
))
|
|
(deftest "supports conditional expressions with if"
|
|
(hs-cleanup!)
|
|
(let ((_el-script (dom-create-element "script")))
|
|
(dom-set-attr _el-script "type" "text/hyperscript-template")
|
|
(dom-set-inner-html _el-script "Result: ${value if condition}")
|
|
(dom-append (dom-body) _el-script)
|
|
))
|
|
(deftest "supports conditional expressions with if (false condition)"
|
|
(hs-cleanup!)
|
|
(let ((_el-script (dom-create-element "script")))
|
|
(dom-set-attr _el-script "type" "text/hyperscript-template")
|
|
(dom-set-inner-html _el-script "Result: ${value if condition}")
|
|
(dom-append (dom-body) _el-script)
|
|
))
|
|
(deftest "supports conditional expressions with if...else"
|
|
(hs-cleanup!)
|
|
(let ((_el-script (dom-create-element "script")))
|
|
(dom-set-attr _el-script "type" "text/hyperscript-template")
|
|
(dom-set-inner-html _el-script "Result: ${value if condition else fallback}")
|
|
(dom-append (dom-body) _el-script)
|
|
))
|
|
(deftest "supports continue in template for loops"
|
|
(hs-cleanup!)
|
|
(let ((_el-script (dom-create-element "script")))
|
|
(dom-set-attr _el-script "type" "text/hyperscript-template")
|
|
(dom-set-inner-html _el-script "#for item in items
|
|
#if item === 2
|
|
#continue
|
|
#end
|
|
${item}
|
|
#end")
|
|
(dom-append (dom-body) _el-script)
|
|
))
|
|
(deftest "supports for...else with empty collection"
|
|
(hs-cleanup!)
|
|
(let ((_el-script (dom-create-element "script")))
|
|
(dom-set-attr _el-script "type" "text/hyperscript-template")
|
|
(dom-set-inner-html _el-script "#for item in items
|
|
Found: ${item}
|
|
#else
|
|
No items found
|
|
#end")
|
|
(dom-append (dom-body) _el-script)
|
|
))
|
|
(deftest "supports for...else with non-empty collection"
|
|
(hs-cleanup!)
|
|
(let ((_el-script (dom-create-element "script")))
|
|
(dom-set-attr _el-script "type" "text/hyperscript-template")
|
|
(dom-set-inner-html _el-script "#for item in items
|
|
Found: ${item}
|
|
#else
|
|
No items found
|
|
#end")
|
|
(dom-append (dom-body) _el-script)
|
|
))
|
|
(deftest "supports for...else with null collection"
|
|
(hs-cleanup!)
|
|
(let ((_el-script (dom-create-element "script")))
|
|
(dom-set-attr _el-script "type" "text/hyperscript-template")
|
|
(dom-set-inner-html _el-script "#for item in items
|
|
Found: ${item}
|
|
#else
|
|
Nothing to show
|
|
#end")
|
|
(dom-append (dom-body) _el-script)
|
|
))
|
|
(deftest "supports if"
|
|
(hs-cleanup!)
|
|
(let ((_el-script (dom-create-element "script")))
|
|
(dom-set-attr _el-script "type" "text/hyperscript-template")
|
|
(dom-set-inner-html _el-script "begin
|
|
#if true
|
|
a
|
|
#else
|
|
b
|
|
#end
|
|
end")
|
|
(dom-append (dom-body) _el-script)
|
|
))
|
|
(deftest "supports nested operations"
|
|
(hs-cleanup!)
|
|
(let ((_el-script (dom-create-element "script")))
|
|
(dom-set-attr _el-script "type" "text/hyperscript-template")
|
|
(dom-set-inner-html _el-script "#for x in stuff
|
|
#if x === 2
|
|
<p>Should be 2 -> ${x}</p>
|
|
#end
|
|
#end")
|
|
(dom-append (dom-body) _el-script)
|
|
))
|
|
(deftest "supports repeat"
|
|
(hs-cleanup!)
|
|
(let ((_el-script (dom-create-element "script")))
|
|
(dom-set-attr _el-script "type" "text/hyperscript-template")
|
|
(dom-set-inner-html _el-script "begin
|
|
#for it in [1, 2, 3]
|
|
${it}
|
|
#end
|
|
end")
|
|
(dom-append (dom-body) _el-script)
|
|
))
|
|
)
|
|
|
|
;; ── throw (7 tests) ──
|
|
(defsuite "hs-upstream-throw"
|
|
(deftest "async exceptions as throws propagate properly"
|
|
(hs-cleanup!)
|
|
(guard (_e (true nil)) (eval-expr-cek (hs-to-sx (hs-compile "def foo() wait 2ms call bar() end"))))
|
|
)
|
|
(deftest "async exceptions propagate properly"
|
|
(hs-cleanup!)
|
|
(guard (_e (true nil)) (eval-expr-cek (hs-to-sx (hs-compile "def foo() wait 2ms throw \"foo\" end def bar() call foo() end"))))
|
|
)
|
|
(deftest "can respond to async exceptions in an event handler with an event handler"
|
|
(hs-cleanup!)
|
|
(let ((_el-d1 (dom-create-element "div")))
|
|
(dom-set-attr _el-d1 "id" "d1")
|
|
(dom-set-attr _el-d1 "_" "on click wait 2ms then throw \"foo\" then put \"bar\" into my.innerHTML end on exception(error) put error into my.innerHTML end")
|
|
(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 respond to exceptions in an event handler with an event handler"
|
|
(hs-cleanup!)
|
|
(let ((_el-d1 (dom-create-element "div")))
|
|
(dom-set-attr _el-d1 "id" "d1")
|
|
(dom-set-attr _el-d1 "_" "on click throw \"foo\" then put \"bar\" into my.innerHTML end on exception(error) put error into my.innerHTML end")
|
|
(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 throw a basic exception"
|
|
(hs-cleanup!)
|
|
(guard (_e (true nil)) (eval-expr-cek (hs-to-sx (hs-compile "def foo() throw \"foo\" end"))))
|
|
)
|
|
(deftest "can throw an async exception"
|
|
(hs-cleanup!)
|
|
(guard (_e (true nil)) (eval-expr-cek (hs-to-sx (hs-compile "def foo() wait 2ms throw \"foo\" end"))))
|
|
)
|
|
(deftest "can throw inside an event handler"
|
|
(hs-cleanup!)
|
|
(let ((_el-d1 (dom-create-element "div")))
|
|
(dom-set-attr _el-d1 "id" "d1")
|
|
(dom-set-attr _el-d1 "_" "on click throw \"foo\" then put \"bar\" into my.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")) "")
|
|
))
|
|
)
|
|
|
|
;; ── toggle (25 tests) ──
|
|
(defsuite "hs-upstream-toggle"
|
|
(deftest "can target another div for class ref toggle"
|
|
(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 toggle .foo on #bar")
|
|
(dom-append (dom-body) _el-bar)
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
(assert (not (dom-has-class? (dom-query-by-id "bar") "foo")))
|
|
(dom-dispatch (dom-query "div:nth-of-type(2)") "click" nil)
|
|
(assert (dom-has-class? (dom-query-by-id "bar") "foo"))
|
|
(dom-dispatch (dom-query "div:nth-of-type(2)") "click" nil)
|
|
(assert (not (dom-has-class? (dom-query-by-id "bar") "foo")))
|
|
))
|
|
(deftest "can toggle *display between two values"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click toggle *display of me between 'none' and 'flex'")
|
|
(dom-set-attr _el-div "style" "display:none")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
(assert= (dom-get-style _el-div "display") "none")
|
|
(dom-dispatch _el-div "click" nil)
|
|
(assert= (dom-get-style _el-div "display") "flex")
|
|
(dom-dispatch _el-div "click" nil)
|
|
(assert= (dom-get-style _el-div "display") "none")
|
|
))
|
|
(deftest "can toggle *opacity between three values"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click toggle *opacity of me between '0', '0.5' and '1'")
|
|
(dom-set-attr _el-div "style" "opacity:0")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
(assert= (dom-get-style _el-div "opacity") "0")
|
|
(dom-dispatch _el-div "click" nil)
|
|
(assert= (dom-get-style _el-div "opacity") "0.5")
|
|
(dom-dispatch _el-div "click" nil)
|
|
(assert= (dom-get-style _el-div "opacity") "1")
|
|
(dom-dispatch _el-div "click" nil)
|
|
(assert= (dom-get-style _el-div "opacity") "0")
|
|
))
|
|
(deftest "can toggle a global variable between three values"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click toggle $state between 'a', 'b' and 'c'")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
(dom-dispatch _el-div "click" nil)
|
|
(dom-dispatch _el-div "click" nil)
|
|
(dom-dispatch _el-div "click" nil)
|
|
(dom-dispatch _el-div "click" nil)
|
|
))
|
|
(deftest "can toggle a global variable between two values"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click toggle $mode between 'edit' and 'preview'")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
(dom-dispatch _el-div "click" nil)
|
|
(dom-dispatch _el-div "click" nil)
|
|
(dom-dispatch _el-div "click" nil)
|
|
))
|
|
(deftest "can toggle between different attributes"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click toggle between [@enabled='true'] and [@disabled='true']")
|
|
(dom-set-attr _el-div "enabled" "true")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
(assert= (dom-get-attr _el-div "enabled") "true")
|
|
(dom-dispatch _el-div "click" nil)
|
|
(assert= (dom-get-attr _el-div "disabled") "true")
|
|
(dom-dispatch _el-div "click" nil)
|
|
(assert= (dom-get-attr _el-div "enabled") "true")
|
|
))
|
|
(deftest "can toggle between two attribute values"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click toggle between [@data-state='active'] and [@data-state='inactive']")
|
|
(dom-set-attr _el-div "data-state" "active")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
(assert= (dom-get-attr _el-div "data-state") "active")
|
|
(dom-dispatch _el-div "click" nil)
|
|
(assert= (dom-get-attr _el-div "data-state") "inactive")
|
|
(dom-dispatch _el-div "click" nil)
|
|
(assert= (dom-get-attr _el-div "data-state") "active")
|
|
))
|
|
(deftest "can toggle between two classes"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-add-class _el-div "foo")
|
|
(dom-set-attr _el-div "_" "on click toggle between .foo and .bar")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
(assert (dom-has-class? _el-div "foo"))
|
|
(assert (not (dom-has-class? _el-div "bar")))
|
|
(dom-dispatch _el-div "click" nil)
|
|
(assert (not (dom-has-class? _el-div "foo")))
|
|
(assert (dom-has-class? _el-div "bar"))
|
|
(dom-dispatch _el-div "click" nil)
|
|
(assert (dom-has-class? _el-div "foo"))
|
|
(assert (not (dom-has-class? _el-div "bar")))
|
|
))
|
|
(deftest "can toggle class ref on a single div"
|
|
(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)
|
|
(assert (not (dom-has-class? _el-div "foo")))
|
|
(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")))
|
|
))
|
|
(deftest "can toggle class ref on a single form"
|
|
(hs-cleanup!)
|
|
(let ((_el-form (dom-create-element "form")))
|
|
(dom-set-attr _el-form "_" "on click toggle .foo")
|
|
(dom-append (dom-body) _el-form)
|
|
(hs-activate! _el-form)
|
|
(assert (not (dom-has-class? _el-form "foo")))
|
|
(dom-dispatch _el-form "click" nil)
|
|
(assert (dom-has-class? _el-form "foo"))
|
|
(dom-dispatch _el-form "click" nil)
|
|
(assert (not (dom-has-class? _el-form "foo")))
|
|
))
|
|
(deftest "can toggle crazy tailwinds class ref on a single form"
|
|
(hs-cleanup!)
|
|
(let ((_el-form (dom-create-element "form")))
|
|
(dom-set-attr _el-form "_" "on click toggle .group-[:nth-of-type(3)_&]:block")
|
|
(dom-append (dom-body) _el-form)
|
|
(hs-activate! _el-form)
|
|
(dom-dispatch _el-form "click" nil)
|
|
(dom-dispatch _el-form "click" nil)
|
|
))
|
|
(deftest "can toggle display"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click toggle *display")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
(assert= (dom-get-style _el-div "display") "block")
|
|
(dom-dispatch _el-div "click" nil)
|
|
(assert= (dom-get-style _el-div "display") "none")
|
|
(dom-dispatch _el-div "click" nil)
|
|
(assert= (dom-get-style _el-div "display") "block")
|
|
))
|
|
(deftest "can toggle display on other elt"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")) (_el-d2 (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click toggle the *display of #d2")
|
|
(dom-set-attr _el-d2 "id" "d2")
|
|
(dom-append (dom-body) _el-div)
|
|
(dom-append (dom-body) _el-d2)
|
|
(hs-activate! _el-div)
|
|
(assert= (dom-get-style (dom-query-by-id "d2") "display") "block")
|
|
(dom-dispatch (nth (dom-query-all (dom-body) "div") 0) "click" nil)
|
|
(assert= (dom-get-style (dom-query-by-id "d2") "display") "none")
|
|
(dom-dispatch (nth (dom-query-all (dom-body) "div") 0) "click" nil)
|
|
(assert= (dom-get-style (dom-query-by-id "d2") "display") "block")
|
|
))
|
|
(deftest "can toggle display w/ my"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click toggle my *display")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
(assert= (dom-get-style _el-div "display") "block")
|
|
(dom-dispatch _el-div "click" nil)
|
|
(assert= (dom-get-style _el-div "display") "none")
|
|
(dom-dispatch _el-div "click" nil)
|
|
(assert= (dom-get-style _el-div "display") "block")
|
|
))
|
|
(deftest "can toggle for a fixed amount of time"
|
|
(hs-cleanup!)
|
|
(let ((_el (dom-create-element "div")))
|
|
(dom-set-attr _el "_" "on click toggle .foo for 10ms")
|
|
(dom-append (dom-body) _el)
|
|
(hs-activate! _el)
|
|
(assert (not (dom-has-class? _el "foo")))
|
|
(dom-dispatch _el "click" nil)
|
|
(assert (dom-has-class? _el "foo")))
|
|
)
|
|
(deftest "can toggle multiple class refs"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-add-class _el-div "bar")
|
|
(dom-set-attr _el-div "_" "on click toggle .foo .bar")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
(assert (not (dom-has-class? _el-div "foo")))
|
|
(assert (dom-has-class? _el-div "bar"))
|
|
(dom-dispatch _el-div "click" nil)
|
|
(assert (dom-has-class? _el-div "foo"))
|
|
(assert (not (dom-has-class? _el-div "bar")))
|
|
(dom-dispatch _el-div "click" nil)
|
|
(assert (not (dom-has-class? _el-div "foo")))
|
|
(assert (dom-has-class? _el-div "bar"))
|
|
))
|
|
(deftest "can toggle non-class attributes"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click toggle [@foo=\"bar\"]")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
(assert (not (dom-has-attr? _el-div "foo")))
|
|
(dom-dispatch _el-div "click" nil)
|
|
(assert= (dom-get-attr _el-div "foo") "bar")
|
|
(dom-dispatch _el-div "click" nil)
|
|
(assert (not (dom-has-attr? _el-div "foo")))
|
|
))
|
|
(deftest "can toggle non-class attributes on selects"
|
|
(hs-cleanup!)
|
|
(let ((_el-select (dom-create-element "select")))
|
|
(dom-set-attr _el-select "_" "on click toggle [@foo=\"bar\"]")
|
|
(dom-append (dom-body) _el-select)
|
|
(hs-activate! _el-select)
|
|
(assert (not (dom-has-attr? _el-select "foo")))
|
|
(dom-dispatch _el-select "click" nil)
|
|
(assert= (dom-get-attr _el-select "foo") "bar")
|
|
(dom-dispatch _el-select "click" nil)
|
|
(assert (not (dom-has-attr? _el-select "foo")))
|
|
))
|
|
(deftest "can toggle opacity"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click toggle *opacity")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
(assert= (dom-get-style _el-div "opacity") "1")
|
|
(dom-dispatch _el-div "click" nil)
|
|
(assert= (dom-get-style _el-div "opacity") "0")
|
|
(dom-dispatch _el-div "click" nil)
|
|
(assert= (dom-get-style _el-div "opacity") "1")
|
|
))
|
|
(deftest "can toggle opacity on other elt"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")) (_el-d2 (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click toggle the *opacity of #d2")
|
|
(dom-set-attr _el-d2 "id" "d2")
|
|
(dom-append (dom-body) _el-div)
|
|
(dom-append (dom-body) _el-d2)
|
|
(hs-activate! _el-div)
|
|
(assert= (dom-get-style (dom-query-by-id "d2") "opacity") "1")
|
|
(dom-dispatch (nth (dom-query-all (dom-body) "div") 0) "click" nil)
|
|
(assert= (dom-get-style (dom-query-by-id "d2") "opacity") "0")
|
|
(dom-dispatch (nth (dom-query-all (dom-body) "div") 0) "click" nil)
|
|
(assert= (dom-get-style (dom-query-by-id "d2") "opacity") "1")
|
|
))
|
|
(deftest "can toggle opacity w/ my"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click toggle my *opacity")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
(assert= (dom-get-style _el-div "opacity") "1")
|
|
(dom-dispatch _el-div "click" nil)
|
|
(assert= (dom-get-style _el-div "opacity") "0")
|
|
(dom-dispatch _el-div "click" nil)
|
|
(assert= (dom-get-style _el-div "opacity") "1")
|
|
))
|
|
(deftest "can toggle until an event on another element"
|
|
(hs-cleanup!)
|
|
(let ((_el-d1 (dom-create-element "div")) (_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-d1 "id" "d1")
|
|
(dom-set-attr _el-div "_" "on click toggle .foo until foo from #d1")
|
|
(dom-append (dom-body) _el-d1)
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
(assert (not (dom-has-class? (dom-query "div:nth-of-type(2)") "foo")))
|
|
(dom-dispatch (dom-query "div:nth-of-type(2)") "click" nil)
|
|
(assert (dom-has-class? (dom-query "div:nth-of-type(2)") "foo"))
|
|
(dom-dispatch (dom-query-by-id "d1") "foo" nil)
|
|
(assert (not (dom-has-class? (dom-query "div:nth-of-type(2)") "foo")))
|
|
))
|
|
(deftest "can toggle visibility"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click toggle *visibility")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
(assert= (dom-get-style _el-div "visibility") "visible")
|
|
(dom-dispatch _el-div "click" nil)
|
|
(assert= (dom-get-style _el-div "visibility") "hidden")
|
|
(dom-dispatch _el-div "click" nil)
|
|
(assert= (dom-get-style _el-div "visibility") "visible")
|
|
))
|
|
(deftest "can toggle visibility on other elt"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")) (_el-d2 (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click toggle the *visibility of #d2")
|
|
(dom-set-attr _el-d2 "id" "d2")
|
|
(dom-append (dom-body) _el-div)
|
|
(dom-append (dom-body) _el-d2)
|
|
(hs-activate! _el-div)
|
|
(assert= (dom-get-style (dom-query-by-id "d2") "visibility") "visible")
|
|
(dom-dispatch (nth (dom-query-all (dom-body) "div") 0) "click" nil)
|
|
(assert= (dom-get-style (dom-query-by-id "d2") "visibility") "hidden")
|
|
(dom-dispatch (nth (dom-query-all (dom-body) "div") 0) "click" nil)
|
|
(assert= (dom-get-style (dom-query-by-id "d2") "visibility") "visible")
|
|
))
|
|
(deftest "can toggle visibility w/ my"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click toggle my *visibility")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
(assert= (dom-get-style _el-div "visibility") "visible")
|
|
(dom-dispatch _el-div "click" nil)
|
|
(assert= (dom-get-style _el-div "visibility") "hidden")
|
|
(dom-dispatch _el-div "click" nil)
|
|
(assert= (dom-get-style _el-div "visibility") "visible")
|
|
))
|
|
)
|
|
|
|
;; ── transition (17 tests) ──
|
|
(defsuite "hs-upstream-transition"
|
|
(deftest "can transition a single property on current element"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click transition *width from 0px to 100px")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
(dom-dispatch _el-div "click" nil)
|
|
(assert= (dom-get-style _el-div "width") "100px")
|
|
))
|
|
(deftest "can transition a single property on current element using style ref"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click transition *width from 0px to 100px")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
(dom-dispatch _el-div "click" nil)
|
|
(assert= (dom-get-style _el-div "width") "100px")
|
|
))
|
|
(deftest "can transition a single property on current element with the my prefix"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click transition my *width from 0px to 100px")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
(dom-dispatch _el-div "click" nil)
|
|
(assert= (dom-get-style _el-div "width") "100px")
|
|
))
|
|
(deftest "can transition a single property on current element with the my prefix using style ref"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click transition my *width from 0px to 100px")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
(dom-dispatch _el-div "click" nil)
|
|
(assert= (dom-get-style _el-div "width") "100px")
|
|
))
|
|
(deftest "can transition a single property on form"
|
|
(hs-cleanup!)
|
|
(let ((_el-form (dom-create-element "form")))
|
|
(dom-set-attr _el-form "_" "on click transition *width from 0px to 100px")
|
|
(dom-append (dom-body) _el-form)
|
|
(hs-activate! _el-form)
|
|
(dom-dispatch _el-form "click" nil)
|
|
(assert= (dom-get-style _el-form "width") "100px")
|
|
))
|
|
(deftest "can transition a single property on form using style ref"
|
|
(hs-cleanup!)
|
|
(let ((_el-form (dom-create-element "form")))
|
|
(dom-set-attr _el-form "_" "on click transition *width from 0px to 100px")
|
|
(dom-append (dom-body) _el-form)
|
|
(hs-activate! _el-form)
|
|
(dom-dispatch _el-form "click" nil)
|
|
(assert= (dom-get-style _el-form "width") "100px")
|
|
))
|
|
(deftest "can transition on another element"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")) (_el-foo (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click transition #foo's *width from 0px to 100px")
|
|
(dom-set-attr _el-foo "id" "foo")
|
|
(dom-append (dom-body) _el-div)
|
|
(dom-append (dom-body) _el-foo)
|
|
(hs-activate! _el-div)
|
|
(dom-dispatch (nth (dom-query-all (dom-body) "div") 0) "click" nil)
|
|
(assert= (dom-get-style (dom-query-by-id "foo") "width") "100px")
|
|
))
|
|
(deftest "can transition on another element with it"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")) (_el-foo (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click get #foo then transition its *width from 0px to 100px")
|
|
(dom-set-attr _el-foo "id" "foo")
|
|
(dom-append (dom-body) _el-div)
|
|
(dom-append (dom-body) _el-foo)
|
|
(hs-activate! _el-div)
|
|
(dom-dispatch (nth (dom-query-all (dom-body) "div") 0) "click" nil)
|
|
(assert= (dom-get-style (dom-query-by-id "foo") "width") "100px")
|
|
))
|
|
(deftest "can transition on another element with of syntax"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")) (_el-foo (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click transition *width of #foo from 0px to 100px")
|
|
(dom-set-attr _el-foo "id" "foo")
|
|
(dom-append (dom-body) _el-div)
|
|
(dom-append (dom-body) _el-foo)
|
|
(hs-activate! _el-div)
|
|
(dom-dispatch (nth (dom-query-all (dom-body) "div") 0) "click" nil)
|
|
(assert= (dom-get-style (dom-query-by-id "foo") "width") "100px")
|
|
))
|
|
(deftest "can transition on another element with possessive"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")) (_el-foo (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click transition #foo's *width from 0px to 100px")
|
|
(dom-set-attr _el-foo "id" "foo")
|
|
(dom-append (dom-body) _el-div)
|
|
(dom-append (dom-body) _el-foo)
|
|
(hs-activate! _el-div)
|
|
(dom-dispatch (nth (dom-query-all (dom-body) "div") 0) "click" nil)
|
|
(assert= (dom-get-style (dom-query-by-id "foo") "width") "100px")
|
|
))
|
|
(deftest "can transition on query ref with of syntax"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")) (_el-span (dom-create-element "span")))
|
|
(dom-set-attr _el-div "_" "on click transition *width of the next <span/> from 0px to 100px")
|
|
(dom-append (dom-body) _el-div)
|
|
(dom-append (dom-body) _el-span)
|
|
(hs-activate! _el-div)
|
|
(dom-dispatch _el-div "click" nil)
|
|
(assert= (dom-get-style _el-span "width") "100px")
|
|
))
|
|
(deftest "can transition on query ref with possessive"
|
|
(error "SKIP (untranslated): can transition on query ref with possessive"))
|
|
(deftest "can transition two properties on current element"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click transition *width from 0px to 100px *height from 0px to 100px")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
(dom-dispatch _el-div "click" nil)
|
|
(assert= (dom-get-style _el-div "width") "100px")
|
|
(assert= (dom-get-style _el-div "height") "100px")
|
|
))
|
|
(deftest "can transition with a custom transition string"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")) (_el-foo (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click transition #foo's *width from 0px to 100px using \"width 2s ease-in\"")
|
|
(dom-set-attr _el-foo "id" "foo")
|
|
(dom-append (dom-body) _el-div)
|
|
(dom-append (dom-body) _el-foo)
|
|
(hs-activate! _el-div)
|
|
(dom-dispatch (nth (dom-query-all (dom-body) "div") 0) "click" nil)
|
|
(assert= (dom-get-style (dom-query-by-id "foo") "width") "100px")
|
|
))
|
|
(deftest "can transition with a custom transition time via the over syntax"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")) (_el-foo (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click transition #foo's *width from 0px to 100px over 2s")
|
|
(dom-set-attr _el-foo "id" "foo")
|
|
(dom-append (dom-body) _el-div)
|
|
(dom-append (dom-body) _el-foo)
|
|
(hs-activate! _el-div)
|
|
(dom-dispatch (nth (dom-query-all (dom-body) "div") 0) "click" nil)
|
|
(assert= (dom-get-style (dom-query-by-id "foo") "width") "100px")
|
|
))
|
|
(deftest "can transition with parameterized values"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click set startWidth to 0 then set endWidth to 100 transition *width from (startWidth)px to (endWidth)px")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
(dom-dispatch _el-div "click" nil)
|
|
(assert= (dom-get-style _el-div "width") "100px")
|
|
))
|
|
(deftest "can use initial to transition to original value"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click 1 transition my *width to 100px on click 2 transition my *width to initial")
|
|
(dom-set-attr _el-div "style" "width: 10px")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
(dom-dispatch _el-div "click" nil)
|
|
(assert= (dom-get-style _el-div "width") "100px")
|
|
(dom-dispatch _el-div "click" nil)
|
|
(assert= (dom-get-style _el-div "width") "10px")
|
|
))
|
|
)
|
|
|
|
;; ── trigger (6 tests) ──
|
|
(defsuite "hs-upstream-trigger"
|
|
(deftest "can trigger events"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click trigger foo end on foo add .foo-set end")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
(assert (not (dom-has-class? _el-div "foo-set")))
|
|
(dom-dispatch _el-div "click" nil)
|
|
(assert (dom-has-class? _el-div "foo-set"))
|
|
))
|
|
(deftest "can trigger events with args"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click trigger foo(x:42) end on foo(x) put x 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 trigger events with colons"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click trigger foo:bar end on foo:bar add .foo-set end")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
(assert (not (dom-has-class? _el-div "foo-set")))
|
|
(dom-dispatch _el-div "click" nil)
|
|
(assert (dom-has-class? _el-div "foo-set"))
|
|
))
|
|
(deftest "can trigger events with dots"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click trigger foo.bar end on foo.bar add .foo-set end")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
(assert (not (dom-has-class? _el-div "foo-set")))
|
|
(dom-dispatch _el-div "click" nil)
|
|
(assert (dom-has-class? _el-div "foo-set"))
|
|
))
|
|
(deftest "can trigger events with dots with args"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click trigger foo.bar(x:42) end on foo.bar(x) put x 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 trigger events with dots with colons"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click trigger foo:bar(x:42) end on foo:bar(x) put x 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")
|
|
))
|
|
)
|
|
|
|
;; ── unlessModifier (1 tests) ──
|
|
(defsuite "hs-upstream-unlessModifier"
|
|
(deftest "unless modifier can conditionally execute a command"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click toggle .foo unless I match .bar")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
(assert (not (dom-has-class? _el-div "foo")))
|
|
(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")))
|
|
(dom-add-class _el-div "bar")
|
|
(assert (not (dom-has-class? _el-div "foo")))
|
|
(dom-dispatch _el-div "click" nil)
|
|
(assert (not (dom-has-class? _el-div "foo")))
|
|
(dom-dispatch _el-div "click" nil)
|
|
(assert (not (dom-has-class? _el-div "foo")))
|
|
))
|
|
)
|
|
|
|
;; ── viewTransition (9 tests) ──
|
|
(defsuite "hs-upstream-viewTransition"
|
|
(deftest "accepts an optional 'using' type string"
|
|
(hs-cleanup!)
|
|
(let ((_el-button (dom-create-element "button")))
|
|
(dom-set-attr _el-button "_" "on click start view transition using \"slide\" then add .typed to me end")
|
|
(dom-set-inner-html _el-button "go")
|
|
(dom-append (dom-body) _el-button)
|
|
(hs-activate! _el-button)
|
|
))
|
|
(deftest "break inside a loop inside a view transition is NOT replaced"
|
|
(hs-cleanup!)
|
|
(let ((_el-button (dom-create-element "button")))
|
|
(dom-set-attr _el-button "_" "on click start view transition then repeat 3 times add .in-loop to me then break end add .after-loop to me end")
|
|
(dom-set-inner-html _el-button "go")
|
|
(dom-append (dom-body) _el-button)
|
|
(hs-activate! _el-button)
|
|
))
|
|
(deftest "exit inside a view transition skips the animation"
|
|
(hs-cleanup!)
|
|
(let ((_el-button (dom-create-element "button")))
|
|
(dom-set-attr _el-button "_" "on click start view transition then add .before to me then exit then add .after to me end")
|
|
(dom-set-inner-html _el-button "go")
|
|
(dom-append (dom-body) _el-button)
|
|
(hs-activate! _el-button)
|
|
))
|
|
(deftest "halt the event inside a view transition skips the animation"
|
|
(hs-cleanup!)
|
|
(let ((_el-button (dom-create-element "button")))
|
|
(dom-set-attr _el-button "_" "on click start view transition then add .before to me then halt end add .after to me")
|
|
(dom-set-inner-html _el-button "go")
|
|
(dom-append (dom-body) _el-button)
|
|
(hs-activate! _el-button)
|
|
))
|
|
(deftest "return inside a def called from a view transition skips the animation"
|
|
(hs-cleanup!)
|
|
(guard (_e (true nil)) (eval-expr-cek (hs-to-sx (hs-compile "def escapeIt return 42 end"))))
|
|
(guard (_e (true nil)) (eval-expr-cek (hs-to-sx (hs-compile "def escapeIt return 42 end"))))
|
|
(let ((_el-button (dom-create-element "button")))
|
|
(dom-set-attr _el-button "_" "on click start view transition then add .before to me then return then add .after to me end add .after-handler to me")
|
|
(dom-set-inner-html _el-button "go")
|
|
(dom-append (dom-body) _el-button)
|
|
(hs-activate! _el-button)
|
|
))
|
|
(deftest "return inside an if branch inside a view transition skips the animation"
|
|
(hs-cleanup!)
|
|
(let ((_el-button (dom-create-element "button")))
|
|
(dom-set-attr _el-button "_" "on click start view transition then add .before to me then if true then return end add .after to me end")
|
|
(dom-set-inner-html _el-button "go")
|
|
(dom-append (dom-body) _el-button)
|
|
(hs-activate! _el-button)
|
|
))
|
|
(deftest "runs the body when view transitions API is available"
|
|
(hs-cleanup!)
|
|
(let ((_el-button (dom-create-element "button")))
|
|
(dom-set-attr _el-button "_" "on click start view transition then add .done to me end")
|
|
(dom-set-inner-html _el-button "go")
|
|
(dom-append (dom-body) _el-button)
|
|
(hs-activate! _el-button)
|
|
))
|
|
(deftest "runs the body when view transitions API is unavailable"
|
|
(hs-cleanup!)
|
|
(let ((_el-button (dom-create-element "button")))
|
|
(dom-set-attr _el-button "_" "on click start view transition then add .done to me end")
|
|
(dom-set-inner-html _el-button "go")
|
|
(dom-append (dom-body) _el-button)
|
|
(hs-activate! _el-button)
|
|
))
|
|
(deftest "throws if a view transition is already in progress"
|
|
(hs-cleanup!)
|
|
(let ((_el-button (dom-create-element "button")))
|
|
(dom-set-attr _el-button "_" "on click start view transition then start view transition then add .inner to me end end")
|
|
(dom-set-inner-html _el-button "go")
|
|
(dom-append (dom-body) _el-button)
|
|
(hs-activate! _el-button)
|
|
))
|
|
)
|
|
|
|
;; ── wait (7 tests) ──
|
|
(defsuite "hs-upstream-wait"
|
|
(deftest "can destructure properties in a wait"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click wait for foo(bar) then put bar into me")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
(dom-dispatch _el-div "click" nil)
|
|
(dom-dispatch _el-div "foo" {:bar "bar"})
|
|
(assert= (dom-text-content _el-div) "bar")
|
|
))
|
|
(deftest "can wait on event"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click add .foo then wait for foo 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 (not (dom-has-class? _el-div "bar")))
|
|
(dom-dispatch _el-div "foo" nil)
|
|
(assert (dom-has-class? _el-div "bar"))
|
|
))
|
|
(deftest "can wait on event on another element"
|
|
(hs-cleanup!)
|
|
(let ((_el-d2 (dom-create-element "div")) (_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-d2 "id" "d2")
|
|
(dom-set-attr _el-div "_" "on click add .foo then wait for foo from #d2 then add .bar")
|
|
(dom-append (dom-body) _el-d2)
|
|
(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 "div:nth-of-type(2)") "foo"))
|
|
(assert (not (dom-has-class? (dom-query "div:nth-of-type(2)") "bar")))
|
|
(dom-dispatch (dom-query-by-id "d2") "foo" nil)
|
|
(assert (dom-has-class? (dom-query "div:nth-of-type(2)") "bar"))
|
|
))
|
|
(deftest "can wait on event or timeout 1"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click add .foo then wait for foo or 0ms 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 "can wait on event or timeout 2"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click add .foo then wait for foo or 0ms 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 "can wait on time"
|
|
(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 "waiting on an event sets 'it' to the event"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "on click wait for foo then put its.detail into me")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
(dom-dispatch _el-div "click" nil)
|
|
(dom-dispatch _el-div "foo" "hyperscript is hyper cool")
|
|
(assert= (dom-text-content _el-div) "hyperscript is hyper cool")
|
|
))
|
|
)
|
|
|
|
;; ── when (41 tests) ──
|
|
(defsuite "hs-upstream-when"
|
|
(deftest "#element.checked is tracked"
|
|
(hs-cleanup!)
|
|
(let ((_el-cb-input (dom-create-element "input")) (_el-span (dom-create-element "span")))
|
|
(dom-set-attr _el-cb-input "id" "cb-input")
|
|
(dom-set-attr _el-cb-input "type" "checkbox")
|
|
(dom-set-attr _el-span "_" "when #cb-input.checked changes put it into me")
|
|
(dom-append (dom-body) _el-cb-input)
|
|
(dom-append (dom-body) _el-span)
|
|
(hs-activate! _el-span)
|
|
))
|
|
(deftest "attribute observers are persistent (not recreated on re-run)"
|
|
(error "SKIP (untranslated): attribute observers are persistent (not recreated on re-run)"))
|
|
(deftest "auto-tracks compound expressions"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "when ($a + $b) changes put it into me")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
))
|
|
(deftest "batches multiple synchronous writes into one effect run"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "when ($batchA + $batchB) changes increment :runCount then put :runCount into me")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
))
|
|
(deftest "boolean short-circuit does not track unread branch"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "when ($x and $y) changes put it into me")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
))
|
|
(deftest "circular guard resets after cascade settles"
|
|
(hs-cleanup!)
|
|
(let ((_el-span (dom-create-element "span")) (_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-span "_" "when $ping changes set $ping to (it + 1)")
|
|
(dom-set-attr _el-div "_" "when $ping changes put it into me")
|
|
(dom-append (dom-body) _el-span)
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-span)
|
|
(hs-activate! _el-div)
|
|
))
|
|
(deftest "comparison on tracked symbol works"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "when ($cmpVal > 5) changes put it into me")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
))
|
|
(deftest "cross-microtask ping-pong is caught by circular guard"
|
|
(hs-cleanup!)
|
|
(let ((_el-span (dom-create-element "span")) (_el-span1 (dom-create-element "span")) (_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-span "_" "when $ping changes set $pong to (it + 1)")
|
|
(dom-set-attr _el-span1 "_" "when $pong changes set $ping to (it + 1)")
|
|
(dom-set-attr _el-div "_" "when $ping changes put it into me")
|
|
(dom-append (dom-body) _el-span)
|
|
(dom-append (dom-body) _el-span1)
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-span)
|
|
(hs-activate! _el-span1)
|
|
(hs-activate! _el-div)
|
|
))
|
|
(deftest "detects attribute changes"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "when @data-title changes put it into me")
|
|
(dom-set-attr _el-div "data-title" "original")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
))
|
|
(deftest "detects changes from $global variable"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "when $global changes put it into me")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
))
|
|
(deftest "detects changes from :element variable"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "init set :count to 0 end when :count changes put it into me end on click increment :count")
|
|
(dom-set-inner-html _el-div "0")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
))
|
|
(deftest "detects form input value changes via user interaction"
|
|
(hs-cleanup!)
|
|
(let ((_el-reactive-input (dom-create-element "input")) (_el-span (dom-create-element "span")))
|
|
(dom-set-attr _el-reactive-input "id" "reactive-input")
|
|
(dom-set-attr _el-reactive-input "type" "text")
|
|
(dom-set-attr _el-reactive-input "value" "start")
|
|
(dom-set-attr _el-span "_" "when #reactive-input.value changes put it into me")
|
|
(dom-append (dom-body) _el-reactive-input)
|
|
(dom-append (dom-body) _el-span)
|
|
(hs-activate! _el-span)
|
|
))
|
|
(deftest "detects property change via hyperscript set"
|
|
(hs-cleanup!)
|
|
(let ((_el-prog-input (dom-create-element "input")) (_el-span (dom-create-element "span")))
|
|
(dom-set-attr _el-prog-input "id" "prog-input")
|
|
(dom-set-attr _el-prog-input "type" "text")
|
|
(dom-set-attr _el-prog-input "value" "initial")
|
|
(dom-set-attr _el-span "_" "when #prog-input.value changes put it into me")
|
|
(dom-append (dom-body) _el-prog-input)
|
|
(dom-append (dom-body) _el-span)
|
|
(hs-activate! _el-span)
|
|
))
|
|
(deftest "diamond: cascaded derived values produce correct final value"
|
|
(hs-cleanup!)
|
|
(let ((_el-d-b (dom-create-element "span")) (_el-d-c (dom-create-element "span")) (_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-d-b "id" "d-b")
|
|
(dom-set-attr _el-d-b "_" "when $a changes set $b to (it * 2)")
|
|
(dom-set-attr _el-d-c "id" "d-c")
|
|
(dom-set-attr _el-d-c "_" "when $a changes set $c to (it * 3)")
|
|
(dom-set-attr _el-div "_" "live increment :runs then put ($b + $c) + ' (runs:' + :runs + ')' into me")
|
|
(dom-append (dom-body) _el-d-b)
|
|
(dom-append (dom-body) _el-d-c)
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-d-b)
|
|
(hs-activate! _el-d-c)
|
|
(hs-activate! _el-div)
|
|
))
|
|
(deftest "disposes effect when element is removed from DOM"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "when $dispose changes put it into me")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
))
|
|
(deftest "does not cross-trigger on unrelated variable writes"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "when $trigger changes then increment :count then put :count into me then set $other to 'side-effect'")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
))
|
|
(deftest "does not execute when variable is undefined initially"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "when $neverSet changes put 'synced' into me")
|
|
(dom-set-inner-html _el-div "original")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
))
|
|
(deftest "element moved in DOM retains reactivity"
|
|
(hs-cleanup!)
|
|
(let ((_el-container-a (dom-create-element "div")) (_el-span (dom-create-element "span")) (_el-container-b (dom-create-element "div")))
|
|
(dom-set-attr _el-container-a "id" "container-a")
|
|
(dom-set-attr _el-span "_" "when $movable changes put it into me")
|
|
(dom-set-attr _el-container-b "id" "container-b")
|
|
(dom-append (dom-body) _el-container-a)
|
|
(dom-append _el-container-a _el-span)
|
|
(dom-append (dom-body) _el-container-b)
|
|
(hs-activate! _el-span)
|
|
))
|
|
(deftest "error in one effect does not break other effects in the same batch"
|
|
(hs-cleanup!)
|
|
(let ((_el-err-a (dom-create-element "span")) (_el-err-b (dom-create-element "span")))
|
|
(dom-set-attr _el-err-a "id" "err-a")
|
|
(dom-set-attr _el-err-a "_" "when $trigger changes put null.boom into me")
|
|
(dom-set-attr _el-err-b "id" "err-b")
|
|
(dom-set-attr _el-err-b "_" "when $trigger changes put 'ok:' + it into me")
|
|
(dom-append (dom-body) _el-err-a)
|
|
(dom-append (dom-body) _el-err-b)
|
|
(hs-activate! _el-err-a)
|
|
(hs-activate! _el-err-b)
|
|
))
|
|
(deftest "executes multiple commands"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "when $multi changes put 'first' into me then add .executed to me")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
))
|
|
(deftest "fires when either expression changes using or"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "when $x or $y changes put it into me")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
))
|
|
(deftest "function call on tracked value works (Math.round)"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "when (Math.round($rawNum)) changes put it into me")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
))
|
|
(deftest "handles NaN without infinite re-firing"
|
|
(hs-cleanup!)
|
|
(let ((_el-nan-input (dom-create-element "input")) (_el-span (dom-create-element "span")))
|
|
(dom-set-attr _el-nan-input "id" "nan-input")
|
|
(dom-set-attr _el-nan-input "type" "text")
|
|
(dom-set-attr _el-nan-input "value" "not a number")
|
|
(dom-set-attr _el-span "_" "when (#nan-input.value * 1) changes put it into me")
|
|
(dom-append (dom-body) _el-nan-input)
|
|
(dom-append (dom-body) _el-span)
|
|
(hs-activate! _el-span)
|
|
))
|
|
(deftest "handles chained reactivity across elements"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")) (_el-output (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "when $source changes set $derived to (it * 2)")
|
|
(dom-set-attr _el-output "id" "output")
|
|
(dom-set-attr _el-output "_" "when $derived changes put it into me")
|
|
(dom-append (dom-body) _el-div)
|
|
(dom-append (dom-body) _el-output)
|
|
(hs-activate! _el-div)
|
|
(hs-activate! _el-output)
|
|
))
|
|
(deftest "handles rapid successive changes correctly"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "when $rapid changes put it into me")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
))
|
|
(deftest "inline style change via JS is NOT detected"
|
|
(hs-cleanup!)
|
|
(let ((_el-style-target (dom-create-element "div")))
|
|
(dom-set-attr _el-style-target "id" "style-target")
|
|
(dom-set-attr _el-style-target "_" "when (*opacity) changes put it into me")
|
|
(dom-set-attr _el-style-target "style" "opacity: 1")
|
|
(dom-set-inner-html _el-style-target "not fired")
|
|
(dom-append (dom-body) _el-style-target)
|
|
(hs-activate! _el-style-target)
|
|
))
|
|
(deftest "isolates element-scoped variables between elements"
|
|
(hs-cleanup!)
|
|
(let ((_el-d1 (dom-create-element "div")) (_el-d2 (dom-create-element "div")))
|
|
(dom-set-attr _el-d1 "id" "d1")
|
|
(dom-set-attr _el-d1 "_" "init set :value to 'A' end when :value changes put it into me end on click set :value to 'A-clicked'")
|
|
(dom-set-inner-html _el-d1 "A")
|
|
(dom-set-attr _el-d2 "id" "d2")
|
|
(dom-set-attr _el-d2 "_" "init set :value to 'B' end when :value changes put it into me end on click set :value to 'B-clicked'")
|
|
(dom-set-inner-html _el-d2 "B")
|
|
(dom-append (dom-body) _el-d1)
|
|
(dom-append (dom-body) _el-d2)
|
|
(hs-activate! _el-d1)
|
|
(hs-activate! _el-d2)
|
|
))
|
|
(deftest "local variable in when expression produces a parse error"
|
|
(error "SKIP (untranslated): local variable in when expression produces a parse error"))
|
|
(deftest "math on tracked symbols works"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "when ($mA * $mB) changes put it into me")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
))
|
|
(deftest "mutating array element in place is NOT detected"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "when $arrMut[0] changes put it into me")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
))
|
|
(deftest "my @attr is tracked"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "when my @data-x changes put it into me")
|
|
(dom-set-attr _el-div "data-x" "one")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
))
|
|
(deftest "only triggers when variable actually changes value"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "when $dedup changes increment :callCount then put :callCount into me")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
))
|
|
(deftest "provides access to `it` and syncs initial value"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "when $global changes put it into me")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
))
|
|
(deftest "rapid detach/reattach in same sync block does not kill effect"
|
|
(hs-cleanup!)
|
|
(let ((_el-thrash-parent (dom-create-element "div")))
|
|
(dom-set-attr _el-thrash-parent "id" "thrash-parent")
|
|
(dom-append (dom-body) _el-thrash-parent)
|
|
))
|
|
(deftest "reassigning whole array IS detected"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "when $arrWhole changes put it.join(',') into me")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
))
|
|
(deftest "string template with tracked symbol works"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "when `hello ${$tplName}` changes put it into me")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
))
|
|
(deftest "supports multiple when features on the same element"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "when $left changes put it into my @data-left end when $right changes put it into my @data-right")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
))
|
|
(deftest "supports three or more expressions with or"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "when $r or $g or $b changes put it into me")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
))
|
|
(deftest "triggers multiple elements watching same variable"
|
|
(hs-cleanup!)
|
|
(let ((_el-d1 (dom-create-element "div")) (_el-d2 (dom-create-element "div")))
|
|
(dom-set-attr _el-d1 "id" "d1")
|
|
(dom-set-attr _el-d1 "_" "when $shared changes put 'first' into me")
|
|
(dom-set-attr _el-d2 "id" "d2")
|
|
(dom-set-attr _el-d2 "_" "when $shared changes put 'second' into me")
|
|
(dom-append (dom-body) _el-d1)
|
|
(dom-append (dom-body) _el-d2)
|
|
(hs-activate! _el-d1)
|
|
(hs-activate! _el-d2)
|
|
))
|
|
(deftest "value of #element is tracked"
|
|
(hs-cleanup!)
|
|
(let ((_el-of-input (dom-create-element "input")) (_el-span (dom-create-element "span")))
|
|
(dom-set-attr _el-of-input "id" "of-input")
|
|
(dom-set-attr _el-of-input "type" "text")
|
|
(dom-set-attr _el-of-input "value" "init")
|
|
(dom-set-attr _el-span "_" "when (value of #of-input) changes put it into me")
|
|
(dom-append (dom-body) _el-of-input)
|
|
(dom-append (dom-body) _el-span)
|
|
(hs-activate! _el-span)
|
|
))
|
|
(deftest "works with on handlers that modify the watched variable"
|
|
(hs-cleanup!)
|
|
(let ((_el-div (dom-create-element "div")))
|
|
(dom-set-attr _el-div "_" "init set :label to 'initial' end when :label changes put it into me end on click set :label to 'clicked'")
|
|
(dom-set-inner-html _el-div "initial")
|
|
(dom-append (dom-body) _el-div)
|
|
(hs-activate! _el-div)
|
|
))
|
|
)
|
|
|
|
;; ── worker (1 tests) ──
|
|
(defsuite "hs-upstream-worker"
|
|
(deftest "raises a helpful error when the worker plugin is not installed"
|
|
(hs-cleanup!)
|
|
(let ((caught nil))
|
|
(guard (_e (true (set! caught (str _e))))
|
|
(hs-compile "worker MyWorker def noop() end end"))
|
|
(assert (not (nil? caught)))
|
|
(assert (string-contains? caught "worker plugin"))
|
|
(assert (string-contains? caught "hyperscript.org/features/worker")))
|
|
)
|
|
)
|