Scope the ⌘R doctor re-check to the Doctor screen

⌘R refetched every cached surface plus the doctor report, so browsing
Installed or Discover and hitting refresh kicked off a full `brew doctor`
diagnostic run in the background. Unlike the other surfaces that is not a
cache refetch, and nothing on screen was waiting for it.

Installed, upgrades, catalogue and config still refresh from any screen;
the doctor report now only re-runs when Doctor is the selected sidebar
item. The decision lives on SidebarItem as an explicit switch, mirroring
axDestination, so a future sidebar case cannot silently opt in.

Adds the first tests to the BrewTests target (file-system-synchronized
group, so no project file change): Doctor re-runs, every other item does
not, and exactly one item does. They compile and run under the Brew-Unit
scheme on CI; the sandbox cannot launch the app-hosted bundle.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YXUw1iTa4GM7qAmFX247Zn
This commit is contained in:
Graeme Arthur
2026-09-09 23:20:47 +10:00
co-authored by Claude Opus 5
parent 504812a023
commit 7357a22041
3 changed files with 39 additions and 3 deletions
+23
View File
@@ -0,0 +1,23 @@
//
// SidebarItemRefreshTests.swift
// BrewTests
//
@testable import Homebrew
import Testing
@MainActor
struct SidebarItemRefreshTests {
@Test func `⌘R re-runs brew doctor from the Doctor screen`() {
#expect(SidebarItem.doctor.refreshesDoctorReport)
}
@Test(arguments: SidebarItem.allCases.filter { $0 != .doctor })
func `⌘R leaves the doctor report alone from every other screen`(item: SidebarItem) {
#expect(!item.refreshesDoctorReport)
}
@Test func `exactly one sidebar screen re-runs brew doctor`() {
#expect(SidebarItem.allCases.filter(\.refreshesDoctorReport) == [.doctor])
}
}
@@ -88,11 +88,12 @@ struct MainWindowView: View {
)
}
/// ⌘R refetches every cached surface at once, whichever tab is showing, since the sidebar counts and
/// the other tabs go stale just as readily as the visible one.
/// ⌘R refetches every cached surface except the Doctor report, whichever tab is showing, since the
/// sidebar counts and the other tabs go stale just as readily as the visible one. Re-running
/// `brew doctor` is a full diagnostic run rather than a refetch, so it only happens from Doctor.
private func refreshAll() {
Task {
async let doctor: Void = doctorRepository.load(forceRefresh: true)
async let doctor: Void = refreshDoctorReportIfSelected()
await installedPackagesRepository.load(forceRefresh: true)
await discoverPackagesRepository.load(forceRefresh: true)
await configRepository.load(forceRefresh: true)
@@ -100,6 +101,11 @@ struct MainWindowView: View {
}
}
private func refreshDoctorReportIfSelected() async {
guard selectedSidebarItem.refreshesDoctorReport else { return }
await doctorRepository.load(forceRefresh: true)
}
/// Approximate catalogue size for the Discover subtitle. Hardcoded for now; should eventually be
/// sourced from the catalogue once a package-count property is exposed.
private static let approximateCatalogueSize = "9,000+"
+7
View File
@@ -30,6 +30,13 @@ enum SidebarItem: String, CaseIterable, Hashable, Identifiable {
}
}
var refreshesDoctorReport: Bool {
switch self {
case .doctor: true
case .installed, .upgrades, .discover, .configuration: false
}
}
/// Test-facing identity for this destination. Kept as an explicit mapping rather than a
/// `rawValue` bridge so renaming a case here can never silently repoint a UI test.
var axDestination: AXID.SidebarDestination {