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);
Related
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());
I have tried to show the dialog box while the user giving the wrong username or password, using the below code.
private void showAlert(String title, String msg) {
customDialog = new Dialog(LoginActivity.this,
android.R.style.Theme_Dialog);
customDialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
customDialog.setContentView(R.layout.custom_alert_dialog);
tvTitle = (TextView) customDialog
.findViewById(R.id.dialog_title);
tvMsg = (TextView) customDialog
.findViewById(R.id.dialog_message);
btnNeutral = (Button) customDialog
.findViewById(R.id.closeAlert);
tvMsg.setText(msg);
tvTitle.setText(title);
tvMsg.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED);
tvMsg.setFocusable(true);
btnNeutral.setText("Close");
btnNeutral.setVisibility(View.VISIBLE);
btnNeutral.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
customDialog.dismiss();
}
});
customDialog.show();
tvMsg.requestFocus();
}
The code working fine but my concern is, when i am trying to use the android talkback. It reads only the title of the dialog box. The talkback needs to read the content(message) of the dialog box instead of title. Can anyone help me to do this?
First, announcing just the title of a new dialog is very standard. Doing otherwise would probably be counter productive in terms of accessibility. This sounds to me like an accessibility requirement from someone motivated to do good, that doesn't really understand the needs of users with disabilities. Shoving focus around arbitrarily is usually bad. Let the operating system do what it wants with focus, it is what Assistive Technology (TalkBack) users will be accustomed to.
This said there are two overarching issues with your code. First, when you say focus, you mean accessibility focus.
tvMsg.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED);
tvMsg.setFocusable(true);
tvMsg.requestFocus();
All of these lines are referring to keyboard, or input focus, none of which are particularly meaningful for a TextView. These are only meaningful for active elements like Buttons and EditText boxes. Will this work if you do it correctly, yes. But, it comes with awkward side effects, like a TextView being added to Tab ordering, which is awkward for Keyboard only users, because TextViews don't have focus highlights, so Focus navigation disappears. What you really want is the following event type:
AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED
Now, for the second point. You're doing all of this before your view actually renders. Replace this line:
tvMsg.requestFocus();
With this line:
tvMsg.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED);
Delete the other lines mentioned above, and you should be golden. Though, again, my ultimate recommendation would just be dropping all of this, and removing those three lines outright, and forgetting about this. Let the operating system do its thing!
So I'm working on my first real attempt at an Android app, just a simple scorekeeper for softball games. I've got it tallying scores, outs, etc, and right now it just displays "Home" and "Away." I'd like to give users the chance to enter in actual team names. To this effect, I added a custom AlertDialog that pops up with an EditText, so when you hit "OK" it'll update the Home/Away team name.
The problem is I've been Googling this for most of the week and I've not found a single way to actually do this. I've tried tagging the fragment's layout XML so I can find the EditText, but it always gives me a null reference and crashes the app. I added a TextWatcher that presumably watched the fragment's text, but once changed and hit "OK," nothing happened. Tried adding the TextWatch to the fragment, that crashed I think, it was about two hours ago and I'm exhausted.
Really, I think I need a way to have the fragment find the TextView with the team name and change it to the value of the EditText when I positive click, but I don't know how to do that. Or maybe I've seen it and don't understand it, I've only been doing this about two months. I'd post my code, but I deleted out all the stuff that didn't work because it was taking up most of the screen real estate. Any ideas?
EDIT: So I followed advice below on defining views, that found the value of the EditText presumably, but hitting "OK" just made it set the TextView to a blank value. I think this is because the EditText's contents went away as the dialog was closed. Either that or this is all wrong. View dialogname = getActivity().getLayoutInflater().inflate(R.layout.fragment_home, null);
EditText mEtName = (EditText) dialogname.findViewById(R.id.homeName);
View mainAct = getActivity().getLayoutInflater().inflate(R.layout.activity_softball, null);
TextView oTextView = (TextView) mainAct.findViewById(R.id.teamOne);
newName = mEtName.getText().toString();
oTextView.setText(newName)
I think you are doing wrong at time of defining id for EditText. You need to give it dialog reference.
rather than doing
Edittext edittext = (EditText) findViewById(R.id.editText);
do like
Edittext edittext = (EditText) dialog.findViewById(R.id.editText);
Been through this issue a while ago. I created my own class which extended DialogFragment. When I tried to initialize EditText which was in the dialog, I got null like
mEtName = (EditText)dialog.findViewById(R.id.editText);
So, I initialized it in this way and it worked:
#Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
...
View dialogName = getActivity().getLayoutInflater().inflate(R.layout.dialog_name, null);
mEtName = (EditText) dialogName.findViewById(R.id.dialog_etxt_name);
}
Where R.layout.dialog_name is my custom dialog layout.
I would like to highlight that I am looking for a Xamarin solution. I have found Java solutions, but I can't seem to convert them to Xamarin. I want to have the user set their birthday and then have the app calculate their age, and display it as text. I have everything functioning. All I am looking to do is change the text on the "ok" button to "Calculate age." I am able to change the text, but the button doesn't grab the date from the picker then. This is how I create my datepicker:
DatePickerDialog setDate = new DatePickerDialog(this, onDateSet, date.Year, date.Month-1, date.Day);
then I use this method to change the text
setDate.SetButton("calculate age", EventHandler<DialogClickEventArgs>)
I have created an EventHandler called Age use for the second argument. What code do I put in the EventHandler to make the button function like the "ok" button? if I set handler:null the method works, I can also get the method to do other things, change text in textbox for a example. Any solution is welcomed.
Wow. No love for Xamarin? I discovered the solution was much simpler. Following from what I learned here: Change DatePickerDialog's button texts. I began throwing darts into the code and this is what stuck. Where I set handler to null I simply set listener to the dialog object like so. setDate.SetButton ("calculate age", listener:setDate);
I'm creating a scenario test framework for Android Cordova/PhoneGap applications that builds on JUnit. There is one scenario I would like to test: you click on some button in the webpage (shown in an Android WebView) and it opens a popup (an AlertDialog). I want to check the message on this popup and click one of the buttons. Therefore I need the view object of this AlertDialog.
I know you can use findViewById, but you have to give an id as parameter, which I don't have since the dialog is created with the following code:
AlertDialog.Builder dlg = new AlertDialog.Builder(ctx.getContext());
dlg.setMessage(message);
dlg.setTitle(title);
....
dlg.create();
dlg.show();
Any idea how I can access the correct view?
Thanks!
The TextView containing the AlertDialog's message is always identified by android.R.id.message. If you capture the result of dlg.create(), you should be able to get a reference to the message TextView by calling .findViewById(android.R.id.message) on it, from which you could then get the text.