April 17, 2018
TABLE OF CONTENTS
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.
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.
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 is an Engineering Manager at Levvel focusing mainly on iOS. He is passionate about leveraging software to deliver great experiences.
Experts from Levvel and Truist discuss insights gained from our 2020 Legacy Modernization Report. We'll cover companies’ legacy systems dependence, as well as how to tackle digital strategy and achieve business goals with modernization efforts.
In this brand new video series from Levvel, our industry experts discuss what the future of insurance looks like, how insurers are leveraging emerging technologies, and what steps established insurers can take now to prepare for the future.
Many organizations struggle to understand how to best innovate and improve. However, doing things the way you’ve always done them will prevent your business from scaling effectively.
Many legacy systems in the business world tend to be Monolithic design in nature. A monolithic application is one where it, and it alone, handles all the business needs. Many industries have this architecture in place for their core applications.