Ошибка тестирования пользовательского интерфейса - ни элемент, ни какой-либо его потомок не фокусируются на клавиатуре secureTextField

139

Это мой случай:

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

UI Testing Failure - Ни элемент, ни потомок не имеют фокусировки на клавиатуре. Элемент:

Что случилось? Это нормально работает textFields, но проблема возникает только с secureTextFields. Есть обходные пути?

Бартломей Семанчик
источник
и странная часть, если я пытаюсь, как это, он работает XCUIApplication (). webViews.secureTextFields ["Password"]. tap () XCUIApplication (). webViews.secureTextFields ["Password"]. typeText ("Welcome")
aurilio
Возможно, вы установили идентификатор доступности, но не установили isAccessibilityElement = true
soumil
Я добавил ответ на аналогичный вопрос здесь: stackoverflow.com/a/59637897/2585413 . Моя проблема заключалась в том, что у меня были другие UIWindows с плохими значениями
.windowLevel

Ответы:

264

Эта проблема причиняла мне боль, но мне удалось найти правильное решение. В симуляторе убедитесь, что «Оборудование -> Клавиатура -> Подключить аппаратную клавиатуру» выключено.

Тед Камински
источник
4
Это исправило проблему. Но это очень плохой обходной путь, поскольку мы не можем применить его автоматически для КИ.
Станислав Панкевич
25
Если вы запускаете свои тесты на CI (Jenkins и т. Д.), Вы можете установить следующие параметры в скрипте перед запуском ваших тестов. «по умолчанию напишите com.apple.iphonesimulator ConnectHardwareKeyboard 0»
charlyatwork
7
Это не решает проблему для меня. Я четко вижу, как текстовое поле фокусируется, когда клавиатура поднята, но среда тестирования никогда не может вводить текст, используя typeText: метод
Майкл,
2
У меня работало на Xcode 11, но снятия флажка Подключить аппаратную клавиатуру может быть недостаточно. Кроме того, необходимо убедиться, что программная клавиатура действительно показана (у меня фактически была ситуация, когда аппаратная клавиатура не была подключена, и программная клавиатура не отображалась, даже если у textField был фокус, а курсор мигал).
Рейнхард Маннер
1
Я столкнулся с этим на Xcode 11, а также. Локально исправляет, но как это можно установить в CI?
Джерг
26

Недавно мы нашли хак, чтобы сделать решение из принятого ответа постоянным. Чтобы отключить настройку симулятора: «Оборудование -> Клавиатура -> Подключить аппаратную клавиатуру» из командной строки, необходимо написать:

defaults write com.apple.iphonesimulator ConnectHardwareKeyboard 0

Это не повлияет на работающий симулятор - вам нужно перезапустить симулятор или запустить новый, чтобы настройки вступили в силу.

AlexDenisov
источник
это ничего не изменило.
netshark1000
@ netshark1000, который может быть изменен с более новой версией Xcode, я проверю это.
Алексей Денисов
1
очень полезно, мне нужно было наоборот, где клавиатура всегда включена, но да, это здорово, спасибо. Я закончил тем, что пошел defaults write com.apple.iphonesimulator ConnectHardwareKeyboard -bool true, но это та же самая концепция.
Лазерный Ястреб
2
Я создал скрипт на этапах сборки, чтобы сделать это. Но мне нужно было убить все симуляторы, поэтому я сделал это:killall "Simulator"; defaults write com.apple.iphonesimulator ConnectHardwareKeyboard 0;
Вагнер Сэйлс
Кажется, это больше не работает, ключ изменился? @AlexDenisov
Саймон Маклафлин
15

Я написал небольшое расширение (Swift), которое идеально подходит для меня. Вот код:

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

Основная идея заключается в том, чтобы продолжать нажимать на элемент (текстовое поле) до того, как появится клавиатура.

Бережный Александр
источник
Это не работает для меня прямо сейчас. У меня Xcode 7.2 (7C68), какая у вас версия? Это решение, которое мы нашли для CI, работает для нас: stackoverflow.com/a/34812979/598057 .
Станислав Панкевич
Чтобы подтвердить это еще раз: у вас работает этот помощник для безопасного текстового поля пароля, а не только для обычного текстового поля?
Станислав Панкевич
Да, это работает для обоих типов текстового поля: обычное и безопасное.
Бережный Александр
1
Проблема с этим ответом состоит в том, что он использует жестко заданную задержку. Вместо этого используйте модель ожидания ожиданий с элементом клавиатуры.
user1122069
11

У Станислава правильная идея.

В командной среде вам нужно что-то, что будет работать автоматически. Я придумал исправить здесь на моем блоге.

В основном вы просто вставляете:

UIPasteboard.generalPasteboard().string = "Their password"
let passwordSecureTextField = app.secureTextFields["password"]
passwordSecureTextField.pressForDuration(1.1)
app.menuItems["Paste"].tap()
RyanPliske
источник
Спасибо, что поделились своим решением. К сожалению, это не работает для меня прямо сейчас. У меня Xcode 7.2 (7C68), что вы? Смотрите другое решение, которое мы нашли для CI: stackoverflow.com/questions/32184837/… .
Станислав Панкевич
8

