UI Test, удаляющий текст в текстовом поле
В моем тесте у меня есть текстовое поле с уже существующим текстом. Я хочу удалить содержимое и ввести новую строку.
let textField = app.textFields
textField.tap()
// delete "Old value"
textField.typeText("New value")
При удалении строки с аппаратной клавиатурой Запись не генерирует для меня ничего. Проделав то же самое с программной клавиатурой, я получил:
let key = app.keys["Usuń"] // Polish name for the key
key.tap()
key.tap()
... // x times
или
app.keys["Usuń"].pressForDuration(1.5)
Я был обеспокоен тем, что мой тест зависит от языка, поэтому я создал что-то вроде этого для поддерживаемых языков:
extension XCUIElementQuery {
var deleteKey: XCUIElement {
get {
// Polish name for the key
if self["Usuń"].exists {
return self["Usuń"]
} else {
return self["Delete"]
}
}
}
}
Он выглядит лучше в коде:
app.keys.deleteKey.pressForDuration(1.5)
но он очень хрупкий. После выхода из Simulator Toggle software keyboard
был reset, и у меня был провал. Мое решение не очень хорошо работает с тестированием CI. Как это можно решить, чтобы быть более универсальным?
Ответы
Ответ 1
Я написал метод расширения, чтобы сделать это для меня, и это довольно быстро:
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 = stringValue.characters.map { _ in XCUIKeyboardKeyDelete }.joined(separator: "")
self.typeText(deleteString)
self.typeText(text)
}
}
Это используется довольно легко: app.textFields["Email"].clearAndEnterText("[email protected]")
Ответ 2
Так как вы исправили свою локализованную проблему с именем ключа в комментариях к своим вопросам, я предположим, что вы можете получить доступ к ключу удаления, просто называя это "Удалить".
Код ниже позволит вам надежно удалить содержимое вашего поля:
while (textField.value as! String).characters.count > 0 {
app.keys["Delete"].tap()
}
Но в то же время ваша проблема может указывать на необходимость более гибкого решения этой проблемы, чтобы улучшить удобство использования вашего приложения. В текстовом поле вы также можете добавить Clear button
, с помощью которого пользователь может сразу удалить текстовое поле;
Откройте раскадровку и выберите текстовое поле, в разделе "Инспектор атрибутов" найдите "Очистить кнопку" и установите его в нужную опцию (например, всегда видна).
![Очистить выбор кнопок]()
Теперь пользователи могут очистить поле простым нажатием на крестик справа от текстового поля:
![Очистить кнопку]()
Или в вашем тесте пользовательского интерфейса:
textField.buttons["Clear text"].tap()
Ответ 3
Я нашел следующее решение:
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
При нажатии и удерживании текстового поля открывается меню, в котором вы можете нажать кнопку "Выбрать все". После этого вам нужно только удалить этот текст с помощью кнопки "удалить" на клавиатуре или просто ввести новый текст. Он перезапишет старый.
Ответ 4
это будет работать для textfield и textview
для 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)
}
}
для SWIFT 4 до SWIFT 99
extension XCUIElement {
func clearText() {
guard let stringValue = self.value as? String else {
return
}
var deleteString = String()
for _ in stringValue {
deleteString += XCUIKeyboardKey.delete.rawValue
}
self.typeText(deleteString)
}
}
ОБНОВЛЕНИЕ XCODE 9
Существует ошибка яблока, где, если текстовое поле пусто, value и placeholderValue равны
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
}
self.typeText(deleteString)
}
}
Ответ 5
Итак, я еще не нашел решение хорошего:/
И мне не нравятся языковые зависимые решения, как и выше, с явным поиском "Clear text".
Итак, я набираю чек, а затем пытаюсь найти четкую кнопку в текстовом поле
Он работает хорошо, если у вас нет настраиваемого текстового поля с более одной кнопкой
Мое лучшее сейчас (у меня нет настраиваемых текстовых полей с большим количеством кнопок):
class func clearTextField(textField : XCUIElement!) -> Bool {
guard textField.elementType != .TextField else {
return false
}
let TextFieldClearButton = textField.buttons.elementBoundByIndex(0)
guard TextFieldClearButton.exists else {
return false
}
TextFieldClearButton.tap()
return true
}
Ответ 6
Xcode 9, Swift 4
Пробовал решения выше, но ни один из них не работал из-за какого-то странного поведения при нажатии - он переместил курсор в начало текстового поля или в какую-то случайную точку в тексте. Подход, который я использовал, - это то, что описано здесь @oliverfrost, но я добавил некоторые проблемы, чтобы решить проблемы и объединить их в аккуратном расширении. Надеюсь, это может быть полезно для кого-то.
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) }
}
}
Использование:
let app = XCUIApplication()
//Just clear text
app.textFields["field1"].clearText()
//Replace text
app.secureTextFields["field2"].clearText(andReplaceWith: "Some Other Text")
Ответ 7
Для тех, кто все еще использует Objective-C
@implementation XCUIElement (Extensions)
-(void)clearText{
if (!self){
return;
}
if (![self.value isKindOfClass:[NSString class]]){
return;
}
NSString* stringValue = (NSString*)self.value;
for (int i=0; i<stringValue.length ; i++) {
[self typeText:XCUIKeyboardKeyDelete];
}
}
@end
Ответ 8
У меня возникли трудности с тем, чтобы вышеупомянутые решения работали для аналогичной проблемы, с которой я столкнулся: курсор помещается перед текстом, а затем работает обратно оттуда. Кроме того, я хотел проверить, чтобы текстовое поле содержало текст перед удалением. Здесь мое решение, вдохновленное расширением https://stackoverflow.com/users/482361/bay-phillips, написано. Я должен отметить, что нажатие клавиши удаления может занять много времени, и его можно заменить на .pressForDuration
func clearAndEnterText(element: XCUIElement, text: String) -> Void
{
guard let stringValue = element.value as? String else {
XCTFail("Tried to clear and enter text into a non string value")
return
}
element.tap()
guard stringValue.characters.count > 0 else
{
app.typeText(text)
return
}
for _ in stringValue.characters
{
app.keys["delete"].tap()
}
app.typeText(text)
}
Ответ 9
Я новичок в тестировании пользовательского интерфейса с iOS, но я смог очистить текстовые поля с помощью этого простого обходного пути. Работая с Xcode8 и планируйте его рефакторинг в ближайшее время:
func testLoginWithCorrectUsernamePassword() {
//Usually this will be completed by Xcode
let app = XCUIApplication()
//Set the text field as a constant
let usernameTextField = app.textFields["User name"]
//Set the delete key to a constant
let deleteKey = app.keys["delete"]
//Tap the username text field to toggle the keyboard
usernameTextField.tap()
//Set the time to clear the field. generally 4 seconds works
deleteKey.press(forDuration: 4.0);
//Enter your code below...
}
Ответ 10
Сделайте это, чтобы удалить текущее строковое значение в текстовом поле, не полагаясь на виртуальную клавиатуру.
//читаем значение вашего текстового поля в этой переменной let textInTextField: String =
let characterCount: Int = textInTextField.count
for _ in 0..<characterCount {
textFields[0].typeText(XCUIKeyboardKey.delete.rawValue)
}
Хорошая вещь об этом решении заключается в том, что он работает независимо от того, какой симулятор имеет виртуальную клавиатуру или нет.
Ответ 11
Теперь в swift 4.2
возможно, вы должны попробовать следующий код:
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()
for _ in 0..<stringValue.count {
self.typeText(XCUIKeyboardKey.delete.rawValue)
}
self.typeText(text)
}
}
Ответ 12
Я использовал то, что описал @oliverfrost, но он не работал на IPhone XR, я немного изменил его для собственного использования, на этот
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 select = XCUIApplication().menuItems["Select"]
//For empty fields there will be no "Select All", so we need to check
if select.waitForExistence(timeout: 0.5), select.exists {
select.tap()
typeText(String(XCUIKeyboardKey.delete.rawValue))
}
if let newVal = newText { typeText(newVal) }
}
}
и, как сказал @zysoft, вы можете использовать его следующим образом:
let app = XCUIApplication()
//Just clear text
app.textFields["field1"].clearText()
//Replace text
app.secureTextFields["field2"].clearText(andReplaceWith: "Some Other Text")
Ответ 13
Swift 5
на основе ответа @Bay Phillips,
extension XCUIElement {
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 = stringValue.map { _ in "\u{8}" }.joined(separator: "")
self.typeText(deleteString)
self.typeText(text)
}
}