nalexn / ViewInspector

Runtime introspection and unit testing of SwiftUI views
MIT License
2.09k stars 145 forks source link

Crash: ViewHosting.swift:162: Fatal error: Unexpectedly found nil while unwrapping an Optional value #312

Open esemusa opened 2 weeks ago

esemusa commented 2 weeks ago

Description of the Issue

The crash occurs because ViewInspector's precondition is not safeguarded against external manipulation during testing. Once the static window is initialized and set as the keyWindow, it becomes accessible to other tests, leading to potential crashes.

https://github.com/nalexn/ViewInspector/blob/21a2ff9e75e66eb97e5f1a35a181e20cd55b1fe2/Sources/ViewInspector/ViewHosting.swift#L136-L145

The crash itself will be triggered here: https://github.com/nalexn/ViewInspector/blob/21a2ff9e75e66eb97e5f1a35a181e20cd55b1fe2/Sources/ViewInspector/ViewHosting.swift#L161-L163

Steps to Reproduce

The following example demonstrates how to reproduce the crash (tested in Xcode 15.4, Simulator iOS 17.5):

import SwiftUI
import ViewInspector
import XCTest

final class ViewInspectorCrash: XCTestCase {
    func testViewInspectorCrash() {
        let view = Text("Crash")

        // This triggers the one-time creation of ViewHosting.window
        ViewHosting.host(view: view)

        // The created window is now the keyWindow and can be accessed and manipulated by any other test
        UIApplication.shared.keyWindow?.rootViewController = nil

        // Manipulation from another test will lead to a crash:
        ViewHosting.host(view: view)
    }
}

Each test execution should be isolated and safe from external interference (ensuring the static window/window.rootViewController is reset or properly cleaned or implementing checks to verify the integrity of the keyWindow before it is used).

nalexn commented 2 weeks ago

Thanks for the heads up