私のテストでは、既存のテキストを含むテキストフィールドがあります。コンテンツを削除して、新しい文字列を入力します。
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 = stringValue.characters.map { _ in XCUIKeyboardKeyDelete }.joined(separator: "")
self.typeText(deleteString)
self.typeText(text)
}
}
これは非常に簡単に使用できます:app.textFields["Email"].clearAndEnterText("[email protected]")
質問のコメントでローカライズされた削除キー名の問題を修正したので、「削除」と呼ぶだけで削除キーにアクセスできると仮定します。
以下のコードを使用すると、フィールドのコンテンツを確実に削除できます。
while (textField.value as! String).characters.count > 0 {
app.keys["Delete"].tap()
}
しかし同時に、あなたの問題は、これをよりエレガントに解決してアプリの使いやすさを改善する必要性を示しているかもしれません。テキストフィールドには、ユーザーがテキストフィールドをすぐに空にできる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
テキストフィールドをタップアンドホールドすると、[すべて選択]ボタンをタップできるメニューが開きます。あとは、キーボードの「削除」ボタンでテキストを削除するか、新しいテキストを入力するだけです。古いものは上書きされます。
これは、テキストフィールドとテキストビューで動作します
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)
}
}
だから、私は良いソリューションをまだ見つけていませんでした:/
また、明示的な「クリアテキスト」ルックアップを使用した上記のような、ロケールに依存するソリューションは好きではありません。
だから、私はタイプチェックを行い、テキストフィールドでクリアボタンを見つけようとします複数のボタンを持つカスタムテキストフィールドがない限りうまく機能します
私の今のベストは(私はボタンが追加されたカスタムテキストフィールドがない):
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
}
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")
まだ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
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)
}
}
私が抱えていた同様の問題に対して、上記のソリューションを動作させるのに多少の困難がありました。カーソルはテキストの前に置かれ、そこから逆方向に動作します。さらに、削除する前に、テキストフィールドにテキストが含まれていることを確認したかったのです。拡張機能 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)
}
@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")
これを行うと、仮想キーボードに依存せずにテキストボックス内の現在の文字列値が削除されます。
//この変数のテキストボックスの値を読み取りますlet textInTextField:String =
let characterCount: Int = textInTextField.count
for _ in 0..<characterCount {
textFields[0].typeText(XCUIKeyboardKey.delete.rawValue)
}
このソリューションの良い点は、シミュレータが仮想キーボードを持っているかどうかに関係なく機能することです。
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...
}