google/EarlGrey

[SwiftUI] Anyway to convert EDOObject to SwiftUI View?

Bobbyphtr opened this issue · 1 comments

I try to create a custom matcher here to read a SwiftUI View.

    func grey_swiftui_element() -> GREYMatcher {
        let matches: GREYMatchesBlock = { (element: Any) -> Bool in
            // try to cast to SwiftUI View (?)
            print(element)
        }
        
        let description: GREYDescribeToBlock = { (description: GREYDescription!) -> Void in
            guard let description = description else {
                return
            }
            description.appendText("Got View")
        }
        
        return GREYElementMatcherBlock.init(matchesBlock: matches, descriptionBlock: description)
    }

When I try to run it and try to cast it to SwiftUI View

(lldb) po element as! any View
2023-07-13 20:37:47.767070+0700 DeveloperSettingsEarlGreyTest-Runner[28781:3152446] EDO WARNING: SwiftUI.AccessibilityNode's class is being compared via isKindOfClass: with the class that doesn't belong to the process of the callee object. It will always return NO. To expect isKindOfClass: to return YES, please use a class object that is fetched by EDOClientService::classObjectWithName:hostPort:.
Could not cast value of type 'EDOObject' (0x1ba22ef80) to 'SwiftUI.View' (0x1ba230bc8).
error: Execution was interrupted, reason: signal SIGABRT.
The process has been returned to the state before expression evaluation.
2023-07-13 20:37:47.769244+0700 DeveloperSettingsEarlGreyTest-Runner[28781:3152446] Could not cast value of type 'EDOObject' (0x1ba22ef80) to 'SwiftUI.View' (0x1ba230bc8).

I tried using AnyView as well. Same result.

(lldb) po element as! AnyView
2023-07-13 20:41:22.657287+0700 DeveloperSettingsEarlGreyTest-Runner[28781:3152446] EDO WARNING: SwiftUI.AccessibilityNode's class is being compared via isKindOfClass: with the class that doesn't belong to the process of the callee object. It will always return NO. To expect isKindOfClass: to return YES, please use a class object that is fetched by EDOClientService::classObjectWithName:hostPort:.
Could not cast value of type 'EDOObject' (0x1ba22ef80) to 'SwiftUI.AnyView' (0x111d3ff20).
2023-07-13 20:41:22.657743+0700 DeveloperSettingsEarlGreyTest-Runner[28781:3152446] Could not cast value of type 'EDOObject' (0x1ba22ef80) to 'SwiftUI.AnyView' (0x111d3ff20).
error: Execution was interrupted, reason: signal SIGABRT.
The process has been returned to the state before expression evaluation.

Is there any way to convert the EDOObject to SwiftUI related View?
Thanks!

Hi Bobbyphtr, it's impossible to proxy SwiftUI View to the testing process because it's struct, and EDOObject can only proxy runtime classes.

To make your use case work, it's better to move your GREYMatcher generating method to the app side, and use eDO to get a proxy of your GREYMatcher. You can do this by creating a Swift classes as below:

@objcMembers
public class MyTestHelperInApp: NSObject {
  dynamic required public init() {}
  dynamic public func grey_swiftui_element() -> GREYMatcher {
    ...
  }
}

Then your test can access your helper class and get the matcher there:

let matcher = GREYRemoteClassInApp(classVal: MyTestHelperInApp.self).init().grey_swiftui_element()
EarlGrey.select(withMatcher:matcher)...

This way your SwiftUI views won't be sent across the process and will be accessed only within your app-under-test.