-
Notifications
You must be signed in to change notification settings - Fork 60
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
3 changed files
with
322 additions
and
346 deletions.
There are no files selected for viewing
152 changes: 0 additions & 152 deletions
152
Tests/ApolloPaginationTests/AnyAsyncGraphQLQueryPagerTests.swift
This file was deleted.
Oops, something went wrong.
223 changes: 223 additions & 0 deletions
223
Tests/ApolloPaginationTests/AsyncGraphQLQueryPagerCoordinatorTests.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,223 @@ | ||
import Apollo | ||
import ApolloAPI | ||
import ApolloInternalTestHelpers | ||
import Combine | ||
import XCTest | ||
|
||
@testable import ApolloPagination | ||
|
||
final class AsyncGraphQLQueryPagerCoordinatorTests: XCTestCase, CacheDependentTesting { | ||
private typealias ReverseQuery = MockQuery<Mocks.Hero.ReverseFriendsQuery> | ||
private typealias ForwardQuery = MockQuery<Mocks.Hero.FriendsQuery> | ||
|
||
var cacheType: TestCacheProvider.Type { | ||
InMemoryTestCacheProvider.self | ||
} | ||
|
||
var cache: NormalizedCache! | ||
var server: MockGraphQLServer! | ||
var client: ApolloClient! | ||
var cancellables: [AnyCancellable] = [] | ||
|
||
override func setUpWithError() throws { | ||
try super.setUpWithError() | ||
|
||
cache = try makeNormalizedCache() | ||
let store = ApolloStore(cache: cache) | ||
|
||
server = MockGraphQLServer() | ||
let networkTransport = MockNetworkTransport(server: server, store: store) | ||
|
||
client = ApolloClient(networkTransport: networkTransport, store: store) | ||
MockSchemaMetadata.stub_cacheKeyInfoForType_Object = IDCacheKeyProvider.resolver | ||
} | ||
|
||
override func tearDownWithError() throws { | ||
cache = nil | ||
server = nil | ||
client = nil | ||
cancellables.forEach { $0.cancel() } | ||
cancellables = [] | ||
|
||
try super.tearDownWithError() | ||
} | ||
|
||
func test_canLoadMore() async throws { | ||
let pager = createForwardPager() | ||
|
||
let serverExpectation = Mocks.Hero.FriendsQuery.expectationForFirstPage(server: server) | ||
|
||
await pager.fetch() | ||
await fulfillment(of: [serverExpectation]) | ||
|
||
var canLoadMore = await pager.canLoadNext | ||
XCTAssertTrue(canLoadMore) | ||
|
||
let secondPageExpectation = Mocks.Hero.FriendsQuery.expectationForSecondPage(server: server) | ||
let secondPageFetch = expectation(description: "Second Page") | ||
secondPageFetch.expectedFulfillmentCount = 2 | ||
let subscription = await pager.subscribe(onUpdate: { _ in | ||
secondPageFetch.fulfill() | ||
}) | ||
try await pager.loadNext() | ||
await fulfillment(of: [secondPageExpectation, secondPageFetch]) | ||
subscription.cancel() | ||
canLoadMore = await pager.canLoadNext | ||
XCTAssertFalse(canLoadMore) | ||
} | ||
|
||
func test_canLoadPrevious() async throws { | ||
let pager = createReversePager() | ||
|
||
let serverExpectation = Mocks.Hero.ReverseFriendsQuery.expectationForLastItem(server: server) | ||
|
||
await pager.fetch() | ||
await fulfillment(of: [serverExpectation]) | ||
|
||
var canLoadMore = await pager.canLoadPrevious | ||
XCTAssertTrue(canLoadMore) | ||
|
||
let secondPageExpectation = Mocks.Hero.ReverseFriendsQuery.expectationForPreviousItem(server: server) | ||
let secondPageFetch = expectation(description: "Second Page") | ||
secondPageFetch.expectedFulfillmentCount = 2 | ||
let subscription = await pager.subscribe(onUpdate: { _ in | ||
secondPageFetch.fulfill() | ||
}) | ||
try await pager.loadPrevious() | ||
await fulfillment(of: [secondPageExpectation, secondPageFetch]) | ||
subscription.cancel() | ||
canLoadMore = await pager.canLoadPrevious | ||
XCTAssertFalse(canLoadMore) | ||
} | ||
|
||
@available(iOS 16.0, macOS 13.0, *) | ||
func test_actor_canCancelMidflight() async throws { | ||
server.customDelay = .milliseconds(150) | ||
let pager = createForwardPager() | ||
let serverExpectation = Mocks.Hero.FriendsQuery.expectationForFirstPage(server: server) | ||
|
||
await pager.subscribe(onUpdate: { _ in | ||
XCTFail("We should never get results back") | ||
}).store(in: &cancellables) | ||
|
||
Task { | ||
try await pager.loadAll() | ||
} | ||
|
||
Task { | ||
try? await Task.sleep(for: .milliseconds(10)) | ||
await pager.cancel() | ||
} | ||
|
||
await fulfillment(of: [serverExpectation], timeout: 1.0) | ||
} | ||
|
||
@available(iOS 16.0, macOS 13.0, *) | ||
func test_actor_cancellation_loadingState() async throws { | ||
server.customDelay = .milliseconds(150) | ||
let pager = createForwardPager() | ||
let serverExpectation = Mocks.Hero.FriendsQuery.expectationForFirstPage(server: server) | ||
|
||
await pager.subscribe(onUpdate: { _ in | ||
XCTFail("We should never get results back") | ||
}).store(in: &cancellables) | ||
|
||
Task { | ||
try await pager.loadAll() | ||
} | ||
|
||
Task { | ||
try? await Task.sleep(for: .milliseconds(10)) | ||
await pager.cancel() | ||
} | ||
|
||
await fulfillment(of: [serverExpectation], timeout: 1.0) | ||
async let isLoadingAll = pager.isLoadingAll | ||
async let isFetching = pager.isFetching | ||
let loadingStates = await [isFetching, isLoadingAll] | ||
loadingStates.forEach { XCTAssertFalse($0) } | ||
} | ||
|
||
@available(iOS 16.0, macOS 13.0, *) | ||
func test_actor_cancellationState_midflight() async throws { | ||
server.customDelay = .milliseconds(1) | ||
let pager = createForwardPager() | ||
let serverExpectation = Mocks.Hero.FriendsQuery.expectationForFirstPage(server: server) | ||
|
||
await pager.fetch() | ||
await fulfillment(of: [serverExpectation], timeout: 1.0) | ||
|
||
server.customDelay = .seconds(3) | ||
Task { | ||
try? await pager.loadNext() | ||
} | ||
let cancellationExpectation = expectation(description: "finished cancellation") | ||
Task { | ||
try? await Task.sleep(for: .milliseconds(50)) | ||
await pager.cancel() | ||
cancellationExpectation.fulfill() | ||
} | ||
|
||
await fulfillment(of: [cancellationExpectation]) | ||
let isFetching = await pager.isFetching | ||
XCTAssertFalse(isFetching) | ||
} | ||
|
||
private func createReversePager() -> AsyncGraphQLQueryPagerCoordinator<ReverseQuery, ReverseQuery> { | ||
let initialQuery = ReverseQuery() | ||
initialQuery.__variables = ["id": "2001", "first": 2, "before": "Y3Vyc29yMw=="] | ||
return AsyncGraphQLQueryPagerCoordinator<ReverseQuery, ReverseQuery>( | ||
client: client, | ||
initialQuery: initialQuery, | ||
watcherDispatchQueue: .main, | ||
extractPageInfo: { data in | ||
switch data { | ||
case .initial(let data), .paginated(let data): | ||
return CursorBasedPagination.Reverse( | ||
hasPrevious: data.hero.friendsConnection.pageInfo.hasPreviousPage, | ||
startCursor: data.hero.friendsConnection.pageInfo.startCursor | ||
) | ||
} | ||
}, | ||
pageResolver: { pageInfo, direction in | ||
guard direction == .previous else { return nil } | ||
let nextQuery = ReverseQuery() | ||
nextQuery.__variables = [ | ||
"id": "2001", | ||
"first": 2, | ||
"before": pageInfo.startCursor, | ||
] | ||
return nextQuery | ||
} | ||
) | ||
} | ||
|
||
private func createForwardPager() -> AsyncGraphQLQueryPagerCoordinator<ForwardQuery, ForwardQuery> { | ||
let initialQuery = ForwardQuery() | ||
initialQuery.__variables = ["id": "2001", "first": 2, "after": GraphQLNullable<String>.null] | ||
return AsyncGraphQLQueryPagerCoordinator<ForwardQuery, ForwardQuery>( | ||
client: client, | ||
initialQuery: initialQuery, | ||
watcherDispatchQueue: .main, | ||
extractPageInfo: { data in | ||
switch data { | ||
case .initial(let data), .paginated(let data): | ||
return CursorBasedPagination.Forward( | ||
hasNext: data.hero.friendsConnection.pageInfo.hasNextPage, | ||
endCursor: data.hero.friendsConnection.pageInfo.endCursor | ||
) | ||
} | ||
}, | ||
pageResolver: { pageInfo, direction in | ||
guard direction == .next else { return nil } | ||
let nextQuery = ForwardQuery() | ||
nextQuery.__variables = [ | ||
"id": "2001", | ||
"first": 2, | ||
"after": pageInfo.endCursor, | ||
] | ||
return nextQuery | ||
} | ||
) | ||
} | ||
} |
Oops, something went wrong.