Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,8 @@ import UIKit

public extension UIApplication {
@objc var mainWindow: UIWindow? {
// The delegate-window fallback covers the moments when no scene key window
// exists: early in scene connection (before makeKeyAndVisible) and in the unit
// test host, which never connects a window scene.
// The delegate-window fallback covers the brief moment early in scene
// connection, before the scene's key window is made visible.
connectedScenes
.compactMap { ($0 as? UIWindowScene)?.keyWindow }
.first
Expand Down
4 changes: 2 additions & 2 deletions WordPress/Classes/System/WordPressAppDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -136,8 +136,8 @@ public class WordPressAppDelegate: UIResponder, UIApplicationDelegate {

/// Opts the app into the UIScene life cycle and names the scene delegate in code,
/// instead of a `UISceneConfigurations` entry duplicated in each target's Info.plist.
/// The unit test host runs TestingAppDelegate, which doesn't implement this method,
/// so tests keep the legacy life cycle.
/// The unit test host (TestingAppDelegate) opts into the scene life cycle the same
/// way, because iOS 27 removed the legacy window life cycle.
public func application(
_ application: UIApplication,
configurationForConnecting connectingSceneSession: UISceneSession,
Expand Down
43 changes: 38 additions & 5 deletions WordPress/Classes/System/main.swift
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import BuildSettingsKit
import Foundation
import SwiftUI
import UIKit

let isRunningTests = NSClassFromString("XCTestCase") != nil
let appDelegateClass = isRunningTests ? NSStringFromClass(TestingAppDelegate.self) : NSStringFromClass(WordPressAppDelegate.self)
let appDelegateClass =
isRunningTests ? NSStringFromClass(TestingAppDelegate.self) : NSStringFromClass(WordPressAppDelegate.self)

// The secrets MUST be configured before the app launches.
//
Expand All @@ -20,11 +22,42 @@ UIApplicationMain(
)

final class TestingAppDelegate: NSObject, UIApplicationDelegate {
/// Opt the unit test host into the UIScene life cycle. iOS 27 removed the legacy
/// window life cycle, so a plain `UIWindow()` created here crashes the host at launch.
/// Mirrors `WordPressAppDelegate`'s programmatic scene opt-in.
func application(
_ application: UIApplication,
configurationForConnecting connectingSceneSession: UISceneSession,
options: UIScene.ConnectionOptions
) -> UISceneConfiguration {
let configuration = UISceneConfiguration(name: nil, sessionRole: connectingSceneSession.role)
if connectingSceneSession.role == .windowApplication {
configuration.delegateClass = TestingSceneDelegate.self
}
return configuration
}
}

final class TestingSceneDelegate: UIResponder, UIWindowSceneDelegate {
var window: UIWindow?

func applicationDidFinishLaunching(_ application: UIApplication) {
window = UIWindow()
window?.rootViewController = UIViewController()
window?.makeKeyAndVisible()
func scene(
_ scene: UIScene,
willConnectTo session: UISceneSession,
options connectionOptions: UIScene.ConnectionOptions
) {
guard let windowScene = scene as? UIWindowScene else {
return
}
let window = UIWindow(windowScene: windowScene)
window.rootViewController = UIHostingController(rootView: TestingRootView())
window.makeKeyAndVisible()
self.window = window
}
}

private struct TestingRootView: View {
var body: some View {
Text("Running unit tests")
}
}