xamarin / Xamarin.Forms

Xamarin.Forms is no longer supported. Migrate your apps to .NET MAUI.
https://aka.ms/xamarin-upgrade
Other
5.62k stars 1.87k forks source link

[Bug] [Android] Label AutomationId binding not working in ListView with Repl testing #10492

Open Chansardrake opened 4 years ago

Chansardrake commented 4 years ago

Description

When AutomationId of Label is binded inside ListView ItemTemplate, on scrolling the AutomationId changed in Repl testing. We have also checked with CollectionView, same behavior occurs.

Issue occurs when ListView CachingStrategy is "RecycleElement"

Sample Link: Sample

Steps to Reproduce

  1. Run the test
  2. Scroll ListView
  3. Enter tree in Repl terminal

Expected Behavior

AutomationId should not change while scrolling (Reusing items)

Actual Behavior

AutomationId of items changed

Basic Information

Screenshots

image

hartez commented 4 years ago

I strongly suspect this is the same issue as #4731.

hartez commented 4 years ago

My best guess here is that when the ListView recycles elements and matches them up with renderers, it doesn't update the automation ID. Possibly the automation IDs can't be updated.

Chansardrake commented 4 years ago

@hartez, Is it possible to fix this issue, since we are also facing the same issue using CollectionView.

jeremycrippsbf commented 4 years ago

Having this issue too, on bindings in list views and collection views. I haven't found a workaround so the testers cant use ids on list items to locate elements in appium :(

nickpeppers commented 4 years ago

Having this issue too, on bindings in list views and collection views. I haven't found a workaround so the testers cant use ids on list items to locate elements in appium :(

Seeing this same issue with ListViews and appium but only on iOS. Has it always been broken or is there a particular version of Xamarin.Forms this use to work with? I've tried the latest 4.8.0.1269, 4.5.0.396, and 3.6.0.344457 which none of those 3 worked for me.

justinhorner commented 4 years ago

Having this issue too, on bindings in list views and collection views. I haven't found a workaround so the testers cant use ids on list items to locate elements in appium :(

Seeing this same issue with ListViews and appium but only on iOS. Has it always been broken or is there a particular version of Xamarin.Forms this use to work with? I've tried the latest 4.8.0.1269It, 4.5.0.396, and 3.6.0.344457 which none of those 3 worked for me.

It has always been an issue for us, regardless of the version of Xamarin

MaxFmi commented 3 years ago

Having the same issue with ListView.GroupHeader using Xamarin.Forms 4.8.0.1560. It ends up with an AutomationId from another item (fyi not a GroupHeader).

nickpeppers commented 3 years ago

@samhouts Is there an ETA on when this might be resolved? Our team uses Appium for a lot of automation and can't fully automate a Xamarin.Forms app for iOS because of this.

iupchris10 commented 3 years ago

I don't know if this will workaround your problem exactly, but I ended up going this route to solve most of my Cell/AutomationId issues.

First, I'm cutting ties with ListView and moving to CollectionView. Then, I make an ItemTemplate, setting the AutomationId on one of the child controls inside the template, rather than the cell container. This is what the UI test will tap on. Here's a simple Text/Detail template. Note the AutomationId binding on CustomLabel...

<CollectionView.ItemTemplate>
<DataTemplate>
<Grid>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="Auto" />
                <ColumnDefinition Width="*" />
            </Grid.ColumnDefinitions>
            <Label Text="{Binding Text}"  />
            <custom:CustomLabel Grid.Column="1" Text="{Binding Detail}"
                    AutomationId="{Binding AutomationId}" />
        </Grid>
</DataTemplate>
</CollectionView.ItemTemplate>`

I have a CustomLabel class that subclasses Label...

public sealed class CustomLabel : Label
{ 
...
}

Then... I have a CustomLabelRenderer in each native project. I override OnElementPropertyChanged to use the AutomationId correctly. This method should be called as you scroll through the list (assuming you are using CollectionView OR ListView with RecycleElement).

[assembly: ExportRenderer(typeof(CustomLabel), typeof(CustomLabelRenderer))]
namespace YourProject.Droid.CustomRenderers
{
    public class CustomLabelRenderer : LabelRenderer
    {
        public CustomLabelRenderer(Context context)
            : base(context)
        { }
...
        protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            var label = sender as CustomLabel;
            switch (e.PropertyName)
            {
                case nameof(CustomLabel.AutomationId):
                    Control.ContentDescription = label.AutomationId;
                    break;
            }
            base.OnElementPropertyChanged(sender, e);
        }

This is working out pretty well for me so far. Best of luck to you.