Give the single-branch switch picker its disabled explanatory row
With branch creation relocated to the settings sheet, a single-branch board's switch menu opened onto nothing and read as broken (ruled 2026-08-06, built with the Git tab): a bare Text — AppKit's standard disabled item, read by VoiceOver as disabled text — now says "No other branches" where the switch entries would be. The filter behind it becomes the pure switchTargets(branches:current:) seam, pinned by BranchSwitchTargetTests: current excluded, nil current passes all through, repository order preserved. Claude-Session: https://claude.ai/code/session_01SR4XGjmBE16ZUYWpfFHXwY
This commit is contained in:
@@ -661,7 +661,7 @@ struct BranchSwitchSequenceTests {
|
||||
var asked = 0
|
||||
switcher.settleSessions = { asked += 1; return .proceed }
|
||||
|
||||
// The picker never offers it (`BoardGitControls.otherBranches`), and the operation is a no-op
|
||||
// The picker never offers it (`BoardGitControls.switchTargets`), and the operation is a no-op
|
||||
// if one ever arrives: same branch, same tree, nothing to announce.
|
||||
#expect(await switcher.switchTo("main"))
|
||||
#expect(GitRepository.branchName(at: fixture.root) == "main")
|
||||
@@ -1038,6 +1038,55 @@ struct BoardGitBranchSurfaceTests {
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - The switch picker's targets
|
||||
|
||||
/// **What the branch menu offers, and what it says when that is nothing** (03-board-ui.md ▸ Board
|
||||
/// popover ▸ Git tab).
|
||||
///
|
||||
/// `BoardGitControls.switchTargets` is the filter as a pure function, pinned here for the reason
|
||||
/// `BoardGitBranchSurface.resolve` is pinned above: the rule is the part worth asserting, and the
|
||||
/// `Menu` it fills is SwiftUI. Its emptiness is load-bearing since 2026-08-06 — with branch
|
||||
/// *creation* relocated to the settings sheet, an empty result is what puts the disabled "No other
|
||||
/// branches" row on screen in place of a menu that would otherwise open onto nothing and read as
|
||||
/// broken.
|
||||
@Suite("Board popover ▸ the switch picker's targets")
|
||||
struct BranchSwitchTargetTests {
|
||||
|
||||
@Test("The branch already checked out is never offered — switching to it would be a no-op")
|
||||
func theCurrentBranchIsExcluded() {
|
||||
#expect(
|
||||
BoardGitControls.switchTargets(branches: ["main", "redesign", "spike"], current: "main")
|
||||
== ["redesign", "spike"]
|
||||
)
|
||||
}
|
||||
|
||||
@Test("A single-branch board has no targets at all — which is what the disabled row is for")
|
||||
func aSingleBranchBoardHasNoTargets() {
|
||||
#expect(BoardGitControls.switchTargets(branches: ["main"], current: "main").isEmpty)
|
||||
// The shape a repository with an unborn HEAD is in: no branches listed at all.
|
||||
#expect(BoardGitControls.switchTargets(branches: [], current: "main").isEmpty)
|
||||
}
|
||||
|
||||
@Test("Before the first branch read every branch is a candidate, rather than none")
|
||||
func anUnreadCurrentPassesEverythingThrough() {
|
||||
// `HistoryStore.branch` is `nil` until `refreshBranch()` answers, which is a moment the
|
||||
// popover is on screen for. Filtering everything out there would be a menu that starts empty
|
||||
// and fills in — the switch's own gate is what decides whether a target can be taken.
|
||||
#expect(
|
||||
BoardGitControls.switchTargets(branches: ["main", "redesign"], current: nil)
|
||||
== ["main", "redesign"]
|
||||
)
|
||||
}
|
||||
|
||||
@Test("The repository's own order survives — the picker never re-sorts what libgit2 listed")
|
||||
func orderIsPreserved() {
|
||||
#expect(
|
||||
BoardGitControls.switchTargets(branches: ["zeta", "alpha", "main", "beta"], current: "main")
|
||||
== ["zeta", "alpha", "beta"]
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Commit identity
|
||||
|
||||
@Suite("Board popover ▸ the commit-identity fields")
|
||||
|
||||
Reference in New Issue
Block a user