Files
radzen-blazor/Radzen.Blazor.Tests/DatePickerTests.cs

1428 lines
57 KiB
C#

using Bunit;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using Xunit;
namespace Radzen.Blazor.Tests
{
public class DatePickerTests
{
[Fact]
public void DatePicker_Renders_CssClass()
{
using var ctx = new TestContext();
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
ctx.JSInterop.SetupModule("_content/Radzen.Blazor/Radzen.Blazor.js");
var component = ctx.RenderComponent<RadzenDatePicker<DateTime>>();
Assert.Contains(@$"rz-datepicker", component.Markup);
Assert.Contains(@$"rz-calendar", component.Markup);
Assert.Contains(@$"rz-calendar-header", component.Markup);
Assert.Contains(@$"rz-calendar-view", component.Markup);
}
[Fact]
public void DatePicker_Renders_ShowTimeParameter()
{
using var ctx = new TestContext();
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
ctx.JSInterop.SetupModule("_content/Radzen.Blazor/Radzen.Blazor.js");
var component = ctx.RenderComponent<RadzenDatePicker<DateTime>>();
component.SetParametersAndRender(parameters => parameters.Add<bool>(p => p.ShowTime, true));
Assert.Contains(@$"rz-timepicker", component.Markup);
Assert.Contains(@$"rz-hour-picker", component.Markup);
Assert.Contains(@$"rz-minute-picker", component.Markup);
}
[Fact]
public void DatePicker_Renders_ShowSecondsParameter()
{
using var ctx = new TestContext();
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
ctx.JSInterop.SetupModule("_content/Radzen.Blazor/Radzen.Blazor.js");
var component = ctx.RenderComponent<RadzenDatePicker<DateTime>>();
component.SetParametersAndRender(parameters =>
{
parameters.Add<bool>(p => p.ShowTime, true);
parameters.Add<bool>(p => p.ShowSeconds, true);
});
Assert.Contains(@$"rz-timepicker", component.Markup);
Assert.Contains(@$"rz-hour-picker", component.Markup);
Assert.Contains(@$"rz-minute-picker", component.Markup);
Assert.Contains(@$"rz-second-picker", component.Markup);
}
[Fact]
public void DatePicker_Renders_ShowTimeOkButtonParameter()
{
using var ctx = new TestContext();
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
ctx.JSInterop.SetupModule("_content/Radzen.Blazor/Radzen.Blazor.js");
var component = ctx.RenderComponent<RadzenDatePicker<DateTime>>();
component.SetParametersAndRender(parameters =>
{
parameters.Add<bool>(p => p.ShowTime, true);
parameters.Add<bool>(p => p.ShowTimeOkButton, true);
});
Assert.Contains(@$"rz-timepicker", component.Markup);
Assert.Contains(@$"rz-hour-picker", component.Markup);
Assert.Contains(@$"rz-minute-picker", component.Markup);
Assert.Contains(@$"<span class=""rz-button-text"">Ok</span>", component.Markup);
}
[Fact]
public void DatePicker_Renders_DateFormatParameter()
{
using var ctx = new TestContext();
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
ctx.JSInterop.SetupModule("_content/Radzen.Blazor/Radzen.Blazor.js");
var component = ctx.RenderComponent<RadzenDatePicker<DateTime>>();
var format = "d";
component.SetParametersAndRender(parameters =>
{
parameters.Add(p => p.DateFormat, format);
parameters.Add<object>(p => p.Value, DateTime.Now);
});
Assert.Contains(@$"value=""{string.Format("{0:" + format + "}", DateTime.Now)}""", component.Markup);
}
[Fact]
public void DatePicker_Renders_HourFormatParameter()
{
using var ctx = new TestContext();
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
ctx.JSInterop.SetupModule("_content/Radzen.Blazor/Radzen.Blazor.js");
var component = ctx.RenderComponent<RadzenDatePicker<DateTime>>();
component.SetParametersAndRender(parameters =>
{
parameters.Add<bool>(p => p.ShowTime, true);
parameters.Add(p => p.HourFormat, "12");
});
Assert.Contains(@$"rz-ampm-picker", component.Markup);
Assert.Contains(@$"rzi-chevron-up", component.Markup);
Assert.Contains(@$"rzi-chevron-down", component.Markup);
}
[Fact]
public void DatePicker_Renders_TimeOnlyParameter()
{
using var ctx = new TestContext();
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
ctx.JSInterop.SetupModule("_content/Radzen.Blazor/Radzen.Blazor.js");
var component = ctx.RenderComponent<RadzenDatePicker<DateTime>>();
component.SetParametersAndRender(parameters =>
{
parameters.Add<bool>(p => p.ShowTime, true);
parameters.Add<bool>(p => p.TimeOnly, true);
});
Assert.DoesNotContain(@$"rz-calendar-header", component.Markup);
}
[Fact]
public void DatePicker_Renders_AllowClearParameter()
{
using var ctx = new TestContext();
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
ctx.JSInterop.SetupModule("_content/Radzen.Blazor/Radzen.Blazor.js");
var component = ctx.RenderComponent<RadzenDatePicker<DateTime>>();
component.SetParametersAndRender(parameters =>
{
parameters.Add<object>(p => p.Value, DateTime.Now);
parameters.Add<bool>(p => p.AllowClear, true);
});
Assert.Contains(@$"<button type=""button"" class=""notranslate rz-dropdown-clear-icon rzi rzi-times""", component.Markup);
}
[Fact]
public void DatePicker_Renders_TabIndexParameter()
{
using var ctx = new TestContext();
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
ctx.JSInterop.SetupModule("_content/Radzen.Blazor/Radzen.Blazor.js");
var component = ctx.RenderComponent<RadzenDatePicker<DateTime>>();
var value = 1;
component.SetParametersAndRender(parameters => parameters.Add<int>(p => p.TabIndex, value));
Assert.Contains(@$"tabindex=""{value}""", component.Markup);
}
[Fact]
public void DatePicker_Renders_EmptyCssClass_WhenValueIsEmpty()
{
using var ctx = new TestContext();
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
ctx.JSInterop.SetupModule("_content/Radzen.Blazor/Radzen.Blazor.js");
var component = ctx.RenderComponent<RadzenDatePicker<DateTime>>();
component.SetParametersAndRender(parameters => parameters.Add(p => p.Value, null));
Assert.Contains(@$"rz-state-empty", component.Markup);
}
[Fact]
public void DatePicker_DoesNotRender_EmptyCssClass_WhenValueIsNotEmpty()
{
using var ctx = new TestContext();
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
ctx.JSInterop.SetupModule("_content/Radzen.Blazor/Radzen.Blazor.js");
var component = ctx.RenderComponent<RadzenDatePicker<DateTime>>();
component.SetParametersAndRender(parameters => parameters.Add(p => p.Value, DateTime.Now));
Assert.DoesNotContain(@$"rz-state-empty", component.Markup);
}
[Fact]
public void DatePicker_Renders_DisabledParameter()
{
using var ctx = new TestContext();
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
ctx.JSInterop.SetupModule("_content/Radzen.Blazor/Radzen.Blazor.js");
var component = ctx.RenderComponent<RadzenDatePicker<DateTime>>();
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 DatePicker_Renders_ReadOnlyParameter()
{
using var ctx = new TestContext();
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
ctx.JSInterop.SetupModule("_content/Radzen.Blazor/Radzen.Blazor.js");
var component = ctx.RenderComponent<RadzenDatePicker<DateTime>>();
var value = true;
component.SetParametersAndRender(parameters => parameters.Add<bool>(p => p.ReadOnly, value));
Assert.Contains(@$"readonly", component.Markup);
}
[Fact]
public void DatePicker_Renders_StyleParameter()
{
using var ctx = new TestContext();
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
ctx.JSInterop.SetupModule("_content/Radzen.Blazor/Radzen.Blazor.js");
var component = ctx.RenderComponent<RadzenDatePicker<DateTime>>();
var value = "width:20px";
component.SetParametersAndRender(parameters => parameters.Add(p => p.Style, value));
Assert.Contains(@$"style=""{value}""", component.Markup);
}
[Fact]
public void DatePicker_Renders_UnmatchedParameter()
{
using var ctx = new TestContext();
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
ctx.JSInterop.SetupModule("_content/Radzen.Blazor/Radzen.Blazor.js");
var component = ctx.RenderComponent<RadzenDatePicker<DateTime>>();
component.SetParametersAndRender(parameters => parameters.AddUnmatched("autofocus", ""));
Assert.Contains(@$"autofocus", component.Markup);
}
[Fact]
public void DatePicker_NotRaises_ChangeEventOnNextMonth()
{
using var ctx = new TestContext();
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
ctx.JSInterop.SetupModule("_content/Radzen.Blazor/Radzen.Blazor.js");
var component = ctx.RenderComponent<RadzenDatePicker<DateTime>>();
var raised = false;
object newValue = null;
component.SetParametersAndRender(parameters =>
{
parameters.Add(p => p.Change, args => { raised = true; newValue = args; });
});
component.Find(".rz-calendar-next-icon").Click();
Assert.False(raised);
}
[Fact]
public void DatePicker_NotRaises_ValueChangedEventOnNextMonth()
{
using var ctx = new TestContext();
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
ctx.JSInterop.SetupModule("_content/Radzen.Blazor/Radzen.Blazor.js");
var component = ctx.RenderComponent<RadzenDatePicker<DateTime>>();
var raised = false;
object newValue = null;
component.SetParametersAndRender(parameters =>
{
parameters.Add(p => p.ValueChanged, args => { raised = true; newValue = args; });
});
component.Find(".rz-calendar-next-icon").Click();
Assert.False(raised);
}
[Fact]
public void DatePicker_NotRaises_ChangeEventOnPrevMonth()
{
using var ctx = new TestContext();
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
ctx.JSInterop.SetupModule("_content/Radzen.Blazor/Radzen.Blazor.js");
var component = ctx.RenderComponent<RadzenDatePicker<DateTime>>();
var raised = false;
object newValue = null;
component.SetParametersAndRender(parameters =>
{
parameters.Add(p => p.Change, args => { raised = true; newValue = args; });
});
component.Find(".rz-calendar-prev-icon").Click();
Assert.False(raised);
}
[Fact]
public void DatePicker_NotRaises_ValueChangedEventOnPrevMonth()
{
using var ctx = new TestContext();
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
ctx.JSInterop.SetupModule("_content/Radzen.Blazor/Radzen.Blazor.js");
var component = ctx.RenderComponent<RadzenDatePicker<DateTime>>();
var raised = false;
object newValue = null;
component.SetParametersAndRender(parameters =>
{
parameters.Add(p => p.ValueChanged, args => { raised = true; newValue = args; });
});
component.Find(".rz-calendar-prev-icon").Click();
Assert.False(raised);
}
[Fact]
public void DatePicker_Raises_ValueChangedEvent_Returns_PreviousDateOnInputOnDisabledDates()
{
IEnumerable<DateTime> dates = new DateTime[] { DateTime.Today };
DateTime previousDay = DateTime.Today.AddDays(-1);
using var ctx = new TestContext();
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
var component = ctx.RenderComponent<RadzenDatePicker<DateTime>>();
var raised = false;
object newValue = null;
component.SetParametersAndRender(parameters =>
{
parameters.Add(p => p.ValueChanged, args => { raised = true; newValue = args; })
.Add(p => p.DateRender, args => { args.Disabled = dates.Contains(args.Date); });
});
var inputElement = component.Find(".rz-inputtext");
// initialize DateTimeValue
ctx.JSInterop.Setup<string>("Radzen.getInputValue", invocation => true).SetResult(previousDay.ToShortDateString());
inputElement.Change(previousDay.AddDays(-1));
// try to enter disabled date
ctx.JSInterop.Setup<string>("Radzen.getInputValue", invocation => true).SetResult(DateTime.Today.ToShortDateString());
inputElement.Change(DateTime.Today);
Assert.True(raised);
Assert.Equal(previousDay, (DateTime)newValue);
}
[Fact]
public void DatePicker_Clears_InputOnDisabledDates()
{
IEnumerable<DateTime> dates = new DateTime[] { DateTime.Today };
DateTime previousDay = DateTime.Today.AddDays(-1);
using var ctx = new TestContext();
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
var component = ctx.RenderComponent<RadzenDatePicker<DateTime?>>();
var raised = false;
object newValue = null;
component.SetParametersAndRender(parameters =>
{
parameters.Add(p => p.ValueChanged, args => { raised = true; newValue = args; })
.Add(p => p.DateRender, args => { args.Disabled = dates.Contains(args.Date); });
});
var inputElement = component.Find(".rz-inputtext");
// initialize DateTimeValue
ctx.JSInterop.Setup<string>("Radzen.getInputValue", invocation => true).SetResult(previousDay.ToShortDateString());
inputElement.Change(previousDay.AddDays(-1));
// try to enter disabled date
ctx.JSInterop.Setup<string>("Radzen.getInputValue", invocation => true).SetResult(DateTime.Today.ToShortDateString());
inputElement.Change(DateTime.Today);
Assert.True(raised);
Assert.Null(newValue);
}
[Fact]
public void DatePicker_Parses_Input_Using_DateFormat()
{
using var ctx = new TestContext();
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
var component = ctx.RenderComponent<RadzenDatePicker<DateTime?>>();
var raised = false;
object newValue = null;
component.SetParametersAndRender(parameters =>
{
parameters.Add(p => p.DateFormat, "ddMM");
parameters.Add(p => p.ValueChanged, args => { raised = true; newValue = args; });
});
var inputElement = component.Find(".rz-inputtext");
string input = "3012";
ctx.JSInterop.Setup<string>("Radzen.getInputValue", invocation => true).SetResult(input);
inputElement.Change(input);
Assert.True(raised);
Assert.Equal(new DateTime(DateTime.Now.Year, 12, 30), newValue);
}
[Fact]
public void DatePicker_Parses_Input_Using_ParseInput()
{
using var ctx = new TestContext();
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
var component = ctx.RenderComponent<RadzenDatePicker<DateTime?>>();
Func<string, DateTime?> customParseInput = (input) =>
{
if (DateTime.TryParseExact(input, "ddMM", null, DateTimeStyles.None, out var result))
{
return result;
}
return null;
};
var raised = false;
object newValue = null;
component.SetParametersAndRender(parameters =>
{
parameters.Add(p => p.ParseInput, customParseInput);
parameters.Add(p => p.ValueChanged, args => { raised = true; newValue = args; });
});
var inputElement = component.Find(".rz-inputtext");
string input = "3012";
ctx.JSInterop.Setup<string>("Radzen.getInputValue", invocation => true).SetResult(input);
inputElement.Change(input);
Assert.True(raised);
Assert.Equal(new DateTime(DateTime.Now.Year, 12, 30), newValue);
}
[Fact]
public void DatePicker_Renders_Blank_WhenValueIsMaxValue()
{
using var ctx = new TestContext();
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
ctx.JSInterop.SetupModule("_content/Radzen.Blazor/Radzen.Blazor.js");
var component = ctx.RenderComponent<RadzenDatePicker<DateTime>>(parameters =>
{
parameters.Add(p => p.Value, DateTime.MaxValue);
});
Assert.Contains(@$"rz-state-empty", component.Markup);
Assert.Contains(@$"value=""""", component.Markup);
}
[Fact]
public void DatePicker_Renders_Blank_WhenValueIsMinValue()
{
using var ctx = new TestContext();
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
ctx.JSInterop.SetupModule("_content/Radzen.Blazor/Radzen.Blazor.js");
var component = ctx.RenderComponent<RadzenDatePicker<DateTime>>(parameters =>
{
parameters.Add(p => p.Value, DateTime.MinValue);
});
Assert.Contains(@$"rz-state-empty", component.Markup);
Assert.Contains(@$"value=""""", component.Markup);
}
[Theory]
[InlineData(DateTimeKind.Local)]
[InlineData(DateTimeKind.Unspecified)]
[InlineData(DateTimeKind.Utc)]
public void DatePicker_Respects_DateTimeKind(DateTimeKind kind)
{
using var ctx = new TestContext();
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
ctx.JSInterop.SetupModule("_content/Radzen.Blazor/Radzen.Blazor.js");
var component = ctx.RenderComponent<RadzenDatePicker<DateTime>>(parameters =>
{
parameters.Add(x => x.Kind, kind);
parameters.Add(x => x.ShowTime, true);
});
var raised = false;
object newValue = null;
component.SetParametersAndRender(parameters =>
{
parameters.Add(p => p.Change, args => { raised = true; newValue = args; });
});
component.Find(".rz-calendar-next-icon").Click();
component.FindAll(".rz-button-text").First(x => x.TextContent == "Ok").Click();
Assert.True(raised);
Assert.Equal(kind, ((DateTime)newValue).Kind);
}
[Fact]
public void DatePicker_Renders_FooterTemplate()
{
using var ctx = new TestContext();
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
ctx.JSInterop.SetupModule("_content/Radzen.Blazor/Radzen.Blazor.js");
string actionsTemplate = "<input type=\"button\" value=\"Test\" />";
var component = ctx.RenderComponent<RadzenDatePicker<DateTime>>(parameters =>
{
parameters.Add(p => p.Value, DateTime.MinValue);
parameters.Add(p => p.FooterTemplate, actionsTemplate);
});
Assert.Contains(actionsTemplate, component.Markup);
}
[Fact]
public void DatePicker_Converts_DateTimeOffSet_FromUtc_ToLocal()
{
using var ctx = new TestContext();
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
ctx.JSInterop.SetupModule("_content/Radzen.Blazor/Radzen.Blazor.js");
var valueUtc = DateTimeOffset.UtcNow;
var kind = DateTimeKind.Local;
var component = ctx.RenderComponent<RadzenDatePicker<DateTimeOffset>>(parameters =>
{
parameters.Add(p => p.Kind, kind);
parameters.Add(p => p.Value, valueUtc);
});
Assert.Equal(kind, (component.Instance.Value as DateTime?)?.Kind);
Assert.Equal(valueUtc.LocalDateTime.ToString(CultureInfo.InvariantCulture), (component.Instance.Value as DateTime?)?.ToString(CultureInfo.InvariantCulture));
}
[Fact]
public void DatePicker_Converts_DateTimeOffSet_Local_ToUtc()
{
using var ctx = new TestContext();
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
ctx.JSInterop.SetupModule("_content/Radzen.Blazor/Radzen.Blazor.js");
var valueUtc = DateTimeOffset.Now;
var kind = DateTimeKind.Utc;
var component = ctx.RenderComponent<RadzenDatePicker<DateTimeOffset>>(parameters =>
{
parameters.Add(p => p.Kind, kind);
parameters.Add(p => p.Value, valueUtc);
});
Assert.Equal(kind, (component.Instance.Value as DateTime?)?.Kind);
Assert.Equal(valueUtc.UtcDateTime.ToString(CultureInfo.InvariantCulture), (component.Instance.Value as DateTime?)?.ToString(CultureInfo.InvariantCulture));
}
[Fact]
public void DatePicker_Displays_Calender_Icon()
{
using var ctx = new TestContext();
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
ctx.JSInterop.SetupModule("_content/Radzen.Blazor/Radzen.Blazor.js");
var component = ctx.RenderComponent<RadzenDatePicker<DateTime>>();
Assert.Contains(@$"rzi-calendar", component.Markup);
}
[Fact]
public void DatePicker_Displays_Schedule_Icon()
{
using var ctx = new TestContext();
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
ctx.JSInterop.SetupModule("_content/Radzen.Blazor/Radzen.Blazor.js");
var component = ctx.RenderComponent<RadzenDatePicker<DateTime>>(parameters =>
{
parameters.Add(p => p.TimeOnly, true);
});
Assert.Contains(@$"rzi-time", component.Markup);
}
[Fact]
public void DatePicker_Supports_DateOnly()
{
using var ctx = new TestContext();
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
ctx.JSInterop.SetupModule("_content/Radzen.Blazor/Radzen.Blazor.js");
DateOnly? dateOnly = new DateOnly(2024, 1, 31);
DateOnly? valueChangedValue = null!;
var component = ctx.RenderComponent<RadzenDatePicker<DateOnly?>>(parameters =>
{
parameters.Add(p => p.Value, dateOnly);
parameters.Add(p => p.ValueChanged, args => { valueChangedValue = args; });
});
Assert.False(component.Instance.ShowTime);
var input = component.Find("input");
input.GetAttribute("value").MarkupMatches(dateOnly.ToString());
// update to new value
var inputElement = component.Find(".rz-inputtext");
DateOnly? enteredValue = new DateOnly(2024, 2, 28);
ctx.JSInterop.Setup<string>("Radzen.getInputValue", invocation => true).SetResult(enteredValue.Value.ToShortDateString());
inputElement.Change(enteredValue);
input.GetAttribute("value").MarkupMatches(enteredValue.ToString());
Assert.Equal(enteredValue, component.Instance.Value);
Assert.Equal(enteredValue, valueChangedValue);
}
[Fact]
public void DatePicker_Supports_TimeOnly()
{
using var ctx = new TestContext();
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
ctx.JSInterop.SetupModule("_content/Radzen.Blazor/Radzen.Blazor.js");
TimeOnly? timeOnly = new TimeOnly(23, 59, 59);
TimeOnly? valueChangedValue = null!;
var component = ctx.RenderComponent<RadzenDatePicker<TimeOnly>>(parameters =>
{
parameters.Add(p => p.Value, timeOnly);
parameters.Add(p => p.ValueChanged, args => { valueChangedValue = args; });
});
Assert.True(component.Instance.TimeOnly);
Assert.True(component.Instance.ShowTime);
var input = component.Find("input");
input.GetAttribute("value").MarkupMatches(timeOnly.ToString());
// update to new value
var inputElement = component.Find(".rz-inputtext");
TimeOnly? enteredValue = new TimeOnly(1, 4, 5);
ctx.JSInterop.Setup<string>("Radzen.getInputValue", invocation => true).SetResult(enteredValue.Value.ToLongTimeString());
inputElement.Change(enteredValue);
input.GetAttribute("value").MarkupMatches(enteredValue.ToString());
Assert.Equal(enteredValue, component.Instance.Value);
Assert.Equal(enteredValue, valueChangedValue);
}
[Fact]
public void DatePicker_ShowCalendarWeek_WeekNumberAddedInAdditionalColumn()
{
using var ctx = new TestContext();
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
ctx.JSInterop.SetupModule("_content/Radzen.Blazor/Radzen.Blazor.js");
var component = ctx.RenderComponent<RadzenDatePicker<DateTime>>(parameter =>
{
parameter.Add(p => p.ShowCalendarWeek, true);
});
Assert.Contains(@$"rz-calendar-week-number", component.Markup);
Assert.Equal(8, component.FindAll(".rz-calendar-view th").Count());
// check header and week number column
Assert.Single(component.FindAll("th.rz-datepicker-week-number"));
Assert.Equal(6, component.FindAll("td.rz-calendar-week-number").Count());
}
[Fact]
public void DatePicker_ShowCalendarWeekFalse_NoAdditionalColumn()
{
using var ctx = new TestContext();
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
ctx.JSInterop.SetupModule("_content/Radzen.Blazor/Radzen.Blazor.js");
var component = ctx.RenderComponent<RadzenDatePicker<DateTime>>(parameter =>
{
parameter.Add(p => p.ShowCalendarWeek, false);
});
Assert.DoesNotContain(@$"rz-calendar-week-number", component.Markup);
Assert.Equal(7, component.FindAll(".rz-calendar-view th").Count());
}
[Fact]
public void DatePicker_ShowCalendarWeekWithCustomTitle_TitleCorrectlyRendered()
{
using var ctx = new TestContext();
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
ctx.JSInterop.SetupModule("_content/Radzen.Blazor/Radzen.Blazor.js");
var component = ctx.RenderComponent<RadzenDatePicker<DateTime>>(parameter =>
{
parameter.Add(p => p.ShowCalendarWeek, true);
parameter.Add(p => p.CalendarWeekTitle, "Wk");
});
var weekNumberHeader = component.Find(".rz-calendar-view th.rz-datepicker-week-number");
Assert.Contains("Wk", weekNumberHeader.InnerHtml);
}
[Fact]
public void DatePicker_Multiple_Selects_IEnumerableDateTime()
{
using var ctx = new TestContext();
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
ctx.JSInterop.SetupModule("_content/Radzen.Blazor/Radzen.Blazor.js");
IEnumerable<DateTime> emitted = null;
var initial = new DateTime(2024, 1, 1);
var component = ctx.RenderComponent<RadzenDatePicker<IEnumerable<DateTime>>>(parameters =>
{
parameters.Add(p => p.Multiple, true);
parameters.Add(p => p.InitialViewDate, initial);
parameters.Add(p => p.ValueChanged, args => { emitted = args; });
});
component.InvokeAsync(() => component.FindAll("td:not(.rz-calendar-other-month) span").First(e => e.TextContent == "10").ParentElement.Click());
component.InvokeAsync(() => component.FindAll("td:not(.rz-calendar-other-month) span").First(e => e.TextContent == "12").ParentElement.Click());
Assert.NotNull(emitted);
var list = emitted.ToList();
Assert.Equal(2, list.Count);
Assert.Contains(new DateTime(2024, 1, 10), list.Select(d => d.Date));
Assert.Contains(new DateTime(2024, 1, 12), list.Select(d => d.Date));
}
[Fact]
public void DatePicker_Multiple_Selects_IEnumerableNullableDateTime()
{
using var ctx = new TestContext();
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
ctx.JSInterop.SetupModule("_content/Radzen.Blazor/Radzen.Blazor.js");
IEnumerable<DateTime?> emitted = null;
var initial = new DateTime(2024, 2, 1);
var component = ctx.RenderComponent<RadzenDatePicker<IEnumerable<DateTime?>>>(parameters =>
{
parameters.Add(p => p.Multiple, true);
parameters.Add(p => p.InitialViewDate, initial);
parameters.Add(p => p.ValueChanged, args => { emitted = args; });
});
component.InvokeAsync(() => component.FindAll("td:not(.rz-calendar-other-month) span").First(e => e.TextContent == "3").ParentElement.Click());
component.InvokeAsync(() => component.FindAll("td:not(.rz-calendar-other-month) span").First(e => e.TextContent == "14").ParentElement.Click());
Assert.NotNull(emitted);
var list = emitted.ToList();
Assert.Equal(2, list.Count);
Assert.Contains(new DateTime(2024, 2, 3), list.Select(d => d.Value.Date));
Assert.Contains(new DateTime(2024, 2, 14), list.Select(d => d.Value.Date));
}
[Fact]
public void DatePicker_Multiple_Emits_IEnumerableDateTimeOffsetNullable_WithUtcKind()
{
using var ctx = new TestContext();
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
ctx.JSInterop.SetupModule("_content/Radzen.Blazor/Radzen.Blazor.js");
IEnumerable<DateTimeOffset?> emitted = null;
var initial = new DateTime(2024, 3, 1);
var component = ctx.RenderComponent<RadzenDatePicker<IEnumerable<DateTimeOffset?>>>(parameters =>
{
parameters.Add(p => p.Multiple, true);
parameters.Add(p => p.InitialViewDate, initial);
parameters.Add(p => p.Kind, DateTimeKind.Utc);
parameters.Add(p => p.ValueChanged, args => { emitted = args; });
});
component.InvokeAsync(() => component.FindAll("td:not(.rz-calendar-other-month) span").First(e => e.TextContent == "5").ParentElement.Click());
component.InvokeAsync(() => component.FindAll("td:not(.rz-calendar-other-month) span").First(e => e.TextContent == "20").ParentElement.Click());
Assert.NotNull(emitted);
var list = emitted.ToList();
Assert.Equal(2, list.Count);
Assert.All(list, dto => Assert.Equal(TimeSpan.Zero, dto.Value.Offset));
}
[Fact]
public void DatePicker_Multiple_Emits_IEnumerableDateOnlyAndTimeOnlyNullable()
{
using var ctx = new TestContext();
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
ctx.JSInterop.SetupModule("_content/Radzen.Blazor/Radzen.Blazor.js");
IEnumerable<DateOnly?> emittedDates = null;
IEnumerable<TimeOnly?> emittedTimes = null;
var initial = new DateTime(2024, 4, 1);
var compDates = ctx.RenderComponent<RadzenDatePicker<IEnumerable<DateOnly?>>>(parameters =>
{
parameters.Add(p => p.Multiple, true);
parameters.Add(p => p.InitialViewDate, initial);
parameters.Add(p => p.ValueChanged, args => { emittedDates = args; });
});
compDates.InvokeAsync(() => compDates.FindAll("td:not(.rz-calendar-other-month) span").First(e => e.TextContent == "7").ParentElement.Click());
compDates.InvokeAsync(() => compDates.FindAll("td:not(.rz-calendar-other-month) span").First(e => e.TextContent == "9").ParentElement.Click());
Assert.NotNull(emittedDates);
var dateList = emittedDates.ToList();
Assert.Equal(2, dateList.Count);
Assert.Contains(new DateOnly(2024, 4, 7), dateList.Select(d => d.Value));
Assert.Contains(new DateOnly(2024, 4, 9), dateList.Select(d => d.Value));
// TimeOnly? emission should produce midnight times for selected dates
var compTimes = ctx.RenderComponent<RadzenDatePicker<IEnumerable<TimeOnly?>>>(parameters =>
{
parameters.Add(p => p.Multiple, true);
parameters.Add(p => p.InitialViewDate, initial);
parameters.Add(p => p.ValueChanged, args => { emittedTimes = args; });
});
compTimes.InvokeAsync(() => compTimes.FindAll("td:not(.rz-calendar-other-month) span").First(e => e.TextContent == "1").ParentElement.Click());
compTimes.InvokeAsync(() => compTimes.FindAll("td:not(.rz-calendar-other-month) span").First(e => e.TextContent == "2").ParentElement.Click());
Assert.NotNull(emittedTimes);
var timeList = emittedTimes.ToList();
Assert.Equal(2, timeList.Count);
Assert.All(timeList, t => Assert.Equal(new TimeOnly(0, 0, 0), t.Value));
}
[Fact]
public void DatePicker_WithoutOkButton_TimeChange_ImmediatelyCommits()
{
using var ctx = new TestContext();
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
ctx.JSInterop.SetupModule("_content/Radzen.Blazor/Radzen.Blazor.js");
var changeCount = 0;
DateTime? lastChangeValue = null;
DateTime? lastValueChanged = null;
var component = ctx.RenderComponent<RadzenDatePicker<DateTime>>(parameters =>
{
parameters.Add(p => p.ShowTime, true);
parameters.Add(p => p.ShowTimeOkButton, false);
parameters.Add(p => p.Value, new DateTime(2024, 6, 15, 10, 30, 0));
parameters.Add(p => p.Change, args => { changeCount++; lastChangeValue = args; });
parameters.Add(p => p.ValueChanged, args => { lastValueChanged = args; });
});
component.Find(".rz-hour-picker .rz-numeric-up").Click();
Assert.Equal(1, changeCount);
Assert.NotNull(lastChangeValue);
Assert.Equal(11, lastChangeValue.Value.Hour);
Assert.NotNull(lastValueChanged);
Assert.Equal(11, lastValueChanged.Value.Hour);
}
[Fact]
public void DatePicker_WithoutOkButton_DayClick_ImmediatelyCommits()
{
using var ctx = new TestContext();
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
ctx.JSInterop.SetupModule("_content/Radzen.Blazor/Radzen.Blazor.js");
var changeRaised = false;
DateTime? lastValueChanged = null;
var component = ctx.RenderComponent<RadzenDatePicker<DateTime>>(parameters =>
{
parameters.Add(p => p.ShowTime, true);
parameters.Add(p => p.ShowTimeOkButton, false);
parameters.Add(p => p.Value, new DateTime(2024, 6, 15, 10, 30, 0));
parameters.Add(p => p.Change, args => { changeRaised = true; });
parameters.Add(p => p.ValueChanged, args => { lastValueChanged = args; });
});
component.FindAll("td:not(.rz-calendar-other-month) span").First(e => e.TextContent == "20").ParentElement.Click();
Assert.True(changeRaised);
Assert.NotNull(lastValueChanged);
Assert.Equal(20, lastValueChanged.Value.Day);
Assert.Equal(10, lastValueChanged.Value.Hour);
}
[Fact]
public void DatePicker_WithOkButton_TimeChange_RevertsOnClose()
{
using var ctx = new TestContext();
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
ctx.JSInterop.SetupModule("_content/Radzen.Blazor/Radzen.Blazor.js");
var initialDate = new DateTime(2024, 6, 15, 10, 30, 0);
var valueChangedCount = 0;
var component = ctx.RenderComponent<RadzenDatePicker<DateTime>>(parameters =>
{
parameters.Add(p => p.ShowTime, true);
parameters.Add(p => p.ShowTimeOkButton, true);
parameters.Add(p => p.Value, initialDate);
parameters.Add(p => p.ValueChanged, args => { valueChangedCount++; });
});
var hourInput = component.Find(".rz-hour-picker input");
Assert.Equal("10", hourInput.GetAttribute("value"));
component.Find(".rz-hour-picker .rz-numeric-up").Click();
hourInput = component.Find(".rz-hour-picker input");
Assert.Equal("11", hourInput.GetAttribute("value"));
Assert.Equal(0, valueChangedCount);
component.InvokeAsync(() => component.Instance.Close());
hourInput = component.Find(".rz-hour-picker input");
Assert.Equal("10", hourInput.GetAttribute("value"));
var input = component.Find(".rz-inputtext");
Assert.Contains("10", input.GetAttribute("value"));
}
[Fact]
public void DatePicker_WithOkButton_TimeChange_CommitsOnOk()
{
using var ctx = new TestContext();
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
ctx.JSInterop.SetupModule("_content/Radzen.Blazor/Radzen.Blazor.js");
DateTime? lastValueChanged = null;
DateTime? lastChangeValue = null;
var component = ctx.RenderComponent<RadzenDatePicker<DateTime>>(parameters =>
{
parameters.Add(p => p.ShowTime, true);
parameters.Add(p => p.ShowTimeOkButton, true);
parameters.Add(p => p.Value, new DateTime(2024, 6, 15, 10, 30, 0));
parameters.Add(p => p.ValueChanged, args => { lastValueChanged = args; });
parameters.Add(p => p.Change, args => { lastChangeValue = args; });
});
component.Find(".rz-hour-picker .rz-numeric-up").Click();
component.FindAll(".rz-button-text").First(x => x.TextContent == "Ok").Click();
Assert.NotNull(lastValueChanged);
Assert.Equal(11, lastValueChanged.Value.Hour);
Assert.NotNull(lastChangeValue);
Assert.Equal(11, lastChangeValue.Value.Hour);
}
[Fact]
public void DatePicker_WithOkButton_DayCommits_ThenTimeRevertsOnClose()
{
using var ctx = new TestContext();
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
ctx.JSInterop.SetupModule("_content/Radzen.Blazor/Radzen.Blazor.js");
DateTime? lastValueChanged = null;
var component = ctx.RenderComponent<RadzenDatePicker<DateTime>>(parameters =>
{
parameters.Add(p => p.ShowTime, true);
parameters.Add(p => p.ShowTimeOkButton, true);
parameters.Add(p => p.Value, new DateTime(2024, 6, 15, 10, 30, 0));
parameters.Add(p => p.ValueChanged, args => { lastValueChanged = args; });
});
component.FindAll("td:not(.rz-calendar-other-month) span").First(e => e.TextContent == "20").ParentElement.Click();
Assert.NotNull(lastValueChanged);
Assert.Equal(20, lastValueChanged.Value.Day);
Assert.Equal(10, lastValueChanged.Value.Hour);
component.Find(".rz-hour-picker .rz-numeric-up").Click();
component.InvokeAsync(() => component.Instance.Close());
var input = component.Find(".rz-inputtext");
Assert.Contains("10", input.GetAttribute("value"));
Assert.Contains("20", input.GetAttribute("value"));
}
[Fact]
public void DatePicker_WithOkButton_OnPopupClose_RevertsTimeChange()
{
using var ctx = new TestContext();
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
ctx.JSInterop.SetupModule("_content/Radzen.Blazor/Radzen.Blazor.js");
var initialDate = new DateTime(2024, 6, 15, 10, 30, 0);
DateTime? lastValueChanged = null;
var valueChangedCount = 0;
var component = ctx.RenderComponent<RadzenDatePicker<DateTime>>(parameters =>
{
parameters.Add(p => p.ShowTime, true);
parameters.Add(p => p.ShowTimeOkButton, true);
parameters.Add(p => p.Value, initialDate);
parameters.Add(p => p.ValueChanged, args => { valueChangedCount++; lastValueChanged = args; });
});
component.Find(".rz-hour-picker .rz-numeric-up").Click();
var countBeforeClose = valueChangedCount;
component.InvokeAsync(() => component.Instance.OnPopupClose());
Assert.Equal(countBeforeClose, valueChangedCount);
var input = component.Find("input");
Assert.Contains("10", input.GetAttribute("value"));
}
[Fact]
public void DatePicker_OkClick_Fires_OnOkButtonClick()
{
using var ctx = new TestContext();
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
ctx.JSInterop.SetupModule("_content/Radzen.Blazor/Radzen.Blazor.js");
var okClickRaised = false;
DateTime? okClickValue = null;
var component = ctx.RenderComponent<RadzenDatePicker<DateTime>>(parameters =>
{
parameters.Add(p => p.ShowTime, true);
parameters.Add(p => p.ShowTimeOkButton, true);
parameters.Add(p => p.OkClick, args => { okClickRaised = true; okClickValue = args; });
});
component.Find(".rz-calendar-next-icon").Click();
component.FindAll(".rz-button-text").First(x => x.TextContent == "Ok").Click();
Assert.True(okClickRaised);
Assert.NotNull(okClickValue);
}
[Fact]
public void DatePicker_OkClick_DoesNotFire_OnDaySelection()
{
using var ctx = new TestContext();
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
ctx.JSInterop.SetupModule("_content/Radzen.Blazor/Radzen.Blazor.js");
var okClickRaised = false;
var changeRaised = false;
var component = ctx.RenderComponent<RadzenDatePicker<DateTime>>(parameters =>
{
parameters.Add(p => p.ShowTime, true);
parameters.Add(p => p.ShowTimeOkButton, true);
parameters.Add(p => p.Change, args => { changeRaised = true; });
parameters.Add(p => p.OkClick, args => { okClickRaised = true; });
});
component.FindAll("td:not(.rz-calendar-other-month) span").First(e => e.TextContent == "15").ParentElement.Click();
Assert.True(changeRaised);
Assert.False(okClickRaised);
}
[Fact]
public void DatePicker_Renders_ImmediateParameter()
{
using var ctx = new TestContext();
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
ctx.JSInterop.SetupModule("_content/Radzen.Blazor/Radzen.Blazor.js");
var component = ctx.RenderComponent<RadzenDatePicker<DateTime>>(parameters =>
parameters.Add(p => p.Immediate, true));
var inputElement = component.Find(".rz-inputtext");
Assert.Contains("oninput", inputElement.ToMarkup());
}
[Fact]
public void DatePicker_DoesNotRender_OninputWhenNotImmediate()
{
using var ctx = new TestContext();
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
ctx.JSInterop.SetupModule("_content/Radzen.Blazor/Radzen.Blazor.js");
var component = ctx.RenderComponent<RadzenDatePicker<DateTime>>();
var inputElement = component.Find(".rz-inputtext");
Assert.DoesNotContain("oninput", inputElement.ToMarkup());
}
[Fact]
public void DatePicker_Immediate_Raises_ChangeOnValidInput()
{
using var ctx = new TestContext();
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
ctx.JSInterop.SetupModule("_content/Radzen.Blazor/Radzen.Blazor.js");
var raised = false;
object newValue = null;
var testDate = new DateTime(2025, 6, 15);
var component = ctx.RenderComponent<RadzenDatePicker<DateTime?>>(parameters =>
{
parameters.Add(p => p.Immediate, true);
parameters.Add(p => p.Change, args => { raised = true; newValue = args; });
});
var inputElement = component.Find(".rz-inputtext");
ctx.JSInterop.Setup<string>("Radzen.getInputValue", invocation => true).SetResult(testDate.ToShortDateString());
inputElement.Input(testDate.ToShortDateString());
Assert.True(raised);
Assert.Equal(testDate, ((DateTime?)newValue)?.Date);
}
[Fact]
public void DatePicker_Immediate_DoesNotUpdateOnInvalidInput()
{
using var ctx = new TestContext();
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
ctx.JSInterop.SetupModule("_content/Radzen.Blazor/Radzen.Blazor.js");
var initialDate = new DateTime(2025, 6, 15);
var changeCount = 0;
// Use non-nullable DateTime so ParseDate does not clear the value on invalid input
var component = ctx.RenderComponent<RadzenDatePicker<DateTime>>(parameters =>
{
parameters.Add(p => p.Immediate, true);
parameters.Add(p => p.Value, initialDate);
parameters.Add(p => p.Change, args => { changeCount++; });
});
var inputElement = component.Find(".rz-inputtext");
// Simulate partial/invalid input
ctx.JSInterop.Setup<string>("Radzen.getInputValue", invocation => true).SetResult("abc");
inputElement.Input("abc");
// ParseDateImmediate ignores invalid input; ParseDate also reverts to FormattedValue for non-nullable.
// Value should remain unchanged.
Assert.Equal(initialDate, component.Instance.Value);
}
[Fact]
public void DatePicker_Immediate_Raises_ValueChangedOnValidInput()
{
using var ctx = new TestContext();
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
ctx.JSInterop.SetupModule("_content/Radzen.Blazor/Radzen.Blazor.js");
var raised = false;
DateTime? newValue = null;
var testDate = new DateTime(2025, 3, 20);
var component = ctx.RenderComponent<RadzenDatePicker<DateTime?>>(parameters =>
{
parameters.Add(p => p.Immediate, true);
parameters.Add(p => p.ValueChanged, args => { raised = true; newValue = args; });
});
var inputElement = component.Find(".rz-inputtext");
ctx.JSInterop.Setup<string>("Radzen.getInputValue", invocation => true).SetResult(testDate.ToShortDateString());
inputElement.Input(testDate.ToShortDateString());
Assert.True(raised);
Assert.Equal(testDate, newValue?.Date);
}
[Fact]
public void DatePicker_NonGregorianCalendar_Renders_CorrectDayNumbers()
{
using var ctx = new TestContext();
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
ctx.JSInterop.SetupModule("_content/Radzen.Blazor/Radzen.Blazor.js");
// Thai Buddhist calendar: same months/days as Gregorian, year offset by +543
var thaiCulture = new CultureInfo("th-TH");
var testDate = new DateTime(2024, 4, 3);
var component = ctx.RenderComponent<RadzenDatePicker<DateTime>>(parameters =>
{
parameters.Add(p => p.Value, testDate);
parameters.Add(p => p.Culture, thaiCulture);
parameters.Add(p => p.Inline, true);
});
var dayCells = component.FindAll("td span.rz-state-default");
var dayNumbers = dayCells.Select(c => c.TextContent.Trim()).Where(t => !string.IsNullOrEmpty(t)).ToList();
// April has 30 days — day numbers 1-30 should appear
Assert.Contains("1", dayNumbers);
Assert.Contains("3", dayNumbers);
Assert.Contains("30", dayNumbers);
}
[Fact]
public void DatePicker_NonGregorianCalendar_ActiveDay_IsCorrect()
{
using var ctx = new TestContext();
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
ctx.JSInterop.SetupModule("_content/Radzen.Blazor/Radzen.Blazor.js");
var thaiCulture = new CultureInfo("th-TH");
// April 3, 2024 Gregorian = day 3 in Thai Buddhist calendar (same day)
var testDate = new DateTime(2024, 4, 3);
var component = ctx.RenderComponent<RadzenDatePicker<DateTime>>(parameters =>
{
parameters.Add(p => p.Value, testDate);
parameters.Add(p => p.Culture, thaiCulture);
parameters.Add(p => p.Inline, true);
});
var activeDay = component.Find("span.rz-state-active");
Assert.Equal("3", activeDay.TextContent.Trim());
}
[Fact]
public void DatePicker_NonGregorianCalendar_MonthDropdown_ShowsCorrectMonth()
{
using var ctx = new TestContext();
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
ctx.JSInterop.SetupModule("_content/Radzen.Blazor/Radzen.Blazor.js");
var thaiCulture = new CultureInfo("th-TH");
var testDate = new DateTime(2024, 4, 3);
var component = ctx.RenderComponent<RadzenDatePicker<DateTime>>(parameters =>
{
parameters.Add(p => p.Value, testDate);
parameters.Add(p => p.Culture, thaiCulture);
parameters.Add(p => p.Inline, true);
});
// Month dropdown should show the Thai name for April (month 4)
var monthDropdown = component.Find(".rz-calendar-month-dropdown");
var monthName = thaiCulture.DateTimeFormat.GetMonthName(4);
Assert.Contains(monthName, monthDropdown.InnerHtml);
}
[Fact]
public void DatePicker_NonGregorianCalendar_YearDropdown_ShowsCalendarYear()
{
using var ctx = new TestContext();
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
ctx.JSInterop.SetupModule("_content/Radzen.Blazor/Radzen.Blazor.js");
var thaiCulture = new CultureInfo("th-TH");
// 2024 Gregorian = 2567 Thai Buddhist
var testDate = new DateTime(2024, 4, 3);
var component = ctx.RenderComponent<RadzenDatePicker<DateTime>>(parameters =>
{
parameters.Add(p => p.Value, testDate);
parameters.Add(p => p.Culture, thaiCulture);
parameters.Add(p => p.Inline, true);
});
var yearDropdown = component.Find(".rz-calendar-year-dropdown");
Assert.Contains("2567", yearDropdown.InnerHtml);
}
[Fact]
public void DatePicker_NonGregorianCalendar_OtherMonthDays_MarkedCorrectly()
{
using var ctx = new TestContext();
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
ctx.JSInterop.SetupModule("_content/Radzen.Blazor/Radzen.Blazor.js");
var thaiCulture = new CultureInfo("th-TH");
var testDate = new DateTime(2024, 4, 3);
var component = ctx.RenderComponent<RadzenDatePicker<DateTime>>(parameters =>
{
parameters.Add(p => p.Value, testDate);
parameters.Add(p => p.Culture, thaiCulture);
parameters.Add(p => p.Inline, true);
});
var currentMonthCells = component.FindAll("td:not(.rz-calendar-other-month):not(.rz-calendar-week-number)");
Assert.True(currentMonthCells.Count > 0);
}
[Fact]
public void DatePicker_NonGregorianCalendar_DayClick_SetsCorrectValue()
{
using var ctx = new TestContext();
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
ctx.JSInterop.SetupModule("_content/Radzen.Blazor/Radzen.Blazor.js");
var thaiCulture = new CultureInfo("th-TH");
var testDate = new DateTime(2024, 4, 1);
DateTime? changedValue = null;
var component = ctx.RenderComponent<RadzenDatePicker<DateTime>>(parameters =>
{
parameters.Add(p => p.Value, testDate);
parameters.Add(p => p.Culture, thaiCulture);
parameters.Add(p => p.Inline, true);
parameters.Add(p => p.ValueChanged, (DateTime v) => { changedValue = v; });
});
// Click on day "10"
var dayCells = component.FindAll("td[role='button'] span.rz-state-default");
var day10 = dayCells.FirstOrDefault(c => c.TextContent.Trim() == "10" && !c.ClassList.Contains("rz-calendar-other-month"));
if (day10 != null)
{
day10.ParentElement!.Click();
Assert.NotNull(changedValue);
Assert.Equal(new DateTime(2024, 4, 10).Date, changedValue!.Value.Date);
}
}
[Fact]
public void DatePicker_NonGregorianCalendar_FormattedValue_UsesCalendarYear()
{
using var ctx = new TestContext();
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
ctx.JSInterop.SetupModule("_content/Radzen.Blazor/Radzen.Blazor.js");
var thaiCulture = new CultureInfo("th-TH");
var testDate = new DateTime(2024, 4, 3);
var component = ctx.RenderComponent<RadzenDatePicker<DateTime>>(parameters =>
{
parameters.Add(p => p.Value, testDate);
parameters.Add(p => p.Culture, thaiCulture);
});
// The formatted value should use Thai Buddhist year 2567
var formattedValue = component.Instance.FormattedValue;
Assert.False(string.IsNullOrEmpty(formattedValue));
Assert.Contains("2567", formattedValue);
}
[Fact]
public void DatePicker_ShowTime_MinToday_DoesNotDisableToday()
{
using var ctx = new TestContext();
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
ctx.JSInterop.SetupModule("_content/Radzen.Blazor/Radzen.Blazor.js");
var today = DateTime.Now;
var min = new DateTime(today.Year, today.Month, today.Day, 14, 0, 0);
var component = ctx.RenderComponent<RadzenDatePicker<DateTime>>(parameters =>
{
parameters.Add(p => p.Value, today);
parameters.Add(p => p.ShowTime, true);
parameters.Add(p => p.Min, min);
});
// Find today's cell - it should not have rz-state-disabled
var todayCell = component.FindAll("td span.rz-calendar-today");
Assert.NotEmpty(todayCell);
Assert.DoesNotContain("rz-state-disabled", todayCell.First().ClassName);
}
[Fact]
public void DatePicker_NoShowTime_MinToday_DisablesToday()
{
using var ctx = new TestContext();
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
ctx.JSInterop.SetupModule("_content/Radzen.Blazor/Radzen.Blazor.js");
var today = DateTime.Now;
var min = new DateTime(today.Year, today.Month, today.Day, 14, 0, 0);
var component = ctx.RenderComponent<RadzenDatePicker<DateTime>>(parameters =>
{
parameters.Add(p => p.Value, today);
parameters.Add(p => p.Min, min);
});
// Without ShowTime, today should be disabled since midnight < 14:00
var todayCell = component.FindAll("td span.rz-calendar-today");
Assert.NotEmpty(todayCell);
Assert.Contains("rz-state-disabled", todayCell.First().ClassName);
}
}
}