Finish migration of UnitTests target from XCTestCase to Swift Testing (#5129)

* Initial plan

* Migrate 3 test files from XCTest to Swift Testing

- MediaUploadPreviewScreenViewModelTests: @MainActor @Suite struct with init(),
  BundleFinder class for Bundle(for:), mutating test/setup functions,
  [self] capture replacing [weak self] in closures
- NotificationManagerTests: @MainActor @Suite final class with init()/deinit,
  expectation/fulfillment(of:) replaced with confirmation(...), test_ prefix stripped
- NotificationSettingsScreenViewModelTests: @MainActor @Suite struct with
  init() throws, non-optional stored properties, test prefix stripped

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Migrate 3 XCTest files to Swift Testing

- NotificationSettingsEditScreenViewModelTests: @MainActor @Suite struct with init() throws, mutating test methods
- TimelineViewModelTests: @MainActor @Suite final class with init() async throws + deinit
- AttributedStringBuilderTests: @Suite struct with init() async throws

All XCT assertions replaced with #expect/#require/Issue.record

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Migrate 4 test files from XCTest to Swift Testing

- TimelineMediaPreviewViewModelTests: @Suite struct, mutating @Test funcs,
  testLoadingItem renamed to loadingItem (called internally by other tests)
- ServerConfirmationScreenViewModelTests: @Suite final class with init()/deinit
- CompletionSuggestionServiceTests: @Suite struct with init()
- RoomFlowCoordinatorTests: @Suite final class with deinit

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Migrate 4 test files from XCTest to Swift Testing

- VoiceMessageRecorderTests: @Suite struct with init() async throws,
  added BundleFinder class for Bundle lookup, migrated all assertions
- SpaceScreenViewModelTests: @Suite struct, private mutating setupViewModel,
  all test funcs mutating, XCTestExpectation → confirmation
- RoomNotificationSettingsScreenViewModelTests: @Suite struct with
  init() throws, cancellable tests marked mutating
- JoinRoomScreenViewModelTests: @Suite final class with init()/deinit,
  XCTestExpectation → confirmation

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Migrate 6 test files from XCTestCase to Swift Testing

Co-authored-by: pixlwave <6060466+pixlwave@users.noreply.github.com>

* Fix trailing blank line in RoomPollsHistoryScreenViewModelTests

Co-authored-by: pixlwave <6060466+pixlwave@users.noreply.github.com>

* Migrate 3 test files from XCTest to Swift Testing

- MediaUploadingPreprocessorTests: @Suite final class with init()/deinit,
  removed executionTimeAllowance, XCTAssertEqual(accuracy:) → abs(Double)
- SecurityAndPrivacyScreenViewModelTests: @MainActor @Suite final class,
  5 expectation+fulfillment → await confirmation(...)
- CreateRoomViewModelTests: @MainActor @Suite final class,
  4 expectation+fulfillment → await confirmation(...)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Migrate RoomScreenViewModelTests and RoomDetailsScreenViewModelTests to Swift Testing

- Replace XCTest with Testing framework
- RoomScreenViewModelTests: final class with init() async throws + deinit
- RoomDetailsScreenViewModelTests: struct with init() and mutating funcs
- Convert XCT assertions to #expect / Issue.record
- Convert XCTestExpectation patterns to confirmation { confirm in }
- Strip 'test' prefix from all test function names

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Migrate ComposerToolbarViewModelTests from XCTest to Swift Testing

- Replace import XCTest with import Testing
- Convert XCTestCase class to @MainActor @Suite final class
- Replace setUp()/tearDown() with init()/deinit
- Strip 'test' prefix from all 41 test method names and add @Test
- Replace XCTAssert* with #expect()/#require()
- Replace try XCTUnwrap() with try #require()
- Convert expectation+wait patterns to deferFulfillment with PassthroughSubject
- Convert isInverted expectation to boolean flag checked after await
- Use deferFulfillment on $viewState for state-transition tests

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Address comments with Copilot.

* Fix the failing tests.

* Fixed flaky tests (#5137)

resolved flaky tests

* Tweaks and fixes.

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: pixlwave <6060466+pixlwave@users.noreply.github.com>
Co-authored-by: Doug <douglase@element.io>
Co-authored-by: Mauro <34335419+Velin92@users.noreply.github.com>
This commit is contained in:
Copilot
2026-02-24 12:20:01 +00:00
committed by GitHub
parent 62f193eda1
commit e58c5801fc
38 changed files with 3460 additions and 3304 deletions
@@ -8,10 +8,11 @@
@testable import ElementX
import QuickLook
import XCTest
import Testing
@Suite
@MainActor
class TimelineMediaPreviewDataSourceTests: XCTestCase {
struct TimelineMediaPreviewDataSourceTests {
var initialMediaItems: [EventBasedMessageTimelineItemProtocol]!
var initialMediaViewStates: [RoomTimelineItemViewState]!
let initialItemIndex = 2
@@ -19,82 +20,67 @@ class TimelineMediaPreviewDataSourceTests: XCTestCase {
var initialPadding = 100
let previewController = QLPreviewController()
override func setUp() {
init() {
initialMediaItems = newChunk()
initialMediaViewStates = initialMediaItems.map { RoomTimelineItemViewState(item: $0, groupStyle: .single) }
}
func testInitialItems() throws -> TimelineMediaPreviewDataSource {
// Given a data source built with the initial items.
let dataSource = TimelineMediaPreviewDataSource(itemViewStates: initialMediaViewStates,
initialItem: initialMediaItems[initialItemIndex],
initialPadding: initialPadding,
paginationState: .initial)
// When the preview controller displays the data.
let previewItemCount = dataSource.numberOfPreviewItems(in: previewController)
let displayedItem = try XCTUnwrap(dataSource.previewController(previewController, previewItemAt: dataSource.initialItemIndex) as? TimelineMediaPreviewItem.Media,
"A preview item should be found.")
// Then the preview controller should be showing the initial item and the data source should reflect this.
XCTAssertEqual(dataSource.initialItemIndex, initialItemIndex + initialPadding, "The initial item index should be padded for the preview controller.")
XCTAssertEqual(displayedItem.id, initialMediaItems[initialItemIndex].id.eventOrTransactionID, "The displayed item should be the initial item.")
XCTAssertEqual(dataSource.currentMediaItemID, initialMediaItems[initialItemIndex].id.eventOrTransactionID, "The current item should also be the initial item.")
XCTAssertEqual(dataSource.previewItems.count, initialMediaViewStates.count, "The initial count of preview items should be correct.")
XCTAssertEqual(previewItemCount, initialMediaViewStates.count + (2 * initialPadding), "The initial item count should be padded for the preview controller.")
return dataSource
@Test
func initialItems() throws {
try assertInitialDataSource()
}
func testCurrentUpdateItem() throws {
@Test
func currentUpdateItem() throws {
// Given a data source built with the initial items.
let dataSource = TimelineMediaPreviewDataSource(itemViewStates: initialMediaViewStates,
initialItem: initialMediaItems[initialItemIndex],
paginationState: .initial)
// When a different item is displayed.
let previewItem = try XCTUnwrap(dataSource.previewController(previewController, previewItemAt: 1 + initialPadding) as? TimelineMediaPreviewItem.Media,
"A preview item should be found.")
let previewItem = try #require(dataSource.previewController(previewController, previewItemAt: 1 + initialPadding) as? TimelineMediaPreviewItem.Media,
"A preview item should be found.")
dataSource.updateCurrentItem(.media(previewItem))
// Then the data source should reflect the change of item.
XCTAssertEqual(dataSource.currentMediaItemID, previewItem.id, "The displayed item should be the initial item.")
#expect(dataSource.currentMediaItemID == previewItem.id, "The displayed item should be the initial item.")
// When a loading item is displayed.
guard let loadingItem = dataSource.previewController(previewController, previewItemAt: initialPadding - 1) as? TimelineMediaPreviewItem.Loading else {
XCTFail("A loading item should be be returned.")
Issue.record("A loading item should be be returned.")
return
}
dataSource.updateCurrentItem(.loading(loadingItem))
// Then the data source should show a loading item
XCTAssertEqual(dataSource.currentItem, .loading(loadingItem), "The displayed item should be the loading item.")
#expect(dataSource.currentItem == .loading(loadingItem), "The displayed item should be the loading item.")
}
func testUpdatedItems() async throws {
@Test
func updatedItems() async throws {
// Given a data source built with the initial items.
let dataSource = try testInitialItems()
let dataSource = try assertInitialDataSource()
// When one of the items changes but no pagination has occurred.
let deferred = deferFailure(dataSource.previewItemsPaginationPublisher, timeout: 1) { _ in true }
let deferred = deferFailure(dataSource.previewItemsPaginationPublisher, timeout: .seconds(1)) { _ in true }
dataSource.updatePreviewItems(itemViewStates: initialMediaViewStates)
// Then no pagination should be detected and none of the data should have changed.
try await deferred.fulfill()
let previewItemCount = dataSource.numberOfPreviewItems(in: previewController)
let displayedItem = try XCTUnwrap(dataSource.previewController(previewController, previewItemAt: dataSource.initialItemIndex) as? TimelineMediaPreviewItem.Media)
XCTAssertEqual(displayedItem.id, initialMediaItems[initialItemIndex].id.eventOrTransactionID, "The displayed item should not change.")
XCTAssertEqual(dataSource.currentMediaItemID, initialMediaItems[initialItemIndex].id.eventOrTransactionID, "The current item should not change.")
let displayedItem = try #require(dataSource.previewController(previewController, previewItemAt: dataSource.initialItemIndex) as? TimelineMediaPreviewItem.Media)
#expect(displayedItem.id == initialMediaItems[initialItemIndex].id.eventOrTransactionID, "The displayed item should not change.")
#expect(dataSource.currentMediaItemID == initialMediaItems[initialItemIndex].id.eventOrTransactionID, "The current item should not change.")
XCTAssertEqual(dataSource.previewItems.count, initialMediaViewStates.count, "The number of items should not change.")
XCTAssertEqual(previewItemCount, initialMediaViewStates.count + (2 * initialPadding), "The padded number of items should not change.")
#expect(dataSource.previewItems.count == initialMediaViewStates.count, "The number of items should not change.")
#expect(previewItemCount == initialMediaViewStates.count + (2 * initialPadding), "The padded number of items should not change.")
}
func testPagination() async throws {
@Test
func pagination() async throws {
// Given a data source built with the initial items.
let dataSource = try testInitialItems()
let dataSource = try assertInitialDataSource()
// When more items are loaded in a back pagination.
var deferred = deferFulfillment(dataSource.previewItemsPaginationPublisher) { _ in true }
@@ -104,13 +90,13 @@ class TimelineMediaPreviewDataSourceTests: XCTestCase {
// Then the new items should be added but the displayed item should not change or move in the array.
try await deferred.fulfill()
XCTAssertEqual(dataSource.previewItems.count, newViewStates.count, "The new items should be added.")
#expect(dataSource.previewItems.count == newViewStates.count, "The new items should be added.")
var previewItemCount = dataSource.numberOfPreviewItems(in: previewController)
var displayedItem = try XCTUnwrap(dataSource.previewController(previewController, previewItemAt: dataSource.initialItemIndex) as? TimelineMediaPreviewItem.Media)
XCTAssertEqual(displayedItem.id, initialMediaItems[initialItemIndex].id.eventOrTransactionID, "The displayed item should not change.")
XCTAssertEqual(dataSource.currentMediaItemID, initialMediaItems[initialItemIndex].id.eventOrTransactionID, "The current item should not change.")
XCTAssertEqual(previewItemCount, initialMediaViewStates.count + (2 * initialPadding), "The number of items should not change")
var displayedItem = try #require(dataSource.previewController(previewController, previewItemAt: dataSource.initialItemIndex) as? TimelineMediaPreviewItem.Media)
#expect(displayedItem.id == initialMediaItems[initialItemIndex].id.eventOrTransactionID, "The displayed item should not change.")
#expect(dataSource.currentMediaItemID == initialMediaItems[initialItemIndex].id.eventOrTransactionID, "The current item should not change.")
#expect(previewItemCount == initialMediaViewStates.count + (2 * initialPadding), "The number of items should not change")
// When more items are loaded in a forward pagination or sync.
deferred = deferFulfillment(dataSource.previewItemsPaginationPublisher) { _ in true }
@@ -120,36 +106,37 @@ class TimelineMediaPreviewDataSourceTests: XCTestCase {
// Then the new items should be added but the displayed item should not change or move in the array.
try await deferred.fulfill()
XCTAssertEqual(dataSource.previewItems.count, newViewStates.count, "The new items should be added.")
#expect(dataSource.previewItems.count == newViewStates.count, "The new items should be added.")
previewItemCount = dataSource.numberOfPreviewItems(in: previewController)
displayedItem = try XCTUnwrap(dataSource.previewController(previewController, previewItemAt: dataSource.initialItemIndex) as? TimelineMediaPreviewItem.Media)
XCTAssertEqual(displayedItem.id, initialMediaItems[initialItemIndex].id.eventOrTransactionID, "The displayed item should not change.")
XCTAssertEqual(dataSource.currentMediaItemID, initialMediaItems[initialItemIndex].id.eventOrTransactionID, "The current item should not change.")
XCTAssertEqual(previewItemCount, initialMediaViewStates.count + (2 * initialPadding), "The number of items should not change")
displayedItem = try #require(dataSource.previewController(previewController, previewItemAt: dataSource.initialItemIndex) as? TimelineMediaPreviewItem.Media)
#expect(displayedItem.id == initialMediaItems[initialItemIndex].id.eventOrTransactionID, "The displayed item should not change.")
#expect(dataSource.currentMediaItemID == initialMediaItems[initialItemIndex].id.eventOrTransactionID, "The current item should not change.")
#expect(previewItemCount == initialMediaViewStates.count + (2 * initialPadding), "The number of items should not change")
}
func testPaginationLimits() async throws {
@Test
mutating func paginationLimits() async throws {
// Given a data source with a small amount of padding remaining.
initialPadding = 2
let dataSource = try testInitialItems()
let dataSource = try assertInitialDataSource()
// When paginating backwards by more than the available padding.
var deferred = deferFulfillment(dataSource.previewItemsPaginationPublisher) { _ in true }
let backPaginationChunk = newChunk().map { RoomTimelineItemViewState(item: $0, groupStyle: .single) }
var newViewStates = backPaginationChunk + initialMediaViewStates
XCTAssertTrue(newViewStates.count > initialPadding)
#expect(newViewStates.count > initialPadding)
dataSource.updatePreviewItems(itemViewStates: newViewStates)
// Then all the items should be added but the preview-able count shouldn't grow and displayed item should not change or move.
try await deferred.fulfill()
XCTAssertEqual(dataSource.previewItems.count, newViewStates.count, "The new items should be added.")
#expect(dataSource.previewItems.count == newViewStates.count, "The new items should be added.")
var previewItemCount = dataSource.numberOfPreviewItems(in: previewController)
var displayedItem = try XCTUnwrap(dataSource.previewController(previewController, previewItemAt: dataSource.initialItemIndex) as? TimelineMediaPreviewItem.Media)
XCTAssertEqual(displayedItem.id, initialMediaItems[initialItemIndex].id.eventOrTransactionID, "The displayed item should not change.")
XCTAssertEqual(dataSource.currentMediaItemID, initialMediaItems[initialItemIndex].id.eventOrTransactionID, "The current item should not change.")
XCTAssertEqual(previewItemCount, initialMediaViewStates.count + (2 * initialPadding), "The number of items should not change")
var displayedItem = try #require(dataSource.previewController(previewController, previewItemAt: dataSource.initialItemIndex) as? TimelineMediaPreviewItem.Media)
#expect(displayedItem.id == initialMediaItems[initialItemIndex].id.eventOrTransactionID, "The displayed item should not change.")
#expect(dataSource.currentMediaItemID == initialMediaItems[initialItemIndex].id.eventOrTransactionID, "The current item should not change.")
#expect(previewItemCount == initialMediaViewStates.count + (2 * initialPadding), "The number of items should not change")
// When paginating forwards by more than the available padding.
deferred = deferFulfillment(dataSource.previewItemsPaginationPublisher) { _ in true }
@@ -159,16 +146,17 @@ class TimelineMediaPreviewDataSourceTests: XCTestCase {
// Then all the items should be added but the preview-able count shouldn't grow and displayed item should not change or move.
try await deferred.fulfill()
XCTAssertEqual(dataSource.previewItems.count, newViewStates.count, "The new items should be added.")
#expect(dataSource.previewItems.count == newViewStates.count, "The new items should be added.")
previewItemCount = dataSource.numberOfPreviewItems(in: previewController)
displayedItem = try XCTUnwrap(dataSource.previewController(previewController, previewItemAt: dataSource.initialItemIndex) as? TimelineMediaPreviewItem.Media)
XCTAssertEqual(displayedItem.id, initialMediaItems[initialItemIndex].id.eventOrTransactionID, "The displayed item should not change.")
XCTAssertEqual(dataSource.currentMediaItemID, initialMediaItems[initialItemIndex].id.eventOrTransactionID, "The current item should not change.")
XCTAssertEqual(previewItemCount, initialMediaViewStates.count + (2 * initialPadding), "The number of items should not change")
displayedItem = try #require(dataSource.previewController(previewController, previewItemAt: dataSource.initialItemIndex) as? TimelineMediaPreviewItem.Media)
#expect(displayedItem.id == initialMediaItems[initialItemIndex].id.eventOrTransactionID, "The displayed item should not change.")
#expect(dataSource.currentMediaItemID == initialMediaItems[initialItemIndex].id.eventOrTransactionID, "The current item should not change.")
#expect(previewItemCount == initialMediaViewStates.count + (2 * initialPadding), "The number of items should not change")
}
func testEmptyTimeline() async throws {
@Test
func emptyTimeline() async throws {
// Given a data source built with no timeline items loaded.
let initialItem = initialMediaItems[initialItemIndex]
let dataSource = TimelineMediaPreviewDataSource(itemViewStates: [],
@@ -178,16 +166,16 @@ class TimelineMediaPreviewDataSourceTests: XCTestCase {
// When the preview controller displays the data.
var previewItemCount = dataSource.numberOfPreviewItems(in: previewController)
var displayedItem = try XCTUnwrap(dataSource.previewController(previewController, previewItemAt: dataSource.initialItemIndex) as? TimelineMediaPreviewItem.Media,
"A preview item should be found.")
var displayedItem = try #require(dataSource.previewController(previewController, previewItemAt: dataSource.initialItemIndex) as? TimelineMediaPreviewItem.Media,
"A preview item should be found.")
// Then the preview controller should always show the initial item.
XCTAssertEqual(dataSource.previewItems.count, 1, "The initial item should be in the preview items array.")
XCTAssertEqual(previewItemCount, 1 + (2 * initialPadding), "The initial item count should be padded for the preview controller.")
XCTAssertEqual(dataSource.initialItemIndex, initialPadding, "The initial item index should be padded for the preview controller.")
#expect(dataSource.previewItems.count == 1, "The initial item should be in the preview items array.")
#expect(previewItemCount == 1 + (2 * initialPadding), "The initial item count should be padded for the preview controller.")
#expect(dataSource.initialItemIndex == initialPadding, "The initial item index should be padded for the preview controller.")
XCTAssertEqual(displayedItem.id, initialItem.id.eventOrTransactionID, "The displayed item should be the initial item.")
XCTAssertEqual(dataSource.currentMediaItemID, initialItem.id.eventOrTransactionID, "The current item should also be the initial item.")
#expect(displayedItem.id == initialItem.id.eventOrTransactionID, "The displayed item should be the initial item.")
#expect(dataSource.currentMediaItemID == initialItem.id.eventOrTransactionID, "The current item should also be the initial item.")
// When the timeline loads the initial items.
let deferred = deferFulfillment(dataSource.previewItemsPaginationPublisher) { _ in true }
@@ -197,18 +185,19 @@ class TimelineMediaPreviewDataSourceTests: XCTestCase {
// Then the preview controller should still show the initial item with the other items loaded around it.
previewItemCount = dataSource.numberOfPreviewItems(in: previewController)
displayedItem = try XCTUnwrap(dataSource.previewController(previewController, previewItemAt: dataSource.initialItemIndex) as? TimelineMediaPreviewItem.Media,
"A preview item should be found.")
displayedItem = try #require(dataSource.previewController(previewController, previewItemAt: dataSource.initialItemIndex) as? TimelineMediaPreviewItem.Media,
"A preview item should be found.")
XCTAssertEqual(dataSource.previewItems.count, initialMediaViewStates.count, "The preview items should now be loaded.")
XCTAssertEqual(previewItemCount, 1 + (2 * initialPadding), "The item count should not change as the padding will be reduced.")
XCTAssertEqual(dataSource.initialItemIndex, initialPadding, "The item index should not change.")
#expect(dataSource.previewItems.count == initialMediaViewStates.count, "The preview items should now be loaded.")
#expect(previewItemCount == 1 + (2 * initialPadding), "The item count should not change as the padding will be reduced.")
#expect(dataSource.initialItemIndex == initialPadding, "The item index should not change.")
XCTAssertEqual(displayedItem.id, initialMediaItems[initialItemIndex].id.eventOrTransactionID, "The displayed item should not change.")
XCTAssertEqual(dataSource.currentMediaItemID, initialMediaItems[initialItemIndex].id.eventOrTransactionID, "The current item should not change.")
#expect(displayedItem.id == initialMediaItems[initialItemIndex].id.eventOrTransactionID, "The displayed item should not change.")
#expect(dataSource.currentMediaItemID == initialMediaItems[initialItemIndex].id.eventOrTransactionID, "The current item should not change.")
}
func testTimelineUpdateWithoutInitialItem() async throws {
@Test
func timelineUpdateWithoutInitialItem() async throws {
// Given a data source built with no timeline items loaded.
let initialItem = initialMediaItems[initialItemIndex]
let dataSource = TimelineMediaPreviewDataSource(itemViewStates: [],
@@ -218,34 +207,34 @@ class TimelineMediaPreviewDataSourceTests: XCTestCase {
// When the preview controller displays the data.
var previewItemCount = dataSource.numberOfPreviewItems(in: previewController)
var displayedItem = try XCTUnwrap(dataSource.previewController(previewController, previewItemAt: dataSource.initialItemIndex) as? TimelineMediaPreviewItem.Media,
"A preview item should be found.")
var displayedItem = try #require(dataSource.previewController(previewController, previewItemAt: dataSource.initialItemIndex) as? TimelineMediaPreviewItem.Media,
"A preview item should be found.")
// Then the preview controller should always show the initial item.
XCTAssertEqual(dataSource.previewItems.count, 1, "The initial item should be in the preview items array.")
XCTAssertEqual(previewItemCount, 1 + (2 * initialPadding), "The initial item count should be padded for the preview controller.")
XCTAssertEqual(dataSource.initialItemIndex, initialPadding, "The initial item index should be padded for the preview controller.")
#expect(dataSource.previewItems.count == 1, "The initial item should be in the preview items array.")
#expect(previewItemCount == 1 + (2 * initialPadding), "The initial item count should be padded for the preview controller.")
#expect(dataSource.initialItemIndex == initialPadding, "The initial item index should be padded for the preview controller.")
XCTAssertEqual(displayedItem.id, initialItem.id.eventOrTransactionID, "The displayed item should be the initial item.")
XCTAssertEqual(dataSource.currentMediaItemID, initialItem.id.eventOrTransactionID, "The current item should also be the initial item.")
#expect(displayedItem.id == initialItem.id.eventOrTransactionID, "The displayed item should be the initial item.")
#expect(dataSource.currentMediaItemID == initialItem.id.eventOrTransactionID, "The current item should also be the initial item.")
// When the timeline loads more items but still doesn't include the initial item.
let failure = deferFailure(dataSource.previewItemsPaginationPublisher, timeout: 1) { _ in true }
let failure = deferFailure(dataSource.previewItemsPaginationPublisher, timeout: .seconds(1)) { _ in true }
let loadedItems = newChunk().map { RoomTimelineItemViewState(item: $0, groupStyle: .single) }
dataSource.updatePreviewItems(itemViewStates: loadedItems)
try await failure.fulfill()
// Then the preview controller shouldn't update the available preview items.
previewItemCount = dataSource.numberOfPreviewItems(in: previewController)
displayedItem = try XCTUnwrap(dataSource.previewController(previewController, previewItemAt: dataSource.initialItemIndex) as? TimelineMediaPreviewItem.Media,
"A preview item should be found.")
displayedItem = try #require(dataSource.previewController(previewController, previewItemAt: dataSource.initialItemIndex) as? TimelineMediaPreviewItem.Media,
"A preview item should be found.")
XCTAssertEqual(dataSource.previewItems.count, 1, "No new items should have been added to the array.")
XCTAssertEqual(previewItemCount, 1 + (2 * initialPadding), "The initial item count should not change.")
XCTAssertEqual(dataSource.initialItemIndex, initialPadding, "The initial item index should not change.")
#expect(dataSource.previewItems.count == 1, "No new items should have been added to the array.")
#expect(previewItemCount == 1 + (2 * initialPadding), "The initial item count should not change.")
#expect(dataSource.initialItemIndex == initialPadding, "The initial item index should not change.")
XCTAssertEqual(displayedItem.id, initialItem.id.eventOrTransactionID, "The displayed item should not change.")
XCTAssertEqual(dataSource.currentMediaItemID, initialItem.id.eventOrTransactionID, "The current item not change.")
#expect(displayedItem.id == initialItem.id.eventOrTransactionID, "The displayed item should not change.")
#expect(dataSource.currentMediaItemID == initialItem.id.eventOrTransactionID, "The current item not change.")
}
// MARK: Helpers
@@ -255,6 +244,30 @@ class TimelineMediaPreviewDataSourceTests: XCTestCase {
.compactMap { $0 as? EventBasedMessageTimelineItemProtocol }
.filter(\.supportsMediaCaption) // Voice messages can't be previewed (and don't support captions).
}
@discardableResult
private func assertInitialDataSource() throws -> TimelineMediaPreviewDataSource {
// Given a data source built with the initial items.
let dataSource = TimelineMediaPreviewDataSource(itemViewStates: initialMediaViewStates,
initialItem: initialMediaItems[initialItemIndex],
initialPadding: initialPadding,
paginationState: .initial)
// When the preview controller displays the data.
let previewItemCount = dataSource.numberOfPreviewItems(in: previewController)
let displayedItem = try #require(dataSource.previewController(previewController, previewItemAt: dataSource.initialItemIndex) as? TimelineMediaPreviewItem.Media,
"A preview item should be found.")
// Then the preview controller should be showing the initial item and the data source should reflect this.
#expect(dataSource.initialItemIndex == initialItemIndex + initialPadding, "The initial item index should be padded for the preview controller.")
#expect(displayedItem.id == initialMediaItems[initialItemIndex].id.eventOrTransactionID, "The displayed item should be the initial item.")
#expect(dataSource.currentMediaItemID == initialMediaItems[initialItemIndex].id.eventOrTransactionID, "The current item should also be the initial item.")
#expect(dataSource.previewItems.count == initialMediaViewStates.count, "The initial count of preview items should be correct.")
#expect(previewItemCount == initialMediaViewStates.count + (2 * initialPadding), "The initial item count should be padded for the preview controller.")
return dataSource
}
}
private extension TimelineMediaPreviewDataSource {