Where communities thrive


  • Join over 1.5M+ people
  • Join over 100K+ communities
  • Free without limits
  • Create your own community
People
Activity
  • Jan 15 11:27
    egil labeled #303
  • Jan 15 11:27
    egil assigned #303
  • Jan 15 11:27
    egil review_requested #303
  • Jan 15 10:30
    ventigrande synchronize #303
  • Jan 15 10:30
    ventigrande opened #303
  • Jan 13 16:57
    egil closed #302
  • Jan 13 16:57
    egil commented #302
  • Jan 13 09:26
    sattyamkishormishra opened #302
  • Jan 09 12:08
    egil edited #300
  • Jan 09 12:08
    egil labeled #300
  • Jan 09 12:08
    egil labeled #300
  • Jan 09 12:08
    egil opened #300
  • Jan 08 10:02
    egil closed #299
  • Jan 08 10:01
    egil edited #299
  • Jan 08 10:01
    egil edited #299
  • Jan 08 10:01
    egil edited #299
  • Jan 08 10:01
    egil edited #299
  • Jan 08 10:01
    egil edited #299
  • Jan 08 10:01
    egil edited #299
  • Jan 08 10:01
    egil edited #299
Egil Hansen
@egil
I dont see a problem with that. The only challange might be that the data arrives asynchronously, and thus you might need to use cut.WaitForAssertion(() => /* assertion goes here */) since the test code runs in one thread and the component and renderer in another, to avoid deadlocks.
How is the Fluxor state store made available to the component?
camelCaseSharp
@camelCaseSharp
According to the Fluxor docs the state store is injected as a private property. Yes I was anticipating the need to use cut.WaitForAssertion after reading your replies 13th Nov to @forex.ray.v1_gitlab and how to handle the delay when a unit test makes a live async remote request for data. Your recent presentation with Microsoft available on YouTube was very helpful particularly that bunit architectural slide, now I can picture where the threads run during a unit test.
Egil Hansen
@egil
great, never got to demo waitforassertion though
but glad it helped
Is it injected with DI or is it a cascading value?
Eitherway, you will want a way to control that in your tests. If you can set the data in the store before your render your component, then its likely that the renderer will render the component synchronously and you wont need to use waitforxxx
control it, as have a way to set data in it.
Anyway, when you get it working, do post a sample in the discussions forum under the show and tell category. Will likely be very useful to others.
camelCaseSharp
@camelCaseSharp
The injection is through DI.
[Inject]
private IState<CounterState> CounterState { get; set; }  https://github.com/mrpmorris/Fluxor/blob/master/Tutorials/02-Blazor/02A-StateActionsReducersTutorial/README.md
Egil Hansen
@egil
Ahh its @mrpmorris thats behind that.
Anyway, it does seem like you can just mock or even better, create fake of IState, and then in your test, write Services.AddSingleton<IState<CounterState>>(new FakeState(....))
Peter Morris
@mrpmorris
Yes, and yes :)
PS: @camelCaseSharp -> https://gitter.im/mrpmorris/fluxor
If you are interested
aschaefer94
@aschaefer94
Hi Egil. I'm writing some tests and running into an issue with context menus. Our solution is using a nuget package (Blazor.ContextMenu v.1.8.0) for context menus in our app. It seems like they may be using the HTML 'oncontextmenu' event rather than the blazor '@oncontextmenu' event, would that make it so that the Element.ContextMenu() call in BUnit can't find the event?
Egil Hansen
@egil
hi @aschaefer94, it sounds as if they are listening to that event through javascript. Since bUnit doesnt run javascript, you cannot trigger their javascript code.
its like they have a c# method that is javascript invocable. If thats the case, you can simply invoke that method yourself.
Egil Hansen
@egil
It looks like they are calling a method in their component called ShowMenu and HideMenu: https://github.com/stavroskasidis/BlazorContextMenu/blob/master/BlazorContextMenu/wwwroot/blazorContextMenu.js#L177
But actually, you might jus be able to get one of these out of the services collection and use that: https://github.com/stavroskasidis/BlazorContextMenu/blob/master/BlazorContextMenu/Services/BlazorContextMenuService.cs#L10
It has hide and show menu methods
aschaefer94
@aschaefer94
That's a good find on the service. It doesn't seem like making the call on the service actually changes my html at this point. Should I be able to call instance methods on their component from my code? It doesn't seem like the ShowMenu and HideMenu methods are publicly available for me to call something like cut.ShowMenu() in my test code.
Egil Hansen
@egil
calling those methods might trigger an async render, which you need to tell your test to wait for. So try adding a cut.WaitForState(() => cut.FindAll("query selector elements you expect").Count > 0)
Otherwise, you can always try to find components in the component tree by using cut.FindComponent<TypeOfComponent>()
Then you can do e.g. var menu = cut.FindComponent<ContextMenu>() and then inspect menu.Instanceto see what options you have on the component.
Egil Hansen
@egil

