Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Xcode 7 UITests with localized UI

In my App I'm using NSLocalizedString to localize my app. Now I want to switch to UITests and have Testcode like this:

[tabBarsQuery.buttons["particiants"] tap]; 

This works for English but fails for other languages.

[tabBarsQuery.buttons[NSLocalizedString("PARTICIPANTS",comment:nil)] tap]; 

Fails - probably because Localizable.strings is in another bundle. How can I test a localized app?

like image 737
netshark1000 Avatar asked Nov 09 '15 12:11

netshark1000


People also ask

How do I localize in SwiftUI?

LocalizedStringKey is a special type that signals SwiftUI to look up localized strings in your bundle. Use it in custom SwiftUI views to make them ready for localization. Enable the "Use Compiler to Extract Swift Strings" build setting to extract LocalizedStringKeys from code when exporting for localization in Xcode.

Is Xcode localized?

In Xcode, localization refers specifically to the set of resources for a specific language and region that you support. You add a localization to your project and select the resources you want to include for that language and region.

What is localized string key SwiftUI?

The key used to look up an entry in a strings file or strings dictionary file.


2 Answers

Option 1: Set a Default Language

Create a new scheme for UI Testing and set the default Application Language. This will lock the app into one localized file so you can write all of your tests for that language.

Set the option from Product -> Scheme -> Manage Schemes or ⌘⇧,. Then select the Options tab and set the language.

Xcode - Set the Default Application Language

Pros: Simple, one-time change.

Cons: Cannot be used to create localized screenshots with snapshot (a tool that runs your app via UI Testing and generates App Store screenshots along the way).

Option 2: Use -accessibilityIdentifier for Localized Strings

Instead of accessing items via their displayed text or value, use accessibilityIdentifier. This is read by the UI Testing framework but never shown or read to users (even with accessibility turned on). In the old UIAutomation docs Apple mentions using this for developer functionality, which this seams like a good use case.

You can then continue to set accessibilityLabel and accessibilityValue like normal, with the localized versions.

Pros: Can be used for more generic solutions, such as taking automated screenshots.

Cons: Might require more work changing each label you need "unlocalized" for testing.

like image 158
Joe Masilotti Avatar answered Oct 19 '22 12:10

Joe Masilotti


I wanted to actually test the content of UI features and not just their existence, so setting a default language or using the accessibility identifiers wouldn't suit.

This builds on Volodymyr's and matsoftware's answers. However their answers rely on deviceLanguage which needs to be explicitly set in SnapshotHelper. This solution dynamically gets the actual supported language the device is using.

  1. Add the Localizable.strings files to your UITest target.
  2. Add the following code to your UITest target:

    var currentLanguage: (langCode: String, localeCode: String)? {     let currentLocale = Locale(identifier: Locale.preferredLanguages.first!)     guard let langCode = currentLocale.languageCode else {         return nil     }     var localeCode = langCode     if let scriptCode = currentLocale.scriptCode {         localeCode = "\(langCode)-\(scriptCode)"     } else if let regionCode = currentLocale.regionCode {         localeCode = "\(langCode)-\(regionCode)"     }     return (langCode, localeCode) }  func localizedString(_ key: String) -> String {     let testBundle = Bundle(for: /* a class in your test bundle */.self)     if let currentLanguage = currentLanguage,         let testBundlePath = testBundle.path(forResource: currentLanguage.localeCode, ofType: "lproj") ?? testBundle.path(forResource: currentLanguage.langCode, ofType: "lproj"),         let localizedBundle = Bundle(path: testBundlePath)     {         return NSLocalizedString(key, bundle: localizedBundle, comment: "")     }     return "?" } 
  3. Access the method by localizedString(key)

For those languages with a script code, the localeCode will be langCode-scriptCode (for example, zh-Hans). Otherwise the localeCode will be langCode-regionCode (for example, pt-BR). The testBundle first tries to resolve the lproj by localeCode, then falls back to just langCode.

If it still can't get the bundle, it returns "?" for the string, so it will fail any UI tests that look for specific strings.

like image 21
SeanR Avatar answered Oct 19 '22 11:10

SeanR