nalexn / ViewInspector

Runtime introspection and unit testing of SwiftUI views
MIT License
2.15k stars 148 forks source link

Toggle's tap() and isOn() are currently unavailable for inspection on iOS 16 #230

Closed melgu closed 4 months ago

melgu commented 1 year ago

I created this issue to keep track of this problem.

Do you have any news? Or do you know of a workaround?

melgu commented 1 year ago

Also, I would maybe argue, that some kind of indicator on the SwiftUI API coverage page for these kind of limitations would be helpful.

kpacholak commented 1 year ago

I am also waitin ;)

Zrzut ekranu 2023-04-1 o 18 05 11
PedrinhoDS commented 11 months ago

Any updates on this with iOS 17?

sureshjoshi commented 7 months ago

So, about an hour ago is the first time I'd actually ever seen/used the Swift Mirror system - so I'm in the process of learning how it works.

It looks like the Toggle is now based on a private SwiftUI.ToggleState which I can't seem to access, so I can't just cast to it here (can we?):

return try Inspector.attribute(label: "_toggleState", value: content.view, type: Binding<SwiftUI.ToggleState>.self)

Here is the reflection of that _toggleState:

Optional(SwiftUI.Binding<SwiftUI.ToggleState>(transaction: SwiftUI.Transaction(plist: []), location: SwiftUI.LocationBox<SwiftUI.FunctionalLocation<SwiftUI.ToggleState>>, _value: off))

So, there is a _value which can be used to at least determine if a toggle is toggled or not (and I also tested some workarounds here using styles and whatnot), but I'm not sure if any of this will let anyone affect the value of the toggle.

That _value is extractable a number of ways - but I don't know the type - assuming SwiftUI.ToggleState is an enum though, but I can't strictly type the binding either way.

Again, I know nothing about Mirrors, so maybe there is some way to go in and tell it to change values and have that reflect through the binding that we can't access? Or is there some way to magic cast to private types? I doubt it - but 🤷🏽

@nalexn If you have any thoughts or directions on this, I'd be available to pursue further.

sureshjoshi commented 7 months ago

Referencing another project I found that might have a workaround for this?

https://github.com/soundcloud/Axt/blob/23a8a92bd77ac9865f8d38f23f07f3ed42ce4da9/Sources/Axt/Native/Toggle.swift#L45

sureshjoshi commented 7 months ago

Alright, good progress here - appears to work for my isOn tests. If I can get the toggle() part of it working, I'll make a PR.

        // ViewInspector equivalent of: https://github.com/soundcloud/Axt/blob/master/Sources/Axt/Native/Toggle.swift
        let toggleStateBinding = try Inspector.attribute(label: "_toggleState", value: content.view)
        let _toggleState = withUnsafePointer(to: toggleStateBinding) {
            $0.withMemoryRebound(to: Binding<ToggleState>.self, capacity: 1) {
                $0.pointee
            }
        }

        return Binding {
            switch _toggleState.wrappedValue {
            case .on:
                true
            case .off, .mixed:
                false
            }
        }

Edit: Alright, turns out that tap() was working, I was just pointed at the wrong version of my code.

I'll fire off a PR tonight if I can get the tests running in this repo.

gabriele-dechit commented 7 months ago

Hello,

I am using ViewInspector on an iOS 13 application and it still warns about isOn/tap not working. Shouldn't they work on iOS versions prior to 16?

sureshjoshi commented 7 months ago

This is the check - what simulator are you running?

if #available(iOS 16.0, macOS 13.0, tvOS 16.0, watchOS 9.0, *)
gabriele-dechit commented 7 months ago

My project is set to iOS 13 minimum version and the simulator I am using is iPhone 15 Pro (iOS 17.2) with Xcode 15.1

melgu commented 7 months ago

@gabriele-dechit Because your simulator runs iOS 17.2 it correctly warns about isOn not working. You have to run an iOS 15 simulator or older.

nalexn commented 4 months ago

This has been fixed in 0.9.11