I have this SwiftUI view (will remove non-relevant parts)
struct LoginView: View {
var body: some View {
VStack {
Spacer()
InputField(title: "Email", text: $email)
InputField(title: "Password", text: $password, showingSecureField: true)
InputField(title: "Store", text: $userStore)
CallToActionButton(
title: newUser ? "Register User" : "Log In",
action: userAction
)
Button(action: { newUser.toggle() }) {
HStack {
CheckBox(title: "Create Account", isChecked: $newUser)
Spacer()
}
}
Spacer()
}
}
I can write a UI Test for that button with this code:
func testClickLoginButton() throws {
let app = XCUIApplication()
app.launch()
let startButton = app.buttons["Log In"]
XCTAssertTrue(startButton.waitForExistence(timeout: 1))
XCTAssertTrue(startButton.isEnabled)
startButton.tap()
}
And it works, as there's a button with that title on screen.
But then I want to automatically put some text in those InputTexts and test them, but can't find them, as they're neither UITextField
nor UITextView
. How can I accomplish this? Thanks!
func testAddEmail() throws {
let app = XCUIApplication()
app.launch()
// fails as can't find any text field containing "Email"
let emailText = app.textFields["Email"]
XCTAssertTrue(emailText.waitForExistence(timeout: 1))
emailText.typeText("[email protected]")
XCTAssertEqual(emailText.value as! String, "[email protected]")
}
I am not an expert and have seen different ways to do UITests in SwiftUI. There are perhaps better ways with snapshots etc but I quickly recreated your example for fun and added an accessibility identifier:
struct InputField: View {
var title: String
@Binding var email: String
var body: some View {
VStack(alignment: .leading) {
Text("Enter your email ")
TextField(title, text: $email)
.accessibility(identifier: "Email")
}
.padding()
}
}
struct ContentView: View {
@State private var email: String = ""
var body: some View {
InputField(title: "Email: ", email: $email)
}
}
Also it might be sometimes required to add a tap before entering the email or text. It was giving me an error because of this.
The UItest would look like this and is passing :)
func testAddEmail() throws {
let app = XCUIApplication()
app.launch()
let emailText = app.textFields["Email"]
XCTAssertTrue(emailText.waitForExistence(timeout: 1))
emailText.tap()
emailText.typeText("[email protected]")
XCTAssertEqual(emailText.value as! String, "[email protected]")
}
Also a cool trick I learned is to put a breakpoint like this:
and in the debugger at the prompt enter the following:
(lldb) po XCUIApplication().textFields
And so you get the list and you see if identifiers are missing. Same thing for buttons and staticTexts etc.