Skip to content

Commit

Permalink
Added fake coil image loader and updated tests to use (slackhq#85)
Browse files Browse the repository at this point in the history
Adding a fake image loader for instrumentation. This replaces use of the fallback property on ImageLoader.Builder. Related to slackhq#9
  • Loading branch information
kierse authored Sep 8, 2022
1 parent d9d5919 commit c548173
Show file tree
Hide file tree
Showing 6 changed files with 104 additions and 6 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
/*
* Copyright (C) 2022 Slack Technologies, LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.slack.circuit.sample

import android.content.Context
import android.graphics.drawable.Drawable
import androidx.annotation.DrawableRes
import coil.ComponentRegistry
import coil.ImageLoader
import coil.decode.DataSource
import coil.disk.DiskCache
import coil.memory.MemoryCache
import coil.request.DefaultRequestOptions
import coil.request.Disposable
import coil.request.ImageRequest
import coil.request.ImageResult
import coil.request.SuccessResult
import kotlinx.coroutines.CompletableDeferred

/**
* Fake Coil ImageLoader based on example found here:
* https://coil-kt.github.io/coil/image_loaders/#testing
*/
class FakeImageLoader(
context: Context,
@DrawableRes drawableResId: Int,
) : ImageLoader {
private val drawable by lazy {
context.getDrawable(drawableResId) ?: throw IllegalArgumentException("drawable not found!")
}

override val defaults = DefaultRequestOptions()
override val components = ComponentRegistry()
override val memoryCache: MemoryCache?
get() = null
override val diskCache: DiskCache?
get() = null

override fun enqueue(request: ImageRequest): Disposable {
request.target?.onStart(request.placeholder)
request.target?.onSuccess(drawable)

return object : Disposable {
override val job = CompletableDeferred(newResult(request, drawable))
override val isDisposed
get() = true
override fun dispose() = Unit
}
}

override suspend fun execute(request: ImageRequest): ImageResult = newResult(request, drawable)

private fun newResult(request: ImageRequest, drawable: Drawable): SuccessResult {
return SuccessResult(
drawable = drawable,
request = request,
dataSource = DataSource.MEMORY_CACHE
)
}

override fun newBuilder() = throw UnsupportedOperationException()

override fun shutdown() = Unit
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,20 +21,33 @@ import androidx.compose.ui.test.assertTextEquals
import androidx.compose.ui.test.junit4.createAndroidComposeRule
import androidx.compose.ui.test.onNodeWithTag
import androidx.compose.ui.test.onNodeWithText
import androidx.compose.ui.test.performTouchInput
import androidx.compose.ui.test.swipeUp
import androidx.test.platform.app.InstrumentationRegistry
import coil.Coil
import com.google.common.truth.Truth.assertThat
import com.slack.circuit.Circuit
import com.slack.circuit.CircuitProvider
import com.slack.circuit.sample.FakeImageLoader
import com.slack.circuit.sample.R
import com.slack.circuit.sample.petdetail.PetDetailTestConstants.ANIMAL_CONTAINER_TAG
import com.slack.circuit.sample.petdetail.PetDetailTestConstants.PROGRESS_TAG
import com.slack.circuit.sample.petdetail.PetDetailTestConstants.UNKNOWN_ANIMAL_TAG
import com.slack.circuit.sample.petdetail.PetPhotoCarouselTestConstants.CAROUSEL_TAG
import org.junit.Before
import org.junit.Rule
import org.junit.Test

class PetDetailTest {
@get:Rule val composeTestRule = createAndroidComposeRule<ComponentActivity>()

@Before
fun setup() {
val fakeImageLoader =
FakeImageLoader(InstrumentationRegistry.getInstrumentation().targetContext, R.drawable.dog2)
Coil.setImageLoader(fakeImageLoader)
}

@Test
fun petDetail_show_progress_indicator_for_loading_state() {
composeTestRule.run {
Expand Down Expand Up @@ -65,7 +78,7 @@ class PetDetailTest {
val success =
PetDetailScreen.State.Success(
url = "url",
photoUrls = listOf(""), // using empty string here to trigger use of fallback image
photoUrls = listOf("http://some.url"),
photoUrlMemoryCacheKey = null,
name = "Baxter",
description = "Grumpy looking Australian Terrier"
Expand Down Expand Up @@ -93,7 +106,7 @@ class PetDetailTest {
onNodeWithTag(PROGRESS_TAG).assertDoesNotExist()
onNodeWithTag(UNKNOWN_ANIMAL_TAG).assertDoesNotExist()

onNodeWithTag(CAROUSEL_TAG).assertIsDisplayed()
onNodeWithTag(CAROUSEL_TAG).assertIsDisplayed().performTouchInput { swipeUp() }
onNodeWithText(success.name).assertIsDisplayed()
onNodeWithText(success.description).assertIsDisplayed()

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,10 @@ import androidx.compose.ui.test.onAllNodesWithTag
import androidx.compose.ui.test.onNodeWithTag
import androidx.compose.ui.test.onNodeWithText
import androidx.compose.ui.test.performClick
import androidx.test.platform.app.InstrumentationRegistry
import coil.Coil
import com.google.common.truth.Truth.assertThat
import com.slack.circuit.sample.FakeImageLoader
import com.slack.circuit.sample.R
import com.slack.circuit.sample.petlist.PetListTestConstants.CARD_TAG
import com.slack.circuit.sample.petlist.PetListTestConstants.GRID_TAG
Expand All @@ -33,12 +36,20 @@ import com.slack.circuit.sample.petlist.PetListTestConstants.NO_ANIMALS_TAG
import com.slack.circuit.sample.petlist.PetListTestConstants.PROGRESS_TAG
import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.test.runTest
import org.junit.Before
import org.junit.Rule
import org.junit.Test

class PetListTest {
@get:Rule val composeTestRule = createAndroidComposeRule<ComponentActivity>()

@Before
fun setup() {
val fakeImageLoader =
FakeImageLoader(InstrumentationRegistry.getInstrumentation().targetContext, R.drawable.dog)
Coil.setImageLoader(fakeImageLoader)
}

@Test
fun petList_show_progress_indicator_for_loading_state() {
composeTestRule.run {
Expand Down Expand Up @@ -102,7 +113,7 @@ class PetListTest {
PetListAnimal(
id = 1L,
name = "Baxter",
imageUrl = null,
imageUrl = "http://some.url",
breed = "Australian Terrier",
gender = "male",
age = "12"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,6 @@ import com.slack.circuit.Screen
import com.slack.circuit.ScreenView
import com.slack.circuit.ScreenViewFactory
import com.slack.circuit.Ui
import com.slack.circuit.sample.R
import com.slack.circuit.sample.di.AppScope
import com.slack.circuit.sample.petdetail.PetPhotoCarouselTestConstants.CAROUSEL_TAG
import com.slack.circuit.ui
Expand Down Expand Up @@ -202,7 +201,6 @@ internal fun PetPhotoCarousel(state: PetPhotoCarouselScreen) {
model =
ImageRequest.Builder(LocalContext.current)
.data(state.photoUrls[page].takeIf(String::isNotBlank))
.fallback(R.drawable.dog)
.apply {
if (page == 0) {
placeholderMemoryCacheKey(state.photoUrlMemoryCacheKey)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -287,7 +287,6 @@ private fun PetListGridItem(modifier: Modifier, animal: PetListAnimal, onClick:
model =
ImageRequest.Builder(LocalContext.current)
.data(animal.imageUrl)
.fallback(R.drawable.dog)
.memoryCacheKey(animal.imageUrl)
.crossfade(true)
// Default is hardware, which isn't usable in Palette
Expand Down
Binary file added sample/src/main/res/drawable/dog2.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit c548173

Please sign in to comment.