So some times I really want to kick myself for not thinking of something earlier. This is one of those times. This morning I realized that the inline render fragment syntax in razor has the potential for much better razor based tests.

Have small spike, where this is possible:

@inherits TestComponentBase2
@code
{
    [Fact]
    public void Test1()
    {
        var cut = RenderFragment(@<div>hello world</div>);

        cut.MarkupMatches(@<div>hello world</div>);
    }

    [Fact]
    public void Test2()
    {
        var cut = RenderComponent<Counter>(@<Counter DarkMode="true">
                                            </Counter>);

        Assert.True(cut.Instance.DarkMode);
    }

    [Fact]
    public void Counter_Increments_When_Button_Is_Clicked()
    {
        var cut = RenderFragment(@<Counter DarkMode="true" />);

        cut.Find("button").Click();

        cut.Find("p").MarkupMatches(@<p>Current count: 1</p>);
    }
}

What do you guys think?

Peter Morris
@mrpmorris
That looks very good!
I like it a lot
Brett McDonald
@bfmsoft
If I want to test a component that has phases. It returns state one and then after it finishes loading returns another state. How can I tell the CUT to rerender after I change the MOQ so it will return the second state? Basically, I want to do the first MarkupMatches(Frag1), change the MOQ so will return the second state, then "somehow tell component to rerender" then do Second MarkupMatches(Frag2)?
Egil Hansen
@egil
@bfmsoft doesnt you changing the Moq somehow causes the component to render automatically?
Otherwise, how does it work in a real app?
Anyway, to answer your question, you can always call cut.Render() or cut.SetParametersAndRender(...) if you need to pass new parameters.
Brett McDonald
@bfmsoft
@egil problem is I don't see Render or SetParametersAndRender offered on "cut" it is type IRedenderedFragment. I am using Razer style tests and fixture.GetComponentUnderTest. I'll reread the article you listed.
Egil Hansen
@egil
ahh you need to use GetComponentUnderTest<TComponent>()
That will return a IRenderedComponent<TComponent>
Marc Chu
@demonsweatlive
Running into some behavior I don't understand. I have a Page component. The Page has a Form component. The Form has controls on it. I am asserting on the contents of the form. I have one particular test where the contents of the form controls are not what I'm expecting. When I examine the markup of the Page, the contents are exactly what I expect to see. But when I examine the contents of the form IRenderFragment, retrieved with _RenderedPage.FindComponent<Form>(), they are different, containing values that were set previously in the test but that were subsequently cleared out.
What could be going on here? Is there some need to refresh something? Is there some race condition?
Egil Hansen
@egil
Hi @demonsweatlive, not sure without seeing any code, but it could be a race condition. For that, you might need this: https://bunit.egilhansen.com/docs/verification/async-assertion.html
Marc Chu
@demonsweatlive
This is what confuses me:
Marc Chu
@demonsweatlive
   IRenderedComponent<Page> _RenderedPage = context.RenderComponent<Page>(); // initialised early in test
//in assertion phase
var markup = _RenderedPage.Markup; //<-------- This markup has exactly what I expect for the Form component.
var form = _RenderedPage.FindComponent<Form>();   
var formMarkup = form.Markup; //  <---------- This markup is different. It has outdated values
How can they be different?
Egil Hansen
@egil
Not sure. Do you do anything between reading the markup from RenderedPage and Form?
Marc Chu
@demonsweatlive
Nothing. Everything in the Act phase is done by this point.
Egil Hansen
@egil
so the markup in form is different from RenderedPage.Find("form"). E.g. you can do RenderedPage.FindComponent<Form>().MarkupMatches(RenderedPage.Find("form")) assuming there is only one form element on the page
I have to run pick up the kids, but if you can create a minimal example that reproduces this issue and share it in the github repo through an issue, that would be great.