The Record -> Replay -> Review Flow

Heads up... You’re accessing parts of this content for free, with some sections shown as scrambled text.

Heads up... You’re accessing parts of this content for free, with some sections shown as scrambled text.

Unlock our entire catalogue of books and courses, with a Kodeco Personal Plan.

Unlock now

Phase 1: The Recording Process - Capturing User Intent

The “Record” phase is the developer’s entry point into the new UI automation workflow. It has been redesigned to be more than a simple macro recorder; it is now an intelligent assistant that helps generate clean, stable, and maintainable test code from the very first interaction.

Initiating a Recording Session

Starting a recording session is a straightforward process designed to integrate seamlessly into the existing Xcode workflow.

Intelligent Element Query Generation

This is where the power of the new recorder becomes apparent. As the developer interacts with the running application, Xcode captures these events and translates them into Swift code. However, unlike its predecessor, the new recorder employs an intelligent strategy for generating element queries.

Recording a User Flow: Adding a New Task

To illustrate this process, let’s record the user flow for adding a new task to the TaskMaster app.

@MainActor
func testAddTaskFlow() throws {
  let app = XCUIApplication()
  app.activate()
  app.buttons["addTaskButton"].firstMatch.tap()
  app.textFields["taskTitleField"].firstMatch.tap()
  app.textFields["taskTitleField"].firstMatch.typeText("Buy groceries")
  app.buttons["saveTaskButton"].firstMatch.tap()
}

Phase 2: The Replay Engine - Execution and Assertion

The “Replay” phase is where the recorded script is executed and, crucially, enhanced with assertions to validate the application’s state. A test script that runs without verifying an outcome is merely an automation; it is the assertion that transforms it into a true test. This phase also serves a dual purpose in the new workflow: it is the data-gathering engine that powers the comprehensive analysis in the “Review” phase.

Running Your UI Test

Xcode provides multiple convenient ways to execute UI tests, allowing for flexibility during development and debugging.

The Art of Assertion: Validating Application State

The core principle of testing is to verify that an actual outcome matches an expected outcome. In UI testing, this is accomplished through assertions. The XCTest framework provides a rich set of assertion functions, such as XCTAssertTrue, XCTAssertFalse, and XCTAssertEqual, to perform these checks.  

Enhancing the Recorded Script with Assertions

The script recorded in Phase 1 successfully automates the steps to add a task, but it doesn’t verify that the task was actually added. To make it a meaningful test, assertions must be added. A widely adopted best practice for structuring test code is the Arrange-Act-Assert (AAA) pattern, also known as Given-When-Then.  

@MainActor
func testAddTaskFlow() throws {
  let app = XCUIApplication()

  // Act 
  app.activate()
  app.buttons["addTaskButton"].firstMatch.tap()
  app.textFields["taskTitleField"].firstMatch.tap()
  app.textFields["taskTitleField"].firstMatch.typeText("Buy groceries")
  app.buttons["saveTaskButton"].firstMatch.tap()
  
  // Assert
  // 1. Verify that the new task cell exists in the list
  let newTaskCell = app.staticTexts
  XCTAssertTrue(newTaskCell["Buy groceries"].exists, "The new task is in the list.")
  
  // 2. Verify that the app has returned to the main task list view.
  let navigationBar = app.navigationBars["Tasks"]
  XCTAssertTrue(navigationBar.exists, "The user is in the main task list view.")
}

Handling Asynchronicity and Delays

In real-world applications, UI elements may not appear instantaneously. They might be loaded from a network request or appear after an animation. Using hard-coded delays like sleep() is an anti-pattern because it makes tests slow and unreliable; the test might fail on a slower machine or pass unnecessarily slowly on a faster one.  

// Assert
let newTaskCell = app.staticTexts
let cellExists = newTaskCell.element.waitForExistence(timeout: 5) // Wait up to 5 seconds
XCTAssertTrue(cellExists, "The new task cell should appear in the list after saving.")

Phase 3: The Review

The “Review” phase represents the most significant innovation in the new UI automation workflow. The Review, a powerful, integrated suite of tools within the Xcode Test Report navigator. This transforms test analysis from a binary pass/fail check into a deep, multi-faceted investigation of application quality. It provides actionable insights into visual correctness, performance, and accessibility, directly linking them to the specific user flow under test.

Xcode Report Navigator screen
Tyegu Beburq Jewoxejas wpqaef

Test break down screen
Mojw ggouq pudp xbfuoz

Test event break down screen
Mupc itupv ctuiw yihm nxhoor

Failed test event break down screen
Keusan qovq ilotv wruot sahv dnyiew

The Test Pyramid in a “Review” World

The “test pyramid” is a foundational concept in software testing, advocating for a large base of fast, inexpensive unit tests, a smaller layer of integration tests, and a very small, carefully selected set of end-to-end UI tests at the top.  

See forum comments
Download course materials from Github
Previous: Introducing the Sample Project Next: Conclusion