Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[ApolloPagination] Update PaginationOutput to operate over GraphQLResults #428

Merged
merged 32 commits into from
Aug 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
223 changes: 137 additions & 86 deletions Tests/ApolloPaginationTests/AsyncGraphQLQueryPagerTests.swift

Large diffs are not rendered by default.

73 changes: 38 additions & 35 deletions Tests/ApolloPaginationTests/BidirectionalPaginationTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ final class BidirectionalPaginationTests: XCTestCase, CacheDependentTesting {
let pager = createPager()
let serverExpectation = Mocks.Hero.BidirectionalFriendsQuery.expectationForFirstFetchInMiddleOfList(server: server)

var results: [Result<(PaginationOutput<Query, Query>, UpdateSource), any Error>] = []
var results: [Result<PaginationOutput<Query, Query>, any Error>] = []
let firstPageExpectation = expectation(description: "First page")
var subscription = await pager.subscribe(onUpdate: { _ in
firstPageExpectation.fulfill()
Expand All @@ -102,11 +102,11 @@ final class BidirectionalPaginationTests: XCTestCase, CacheDependentTesting {
subscription.cancel()
var result = try await XCTUnwrapping(await pager.currentValue)
results.append(result)
XCTAssertSuccessResult(result) { (output, source) in
XCTAssertSuccessResult(result) { output in
XCTAssertTrue(output.nextPages.isEmpty)
XCTAssertEqual(output.initialPage.hero.friendsConnection.friends.count, 1)
XCTAssertEqual(output.initialPage.hero.friendsConnection.totalCount, 3)
XCTAssertEqual(source, .fetch)
XCTAssertEqual(output.initialPage?.data?.hero.friendsConnection.friends.count, 1)
XCTAssertEqual(output.initialPage?.data?.hero.friendsConnection.totalCount, 3)
XCTAssertEqual(output.initialPage?.source, .server)
}

let secondPageExpectation = Mocks.Hero.BidirectionalFriendsQuery.expectationForLastPage(server: server)
Expand All @@ -123,17 +123,17 @@ final class BidirectionalPaginationTests: XCTestCase, CacheDependentTesting {
result = try await XCTUnwrapping(await pager.currentValue)
results.append(result)

try XCTAssertSuccessResult(result) { (output, source) in
try XCTAssertSuccessResult(result) { output in
// Assert first page is unchanged
XCTAssertEqual(try? results.first?.get().0.initialPage, try? results.last?.get().0.initialPage)
XCTAssertEqual(try? results.first?.get().initialPage, try? results.last?.get().initialPage)

XCTAssertFalse(output.nextPages.isEmpty)
XCTAssertEqual(output.nextPages.count, 1)
XCTAssertTrue(output.previousPages.isEmpty)
XCTAssertEqual(output.previousPages.count, 0)
let page = try XCTUnwrap(output.nextPages.first)
XCTAssertEqual(page.hero.friendsConnection.friends.count, 1)
XCTAssertEqual(source, .fetch)
XCTAssertEqual(page.data?.hero.friendsConnection.friends.count, 1)
XCTAssertEqual(page.source, .server)
}
var previousCount = await pager.previousPageVarMap.values.count
XCTAssertEqual(previousCount, 0)
Expand All @@ -155,17 +155,17 @@ final class BidirectionalPaginationTests: XCTestCase, CacheDependentTesting {
result = try await XCTUnwrapping(await pager.currentValue)
results.append(result)

try XCTAssertSuccessResult(result) { (output, source) in
try XCTAssertSuccessResult(result) { output in
// Assert first page is unchanged
XCTAssertEqual(try? results.first?.get().0.initialPage, try? results.last?.get().0.initialPage)
XCTAssertEqual(try? results.first?.get().initialPage, try? results.last?.get().initialPage)

XCTAssertFalse(output.nextPages.isEmpty)
XCTAssertEqual(output.nextPages.count, 1)
XCTAssertFalse(output.previousPages.isEmpty)
XCTAssertEqual(output.previousPages.count, 1)
let page = try XCTUnwrap(output.previousPages.first)
XCTAssertEqual(page.hero.friendsConnection.friends.count, 1)
XCTAssertEqual(source, .fetch)
XCTAssertEqual(page.data?.hero.friendsConnection.friends.count, 1)
XCTAssertEqual(page.source, .server)
}
previousCount = await pager.previousPageVarMap.values.count
XCTAssertEqual(previousCount, 1)
Expand All @@ -190,12 +190,14 @@ final class BidirectionalPaginationTests: XCTestCase, CacheDependentTesting {
timeout: 5
)

let (result, _) = try await XCTUnwrapping(try await pager.currentValue?.get())
let result = try await XCTUnwrapping(try await pager.currentValue?.get())
XCTAssertFalse(result.previousPages.isEmpty)
XCTAssertEqual(result.initialPage.hero.friendsConnection.friends.count, 1)
XCTAssertEqual(result.initialPage?.data?.hero.friendsConnection.friends.count, 1)
XCTAssertFalse(result.nextPages.isEmpty)

let friends = (result.previousPages.first?.hero.friendsConnection.friends ?? []) + result.initialPage.hero.friendsConnection.friends + (result.nextPages.first?.hero.friendsConnection.friends ?? [])
let friends = (
result.previousPages.compactMap(\.data?.hero.friendsConnection.friends)
+ result.nextPages.compactMap(\.data?.hero.friendsConnection.friends)
).flatMap { $0 } + (result.initialPage?.data?.hero.friendsConnection.friends ?? [])

XCTAssertEqual(Set(friends).count, 3)
}
Expand All @@ -206,7 +208,7 @@ final class BidirectionalPaginationTests: XCTestCase, CacheDependentTesting {
let pager = GraphQLQueryPagerCoordinator(pager: createPager())
let serverExpectation = Mocks.Hero.BidirectionalFriendsQuery.expectationForFirstFetchInMiddleOfList(server: server)

var results: [Result<(PaginationOutput<Query, Query>, UpdateSource), any Error>] = []
var results: [Result<PaginationOutput<Query, Query>, any Error>] = []
let firstPageExpectation = expectation(description: "First page")
var subscription = await pager.publisher.sink { _ in
firstPageExpectation.fulfill()
Expand All @@ -216,11 +218,11 @@ final class BidirectionalPaginationTests: XCTestCase, CacheDependentTesting {
subscription.cancel()
var result = try await XCTUnwrapping(await pager.pager.currentValue)
results.append(result)
XCTAssertSuccessResult(result) { (output, source) in
XCTAssertSuccessResult(result) { output in
XCTAssertTrue(output.nextPages.isEmpty)
XCTAssertEqual(output.initialPage.hero.friendsConnection.friends.count, 1)
XCTAssertEqual(output.initialPage.hero.friendsConnection.totalCount, 3)
XCTAssertEqual(source, .fetch)
XCTAssertEqual(output.initialPage?.data?.hero.friendsConnection.friends.count, 1)
XCTAssertEqual(output.initialPage?.data?.hero.friendsConnection.totalCount, 3)
XCTAssertEqual(output.initialPage?.source, .server)
}

let secondPageExpectation = Mocks.Hero.BidirectionalFriendsQuery.expectationForLastPage(server: server)
Expand All @@ -237,17 +239,17 @@ final class BidirectionalPaginationTests: XCTestCase, CacheDependentTesting {
result = try await XCTUnwrapping(await pager.pager.currentValue)
results.append(result)

try XCTAssertSuccessResult(result) { (output, source) in
try XCTAssertSuccessResult(result) { output in
// Assert first page is unchanged
XCTAssertEqual(try? results.first?.get().0.initialPage, try? results.last?.get().0.initialPage)
XCTAssertEqual(try? results.first?.get().initialPage, try? results.last?.get().initialPage)

XCTAssertFalse(output.nextPages.isEmpty)
XCTAssertEqual(output.nextPages.count, 1)
XCTAssertTrue(output.previousPages.isEmpty)
XCTAssertEqual(output.previousPages.count, 0)
let page = try XCTUnwrap(output.nextPages.first)
XCTAssertEqual(page.hero.friendsConnection.friends.count, 1)
XCTAssertEqual(source, .fetch)
XCTAssertEqual(page.data?.hero.friendsConnection.friends.count, 1)
XCTAssertEqual(page.source, .server)
}

let previousPageExpectation = Mocks.Hero.BidirectionalFriendsQuery.expectationForPreviousPage(server: server)
Expand All @@ -265,17 +267,17 @@ final class BidirectionalPaginationTests: XCTestCase, CacheDependentTesting {
result = try await XCTUnwrapping(await pager.pager.currentValue)
results.append(result)

try XCTAssertSuccessResult(result) { (output, source) in
try XCTAssertSuccessResult(result) { output in
// Assert first page is unchanged
XCTAssertEqual(try? results.first?.get().0.initialPage, try? results.last?.get().0.initialPage)
XCTAssertEqual(try? results.first?.get().initialPage, try? results.last?.get().initialPage)

XCTAssertFalse(output.nextPages.isEmpty)
XCTAssertEqual(output.nextPages.count, 1)
XCTAssertFalse(output.previousPages.isEmpty)
XCTAssertEqual(output.previousPages.count, 1)
let page = try XCTUnwrap(output.previousPages.first)
XCTAssertEqual(page.hero.friendsConnection.friends.count, 1)
XCTAssertEqual(source, .fetch)
XCTAssertEqual(page.data?.hero.friendsConnection.friends.count, 1)
XCTAssertEqual(page.source, .server)
}
}

Expand All @@ -296,14 +298,15 @@ final class BidirectionalPaginationTests: XCTestCase, CacheDependentTesting {
timeout: 5
)

let result = try await XCTUnwrapping(try await pager.pager.currentValue?.get().0)
let result = try await XCTUnwrapping(try await pager.pager.currentValue?.get())
XCTAssertFalse(result.previousPages.isEmpty)
XCTAssertEqual(result.initialPage.hero.friendsConnection.friends.count, 1)
XCTAssertEqual(result.initialPage?.data?.hero.friendsConnection.friends.count, 1)
XCTAssertFalse(result.nextPages.isEmpty)

let friends = (result.previousPages.first?.hero.friendsConnection.friends ?? [])
+ result.initialPage.hero.friendsConnection.friends
+ (result.nextPages.first?.hero.friendsConnection.friends ?? [])
let friends = (
result.previousPages.compactMap(\.data?.hero.friendsConnection.friends)
+ result.nextPages.compactMap(\.data?.hero.friendsConnection.friends)
).flatMap { $0 } + (result.initialPage?.data?.hero.friendsConnection.friends ?? [])

XCTAssertEqual(Set(friends).count, 3)
}
Expand Down
4 changes: 2 additions & 2 deletions Tests/ApolloPaginationTests/ConcurrencyTest.swift
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ final class ConcurrencyTests: XCTestCase {

func test_concurrentFetches() async throws {
let pager = createPager()
var results: [Result<(PaginationOutput<Query, Query>, UpdateSource), any Error>] = []
var results: [Result<PaginationOutput<Query, Query>, any Error>] = []
let resultsExpectation = expectation(description: "Results arrival")
resultsExpectation.expectedFulfillmentCount = 2
await pager.subscribe { result in
Expand All @@ -160,7 +160,7 @@ final class ConcurrencyTests: XCTestCase {

func test_concurrentFetches_nonisolated() throws {
let pager = createNonisolatedPager()
var results: [Result<(PaginationOutput<Query, Query>, UpdateSource), any Error>] = []
var results: [Result<PaginationOutput<Query, Query>, any Error>] = []
let initialExpectation = expectation(description: "Initial")
initialExpectation.assertForOverFulfill = false
let nextExpectation = expectation(description: "Next")
Expand Down
40 changes: 20 additions & 20 deletions Tests/ApolloPaginationTests/ForwardPaginationTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ final class ForwardPaginationTests: XCTestCase, CacheDependentTesting {

let serverExpectation = Mocks.Hero.FriendsQuery.expectationForFirstPage(server: server)

var results: [Result<(PaginationOutput<Query, Query>, UpdateSource), any Error>] = []
var results: [Result<PaginationOutput<Query, Query>, any Error>] = []
let firstPageExpectation = expectation(description: "First page")
var subscription = await pager.subscribe(onUpdate: { _ in
firstPageExpectation.fulfill()
Expand All @@ -57,11 +57,11 @@ final class ForwardPaginationTests: XCTestCase, CacheDependentTesting {
subscription.cancel()
var result = try await XCTUnwrapping(await pager.currentValue)
results.append(result)
XCTAssertSuccessResult(result) { (output, source) in
XCTAssertSuccessResult(result) { output in
XCTAssertTrue(output.nextPages.isEmpty)
XCTAssertEqual(output.initialPage.hero.friendsConnection.friends.count, 2)
XCTAssertEqual(output.initialPage.hero.friendsConnection.totalCount, 3)
XCTAssertEqual(source, .fetch)
XCTAssertEqual(output.initialPage?.data?.hero.friendsConnection.friends.count, 2)
XCTAssertEqual(output.initialPage?.data?.hero.friendsConnection.totalCount, 3)
XCTAssertEqual(output.initialPage?.source, .server)
}

let secondPageExpectation = Mocks.Hero.FriendsQuery.expectationForSecondPage(server: server)
Expand All @@ -78,17 +78,17 @@ final class ForwardPaginationTests: XCTestCase, CacheDependentTesting {
result = try await XCTUnwrapping(await pager.currentValue)
results.append(result)

try XCTAssertSuccessResult(result) { (output, source) in
try XCTAssertSuccessResult(result) { output in
// Assert first page is unchanged
XCTAssertEqual(try? results.first?.get().0.initialPage, try? results.last?.get().0.initialPage)
XCTAssertEqual(try? results.first?.get().initialPage, try? results.last?.get().initialPage)

XCTAssertFalse(output.nextPages.isEmpty)
XCTAssertEqual(output.nextPages.count, 1)
XCTAssertTrue(output.previousPages.isEmpty)
XCTAssertEqual(output.previousPages.count, 0)
let page = try XCTUnwrap(output.nextPages.first)
XCTAssertEqual(page.hero.friendsConnection.friends.count, 1)
XCTAssertEqual(source, .fetch)
XCTAssertEqual(page.data?.hero.friendsConnection.friends.count, 1)
XCTAssertEqual(page.source, .server)
}
let previousCount = await pager.previousPageVarMap.values.count
XCTAssertEqual(previousCount, 0)
Expand Down Expand Up @@ -183,11 +183,11 @@ final class ForwardPaginationTests: XCTestCase, CacheDependentTesting {
await fulfillment(of: [serverExpectation, firstPageExpectation], timeout: 1)
subscription.cancel()
let result = try await XCTUnwrapping(await pager.currentValue)
XCTAssertSuccessResult(result) { (output, source) in
XCTAssertSuccessResult(result) { output in
XCTAssertTrue(output.nextPages.isEmpty)
XCTAssertEqual(output.initialPage.hero.friendsConnection.friends.count, 2)
XCTAssertEqual(output.initialPage.hero.friendsConnection.totalCount, 3)
XCTAssertEqual(source, .fetch)
XCTAssertEqual(output.initialPage?.data?.hero.friendsConnection.friends.count, 2)
XCTAssertEqual(output.initialPage?.data?.hero.friendsConnection.totalCount, 3)
XCTAssertEqual(output.initialPage?.source, .server)
}

let secondPageExpectation = Mocks.Hero.FriendsQuery.expectationForSecondPage(server: server)
Expand All @@ -201,14 +201,14 @@ final class ForwardPaginationTests: XCTestCase, CacheDependentTesting {
await fulfillment(of: [secondPageExpectation, secondPageFetch], timeout: 1)
subscription.cancel()
let newResult = try await XCTUnwrapping(await pager.currentValue)
try XCTAssertSuccessResult(newResult) { (output, source) in
try XCTAssertSuccessResult(newResult) { output in
// Assert first page is unchanged
XCTAssertEqual(try? result.get().0.initialPage, try? newResult.get().0.initialPage)
XCTAssertEqual(try? result.get().initialPage, try? newResult.get().initialPage)
XCTAssertFalse(output.nextPages.isEmpty)
XCTAssertEqual(output.nextPages.count, 1)
let page = try XCTUnwrap(output.nextPages.first)
XCTAssertEqual(page.hero.friendsConnection.friends.count, 1)
XCTAssertEqual(source, .fetch)
XCTAssertEqual(page.data?.hero.friendsConnection.friends.count, 1)
XCTAssertEqual(page.source, .server)
}
let count = await pager.nextPageVarMap.values.count
XCTAssertEqual(count, 1)
Expand All @@ -227,10 +227,10 @@ final class ForwardPaginationTests: XCTestCase, CacheDependentTesting {
}
await fulfillment(of: [transactionExpectation, mutationExpectation])
let finalResult = try await XCTUnwrapping(await pager.currentValue)
XCTAssertSuccessResult(finalResult) { (output, _) in
XCTAssertEqual(output.initialPage.hero.name, "C3PO")
XCTAssertSuccessResult(finalResult) { output in
XCTAssertEqual(output.initialPage?.data?.hero.name, "C3PO")
XCTAssertEqual(output.nextPages.count, 1)
XCTAssertEqual(output.nextPages.first?.hero.name, "C3PO")
XCTAssertEqual(output.nextPages.first?.data?.hero.name, "C3PO")
}
}

Expand Down
87 changes: 87 additions & 0 deletions Tests/ApolloPaginationTests/FriendsQuery+TestHelpers.swift
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,93 @@ extension Mocks.Hero.FriendsQuery {
]
}
}

static func expectationForFirstPageWithErrors(server: MockGraphQLServer) -> XCTestExpectation {
let query = MockQuery<Mocks.Hero.FriendsQuery>()
query.__variables = ["id": "2001", "first": 2, "after": GraphQLNullable<String>.null]
return server.expect(query) { _ in
let pageInfo: [AnyHashable: AnyHashable] = [
"__typename": "PageInfo",
"endCursor": "Y3Vyc29yMg==",
"hasNextPage": true,
]
let friends: [[String: AnyHashable]] = [
[
"__typename": "Human",
"name": "Luke Skywalker",
"id": "1000",
],
[
"__typename": "Human",
"name": "Han Solo",
"id": "1002",
],
]
let friendsConnection: [String: AnyHashable] = [
"__typename": "FriendsConnection",
"totalCount": 3,
"friends": friends,
"pageInfo": pageInfo,
]

let hero: [String: AnyHashable] = [
"__typename": "Droid",
"id": "2001",
"name": "R2-D2",
"friendsConnection": friendsConnection,
]

let data: [String: AnyHashable] = [
"hero": hero
]

return [
"data": data,
"errors": [
[
"message": "uh oh!"
],
[
"message": "Some error"
],
],
]
}
}

static func expectationForFirstPageErrorsOnly(server: MockGraphQLServer) -> XCTestExpectation {
let query = MockQuery<Mocks.Hero.FriendsQuery>()
query.__variables = ["id": "2001", "first": 2, "after": GraphQLNullable<String>.null]
return server.expect(query) { _ in
return [
"errors": [
[
"message": "uh oh!"
],
[
"message": "Some error"
],
],
]
}
}

static func expectationForSecondPageErrorsOnly(server: MockGraphQLServer) -> XCTestExpectation {
let query = MockQuery<Mocks.Hero.FriendsQuery>()
query.__variables = ["id": "2001", "first": 2, "after": "Y3Vyc29yMg=="]
return server.expect(query) { _ in
return [
"errors": [
[
"message": "uh oh!"
],
[
"message": "Some error"
],
],
]
}
}
}

extension Mocks.Hero.ReverseFriendsQuery {
Expand Down
Loading
Loading