Files
rose-ash/spec/tests/test-hyperscript-conformance-dev.sx
giles 0515295317 HS: extend parser/runtime + new node test runner; ignore test-results/
- Parser: `--` line comments, `|` op, `result` → `the-result`, query-scoped
  `<sel> in <expr>`, `is a/an <type>` predicate, multi-`as` chaining with `|`,
  `match`/`precede` keyword aliases, `[attr]` add/toggle, between attr forms
- Runtime: per-element listener registry + hs-deactivate!, attr toggle
  variants, set-inner-html boots subtree, hs-append polymorphic on
  string/list/element, default? / array-set! / query-all-in / list-set
  via take+drop, hs-script idempotence guard
- Integration: skip reserved (me/it/event/you/yourself) when collecting vars
- Tokenizer: emit `--` comments and `|` op
- Test framework + conformance runner updates; new tests/hs-run-filtered.js
  (single-process Node runner using OCaml VM step-limit to bound infinite
  loops); generate-sx-conformance-dev.py improvements
- mcp_tree.ml + run_tests.ml: harness extensions
- .gitignore: top-level test-results/ (Playwright artifacts)

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

491 lines
18 KiB
Plaintext

;; Dev-branch hyperscript conformance tests — expression evaluation
;; Source: spec/tests/hyperscript-upstream-tests.json (no-HTML tests from v0.9.90-dev)
;; DO NOT EDIT — regenerate with: python3 tests/playwright/generate-sx-conformance-dev.py
;; ── halt (1 tests) ──
(defsuite "hs-dev-halt"
(deftest "halt works outside of event context"
;; needs DOM/browser — covered by Playwright suite
(assert true))
)
;; ── bind (1 tests) ──
(defsuite "hs-dev-bind"
(deftest "unsupported element: bind to plain div errors"
;; needs DOM/browser — covered by Playwright suite
(assert true))
)
;; ── when (2 tests) ──
(defsuite "hs-dev-when"
(deftest "local variable in when expression produces a parse error"
;; needs DOM/browser — covered by Playwright suite
(assert true))
(deftest "attribute observers are persistent (not recreated on re-run)"
;; needs DOM/browser — covered by Playwright suite
(assert true))
)
;; ── evalStatically (8 tests) ──
(defsuite "hs-dev-evalStatically"
(deftest "works on number literals"
(assert= 42 (eval-hs "42"))
(assert= 3.14 (eval-hs "3.14"))
)
(deftest "works on boolean literals"
(assert= true (eval-hs "true"))
(assert= false (eval-hs "false"))
)
(deftest "works on null literal"
(assert= nil (eval-hs "null"))
)
(deftest "works on plain string literals"
(assert= "hello" (eval-hs "\"hello\""))
(assert= "world" (eval-hs "'world'"))
)
(deftest "works on time expressions"
(assert= 200 (eval-hs "200ms"))
(assert= 2000 (eval-hs "2s"))
)
(deftest "throws on template strings"
;; needs DOM/browser — covered by Playwright suite
(assert true))
(deftest "throws on symbol references"
;; needs DOM/browser — covered by Playwright suite
(assert true))
(deftest "throws on math expressions"
;; needs DOM/browser — covered by Playwright suite
(assert true))
)
;; ── collectionExpressions (12 tests) ──
(defsuite
"hs-dev-collectionExpressions"
(deftest
"filters an array by condition"
(let
((result (eval-hs "set arr to [{name: \"a\", active: true}, {name: \"b\", active: false}, {name: \"c\", active: true}] then return arr where its active")))
(assert= (list "a" "c") (map (fn (x) (get x "name")) result))))
(deftest
"filters with comparison"
(assert=
(list 4 5)
(eval-hs "set arr to [1, 2, 3, 4, 5] then return arr where it > 3")))
(deftest
"sorts by a property"
(let
((result (eval-hs "set arr to [{name: \"Charlie\"}, {name: \"Alice\"}, {name: \"Bob\"}] then return arr sorted by its name")))
(assert=
(list "Alice" "Bob" "Charlie")
(map (fn (x) (get x "name")) result))))
(deftest
"sorts descending"
(assert=
(list 3 2 1)
(eval-hs "set arr to [3, 1, 2] then return arr sorted by it descending")))
(deftest
"sorts numbers by a computed key"
(let
((result (eval-hs "set arr to [{name: \"b\", age: 30}, {name: \"a\", age: 20}, {name: \"c\", age: 25}] then return arr sorted by its age")))
(assert= (list "a" "c" "b") (map (fn (x) (get x "name")) result))))
(deftest
"maps to a property"
(assert=
(list "Alice" "Bob")
(eval-hs
"set arr to [{name: \"Alice\"}, {name: \"Bob\"}] then return arr mapped to its name")))
(deftest
"maps with an expression"
(assert=
(list 2 4 6)
(eval-hs "set arr to [1, 2, 3] then return arr mapped to (it * 2)")))
(deftest
"where then mapped to"
(assert=
(list "Alice" "Charlie")
(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")))
(deftest
"sorted by then mapped to"
(assert=
(list "Alice" "Charlie")
(eval-hs
"set arr to [{name: \"Charlie\", age: 30}, {name: \"Alice\", age: 20}] then return arr sorted by its age mapped to its name")))
(deftest
"where then sorted by then mapped to"
(assert=
(list "Bob" "Charlie")
(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")))
(deftest
"the result inside where refers to previous command result, not current element"
(assert=
(list 4 5)
(eval-hs
"get 3 then set arr to [1, 2, 3, 4, 5] then return arr where it > the result")))
(deftest
"where binds after property access"
(assert= (list 3 4) (eval-hs "obj.items where it > 2" {:locals {:obj {:items (list 1 2 3 4)}}}))))
;; ── splitJoin (7 tests) ──
(defsuite "hs-dev-splitJoin"
(deftest "splits a string by delimiter"
(assert= (list "a" "b" "c") (eval-hs "return \"a,b,c\" split by \",\""))
)
(deftest "splits by whitespace"
(assert= (list "hello" "world") (eval-hs "return \"hello world\" split by \" \""))
)
(deftest "joins an array with delimiter"
(assert= "a, b, c" (eval-hs "return [\"a\", \"b\", \"c\"] joined by \", \""))
)
(deftest "joins with empty string"
(assert= "xyz" (eval-hs "return [\"x\", \"y\", \"z\"] joined by \"\""))
)
(deftest "split then where then joined"
(assert= "a-b-c" (eval-hs "return \"a,,b,,c\" split by \",\" where it is not \"\" joined by \"-\""))
)
(deftest "split then sorted then joined"
(assert= "apple, banana, cherry" (eval-hs "return \"banana,apple,cherry\" split by \",\" sorted by it joined by \", \""))
)
(deftest "split then mapped then joined"
(assert= "5,5" (eval-hs "return \"hello world\" split by \" \" mapped to its length joined by \",\""))
)
)
;; ── pick (7 tests) ──
(defsuite "hs-dev-pick"
(deftest "does not hang on zero-length regex matches"
;; needs DOM/browser — covered by Playwright suite
(assert true))
(deftest "can pick first n items"
(assert= (list 10 20 30) (eval-hs "pick first 3 of arr" {:locals {:arr (list 10 20 30 40 50)}})))
(deftest "can pick last n items"
(assert= (list 40 50) (eval-hs "pick last 2 of arr" {:locals {:arr (list 10 20 30 40 50)}})))
(deftest "can pick random item"
(assert-true (some (fn (x) (= x (eval-hs "pick random of arr" {:locals {:arr (list 10 20 30)}}))) (list 10 20 30))))
(deftest "can pick random n items"
(assert= 2 (len (eval-hs "pick random 2 of arr" {:locals {:arr (list 10 20 30 40 50)}}))))
(deftest "can pick items using 'of' syntax"
(assert= (list 11 12) (eval-hs "pick items 1 to 3 of arr" {:locals {:arr (list 10 11 12 13 14 15 16)}})))
(deftest "can pick match using 'of' syntax"
;; needs DOM/browser — covered by Playwright suite
(assert true))
)
;; ── transition (1 tests) ──
(defsuite "hs-dev-transition"
(deftest "can transition on query ref with possessive"
;; needs DOM/browser — covered by Playwright suite
(assert true))
)
;; ── socket (4 tests) ──
(defsuite "hs-dev-socket"
(deftest "parses socket with absolute ws:// URL"
;; needs DOM/browser — covered by Playwright suite
(assert true))
(deftest "converts relative URL to wss:// on https pages"
;; needs DOM/browser — covered by Playwright suite
(assert true))
(deftest "converts relative URL to ws:// on http pages"
;; needs DOM/browser — covered by Playwright suite
(assert true))
(deftest "namespaced sockets work"
;; needs DOM/browser — covered by Playwright suite
(assert true))
)
;; ── bootstrap (3 tests) ──
(defsuite "hs-dev-bootstrap"
(deftest "fires hyperscript:before:init and hyperscript:after:init"
;; needs DOM/browser — covered by Playwright suite
(assert true))
(deftest "hyperscript:before:init can cancel initialization"
;; needs DOM/browser — covered by Playwright suite
(assert true))
(deftest "logAll config logs events to console"
;; needs DOM/browser — covered by Playwright suite
(assert true))
)
;; ── parser (3 tests) ──
(defsuite "hs-dev-parser"
(deftest "fires hyperscript:parse-error event with all errors"
;; needs DOM/browser — covered by Playwright suite
(assert true))
(deftest "_hyperscript() evaluate API still throws on first error"
;; needs DOM/browser — covered by Playwright suite
(assert true))
(deftest "parse error at EOF on trailing newline does not crash"
;; needs DOM/browser — covered by Playwright suite
(assert true))
)
;; ── asExpression (17 tests) ──
(defsuite "hs-dev-asExpression"
(deftest "converts value as Boolean"
(assert= true (eval-hs "1 as Boolean"))
(assert= false (eval-hs "0 as Boolean"))
(assert= false (eval-hs "'' as Boolean"))
(assert= true (eval-hs "'hello' as Boolean"))
)
(deftest "can use the a modifier if you like"
;; needs DOM/browser — covered by Playwright suite
(assert true))
(deftest "parses string as JSON to object"
(let ((result (eval-hs "'{\"foo\":\"bar\"}' as JSON")))
(assert= "bar" (get result "foo"))
))
(deftest "converts value as JSONString"
(assert= "{\"foo\":\"bar\"}" (eval-hs "{foo:'bar'} as JSONString"))
)
(deftest "pipe operator chains conversions"
;; needs DOM/browser — covered by Playwright suite
(assert true))
(deftest "can use the an modifier if you'd like"
(let ((result (eval-hs "'{\"foo\":\"bar\"}' as an Object")))
(assert= "bar" (get result "foo"))
))
(deftest "collects duplicate text inputs into an array"
;; needs DOM/browser — covered by Playwright suite
(assert true))
(deftest "converts multiple selects with programmatically changed selections"
;; needs DOM/browser — covered by Playwright suite
(assert true))
(deftest "converts a form element into Values | JSONString"
;; needs DOM/browser — covered by Playwright suite
(assert true))
(deftest "converts a form element into Values | FormEncoded"
;; needs DOM/browser — covered by Playwright suite
(assert true))
(deftest "converts array as Set"
;; expect(result.isSet).toBe(true)
;; STUB: needs JS bridge — eval-only
(assert true))
(deftest "converts object as Map"
;; expect(result.isMap).toBe(true)
;; STUB: needs JS bridge — eval-only
(assert true))
(deftest "converts object as Keys"
(assert= (list "a" "b") (eval-hs "{a:1, b:2} as Keys"))
)
(deftest "converts object as Entries"
(assert= (list (list "a" 1)) (eval-hs "{a:1} as Entries"))
)
(deftest "converts array as Reversed"
(assert= (list 3 2 1) (eval-hs "[1,2,3] as Reversed"))
)
(deftest "converts array as Unique"
(assert= (list 1 2 3) (eval-hs "[1,2,2,3,3] as Unique"))
)
(deftest "converts nested array as Flat"
(assert= (list 1 2 3 4) (eval-hs "[[1,2],[3,4]] as Flat"))
)
)
;; ── comparisonOperator (28 tests) ──
(defsuite "hs-dev-comparisonOperator"
(deftest "is ignoring case works"
(assert= true (eval-hs "'Hello' is 'hello' ignoring case"))
(assert= true (eval-hs "'Hello' is 'HELLO' ignoring case"))
(assert= false (eval-hs "'Hello' is 'world' ignoring case"))
)
(deftest "is not ignoring case works"
(assert= true (eval-hs "'Hello' is not 'world' ignoring case"))
(assert= false (eval-hs "'Hello' is not 'hello' ignoring case"))
)
(deftest "contains ignoring case works"
(assert= true (eval-hs "'Hello World' contains 'hello' ignoring case"))
(assert= true (eval-hs "'Hello World' contains 'WORLD' ignoring case"))
(assert= false (eval-hs "'Hello World' contains 'missing' ignoring case"))
)
(deftest "matches ignoring case works"
(assert= true (eval-hs "'Hello' matches 'hello' ignoring case"))
(assert= true (eval-hs "'Hello' matches 'HELLO' ignoring case"))
)
(deftest "starts with works"
(assert= true (eval-hs "'hello world' starts with 'hello'"))
(assert= false (eval-hs "'hello world' starts with 'world'"))
(assert= true (eval-hs "'hello' starts with 'hello'"))
(assert= false (eval-hs "'' starts with 'x'"))
)
(deftest "ends with works"
(assert= true (eval-hs "'hello world' ends with 'world'"))
(assert= false (eval-hs "'hello world' ends with 'hello'"))
(assert= true (eval-hs "'hello' ends with 'hello'"))
(assert= false (eval-hs "'' ends with 'x'"))
)
(deftest "does not start with works"
(assert= false (eval-hs "'hello world' does not start with 'hello'"))
(assert= true (eval-hs "'hello world' does not start with 'world'"))
)
(deftest "does not end with works"
(assert= false (eval-hs "'hello world' does not end with 'world'"))
(assert= true (eval-hs "'hello world' does not end with 'hello'"))
)
(deftest "starts with null is false"
(assert= false (eval-hs "null starts with 'x'"))
(assert= true (eval-hs "null does not start with 'x'"))
)
(deftest "ends with null is false"
(assert= false (eval-hs "null ends with 'x'"))
(assert= true (eval-hs "null does not end with 'x'"))
)
(deftest "starts with ignoring case works"
(assert= true (eval-hs "'Hello World' starts with 'hello' ignoring case"))
(assert= true (eval-hs "'Hello World' starts with 'HELLO' ignoring case"))
(assert= false (eval-hs "'Hello World' starts with 'world' ignoring case"))
)
(deftest "ends with ignoring case works"
(assert= true (eval-hs "'Hello World' ends with 'world' ignoring case"))
(assert= true (eval-hs "'Hello World' ends with 'WORLD' ignoring case"))
(assert= false (eval-hs "'Hello World' ends with 'hello' ignoring case"))
)
(deftest "starts with coerces to string"
(assert= true (eval-hs "123 starts with '12'"))
(assert= false (eval-hs "123 starts with '23'"))
)
(deftest "ends with coerces to string"
(assert= true (eval-hs "123 ends with '23'"))
(assert= false (eval-hs "123 ends with '12'"))
)
(deftest "is between works"
(assert= true (eval-hs "5 is between 1 and 10"))
(assert= true (eval-hs "1 is between 1 and 10"))
(assert= true (eval-hs "10 is between 1 and 10"))
(assert= false (eval-hs "0 is between 1 and 10"))
(assert= false (eval-hs "11 is between 1 and 10"))
)
(deftest "is not between works"
(assert= false (eval-hs "5 is not between 1 and 10"))
(assert= true (eval-hs "0 is not between 1 and 10"))
(assert= true (eval-hs "11 is not between 1 and 10"))
(assert= false (eval-hs "1 is not between 1 and 10"))
(assert= false (eval-hs "10 is not between 1 and 10"))
)
(deftest "between works with strings"
(assert= true (eval-hs "'b' is between 'a' and 'c'"))
(assert= false (eval-hs "'d' is between 'a' and 'c'"))
)
(deftest "I am between works"
(assert= true (eval-hs "I am between 1 and 10" {:me 5}))
(assert= false (eval-hs "I am between 1 and 10" {:me 0}))
)
(deftest "I am not between works"
(assert= false (eval-hs "I am not between 1 and 10" {:me 5}))
(assert= true (eval-hs "I am not between 1 and 10" {:me 0}))
)
(deftest "precedes with null is false"
(assert= false (eval-hs "null precedes null"))
(assert= true (eval-hs "null does not precede null"))
)
(deftest "is really works without equal to"
(assert= true (eval-hs "2 is really 2"))
(assert= false (eval-hs "2 is really '2'"))
)
(deftest "is not really works without equal to"
(assert= true (eval-hs "2 is not really '2'"))
(assert= false (eval-hs "2 is not really 2"))
)
(deftest "is equal works without to"
(assert= true (eval-hs "2 is equal 2"))
(assert= false (eval-hs "2 is equal 1"))
)
(deftest "is not equal works without to"
(assert= false (eval-hs "2 is not equal 2"))
(assert= true (eval-hs "2 is not equal 1"))
)
(deftest "am works as alias for is"
(assert= true (eval-hs "2 am 2"))
(assert= false (eval-hs "2 am 1"))
)
(deftest "is not undefined still works as equality"
(assert= true (eval-hs "5 is not undefined"))
(assert= false (eval-hs "null is not undefined"))
)
(deftest "is not null still works as equality"
(assert= true (eval-hs "5 is not null"))
(assert= false (eval-hs "null is not null"))
)
(deftest "is still does equality when rhs variable exists"
(assert= true (eval-hs "x is y" {:locals {:x 5 :y 5}}))
(assert= false (eval-hs "x is y" {:locals {:x 5 :y 6}}))
)
)
;; ── cookies (1 tests) ──
(defsuite "hs-dev-cookies"
(deftest "length is 0 when no cookies are set"
;; needs DOM/browser — covered by Playwright suite
(assert true))
)
;; ── in (1 tests) ──
(defsuite "hs-dev-in"
(deftest "null value in array returns empty"
(assert= (list) (eval-hs "null in [1, 2, 3]"))
)
)
;; ── logicalOperator (3 tests) ──
(defsuite "hs-dev-logicalOperator"
(deftest "and short-circuits when lhs promise resolves to false"
;; needs DOM/browser — covered by Playwright suite
(assert true))
(deftest "or short-circuits when lhs promise resolves to true"
;; needs DOM/browser — covered by Playwright suite
(assert true))
(deftest "or evaluates rhs when lhs promise resolves to false"
;; needs DOM/browser — covered by Playwright suite
(assert true))
)
;; ── mathOperator (5 tests) ──
(defsuite "hs-dev-mathOperator"
(deftest "array + array concats"
(assert= (list 1 2 3 4) (eval-hs "[1, 2] + [3, 4]"))
)
(deftest "array + single value appends"
(assert= (list 1 2 3) (eval-hs "[1, 2] + 3"))
)
(deftest "array + array does not mutate original"
(assert= (list 1 2) (eval-hs "set a to [1, 2] then set b to a + [3] then return a"))
)
(deftest "array concat chains"
(assert= (list 1 2 3) (eval-hs "[1] + [2] + [3]"))
)
(deftest "empty array + array works"
(assert= (list 1 2) (eval-hs "[] + [1, 2]"))
)
)
;; ── no (4 tests) ──
(defsuite "hs-dev-no"
(deftest "no returns false for non-empty array"
(assert= false (eval-hs "no ['thing']"))
)
(deftest "no with where filters then checks emptiness"
(assert= true (eval-hs "no [1, 2, 3] where it > 5"))
)
(deftest "no with where returns false when matches exist"
(assert= false (eval-hs "no [1, 2, 3] where it > 1"))
)
(deftest "no with where and is not"
(assert= false (eval-hs "no [1, 2, 3] where it is not 2"))
)
)
;; ── objectLiteral (1 tests) ──
(defsuite "hs-dev-objectLiteral"
(deftest "allows trailing commas"
;; needs DOM/browser — covered by Playwright suite
(assert true))
)
;; ── relativePositionalExpression (1 tests) ──
(defsuite "hs-dev-relativePositionalExpression"
(deftest "can write to next element with put command"
;; needs DOM/browser — covered by Playwright suite
(assert true))
)