Awesome library by the way. I'm currently trying to use it to test one of the libraries that I'm maintaining. However, I've encountered an issue wherein .viewController() fails to locate the underlying UIViewController in a UIViewControllerRepresentable. I'm entirely not sure if I'm overlooking something in my approach. Hence, I'd greatly appreciate any help.
Here's a minimal reproducible example based on my library's implementation. I use background() modifier as a bridge for the UIKit implementation behind the scene.
Test was run using Xcode 15.3, iOS 17.4 simulator on macOS 14.4.1.
Let me know if you need additional information. Thank you!
import Combine
import SwiftUI
import ViewInspector
import XCTest
final class Test: XCTestCase {
func testBridge() throws {
let sut = ContentView()
let exp = sut.inspection.inspect(after: 0.1) { view in
XCTAssertTrue(try view.actualView().isPresented)
let bridge = try view.find(UIViewControllerBridge<Text>.self).actualView()
XCTAssertTrue(bridge.isPresented)
let viewController = try bridge.viewController() // failed - View for UIViewControllerBridge<Text> is absent
XCTAssertTrue(viewController.internalState)
}
ViewHosting.host(view: sut)
wait(for: [exp], timeout: 1.0)
}
}
struct ContentView: View {
@State var isPresented = false
internal let inspection = Inspection<Self>()
var body: some View {
Text("text")
.onReceive(inspection.notice) {
inspection.visit(self, $0)
}
.onAppear {
isPresented = true
}
.background(
UIViewControllerBridge(isPresented: $isPresented) {
Text("pop up")
}
)
}
}
struct UIViewControllerBridge<Content>: UIViewControllerRepresentable where Content: View {
@Binding var isPresented: Bool
let content: () -> Content
func makeUIViewController(context _: Context) -> CustomUIViewController<Content> {
return CustomUIViewController()
}
func updateUIViewController(
_ viewController: CustomUIViewController<Content>,
context: Context
) {
viewController.update(
$isPresented,
content
)
}
}
class CustomUIViewController<Content>: UIViewController where Content: View {
var internalState = false
func update(
_ isPresented: Binding<Bool>,
_ content: () -> Content
) {
internalState = isPresented.wrappedValue
print("isPresented: \(isPresented.wrappedValue)")
// present the content() in another UIWindow
}
}
internal final class Inspection<V> {
let notice = PassthroughSubject<UInt, Never>()
var callbacks: [UInt: (V) -> Void] = [:]
func visit(_ view: V, _ line: UInt) {
if let callback = callbacks.removeValue(forKey: line) {
callback(view)
}
}
}
extension Inspection: InspectionEmissary {}
Hello @nalexn,
Awesome library by the way. I'm currently trying to use it to test one of the libraries that I'm maintaining. However, I've encountered an issue wherein
.viewController()
fails to locate the underlyingUIViewController
in aUIViewControllerRepresentable
. I'm entirely not sure if I'm overlooking something in my approach. Hence, I'd greatly appreciate any help.Here's a minimal reproducible example based on my library's implementation. I use
background()
modifier as a bridge for the UIKit implementation behind the scene.Test was run using Xcode 15.3, iOS 17.4 simulator on macOS 14.4.1.
Let me know if you need additional information. Thank you!