IT

UI 테스트 텍스트 필드의 텍스트 삭제

itgroup 2023. 10. 25. 23:14
반응형

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 테스트와 잘 맞지 않습니다.어떻게 하면 이것이 더 보편적으로 해결될 수 있을까요?

이 작업을 위해 확장 방법을 작성했는데 꽤 빠릅니다.

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

그런 다음 이 기능을 쉽게 사용할 수 있습니다.app.textFields["Email"].clearAndEnterText("newemail@domain.example")

텍스트 필드 및 텍스트 보기에 적합합니다.

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

업데이트 XCODE 9

텍스트 필드가 비어 있으면 값과 자리 표시자 값이 같은 애플 버그가 있습니다.

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

질문에 대한 설명에서 지역화된 삭제 키 이름 문제를 수정했으므로 "삭제"라고 부르는 것만으로 삭제 키에 액세스할 수 있다고 가정합니다.

아래 코드를 사용하면 필드의 내용을 확실하게 삭제할 수 있습니다.

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

또는 Swift 4+:

while !(textView.value as! String).isEmpty {
    app.keys["Delete"].tap()
}

하지만 동시에, 당신의 문제는 당신의 앱의 사용성을 향상시키기 위해 이 문제를 더 부드럽게 해결해야 할 필요성을 나타낼 수 있습니다.텍스트 필드에 추가할 수도 있습니다.Clear button사용자가 텍스트 필드를 즉시 비울 수 있는.

스토리보드를 열고 특성 검사자에서 "지우기 단추"를 찾은 후 원하는 옵션(예: 항상 표시됨)으로 설정한 텍스트 필드를 선택합니다.

Clear button selection

이제 사용자는 텍스트 필드 오른쪽에 있는 십자가를 간단히 눌러 필드를 지울 수 있습니다.

Clear button

또는 UI 테스트에서:

textField.buttons["Clear text"].tap()

다음과 같은 해결책을 찾았습니다.

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

텍스트 필드를 길게 누르면 "모두 선택" 버튼을 누를 수 있는 메뉴가 열립니다.그런 다음 키보드의 "삭제" 버튼으로 해당 텍스트를 제거하거나 새 텍스트를 입력하기만 하면 됩니다.이전 것을 덮어씁니다.

Xcode 9, 스위프트 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")

사용가능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")

그래서 아직 좋은 해결책을 찾지 못했습니다 :/

그리고 위와 같은 명시적인 "클리어 텍스트" 검색과 같은 로케일 의존 솔루션은 좋아하지 않습니다.

그래서 입력 확인을 한 다음 텍스트 필드에서 단추를 지우려고 합니다. 단추가 둘 이상인 사용자 지정 텍스트 필드가 없는 한 잘 작동합니다.

이제 가장 좋은 방법은 (더 많은 단추가 있는 사용자 지정 텍스트 필드가 없습니다)입니다.

    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
    }

텍스트 필드 전체를 여러 번 두드려 선택하는 iOS 기능을 사용하는 솔루션을 찾았습니다.그런 다음 문자를 입력하거나 삭제를 눌러 텍스트 필드를 삭제합니다(키보드가 활성화된 경우).

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

길이상 텍스트 뷰에 부분적으로 가려질 수 있는 텍스트를 안정적으로 사용할 수 있는 유일한 솔루션입니다.iOS 16과 Xcode 14에서 테스트를 받았습니다.

extension XCUIElement {
    /// Removes any current text in the field before typing in the new value and submitting
    /// Based on: https://stackoverflow.com/a/32894080
    func clear() {
        if self.value as? String == nil {
            XCTFail("Tried to clear and enter text into a non string value")
            return
        }

        // Repeatedly delete text as long as there is something in the text field.
        // This is required to clear text that does not fit in to the textfield and is partially hidden initally.
        // Important to check for placeholder value, otherwise it gets into an infinite loop.
        while let stringValue = self.value as? String, !stringValue.isEmpty, stringValue != self.placeholderValue {
            // Move the cursor to the end of the text field
            let lowerRightCorner = self.coordinate(withNormalizedOffset: CGVector(dx: 0.9, dy: 0.9))
            lowerRightCorner.tap()
            let delete = String(repeating: XCUIKeyboardKey.delete.rawValue, count: stringValue.count)
            self.typeText(delete)
        }
    }

    func clearAndEnterText(text: String) {
        self.clear()
        // new line at end submits
        self.typeText("\(text)\n")
    }
}

가상 키보드에 의존하지 않고 텍스트 상자의 현재 문자열 값을 삭제하려면 이 작업을 수행합니다.

//이 변수 let textIn에서 텍스트 상자 값 읽기텍스트 필드:문자열 =

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

이 솔루션의 좋은 점은 시뮬레이터에 가상 키보드가 있든 없든 상관없이 작동한다는 것입니다.

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

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

저는 제가 겪고 있는 비슷한 문제에 대해 위의 솔루션을 사용하는 데 약간 어려움을 겪었습니다.커서가 텍스트 앞에 놓이고 그 다음부터는 거꾸로 작동합니다.또한 삭제하기 전에 텍스트 필드에 텍스트가 있는지 확인하고 싶었습니다.다음은 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)
    }

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

@oliverfrost님이 설명해주신 내용을 사용했는데 아이폰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")

스위프트 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)
    }

}

이것은 아고스트 비로의 대답에 근거한 나의 해결책입니다.maxAttempts 매개 변수를 추가하여 테스트가 여러 번 시도했지만 클리어되지 않은 경우 무한 루프 대신 테스트가 실패합니다. (새로운 iOS 버전과 같이 무언가를 적용하는 것이 잘못되었거나 클리어 로직을 업데이트해야 합니다.어떤 이유로 많은 삭제가 필요한 특정 텍스트 필드가 있는 경우.그러면 maxAttempts 파라미터를 늘릴 수 있습니다.

extension XCUIElement {
    func clearValue(maxAttempts: Int = 3) {
        for attempt in 0...maxAttempts {
            if attempt == maxAttempts {
                XCTFail("Couldn't clear value of element: \(self)")
                break // In case XCTestCase.continueAfterFailure == true
            }
            // If the text field is empty, then value returns the placeholderValue. So if they are equal then it can be considered cleared.
            if let value = value as? String, !value.isEmpty && value != placeholderValue {
                // Move the cursor to the end of the text field
                let lowerRightCorner = coordinate(withNormalizedOffset: CGVector(dx: 0.9, dy: 0.8))
                lowerRightCorner.tap()
                typeText(NSString().padding(toLength: value.count, withPad: XCUIKeyboardKey.delete.rawValue, startingAt: 0))
            } else {
                break
            }
        }
    }
}

원래 질문에서 이것이 "약해지기 쉬운" 것으로 표시되었다는 것을 알고 있지만, 요즘에는 이것이 가장 쉬운 해결책인 것 같습니다.

myTextView.press(forDuration: 1.2)
app.menuItems["Select All"].tap()
app.menuItems["Cut"].tap()

언급URL : https://stackoverflow.com/questions/32821880/ui-test-deleting-text-in-text-field

반응형