try enabling UI tests again

This commit is contained in:
Phillip Thelen 2023-02-14 17:53:20 +01:00
parent 7f26f973f9
commit cd1492ca2d
5 changed files with 70 additions and 61 deletions

View file

@ -40,31 +40,31 @@ jobs:
with:
arguments: testProdDebugUnitTest
# ui-test:
# runs-on: macos-latest
# strategy:
# matrix:
# api-level: [24, 26, 28, 29, 30, 31]
# steps:
# - uses: actions/checkout@v2
# - name: set up JDK 11
# uses: actions/setup-java@v2
# with:
# java-version: '11'
# distribution: 'adopt'
# cache: gradle
# - name: Prepare
# run: ./.github/prepare-workflow
# - name: Validate Gradle wrapper
# uses: gradle/wrapper-validation-action@e6e38bacfdf1a337459f332974bb2327a31aaf4b
# - name: run tests
# uses: reactivecircus/android-emulator-runner@v2
# with:
# api-level: ${{ matrix.api-level }}
# arch: x86_64
# emulator-options: -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none
# disable-animations: true
# script: ./gradlew connectedProdDebugAndroidTest
ui-test:
runs-on: macos-latest
strategy:
matrix:
api-level: [24, 26, 28, 29, 30, 31]
steps:
- uses: actions/checkout@v2
- name: set up JDK 11
uses: actions/setup-java@v2
with:
java-version: '11'
distribution: 'adopt'
cache: gradle
- name: Prepare
run: ./.github/prepare-workflow
- name: Validate Gradle wrapper
uses: gradle/wrapper-validation-action@e6e38bacfdf1a337459f332974bb2327a31aaf4b
- name: run tests
uses: reactivecircus/android-emulator-runner@v2
with:
api-level: ${{ matrix.api-level }}
arch: x86_64
emulator-options: -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none
disable-animations: true
script: ./gradlew connectedProdDebugAndroidTest
lint:
runs-on: ubuntu-latest

View file

