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?



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.


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.


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.


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

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


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


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.


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

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

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


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


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.


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


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.


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


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


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


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.


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


0

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

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

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


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


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. :)

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

Jaka jest różnica między Twoim kodem a kodem zadanym w pytaniu.
Shivam Pokhriyal
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.