Ariver
2026-06-28 9ba7cd3b47fb91eaaa8d0c3df8b7286a89be1756
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
#!/bin/bash
# Round01.1 view-mode entry QA. It verifies that the installed-app path exposes
# menu entries plus the in-panel Quick Switch view-mode toggle for switching
# Waterfall view modes, and reports visible About version/build metadata.
 
set -euo pipefail
 
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
OUTPUT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
# shellcheck source=build-output-paths.sh
source "$SCRIPT_DIR/build-output-paths.sh"
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_VERTICAL_HOVER="$BUILD_REPORT_ROOT/round01-view-mode-entry-vertical-hover-report.json"
REPORT_HORIZONTAL_HOVER="$BUILD_REPORT_ROOT/round01-view-mode-entry-horizontal-hover-report.json"
REPORT_TOGGLE_TO_HORIZONTAL="$BUILD_REPORT_ROOT/round01-view-mode-entry-toggle-to-horizontal-report.json"
REPORT_TOGGLE_TO_VERTICAL="$BUILD_REPORT_ROOT/round01-view-mode-entry-toggle-to-vertical-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}"
OLD_WATERFALL_MODE_SET=0
OLD_WATERFALL_MODE=""
 
fail() {
  echo "Round01.1 view-mode entry QA failed: $*" >&2
  exit 1
}
 
aligner_pids_for_current_app() {
  ps -axo pid=,args= | while read -r pid command; do
    case "$command" in
      "$APP/Contents/MacOS/Aligner"*) echo "$pid" ;;
    esac
  done
}
 
stop_current_aligner() {
  for pid in $(aligner_pids_for_current_app); do
    kill "$pid" 2>/dev/null || true
  done
 
  for _ in {1..30}; do
    [ -z "$(aligner_pids_for_current_app)" ] && return
    sleep 0.1
  done
 
  fail "current Aligner app did not exit before QA"
}
 
preserve_user_preference() {
  if OLD_WATERFALL_MODE="$(/usr/bin/defaults read "$DOMAIN" "$WATERFALL_MODE_KEY" 2>/dev/null)"; then
    OLD_WATERFALL_MODE_SET=1
  else
    OLD_WATERFALL_MODE_SET=0
    OLD_WATERFALL_MODE=""
  fi
}
 
restore_user_preference() {
  if [ "$OLD_WATERFALL_MODE_SET" -eq 1 ]; then
    /usr/bin/defaults write "$DOMAIN" "$WATERFALL_MODE_KEY" -string "$OLD_WATERFALL_MODE"
  else
    /usr/bin/defaults delete "$DOMAIN" "$WATERFALL_MODE_KEY" >/dev/null 2>&1 || true
  fi
}
 
wait_for_loaded_report() {
  local report="$1"
  local expected_mode="$2"
 
  /usr/bin/python3 - "$report" "$expected_mode" "$REPORT_WAIT" <<'PY'
import json
import sys
import time
 
path = sys.argv[1]
expected_mode = sys.argv[2]
timeout = float(sys.argv[3])
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
        root = report.get("rootView", {})
        if (
            report.get("snapshotLoaded") is True
            and report.get("resolvedWaterfallViewMode") == expected_mode
            and root.get("waterfallViewMode") == expected_mode
        ):
            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"view-mode entry report did not reach {expected_mode} within {timeout:.1f}s", file=sys.stderr)
sys.exit(1)
PY
}
 
assert_report() {
  local report="$1"
  local expected_mode="$2"
  local expected_vertical_state="$3"
  local expected_horizontal_state="$4"
  local app_version="$5"
  local app_build="$6"
 
  /usr/bin/python3 - "$report" "$expected_mode" "$expected_vertical_state" "$expected_horizontal_state" "$app_version" "$app_build" <<'PY'
import json
import re
import sys
 
path = sys.argv[1]
expected_mode = sys.argv[2]
expected_vertical_state = sys.argv[3]
expected_horizontal_state = sys.argv[4]
app_version = sys.argv[5]
app_build = sys.argv[6]
 
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)
 
