Test runner: return-value error handling, no guard/cek-try/throws

guard and cek-try both create CEK frames that don't survive async
perform/resume. Instead, run-action returns nil on success and an
error string on failure. The for-each loop checks the return value
and sets fail-msg. No exceptions cross async boundaries.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-17 23:09:38 +00:00
parent db8e680caf
commit 84996d74e2
5 changed files with 77 additions and 66 deletions

View File

@@ -999,7 +999,31 @@
(hs-to-sx (nth ast 1))
(hs-to-sx (nth ast 2)))))
((= head (quote do))
(cons (quote do) (map hs-to-sx (rest ast))))
(let
((compiled (map hs-to-sx (rest ast))))
(if
(and
(> (len compiled) 1)
(some
(fn
(c)
(and
(list? c)
(or
(= (first c) (quote hs-fetch))
(= (first c) (quote hs-wait))
(= (first c) (quote perform)))))
compiled))
(reduce
(fn
(body cmd)
(list
(quote let)
(list (list (quote it) cmd))
body))
(nth compiled (- (len compiled) 1))
(reverse (rest (reverse compiled))))
(cons (quote do) compiled))))
((= head (quote wait)) (list (quote hs-wait) (nth ast 1)))
((= head (quote wait-for)) (emit-wait-for ast))
((= head (quote log))

File diff suppressed because one or more lines are too long

View File

@@ -1859,7 +1859,8 @@
(let
((acc2 (append acc (list cmd))))
(cond
((match-kw "then") (cl-collect acc2))
((match-kw "then")
(cl-collect (append acc2 (list (quote __then__)))))
((and (not (at-end?)) (= (tp-type) "keyword") (cmd-kw? (tp-val)))
(cl-collect acc2))
(true acc2)))))))
@@ -1868,7 +1869,10 @@
(cond
((= (len cmds) 0) nil)
((= (len cmds) 1) (first cmds))
(true (cons (quote do) cmds))))))
(true
(cons
(quote do)
(filter (fn (c) (not (= c (quote __then__)))) cmds)))))))
(define
parse-on-feat
(fn

File diff suppressed because one or more lines are too long

View File

@@ -47,53 +47,44 @@
nil
(do (hs-wait 200) (wait-for-el sel (- max-tries 1))))))))
(run-action
(fn
(action)
(let
((doc (get-doc)) (type (first action)))
(fn (action)
(let ((doc (get-doc)) (type (first action)))
(cond
(= type :click)
(let
((el (host-call doc "querySelector" (nth action 1))))
(when (nil? el) (error (str "Not found: " (nth action 1))))
(host-call el "click"))
(let ((el (host-call doc "querySelector" (nth action 1))))
(if (nil? el) (str "Not found: " (nth action 1))
(do (host-call el "click") nil)))
(= type :fill)
(let
((el (host-call doc "querySelector" (nth action 1))))
(when (nil? el) (error (str "Not found: " (nth action 1))))
(host-call el "focus")
(dom-set-prop el "value" (nth action 2))
(dom-dispatch el "input" nil)
(dom-dispatch el "change" nil))
(let ((el (host-call doc "querySelector" (nth action 1))))
(if (nil? el) (str "Not found: " (nth action 1))
(do (host-call el "focus")
(dom-set-prop el "value" (nth action 2))
(dom-dispatch el "input" nil)
(dom-dispatch el "change" nil)
nil)))
(= type :wait)
(hs-wait (nth action 1))
(do (hs-wait (nth action 1)) nil)
(= type :assert-text)
(let
((el (host-call doc "querySelector" (nth action 1))))
(when (nil? el) (error (str "Not found: " (nth action 1))))
(let
((txt (dom-text-content el))
(kw (nth action 2))
(expected (nth action 3)))
(when
(and (= kw :contains) (not (contains? txt expected)))
(error (str "Expected '" expected "' in '" (slice txt 0 60) "'")))
(when
(and (= kw :not-contains) (contains? txt expected))
(error (str "Unexpected '" expected "'")))))
(let ((el (host-call doc "querySelector" (nth action 1))))
(if (nil? el) (str "Not found: " (nth action 1))
(let ((txt (dom-text-content el))
(kw (nth action 2))
(expected (nth action 3)))
(cond
(and (= kw :contains) (not (contains? txt expected)))
(str "Expected '" expected "' in '" (slice txt 0 60) "'")
(and (= kw :not-contains) (contains? txt expected))
(str "Unexpected '" expected "'")
true nil))))
(= type :assert-count)
(let
((els (host-call doc "querySelectorAll" (nth action 1))))
(let
((count (host-get els "length"))
(kw (nth action 2))
(expected (nth action 3)))
(when
(and (= kw :gte) (< count expected))
(let ((els (host-call doc "querySelectorAll" (nth action 1))))
(let ((count (host-get els "length"))
(kw (nth action 2))
(expected (nth action 3)))
(if (and (= kw :gte) (< count expected))
(str "Expected >=" expected " got " count)
nil)))
true
nil))))
true nil))))
(run-all
(fn
()
@@ -111,26 +102,18 @@
(console-log "[test] reload-frame")
(reload-frame)
(console-log "[test] running actions")
(guard
(e
(true
(reset! results (assoc (deref results) name "fail"))
(console-log (str "[test] FAIL " name ": " e))))
(let
((actions (get test :actions)))
(when
(not (empty? actions))
(let
((first-sel (nth (first actions) 1)))
(when
(string? first-sel)
(console-log (str "[test] wait-for: " first-sel))
(let ((found (wait-for-el first-sel 15)))
(when (nil? found)
(error (str "Timeout waiting for: " first-sel)))))))
(for-each run-action actions)
(reset! results (assoc (deref results) name "pass"))
(console-log (str "[test] PASS " name))))))
(let ((actions (get test :actions)) (fail-msg nil))
(when (not (empty? actions))
(let ((first-sel (nth (first actions) 1)))
(when (string? first-sel)
(console-log (str "[test] wait-for: " first-sel))
(let ((found (wait-for-el first-sel 15)))
(when (nil? found) (set! fail-msg (str "Timeout: " first-sel)))))))
(when (nil? fail-msg)
(for-each (fn (action) (when (nil? fail-msg) (let ((err (run-action action))) (when (string? err) (set! fail-msg err))))) actions))
(if (nil? fail-msg)
(do (reset! results (assoc (deref results) name "pass")) (console-log (str "[test] PASS " name)))
(do (reset! results (assoc (deref results) name "fail")) (console-log (str "[test] FAIL " name ": " fail-msg)))))))
tests)
(reset! running false)
(reset! current "Done")