Controlling a Picker (Android NumberPicker, iOS UIPickerView) from UITest

Posting this extension method snippet in case it helps anyone else:

    /// <summary>
    /// Set by index on Android and by name on iOS
    /// </summary>
    public static bool SetPicker (this IApp app, int index, string name )
    {
        if (string.IsNullOrEmpty (name))
            throw new ArgumentNullException ("name");
        if (app.IsAndroid())
        {
            var results = app.Query (c => c.Class ("numberPicker").Invoke ("setValue", index));
            app.Tap (c => c.Marked ("OK"));
            return results.Any ();
        }
        else
        {
            app.Tap (c => c.Marked (name));
            app.Tap (c => c.Button ("Done"));
            return true;
        }
    }

In order to test a Xamarin Forms app in both iOS and Android flavors it's somewhat challenging to come up with a sequence of clicks and drags to operate the picker and when you have it working you'll then find that Android 5 has a different layout from 4 requiring yet more special-case code.

This code assumes you've already tapped the picker to open it. You pass it both the index and the text of the item you want to pick.

If anyone has a better way to control pickers on Android and iOS I'd be interested to hear it.

Posts

  • Thanks for sharing @IanMercer‌.

  • PrabakaranRamasamyPrabakaranRamasamy USMember ✭✭✭

    @IanMercer this approach is not working for hidden items.

  • Here is a method I haven't finished yet as the time part is not implemented. However, the date part works on Xamarin.iOS and Xamarin.Android apps. I am sure it can be tweaked to work for Xamarin.Forms:

        protected void SetPickerDate(DateTime desired,bool includeDate,bool includeTime)
        {
            if (includeDate) {
                if (platform == Platform.Android) {
                    int yearNum = desired.Year;
                    //Android starts from 0
                    int monthNum = desired.Month - 1;
                    int dateNum = desired.Day;
                    app.WaitForElement (x => x.Class ("DatePicker"), "Timed out waiting for date picker", TimeSpan.FromMinutes (1));
                    app.Query (x => x.Class ("DatePicker").Invoke ("updateDate", yearNum, monthNum, dateNum));
                } else {
                    string yearStr = "" + desired.Year;
                    string monthStr = desired.ToString("MMMM");
                    string dateStr = "" + desired.Day;
                    app.ScrollDownTo (x => x.Text (monthStr), x => x.Class ("UIPickerTableView").Index (0), ScrollStrategy.Auto, TimeSpan.FromMinutes (1));
                    app.Tap (x => x.Text (monthStr));
                    app.ScrollDownTo (x => x.Text (dateStr), x => x.Class ("UIPickerTableView").Index (3), ScrollStrategy.Auto, TimeSpan.FromMinutes (1));
                    app.Tap (x => x.Text (dateStr));
                    app.ScrollUpTo (x => x.Text (yearStr), x => x.Class ("UIPickerTableView").Index (6), ScrollStrategy.Auto, TimeSpan.FromMinutes (1));
                    app.Tap (x => x.Text (yearStr));
                }
            }
        }
    
  • RichardSevioraRichardSeviora CAMember

    I've taken Shawn's very good work and created an extension class to IAPP to handle both Date and Time pickers in iOS and Android. This also works in Xamarin Forms by default (tested w/ V2.3.0.38-pre2).

    It does make the assumption that the picker is present. If it is NOT present, it'll fail after waiting.

    https://gist.github.com/richseviora/6c978795fe5fb53ab78ed0017a0afd18

    Shawn your scroll logic for iOS wasn't valid for me, what version of UITest are you using? (couldn't tag you in this directly, broke on the period in your name)

Sign In or Register to comment.