Search code examples
iosswiftxcode7xcode-ui-testing

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?


Solution

  • 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.