bUnit .Change(value) does not update bind value in SfMaskedTextBox

I have a phone number input box that is masked, and when unit testing with the Mask property set, the .Change method does not update the bind value. Deleting the Mask property allows the .Change method to work fine.



<SfMaskedTextBox ID="phone-input-box" @bind-Value="@modelObject.Phone" Mask="(000)000-0000" Type="InputType.Tel" />




In the unit test:

testView.Find("#phone-input-box").Change("5551231234");



if I delete the Mask property, it works just fine. How do I unit test a masked text box?


3 Replies 1 reply marked as answer

KP Kokila Poovendran Syncfusion Team August 26, 2024 05:02 AM UTC

Hi Christopher Heard,

Thank you for reaching out.

We understand that you are facing an issue where the .Change method does not update the bound value in the SfMaskedTextBox component during unit testing with bUnit, especially when the Mask property is set.

To address this, we suggest using a different approach to update the value during unit testing with bUnit. Below is a sample code snippet that demonstrates how to test a masked text box using bUnit:


public void ValueBinding()

{

    var maskedTextBox = RenderComponent<SfMaskedTextBox>(parameters => parameters

        .Add(p => p.Mask, "(000) 000-00-000")

        .Add(p => p.Value, "12345678901"));


    // Verify the initial masked value and raw value

    Assert.Equal("(123) 456-78-901", maskedTextBox.Find("input").GetAttribute("value"));

    Assert.Equal("12345678901", maskedTextBox.Instance.Value);


    // Update the Value parameter and verify changes

    maskedTextBox.SetParametersAndRender(parameters => parameters.Add(p => p.Value, "10987654321"));

    Assert.Equal("(109) 876-54-321", maskedTextBox.Find("input").GetAttribute("value"));

    Assert.Equal("10987654321", maskedTextBox.Instance.Value);

}




By using the SetParametersAndRender method, you can update the component parameters and ensure the changes are reflected correctly in the masked text box during the test.


For more details on configuring Blazor components for bUnit testing, please refer to our documentation.


Please try this approach and let us know if it meets your requirements or if you need further assistance.




R
egards,

Kokila Poovendran.





CH Christopher Heard August 30, 2024 05:42 PM UTC

The SfMaskedTextBox is only one piece of a component I am unit testing. The code you provided allows me to test the specific SfMaskedTextBox , but I cannot do the RenderComponent method when testing the parent component or it will be updating a new instance of the textbox rather than the one in my TestView component.



I did try finding the component through the parent component. This does update the value on the SfMaskedTextBox, but it did not update the bound model parameter. I'm guessing this approach does not trigger the OnChange event to update the @bind-Value tied to the SfMaskedTextBox.

testViewComponent.FindComponent<SfMaskedTextBox>().SetParametersAndRender(parameters => parameters.Add(p => p.Value,"5551231234"));


<SfMaskedTextBox @bind-Value="phone.Number" Mask="(000)000-0000" Placeholder="Phone number"/>


The phone.Number is not updated by calling SetParametersAndRender




PK Priyanka Karthikeyan Syncfusion Team November 29, 2024 02:03 PM UTC

Hi Christopher Heard,


Thank you for your patience. In order to ensure proper model binding when testing a Syncfusion SfMaskedTextBox component with two-way binding (@bind-Value), we have to explicitly invoking the ValueChanged event, which Syncfusion components use to propagate the value change to the bound model.

Here is the code snippet:

Counter.razor

<SfMaskedTextBox @bind-Value="phone.Number"
Mask="(000)000-0000"
Placeholder="Phone number" />

<p>Bound Value: @phone.Number</p>

@code {
public PhoneModel phone = new PhoneModel();

public class PhoneModel
{
public string Number { get; set; }
}
}

Test Case: CounterCSharpTests.cs

using Syncfusion.Blazor.Inputs;
using Syncfusion.Blazor;
using Microsoft.Extensions.DependencyInjection;
using System.Threading.Tasks;
using Xunit;

namespace BlazorTestProject
{
public class CounterCSharpTests : TestContext
{
public CounterCSharpTests()
{
Services.AddSyncfusionBlazor();
}
[Fact]
public void Test_SfMaskedTextBox_BindValue()
{
// Arrange: Render the parent component
var testViewComponent = RenderComponent<Counter>();

// Act: Find the SfMaskedTextBox and set its value via parameters
var maskedTextBox = testViewComponent.FindComponent<SfMaskedTextBox>();
maskedTextBox.SetParametersAndRender(parameters => parameters.Add(p => p.Value, "5551231234"));

// Trigger ValueChanged to simulate binding
maskedTextBox.InvokeAsync(() => maskedTextBox.Instance.ValueChanged.InvokeAsync("5551231234"));

// Assert: Check if the bound model is updated correctly
var updatedValue = testViewComponent.Instance.phone.Number;
Assert.Equal("5551231234", updatedValue);

// Assert: Ensure that the rendered markup reflects the updated value
Assert.Contains("Bound Value: 5551231234", testViewComponent.Markup);
}
}
}


Explanation of Fix:

  1. SetParametersAndRender: Updates the Value parameter of the SfMaskedTextBox component. However, this alone does not update the model unless the ValueChanged event is triggered.
  2. Triggering ValueChanged: The ValueChanged event is invoked manually to simulate the behavior of the @bind-Value mechanism in Blazor. This ensures that the model (phone.Number) is updated correctly.
  3. Assertions: After updating the value, we verify both the updated model (phone.Number) and the rendered markup to confirm that everything is functioning as expected.


Regards,

Priyanka K


Attachment: BlazorTestProject_61f5e1fb.zip

Marked as answer
Loader.
Up arrow icon