Files
steipete--codexbar/Tests/CodexBarTests/StatusItemControllerSplitLifecycleTests.swift
2026-07-13 12:22:33 +08:00

566 lines
27 KiB
Swift

import AppKit
import CodexBarCore
import Testing
@testable import CodexBar
@MainActor
@Suite(.serialized)
struct StatusItemControllerSplitLifecycleTests {
private func disableMenuCardsForTesting() {
StatusItemController.menuCardRenderingEnabled = false
StatusItemController.setMenuRefreshEnabledForTesting(false)
}
private func makeStatusBarForTesting() -> NSStatusBar {
.system
}
private func makeSettings() -> SettingsStore {
let suite = "StatusItemControllerSplitLifecycleTests-\(UUID().uuidString)"
let defaults = UserDefaults(suiteName: suite)!
defaults.removePersistentDomain(forName: suite)
return SettingsStore(
userDefaults: defaults,
configStore: testConfigStore(suiteName: suite),
zaiTokenStore: NoopZaiTokenStore(),
syntheticTokenStore: NoopSyntheticTokenStore())
}
private func containsHostingView(_ view: NSView) -> Bool {
if String(describing: type(of: view)).contains("NSHostingView") {
return true
}
return view.subviews.contains { self.containsHostingView($0) }
}
private func makeSplitController() throws -> (SettingsStore, StatusItemController) {
self.disableMenuCardsForTesting()
let settings = self.makeSettings()
settings.statusChecksEnabled = false
settings.refreshFrequency = .manual
settings.mergeIcons = false
settings.providerDetectionCompleted = true
let registry = ProviderRegistry.shared
for provider in UsageProvider.allCases {
if let metadata = registry.metadata[provider] {
settings.setProviderEnabled(provider: provider, metadata: metadata, enabled: false)
}
}
try settings.setProviderEnabled(provider: .codex, metadata: #require(registry.metadata[.codex]), enabled: true)
try settings.setProviderEnabled(
provider: .claude,
metadata: #require(registry.metadata[.claude]),
enabled: true)
let fetcher = UsageFetcher()
let store = UsageStore(fetcher: fetcher, browserDetection: BrowserDetection(cacheTTL: 0), settings: settings)
let controller = StatusItemController(
store: store,
settings: settings,
account: fetcher.loadAccountInfo(),
updater: DisabledUpdaterController(),
preferencesSelection: PreferencesSelection(),
statusBar: self.makeStatusBarForTesting())
return (settings, controller)
}
@Test
func `provider config notifications relay background work impact between settings stores`() {
self.disableMenuCardsForTesting()
let sourceSettings = self.makeSettings()
let controllerSettings = self.makeSettings()
controllerSettings.statusChecksEnabled = false
controllerSettings.refreshFrequency = .manual
let fetcher = UsageFetcher()
let store = UsageStore(
fetcher: fetcher,
browserDetection: BrowserDetection(cacheTTL: 0),
settings: controllerSettings)
let controller = StatusItemController(
store: store,
settings: controllerSettings,
account: fetcher.loadAccountInfo(),
updater: DisabledUpdaterController(),
preferencesSelection: PreferencesSelection(),
statusBar: self.makeStatusBarForTesting(),
observeProviderConfigNotifications: true)
defer { controller.releaseStatusItemsForTesting() }
let initialBackgroundRevision = controllerSettings.backgroundWorkSettingsRevision
let reorderedProviders = Array(sourceSettings.orderedProviders().reversed())
sourceSettings.setProviderOrder(reorderedProviders)
#expect(controllerSettings.orderedProviders() == reorderedProviders)
#expect(controllerSettings.backgroundWorkSettingsRevision == initialBackgroundRevision)
sourceSettings.codexUsageDataSource = .cli
#expect(controllerSettings.codexUsageDataSource == .cli)
#expect(controllerSettings.backgroundWorkSettingsRevision == initialBackgroundRevision + 1)
}
@Test
func `merged mode removes split provider status items`() throws {
let (settings, controller) = try self.makeSplitController()
defer { controller.releaseStatusItemsForTesting() }
#expect(controller.statusItems[.codex] != nil)
#expect(controller.statusItems[.claude] != nil)
#expect(controller.expectedVisibleStatusItemAutosaveNames == ["codexbar-codex", "codexbar-claude"])
settings.mergeIcons = true
controller.handleProviderConfigChange(reason: "test")
#expect(controller.statusItem.isVisible == true)
#expect(controller.statusItems.isEmpty)
#expect(controller.expectedVisibleStatusItemAutosaveNames == ["codexbar-merged"])
}
@Test
func `removing split provider status items clears all menu lifecycle state`() throws {
let (settings, controller) = try self.makeSplitController()
defer { controller.releaseStatusItemsForTesting() }
let menus = try [UsageProvider.codex, .claude].map { provider in
try #require(controller.providerMenus[provider])
}
let keys = menus.map(ObjectIdentifier.init)
for (menu, key) in zip(menus, keys) {
controller.menuProviders[key] = .codex
controller.menuReadinessSignatures[key] = "readiness"
controller.menuIdentitySignatures[key] = "identity"
controller.menuSession.markFresh(key)
controller.menuSession.deferUntilNextOpen(key)
controller.menuSession.deferParentRebuild(key)
controller.openMenus[key] = menu
controller.menuRefreshTasks[key] = Task {
try? await Task.sleep(for: .seconds(60))
}
controller.closedMenuRebuildTasks[key] = Task {
try? await Task.sleep(for: .seconds(60))
}
controller.openMenuRebuildTasks[key] = Task {
try? await Task.sleep(for: .seconds(60))
}
_ = controller.closedMenuRebuildRequests.replaceRequest(for: key)
_ = controller.openMenuRebuildRequests.replaceRequest(for: key)
controller.openMenuRebuildsClosingHostedSubviewMenus.insert(key)
controller.highlightedMenuItems[key] = NSMenuItem(title: "Highlighted", action: nil, keyEquivalent: "")
controller.nativeHighlightDeferredMenuRebuilds[key] = .init(provider: .codex)
controller.pendingMenuBaselineResyncs.insert(key)
}
settings.mergeIcons = true
controller.handleProviderConfigChange(reason: "test")
for key in keys {
#expect(controller.menuProviders[key] == nil)
#expect(controller.menuReadinessSignatures[key] == nil)
#expect(controller.menuIdentitySignatures[key] == nil)
#expect(controller.menuSession.renderedVersion(for: key) == nil)
#expect(!controller.menuSession.isDeferredUntilNextOpen(key))
#expect(!controller.menuSession.isParentRebuildDeferred(key))
#expect(controller.openMenus[key] == nil)
#expect(controller.menuRefreshTasks[key] == nil)
#expect(controller.closedMenuRebuildTasks[key] == nil)
#expect(controller.openMenuRebuildTasks[key] == nil)
#expect(controller.closedMenuRebuildRequests.tokens[key] == nil)
#expect(controller.openMenuRebuildRequests.tokens[key] == nil)
#expect(!controller.openMenuRebuildsClosingHostedSubviewMenus.contains(key))
#expect(controller.highlightedMenuItems[key] == nil)
#expect(controller.nativeHighlightDeferredMenuRebuilds[key] == nil)
#expect(!controller.pendingMenuBaselineResyncs.contains(key))
}
}
@Test
func `menu bar icons stay appkit hosted`() throws {
let (settings, controller) = try self.makeSplitController()
defer { controller.releaseStatusItemsForTesting() }
let codexButton = try #require(controller.statusItems[.codex]?.button)
#expect(codexButton.image != nil)
#expect(!self.containsHostingView(codexButton))
settings.mergeIcons = true
controller.handleProviderConfigChange(reason: "test")
let mergedButton = try #require(controller.statusItem.button)
#expect(mergedButton.image != nil)
#expect(!self.containsHostingView(mergedButton))
}
@Test
func `status items publish stable manager identity`() throws {
let (_, controller) = try self.makeSplitController()
defer { controller.releaseStatusItemsForTesting() }
let codexButton = try #require(controller.statusItems[.codex]?.button)
let claudeButton = try #require(controller.statusItems[.claude]?.button)
#expect(controller.statusItem.autosaveName == "codexbar-merged")
#expect(controller.statusItems[.codex]?.autosaveName == "codexbar-codex")
#expect(controller.statusItems[.claude]?.autosaveName == "codexbar-claude")
#expect(controller.statusItem.button?.accessibilityIdentifier() == "CodexBar.StatusItem")
#expect(codexButton.accessibilityIdentifier() == "CodexBar.StatusItem.codex")
#expect(claudeButton.accessibilityIdentifier() == "CodexBar.StatusItem.claude")
#expect(controller.statusItem.button?.accessibilityTitle() == "CodexBar")
#expect(codexButton.accessibilityTitle() == "CodexBar")
#expect(claudeButton.accessibilityTitle() == "CodexBar")
}
@Test
func `status item identity returns stable autosave names`() {
#expect(StatusItemController.StatusItemIdentity.merged.autosaveName == "codexbar-merged")
#expect(StatusItemController.StatusItemIdentity.provider(.codex).autosaveName == "codexbar-codex")
#expect(StatusItemController.StatusItemIdentity.provider(.claude).autosaveName == "codexbar-claude")
}
@Test
func `status item placement preflight leaves fresh install placement unset`() throws {
let suite = "StatusItemControllerSplitLifecycleTests-placement-missing-\(UUID().uuidString)"
let defaults = try #require(UserDefaults(suiteName: suite))
defaults.removePersistentDomain(forName: suite)
defer { defaults.removePersistentDomain(forName: suite) }
let key = MenuBarStatusItemPlacementPreflight.preferredPositionKey(autosaveName: "codexbar-merged")
#expect(!MenuBarStatusItemPlacementPreflight.prepare(defaults: defaults, autosaveName: "codexbar-merged"))
#expect(defaults.object(forKey: key) == nil)
}
@Test
func `status item placement preflight preserves missing new key when legacy item placement exists`() throws {
let suite = "StatusItemControllerSplitLifecycleTests-placement-legacy-\(UUID().uuidString)"
let defaults = try #require(UserDefaults(suiteName: suite))
defaults.removePersistentDomain(forName: suite)
defer { defaults.removePersistentDomain(forName: suite) }
defaults.set(42, forKey: "NSStatusItem Preferred Position Item-0")
let key = MenuBarStatusItemPlacementPreflight.preferredPositionKey(autosaveName: "codexbar-merged")
#expect(!MenuBarStatusItemPlacementPreflight.prepare(
defaults: defaults,
autosaveName: "codexbar-merged",
legacyDefaultItemIndex: 0))
#expect(defaults.object(forKey: key) == nil)
#expect(defaults.double(forKey: "NSStatusItem Preferred Position Item-0") == 42)
}
@Test
func `status item placement preflight clears suspicious matching legacy placement`() throws {
let suite = "StatusItemControllerSplitLifecycleTests-placement-legacy-high-\(UUID().uuidString)"
let defaults = try #require(UserDefaults(suiteName: suite))
defaults.removePersistentDomain(forName: suite)
defer { defaults.removePersistentDomain(forName: suite) }
defaults.set(11298, forKey: "NSStatusItem Preferred Position Item-0")
let key = MenuBarStatusItemPlacementPreflight.preferredPositionKey(autosaveName: "codexbar-merged")
#expect(MenuBarStatusItemPlacementPreflight.prepare(
defaults: defaults,
autosaveName: "codexbar-merged",
legacyDefaultItemIndex: 0,
maximumPreferredPosition: 3000))
#expect(defaults.object(forKey: key) == nil)
#expect(defaults.object(forKey: "NSStatusItem Preferred Position Item-0") == nil)
}
@Test
func `status item placement preflight preserves missing new key when mixed legacy placements exist`() throws {
let suite = "StatusItemControllerSplitLifecycleTests-placement-legacy-mixed-\(UUID().uuidString)"
let defaults = try #require(UserDefaults(suiteName: suite))
defaults.removePersistentDomain(forName: suite)
defer { defaults.removePersistentDomain(forName: suite) }
defaults.set(42, forKey: "NSStatusItem Preferred Position Item-0")
defaults.set(11298, forKey: "NSStatusItem Preferred Position Item-1")
let key = MenuBarStatusItemPlacementPreflight.preferredPositionKey(autosaveName: "codexbar-merged")
#expect(!MenuBarStatusItemPlacementPreflight.prepare(
defaults: defaults,
autosaveName: "codexbar-merged",
legacyDefaultItemIndex: 0))
#expect(defaults.object(forKey: key) == nil)
#expect(defaults.double(forKey: "NSStatusItem Preferred Position Item-0") == 42)
#expect(defaults.double(forKey: "NSStatusItem Preferred Position Item-1") == 11298)
}
@Test
func `status item placement preflight clears provider matching suspicious legacy placement`() throws {
let suite = "StatusItemControllerSplitLifecycleTests-placement-provider-mixed-\(UUID().uuidString)"
let defaults = try #require(UserDefaults(suiteName: suite))
defaults.removePersistentDomain(forName: suite)
defer { defaults.removePersistentDomain(forName: suite) }
defaults.set(42, forKey: "NSStatusItem Preferred Position Item-0")
defaults.set(11298, forKey: "NSStatusItem Preferred Position Item-1")
let key = MenuBarStatusItemPlacementPreflight.preferredPositionKey(autosaveName: "codexbar-codex")
#expect(MenuBarStatusItemPlacementPreflight.prepare(
defaults: defaults,
autosaveName: "codexbar-codex",
legacyDefaultItemIndex: 1,
maximumPreferredPosition: 3000))
#expect(defaults.object(forKey: key) == nil)
#expect(defaults.double(forKey: "NSStatusItem Preferred Position Item-0") == 42)
#expect(defaults.object(forKey: "NSStatusItem Preferred Position Item-1") == nil)
}
@Test
func `status item placement preflight leaves provider key unset when only merged legacy placement exists`() throws {
let suite = "StatusItemControllerSplitLifecycleTests-placement-provider-single-legacy-\(UUID().uuidString)"
let defaults = try #require(UserDefaults(suiteName: suite))
defaults.removePersistentDomain(forName: suite)
defer { defaults.removePersistentDomain(forName: suite) }
defaults.set(42, forKey: "NSStatusItem Preferred Position Item-0")
let key = MenuBarStatusItemPlacementPreflight.preferredPositionKey(autosaveName: "codexbar-codex")
#expect(!MenuBarStatusItemPlacementPreflight.prepare(
defaults: defaults,
autosaveName: "codexbar-codex",
legacyDefaultItemIndex: 1))
#expect(defaults.object(forKey: key) == nil)
#expect(defaults.double(forKey: "NSStatusItem Preferred Position Item-0") == 42)
}
@Test
func `status item placement preflight preserves provider key with matching legacy placement`() throws {
let suite = "StatusItemControllerSplitLifecycleTests-placement-provider-matching-legacy-\(UUID().uuidString)"
let defaults = try #require(UserDefaults(suiteName: suite))
defaults.removePersistentDomain(forName: suite)
defer { defaults.removePersistentDomain(forName: suite) }
defaults.set(42, forKey: "NSStatusItem Preferred Position Item-0")
defaults.set(58, forKey: "NSStatusItem Preferred Position Item-1")
let key = MenuBarStatusItemPlacementPreflight.preferredPositionKey(autosaveName: "codexbar-codex")
#expect(!MenuBarStatusItemPlacementPreflight.prepare(
defaults: defaults,
autosaveName: "codexbar-codex",
legacyDefaultItemIndex: 1))
#expect(defaults.object(forKey: key) == nil)
#expect(defaults.double(forKey: "NSStatusItem Preferred Position Item-0") == 42)
#expect(defaults.double(forKey: "NSStatusItem Preferred Position Item-1") == 58)
}
@Test
func `status item placement preflight clears suspicious high position`() throws {
let suite = "StatusItemControllerSplitLifecycleTests-placement-high-\(UUID().uuidString)"
let defaults = try #require(UserDefaults(suiteName: suite))
defaults.removePersistentDomain(forName: suite)
defer { defaults.removePersistentDomain(forName: suite) }
let key = MenuBarStatusItemPlacementPreflight.preferredPositionKey(autosaveName: "codexbar-merged")
defaults.set(11298, forKey: key)
#expect(MenuBarStatusItemPlacementPreflight.prepare(
defaults: defaults,
autosaveName: "codexbar-merged",
maximumPreferredPosition: 3000))
#expect(defaults.object(forKey: key) == nil)
}
@Test
func `status item placement preflight clears old forced zero position`() throws {
let suite = "StatusItemControllerSplitLifecycleTests-placement-zero-\(UUID().uuidString)"
let defaults = try #require(UserDefaults(suiteName: suite))
defaults.removePersistentDomain(forName: suite)
defer { defaults.removePersistentDomain(forName: suite) }
let key = MenuBarStatusItemPlacementPreflight.preferredPositionKey(autosaveName: "codexbar-merged")
defaults.set(0, forKey: key)
#expect(MenuBarStatusItemPlacementPreflight.prepare(defaults: defaults, autosaveName: "codexbar-merged"))
#expect(defaults.object(forKey: key) == nil)
}
@Test
func `status item placement preflight clears malformed position`() throws {
let suite = "StatusItemControllerSplitLifecycleTests-placement-malformed-\(UUID().uuidString)"
let defaults = try #require(UserDefaults(suiteName: suite))
defaults.removePersistentDomain(forName: suite)
defer { defaults.removePersistentDomain(forName: suite) }
let key = MenuBarStatusItemPlacementPreflight.preferredPositionKey(autosaveName: "codexbar-merged")
defaults.set("not-a-position", forKey: key)
#expect(MenuBarStatusItemPlacementPreflight.prepare(defaults: defaults, autosaveName: "codexbar-merged"))
#expect(defaults.object(forKey: key) == nil)
}
@Test
func `status item placement preflight preserves reasonable position`() throws {
let suite = "StatusItemControllerSplitLifecycleTests-placement-preserve-\(UUID().uuidString)"
let defaults = try #require(UserDefaults(suiteName: suite))
defaults.removePersistentDomain(forName: suite)
defer { defaults.removePersistentDomain(forName: suite) }
let key = MenuBarStatusItemPlacementPreflight.preferredPositionKey(autosaveName: "codexbar-merged")
defaults.set(42, forKey: key)
#expect(!MenuBarStatusItemPlacementPreflight.prepare(defaults: defaults, autosaveName: "codexbar-merged"))
#expect(defaults.double(forKey: key) == 42)
}
@Test
func `status item placement preflight preserves large display position`() throws {
let suite = "StatusItemControllerSplitLifecycleTests-placement-preserve-large-\(UUID().uuidString)"
let defaults = try #require(UserDefaults(suiteName: suite))
defaults.removePersistentDomain(forName: suite)
defer { defaults.removePersistentDomain(forName: suite) }
let key = MenuBarStatusItemPlacementPreflight.preferredPositionKey(autosaveName: "codexbar-merged")
defaults.set(2500, forKey: key)
#expect(!MenuBarStatusItemPlacementPreflight.prepare(
defaults: defaults,
autosaveName: "codexbar-merged",
maximumPreferredPosition: 2560))
#expect(defaults.double(forKey: key) == 2500)
}
@Test
func `status item defaults repair removes stale hidden Control Center keys once`() throws {
let suite = "StatusItemControllerSplitLifecycleTests-repair-\(UUID().uuidString)"
let defaults = try #require(UserDefaults(suiteName: suite))
defaults.removePersistentDomain(forName: suite)
defaults.set(false, forKey: "NSStatusItem VisibleCC Item-0")
defaults.set(0, forKey: "NSStatusItem VisibleCC Item-12")
defaults.set(false, forKey: "NSStatusItem VisibleCC codexbar-merged")
defaults.set(true, forKey: "NSStatusItem VisibleCC Item-1")
defaults.set(false, forKey: "NSStatusItem VisibleCC com.apple.clock")
defer {
defaults.removePersistentDomain(forName: suite)
}
let repairedKeys = MenuBarStatusItemDefaultsRepair.repairHiddenVisibilityDefaultsIfNeeded(defaults: defaults)
#expect(repairedKeys == [
"NSStatusItem VisibleCC Item-0",
"NSStatusItem VisibleCC Item-12",
"NSStatusItem VisibleCC codexbar-merged",
])
#expect(defaults.object(forKey: "NSStatusItem VisibleCC Item-0") == nil)
#expect(defaults.object(forKey: "NSStatusItem VisibleCC Item-12") == nil)
#expect(defaults.object(forKey: "NSStatusItem VisibleCC codexbar-merged") == nil)
#expect(defaults.bool(forKey: "NSStatusItem VisibleCC Item-1"))
#expect(defaults.object(forKey: "NSStatusItem VisibleCC com.apple.clock") != nil)
defaults.set(false, forKey: "NSStatusItem VisibleCC Item-2")
#expect(MenuBarStatusItemDefaultsRepair.repairHiddenVisibilityDefaultsIfNeeded(defaults: defaults).isEmpty)
#expect(defaults.object(forKey: "NSStatusItem VisibleCC Item-2") != nil)
}
@Test
func `status item visibility default distinguishes enabled disabled and unset`() throws {
let suite = "StatusItemControllerSplitLifecycleTests-visibility-default-\(UUID().uuidString)"
let defaults = try #require(UserDefaults(suiteName: suite))
defaults.removePersistentDomain(forName: suite)
defaults.set(true, forKey: "NSStatusItem VisibleCC codexbar-merged")
defaults.set(false, forKey: "NSStatusItem VisibleCC codexbar-claude")
defer { defaults.removePersistentDomain(forName: suite) }
#expect(MenuBarStatusItemDefaultsRepair.visibilityDefault(
defaults: defaults,
autosaveName: "codexbar-merged") == true)
#expect(MenuBarStatusItemDefaultsRepair.visibilityDefault(
defaults: defaults,
autosaveName: "codexbar-claude") == false)
#expect(MenuBarStatusItemDefaultsRepair.visibilityDefault(
defaults: defaults,
autosaveName: "codexbar-codex") == nil)
}
@Test
func `non destructive visibility refresh preserves split provider status items`() throws {
let (_, controller) = try self.makeSplitController()
defer { controller.releaseStatusItemsForTesting() }
let oldCodexItem = try #require(controller.statusItems[.codex])
let oldClaudeItem = try #require(controller.statusItems[.claude])
let oldCodexButton = try #require(oldCodexItem.button)
controller.refreshExistingStatusItemsForVisibilityRecovery()
let newCodexItem = try #require(controller.statusItems[.codex])
let newClaudeItem = try #require(controller.statusItems[.claude])
#expect(newCodexItem === oldCodexItem)
#expect(newClaudeItem === oldClaudeItem)
#expect(newCodexItem.button === oldCodexButton)
#expect(newCodexItem.autosaveName == "codexbar-codex")
#expect(newCodexItem.button?.accessibilityIdentifier() == "CodexBar.StatusItem.codex")
}
@Test
func `non destructive visibility refresh preserves merged status item`() throws {
let (settings, controller) = try self.makeSplitController()
defer { controller.releaseStatusItemsForTesting() }
settings.mergeIcons = true
controller.handleProviderConfigChange(reason: "test")
let oldMergedItem = controller.statusItem
let oldMergedButton = try #require(controller.statusItem.button)
controller.refreshExistingStatusItemsForVisibilityRecovery()
#expect(controller.statusItem === oldMergedItem)
#expect(controller.statusItem.button === oldMergedButton)
#expect(controller.statusItem.autosaveName == "codexbar-merged")
#expect(controller.statusItem.button?.accessibilityIdentifier() == "CodexBar.StatusItem")
}
@Test
func `recreation produces immediately healthy snapshots for synchronous guidance check`() throws {
// verifyScreenChangeRecoveryIfNeeded does a synchronous re-check immediately after
// the single recreation to decide whether to show macOS 26 Allow-in-Menu-Bar guidance.
// AppKit must materialise the button and window before returning from
// recreateStatusItemsForVisibilityRecovery, so the item must not appear blocked at
// that point. Only a genuine system-level block would leave it blocked — which is
// exactly the case where guidance is useful.
let (_, controller) = try self.makeSplitController()
defer { controller.releaseStatusItemsForTesting() }
controller.recreateStatusItemsForVisibilityRecovery()
let allItems = [controller.statusItem] + Array(controller.statusItems.values)
let snapshots = MenuBarVisibilityWatcher.visibilitySnapshots(allItems)
#expect(!MenuBarVisibilityWatcher.hasAnyBlockedVisibleSnapshot(snapshots))
}
@Test
func `visibility recovery recreates split provider status items`() throws {
let (_, controller) = try self.makeSplitController()
defer { controller.releaseStatusItemsForTesting() }
let oldCodexItem = try #require(controller.statusItems[.codex])
controller.recreateStatusItemsForVisibilityRecovery()
let newCodexItem = try #require(controller.statusItems[.codex])
#expect(newCodexItem !== oldCodexItem)
#expect(newCodexItem.autosaveName == "codexbar-codex")
#expect(newCodexItem.button?.accessibilityIdentifier() == "CodexBar.StatusItem.codex")
}
@Test
func `visibility recovery renders replacement merged status item`() throws {
let (settings, controller) = try self.makeSplitController()
defer { controller.releaseStatusItemsForTesting() }
settings.mergeIcons = true
controller.handleProviderConfigChange(reason: "test")
let renderedSignature = try #require(controller.lastAppliedMergedIconRenderSignature)
controller.lastAppliedMergedIconRenderSignature = renderedSignature
controller.recreateStatusItemsForVisibilityRecovery()
let mergedButton = try #require(controller.statusItem.button)
#expect(mergedButton.image != nil)
#expect(controller.statusItem.autosaveName == "codexbar-merged")
#expect(mergedButton.accessibilityIdentifier() == "CodexBar.StatusItem")
}
}