adospace / reactorui-maui

MauiReactor is a MVU UI framework built on top of .NET MAUI
MIT License
555 stars 46 forks source link

Collections items don't seem to materialize in a unit test #147

Closed powerdude closed 10 months ago

powerdude commented 10 months ago

Hello, I have the following test class:

public class BugTest
{
    public record DataModel
    {
        public string Name { get; set; }

        public string Id { get; set; }
    }

    public interface IMediator
    {
        Task<DataModel[]> GetDataAsync();
    }

    public class BugPage : Component<BugPage.PageState>
    {
        public class PageState
        {
            public DataModel[] Favorites { get; set; } = Array.Empty<DataModel>();
        }

        public override VisualNode Render() =>
            new ContentPage
            {
                RenderList()
            }.Title("Bug");

        protected override void OnMounted()
        {
            Fetch();

            base.OnMounted();
        }

        private async void Fetch()
        {
            var mediator = Services.GetRequiredService<IMediator>();
            var locations = await mediator.GetDataAsync();

            SetState(s => s.Favorites = locations.ToArray());
        }

        private VisualNode RenderList() =>
            new CollectionView().AutomationId("list").ItemsSource(State.Favorites, RenderFavoriteItem);

        private VisualNode RenderFavoriteItem(DataModel location) =>

                     new Label(location.Name).AutomationId("name") 
               ;

    }

    public class StubbedMediator : IMediator
    {
        /// <inheritdoc />
        public Task<DataModel[]> GetDataAsync() =>
            Task.FromResult(new[] { new DataModel { Name = "name", Id = "m" } });
    }

    [Fact]
    public void Test1()
    {
        var mediator = new StubbedMediator();
        using var serviceContext = new ServiceContext(services => services.AddSingleton<IMediator>(mediator));
        var page = TemplateHost.Create(new BugPage());

        page.Find<MauiControls.CollectionView>("list").ItemsSource.Cast<object>().Count().Should().Be(1);
        page.Find<MauiControls.Label>("name").Text.Should().Be("m");
    }
}

It seems like BugPage.RenderFavoriteItem doesn't get called. Is there something wrong with how the page is set up?

adospace commented 10 months ago

hum, at glance, page.Find<MauiControls.Label>("name").Text.Should().Be("m"); shouldn't be page.Find<MauiControls.Label>("name").Text.Should().Be("name"); ?

is the test failing?

powerdude commented 10 months ago

Well, an exception is thrown before it gets to the assertion. System.InvalidOperationException: Element with automation id name not found or requested type is not correct When I debug, I also see that the RenderFavoriteItem is never called.

adospace commented 10 months ago

OK, I see the problem, items are not materialized until the view is actually rendered (more or less) so in our case, this never occurs. I'm going to fix it by forcing the creation of the items internally when the automation lookup is performed.

Anyway, I'm not sure that this could solve any kind of issues involving a DataTemplate, but for now for every ItemsView-derived control it works.

Please update to the latest version of the package as it will be available,

Thanks for your cooperation

powerdude commented 10 months ago

Hey @adospace, thank you for the quick fix. Unfortunately, it still won't find the item if the view is just a label. So this works:

 private VisualNode RenderFavoriteItem(DataModel location) => new VStack()
                               {
                                     new Label(location.Name).AutomationId("l")
                               };

but this doesn't:

 private VisualNode RenderFavoriteItem(DataModel location) => 
               new Label(location.Name).AutomationId("l")
adospace commented 10 months ago

ah yes, sorry, now it should also work for the first level control, please check the latest version 142