Files
2026-05-18 15:53:59 +03:30

295 lines
8.1 KiB
C#

using System.Globalization;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Localization;
using Bunit;
using Bunit.JSInterop;
using SufiChain.SufiBlazor.Components.Forms;
using SufiChain.SufiBlazor.Contracts.Editors;
using SufiChain.SufiBlazor.Localization;
using Xunit;
namespace SufiChain.SufiBlazor.Tests.Components.Forms;
file class StubStringLocalizer : IStringLocalizer<SufiBlazorResource>
{
public LocalizedString this[string name] => new(name, name);
public LocalizedString this[string name, params object[] arguments] => new(name, string.Format(CultureInfo.InvariantCulture, name, arguments));
public IEnumerable<LocalizedString> GetAllStrings(bool includeParentCultures) => Array.Empty<LocalizedString>();
}
public class SbRichTextEditorTests : BunitContext
{
public SbRichTextEditorTests()
{
Services.AddSingleton<IStringLocalizer<SufiBlazorResource>>(new StubStringLocalizer());
JSInterop.Mode = JSRuntimeMode.Loose;
}
private IRenderedComponent<SbRichTextEditor> RenderEditor(
Action<ComponentParameterCollectionBuilder<SbRichTextEditor>>? configure = null)
{
return Render<SbRichTextEditor>(p =>
{
configure?.Invoke(p);
});
}
[Fact]
public void RendersEditorStructure()
{
// Arrange & Act
var cut = RenderEditor();
// Assert
var container = cut.Find(".sb-editor");
Assert.NotNull(container);
Assert.NotNull(cut.Find(".sb-editor__content"));
}
[Fact]
public void RendersToolbarByDefault()
{
// Arrange & Act
var cut = RenderEditor();
// Assert
var toolbar = cut.Find(".sb-editor__toolbar");
Assert.NotNull(toolbar);
Assert.Equal("toolbar", toolbar.GetAttribute("role"));
Assert.NotNull(cut.FindAll(".sb-editor__toolbar-btn"));
}
[Fact]
public void HidesToolbarWhenHideToolbarTrue()
{
// Arrange & Act
var cut = RenderEditor(p => p.Add(x => x.HideToolbar, true));
// Assert
Assert.Empty(cut.FindAll(".sb-editor__toolbar"));
}
[Fact]
public void RendersEditorContentArea()
{
// Arrange & Act
var cut = RenderEditor();
// Assert
var content = cut.Find(".sb-editor__content");
Assert.NotNull(content);
Assert.Equal("textbox", content.GetAttribute("role"));
Assert.Equal("true", content.GetAttribute("aria-multiline"));
}
[Fact]
public void ShowsCharacterCountWhenEnabled()
{
// Arrange & Act
var cut = RenderEditor(p => p.Add(x => x.ShowCharacterCount, true));
// Assert
var footer = cut.Find(".sb-editor__footer");
Assert.NotNull(footer);
Assert.Contains("0 characters", cut.Markup);
}
[Fact]
public void ShowsWordCountWhenEnabled()
{
// Arrange & Act
var cut = RenderEditor(p => p.Add(x => x.ShowWordCount, true));
// Assert
var footer = cut.Find(".sb-editor__footer");
Assert.NotNull(footer);
Assert.Contains("0 words", cut.Markup);
}
[Fact]
public void DoesNotRenderFooterWhenCountsDisabled()
{
// Arrange & Act
var cut = RenderEditor();
// Assert
Assert.Empty(cut.FindAll(".sb-editor__footer"));
}
[Fact]
public void AppliesDisabledClassWhenDisabled()
{
// Arrange & Act
var cut = RenderEditor(p => p.Add(x => x.Disabled, true));
// Assert
var container = cut.Find(".sb-editor");
Assert.Contains("sb-editor--disabled", container.ClassList);
}
[Fact]
public void AppliesReadOnlyClassWhenReadOnly()
{
// Arrange & Act
var cut = RenderEditor(p => p.Add(x => x.ReadOnly, true));
// Assert
var container = cut.Find(".sb-editor");
Assert.Contains("sb-editor--readonly", container.ClassList);
}
[Fact]
public void AppliesRtlClassWhenRightToLeftTrue()
{
// Arrange & Act
var cut = RenderEditor(p => p.Add(x => x.RightToLeft, true));
// Assert
var container = cut.Find(".sb-editor");
Assert.Contains("sb-editor--rtl", container.ClassList);
}
[Fact]
public void SetsDirAttributeRtlWhenRightToLeftTrue()
{
// Arrange & Act
var cut = RenderEditor(p => p.Add(x => x.RightToLeft, true));
// Assert
var container = cut.Find(".sb-editor");
Assert.Equal("rtl", container.GetAttribute("dir"));
}
[Fact]
public void SetsDirAttributeLtrWhenRightToLeftFalse()
{
// Arrange & Act
var cut = RenderEditor(p => p.Add(x => x.RightToLeft, false));
// Assert
var container = cut.Find(".sb-editor");
Assert.Equal("ltr", container.GetAttribute("dir"));
}
[Fact]
public void AppliesClassParameter()
{
// Arrange & Act
var cut = RenderEditor(p => p.Add(x => x.Class, "my-editor"));
// Assert
var container = cut.Find(".sb-editor");
Assert.Contains("my-editor", container.ClassList);
}
[Fact]
public void AppliesHeightStyle()
{
// Arrange & Act
var cut = RenderEditor(p => p.Add(x => x.Height, "400px"));
// Assert
var container = cut.Find(".sb-editor");
var style = container.GetAttribute("style");
Assert.NotNull(style);
Assert.Contains("--sb-editor-height: 400px", style);
}
[Fact]
public void UsesPlaceholderInContentAriaLabel()
{
// Arrange & Act
var cut = RenderEditor(p => p.Add(x => x.Placeholder, "Type your content..."));
// Assert
var content = cut.Find(".sb-editor__content");
Assert.Equal("Type your content...", content.GetAttribute("aria-label"));
}
[Fact]
public void ToolbarHasAriaLabel()
{
// Arrange & Act
var cut = RenderEditor(p => p.Add(x => x.ToolbarAriaLabel, "Format text"));
// Assert
var toolbar = cut.Find(".sb-editor__toolbar");
Assert.Equal("Format text", toolbar.GetAttribute("aria-label"));
}
[Fact]
public void ContentHasAriaReadonlyWhenReadOnly()
{
// Arrange & Act
var cut = RenderEditor(p => p.Add(x => x.ReadOnly, true));
// Assert
var content = cut.Find(".sb-editor__content");
Assert.Equal("true", content.GetAttribute("aria-readonly"));
}
[Fact]
public void ContentHasAriaDisabledWhenDisabled()
{
// Arrange & Act
var cut = RenderEditor(p => p.Add(x => x.Disabled, true));
// Assert
var content = cut.Find(".sb-editor__content");
Assert.Equal("true", content.GetAttribute("aria-disabled"));
}
[Fact]
public void UsesCustomToolbarItemsWhenProvided()
{
// Arrange
var customItems = new List<SbEditorToolbarItem>
{
SbEditorToolbarItem.Bold,
SbEditorToolbarItem.Separator,
SbEditorToolbarItem.Italic
};
// Act
var cut = RenderEditor(p => p.Add(x => x.ToolbarItems, customItems));
// Assert - toolbar should have fewer buttons than default
var buttons = cut.FindAll(".sb-editor__toolbar-btn");
Assert.Equal(2, buttons.Count); // Bold and Italic
}
[Fact]
public void RendersLinkAndImageDialogs()
{
// Arrange & Act
var cut = RenderEditor();
// Assert - dialogs are in the DOM (closed by default)
Assert.NotNull(cut.FindComponent<SufiChain.SufiBlazor.Components.Overlays.SbDialog>());
}
[Fact]
public void UsesCustomWordCountFormat()
{
// Arrange & Act
var cut = RenderEditor(p => p
.Add(x => x.ShowWordCount, true)
.Add(x => x.WordCountFormat, "{0} mots"));
// Assert
Assert.Contains("0 mots", cut.Markup);
}
[Fact]
public void UsesCustomCharacterCountFormat()
{
// Arrange & Act
var cut = RenderEditor(p => p
.Add(x => x.ShowCharacterCount, true)
.Add(x => x.CharacterCountFormat, "{0} chars"));
// Assert
Assert.Contains("0 chars", cut.Markup);
}
}