From 5967b4c79bc019919de9476c8a1b84bfb3572130 Mon Sep 17 00:00:00 2001 From: PJ Date: Sun, 16 Aug 2026 17:45:47 +0530 Subject: [PATCH] docs(manual): document innermost text matching, escape and the web scroll verb text: names the innermost match and both selector forms scan the same set, root included. escape joins the key list, with a per-platform note and the rule that a key the platform cannot send fails the action. scroll and swipe are one gesture on a touch device and two different ones in a browser, so say which reaches what. --- docs/manual/spec-language.md | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/docs/manual/spec-language.md b/docs/manual/spec-language.md index 9b4516d..6f951ed 100644 --- a/docs/manual/spec-language.md +++ b/docs/manual/spec-language.md @@ -47,7 +47,7 @@ interface State { ## Selectors -Selectors are passed to `ax.find()`, `ax.findAll()`, and element-scoped `.find()` / `.findAll()`. +Selectors are passed to `ax.find()`, `ax.findAll()`, and element-scoped `.find()` / `.findAll()`. A tree-level lookup scans the whole hierarchy, the root element included; an element-scoped one scans that element's descendants. Both selector forms scan the same set, so `ax.find("id:page")` and `ax.find({ id: "page" })` return the same element. ### String selectors @@ -55,13 +55,15 @@ Selectors are passed to `ax.find()`, `ax.findAll()`, and element-scoped `.find() |---|---| | `id:` | Exact match on resource-id, or element whose resource-id ends with `:id/` (Android) | | `idPrefix:` | Starts-with match on resource-id, matched against the whole id and against the local name after `:id/` (Android) | -| `text:` | Substring match on text content | +| `text:` | Substring match on text content, innermost match only | | `desc:` | Exact match on accessibility description; also matches when description starts with `, ` (iOS merged labels) | | `descPrefix:` | Starts-with match on accessibility description | | `:` | Substring match on any raw attribute by name | Boolean attributes (`"true"` / `"false"`) use exact match rather than substring. +`text:` names the innermost match. An element's text is its whole subtree's text on web and on iOS, so a badge reading "Sent ✓" makes every ancestor of it read as a match too, up to the root. A match a descendant of it also makes is dropped, which leaves the deepest element carrying the value: `ax.find("text:Sent")` lands on the badge, and `ax.findAll("text:Sent")` returns the badges without their ancestors. An ancestor whose own text carries the value where no descendant of it does keeps its match. `{ text: "Sent" }` means the same thing. + ### Object selectors Pass an object to apply multiple attribute filters with AND semantics: @@ -229,9 +231,9 @@ PressKey({ key: Key }) Wait({ durationMillis: number }) ``` -`Key` values: `"back"`, `"home"`, `"enter"`, `"tab"`, `"up"`, `"down"`, `"left"`, `"right"`. +`Key` values: `"back"`, `"home"`, `"enter"`, `"tab"`, `"escape"`, `"up"`, `"down"`, `"left"`, `"right"`. -On web, `"back"` maps to Backspace and `"home"` is not supported. All other keys work on all platforms. +Android sends all nine. Web sends every key except `"back"` and `"home"`, which have no in-page meaning. iOS sends `"enter"` and `"escape"`. A key the platform cannot send fails the action with an error rather than pressing nothing. ### Built-in generators @@ -254,6 +256,12 @@ you need one. four directions. The sideways ones are what reach swipe-to-dismiss and swipe-to-delete on a list row. +On a touch device the two verbs are one gesture: a Scroll is dispatched as a drag. A +browser is not a touch device, so `Scroll` there is a wheel over the point, which moves the +container under it by exactly the distance asked for, and `Swipe` is a touch drag, which +reaches the handlers only a finger reaches and carries a drag's momentum. Reach for `Swipe` +when a container scrolls by handling the drag itself rather than by overflowing. + ### `actions(generator)` Wraps a callback that returns `Action[]`. The callback runs each step the generator is eligible.