Fixing Animations in UI Tests
Book

Exploring Freelancing

Navigate freelancing as a developer; find clients, manage contracts, ensure timely payment, and learn from experiences!

While running my UI tests for a UI refactor, I noticed that two of them failed repeatedly.

I wasn’t sure what was going wrong until I remembered replacing the normal buttons with a conditional view that changed the text.

And I added a subtle animation when the condition changes.

The tests finish before the animation is completed, and the text isn’t changed, leading to the test being failed.

func testNextButton() {
  app.buttons["rgb"].tap()
  
  let evaluateButton = app.buttons["evaluate"]
  
  evaluateButton.tap()
  
  /// Cannot find the "next" text
  let nextButton = app.buttons["next"]
  
  nextButton.tap()
  
  evaluateButton.tap()
  nextButton.tap()
}

The solution to this was disabling both normal and core animations.

I added a launch argument to detect that UI tests are running, and disable the animation accordingly.

struct LaunchArguments {
  static let isRunningUITests = "isRunningUITests"
}

In the test class, I appended the launch argument before the app launches:

class Chroma_GameUITests: XCTestCase {
  let app = XCUIApplication()

  override func setUpWithError() throws {
    continueAfterFailure = false
    app.launchArguments.append(LaunchArguments.isRunningUITests)
    app.launch()
}

And check for this launch argument in the App:

extension ChromaApp {
  private func checkForUITests() {
    if ProcessInfo.processInfo.arguments.contains(LaunchArguments.isRunningUITests) {
      if let scene = UIApplication.shared.connectedScenes.first,
         let windowSceneDelegate = scene.delegate as? UIWindowSceneDelegate,
         let window = windowSceneDelegate.window {
        // Disable Core Animations
        window?.layer.speed = 0
      }
      
      // Disable UIView animations
      UIView.setAnimationsEnabled(false)
    }
  }
}

Running Tests Repeatedly

In Xcode 13, there’s a new feature where you can right-click the diamond icon and run the tests repeatedly:

Tests options after clicking the diamond button

Then, you can configure the maximum repetitions, when the test stops, and if you want to relaunch the test after each repetition:

Options for repeating the tests

To be 100% sure, I ran the conflicting test 100 times, both before disabling animations and afterward. It always fails when the animation isn’t disabled and passes when the animation is disabled.

This solves the problem I initially didn’t have but was created by adding that subtle animation on the button.

If you have got a better approach, then tag me on @rudrankriyam on Twitter!

Thanks for reading!

Book

Exploring Freelancing

Navigate freelancing as a developer; find clients, manage contracts, ensure timely payment, and learn from experiences!

Written by

Rudrank Riyam

Hi, my name is Rudrank. I create apps for Apple Platforms while listening to music all day and night. Author of "Exploring MusicKit". Apple WWDC 2019 scholarship winner.