Другой причиной этой ошибки является наличие родительского представления текстового поля, в которое вы пытаетесь ввести текст, который установлен как элемент доступности ( view.isAccessibilityElement = true). В этом случае XCTest не может получить дескриптор подпредставления для ввода текста и возвращает ошибку.

UI Testing Failure - Ни элемент, ни потомок не имеют фокусировки на клавиатуре.

Дело не в том, что ни один элемент не имеет фокуса (как вы часто можете видеть клавиатуру вверх и мигающий курсор в UITextField), просто ни один элемент не может достичь фокуса. Я столкнулся с этим при попытке ввести текст в UISearchBar. Сама панель поиска не является текстовым полем, при установке его в качестве элемента доступности доступ к базовому UITextField был заблокирован. Чтобы решить эту проблему, searchBar.accessibilityIdentifier = "My Identifier"был установлен на UISearchBarоднако isAccessibilityElementне был установлен true. После этого протестируйте код вида:

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

Работает

user3847320
источник
6

Это происходило со мной много раз. Вы должны отключить аппаратное обеспечение клавиатуры и ту же раскладку, что и OSX в вашем симуляторе

Оборудование / Клавиатура (отключить все)

После этого программное обеспечение клавиатуры не исчезнет, ​​и ваши тесты смогут набирать текст

Отключить аппаратное обеспечение

Фернандо Мартинес
источник
5

Используйте режим сна между запуском приложения и вводом данных в текстовые поля, например так:

sleep(2)

В моем случае я продолжал получать эту ошибку каждый раз, и только это решение помогло мне.

Kingalione
источник
1
Проблема в том, что если у вас есть большое количество тестов пользовательского интерфейса, которые выполняют что-то вроде первоначального входа в систему, это добавит огромные накладные расходы к вашему тесту CI.
delta2flat
4

Это может помочь: я просто добавляю «касание» перед ошибкой; вот и все :)

[app.textFields[@"theTitle"] tap];
[app.textFields[@"theTitle"] typeText:@"kk"];
Карлос Перальта
источник
2
Это определенно не работает для безопасного текстового поля пароля.
Станислав Панкевич
Это работало для моего безопасного текстового поля пароля просто отлично. Хорошее решение
Трэвис М.
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

Запишите случай, как хотите, с клавиатурой или без клавиатуры. Но перед игрой сделайте следующее.

Этот следующий параметр (подключить аппаратную клавиатуру) должен быть отключен во время воспроизведения теста.

введите описание изображения здесь

umairhhhs
источник
4

В моем случае это Hardware -> Keyboard -> Connect Hardware Keyboard-> Отключить не работает для меня.

Но когда я последовал

1) Hardware -> Keyboard -> Connect Hardware Keyboard-> Включить и запустить приложение
2) Hardware -> Keyboard -> Connect Hardware Keyboard-> Отключить .

У меня сработало

BharathRao
источник
Работал на меня, MAN Я ненавижу этот аспект XCode!
bwobbones
3

[Повторно комментируя комментарий Бартломея Семанчика, потому что он решил проблему для меня]

Мне нужно было сделать Simulator> Reset Contents and Settings в строке меню симулятора, чтобы это начало работать для меня.

rogueleaderr
источник
Сброс симулятора мне тоже помог. Интересно, что проблема возникла только в симуляторе, в то время как тот же тест (нажмите поле tex, после которого вводились символы) работал нормально на устройстве.
Кристиан
1

Иногда текстовые поля не реализуются как текстовые поля, или они заключены в другой элемент пользовательского интерфейса и не легко доступны. Вот работа вокруг:

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

Ваша первая строка - это просто определение запроса , которое не означает, что passwordSecureTextFieldоно действительно существует.

Ваша вторая строка будет динамически выполнять запрос и попытаться (повторно) связать запрос с элементом пользовательского интерфейса. Вы должны установить точку останова и убедиться, что найден один и только один элемент. Или просто используйте assert:

XCTAssertFalse(passwordSecureTextField.exists);

В противном случае все выглядит хорошо, tapдолжна быть видима клавиатура, а затем typeTextпросто должна работать. Журнал ошибок должен рассказать вам больше информации.

ЛОМ
источник
1
passwordSecureTextFieldсуществуют. Я исправил проблему, но очистил память и снова переписал эти строки. Странно, но это сработало.
Бартломей Семанчик
Рад слышать, что это исправлено! Я столкнулся с подобной проблемой вчера с бета 6 :)
JOM
бета 6? :-) правда? У меня только 5 :)
Bartłomiej Semańczyk
Вы были заняты кодированием :) Бета 6 не записывалась tapдля меня, потребовалось некоторое время, чтобы понять это. Хорошая отладочная практика!
JOM
Может быть, вы знаете ответ на этот вопрос: stackoverflow.com/questions/32219015/… ?
Бартломей Семанчик
0

