From 0746c907291948bbcf41f277cee8c41457917d3b Mon Sep 17 00:00:00 2001 From: giles Date: Mon, 27 Apr 2026 03:12:04 +0000 Subject: [PATCH] HS: fix as Values SELECT + multi-select programmatic changes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - hs-value-of-node: use selectedIndex fallback when SELECT.value is empty (mock DOM doesn't auto-compute it from selected options) - generate-sx-tests: manual body for 'programmatically changed selections' test — deselect dog, select cat before reading values Co-Authored-By: Claude Sonnet 4.6 --- lib/hyperscript/runtime.sx | 12 +++++++++++- shared/static/wasm/sx/hs-runtime.sx | 12 +++++++++++- spec/tests/test-hyperscript-behavioral.sx | 14 +++++++++----- tests/playwright/generate-sx-tests.py | 12 ++++++++++++ 4 files changed, 43 insertions(+), 7 deletions(-) diff --git a/lib/hyperscript/runtime.sx b/lib/hyperscript/runtime.sx index b3284eac..a356d826 100644 --- a/lib/hyperscript/runtime.sx +++ b/lib/hyperscript/runtime.sx @@ -1180,7 +1180,17 @@ (if (host-get node "multiple") (hs-select-multi-values node) - (host-get node "value"))) + (let + ((idx (host-get node "selectedIndex")) + (opts (host-get node "options")) + (raw-val (host-get node "value"))) + (if + (and (not (nil? raw-val)) (not (= raw-val ""))) + raw-val + (if + (and (not (nil? opts)) (>= idx 0)) + (host-get (if (list? opts) (nth opts idx) (host-get opts idx)) "value") + ""))))) ((or (= typ "checkbox") (= typ "radio")) (if (host-get node "checked") (host-get node "value") nil)) (true (host-get node "value")))))) diff --git a/shared/static/wasm/sx/hs-runtime.sx b/shared/static/wasm/sx/hs-runtime.sx index b3284eac..a356d826 100644 --- a/shared/static/wasm/sx/hs-runtime.sx +++ b/shared/static/wasm/sx/hs-runtime.sx @@ -1180,7 +1180,17 @@ (if (host-get node "multiple") (hs-select-multi-values node) - (host-get node "value"))) + (let + ((idx (host-get node "selectedIndex")) + (opts (host-get node "options")) + (raw-val (host-get node "value"))) + (if + (and (not (nil? raw-val)) (not (= raw-val ""))) + raw-val + (if + (and (not (nil? opts)) (>= idx 0)) + (host-get (if (list? opts) (nth opts idx) (host-get opts idx)) "value") + ""))))) ((or (= typ "checkbox") (= typ "radio")) (if (host-get node "checked") (host-get node "value") nil)) (true (host-get node "value")))))) diff --git a/spec/tests/test-hyperscript-behavioral.sx b/spec/tests/test-hyperscript-behavioral.sx index e739487b..8315a315 100644 --- a/spec/tests/test-hyperscript-behavioral.sx +++ b/spec/tests/test-hyperscript-behavioral.sx @@ -3817,11 +3817,15 @@ ) (deftest "converts multiple selects with programmatically changed selections" (let ((_node (dom-create-element "form"))) - (dom-set-inner-html _node "") - (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") - )) + (dom-set-inner-html _node "") + (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)) diff --git a/tests/playwright/generate-sx-tests.py b/tests/playwright/generate-sx-tests.py index c8205bcf..a8e9c586 100644 --- a/tests/playwright/generate-sx-tests.py +++ b/tests/playwright/generate-sx-tests.py @@ -128,6 +128,18 @@ SKIP_TEST_NAMES = { # Manually-written SX test bodies for tests whose upstream body cannot be # auto-translated. Key = test name; value = SX lines to emit inside deftest. MANUAL_TEST_BODIES = { + "converts multiple selects with programmatically changed selections": [ + ' (let ((_node (dom-create-element "form")))', + ' (dom-set-inner-html _node "")', + ' (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")', + ' ))))', + ], "iterate cookies values work": [ ' (hs-cleanup!)', ' (host-set! (host-global "cookies") "foo" "bar")',