composeTestRule not work in Scenario() in kaspresso - android

I'm trying to write Scenario() with composeTestRule in Kaspresso, but I get an error:
Test not setup properly. Use a ComposeTestRule in your test to be able to interact with composables
My scenario for example:
class FillOtp(
) : Scenario() {
override val steps: TestContext<Unit>.() -> Unit = {
val baseTest = BaseTest()
step("Write 0000") {
baseTest.composeTestRule
.onNodeWithTag("test")
.performClick()
MyScreen {
pinEdit {
typeText("0000")
}
continueBtn.click()
}
}
}
}
}
But I have added composeTestRule in BaseTest() class. And composeTestRule works successfully in tests without Scenario()
could you help me solve the problem ?

On another site I was offered the answer:
You can pass it to the constructor from the test:
class MyScenario(semanticsProvider: SemanticsNodeInteractionsProvider) : Scenario() {
override val steps: TestContext<Unit>.() -> Unit = {
semanticsProvider.onNode(...)
}
}
And in test:
scenario(MyScenario(composeTestRule))

Related

How to handle Espresso idling resource in Compose Android

Pretty new to Compose and I am having an Espresso test to become idle timed out when I run all my tests in the test folder. When I run test alone it does pass, I have tried following instruction from this medium post on the waitUntil but I am still facing the same issue. Here is my code snippet.
// https://medium.com/androiddevelopers/alternatives-to-idling-resources-in-compose-tests-8ae71f9fc473
My question is what am I missing ?
#RunWith(AndroidJUnit4::class)
class PCardTest {
#get:Rule
val composeTestRule = createComposeRule()
private val pd = PData(
"home",
"Dec 1, 2021 - May 31, 2022",
)
#Before
fun setUp() {
composeTestRule.setContent {
PCard(pd = pd)
}
}
#Test
fun should_match_home() {
val t = "T ${pd.home}"
composeTestRule.waitUntilDoesNotExist(hasTestTag("T"))
composeTestRule.onNodeWithText(t).assertExists()
}
#Test
fun start_end_date_should_match() {
val startEndDate = pd.datesFrom
composeTestRule.waitUntilDoesNotExist(hasTestTag("Start"))
composeTestRule.onNodeWithText(startEndDate).assertExists()
}

changing test cases from junit to mockito in android app

i am trying to test out an email field in login screen. i want to change the following code using mockito. can it be done. pls help??
class EmailValidatorTest {
#Test
fun emailValidator_CorrectEmailSimple_ReturnsGood() {
val email = "name#email.com"
assertThat(EmailPasswordChecker.getEmailState(email)).isEqualTo(EmailState.GOOD)
}
#Test
fun emailValidator_CorrectEmailSubDomain_ReturnsGood() {
val email = "name#email.co.uk"
assertThat(EmailPasswordChecker.getEmailState(email)).isEqualTo(EmailState.GOOD)
}
#Test
fun emailValidator_InvalidEmailNoTld_ReturnsIncorrect() {
val email = "name#email"
assertThat(EmailPasswordChecker.getEmailState(email)).isEqualTo(EmailState.INCORRECT)
}
#Test
fun emailValidator_InvalidEmailDoubleDot_ReturnsIncorrect() {
val email = "name#email..com"
assertThat(EmailPasswordChecker.getEmailState(email)).isEqualTo(EmailState.INCORRECT)
}
#Test
fun emailValidator_InvalidEmailNoUsername_ReturnsIncorrect() {
val email = "#email.com"
assertThat(EmailPasswordChecker.getEmailState(email)).isEqualTo(EmailState.INCORRECT)
}
#Test
fun emailValidator_EmptyString_ReturnsEmpty() {
val email = ""
assertThat(EmailPasswordChecker.getEmailState(email)).isEqualTo(EmailState.EMPTY)
}
here is some more helper code->
object EmailPasswordChecker{
//some code that i cant share
}
enum class EmailState {
GOOD,
INCORRECT,
EMPTY
}
these are simple tests that i wrote using JUnit. but now i need to change them using mockito. can someone help me with the code? i am fairly new to testing so i am not exactly able to figure out how this framework is working.

How to assert next started activity for a composable test?

I have a composable with a button that launches one of the native activities (Google Settings).
To test this before compose (using Robolectric) I would do something like this:
My test:
#Test
fun `MyFragment - when button clicked - starts activity`() {
// ...
val shadowActivity: ShadowActivity = Shadow.extract(activity)
val nextStartedActivity = shadowActivity.nextStartedActivity
assertNotNull(nextStartedActivity)
assertEquals(Settings.ACTION_APPLICATION_DETAILS_SETTINGS, nextStartedActivity.action)
}
With compose tests (not using activity scenario) it's different. There is no activity handle, only a composeTestRule:
My test:
// ...
private val buttonNode get() = composeTestRule.onNodeWithContentDescription("Button")
#Test
fun `MyComposableToTest - when button clicked - starts activity`() {
composeTestRule.setContent {
MyComposableToTest()
}
buttonNode.assertExists().assertHasClickAction().assertIsEnabled().performClick()
// No possibility to get current activity
}
How can I assert that a new activity is started when testing a Composable?
Some context:
Android Gradle Plugin 7.0.3
Robolectric 4.7.3
Compose 1.1.0-beta04
You are able to fetch the context from the ComposeContentTestRule like this:
lateinit var context : Context
composeTestRule.setContent {
context = LocalContext.current
MyComposableToTest()
}
and then to assert the next started activity
val shadowActivity: ShadowActivity = Shadow.extract(context as ComponentActivity)
val nextStartedActivity = shadowActivity.nextStartedActivity
assertEquals(Settings.ACTION_APPLICATION_DETAILS_SETTINGS, nextStartedActivity.action)
This is how I did it for my instrumented test (NOT using Robolectric).
build.gradle[.kts]:
androidTestImplementation("androidx.test.espresso:espresso-intents:3.4.0")
The test class (in src/androidTest/... directory):
import androidx.test.espresso.intent.Intents
import androidx.test.espresso.intent.Intents.intended
import androidx.test.espresso.intent.matcher.IntentMatchers.hasComponent
// ...
#RunWith(AndroidJUnit4::class)
class MainActivityInstrumentedTest {
#get:Rule val composeTestRule = createAndroidComposeRule<MainActivity>()
#Test fun testTheIntent() {
Intents.init() // IMPORTANT (to be able to use "intended" function)
composeTestRule.setContent {
MyAppTheme {
MainScreen()
}
}
composeTestRule.onNodeWithText("My Button").performClick()
intended(hasComponent(MySecondActivity::class.java.name))
Intents.release()
}
}

Waiting for livedata to complete in UI Espresso test

I'm new to testing and Espresso, so bear with me please.
I have an app with some simple image editing and I have decided to cover it with UI tests.
For starters I have decided to test the initial image uploading, processing and moving to the next screen.
here is the test I came up with so far:
#LargeTest
#RunWith(AndroidJUnit4::class)
class VerifyLoadImage {
lateinit var testContext: Context
#Rule
#JvmField
var mActivityTestRule = ActivityScenarioRule(MainActivity::class.java)
#Before
fun loadContext() {
testContext = InstrumentationRegistry.getInstrumentation().context
}
#Test
fun loadImageToCrop() {
mActivityTestRule.scenario.onActivity { mainActivity ->
// get the activity
val navigationFragment = mainActivity.supportFragmentManager.findFragmentById(R.id.fragmentContainer)
//verify that current fragment displayed is ImagePickerFragment
val currentFragment = navigationFragment?.getDisplayedChildFragment()?.let { it as? ImagePickerFragment }
?: throw AssertionError("currentFragment is not instance of ImagePickerFragment")
//call the method to upload the image from input stream, process it and then navigate to the crop screen
currentFragment.loadBitmapAndOpenCropScreen(AssetInputStreamProvider(testContext, "sample_image.jpg"))
//verify that crop screen is currently displayed
assert(navigationFragment.getDisplayedChildFragment() is CropFragment)
}
}
}
private fun Fragment.getDisplayedChildFragment() = childFragmentManager.fragments.first()
this is the code in currentFragment.loadBitmapAndOpenCropScreen
internal fun loadBitmapAndOpenCropScreen(inputStreamProvider: InputStreamProvider) {
activityViewModel.loadBitmap(inputStreamProvider).observe(viewLifecycleOwner) {
when (it) {
Loading -> showLoading()
is Success -> {
hideLoading()
findNavController().navigate(ImagePickerFragmentDirections.toCrop())
}
is Error -> hideLoading()
}
}
}
the problem is that when testing, the LiveData never changes updates at all [works normally when launching the app].
I would appreciate any help here.
Try InstantTaskExecutorRule
#Rule
#JvmField
var mInstantTaskExecutorRule = InstantTaskExecutorRule()

Android - Testing Fragments With Espresso by Using launchFragmentInContainer Never Completes

My test is never running to completion and I have absolutely no idea why. I can see the toast displayed on my phone's screen. There is absolutely nothing in the logs.
#RunWith(AndroidJUnit4::class)
#SmallTest
class BaseDataFragmentUITest
{
#Test
fun isDisplayingToastWhenFAILED_TO_UPDATE()
{
val fragmentScenario = launchFragmentInContainer<TestBaseDataFragmentImp>()
val toastString: String = context.resources.getString(com.developerkurt.gamedatabase.R.string.data_update_fail)
fragmentScenario.onFragment {
it.handleDataStateChange(BaseRepository.DataState.FAILED_TO_UPDATE)
onView(withText(toastString)).inRoot(withDecorView(not(it.requireActivity().getWindow().getDecorView()))).check(matches(isDisplayed()))
}
}
}
Apparently, Espresso assertions shouldn't be made inside of the onFragment block. So when I wrote the test like this it worked:
#Test
fun isDisplayingToastWhenFAILED_TO_UPDATE()
{
val fragmentScenario = launchFragmentInContainer<TestBaseDataFragmentImp>()
val toastString: String = context.resources.getString(com.developerkurt.gamedatabase.R.string.data_update_fail)
var decorView: View? = null
fragmentScenario.onFragment {
it.handleDataStateChange(BaseRepository.DataState.FAILED_TO_UPDATE)
decorView = it.requireActivity().getWindow().getDecorView()
}
onView(withText(toastString)).inRoot(withDecorView(not(decorView!!))).check(matches(isDisplayed()))
}

Categories

Resources