Skip to content

Commit ecfe239

Browse files
committed
fix(ios): gate get text snapshot-text fast-path to iOS only
Review (P1): the fast-path skipped the backend read on Android/Linux/macOS too, but those backends read value-first (macOS helper: AXValue→title→description; Linux similar) whereas snapshot readable text is label-first for non-editables — so skipping their read changed get text output. Restrict the optimization to the iOS XCUITest path (the slow allElementsBoundByIndex re-read it targets). Adds a test asserting non-iOS platforms still dispatch the backend read.
1 parent 64dd8d1 commit ecfe239

2 files changed

Lines changed: 24 additions & 5 deletions

File tree

src/daemon/handlers/__tests__/interaction-read.test.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,4 +54,17 @@ describe('readTextForNode', () => {
5454
expect(text).toBe('General');
5555
expect(mockDispatch).not.toHaveBeenCalled();
5656
});
57+
58+
it('does NOT skip the backend read on non-iOS platforms (value-first read semantics differ)', async () => {
59+
for (const platform of ['android', 'macos', 'linux'] as const) {
60+
mockDispatch.mockClear();
61+
const text = await readTextForNode({
62+
...baseParams,
63+
device: { platform } as never,
64+
node: node({ type: 'button', label: 'General' }),
65+
});
66+
expect(mockDispatch).toHaveBeenCalledOnce();
67+
expect(text).toBe('backend-text');
68+
}
69+
});
5770
});

src/daemon/handlers/interaction-read.ts

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,13 +23,19 @@ export async function readTextForNode(params: {
2323
return fallbackText;
2424
}
2525

26-
// The backend `read` re-resolves the element at a point, which on iOS XCUITest enumerates
27-
// the full element tree (allElementsBoundByIndex) and is ~20x slower than the snapshot we
26+
// iOS only: the XCUITest backend `read` re-resolves the element at a point by enumerating
27+
// the full element tree (allElementsBoundByIndex), which is ~20x slower than the snapshot we
2828
// already captured to resolve this node. That re-read only recovers fuller text for
2929
// editable/expandable inputs (textField/searchField/textView/…), where the live value can
30-
// exceed the snapshot. For every other element type the snapshot node text is authoritative,
31-
// so return it directly and skip the expensive round-trip.
32-
if (fallbackText && !prefersValueForReadableText(node.type ?? '')) {
30+
// exceed the snapshot; for every other element type the snapshot node text is authoritative.
31+
// Restricted to iOS because other backends read differently — macOS helper and Linux reads
32+
// are value-first (AXValue/title/description), unlike the label-first snapshot readable text,
33+
// so skipping their backend read would change the returned text.
34+
if (
35+
device.platform === 'ios' &&
36+
fallbackText &&
37+
!prefersValueForReadableText(node.type ?? '')
38+
) {
3339
return fallbackText;
3440
}
3541

0 commit comments

Comments
 (0)