EarlGrey
EarlGrey copied to clipboard
SwiftUI ViewRepresentable and UIViewRepresentable is not correctly placed in element hierarchy.
Background
Hi there! I'm a beginner and still learning about EarlGrey and how to use them.
I created a simple SwiftUI View as simple as this. And want to test them.
Here's the SwiftUI Code
struct RegisterView: View {
@EnvironmentObject var viewModel: RegisterViewModel
@State var ageText: String = ""
@State var nameText: String = ""
@State var isFormValid: Bool = false
var body: some View {
VStack {
Text("Welcome to SwiftUI")
.font(Font.title)
.fontWeight(.semibold)
Text("Register here!")
.multilineTextAlignment(.center)
.padding(.bottom, 16.0)
VStack(spacing: 16.0) {
BorderedTextField(placeholder: "Name",
textBind: $nameText,
errorTextBind: $viewModel.nameValidationError)
.onChange(of: nameText) { newValue in
self.viewModel.name = newValue.isEmpty ? nil : newValue
}
.accessibilityIdentifier("register.name.field")
BorderedTextField(placeholder: "Age",
textBind: $ageText,
errorTextBind: $viewModel.ageValidationError)
.onChange(of: ageText, perform: { newValue in
// Convert into Integers
self.viewModel.age = Int(newValue)
})
.accessibilityIdentifier("register.age.field")
.keyboardType(.numberPad)
Button {
// Submit action
} label: {
NavigationLink("Next") {
PhoneNumberView()
.environmentObject(viewModel)
}
.frame(maxWidth: .infinity)
.padding(8.0)
}
.disabled(!isFormValid)
.buttonStyle(.automatic)
.accessibilityIdentifier("register.button.next")
} // - Register Form
Text("RegisterViewModel")
Text("Name: \(viewModel.name ?? "nil")")
Text("Age: \(viewModel.age == nil ? "nil" : String(viewModel.age!))")
} // - Main Stack
.padding(.horizontal, 16.0)
.onReceive(self.viewModel.isFirstFormValid
.throttle(for: .milliseconds(500), scheduler: RunLoop.main, latest: true)
) { output in
self.isFormValid = output
}
}
}
Here's the BorderedTextField
struct BorderedTextField: View {
/// Placeholder localize string key
private var placeholder: LocalizedStringKey
/// Text binding.
@Binding
private var textBind: String
@Binding
private var errorTextBind: String?
/// Initialize a textfield with bordered pattern
/// - Parameters:
/// - placeholder: Localized Key for Placeholder.
/// - textBind: Text binding
init(placeholder: LocalizedStringKey,
textBind: Binding<String>,
errorTextBind: Binding<String?>? = nil) {
self.id = id
self.placeholder = placeholder
self._textBind = textBind
self._errorTextBind = errorTextBind ?? Binding<String?>.constant(nil)
}
var body: some View {
VStack(alignment: .leading) {
TextField(placeholder, text: $textBind)
.padding()
.overlay(
RoundedRectangle(cornerRadius: 8.0)
.stroke()
)
.accessibilityIdentifier("borderedtextfield.textfield")
Text(errorTextBind ?? "")
.foregroundColor(Color.red)
.accessibilityIdentifier("borderedtextfield.errortext")
}
.accessibilityElement(children: .contain)
}
}
I used accessibilityElement to retain all the child accessibilityIdentifier so I can differentiate them by their parents. Thus a ViewHierarchy structure is important.
Expectation
I hope that the View Hierarchy on EarlGrey is shown like what XCUIApplication does.

I thought my current accessibilityIdentifier structure using accessibilityElement can work on UITest. But I was wrong when I'm using EarlGrey.
The Issue
After taking sometime looking at the View Hierarchy I discover this.
All UIViewControllerRepresentable and UIViewRepresentable somewhat being put outside of the View Hierarchy. This will eliminate my chance on using the parent identifier to get a certain component.
I checked with a UIViewControllerRepresentable and a UIButton wrapped inside UIViewRepresentable. It will put the View outside of the view hierarchy.
And yes. I'm surprised, underneath Apple still use UIViewRepresentable on UITextField for SwiftUI TextField haha.
Any help is really appreciated. Thank you!
Thanks a lot for this issue. We'll take a look - we are trying to add SwiftUI support at the moment.
Thanks for checking out my issue! Waiting for the heads up soon! @tirodkar