Updating an EditText with Espresso - android

I'm attempting to update an EditText as part of an Espresso test with:
onView(allOf(withClassName(endsWith("EditText")), withText(is("Test")))).perform(clearText())
.perform(click())
.perform(typeText("Another test"));
However I receive the following error:
com.google.android.apps.common.testing.ui.espresso.NoMatchingViewException: No views in hierarchy found matching: (with class name: a string ending with "EditText" and with text: is "Test")
By breaking down the test line I can see that this occurs after performing clearText(), so I assume that the matchers are being re-run prior to each perform and fail the prior to the second action. Although this makes sense, it leaves me somewhat confused as to how to update the EditText using Espresso. How should I do this?
Note that I cannot use a resource ID or similar in this scenario and have to use the combination as shown above to identify the correct view.

You can use the replaceText method.
onView(allOf(withClassName(endsWith("EditText")), withText(is("Test"))))
.perform(replaceText("Another test"));

Three things to try:
1. You can run performs in succession.
onView(...)
.perform(clearText(), typeText("Some Text"));
2. There is a recorded issue on the Espresso page which was marked as invalid (but is still very much a bug). A workaround for this is to pause the test in-between performs.
public void test01(){
onView(...).perform(clearText(), typeText("Some Text"));
pauseTestFor(500);
onView(...).perform(clearText(), typeText("Some Text"));
}
private void pauseTestFor(long milliseconds) {
try {
Thread.sleep(milliseconds);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
3. Are you absolutely sure that your EditText contains the text, "Test"?

To set value in EditText with Espresso
simple like this
onView(withId(R.id.yourIdEditText)).perform(typeText("Your Text"))

I was having a similar issue and solved it using the containsString matcher and Class.getSimpleName(). Like this:
onView(withClassName(containsString(PDFViewPagerIVZoom.class.getSimpleName()))).check(matches(isDisplayed()));
You can see the full code here

You could try two things. First I would try to use
onView(withId(<id>).perform...
This way you would always have access to the EditText field even when other EditText fields are on the screen.
If that's not an option, you could split up your perform calls.
onView(allOf(withClassName(endsWith("EditText")),withText(is("Test")))).perform(clearText());
onView(withClassName(endsWith("EditText"))).perform(click());
onView(withClassName(endsWith("EditText"))).perform(typeText("Another Test");

Related

Android Espresso : How to perform an action when the view is displayed on the screen?

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()));

Using espresso, how can I decide which view action to use according to displayed view?

I have a form that displays one component at a time, it may be: EditText, Spinner, ListView, or something else according to some rules.
And each component has a different test code.
Using Espresso, how can I check which component is displayed and do its action?
pseudo code
if( ask to enter the number ){
onView(withId(R.id.et_number)).perform(replaceText("12345"));
}else if(ask to select my country){
onView(withRecyclerView(R.id.rv_country).atPosition(0)).perform(click());
}
What is the best way to implement this case? And if I have to create my custom matcher, how is the implementation for this case?
I would be grateful to anyone who gives me a simple example.
I did something similar before. What I did was to check if a element was displayed inside a try and catch the exception.
Try this:
try { // supposing et_number is displayed
onView(withId(R.id.et_number)).check.matches(isCompletelyDisplayed())); // will throw an exception if its not displayed
onView(withId(R.id.et_number)).perform(replaceText("12345"));
} catch (Exception e) { // et_number is not displayed
onView(withRecyclerView(R.id.rv_country).atPosition(0)).perform(click());
}

Android - AutoCompleteTextView not showing after setText is called

I'm having a weird issue with AutoCompleteTextView.
I have a AutoCompleteTextView that shows suggestions of cities when typing in it.
The list of cities is retrieved from a remote server via JSON. When I use the soft keyboard or the Mic Button on the soft keyboard, the suggestions work fine. AutoCompleteTextView does show the suggested cities.
But, I have a problem when I try to set the text using myAutoCompleteTextView.setText("Chi") , the auto complete does not show..
I have also tried myAutoCompleteTextView.append("Chi") but still no luck..
The adapter is there, its just that the suggestions don't show.
Any tips?
Thanks.
Yes you are right there is a bug in AutocompleteTextview to show default suggestion using setText(""); method.
But you can achieve this by adding some more lines of code as below.
autoText.postDelayed(new Runnable() {
#Override
public void run() {
autoText.showDropDown();
}
},500);
autoText.setText("chi");
autoText.setSelection(autoText.getText().length());
It is due to filtering,
No Need to any extra code for manage it, I found it in very easy and working way.
Google Dev. Reference link
autoText.setText("Default Value here",false)
autoText.setSelection(autoText.text.count()) // kotlin
as per documentation second parameter you can pass for filtering.
boolean: If false, no filtering will be performed as a result of this call.
Biraj Zalavadia's answer work, but you must write to "settext" in Runnable.
Like this:
mACTextViewEmail.postDelayed(new Runnable() {
#Override
public void run() {
mACTextViewEmail.showDropDown();
mACTextViewEmail.setText("My text is here");
mACTextViewEmail.setSelection(mACTextViewEmail.getText().length());
}
},500);
I searched for it and just found this solution that worked so well
Look at this issue
fun AutoCompleteTextView.showDropdown(adapter: ArrayAdapter<String>?) {
if(!TextUtils.isEmpty(this.text.toString())){
adapter?.filter?.filter(null)
}
}
In kotlin language, you can use this extension function.

Android Toast Accumulation Testing

Like many others, i've been trying to solve the problem of toast accumulation.
How to prevent Multiple Toast Overlaps
toast issue in android
Cancelling an already open toast in Android
Best way to avoid Toast accumulation in Android
I finally decided to keep track of the current displayed toast and cancel it when another arrives (there's some more logic involved), but i could have use only one toast and change it message. What i want to know is this... Is there a way to TEST this behaviour? Im currently using Robotium and tried different things, but unfortunately the methods to check for toasts (solo.waitForText and solo.searchForText) aren't helping me as i can't make something like
assertTrue(solo.waitForText(text));
//maybe even some sleep here
assertFalse(solo.searchText(text);
Has anyone done something like this? Is there a way to test this using Robotium? using somethig else?
You can use a robotium condition to wait for the text to disappear. Here's a method I use for that.
private void waitForTextToDisappear(final String text, int wait) {
Condition textNotFound = new Condition() {
#Override
public boolean isSatisfied() {
return !solo.searchText(text);
}
};
assertTrue("Text gone: " + text, solo.waitForCondition(textNotFound, wait));
}

Simple TextView.setText causes 40% CPU Usage

Running my application causes ~40% CPU usage on my Phone:
final String position = String.format("%02d:%02d:%02d", time.getHours(), time.getMinutes(),
time.getSeconds());
getActivity().runOnUiThread(new Runnable() {
#Override
public void run() {
c.mTxtPosition.setText(position);
...
By commenting out the setText method the CPU Usage drops to the expected level of ~4%. The method is invoked every second and does refresh ImageViews, CustomViews ... without causing the same load excess.
Besides the CPU Usage dalvik constantly reports garbage collecting of about 10-1000 objects just by calling setText().
Creating a tracefile like this:
Debug.startMethodTracing("setText");
c.mTxtPosition.setText(position);
Debug.stopMethodTracing();
traceview lists the following methods as Top 5 by their respective exclusive CPU%:
ViewParent.invalidateChildInParent(16%)
View.requestLayout(11%)
ViewGroup.invalidateChild(9%)
TextView.setText(7%)
toplevel(6%)
Has anybody an explanation for this?
I noticed this myself a while ago, I think the problem is that every time you call setText, the size of the textbox can change, thus requiring the entire screen to go through relayout (expensive).
I haven't tried this myself yet, but if your textbox is simple and can be made to be a relatively fixed size, maybe try to subclass TextView and create a view that does not resize itself on setText, but rather just draws whatever it can into the existing area? That would save a lot of time.
Perhaps theres already a flag to setText that can make it do this, but I'm not aware of it, though I haven't searched closely.
In my case, I update a TextView from touch event, which cause a lot of updating The solution was to change the TextView layout_width & layout_height to fixed sized.
some possible improvements :
try using a handler which updates the textview every 0.5 seconds instead of a thread that does it.
make the runnable a final constant object instead of craeting a new one every second.
consider checking that the time has changed (newTimeInMs-LastPublishedTimeInMs>=1000) before telling the textview to update itself.
instead of String.format , try using StringBuilder . however , you won't enjoy the locale solution that the String.format gives (for example , for arabic digits) .
In my case it was this property of TextView:
android:ellipsize="marquee"
Removing it speeded up setting text.
If you look at the source code of setText method you can see that it does a lot of heavy lifting - there is measuring, drawing and object allocations, all of which run on the main thread.
You can use the new PrecomputedText API in order to do all of this on the background thread and make setText faster.
You can use the following working example using kotlin & coroutines
private fun TextView.setTextAsync(text: String) {
val textView = this
lifecycleScope.launch {
val params = TextViewCompat.getTextMetricsParams(textView)
val precomputedText = withContext(Dispatchers.Default) {
PrecomputedTextCompat.create(text, params)
}
TextViewCompat.setPrecomputedText(textView, precomputedText)
}
}
For more details you can read an article about it on my blog
https://androidexplained.github.io/android/ui/2020/10/21/improving-textview-settext-performance.html

Categories

Resources