Fehler beim Testen der Benutzeroberfläche - Weder ein Element noch ein Nachkomme hat den Tastaturfokus auf SecureTextField


138

Das ist mein Fall:

let passwordSecureTextField = app.secureTextFields["password"]
passwordSecureTextField.tap()
passwordSecureTextField.typeText("wrong_password") //here is an error

Fehler beim Testen der Benutzeroberfläche - Weder ein Element noch ein Nachkomme hat einen Tastaturfokus. Element:

Was ist falsch? Dies funktioniert gut für normal textFields, aber Probleme treten nur bei secureTextFields. Problemumgehungen?



und der seltsame Teil ist, wenn ich es so versuche, funktioniert es XCUIApplication (). webViews.secureTextFields ["Passwort"]. tippen Sie auf () XCUIApplication (). webViews.secureTextFields ["Passwort"]. typeText ("Willkommen")
aurilio

Möglicherweise haben Sie die Eingabehilfen-
ID festgelegt,

Ich habe hier eine Antwort auf eine ähnliche Frage hinzugefügt: stackoverflow.com/a/59637897/2585413 . Mein Problem war, dass ich andere UIWindows mit schlechten .windowLevel-Werten hatte
nteissler

Antworten:


264

Dieses Problem verursachte mir eine Welt voller Schmerzen, aber ich habe es geschafft, eine richtige Lösung zu finden. Stellen Sie im Simulator sicher, dass "Hardware -> Tastatur -> Hardware-Tastatur verbinden" deaktiviert ist.


4
Dies hat das Problem behoben. Die Problemumgehung ist jedoch sehr schlecht, da wir sie nicht automatisch für CI anwenden können.
Stanislav Pankevich

25
Wenn Sie Ihre Tests auf CI (Jenkins usw.) ausführen, können Sie die folgenden Parameter in einem Skript festlegen, bevor Sie Ihre Tests ausführen. "Standardeinstellungen schreiben com.apple.iphonesimulator ConnectHardwareKeyboard 0"
charlyatwork

7
Das löst das Problem für mich nicht. Ich kann deutlich sehen, wie das Textfeld mit der Tastatur nach oben fokussiert wird, aber das Testframework kann niemals Text mit der typeText: -Methode eingeben
Michael

2
Hat bei Xcode 11 für mich funktioniert, aber das Deaktivieren der Option Connect-Hardwaretastatur reicht möglicherweise nicht aus. Man muss außerdem sicherstellen, dass die Softwaretastatur wirklich angezeigt wird (ich hatte tatsächlich die Situation, dass keine Hardwaretastatur angeschlossen war und keine Softwaretastatur angezeigt wurde, selbst wenn das Textfeld fokussiert war und der Cursor blinkte).
Reinhard Männer

1
Ich bin auch auf Xcode 11 darauf gestoßen. Fixes lokal, aber wie kann dies in CI eingestellt werden?
Jherg

26

Kürzlich haben wir einen Hack gefunden, um die Lösung aus akzeptierten Antworten dauerhaft zu machen. Um die Simulatoreinstellung zu deaktivieren: 'Hardware -> Tastatur -> Hardware-Tastatur verbinden' über die Befehlszeile sollte Folgendes geschrieben werden:

defaults write com.apple.iphonesimulator ConnectHardwareKeyboard 0

Ein laufender Simulator ist davon nicht betroffen. Sie müssen den Simulator neu starten oder einen neuen starten, damit sich diese Einstellung auswirkt.


das hat nichts geändert.
Netshark1000

@ netshark1000, die mit der neueren Version von Xcode geändert werden kann, werde ich überprüfen.
AlexDenisov

1
Sehr hilfreich, ich brauchte das Gegenteil, wo die Tastatur immer aktiviert ist, aber ja, das ist großartig, danke. Am Ende habe ich mitgemacht defaults write com.apple.iphonesimulator ConnectHardwareKeyboard -bool true, aber es ist das gleiche Konzept.
Laser Hawk

2
Ich habe dazu ein Skript für Build-Phasen erstellt. Aber ich musste alle Simulatoren töten, also tat ich das:killall "Simulator"; defaults write com.apple.iphonesimulator ConnectHardwareKeyboard 0;
Wagner Sales

Das scheint nicht mehr zu funktionieren, hat sich der Schlüssel geändert? @AlexDenisov
Simon McLoughlin

