Files
radzen-blazor/Radzen.Blazor.Tests/NumericTests.cs
Vladimir Enchev 43d2c24267 Js csp (#2500)
* Fixed all JS CSP related errors across all components
2026-06-15 18:44:02 +03:00

875 lines
34 KiB
C#

using System;
using Bunit;
using Microsoft.AspNetCore.Components.Web;
using Newtonsoft.Json.Linq;
using Xunit;
namespace Radzen.Blazor.Tests
{
public class NumericTests
{
[Fact]
public void Numeric_Renders_CssClasses()
{
using var ctx = new TestContext();
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
var component = ctx.RenderComponent<RadzenNumeric<double>>();
component.Render();
Assert.Contains(@$"rz-numeric", component.Markup);
Assert.Contains(@$"rz-numeric-up", component.Markup);
Assert.Contains(@$"rz-numeric-down", component.Markup);
}
[Fact]
public void Numeric_Renders_ValueParameter()
{
using var ctx = new TestContext();
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
var component = ctx.RenderComponent<RadzenNumeric<double>>();
var value = 3.5;
component.SetParametersAndRender(parameters => parameters.Add<double>(p => p.Value, value));
Assert.Contains(@$"value=""{value}""", component.Markup);
}
[Fact]
public void Numeric_Respect_MinParameter()
{
using var ctx = new TestContext();
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
ctx.JSInterop.SetupModule("_content/Radzen.Blazor/Radzen.Blazor.js");
var component = ctx.RenderComponent<RadzenNumeric<double>>();
var minValue = 2;
var raised = false;
component.SetParametersAndRender(parameters =>
{
component.SetParametersAndRender(parameters => parameters.Add(p => p.Change, args => { raised = true; }));
parameters.Add<double>(p => p.Value, minValue);
parameters.Add<decimal?>(p => p.Min, minValue);
});
component.Find(".rz-numeric-down").Click();
Assert.False(raised, $"Numeric value should Change event if value is less than min value.");
}
[Fact]
public void Numeric_Respect_Nullable_With_MinParameter()
{
using var ctx = new TestContext();
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
ctx.JSInterop.SetupModule("_content/Radzen.Blazor/Radzen.Blazor.js");
var component = ctx.RenderComponent<RadzenNumeric<double?>>();
var raised = false;
var value = 3.5;
object newValue = null;
component.SetParametersAndRender(parameters =>
{
parameters.Add(p => p.Change, args => { raised = true; newValue = args; });
parameters.Add<decimal?>(p => p.Min, 1);
});
component.Find("input").Change(value);
Assert.True(raised);
Assert.True(object.Equals(value, newValue));
component.Find("input").Change("");
Assert.True(raised);
Assert.True(object.Equals(null, newValue));
}
[Fact]
public void Numeric_Respect_MaxParameter()
{
using var ctx = new TestContext();
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
ctx.JSInterop.SetupModule("_content/Radzen.Blazor/Radzen.Blazor.js");
var component = ctx.RenderComponent<RadzenNumeric<double>>();
var maxValue = 10;
var raised = false;
component.SetParametersAndRender(parameters =>
{
component.SetParametersAndRender(parameters => parameters.Add(p => p.Change, args => { raised = true; }));
parameters.Add<double>(p => p.Value, maxValue);
parameters.Add<decimal?>(p => p.Max, maxValue);
});
component.Find(".rz-numeric-up").Click();
Assert.False(raised, $"Numeric value should Change event if value is less than min value.");
}
[Fact]
public void Numeric_Renders_StyleParameter()
{
using var ctx = new TestContext();
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
var component = ctx.RenderComponent<RadzenNumeric<double>>();
var value = "width:20px";
component.SetParametersAndRender(parameters => parameters.Add(p => p.Style, value));
Assert.Contains(@$"style=""{value}""", component.Markup);
}
[Fact]
public void Numeric_Renders_UnmatchedParameter()
{
using var ctx = new TestContext();
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
var component = ctx.RenderComponent<RadzenNumeric<double>>();
component.SetParametersAndRender(parameters => parameters.AddUnmatched("autofocus", ""));
Assert.Contains(@$"autofocus", component.Markup);
}
[Fact]
public void Numeric_Renders_NameParameter()
{
using var ctx = new TestContext();
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
var component = ctx.RenderComponent<RadzenNumeric<double>>();
var value = "Test";
component.SetParametersAndRender(parameters => parameters.Add(p => p.Name, value));
Assert.Contains(@$"name=""{value}""", component.Markup);
}
[Fact]
public void Numeric_Renders_TabIndexParameter()
{
using var ctx = new TestContext();
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
var component = ctx.RenderComponent<RadzenNumeric<double>>();
var value = 1;
component.SetParametersAndRender(parameters => parameters.Add<int>(p => p.TabIndex, value));
Assert.Contains(@$"tabindex=""{value}""", component.Markup);
}
[Fact]
public void Numeric_Renders_PlaceholderParameter()
{
using var ctx = new TestContext();
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
var component = ctx.RenderComponent<RadzenNumeric<double>>();
var value = "Test";
component.SetParametersAndRender(parameters => parameters.Add(p => p.Placeholder, value));
Assert.Contains(@$"placeholder=""{value}""", component.Markup);
}
[Fact]
public void Numeric_Renders_DisabledParameter()
{
using var ctx = new TestContext();
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
var component = ctx.RenderComponent<RadzenNumeric<double>>();
component.SetParametersAndRender(parameters => parameters.Add<bool>(p => p.Disabled, true));
Assert.Contains(@$"disabled", component.Markup);
Assert.Contains(@$"rz-state-disabled", component.Markup);
}
[Fact]
public void Numeric_Renders_ReadOnlyParameter()
{
using var ctx = new TestContext();
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
var component = ctx.RenderComponent<RadzenNumeric<double>>();
var value = true;
component.SetParametersAndRender(parameters => parameters.Add<bool>(p => p.ReadOnly, value));
Assert.Contains(@$"readonly", component.Markup);
}
[Fact]
public void Numeric_Renders_AutoCompleteParameter()
{
using var ctx = new TestContext();
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
var component = ctx.RenderComponent<RadzenNumeric<double>>();
component.SetParametersAndRender(parameters => parameters.AddUnmatched("AutoComplete", false));
Assert.Contains(@$"autocomplete=""off""", component.Markup);
Assert.Contains(@$"aria-autocomplete=""none""", component.Markup);
component.SetParametersAndRender(parameters => parameters.AddUnmatched("AutoComplete", true));
Assert.Contains(@$"autocomplete=""on""", component.Markup);
Assert.DoesNotContain(@$"aria-autocomplete", component.Markup);
component.SetParametersAndRender(parameters => parameters.AddUnmatched("autocomplete", "custom"));
Assert.Contains(@$"autocomplete=""custom""", component.Markup);
Assert.DoesNotContain(@$"aria-autocomplete", component.Markup);
component.Instance.DefaultAutoCompleteAttribute = "autocomplete-custom";
component.SetParametersAndRender(parameters => parameters.AddUnmatched("AutoComplete", false));
Assert.Contains(@$"autocomplete=""autocomplete-custom""", component.Markup);
Assert.Contains(@$"aria-autocomplete=""none""", component.Markup);
}
[Fact]
public void Numeric_Renders_TypedAutoCompleteParameter()
{
using var ctx = new TestContext();
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
var component = ctx.RenderComponent<RadzenNumeric<double>>();
component.SetParametersAndRender(parameters => parameters.AddUnmatched("AutoComplete", false));
component.SetParametersAndRender(parameters => parameters.Add<AutoCompleteType>(p => p.AutoCompleteType, AutoCompleteType.On));
Assert.Contains(@$"autocomplete=""off""", component.Markup);
component.SetParametersAndRender(parameters => parameters.AddUnmatched("AutoComplete", true));
component.SetParametersAndRender(parameters => parameters.Add<AutoCompleteType>(p => p.AutoCompleteType, AutoCompleteType.Off));
Assert.Contains(@$"autocomplete=""off""", component.Markup);
component.SetParametersAndRender(parameters => parameters.AddUnmatched("AutoComplete", true));
component.SetParametersAndRender(parameters => parameters.Add<AutoCompleteType>(p => p.AutoCompleteType, AutoCompleteType.BdayMonth));
Assert.Contains(@$"autocomplete=""{AutoCompleteType.BdayMonth.GetAutoCompleteValue()}""", component.Markup);
component.SetParametersAndRender(parameters => parameters.AddUnmatched("AutoComplete", true));
component.SetParametersAndRender(parameters => parameters.Add<AutoCompleteType>(p => p.AutoCompleteType, AutoCompleteType.BdayYear));
Assert.Contains(@$"autocomplete=""{AutoCompleteType.BdayYear.GetAutoCompleteValue()}""", component.Markup);
}
[Fact]
public void Numeric_Raises_ChangedEvent()
{
using var ctx = new TestContext();
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
ctx.JSInterop.SetupModule("_content/Radzen.Blazor/Radzen.Blazor.js");
var component = ctx.RenderComponent<RadzenNumeric<double>>();
var raised = false;
var value = 3.5;
object newValue = null;
component.SetParametersAndRender(parameters => parameters.Add(p => p.Change, args => { raised = true; newValue = args; }));
component.Find("input").Change(value);
Assert.True(raised);
Assert.True(object.Equals(value, newValue));
}
[Fact]
public void Numeric_Raises_ChangeEvent_OnBackspace_When_Immediate()
{
using var ctx = new TestContext();
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
ctx.JSInterop.SetupModule("_content/Radzen.Blazor/Radzen.Blazor.js");
var component = ctx.RenderComponent<RadzenNumeric<double?>>(parameters =>
parameters.Add(p => p.Immediate, true).Add(p => p.Value, 5));
var raised = false;
object newValue = 1;
ctx.JSInterop.Setup<string>("Radzen.getInputValue", _ => true).SetResult("");
component.SetParametersAndRender(parameters => parameters.Add(p => p.Change, args => { raised = true; newValue = args; }));
component.Find("input").KeyDown(new KeyboardEventArgs { Key = "Backspace", Code = "Backspace" });
Assert.True(raised);
Assert.Null(newValue);
}
[Fact]
public void Numeric_Raises_ChangeEvent_OnDelete_When_Immediate()
{
using var ctx = new TestContext();
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
ctx.JSInterop.SetupModule("_content/Radzen.Blazor/Radzen.Blazor.js");
var component = ctx.RenderComponent<RadzenNumeric<double?>>(parameters =>
parameters.Add(p => p.Immediate, true).Add(p => p.Value, 5));
var raised = false;
object newValue = 1;
ctx.JSInterop.Setup<string>("Radzen.getInputValue", _ => true).SetResult("");
component.SetParametersAndRender(parameters => parameters.Add(p => p.Change, args => { raised = true; newValue = args; }));
component.Find("input").KeyDown(new KeyboardEventArgs { Key = "Delete", Code = "Delete" });
Assert.True(raised);
Assert.Null(newValue);
}
[Fact]
public void Numeric_Restores_Cursor_After_Immediate_KeyDown()
{
using var ctx = new TestContext();
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
ctx.JSInterop.SetupModule("_content/Radzen.Blazor/Radzen.Blazor.js");
ctx.JSInterop.Setup<int[]>("Radzen.getSelectionRange", _ => true).SetResult(new[] { 3, 3 });
ctx.JSInterop.Setup<string>("Radzen.getInputValue", _ => true).SetResult("21345.00");
var component = ctx.RenderComponent<RadzenNumeric<decimal?>>(parameters =>
parameters.Add(p => p.Immediate, true).Add(p => p.Format, "#.00").Add(p => p.Value, 2345m));
component.Find("input").KeyDown(new KeyboardEventArgs { Key = "1", Code = "Digit1" });
var invocations = ctx.JSInterop.Invocations["Radzen.setSelectionRange"];
Assert.NotEmpty(invocations);
var invocation = invocations[invocations.Count - 1];
Assert.Equal(3, invocation.Arguments[1]);
Assert.Equal(3, invocation.Arguments[2]);
}
[Fact]
public void Numeric_Raises_ValueChangedEvent()
{
using var ctx = new TestContext();
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
ctx.JSInterop.SetupModule("_content/Radzen.Blazor/Radzen.Blazor.js");
var component = ctx.RenderComponent<RadzenNumeric<double>>();
var raised = false;
var value = 3.5;
object newValue = null;
component.SetParametersAndRender(parameters => parameters.Add(p => p.ValueChanged, args => { raised = true; newValue = args; }));
component.Find("input").Change(value);
Assert.True(raised);
Assert.True(object.Equals(value, newValue));
}
[Fact]
public void Numeric_Raises_ChangedAndValueChangedEventOnStepUp()
{
using var ctx = new TestContext();
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
ctx.JSInterop.SetupModule("_content/Radzen.Blazor/Radzen.Blazor.js");
var component = ctx.RenderComponent<RadzenNumeric<double>>();
var raised = false;
var value = 3.5;
var expectedValue = 5.5;
object newValue = null;
component.SetParametersAndRender(parameters =>
{
parameters.Add<double>(p => p.Value, value);
parameters.Add(p => p.Step, "2");
parameters.Add(p => p.Change, args => { raised = true; newValue = args; });
});
component.Find(".rz-numeric-up").Click();
Assert.True(raised, "Numeric Change should be raised on step up");
Assert.True(object.Equals(expectedValue, newValue), $"Numeric value should be incremented on step up. Expected value: {expectedValue}, value: {newValue}");
raised = false;
component.SetParametersAndRender(parameters => parameters.Add(p => p.ValueChanged, args => { raised = true; }));
component.Find(".rz-numeric-up").Click();
Assert.True(raised, "Numeric ValueChanged should be raised on step up");
}
[Fact]
public void Numeric_Raises_ChangedAndValueChangedEventOnStepDown()
{
using var ctx = new TestContext();
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
ctx.JSInterop.SetupModule("_content/Radzen.Blazor/Radzen.Blazor.js");
var component = ctx.RenderComponent<RadzenNumeric<double>>();
var raised = false;
var value = 3.5;
var expectedValue = 1.5;
object newValue = null;
component.SetParametersAndRender(parameters =>
{
parameters.Add<double>(p => p.Value, value);
parameters.Add(p => p.Step, "2");
parameters.Add(p => p.Change, args => { raised = true; newValue = args; });
});
component.Find(".rz-numeric-down").Click();
Assert.True(raised, "Numeric Change should be raised on step up");
Assert.True(object.Equals(expectedValue, newValue), $"Numeric value should be incremented on step up. Expected value: {expectedValue}, value: {newValue}");
raised = false;
component.SetParametersAndRender(parameters => parameters.Add(p => p.ValueChanged, args => { raised = true; }));
component.Find(".rz-numeric-down").Click();
Assert.True(raised, "Numeric ValueChanged should be raised on step up");
}
[Fact]
public void Numeric_UpDown_Rendered()
{
using var ctx = new TestContext();
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
var component = ctx.RenderComponent<RadzenNumeric<double>>();
component.Render();
Assert.Contains(@$"rz-numeric-button-icon", component.Markup);
Assert.Contains(@$"rz-numeric-up", component.Markup);
Assert.Contains(@$"rz-numeric-down", component.Markup);
}
[Fact]
public void Numeric_UpDown_NotRenderedIfHidden()
{
using var ctx = new TestContext();
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
var component = ctx.RenderComponent<RadzenNumeric<double>>(ComponentParameter.CreateParameter(nameof(RadzenNumeric<double>.ShowUpDown), false));
component.Render();
Assert.DoesNotContain(@$"rz-numeric-button-icon", component.Markup);
Assert.DoesNotContain(@$"rz-numeric-up", component.Markup);
Assert.DoesNotContain(@$"rz-numeric-down", component.Markup);
}
[Fact]
public void Numeric_Formatted()
{
using var ctx = new TestContext();
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
double valueToTest = 100.234;
string format = "0.00";
var component = ctx.RenderComponent<RadzenNumeric<double>>(
ComponentParameter.CreateParameter(nameof(RadzenNumeric<double>.Format), format),
ComponentParameter.CreateParameter(nameof(RadzenNumeric<double>.Value), valueToTest)
);
component.Render();
Assert.Contains($" value=\"{valueToTest.ToString(format)}\"", component.Markup);
}
public static TheoryData<decimal, decimal> NumericFormatterPreservesLeadingZerosData =>
new()
{
{ 10.000m, 100.000m },
{ 100.000m, 10.000m }
};
[Theory]
[MemberData(nameof(NumericFormatterPreservesLeadingZerosData))]
public void Numeric_Formatter_PreservesLeadingZeros(decimal oldValue, decimal newValue)
{
using var ctx = new TestContext();
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
ctx.JSInterop.SetupModule("_content/Radzen.Blazor/Radzen.Blazor.js");
string format = "0.000";
var component = ctx.RenderComponent<RadzenNumeric<decimal>>(
ComponentParameter.CreateParameter(nameof(RadzenNumeric<decimal>.Format), format),
ComponentParameter.CreateParameter(nameof(RadzenNumeric<decimal>.Value), oldValue)
);
component.Render();
Assert.Contains($" value=\"{oldValue.ToString(format)}\"", component.Markup);
component.Find("input").Change(newValue);
Assert.Contains($" value=\"{newValue.ToString(format)}\"", component.Markup);
}
[Fact]
public void Numeric_Uses_ConvertValue()
{
using var ctx = new TestContext();
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
ctx.JSInterop.SetupModule("_content/Radzen.Blazor/Radzen.Blazor.js");
var value = new Dollars(11m);
Dollars? ConvertFunc(string s) => decimal.TryParse(s, System.Globalization.CultureInfo.InvariantCulture, out var val) ? new Dollars(val) : null;
var component = ctx.RenderComponent<RadzenNumeric<Dollars?>>(
ComponentParameter.CreateParameter(nameof(RadzenNumeric<Dollars?>.ConvertValue), (Func<string, Dollars?>)ConvertFunc),
ComponentParameter.CreateParameter(nameof(RadzenNumeric<Dollars?>.Value), value),
ComponentParameter.CreateParameter(nameof(RadzenNumeric<Dollars>.Culture), System.Globalization.CultureInfo.InvariantCulture)
);
component.Render();
Assert.Contains($" value=\"{value.ToString()}\"", component.Markup);
var newValue = new Dollars(13.53m);
component.Find("input").Change("13.53");
Assert.Contains($" value=\"{newValue.ToString()}\"", component.Markup);
}
[Fact]
public void Numeric_Supports_TypeConverter()
{
using var ctx = new TestContext();
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
var valueToTest = new Dollars(100.234m);
string format = "0.00";
var component = ctx.RenderComponent<RadzenNumeric<Dollars>>(
ComponentParameter.CreateParameter(nameof(RadzenNumeric<Dollars>.Format), format),
ComponentParameter.CreateParameter(nameof(RadzenNumeric<Dollars>.Value), valueToTest)
);
component.Render();
Assert.Contains($" value=\"{valueToTest.ToString(format, System.Globalization.CultureInfo.CurrentCulture)}\"", component.Markup);
}
[Fact]
public void Numeric_Supports_TypeConverterWithCulture()
{
using var ctx = new TestContext();
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
var valueToTest = new Dollars(100.234m);
string format = "0.00";
var component = ctx.RenderComponent<RadzenNumeric<Dollars>>(
ComponentParameter.CreateParameter(nameof(RadzenNumeric<Dollars>.Format), format),
ComponentParameter.CreateParameter(nameof(RadzenNumeric<Dollars>.Value), valueToTest),
ComponentParameter.CreateParameter(nameof(RadzenNumeric<Dollars>.Culture), System.Globalization.CultureInfo.InvariantCulture)
);
component.Render();
Assert.Contains($" value=\"{valueToTest.ToString(format, System.Globalization.CultureInfo.InvariantCulture)}\"", component.Markup);
}
[Fact]
public void Numeric_Supports_EmptyString()
{
using var ctx = new TestContext();
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
var valueToTest = "";
string format = "0.00";
var component = ctx.RenderComponent<RadzenNumeric<string>>(
ComponentParameter.CreateParameter(nameof(RadzenNumeric<string>.Format), format),
ComponentParameter.CreateParameter(nameof(RadzenNumeric<string>.Value), valueToTest),
ComponentParameter.CreateParameter(nameof(RadzenNumeric<Dollars>.Culture), System.Globalization.CultureInfo.InvariantCulture)
);
component.Render();
Assert.Contains($" value=\"0.00\"", component.Markup);
}
[Fact]
public void Numeric_Supports_ValueString()
{
using var ctx = new TestContext();
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
var valueToTest = "12.50";
string format = "0.00";
var component = ctx.RenderComponent<RadzenNumeric<string>>(
ComponentParameter.CreateParameter(nameof(RadzenNumeric<string>.Format), format),
ComponentParameter.CreateParameter(nameof(RadzenNumeric<string>.Value), valueToTest),
ComponentParameter.CreateParameter(nameof(RadzenNumeric<Dollars>.Culture), System.Globalization.CultureInfo.InvariantCulture)
);
component.Render();
Assert.Contains($" value=\"{valueToTest}\"", component.Markup);
}
[Fact]
public void Numeric_Supports_ValueStringEsCLCulture()
{
using var ctx = new TestContext();
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
var valueToTest = "12,50";
string format = "0.00";
var component = ctx.RenderComponent<RadzenNumeric<string>>(
ComponentParameter.CreateParameter(nameof(RadzenNumeric<string>.Format), format),
ComponentParameter.CreateParameter(nameof(RadzenNumeric<string>.Value), valueToTest),
ComponentParameter.CreateParameter(nameof(RadzenNumeric<Dollars>.Culture), System.Globalization.CultureInfo.GetCultureInfo("es-CL"))
);
component.Render();
Assert.Contains($" value=\"{valueToTest}\"", component.Markup);
}
[Fact]
public void Numeric_Supports_ValueStringEnUSCulture()
{
using var ctx = new TestContext();
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
var valueToTest = "12.50";
string format = "0.00";
var component = ctx.RenderComponent<RadzenNumeric<string>>(
ComponentParameter.CreateParameter(nameof(RadzenNumeric<string>.Format), format),
ComponentParameter.CreateParameter(nameof(RadzenNumeric<string>.Value), valueToTest),
ComponentParameter.CreateParameter(nameof(RadzenNumeric<Dollars>.Culture), System.Globalization.CultureInfo.GetCultureInfo("en-US"))
);
component.Render();
Assert.Contains($" value=\"{valueToTest}\"", component.Markup);
}
[Fact]
public void Numeric_Supports_IComparable()
{
using var ctx = new TestContext();
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
ctx.JSInterop.SetupModule("_content/Radzen.Blazor/Radzen.Blazor.js");
var component = ctx.RenderComponent<RadzenNumeric<Dollars>>();
var maxValue = 2;
component.SetParametersAndRender(parameters =>
{
component.SetParametersAndRender(parameters =>
{
parameters.Add(p => p.Value, new Dollars(1m));
parameters.Add(p => p.Max, maxValue);
});
});
component.Find("input").Change(13.53);
var maxDollars = new Dollars(maxValue);
Assert.Contains($" value=\"{maxDollars}\"", component.Markup);
Assert.Equal(component.Instance.Value, maxDollars);
}
[Fact]
public void Numeric_Format_WithOptionalDecimals_PreservesValue()
{
using var ctx = new TestContext();
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
ctx.JSInterop.SetupModule("_content/Radzen.Blazor/Radzen.Blazor.js");
var component = ctx.RenderComponent<RadzenNumeric<float>>(
ComponentParameter.CreateParameter(nameof(RadzenNumeric<float>.Format), "0.##"),
ComponentParameter.CreateParameter(nameof(RadzenNumeric<float>.Culture), System.Globalization.CultureInfo.InvariantCulture)
);
object newValue = null;
component.SetParametersAndRender(parameters =>
parameters.Add(p => p.Change, args => { newValue = args; }));
component.Find("input").Change("10.55");
Assert.NotNull(newValue);
Assert.Equal(10.55f, (float)newValue, 2);
}
[Fact]
public void Numeric_Format_WithOptionalDecimals_PreservesValue_CommaCulture()
{
using var ctx = new TestContext();
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
ctx.JSInterop.SetupModule("_content/Radzen.Blazor/Radzen.Blazor.js");
var culture = System.Globalization.CultureInfo.GetCultureInfo("de-DE");
var component = ctx.RenderComponent<RadzenNumeric<float>>(
ComponentParameter.CreateParameter(nameof(RadzenNumeric<float>.Format), "0.##"),
ComponentParameter.CreateParameter(nameof(RadzenNumeric<float>.Culture), culture)
);
object newValue = null;
component.SetParametersAndRender(parameters =>
parameters.Add(p => p.Change, args => { newValue = args; }));
component.Find("input").Change("10,55");
Assert.NotNull(newValue);
Assert.Equal(10.55f, (float)newValue, 2);
}
[Fact]
public void Numeric_Supports_IFormattable()
{
using var ctx = new TestContext();
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
var valueToTest = new Temperature(60.23m);
const string format = "F";
var component = ctx.RenderComponent<RadzenNumeric<Temperature>>(
ComponentParameter.CreateParameter(nameof(RadzenNumeric<Temperature>.Format), format),
ComponentParameter.CreateParameter(nameof(RadzenNumeric<Temperature>.Value), valueToTest)
);
component.Render();
var input = component.Find("input").GetAttribute("value");
input.MarkupMatches(valueToTest.ToString(format));
}
[Fact]
public void Numeric_Raises_KeyDownEvent()
{
using var ctx = new TestContext();
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
ctx.JSInterop.SetupModule("_content/Radzen.Blazor/Radzen.Blazor.js");
var component = ctx.RenderComponent<RadzenNumeric<int>>(parameters => parameters.Add(p => p.Value, 5));
NumericKeyboardEventArgs raised = null;
component.SetParametersAndRender(parameters => parameters.Add(p => p.KeyDown, args => { raised = args; }));
component.Find("input").KeyDown(new KeyboardEventArgs { Key = "ArrowUp", Code = "ArrowUp" });
Assert.NotNull(raised);
Assert.Equal("ArrowUp", raised.OriginalEvent.Code);
Assert.False(raised.IsDefaultPrevented);
}
[Fact]
public void Numeric_KeyDown_PreventDefault_Suppresses_ArrowUp_Increment()
{
using var ctx = new TestContext();
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
ctx.JSInterop.SetupModule("_content/Radzen.Blazor/Radzen.Blazor.js");
var component = ctx.RenderComponent<RadzenNumeric<int>>(parameters => parameters.Add(p => p.Value, 5));
var changeRaised = false;
component.SetParametersAndRender(parameters => parameters
.Add(p => p.KeyDown, args => args.PreventDefault())
.Add(p => p.Change, _ => changeRaised = true));
component.Find("input").KeyDown(new KeyboardEventArgs { Key = "ArrowUp", Code = "ArrowUp" });
Assert.False(changeRaised);
Assert.Equal(5, component.Instance.Value);
}
[Fact]
public void Numeric_KeyDown_PreventDefault_Suppresses_ArrowDown_Decrement()
{
using var ctx = new TestContext();
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
ctx.JSInterop.SetupModule("_content/Radzen.Blazor/Radzen.Blazor.js");
var component = ctx.RenderComponent<RadzenNumeric<int>>(parameters => parameters.Add(p => p.Value, 5));
var changeRaised = false;
component.SetParametersAndRender(parameters => parameters
.Add(p => p.KeyDown, args => args.PreventDefault())
.Add(p => p.Change, _ => changeRaised = true));
component.Find("input").KeyDown(new KeyboardEventArgs { Key = "ArrowDown", Code = "ArrowDown" });
Assert.False(changeRaised);
Assert.Equal(5, component.Instance.Value);
}
[Fact]
public void Numeric_KeyDown_Without_PreventDefault_Still_Increments_On_ArrowUp()
{
using var ctx = new TestContext();
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
ctx.JSInterop.SetupModule("_content/Radzen.Blazor/Radzen.Blazor.js");
var component = ctx.RenderComponent<RadzenNumeric<int>>(parameters => parameters.Add(p => p.Value, 5));
var changeRaised = false;
component.SetParametersAndRender(parameters => parameters
.Add(p => p.KeyDown, _ => { })
.Add(p => p.Change, _ => changeRaised = true));
component.Find("input").KeyDown(new KeyboardEventArgs { Key = "ArrowUp", Code = "ArrowUp" });
Assert.True(changeRaised);
Assert.Equal(6, component.Instance.Value);
}
}
}