UI测试失败-元素或任何后代都没有将键盘焦点放在secureTextField上


139

这是我的情况:

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

UI测试失败-元素或任何后代都没有键盘焦点。元件:

怎么了?这对于正常情况是很好的textFields,但是问题仅在出现时出现secureTextFields。任何解决方法?



而奇怪的是,如果我这样尝试,它会起作用XCUIApplication()。webViews.secureTextFields [“ Password”]。tap()XCUIApplication()。webViews.secureTextFields [“ Password”]。typeText(“ Welcome”)
aurilio

可能是您已经设置了可访问性标识符,但尚未设置isAccessibilityElement = true
soumil

我在这里添加了对类似问题的答案:stackoverflow.com/a/59637897/2585413。我的问题是,我还存在其他UIWindows,它们的.windowLevel值不正确
nteissler

Answers:


264

这个问题使我感到非常痛苦,但是我设法找到了适当的解决方案。在模拟器中,确保已关闭“硬件->键盘->连接硬件键盘”。


4
这已解决了该问题。但这是非常差的解决方法,因为我们无法将其自动应用于CI。
Stanislav Pankevich '16

25
如果您在CI(Jenkins等)上运行测试,则可以在运行测试之前在脚本中设置以下参数。“默认值写入com.apple.iphonesimulator ConnectHardwareKeyboard 0”
charlyatwork,2016年

7
这对我来说并不能解决问题。我可以清楚地看到文本框获得焦点,键盘,但使用的TypeText测试框架就不会进入文本:方法
迈克尔

2
在Xcode 11上为我工作,但是取消选中Connect硬件键盘可能还不够。另外,还必须确保真正显示了软件键盘(实际上,我没有连接硬件键盘,也没有显示软件键盘,即使textField已聚焦并且光标闪烁)。
ReinhardMänner,

1
我也在Xcode 11上遇到了这个问题。在本地修复,但是如何在CI中设置呢?
jherg '19

26

最近,我们发现了一种骇客程序,可以使接受的答案的解决方案持久化。要禁用模拟器设置:在命令行一中,“硬件->键盘->连接硬件键盘”应输入:

defaults write com.apple.iphonesimulator ConnectHardwareKeyboard 0

它不会影响正在运行的模拟器-您需要重新启动模拟器或启动新的模拟器才能使该设置生效。


这并没有改变什么。
netshark1000 '16

@ netshark1000可能会随Xcode的较新版本更改,我将对其进行检查。
AlexDenisov '16

1
非常有用,我需要始终启用键盘的相反功能,但是,非常感谢。我最终选择了 defaults write com.apple.iphonesimulator ConnectHardwareKeyboard -bool true,但是概念相同。
Laser Hawk'Nov

2
我在构建阶段创建了一个脚本来做到这一点。但是我需要杀死所有模拟器,所以我这样做了:killall "Simulator"; defaults write com.apple.iphonesimulator ConnectHardwareKeyboard 0;
Wagner Sales

这似乎不再起作用,密钥是否已更改??@AlexDenisov
Simon McLoughlin

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
Stanislav Pankevich '16

再确认一次:此帮助程序可为您使用安全的密码文本字段,而不仅仅是常规文本字段?
Stanislav Pankevich '16

是的,它适用于两种类型的文本字段:常规和安全。
berezhnyi oleksandr

1
这个答案的问题是它使用了硬编码的延迟。相反,请使用带有键盘元素的等待期望模型。
user1122069 17-10-24

11

斯坦尼斯拉夫有正确的想法。

在团队环境中,您需要一些可以自动工作的东西。我想出了一个修复这里在我的博客。

基本上,您只需粘贴:

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

感谢您分享您的解决方案。不幸的是,它现在对我不起作用。我有Xcode 7.2(7C68),您呢?请参阅我们为CI找到的其他解决方案:stackoverflow.com/questions/32184837/…
Stanislav Pankevich '16

8

导致此错误的另一个原因是,如果您试图输入被设置为可访问性元素(view.isAccessibilityElement = true)的文本,则在文本字段的父视图中进行操作。在这种情况下,XCTest无法获得子视图上的句柄以输入文本并返回错误。

UI测试失败-元素或任何后代都没有键盘焦点。

并不是没有元素具有焦点(您经常可以在UITextField中看到键盘向上移动和光标闪烁),而是它可以到达的任何元素没有焦点。尝试在UISearchBar中输入文本时遇到了这个问题。搜索栏本身不是文本字段,将其设置为可访问性元素时,将阻止对基础UITextField的访问。为了解决这个问题,searchBar.accessibilityIdentifier = "My Identifier"是在设置UISearchBar但是isAccessibilityElement未设置为true。在此之后,测试代码的形式为:

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

作品


6

它在我身上发生了很多次。您必须在模拟器中禁用键盘硬件和与OSX相同的布局

硬件/键盘(全部禁用)

之后,键盘软件将无法关闭,您的测试可以键入文本

禁用硬件


5

在启动应用程序和在文本字段中输入数据之间进行睡眠,如下所示:

sleep(2)

