Niepowodzenie testowania interfejsu użytkownika - żaden element ani żaden element podrzędny nie ma fokusu klawiatury na secureTextField

139

To jest moja sprawa:

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

Niepowodzenie testowania interfejsu użytkownika - ani element, ani element podrzędny nie mają fokusu na klawiaturze. Element:

Co jest nie tak? Działa to normalnie textFields, ale problem pojawia się tylko w przypadku secureTextFields. Jakieś obejścia?

Bartłomiej Semańczyk
źródło
a dziwne jest to, że jeśli spróbuję w ten sposób, działa XCUIApplication (). webViews.secureTextFields ["Hasło"]. tap () XCUIApplication (). webViews.secureTextFields ["Hasło"]. typeText ("Witamy")
aurilio
Może się zdarzyć, że ustawiłeś identyfikator dostępności, ale nie ustawiłeś isAccessibilityElement = true
soumil
Tutaj dodałem odpowiedź na podobne pytanie: stackoverflow.com/a/59637897/2585413 . Mój problem polegał na tym, że miałem inne UIWindows ze złymi wartościami
.windowLevel

Odpowiedzi:

264

Ten problem sprawił mi wiele bólu, ale udało mi się znaleźć właściwe rozwiązanie. W symulatorze upewnij się, że opcja „Sprzęt -> Klawiatura -> Podłącz klawiaturę sprzętową” jest wyłączona.

Ted Kaminski
źródło
4
To rozwiązało problem. Ale jest to bardzo słabe obejście, ponieważ nie możemy go automatycznie zastosować do CI.
Stanislav Pankevich
25
Jeśli uruchamiasz testy na CI (Jenkins itp.) Możesz ustawić następujące parametry w skrypcie przed uruchomieniem testów. „defaults write com.apple.iphonesimulator ConnectHardwareKeyboard 0”
charlyatwork
7
To nie rozwiązuje problemu. Wyraźnie widzę, że pole tekstowe uzyskuje fokus, przy podniesionej klawiaturze, ale platforma testowa nigdy nie może wprowadzić tekstu przy użyciu metody typeText:
Michael
2
Pracowałem dla mnie na Xcode 11, ale odznaczenie opcji Połącz klawiaturę sprzętową może nie wystarczyć. Należy dodatkowo upewnić się, że klawiatura programowa jest naprawdę pokazana (miałem właściwie sytuację, w której nie podłączono klawiatury sprzętowej i nie pokazano klawiatury programowej, nawet jeśli textField miał fokus, a kursor migał).
Reinhard Männer
1
Natknąłem się na to również na Xcode 11. Naprawia lokalnie, ale jak można to ustawić w CI?
jherg
26

Niedawno znaleźliśmy sposób, aby utrwalić rozwiązanie z zaakceptowanej odpowiedzi. Aby wyłączyć ustawienie symulatora: „Sprzęt -> Klawiatura -> Podłącz klawiaturę sprzętową” z linii poleceń należy wpisać:

defaults write com.apple.iphonesimulator ConnectHardwareKeyboard 0

Nie wpłynie to na uruchomiony symulator - musisz zrestartować symulator lub uruchomić nowy, aby to ustawienie odniosło skutek.

AlexDenisov
źródło
to niczego nie zmieniło.
netshark1000
@ netshark1000, który można zmienić w nowszej wersji Xcode, sprawdzę to.
AlexDenisov
1
niezwykle pomocne, potrzebowałem czegoś przeciwnego, w którym klawiatura jest zawsze włączona, ale tak, to jest świetne, dzięki. Skończyło się na tym defaults write com.apple.iphonesimulator ConnectHardwareKeyboard -bool true, że to ta sama koncepcja.
Laser Hawk
2
Stworzyłem skrypt na etapach kompilacji, aby to zrobić. Ale musiałem zabić wszystkie symulatory, więc zrobiłem to:killall "Simulator"; defaults write com.apple.iphonesimulator ConnectHardwareKeyboard 0;
Sprzedaż Wagnera
To już nie działa, czy klucz się zmienił? @AlexDenisov
Simon McLoughlin
15

Napisałem małe rozszerzenie (Swift), które działa idealnie dla mnie. Oto kod:

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

Główną ideą jest ciągłe dotykanie elementu (pola tekstowego) przed wyświetleniem klawiatury.