15

Ich habe eine kleine Erweiterung (Swift) geschrieben, die perfekt für mich funktioniert. Hier ist der Code:

extension XCTestCase {

    func tapElementAndWaitForKeyboardToAppear(element: XCUIElement) {
        let keyboard = XCUIApplication().keyboards.element
        while (true) {
            element.tap()
            if keyboard.exists {
                break;
            }
            NSRunLoop.currentRunLoop().runUntilDate(NSDate(timeIntervalSinceNow: 0.5))
        }
    }
}

Die Hauptidee besteht darin, weiterhin auf ein Element (Textfeld) zu tippen, bevor die Tastatur angezeigt wird.


Das funktioniert momentan bei mir nicht. Ich habe Xcode 7.2 (7C68). Welche Version haben Sie? Diese Lösung, die wir für CI gefunden haben, funktioniert für uns: stackoverflow.com/a/34812979/598057 .
Stanislav Pankevich

Um es noch einmal zu bestätigen: Dieser Helfer funktioniert für Sie für ein sicheres Passwort-Textfeld, nicht nur für ein normales Textfeld?
Stanislav Pankevich

Ja, es funktioniert für beide Arten von Textfeldern: regulär und sicher.
berezhnyi oleksandr

1
Das Problem bei dieser Antwort ist, dass eine fest codierte Verzögerung verwendet wird. Verwenden Sie stattdessen das Modell zum Warten auf Erwartungen mit dem Tastaturelement.
user1122069

11

Stanislav hat die richtige Idee.

In einer Teamumgebung benötigen Sie etwas, das automatisch funktioniert. Ich habe hier in meinem Blog eine Lösung gefunden .

Grundsätzlich fügen Sie einfach ein:

UIPasteboard.generalPasteboard().string = "Their password"
let passwordSecureTextField = app.secureTextFields["password"]
passwordSecureTextField.pressForDuration(1.1)
app.menuItems["Paste"].tap()

Vielen Dank, dass Sie Ihre Lösung geteilt haben. Leider funktioniert es momentan bei mir nicht. Ich habe Xcode 7.2 (7C68), was Sie? Weitere Lösungen, die wir für CI gefunden haben: stackoverflow.com/questions/32184837/… .
Stanislav Pankevich

8

Eine weitere Ursache für diesen Fehler ist eine übergeordnete Ansicht des Textfelds, in das Sie versuchen, Text einzugeben, der als Eingabehilfenelement festgelegt ist ( view.isAccessibilityElement = true). In diesem Fall kann XCTest die Unteransicht nicht handhaben, um den Text einzugeben, und gibt den Fehler zurück.

Fehler beim Testen der Benutzeroberfläche - Weder ein Element noch ein Nachkomme hat einen Tastaturfokus.

Es ist nicht so, dass kein Element den Fokus hat (wie Sie oft sehen können, wie die Tastatur im UITextField nach oben zeigt und der Cursor blinkt), sondern nur, dass kein Element, das es erreichen kann, den Fokus hat. Ich bin darauf gestoßen, als ich versucht habe, Text in eine UISearchBar einzugeben. Die Suchleiste selbst ist nicht das Textfeld. Wenn Sie sie als Eingabehilfenelement festlegen, wurde der Zugriff auf das zugrunde liegende UITextField blockiert. Um dies zu beheben, searchBar.accessibilityIdentifier = "My Identifier"wurde auf gesetzt, UISearchBarjedoch isAccessibilityElementwurde das nicht auf gesetzt true. Danach Testcode des Formulars:

app.otherElements["My Identifier"].tap()
app.otherElements["My Identifier"].typeText("sample text")

Funktioniert


6

Es kam mir viele Male vor. Sie müssen die Tastaturhardware und das gleiche Layout wie OSX in Ihrem Simulator deaktivieren

Hardware / Tastatur (alle deaktivieren)

Danach wird die Tastatursoftware nicht mehr geschlossen und Ihre Tests können Text eingeben

Hardware deaktivieren


5

Verwenden Sie einen Ruhezustand zwischen dem Starten der App und dem Eingeben von Daten in Textfelder wie folgt:

sleep(2)

In meinem Fall bekam ich jedes Mal diesen Fehler und nur diese Lösung half mir.


1
Das Problem ist, wenn Sie eine große Anzahl von UI-Tests haben, die so etwas wie eine anfängliche Anmeldung durchführen, erhöht dies Ihren CI-Testlauf erheblich.
Delta2flat

