diff --git a/.config/dotnet-tools.json b/.config/dotnet-tools.json
new file mode 100644
index 0000000000..be95a01fc5
--- /dev/null
+++ b/.config/dotnet-tools.json
@@ -0,0 +1,12 @@
+{
+ "version": 1,
+ "isRoot": true,
+ "tools": {
+ "dotnet-serve": {
+ "version": "1.5.0",
+ "commands": [
+ "dotnet-serve"
+ ]
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Components/Blazor/Build/src/targets/All.props b/src/Components/Blazor/Build/src/targets/All.props
index 690a29fbab..d1d242f4d9 100644
--- a/src/Components/Blazor/Build/src/targets/All.props
+++ b/src/Components/Blazor/Build/src/targets/All.props
@@ -4,12 +4,6 @@
$(DefaultWebContentItemExcludes);wwwroot\**
-
- true
-
-
- true
-
true
diff --git a/src/Components/Blazor/Build/src/targets/All.targets b/src/Components/Blazor/Build/src/targets/All.targets
index 6aa60e8227..6c69e85a40 100644
--- a/src/Components/Blazor/Build/src/targets/All.targets
+++ b/src/Components/Blazor/Build/src/targets/All.targets
@@ -13,6 +13,9 @@
true
+
+
+ true
diff --git a/src/ProjectTemplates/test/BlazorWasmTemplateTest.cs b/src/ProjectTemplates/test/BlazorWasmTemplateTest.cs
index 0211862919..0a6ea40f83 100644
--- a/src/ProjectTemplates/test/BlazorWasmTemplateTest.cs
+++ b/src/ProjectTemplates/test/BlazorWasmTemplateTest.cs
@@ -6,7 +6,7 @@ using System.Net;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.E2ETesting;
-using Microsoft.AspNetCore.Testing;
+using Microsoft.Extensions.CommandLineUtils;
using OpenQA.Selenium;
using Templates.Test.Helpers;
using Xunit;
@@ -28,11 +28,11 @@ namespace Templates.Test
public async Task BlazorWasmStandaloneTemplate_Works()
{
var project = await ProjectFactory.GetOrCreateProject("blazorstandalone", Output);
+ project.TargetFramework = "netstandard2.1";
var createResult = await project.RunDotNetNewAsync("blazorwasm");
Assert.True(0 == createResult.ExitCode, ErrorMessages.GetFailedProcessMessage("create/restore", project, createResult));
- // We can't run a published standalone app, but let's just make sure it publishes fine
var publishResult = await project.RunDotNetPublishAsync();
Assert.True(0 == publishResult.ExitCode, ErrorMessages.GetFailedProcessMessage("publish", project, publishResult));
@@ -40,6 +40,18 @@ namespace Templates.Test
Assert.True(0 == buildResult.ExitCode, ErrorMessages.GetFailedProcessMessage("build", project, buildResult));
await BuildAndRunTest(project.ProjectName, project);
+
+ var publishDir = Path.Combine(project.TemplatePublishDir, project.ProjectName, "dist");
+ AspNetProcess.EnsureDevelopmentCertificates();
+
+ Output.WriteLine("Running dotnet serve on published output...");
+ using var serveProcess = ProcessEx.Run(Output, publishDir, DotNetMuxer.MuxerPathOrDefault(), "serve -S");
+
+ // Todo: Use dynamic port assignment: https://github.com/natemcmaster/dotnet-serve/pull/40/files
+ var listeningUri = "https://localhost:8080";
+ Output.WriteLine($"Opening browser at {listeningUri}...");
+ Browser.Navigate().GoToUrl(listeningUri);
+ TestBasicNavigation(project.ProjectName);
}
[Fact]
@@ -70,7 +82,7 @@ namespace Templates.Test
if (BrowserFixture.IsHostAutomationSupported())
{
aspNetProcess.VisitInBrowser(Browser);
- TestBasicNavigation(project.ProjectName, serverProject);
+ TestBasicNavigation(project.ProjectName);
}
else
{
@@ -90,7 +102,7 @@ namespace Templates.Test
if (BrowserFixture.IsHostAutomationSupported())
{
aspNetProcess.VisitInBrowser(Browser);
- TestBasicNavigation(appName, project);
+ TestBasicNavigation(appName);
}
else
{
@@ -98,7 +110,7 @@ namespace Templates.Test
}
}
- private void TestBasicNavigation(string appName, Project project)
+ private void TestBasicNavigation(string appName)
{
// Give components.server enough time to load so that it can replace
// the prerendered content before we start making assertions.
diff --git a/src/ProjectTemplates/test/Helpers/AspNetProcess.cs b/src/ProjectTemplates/test/Helpers/AspNetProcess.cs
index c4415bf55f..753eb1258a 100644
--- a/src/ProjectTemplates/test/Helpers/AspNetProcess.cs
+++ b/src/ProjectTemplates/test/Helpers/AspNetProcess.cs
@@ -51,8 +51,7 @@ namespace Templates.Test.Helpers
Timeout = TimeSpan.FromMinutes(2)
};
- var now = DateTimeOffset.Now;
- new CertificateManager().EnsureAspNetCoreHttpsDevelopmentCertificate(now, now.AddYears(1));
+ EnsureDevelopmentCertificates();
output.WriteLine("Running ASP.NET application...");
@@ -64,6 +63,12 @@ namespace Templates.Test.Helpers
}
}
+ internal static void EnsureDevelopmentCertificates()
+ {
+ var now = DateTimeOffset.Now;
+ new CertificateManager().EnsureAspNetCoreHttpsDevelopmentCertificate(now, now.AddYears(1));
+ }
+
public void VisitInBrowser(IWebDriver driver)
{
_output.WriteLine($"Opening browser at {ListeningUri}...");
diff --git a/src/ProjectTemplates/test/Helpers/Project.cs b/src/ProjectTemplates/test/Helpers/Project.cs
index ad5cbfe95c..33e50d2091 100644
--- a/src/ProjectTemplates/test/Helpers/Project.cs
+++ b/src/ProjectTemplates/test/Helpers/Project.cs
@@ -21,13 +21,10 @@ namespace Templates.Test.Helpers
{
private const string _urls = "http://127.0.0.1:0;https://127.0.0.1:0";
- public const string DefaultFramework = "netcoreapp5.0";
-
public static bool IsCIEnvironment => typeof(Project).Assembly.GetCustomAttributes()
.Any(a => a.Key == "ContinuousIntegrationBuild");
- public static string ArtifactsLogDir => typeof(Project).Assembly.GetCustomAttributes()
- .Single(a => a.Key == "ArtifactsLogDir")?.Value;
+ public static string ArtifactsLogDir => GetAssemblyMetadata("ArtifactsLogDir");
public SemaphoreSlim DotNetNewLock { get; set; }
public SemaphoreSlim NodeLock { get; set; }
@@ -35,14 +32,16 @@ namespace Templates.Test.Helpers
public string ProjectArguments { get; set; }
public string ProjectGuid { get; set; }
public string TemplateOutputDir { get; set; }
- public string TemplateBuildDir => Path.Combine(TemplateOutputDir, "bin", "Debug", DefaultFramework);
- public string TemplatePublishDir => Path.Combine(TemplateOutputDir, "bin", "Release", DefaultFramework, "publish");
+ public string TargetFramework { get; set; } = GetAssemblyMetadata("Test.DefaultTargetFramework");
+
+ public string TemplateBuildDir => Path.Combine(TemplateOutputDir, "bin", "Debug", TargetFramework);
+ public string TemplatePublishDir => Path.Combine(TemplateOutputDir, "bin", "Release", TargetFramework, "publish");
private string TemplateServerDir => Path.Combine(TemplateOutputDir, $"{ProjectName}.Server");
private string TemplateClientDir => Path.Combine(TemplateOutputDir, $"{ProjectName}.Client");
- public string TemplateClientDebugDir => Path.Combine(TemplateClientDir, "bin", "Debug", DefaultFramework);
- public string TemplateClientReleaseDir => Path.Combine(TemplateClientDir, "bin", "Release", DefaultFramework, "publish");
- public string TemplateServerReleaseDir => Path.Combine(TemplateServerDir, "bin", "Release", DefaultFramework, "publish");
+ public string TemplateClientDebugDir => Path.Combine(TemplateClientDir, "bin", "Debug", TargetFramework);
+ public string TemplateClientReleaseDir => Path.Combine(TemplateClientDir, "bin", "Release", TargetFramework, "publish");
+ public string TemplateServerReleaseDir => Path.Combine(TemplateServerDir, "bin", "Release", TargetFramework, "publish");
public ITestOutputHelper Output { get; set; }
public IMessageSink DiagnosticsMessageSink { get; set; }
@@ -110,7 +109,7 @@ namespace Templates.Test.Helpers
}
}
- internal async Task RunDotNetPublishAsync(bool takeNodeLock = false, IDictionary packageOptions = null, string additionalArgs = null)
+ internal async Task RunDotNetPublishAsync(bool takeNodeLock = false, IDictionary packageOptions = null, string additionalArgs = null)
{
Output.WriteLine("Publishing ASP.NET application...");
@@ -132,7 +131,7 @@ namespace Templates.Test.Helpers
}
}
- internal async Task RunDotNetBuildAsync(bool takeNodeLock = false, IDictionary packageOptions = null, string additionalArgs = null)
+ internal async Task RunDotNetBuildAsync(bool takeNodeLock = false, IDictionary packageOptions = null, string additionalArgs = null)
{
Output.WriteLine("Building ASP.NET application...");
@@ -524,5 +523,18 @@ namespace Templates.Test.Helpers
}
public override string ToString() => $"{ProjectName}: {TemplateOutputDir}";
+
+ private static string GetAssemblyMetadata(string key)
+ {
+ var attribute = typeof(Project).Assembly.GetCustomAttributes()
+ .FirstOrDefault(a => a.Key == key);
+
+ if (attribute is null)
+ {
+ throw new ArgumentException($"AssemblyMetadataAttribute with key {key} was not found.");
+ }
+
+ return attribute.Value;
+ }
}
}
diff --git a/src/ProjectTemplates/test/ProjectTemplates.Tests.csproj b/src/ProjectTemplates/test/ProjectTemplates.Tests.csproj
index c3a9be00fb..83222ec7aa 100644
--- a/src/ProjectTemplates/test/ProjectTemplates.Tests.csproj
+++ b/src/ProjectTemplates/test/ProjectTemplates.Tests.csproj
@@ -58,6 +58,10 @@
<_Parameter1>TestPackageRestorePath
<_Parameter2>$(TestPackageRestorePath)
+
+ <_Parameter1>Test.DefaultTargetFramework
+ <_Parameter2>$(DefaultNetCoreTargetFramework)
+
<_Parameter1>ContinuousIntegrationBuild
<_Parameter2>true