/dev/trouble
Eric Roller's Development Blog

For a long time, I have been trying to avoid scroll bars in the screenshots that I generate. The solution that I came up with was simply to wait for them to disappear:

thirdBlock.element.swipeUp()

// Wait for the scroll indicators to be hidden
Thread.sleep(forTimeInterval: 2.5)

takeSnapshot("Last_Block")

I have also been using fastlane for several years to automate this. While I try very hard never to add any screenshot-specific exceptions to the code, there has always been the odd need to do it, for instance to handle situations that are not supported by the iOS simulator.

Preprocessor Macros

For code sections that are only used during development, you should mask them out using "preprocessor macros" like:

#if DEBUG
print("Data finished loading.")
#endif

This works using an Xcode project setting that defines SWIFT_ACTIVE_COMPILATION_CONDITIONS to use DEBUG, which results in the command-line option -D DEBUG to be used by CompileSwift. You can see this if you dive deep into your build logs.

Similarly, you can mask sections that are only (or never) to be used in the simulator like this:

#if targetEnvironment(simulator)
    // iOS simulator only
#else
    // iOS device only
#endif

Simple inversions are also supported in Swift using an exclamation mark (read it as: "not"):

#if ! targetEnvironment(simulator)
    // iOS device only
#endif

Fastlane-Specific Code

The same can be done for fastlane-specific code, but it is necessary to define a macro, for instance in the fastlane/Snapfile. Here we define FASTLANE:

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

which allow us to use in the code:

#if FASTLANE
    // fastlane only
#endif

No Scroll Bars in Fastlane

Using the above macro, I have now simply disabled the scroll bar indicators in the code:

override func viewDidLoad() {
    super.viewDidLoad()

    navigationItem.rightBarButtonItem = editButtonItem

    #if FASTLANE
    tableView.showsVerticalScrollIndicator = false
    tableView.bounces = false
    #endif
}

And this means that the test script can be made to run without additional delays (compare above):

thirdBlock.element.swipeUp()
takeSnapshot("Last_Block")

[UPDATE 2021-01-21] In SwiftUI, you could use:

List {
    ...
}
.onAppear {
    #if FASTLANE
    UITableView.appearance()
        .showsVerticalScrollIndicator = false
    #endif
}

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"))

Wasted a couple of hours debugging an issue with the use of a custom font on a UILabel; the text simply wouldn't show up on the iPhone Simulator.

No such problems with the (bold) system fonts of any size.

As it turned out, this is an issue (bug) with the iPhone Simulator; when running it on a device, the label is shown correctly.

Also note that there is a "fonts" app and an iOS fonts website that show all the fonts that are available on the iPhone or iPad.

I have been wondering how to get any pictures onto the iPhone simulator for ages and have thought one would need to sync it with iTunes.

But no, I stumbled over the solution by accident: One simply uses Safari on the iPhone Simulator to navigate to an image and the uses the built-in controls to save it.

Hint: to navigate to an image that you have open in your browser on your desktop, simply drag and drop the image (or the URL) to the iPhone Simulator. The same works for any image in the Finder!