status_menu = report.get("statusMenu", {})
main_menu = report.get("mainMenu", {})
settings_window = report.get("settingsWindow", {})
root = report.get("rootView", {})
expected_target_mode = "verticalColumns" if expected_mode == "horizontalMasonry" else "horizontalMasonry"
expected_icon_kind = "H2" if expected_mode == "horizontalMasonry" else "Z2"
expected_accessibility_label = "切换到纵栏瀑布" if expected_target_mode == "verticalColumns" else "切换到横栏瀑布"
standard_blue = {"red": 135 / 255, "green": 200 / 255, "blue": 1.0, "alpha": 1.0}
 
require(report.get("snapshotLoaded") is True, "snapshotLoaded must be true")
require(report.get("quickSwitchVisible") is True, "Quick Switch must be visible during entry QA")
require(report.get("preferenceWaterfallViewMode") == expected_mode, "preference Waterfall mode must match expected mode")
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 False, "Quick Switch must not expose the old top-right Settings button")
require(root.get("viewModeToggleButtonVisible") is True, "Quick Switch must expose a top-right view-mode toggle button")
toggle_frame = root.get("viewModeToggleButtonFrame", {})
require(toggle_frame.get("width", 0) == 30 and toggle_frame.get("height", 0) == 30, "view-mode toggle visual button must be 30pt")
require(root.get("viewModeToggleHitSize") == 34, "view-mode toggle must keep a 34pt hit target")
require(toggle_frame.get("x", 0) + toggle_frame.get("width", 0) > root.get("bounds", {}).get("width", 0) * 0.90, "view-mode toggle button must sit near the top-right edge")
require(root.get("viewModeToggleCurrentMode") == expected_mode, "view-mode toggle must report the current mode")
require(root.get("viewModeToggleTargetMode") == expected_target_mode, "view-mode toggle must report the next target mode")
require(root.get("viewModeToggleIconKind") == expected_icon_kind, "view-mode toggle icon kind must represent the selected current mode")
require(root.get("viewModeToggleVisualState") == expected_icon_kind, "view-mode toggle visual state must match the selected current mode")
require(root.get("viewModeToggleAccessibilityLabel") == expected_accessibility_label, "view-mode toggle label must name the target mode")
blue = root.get("viewModeToggleStandardBlueColor", {})
for channel, expected in standard_blue.items():
    require(abs(blue.get(channel, -1) - expected) <= 0.002, f"view-mode toggle standard blue must be #87C8FF for {channel}")
require(abs(root.get("viewModeToggleGlyphLineWidth", 0) - 1.65) <= 0.001, "view-mode toggle glyphs must share the standard line width")
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")
require(re.match(r"^[0-9]{8}\.[0-9]{4}$", app_build) is not None, "build must be YYYYMMDD.HHMM")
 
print(json.dumps({
    "mode": expected_mode,
    "aboutVersion": report.get("aboutVersion"),
    "aboutBuild": report.get("aboutBuild"),
    "statusMenu": status_menu,
    "mainMenu": main_menu,
    "viewModeToggleButtonFrame": toggle_frame,
    "viewModeToggleTargetMode": root.get("viewModeToggleTargetMode"),
    "viewModeToggleIconKind": root.get("viewModeToggleIconKind"),
    "viewModeToggleVisualState": root.get("viewModeToggleVisualState")
}, indent=2, ensure_ascii=False))
PY
}
 
wait_for_hover_report() {
  local report="$1"
  local expected_mode="$2"
 
  /usr/bin/python3 - "$report" "$expected_mode" "$REPORT_WAIT" <<'PY'
import json
import sys
import time
 
path = sys.argv[1]
expected_mode = sys.argv[2]
timeout = float(sys.argv[3])
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
        root = report.get("rootView", {})
        if (
            report.get("snapshotLoaded") is True
            and report.get("quickSwitchVisible") is True
            and report.get("resolvedWaterfallViewMode") == expected_mode
            and root.get("waterfallViewMode") == expected_mode
            and root.get("lastMouseCommand") == "hover-view-toggle"
        ):
            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"view-mode hover report did not reach {expected_mode} within {timeout:.1f}s", file=sys.stderr)
sys.exit(1)
PY
}
 
