DEV Community

Cover image for XCUITest Collection Testing: Automating Tables, Lists and Dynamic Content
QAPulse by SK
QAPulse by SK

Posted on Originally published at skakarh.com

XCUITest Collection Testing: Automating Tables, Lists and Dynamic Content

XCUITest Collection Testing is essential for validating iOS interfaces where users interact with tables, collection views, lists, reusable cells, and dynamically loaded content. Unlike static screens, collection-based interfaces constantly change their visible elements, positions, and data, making reliable element identification, scrolling, synchronization, and state validation critical for production-grade UI automation.

What is XCUITest Collection Testing?

XCUITest Collection Testing is the practice of automating and validating iOS tables, collection views, lists, reusable cells, and dynamic content using XCUITest.

Common targets include:

  • UITableView
  • UICollectionView
  • SwiftUI List
  • SwiftUI LazyVStack
  • SwiftUI LazyVGrid
  • Dynamic search results
  • Infinite scrolling feeds
  • Reusable cells
  • Paginated content
  • Empty states
  • Loading states
  • Error states
  • Dynamic badges
  • Expandable rows
  • Nested collection content

A typical automation workflow looks like this:

Launch Application
       ↓
Locate Collection
       ↓
Wait for Content
       ↓
Find Target Cell
       ↓
Scroll if Required
       ↓
Interact With Cell
       ↓
Validate Cell State
       ↓
Validate Result
Enter fullscreen mode Exit fullscreen mode

Definition

XCUITest Collection Testing validates the behavior, structure, interaction, scrolling, synchronization, and dynamic state of iOS tables, lists, collection views, and reusable content.

Key Points

  • Use stable accessibility identifiers.
  • Query collections semantically.
  • Avoid hard-coded indexes when possible.
  • Synchronize with dynamic content.
  • Use waitForExistence(timeout:).
  • Check isHittable before interaction.
  • Scroll based on target visibility.
  • Validate cell content.
  • Test empty and loading states.
  • Test pagination and infinite scrolling.
  • Validate dynamic content changes.
  • Separate collection structure from business assertions.
  • Use reusable Page Objects for complex collections.
  • Avoid coordinate-based scrolling.
  • Do not rely blindly on firstMatch.
  • Validate the result after cell interaction.

Why Collection Testing Is Different

A static screen might contain:

Login
Email
Password
Login Button
Enter fullscreen mode Exit fullscreen mode

The structure is predictable.

A collection screen can contain:

Item 1
Item 2
Item 3
Item 4
...
Item 1000
Enter fullscreen mode Exit fullscreen mode

Only a subset may exist in the visible viewport.

The application may also load content progressively:

Initial Request
      ↓
Loading
      ↓
First 20 Items
      ↓
Scroll
      ↓
Next Request
      ↓
Next 20 Items
      ↓
Continue
Enter fullscreen mode Exit fullscreen mode

This creates several automation challenges.

Dynamic Position

A target item may not always be at index 4.

Dynamic Data

Content may change between test runs.

Reusable Cells

The same cell structure may represent different records.

Lazy Loading

Elements may not exist until the user scrolls.

Asynchronous Updates

The collection can change after an API response.

Therefore, robust XCUITest Collection Testing should identify content by meaning rather than position whenever possible.

1. Finding a Table

A table can commonly be queried through:

let table =
    app.tables.firstMatch
Enter fullscreen mode Exit fullscreen mode

Then synchronize:

XCTAssertTrue(
    table.waitForExistence(
        timeout: 10
    )
)
Enter fullscreen mode Exit fullscreen mode

A more reliable approach is to provide an accessibility identifier:

let table =
    app.tables[
        "products.table"
    ]
Enter fullscreen mode Exit fullscreen mode

Then:

XCTAssertTrue(
    table.waitForExistence(
        timeout: 10
    )
)
Enter fullscreen mode Exit fullscreen mode

Stable identifiers are preferable when you control the application code.

2. Finding Table Cells

A basic query is:

let cell =
    app.cells["product.cell"]
Enter fullscreen mode Exit fullscreen mode

However, reusable cells normally represent multiple records.

Instead of relying only on a generic cell identifier, expose meaningful identifiers for important content.

For example:

products.cell.101
products.cell.102
products.cell.103
Enter fullscreen mode Exit fullscreen mode

Or use stable business identifiers:

product.iphone15
product.macbook
product.airpods
Enter fullscreen mode Exit fullscreen mode

Then:

let product =
    app.cells[
        "product.iphone15"
    ]
Enter fullscreen mode Exit fullscreen mode

This is usually more maintainable than:

app.cells.element(
    boundBy: 5
)
Enter fullscreen mode Exit fullscreen mode

3. Why Index-Based Queries Are Fragile

Consider:

let cell =
    app.cells.element(
        boundBy: 4
    )
Enter fullscreen mode Exit fullscreen mode

This assumes the target is always the fifth cell.

That assumption can break when:

  • Sorting changes.
  • Filtering changes.
  • New records are inserted.
  • Backend data changes.
  • Feature flags change.
  • Personalization changes.
  • Pagination changes.
  • Ads appear.
  • A header is introduced.

Instead, identify the actual content:

let cell =
    app.cells[
        "product.iphone15"
    ]
Enter fullscreen mode Exit fullscreen mode

This makes the test intention explicit.

4. Testing Collection Content

Finding a cell is not enough.

Validate its content:


👉 Continue reading the full article on skakarh.com →

Originally published at skakarh.com/xcuitest-collection-testing.
Subscribe to QA Pulse by SK
weekly signal for QA, Test Automation and AI in Software Engineering.

Top comments (0)