web-dev-qa-db-ja.com

テキストフィールドのテキストを削除するUIテスト

私のテストでは、既存のテキストを含むテキストフィールドがあります。コンテンツを削除して、新しい文字列を入力します。

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テストではうまく機能しません。これをどのように解決してより普遍的にすることができますか?

60
Tomasz Bąk

これを行うための拡張メソッドを作成しましたが、非常に高速です。

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]")

130
Bay Phillips

質問のコメントでローカライズされた削除キー名の問題を修正したので、「削除」と呼ぶだけで削除キーにアクセスできると仮定します。

以下のコードを使用すると、フィールドのコンテンツを確実に削除できます。

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

しかし同時に、あなたの問題は、これをよりエレガントに解決してアプリの使いやすさを改善する必要性を示しているかもしれません。テキストフィールドには、ユーザーがテキストフィールドをすぐに空にできるClear buttonを追加することもできます。

ストーリーボードを開き、テキストフィールドを選択し、属性インスペクターの下で[クリアボタン]を見つけて、目的のオプションに設定します(常に表示されます)。

Clear button selection

ユーザーは、テキストフィールドの右側にある十字をタップするだけでフィールドをクリアできます。

Clear button

または、UIテストで:

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

私は次の解決策を見つけました:

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

テキストフィールドをタップアンドホールドすると、[すべて選択]ボタンをタップできるメニューが開きます。あとは、キーボードの「削除」ボタンでテキストを削除するか、新しいテキストを入力するだけです。古いものは上書きされます。

11
oliverfrost

これは、テキストフィールドとテキストビューで動作します

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

forSwift 4toSwift 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 があります。テキストフィールドが空の場合、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)
    }
}
9
Ted

だから、私は良いソリューションをまだ見つけていませんでした:/

また、明示的な「クリアテキスト」ルックアップを使用した上記のような、ロケールに依存するソリューションは好きではありません。

だから、私はタイプチェックを行い、テキストフィールドでクリアボタンを見つけようとします複数のボタンを持つカスタムテキストフィールドがない限りうまく機能します

私の今のベストは(私はボタンが追加されたカスタムテキストフィールドがない):

    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

上記の解決策を試してみましたが、タップの奇妙な動作のために機能しませんでした-テキストフィールドの先頭またはテキストのランダムなポイントにカーソルを移動しました。私が使用したアプローチは、@ oliverfrostが here で説明したものですが、問題を回避し、それをきちんとした拡張機能に結合するためにいくつかのタッチを追加しました。それが誰かに役立つことを願っています。

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

まだ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

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

私が抱えていた同様の問題に対して、上記のソリューションを動作させるのに多少の困難がありました。カーソルはテキストの前に置かれ、そこから逆方向に動作します。さらに、削除する前に、テキストフィールドにテキストが含まれていることを確認したかったのです。拡張機能 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)
    }
0
Phillip English

@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")
0

これを行うと、仮想キーボードに依存せずにテキストボックス内の現在の文字列値が削除されます。

//この変数のテキストボックスの値を読み取りますlet textInTextField:String =

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

このソリューションの良い点は、シミュレータが仮想キーボードを持っているかどうかに関係なく機能することです。

0
Dilip Agheda

IOSでのUIテストは初めてですが、この簡単な回避策でテキストフィールドをクリアすることができました。 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...
}
0