From 6983a4ed2137bf1a8377e5d1cf82183e02e617f8 Mon Sep 17 00:00:00 2001
From: Ariver <shanghai3168@gmail.com>
Date: Sat, 13 Jun 2026 14:08:17 +0800
Subject: [PATCH] Fix multi-page targeting and split view tile QA
---
C3.tools/round1-view-mode-entry-qa.sh | 130 +++++++++++++++++++++++++++++++++++++++++++
1 files changed, 129 insertions(+), 1 deletions(-)
diff --git a/C3.tools/round1-view-mode-entry-qa.sh b/C3.tools/round1-view-mode-entry-qa.sh
index 87491ee..cb53ff4 100755
--- a/C3.tools/round1-view-mode-entry-qa.sh
+++ b/C3.tools/round1-view-mode-entry-qa.sh
@@ -12,6 +12,7 @@
APP="$BUILD_CURRENT_APP"
REPORT_VERTICAL="$BUILD_REPORT_ROOT/round01-view-mode-entry-vertical-report.json"
REPORT_HORIZONTAL="$BUILD_REPORT_ROOT/round01-view-mode-entry-horizontal-report.json"
+REPORT_SETTINGS="$BUILD_REPORT_ROOT/round01-view-mode-entry-settings-report.json"
DOMAIN="com.ar.Aligner"
WATERFALL_MODE_KEY="com.ar.Aligner.preferences.quickSwitch.waterfallViewMode"
REPORT_WAIT="${ALIGNER_ROUND1_VIEW_MODE_ENTRY_REPORT_WAIT:-6.0}"
@@ -131,6 +132,8 @@
sys.exit(1)
status_menu = report.get("statusMenu", {})
+main_menu = report.get("mainMenu", {})
+settings_window = report.get("settingsWindow", {})
root = report.get("rootView", {})
require(report.get("snapshotLoaded") is True, "snapshotLoaded must be true")
@@ -139,11 +142,23 @@
require(report.get("resolvedWaterfallViewMode") == expected_mode, "resolved Waterfall mode must match expected mode")
require(root.get("waterfallViewMode") == expected_mode, "root view Waterfall mode must match expected mode")
require(status_menu.get("hasAboutItem") is True, "status menu must expose About Aligner")
+require(status_menu.get("hasSettingsItem") is True, "status menu must expose Settings")
require(status_menu.get("hasQuickSwitchViewSubmenu") is True, "status menu must expose Quick Switch View submenu")
require(status_menu.get("hasVerticalColumnsItem") is True, "status menu must expose Vertical Columns item")
require(status_menu.get("hasHorizontalWaterfallItem") is True, "status menu must expose Horizontal Waterfall item")
require(status_menu.get("verticalColumnsState") == expected_vertical_state, "Vertical Columns check state must match expected mode")
require(status_menu.get("horizontalWaterfallState") == expected_horizontal_state, "Horizontal Waterfall check state must match expected mode")
+require(main_menu.get("hasMenu") is True, "main menu must exist")
+require(main_menu.get("hasAppMenu") is True, "main menu must expose app menu")
+require(main_menu.get("hasSettingsItem") is True, "main menu must expose Settings")
+require(main_menu.get("settingsKeyEquivalent") == ",", "Settings must use Cmd+, key equivalent")
+require(main_menu.get("hasQuickSwitchViewSubmenuInAppMenu") is True, "app menu must expose Quick Switch View submenu")
+require(main_menu.get("hasQuickSwitchViewSubmenuInViewMenu") is True, "View menu must expose Quick Switch View submenu")
+require(root.get("settingsButtonVisible") is True, "Quick Switch must expose a top-right Settings button")
+settings_frame = root.get("settingsButtonFrame", {})
+require(settings_frame.get("width", 0) >= 30 and settings_frame.get("height", 0) >= 30, "Settings button must have tappable size")
+require(settings_frame.get("x", 0) + settings_frame.get("width", 0) > root.get("bounds", {}).get("width", 0) * 0.90, "Settings button must sit near the top-right edge")
+require(settings_window.get("visible") is False, "Settings window should not be open in passive view-mode entry cases")
require(report.get("aboutVersion") == app_version, "About version must match app Info.plist")
require(report.get("aboutBuild") == app_build, "About build must match app Info.plist")
require(re.match(r"^[0-9]+\.[0-9]+\.[0-9]+$", app_version) is not None, "version must be MAJOR.MINOR.PATCH")
@@ -153,7 +168,94 @@
"mode": expected_mode,
"aboutVersion": report.get("aboutVersion"),
"aboutBuild": report.get("aboutBuild"),
- "statusMenu": status_menu
+ "statusMenu": status_menu,
+ "mainMenu": main_menu,
+ "settingsButtonFrame": settings_frame
+}, indent=2, ensure_ascii=False))
+PY
+}
+
+wait_for_settings_report() {
+ local report="$1"
+
+ /usr/bin/python3 - "$report" "$REPORT_WAIT" <<'PY'
+import json
+import sys
+import time
+
+path = sys.argv[1]
+timeout = float(sys.argv[2])
+deadline = time.monotonic() + timeout
+last_report = None
+
+while time.monotonic() < deadline:
+ try:
+ with open(path, "r", encoding="utf-8") as file:
+ report = json.load(file)
+ last_report = report
+ if report.get("settingsWindow", {}).get("visible") is True:
+ sys.exit(0)
+ except FileNotFoundError:
+ pass
+ except json.JSONDecodeError:
+ pass
+ time.sleep(0.2)
+
+if last_report is not None:
+ print(json.dumps(last_report, indent=2, ensure_ascii=False), file=sys.stderr)
+print(f"settings report did not become visible within {timeout:.1f}s", file=sys.stderr)
+sys.exit(1)
+PY
+}
+
+assert_settings_report() {
+ local report="$1"
+ local app_version="$2"
+ local app_build="$3"
+
+ /usr/bin/python3 - "$report" "$app_version" "$app_build" <<'PY'
+import json
+import sys
+
+path = sys.argv[1]
+app_version = sys.argv[2]
+app_build = sys.argv[3]
+
+with open(path, "r", encoding="utf-8") as file:
+ report = json.load(file)
+
+def require(condition, message):
+ if not condition:
+ print(message, file=sys.stderr)
+ print(json.dumps(report, indent=2, ensure_ascii=False), file=sys.stderr)
+ sys.exit(1)
+
+root = report.get("rootView", {})
+main_menu = report.get("mainMenu", {})
+settings_window = report.get("settingsWindow", {})
+
+require(report.get("snapshotLoaded") is True, "settings case must load the snapshot before clicking the gear")
+require(report.get("quickSwitchVisible") is False, "clicking the Settings gear must close Quick Switch")
+require(root.get("lastMouseCommand") == "click-settings", "debug mouse sequence must click the Settings gear")
+require(root.get("settingsButtonVisible") is True, "Quick Switch root must report the Settings gear")
+require(main_menu.get("hasSettingsItem") is True, "main menu must expose Settings")
+require(main_menu.get("settingsKeyEquivalent") == ",", "Settings must use Cmd+, key equivalent")
+require(settings_window.get("exists") is True, "Settings window controller must be created")
+require(settings_window.get("visible") is True, "Settings window must be visible after clicking gear")
+require(settings_window.get("selectedTabLabel") == "视图", "Settings must open on the View tab")
+require(settings_window.get("selectedTabIdentifier") == "view", "Settings View tab identifier must be stable")
+require(settings_window.get("hasViewTab") is True, "Settings window must expose View tab")
+require(settings_window.get("usesSwiftUI") is False, "Settings window must not use SwiftUI")
+require(settings_window.get("waterfallViewMode") == "verticalColumns", "Settings must read the current Waterfall view mode")
+require(report.get("aboutVersion") == app_version, "About version must match app Info.plist")
+require(report.get("aboutBuild") == app_build, "About build must match app Info.plist")
+
+print(json.dumps({
+ "case": "settings-entry",
+ "quickSwitchVisible": report.get("quickSwitchVisible"),
+ "lastMouseCommand": root.get("lastMouseCommand"),
+ "settingsWindow": settings_window,
+ "mainMenu": main_menu
}, indent=2, ensure_ascii=False))
PY
}
@@ -186,6 +288,31 @@
stop_current_aligner
}
+run_settings_case() {
+ local report="$1"
+ local app_version="$2"
+ local app_build="$3"
+
+ stop_current_aligner
+ rm -f "$report"
+ /usr/bin/defaults write "$DOMAIN" "$WATERFALL_MODE_KEY" -string "verticalColumns"
+
+ "$APP/Contents/MacOS/Aligner" \
+ --round0-skip-permissions \
+ --round01-open-quick-switch \
+ --round01-fixture-app-count=4 \
+ --round01-fixture-windows-per-app=2 \
+ --round01-disable-screenshot-refresh \
+ --round01-debug-mouse-sequence="click-settings" \
+ --round01-quick-switch-report="$report" \
+ --round01-quick-switch-quit-after=1.2 &
+
+ wait_for_settings_report "$report"
+ assert_settings_report "$report" "$app_version" "$app_build"
+ wait "$!" || true
+ stop_current_aligner
+}
+
[ -x "$APP/Contents/MacOS/Aligner" ] || fail "missing executable app at $APP"
INFO_PLIST="$APP/Contents/Info.plist"
APP_VERSION="$(/usr/libexec/PlistBuddy -c 'Print :CFBundleShortVersionString' "$INFO_PLIST" 2>/dev/null)" \
@@ -198,5 +325,6 @@
run_case "verticalColumns" "$REPORT_VERTICAL" "on" "off" "$APP_VERSION" "$APP_BUILD"
run_case "horizontalMasonry" "$REPORT_HORIZONTAL" "off" "on" "$APP_VERSION" "$APP_BUILD"
+run_settings_case "$REPORT_SETTINGS" "$APP_VERSION" "$APP_BUILD"
echo "Round01.1 view-mode entry QA passed"
--
Gitblit v1.9.3