HS reset/first/last: defaultValue tracking, list-of-elements reset, find().first|last

Mock DOM:
- El now tracks defaultValue/defaultChecked/defaultSelected and a reset()
  method that walks descendant form controls, restoring them.
- setAttribute(value|checked|selected) sets the matching default-* too, so
  the initial HTML state can be restored later.
- parseHTMLFragments + _setInnerHTML capture a textarea's textContent as
  its value AND defaultValue.

Generator (pw-body):
- add_action / add_assertion extract .first() / .last() / .nth(N) modifiers
  into (nth (dom-query-all …) i) or a (let ((_all …)) (nth _all (- … 1)))
  tail so multi-match helpers hit the right element.

Compiler:
- emit-reset! with a .<class>/.<sel> query target now compiles to hs-query-all
  so 'reset .resettable' resets every matching control (not just the first).

Net: reset 1→8 (100%).
This commit is contained in:
2026-04-23 17:15:40 +00:00
parent 5b31d935bd
commit d6137f0d6f
5 changed files with 153 additions and 91 deletions

View File

@@ -1835,7 +1835,14 @@
((= head (quote select!))
(list (quote hs-select!) (hs-to-sx (nth ast 1))))
((= head (quote reset!))
(list (quote hs-reset!) (hs-to-sx (nth ast 1))))
(let
((raw-tgt (nth ast 1)))
(cond
((and (list? raw-tgt) (= (first raw-tgt) (quote query)))
(list
(quote hs-reset!)
(list (quote hs-query-all) (nth raw-tgt 1))))
(true (list (quote hs-reset!) (hs-to-sx raw-tgt))))))
((= head (quote default!))
(let
((tgt-ast (nth ast 1))

View File

@@ -1835,7 +1835,14 @@
((= head (quote select!))
(list (quote hs-select!) (hs-to-sx (nth ast 1))))
((= head (quote reset!))
(list (quote hs-reset!) (hs-to-sx (nth ast 1))))
(let
((raw-tgt (nth ast 1)))
(cond
((and (list? raw-tgt) (= (first raw-tgt) (quote query)))
(list
(quote hs-reset!)
(list (quote hs-query-all) (nth raw-tgt 1))))
(true (list (quote hs-reset!) (hs-to-sx raw-tgt))))))
((= head (quote default!))
(let
((tgt-ast (nth ast 1))

View File

@@ -1263,7 +1263,7 @@
(hs-activate! _el-div)
(hs-activate! _el-bar)
(assert (not (dom-has-class? (dom-query-by-id "bar") "foo-sent")))
(dom-dispatch _el-div "click" nil)
(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"
@@ -1276,7 +1276,7 @@
(dom-append (dom-body) _el-bar)
(hs-activate! _el-div)
(hs-activate! _el-bar)
(dom-dispatch _el-div "click" nil)
(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"
@@ -1312,7 +1312,7 @@
(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? (dom-query ".divs") "foo")))
(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")))
))
@@ -2050,7 +2050,7 @@
(dom-append _el-div _el-d1)
(hs-activate! _el-d1)
(assert= (dom-text-content (dom-query-by-id "d1")) "")
(dom-dispatch _el-div "click" nil)
(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"
@@ -3130,8 +3130,8 @@
(dom-append (dom-body) _el-button)
(hs-activate! _el-button)
(dom-dispatch _el-button "click" nil)
(assert= (dom-text-content (dom-query ".clearme")) "")
(assert= (dom-text-content (dom-query ".clearme")) "")
(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!)
@@ -4123,7 +4123,7 @@
(dom-append _el-td11 _el-master)
(hs-activate! _el-master)
(dom-dispatch (dom-query-by-id "master") "click" nil)
(dom-dispatch (dom-query ".cb") "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 ','")
@@ -4207,8 +4207,8 @@
(dom-append (dom-body) _el-b2)
(hs-activate! _el-button)
(hs-activate! _el-b2)
(dom-dispatch _el-button "click" nil)
(assert= (dom-text-content _el-button) "2")
(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")
))
@@ -9433,7 +9433,7 @@
(dom-append (dom-body) _el-d2)
(dom-append _el-d2 _el-div4)
(hs-activate! _el-div)
(dom-dispatch _el-div "click" nil)
(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")
))
@@ -9451,7 +9451,7 @@
(dom-append (dom-body) _el-d2)
(dom-append _el-d2 _el-div4)
(hs-activate! _el-div)
(dom-dispatch _el-div "click" nil)
(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")
))
@@ -9484,7 +9484,7 @@
(dom-append (dom-body) _el-div)
(dom-append (dom-body) _el-div2)
(hs-activate! _el-div)
(dom-dispatch _el-div "click" nil)
(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"
@@ -9496,7 +9496,7 @@
(dom-append (dom-body) _el-div)
(dom-append (dom-body) _el-div2)
(hs-activate! _el-div)
(dom-dispatch _el-div "click" nil)
(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"
@@ -9518,7 +9518,7 @@
(dom-append (dom-body) _el-div)
(dom-append (dom-body) _el-div2)
(hs-activate! _el-div)
(dom-dispatch _el-div "click" nil)
(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"
@@ -9530,7 +9530,7 @@
(dom-append (dom-body) _el-div)
(dom-append (dom-body) _el-div2)
(hs-activate! _el-div)
(dom-dispatch _el-div "click" nil)
(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"
@@ -9869,7 +9869,7 @@
(dom-append (dom-body) _el-div)
(dom-append (dom-body) _el-that)
(hs-activate! _el-div)
(dom-dispatch _el-div "click" nil)
(dom-dispatch (nth (dom-query-all (dom-body) "div") 0) "click" nil)
))
(deftest "can remove parent element"
(hs-cleanup!)
@@ -10369,13 +10369,13 @@
(dom-append (dom-body) _el-input1)
(dom-append (dom-body) _el-button)
(hs-activate! _el-button)
(dom-set-prop (dom-query ".resettable") "value" "changed1")
(dom-dispatch (dom-query ".resettable") "input" nil)
(dom-set-prop (dom-query ".resettable") "value" "changed2")
(dom-dispatch (dom-query ".resettable") "input" nil)
(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 (dom-query ".resettable") "value") "one")
(assert= (dom-get-prop (dom-query ".resettable") "value") "two")
(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!)
@@ -10612,8 +10612,8 @@
(dom-append (dom-body) _el-bar)
(hs-activate! _el-div)
(hs-activate! _el-bar)
(dom-dispatch _el-div "click" nil)
(assert (dom-has-class? _el-div "foo-sent"))
(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!)
@@ -10626,7 +10626,7 @@
(hs-activate! _el-div)
(hs-activate! _el-bar)
(assert (not (dom-has-class? (dom-query-by-id "bar") "foo-sent")))
(dom-dispatch _el-div "click" nil)
(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"
@@ -10640,7 +10640,7 @@
(hs-activate! _el-div)
(hs-activate! _el-bar)
(assert (not (dom-has-class? (dom-query-by-id "bar") "foo-sent")))
(dom-dispatch _el-div "click" nil)
(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"
@@ -10653,7 +10653,7 @@
(dom-append (dom-body) _el-bar)
(hs-activate! _el-div)
(hs-activate! _el-bar)
(dom-dispatch _el-div "click" nil)
(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"
@@ -10667,7 +10667,7 @@
(hs-activate! _el-div)
(hs-activate! _el-bar)
(assert (not (dom-has-class? (dom-query-by-id "bar") "foo-sent")))
(dom-dispatch _el-div "click" nil)
(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"
@@ -10680,7 +10680,7 @@
(dom-append (dom-body) _el-bar)
(hs-activate! _el-div)
(hs-activate! _el-bar)
(dom-dispatch _el-div "click" nil)
(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"
@@ -10694,7 +10694,7 @@
(hs-activate! _el-div)
(hs-activate! _el-bar)
(assert (not (dom-has-class? (dom-query-by-id "bar") "foo-sent")))
(dom-dispatch _el-div "click" nil)
(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"
@@ -10707,7 +10707,7 @@
(dom-append (dom-body) _el-bar)
(hs-activate! _el-div)
(hs-activate! _el-bar)
(dom-dispatch _el-div "click" nil)
(dom-dispatch (nth (dom-query-all (dom-body) "div") 0) "click" nil)
(assert= (dom-text-content (dom-query-by-id "bar")) "42")
))
)
@@ -10767,8 +10767,8 @@
(dom-append (dom-body) _el-div)
(dom-append _el-div _el-d1)
(hs-activate! _el-div)
(dom-dispatch _el-div "click" nil)
(assert= (dom-text-content _el-div) "foo")
(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!)
@@ -10778,8 +10778,8 @@
(dom-append (dom-body) _el-div)
(dom-append _el-div _el-d1)
(hs-activate! _el-div)
(dom-dispatch _el-div "click" nil)
(assert= (dom-text-content _el-div) "foo")
(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!)
@@ -10789,8 +10789,8 @@
(dom-append (dom-body) _el-div)
(dom-append _el-div _el-d1)
(hs-activate! _el-div)
(dom-dispatch _el-div "click" nil)
(assert= (dom-text-content _el-div) "foo")
(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!)
@@ -10821,8 +10821,8 @@
(dom-append (dom-body) _el-div)
(dom-append (dom-body) _el-div1)
(hs-activate! _el-div)
(dom-dispatch (dom-query ".divs") "click" nil)
(assert= (dom-text-content (dom-query ".divs")) "foo")
(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"
@@ -10844,7 +10844,7 @@
(dom-append (dom-body) _el-div)
(dom-append (dom-body) _el-div2)
(hs-activate! _el-div)
(dom-dispatch _el-div "click" nil)
(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"
@@ -10856,7 +10856,7 @@
(dom-append (dom-body) _el-div)
(dom-append (dom-body) _el-div2)
(hs-activate! _el-div)
(dom-dispatch _el-div "click" nil)
(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"
@@ -10868,7 +10868,7 @@
(dom-append (dom-body) _el-div)
(dom-append (dom-body) _el-div2)
(hs-activate! _el-div)
(dom-dispatch _el-div "click" nil)
(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"
@@ -10880,7 +10880,7 @@
(dom-append (dom-body) _el-div)
(dom-append (dom-body) _el-div2)
(hs-activate! _el-div)
(dom-dispatch _el-div "click" nil)
(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"
@@ -10892,7 +10892,7 @@
(dom-append (dom-body) _el-div)
(dom-append (dom-body) _el-div2)
(hs-activate! _el-div)
(dom-dispatch _el-div "click" nil)
(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"
@@ -10904,7 +10904,7 @@
(dom-append (dom-body) _el-div)
(dom-append (dom-body) _el-div2)
(hs-activate! _el-div)
(dom-dispatch _el-div "click" nil)
(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"
@@ -11042,7 +11042,7 @@
(dom-append (dom-body) _el-trigger)
(hs-activate! _el-trigger)
(dom-dispatch (dom-query-by-id "trigger") "click" nil)
(assert (dom-has-class? (dom-query ".item") "done"))
(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"
@@ -11209,7 +11209,7 @@
(hs-activate! _el-div)
(assert (not (dom-visible? (dom-query-by-id "d1"))))
(assert (not (dom-visible? (dom-query-by-id "d2"))))
(dom-dispatch _el-div "click" nil)
(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")
))
@@ -11227,7 +11227,7 @@
(hs-activate! _el-div)
(assert (not (dom-visible? (dom-query-by-id "d1"))))
(assert (not (dom-visible? (dom-query-by-id "d2"))))
(dom-dispatch _el-div "click" nil)
(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")
))
@@ -11479,8 +11479,8 @@
(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? _el-div "unselected"))
(assert (not (dom-has-class? _el-div "selected")))
(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"))
@@ -11498,8 +11498,8 @@
(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? _el-div "selected")))
(assert (dom-has-class? _el-div "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") 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"))
@@ -11518,7 +11518,7 @@
(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? _el-div "foo")))
(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"))
))
@@ -11535,7 +11535,7 @@
(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? _el-div "foo")))
(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")))
))
@@ -11552,7 +11552,7 @@
(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? _el-form "foo")))
(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")))
))
@@ -11570,7 +11570,7 @@
(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? _el-div "data-foo")))
(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") "")
))
@@ -11586,9 +11586,9 @@
(dom-append (dom-body) _el-div1)
(dom-append (dom-body) _el-div2)
(hs-activate! _el-div1)
(assert= (dom-get-attr _el-div "data-foo") "bar")
(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? _el-div "data-foo")))
(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")))
))
@@ -11605,7 +11605,7 @@
(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 _el-div "data-foo") "qux")
(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")
))
@@ -11623,7 +11623,7 @@
(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 _el-div "data-foo") "qux")
(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")
))
@@ -11639,9 +11639,9 @@
(dom-append (dom-body) _el-div1)
(dom-append (dom-body) _el-div2)
(hs-activate! _el-div1)
(assert= (dom-get-attr _el-div "data-foo") "bar")
(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? _el-div "data-foo")))
(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")))
))
@@ -11659,7 +11659,7 @@
(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? _el-div "foo")))
(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")))
@@ -11679,8 +11679,8 @@
(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? _el-div "foo")))
(assert (not (dom-has-class? _el-div "bar")))
(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"))
@@ -11698,7 +11698,7 @@
(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 _el-div "data-foo") "qux")
(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")
))
@@ -12499,9 +12499,9 @@ end")
(dom-append (dom-body) _el-d2)
(hs-activate! _el-div)
(assert= (dom-get-style (dom-query-by-id "d2") "display") "block")
(dom-dispatch _el-div "click" nil)
(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 _el-div "click" nil)
(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"
@@ -12588,9 +12588,9 @@ end")
(dom-append (dom-body) _el-d2)
(hs-activate! _el-div)
(assert= (dom-get-style (dom-query-by-id "d2") "opacity") "1")
(dom-dispatch _el-div "click" nil)
(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 _el-div "click" nil)
(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"
@@ -12640,9 +12640,9 @@ end")
(dom-append (dom-body) _el-d2)
(hs-activate! _el-div)
(assert= (dom-get-style (dom-query-by-id "d2") "visibility") "visible")
(dom-dispatch _el-div "click" nil)
(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 _el-div "click" nil)
(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"
@@ -12723,7 +12723,7 @@ end")
(dom-append (dom-body) _el-div)
(dom-append (dom-body) _el-foo)
(hs-activate! _el-div)
(dom-dispatch _el-div "click" nil)
(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"
@@ -12734,7 +12734,7 @@ end")
(dom-append (dom-body) _el-div)
(dom-append (dom-body) _el-foo)
(hs-activate! _el-div)
(dom-dispatch _el-div "click" nil)
(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"
@@ -12745,7 +12745,7 @@ end")
(dom-append (dom-body) _el-div)
(dom-append (dom-body) _el-foo)
(hs-activate! _el-div)
(dom-dispatch _el-div "click" nil)
(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"
@@ -12756,7 +12756,7 @@ end")
(dom-append (dom-body) _el-div)
(dom-append (dom-body) _el-foo)
(hs-activate! _el-div)
(dom-dispatch _el-div "click" nil)
(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"
@@ -12788,7 +12788,7 @@ end")
(dom-append (dom-body) _el-div)
(dom-append (dom-body) _el-foo)
(hs-activate! _el-div)
(dom-dispatch _el-div "click" nil)
(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"
@@ -12799,7 +12799,7 @@ end")
(dom-append (dom-body) _el-div)
(dom-append (dom-body) _el-foo)
(hs-activate! _el-div)
(dom-dispatch _el-div "click" nil)
(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"

View File

@@ -33,8 +33,8 @@ function mkStyle(tag) {
return s;
}
class El {
constructor(t) { this.tagName=t.toUpperCase(); this.nodeName=this.tagName; this.nodeType=1; this.id=''; this.className=''; this.classList=new CL(this); this.style=mkStyle(this.tagName); this.attributes={}; this.children=[]; this.childNodes=[]; this.childNodes.item=function(i){return this[i]||null;}; this.parentElement=null; this.parentNode=null; this.textContent=''; this.innerHTML=''; this._listeners={}; this.dataset={}; this.open=false; this.value=''; this.checked=false; this.disabled=false; this.type=''; this.name=''; this.selectedIndex=-1; this.options=[]; }
setAttribute(n,v) { this.attributes[n]=String(v); if(n==='id')this.id=v; if(n==='class'){this.className=v;this.classList._sync(v);} if(n==='value')this.value=v; if(n==='name')this.name=v; if(n==='type')this.type=v; if(n==='checked')this.checked=true; if(n==='selected')this.selected=true; if(n==='multiple')this.multiple=true; if(n==='disabled')this.disabled=true; if(n==='style'){const s=String(v);for(const d of s.split(';')){const c=d.indexOf(':');if(c>0){const k=d.slice(0,c).trim();const val=d.slice(c+1).trim();if(k)this.style.setProperty(k,val);}} } }
constructor(t) { this.tagName=t.toUpperCase(); this.nodeName=this.tagName; this.nodeType=1; this.id=''; this.className=''; this.classList=new CL(this); this.style=mkStyle(this.tagName); this.attributes={}; this.children=[]; this.childNodes=[]; this.childNodes.item=function(i){return this[i]||null;}; this.parentElement=null; this.parentNode=null; this.textContent=''; this.innerHTML=''; this._listeners={}; this.dataset={}; this.open=false; this.value=''; this.defaultValue=''; this.checked=false; this.defaultChecked=false; this.disabled=false; this.type=''; this.name=''; this.selectedIndex=-1; this.defaultSelected=false; this.selected=false; this.options=[]; }
setAttribute(n,v) { this.attributes[n]=String(v); if(n==='id')this.id=v; if(n==='class'){this.className=v;this.classList._sync(v);} if(n==='value'){this.value=v;this.defaultValue=v;} if(n==='name')this.name=v; if(n==='type')this.type=v; if(n==='checked'){this.checked=true;this.defaultChecked=true;} if(n==='selected'){this.selected=true;this.defaultSelected=true;} if(n==='multiple')this.multiple=true; if(n==='disabled')this.disabled=true; if(n==='style'){const s=String(v);for(const d of s.split(';')){const c=d.indexOf(':');if(c>0){const k=d.slice(0,c).trim();const val=d.slice(c+1).trim();if(k)this.style.setProperty(k,val);}} } }
getAttribute(n) { return this.attributes[n]!==undefined?this.attributes[n]:null; }
removeAttribute(n) { delete this.attributes[n]; if(n==='disabled')this.disabled=false; }
hasAttribute(n) { return n in this.attributes; }
@@ -52,6 +52,28 @@ class El {
contains(o) { if(o===this)return true; for(const c of this.children)if(c===o||c.contains(o))return true; return false; }
cloneNode(d) { const e=new El(this.tagName.toLowerCase()); Object.assign(e.attributes,this.attributes); e.id=this.id; e.className=this.className; e.classList._sync(this.className); for(const k of Object.keys(this.style)){if(typeof this.style[k]!=='function')e.style[k]=this.style[k];} e.textContent=this.textContent; e.innerHTML=this.innerHTML; e.value=this.value; if(d)for(const c of this.children)e.appendChild(c.cloneNode(true)); return e; }
focus(){} blur(){} click(){this.dispatchEvent(new Ev('click',{bubbles:true}));} remove(){if(this.parentElement)this.parentElement.removeChild(this);}
reset(){
// Form reset: walk descendants, restore defaultValue / defaultChecked /
// defaultSelected.
const walk = (el) => {
for (const c of (el.children || [])) {
const tag = c.tagName;
if (tag === 'INPUT' || tag === 'TEXTAREA') {
if (c.type === 'checkbox' || c.type === 'radio') c.checked = !!c.defaultChecked;
else c.value = c.defaultValue || '';
} else if (tag === 'OPTION') {
c.selected = !!c.defaultSelected;
} else if (tag === 'SELECT') {
for (const o of (c.options || [])) o.selected = !!o.defaultSelected;
const first = (c.options || []).findIndex(o => o.selected);
c.selectedIndex = first >= 0 ? first : 0;
c.value = first >= 0 && c.options[first] ? (c.options[first].value || '') : '';
}
walk(c);
}
};
walk(this);
}
_syncText() {
// Sync textContent from children
const t = this.children.map(c => c.textContent || '').join('');
@@ -70,6 +92,12 @@ class El {
} else {
this.textContent = '';
}
// Textarea: its value is its textContent. Capture defaultValue on first
// set so later reset() can restore.
if (this.tagName === 'TEXTAREA') {
this.value = this.textContent;
if (!('_origDefault' in this)) { this.defaultValue = this.textContent; this._origDefault = true; }
}
}
get firstElementChild() { return this.children[0]||null; }
get lastElementChild() { return this.children[this.children.length-1]||null; }
@@ -159,6 +187,16 @@ function parseHTMLFragments(html) {
el.textContent = inner;
}
el.innerHTML = inner;
// Textarea: its "value" comes from inner text, not an attr.
if (el.tagName === 'TEXTAREA') {
el.value = inner;
el.defaultValue = inner;
}
// Option: textContent is the label; if no value attr, it defaults to
// the label. Track defaultSelected separately from runtime selected.
if (el.tagName === 'OPTION' && !el.attributes.value) {
el.value = inner.trim();
}
}
results.push(el);
lastIndex = re.lastIndex;

View File

@@ -800,19 +800,24 @@ def parse_dev_body(body, elements, var_names):
def add_action(stmt):
am = re.search(
r"find\((['\"])(.+?)\1\)(?:\.(?:first|last)\(\)|\.nth\((\d+)\))?"
r"find\((['\"])(.+?)\1\)(?:\.(first|last)\(\)|\.nth\((\d+)\))?"
r"\.(click|dispatchEvent|fill|check|uncheck|focus|selectOption)\(([^)]*)\)",
stmt,
)
if not am or 'expect' in stmt:
return False
selector = am.group(2)
nth_idx = am.group(3)
action_type = am.group(4)
action_arg = am.group(5).strip("'\"")
first_last = am.group(3)
nth_idx = am.group(4)
action_type = am.group(5)
action_arg = am.group(6).strip("'\"")
target = selector_to_sx(selector, elements, var_names)
if nth_idx is not None:
target = f'(nth (dom-query-all (dom-body) "{selector}") {nth_idx})'
elif first_last == 'last':
target = f'(let ((_all (dom-query-all (dom-body) "{selector}"))) (nth _all (- (len _all) 1)))'
elif first_last == 'first':
target = f'(nth (dom-query-all (dom-body) "{selector}") 0)'
if action_type == 'click':
ops.append(f'(dom-dispatch {target} "click" nil)')
elif action_type == 'dispatchEvent':
@@ -837,7 +842,7 @@ def parse_dev_body(body, elements, var_names):
def add_assertion(stmt):
em = re.search(
r"expect\(find\((['\"])(.+?)\1\)(?:\.(?:first|last)\(\)|\.nth\((\d+)\))?\)\.(not\.)?"
r"expect\(find\((['\"])(.+?)\1\)(?:\.(first|last)\(\)|\.nth\((\d+)\))?\)\.(not\.)?"
r"(toHaveText|toHaveClass|toHaveCSS|toHaveAttribute|toHaveValue|toBeVisible|toBeHidden|toBeChecked)"
r"\(((?:[^()]|\([^()]*\))*)\)",
stmt,
@@ -845,13 +850,18 @@ def parse_dev_body(body, elements, var_names):
if not em:
return False
selector = em.group(2)
nth_idx = em.group(3)
negated = bool(em.group(4))
assert_type = em.group(5)
args_str = em.group(6)
first_last = em.group(3)
nth_idx = em.group(4)
negated = bool(em.group(5))
assert_type = em.group(6)
args_str = em.group(7)
target = selector_to_sx(selector, elements, var_names)
if nth_idx is not None:
target = f'(nth (dom-query-all (dom-body) "{selector}") {nth_idx})'
elif first_last == 'last':
target = f'(let ((_all (dom-query-all (dom-body) "{selector}"))) (nth _all (- (len _all) 1)))'
elif first_last == 'first':
target = f'(nth (dom-query-all (dom-body) "{selector}") 0)'
sx = pw_assertion_to_sx(target, negated, assert_type, args_str)
if sx:
ops.append(sx)