One common requirement for many testers is to ensure that iOS Push Notifications are getting sent correctly from a backend service. Push notifications, of course, are an integral part of the experience of many apps, letting the user know when a message has been received, or some event has occurred that might make them open up your app. Testing this part of the user experience is therefore essential.
Continuously track digital experience across diverse delivery channels on real devices. Learn more.
The automation tools provided by Apple don't make this easy. XCUITest has no built-in API methods for inspecting push notifications received. Nor is there any way to even simulate push notifications on a simulator, which makes real devices a hard requirement for automation.
Thankfully, Appium has the facility to automate the entire device UI from the perspective of a user interacting with the screen. This means we can do crazy things like swipe to open the notifications shade and read the element hierarchy there to determine if our notification has arrived. This tip was brought to my attention by Telmo Cardoso at AppiumConf 2018, and I recommend checking out his talk for a bunch of interesting stuff.
Let's dive in and see how to do this. First of all, this is what you'll need to make it work:
- A real iPhone or iPad with the ability to receive push notifications, set up as part of a provisioning profile. The device should be set up to allow push notifications for your app to show up on the lock screen.
- Appium set up for real device testing of iOS apps (see the Appium docs for more info). Note that you may have to have a paid Apple developer account to automate real iOS devices.
- Your app as an exported .ipa file, signed and installable on your phone. (Probably best to deploy from Xcode first before running with Appium, to make sure the app can be provisioned on your device).
- Your Apple organization ID, and the appropriate signing certificates, etc..., (we'll need to sign Appium's iOS engine WebDriverAgent to run on your device too, in addition to your app).
- A way to trigger your backend app service to send a push notification to a specific device, based on the device udid, from your test code. This might mean pestering your backend devs to give you an API you can call, or a library you can mix in with your Appium test code.
With all this in hand, our test flow should look like:
- Launch an Appium session with our app.
- Close out our app, to mimic the experience of a user receiving a push notification while doing something else.
- Trigger the backend service to send a push notification to the device under test. Ideally this call should block until the notification has been confirmed sent. (Otherwise, we can run the next step in a loop until successful).
- Swipe open the notification shade on the device.
- Check the elements on the notification shade for one that matches the message that was sent via the backend service.
- Swipe closed the notification shade.
- Re-open your app if you want, to verify that the app state has also updated in conjunction with the notification received.
Such a flow could look like this in Java:
The terminateApp and activateApp commands are self-explanatory, and simply require the bundle ID of your app. The only mystery here is in the showNotifications and hideNotifications methods. These are not driver methods, but rather helper methods I've implemented to take care of swiping the notifications shade down (to open) and up (to close). The implementation currently uses the TouchAction interface to set up the swipe. Assuming we have a field called screenSize in our test class which has previously queried the screen dimensions from Appium, then our notifications helpers look like:
Essentially, we have one method with any real logic, and all it does is set up the appropriate TouchAction actions for a swipe, namely a press, followed by a wait, followed by a moveTo. There's some other logic here to make sure we're setting our start and stop points correctly: exactly in the middle of the screen horizontally, and from top to bottom (with a padding of 5 pixels on either side).
Don’t Rely on iOS Emulators & Android Simulators. Test on Real Devices.
That's it! With the notification shade down, we can just regular old findElement commands to locate our arrived notification. In this case, we use an xpath query based on a portion of the label, with text corresponding to what we want to verify in terms of the notification that was received from our backend service.
This tip illustrates an important point about using Appium. Sometimes, we look for specific features within Appium to help us accomplish our tasks. It would be great, we think, if Appium had a "getPushNotifications" command we could use to easily check whether a notification arrived. But such a command would take us out of the realm of UI testing. When using Appium, we can simply ask ourselves, "How would a user check this?" and more often than not, we're able to do the same thing with Appium. In this case, the "advanced" trick described in this article is really not a trick at all; it's just thinking like a user!
Test your mobile apps on real devices in 90+ locations worldwide. Know more.
Check out the following code below for a full example. It won't run without modification, because due to Apple's security policies around running apps on real devices, you'll need to kick off the test with your own (signed) app and include your own signing details and so on. And as always, the code is up at the Appium Pro repo on GitHub: