Please provide a way to disable ignore Hardware Keyboards when running UI Tests

Number:rdar://FB9148288 Date Originated:2021-06-09
Status:Open Resolved:
Product:XCTest Product Version:
Classification:Suggestion Reproducible:
Currently, when running UI tests, the `XCUIElement.typeText(_:)` method is entirely dependant on the software keyboard meaning that if you attempt to run your UI Tests on the simulator but happen to have enabled the “Connect Hardware Keyboard” option, your UI Tests will likely fail in an obscure way due to the software keyboard not being presented in the UI.

The workaround for this is to uncheck “Connect Hardware Keyboard” in the Simulator menu which is relatively straightforward (it even has a keyboard shortcut) however since it is typically more convenient to use the “Connect Hardware Keyboard” option in day-to-day use of the simulator (when you aren’t running UI Tests), having to toggle the hardware keyboard on and off can be frustrating. Especially if it takes a long time for the UI Tests to build, launch and hit a scenario where `typeText(_:)` is called.

To improve the developer experience when switching context between regular debugging and UI testing, please provide a public API to allow us to disable the use of Hardware Keyboards when running test suites. The following code added to `UIApplicationDelegate.application(_:didFinishLaunchingWithOptions:)` provides a workaround using private API:

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


This workaround is great, but it has a few pitfalls:

1. Its abusing private API.
2. It requires adding hacks into production codepaths that could easily be shipped by mistake if this becomes common practice.

Instead, please provide a way to achieve similar results by configuring `XCUIApplication`, such as the following:

var app = XCUIApplication()
app.ignoreHardwareKeyboard = true

The above snippet is purely an example and I am sure there are many better ways to achieve the same result, but a solution such as the above aims to achieve three key things:

1. Provide a configuration to opt-out on a per-process level in a way that doesn’t persist 
2. Avoid nasty workarounds in the Target Application code
3. Provide a way to disable the Hardware Keyboard even if we don’t control the source code for the Target Application (i.e if we are testing universal links using Safari)

Alternatively this kind of thing could be provided as an undocumented (or documented) launch argument/environment setting, or it could even be a scheme setting. However I don’t think its appropriate for it to be provided by `simctl` since this is something that we need to be able to control on local machines outside of automated CI environments and there isn’t really a way to hook into `simctl` from local UI test runs. 



Please note: Reports posted here will not necessarily be seen by Apple. All problems should be submitted at before they are posted here. Please only post information for Radars that you have filed yourself, and please do not include Apple confidential information in your posts. Thank you!