Android Compose Unit testing - Toggle a Switch - android

Given a button with a Modifier:
TextButton(modified = Modifier.testTag("abc123"))
when you want to create a test to click it, you do:
composeTestRule.onNodeWithTag("abc123").performClick()
but when I'm having a:
Switch(modifier = Modifier.testTag("abc123"))
I'm trying every single perform gesture but I can't get the Switch to toggle, and can't get any documentation from Android.
What's the correct way to toggle it automatically in order to test it?

I had issues toggling a switch with performClick(), but it turned out the switch wasn't visible on screen, performClick() will then simply click the coordinates (0,0) without any error.
So to ensure it's displayed first:
composeTestRule.onNodeWithTag("abc123")
.assertIsDisplayed()
.performClick()
OLD ANSWER (can still be used if you need to click something which is not displayed)
This seems to be a working way to toggle a material Switch in a Jetpack Compose test:
composeTestRule.onNodeWithTag("abc123")
.performSemanticsAction(SemanticsActions.OnClick)

I don't know if you are still struggling with this, but the following seems to work for me:
composeTestRule
.onNodeWithTag("abc123")
.performGesture { swipeLeft() } // or swipeRight to turn it on

Related

Android Studio Kotlin - Onclick listener not being recognized

So this is my first time using Kotlin and Android studio and I really got to say thus far my experience has been horrible. No other language or IDE has put me in the position where I had to do more than hours research to try and make a simple button load the next page and then still being unable to do it.
This is my Login.kt page
and there you can see its having problems with the findviewbyID and setonlclicklistener.
Top of my Activity_login.xml page
The button im trying to create the onclick event for.
Please keep in mind I did try just the normal creation of setonclick for the button but then I didnt seem to recognize that I have a button with the ID of login_btn
change the init button to
val button=findViewById<Button>(R.id.login_btn)
in my case i have removed onclick from xml.
val button : Button = findViewById(R.id.login_btn);
button.setOnClickListener {
}
If no answers above can help you, you can use viewbinding to access your view. I had so many problems while using findViewById as a newbie. Here is the documentation,
https://developer.android.com/topic/libraries/view-binding

Switch button animation doesn't work in Drawer Navigation View

After spending a lot of time and not finding a suitable solution, I decided to turn to this service for help.
I have an example of the simplest application that implements Drawer. This example contains only menu items without any implementations. In the menu item Share, I added a Switch and a listener to it:
main_nav.xml
<item
android:id="#+id/nav_share"
android:icon="#drawable/ic_menu_share"
app:actionViewClass="androidx.appcompat.widget.SwitchCompat"
android:title="#string/menu_share" />
MainActivity.kt
val menuItem = navigation_view.menu.findItem(R.id.nav_share)
val switch_id = menuItem.actionView as SwitchCompat
switch_id.isChecked = true
switch_id.setOnClickListener {
// TODO: empty scope
}
The switch works smoothly and with animation as shown below:
But now I need to turn off the Home menu item if the Switch is off:
switch_id.setOnClickListener {
navigation_view.menu.findItem(R.id.nav_home).isEnabled = switch_id.isChecked
}
After adding this line, my Switch animation breaks!
I spent two days solving this issue and in the end to no avail.
My question: WTF with android menu in 2021? Why does accessing a menu item break the animation and how can I fix it? I would be grateful for any help !!
I created an issue with this question in Android Tracker and got an answer:
Either way, this is likely to be a non-trivial fix for an issue that
is not a regression and not impacting correctness of the UI. At this
time, we have no plans to address the issue.
And then a workaround was suggested:
Something along the lines of adding a setOnCheckedChangeListener that
posts a delayed Runnable to effect the change. I'd recommend asking on
StackOverflow if you need a detailed example.
E.g.
How to delay "runOnUiThread" in android?
I added a postDelay(200) and the Switch animation works fine:
switch.setOnCheckedChangeListener { _, isChecked ->
Handler(Looper.getMainLooper()).postDelayed({
navigationView.menu.findItem(R.id.nav_home).isEnabled = isChecked
}, 200)
}

What is the purpose of the soundEffectsEnabled view attribute in Android?

