fix: hide all window in TFM default tests

This commit is contained in:
Kaede Akino committed 2026-09-24 11:49:35 +08:00
1 parent 14ec76db99
commit d9968bcc3d
9 files changed
+82 -25

No files matched your search

+39 -4
View File
@@ -13,6 +13,25 @@ import TermindRemoteInfrastructure
@main
struct TermindApp: App {
static let isRunningTests: Bool = {
#if DEBUG
ProcessInfo.processInfo.environment["XCTestConfigurationFilePath"] != nil
#else
false
#endif
}()
static var suppressesAutomaticTestWindows: Bool {
#if DEBUG
guard isRunningTests, ProcessInfo.processInfo.environment["TERMIND_WINDOW_TESTS"] != "1" else {
return false
}
return ScreenshotDemoConfiguration.active == nil
#else
return false
#endif
}
/// Hosts metadata is stored in SwiftData; secrets stay behind Keychain
/// references held by the value-type projections used throughout the UI.
private let modelContainer: ModelContainer
@@ -29,8 +48,7 @@ struct TermindApp: App {
launchLanguage = AppLanguage.stored()
#endif
do {
let isRunningTests =
ProcessInfo.processInfo.environment["XCTestConfigurationFilePath"] != nil
let isRunningTests = Self.isRunningTests
#if DEBUG
let usesInMemoryStore = isRunningTests || screenshotDemo != nil
#else
@@ -188,7 +206,11 @@ struct TermindApp: App {
#endif
}
#if DEBUG
.restorationBehavior(ScreenshotDemoConfiguration.active == nil ? .automatic : .disabled)
// XCTest launches the real app. Gating individual tests does not stop
// SwiftUI from opening or restoring the host's own main window.
.defaultLaunchBehavior(Self.suppressesAutomaticTestWindows ? .suppressed : .automatic)
.restorationBehavior(
Self.isRunningTests || ScreenshotDemoConfiguration.active != nil ? .disabled : .automatic)
#endif
.defaultSize(app.windowSizeStore.defaultSize)
// All main pages share one content floor. Opening the sidebar lets
@@ -202,6 +224,10 @@ struct TermindApp: App {
.environment(\.locale, launchLanguage.locale)
.modelContainer(modelContainer)
}
#if DEBUG
.defaultLaunchBehavior(Self.suppressesAutomaticTestWindows ? .suppressed : .automatic)
.restorationBehavior(Self.isRunningTests ? .disabled : .automatic)
#endif
.defaultSize(width: 560, height: 240)
.windowResizability(.contentSize)
// SwiftUI lists every `Window` scene in the Window menu so people can
@@ -247,7 +273,9 @@ struct TermindApp: App {
weak var app: AppModel? {
didSet {
guard let app else { return }
guard ProcessInfo.processInfo.environment["XCTestConfigurationFilePath"] == nil else { return }
#if DEBUG
guard !TermindApp.isRunningTests else { return }
#endif
app.serverMetrics.start()
metricsActivity.start(app.serverMetrics)
metricsMenu.openMainWindow = { [weak app] in app?.mainWindows.openMetrics() }
@@ -321,12 +349,19 @@ struct TermindApp: App {
}
func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool {
#if DEBUG
// Closing an offscreen fixture must not terminate the test runner.
guard !TermindApp.isRunningTests else { return false }
#endif
let menuEnabled =
UserDefaults.standard.object(forKey: DesktopSettingsKey.showMetricsInMenuBar) as? Bool ?? true
return !menuEnabled && app?.serverMetrics.keepsRunning != true
}
func applicationShouldHandleReopen(_ sender: NSApplication, hasVisibleWindows flag: Bool) -> Bool {
#if DEBUG
guard !TermindApp.suppressesAutomaticTestWindows else { return false }
#endif
guard !flag else { return true }
return app?.mainWindows.handleReopen() ?? true
}
+1 -1
View File
@@ -326,7 +326,7 @@ struct AgentHostAuthenticationTests {
#expect(store.key(key.id)?.requiresPassphraseEntry == true)
}
@Test
@Test(.requiresVisibleWindow)
func savedIdentityWithProtectedKeyRequestsOnlyPassphraseExternally() async throws {
let keychain = MemoryHostSecretStore()
let reference = "termind.key.\(UUID().uuidString)"
+20
View File
@@ -0,0 +1,20 @@
import AppKit
import Testing
@testable import Termind
@MainActor
struct AppTestHostTests {
@Test
func defaultTestHostDoesNotPresentWindowsOrReopenTheMainScene() {
guard TermindApp.suppressesAutomaticTestWindows else { return }
#expect(NSApp.windows.allSatisfy { !$0.isVisible })
let delegate = AppDelegate()
#expect(!delegate.applicationShouldHandleReopen(NSApp, hasVisibleWindows: false))
}
@Test
func closingTheLastFixtureWindowDoesNotTerminateTheTestHost() {
#expect(!AppDelegate().applicationShouldTerminateAfterLastWindowClosed(NSApp))
}
}
+2 -2
View File
@@ -37,7 +37,7 @@ struct DockMenuTests {
#expect(try #require(delegate.applicationDockMenu(NSApp)).items[0].isEnabled == false)
}
@Test(arguments: [false, true])
@Test(.requiresVisibleWindow, arguments: [false, true])
func repeatedDockActionsCreateDistinctWelcomeWindowsWithoutAnExistingWindow(closePreviousWindow: Bool) throws {
let app = AppModel(hosts: HostLibraryModel())
let delegate = AppDelegate()
@@ -79,7 +79,7 @@ struct DockMenuTests {
#expect(secondModel.assistantQuery.isEmpty)
}
@Test(arguments: [false, true])
@Test(.requiresVisibleWindow, arguments: [false, true])
func dockNewWindowPreservesTheExistingPageAndWorkspaceEvenInFullScreen(fullScreen: Bool) throws {
let host = Host(name: "Server", host: "server.example")
let app = AppModel(hosts: HostLibraryModel(hosts: [host]))
+13 -13
View File
@@ -17,7 +17,7 @@ import struct TermindDomain.Host
@Suite(.serialized)
@MainActor
struct ExternalAuthCoordinatorTests {
@Test func interactiveResponsesAreScopedAndInformationalRoundsComplete() async throws {
@Test(.requiresVisibleWindow) func interactiveResponsesAreScopedAndInformationalRoundsComplete() async throws {
let coordinator = ExternalAuthCoordinator()
let challenge = SSHKeyboardInteractiveChallenge(
connectionID: UUID(), hostID: UUID(), hostname: "server.example", port: 22,
@@ -38,7 +38,7 @@ struct ExternalAuthCoordinatorTests {
#expect(coordinator.current == nil)
}
@Test func stoppingMCPPreservesAppAuthentication() async throws {
@Test(.requiresVisibleWindow) func stoppingMCPPreservesAppAuthentication() async throws {
let coordinator = ExternalAuthCoordinator()
let challenge = SSHKeyboardInteractiveChallenge(
connectionID: UUID(), hostID: UUID(), hostname: "server.example", port: 22,
@@ -89,7 +89,7 @@ struct ExternalAuthCoordinatorTests {
#expect(window.standardWindowButton(.zoomButton)?.isHidden == false)
}
@Test
@Test(.requiresVisibleWindow)
func popupQueueResumesInFIFOOrder() async throws {
let coordinator = ExternalAuthCoordinator()
let runID = UUID()
@@ -117,7 +117,7 @@ struct ExternalAuthCoordinatorTests {
#expect(coordinator.pending.isEmpty)
}
@Test
@Test(.requiresVisibleWindow)
func protectedKeyCanRaisePassphraseImmediatelyAfterIdentity() async throws {
let coordinator = ExternalAuthCoordinator()
let handler = coordinator.handler(clientName: "Codex", runID: UUID())
@@ -170,7 +170,7 @@ struct ExternalAuthCoordinatorTests {
#expect(coordinator.pending.isEmpty)
}
@Test
@Test(.requiresVisibleWindow)
func closingThePopupCancelsEveryWaiter() async throws {
let coordinator = ExternalAuthCoordinator()
let task = Task {
@@ -186,7 +186,7 @@ struct ExternalAuthCoordinatorTests {
#expect(coordinator.pending.isEmpty)
}
@Test
@Test(.requiresVisibleWindow)
func staleWindowDisappearanceCannotCancelANewerPassphraseRequest() async throws {
let coordinator = ExternalAuthCoordinator()
let firstRequest = authenticationRequest(name: "First")
@@ -226,7 +226,7 @@ struct ExternalAuthCoordinatorTests {
#expect(coordinator.pending.isEmpty)
}
@Test
@Test(.requiresVisibleWindow)
func secretRequestsUseTheSamePopupQueueAndRejectOrdinaryQuestions() async throws {
let coordinator = ExternalAuthCoordinator()
let runID = UUID()
@@ -257,7 +257,7 @@ struct ExternalAuthCoordinatorTests {
)
}
@Test
@Test(.requiresVisibleWindow)
func cancellingAQueuedSessionDoesNotRepresentTheCurrentPopup() async throws {
let coordinator = ExternalAuthCoordinator()
let currentRunID = UUID()
@@ -286,7 +286,7 @@ struct ExternalAuthCoordinatorTests {
#expect(await current.value == .cancelled)
}
@Test
@Test(.requiresVisibleWindow)
func visibleSecretTimesOutAndLeavesNoPendingPopup() async throws {
let coordinator = ExternalAuthCoordinator()
let request = secretRequest(timeout: .milliseconds(40))
@@ -299,7 +299,7 @@ struct ExternalAuthCoordinatorTests {
#expect(coordinator.pending.isEmpty)
}
@Test
@Test(.requiresVisibleWindow)
func queuedSecretDoesNotSpendItsTimeoutBehindSSHPrompt() async throws {
let coordinator = ExternalAuthCoordinator()
let sshRequest = authenticationRequest(name: "Current")
@@ -324,7 +324,7 @@ struct ExternalAuthCoordinatorTests {
#expect(coordinator.pending.isEmpty)
}
@Test
@Test(.requiresVisibleWindow)
func answeredSecretCannotLaterRetireANewerPopup() async throws {
let coordinator = ExternalAuthCoordinator()
let request = secretRequest(timeout: .milliseconds(40))
@@ -355,7 +355,7 @@ struct ExternalAuthCoordinatorTests {
#expect(await ssh.value == .cancelled)
}
@Test
@Test(.requiresVisibleWindow)
func hostKeyUsesPopupQueueAndReturnsSelectedTrustScope() async throws {
let coordinator = ExternalAuthCoordinator()
let request = hostKeyRequest()
@@ -376,7 +376,7 @@ struct ExternalAuthCoordinatorTests {
#expect(coordinator.pending.isEmpty)
}
@Test
@Test(.requiresVisibleWindow)
func closingHostKeyPopupDeniesTheWaitingCall() async throws {
let coordinator = ExternalAuthCoordinator()
let task = Task {
+1 -1
View File
@@ -208,7 +208,7 @@ struct MCPServerSessionTests {
#expect(message.contains("\"id\":1"))
}
@Test
@Test(.requiresVisibleWindow)
func deletingASessionCancelsItsSecretPopupWithoutResurrectingTheSession() async throws {
let authentication = ExternalAuthCoordinator()
let protocolServer = MCPServerProtocol(
+3 -3
View File
@@ -190,7 +190,7 @@ struct MCPServerToolsTests {
#expect(!result.isError)
}
@Test
@Test(.requiresVisibleWindow)
func secretPromptReturnsOnlyASessionBoundOneShotHandle() async throws {
let authentication = ExternalAuthCoordinator()
let server = makeMCPServerTools(externalAuthentication: authentication)
@@ -251,7 +251,7 @@ struct MCPServerToolsTests {
}
}
@Test
@Test(.requiresVisibleWindow)
func timedOutSecretPromptReturnsAnErrorAndIssuesNoHandle() async throws {
let authentication = ExternalAuthCoordinator()
let server = makeMCPServerTools(externalAuthentication: authentication)
@@ -286,7 +286,7 @@ struct MCPServerToolsTests {
#expect(await broker.count == 0)
}
@Test
@Test(.requiresVisibleWindow)
func endingASessionCancelsItsPromptAndDiscardsSecrets() async throws {
let authentication = ExternalAuthCoordinator()
let server = makeMCPServerTools(externalAuthentication: authentication)
+2 -1
View File
@@ -41,7 +41,8 @@ struct SFTPApplicationOpenerTests {
#expect(SFTPApplicationOpener.appStoreSearchURL(for: "README") == nil)
}
@Test func missingApplicationPropagatesLaunchFailure() async throws {
// Launch Services may show a system alert even though this open request is expected to fail.
@Test(.requiresVisibleWindow) func missingApplicationPropagatesLaunchFailure() async throws {
let directory = FileManager.default.temporaryDirectory.appending(path: UUID().uuidString)
try FileManager.default.createDirectory(at: directory, withIntermediateDirectories: true)
defer { try? FileManager.default.removeItem(at: directory) }
+1
View File
@@ -3,6 +3,7 @@ import Testing
extension Trait where Self == ConditionTrait {
/// Window presentation and focus changes require an explicit opt-in, even on a machine with a display.
/// This includes Dock actions, external authentication requests, and Launch Services alerts.
static var requiresVisibleWindow: Self {
.enabled(
if: ProcessInfo.processInfo.environment["TERMIND_WINDOW_TESTS"] == "1",