File: Controls\TextVisualizerDialogTests.cs
Web Access
Project: src\tests\Aspire.Dashboard.Components.Tests\Aspire.Dashboard.Components.Tests.csproj (Aspire.Dashboard.Components.Tests)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
using System.Collections.Immutable;
using Aspire.Dashboard.Components.Dialogs;
using Aspire.Dashboard.Components.Tests.Shared;
using Aspire.Dashboard.Model;
using Bunit;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.FluentUI.AspNetCore.Components;
using Xunit;
 
namespace Aspire.Dashboard.Components.Tests.Controls;
 
public class TextVisualizerDialogTests : TestContext
{
    [Fact]
    public async Task Render_TextVisualizerDialog_WithValidJson_FormatsJsonAsync()
    {
        var rawJson = """
                      // line comment
                      [
                          /* block comment */
                          1,
                          { "test": {    "nested": "value" } }
                      ]
                      """// line comment
                      [
                          /* block comment */
                          1,
                          { "test": {    "nested": "value" } }
                      ]
                      """;
 
        var expectedJson = """
                           /* line comment*/
                           [
                             /* block comment */
                             1,
                             {
                               "test": {
                                 "nested": "value"
                               }
                             }
                           ]
                           """/* line comment*/
                           [
                             /* block comment */
                             1,
                             {
                               "test": {
                                 "nested": "value"
                               }
                             }
                           ]
                           """;
 
        var cut = SetUpDialog(out var dialogService);
        await dialogService.ShowDialogAsync<TextVisualizerDialog>(new TextVisualizerDialogViewModel(rawJson, string.Empty), []);
 
        var instance = cut.FindComponent<TextVisualizerDialog>().Instance;
 
        Assert.Equal(expectedJson, instance.FormattedText);
        Assert.Equal(TextVisualizerDialog.JsonFormat, instance.FormatKind);
        Assert.Equal([TextVisualizerDialog.JsonFormat, TextVisualizerDialog.PlaintextFormat], instance.EnabledOptions.ToImmutableSortedSet());
    }
 
    [Fact]
    public async Task Render_TextVisualizerDialog_WithValidXml_FormatsXml_CanChangeFormatAsync()
    {
        const string rawXml = """<parent><child>text<!-- comment --></child></parent>""";
        const string expectedXml =
            """
            <?xml version="1.0" encoding="utf-16"?>
            <parent>
              <child>text<!-- comment --></child>
            </parent>
            """;
 
        var cut = SetUpDialog(out var dialogService);
        await dialogService.ShowDialogAsync<TextVisualizerDialog>(new TextVisualizerDialogViewModel(rawXml, string.Empty), []);
 
        var instance = cut.FindComponent<TextVisualizerDialog>().Instance;
 
        Assert.Equal(TextVisualizerDialog.XmlFormat, instance.FormatKind);
        Assert.Equal(expectedXml, instance.FormattedText);
        Assert.Equal([TextVisualizerDialog.PlaintextFormat, TextVisualizerDialog.XmlFormat], instance.EnabledOptions.ToImmutableSortedSet());
 
        // changing format works
        instance.ChangeFormat(TextVisualizerDialog.PlaintextFormat, rawXml);
 
        Assert.Equal(TextVisualizerDialog.PlaintextFormat, instance.FormatKind);
        Assert.Equal(rawXml, instance.FormattedText);
    }
 
    [Fact]
    public async Task Render_TextVisualizerDialog_WithValidXml_FormatsXmlWithDoctypeAsync()
    {
        const string rawXml = """<?xml version="1.0" encoding="utf-16"?><test>text content</test>""";
        const string expectedXml =
            """
            <?xml version="1.0" encoding="utf-16"?>
            <test>text content</test>
            """;
 
        var cut = SetUpDialog(out var dialogService);
        await dialogService.ShowDialogAsync<TextVisualizerDialog>(new TextVisualizerDialogViewModel(rawXml, string.Empty), []);
 
        var instance = cut.FindComponent<TextVisualizerDialog>().Instance;
 
        Assert.Equal(TextVisualizerDialog.XmlFormat, instance.FormatKind);
        Assert.Equal(expectedXml, instance.FormattedText);
        Assert.Equal([TextVisualizerDialog.PlaintextFormat, TextVisualizerDialog.XmlFormat], instance.EnabledOptions.ToImmutableSortedSet());
    }
 
    [Fact]
    public async Task Render_TextVisualizerDialog_WithInvalidJson_FormatsPlaintextAsync()
    {
        const string rawText = """{{{{{{"test": 4}""";
 
        var cut = SetUpDialog(out var dialogService);
        await dialogService.ShowDialogAsync<TextVisualizerDialog>(new TextVisualizerDialogViewModel(rawText, string.Empty), []);
 
        var instance = cut.FindComponent<TextVisualizerDialog>().Instance;
 
        Assert.Equal(TextVisualizerDialog.PlaintextFormat, instance.FormatKind);
        Assert.Equal(rawText, instance.FormattedText);
        Assert.Equal([TextVisualizerDialog.PlaintextFormat], instance.EnabledOptions.ToImmutableSortedSet());
    }
 
    [Fact]
    public async Task Render_TextVisualizerDialog_WithDifferentThemes_LineClassesChange()
    {
        var xml = @"<hello><!-- world --></hello>";
        var themeManager = new ThemeManager(new TestThemeResolver { EffectiveTheme = "Light" });
        var cut = SetUpDialog(out var dialogService, themeManager: themeManager);
        themeManager.EffectiveTheme = "Light";
        await dialogService.ShowDialogAsync<TextVisualizerDialog>(new TextVisualizerDialogViewModel(xml, string.Empty), []);
 
        Assert.NotEmpty(cut.FindAll(".theme-a11y-light-min"));
 
        themeManager.EffectiveTheme = "Dark";
        var instance = cut.FindComponent<TextVisualizerDialog>();
        instance.Render();
 
        Assert.NotEmpty(cut.FindAll(".theme-a11y-dark-min"));
    }
 
    [Fact]
    public async Task Render_TextVisualizerDialog_ResolveTheme_LineClassesChange()
    {
        var xml = @"<hello><!-- world --></hello>";
 
        var cut = SetUpDialog(out var dialogService);
        await dialogService.ShowDialogAsync<TextVisualizerDialog>(new TextVisualizerDialogViewModel(xml, string.Empty), []);
 
        Assert.NotEmpty(cut.FindAll(".theme-a11y-dark-min"));
    }
 
    private IRenderedFragment SetUpDialog(out IDialogService dialogService, ThemeManager? themeManager = null)
    {
        themeManager ??= new ThemeManager(new TestThemeResolver());
 
        Services.AddFluentUIComponents();
        Services.AddSingleton(themeManager);
        Services.AddSingleton<LibraryConfiguration>();
        Services.AddLocalization();
        var module = JSInterop.SetupModule("/Components/Dialogs/TextVisualizerDialog.razor.js");
        module.SetupVoid();
 
        var cut = Render(builder =>
        {
            builder.OpenComponent<FluentDialogProvider>(0);
            builder.CloseComponent();
        });
 
        // Setting a provider ID on menu service is required to simulate <FluentMenuProvider> on the page.
        // This makes FluentMenu render without error.
        var menuService = Services.GetRequiredService<IMenuService>();
        menuService.ProviderId = "Test";
 
        dialogService = Services.GetRequiredService<IDialogService>();
        return cut;
    }
}