assert_hover_report() {
  local report="$1"
  local expected_mode="$2"
  local expected_visual_state="$3"
 
  /usr/bin/python3 - "$report" "$expected_mode" "$expected_visual_state" <<'PY'
import json
import sys
 
path = sys.argv[1]
expected_mode = sys.argv[2]
expected_visual_state = 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", {})
require(root.get("waterfallViewMode") == expected_mode, "hover case must keep current view mode")
require(root.get("lastMouseCommand") == "hover-view-toggle", "hover case must use the view toggle hover command")
require(root.get("viewModeToggleButtonHovered") is True, "hover case must mark the toggle hovered")
require(root.get("viewModeToggleHoverPreviewSuppressed") is False, "hover preview must not be suppressed in hover case")
require(root.get("viewModeToggleVisualState") == expected_visual_state, "hover case must expose the target unselected visual state")
require(root.get("viewModeToggleIconKind") == expected_visual_state, "hover icon kind must match visual state")
 
print(json.dumps({
    "case": "view-mode-hover",
    "mode": expected_mode,
    "viewModeToggleVisualState": root.get("viewModeToggleVisualState"),
    "viewModeToggleIconKind": root.get("viewModeToggleIconKind")
}, indent=2, ensure_ascii=False))
PY
}
 
wait_for_toggle_report() {
  local report="$1"
  local expected_mode="$2"
 
  /usr/bin/python3 - "$report" "$expected_mode" "$REPORT_WAIT" <<'PY'
import json
import sys
import time
 
path = sys.argv[1]
expected_mode = sys.argv[2]
timeout = float(sys.argv[3])
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
        root = report.get("rootView", {})
        if (
            report.get("snapshotLoaded") is True
            and report.get("quickSwitchVisible") is True
            and report.get("resolvedWaterfallViewMode") == expected_mode
            and root.get("waterfallViewMode") == expected_mode
            and root.get("lastMouseCommand") == "click-view-toggle"
        ):
            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"view-mode toggle report did not reach {expected_mode} within {timeout:.1f}s", file=sys.stderr)
sys.exit(1)
PY
}
 
assert_toggle_report() {
  local report="$1"
  local initial_mode="$2"
  local expected_mode="$3"
  local expected_vertical_state="$4"
  local expected_horizontal_state="$5"
  local app_version="$6"
  local app_build="$7"
 
  /usr/bin/python3 - "$report" "$initial_mode" "$expected_mode" "$expected_vertical_state" "$expected_horizontal_state" "$app_version" "$app_build" <<'PY'
import json
import sys
 
path = sys.argv[1]
initial_mode = sys.argv[2]
expected_mode = sys.argv[3]
expected_vertical_state = sys.argv[4]
expected_horizontal_state = sys.argv[5]
app_version = sys.argv[6]
app_build = sys.argv[7]
 
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", {})
status_menu = report.get("statusMenu", {})
main_menu = report.get("mainMenu", {})
settings_window = report.get("settingsWindow", {})
expected_icon_kind = "H2" if expected_mode == "horizontalMasonry" else "Z2"
expected_label = "切换到纵栏瀑布" if initial_mode == "verticalColumns" else "切换到横栏瀑布"
 
require(report.get("snapshotLoaded") is True, "toggle case must load the snapshot before clicking the view-mode toggle")
require(report.get("quickSwitchVisible") is True, "clicking the view-mode toggle must keep Quick Switch visible")
require(report.get("preferenceWaterfallViewMode") == expected_mode, "preference Waterfall mode must switch after toggle")
require(report.get("resolvedWaterfallViewMode") == expected_mode, "resolved Waterfall mode must switch after toggle")
require(root.get("waterfallViewMode") == expected_mode, "root view Waterfall mode must switch after toggle")
require(root.get("lastMouseCommand") == "click-view-toggle", "debug mouse sequence must click the view-mode toggle")
require(root.get("settingsButtonVisible") is False, "old Settings button must stay hidden")
require(root.get("viewModeToggleButtonVisible") is True, "Quick Switch root must report the view-mode toggle")
require(root.get("viewModeToggleCurrentMode") == expected_mode, "toggle current mode must update after click")
require(root.get("viewModeToggleTargetMode") == initial_mode, "toggle target mode must flip back to the initial mode after click")
require(root.get("viewModeToggleIconKind") == expected_icon_kind, "toggle icon must represent the selected mode after click")
require(root.get("viewModeToggleVisualState") == expected_icon_kind, "toggle visual state must represent the selected mode after click")
require(root.get("viewModeToggleHoverPreviewSuppressed") is True, "click should suppress hover preview until pointer exits")
require(root.get("viewModeToggleAccessibilityLabel") == expected_label, "toggle label must represent the next target mode after click")
require(status_menu.get("verticalColumnsState") == expected_vertical_state, "Vertical Columns menu state must update after toggle")
require(status_menu.get("horizontalWaterfallState") == expected_horizontal_state, "Horizontal Waterfall menu state must update after toggle")
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("visible") is False, "view-mode toggle must not open Settings")
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": "view-mode-toggle",
    "initialMode": initial_mode,
    "expectedMode": expected_mode,
    "quickSwitchVisible": report.get("quickSwitchVisible"),
    "lastMouseCommand": root.get("lastMouseCommand"),
    "viewModeToggleIconKind": root.get("viewModeToggleIconKind"),
    "viewModeToggleVisualState": root.get("viewModeToggleVisualState"),
    "statusMenu": status_menu,
    "mainMenu": main_menu
}, indent=2, ensure_ascii=False))
PY
}
 
