【问题标题】:Is it possible to "toggle software keyboard" via the code in UI test?是否可以通过 UI 测试中的代码“切换软件键盘”?
【发布时间】:2016-10-26 21:38:47
【问题描述】:

我有 UI 测试来测试登录功能(并使用它来测试其他内容),但有时当焦点从一个字段更改为另一个字段时 - 键盘隐藏,虽然光标在字段中闪烁,但我收到错误在field.typeText - no focused fields to fill

我不知何故意识到,点击Hardware -> Keyboard -> toggle software keyboard 会使键盘在屏幕上持续存在,因此测试效果很好。但我需要让它在任何测试设备上、在任何开发人员机器上工作,所以我想以编程方式设置此选项,而不会在项目的自述文件中烦人“如果测试失败,请转到……并手动设置……”。

有可能吗?

【问题讨论】:

    标签: ios xcode ios-simulator xcode-ui-testing


    【解决方案1】:

    在 Xcode 10.3 和 Xcode 11 中测试。下面的 sn-p 需要位于应用目标中(不是测试包)——例如,在 AppDelegate.swift时间>。通过将任何UIKeyboardInputModeautomaticHardwareLayout 属性设置为nil,它将禁用任何硬件键盘自动连接。

    ? 不依赖于模拟器的设置。

    #if targetEnvironment(simulator)
    // Disable hardware keyboards.
    let setHardwareLayout = NSSelectorFromString("setHardwareLayout:")
    UITextInputMode.activeInputModes
        // Filter `UIKeyboardInputMode`s.
        .filter({ $0.responds(to: setHardwareLayout) })
        .forEach { $0.perform(setHardwareLayout, with: nil) }
    #endif
    

    或 Objective-C:

    #if TARGET_IPHONE_SIMULATOR
    SEL setHardwareLayout = NSSelectorFromString(@"setHardwareLayout:");
    for (UITextInputMode *inputMode in [UITextInputMode activeInputModes]) {
        if ([inputMode respondsToSelector:setHardwareLayout]) {
            // Note: `performSelector:withObject:` will complain, so we have to use some black magic.
            ((void (*)(id, SEL, id))[inputMode methodForSelector:setHardwareLayout])(inputMode, setHardwareLayout, NULL);
        }
    }
    #endif
    

    【讨论】:

    • 你知道在AppDelegate.m中怎么做吗?
    • 我不明白。你想要objective-c等价物吗?
    • 是的,请 :-) 我们的应用是一个 React Native 应用,其中 AppDelegate 在 Objective-c 中。
    • 这似乎是唯一有效的解决方案。
    • 可以添加到 AppDelegate:didFinishLaunchingWithOptions 效果很好。将修复测试,但甚至不会因更改模拟器设置而惹恼您。最佳解决方案!
    【解决方案2】:

    受上面 real_kappa_guy s answer 的启发,我通过检查键盘是否启用然后运行苹果脚本发送键盘快捷键 Cmd-shift-k (需要添加到 pre -测试动作):

    if test `/usr/libexec/PlistBuddy -c "Print DevicePreferences:${TARGET_DEVICE_IDENTIFIER}:ConnectHardwareKeyboard" ~/Library/Preferences/com.apple.iphonesimulator.plist` == true; then 
    osascript <<EOD
      tell application "Simulator" to activate
      tell application "System Events"
          keystroke "K" using {command down, shift down}
      end tell
    EOD
    fi
    

    【讨论】:

      【解决方案3】:

      对于 Xcode 10.2,这些解决方案都不适合我,plist 已正确更改,但键盘直到隐藏。如果没有显示键盘,我必须使用 oascript 在模拟器上按 Ctrl + Shift + K。这不是美,但它是唯一有效的解决方法。

      tell application "Simulator" to activate
      tell application "System Events"
          keystroke "K" using {command down, shift down}
      end tell
      

      【讨论】:

      • 不错的解决方法。我遇到了类似的问题,只是发现设置默认ConnectHardwareKeyboard NO后,我们必须重新启动模拟器,可能是使用“killall Simulator”shell命令。
      • 我想用一个像你这样的AppleScript,但问题是cmd-shift-K是一个切换,所以如果模拟器已经有你想要的硬件键盘配置,它会反转它。
      • @GuillaumeLaurent 在我的情况下,我只在未显示硬件键盘时调用脚本。如何确定它完全取决于您的 UI 测试的用途
      • 感谢您。唯一的问题是,如果它被禁用,它将重新启用键盘,所以如果你事先进行检查,它就可以工作! (见下面我的回答)
      【解决方案4】:

      使用 Xcode 10.1 测试 我尝试了不同的方法,但都没有解决如何获取模拟器 UDID

      #Find the UDID of the booted simulator
      #And use PlistBuddy to change the flag to true or false
      #Set the variable useHardwareKeyboard with the desired result
      #Relaunch the simulator
      useHardwareKeyboard=false
      export UDID=$(xcrun simctl list devices | grep "(Booted)" | grep -E -o -i "([0-9a-f]{8}-([0-9a-f]{4}-){3}[0-9a-f]{12})")
      /usr/libexec/PlistBuddy -c "Set :DevicePreferences:$UDID:ConnectHardwareKeyboard ${useHardwareKeyboard}" ~/Library/Preferences/com.apple.iphonesimulator.plist
      xcrun simctl shutdown $UDID
      xcrun simctl boot $UDID
      

      您还可以验证这些更改。

      找到你的模拟器 UDID:(更多:https://nshipster.com/simctl/

      xcrun simctl list devices | grep "(Booted)" | grep -E -o -i "([0-9a-f]{8}-([0-9a-f]{4}-){3}[0-9a-f]{12})"
      

      运行以下命令之一并根据上面的 UDID 找到您的更改:

      defaults read com.apple.iphonesimulator
      #OR
      open ~/Library/Preferences/com.apple.iphonesimulator.plist
      

      【讨论】:

        【解决方案5】:

        在 Xcode 9 之前,您可以通过禁用 Simulator.app 中的硬件键盘来解决此问题,这将导致软件键盘始终存在。例如:

        defaults write com.apple.iphonesimulator ConnectHardwareKeyboard -bool NO
        

        【讨论】:

        • 看起来在模拟器中手动启用它后,它也保持启用 UI 测试。伤心。
        • 是的,但您至少可以在运行 UI 测试之前自动禁用它,然后在 UI 测试后重新启用它。请确保您向bugreport.apple.com 提交有关此错误的雷达报告。
        • 这不再起作用,因为该属性现在属于每个模拟器 udid,请参阅我的答案。
        • 我使用了这个解决方案(来自不同的来源)一段时间,但如果测试是通过控制台运行的(例如在 CI 服务器上),它会随机失败。我切换到在 AppDelegate 上禁用键盘的解决方案,它现在似乎可以工作。解决办法是:stackoverflow.com/a/57618331/705982
        【解决方案6】:

        模拟器的 .plist 文件已更改以添加对多个模拟器的支持。 ConnectHardwareKeyboard 布尔值现在嵌套在设备的 UDID 下方。幸运的是,这个 UDID 也存储在 plist 文件中。您可以在 UITest 目标的构建阶段下使用“运行脚本”添加此代码。

        Xcode 9 答案:

        #grab the UDID from the plist
        UDID=$(defaults read com.apple.iphonesimulator CurrentDeviceUDID)
        
        #overwrite the existing value with false
        #OR if the plist doesn't have that value add it in
        /usr/libexec/PlistBuddy -c "Set :DevicePreferences:$UDID:ConnectHardwareKeyboard 
        false" ~/Library/Preferences/com.apple.iphonesimulator.plist 
        || 
        /usr/libexec/PlistBuddy -c  "Add :DevicePreferences:$UDID:ConnectHardwareKeyboard
        bool false" ~/Library/Preferences/com.apple.iphonesimulator.plist
        

        或者您可以使用其他代码来影响所有模拟器:

        /usr/libexec/PlistBuddy -c "Print :DevicePreferences" ~/Library/Preferences/com.apple.iphonesimulator.plist | perl -lne 'print $1 if /^    (\S*) =/' | while read -r a; do /usr/libexec/PlistBuddy -c "Set :DevicePreferences:$a:ConnectHardwareKeyboard
        false" ~/Library/Preferences/com.apple.iphonesimulator.plist || /usr/libexec/PlistBuddy -c  "Add :DevicePreferences:$a:ConnectHardwareKeyboard
        bool false" ~/Library/Preferences/com.apple.iphonesimulator.plist; done
        

        【讨论】:

        • 您应该避免使用 PlistBuddy 来编辑首选项,因为它会绕过 cfprefsd。
        • @JeremyHuddlestonSequoia 还有什么选择?
        • defaults,可能,但我不认为它可以对这里需要的属性列表进行复杂的修改。
        • 答案很好。但对我来说,从默认值读取的 CurrentDeviceUDID 与用于测试的设备不同。我在包含正确设备UDID的测试环境中找到TARGET_DEVICE_IDENTIFIER
        【解决方案7】:

        按照 Brooks 的出色回答,这将适用于所有模拟器:

        /usr/libexec/PlistBuddy -c "Print :DevicePreferences" ~/Library/Preferences/com.apple.iphonesimulator.plist | perl -lne 'print $1 if /^    (\S*) =/' | while read -r a; do /usr/libexec/PlistBuddy -c "Set :DevicePreferences:$a:ConnectHardwareKeyboard
        false" ~/Library/Preferences/com.apple.iphonesimulator.plist || /usr/libexec/PlistBuddy -c  "Add :DevicePreferences:$a:ConnectHardwareKeyboard
        bool false" ~/Library/Preferences/com.apple.iphonesimulator.plist; done
        

        【讨论】:

        • 我无法将两个答案标记为正确,而您的答案是对 Brooks 答案的增强,所以我建议您编辑他的答案并为所有 udid 添加变体。
        • 不适用于 Xcode 9.4,返回 Unrecognized Type: false
        • 在 Xcode 9.4.1 上测试和工作。这些不是多行,而是一长行。也尽量不要粘贴富文本。有时在第一次运行时不起作用。你也可以试试这个文件github.com/evertoncunha/cocoaheads-2018-07/blob/master/fastlane/…
        • 感谢@EvertonCunha 的脚本。不幸的是,当我运行它时,我可以看到 plist 被编辑但模拟器仍然没有显示键盘。我什至检查了你的要点,我看到你包含一个杀死模拟器的命令,但这对我也不起作用。有什么线索吗?
        • @RaphaelOliveira 这仍然发生在我身上。似乎只有通过模拟器中的菜单“切换软件键盘”才会持久。很想知道如何通过命令行执行此操作。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2017-09-09
        • 2023-03-15
        • 1970-01-01
        • 2012-03-03
        • 2011-08-25
        • 2021-04-09
        • 1970-01-01
        相关资源
        最近更新 更多