berezhnyi oleksandr
źródło
To teraz nie działa dla mnie. Mam Xcode 7.2 (7C68), jaką masz wersję? To rozwiązanie, które znaleźliśmy dla CI, działa dla nas: stackoverflow.com/a/34812979/598057 .
Stanislav Pankevich
Aby potwierdzić to jeszcze raz: ten pomocnik pracuje dla Ciebie w bezpiecznym polu tekstowym hasła, a nie tylko zwykłym polu tekstowym?
Stanislav Pankevich
Tak, działa dla obu typów pól tekstowych: zwykłego i bezpiecznego.
bereżnyj oleksandr
1
Problem z tą odpowiedzią polega na tym, że używa ona opóźnienia zakodowanego na stałe. Zamiast tego użyj modelu oczekiwania na oczekiwania z elementem klawiatury.
user1122069
11

Stanislav ma dobry pomysł.

W środowisku zespołowym potrzebujesz czegoś, co zadziała automatycznie. Tutaj, na moim blogu, znalazłem poprawkę .

Zasadniczo wystarczy wkleić:

UIPasteboard.generalPasteboard().string = "Their password"
let passwordSecureTextField = app.secureTextFields["password"]
passwordSecureTextField.pressForDuration(1.1)
app.menuItems["Paste"].tap()
RyanPliske
źródło
Dziękujemy za udostępnienie rozwiązania. Niestety teraz nie działa dla mnie. Mam Xcode 7.2 (7C68), co ty? Zobacz inne rozwiązanie, które znaleźliśmy dla CI: stackoverflow.com/questions/32184837/… .
Stanislav Pankevich
8

Inną przyczyną tego błędu jest występowanie nadrzędnego widoku pola tekstowego, w którym próbujesz wprowadzić tekst, który jest ustawiony jako element ułatwień dostępu ( view.isAccessibilityElement = true). W takim przypadku XCTest nie jest w stanie uzyskać uchwytu widoku podrzędnego, aby wprowadzić tekst i zwraca błąd.

Niepowodzenie testowania interfejsu użytkownika - ani element, ani element podrzędny nie mają fokusu na klawiaturze.

Nie chodzi o to, że żaden element nie ma fokusu (jak często można zobaczyć podniesioną klawiaturę i migający kursor w UITextField), po prostu żaden element, do którego może dotrzeć, nie ma fokusu. Natknąłem się na to, próbując wprowadzić tekst w UISearchBar. Sam pasek wyszukiwania nie jest polem tekstowym, podczas ustawiania go jako elementu dostępności, dostęp do bazowego UITextField został zablokowany. Aby rozwiązać ten problem, searchBar.accessibilityIdentifier = "My Identifier"ustawiono, UISearchBarale isAccessibilityElementnie ustawiono true. Następnie przetestuj kod formularza:

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

Pracuje

user3847320
źródło
6

Zdarzyło mi się to wiele razy. Musisz wyłączyć sprzęt klawiatury i taki sam układ jak OSX w swoim symulatorze

Sprzęt / klawiatura (wyłącz wszystkie)

Po tym oprogramowanie klawiatury nie zostanie odrzucone, a testy będą mogły wpisywać tekst

Wyłącz sprzęt

Fernando Martínez
źródło
5

Użyj trybu uśpienia między uruchomieniem aplikacji a wpisywaniem danych w polach tekstowych, takich jak to:

sleep(2)

W moim przypadku za każdym razem otrzymywałem ten błąd i tylko to rozwiązanie pomogło mi.

Kingalione
źródło
1
Problem polega na tym, że jeśli masz dużą liczbę testów interfejsu użytkownika, które wykonują coś w rodzaju pierwszego logowania, spowoduje to ogromne obciążenie dla przebiegu testu CI.
delta2flat
4

To może pomóc: po prostu dodaję akcję „stuknij” przed błędem; to wszystko :)

[app.textFields[@"theTitle"] tap];
[app.textFields[@"theTitle"] typeText:@"kk"];
Carlos Peralta
źródło
2
To zdecydowanie nie działa w przypadku bezpiecznego pola tekstowego hasła.
Stanislav Pankevich
To działało w przypadku mojego bezpiecznego pola tekstowego hasła. Dobre rozwiązanie.
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()
}
Anthony
źródło
4

Nagrywaj obudowę, jak chcesz, klawiatura lub bez podłączonej klawiatury. Ale przed rozpoczęciem testu wykonaj następujące czynności.

