File: NewUpAndBuildStandaloneTemplateTests.cs
Web Access
Project: src\tests\Aspire.Templates.Tests\Aspire.Templates.Tests.csproj (Aspire.Templates.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.Xml.Linq;
using Xunit;
 
namespace Aspire.Templates.Tests;
 
public abstract class NewUpAndBuildStandaloneTemplateTestsBase(ITestOutputHelper testOutput) : TemplateTestsBase(testOutput)
{
    protected async Task CanNewAndBuildActual(string templateName, string extraArgs, TestSdk sdk, TestTargetFramework tfm, string? error)
    {
        var id = GetNewProjectId(prefix: $"new_build_{templateName}_{tfm.ToTFMString()}");
 
        var buildEnvToUse = sdk switch
        {
            TestSdk.Net10 => BuildEnvironment.ForNet10SdkOnly,
            TestSdk.Net11 => BuildEnvironment.ForNet11SdkOnly,
            TestSdk.Net11WithAllSupportedRuntimes => BuildEnvironment.ForNet11SdkWithAllSupportedRuntimes,
            _ => throw new ArgumentOutOfRangeException(nameof(sdk))
        };
 
        try
        {
            await using var project = await AspireProject.CreateNewTemplateProjectAsync(
                id,
                templateName,
                _testOutput,
                buildEnvironment: buildEnvToUse,
                extraArgs: extraArgs,
                targetFramework: tfm);
 
            Assert.True(error is null, $"Expected to throw an exception with message: {error}");
 
            if (templateName == "aspire-starter")
            {
                await AssertStarterAspNetCoreTemplateContentAsync(project, tfm);
                if (!string.IsNullOrEmpty(extraArgs))
                {
                    AssertStarterTestFrameworkPackages(project.TestsProjectDirectory, extraArgs);
                }
            }
 
            await project.BuildAsync(extraBuildArgs: [$"-c Debug"]);
        }
        catch (ToolCommandException tce) when (error is not null)
        {
            Assert.NotNull(tce.Result);
            Assert.Contains(error, tce.Result.Value.Output);
        }
    }
 
    private static void AssertStarterTestFrameworkPackages(string testProjectDir, string extraArgs)
    {
        var projectPath = Directory.EnumerateFiles(testProjectDir, "*.csproj").Single();
        var project = XDocument.Load(projectPath);
        var packageReferences = project
            .Descendants("PackageReference")
            .Where(element => element.Attribute("Include")?.Value != "Aspire.Hosting.Testing")
            .Select(element => $"{element.Attribute("Include")?.Value}/{element.Attribute("Version")?.Value}")
            .OrderBy(packageReference => packageReference)
            .ToArray();
 
        string[] expectedPackageReferences = extraArgs switch
        {
            "--test-framework MSTest" =>
            [
                "MSTest/4.4.0",
            ],
            "--test-framework NUnit" =>
            [
                "Microsoft.NET.Test.Sdk/18.10.0",
                "NUnit/4.6.1",
                "NUnit.Analyzers/4.14.0",
                "NUnit3TestAdapter/6.3.0",
            ],
            "--test-framework xUnit.net --xunit-version v3mtp" =>
            [
                "xunit.v3/4.0.0",
            ],
            "--test-framework xUnit.net --xunit-version v3" =>
            [
                "coverlet.collector/10.0.1",
                "Microsoft.NET.Test.Sdk/18.10.0",
                "xunit.runner.visualstudio/4.0.0",
                "xunit.v3.mtp-off/4.0.0",
            ],
            "--test-framework xUnit.net" or "--test-framework xUnit.net --xunit-version v2" =>
            [
                "coverlet.collector/10.0.1",
                "Microsoft.NET.Test.Sdk/18.10.0",
                "xunit/2.9.3",
                "xunit.runner.visualstudio/4.0.0",
            ],
            _ => throw new InvalidOperationException($"Unexpected starter test arguments '{extraArgs}'."),
        };
 
        Assert.Equal(expectedPackageReferences.OrderBy(packageReference => packageReference), packageReferences);
 
        if (extraArgs is "--test-framework xUnit.net --xunit-version v3" or "--test-framework xUnit.net --xunit-version v3mtp")
        {
            Assert.Equal("Exe", project.Descendants("OutputType").Single().Value);
        }
    }
 
    private static async Task AssertStarterAspNetCoreTemplateContentAsync(AspireProject project, TestTargetFramework tfm)
    {
        var webProjectDirectory = Path.Combine(project.RootDir, $"{project.Id}.Web");
 
        var appContent = await File.ReadAllTextAsync(Path.Combine(webProjectDirectory, "Components", "App.razor"));
        Assert.Equal(tfm == TestTargetFramework.Net11, appContent.Contains("<BasePath />", StringComparison.Ordinal));
        Assert.Equal(tfm != TestTargetFramework.Net11, appContent.Contains("<base href=\"/\" />", StringComparison.Ordinal));
 
        var importsContent = await File.ReadAllTextAsync(Path.Combine(webProjectDirectory, "Components", "_Imports.razor"));
        Assert.Equal(tfm == TestTargetFramework.Net11, importsContent.Contains("@using Microsoft.AspNetCore.Components.Endpoints", StringComparison.Ordinal));
 
        var errorPageContent = await File.ReadAllTextAsync(Path.Combine(webProjectDirectory, "Components", "Pages", "Error.razor"));
        Assert.True(errorPageContent.Contains("[PersistentState]", StringComparison.Ordinal));
 
        var navMenuContent = await File.ReadAllTextAsync(Path.Combine(webProjectDirectory, "Components", "Layout", "NavMenu.razor"));
        const string expectedNavMenuScript = "<script type=\"module\" src=\"@Assets[\"Components/Layout/NavMenu.razor.js\"]\"></script>";
        Assert.Contains(expectedNavMenuScript, navMenuContent, StringComparison.Ordinal);
        Assert.Contains("id=\"nav-scrollable\"", navMenuContent, StringComparison.Ordinal);
        Assert.False(navMenuContent.Contains("onclick=", StringComparison.Ordinal));
        Assert.True(File.Exists(Path.Combine(webProjectDirectory, "Components", "Layout", "NavMenu.razor.js")));
    }
}
 
public class NewUpAndBuildStandaloneTemplateTests(ITestOutputHelper testOutput) : NewUpAndBuildStandaloneTemplateTestsBase(testOutput)
{
    [Theory]
    [MemberData(nameof(TestDataForNewAndBuildTemplateTests), arguments: ["aspire", ""])]
    [MemberData(nameof(TestDataForNewAndBuildTemplateTests), arguments: ["aspire-starter", ""])]
    [MemberData(nameof(TestDataForNewAndBuildTemplateTests), arguments: ["aspire-ts-cs-starter", ""])]
    [Trait("category", "basic-build")]
    public Task CanNewAndBuild(string templateName, string extraArgs, TestSdk sdk, TestTargetFramework tfm, string? error)
    {
        return CanNewAndBuildActual(templateName, extraArgs, sdk, tfm, error);
    }
}