4

Dies kann vielleicht helfen: Ich füge vor dem Fehler einfach eine "Tap" -Aktion hinzu. das ist alles :)

[app.textFields[@"theTitle"] tap];
[app.textFields[@"theTitle"] typeText:@"kk"];

2
Dies funktioniert definitiv nicht für ein sicheres Passwort-Textfeld.
Stanislav Pankevich

Dies funktionierte für mein Textfeld für sicheres Passwort einwandfrei. Gute Lösung.
Travis M.

4
func pasteTextFieldText(app:XCUIApplication, element:XCUIElement, value:String, clearText:Bool) {
    // Get the password into the pasteboard buffer
    UIPasteboard.generalPasteboard().string = value

    // Bring up the popup menu on the password field
    element.tap()

    if clearText {
        element.buttons["Clear text"].tap()
    }

    element.doubleTap()

    // Tap the Paste button to input the password
    app.menuItems["Paste"].tap()
}

4

Nehmen Sie den Fall auf, wie Sie möchten, Tastatur oder ohne Tastatur. Führen Sie jedoch die folgenden Schritte aus, bevor Sie den Test spielen.

Diese folgende Option (Hardware-Tastatur anschließen) sollte während des Testspiels deaktiviert sein.

Geben Sie hier die Bildbeschreibung ein


4

In meinem Fall hat diese Hardware -> Keyboard -> Connect Hardware Keyboard-> Deaktivierung bei mir nicht funktioniert.

Aber als ich folgte

1) Hardware -> Keyboard -> Connect Hardware Keyboard-> App aktivieren und ausführen
2) Hardware -> Keyboard -> Connect Hardware Keyboard-> Deaktivieren .

Es hat bei mir funktioniert


Arbeitete für mich, MAN Ich hasse diesen Aspekt von XCode!
Bwobbones

3

[Reposting Bartłomiej Semańczyks Kommentar als Antwort, weil er das Problem für mich gelöst hat]

Ich musste Simulator> Inhalt und Einstellungen zurücksetzen in der Simulator-Menüleiste ausführen, damit dies für mich funktioniert.


Das Zurücksetzen des Simulators hat mir auch geholfen. Interessanterweise trat das Problem nur im Simulator auf, während der gleiche Test (Tippen auf Texfield, gefolgt von der Eingabe von Zeichen) auf einem Gerät einwandfrei lief.
Christian

1

Manchmal werden Textfelder nicht als Textfelder implementiert oder in ein anderes UI-Element eingeschlossen und sind nicht leicht zugänglich. Hier ist eine Lösung:

//XCUIApplication().scrollViews.otherElements.staticTexts["Email"] the locator for the element
RegistrationScreenStep1of2.emailTextField.tap()
let keys = app.keys
 keys["p"].tap() //type the keys that you need
 
 //If you stored your data somewhere and need to access that string //you can cats your string to an array and then pass the index //number to key[]
 
 let newUserEmail = Array(newPatient.email())
 let password = Array(newPatient.password)
 
 //When you cast your string to an array the elements of the array //are Character so you would need to cast them into string otherwise //Xcode will compain. 
 
 let keys = app.keys
     keys[String(newUserEmail[0])].tap()
     keys[String(newUserEmail[1])].tap()
     keys[String(newUserEmail[2])].tap()
     keys[String(newUserEmail[3])].tap()
     keys[String(newUserEmail[4])].tap()
     keys[String(newUserEmail[5])].tap()       


0

Ihre erste Zeile ist nur eine Abfragedefinition , was nicht bedeutet, dass passwordSecureTextFielddiese tatsächlich existieren würde.

Ihre zweite Zeile führt die Abfrage dynamisch aus und versucht, die Abfrage (erneut) an das UI-Element zu binden. Sie sollten einen Haltepunkt darauf setzen und sicherstellen, dass nur ein Element gefunden wird. Oder verwenden Sie einfach eine Behauptung:

XCTAssertFalse(passwordSecureTextField.exists);

Ansonsten sieht es ok aus, tapsollte die Tastatur sichtbar machen und dann typeTexteinfach funktionieren. Das Fehlerprotokoll sollte Ihnen weitere Informationen geben.


