UI Test deleting text in text field
I wrote an extension method to do this for me and it's pretty fast:
extension XCUIElement {
/**
Removes any current text in the field before typing in the new value
- Parameter text: the text to enter into the field
*/
func clearAndEnterText(text: String) {
guard let stringValue = self.value as? String else {
XCTFail("Tried to clear and enter text into a non string value")
return
}
self.tap()
let deleteString = String(repeating: XCUIKeyboardKey.delete.rawValue, count: stringValue.count)
self.typeText(deleteString)
self.typeText(text)
}
}
This is then used pretty easily: app.textFields["Email"].clearAndEnterText("[email protected]")
Since you fixed your localized delete key name problem in the comments of your questions, I'll assume you can access the delete key by just calling it "Delete".
The code below will allow you to reliably delete the contents of your field:
while (textField.value as! String).characters.count > 0 {
app.keys["Delete"].tap()
}
or Swift 4+:
while !(textView.value as! String).isEmpty {
app.keys["Delete"].tap()
}
But at the same time, your issue might indicate the need to solve this more elegantly to improve the usability of your app. On the text field you can also add a Clear button
with which a user can immediately empty the text field;
Open the storyboard and select the text field, under the attributes inspector find "Clear button" and set it to the desired option (e.g. is always visible).
Now users can clear the field with a simple tap on the cross at the right of the text field:
Or in your UI test:
textField.buttons["Clear text"].tap()
this will work for textfield and textview
for SWIFT 3
extension XCUIElement {
func clearText() {
guard let stringValue = self.value as? String else {
return
}
var deleteString = String()
for _ in stringValue {
deleteString += XCUIKeyboardKeyDelete
}
self.typeText(deleteString)
}
}
for SWIFT 4, SWIFT 5
extension XCUIElement {
func clearText() {
guard let stringValue = self.value as? String else {
return
}
var deleteString = String()
for _ in stringValue {
deleteString += XCUIKeyboardKey.delete.rawValue
}
typeText(deleteString)
}
}
UPDATE XCODE 9
There is an apple bug where if the textfield is empty, value and placeholderValue are equal
extension XCUIElement {
func clearText() {
guard let stringValue = self.value as? String else {
return
}
// workaround for apple bug
if let placeholderString = self.placeholderValue, placeholderString == stringValue {
return
}
var deleteString = String()
for _ in stringValue {
deleteString += XCUIKeyboardKey.delete.rawValue
}
typeText(deleteString)
}
}
I found following solution:
let myTextView = app.textViews["some_selector"]
myTextView.pressForDuration(1.2)
app.menuItems["Select All"].tap()
app.typeText("New text you want to enter")
// or use app.keys["delete"].tap() if you have keyboard enabled
When you tap and hold on the text field it opens menu where you can tap on "Select all" button. After that all you need is to remove that text with "delete" button on the keyboard or just enter new text. It will overwrite the old one.
Xcode 9, Swift 4
Tried the solutions above, but none worked due to some weird behavior on tap - it moved the cursor to either beginning of the text field, or at some random point in text. The approach I used is what @oliverfrost described here, but I've added some touches to work around the issues and combine it in a neat extension. I hope it can be useful for someone.
extension XCUIElement {
func clearText(andReplaceWith newText:String? = nil) {
tap()
tap() //When there is some text, its parts can be selected on the first tap, the second tap clears the selection
press(forDuration: 1.0)
let selectAll = XCUIApplication().menuItems["Select All"]
//For empty fields there will be no "Select All", so we need to check
if selectAll.waitForExistence(timeout: 0.5), selectAll.exists {
selectAll.tap()
typeText(String(XCUIKeyboardKey.delete.rawValue))
}
if let newVal = newText { typeText(newVal) }
}
}
Usage:
let app = XCUIApplication()
//Just clear text
app.textFields["field1"].clearText()
//Replace text
app.secureTextFields["field2"].clearText(andReplaceWith: "Some Other Text")