Не перепутайте, проблема возникла из-за того, что вы записали время тестирования, в котором ваше приложение будет подключаться к аппаратной клавиатуре, а симулятор времени автоматического тестирования использует только программную клавиатуру. так что как решить эту проблему. Просто используйте программную клавиатуру на время записи. Вы можете увидеть магию.

codercat
источник
0

Проблема для меня была такой же, как и для Теда. На самом деле, если поле пароля будет выбрано после того, как поле входа в систему и аппаратное КБ включены, программная клавиатура будет отключена при втором нажатии поля, и это не относится к тестам пользовательского интерфейса.

После некоторого времени возни с AppleScript вот что я придумал (улучшения приветствуются):

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

Создайте файл сценария с приведенным выше кодом и добавьте его к необходимым целям (возможно, только для целей тестирования пользовательского интерфейса, вы можете добавить аналогичный сценарий к целям разработки, чтобы повторно включить HW-клавиатуру во время разработки). Вы должны добавить Run Scriptфазу в фазы сборки и использовать ее следующим образом: osascript Path/To/Script/script_name.applescript

Тимур Кучкаров
источник
0

Мы столкнулись с той же ошибкой при установке accessibilityIdentifierзначения для пользовательского представления ( UIStackViewподкласса), содержащего UIControlподпредставления. В этом случае XCTest не удалось получить фокус клавиатуры для дочерних элементов.

Нашим решением было просто удалить accessibilityIdentifierиз нашего родительского представления и установить accessibilityIdentifierдля подпредставлений через выделенные свойства.

shadowhorst
источник
0

Другой ответ, но для нас проблема заключалась в том, что представление было слишком близко к другому мнению, что распознаватель жестов на нем. Мы обнаружили, что нам нужно, чтобы изображение было не менее 20 пикселей (в нашем случае ниже). Буквально 15 не сработало, а 20 и более сработало. Это странно, я признаю, но у нас было несколько UITextViews, которые работали, и некоторые, которые не работали, и все находились под одним и тем же родителем и имели идентичное другое позиционирование (и, конечно, имена переменных). Клавиатура включена или выключена или что-то не имеет значения. Доступность показала поля. Мы перезагрузили наши компьютеры. Мы сделали чистые сборки. Свежий источник проверки.

Дэвид Дж
источник
0

Что решило эту проблему для меня, так это добавив 1 секунду сна:

let textField = app.textFields["identifier"]
textField.tap()
sleep(1)
textField.typeText(text)
Пшемыслав Вжесинский
источник
0

Я столкнулся с этой проблемой и смог исправить ее в своем сценарии, взяв решение, опубликованное @AlexDenisov, и добавив его в свои предварительные действия для запуска и тестирования .

введите описание изображения здесь

CodeBender
источник
0

Нет необходимости включать / выключать клавиатуру в I / O. Не используйте .typeText для secureTextField, просто используйте

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

Бонус: Вы получаете щелчок звука клавиатуры :)

здравко здравкин
источник
0

Наконец, я написал скрипт, который редактирует файл .plist симулятора и устанавливает для ConnectHardwareKeyboardсвойства false значение для выбранного симулятора. Вы правильно поняли, это изменяет свойство для специально выбранного симулятора в словаре «DevicePreferences», а не редактирует глобальное свойство.

Сначала создайте сценарий оболочки с именем disable-hardware-keyboard.sh со следующим содержимым. Вы можете поместить его в «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

Теперь выполните следующие шаги, чтобы вызвать его, передав в качестве аргумента udid выбранного симулятора:

  1. Отредактируйте свою схему XCode (или UI тестирует определенную схему, если у вас есть)
  2. Перейти к: Тест> Предварительные действия
  3. Чтобы добавить новый сценарий, коснитесь символа «+»> «Действие запуска нового сценария».
  4. Важное замечание: В раскрывающемся списке «Предоставить параметры сборки из» выберите цель основного приложения, а не цель тестирования пользовательского интерфейса.
  5. Теперь добавьте следующий скрипт в текстовую область ниже.

Скрипт внутри Test> Pre-actions:

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

Время проверить это:

  1. Запустить симулятор
  2. Включить аппаратную клавиатуру для него
  3. Запустите любой тест пользовательского интерфейса с помощью клавиатуры. Наблюдайте, как симулятор перезагружается и аппаратная клавиатура отключена. И взаимодействие с клавиатурой теста работает нормально. :)
Хасаан Али
источник
-1

Была такая же проблема с Securetextfields. Опция подключения оборудования в моем симуляторе была, но все же столкнулась с проблемой. Наконец, это сработало для меня (Swift 3):

 let enterPasswordSecureTextField = app.secureTextFields["Enter Password"]
    enterPasswordSecureTextField.tap()
    enterPasswordSecureTextField.typeText("12345678")
РАУ
источник
В чем разница между вашим кодом и кодом, заданным в вопросе.
Шивам Похриял