web-dev-qa-db-fra.com

Test de l'interface utilisateur supprimant du texte dans un champ de texte

Dans mon test, j'ai un champ de texte avec un texte préexistant. Je veux supprimer le contenu et taper une nouvelle chaîne.

let textField = app.textFields
textField.tap()
// delete "Old value"
textField.typeText("New value")

Lors de la suppression d'une chaîne avec un clavier matériel L'enregistrement n'a généré rien pour moi. Après avoir fait la même chose avec le clavier logiciel, j'ai obtenu:

let key = app.keys["Usuń"] // Polish name for the key
key.tap()
key.tap() 
... // x times

ou

app.keys["Usuń"].pressForDuration(1.5)

Je craignais que mon test dépende de la langue. J'ai donc créé quelque chose comme ceci pour les langues prises en charge:

extension XCUIElementQuery {
    var deleteKey: XCUIElement {
        get {
            // Polish name for the key
            if self["Usuń"].exists {
                return self["Usuń"]
            } else {
                return self["Delete"]
            }
        }
    }
}

C'est plus joli en code:

app.keys.deleteKey.pressForDuration(1.5)

mais c'est très fragile. Après avoir quitté Simulator, Toggle software keyboard a été réinitialisé et le test a échoué. Ma solution ne fonctionne pas bien avec le test de CI. Comment cela peut-il être résolu pour être plus universel?

50
Tomasz Bąk

J'ai écrit une méthode d'extension pour le faire pour moi et c'est assez rapide:

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

Ceci est alors utilisé assez facilement: app.textFields["Email"].clearAndEnterText("[email protected]")

121
Bay Phillips

Puisque vous avez résolu le problème de votre nom de clé de suppression localisée dans les commentaires de vos questions, je suppose que vous pouvez accéder à la clé de suppression en l'appelant simplement "Supprimer".

Le code ci-dessous vous permettra de supprimer de manière fiable le contenu de votre champ:

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

Mais en même temps, votre problème pourrait indiquer la nécessité de résoudre ce problème de manière plus élégante pour améliorer la convivialité de votre application. Sur le champ de texte, vous pouvez également ajouter un Clear button avec lequel un utilisateur peut immédiatement vider le champ de texte;

Ouvrez le storyboard et sélectionnez le champ de texte. Sous l'inspecteur d'attributs, recherchez "Bouton Effacer" et réglez-le sur l'option souhaitée (par exemple, il est toujours visible).

 Clear button selection

Maintenant, les utilisateurs peuvent effacer le champ d'un simple tapotement sur la croix à droite du champ de texte:

 Clear button

Ou dans votre test d'interface utilisateur:

textField.buttons["Clear text"].tap()
18
Martijn Hols

J'ai trouvé la solution suivante:

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

Lorsque vous maintenez le doigt appuyé sur le champ de texte, il ouvre un menu dans lequel vous pouvez appuyer sur le bouton "Tout sélectionner". Après cela, tout ce dont vous avez besoin est de supprimer ce texte avec le bouton "Supprimer" du clavier ou tout simplement d'entrer un nouveau texte. Cela écrasera l'ancien.

10
oliverfrost

cela fonctionnera pour textfield et textview

pour 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)
    }
}

pour 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)
    }
}

UPDATE XCODE 9

Il y a un bogue Apple où si le champ de texte est vide, value et placeholderValue sont égaux

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)
    }
}
7
Ted

Donc, je n'ai pas encore trouvé bien solution: /

Et je n'aime pas les solutions dépendantes de la localisation, comme ci-dessus avec une recherche explicite "Clear text".

Donc, je tape check, puis j'essaie de trouver un bouton vide dans le champ de texte Cela fonctionne bien, sauf si vous avez un champ de texte personnalisé avec plus d'un bouton

Mon meilleur maintenant est (je n'ai pas de champs de texte personnalisés avec plus de boutons):

    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
    }
4
Oleg Shanyuk

Xcode 9, Swift 4

J'ai essayé les solutions ci-dessus, mais aucune n'a fonctionné en raison d'un comportement étrange au toucher: le curseur a été déplacé au début du champ de texte ou à un point quelconque du texte. L’approche que j’ai utilisée correspond à celle décrite par @oliverfrost ici , mais j’ai ajouté quelques contacts pour contourner les problèmes et les combiner dans une extension ordonnée. J'espère que cela peut être utile pour quelqu'un. 

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")
3
zysoft

Pour ceux qui utilisent encore 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
1
Skander Fathallah

Maintenant, dans Swift 4.2, vous devriez peut-être essayer le code suivant:

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)
    }
}
0
Alfredo Luco G

J'ai eu quelques difficultés à faire en sorte que les solutions ci-dessus répondent à un problème similaire: le curseur se place avant le texte, puis à l'envers. De plus, je voulais vérifier que le champ de texte contenait du texte avant de le supprimer. Voici ma solution inspirée de l'extension https://stackoverflow.com/users/482361/bay-phillips wrote. Je devrais noter que le fait d'appuyer sur la touche Suppr peut prendre un certain temps et qu'il peut être remplacé par .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)
    }
0
Phillip English

J'ai utilisé ce que @oliverfrost a décrit mais cela ne fonctionnait pas sur IPhone XR, je l'ai légèrement modifié pour mon usage

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

et comme @zysoft l'a dit, vous pouvez l'utiliser comme:

let app = XCUIApplication()
//Just clear text
app.textFields["field1"].clearText() 
//Replace text    
app.secureTextFields["field2"].clearText(andReplaceWith: "Some Other Text")
0
Hamid Shahsavari

Faites ceci pour supprimer la valeur de chaîne actuelle dans une zone de texte sans utiliser le clavier virtuel.

// lit la valeur de votre zone de texte dans cette variable let textInTextField: String = 

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

le bon côté de cette solution est qu’elle fonctionne, que le simulateur dispose d’un clavier virtuel ou non.

0
Dilip Agheda

Je suis nouveau dans les tests d'interface utilisateur avec iOS, mais j'ai pu effacer les champs de texte avec cette solution de contournement simple. Travailler avec Xcode8 et planifier le refactoring très bientôt:

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...
}
0
Jonathan Sweeney