What is the use of the the view attribute soundEffectsEnabled (Boolean) as seen in Android Studio properties panel?
I tried setting it to true for a Button as seen in the image above, for getting a click sound when the button is clicked, but it had no effect. I looked up the documentation for the attribute at the link given below but it does not seem to be descriptive enough.
https://developer.android.com/reference/android/view/View#attr_android:soundEffectsEnabled
I understand that I can try to add sound effects by updating the onClickListener for the button and adding media resources, but I wanted to understand what the purpose of the soundEffectsEnabled attribute is, and how it can be useful. Thanks.
Answering my own question:
Setting the soundEffectsEnabled attribute of the view to true is required for enabling the click sound. However, two other things need to be done apart from this:
Make a function call to View.playSoundEffect() in the onClickListner of the view to produce a sound, as follows:
fun setListenerForButton(button: Button) {
button.setOnClickListener(object : View.OnClickListener{
override fun onClick(v: View?) {
v?.playSoundEffect(android.view.SoundEffectConstants.CLICK)
// Other functionality as required goes here
}
})
}
Enable sounds (and possibly haptic feedback) upon touch in your device settings. Generally this can be found in a place like Settings -> Sound -> (Advanced ->) Touch sounds

Espresso, Find dialog and dismiss it

I tried to find a dialog cancel button and push it in Espresso UI Testing, but I couldn't.
This is my code.
onView(withId(R.id.dialog_close_button)).check(matches(isDisplayed()))
What is the best solution for it?
Please comment your opinion.
If you use the UI-Automator with AndroidX, you can find the dialog and buttons.
It is a gradle dependency code.
dependencies {
androidTestImplementation 'androidx.test.uiautomator:uiautomator:2.2.0'
}
You can reach the button with this code.
It is Kotlin code.
val cancel = activityTestRule.activity.getString(R.string.dialog_cancel_button)
val button = UiDevice
.getInstance(InstrumentationRegistry.getInstrumentation())
.findObject(
UiSelector()
.text(cancel.toUpperCase())
.text(cancel)
)
if (button.exists() && button.isEnabled) {
button.click()
}
If it's an Android dialog and you use two buttons you can find the view using:
onView.withId(android.R.id.button1).perform(ViewActions.click()) //Click on accept button
onView.withId(android.R.id.button2).perform(ViewActions.click()) //Click on cancel button
If you want to test if they are visible you want to use:
assert onView.withId(android.R.id.button1).check(matches(ViewMatchers.isDisplayed()))
Then if you don't want the android one, just replace the id's for yours and it should work, remember if you have duplicated ID's it will complain
EDIT
I suggest to use Layout Inspector, so you can find the ID of each component of your screen so you can replace it with the old answer.
So the steps are :
Open the app and find that dialog
Then go to Tools > Layout Inspector > Choose your processor
Click on the item you want to click with Espresso
Replace it in your onView.withId(HERE_GOES_THE_ID)...
You should add the RootMatcher isDialog() to match Roots that are dialogs (i.e. is not a window of the currently resumed activity).
And also don't forget to perform click on that button if you want to dismiss the dialog as you said in the title.
Use this code:
onView(withId(R.id.dialog_close_button))
.inRoot(isDialog())
.check(matches(isDisplayed()))
.perform(click());

How to scroll list once in android application using Appium and Python

I want to scroll into a list in an Android app using Python and the following code is working for me:
self.driver.find_element_by_android_uiautomator('new UiScrollable(newUiSelector().scrollable(true).instance(0)).scrollIntoView(new UiSelector().text("India").instance(0));')
But this scrolls the list until it doesn't India, but I only want to scroll once.
I tried this one also:
el1 = self.driver.find_element_by_xpath("//*[#resource-id = 'resource-id' and #index ='1']")
el2 = self.driver.find_element_by_xpath("//*[#resource-id = 'resource-id' and #index ='0']")
self.driver.scroll(el1, el2)
This also scrolling the list but it is doing a long scrolling, but i want to go to each and every element in the list.
Can anyone tell me how to scroll the list once?
I tried below mentioned code and worked perfectly for me which i wants. i just used the touch action like press and release, as i want to scroll once, so remove release() part from it and then it worked perfectly for me :)
el1 = self.driver.find_element_by_xpath("<xpath>")
el2 = self.driver.find_element_by_xpath("<xpath>")
action = TouchAction(self.driver)
action.press(el1).move_to(el2).perform()
Who else want the same, he/she can use the same fundamentals.
I have just scrolled, and it awesome. You just need to swipe from bottom to up, when test is running. Try it, it works 100%.

Categories

Resources