Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ViewInspector is unable to find Button in .toolbar modifier applied to UIViewControllerRepresentable #232

Open
myost opened this issue Mar 9, 2023 · 0 comments
Labels
bug Something isn't working

Comments

@myost
Copy link

myost commented Mar 9, 2023

Recently I wrote a test in the large app that I work on for a view that used a UIViewControllerRepresentable with a toolbar modifier applied to it.

The test failed because it couldn't find the modifier even when searching the parent view for the accessibility identifier of the toolbar button. But, when I embedded the UIViewControllerRepresentable in a ZStack and applied the toolbar to the ZStack instead the test succeeded & the app still worked as expected. I wasn't trying to test other modifiers but it seemed like they were also duplicated in the output, so this could be an issue with any modifier applied to a UIViewControllerRepresentable. It seems like the UIViewControllerRepresentable is acting more like a Group than a View. I'm not sure if that is expected, but it would be great to be able to inspect a modifier that gets applied directly to the view instead of using the workaround.

Code Example

This is a min reproducible example of the view structure:

import SwiftUI

struct MyView: View {
    static let strings = ["Google", "Apple", "View Inspector"]

    @State var selected: String?
    @State var presentChild = false

    var body: some View {
        VStack {
            ForEach(Self.strings, id: \.self) { string in
                Button(action: {
                    selected = string
                    presentChild = true
                }, label: {
                    Text(string)
                        .foregroundColor(.blue)
                        .padding()
                })
            }
            if let selected {
                NavigationLink(
                    destination:
//                        ZStack {
                            ChildViewControllerRepresentable(title: selected)
//                        }
                        .navigationBarBackButtonHidden(true)
                        .toolbar {
                            ToolbarItem(placement: .navigationBarLeading) {
                                Button(action: {
                                    presentChild = false
                                    self.selected = nil
                                }, label: {
                                    Image(systemName: "chevron.left")
                                })
                                .accessibility(identifier: "ChildBackButton")
                            }
                        },
                    isActive: $presentChild,
                    label: {
                        EmptyView()
                    })
                .accessibility(identifier: "ParentNavigationLink")
            }
        }
    }
}

struct ChildViewControllerRepresentable: UIViewControllerRepresentable {
    let title: String

    func makeUIViewController(context: Context) -> WrapperViewController {
        return WrapperViewController(title: title)
    }

    class Coordinator { }

    func makeCoordinator() -> Self.Coordinator { Coordinator() }

    func updateUIViewController(_: WrapperViewController, context _: Context) { }
}

final class WrapperViewController: UIViewController {
    init(title: String?) {
        super.init(nibName: nil, bundle: nil)
        self.title = title
    }

    required init?(coder _: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}

And the associated test method which will fail if you copy & paste the code from above, but will succeed if you comment the ZStack back in:

    func testNavLinkWhenSelectedObjectExists() throws {
        let testString = MyView.strings.first!
        let view = MyView(selected: testString, presentChild: true)

        let childView = try view
            .inspect()
            .find(viewWithAccessibilityIdentifier: "ParentNavigationLink")
            .find(ChildViewControllerRepresentable.self)
            .actualView()

        XCTAssertEqual(childView.title, testString)

        let _ = try view
            .inspect()
            .find(viewWithAccessibilityIdentifier: "ChildBackButton")
            .button()
            .tap()
    }

Here's a screenshot of the output when I run the test locally:

Screenshot 2023-03-09 at 5 43 55 PM

@nalexn nalexn added the bug Something isn't working label Feb 3, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

2 participants