AyCode.Blazor/AyCode.Blazor.Components.Tests/Grids/MgGridBaseTests.cs

227 lines
8.5 KiB
C#

using AyCode.Blazor.Components.Components.Grids;
using AyCode.Core.Tests.TestModels;
using AyCode.Services.Server.Tests.SignalRs;
using AyCode.Services.SignalRs;
using Bunit;
using DevExpress.Blazor;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace AyCode.Blazor.Components.Tests.Grids;
/// <summary>
/// Tests for MgGridBase layout persistence functionality.
/// Tests that column width changes are persisted and loaded correctly.
/// </summary>
[TestClass]
public class MgGridBaseTests : BunitTestContext
{
private TestLogger _logger = null!;
private TestableSignalRHub2 _hub = null!;
private TestableSignalRClient2 _client = null!;
private TestSignalRService2 _service = null!;
private SignalRCrudTags _crudTags = null!;
private const string StorageKey = "TestGrid_Master_AutoSave_0";
[TestInitialize]
public void TestSetup()
{
Context = new BunitContext();
Context.Services.AddDevExpressBlazor();
_logger = new TestLogger();
_hub = new TestableSignalRHub2();
_service = new TestSignalRService2();
_client = new TestableSignalRClient2(_hub, _logger);
_hub.RegisterService(_service, _client);
_crudTags = new SignalRCrudTags(
TestSignalRTags.DataSourceGetAll,
TestSignalRTags.DataSourceGetItem,
TestSignalRTags.DataSourceAdd,
TestSignalRTags.DataSourceUpdate,
TestSignalRTags.DataSourceRemove
);
TestMgGridOrderItem.ClearLayoutStorage();
Context.JSInterop.Mode = JSRuntimeMode.Loose;
}
[TestCleanup]
public void TestTeardown() => Context?.Dispose();
private IRenderedComponent<TestMgGridOrderItem> RenderTestGrid(
string autoSaveLayoutName = "TestGrid",
System.Action<DynamicColumnAddingEventArgs>? onDynamicColumnAttributeAdding = null)
{
var dataSource = new TestGridOrderItemDataSource(_client, _crudTags);
return Context!.Render<TestMgGridOrderItem>(parameters =>
{
parameters
.Add(p => p.DataSource, dataSource)
.Add(p => p.Logger, _logger)
.Add(p => p.SignalRClient, _client)
.Add(p => p.AutoSaveLayoutName, autoSaveLayoutName)
.Add(p => p.GetAllMessageTag, _crudTags.GetAllMessageTag)
.Add(p => p.AddMessageTag, _crudTags.AddMessageTag)
.Add(p => p.UpdateMessageTag, _crudTags.UpdateMessageTag)
.Add(p => p.RemoveMessageTag, _crudTags.RemoveMessageTag);
if (onDynamicColumnAttributeAdding != null)
{
parameters.Add(p => p.OnDynamicColumnAttributeAdding, onDynamicColumnAttributeAdding);
}
});
}
#region Layout Persistence Tests
[TestMethod]
public async Task MgGridBase_ColumnWidth_ShouldBePersisted_WhenNewGridIsRendered()
{
// Arrange - Render first grid
var cut1 = RenderTestGrid();
// Wait for data source to load
await cut1.Instance.WaitForDataSourceLoadedAsync();
// Get columns from first grid
var columns1 = cut1.Instance.GetDataColumns();
Assert.IsTrue(columns1.Count > 0, "Grid should have columns after data source loaded");
// Set column width on first grid (must use BeginUpdate/EndUpdate on the dispatcher)
var firstColumn = columns1[0];
var expectedWidth = "150px";
await cut1.InvokeAsync(() =>
{
cut1.Instance.BeginUpdate();
firstColumn.Width = expectedWidth;
cut1.Instance.EndUpdate();
});
// Trigger layout save by disposing
await cut1.Instance.DisposeAsync();
// Act - Render second grid with same TDataItem
var cut2 = RenderTestGrid();
// Wait for data source to load
await cut2.Instance.WaitForDataSourceLoadedAsync();
// Assert - Second grid should have the same column width
var columns2 = cut2.Instance.GetDataColumns();
Assert.IsTrue(columns2.Count > 0, "Second grid should have columns");
var secondGridFirstColumn = columns2[0];
Assert.AreEqual(expectedWidth, secondGridFirstColumn.Width,
$"Column width should be persisted. Expected: {expectedWidth}, Actual: {secondGridFirstColumn.Width}");
}
[TestMethod]
public async Task MgGridBase_LayoutStorage_ShouldContainLayout_AfterGridRenders()
{
// Arrange & Act
var cut = RenderTestGrid();
await cut.Instance.WaitForDataSourceLoadedAsync();
// Assert
Assert.IsTrue(TestMgGridOrderItem.LayoutStorage.ContainsKey(StorageKey),
"Layout should be saved to storage after grid renders");
Assert.IsNotNull(TestMgGridOrderItem.LayoutStorage[StorageKey]);
}
[TestMethod]
public async Task MgGridBase_DifferentGridNames_ShouldHaveDifferentLayouts()
{
// Arrange - Render first grid with name "Grid1"
var cut1 = RenderTestGrid("Grid1");
await cut1.Instance.WaitForDataSourceLoadedAsync();
// Render second grid with name "Grid2"
var cut2 = RenderTestGrid("Grid2");
await cut2.Instance.WaitForDataSourceLoadedAsync();
// Assert - Different storage keys should exist
var storageKeys = TestMgGridOrderItem.LayoutStorage.Keys.ToList();
// There should be at least 2 different keys
Assert.IsTrue(storageKeys.Count >= 2,
$"Should have at least 2 storage keys, found: {string.Join(", ", storageKeys)}");
// Keys should contain Grid1 and Grid2
Assert.IsTrue(storageKeys.Any(k => k.Contains("Grid1")),
$"Should have Grid1 key. Keys: {string.Join(", ", storageKeys)}");
Assert.IsTrue(storageKeys.Any(k => k.Contains("Grid2")),
$"Should have Grid2 key. Keys: {string.Join(", ", storageKeys)}");
}
[TestMethod]
public async Task MgGridBase_IsMasterGrid_ShouldBeTrueWhenNoParentDataItem()
{
// Act
var cut = RenderTestGrid();
await cut.Instance.WaitForDataSourceLoadedAsync();
// Assert
Assert.IsTrue(cut.Instance.IsMasterGrid);
}
[TestMethod]
public async Task MgGridBase_Columns_ShouldBeBuiltFromReflection()
{
// Arrange & Act
var cut = RenderTestGrid();
await cut.Instance.WaitForDataSourceLoadedAsync();
// Assert - Should have columns for TestOrderItem properties
var columns = cut.Instance.GetDataColumns();
Assert.IsTrue(columns.Count > 0, "Grid should have columns built from TDataItem");
// Verify some expected column names exist
var columnNames = columns.Select(c => c.FieldName).ToList();
Assert.IsTrue(columnNames.Contains(nameof(TestOrderItem.Id)), "Should have Id column");
Assert.IsTrue(columnNames.Contains(nameof(TestOrderItem.ProductName)), "Should have ProductName column");
Assert.IsTrue(columnNames.Contains(nameof(TestOrderItem.Quantity)), "Should have Quantity column");
}
#endregion
#region MgGridDataColumn UrlLink Tests
[TestMethod]
public async Task MgGridDataColumn_UrlLink_ShouldRenderLinkWithReplacedValues()
{
// Arrange - Render grid with UrlLink on Id column
var cut = RenderTestGrid(onDynamicColumnAttributeAdding: args =>
{
if (args.FieldName == nameof(TestOrderItem.Id))
{
args.AdditionalAttributes[nameof(MgGridDataColumn.UrlLink)] = "https://example.com/edit/{Id}";
}
});
// Wait for data source to load
await cut.Instance.WaitForDataSourceLoadedAsync();
// Get the first row's Id value from the grid
var firstRowId = cut.Instance.GetRowValue(0, nameof(TestOrderItem.Id));
Assert.IsNotNull(firstRowId, "First row should have an Id value");
// Build the expected URL with the actual Id value
var expectedUrl = $"https://example.com/edit/{firstRowId}";
// Find the anchor element with the exact expected href
var anchor = cut.Find($"a[href=\"{expectedUrl}\"]");
// Assert - The anchor should exist and its text content should be the Id value
Assert.IsNotNull(anchor, $"Should find anchor with href='{expectedUrl}'");
Assert.AreEqual(firstRowId.ToString(), anchor.TextContent,
$"Anchor text should be the Id value '{firstRowId}', but was '{anchor.TextContent}'");
}
#endregion
}