Skip to content

Commit f085155

Browse files
committed
fix(ui-automation): Keep inactive tabs in next-step suggestions
Allow unselected tab elements to remain eligible as screen-changing tap examples while still filtering selected/current tabs and non-tab selected controls from generic next-step suggestions. Add regression coverage for inactive tabs so the tab-priority path stays reachable.
1 parent bcc7720 commit f085155

2 files changed

Lines changed: 40 additions & 4 deletions

File tree

src/mcp/tools/ui-automation/__tests__/runtime-next-steps.test.ts

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,40 @@ describe('runtime snapshot next steps', () => {
105105
});
106106
});
107107

108+
it('keeps unselected tabs available as screen-changing tap suggestions', () => {
109+
recordSnapshot([
110+
createNode({
111+
type: 'Tab',
112+
role: 'AXTab',
113+
AXLabel: 'Current',
114+
AXValue: 'selected',
115+
AXSelected: true,
116+
}),
117+
createNode({
118+
type: 'Tab',
119+
role: 'AXTab',
120+
AXLabel: 'Search',
121+
AXValue: 'not selected',
122+
AXSelected: false,
123+
}),
124+
]);
125+
126+
const snapshot = currentRuntimeSnapshot();
127+
const searchTabRef = snapshot.elements.find((element) => element.label === 'Search')?.ref;
128+
129+
const steps = createRuntimeSnapshotNextSteps({
130+
simulatorId,
131+
runtimeSnapshot: snapshot,
132+
includeRefreshAndWait: false,
133+
});
134+
135+
expect(steps).toContainEqual({
136+
label: 'Tap an elementRef',
137+
tool: 'tap',
138+
params: { simulatorId, elementRef: searchTabRef },
139+
});
140+
});
141+
108142
it('uses hierarchy depth only as a foreground-root tie breaker', () => {
109143
recordSnapshot([
110144
nestNode(

src/mcp/tools/ui-automation/shared/runtime-next-steps.ts

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -84,12 +84,14 @@ function isStateChangingTapNextStepElement(element: {
8484
value?: string;
8585
}): boolean {
8686
const value = compactTapNextStepText(element.value).toLowerCase();
87-
return (
88-
element.role === 'switch' ||
87+
const hasSelectionState =
8988
element.state?.selected === true ||
90-
element.state?.selected === false ||
9189
value === 'selected' ||
92-
value === 'not selected' ||
90+
(element.role !== 'tab' && (element.state?.selected === false || value === 'not selected'));
91+
92+
return (
93+
element.role === 'switch' ||
94+
hasSelectionState ||
9395
value === '0' ||
9496
value === '1' ||
9597
value === 'off' ||

0 commit comments

Comments
 (0)