diff --git a/packages/experimental/cua-macos/native/tests/e2e.py b/packages/experimental/cua-macos/native/tests/e2e.py index a5d0ea2a58..b16193bbdf 100644 --- a/packages/experimental/cua-macos/native/tests/e2e.py +++ b/packages/experimental/cua-macos/native/tests/e2e.py @@ -91,7 +91,6 @@ def main(): parser.add_argument("--helper", type=Path, help="Existing native helper executable for this run") parser.add_argument("--artifacts", type=Path, help="Save fixture screenshots and private JSON protocol transcript") parser.add_argument("--panels-only", action="store_true", help="Exercise system file panels without unrelated pointer gestures") - parser.add_argument("--pointer-only", action="store_true", help="Exercise window input without the system file-panel scenario") parser.add_argument("--hover-only", action="store_true", help="Exercise native hover without keyboard or file-panel scenarios") args = parser.parse_args() artifacts = args.artifacts @@ -193,7 +192,7 @@ def main(): call("click", hover_target) wait_state(lambda actual: actual["hoverClicks"] == 1, "Native hover control did not activate") call("hover", {**owner, "windowId": primary["windowId"], "x": 10, "y": 40, "useSystemPointer": True}) - state = wait_state(lambda actual: not actual["hoverVisible"], "AppKit tracking area did not exit") + wait_state(lambda actual: not actual["hoverVisible"], "AppKit tracking area did not exit") if args.hover_only: check_hover() @@ -257,15 +256,14 @@ def main(): call("screenshot", {**owner, "windowId": secondary["windowId"]}, "WINDOW_UNAVAILABLE") call("click", button_target(second, "Increment secondary"), "STALE_SNAPSHOT") - if not args.pointer_only: - check_file_panel(call, owner, primary_params, primary, directory, wait_state, button_target) + check_file_panel(call, owner, primary_params, primary, directory, wait_state, button_target) state = json.loads(state_path.read_text()) assert {key: state[key] for key in expected_pointer_counts} == expected_pointer_counts, state stop(fixture) call("listWindows", owner, "APP_UNAVAILABLE") call("listWindows", owner, "STALE_APP") helper.eof() - print("PASS: capability preflight, two-window snapshots, scoped invalidation, AX readback, Unicode input, single scroll/right-click/drag dispatch, image dimensions, native hover, stale app cleanup, EOF" + (" (file panel omitted)" if args.pointer_only else ", system file panel")) + print("PASS: capability preflight, two-window snapshots, scoped invalidation, AX readback, Unicode input, single scroll/right-click/drag dispatch, image dimensions, native hover, stale app cleanup, EOF", system file panel") finally: def save_artifacts(): if artifacts is not None: diff --git a/packages/experimental/cua-macos/native/tests/electron_e2e.py b/packages/experimental/cua-macos/native/tests/electron_e2e.py index adfb3a0608..ce3bf63b00 100644 --- a/packages/experimental/cua-macos/native/tests/electron_e2e.py +++ b/packages/experimental/cua-macos/native/tests/electron_e2e.py @@ -21,6 +21,7 @@ def main(): parser.add_argument("--helper", type=Path, help="Existing native helper executable for this run") parser.add_argument('--electron', type=Path, help='Existing Electron executable; no download is attempted') parser.add_argument('--artifacts', type=Path, help='Save fixture-only PNG and private protocol transcript') + parser.add_argument("--hover-only", action="store_true", help="Exercise hover independently of text input") args = parser.parse_args() repo = ROOT.parents[3] executable = args.electron or repo / 'apps/desktop/node_modules/electron/dist/Electron.app/Contents/MacOS/Electron' @@ -95,23 +96,24 @@ def main(): raise AssertionError(description + ': ' + json.dumps(actual)) time.sleep(0.025) - call('click', {**owner, 'snapshotId': state['snapshotId'], 'elementIndex': buttons[0]['index']}) - wait_state(lambda actual: actual['clicks'] == 1 and actual['lastClickTrusted'] is True, - 'Native AX press did not produce one trusted DOM click') - state = observe() - assert 'Clicks: 1' in state['tree'], state['tree'] - _, fields = targets(state) - field = fields[0]['bounds'] window = next(window for window in state['windows'] if window['windowId'] == window_id) - call('click', {**owner, 'windowId': window_id, 'snapshotId': state['snapshotId'], - 'x': field[0] + field[2] / 2 - window['bounds']['x'], - 'y': field[1] + field[3] / 2 - window['bounds']['y']}) - call('typeText', {**owner, 'text': 'Electron 中文 🧪'}) - wait_state(lambda actual: actual['text'] == 'Electron 中文 🧪' and actual['lastInputTrusted'] is True, - 'Chromium did not receive complete trusted Unicode input') - call('pressKey', {**owner, 'key': 'a', 'modifiers': ['command']}) - call('typeText', {**owner, 'text': '第二次 Electron'}) - wait_state(lambda actual: actual['text'] == '第二次 Electron', 'Chromium Command+A did not replace the field') + if not args.hover_only: + call('click', {**owner, 'snapshotId': state['snapshotId'], 'elementIndex': buttons[0]['index']}) + wait_state(lambda actual: actual['clicks'] == 1 and actual['lastClickTrusted'] is True, + 'Native AX press did not produce one trusted DOM click') + state = observe() + assert 'Clicks: 1' in state['tree'], state['tree'] + _, fields = targets(state) + field = fields[0]['bounds'] + call('click', {**owner, 'windowId': window_id, 'snapshotId': state['snapshotId'], + 'x': field[0] + field[2] / 2 - window['bounds']['x'], + 'y': field[1] + field[3] / 2 - window['bounds']['y']}) + call('typeText', {**owner, 'text': 'Electron 中文 🧪'}) + wait_state(lambda actual: actual['text'] == 'Electron 中文 🧪' and actual['lastInputTrusted'] is True, + 'Chromium did not receive complete trusted Unicode input') + call('pressKey', {**owner, 'key': 'a', 'modifiers': ['command']}) + call('typeText', {**owner, 'text': '第二次 Electron'}) + wait_state(lambda actual: actual['text'] == '第二次 Electron', 'Chromium Command+A did not replace the field') image = call('screenshot', {**owner, 'windowId': window_id}) png = base64.b64decode(image['data'], validate=True) assert png.startswith(b'\x89PNG\r\n\x1a\n') @@ -151,7 +153,8 @@ def main(): call('hover', {**owner, 'windowId': window_id, 'x': 10, 'y': 40}) wait_state(lambda actual: not actual['popupOpen'], 'Leaving the hover region did not close it') helper.eof() - print(f"PASS: Electron {runtime['electron']} native AX readiness, trusted DOM click, Unicode input, Command+A replacement, PNG capture, delayed hover across observations, popup entry/click/exit") + print(f"PASS: Electron {runtime['electron']} delayed hover across observations, popup entry/click/exit, invalid targets" + + (" (text input omitted)" if args.hover_only else ", trusted DOM click, Unicode input, Command+A replacement, PNG capture")) except Exception: diagnostics.flush() diagnostics.seek(0) diff --git a/snapshots/session/cua-native/tool-schemas.expected.json b/snapshots/session/cua-native/tool-schemas.expected.json index d8243f105c..27da0ddab3 100644 --- a/snapshots/session/cua-native/tool-schemas.expected.json +++ b/snapshots/session/cua-native/tool-schemas.expected.json @@ -316,6 +316,7 @@ "maximum": 9007199254740991 }, "useSystemPointer": { + "description": "Move the visible system cursor for native hover tracking; requires the target to be unobscured in the foreground app. Default false sends window-directed movement.", "type": "boolean" } }, @@ -351,6 +352,7 @@ "minimum": 0 }, "useSystemPointer": { + "description": "Move the visible system cursor for native hover tracking; requires the target to be unobscured in the foreground app. Default false sends window-directed movement.", "type": "boolean" } },