Ta następująca opcja (podłącz klawiaturę sprzętową) powinna być odznaczona podczas odtwarzania testu.

wprowadź opis obrazu tutaj

umairhhhs
źródło
4

W moim przypadku to Hardware -> Keyboard -> Connect Hardware Keyboard-> Disable nie działało dla mnie.

Ale kiedy poszedłem za nim

1) Hardware -> Keyboard -> Connect Hardware Keyboard-> Włączone i uruchom aplikację
2) Hardware -> Keyboard -> Connect Hardware Keyboard-> Wyłącz .

U mnie to zadziałało

BharathRao
źródło
Pracował dla mnie, MAN Nienawidzę tego aspektu XCode!
bwobbones
3

[Ponowne zamieszczenie komentarza Bartłomieja Semańczyka jako odpowiedzi, ponieważ rozwiązało to za mnie problem]

Musiałem zrobić Symulator> Resetuj zawartość i ustawienia na pasku menu symulatora, aby to zaczęło działać dla mnie.

rogueleaderr
źródło
Zresetowanie symulatora też mi pomogło. Co ciekawe, problem wystąpił tylko w symulatorze, podczas gdy ten sam test (dotknięcie pola tekstowego, a następnie wpisanie znaków) działał dobrze na urządzeniu.
Christian
1

Czasami pola tekstowe nie są implementowane jako pola tekstowe lub są opakowane w inny element interfejsu użytkownika i nie są łatwo dostępne. Oto obejście:

//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()       

Eugene Berezin
źródło
0

Twoja pierwsza linia to tylko definicja zapytania , co nie oznacza, passwordSecureTextFieldże faktycznie istniałaby.

Twoja druga linia dynamicznie wykona zapytanie i spróbuje (ponownie) powiązać zapytanie z elementem UI. Powinieneś umieścić na nim punkt przerwania i sprawdzić, czy został znaleziony jeden i tylko jeden element. Lub po prostu użyj potwierdzenia:

XCTAssertFalse(passwordSecureTextField.exists);

W przeciwnym razie wygląda dobrze, tappowinno wymusić widoczność klawiatury, a następnie typeTextpowinno działać. Dziennik błędów powinien zawierać więcej informacji.

JOM
źródło
1
passwordSecureTextFieldistnieje. Naprawiłem problem, ale wyczyściłem pamięć i przepisałem te linie ponownie. Dziwne, ale zadziałało.
Bartłomiej Semańczyk 26.08.15
Dobrze słyszeć, że to naprawione! Wczoraj napotkałem podobny problem z wersją beta 6 :)
JOM
beta 6? :-) naprawdę? Mam tylko 5 :)
Bartłomiej Semańczyk 26.08.15
Byłeś zajęty kodowaniem :) Beta 6 nie nagrywała tapdla mnie, zajęło trochę czasu, zanim to rozgryzłem. Dobra praktyka debugowania!
JOM
Może znasz odpowiedź na to pytanie: stackoverflow.com/questions/32219015/… ?
Bartłomiej Semańczyk 26.08.15
0

Nie zawracaj sobie głowy, wykryto problem, ponieważ został zarejestrowany czas testowania, w którym aplikacja połączy klawiaturę sprzętową, podczas gdy automatyczny symulator czasu testowania wymaga tylko klawiatury programowej. więc jak rozwiązać ten problem. Po prostu użyj klawiatury programowej do czasu nagrywania. możesz zobaczyć magię.

codercat
źródło
0

Dla mnie problem był taki sam jak dla Teda. W rzeczywistości, jeśli pole hasła zostanie dotknięte po polu logowania, a sprzętowa baza danych jest włączona, klawiatura programowa zlikwiduje się po dotknięciu drugiego pola i nie jest to specyficzne dla testów interfejsu użytkownika.

Po pewnym czasie mieszania z AppleScript, oto co wymyśliłem (ulepszenia są mile widziane):

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

Utwórz plik skryptu z powyższym kodem i dodaj go do niezbędnych celów (prawdopodobnie tylko dla testów interfejsu użytkownika, możesz chcieć dodać podobny skrypt do celów programistycznych, aby ponownie włączyć klawiaturę sprzętową podczas programowania). Należy dodać Run Scriptfazę w fazach kompilacji i używać jej w następujący sposób: osascript Path/To/Script/script_name.applescript

Timur Kuchkarov
źródło
0

