HS generator+runtime: nth() dispatch+expect, dom-query-all SX-list passthrough, nth-of-type selector
- generate-sx-tests.py: add_action/add_assertion accept .nth(N) in PW-body
tests so 'find(sel).nth(1).dispatchEvent(...)' lands as a dispatch on
the Nth matching element, and assertions target that same element.
- shared/static/wasm/sx/dom.sx: dom-query-all hands through an already-SX
list unchanged — the bridge often pre-converts NodeLists/arrays to SX
lists, so the host-get 'length' / host-call 'item' loop was returning
empty. Guards node-list=nil and non-list types too.
- tests/hs-run-filtered.js (mock DOM): fnd() understands
':nth-of-type(N)', ':first-of-type', ':last-of-type' by matching the
stripped base selector and returning the correct-indexed sibling.
Covers upstream tests that write 'find("div:nth-of-type(2)")' to
pick the HS-owning element.
- Runtime runtime.sx: hs-sorted-by, hs-fetch format normalizer (JSON/
Object/etc.), nil-safe hs-joined-by/hs-split-by, emit-fetch chain sets
the-result when wrapped in let((it …)).
Net: take 0→6, hide 11→12, show 15→16, fetch 11→15,
collectionExpressions 13→15 (remaining are a WASM JIT bug on
{…} literals inside arrays).
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -796,16 +796,19 @@ def parse_dev_body(body, elements, var_names):
|
||||
|
||||
def add_action(stmt):
|
||||
am = re.search(
|
||||
r"find\((['\"])(.+?)\1\)(?:\.(?:first|last)\(\))?"
|
||||
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)
|
||||
action_type = am.group(3)
|
||||
action_arg = am.group(4).strip("'\"")
|
||||
nth_idx = am.group(3)
|
||||
action_type = am.group(4)
|
||||
action_arg = am.group(5).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})'
|
||||
if action_type == 'click':
|
||||
ops.append(f'(dom-dispatch {target} "click" nil)')
|
||||
elif action_type == 'dispatchEvent':
|
||||
@@ -830,7 +833,7 @@ def parse_dev_body(body, elements, var_names):
|
||||
|
||||
def add_assertion(stmt):
|
||||
em = re.search(
|
||||
r"expect\(find\((['\"])(.+?)\1\)(?:\.(?:first|last)\(\))?\)\.(not\.)?"
|
||||
r"expect\(find\((['\"])(.+?)\1\)(?:\.(?:first|last)\(\)|\.nth\((\d+)\))?\)\.(not\.)?"
|
||||
r"(toHaveText|toHaveClass|toHaveCSS|toHaveAttribute|toHaveValue|toBeVisible|toBeHidden|toBeChecked)"
|
||||
r"\(((?:[^()]|\([^()]*\))*)\)",
|
||||
stmt,
|
||||
@@ -838,10 +841,13 @@ def parse_dev_body(body, elements, var_names):
|
||||
if not em:
|
||||
return False
|
||||
selector = em.group(2)
|
||||
negated = bool(em.group(3))
|
||||
assert_type = em.group(4)
|
||||
args_str = em.group(5)
|
||||
nth_idx = em.group(3)
|
||||
negated = bool(em.group(4))
|
||||
assert_type = em.group(5)
|
||||
args_str = em.group(6)
|
||||
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})'
|
||||
sx = pw_assertion_to_sx(target, negated, assert_type, args_str)
|
||||
if sx:
|
||||
ops.append(sx)
|
||||
|
||||
Reference in New Issue
Block a user