Levvel Blog - How to Set Up Xcode UI Testing for Today Extensions

How to Set Up Xcode UI Testing for Today Extensions

Today Extensions are a great way to add quick and glanceable UI to your app. Xcode UI Testing, along with iOSSnapshotTestCase (previously named FBSnapshotTestCase), is a great way to test UI in your app. So, why not use them together? Well, there are a few problems with that.

First, Xcode doesn’t allow a Today Extension target to be set as the target application for a UI Test. Second, iOSSnapshotTestCase doesn’t work out of the box with Xcode UI Testing.

I will cover workarounds for both of these issues below.

Manipulating the World Outside of Your App

Since Xcode doesn’t allow a Today Extension target to be set as the target application for a UI Test, we need a way to get to the Today Extension after the app has launched. While using Xcode UI Test recorder is usually a great start to creating a UI Test, it won’t work without some tweaking. For one thing, it doesn’t record hitting the home button to get to the home screen. Getting to the homescreen and controlling it used to be fairly difficult and involved imported private headers, but now it’s easy—just call XCUIDevice.shared.press(XCUIDevice.Button.home). Then, once on the home screen, it records:


let scrollView = XCUIApplication().otherElements["Home screen icons"].otherElements["SBFolderScalingView"].children(matching: .scrollView).element

scrollView.swipeRight()

The problem here is that XCUIApplication is SpringBoard and not the current target application, so the test runner isn’t able to find “Home screen icons.” To fix this, we need to find SpringBoard’s scroll view like this:


XCUIDevice.shared.press(XCUIDevice.Button.home)

XCUIDevice.shared.press(XCUIDevice.Button.home) //Do this twice to go to the first home screen

let springboard = XCUIApplication(bundleIdentifier: "com.apple.springboard")

let scrollView = springboard.otherElements["Home screen icons"].otherElements["SBFolderScalingView"].children(matching: .scrollView).element

scrollView.swipeRight() //Swipe over to the Today view

Now we have the Today View on screen. Note that this method is also useful for manipulating other apps, like Settings, in order to test permission changes, such as notifications settings for an app.

Getting iOSSnapshotTestCase to Play Nice with Xcode UI Testing

Typically, iOSSnapshotTestCase is used in a white box testing scenario in which a programmatically-created view is compared to a screenshot previously captured using iOSSnapshotTestCase in record mode. However, Xcode UI Testing is used in a black box testing scenario in which the running app is inspected.

To get set up, follow the instructions in iOSSnapshotTestCase’s ReadMe—except you will want to add iOSSnapshotTestCase to your UI Test target, instead of just your Unit Test target. To bridge the gap between the iOSSnapshotTestCase and Xcode UI Testing, simply create a UIImageView with an image captured during UI Testing:


sleep(1) //wait for swipe animation to finish

let image = springboard.screenshot().image

FBSnapshotVerifyView(UIImageView(image: croppedImage))

Next, set iOSSnapshotTestCase record mode to Yes, run the test, set record mode to No, run the test and … the test failed. Well, the test probably failed because taking a screenshot of the SpringBoard includes the status bar with the time, which more than likely changed since the reference screenshot was recorded.

To avoid this external state change, we need to crop the status bar out of the image. Fortunately, cropping the status bar is easy with Joseph Susnick’s UIImage extension. Add the extension to your UI Test target, and then call removingStatusBar on the screenshot image:


sleep(1) //wait for swipe animation to finish

let croppedImage = springboard.screenshot().image.removingStatusBar

FBSnapshotVerifyView(UIImageView(image: croppedImage))

It took a few hoops to jump through, but now you can verify the look and feel of your Today Extension.

Steve Moser

Steve Moser

Senior Consultant

Steve Moser is a Mobile Application Developer at Levvel focusing mainly on iOS. He is passionate about leveraging software to deliver great experiences.

Related Posts