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

时间:2015-08-24 14:29:13

标签: ios xcode swift ios9 xcode-ui-testing

这是我的情况:

textFields
  

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

有什么问题?这对普通secureTextFields很有用,但问题只出现在{{1}}。任何解决方法?

26 个答案:

答案 0 :(得分:167)

这个问题给我带来了痛苦的世界,但我已经设法找到了一个合适的解决方案。在模拟器中,确保'硬件 - >键盘 - >连接硬件键盘'关闭。

答案 1 :(得分:14)

我写了一个小扩展(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))
        }
    }
}

主要思想是在键盘出现之前继续点击一个元素(文本字段)。

答案 2 :(得分:14)

最近我们发现了一个黑客,可以从接受的答案持久化解决方案。要禁用模拟器设置:'硬件 - >键盘 - >从命令行连接硬件键盘'应该写:

defaults write com.apple.iphonesimulator ConnectHardwareKeyboard 0

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

答案 3 :(得分:11)

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

在团队环境中,您需要能够自动运行的东西。我在我的博客上提出了修复here

基本上你只需粘贴:

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

答案 4 :(得分:6)

此错误的另一个原因是,如果您正在尝试输入设置为辅助功能元素(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")

作品

答案 5 :(得分:5)

在我的情况下,此Hardware -> Keyboard -> Connect Hardware Keyboard-> 禁用不适用于我。

但是当我关注

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

对我有用

答案 6 :(得分:5)

在启动应用程序和在像这样的文本字段中输入数据之间使用休眠:

$(document).on("click",".menu",function(){

      $("#myModal").modal("show")
})

在我的情况下,我每次都会收到此错误,只有这个解决方案帮助了我。

答案 7 :(得分: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()
}

答案 8 :(得分:4)

我多次与我同在。 您必须在模拟器中禁用键盘硬件和与OSX相同的布局

硬件/键盘(全部禁用)

之后键盘软件不会解散,您的测试可以输入文字

Disable Hardware

答案 9 :(得分:3)

根据需要记录案例,键盘或没有连接键盘。 但在进行测试之前,请执行以下操作。

在播放测试时,应取消选中以下选项(连接硬件键盘)。

enter image description here

答案 10 :(得分:3)

这可能有所帮助:我只是在错误之前添加“点按”操作;这就是:)

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

答案 11 :(得分:2)

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

我需要做模拟器>重置模拟器菜单栏中的内容和设置,让我开始为我工作。

答案 12 :(得分:1)

我遇到了这个问题,并且能够解决此问题,方法是采用@AlexDenisov发布的解决方案,并将其添加到我的操作前进行运行测试

Pre-Action Run Script

答案 13 :(得分:0)

长话短说:iOS Simulator中的硬件键盘输入似乎已损坏很长时间了。

问题是-[UIApplicationSupport _accessibilityHardwareKeyboardActive]中的com.apple.UIKit.axbundle私有方法有时会返回NO,尽管它应该返回YES(当文本输入视图为firstResponder时,并且光标闪烁,这从字面上意味着硬件键盘处于活动状态。

将此代码放在应用程序中的任何位置,以使iOS Simulator相信,如果“软件键盘”处于非活动状态,则硬件键盘处于活动状态。

    
#if TARGET_OS_SIMULATOR
__attribute__((constructor))
static void Fix_UIApplicationAccessibility__accessibilityHardwareKeyboardActive(void) {
    {
        static id observer = nil;

        observer = [[NSNotificationCenter defaultCenter] addObserverForName:NSBundleDidLoadNotification
                                                          object:nil
                                                           queue:nil
                                                      usingBlock:^(NSNotification * _Nonnull note) {
            NSBundle *bundle = note.object;
            if ([bundle.bundleIdentifier isEqualToString:@"com.apple.UIKit.axbundle"]) {
                Class cls = objc_lookUpClass("UIApplicationAccessibility");
                SEL sel = sel_getUid("_accessibilityHardwareKeyboardActive");
                Method m = class_getInstanceMethod(cls, sel);
                method_setImplementation(m, imp_implementationWithBlock(^BOOL(UIApplication *app) {
                    return ![[app valueForKey:@"_accessibilitySoftwareKeyboardActive"] boolValue];
                }));
            }
        }];
    }
}
#endif

答案 14 :(得分:0)

在模拟器 UI 处于前台时运行 UI 测试时(当您可以看到模拟器窗口中的更改时),上述答案为我解决了这个问题。但是,在后台运行它们时它不起作用(例如,这是 fastlane 运行它们的方式)。

我不得不去Simulator > Device > Erase All Content and Settings...

明确地说,我在模拟器设置中手动禁用-启用-禁用硬件键盘,设置 defaults write com.apple.iphonesimulator ConnectHardwareKeyboard 0,然后然后擦除内容和设置。

答案 15 :(得分:0)

您的第一行只是查询定义,这并不意味着passwordSecureTextField实际存在。

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

XCTAssertFalse(passwordSecureTextField.exists);

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

答案 16 :(得分:0)

为我工作:

extension XCUIElement {
    func typeTextAlt(_ text: String) {
        // Solution for `Neither element nor any descendant has keyboard focus.`
        if !(self.value(forKey: "hasKeyboardFocus") as? Bool ?? false) {
            XCUIDevice.shared.press(XCUIDevice.Button.home)
            XCUIApplication().activate()
        }
        self.typeText(text)
    }
}

答案 17 :(得分: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. 重要:在“从中提供构建设置”下拉菜单中,选择您的主要应用目标,而不是UI测试目标。
  5. 现在在下面的文本区域中添加以下脚本。

测试中的脚本>预操作:

#!/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测试。 观察,模拟器重新启动,并且硬件键盘被禁用。而且测试的键盘交互工作正常。 :)

答案 18 :(得分:0)

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

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

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

答案 19 :(得分:0)

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

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

答案 20 :(得分:0)

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

答案 21 :(得分:0)

有时文本字段未实现为文本字段,或者它们包装在另一个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()       

答案 22 :(得分:0)

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

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

答案 23 :(得分: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测试目标,您可能希望在开发期间向开发目标添加类似的脚本以重新启用HW键盘)。 您应该在构建阶段添加Run Script阶段并像这样使用它: osascript Path/To/Script/script_name.applescript

答案 24 :(得分:0)

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

答案 25 :(得分:-1)

与Securetextfields存在同样的问题。我的模拟器中的连接硬件选项是,但仍遇到问题。最后,这对我有用(Swift 3):

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