Moving Fast With Maps (Automation) On iOS

Veronica Ray
Compass True North
Published in
5 min readMay 18, 2021

--

Photo by Annie Spratt on Unsplash

At Compass we release a new version of the app every week. This fast release cadence is made possible in part by the heavy UI test automation coverage. UI testing frameworks run the mobile app on a simulator and programmatically use it the way a person would. With its XCUITest framework, Apple makes it easy to identify and interact with its native UI elements like buttons and date pickers. The map is powered by Google’s Maps SDK, which doesn’t make this task easy.

Our team focuses on the Search feature for the iOS Compass app. For many months, our team put off automating the 89 maps UI test cases (10% of our whole test suite) in favor of easier UI tests. We thought writing maps UI tests on iOS would be too challenging, even impossible. Eventually it became clear that in order to meet our 2020 automated test goals we needed to add maps UI tests. In just over two months we went from nothing to 43% of all manual maps test cases automated. This represents 39 out of 89 tests. This contributed to us meeting our goal of automating 80% of our test cases.

First we bucketed our 89 maps manual test cases into categories based on their difficulty. 75% seemed doable with some effort, 15% had one challenging step but was otherwise doable, and just 10% seemed truly difficult. Some test cases needed an x-ray approach to determine that they just relied on basic pinch and zoom gestures, not anything map specific. This was a big mental shift for a team that had always viewed automating map tests as inherently difficult. Online documentation was scarce, and only provided a starting point. The sparse information and lack of end to end examples could easily make any team think that this is a challenging project with uncertain prospects. I hope this post provides the documentation I wish I could find at that step of our research.

An accessibility identifier is a string property that all UI elements have. In your UI test you might want to select the first button on the screen with a certain identifier. We determined that identifying map markers using accessibility identifiers was possible.

What was truly difficult? Drawing complex shapes and verifying map specific UI unrelated to the markers, like satellite view or a school district boundary.

Many tests can be automated if you can just identify a map cluster with a certain text and pan and zoom around the map. It’s risky to leave out steps when automating a manual test if you eventually want the automated test to replace the manual one. I encourage folks embarking on this journey to only tackle manual test cases where they can automate all the steps.

The first step was to set the value of accessibilityElementsHidden on our instance of GMSMapView to false. After that it was necessary to look beyond the Google Maps SDK documentation.

In order to identify the first GMSMarker on the map, you could do this:

Then in your UI tests you can do:

However, it’s not very useful to identify the first map marker. We might want to tap the first cluster or assert that we have a listing pin with a price of $200,000. The map markers are GMSMarkers in the Google Maps SDK and we set their iconView property to a custom view.

That’s why our map pins are different colors and show whether the listing is a Compass Exclusive or has an Open House.

When it came to UI tests though, it was like this iconView didn’t exist. I couldn’t find any information online and Google Maps developer support just told me to file a bug report.

When you encounter a potential bug in a 3rd party library you have three options: 1) work around the bug 2) fix the bug yourself or 3) file a detailed bug report and follow up to ensure it’s resolved. Options two and three can require a large amount of effort and time. Fortunately, we found a workaround. We would store data about the text and color of the marker in its accessibility identifier. At first glance, this is a brittle and unscalable solution. It seemed like you couldn’t just pick the first marker in cases where the text and color didn’t matter, you had to always know ahead of time what text and color the marker would have. In the past I would have dismissed an idea like this immediately. However, if we created the right public API this implementation detail wouldn’t need to feel brittle and unscalable to the developers writing UI tests. Given the alternatives, this was a pragmatic tradeoff.

Our MapMarker subclass of GMSMarker handles all the different types of markers. An example for how we’d identify just clusters:

If you are doing networking recording in your UI tests and want to identify a cluster with a certain text, you can do:

At this point we were ready to stand on the shoulders of giants. We built on top of the existing UI testing infrastructure developed by Lucas Lain. This infrastructure uses the Robot pattern, developed by Jake Wharton at Square for testing in Kotlin. The Compass codebase has many bots covering different parts of the app. These bots expose a public API for “what” the bot does. The developer then doesn’t need to focus on the “how”. A new bot would enable any iOS developer to add map verifications to their UI tests.

I developed the initial MapBot that can be used in any UI test. Here’s a simple test that uses the MapBot:

As people wrote new tests they added to and improved the original MapBot. We now support gestures, pins, clusters and custom boundaries. One exciting recent addition was support for tapping the map at a specific coordinate.

If you want to do the impossible, sometimes you just need to invest a little time. Challenging team goals can also push us to tackle problems we previously put off. Finally, a friendly API can make any code more appealing!

--

--