بنقرة واحدة
verify
Build, launch, and visually verify Perch's shelf UI from the CLI
التثبيت باستخدام Codex أو Claude انسخ هذا Prompt والصقه في Codex أو Claude أو مساعد آخر ليراجع صفحة Skill ويثبّتها لك.
القائمة
Build, launch, and visually verify Perch's shelf UI from the CLI
التثبيت باستخدام Codex أو Claude انسخ هذا Prompt والصقه في Codex أو Claude أو مساعد آخر ليراجع صفحة Skill ويثبّتها لك.
استنادا إلى تصنيف SOC المهني
| name | verify |
| description | Build, launch, and visually verify Perch's shelf UI from the CLI |
swift build
PERCH_UITEST_ROOT=<scratch-dir>/perch-store PERCH_UITEST_HOVER=1 .build/debug/Perch > perch.log 2>&1 &
⚠️ A $HOME override does NOT isolate anything.
FileManager.url(for: .applicationSupportDirectory) and CFPreferences both
resolve the real home (getpwuid), ignoring $HOME — a test instance launched
that way seeds items straight into the user's REAL store
(~/Library/Application Support/Perch/). This happened once; four test items
had to be dug back out of the real index.json.
Isolate the store with a temporary env-guarded override at the top of
HoldingDirectory.standard() (remove before finishing):
if let testRoot = ProcessInfo.processInfo.environment["PERCH_UITEST_ROOT"] {
let holding = HoldingDirectory(root: URL(fileURLWithPath: testRoot, isDirectory: true))
try FileManager.default.createDirectory(at: holding.itemsDir, withIntermediateDirectories: true)
return holding
}
Confirm isolation before driving anything: the log must say "loaded 0 stored item(s)" and the seed must appear under the scratch store.
UserDefaults are ALWAYS the user's real ones — the test card renders with their actual theme (icons-only compact card is ~80pt wide), and anything the hook sets persists for the real app. Only set values that match theirs or are guarded by a changed-value check.
The user's production Perch is usually running from /Applications — never
kill it. Have the hook set arrivals.suppressed = true: the watched
Downloads/Desktop are the real ones, and a file landing mid-test would
otherwise add ghost rows that shift the measured geometry.
The debug build may pop a Sparkle "Unable to Check For Updates" window (~260×282); it's harmless — ignore it, don't confuse it for a shelf.
There is no permanent test hook. Add a temporary env-guarded block at the end of
ShelfController.start() and remove it before finishing:
if ProcessInfo.processInfo.environment["PERCH_UITEST_HOVER"] != nil {
themeStore.showsGrabHandle = true
let seed = FileManager.default.temporaryDirectory
.appendingPathComponent("perch-hover-test.txt")
try? "hover test".write(to: seed, atomically: true, encoding: .utf8)
adoptArrival(ArrivalOffer(url: seed, addedAt: Date()))
revealAtPreferredEdge()
}
A shelf with items stays revealed (retract only fires when empty), so the card is stable for capture. With default (fresh-HOME) settings a one-item card is ~80×62 — nearly the same footprint as the empty tile; don't mistake it for a failed seed. Check the log for "Perch adopted arrival".
python3 has no Quartz module here; use a Swift snippet calling
CGWindowListCopyWindowInfo to get Perch window IDs and bounds (edge tabs
are also Perch windows — pick by size/position).screencapture -o -x -l<windowID>. Never
-R region or full-screen — that once caught the user's personal screen.Popup menus resist scripting. Instead, have the temporary hook register a
DistributedNotificationCenter observer that calls the controller method
(e.g. toggleFreeShelfLock()), then post from the CLI:
swift -e 'import Foundation; DistributedNotificationCenter.default().postNotificationName(Notification.Name("PerchUITestToggleLock"), object: nil, userInfo: nil, deliverImmediately: true)'
Gotcha: a killed instance flushes its store on teardown — rm -rf the test
HOME only after the old process is fully gone, or the store resurrects and the
next run starts with extra items.
Tracking areas follow the real cursor; post CGEvents (.mouseMoved,
.leftMouseDown/Dragged/Up at .cghidEventTap) in small steps with ~40-50ms
sleeps — one teleport can miss enter/exit events. Save the cursor position
first and restore it after. Hover the card's center, not the screen edge, so
the production Perch's edge strips don't trigger.