1
passwordSecureTextFieldexistiert. Ich habe das Problem behoben, aber den Speicher bereinigt und diese Zeilen erneut geschrieben. Seltsam, aber es hat funktioniert.
Bartłomiej Semańczyk

Gut zu hören, dass es behoben ist! Ich bin gestern mit Beta 6 auf ein ähnliches Problem gestoßen :)
JOM

Beta 6? :-) wirklich? Ich habe nur 5 :)
Bartłomiej Semańczyk

Du warst mit dem Programmieren beschäftigt :) Beta 6 hat nicht tapfür mich aufgenommen, es hat einige Zeit gedauert, es herauszufinden. Gute Debug-Praxis!
JOM

Vielleicht kennen Sie die Antwort darauf: stackoverflow.com/questions/32219015/… ?
Bartłomiej Semańczyk

0

Nicht durcheinander bringen. Das Problem ist darauf zurückzuführen, dass Sie Ihre Testzeit aufgezeichnet haben. Ihre App verbindet die Hardwaretastatur, während Ihr automatischer Testzeitsimulator nur die Softwaretastatur verwendet. Also, wie man diese Probleme behebt. Verwenden Sie einfach die Software-Tastatur für Ihre Aufnahmezeit. Sie können die Magie sehen.


0

Das Problem war für mich das gleiche wie für Ted. Wenn das Kennwortfeld nach dem Anmeldefeld getippt wird und die Hardware-KB aktiviert ist, wird sich die Softwaretastatur beim zweiten Tippen auf das Feld selbst schließen und ist nicht spezifisch für UI-Tests.

Nach einiger Zeit mit AppleScript habe ich mir Folgendes ausgedacht (Verbesserungen sind willkommen):

tell application "Simulator" activate tell application "System Events" try tell process "Simulator" tell menu bar 1 tell menu bar item "Hardware" tell menu "Hardware" tell menu item "Keyboard" tell menu "Keyboard" set menuItem to menu item "Connect Hardware Keyboard" tell menu item "Connect Hardware Keyboard" set checkboxStatus to value of attribute "AXMenuItemMarkChar" of menuItem if checkboxStatus is equal to "✓" then click end if end tell end tell end tell end tell end tell end tell end tell on error tell application "System Preferences" activate set securityPane to pane id "com.apple.preference.security" tell securityPane to reveal anchor "Privacy_Accessibility" display dialog "Xcode needs Universal access to disable hardware keyboard during tests(otherwise tests may fail because of focus issues)" end tell end try end tell end tell

Erstellen Sie eine Skriptdatei mit dem obigen Code und fügen Sie sie den erforderlichen Zielen hinzu (wahrscheinlich nur UI-Testziele. Möglicherweise möchten Sie Ihren Entwicklungszielen ein ähnliches Skript hinzufügen, um die HW-Tastatur während der Entwicklung wieder zu aktivieren). Sie sollten Run ScriptPhase in Build-Phasen hinzufügen und wie folgt verwenden: osascript Path/To/Script/script_name.applescript


0

Beim Festlegen des accessibilityIdentifierWerts für eine benutzerdefinierte Ansicht ( UIStackViewUnterklasse) mit UIControlUnteransichten ist der gleiche Fehler aufgetreten. In diesem Fall konnte XCTest den Tastaturfokus für die untergeordneten Elemente nicht ermitteln.

Unsere Lösung bestand einfach darin, das accessibilityIdentifieraus unserer übergeordneten Ansicht zu entfernen und das accessibilityIdentifierfür die Unteransichten über dedizierte Eigenschaften festzulegen.


0

Eine andere Antwort, aber für uns war das Problem, dass die Ansicht einer anderen Ansicht zu nahe kam, als dass ein Gestenerkenner darauf. Wir haben festgestellt, dass die Ansicht mindestens 20 Pixel entfernt sein muss (in unserem Fall unten). Im wahrsten Sinne des Wortes haben 15 nicht funktioniert und 20 oder mehr. Ich gebe zu, dass dies seltsam ist, aber wir hatten einige UITextViews, die funktionierten, und einige, die nicht funktionierten und alle unter derselben übergeordneten und identischen anderen Positionierung waren (und natürlich Variablennamen). Das Ein- und Ausschalten der Tastatur oder was auch immer machte keinen Unterschied. Zugänglichkeit zeigte die Felder. Wir haben unsere Computer neu gestartet. Wir haben sauber gebaut. Frische Quellenkassen.


