File: Builder\RazorComponentsEndpointConventionBuilderExtensionsTest.cs
Web Access
Project: src\src\Components\Endpoints\test\Microsoft.AspNetCore.Components.Endpoints.Tests.csproj (Microsoft.AspNetCore.Components.Endpoints.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.Diagnostics;
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Discovery;
using Microsoft.AspNetCore.Components.Endpoints;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Routing;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.FileProviders;
 
namespace Microsoft.AspNetCore.Builder;
 
public class RazorComponentsEndpointConventionBuilderExtensionsTest
{
    [Fact]
    public void WithStaticAssets_DoesNotAddResourceCollection_ToEndpoints_NoStaticAssetsMapped()
    {
        // Arrange
        var endpointBuilder = new TestEndpointRouteBuilder();
        var builder = CreateRazorComponentsAppBuilder(endpointBuilder);
 
        // Act
        builder.WithStaticAssets();
 
        // Assert
        Assert.All(endpointBuilder.DataSources.First().Endpoints, e =>
        {
            if (e.Metadata.GetMetadata<ComponentTypeMetadata>() == null)
            {
                return;
            }
 
            var metadata = e.Metadata.GetMetadata<ResourceAssetCollection>();
            Assert.Null(metadata);
        });
    }
 
    [Fact]
    public void WithStaticAssets_DoesNotAddResourceCollection_ToEndpoints_NoMatchingStaticAssetsMapped()
    {
        // Arrange
        var endpointBuilder = new TestEndpointRouteBuilder();
        endpointBuilder.MapStaticAssets("TestManifests/Test.staticwebassets.endpoints.json");
        var builder = CreateRazorComponentsAppBuilder(endpointBuilder);
 
        // Act
        builder.WithStaticAssets();
 
        // Assert
        Assert.All(endpointBuilder.DataSources.Skip(1).First().Endpoints, e =>
        {
            var metadata = e.Metadata.GetMetadata<ResourceAssetCollection>();
            Assert.Null(metadata);
        });
    }
 
    [Fact]
    public void WithStaticAssets_AddsResourceCollection_ToEndpoints_NamedManifest()
    {
        // Arrange
        var endpointBuilder = new TestEndpointRouteBuilder();
        endpointBuilder.MapStaticAssets("TestManifests/Test.staticwebassets.endpoints.json");
        var builder = CreateRazorComponentsAppBuilder(endpointBuilder);
 
        // Act
        builder.WithStaticAssets("TestManifests/Test.staticwebassets.endpoints.json");
 
        // Assert
        Assert.All(endpointBuilder.DataSources.Skip(1).First().Endpoints, e =>
        {
            var metadata = e.Metadata.GetMetadata<ResourceAssetCollection>();
            Assert.NotNull(metadata);
            var list = Assert.IsAssignableFrom<IReadOnlyList<ResourceAsset>>(metadata);
            Assert.Single(list);
            Assert.Equal("named.css", list[0].Url);
        });
    }
 
    [Fact]
    public void WithStaticAssets_AddsDefaultResourceCollection_ToEndpoints_ByDefault()
    {
        // Arrange
        var endpointBuilder = new TestEndpointRouteBuilder();
        endpointBuilder.MapStaticAssets();
 
        // Act
        var builder = CreateRazorComponentsAppBuilder(endpointBuilder);
 
        // Assert
        Assert.All(endpointBuilder.DataSources.Skip(1).First().Endpoints, e =>
        {
            var metadata = e.Metadata.GetMetadata<ResourceAssetCollection>();
            Assert.NotNull(metadata);
            var list = Assert.IsAssignableFrom<IReadOnlyList<ResourceAsset>>(metadata);
            Assert.Single(list);
            Assert.Equal("default.css", list[0].Url);
        });
    }
 
    [Fact]
    public void WithStaticAssets_AddsResourceCollection_ToEndpoints_DefaultManifest()
    {
        // Arrange
        var endpointBuilder = new TestEndpointRouteBuilder();
        endpointBuilder.MapStaticAssets();
        var builder = CreateRazorComponentsAppBuilder(endpointBuilder);
 
        // Act
        builder.WithStaticAssets();
 
        // Assert
        Assert.All(endpointBuilder.DataSources.Skip(1).First().Endpoints, e =>
        {
            var metadata = e.Metadata.GetMetadata<ResourceAssetCollection>();
            Assert.NotNull(metadata);
            var list = Assert.IsAssignableFrom<IReadOnlyList<ResourceAsset>>(metadata);
            Assert.Single(list);
            Assert.Equal("default.css", list[0].Url);
        });
    }
 
    [Fact]
    public void WithStaticAssets_AddsDefaultResourceCollectionToEndpoints_WhenNoManifestProvided_EvenIfManyAvailable()
    {
        // Arrange
        var endpointBuilder = new TestEndpointRouteBuilder();
        endpointBuilder.MapStaticAssets();
        endpointBuilder.MapStaticAssets("TestManifests/Test.staticwebassets.endpoints.json");
 
        // Act
        var builder = CreateRazorComponentsAppBuilder(endpointBuilder);
 
        // Assert
        Assert.All(endpointBuilder.DataSources.Skip(2).First().Endpoints, e =>
        {
            var metadata = e.Metadata.GetMetadata<ResourceAssetCollection>();
            Assert.NotNull(metadata);
            var list = Assert.IsAssignableFrom<IReadOnlyList<ResourceAsset>>(metadata);
            Assert.Single(list);
            Assert.Equal("default.css", list[0].Url);
        });
    }
 
    [Fact]
    public void WithStaticAssets_AddsMatchingResourceCollectionToEndpoints_WhenExplicitManifestProvided_EvenIfManyAvailable()
    {
        // Arrange
        var endpointBuilder = new TestEndpointRouteBuilder();
        endpointBuilder.MapStaticAssets();
        endpointBuilder.MapStaticAssets("TestManifests/Test.staticwebassets.endpoints.json");
        var builder = CreateRazorComponentsAppBuilder(endpointBuilder);
 
        // Act
        builder.WithStaticAssets("TestManifests/Test.staticwebassets.endpoints.json");
 
        // Assert
        Assert.All(endpointBuilder.DataSources.Skip(2).First().Endpoints, e =>
        {
            var metadata = e.Metadata.GetMetadata<ResourceAssetCollection>();
            Assert.NotNull(metadata);
            var list = Assert.IsAssignableFrom<IReadOnlyList<ResourceAsset>>(metadata);
            Assert.Single(list);
            Assert.Equal("named.css", list[0].Url);
        });
    }
 
    [Fact]
    public void WithStaticAssets_AddsCollectionFromGroup_WhenMappedInsideAnEndpointGroup()
    {
        // Arrange
        var endpointBuilder = new TestEndpointRouteBuilder();
        endpointBuilder.MapStaticAssets();
 
        var group = endpointBuilder.MapGroup("/group");
        group.MapStaticAssets("TestManifests/Test.staticwebassets.endpoints.json");
        var builder = CreateRazorComponentsAppBuilder(group);
 
        // Act
        builder.WithStaticAssets("TestManifests/Test.staticwebassets.endpoints.json");
 
        // Assert
        var groupEndpoints = Assert.IsAssignableFrom<IEndpointRouteBuilder>(group).DataSources;
        Assert.All(groupEndpoints.Skip(1).First().Endpoints, e =>
        {
            var metadata = e.Metadata.GetMetadata<ResourceAssetCollection>();
            Assert.NotNull(metadata);
            var list = Assert.IsAssignableFrom<IReadOnlyList<ResourceAsset>>(metadata);
            Assert.Single(list);
            Assert.Equal("named.css", list[0].Url);
        });
    }
 
    [Fact]
    public void WithStaticAssets_DoesNotAddResourceCollectionFromGroup_WhenMappingNotFound_InsideGroup()
    {
        // Arrange
        var endpointBuilder = new TestEndpointRouteBuilder();
        endpointBuilder.MapStaticAssets();
 
        var group = endpointBuilder.MapGroup("/group");
        group.MapStaticAssets("TestManifests/Test.staticwebassets.endpoints.json");
        var builder = CreateRazorComponentsAppBuilder(group);
 
        // Act
        builder.WithStaticAssets();
 
        // Assert
        var groupEndpoints = Assert.IsAssignableFrom<IEndpointRouteBuilder>(group).DataSources;
        Assert.All(groupEndpoints.Skip(1).First().Endpoints, e =>
        {
            var metadata = e.Metadata.GetMetadata<ResourceAssetCollection>();
            Assert.Null(metadata);
        });
    }
 
    [Theory]
    [InlineData("/_framework/blazor.web.js")]
    [InlineData("/_framework/opaque-redirect")]
    public void MapRazorComponents_CanAddConventions_ToBlazorWebEndpoints(string frameworkEndpoint)
    {
        // Arrange
        var endpointBuilder = new TestEndpointRouteBuilder();
        // Act
        var builder = CreateRazorComponentsAppBuilder(endpointBuilder);
        var obj = new object();
        builder.Add(e =>
        {
            if (e is RouteEndpointBuilder rb)
            {
                if (rb.RoutePattern.RawText == frameworkEndpoint)
                {
                    rb.Metadata.Add(obj);
                }
            }
        });
 
        // Assert
        var endpoints = endpointBuilder.DataSources.Single().Endpoints;
        var webJSEndpoint = Assert.Single(endpoints, e => e.Metadata.Contains(obj));
        Assert.Equal(frameworkEndpoint, ((RouteEndpoint)webJSEndpoint).RoutePattern.RawText);
    }
 
    private RazorComponentsEndpointConventionBuilder CreateRazorComponentsAppBuilder(IEndpointRouteBuilder endpointBuilder)
    {
        var builder = endpointBuilder.MapRazorComponents<App>();
        builder.ApplicationBuilder.AddLibrary(new AssemblyComponentLibraryDescriptor(
            "App",
            [new PageComponentBuilder {
                PageType = typeof(App),
                RouteTemplates = ["/"],
                AssemblyName = "App",
            }],
            []
        ));
        return builder;
    }
 
    private class TestEndpointRouteBuilder : IEndpointRouteBuilder
    {
        private readonly ApplicationBuilder _applicationBuilder;
 
        public TestEndpointRouteBuilder()
        {
            _applicationBuilder = new ApplicationBuilder(ServiceProvider);
        }
 
        public IServiceProvider ServiceProvider { get; } = CreateServiceProvider();
 
        private static IServiceProvider CreateServiceProvider()
        {
            var collection = new ServiceCollection();
            collection.AddSingleton<IConfiguration>(new ConfigurationBuilder().Build());
            collection.AddSingleton<IWebHostEnvironment>(new TestWebHostEnvironment());
            collection.AddRazorComponents();
            return collection.BuildServiceProvider();
        }
 
        public ICollection<EndpointDataSource> DataSources { get; } = [];
 
        public IApplicationBuilder CreateApplicationBuilder()
        {
            return _applicationBuilder.New();
        }
 
        private class TestWebHostEnvironment : IWebHostEnvironment
        {
            public string ApplicationName { get; set; } = "TestApplication";
            public string EnvironmentName { get; set; } = "TestEnvironment";
            public string WebRootPath { get; set; } = "";
            public IFileProvider WebRootFileProvider { get => ContentRootFileProvider; set { } }
            public string ContentRootPath { get; set; } = Directory.GetCurrentDirectory();
            public IFileProvider ContentRootFileProvider { get; set; } = CreateTestFileProvider();
 
            private static TestFileProvider CreateTestFileProvider()
            {
                var provider = new TestFileProvider();
                provider.AddFile("site.css", "body { color: red; }");
                return provider;
            }
        }
 
        private class TestDiagnosticSource : DiagnosticSource
        {
            public override bool IsEnabled(string name)
            {
                return false;
            }
 
            public override void Write(string name, object value) { }
        }
    }
 
    private class App : IComponent
    {
        void IComponent.Attach(RenderHandle renderHandle) => throw new NotImplementedException();
        Task IComponent.SetParametersAsync(ParameterView parameters) => throw new NotImplementedException();
    }
}