diff --git a/EssentialApp/EssentialAppTests/FeedUIIntegrationTests.swift b/EssentialApp/EssentialAppTests/FeedUIIntegrationTests.swift index 2a14230..8b9c31c 100644 --- a/EssentialApp/EssentialAppTests/FeedUIIntegrationTests.swift +++ b/EssentialApp/EssentialAppTests/FeedUIIntegrationTests.swift @@ -164,6 +164,23 @@ final class FeedUIIntegrationTests: XCTestCase { XCTAssertEqual(loader.cancelledImageURLs, [image0.url, image1.url], "Expected two cancelled image URL requests once second image is also not visible anymore") } + func test_feedImageView_reloadsImageURLWhenBecomingVisibleAgain() { + let image0 = makeImage(url: URL(string: "http://url-0.com")!) + let image1 = makeImage(url: URL(string: "http://url-1.com")!) + let (sut, loader) = makeSUT() + + sut.simulateAppearance() + loader.completeFeedLoading(with: [image0, image1]) + + sut.simulateFeedImageBecomingVisibleAgain(at: 0) + + XCTAssertEqual(loader.loadedImageURLs, [image0.url, image0.url], "Expected two image URL request after first view becomes visible again") + + sut.simulateFeedImageBecomingVisibleAgain(at: 1) + + XCTAssertEqual(loader.loadedImageURLs, [image0.url, image0.url, image1.url, image1.url], "Expected two new image URL request after second view becomes visible again") + } + func test_feedImageViewLoadingIndicator_isVisibleWhileLoadingImage() { let (sut, loader) = makeSUT() @@ -182,6 +199,10 @@ final class FeedUIIntegrationTests: XCTestCase { loader.completeImageLoadingWithError(at: 1) XCTAssertEqual(view0?.isShowingImageLoadingIndicator, false, "Expected no loading indicator state change for first view once second image loading completes with error") XCTAssertEqual(view1?.isShowingImageLoadingIndicator, false, "Expected no loading indicator for second view once second image loading completes with error") + + view1?.simulateRetryAction() + XCTAssertEqual(view0?.isShowingImageLoadingIndicator, false, "Expected no loading indicator state change for first view once second image loading completes with error") + XCTAssertEqual(view1?.isShowingImageLoadingIndicator, true, "Expected loading indicator state change for second view on retry action") } func test_feedImageView_rendersImageLoadedFromURL() { @@ -326,6 +347,26 @@ final class FeedUIIntegrationTests: XCTestCase { XCTAssertEqual(newView.renderedImage, imageData) } + func test_feedImageView_configuresViewCorrectlyWhenCellBecomingVisibleAgain() { + let (sut, loader) = makeSUT() + + sut.simulateAppearance() + loader.completeFeedLoading(with: [makeImage()]) + + let view0 = sut.simulateFeedImageBecomingVisibleAgain(at: 0) + + XCTAssertEqual(view0?.renderedImage, nil, "Expected no rendered image when view becomes visible again") + XCTAssertEqual(view0?.isShowingRetryAction, false, "Expected no retry action when view becomes visible again") + XCTAssertEqual(view0?.isShowingImageLoadingIndicator, true, "Expected loading indicator when view becomes visible again") + + let imageData = UIImage.make(withColor: .red).pngData()! + loader.completeImageLoading(with: imageData, at: 1) + + XCTAssertEqual(view0?.renderedImage, imageData, "Expected rendered image when image loads successfully after view becomes visible again") + XCTAssertEqual(view0?.isShowingRetryAction, false, "Expected no retry when image loads successfully after view becomes visible again") + XCTAssertEqual(view0?.isShowingImageLoadingIndicator, false, "Expected no loading indicator when image loads successfully after view becomes visible again") + } + func test_feedImageView_doesNotRenderLoadedImageWhenNotVisibleAnymore() { let (sut, loader) = makeSUT() diff --git a/EssentialApp/EssentialAppTests/Helpers/FeedViewController+TestHelpers.swift b/EssentialApp/EssentialAppTests/Helpers/ListViewController+TestHelpers.swift similarity index 89% rename from EssentialApp/EssentialAppTests/Helpers/FeedViewController+TestHelpers.swift rename to EssentialApp/EssentialAppTests/Helpers/ListViewController+TestHelpers.swift index 0896610..f8bdc5d 100644 --- a/EssentialApp/EssentialAppTests/Helpers/FeedViewController+TestHelpers.swift +++ b/EssentialApp/EssentialAppTests/Helpers/ListViewController+TestHelpers.swift @@ -47,6 +47,17 @@ extension ListViewController { return feedImageView(at: index) as? FeedImageCell } + @discardableResult + func simulateFeedImageBecomingVisibleAgain(at row: Int) -> FeedImageCell? { + let view = simulateFeedImageViewNotVisible(at: row) + + let delegate = tableView.delegate + let index = IndexPath(row: row, section: feedImagesSection) + delegate?.tableView?(tableView, willDisplay: view!, forRowAt: index) + + return view + } + @discardableResult func simulateFeedImageViewNotVisible(at row: Int) -> FeedImageCell? { let view = simulateFeedImageViewVisible(at: row) diff --git a/EssentialFeed/EssentialFeediOS/Feed UI/Controllers/FeedImageCellController.swift b/EssentialFeed/EssentialFeediOS/Feed UI/Controllers/FeedImageCellController.swift index dd541f0..c206649 100644 --- a/EssentialFeed/EssentialFeediOS/Feed UI/Controllers/FeedImageCellController.swift +++ b/EssentialFeed/EssentialFeediOS/Feed UI/Controllers/FeedImageCellController.swift @@ -43,6 +43,11 @@ extension FeedImageCellController: UITableViewDataSource, UITableViewDelegate, U return cell! } + public func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) { + self.cell = cell as? FeedImageCell + delegate.didRequestImage() + } + public func tableView(_ tableView: UITableView, didEndDisplaying cell: UITableViewCell, forRowAt indexPath: IndexPath) { cancelLoad() } diff --git a/EssentialFeed/EssentialFeediOS/Shared UI/Controllers/ListViewController.swift b/EssentialFeed/EssentialFeediOS/Shared UI/Controllers/ListViewController.swift index b174a22..274594e 100644 --- a/EssentialFeed/EssentialFeediOS/Shared UI/Controllers/ListViewController.swift +++ b/EssentialFeed/EssentialFeediOS/Shared UI/Controllers/ListViewController.swift @@ -82,6 +82,11 @@ public final class ListViewController: UITableViewController, UITableViewDataSou onViewIsAppearing?(self) } + public override func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) { + let dl = cellController(at: indexPath)?.delegate + dl?.tableView?(tableView, willDisplay: cell, forRowAt: indexPath) + } + public override func tableView(_ tableView: UITableView, didEndDisplaying cell: UITableViewCell, forRowAt indexPath: IndexPath) { let dl = cellController(at: indexPath)?.delegate dl?.tableView?(tableView, didEndDisplaying: cell, forRowAt: indexPath)