@@ -2078,6 +2078,7 @@ final class AppDelegate: NSObject, NSApplicationDelegate, UNUserNotificationCent
20782078 private var didSetupMultiWindowNotificationsUITest = false
20792079 private var didSetupDisplayResolutionUITestDiagnostics = false
20802080 private var displayResolutionUITestObservers: [NSObjectProtocol] = []
2081+ private var didRequestFallbackUITestWindow = false
20812082 private struct UITestRenderDiagnosticsSnapshot {
20822083 let panelId: UUID
20832084 let drawCount: Int
@@ -2384,13 +2385,7 @@ final class AppDelegate: NSObject, NSApplicationDelegate, UNUserNotificationCent
23842385 )
23852386 }
23862387 DispatchQueue.main.asyncAfter(deadline: .now() + 0.25) { [weak self] in
2387- guard let self else { return }
2388- if NSApp.windows.isEmpty {
2389- self.openNewMainWindow(nil)
2390- }
2391- self.moveUITestWindowToTargetDisplayIfNeeded()
2392- NSRunningApplication.current.activate(options: [.activateAllWindows, .activateIgnoringOtherApps])
2393- self.writeUITestDiagnosticsIfNeeded(stage: "afterForceWindow")
2388+ self?.stabilizeUITestLaunchWindowAndForeground()
23942389 }
23952390 if env["CMUX_UI_TEST_BROWSER_IMPORT_HINT_OPEN_BLANK_BROWSER"] == "1" {
23962391 DispatchQueue.main.asyncAfter(deadline: .now() + 0.45) { [weak self] in
@@ -2416,6 +2411,46 @@ final class AppDelegate: NSObject, NSApplicationDelegate, UNUserNotificationCent
24162411 }
24172412
24182413#if DEBUG
2414+ // Retry launch stabilization until a delayed WindowGroup materialization produces
2415+ // a visible key window that XCUITest can bring to the foreground on the shared VM.
2416+ private func stabilizeUITestLaunchWindowAndForeground(attempt: Int = 0) {
2417+ let env = ProcessInfo.processInfo.environment
2418+ guard isRunningUnderXCTest(env) else { return }
2419+
2420+ if NSApp.windows.isEmpty, !didRequestFallbackUITestWindow {
2421+ didRequestFallbackUITestWindow = true
2422+ openNewMainWindow(nil)
2423+ }
2424+
2425+ moveUITestWindowToTargetDisplayIfNeeded()
2426+ activateUITestAppIfNeeded()
2427+
2428+ let hasWindow = !NSApp.windows.isEmpty
2429+ let hasVisibleWindow = NSApp.windows.contains { $0.isVisible }
2430+ let hasKeyWindow = NSApp.keyWindow != nil
2431+ let stage = attempt == 0 ? "afterForceWindow" : "afterForceWindow.retry\(attempt)"
2432+ writeUITestDiagnosticsIfNeeded(stage: stage)
2433+
2434+ guard attempt < 20 else { return }
2435+ if !hasWindow || !hasVisibleWindow || !hasKeyWindow || !NSRunningApplication.current.isActive {
2436+ DispatchQueue.main.asyncAfter(deadline: .now() + 0.25) { [weak self] in
2437+ self?.stabilizeUITestLaunchWindowAndForeground(attempt: attempt + 1)
2438+ }
2439+ }
2440+ }
2441+
2442+ private func activateUITestAppIfNeeded() {
2443+ if let window = NSApp.windows.first {
2444+ window.makeKeyAndOrderFront(nil)
2445+ window.orderFrontRegardless()
2446+ }
2447+ if #available(macOS 14.0, *) {
2448+ NSRunningApplication.current.activate(options: [.activateAllWindows])
2449+ } else {
2450+ NSRunningApplication.current.activate(options: [.activateAllWindows, .activateIgnoringOtherApps])
2451+ }
2452+ }
2453+
24192454 private func writeUITestDiagnosticsIfNeeded(stage: String) {
24202455 let env = ProcessInfo.processInfo.environment
24212456 guard let path = env["CMUX_UI_TEST_DIAGNOSTICS_PATH"], !path.isEmpty else { return }
0 commit comments