mirror of
https://github.com/sudoxnym/habitica-android.git
synced 2026-05-20 12:49:02 +00:00
Improve tests
This commit is contained in:
parent
60ec4c0533
commit
e60ff5a303
11 changed files with 225 additions and 24 deletions
|
|
@ -1,7 +1,10 @@
|
|||
package com.habitrpg.android.habitica.ui.fragments
|
||||
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.fragment.app.testing.FragmentScenario
|
||||
import androidx.viewbinding.ViewBinding
|
||||
import com.habitrpg.android.habitica.api.GSonFactoryCreator
|
||||
import com.habitrpg.android.habitica.data.ContentRepository
|
||||
import com.habitrpg.android.habitica.data.InventoryRepository
|
||||
import com.habitrpg.android.habitica.data.SocialRepository
|
||||
import com.habitrpg.android.habitica.data.TutorialRepository
|
||||
|
|
@ -9,7 +12,11 @@ import com.habitrpg.android.habitica.data.UserRepository
|
|||
import com.habitrpg.android.habitica.helpers.AppConfigManager
|
||||
import com.habitrpg.android.habitica.helpers.RxErrorHandler
|
||||
import com.habitrpg.android.habitica.models.BaseObject
|
||||
import com.habitrpg.android.habitica.models.user.Stats
|
||||
import com.habitrpg.android.habitica.models.ContentResult
|
||||
import com.habitrpg.android.habitica.models.inventory.Egg
|
||||
import com.habitrpg.android.habitica.models.inventory.Food
|
||||
import com.habitrpg.android.habitica.models.inventory.HatchingPotion
|
||||
import com.habitrpg.android.habitica.models.inventory.QuestContent
|
||||
import com.habitrpg.android.habitica.models.user.User
|
||||
import com.habitrpg.android.habitica.ui.viewmodels.MainUserViewModel
|
||||
import com.kaspersky.kaspresso.testcases.api.testcase.TestCase
|
||||
|
|
@ -23,8 +30,9 @@ import io.reactivex.rxjava3.core.BackpressureStrategy
|
|||
import io.reactivex.rxjava3.core.Flowable
|
||||
import io.reactivex.rxjava3.subjects.PublishSubject
|
||||
import org.junit.Before
|
||||
import java.io.InputStreamReader
|
||||
|
||||
abstract class FragmentTestCase<F : BaseFragment<VB>, VB : ViewBinding, S : Screen<S>> : TestCase() {
|
||||
abstract class FragmentTestCase<F : Fragment, VB : ViewBinding, S : Screen<S>> : TestCase() {
|
||||
|
||||
lateinit var scenario: FragmentScenario<F>
|
||||
lateinit var fragment: F
|
||||
|
|
@ -34,6 +42,7 @@ abstract class FragmentTestCase<F : BaseFragment<VB>, VB : ViewBinding, S : Scre
|
|||
val socialRepository: SocialRepository = mockk(relaxed = true)
|
||||
val tutorialRepository: TutorialRepository = mockk(relaxed = true)
|
||||
val appConfigManager: AppConfigManager = mockk(relaxed = true)
|
||||
val contentRepository: ContentRepository = mockk(relaxed = true)
|
||||
val userViewModel: MainUserViewModel = mockk(relaxed = true)
|
||||
|
||||
abstract fun makeFragment()
|
||||
|
|
@ -50,8 +59,9 @@ abstract class FragmentTestCase<F : BaseFragment<VB>, VB : ViewBinding, S : Scre
|
|||
fun setUpFragment() {
|
||||
clearAllMocks()
|
||||
|
||||
user = User()
|
||||
user.stats = Stats()
|
||||
val userStream = javaClass.classLoader?.getResourceAsStream("user.json")
|
||||
val gson = GSonFactoryCreator.createGson()
|
||||
user = gson.fromJson<User>(gson.newJsonReader(InputStreamReader(userStream)), User::class.java)
|
||||
user.stats?.lvl = 20
|
||||
user.stats?.points = 30
|
||||
every { userRepository.getUser() } returns userEvents
|
||||
|
|
@ -60,6 +70,21 @@ abstract class FragmentTestCase<F : BaseFragment<VB>, VB : ViewBinding, S : Scre
|
|||
throw errorSlot.captured
|
||||
}
|
||||
every { socialRepository.getUnmanagedCopy(capture(unmanagedSlot)) } answers { unmanagedSlot.captured }
|
||||
val contentStream = javaClass.classLoader?.getResourceAsStream("content.json")
|
||||
val reader = gson.newJsonReader(InputStreamReader(contentStream))
|
||||
val content = gson.fromJson<ContentResult>(reader, ContentResult::class.java)
|
||||
every { inventoryRepository.getPets() } returns Flowable.just(content.pets)
|
||||
every { inventoryRepository.getItems(Food::class.java) } returns Flowable.just(content.food)
|
||||
every { inventoryRepository.getItems(Egg::class.java) } returns Flowable.just(content.eggs)
|
||||
every { inventoryRepository.getItems(HatchingPotion::class.java) } returns Flowable.just(content.hatchingPotions)
|
||||
every { inventoryRepository.getItems(QuestContent::class.java) } returns Flowable.just(content.quests)
|
||||
|
||||
every { inventoryRepository.getItems(Food::class.java, any()) } returns Flowable.just(content.food)
|
||||
every { inventoryRepository.getItems(Egg::class.java, any()) } answers {
|
||||
Flowable.just(content.eggs)
|
||||
}
|
||||
every { inventoryRepository.getItems(HatchingPotion::class.java, any()) } returns Flowable.just(content.hatchingPotions)
|
||||
every { inventoryRepository.getItems(QuestContent::class.java, any()) } returns Flowable.just(content.quests)
|
||||
makeFragment()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,65 @@
|
|||
package com.habitrpg.android.habitica.ui.fragments
|
||||
|
||||
import android.view.View
|
||||
import androidx.fragment.app.testing.launchFragmentInContainer
|
||||
import androidx.test.filters.LargeTest
|
||||
import com.habitrpg.android.habitica.R
|
||||
import com.habitrpg.android.habitica.databinding.DrawerMainBinding
|
||||
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.spyk
|
||||
import org.hamcrest.Matcher
|
||||
import org.junit.Test
|
||||
|
||||
class SectionHeaderItem(parent: Matcher<View>) : KRecyclerItem<SectionHeaderItem>(parent) {
|
||||
val title = KTextView(parent) { isRoot() }
|
||||
}
|
||||
|
||||
class MainItem(parent: Matcher<View>) : KRecyclerItem<MainItem>(parent) {
|
||||
val title = KTextView(parent) { withId(R.id.titleTextView) }
|
||||
}
|
||||
|
||||
class NavigationDrawerScreen : Screen<NavigationDrawerScreen>() {
|
||||
val recycler: KRecyclerView = KRecyclerView({
|
||||
withId(R.id.recyclerView)
|
||||
}, itemTypeBuilder = {
|
||||
itemType(::SectionHeaderItem)
|
||||
itemType(::MainItem)
|
||||
})
|
||||
}
|
||||
|
||||
@LargeTest
|
||||
internal class NavigationDrawerFragmentTest : FragmentTestCase<NavigationDrawerFragment, DrawerMainBinding, NavigationDrawerScreen>() {
|
||||
override fun makeFragment() {
|
||||
scenario = launchFragmentInContainer(null, R.style.MainAppTheme) {
|
||||
fragment = spyk()
|
||||
fragment.userRepository = userRepository
|
||||
fragment.inventoryRepository = inventoryRepository
|
||||
fragment.socialRepository = socialRepository
|
||||
fragment.contentRepository = contentRepository
|
||||
fragment.configManager = appConfigManager
|
||||
return@launchFragmentInContainer fragment
|
||||
}
|
||||
}
|
||||
|
||||
override val screen = NavigationDrawerScreen()
|
||||
|
||||
@Test
|
||||
fun showsMenuItems() {
|
||||
screen {
|
||||
recycler {
|
||||
isVisible()
|
||||
childWith<MainItem> { withDescendant { withText("Tasks") } }.isVisible()
|
||||
childWith<MainItem> { withDescendant { withText("Market") } }.isVisible()
|
||||
childWith<MainItem> { withDescendant { withText("Items") } }.isVisible()
|
||||
childWith<MainItem> { withDescendant { withText("Purchase Gems") } }.isVisible()
|
||||
childWith<MainItem> { withDescendant { withText("Subscription") } }.isVisible()
|
||||
childWith<MainItem> { withDescendant { withText("Party") } }.isVisible()
|
||||
childWith<MainItem> { withDescendant { withText("Tavern") } }.isVisible()
|
||||
childWith<MainItem> { withDescendant { withText("Support") } }.isVisible()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,62 @@
|
|||
package com.habitrpg.android.habitica.ui.fragments.inventory.items
|
||||
|
||||
import android.view.View
|
||||
import androidx.fragment.app.testing.launchFragmentInContainer
|
||||
import com.habitrpg.android.habitica.R
|
||||
import com.habitrpg.android.habitica.databinding.FragmentRecyclerviewBinding
|
||||
import com.habitrpg.android.habitica.ui.fragments.FragmentTestCase
|
||||
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.every
|
||||
import io.mockk.spyk
|
||||
import io.reactivex.rxjava3.core.Flowable
|
||||
import org.hamcrest.Matcher
|
||||
import org.junit.Test
|
||||
|
||||
class ItemItem(parent: Matcher<View>) : KRecyclerItem<ItemItem>(parent) {
|
||||
val title = KTextView(parent) { withId(R.id.titleTextView) }
|
||||
val owned = KTextView(parent) { withId(R.id.ownedTextView) }
|
||||
}
|
||||
|
||||
class ItemScreen : Screen<ItemScreen>() {
|
||||
val recycler: KRecyclerView = KRecyclerView({
|
||||
withId(R.id.recyclerView)
|
||||
}, itemTypeBuilder = {
|
||||
itemType(::ItemItem)
|
||||
})
|
||||
}
|
||||
|
||||
internal class ItemRecyclerFragmentTest : FragmentTestCase<ItemRecyclerFragment, FragmentRecyclerviewBinding, ItemScreen>() {
|
||||
override fun makeFragment() {
|
||||
every { inventoryRepository.getOwnedItems("eggs") } answers {
|
||||
Flowable.just(user.items?.eggs!!.filter { it.numberOwned > 0 })
|
||||
}
|
||||
scenario = launchFragmentInContainer(null, R.style.MainAppTheme) {
|
||||
fragment = spyk()
|
||||
fragment.shouldInitializeComponent = false
|
||||
fragment.userRepository = userRepository
|
||||
fragment.inventoryRepository = inventoryRepository
|
||||
fragment.socialRepository = socialRepository
|
||||
fragment.userViewModel = userViewModel
|
||||
fragment.itemType = "eggs"
|
||||
return@launchFragmentInContainer fragment
|
||||
}
|
||||
}
|
||||
|
||||
override val screen = ItemScreen()
|
||||
|
||||
@Test
|
||||
fun hasOnlyOwnedItems() {
|
||||
screen {
|
||||
recycler {
|
||||
isVisible()
|
||||
children<ItemItem> {
|
||||
isVisible()
|
||||
owned.hasNoText("0")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
1
Habitica/src/androidTest/resources/content.json
Normal file
1
Habitica/src/androidTest/resources/content.json
Normal file
File diff suppressed because one or more lines are too long
1
Habitica/src/androidTest/resources/party-members.json
Normal file
1
Habitica/src/androidTest/resources/party-members.json
Normal file
File diff suppressed because one or more lines are too long
1
Habitica/src/androidTest/resources/party.json
Normal file
1
Habitica/src/androidTest/resources/party.json
Normal file
File diff suppressed because one or more lines are too long
29
Habitica/src/androidTest/resources/tasks.json
Normal file
29
Habitica/src/androidTest/resources/tasks.json
Normal file
File diff suppressed because one or more lines are too long
1
Habitica/src/androidTest/resources/user.json
Normal file
1
Habitica/src/androidTest/resources/user.json
Normal file
File diff suppressed because one or more lines are too long
1
Habitica/src/androidTest/resources/world-state.json
Normal file
1
Habitica/src/androidTest/resources/world-state.json
Normal file
|
|
@ -0,0 +1 @@
|
|||
{"worldBoss":{},"currentEvent":{"event":"noCurrentEvent","start":"2022-02-18T20:00-05:00","end":"2022-03-31T20:00-05:00","season":"normal","npcImageSuffix":""},"npcImageSuffix":"","currentEventList":[{"event":"noCurrentEvent","start":"2022-02-18T20:00-05:00","end":"2022-03-31T20:00-05:00","season":"normal","npcImageSuffix":""}]}
|
||||
|
|
@ -70,24 +70,39 @@ import retrofit2.converter.gson.GsonConverterFactory;
|
|||
|
||||
public class GSonFactoryCreator {
|
||||
|
||||
public static GsonConverterFactory create() {
|
||||
Type skillListType = new TypeToken<List<Skill>>() {}.getType();
|
||||
Type taskTagClassListType = new TypeToken<RealmList<Tag>>() {}.getType();
|
||||
Type customizationListType = new TypeToken<RealmList<Customization>>() {}.getType();
|
||||
Type tutorialStepListType = new TypeToken<RealmList<TutorialStep>>() {}.getType();
|
||||
Type faqArticleListType = new TypeToken<RealmList<FAQArticle>>() {}.getType();
|
||||
Type itemDataListType = new TypeToken<RealmList<Equipment>>() {}.getType();
|
||||
Type questCollectListType = new TypeToken<RealmList<QuestCollect>>() {}.getType();
|
||||
Type chatMessageListType = new TypeToken<RealmList<ChatMessage>>() {}.getType();
|
||||
Type challengeListType = new TypeToken<List<Challenge>>() {}.getType();
|
||||
Type challengeRealmListType = new TypeToken<RealmList<Challenge>>() {}.getType();
|
||||
Type questDropItemListType = new TypeToken<RealmList<QuestDropItem>>() {}.getType();
|
||||
Type ownedItemListType = new TypeToken<RealmList<OwnedItem>>() {}.getType();
|
||||
Type ownedPetListType = new TypeToken<RealmList<OwnedPet>>() {}.getType();
|
||||
Type ownedMountListType = new TypeToken<RealmList<OwnedMount>>() {}.getType();
|
||||
Type achievementsListType = new TypeToken<List<Achievement>>() {}.getType();
|
||||
public static Gson createGson() {
|
||||
Type skillListType = new TypeToken<List<Skill>>() {
|
||||
}.getType();
|
||||
Type taskTagClassListType = new TypeToken<RealmList<Tag>>() {
|
||||
}.getType();
|
||||
Type customizationListType = new TypeToken<RealmList<Customization>>() {
|
||||
}.getType();
|
||||
Type tutorialStepListType = new TypeToken<RealmList<TutorialStep>>() {
|
||||
}.getType();
|
||||
Type faqArticleListType = new TypeToken<RealmList<FAQArticle>>() {
|
||||
}.getType();
|
||||
Type itemDataListType = new TypeToken<RealmList<Equipment>>() {
|
||||
}.getType();
|
||||
Type questCollectListType = new TypeToken<RealmList<QuestCollect>>() {
|
||||
}.getType();
|
||||
Type chatMessageListType = new TypeToken<RealmList<ChatMessage>>() {
|
||||
}.getType();
|
||||
Type challengeListType = new TypeToken<List<Challenge>>() {
|
||||
}.getType();
|
||||
Type challengeRealmListType = new TypeToken<RealmList<Challenge>>() {
|
||||
}.getType();
|
||||
Type questDropItemListType = new TypeToken<RealmList<QuestDropItem>>() {
|
||||
}.getType();
|
||||
Type ownedItemListType = new TypeToken<RealmList<OwnedItem>>() {
|
||||
}.getType();
|
||||
Type ownedPetListType = new TypeToken<RealmList<OwnedPet>>() {
|
||||
}.getType();
|
||||
Type ownedMountListType = new TypeToken<RealmList<OwnedMount>>() {
|
||||
}.getType();
|
||||
Type achievementsListType = new TypeToken<List<Achievement>>() {
|
||||
}.getType();
|
||||
|
||||
Gson gson = new GsonBuilder()
|
||||
return new GsonBuilder()
|
||||
.registerTypeAdapter(taskTagClassListType, new TaskTagDeserializer())
|
||||
.registerTypeAdapter(Boolean.class, new BooleanAsIntAdapter())
|
||||
.registerTypeAdapter(boolean.class, new BooleanAsIntAdapter())
|
||||
|
|
@ -122,6 +137,8 @@ public class GSonFactoryCreator {
|
|||
.registerTypeAdapter(SocialAuthentication.class, new SocialAuthenticationDeserializer())
|
||||
.setDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'")
|
||||
.create();
|
||||
return GsonConverterFactory.create(gson);
|
||||
}
|
||||
public static GsonConverterFactory create() {
|
||||
return GsonConverterFactory.create(createGson());
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,7 +29,6 @@ import com.habitrpg.android.habitica.models.inventory.SpecialItem
|
|||
import com.habitrpg.android.habitica.models.responses.SkillResponse
|
||||
import com.habitrpg.android.habitica.models.user.OwnedItem
|
||||
import com.habitrpg.android.habitica.models.user.OwnedPet
|
||||
import com.habitrpg.android.habitica.models.user.User
|
||||
import com.habitrpg.android.habitica.ui.activities.BaseActivity
|
||||
import com.habitrpg.android.habitica.ui.activities.MainActivity
|
||||
import com.habitrpg.android.habitica.ui.activities.SkillMemberActivity
|
||||
|
|
@ -63,7 +62,6 @@ class ItemRecyclerFragment : BaseFragment<FragmentItemsBinding>(), SwipeRefreshL
|
|||
var itemType: String? = null
|
||||
var transformationItems: MutableList<OwnedItem> = mutableListOf()
|
||||
var itemTypeText: String? = null
|
||||
var user: User? = null
|
||||
private var selectedSpecialItem: SpecialItem? = null
|
||||
internal var layoutManager: androidx.recyclerview.widget.LinearLayoutManager? = null
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue