demigor / nreact

React for C#/Xaml
MIT License
63 stars 5 forks source link

What's the best way to walk through the rendered UI? #2

Closed danielkornev closed 8 years ago

danielkornev commented 8 years ago

First of all, wanna acknowledge, your work is brilliant!

Now, the issue.

In WPF, there is a VisualTreeHelper class.

Now, I'm trying to use NUnit testing with NReact, so that I could validate that the control has been rendered correctly...

[Test(Description = "renders a list with only the active items if the filter is active")]
        public void RendersAlistWithOnlyTheActiveItemsIfTheFilterIsActive()
        {
            var todos = new List<Dictionary<string, string>>
            {
                new Dictionary<string, string>
                {
                    ["id"] = "1",
                    ["text"] = "React",
                    ["status"] = "active"
                },
                new Dictionary<string, string>
                {
                    ["id"] = "2",
                    ["text"] = "Redux",
                    ["status"] = "active"
                },
                new Dictionary<string, string>
                {
                    ["id"] = "3",
                    ["text"] = "Immutable",
                    ["status"] = "completed"
                }
            };

            var filter = "active";

            var todolist = new TodoList(filter, todos);

            var component = todolist.Render();

            var sp = component.ToString();

            //Assert.AreEqual(items.Count, 2);
            //Assert.AreEqual(items[0]["text"], "React");
            //Assert.AreEqual(items[1]["text"], "Redux");
        }

In this test, I need to access the actual children of the component, to check if correct items are shown, and if the correct number of children is shown.

The only property I can access is Key, which here is null, and the only method I can run is Render() (as with React with HTML/JS), but all I get is this:

<StackPanel Children=[ <TodoItem />, <TodoItem /> ]/>

Which is insufficient as TodoItems don't contain any meaningful information (but they actually do have - Id, Text, Status), and it's unclear how one could parse it correctly with the XLINQ as square brackets are not supported by XML parser in .NET...

Thus a question - what's the best way to walk through the rendered UI, in the absence of the VisualTreeHelper?

danielkornev commented 8 years ago

Ok, here's an example of an NUnit test written for NReact:

[Test(Description = "supports 'all' filter")]
        public void RendersAllWhenAllFilterIsPassed()
        {
            var todolist = new TodoList(null, _todos);
            var panel = todolist.Render().RenderAsFrameworkElement() as StackPanel;
            Assert.AreEqual(3, panel?.Children?.Count);
            Assert.AreEqual(new[] { "React", "Redux", "Immutable" }, panel?.Children?.OfType<TextBlock>().Select((elem, i) => elem.Text));
        }

where RenderAsFrameworkElement() is an extension method:

public static class NXamlExtensions
    {
        public static FrameworkElement RenderAsFrameworkElement(this NElement nelement)
        {
            var cc = new ContentControl();
            cc.Render(nelement);

            return cc.Content as FrameworkElement;
        }
    } // class
demigor commented 8 years ago

Sorry for late response, Daniel. I was on vacation in Australia, having no time to provide a meaningful answer on this issue. Now I'm back and ready for action ;)

Render() method returns NReact virtual DOM representation (NClass, NElement etc). There is a NElement.Get method to retrieve assigned property in generic manner (including children array).

Your approach includes additional Materialization step (instantiation respective Xaml elements), which could only be done on the main thread. But in the end this gives you full End-to-End test case.

danielkornev commented 8 years ago

Hmm, sorry for late response on my side now, Lex, - been busy with the other aspects of applying CI to our product development process, and so on. :)

Coming back to NReact, I wonder if virtual DOM is good enough for UI testing, or materialization is the way?

demigor commented 8 years ago

There are several reasons to test rendered Xaml elements:

1) Materialization part of rendering process welcomes more testing. 2) Asserting properties of strongly typed Xaml components is more convenient. In case of VDOM, no Intellisense is available etc. 3) Full end-to-end testing.

If you have some ideas on improving testing story, feel free to share...

danielkornev commented 8 years ago

hmm, not really. For now, I'm working on finishing the TodoMVC tutorial using NReact and React.Net (not really there, yet, though) - http://www.theodo.fr/blog/2016/03/getting-started-with-react-redux-and-immutable-a-test-driven-tutorial-part-1/

NReact is an amazing opportunity to bring the hot web ideas to the client apps development...

BTW I wonder what do you think about Avalonia (nee Persplex)?

demigor commented 8 years ago

I haven't yet tried Avalonia myself. Demos look promising. From what I saw, I believe, it is possible to make NReact support Avalonia as well. Especially, if Avalonia keeps XAML semantics (DependencyProperties, UIElement etc) intact.

danielkornev commented 8 years ago

Same there, hadn't tried Avalonia itself, but it looks promising.

Ok, one more question here :) What are your thoughts on Redux.Net?

https://github.com/GuillaumeSalles/redux.NET