Documenting iOS apps, visually

How we built and use UI automation to snap full view hierarchies of the app in each page and export them to a Sketch file.

Let’s admit it, it’s hard to remember all the UIView’s classes, even in medium-sized iOS apps. There’re hundreds of those files, made by multiple people, using different languages, scattered around the whole project!

TL;DR: We use UI automation to snap full view hierarchies of the app in each page and export them to a Sketch file.
👉 Check out the code.

Searching for a UIButton

True Story

First you look at the page in a running app. You notice it’s not a regular UIButton, there might be some subclass going on.

Then you guess:

“Oh it’s a button to add item to the cart, must be something like AddToCartButton.swift"

You type it on Open Quickly, found one with a slightly different name, AddCartButton.swift. It’s close enough. You also found a XIB file, AddCartButton.xib! So you think:

“Thanks god we use Interface Builder. Now I know how it looks like just by looking at it.”

Then you wait for the XIB to open… Luckily Xcode doesn’t crash, but seems like it’s not the one you’re looking for. Anyway, you come up with another guess:

“Hmm. It’s in Promotion page, it might be PromotionCartButton something.”

Then you might either go with a combination of this:
  • Repeat that guessing process again with that name,
  • Find the one who actually knows (and hopefully that person remembers),
  • Trace from a view controller (in case you know which one),
  • Trace from Main.storyboard,
  • Trace from AppDelegate.swift and search all the way down,
  • Also don’t forget we also have to deal with programmatically-created views separately.

After going through them, you finally get the answer.

And it turns out that…

It’s a regular UIButton, embedded in a custom UIView subclass AddToCartView! There’s no way we would know this.

A Visual Documentation for App

With UI automation testing, we can take snapshot of an app in realtime as the bot navigates through it.

To do this we use Salsa to exports iOS views to a Sketch file. We can mirror the exact view hierarchy of a running app in various states.

A sample test case:

import EarlGrey
import Salsa
import XCTest
@testable import YourApp

class Test: XCTestCase {
  override func setup() {
  func testSnap() {
    let allTabBarsFlow = artboardSession(name: "All TabBars") { (s) in
      tap(id: "Tab1")
      s.snapWindow(name: "Tab 1")

      tap(id: "Tab2")
      s.snapWindow(name: "Tab 2")
    // Stack all artboards vertically
    let artboards = AutoSketch.arrange(layers: [[allTabBarsFlow, ...]], verticalPadding: 200, horizontalPadding: 200)
    let page = Page(name: "Artboards", layers: artboards)
    let document = Document(pages: [page], colors: [], textStyles: [])

    do {
      try document.export()
    } catch let error {
      XCTFail("Failed to export file: \(error)")

With Salsa + UI automation, we can make a Sketch file that consists of the whole app flow, allowing us to debug views almost instantly on Sketch. It’s like Xcode’s View Debugging on steroid.

New team members can just click the view group and know its subclass instantly.

Just check out how to setup here:

It’s not a silver bullet though, considering all these points:

  • No need to wait for XIBs or Storyboards to load.
  • No more guesswork on the view subclass names.
  • Works with programmatically-created views.
  • Contains the context of each view well. For example, similar-looking buttons on different pages may use different XIBs. Does this page use collection view, table view, or just a custom view? Are these reusable cells or just views? Each view is in its own file and it depends on how it’s used. Good luck searching for it the whole project (cmd + shift + f).
  • The bigger a development team, the better its benefits.
  • Quick to get brief overview of the app.

  • Cannot capture the whole scroll view, table view, or collection view content, as some content is out of screen. One workaround is to scroll down and capture, but kind of awkward. But if you use scroll view with a wrapper content view, you can capture that content view instead.
  • UI automation through your whole app is the most work here. It’s a trial-and-error process. Find the button to tap, waiting for loading indicator to hide until you can capture, waiting for something to appear etc.
  • Need to rerun automation when there’s major change.

The End Result

View Debugging with the generated Sketch file

Groups are almost the exact copy of what you see in the View Debugging feature of Xcode.
Like 238 likes
AunR Rueopas

Join the conversation

This will be shown public
All comments are moderated

Get our stories delivered

From us to your inbox weekly.