diff --git a/Forji/ForjiTests/PaginationStateTests.swift b/Forji/ForjiTests/PaginationStateTests.swift index 32cd25f..c8cabd6 100644 --- a/Forji/ForjiTests/PaginationStateTests.swift +++ b/Forji/ForjiTests/PaginationStateTests.swift @@ -439,3 +439,50 @@ struct PaginationStateLoadMoreTests { #expect(!pagination.isLoading) } } + +// MARK: - Keyed de-duplication + +struct PaginationStateDedupeTests { + + @Test @MainActor func loadMoreFiltersKeysSeenOnEarlierPages() async { + let pagination = PaginationState(pageSize: 2) + pagination.dedupeKey = { $0 } + await pagination.reload { _, _ in ["a", "b"] }.value + + // "b" resurfaces on page 2 — only "c" is new + await pagination.loadMore { _, _ in ["b", "c"] } + #expect(pagination.items == ["a", "b", "c"]) + #expect(pagination.hasMore) // the page contributed a new item + } + + @Test @MainActor func hasMoreFollowsNewItemsNotPageSize() async { + let pagination = PaginationState(pageSize: 5) + pagination.dedupeKey = { $0 } + await pagination.reload { _, _ in ["a", "b"] }.value + #expect(pagination.hasMore) // 2 < pageSize 5, but the page contributed new items + } + + @Test @MainActor func hasMoreFalseWhenFullPageIsAllDuplicates() async { + let pagination = PaginationState(pageSize: 2) + pagination.dedupeKey = { $0 } + await pagination.reload { _, _ in ["a", "b"] }.value + #expect(pagination.hasMore) + + // 2 >= pageSize 2, but every key was already seen -> pagination ends + await pagination.loadMore { _, _ in ["a", "b"] } + #expect(pagination.items == ["a", "b"]) + #expect(!pagination.hasMore) + } + + @Test @MainActor func reloadResetsSeenKeys() async { + let pagination = PaginationState(pageSize: 2) + pagination.dedupeKey = { $0 } + await pagination.reload { _, _ in ["a", "b"] }.value + await pagination.loadMore { _, _ in ["b", "c"] } + #expect(pagination.items == ["a", "b", "c"]) + + // A fresh reload must accept keys seen in the previous cycle + await pagination.reload { _, _ in ["a", "b"] }.value + #expect(pagination.items == ["a", "b"]) + } +}