341 lines
9.8 KiB
C#
341 lines
9.8 KiB
C#
using Bunit;
|
|
using Bunit.TestDoubles;
|
|
using Microsoft.AspNetCore.Components;
|
|
using Microsoft.Extensions.DependencyInjection;
|
|
using SufiChain.SufiBlazor.Components.Navigation;
|
|
using Xunit;
|
|
|
|
namespace SufiChain.SufiBlazor.Tests.Components.Navigation;
|
|
|
|
public class SbNavMenuTests : BunitContext
|
|
{
|
|
private IRenderedComponent<SbNavMenu> RenderNavMenu(
|
|
Action<ComponentParameterCollectionBuilder<SbNavMenu>>? configure = null)
|
|
{
|
|
return Render<SbNavMenu>(p => configure?.Invoke(p));
|
|
}
|
|
|
|
private IRenderedComponent<SbNavItem> RenderNavItem(
|
|
Action<ComponentParameterCollectionBuilder<SbNavItem>>? configure = null)
|
|
{
|
|
return Render<SbNavItem>(p => configure?.Invoke(p));
|
|
}
|
|
|
|
// --- SbNavMenu tests ---
|
|
|
|
[Fact]
|
|
public void RendersNavMenuStructure()
|
|
{
|
|
// Arrange & Act
|
|
var cut = RenderNavMenu(p => p.AddChildContent("<span>Nav content</span>"));
|
|
|
|
// Assert
|
|
var nav = cut.Find("nav.sb-nav-menu");
|
|
Assert.NotNull(nav);
|
|
Assert.Equal("nav", nav.TagName.ToLowerInvariant());
|
|
Assert.Equal("Navigation", nav.GetAttribute("aria-label"));
|
|
}
|
|
|
|
[Fact]
|
|
public void RendersChildContent()
|
|
{
|
|
// Arrange & Act
|
|
var cut = RenderNavMenu(p => p.AddChildContent("<ul><li>Item</li></ul>"));
|
|
|
|
// Assert
|
|
Assert.Contains("Item", cut.Markup);
|
|
Assert.NotNull(cut.Find("ul"));
|
|
}
|
|
|
|
[Fact]
|
|
public void UsesCustomAriaLabel()
|
|
{
|
|
// Arrange & Act
|
|
var cut = RenderNavMenu(p => p
|
|
.Add(x => x.AriaLabel, "Main menu")
|
|
.AddChildContent("<span></span>"));
|
|
|
|
// Assert
|
|
var nav = cut.Find("nav");
|
|
Assert.Equal("Main menu", nav.GetAttribute("aria-label"));
|
|
}
|
|
|
|
[Fact]
|
|
public void AddsCollapsedClassWhenCollapsedTrue()
|
|
{
|
|
// Arrange & Act
|
|
var cut = RenderNavMenu(p => p
|
|
.Add(x => x.Collapsed, true)
|
|
.AddChildContent("<span></span>"));
|
|
|
|
// Assert
|
|
var nav = cut.Find("nav.sb-nav-menu");
|
|
Assert.Contains("sb-nav-menu--collapsed", nav.ClassList);
|
|
}
|
|
|
|
[Fact]
|
|
public void DoesNotAddCollapsedClassWhenCollapsedFalse()
|
|
{
|
|
// Arrange & Act
|
|
var cut = RenderNavMenu(p => p
|
|
.Add(x => x.Collapsed, false)
|
|
.AddChildContent("<span></span>"));
|
|
|
|
// Assert
|
|
var nav = cut.Find("nav.sb-nav-menu");
|
|
Assert.DoesNotContain("sb-nav-menu--collapsed", nav.ClassList);
|
|
}
|
|
|
|
[Fact]
|
|
public void AppliesClassParameter()
|
|
{
|
|
// Arrange & Act
|
|
var cut = RenderNavMenu(p => p
|
|
.Add(x => x.Class, "sidebar-menu")
|
|
.AddChildContent("<span></span>"));
|
|
|
|
// Assert
|
|
var nav = cut.Find("nav.sb-nav-menu");
|
|
Assert.Contains("sidebar-menu", nav.ClassList);
|
|
}
|
|
|
|
[Fact]
|
|
public void AppliesStyleParameter()
|
|
{
|
|
// Arrange & Act
|
|
var cut = RenderNavMenu(p => p
|
|
.Add(x => x.Style, "width: 200px;")
|
|
.AddChildContent("<span></span>"));
|
|
|
|
// Assert
|
|
var nav = cut.Find("nav");
|
|
var style = nav.GetAttribute("style");
|
|
Assert.Contains("width: 200px", style);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task ToggleAsync_FlipsCollapsedAndInvokesCallback()
|
|
{
|
|
// Arrange
|
|
var received = false;
|
|
var cut = RenderNavMenu(p => p
|
|
.Add(x => x.Collapsed, false)
|
|
.Add(x => x.CollapsedChanged, EventCallback.Factory.Create<bool>(this, v => received = v))
|
|
.AddChildContent("<span></span>"));
|
|
|
|
// Act
|
|
await cut.InvokeAsync(() => cut.Instance.ToggleAsync());
|
|
|
|
// Assert
|
|
Assert.True(received);
|
|
cut.Render();
|
|
var nav = cut.Find("nav.sb-nav-menu");
|
|
Assert.Contains("sb-nav-menu--collapsed", nav.ClassList);
|
|
}
|
|
|
|
[Fact]
|
|
public void PassesAdditionalAttributes()
|
|
{
|
|
// Arrange & Act
|
|
var cut = RenderNavMenu(p => p
|
|
.Add(x => x.AdditionalAttributes, new Dictionary<string, object> { { "data-testid", "main-nav" } })
|
|
.AddChildContent("<span></span>"));
|
|
|
|
// Assert
|
|
var nav = cut.Find("nav");
|
|
Assert.Equal("main-nav", nav.GetAttribute("data-testid"));
|
|
}
|
|
|
|
[Fact]
|
|
public void RendersNavItemChildren()
|
|
{
|
|
// Arrange & Act
|
|
var cut = Render<SbNavMenu>(p => p.AddChildContent(b =>
|
|
{
|
|
b.OpenComponent<SbNavItem>(0);
|
|
b.AddAttribute(1, "Href", "/");
|
|
b.AddAttribute(2, "Text", "Home");
|
|
b.CloseComponent();
|
|
b.OpenComponent<SbNavItem>(3);
|
|
b.AddAttribute(4, "Href", "/about");
|
|
b.AddAttribute(5, "Text", "About");
|
|
b.CloseComponent();
|
|
}));
|
|
|
|
// Assert
|
|
var nav = cut.Find("nav.sb-nav-menu");
|
|
Assert.NotNull(nav);
|
|
var items = cut.FindAll("a.sb-nav-item");
|
|
Assert.Equal(2, items.Count);
|
|
Assert.Contains("Home", cut.Markup);
|
|
Assert.Contains("About", cut.Markup);
|
|
}
|
|
|
|
// --- SbNavItem tests ---
|
|
|
|
[Fact]
|
|
public void NavItem_RendersAsAnchor()
|
|
{
|
|
// Arrange & Act
|
|
var cut = RenderNavItem(p => p
|
|
.Add(x => x.Href, "/dashboard")
|
|
.Add(x => x.Text, "Dashboard"));
|
|
|
|
// Assert
|
|
var anchor = cut.Find("a.sb-nav-item");
|
|
Assert.NotNull(anchor);
|
|
Assert.Equal("/dashboard", anchor.GetAttribute("href"));
|
|
}
|
|
|
|
[Fact]
|
|
public void NavItem_RendersText()
|
|
{
|
|
// Arrange & Act
|
|
var cut = RenderNavItem(p => p
|
|
.Add(x => x.Href, "/")
|
|
.Add(x => x.Text, "Home"));
|
|
|
|
// Assert
|
|
var text = cut.Find(".sb-nav-item__text");
|
|
Assert.NotNull(text);
|
|
Assert.Contains("Home", text.TextContent);
|
|
}
|
|
|
|
[Fact]
|
|
public void NavItem_RendersIconWhenProvided()
|
|
{
|
|
// Arrange & Act
|
|
var cut = RenderNavItem(p => p
|
|
.Add(x => x.Href, "/")
|
|
.Add(x => x.Text, "Home")
|
|
.Add(x => x.Icon, (RenderFragment)(b => b.AddMarkupContent(0, "<span>ico</span>"))));
|
|
|
|
// Assert
|
|
var icon = cut.Find(".sb-nav-item__icon");
|
|
Assert.NotNull(icon);
|
|
Assert.Contains("ico", icon.InnerHtml);
|
|
}
|
|
|
|
[Fact]
|
|
public void NavItem_RendersBadgeWhenProvided()
|
|
{
|
|
// Arrange & Act
|
|
var cut = RenderNavItem(p => p
|
|
.Add(x => x.Href, "/inbox")
|
|
.Add(x => x.Text, "Inbox")
|
|
.Add(x => x.Badge, (RenderFragment)(b => b.AddMarkupContent(0, "3"))));
|
|
|
|
// Assert
|
|
var badge = cut.Find(".sb-nav-item__badge");
|
|
Assert.NotNull(badge);
|
|
Assert.Contains("3", badge.TextContent);
|
|
}
|
|
|
|
[Fact]
|
|
public void NavItem_AddsActiveClassWhenCurrentPage()
|
|
{
|
|
// Arrange - navigate to /products then render item with Href="/products"
|
|
var navMan = Services.GetRequiredService<BunitNavigationManager>();
|
|
navMan.NavigateTo("http://localhost/products");
|
|
|
|
var cut = RenderNavItem(p => p
|
|
.Add(x => x.Href, "/products")
|
|
.Add(x => x.Text, "Products"));
|
|
|
|
// Assert
|
|
var anchor = cut.Find("a.sb-nav-item");
|
|
Assert.Contains("sb-nav-item--active", anchor.ClassList);
|
|
}
|
|
|
|
[Fact]
|
|
public void NavItem_DoesNotAddActiveClassWhenNotCurrentPage()
|
|
{
|
|
// Arrange - default URI is base, render item with Href="/other"
|
|
var cut = RenderNavItem(p => p
|
|
.Add(x => x.Href, "/other-page")
|
|
.Add(x => x.Text, "Other"));
|
|
|
|
// Assert
|
|
var anchor = cut.Find("a.sb-nav-item");
|
|
Assert.DoesNotContain("sb-nav-item--active", anchor.ClassList);
|
|
}
|
|
|
|
[Fact]
|
|
public void NavItem_AddsDisabledClassWhenDisabledTrue()
|
|
{
|
|
// Arrange & Act
|
|
var cut = RenderNavItem(p => p
|
|
.Add(x => x.Href, "/")
|
|
.Add(x => x.Text, "Disabled")
|
|
.Add(x => x.Disabled, true));
|
|
|
|
// Assert
|
|
var anchor = cut.Find("a.sb-nav-item");
|
|
Assert.Contains("sb-nav-item--disabled", anchor.ClassList);
|
|
}
|
|
|
|
[Fact]
|
|
public void NavItem_AppliesClassParameter()
|
|
{
|
|
// Arrange & Act
|
|
var cut = RenderNavItem(p => p
|
|
.Add(x => x.Href, "/")
|
|
.Add(x => x.Text, "Item")
|
|
.Add(x => x.Class, "custom-item"));
|
|
|
|
// Assert
|
|
var anchor = cut.Find("a.sb-nav-item");
|
|
Assert.Contains("custom-item", anchor.ClassList);
|
|
}
|
|
|
|
[Fact]
|
|
public void NavItem_AppliesStyleParameter()
|
|
{
|
|
// Arrange & Act
|
|
var cut = RenderNavItem(p => p
|
|
.Add(x => x.Href, "/")
|
|
.Add(x => x.Text, "Item")
|
|
.Add(x => x.Style, "font-weight: bold;"));
|
|
|
|
// Assert
|
|
var anchor = cut.Find("a");
|
|
var style = anchor.GetAttribute("style");
|
|
Assert.Contains("font-weight: bold", style);
|
|
}
|
|
|
|
[Fact]
|
|
public void NavItem_PassesAdditionalAttributes()
|
|
{
|
|
// Arrange & Act
|
|
var cut = RenderNavItem(p => p
|
|
.Add(x => x.Href, "/")
|
|
.Add(x => x.Text, "Item")
|
|
.Add(x => x.AdditionalAttributes, new Dictionary<string, object> { { "data-testid", "nav-home" } }));
|
|
|
|
// Assert
|
|
var anchor = cut.Find("a");
|
|
Assert.Equal("nav-home", anchor.GetAttribute("data-testid"));
|
|
}
|
|
|
|
[Fact]
|
|
public void NavItem_WorksInsideSbNavMenu()
|
|
{
|
|
// Arrange & Act
|
|
var cut = Render<SbNavMenu>(p => p.AddChildContent(b =>
|
|
{
|
|
b.OpenComponent<SbNavItem>(0);
|
|
b.AddAttribute(1, "Href", "/dashboard");
|
|
b.AddAttribute(2, "Text", "Dashboard");
|
|
b.CloseComponent();
|
|
}));
|
|
|
|
// Assert
|
|
var nav = cut.Find("nav.sb-nav-menu");
|
|
var item = cut.Find("a.sb-nav-item");
|
|
Assert.NotNull(nav);
|
|
Assert.NotNull(item);
|
|
Assert.Equal("/dashboard", item.GetAttribute("href"));
|
|
Assert.Contains("Dashboard", cut.Markup);
|
|
}
|
|
}
|