@ -76,6 +76,8 @@ dependencies {
androidTestImplementation 'androidx.test.ext:junit-ktx:1.1.5'
androidTestImplementation "io.mockk:mockk-android:$mockk_version"
androidTestImplementation "io.kotest:kotest-assertions-core:$kotest_version"
androidTestImplementation("org.jetbrains.kotlin:kotlin-reflect:$kotlin_version")
androidTestUtil("androidx.test:orchestrator:1.4.2")
implementation 'com.facebook.shimmer:shimmer:0.5.0'
@ -285,6 +287,10 @@ android {
disable 'MissingTranslation', 'InvalidPackage'
enable 'LogConditional', 'IconExpectedSize', 'MissingRegistered', 'TypographyQuotes'
}
packagingOptions {
resources.excludes.add("META-INF/*")
}
}
android.testOptions {

View file

@ -24,13 +24,14 @@ import io.github.kakaocup.kakao.spinner.KSpinner
import io.github.kakaocup.kakao.spinner.KSpinnerItem
import io.github.kakaocup.kakao.text.KButton
import io.github.kakaocup.kakao.toolbar.KToolbar
import io.mockk.coVerify
import io.mockk.every
import io.mockk.justRun
import io.mockk.mockk
import io.mockk.mockkObject
import io.mockk.slot
import io.mockk.verify
import io.reactivex.rxjava3.core.Flowable
import kotlinx.coroutines.flow.flowOf
import org.junit.After
import org.junit.Before
import org.junit.Test
@ -162,7 +163,7 @@ class TaskFormActivityTest : ActivityTestCase() {
device.activities.isCurrent(TaskFormActivity::class.java)
textEditText.typeText("New Habit")
KButton { withId(R.id.action_save) }.click()
verify(exactly = 1) { taskRepository.createTaskInBackground(any(), assignChanges) }
verify(exactly = 1) { taskRepository.createTaskInBackground(any(), emptyMap()) }
}
}
@ -176,7 +177,7 @@ class TaskFormActivityTest : ActivityTestCase() {
val bundle = Bundle()
bundle.putString(TaskFormActivity.TASK_TYPE_KEY, TaskType.HABIT.value)
bundle.putString(TaskFormActivity.TASK_ID_KEY, task.id!!)
every { taskRepository.getUnmanagedTask(any()) } returns Flowable.just(task)
every { taskRepository.getUnmanagedTask(any()) } returns flowOf(task)
val intent = Intent(ApplicationProvider.getApplicationContext(), TaskFormActivity::class.java)
intent.putExtras(bundle)
@ -184,7 +185,7 @@ class TaskFormActivityTest : ActivityTestCase() {
screen {
toolbar {
KView { withId(R.id.action_save) }.click()
verify(exactly = 1) { taskRepository.updateTaskInBackground(any(), assignChanges) }
verify(exactly = 1) { taskRepository.updateTaskInBackground(any(), emptyMap()) }
}
}
}
@ -200,7 +201,7 @@ class TaskFormActivityTest : ActivityTestCase() {
bundle.putString(TaskFormActivity.TASK_TYPE_KEY, TaskType.DAILY.value)
bundle.putString(TaskFormActivity.TASK_TYPE_KEY, TaskType.DAILY.value)
bundle.putString(TaskFormActivity.TASK_ID_KEY, task.id!!)
every { taskRepository.getUnmanagedTask(any()) } returns Flowable.just(task)
every { taskRepository.getUnmanagedTask(any()) } returns flowOf(task)
val intent = Intent(ApplicationProvider.getApplicationContext(), TaskFormActivity::class.java)
intent.putExtras(bundle)
@ -209,7 +210,7 @@ class TaskFormActivityTest : ActivityTestCase() {
device.activities.isCurrent(TaskFormActivity::class.java)
KButton { withId(R.id.action_delete) }.click()
KButton { withText(R.string.delete_task) }.click()
verify(exactly = 1) { taskRepository.deleteTask(task.id!!) }
coVerify(exactly = 1) { taskRepository.deleteTask(task.id!!) }
}
}
@ -287,8 +288,8 @@ class TaskFormActivityTest : ActivityTestCase() {
val bundle = Bundle()
bundle.putString(TaskFormActivity.TASK_TYPE_KEY, TaskType.DAILY.value)
bundle.putString(TaskFormActivity.TASK_ID_KEY, task.id!!)
every { taskRepository.getUnmanagedTask(any()) } returns Flowable.just(task)
justRun { taskRepository.updateTaskInBackground(capture(taskSlot), assignChanges) }
every { taskRepository.getUnmanagedTask(any()) } returns flowOf(task)
justRun { taskRepository.updateTaskInBackground(capture(taskSlot), emptyMap()) }
val intent = Intent(ApplicationProvider.getApplicationContext(), TaskFormActivity::class.java)
intent.putExtras(bundle)
@ -313,7 +314,7 @@ class TaskFormActivityTest : ActivityTestCase() {
typeText("3")
}
KButton { withId(R.id.action_save) }.click()
verify { taskRepository.updateTaskInBackground(any(), assignChanges) }
verify { taskRepository.updateTaskInBackground(any(), emptyMap()) }
assert(taskSlot.captured.everyX == 3)
assert(taskSlot.captured.frequency == Frequency.WEEKLY)
}

View file

@ -22,12 +22,13 @@ import io.github.kakaocup.kakao.text.KTextView
import io.kotest.matchers.shouldBe
import io.mockk.CapturingSlot
import io.mockk.clearMocks
import io.mockk.coEvery
import io.mockk.coVerify
import io.mockk.every
import io.mockk.mockk
import io.mockk.mockkObject
import io.mockk.spyk
import io.mockk.verify
import io.reactivex.rxjava3.core.Flowable
import kotlinx.coroutines.flow.flowOf
import org.hamcrest.Matcher
import org.hamcrest.Matchers.isA
import org.junit.Test
@ -70,10 +71,10 @@ class ItemScreen : Screen<ItemScreen>() {
internal class ItemRecyclerFragmentTest : FragmentTestCase<ItemRecyclerFragment, FragmentRecyclerviewBinding, ItemScreen>(false) {
override fun makeFragment() {
every { inventoryRepository.getOwnedItems("eggs") } answers {
Flowable.just(user.items?.eggs!!.filter { it.numberOwned > 0 })
flowOf(user.items?.eggs!!.filter { it.numberOwned > 0 })
}
every { inventoryRepository.getOwnedItems("hatchingPotions") } answers {
Flowable.just(user.items?.hatchingPotions!!.filter { it.numberOwned > 0 })
flowOf(user.items?.hatchingPotions!!.filter { it.numberOwned > 0 })
}
fragment = spyk()
fragment.shouldInitializeComponent = false
@ -113,10 +114,10 @@ internal class ItemRecyclerFragmentTest : FragmentTestCase<ItemRecyclerFragment,
every { inventoryRepository.getOwnedItems("food") } answers {
var items = user.items?.food!!.filter { it.numberOwned > 0 }
items = (items + items).sortedBy { it.key }
Flowable.just(items)
flowOf(items)
}
every { inventoryRepository.getItems(Food::class.java, any()) } answers {
Flowable.just((content.eggs + content.eggs).sortedBy { it.key })
flowOf((content.eggs + content.eggs).sortedBy { it.key })
}
fragment.itemType = "food"
val foundItems = mutableListOf<CharSequence?>()
@ -134,7 +135,7 @@ internal class ItemRecyclerFragmentTest : FragmentTestCase<ItemRecyclerFragment,
@Test
fun canHatchPetWithEggs() {
val slot = CapturingSlot<HatchPetUseCase.RequestValues>()
every { hatchPetUseCase.callInteractor(capture(slot)) } returns mockk(relaxed = true)
coEvery { hatchPetUseCase.callInteractor(capture(slot)) } returns mockk(relaxed = true)
fragment.itemType = "eggs"
launchFragment()
screen {
@ -142,7 +143,7 @@ internal class ItemRecyclerFragmentTest : FragmentTestCase<ItemRecyclerFragment,
childWith<ItemItem> { withDescendant { withText("Wolf") } }.click()
KView { withText(R.string.hatch_with_potion) }.click()
KView { withText("Shade") }.click()
verify { hatchPetUseCase.callInteractor(any()) }
coVerify { hatchPetUseCase.callInteractor(any()) }
slot.captured.egg.key shouldBe "Wolf"
slot.captured.potion.key shouldBe "Shade"
}
@ -152,7 +153,7 @@ internal class ItemRecyclerFragmentTest : FragmentTestCase<ItemRecyclerFragment,
@Test
fun canHatchPetWithPotions() {
val slot = CapturingSlot<HatchPetUseCase.RequestValues>()
every { hatchPetUseCase.callInteractor(capture(slot)) } returns mockk(relaxed = true)
coEvery { hatchPetUseCase.callInteractor(capture(slot)) } returns mockk(relaxed = true)
fragment.itemType = "hatchingPotions"
launchFragment()
screen {
@ -160,7 +161,7 @@ internal class ItemRecyclerFragmentTest : FragmentTestCase<ItemRecyclerFragment,
childWith<ItemItem> { withDescendant { withText("Shade") } }.click()
KView { withText(R.string.hatch_egg) }.click()
KView { withText("Wolf") }.click()
verify { hatchPetUseCase.callInteractor(any()) }
coVerify { hatchPetUseCase.callInteractor(any()) }
slot.captured.egg.key shouldBe "Wolf"
slot.captured.potion.key shouldBe "Shade"
}
@ -170,19 +171,19 @@ internal class ItemRecyclerFragmentTest : FragmentTestCase<ItemRecyclerFragment,
@Test
fun canSellItems() {
val slot = CapturingSlot<OwnedItem>()
every { inventoryRepository.sellItem(capture(slot)) } returns mockk(relaxed = true)
coEvery { inventoryRepository.sellItem(capture(slot)) } returns mockk(relaxed = true)
fragment.itemType = "eggs"
launchFragment()
screen {
recycler {
childWith<ItemItem> { withDescendant { withText("Cactus") } }.click()
KView { withText("Sell (3 Gold)") }.click()
verify { inventoryRepository.sellItem(any()) }
coVerify { inventoryRepository.sellItem(any()) }
slot.captured.key shouldBe "Cactus"
childWith<ItemItem> { withDescendant { withText("Panda Cub") } }.click()
KView { withText("Sell (3 Gold)") }.click()
verify { inventoryRepository.sellItem(any()) }
coVerify { inventoryRepository.sellItem(any()) }
slot.captured.key shouldBe "PandaCub"
}
}

View file

@ -14,10 +14,11 @@ import io.github.kakaocup.kakao.recycler.KRecyclerItem
import io.github.kakaocup.kakao.recycler.KRecyclerView
import io.github.kakaocup.kakao.screen.Screen
import io.github.kakaocup.kakao.text.KTextView
import io.mockk.coEvery
import io.mockk.coVerify
import io.mockk.every
import io.mockk.spyk
import io.mockk.verify
import io.reactivex.rxjava3.core.Flowable
import kotlinx.coroutines.flow.flowOf
import org.hamcrest.Matcher
import org.junit.Test
@ -54,7 +55,7 @@ internal class TaskRecyclerViewFragmentTest : FragmentTestCase<TaskRecyclerViewF
@Test
fun displaysHabits() {
every { taskRepository.getTasks(TaskType.HABIT, any()) } returns Flowable.just(tasks.filter { it.type == TaskType.HABIT })
every { taskRepository.getTasks(TaskType.HABIT, any(), emptyArray()) } returns flowOf(tasks.filter { it.type == TaskType.HABIT })
fragment.taskType = TaskType.HABIT
launchFragment()
screen {
@ -73,7 +74,7 @@ internal class TaskRecyclerViewFragmentTest : FragmentTestCase<TaskRecyclerViewF
@Test
fun displaysDailies() {
every { taskRepository.getTasks(TaskType.DAILY, any()) } returns Flowable.just(tasks.filter { it.type == TaskType.DAILY })
every { taskRepository.getTasks(TaskType.DAILY, any(), emptyArray()) } returns flowOf(tasks.filter { it.type == TaskType.DAILY })
fragment.taskType = TaskType.DAILY
launchFragment()
screen {
@ -88,7 +89,7 @@ internal class TaskRecyclerViewFragmentTest : FragmentTestCase<TaskRecyclerViewF
@Test
fun displaysTodos() {
every { taskRepository.getTasks(TaskType.TODO, any()) } returns Flowable.just(tasks.filter { it.type == TaskType.TODO })
every { taskRepository.getTasks(TaskType.TODO, any(), emptyArray()) } returns flowOf(tasks.filter { it.type == TaskType.TODO })
fragment.taskType = TaskType.TODO
launchFragment()
screen {
@ -179,7 +180,7 @@ internal class TaskRecyclerViewFragmentTest : FragmentTestCase<TaskRecyclerViewF
@Test
fun scoreHabitUp() {
val habits = tasks.filter { it.type == TaskType.HABIT }
every { taskRepository.getTasks(TaskType.HABIT, any()) } returns Flowable.just(habits)
every { taskRepository.getTasks(TaskType.HABIT, any(), emptyArray()) } returns flowOf(habits)
fragment.taskType = TaskType.HABIT
launchFragment()
screen {
@ -190,7 +191,7 @@ internal class TaskRecyclerViewFragmentTest : FragmentTestCase<TaskRecyclerViewF
KView(this.parent) {
withId(R.id.btnPlus)
}.click()
verify(exactly = 1) { taskRepository.taskChecked(any(), habits.first().id!!, true, false, any()) }
coVerify(exactly = 1) { taskRepository.taskChecked(any(), habits.first().id!!, true, false, any()) }
}
}
}
@ -200,7 +201,7 @@ internal class TaskRecyclerViewFragmentTest : FragmentTestCase<TaskRecyclerViewF
fun scoreHabitDown() {
val habits = tasks.filter { it.type == TaskType.HABIT }
val firstHabit = habits.first()
every { taskRepository.getTasks(TaskType.HABIT, any()) } returns Flowable.just(habits)
every { taskRepository.getTasks(TaskType.HABIT, any(), emptyArray()) } returns flowOf(habits)
fragment.taskType = TaskType.HABIT
launchFragment()
screen {
@ -211,7 +212,7 @@ internal class TaskRecyclerViewFragmentTest : FragmentTestCase<TaskRecyclerViewF
KView(this.parent) {
withId(R.id.btnMinus)
}.click()
verify(exactly = 1) { taskRepository.taskChecked(any(), firstHabit.id!!, false, false, any()) }
coVerify(exactly = 1) { taskRepository.taskChecked(any(), firstHabit.id!!, false, false, any()) }
}
}
}
@ -220,7 +221,7 @@ internal class TaskRecyclerViewFragmentTest : FragmentTestCase<TaskRecyclerViewF
@Test
fun completeDaily() {
val dailies = tasks.filter { it.type == TaskType.DAILY }
every { taskRepository.getTasks(TaskType.DAILY, any()) } returns Flowable.just(dailies)
every { taskRepository.getTasks(TaskType.DAILY, any(), emptyArray()) } returns flowOf(dailies)
fragment.taskType = TaskType.DAILY
launchFragment()
screen {
@ -230,13 +231,13 @@ internal class TaskRecyclerViewFragmentTest : FragmentTestCase<TaskRecyclerViewF
KView(this.parent) {
withId(R.id.checkBoxHolder)
}.click()
verify(exactly = 1) { taskRepository.taskChecked(any(), dailies.first().id!!, true, false, any()) }
coVerify(exactly = 1) { taskRepository.taskChecked(any(), dailies.first().id!!, true, false, any()) }
}
childAt<TaskItem>(1) {
KView(this.parent) {
withId(R.id.checkBoxHolder)
}.click()
verify(exactly = 1) { taskRepository.taskChecked(any(), dailies[1].id!!, false, false, any()) }
coVerify(exactly = 1) { taskRepository.taskChecked(any(), dailies[1].id!!, false, false, any()) }
}
}
}
@ -245,7 +246,7 @@ internal class TaskRecyclerViewFragmentTest : FragmentTestCase<TaskRecyclerViewF
@Test
fun completeTodo() {
val todos = tasks.filter { it.type == TaskType.TODO }
every { taskRepository.getTasks(TaskType.TODO, any()) } returns Flowable.just(todos)
coEvery { taskRepository.getTasks(TaskType.TODO, any(), emptyArray()) } returns flowOf(todos)
fragment.taskType = TaskType.TODO
launchFragment()
screen {
@ -255,7 +256,7 @@ internal class TaskRecyclerViewFragmentTest : FragmentTestCase<TaskRecyclerViewF
KView(this.parent) {
withId(R.id.checkBoxHolder)
}.click()
verify(exactly = 1) { taskRepository.taskChecked(any(), todos.first().id!!, true, false, any()) }
coVerify(exactly = 1) { taskRepository.taskChecked(any(), todos.first().id!!, true, false, any()) }
}
}
}