Search code examples
c#blazorbunit

Test that an InputCheckbox invokes a method


I have an InputCheckbox on a page defined as:

<InputCheckbox id="my-cb" ValueChanged="@CallApi" ValueExpression="@(() => MyFlag)">


@code {
    public bool MyFlag { get; set; }

    async Task CallApi()
    {
        // call api
    }
}

Interactively this works, clicking on the checkbox calls my api. I use ValueChanged and ValueExpression for reasons best explained in this post.

In my unit test I have setup a Mock of my api and want to test if the mocked api is invoked. However, finding the <InputCheckbox/> and invoking the Change event does not trigger the call even to CallApi().

var cbx = cut.Find("#my-cb");
cbx.Change(); // does not call `CallApi`

I suspect because no @onclick method is specified (for the reasons in the post).

I have also tried changing the value of MyFlag which doesn't work either.

cut.Instance.MyFlag = true;

Solution

  • There are several issues with your code:

    1. If you are using ValueChanged you need to set Value to MyFlag.
    2. In CallApi you need to accept the value provided and set MyFlag.
    3. In the tests you must provide a ChangeEventArgs instance when calling Change. That should have generated an error.
    4. <InputCheckbox ...> is ill formed and should have generated a warning.

    This is my version of your page.

    @page "/"
    
    <PageTitle>Index</PageTitle>
    
    <h1>Hello, world!</h1>
    
    @*Original*@
    <InputCheckbox id="my-cb" Value=this.MyFlag ValueChanged=CallApi ValueExpression="() => MyFlag" />
    
    @*Can do this is Net7.0*@
    <InputCheckbox id="my-cb1" @bind-Value:get=this.MyFlag @bind-Value:set=CallApi />
    
    @*Display the Value*@
    <div class="bg-dark text-white m-2 p-1 ">
        <pre>MyFlag : @this.MyFlag</pre>
    </div>
    
    @code {
        public bool MyFlag { get; set; }
    
        async Task CallApi(bool value)
        {
            this.MyFlag = value;
            await Task.Delay(10);
            // call api
        }
    }
    

    Here are three tests. Note that Change needs to provide a ChangeEventArgs instance.

    public class UnitTest1 : TestContext
    {
        [Fact]
        public void CheckIndexCheckboxTrue()
        {
            // Act
            var cut = RenderComponent<SO76081912.Pages.Index>();
    
            var cbx = cut.Find("#my-cb");
            cbx.Change(new ChangeEventArgs() { Value=true });
            
            // Assert
            cut.Instance.MyFlag = true;
        }
    
        [Fact]
        public void CheckIndexCheckboxFalse()
        {
            // Act
            var cut = RenderComponent<SO76081912.Pages.Index>();
    
            var cbx = cut.Find("#my-cb");
            cbx.Change(new ChangeEventArgs() { Value = false });
    
            // Assert
            cut.Instance.MyFlag = false;
        }
    
        [Fact]
        public void CheckIndexCheckbox1True()
        {
            // Act
            var cut = RenderComponent<SO76081912.Pages.Index>();
    
            var cbx = cut.Find("#my-cb1");
            cbx.Change(new ChangeEventArgs() { Value = true });
    
            // Assert
            cut.Instance.MyFlag = true;
        }
    }
    

    enter image description here