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());
Related
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
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
I want to add instrumental tests to my Android app.
There is a login screen that perform a load to a certain data first and when succeed it display to the user the auth. forms (username+password).
I want to perform an action to the EditText widgets like typeText like below:
#Test
fun agnetlogin() {
onView(withId(R.id.edt_login)).perform(typeText(loginToBeTyped), closeSoftKeyboard())
onView(withId(R.id.edt_password)).perform(typeText(passwordToBeTyped), closeSoftKeyboard())
onView(withId(R.id.btn_sign_in)).perform(click())
}
but I get the error that the views doesn't exit in hierarchy and it's normal because the visibilities is set to gone when data is charging.
#J.M.J, the good practice to check whether the view is displayed in the view or not. It also avoids errors, you can check for whether the view is displayed or not as below example.
onView(withId(R.id.my_view))
.perform(click())
.check(matches(isDisplayed()));
or if you know that the view is already presented, you can check with a specific name like
onView(withId(R.id.my_view))
.check(matches(withText("Hello Espresso!")))
.perform(click())
.check(matches(isDisplayed()));
You could add an Idlingrecource manager which will wait until your input fields are loaded before performing actions on them:
https://medium.com/azimolabs/wait-for-it-idlingresource-and-conditionwatcher-602055f32356
A quick and dirty solution might be to put a sleep (e.g. for 5 seconds) in front of your code:
Thread.sleep(5000);
onView(withId(R.id.my_view))
.perform(click())
.check(matches(isDisplayed()));
If I want to press ADD button, I tried:
onView(withText("ADD")).perform(click())
as well as
onView(withText("ADD"))
.inRoot(isDialog())
.check(matches(isDisplayed()))
.perform(click());
But none of them work well
I will offer you to use uiautomator for this case, more info
Try to do this
Thread.sleep(TimeUnit.SECONDS.toMillis(1));
UiDevice device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
UiObject obj = device.findObject(new UiSelector().textContains("ADD").clickable(true));
obj.click();
The Espresso withText() is case sensitive. You are checking for 'ADD' in the test, but setting the value to 'Add' in the construction of your dialog. If 'ADD' shows up visually in your UI, that's likely due to a style or textallcaps being set on your textView, but Espresso is actually looking for the underlying text value set on the widget.
I am performing a click on the "Set"-button in a DatePickerDialog with Robotium via
solo.clickOnButton("Set");
If I now change the language of the testing device to a different language, Robotium is not able to find the button, as the text is not "Set" anymore but the translated word.
Is there any possibility to access the button in the Picker in a different way?
As in Jelly Bean the DatePicker lost the "Cancel" button, I cannot use the clickOnButton(int index) method.
The only idea I have would be to use setButton on the DatePickerDialog to have access to the localized string resource of the button text or keep a reference to the button.
But maybe someone knows of a better way to gain access without the need of custom button text.
Regards
Kim
If you have access to the source code, you can use both getString() and getView():
Button button = (Button) solo.getView(R.id.x);
solo.clickOnView(button);
There is also solo.getString(R.string.x) that is good to use for localized builds.
I know that it's not the best solution but it works for me:
solo.clickOnButton(0);
Here's my suggestion (assuming you are showing the dialog via a DialogFragment): I have a SelectDateDialogFragment with a unique TAG and an onCreateDialog() method which creates a DatePickerDialog. I then show the dialog via selectDateDialogfragment.show(getFragmentManager(), SelectDateDialogFragment.TAG). In the Robotium tests, I use code like the following to click the dialog's buttons:
solo.clickOnView(editDateButton);
solo.waitForFragmentByTag(SelectDateDialogFragment.TAG);
solo.setDatePicker(0, 2000, 1, 1);
SelectDateDialogFragment dialogFragment = (SelectDateDialogFragment) activity.getFragmentManager()
.findFragmentByTag(SelectDateDialogFragment.TAG);
DatePickerDialog dialog = (DatePickerDialog) dialogFragment.getDialog();
Button okButton = dialog.getButton(DialogInterface.BUTTON_POSITIVE);
solo.clickOnView(okButton);
solo.waitForDialogToClose();
I would like to share some details with you.
First:
solo.clickOnButton(0);
worked well for me some time. But as the new Dialogs don't have the "Set" and "Cancel" buttons, but instead "Cancel" and "OK", this solution would now select the cancel button on newer devices while just switching to
solo.clickOnButton(1);
would break the test for older devices.
So I migrated to csoltenborn's solution with two modifications:
as I want to stay compatible with older devices I use the SupportFragmentManager
as my fragment is nested in another fragment depending on the device and it's orientation, I sometimes have to access a certain fragments ChildFragmentManager.
This is my solution, maybe it can add to csoltenborn's good answer:
DialogFragment dialogFrag;
Fragment outerFragment = getActivity().getSupportFragmentManager().findFragmentByTag("outerFragmentTAG");
if (outerFragment == null) {
dialogFrag = (DialogFragment)getActivity().getSupportFragmentManager().findFragmentByTag("datePicker");
} else {
dialogFrag = (DialogFragment)outerFragment.getChildFragmentManager().findFragmentByTag("datePicker");
}
Button okButton = ((DatePickerDialog)dialogFrag.getDialog()).getButton(DialogInterface.BUTTON_POSITIVE);
solo.clickOnView(okButton);