Napotkaliśmy ten sam błąd podczas ustawiania accessibilityIdentifierwartości dla widoku niestandardowego ( UIStackViewpodklasy) zawierającego UIControlpodglądy. W takim przypadku XCTest nie był w stanie uzyskać fokusu klawiatury dla elementów potomnych.

Nasze rozwiązanie polegało po prostu na usunięciu accessibilityIdentifierwidoku nadrzędnego i ustawieniu accessibilityIdentifierpodglądów podrzędnych za pośrednictwem dedykowanych właściwości.

shadowhorst
źródło
0

Inna odpowiedź, ale dla nas problem polegał na tym, że widok był zbyt zbliżony do innego widoku, który zawiera rozpoznawanie gestów. Okazało się, że potrzebujemy widoku oddalonego o co najmniej 20 pikseli (w naszym przypadku poniżej). Dosłownie 15 nie działało, a 20 lub więcej. Przyznaję, że to dziwne, ale mieliśmy kilka UITextViews, które działały, a niektóre, które nie działały, i wszystkie znajdowały się pod tym samym nadrzędnym i identycznym innym pozycjonowaniem (i oczywiście nazwami zmiennych). Klawiatura włączona, wyłączona czy cokolwiek innego nie robiło różnicy. Dostępność pokazała pola. Ponownie uruchomiliśmy nasze komputery. Zrobiliśmy czyste kompilacje. Kasy ze świeżych źródeł.

David J.
źródło
0

Rozwiązaniem tego problemu było dodanie 1 sekundy snu:

let textField = app.textFields["identifier"]
textField.tap()
sleep(1)
textField.typeText(text)
Przemysław Wrzesiński
źródło
0

Natknąłem się na ten problem i udało mi się go naprawić w moim scenariuszu, biorąc rozwiązanie opublikowane przez @AlexDenisov i dodając je do moich działań wstępnych do uruchomienia i testu .

wprowadź opis obrazu tutaj

CodeBender
źródło
0

Nie ma potrzeby włączania / wyłączania klawiatury we / wy. Nie używaj .typeText dla secureTextField, po prostu użyj

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

Bonus: kliknięcie dźwięku klawiatury :)

zdravko zdravkin
źródło
0

Na koniec napisałem skrypt, który edytuje plik .plist symulatora i ustawia ConnectHardwareKeyboardwłaściwość na false dla wybranego symulatora. Słyszałeś to dobrze, zmienia właściwość specjalnie wybranego symulatora w słowniku „DevicePreferences” zamiast edytować właściwość globalną.

Najpierw utwórz skrypt powłoki o nazwie disable-hardware-keyboard.sh z następującą zawartością. Możesz go umieścić w „YourProject / xyzUITests / Scripts /” .:

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

Teraz wykonaj następujące kroki, aby wywołać to z przekazaniem udid wybranego symulatora jako argumentu:

  1. Edytuj swój schemat Xcode (lub specyficzny schemat testów interfejsu użytkownika, jeśli taki masz)
  2. Idź do: Test> Działania wstępne
  3. Dodaj nowy skrypt, dotykając symbolu „+”> „Nowa akcja skryptu uruchamiania”.
  4. Ważne: w menu rozwijanym „Podaj ustawienia kompilacji z” wybierz główny cel aplikacji, a nie cel testów interfejsu użytkownika.
  5. Teraz dodaj następujący skrypt w polu tekstowym poniżej.

Skrypt w Test> Działania wstępne:

#!/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

Czas to przetestować:

  1. Uruchom symulator
  2. Włącz klawiaturę sprzętową
  3. Uruchom dowolny test interfejsu użytkownika za pomocą klawiatury. Obserwuj, jak symulator uruchamia się ponownie, a klawiatura sprzętowa jest wyłączona. A testowa interakcja klawiatury działa dobrze. :)
Hasaan Ali
źródło
-1

Miałem ten sam problem z Securetextfields. Opcja łączenia sprzętu w moim symulatorze była wyłączona, ale nadal występował problem. Wreszcie zadziałało to dla mnie (Swift 3):

 let enterPasswordSecureTextField = app.secureTextFields["Enter Password"]
    enterPasswordSecureTextField.tap()
    enterPasswordSecureTextField.typeText("12345678")
Rads
źródło
Jaka jest różnica między Twoim kodem a kodem zadanym w pytaniu.
Shivam Pokhriyal