From 037a803f0e9c08f9ca3f05b3b4a9f625a471ee1c Mon Sep 17 00:00:00 2001 From: PJ Date: Thu, 13 Aug 2026 22:55:20 +0530 Subject: [PATCH] fix(spec): key web attrs by the names the markup writes attrs was spread from element.dataset, whose DOMStringMap keys are camelCase, so a spec reading attrs["data-cents"] the way every native host reports it read undefined. In folio-web that left ledgerTxnCount and ledgerBalance permanently zero: someTransactionExists could never be satisfied, balanceMatchesTransaction Delta could never fire, and totalBalanceMatchesAccounts compared 0 to 0 and passed vacuously. Three properties reported nothing because the harness was blind, not because the application was correct. The handle also fills hintText and editable now, so an authored InputText on web names its field the way the same action names it on Android instead of rendering as Type "12.34" into "". Claude-Session: https://claude.ai/code/session_01A5KmftdEJ49A9z5mF5ESrX --- pkg/spec/src/web-runtime.ts | 46 +++++++++++-- pkg/spec/test/web-runtime.test.ts | 107 ++++++++++++++++++++++++++++++ 2 files changed, 148 insertions(+), 5 deletions(-) diff --git a/pkg/spec/src/web-runtime.ts b/pkg/spec/src/web-runtime.ts index e355bc1..5e5dcc6 100644 --- a/pkg/spec/src/web-runtime.ts +++ b/pkg/spec/src/web-runtime.ts @@ -359,6 +359,38 @@ function evaluateXPathAll(xpath: string, root: Node): Element[] { return out; } +// rawAttributes keys an element's attributes by the names the markup writes, +// which is what `attrs` means on every other backend. element.dataset would key +// `data-cents` as `cents`, so a spec reading attrs["data-cents"] the way the +// native hosts report it read undefined on web and every assertion over it +// passed vacuously. +function rawAttributes(element: Element): Record { + const out: Record = {}; + for (const attribute of Array.from(element.attributes ?? [])) { + out[attribute.name] = attribute.value; + } + return out; +} + +// fieldHint names an editable field the way a user reads it, in the order the +// accessible name is computed: its own aria-label, the