I'm trying to create a snapshot test using swift-snapshot-testing
of a UIView
that contains an async image managed by Kingfisher
. To avoid depending on internet connection my approach is using a local file url instead of an external url pointing to the test image.
My issue is that, although I'm using a local image, the test still ends before the image is retrieved.
I got same results doing a quick test with Nuke
.
What should I do to manage this situation ?
Here is the test code:
@MainActor func testSnapshot() throws {
let bundle = Bundle(for: Self.self)
let imageURL = try XCTUnwrap(bundle.url(forResource: "myImage", withExtension: "png"))
let state = WeatherInfoView.State(temperature: "18º",
text: "Overcast clouds",
imageURL: imageURL,
location: "Bonjal, Indonesia")
let view = WeatherInfoView()
view.apply(state: state)
view.widthAnchor.constraint(equalToConstant: 424).isActive = true
view.heightAnchor.constraint(equalToConstant: 424).isActive = true
assertSnapshot(of: view, as: .image)
}
And this is the view related code:
extension WeatherInfoView: StatefulView {
struct State {
let temperature: String
let text: String?
let imageURL: URL?
let location: String
}
func apply(state: State) {
temperatureLabel.text = state.temperature
descriptionLabel.text = state.text
imageView.kf.setImage(with: state.imageURL)
locationLabel.text = state.location
}
}
In the past I was using as a workaround solution passing a placeholder image and use it on the snapshot tests. But I'm not totally happy adding properties to the view state that are used just for the tests.
In your test you can add the image to the Kingfisher cache so that it'll immediately be available when the view tries to retrieve it.
image
is the UIImage
you want to be shown in the snapshot
url
can be any url, it doesn't even have to be valid, it just needs to be the same as the one passed to the view.
KingfisherManager.shared.cache.store(
image,
forKey: url.cacheKey,
toDisk: false
)
Another thing it that this could be reading/writing to the cache of your app depending on how your test target is setup (ie, if your app is the test host). A way to avoid that is to make a new ImageCache
that is only used in the tests. Kingfisher can also be set to only look in the image cache so the tests will never try to make a network request.
let imageCache = ImageCache(name: "test-image-cache")
imageCache.store(
image,
forKey: url.cacheKey,
toDisk: false
)
KingfisherManager.shared.defaultOptions = [
.onlyFromCache,
.targetCache(imageCache)
]