0

Was dieses Problem für mich behoben hat, war das Hinzufügen eines Schlafes von 1 Sekunde:

let textField = app.textFields["identifier"]
textField.tap()
sleep(1)
textField.typeText(text)

0

Ich bin auf dieses Problem gestoßen und konnte es in meinem Szenario beheben, indem ich die von @AlexDenisov veröffentlichte Lösung nahm und sie zu meinen Voraktionen für run & test hinzufügte .

Geben Sie hier die Bildbeschreibung ein


0

Keine Notwendigkeit, die Tastatur in der E / A ein- oder auszuschalten. Verwenden Sie .typeText nicht für SecureTextField, sondern nur

app.keys["p"].tap()
app.keys["a"].tap()
app.keys["s"].tap()
app.keys["s"].tap()

Bonus: Sie erhalten einen Klick auf die Tastatur :)


0

Schließlich habe ich ein Skript geschrieben, das die .plist-Datei des Simulators bearbeitet und die ConnectHardwareKeyboardEigenschaft für den ausgewählten Simulator auf false setzt . Sie haben es richtig gehört, es ändert die Eigenschaft für den speziell ausgewählten Simulator im Wörterbuch "DevicePreferences", anstatt die globale Eigenschaft zu bearbeiten.

Erstellen Sie zunächst ein Shell-Skript mit dem Namen disable-hardware-keyboard.sh mit den folgenden Inhalten. Sie können es in "YourProject / xyzUITests / Scripts /" platzieren:

echo "Script: Set ConnectHardwareKeyboard to false for given Simulator UDID"

if [[ $1 != *-*-*-*-* ]]; then
    echo "Pass device udid as first argument."
    exit 1
else
    DEVICE_ID=$1
fi

DEVICE_PREFERENCES_VALUE='<dict><key>ConnectHardwareKeyboard</key><false/></dict>'
killall Simulator # kill restart the simulator to make the plist changes picked up
defaults write com.apple.iphonesimulator DevicePreferences -dict-add $DEVICE_ID $DEVICE_PREFERENCES_VALUE
open -a Simulator # IMPORTANT

Führen Sie nun die folgenden Schritte aus, um das udid des ausgewählten Simulators als Argument zu übergeben:

  1. Bearbeiten Sie Ihr Xcode-Schema (oder die Benutzeroberfläche testet ein bestimmtes Schema, falls Sie eines haben).
  2. Gehen Sie zu: Test> Voraktionen
  3. Fügen Sie ein neues Skript hinzu, indem Sie auf das Symbol "+"> "Neue Aktion" Skript ausführen "tippen.
  4. Wichtig: Wählen Sie in der Dropdown-Liste "Build-Einstellungen bereitstellen von" Ihr Haupt-App-Ziel aus, nicht das UI-Testziel.
  5. Fügen Sie nun das folgende Skript in den Textbereich unten ein.

Skript in Test> Voraktionen:

#!/bin/sh
# $PROJECT_DIR is path to your source project. This is provided when we select "Provide build settings from" to "AppTarget"
# $TARGET_DEVICE_IDENTIFIER is the UDID of the selected simulator
sh $PROJECT_DIR/xyzUITests/Scripts/disable-hardware-keyboard.sh $TARGET_DEVICE_IDENTIFIER

# In order to see output of above script, append following with it:
#  | tee ~/Desktop/ui-test-scheme-prescript.txt

Zeit, es zu testen:

  1. Starten Sie den Simulator
  2. Aktivieren Sie die Hardwaretastatur dafür
  3. Führen Sie einen beliebigen UI-Test mit Tastaturinteraktion aus. Beachten Sie, dass der Simulator neu gestartet wird und die Hardwaretastatur deaktiviert ist. Und die Tastaturinteraktion des Tests funktioniert einwandfrei. :) :)

-1

Hatte das gleiche Problem mit Securetextfields. Die Verbindungshardwareoption in meinem Simulator war von, stieß aber immer noch auf das Problem. Schließlich funktionierte dies für mich (Swift 3):

 let enterPasswordSecureTextField = app.secureTextFields["Enter Password"]
    enterPasswordSecureTextField.tap()
    enterPasswordSecureTextField.typeText("12345678")

Was ist der Unterschied zwischen Ihrem Code und dem in der Frage gestellten Code?
Shivam Pokhriyal
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.