如何在 Xamarin Forms 应用程序的 TabbedPage 栏项目上设置 AutomationId 以进行 UI 测试

How to set AutomationId on TabbedPage bar items in Xamarin Forms app for UI test

我正在 Xamarin UI 测试基于选项卡的 Xamarin Forms 应用程序编写测试。我想在每个选项卡项上设置自动化 ID,以便我的 UI 测试可以单击特定选项卡,而无需参考已本地化的选项卡文本标签。

我想您需要使用自定义渲染器并设置 ContentDescription (Android) 和 AccessibilityIdentifier (iOS),我一直在尝试这样做,但结果喜忧参半。这样做的正确方法是什么?如果我使用自定义渲染器走在正确的轨道上,我应该在 IOS/Android 中重写哪个渲染器方法来实现这个?

更新:

iOS: 答案由@apineda 提供。在问题下方查看他的解决方案。

Android: 似乎需要自定义渲染器。这有点令人讨厌,但它确实有效。我们必须递归地搜索选项卡栏项目的视图层次结构,并为每个项目设置 "ContentDescription"。由于我们使用的是底部导航栏,因此我们向后搜索以获得更好的性能。对于顶部导航栏,您需要搜索 "TabLayout" 而不是 "BottomNavigationItemView"。

[assembly: ExportRenderer(typeof(MainPage), typeof(CustomTabbedPageRenderer))]
namespace Company.Project.Droid.CustomRenderers
{
    public class CustomTabbedPageRenderer : TabbedRenderer
    {
        private bool tabsSet = false;

        public CustomTabbedPageRenderer(Context context)
            : base(context)
        {

        }

        protected override void DispatchDraw(Canvas canvas)
        {
            if (!tabsSet)
            {
                SetTabsContentDescription(this);
            }

            base.DispatchDraw(canvas);
        }

        private void SetTabsContentDescription(Android.Views.ViewGroup viewGroup)
        {
            if (tabsSet)
            {
                return;
            }

            // loop through the view hierarchy backwards. this will work faster since the tab bar
            // is at the bottom of the page
            for (int i = viewGroup.ChildCount -1; i >= 0; i--)
            {
                var menuItem = viewGroup.GetChildAt(i) as BottomNavigationItemView;

                if (menuItem != null)
                {
                    menuItem.ContentDescription = "TabBarItem" + i.ToString();

                    // mark the tabs as set, so we don't do this loop again
                    tabsSet = true;
                }
                else
                {
                    var viewGroupChild = viewGroup.GetChildAt(i) as Android.Views.ViewGroup;
                    if (viewGroupChild != null && viewGroupChild.ChildCount > 0)
                    {
                        SetTabsContentDescription(viewGroupChild);
                    }
                }
            }
        }
    }
}

您不需要 CustomRenderer。您只需将 AutomationId 设置为 TabPage 的子项 Pages,并将其分配给栏 Item。

假设您有如下 TabPage

<?xml version="1.0" encoding="UTF-8"?>
<TabbedPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
                xmlns:local="clr-namespace:MyGreatNamespace"
             x:Class="MyGreatNamespace.MyTabPage">
    <TabbedPage.Children>
         <local:MainPage AutomationId="MainTab" Title="Main Page" />
         <local:PageOne AutomationId="TabOne" Title="Page One" />
         <local:PageTwo AutomationId="TabTwo" Title="Page Two" />
    </TabbedPage.Children>
</TabbedPage>

使用此配置,您将能够:

app.Tap("TabTwo");

而且您不需要使用 Text 属性。

希望对您有所帮助。-

更新:

刚刚确认以上不适用于 Android(注意到您最初的问题是针对 Android)但仅适用于 iOS。由于某种原因,行为有所不同。

您仍然可以使用文本的本地化版本 "Tap it",如下所述。

处理本地化文本时可以使用的一个技巧是设置正确的文化,然后在 XAML 中使用相同的资源集作为测试的一部分。

app.Tap(AppResources.MyMainTabText);