UI测试删除文本字段中的文本

时间:2015-09-28 11:28:05

标签: swift uitextfield xcode7 uikeyboard xcode-ui-testing

在我的测试中,我有一个带有预先存在文本的文本字段。我想删除内容并输入新字符串。

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)

但它非常脆弱。从模拟器退出Toggle software keyboard后重置,我的测试失败了。我的解决方案不适用于CI测试。如何解决这个问题才能更具普遍性?

14 个答案:

答案 0 :(得分:125)

我写了一个扩展方法为我做这个,而且速度非常快:

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("newemail@domain.com")

答案 1 :(得分:19)

由于您在问题的评论中修复了本地化的删除密钥名称问题,因此我假设您只需将其命名为“删除”即可访问删除密钥。

以下代码可让您可靠地删除字段内容:

    while (textField.value as! String).characters.count > 0 {
        app.keys["Delete"].tap()
    }

但与此同时,您的问题可能表明需要更优雅地解决此问题,以提高应用的可用性。在文本字段中,您还可以添加Clear button,用户可以使用该textField.buttons["Clear text"].tap() 立即清空文本字段;

打开故事板并选择文本字段,在属性检查器下找到“清除按钮”并将其设置为所需选项(例如始终可见)。

Clear button selection

现在,用户只需点击文本字段右侧的十字架即可清除该字段:

Clear button

或者在您的UI测试中:

    $target_path = '../../../media/ticket_attachments/';

答案 2 :(得分:10)

我找到了以下解决方案:

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

当您点按并按住文本字段时,它会打开菜单,您可以点按"全选"按钮。之后,您只需要使用"删除"删除该文本。键盘上的按钮或只需输入新文本。它将覆盖旧的。

答案 3 :(得分:8)

这适用于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

an apple bug,如果textfield为空,则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)
    }
}

答案 4 :(得分:4)

所以,我还没有找到任何好的解决方案:/

而且我不喜欢与语言环境相关的解决方案,如上所述,使用明确的"明文"查找。

所以,我打字检查,然后尝试在文本字段中找到清除按钮 除非您的自定义文本字段包含多个按钮

,否则它的效果很好

我现在最好的是(我没有包含更多按钮的自定义文本字段):

    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
    }

答案 5 :(得分:1)

对于仍在使用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

答案 6 :(得分:0)

我遇到上述解决方案以解决我遇到的类似问题时遇到了一些困难:光标会在文本之前放置,然后从那里向后工作。另外,我想在删除之前检查文本字段中是否有文本。这是我的解决方案受到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)
    }

答案 7 :(得分:0)

我是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...
}

答案 8 :(得分:0)

执行此操作以在不依赖虚拟键盘的情况下删除文本框中的当前字符串值。

///在此变量中读取文本框的值 让textInTextField:String =

  let characterCount: Int = textInTextField.count
  for _ in 0..<characterCount {
    textFields[0].typeText(XCUIKeyboardKey.delete.rawValue)
  }

此解决方案的优点是,不管模拟器是否具有虚拟键盘,它都可以工作。

答案 9 :(得分:0)

现在在max_statement_time中,您应该尝试以下代码:

swift 4.2

答案 10 :(得分:0)

我使用了@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")

答案 11 :(得分:0)

雨燕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)
    }

}

答案 12 :(得分:0)

我找到了一个使用iOS功能的解决方案,该功能可以通过点按几次来选择整个文本字段。然后,我们通过输入任何字符或按Delete键(如果启用了键盘)来删除文本字段。

let myTextView = app.textViews["some_selector"]
myTextView.tap(withNumberOfTaps: 5, numberOfTouches: 1)
app.typeText("New text you want to enter") 
// or use app.keys["delete"].tap() if you have keyboard enabled

答案 13 :(得分:0)

您可以使用doubleTap选择所有文本,然后键入要替换的新文本:

extension XCUIElement {
  func typeNewText(_ text: String) {
    if let existingText = value as? String, !existingText.isEmpty {
      if existingText != text {
        doubleTap()
      } else {
        return
      }
    }

    typeText(text)
  }
}

用法:

textField.typeNewText("New Text")