Skip to content

Commit

Permalink
iOS17+ fix: Move data refresh from viewDidLoad to new ViewControlle…
Browse files Browse the repository at this point in the history
…r's `viewIsAppearing` lifecycle method

- This change is needed since UIRefreshControl updates must happen when the view is on-screen on iOS17+ (it ignores updates otherwise!).

- `viewDidLoad` is called once per VC, but the new `viewIsAppearing` may be called multiple times - so we added logic to ensure the refresh only happens in the first `viewIsAppearing` occurrence to mimic the previous behavior in `viewDidLoad`.

- When running tests, the views are never added on-screen, so UIRefreshControl doesn't work as expected on iOS 17+. To allow testability, we replace the UIRefreshControl with a UIRefreshControlSpy test-double.
  • Loading branch information
caiozullo committed Sep 28, 2023
1 parent 06367e3 commit 9703c8d
Show file tree
Hide file tree
Showing 5 changed files with 131 additions and 54 deletions.
37 changes: 24 additions & 13 deletions EssentialApp/EssentialAppTests/CommentsUIIntegrationTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,17 +14,17 @@ class CommentsUIIntegrationTests: XCTestCase {
func test_commentsView_hasTitle() {
let (sut, _) = makeSUT()

sut.loadViewIfNeeded()
sut.simulateAppearance()

XCTAssertEqual(sut.title, commentsTitle)
}

func test_loadCommentsActions_requestCommentsFromLoader() {
let (sut, loader) = makeSUT()
XCTAssertEqual(loader.loadCommentsCallCount, 0, "Expected no loading requests before view is loaded")
XCTAssertEqual(loader.loadCommentsCallCount, 0, "Expected no loading requests before view appears")

sut.loadViewIfNeeded()
XCTAssertEqual(loader.loadCommentsCallCount, 1, "Expected a loading request once view is loaded")
sut.simulateAppearance()
XCTAssertEqual(loader.loadCommentsCallCount, 1, "Expected a loading request once view appears")

sut.simulateUserInitiatedReload()
XCTAssertEqual(loader.loadCommentsCallCount, 1, "Expected no request until previous completes")
Expand All @@ -38,11 +38,22 @@ class CommentsUIIntegrationTests: XCTestCase {
XCTAssertEqual(loader.loadCommentsCallCount, 3, "Expected yet another loading request once user initiates another reload")
}

func test_loadCommentsActions_runsAutomaticallyOnlyOnFirstAppearance() {
let (sut, loader) = makeSUT()
XCTAssertEqual(loader.loadCommentsCallCount, 0, "Expected no loading requests before view appears")

sut.simulateAppearance()
XCTAssertEqual(loader.loadCommentsCallCount, 1, "Expected a loading request once view appears")

sut.simulateAppearance()
XCTAssertEqual(loader.loadCommentsCallCount, 1, "Expected no loading request the second time view appears")
}

func test_loadingCommentsIndicator_isVisibleWhileLoadingComments() {
let (sut, loader) = makeSUT()

sut.loadViewIfNeeded()
XCTAssertTrue(sut.isShowingLoadingIndicator, "Expected loading indicator once view is loaded")
sut.simulateAppearance()
XCTAssertTrue(sut.isShowingLoadingIndicator, "Expected loading indicator once view appears")

loader.completeCommentsLoading(at: 0)
XCTAssertFalse(sut.isShowingLoadingIndicator, "Expected no loading indicator once loading completes successfully")
Expand All @@ -59,7 +70,7 @@ class CommentsUIIntegrationTests: XCTestCase {
let comment1 = makeComment(message: "another message", username: "another username")
let (sut, loader) = makeSUT()

sut.loadViewIfNeeded()
sut.simulateAppearance()
assertThat(sut, isRendering: [ImageComment]())

loader.completeCommentsLoading(with: [comment0], at: 0)
Expand All @@ -74,7 +85,7 @@ class CommentsUIIntegrationTests: XCTestCase {
let comment = makeComment()
let (sut, loader) = makeSUT()

sut.loadViewIfNeeded()
sut.simulateAppearance()
loader.completeCommentsLoading(with: [comment], at: 0)
assertThat(sut, isRendering: [comment])

Expand All @@ -87,7 +98,7 @@ class CommentsUIIntegrationTests: XCTestCase {
let comment = makeComment()
let (sut, loader) = makeSUT()

sut.loadViewIfNeeded()
sut.simulateAppearance()
loader.completeCommentsLoading(with: [comment], at: 0)
assertThat(sut, isRendering: [comment])

Expand All @@ -98,7 +109,7 @@ class CommentsUIIntegrationTests: XCTestCase {

func test_loadCommentsCompletion_dispatchesFromBackgroundToMainThread() {
let (sut, loader) = makeSUT()
sut.loadViewIfNeeded()
sut.simulateAppearance()

let exp = expectation(description: "Wait for background queue")
DispatchQueue.global().async {
Expand All @@ -111,7 +122,7 @@ class CommentsUIIntegrationTests: XCTestCase {
func test_loadCommentsCompletion_rendersErrorMessageOnErrorUntilNextReload() {
let (sut, loader) = makeSUT()

sut.loadViewIfNeeded()
sut.simulateAppearance()
XCTAssertEqual(sut.errorMessage, nil)

loader.completeCommentsLoadingWithError(at: 0)
Expand All @@ -124,7 +135,7 @@ class CommentsUIIntegrationTests: XCTestCase {
func test_tapOnErrorView_hidesErrorMessage() {
let (sut, loader) = makeSUT()

sut.loadViewIfNeeded()
sut.simulateAppearance()
XCTAssertEqual(sut.errorMessage, nil)

loader.completeCommentsLoadingWithError(at: 0)
Expand All @@ -147,7 +158,7 @@ class CommentsUIIntegrationTests: XCTestCase {
}).eraseToAnyPublisher()
})

sut?.loadViewIfNeeded()
sut?.simulateAppearance()
}

XCTAssertEqual(cancelCallCount, 0)
Expand Down
8 changes: 6 additions & 2 deletions EssentialApp/EssentialAppTests/FeedAcceptanceTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,9 @@ class FeedAcceptanceTests: XCTestCase {
sut.configureWindow()

let nav = sut.window?.rootViewController as? UINavigationController
return nav?.topViewController as! ListViewController
let vc = nav?.topViewController as! ListViewController
vc.simulateAppearance()
return vc
}

private func enterBackground(with store: InMemoryFeedStore) {
Expand All @@ -106,7 +108,9 @@ class FeedAcceptanceTests: XCTestCase {
RunLoop.current.run(until: Date())

let nav = feed.navigationController
return nav?.topViewController as! ListViewController
let vc = nav?.topViewController as! ListViewController
vc.simulateAppearance()
return vc
}

private func response(for url: URL) -> (Data, HTTPURLResponse) {
Expand Down
Loading

0 comments on commit 9703c8d

Please sign in to comment.