Skip to content

Commit 2e842d1

Browse files
committed
fix(snapshot): address ownership review feedback
1 parent b52fc29 commit 2e842d1

6 files changed

Lines changed: 47 additions & 23 deletions

File tree

packages/contracts/src/facades/snapshot.ts

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
export { isScrollableNodeLike, isScrollableType } from '../snapshot-scroll.ts';
2-
export { buildSnapshotNodeMap, findNearestAncestor, findSnapshotAncestor } from '../snapshot-tree.ts';
2+
export {
3+
buildSnapshotNodeMap,
4+
findNearestAncestor,
5+
findSnapshotAncestor,
6+
} from '../snapshot-tree.ts';
37
export {
48
findNearestScrollableAncestor,
59
isNodeVisibleInEffectiveViewport,
@@ -10,4 +14,9 @@ export {
1014
resolveEffectiveViewportRect,
1115
resolveViewportRect,
1216
} from '../snapshot-visibility.ts';
13-
export { extractNodeText, isFillableType, isMeaningfulLabel, normalizeType } from '../snapshot-text.ts';
17+
export {
18+
extractNodeText,
19+
isFillableType,
20+
isMeaningfulLabel,
21+
normalizeType,
22+
} from '../snapshot-text.ts';

packages/contracts/src/snapshot.test.ts

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import type { RawSnapshotNode, Rect, SnapshotNode } from '@agent-device/kernel/s
44
import {
55
buildSnapshotNodeMap,
66
extractNodeText,
7+
findNearestAncestor,
78
findNearestScrollableAncestor,
89
findSnapshotAncestor,
910
isFillableType,
@@ -28,8 +29,6 @@ test('snapshot text semantics normalize roles, identify fillable controls, and e
2829
assert.equal(isFillableType('android.widget.EditText', 'android'), true);
2930
assert.equal(
3031
extractNodeText({
31-
index: 0,
32-
ref: '@e0',
3332
label: ' ',
3433
value: ' Enter name ',
3534
identifier: 'name',
@@ -68,6 +67,19 @@ test('findSnapshotAncestor terminates on a parent-linkage cycle without resolvin
6867
assert.equal(ancestor, null);
6968
});
7069

70+
test('findNearestAncestor adapts a predicate to the shared tree walk', () => {
71+
const nodes: SnapshotNode[] = [
72+
{ ref: 'e10', index: 10, type: 'Window' },
73+
{ ref: 'e30', index: 30, parentIndex: 20, type: 'Text' },
74+
{ ref: 'e20', index: 20, parentIndex: 10, type: 'Cell' },
75+
];
76+
77+
assert.equal(
78+
findNearestAncestor(nodes, nodes[1]!, (ancestor) => ancestor.type === 'Window')?.index,
79+
10,
80+
);
81+
});
82+
7183
test('snapshot tree and scroll semantics identify nodes through their stable indexes', () => {
7284
const nodes = [
7385
node({ index: 0, type: 'Window' }),

src/core/interaction-targeting.ts

Lines changed: 1 addition & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -124,19 +124,7 @@ export function isRootInteractionContainer(
124124
);
125125
}
126126

127-
/**
128-
* The retarget itself. Runtime callers reach it through the promotion stage of
129-
* `selector-pipeline-policy.ts`, which is what decides whether a given caller
130-
* promotes at all; this stays exported for that runner and for focused tests.
131-
*/
132-
export function resolveActionableTouchNode(
133-
nodes: SnapshotNode[],
134-
node: SnapshotNode,
135-
): SnapshotNode {
136-
return resolveActionableTouchResolution(nodes, node).node;
137-
}
138-
139-
/** @internal Exposed for focused policy tests; runtime callers should use resolveActionableTouchNode. */
127+
/** @internal Exposed for focused policy tests. */
140128
export function resolveActionableTouchResolution(
141129
nodes: SnapshotNode[],
142130
node: SnapshotNode,

src/core/snapshot-chrome.ts

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -239,11 +239,7 @@ function collectAndroidSettleChrome(
239239
appBundleId: string | undefined,
240240
): SettleChrome {
241241
const byIndex = new Map(nodes.map((node) => [node.index, node]));
242-
const imeIndexes = new Set(
243-
nodes
244-
.filter(isAndroidInputMethodNode)
245-
.map((node) => node.index),
246-
);
242+
const imeIndexes = new Set(nodes.filter(isAndroidInputMethodNode).map((node) => node.index));
247243
const imeContainerIndexes = new Set(
248244
[...imeIndexes].filter((index) => {
249245
const parentIndex = byIndex.get(index)?.parentIndex;

src/core/snapshot-tree-ingestion.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
import type { RawSnapshotNode } from '@agent-device/kernel/snapshot';
2-
import { extractNodeText, isMeaningfulLabel, normalizeType } from '@agent-device/contracts/snapshot';
2+
import {
3+
extractNodeText,
4+
isMeaningfulLabel,
5+
normalizeType,
6+
} from '@agent-device/contracts/snapshot';
37

48
export function normalizeSnapshotTree(nodes: RawSnapshotNode[]): RawSnapshotNode[] {
59
const originalToNormalizedIndex = new Map<number, number>();

src/platforms/android/__tests__/input-ownership.test.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,25 @@ import assert from 'node:assert/strict';
22
import { test } from 'vitest';
33
import {
44
classifyAndroidInputOwnership,
5+
isAndroidInputMethodNode,
56
parseAndroidInputMethodPackage,
67
readAndroidActiveInputMethodPackage,
78
} from '@agent-device/contracts/platform';
89

10+
test('classifies raw snapshot nodes through the node-shaped IME predicate', () => {
11+
assert.equal(
12+
isAndroidInputMethodNode({
13+
bundleId: 'com.google.android.inputmethod.latin',
14+
identifier: 'com.google.android.inputmethod.latin:id/key',
15+
}),
16+
true,
17+
);
18+
assert.equal(
19+
isAndroidInputMethodNode({ bundleId: 'com.example.app', identifier: 'save' }),
20+
false,
21+
);
22+
});
23+
924
test('classifies active input method package as IME-owned', () => {
1025
assert.deepEqual(
1126
classifyAndroidInputOwnership({

0 commit comments

Comments
 (0)