/dev/trouble
Eric Roller's Development Blog

When creating screenshots with fastlane, there is support for checking at runtime within the app whether fastlane is being used by looking at a user default:

if UserDefaults.standard.bool(forKey: "FASTLANE_SNAPSHOT") {
    // runtime check that we are in snapshot mode
}

Unfortunately, that does not work from within the test code since the tests are run in a separate helper app!

In the test code, I would like to use something like the following such that I can test and tweak the code within Xcode before running fastlane on it:

#if FASTLANE
    snapshot("1_init", timeWaitingForIdle: 0)
#else
    let attach = XCTAttachment(screenshot: XCUIScreen.main.screenshot())
    attach.lifetime = .keepAlways
    add(attach)
#endif

One would think the FASTLANE_SNAPSHOT=YES build setting would be suitable for this task, but I have not found any way to detect it from within Swift, possibly because values like YES are not supported by the compiler.

This, however, seems to do the trick: Add this line to your Snapfile:

# Add a define for xcodebuild
xcargs "SWIFT_ACTIVE_COMPILATION_CONDITIONS=FASTLANE"

While creating UI testing scripts to create screenshots, it became necessary to detect which iOS device is currently loaded in the Simulator, specifically whether its is an iPhone or an iPad. This can be done by inspecting environment variables like SIMULATOR_DEVICE_NAME:

// Assume iPad as default
var deviceIsPhone = false

override func setUp() {
    super.setup()

    // The variable is only present in the simulator
    if let simDeviceName = ProcessInfo().environment["SIMULATOR_DEVICE_NAME"] {
        print("Testing Device: \(simDeviceName)")
        deviceIsPhone = simDeviceName.hasPrefix("iPhone")
    }
}

Other helpful variables are:

"SIMULATOR_MODEL_IDENTIFIER": "iPad5,4"
"SIMULATOR_DEVICE_NAME": "iPad Air 2"
"SIMULATOR_MAINSCREEN_HEIGHT": "2048"
"SIMULATOR_MAINSCREEN_WIDTH": "1536"
"SIMULATOR_MAINSCREEN_SCALE": "2.000000"

Also, to list all variables in your simulator log, try this:

print(ProcessInfo().environment.debugDescription.split(separator: ",").joined(separator: "\n"))