XCUITest: what is the definitive, locale-agnostic way to dismiss the (software) keyboard?

I have XCUITest automation whose main purpose, beside testing, is to make clean, localized screenshots for use in the App Store. The storyboard view controllers contain UITextViews that do not dismiss on typing/tapping the return key. For the sake of argument, assume I am targeting iPad only--I have a solution for iPhone, because that needed another way to dismiss the keyboard anyway.


I am having difficulty finding an XCUITest keyboard-dismissing solution that works across all devices, independently of Simulator settings and the test's locale settings.


Nominally, the following appears to work for English


if XCUIApplication().keyboards.buttons["Hide keyboard"].exists {
    XCUIApplication().keyboards.buttons["Hide keyboard"].tap()
}
if XCUIApplication().keyboards.buttons["Dismiss"].exists {
    XCUIApplication().keyboards.buttons["Dismiss"].tap()
}


However, if I specify another language, such as French, and region, such as France, in the Scheme, for either or both of the Run and Test targets, it fails, because (presumably) the keyboard accessibility labels are localized. Except for the "exists" tests above, the taps are essentially the same as what might recorded if I use the record feature in Xcode. There are two alternative button taps, depending in part on the toggle software keyboard setting.


Is there a best practice for dismissing the keyboard, that is more straightforward and locale-agnostic?

Replies

My reply is probably too late for you, but i figured others might have a similar problem.

I solved this by having Strings always be run through a helper function that picks the string from a localizable.plist just like you'd do in the app.

Code Block
func localizedString(key:String) -> String {
let localizationBundle = Bundle(path: Bundle(for: AppUITests.UITestBase.self).bundlePath)
let result = NSLocalizedString(key, bundle:localizationBundle!, comment: "")
return result
}

Usage in your example would be:
Code Block
if XCUIApplication().keyboards.buttons[localizedString(key: "hideKeyboard")].exists {
XCUIApplication().keyboards.buttons[localizedString(key: "hideKeyboard")].tap()
}
if XCUIApplication().keyboards.buttons[localizedString(key: "dismissKeyboard")].exists {
XCUIApplication().keyboards.buttons[localizedString(key: "dismissKeyboard")].tap()
}

hideKeyboard and dismissKeyboard refer to the related String in each localizable.plist which you either provide yourself or link to within your Bundle Settings.

This approach also allows you to create Tests that run on any device-language without having to rely on Accessibility-IDs which results in a more blackbox like environment.