Scheme language setting ignored in iOS unit and ui tests
Asked Answered
O

1

17

My final goal is to issue

xcodebuild test

from command line picking different schemes for different languages.

Currently I have two schemes, the only difference between them is the application language. In one scheme it is English, in the other is Spanish. If I use Xcode to run the application it works nice, it is launched with the language specified in the scheme I have picked, both EN or ES are okay.

If I run the tests from Xcode, language setting is ignored. Whichever scheme I pick, it doesn't matter, it is always displayed as the device language. The same on simulator. The same when running tests with xcodebuild test picking scheme. (Adding an echo command to the scheme ensures that the correct one is picked)

In the scheme editor "Use the Run action's arguments and environment variables" is checked.

What am I doing wrong?

Thank you.

Opposition answered 17/2, 2016 at 17:6 Comment(0)
H
39

Yes, it seems like all environment variables and launch arguments provided in schemes are ignored in XCTest tests.

However, you can set the language programmatically in the test, for example in setUp() method:

override func setUp() {
    super.setUp()

    // Put setup code here. This method is called before the invocation of each test method in the class.

    let app = XCUIApplication()
    app.launchArguments += ["-AppleLanguages", "(en-US)"]
    app.launchArguments += ["-AppleLocale", "\"en-US\""]

    app.launch()

}

Now, you could extend this approach and do something like Snapshot does:

2 thing have to be passed on from snapshot to the xcodebuild command line tool:

  • The device type is passed via the destination parameter of the xcodebuild parameter

  • The language is passed via a temporary file which is written by snapshot before running the tests and read by the UI Tests when launching the application

In the end, In order to change the language on schema bases you can do the following:

1. Write a pre-action script for Test that creates a temp file:

mkdir -p ~/Library/Caches/xcode-helper
echo "en-US" > ~/Library/Caches/xcode-helper/language.txt

2. Load up the file in setUp() and set the app language:

override func setUp() {
    super.setUp()

    let app = XCUIApplication()

    let path = NSProcessInfo().environment["SIMULATOR_HOST_HOME"]! as NSString
    let filepath = path.stringByAppendingPathComponent("Library/Caches/xcode-helper/language.txt")


    let trimCharacterSet = NSCharacterSet.whitespaceAndNewlineCharacterSet()
    let language = try! NSString(contentsOfFile: filepath, encoding: NSUTF8StringEncoding).stringByTrimmingCharactersInSet(trimCharacterSet) as String

    app.launchArguments += ["-AppleLanguages", "(\(language))"]
    app.launchArguments += ["-AppleLocale", "\"\(language)\""]

    app.launch()
}

From now on, the Xcode will run the test with the language/locale specified in the scheme's pre-action script.

UPDATE

Turns out, tests do not ignore the arguments provided in the scheme. The arguments are actually passed to the test itself but not to the tested app. Which might be unexpected but it makes sense.

That being said, all you need to do this:

1. Set -AppleLanguages (en-US) and -AppleLocale en_US launch arguments for the test in scheme

Screenshot - Set <code>-AppleLanguages (en)</code> and <code>-AppleLocale "en_US"</code> launch arguments for the test in scheme

2. Pass the launch arguments in the test to the XCUIApplication instance before calling launch() method

override func setUp() {
    super.setUp()

    // Put setup code here. This method is called before the invocation of each test method in the class.

    let app = XCUIApplication()
    app.launchArguments += NSProcessInfo().arguments
    app.launch()
}
Hayes answered 22/4, 2016 at 10:39 Comment(5)
Ok, this is about UI Tests. What about Unit Tests?Grounds
@Grounds IMO you need to do something similar to what Snapshot does - use a temp file and read from it in the UI test (see the first part of the answer)Hayes
but unit test bundle does not handle app launching, it does not launch the app at all. I don't get you how it's supposed to help, can you please elaborate?Grounds
Thanks for posting the update! With newer Swift versions, it's just app.launchArguments += ProcessInfo().arguments to pass through the arguments.Kean
This doesn't work for unit tests. Anyone got a workaround for those?Arndt

© 2022 - 2024 — McMap. All rights reserved.