test(cua): keep hover regressions independent of keyboard focus
This commit is contained in:
1 parent
9781ac0fda
commit
02bbff61b6
3 files changed
+25
-22
No files matched your search
@@ -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:
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
},
|
||||
|
||||
Reference in new issue
Block a user