run_case() {
  local mode="$1"
  local report="$2"
  local vertical_state="$3"
  local horizontal_state="$4"
  local app_version="$5"
  local app_build="$6"
 
  stop_current_aligner
  rm -f "$report"
  /usr/bin/defaults write "$DOMAIN" "$WATERFALL_MODE_KEY" -string "$mode"
 
  "$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-quick-switch-report="$report" \
    --round01-quick-switch-auto-hide-after=1.0 \
    --round01-quick-switch-quit-after=1.2 &
 
  wait_for_loaded_report "$report" "$mode"
  assert_report "$report" "$mode" "$vertical_state" "$horizontal_state" "$app_version" "$app_build"
  wait "$!" || true
  stop_current_aligner
}
 
run_hover_case() {
  local mode="$1"
  local expected_visual_state="$2"
  local report="$3"
 
  stop_current_aligner
  rm -f "$report"
  /usr/bin/defaults write "$DOMAIN" "$WATERFALL_MODE_KEY" -string "$mode"
 
  "$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="hover-view-toggle" \
    --round01-quick-switch-report="$report" \
    --round01-quick-switch-quit-after=1.2 &
 
  wait_for_hover_report "$report" "$mode"
  assert_hover_report "$report" "$mode" "$expected_visual_state"
  wait "$!" || true
  stop_current_aligner
}
 
run_toggle_case() {
  local initial_mode="$1"
  local expected_mode="$2"
  local report="$3"
  local vertical_state="$4"
  local horizontal_state="$5"
  local app_version="$6"
  local app_build="$7"
 
  stop_current_aligner
  rm -f "$report"
  /usr/bin/defaults write "$DOMAIN" "$WATERFALL_MODE_KEY" -string "$initial_mode"
 
  "$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-view-toggle" \
    --round01-quick-switch-report="$report" \
    --round01-quick-switch-quit-after=1.2 &
 
  wait_for_toggle_report "$report" "$expected_mode"
  assert_toggle_report "$report" "$initial_mode" "$expected_mode" "$vertical_state" "$horizontal_state" "$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)" \
  || fail "unable to read CFBundleShortVersionString from $INFO_PLIST"
APP_BUILD="$(/usr/libexec/PlistBuddy -c 'Print :CFBundleVersion' "$INFO_PLIST" 2>/dev/null)" \
  || fail "unable to read CFBundleVersion from $INFO_PLIST"
 
preserve_user_preference
trap 'stop_current_aligner; restore_user_preference' EXIT
 
run_case "verticalColumns" "$REPORT_VERTICAL" "on" "off" "$APP_VERSION" "$APP_BUILD"
run_case "horizontalMasonry" "$REPORT_HORIZONTAL" "off" "on" "$APP_VERSION" "$APP_BUILD"
run_hover_case "verticalColumns" "H1" "$REPORT_VERTICAL_HOVER"
run_hover_case "horizontalMasonry" "Z1" "$REPORT_HORIZONTAL_HOVER"
run_toggle_case "verticalColumns" "horizontalMasonry" "$REPORT_TOGGLE_TO_HORIZONTAL" "off" "on" "$APP_VERSION" "$APP_BUILD"
run_toggle_case "horizontalMasonry" "verticalColumns" "$REPORT_TOGGLE_TO_VERTICAL" "on" "off" "$APP_VERSION" "$APP_BUILD"
 
echo "Round01.1 view-mode entry QA passed"