Выбрать элемент в iOS Picker с помощью Xamarin UITest? - PullRequest
0 голосов
/ 03 апреля 2019

Мы тестируем наше приложение Xamarin.Forms, используя UITest, и нам нужно выбрать значение средства выбора на iOS.

Можно выбрать по номеру строки в коллекции предметов, как это:

app.Query(x => x.Class("UIPickerView").Invoke("selectRow", 1, "inComponent", 0, "animated", true))

где мы выбираем строку 1 в приведенном выше примере.

Однако нам нужно иметь возможность выбирать по значению - так, например, с помощью средства выбора, имеющего список заголовков, чтобы выбрать заголовок «Mrs», нам нужно сделать что-то вроде:

app.Query (x => x.Class ("UIPickerView"). Invoke ("selectValue", "Mrs", "inComponent", 0, "animated", true))

Однако в UIPickerView нет метода selectValue (или аналогичного метода) (ссылка здесь ).

Одна мысль состоит в том, чтобы получить количество строк в элементах и ​​перебрать их, но когда я пытаюсь вызвать getNumberOfRows, я получаю следующую ошибку:

app.Query (x => x.Class ("UIPickerView"). Invoke ("numberOfRows", "inComponent", 0))

Ошибка при выполнении запроса ([неизвестно]). Исключение: System.Exception: Для вызова селектора iOS требуется либо 0, либо неравное число аргументы (они должны совпадать попарно, включая имя метода). в Xamarin.UITest.Queries.InvokeHelper.AppTypedSelector (Xamarin.UITest.Queries.AppQuery appQuery, Xamarin.UITest.Queries.ITokenContainer tokenContainer, System.Object [] Аргументы queryParams, System.String methodName, System.Object [], System.Boolean явноRequestedValue) [0x0011a] в <2a16c16730a54859bda72c6bc1c728f7>: 0 в Xamarin.UITest.Queries.InvokeHelper.Invoke (Xamarin.UITest.Queries.AppQuery appQuery, System.String methodName, System.Object [] arguments) [0x00000] в <2a16c16730a54859bda72c6bc1c728f7>: 0 в Xamarin.UITest.Queries.AppQuery.Invoke (System.String methodName, System.Object arg1, System.Object arg2) [0x00000] в <2a16c16730a54859bda72c6bc1c728f7>: 0 в .m__0 (Xamarin.UITest.Queries.AppQuery x) [0x0000b] в <0de9804cff324d049415e25573e8da8a>: 0 в Xamarin.UITest.SharedApp.Expand [T] (System.Func 2[T,TResult] typedQuery) [0x0000c] in <2a16c16730a54859bda72c6bc1c728f7>:0 at Xamarin.UITest.iOS.iOSApp+<>c__DisplayClass17_0 1 [T] .b__0 () [0x00000] в <2a16c16730a54859bda72c6bc1c728f7>: 0 в Xamarin.UITest.Utils.ErrorReporting.With [T] (System.Func`1 [TResult] func, System.Object [] args, System.String memberName) [0x0000e] в <2a16c16730a54859bda72c6bc1c728f7>: 0 Исключение: ошибка при выполнение запроса ([неизвестно])

Причина ошибки совершенно ясна - метод ожидает определенного сочетания параметров, но я не вижу, как правильно сформулировать запрос.

То есть какие-нибудь мысли / указатели о том, как я могу выбирать по значению, а не по номеру строки и / или как получить количество элементов?

Ответы [ 2 ]

0 голосов
/ 10 апреля 2019

Лучшее решение - написать бэкдор UITest, а затем в бэкдоре найти рендер для сборщика и управлять им напрямую.

Суть решения была предоставлена ​​мне @LandLu на форумах Xamarin:

Сначала вы должны получить текущий контроллер вида. Затем выполните итерацию подпредставления, чтобы получить рендер. Вот мой сервис зависимостей, на который вы ссылаетесь:

[assembly: Dependency(typeof(FindViewClass))]
namespace Demo.iOS
{
    public class FindViewClass : IFindView
    {
        public void FindViewOfClass()
        {
            UIViewController currentViewController = topViewController();
            getView(currentViewController.View);
        }

        List<PickerRenderer> pickerList = new List<PickerRenderer>();
        void getView(UIView view)
        {
            if (view is PickerRenderer)
            {
                pickerList.Add((PickerRenderer)view);
            }
            else
            {
                foreach (UIView subView in view.Subviews)
                {
                    getView(subView);
                }               
            }
        }

        UIViewController topViewController()
        {
            return topViewControllerWithRootViewController(UIApplication.SharedApplication.KeyWindow.RootViewController);
        }

        UIViewController topViewControllerWithRootViewController(UIViewController rootViewController)
        {
            if (rootViewController is UITabBarController)
            {
                UITabBarController tabbarController = (UITabBarController)rootViewController;
                return topViewControllerWithRootViewController(tabbarController.SelectedViewController);
            }
            else if (rootViewController is UINavigationController)
            {
                UINavigationController navigationController = (UINavigationController)rootViewController;
                return topViewControllerWithRootViewController(navigationController.VisibleViewController);
            }
            else if (rootViewController.PresentedViewController != null)
            {
                UIViewController presentedViewController = rootViewController.PresentedViewController;
                return topViewControllerWithRootViewController(presentedViewController);
            }
            return rootViewController;
        }
    }
}

Как только я это сделаю, я могу выбрать нужный индекс / элемент с помощью свойства Element средства визуализации.

Редактировать Я обработал это в GitHub репозиторий , который реализует набор Backdoor, чтобы упростить выбор iOS Picker

0 голосов
/ 03 апреля 2019

Хорошо ... У меня есть кое-что, что работает.

Предполагается, что мы выбираем строки в базовом списке элементов, а затем проверяем, отображает ли средство выбора нужное нам значение.

Примечания 1. У меня есть вспомогательный класс UIElement, который позволяет мне получить базовый элемент управления или AutomationId.

  1. Два нижеприведенных метода используются для того, чтобы я мог вызвать SelectPickerValue непосредственно с моих TestPages или использовать TapAndSelectPickerValue - мне, вероятно, следует привести в порядок это.

  2. Я не воспользовался возможностью прокрутки в другую сторону, если текущее значение находится в середине доступных значений.

  3. Если элемент находится в поле зрения, можно просто нажать на него - но если это не так, мы должны сделать прокрутку / выбор строки.

       internal static void TapAndSelectPickerValue(UIElement element, string v, int maxRows = 10)
        {
            app.Tap(element.UIControl);
            SelectPickerValue(v, maxRows, element.AutomationId);
        }

        internal static void SelectPickerValue(string v, int maxItems = 10,string pickerId = "")
        {
            if (_platform == Platform.iOS)
            {
                bool managedToSelect = false;

                // Check that we haven't already got the value we want selected.
                Xamarin.UITest.Queries.AppResult[] valueCheckResult = app.Query(x => x.Text(v).Id(pickerId));

                if (valueCheckResult.Length == 0)
                {
                    int rowNumber = 0;

                    // Select rows until we either reach the max to try, or we get the one we want selected
                    for (rowNumber = 0; rowNumber < maxItems; rowNumber++)
                    {
                        app.Query(x => x.Class("UIPickerView").Invoke("selectRow", rowNumber, "inComponent", 0, "animated", true));

                        // This is a hack to move the item so that Xamarin Forms will generate the event to update the UI
                        var rect = app.Query(x => x.Class("UIPickerTableView").Index(0).Child()).First().Rect;
                        app.DragCoordinates(rect.CenterX, rect.CenterY, rect.CenterX, rect.CenterY + 22);
                        app.DragCoordinates(rect.CenterX, rect.CenterY, rect.CenterX, rect.CenterY - 22);

                        // check to see if the Picker is now displaying the value we want
                        valueCheckResult = app.Query(x => x.Text(v).Id(pickerId));
                        if (valueCheckResult.Length == 1)
                        {
                            managedToSelect = true;
                            break;
                        }

                    }
                }

                // If we couldn't select the value we wanted, raise an exception
                if (!managedToSelect)
                {
                    throw new Exception($"Could not select value '{v}' for picker '{pickerId}'");
                }

                // Close the Picker
                app.Tap(c => c.Text("Done"));
            }
            else
            {
                app.ScrollDownTo(m => m.Text(v), x => x.Id("select_dialog_listview"));
                app.Tap(x => x.Text(v));
            }
        }
...