就我而言,我每次都会不断收到此错误,只有这种解决方案帮助了我。


1
问题是,如果您有大量执行初次登录之类的UI测试,这将为CI测试运行增加大量开销。
delta2flat


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

记录外壳,但要使用键盘或不连接键盘。但是在进行测试之前,请执行以下操作。

进行测试时,应不要选中以下选项(连接硬件键盘)。

在此处输入图片说明


4

就我而言,这Hardware -> Keyboard -> Connect Hardware Keyboard-> 禁用对我没有用。

但是当我跟随

1)Hardware -> Keyboard -> Connect Hardware Keyboard-> 启用并运行应用程序
2)Hardware -> Keyboard -> Connect Hardware Keyboard-> 禁用

对我有用


为我工作,MAN我讨厌XCode的这方面!
bwobbones

3

[将BartłomiejSemańczyk的评论重新发布为答案,因为它为我解决了问题]

我需要在模拟器菜单栏中执行“模拟器”>“重置内容和设置”,以使此操作对我有效。


重置模拟器对我也有帮助。有趣的是,该问题只发生在模拟器中,而同一测试(点击texfield,然后键入字符)在设备上运行良好。
基督教徒

1

有时文本字段未实现为文本字段,或者它们被包装到另一个UI元素中并且不易于访问。解决方法:

//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实际上会存在。

您的第二行将动态执行查询,并尝试将查询(重新)绑定到UI元素。您应该在其上放置一个断点,并验证仅找到一个元素。或者只是使用一个断言:

XCTAssertFalse(passwordSecureTextField.exists);

否则看起来没问题,tap应该强制键盘可见,然后typeText才能正常工作。错误日志应该告诉您更多信息。


1
passwordSecureTextField存在。我解决了问题,但清理了内存,然后再次重写了这些行。很奇怪,但是行得通。
巴特洛梅耶Semańczyk

很高兴听到它是固定的!我昨天在Beta 6中遇到了类似的问题:)
JOM 2015年

beta 6?:-)真的吗?我只有5 :)
巴特洛梅耶Semańczyk

您一直在忙编码:) Beta 6没有tap为我录制,花了一些时间才弄清楚。良好的调试习惯!
2015年


0

别搞砸了,这里有一个问题,原因是您记录了您的应用程序将连接硬件键盘的测试时间,而自动测试时间模拟器仅使用软件键盘。因此有关如何解决此问题。只需在录制时间使用软键盘即可。你可以看到魔术。


0

对我来说,问题和对特德一样。实际上,如果在登录字段后打开密码字段并打开了硬件KB,则软件键盘将在第二次点击时自动关闭,这并不特定于UI测试。

经过一段时间的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

使用上面的代码创建一个脚本文件,并将其添加到必要的目标(可能仅是UI测试目标,您可能希望向开发目标中添加类似的脚本,以便在开发过程中重新启用硬件键盘)。您应该Run Script在构建阶段中添加阶段,并像这样使用它: osascript Path/To/Script/script_name.applescript


0

accessibilityIdentifierUIStackView包含UIControl子视图的自定义视图(子类)设置值时,我们遇到了相同的错误。在这种情况下,XCTest无法获得后代元素的键盘焦点。

我们的解决方案只是accessibilityIdentifier从父视图中删除,并accessibilityIdentifier通过专用属性为子视图设置。


0

另一个答案,但对我们来说,问题是该视图太接近手势识别器上的另一个视图。我们发现我们需要视图至少相距20像素(在下面的示例中)。从字面上看,有15个无效,而有20个以上无效。我承认这很奇怪,但是我们有一些UITextViews在工作,有的没有用,并且全部在同一个父对象下,并且在其他位置相同(当然还有变量名)。键盘的开或关或其他无关紧要的地方。可访问性显示了这些字段。我们重新启动了计算机。我们做了干净的建筑。新鲜的源结帐。


0

为我解决此问题的原因是增加了1秒钟的睡眠时间:

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

0

我遇到了这个问题,并且能够通过采用@AlexDenisov发布的解决方案并将其添加到我的操作前准备中以进行运行测试,从而在我的方案中解决此问题。

在此处输入图片说明


0

无需在I / O中打开/关闭键盘。不要将.typeText用于secureTextField,只需使用

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

奖励:您会得到键盘声音,点击:)


0

最后,我编写了一个脚本,该脚本编辑Simulator的.plist文件,并将ConnectHardwareKeyboard所选模拟器的属性设置为false。您没听错,它会更改“ DevicePreferences”词典中专门选择的模拟器的属性,而不是编辑global属性。

首先,使用以下内容创建一个名为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. 重要提示:在“从中提供构建设置”下拉菜单中,选择您的主要应用目标,而不是UI测试目标。
  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. 通过键盘交互运行任何UI测试。观察模拟器重新启动,并且硬件键盘已禁用。并且测试的键盘交互工作正常。:)

-1

Securetextfields也有同样的问题。我的模拟器中的connect hardware选项属于,但仍然遇到问题。最后,这对我有用(快速3):

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

您的代码和问题中要求的代码有什么区别?
Shivam Pokhriyal,
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.