When a user signs into my application, an alert dialog appears if it is their first time.
Otherwise, it does not appear.
This makes it tricky when I am trying to write UI tests.
Since the alert dialog appears conditionally, I cannot close it using:
onView(withId(android.R.id.button1)).perform(click())
as I have seen suggested on other posts.
However, if it does appear and I do not close it within my test, the test is blocked from moving on (as it does not recognise any other view ids) and fails.
Does anyone have any recommendations about how I might handle this?
Thank you!
However, if it does appear and I do not close it within my test, the
test is blocked from moving on (as it does not recognise any other
view ids) and fails.
Does anyone have any recommendations about how I might handle this?
Whenever you write a test, you must ensure that the required conditions are in place to reliably and consistently run the test in question. This is the "arrange" portion of the Arrange, Act, Assert idiom.
Therefore, if you're testing a flow that involves the dialog, you must arrange the test to set up the condition under which that dialog shows.
If you're testing a flow that does not involve the dialog, you must arrange the test to set up the condition under which the dialog does not show.
You have not posted code so I have no idea what the "condition" for showing the dialog is, but basically you need to do something in your test that ensures that condition is false if you don't want the dialog or true if you do. Maybe this is setting a shared preference?
So for example, your test might look generally like this:
#Test
fun myAwesomeTest() {
// Arrange - do something to ensure dialog does not show
SomeHelperClass.setConditionToShowDialog(false)
// Act - do actions knowing the dialog will not show
onView(withId(R.id.awesomeId)).perform(click())
// Assert
onView(withId(R.id.duperId)).check(matches(isVisible()))
}
Again, without specifics of your code, it's hard to give more detail but hopefully that is enough to get you going.
Hope that helps!
It sounds like (but I have to guess since you didn't provide more details on this) you're controlling the showing of that "first time" dialog based on a value that you store locally, maybe with PersistentState.
If that is the case, you can control that value directly from your Espresso tests, and thereby make the state of your tests be as expected.
Also, just a side note -- I would strongly advise against having dependent Espresso tests, which it sounds like you have, based on "if it does appear and I do not close it within my test, the test is blocked from moving on".
Your tests must be able to be executed in random order and pass.
Related
Espresso doesn't perform click on a Dialog for enabling GPS generated on this code:
rae.startResolutionForResult(
context,
Constants.GPS_REQUEST
)
I haven't created this dialog so is not part of my "screen" nor "app", it's generated by the system or request to solve the gps resolution.
So I check if gps is enabled, if isn't then this is my line of code to press it:
onView(withText("OK")).perform(click())
But it doesn't work since it looks like Espresso keeps waiting for something to happen and then it crashes alone:
androidx.test.espresso.NoActivityResumedException: No activities in stage RESUMED. Did you forget to launch the activity. (test.getActivity() or similar)?
It doesn't matter if i set random words on the withText("Random words sjdj") it won't work because "it's waiting"
I thought about performing a click on coordinates but that looks like a flakky test because of the height and width and might not be accurate at all (I'm saying it from ignorance) and probably won't work because espresso is waiting.
Edit 1:
If I wait until test stops by itself it throws me the next error:
androidx.test.espresso.NoActivityResumedException: No activities in stage RESUMED. Did you forget to launch the activity. (test.getActivity() or similar)?
I guess Activity is onPause or something like that and is waiting for the dialog resolution?
But if i set the location good, test works as it should
What can I do to accept/cancel this dialog?
I don't want to be manually checking if location is on. I want to test that everything works as it should.
Here's an image of the actual screen
Found someone who had the same problem as me and the solution was to use an UiAutomator which use the UI of the Device! which Espresso can't reach!
Solution
I've been recently trying out Android's in-app-update API here https://developer.android.com/guide/playcore/in-app-updates and calling appUpdateManager.completeUpdate() this method after successfully downloading the update seems to work, if I stay put on the view (fragment / activity) or rest my app in the background, but if I move to my app's other view it crashes, This is similar to Snackbar implementation trying to find views when the update fails or is cancelled but I move to a different fragment / activity. Is there a more efficient way to handle this globally throughout the app? It's really hard to debug it since you need an internal production build to test it out.
A similar solution I can think of is how toast behaves, even if you kill the view / activity, the toast will still show to the user, but I still want to use Snackbar and also need to call completeUpdate() if download is finished, where my user still has the freedom to browse the app and not crash.
Snackbar needs CoordinatorLayout to be shown (most common usage), it's just a View, so when you want to show it, you need active GUI on foreground. when you start app update and move somewhere where Snackbar can't be shown then your Exception occurs
Toast is kind of system service with possibility to be shown on top of everything, completely different approach. for showing Toast you need only Context
I'm doing some black box testing (using UiAutomator 2.0 btw, extending InstrumentationTestCase) and I need to know:
1 - when a new activity is created
2 - to know if it's the first time the activity is created
I need this because there are some tests that I want to apply when a new activity appears but I want this detection to be automatic, not manual.
Prior to Android L there was the UiDevice.getCurrentActivityName() method. However, now it is deprecated (moreover, they don't even ensure it works for previous versions). This also happened with the options to getting the activity though the PackageManager.
As such, I would like to know:
Is it possible to programatically detect a new activity? If so, is is possible to know if it's the first time the activity occurs.
If it's not possible, how should I define an activity according to its UI? How many widgets should change for me to conclude it's a different activity?
Thanks.
EDIT: Just to be clear, I don't want to test what happens when the activity is created, I want to be able to identify if it's the first time this activity occurs in a run.
Here is what I currently implemented for this problem, base on a assumption that the same Activity won't change it's UI View hierarchy dynamically. This is OK to me, seems I only want to distinguish between UI changes, not necessary for Activities.
1.Build a signature to identify between screens
signature1:FrameLayout;ListView;LinearLayout;RelativeLayout;...
signature2:FrameLayout;FrameLayout;FrameLayout;LinearLayout;...
2.Then, use a List to keep screens you already known.
3.For performance, you can use a fixed length for screen signatue.
The idea is refer to this paper
And if adb is ok to you, you can use this command,
adb shell dumpsys activity
This refer to another post here
I'm new to Robotium, I have two questions.
1) I'm trying to make click on custom listview item but its not working. I tried with clickInList(int) and clickInlist(int, int).
2) Handling random AlertDialog:
How to handle display alert dialog dynamically in Robotium? For example I'm using alert dialog when I get any message during call webservice, like connection failure, no internet, server error, timeout, etc..,
Thanks in advance.
There are two important things to note about the clickInList(int) method that aren't readily apparent: First, the list items are 1-indexed, so to click the first item of the list, use clickInList(1) not clickInList(0). Second, the clicking is relative to the visible items on the screen, so clickInList(1) will click the first visible item on the list, not the first item overall.
As for the dynamic handling of a Dialog, arbitrary pop-ups aren't really what Robotium was meant to handle. It's supposed to test user interaction with the app under known, controlled, repeatable conditions. If something unexpected happens in the middle of the test, such as losing connection, it should be considered a failure; There's a good chance your test wouldn't be able to run to completion anyway. As a hacky work-around, you can check for the existence of the Dialog before each of your events, something like:
if(solo.searchText("Dialog text") {
//handle closing dialog
}
However, I'd advise against this, it'll slow down your test considerably, and again, even if you close the dialog, the fact that the error happened in the first place is probably going to cause a later part of your test to fail.
I know this is a fundamental java question, but i am relatively new to java.
How do i structure the code attached (monitoring) within a UI.
What the code does is just log values, and if certain conditions are activated, it does stuff. The loop () method does pretty much everything, but there are a few small things done by the preceding methods.
Let's say in the UI, I have a 'calibrate' button, which if pressed, runs a calibrate method/thread, and a 'monitoring' button which runs a different 'monitoring' method/thread. The problem is, these methods/threads are at the moment defined in their own project as classes. My ideas are along the lines that i need to construct these 2 classes and then call the methods i want from them in response to UI interaction. However, if i call just the method, for example:
if (monitoring button) {
monitoring.method1;
}
this means that i can't do anything in parallel to that, so I need to make what happens in those classes into thread somehow.
Cheers,
Rokky
Take a look at AsyncTask, this will allow you to run logic in a background thread, leaving your activity free to respond to the user.