Build fewer things in blazor-wasm (#17533)

This commit is contained in:
Pranav K 2019-12-03 13:47:33 -08:00 committed by GitHub
parent 40a0173e9d
commit 76ae0a2e21
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 7 additions and 1962 deletions

View File

@ -69,26 +69,11 @@ variables:
# used for post-build phases, internal builds only
- ${{ if and(ne(variables['System.TeamProject'], 'public'), notin(variables['Build.Reason'], 'PullRequest')) }}:
- group: DotNet-AspNet-SDLValidation-Params
stages:
- stage: build
displayName: Build
jobs:
# Code check
- template: jobs/default-build.yml
parameters:
jobName: Code_check
jobDisplayName: Code check
agentOs: Windows
steps:
- powershell: ./eng/scripts/CodeCheck.ps1 -ci
displayName: Run eng/scripts/CodeCheck.ps1
artifacts:
- name: Code_Check_Logs
path: artifacts/log/
publishOnError: true
includeForks: true
# Build Windows (x64/x86)
- template: jobs/default-build.yml
parameters:
@ -114,34 +99,11 @@ stages:
-arch x64
-pack
-all
-buildNative
-NoBuildNative
/bl:artifacts/log/build.x64.binlog
$(_BuildArgs)
displayName: Build x64
# Build the x86 shared framework
# TODO: make it possible to build for one Windows architecture at a time
# This is going to actually build x86 native assets. See https://github.com/aspnet/AspNetCore/issues/7196
- script: ./build.cmd
-ci
-arch x86
-pack
-all
-buildNative
-noBuildJava
/p:OnlyPackPlatformSpecificPackages=true
/bl:artifacts/log/build.x86.binlog
$(_BuildArgs)
displayName: Build x86
# This is in a separate build step with -forceCoreMsbuild to workaround MAX_PATH limitations - https://github.com/Microsoft/msbuild/issues/53
- script: .\src\SiteExtensions\build.cmd
-ci
-pack
-noBuildDeps
$(_BuildArgs)
displayName: Build SiteExtension
# This runs code-signing on all packages, zips, and jar files as defined in build/CodeSign.targets. If https://github.com/dotnet/arcade/issues/1957 is resolved,
# consider running code-signing inline with the other previous steps.
# Sign check is disabled because it is run in a separate step below, after installers are built.
@ -155,29 +117,6 @@ stages:
$(_BuildArgs)
displayName: Code sign packages
# Windows installers bundle both x86 and x64 assets
- script: ./build.cmd
-ci
-sign
-buildInstallers
/bl:artifacts/log/installers.msbuild.binlog
/p:DotNetSignType=$(_SignType)
/p:AssetManifestFileName=aspnetcore-win-x64-x86.xml
$(_BuildArgs)
$(_PublishArgs)
/p:PublishInstallerBaseVersion=true
displayName: Build Installers
# A few files must also go to the VS package feed.
- ${{ if and(ne(variables['System.TeamProject'], 'public'), notin(variables['Build.Reason'], 'PullRequest')) }}:
- task: NuGetCommand@2
displayName: Push Visual Studio packages
inputs:
command: push
packagesToPush: 'artifacts/packages/**/VS.Redist.Common.AspNetCore.*.nupkg'
nuGetFeedType: external
publishFeedCredentials: 'DevDiv - VS package feed'
artifacts:
- name: Windows_Logs
path: artifacts/log/
@ -186,251 +125,6 @@ stages:
- name: Windows_Packages
path: artifacts/packages/
# Build Windows ARM
- template: jobs/default-build.yml
parameters:
codeSign: true
jobName: Windows_arm_build
jobDisplayName: "Build: Windows ARM"
agentOs: Windows
buildArgs:
-arch arm
-sign
-pack
-noBuildNodeJS
-noBuildJava
/bl:artifacts/log/build.win-arm.binlog
/p:DotNetSignType=$(_SignType)
/p:OnlyPackPlatformSpecificPackages=true
/p:AssetManifestFileName=aspnetcore-win-arm.xml
$(_BuildArgs)
$(_PublishArgs)
installNodeJs: false
installJdk: false
artifacts:
- name: Windows_arm_Logs
path: artifacts/log/
publishOnError: true
includeForks: true
- name: Windows_arm_Packages
path: artifacts/packages/
# Build MacOS
- template: jobs/default-build.yml
parameters:
jobName: MacOs_x64_build
jobDisplayName: "Build: macOS"
agentOs: macOs
buildArgs:
--pack
--all
--no-build-nodejs
--no-build-java
-p:OnlyPackPlatformSpecificPackages=true
-bl:artifacts/log/build.macos.binlog
-p:AssetManifestFileName=aspnetcore-MacOS_x64.xml
$(_BuildArgs)
$(_PublishArgs)
installNodeJs: false
installJdk: false
artifacts:
- name: MacOS_x64_Logs
path: artifacts/log/
publishOnError: true
includeForks: true
- name: MacOS_x64_Packages
path: artifacts/packages/
- template: jobs/codesign-xplat.yml
parameters:
inputName: MacOS_x64
# Build Linux x64
- template: jobs/default-build.yml
parameters:
jobName: Linux_x64_build
jobDisplayName: "Build: Linux x64"
agentOs: Linux
steps:
- script: ./build.sh
--ci
--arch x64
--pack
--all
--no-build-nodejs
--no-build-java
-p:OnlyPackPlatformSpecificPackages=true
-bl:artifacts/log/build.linux-x64.binlog
$(_BuildArgs)
displayName: Run build.sh
- script: |
git clean -xfd src/**/obj/
./dockerbuild.sh bionic \
--ci \
--arch x64 \
--build-installers \
--no-build-deps \
--no-build-nodejs \
-p:OnlyPackPlatformSpecificPackages=true \
-p:BuildRuntimeArchive=false \
-p:LinuxInstallerType=deb \
-bl:artifacts/log/build.deb.binlog \
$(_BuildArgs)
displayName: Build Debian installers
- script: |
git clean -xfd src/**/obj/
./dockerbuild.sh rhel \
--ci \
--arch x64 \
--build-installers \
--no-build-deps \
--no-build-nodejs \
-p:OnlyPackPlatformSpecificPackages=true \
-p:BuildRuntimeArchive=false \
-p:LinuxInstallerType=rpm \
-bl:artifacts/log/build.rpm.binlog \
-p:AssetManifestFileName=aspnetcore-Linux_x64.xml \
$(_BuildArgs) \
$(_PublishArgs)
displayName: Build RPM installers
installNodeJs: false
installJdk: false
artifacts:
- name: Linux_x64_Logs
path: artifacts/log/
publishOnError: true
includeForks: true
- name: Linux_x64_Packages
path: artifacts/packages/
- template: jobs/codesign-xplat.yml
parameters:
inputName: Linux_x64
# Build Linux ARM
- template: jobs/default-build.yml
parameters:
jobName: Linux_arm_build
jobDisplayName: "Build: Linux ARM"
agentOs: Linux
buildArgs:
--arch arm
--pack
--all
--no-build-nodejs
--no-build-java
-p:OnlyPackPlatformSpecificPackages=true
-bl:artifacts/log/build.linux-arm.binlog
-p:AssetManifestFileName=aspnetcore-Linux_arm.xml
$(_BuildArgs)
$(_PublishArgs)
installNodeJs: false
installJdk: false
artifacts:
- name: Linux_arm_Logs
path: artifacts/log/
publishOnError: true
includeForks: true
- name: Linux_arm_Packages
path: artifacts/packages/
- template: jobs/codesign-xplat.yml
parameters:
inputName: Linux_arm
# Build Linux ARM64
- template: jobs/default-build.yml
parameters:
jobName: Linux_arm64_build
jobDisplayName: "Build: Linux ARM64"
agentOs: Linux
buildArgs:
--arch arm64
--all
--pack
--no-build-nodejs
--no-build-java
-p:OnlyPackPlatformSpecificPackages=true
-bl:artifacts/log/build.arm64.binlog
-p:AssetManifestFileName=aspnetcore-Linux_arm64.xml
$(_BuildArgs)
$(_PublishArgs)
installNodeJs: false
installJdk: false
artifacts:
- name: Linux_arm64_Logs
path: artifacts/log/
publishOnError: true
includeForks: true
- name: Linux_arm64_Packages
path: artifacts/packages/
- template: jobs/codesign-xplat.yml
parameters:
inputName: Linux_arm64
# Build Linux Musl x64
- template: jobs/default-build.yml
parameters:
jobName: Linux_musl_x64_build
jobDisplayName: "Build: Linux Musl x64"
agentOs: Linux
buildScript: ./dockerbuild.sh alpine
buildArgs:
--ci
--arch x64
--os-name linux-musl
--pack
--all
--no-build-nodejs
--no-build-java
-p:OnlyPackPlatformSpecificPackages=true
-bl:artifacts/log/build.musl.binlog
-p:AssetManifestFileName=aspnetcore-Linux_musl_x64.xml
$(_BuildArgs)
$(_PublishArgs)
installNodeJs: false
installJdk: false
artifacts:
- name: Linux_musl_x64_Logs
path: artifacts/log/
publishOnError: true
includeForks: true
- name: Linux_musl_x64_Packages
path: artifacts/packages/
- template: jobs/codesign-xplat.yml
parameters:
inputName: Linux_musl_x64
# Build Linux Musl ARM64
- template: jobs/default-build.yml
parameters:
jobName: Linux_musl_arm64_build
jobDisplayName: "Build: Linux Musl ARM64"
agentOs: Linux
buildScript: ./dockerbuild.sh ubuntu-alpine37
buildArgs:
--ci
--arch arm64
--os-name linux-musl
--pack
--all
--no-build-nodejs
--no-build-java
-p:OnlyPackPlatformSpecificPackages=true
-bl:artifacts/log/build.musl.binlog
-p:AssetManifestFileName=aspnetcore-Linux_musl_arm64.xml
$(_BuildArgs)
$(_PublishArgs)
installNodeJs: false
installJdk: false
artifacts:
- name: Linux_musl_arm64_Logs
path: artifacts/log/
publishOnError: true
includeForks: true
- name: Linux_musl_arm64_Packages
path: artifacts/packages/
- template: jobs/codesign-xplat.yml
parameters:
inputName: Linux_musl_arm64
# Test jobs
- template: jobs/default-build.yml
parameters:
@ -567,63 +261,15 @@ stages:
publishOnError: true
includeForks: true
# Source build
- job: Source_Build
displayName: 'Test: Linux Source Build'
container: centos:7
pool:
vmImage: 'ubuntu-16.04'
variables:
DotNetCoreSdkDir: $(Agent.ToolsDirectory)/dotnet
DOTNET_SYSTEM_GLOBALIZATION_INVARIANT: true
steps:
- script: |
source eng/common/native/common-library.sh
mkdir -p $HOME/bin
GetFile https://github.com/stedolan/jq/releases/download/jq-1.6/jq-linux64 $HOME/bin/jq
chmod +x $HOME/bin/jq
echo "##vso[task.prependpath]$HOME/bin"
displayName: Install jq
- script: ./eng/scripts/ci-source-build.sh --ci --configuration Release /p:BuildManaged=true /p:BuildNodeJs=false
displayName: Run ci-source-build.sh
- task: PublishBuildArtifacts@1
displayName: Upload logs
condition: always()
continueOnError: true
inputs:
pathtoPublish: artifacts/log/
artifactName: Source_Build_Logs
artifactType: Container
parallel: true
- task: PublishBuildArtifacts@1
displayName: Upload package artifacts
# Only capture source build artifacts in PRs for the sake of inspecting
# changes that impact source-build. The artifacts from this build pipeline are never actually used.
condition: and(succeeded(), eq(variables['Build.Reason'], 'PullRequest'))
inputs:
pathtoPublish: artifacts/packages/
artifactName: Source_Build_Packages
artifactType: Container
parallel: true
# Publish to the BAR
- ${{ if and(ne(variables['System.TeamProject'], 'public'), notin(variables['Build.Reason'], 'PullRequest')) }}:
- template: /eng/common/templates/job/publish-build-assets.yml
parameters:
dependsOn:
- Windows_build
- Windows_arm_build
- CodeSign_Xplat_MacOS_x64
- CodeSign_Xplat_Linux_x64
- CodeSign_Xplat_Linux_arm
- CodeSign_Xplat_Linux_arm64
- CodeSign_Xplat_Linux_musl_x64
- CodeSign_Xplat_Linux_musl_arm64
# In addition to the dependencies above, ensure the build was successful overall.
- Code_check
- Linux_Test
- MacOS_Test
- Source_Build
- Windows_Templates_Test
- Windows_Test
pool:

View File

@ -50,6 +50,11 @@
" />
</ItemGroup>
<PropertyGroup>
<!-- For the Blazor WASM branch, only build a subset of projects -->
<ProjectToBuild>$(RepoRoot)src\Components\**\*.csproj;$(RepoRoot)src\ProjectTemplates\**\*.csproj</ProjectToBuild>
</PropertyGroup>
<Choose>
<!-- Project selection can be overridden on the command line by passing in -projects -->
<When Condition="'$(ProjectToBuild)' != ''">

View File

@ -1,168 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Net;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.E2ETesting;
using Microsoft.AspNetCore.Testing;
using OpenQA.Selenium;
using Templates.Test.Helpers;
using Xunit;
using Xunit.Abstractions;
namespace Templates.Test
{
public class BlazorServerTemplateTest : BrowserTestBase
{
public BlazorServerTemplateTest(ProjectFactoryFixture projectFactory, BrowserFixture browserFixture, ITestOutputHelper output) : base(browserFixture, output)
{
ProjectFactory = projectFactory;
}
public ProjectFactoryFixture ProjectFactory { get; set; }
public Project Project { get; private set; }
[Fact]
public async Task BlazorServerTemplateWorks_NoAuth()
{
Project = await ProjectFactory.GetOrCreateProject("blazorservernoauth", Output);
var createResult = await Project.RunDotNetNewAsync("blazorserver");
Assert.True(0 == createResult.ExitCode, ErrorMessages.GetFailedProcessMessage("create/restore", Project, createResult));
var publishResult = await Project.RunDotNetPublishAsync();
Assert.True(0 == publishResult.ExitCode, ErrorMessages.GetFailedProcessMessage("publish", Project, publishResult));
// Run dotnet build after publish. The reason is that one uses Config = Debug and the other uses Config = Release
// The output from publish will go into bin/Release/netcoreappX.Y/publish and won't be affected by calling build
// later, while the opposite is not true.
var buildResult = await Project.RunDotNetBuildAsync();
Assert.True(0 == buildResult.ExitCode, ErrorMessages.GetFailedProcessMessage("build", Project, buildResult));
using (var aspNetProcess = Project.StartBuiltProjectAsync())
{
Assert.False(
aspNetProcess.Process.HasExited,
ErrorMessages.GetFailedProcessMessageOrEmpty("Run built project", Project, aspNetProcess.Process));
await aspNetProcess.AssertStatusCode("/", HttpStatusCode.OK, "text/html");
if (BrowserFixture.IsHostAutomationSupported())
{
aspNetProcess.VisitInBrowser(Browser);
TestBasicNavigation();
}
else
{
BrowserFixture.EnforceSupportedConfigurations();
}
}
using (var aspNetProcess = Project.StartPublishedProjectAsync())
{
Assert.False(
aspNetProcess.Process.HasExited,
ErrorMessages.GetFailedProcessMessageOrEmpty("Run published project", Project, aspNetProcess.Process));
await aspNetProcess.AssertStatusCode("/", HttpStatusCode.OK, "text/html");
if (BrowserFixture.IsHostAutomationSupported())
{
aspNetProcess.VisitInBrowser(Browser);
TestBasicNavigation();
}
else
{
BrowserFixture.EnforceSupportedConfigurations();
}
}
}
[Theory]
[InlineData(true)]
[InlineData(false)]
public async Task BlazorServerTemplateWorks_IndividualAuth(bool useLocalDB)
{
Project = await ProjectFactory.GetOrCreateProject("blazorserverindividual" + (useLocalDB ? "uld" : ""), Output);
var createResult = await Project.RunDotNetNewAsync("blazorserver", auth: "Individual", useLocalDB: useLocalDB);
Assert.True(0 == createResult.ExitCode, ErrorMessages.GetFailedProcessMessage("create/restore", Project, createResult));
var publishResult = await Project.RunDotNetPublishAsync();
Assert.True(0 == publishResult.ExitCode, ErrorMessages.GetFailedProcessMessage("publish", Project, publishResult));
// Run dotnet build after publish. The reason is that one uses Config = Debug and the other uses Config = Release
// The output from publish will go into bin/Release/netcoreappX.Y/publish and won't be affected by calling build
// later, while the opposite is not true.
var buildResult = await Project.RunDotNetBuildAsync();
Assert.True(0 == buildResult.ExitCode, ErrorMessages.GetFailedProcessMessage("build", Project, buildResult));
using (var aspNetProcess = Project.StartBuiltProjectAsync())
{
Assert.False(
aspNetProcess.Process.HasExited,
ErrorMessages.GetFailedProcessMessageOrEmpty("Run built project", Project, aspNetProcess.Process));
await aspNetProcess.AssertStatusCode("/", HttpStatusCode.OK, "text/html");
if (BrowserFixture.IsHostAutomationSupported())
{
aspNetProcess.VisitInBrowser(Browser);
TestBasicNavigation();
}
else
{
BrowserFixture.EnforceSupportedConfigurations();
}
}
using (var aspNetProcess = Project.StartPublishedProjectAsync())
{
Assert.False(
aspNetProcess.Process.HasExited,
ErrorMessages.GetFailedProcessMessageOrEmpty("Run published project", Project, aspNetProcess.Process));
await aspNetProcess.AssertStatusCode("/", HttpStatusCode.OK, "text/html");
if (BrowserFixture.IsHostAutomationSupported())
{
aspNetProcess.VisitInBrowser(Browser);
TestBasicNavigation();
}
}
}
private void TestBasicNavigation()
{
// Give components.server enough time to load so that it can replace
// the prerendered content before we start making assertions.
Thread.Sleep(5000);
Browser.Exists(By.TagName("ul"));
// <title> element gets project ID injected into it during template execution
Browser.Equal(Project.ProjectName.Trim(), () => Browser.Title.Trim());
// Initially displays the home page
Browser.Equal("Hello, world!", () => Browser.FindElement(By.TagName("h1")).Text);
// Can navigate to the counter page
Browser.FindElement(By.PartialLinkText("Counter")).Click();
Browser.Contains("counter", () => Browser.Url);
Browser.Equal("Counter", () => Browser.FindElement(By.TagName("h1")).Text);
// Clicking the counter button works
Browser.Equal("Current count: 0", () => Browser.FindElement(By.CssSelector("h1 + p")).Text);
Browser.FindElement(By.CssSelector("p+button")).Click();
Browser.Equal("Current count: 1", () => Browser.FindElement(By.CssSelector("h1 + p")).Text);
// Can navigate to the 'fetch data' page
Browser.FindElement(By.PartialLinkText("Fetch data")).Click();
Browser.Contains("fetchdata", () => Browser.Url);
Browser.Equal("Weather forecast", () => Browser.FindElement(By.TagName("h1")).Text);
// Asynchronously loads and displays the table of weather forecasts
Browser.Exists(By.CssSelector("table>tbody>tr"));
Browser.Equal(5, () => Browser.FindElements(By.CssSelector("p+table>tbody>tr")).Count);
}
}
}

View File

@ -1,73 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Threading.Tasks;
using Templates.Test.Helpers;
using Xunit;
using Xunit.Abstractions;
namespace Templates.Test
{
public class EmptyWebTemplateTest
{
public EmptyWebTemplateTest(ProjectFactoryFixture projectFactory, ITestOutputHelper output)
{
ProjectFactory = projectFactory;
Output = output;
}
public Project Project { get; set; }
public ProjectFactoryFixture ProjectFactory { get; }
public ITestOutputHelper Output { get; }
[Fact]
public async Task EmptyWebTemplateCSharp()
{
await EmtpyTemplateCore(languageOverride: null);
}
[Fact]
public async Task EmptyWebTemplateFSharp()
{
await EmtpyTemplateCore("F#");
}
private async Task EmtpyTemplateCore(string languageOverride)
{
Project = await ProjectFactory.GetOrCreateProject("empty" + (languageOverride == "F#" ? "fsharp" : "csharp"), Output);
var createResult = await Project.RunDotNetNewAsync("web", language: languageOverride);
Assert.True(0 == createResult.ExitCode, ErrorMessages.GetFailedProcessMessage("create/restore", Project, createResult));
var publishResult = await Project.RunDotNetPublishAsync();
Assert.True(0 == publishResult.ExitCode, ErrorMessages.GetFailedProcessMessage("publish", Project, publishResult));
// Run dotnet build after publish. The reason is that one uses Config = Debug and the other uses Config = Release
// The output from publish will go into bin/Release/netcoreappX.Y/publish and won't be affected by calling build
// later, while the opposite is not true.
var buildResult = await Project.RunDotNetBuildAsync();
Assert.True(0 == buildResult.ExitCode, ErrorMessages.GetFailedProcessMessage("build", Project, buildResult));
using (var aspNetProcess = Project.StartBuiltProjectAsync())
{
Assert.False(
aspNetProcess.Process.HasExited,
ErrorMessages.GetFailedProcessMessageOrEmpty("Run built project", Project, aspNetProcess.Process));
await aspNetProcess.AssertOk("/");
}
using (var aspNetProcess = Project.StartPublishedProjectAsync())
{
Assert.False(
aspNetProcess.Process.HasExited,
ErrorMessages.GetFailedProcessMessageOrEmpty("Run published project", Project, aspNetProcess.Process));
await aspNetProcess.AssertOk("/");
}
}
}
}

View File

@ -1,89 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Runtime.InteropServices;
using System.Threading.Tasks;
using Templates.Test.Helpers;
using Xunit;
using Xunit.Abstractions;
namespace Templates.Test
{
public class GrpcTemplateTest
{
public GrpcTemplateTest(ProjectFactoryFixture projectFactory, ITestOutputHelper output)
{
ProjectFactory = projectFactory;
Output = output;
}
public Project Project { get; set; }
public ProjectFactoryFixture ProjectFactory { get; }
public ITestOutputHelper Output { get; }
[Fact]
public async Task GrpcTemplate()
{
Project = await ProjectFactory.GetOrCreateProject("grpc", Output);
var createResult = await Project.RunDotNetNewAsync("grpc");
Assert.True(0 == createResult.ExitCode, ErrorMessages.GetFailedProcessMessage("create/restore", Project, createResult));
var publishResult = await Project.RunDotNetPublishAsync();
Assert.True(0 == publishResult.ExitCode, ErrorMessages.GetFailedProcessMessage("publish", Project, publishResult));
var buildResult = await Project.RunDotNetBuildAsync();
Assert.True(0 == buildResult.ExitCode, ErrorMessages.GetFailedProcessMessage("build", Project, buildResult));
using (var serverProcess = Project.StartBuiltProjectAsync())
{
// These templates are HTTPS + HTTP/2 only which is not supported on Mac due to missing ALPN support.
// https://github.com/aspnet/AspNetCore/issues/11061
if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
{
Assert.True(serverProcess.Process.HasExited, "built");
Assert.Contains("System.NotSupportedException: HTTP/2 over TLS is not supported on macOS due to missing ALPN support.",
ErrorMessages.GetFailedProcessMessageOrEmpty("Run built service", Project, serverProcess.Process));
}
else if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows) && Environment.OSVersion.Version < new Version(6, 2))
{
Assert.True(serverProcess.Process.HasExited, "built");
Assert.Contains("System.NotSupportedException: HTTP/2 over TLS is not supported on Windows 7 due to missing ALPN support.",
ErrorMessages.GetFailedProcessMessageOrEmpty("Run built service", Project, serverProcess.Process));
}
else
{
Assert.False(
serverProcess.Process.HasExited,
ErrorMessages.GetFailedProcessMessageOrEmpty("Run built service", Project, serverProcess.Process));
}
}
using (var aspNetProcess = Project.StartPublishedProjectAsync())
{
// These templates are HTTPS + HTTP/2 only which is not supported on Mac due to missing ALPN support.
// https://github.com/aspnet/AspNetCore/issues/11061
if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
{
Assert.True(aspNetProcess.Process.HasExited, "published");
Assert.Contains("System.NotSupportedException: HTTP/2 over TLS is not supported on macOS due to missing ALPN support.",
ErrorMessages.GetFailedProcessMessageOrEmpty("Run published service", Project, aspNetProcess.Process));
}
else if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows) && Environment.OSVersion.Version < new Version(6, 2))
{
Assert.True(aspNetProcess.Process.HasExited, "published");
Assert.Contains("System.NotSupportedException: HTTP/2 over TLS is not supported on Windows 7 due to missing ALPN support.",
ErrorMessages.GetFailedProcessMessageOrEmpty("Run published service", Project, aspNetProcess.Process));
}
else
{
Assert.False(
aspNetProcess.Process.HasExited,
ErrorMessages.GetFailedProcessMessageOrEmpty("Run published service", Project, aspNetProcess.Process));
}
}
}
}
}

View File

@ -1,190 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Threading.Tasks;
using Templates.Test.Helpers;
using Xunit;
using Xunit.Abstractions;
namespace Templates.Test
{
public class IdentityUIPackageTest
{
public IdentityUIPackageTest(ProjectFactoryFixture projectFactory, ITestOutputHelper output)
{
ProjectFactory = projectFactory;
Output = output;
}
public Project Project { get; set; }
public ProjectFactoryFixture ProjectFactory { get; set; }
public ITestOutputHelper Output { get; }
public static TheoryData<IDictionary<string, string>, string, string[]> MSBuildIdentityUIPackageOptions
{
get
{
var data = new TheoryData<IDictionary<string, string>, string, string[]>();
data.Add(new Dictionary<string, string>
{
["IdentityUIFrameworkVersion"] = "Bootstrap3"
},
"Bootstrap v3.4.1",
Bootstrap3ContentFiles);
data.Add(new Dictionary<string, string>(), "Bootstrap v4.3.1", Bootstrap4ContentFiles);
return data;
}
}
public static string[] Bootstrap3ContentFiles { get; } = new string[]
{
"Identity/css/site.css",
"Identity/js/site.js",
"Identity/lib/bootstrap/dist/css/bootstrap-theme.css",
"Identity/lib/bootstrap/dist/css/bootstrap-theme.css.map",
"Identity/lib/bootstrap/dist/css/bootstrap-theme.min.css",
"Identity/lib/bootstrap/dist/css/bootstrap-theme.min.css.map",
"Identity/lib/bootstrap/dist/css/bootstrap.css",
"Identity/lib/bootstrap/dist/css/bootstrap.css.map",
"Identity/lib/bootstrap/dist/css/bootstrap.min.css",
"Identity/lib/bootstrap/dist/css/bootstrap.min.css.map",
"Identity/lib/bootstrap/dist/fonts/glyphicons-halflings-regular.eot",
"Identity/lib/bootstrap/dist/fonts/glyphicons-halflings-regular.svg",
"Identity/lib/bootstrap/dist/fonts/glyphicons-halflings-regular.ttf",
"Identity/lib/bootstrap/dist/fonts/glyphicons-halflings-regular.woff",
"Identity/lib/bootstrap/dist/fonts/glyphicons-halflings-regular.woff2",
"Identity/lib/bootstrap/dist/js/bootstrap.js",
"Identity/lib/bootstrap/dist/js/bootstrap.min.js",
"Identity/lib/bootstrap/dist/js/npm.js",
"Identity/lib/jquery/LICENSE.txt",
"Identity/lib/jquery/dist/jquery.js",
"Identity/lib/jquery/dist/jquery.min.js",
"Identity/lib/jquery/dist/jquery.min.map",
"Identity/lib/jquery-validation/LICENSE.md",
"Identity/lib/jquery-validation/dist/additional-methods.js",
"Identity/lib/jquery-validation/dist/additional-methods.min.js",
"Identity/lib/jquery-validation/dist/jquery.validate.js",
"Identity/lib/jquery-validation/dist/jquery.validate.min.js",
"Identity/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.js",
"Identity/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.min.js",
"Identity/lib/jquery-validation-unobtrusive/LICENSE.txt",
};
public static string[] Bootstrap4ContentFiles { get; } = new string[]
{
"Identity/favicon.ico",
"Identity/css/site.css",
"Identity/js/site.js",
"Identity/lib/bootstrap/dist/css/bootstrap-grid.css",
"Identity/lib/bootstrap/dist/css/bootstrap-grid.css.map",
"Identity/lib/bootstrap/dist/css/bootstrap-grid.min.css",
"Identity/lib/bootstrap/dist/css/bootstrap-grid.min.css.map",
"Identity/lib/bootstrap/dist/css/bootstrap-reboot.css",
"Identity/lib/bootstrap/dist/css/bootstrap-reboot.css.map",
"Identity/lib/bootstrap/dist/css/bootstrap-reboot.min.css",
"Identity/lib/bootstrap/dist/css/bootstrap-reboot.min.css.map",
"Identity/lib/bootstrap/dist/css/bootstrap.css",
"Identity/lib/bootstrap/dist/css/bootstrap.css.map",
"Identity/lib/bootstrap/dist/css/bootstrap.min.css",
"Identity/lib/bootstrap/dist/css/bootstrap.min.css.map",
"Identity/lib/bootstrap/dist/js/bootstrap.bundle.js",
"Identity/lib/bootstrap/dist/js/bootstrap.bundle.js.map",
"Identity/lib/bootstrap/dist/js/bootstrap.bundle.min.js",
"Identity/lib/bootstrap/dist/js/bootstrap.bundle.min.js.map",
"Identity/lib/bootstrap/dist/js/bootstrap.js",
"Identity/lib/bootstrap/dist/js/bootstrap.js.map",
"Identity/lib/bootstrap/dist/js/bootstrap.min.js",
"Identity/lib/bootstrap/dist/js/bootstrap.min.js.map",
"Identity/lib/jquery/LICENSE.txt",
"Identity/lib/jquery/dist/jquery.js",
"Identity/lib/jquery/dist/jquery.min.js",
"Identity/lib/jquery/dist/jquery.min.map",
"Identity/lib/jquery-validation/LICENSE.md",
"Identity/lib/jquery-validation/dist/additional-methods.js",
"Identity/lib/jquery-validation/dist/additional-methods.min.js",
"Identity/lib/jquery-validation/dist/jquery.validate.js",
"Identity/lib/jquery-validation/dist/jquery.validate.min.js",
"Identity/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.js",
"Identity/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.min.js",
"Identity/lib/jquery-validation-unobtrusive/LICENSE.txt",
};
[Theory]
[MemberData(nameof(MSBuildIdentityUIPackageOptions))]
public async Task IdentityUIPackage_WorksWithDifferentOptions(IDictionary<string, string> packageOptions, string versionValidator, string[] expectedFiles)
{
Project = await ProjectFactory.GetOrCreateProject("identityuipackage" + string.Concat(packageOptions.Values), Output);
var useLocalDB = false;
var createResult = await Project.RunDotNetNewAsync("razor", auth: "Individual", useLocalDB: useLocalDB, environmentVariables: packageOptions);
Assert.True(0 == createResult.ExitCode, ErrorMessages.GetFailedProcessMessage("create/restore", Project, createResult));
var projectFileContents = ReadFile(Project.TemplateOutputDir, $"{Project.ProjectName}.csproj");
Assert.Contains(".db", projectFileContents);
var publishResult = await Project.RunDotNetPublishAsync(packageOptions: packageOptions);
Assert.True(0 == publishResult.ExitCode, ErrorMessages.GetFailedProcessMessage("publish", Project, publishResult));
// Run dotnet build after publish. The reason is that one uses Config = Debug and the other uses Config = Release
// The output from publish will go into bin/Release/netcoreappX.Y/publish and won't be affected by calling build
// later, while the opposite is not true.
var buildResult = await Project.RunDotNetBuildAsync(packageOptions: packageOptions);
Assert.True(0 == buildResult.ExitCode, ErrorMessages.GetFailedProcessMessage("build", Project, buildResult));
var migrationsResult = await Project.RunDotNetEfCreateMigrationAsync("razorpages");
Assert.True(0 == migrationsResult.ExitCode, ErrorMessages.GetFailedProcessMessage("run EF migrations", Project, migrationsResult));
Project.AssertEmptyMigration("razorpages");
using (var aspNetProcess = Project.StartBuiltProjectAsync())
{
Assert.False(
aspNetProcess.Process.HasExited,
ErrorMessages.GetFailedProcessMessageOrEmpty("Run built project", Project, aspNetProcess.Process));
var response = await aspNetProcess.SendRequest("/Identity/lib/bootstrap/dist/css/bootstrap.css");
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
Assert.Contains(versionValidator, await response.Content.ReadAsStringAsync());
await ValidatePublishedFiles(aspNetProcess, expectedFiles);
}
using (var aspNetProcess = Project.StartPublishedProjectAsync())
{
Assert.False(
aspNetProcess.Process.HasExited,
ErrorMessages.GetFailedProcessMessageOrEmpty("Run built project", Project, aspNetProcess.Process));
var response = await aspNetProcess.SendRequest("/Identity/lib/bootstrap/dist/css/bootstrap.css");
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
Assert.Contains(versionValidator, await response.Content.ReadAsStringAsync());
await ValidatePublishedFiles(aspNetProcess, expectedFiles);
}
}
private async Task ValidatePublishedFiles(AspNetProcess aspNetProcess, string[] expectedContentFiles)
{
foreach (var file in expectedContentFiles)
{
var response = await aspNetProcess.SendRequest(file);
Assert.True(response?.StatusCode == HttpStatusCode.OK, $"Couldn't find file '{file}'");
}
}
private string ReadFile(string basePath, string path)
{
var fullPath = Path.Combine(basePath, path);
var doesExist = File.Exists(fullPath);
Assert.True(doesExist, $"Expected file to exist, but it doesn't: {path}");
return File.ReadAllText(Path.Combine(basePath, path));
}
}
}

View File

@ -1,36 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Threading.Tasks;
using Templates.Test.Helpers;
using Xunit;
using Xunit.Abstractions;
namespace Templates.Items.Test
{
public class BlazorServerTest
{
public BlazorServerTest(ProjectFactoryFixture projectFactory, ITestOutputHelper output)
{
ProjectFactory = projectFactory;
Output = output;
}
public Project Project { get; set; }
public ProjectFactoryFixture ProjectFactory { get; }
public ITestOutputHelper Output { get; }
[Fact]
public async Task BlazorServerItemTemplate()
{
Project = await ProjectFactory.GetOrCreateProject("razorcomponentitem", Output);
var createResult = await Project.RunDotNetNewAsync("razorcomponent --name Different");
Assert.True(0 == createResult.ExitCode, ErrorMessages.GetFailedProcessMessage("create", Project, createResult));
Project.AssertFileExists("Different.razor", shouldExist: true);
Assert.Contains("<h3>Different</h3>", Project.ReadFile("Different.razor"));
}
}
}

View File

@ -1,216 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;
using Templates.Test.Helpers;
using System.Linq;
using Xunit;
using Xunit.Abstractions;
using Microsoft.AspNetCore.Testing;
namespace Templates.Test
{
public class MvcTemplateTest
{
public MvcTemplateTest(ProjectFactoryFixture projectFactory, ITestOutputHelper output)
{
ProjectFactory = projectFactory;
Output = output;
}
public Project Project { get; set; }
public ProjectFactoryFixture ProjectFactory { get; }
public ITestOutputHelper Output { get; }
[Fact]
public async Task MvcTemplate_NoAuthFSharp() => await MvcTemplateCore(languageOverride: "F#");
[Fact]
public async Task MvcTemplate_NoAuthCSharp() => await MvcTemplateCore(languageOverride: null);
private async Task MvcTemplateCore(string languageOverride)
{
Project = await ProjectFactory.GetOrCreateProject("mvcnoauth" + (languageOverride == "F#" ? "fsharp" : "csharp"), Output);
var createResult = await Project.RunDotNetNewAsync("mvc", language: languageOverride);
Assert.True(0 == createResult.ExitCode, ErrorMessages.GetFailedProcessMessage("create/restore", Project, createResult));
var projectExtension = languageOverride == "F#" ? "fsproj" : "csproj";
var projectFileContents = Project.ReadFile($"{Project.ProjectName}.{projectExtension}");
Assert.DoesNotContain(".db", projectFileContents);
Assert.DoesNotContain("Microsoft.EntityFrameworkCore.Tools", projectFileContents);
Assert.DoesNotContain("Microsoft.VisualStudio.Web.CodeGeneration.Design", projectFileContents);
Assert.DoesNotContain("Microsoft.EntityFrameworkCore.Tools.DotNet", projectFileContents);
Assert.DoesNotContain("Microsoft.Extensions.SecretManager.Tools", projectFileContents);
var publishResult = await Project.RunDotNetPublishAsync();
Assert.True(0 == publishResult.ExitCode, ErrorMessages.GetFailedProcessMessage("publish", Project, publishResult));
// Run dotnet build after publish. The reason is that one uses Config = Debug and the other uses Config = Release
// The output from publish will go into bin/Release/netcoreappX.Y/publish and won't be affected by calling build
// later, while the opposite is not true.
var buildResult = await Project.RunDotNetBuildAsync();
Assert.True(0 == buildResult.ExitCode, ErrorMessages.GetFailedProcessMessage("build", Project, buildResult));
IEnumerable<string> menuLinks = new List<string> {
PageUrls.HomeUrl,
PageUrls.HomeUrl,
PageUrls.PrivacyFullUrl
};
var footerLinks = new string[] { PageUrls.PrivacyFullUrl };
var pages = new List<Page>
{
new Page
{
Url = PageUrls.HomeUrl,
Links = menuLinks.Append(PageUrls.DocsUrl).Concat(footerLinks)
},
new Page
{
Url = PageUrls.PrivacyFullUrl,
Links = menuLinks.Concat(footerLinks)
}
};
using (var aspNetProcess = Project.StartBuiltProjectAsync())
{
Assert.False(
aspNetProcess.Process.HasExited,
ErrorMessages.GetFailedProcessMessageOrEmpty("Run built project", Project, aspNetProcess.Process));
await aspNetProcess.AssertPagesOk(pages);
}
using (var aspNetProcess = Project.StartPublishedProjectAsync())
{
Assert.False(
aspNetProcess.Process.HasExited,
ErrorMessages.GetFailedProcessMessageOrEmpty("Run published project", Project, aspNetProcess.Process));
await aspNetProcess.AssertPagesOk(pages);
}
}
[Theory]
[InlineData(true)]
[InlineData(false)]
public async Task MvcTemplate_IndividualAuth(bool useLocalDB)
{
Project = await ProjectFactory.GetOrCreateProject("mvcindividual" + (useLocalDB ? "uld" : ""), Output);
var createResult = await Project.RunDotNetNewAsync("mvc", auth: "Individual", useLocalDB: useLocalDB);
Assert.True(0 == createResult.ExitCode, ErrorMessages.GetFailedProcessMessage("create/restore", Project, createResult));
var projectFileContents = Project.ReadFile($"{Project.ProjectName}.csproj");
if (!useLocalDB)
{
Assert.Contains(".db", projectFileContents);
}
var publishResult = await Project.RunDotNetPublishAsync();
Assert.True(0 == publishResult.ExitCode, ErrorMessages.GetFailedProcessMessage("publish", Project, publishResult));
// Run dotnet build after publish. The reason is that one uses Config = Debug and the other uses Config = Release
// The output from publish will go into bin/Release/netcoreappX.Y/publish and won't be affected by calling build
// later, while the opposite is not true.
var buildResult = await Project.RunDotNetBuildAsync();
Assert.True(0 == buildResult.ExitCode, ErrorMessages.GetFailedProcessMessage("build", Project, buildResult));
var migrationsResult = await Project.RunDotNetEfCreateMigrationAsync("mvc");
Assert.True(0 == migrationsResult.ExitCode, ErrorMessages.GetFailedProcessMessage("run EF migrations", Project, migrationsResult));
Project.AssertEmptyMigration("mvc");
var pages = new List<Page> {
new Page
{
Url = PageUrls.ForgotPassword,
Links = new string [] {
PageUrls.HomeUrl,
PageUrls.RegisterUrl,
PageUrls.LoginUrl,
PageUrls.HomeUrl,
PageUrls.PrivacyUrl,
PageUrls.PrivacyUrl
}
},
new Page
{
Url = PageUrls.HomeUrl,
Links = new string[] {
PageUrls.HomeUrl,
PageUrls.RegisterUrl,
PageUrls.LoginUrl,
PageUrls.HomeUrl,
PageUrls.PrivacyUrl,
PageUrls.DocsUrl,
PageUrls.PrivacyUrl
}
},
new Page
{
Url = PageUrls.PrivacyFullUrl,
Links = new string[] {
PageUrls.HomeUrl,
PageUrls.RegisterUrl,
PageUrls.LoginUrl,
PageUrls.HomeUrl,
PageUrls.PrivacyUrl,
PageUrls.PrivacyUrl
}
},
new Page
{
Url = PageUrls.LoginUrl,
Links = new string[] {
PageUrls.HomeUrl,
PageUrls.RegisterUrl,
PageUrls.LoginUrl,
PageUrls.HomeUrl,
PageUrls.PrivacyUrl,
PageUrls.ForgotPassword,
PageUrls.RegisterUrl,
PageUrls.ExternalArticle,
PageUrls.PrivacyUrl }
},
new Page
{
Url = PageUrls.RegisterUrl,
Links = new string [] {
PageUrls.HomeUrl,
PageUrls.RegisterUrl,
PageUrls.LoginUrl,
PageUrls.HomeUrl,
PageUrls.PrivacyUrl,
PageUrls.ExternalArticle,
PageUrls.PrivacyUrl
}
}
};
using (var aspNetProcess = Project.StartBuiltProjectAsync())
{
Assert.False(
aspNetProcess.Process.HasExited,
ErrorMessages.GetFailedProcessMessageOrEmpty("Run built project", Project, aspNetProcess.Process));
await aspNetProcess.AssertPagesOk(pages);
}
using (var aspNetProcess = Project.StartPublishedProjectAsync())
{
Assert.False(
aspNetProcess.Process.HasExited,
ErrorMessages.GetFailedProcessMessageOrEmpty("Run published project", Project, aspNetProcess.Process));
await aspNetProcess.AssertPagesOk(pages);
}
}
}
}

View File

@ -1,62 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Threading.Tasks;
using Templates.Test.Helpers;
using Xunit;
using Xunit.Abstractions;
namespace Templates.Test
{
public class RazorClassLibraryTemplateTest
{
public RazorClassLibraryTemplateTest(ProjectFactoryFixture projectFactory, ITestOutputHelper output)
{
ProjectFactory = projectFactory;
Output = output;
}
public Project Project { get; set; }
public ProjectFactoryFixture ProjectFactory { get; }
public ITestOutputHelper Output { get; }
[Fact]
public async Task RazorClassLibraryTemplate_WithViews_Async()
{
Project = await ProjectFactory.GetOrCreateProject("razorclasslibwithviews", Output);
var createResult = await Project.RunDotNetNewAsync("razorclasslib", args: new[] { "--support-pages-and-views", "true" });
Assert.True(0 == createResult.ExitCode, ErrorMessages.GetFailedProcessMessage("create/restore", Project, createResult));
var publishResult = await Project.RunDotNetPublishAsync();
Assert.True(0 == publishResult.ExitCode, ErrorMessages.GetFailedProcessMessage("publish", Project, publishResult));
// Run dotnet build after publish. The reason is that one uses Config = Debug and the other uses Config = Release
// The output from publish will go into bin/Release/netcoreappX.Y/publish and won't be affected by calling build
// later, while the opposite is not true.
var buildResult = await Project.RunDotNetBuildAsync();
Assert.True(0 == buildResult.ExitCode, ErrorMessages.GetFailedProcessMessage("build", Project, buildResult));
}
[Fact]
public async Task RazorClassLibraryTemplateAsync()
{
Project = await ProjectFactory.GetOrCreateProject("razorclasslib", Output);
var createResult = await Project.RunDotNetNewAsync("razorclasslib");
Assert.True(0 == createResult.ExitCode, ErrorMessages.GetFailedProcessMessage("create/restore", Project, createResult));
var publishResult = await Project.RunDotNetPublishAsync();
Assert.True(0 == publishResult.ExitCode, ErrorMessages.GetFailedProcessMessage("publish", Project, publishResult));
// Run dotnet build after publish. The reason is that one uses Config = Debug and the other uses Config = Release
// The output from publish will go into bin/Release/netcoreappX.Y/publish and won't be affected by calling build
// later, while the opposite is not true.
var buildResult = await Project.RunDotNetBuildAsync();
Assert.True(0 == buildResult.ExitCode, ErrorMessages.GetFailedProcessMessage("build", Project, buildResult));
}
}
}

View File

@ -1,222 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Testing;
using Templates.Test.Helpers;
using Xunit;
using Xunit.Abstractions;
namespace Templates.Test
{
public class RazorPagesTemplateTest
{
public RazorPagesTemplateTest(ProjectFactoryFixture projectFactory, ITestOutputHelper output)
{
ProjectFactory = projectFactory;
Output = output;
}
public Project Project { get; set; }
public ProjectFactoryFixture ProjectFactory { get; set; }
public ITestOutputHelper Output { get; }
[Fact]
public async Task RazorPagesTemplate_NoAuth()
{
Project = await ProjectFactory.GetOrCreateProject("razorpagesnoauth", Output);
var createResult = await Project.RunDotNetNewAsync("razor");
Assert.True(0 == createResult.ExitCode, ErrorMessages.GetFailedProcessMessage("razor", Project, createResult));
var projectFileContents = ReadFile(Project.TemplateOutputDir, $"{Project.ProjectName}.csproj");
Assert.DoesNotContain(".db", projectFileContents);
Assert.DoesNotContain("Microsoft.EntityFrameworkCore.Tools", projectFileContents);
Assert.DoesNotContain("Microsoft.VisualStudio.Web.CodeGeneration.Design", projectFileContents);
Assert.DoesNotContain("Microsoft.EntityFrameworkCore.Tools.DotNet", projectFileContents);
Assert.DoesNotContain("Microsoft.Extensions.SecretManager.Tools", projectFileContents);
var publishResult = await Project.RunDotNetPublishAsync();
Assert.True(0 == publishResult.ExitCode, ErrorMessages.GetFailedProcessMessage("publish", Project, createResult));
// Run dotnet build after publish. The reason is that one uses Config = Debug and the other uses Config = Release
// The output from publish will go into bin/Release/netcoreappX.Y/publish and won't be affected by calling build
// later, while the opposite is not true.
var buildResult = await Project.RunDotNetBuildAsync();
Assert.True(0 == buildResult.ExitCode, ErrorMessages.GetFailedProcessMessage("build", Project, createResult));
var pages = new List<Page>
{
new Page
{
Url = PageUrls.HomeUrl,
Links = new string[] {
PageUrls.HomeUrl,
PageUrls.HomeUrl,
PageUrls.PrivacyUrl,
PageUrls.DocsUrl,
PageUrls.PrivacyUrl
}
},
new Page
{
Url = PageUrls.PrivacyUrl,
Links = new string[] {
PageUrls.HomeUrl,
PageUrls.HomeUrl,
PageUrls.PrivacyUrl,
PageUrls.PrivacyUrl }
}
};
using (var aspNetProcess = Project.StartBuiltProjectAsync())
{
Assert.False(
aspNetProcess.Process.HasExited,
ErrorMessages.GetFailedProcessMessageOrEmpty("Run built project", Project, aspNetProcess.Process));
await aspNetProcess.AssertPagesOk(pages);
}
using (var aspNetProcess = Project.StartPublishedProjectAsync())
{
Assert.False(
aspNetProcess.Process.HasExited,
ErrorMessages.GetFailedProcessMessageOrEmpty("Run published project", Project, aspNetProcess.Process));
await aspNetProcess.AssertPagesOk(pages);
}
}
[Theory]
[InlineData(false)]
[InlineData(true)]
public async Task RazorPagesTemplate_IndividualAuth(bool useLocalDB)
{
Project = await ProjectFactory.GetOrCreateProject("razorpagesindividual" + (useLocalDB ? "uld" : ""), Output);
var createResult = await Project.RunDotNetNewAsync("razor", auth: "Individual", useLocalDB: useLocalDB);
Assert.True(0 == createResult.ExitCode, ErrorMessages.GetFailedProcessMessage("create/restore", Project, createResult));
var projectFileContents = ReadFile(Project.TemplateOutputDir, $"{Project.ProjectName}.csproj");
if (!useLocalDB)
{
Assert.Contains(".db", projectFileContents);
}
var publishResult = await Project.RunDotNetPublishAsync();
Assert.True(0 == publishResult.ExitCode, ErrorMessages.GetFailedProcessMessage("publish", Project, publishResult));
// Run dotnet build after publish. The reason is that one uses Config = Debug and the other uses Config = Release
// The output from publish will go into bin/Release/netcoreappX.Y/publish and won't be affected by calling build
// later, while the opposite is not true.
var buildResult = await Project.RunDotNetBuildAsync();
Assert.True(0 == buildResult.ExitCode, ErrorMessages.GetFailedProcessMessage("build", Project, buildResult));
var migrationsResult = await Project.RunDotNetEfCreateMigrationAsync("razorpages");
Assert.True(0 == migrationsResult.ExitCode, ErrorMessages.GetFailedProcessMessage("run EF migrations", Project, migrationsResult));
Project.AssertEmptyMigration("razorpages");
var pages = new List<Page> {
new Page
{
Url = PageUrls.ForgotPassword,
Links = new string [] {
PageUrls.HomeUrl,
PageUrls.RegisterUrl,
PageUrls.LoginUrl,
PageUrls.HomeUrl,
PageUrls.PrivacyUrl,
PageUrls.PrivacyUrl
}
},
new Page
{
Url = PageUrls.HomeUrl,
Links = new string[] {
PageUrls.HomeUrl,
PageUrls.RegisterUrl,
PageUrls.LoginUrl,
PageUrls.HomeUrl,
PageUrls.PrivacyUrl,
PageUrls.DocsUrl,
PageUrls.PrivacyUrl
}
},
new Page
{
Url = PageUrls.PrivacyUrl,
Links = new string[] {
PageUrls.HomeUrl,
PageUrls.RegisterUrl,
PageUrls.LoginUrl,
PageUrls.HomeUrl,
PageUrls.PrivacyUrl,
PageUrls.PrivacyUrl
}
},
new Page
{
Url = PageUrls.LoginUrl,
Links = new string[] {
PageUrls.HomeUrl,
PageUrls.RegisterUrl,
PageUrls.LoginUrl,
PageUrls.HomeUrl,
PageUrls.PrivacyUrl,
PageUrls.ForgotPassword,
PageUrls.RegisterUrl,
PageUrls.ExternalArticle,
PageUrls.PrivacyUrl }
},
new Page
{
Url = PageUrls.RegisterUrl,
Links = new string [] {
PageUrls.HomeUrl,
PageUrls.RegisterUrl,
PageUrls.LoginUrl,
PageUrls.HomeUrl,
PageUrls.PrivacyUrl,
PageUrls.ExternalArticle,
PageUrls.PrivacyUrl
}
}
};
using (var aspNetProcess = Project.StartBuiltProjectAsync())
{
Assert.False(
aspNetProcess.Process.HasExited,
ErrorMessages.GetFailedProcessMessageOrEmpty("Run built project", Project, aspNetProcess.Process));
await aspNetProcess.AssertPagesOk(pages);
}
using (var aspNetProcess = Project.StartPublishedProjectAsync())
{
Assert.False(
aspNetProcess.Process.HasExited,
ErrorMessages.GetFailedProcessMessageOrEmpty("Run built project", Project, aspNetProcess.Process));
await aspNetProcess.AssertPagesOk(pages);
}
}
private string ReadFile(string basePath, string path)
{
var fullPath = Path.Combine(basePath, path);
var doesExist = File.Exists(fullPath);
Assert.True(doesExist, $"Expected file to exist, but it doesn't: {path}");
return File.ReadAllText(Path.Combine(basePath, path));
}
}
}

View File

@ -1,30 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Threading.Tasks;
using Microsoft.AspNetCore.E2ETesting;
using Microsoft.AspNetCore.Testing;
using Templates.Test.Helpers;
using Xunit;
using Xunit.Abstractions;
namespace Templates.Test.SpaTemplateTest
{
public class AngularTemplateTest : SpaTemplateTestBase
{
public AngularTemplateTest(ProjectFactoryFixture projectFactory, BrowserFixture browserFixture, ITestOutputHelper output)
: base(projectFactory, browserFixture, output) { }
[Fact]
public Task AngularTemplate_Works()
=> SpaTemplateImplAsync("angularnoauth", "angular", useLocalDb: false, usesAuth: false);
[Fact]
public Task AngularTemplate_IndividualAuth_Works()
=> SpaTemplateImplAsync("angularindividual", "angular", useLocalDb: false, usesAuth: true);
[Fact]
public Task AngularTemplate_IndividualAuth_Works_LocalDb()
=> SpaTemplateImplAsync("angularindividualuld", "angular", useLocalDb: true, usesAuth: true);
}
}

View File

@ -1,23 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Threading.Tasks;
using Microsoft.AspNetCore.E2ETesting;
using Templates.Test.Helpers;
using Xunit;
using Xunit.Abstractions;
namespace Templates.Test.SpaTemplateTest
{
public class ReactReduxTemplateTest : SpaTemplateTestBase
{
public ReactReduxTemplateTest(ProjectFactoryFixture projectFactory, BrowserFixture browserFixture, ITestOutputHelper output)
: base(projectFactory, browserFixture, output)
{
}
[Fact]
public Task ReactReduxTemplate_Works_NetCore()
=> SpaTemplateImplAsync("reactredux", "reactredux", useLocalDb: false, usesAuth: false);
}
}

View File

@ -1,32 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Threading.Tasks;
using Microsoft.AspNetCore.E2ETesting;
using Microsoft.AspNetCore.Testing;
using Templates.Test.Helpers;
using Xunit;
using Xunit.Abstractions;
namespace Templates.Test.SpaTemplateTest
{
public class ReactTemplateTest : SpaTemplateTestBase
{
public ReactTemplateTest(ProjectFactoryFixture projectFactory, BrowserFixture browserFixture, ITestOutputHelper output)
: base(projectFactory, browserFixture, output)
{
}
[Fact]
public Task ReactTemplate_Works_NetCore()
=> SpaTemplateImplAsync("reactnoauth", "react", useLocalDb: false, usesAuth: false);
[Fact]
public Task ReactTemplate_IndividualAuth_NetCore()
=> SpaTemplateImplAsync("reactindividual", "react", useLocalDb: false, usesAuth: true);
[Fact]
public Task ReactTemplate_IndividualAuth_NetCore_LocalDb()
=> SpaTemplateImplAsync("reactindividualuld", "react", useLocalDb: true, usesAuth: true);
}
}

View File

@ -1,339 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using Microsoft.AspNetCore.E2ETesting;
using Newtonsoft.Json.Linq;
using OpenQA.Selenium;
using Templates.Test.Helpers;
using Xunit;
using Xunit.Abstractions;
// Turn off parallel test run for Edge as the driver does not support multiple Selenium tests at the same time
#if EDGE
[assembly: CollectionBehavior(CollectionBehavior.CollectionPerAssembly)]
#endif
namespace Templates.Test.SpaTemplateTest
{
public class SpaTemplateTestBase : BrowserTestBase
{
public SpaTemplateTestBase(
ProjectFactoryFixture projectFactory, BrowserFixture browserFixture, ITestOutputHelper output) : base(browserFixture, output)
{
ProjectFactory = projectFactory;
}
public ProjectFactoryFixture ProjectFactory { get; set; }
public Project Project { get; set; }
// Rather than using [Theory] to pass each of the different values for 'template',
// it's important to distribute the SPA template tests over different test classes
// so they can be run in parallel. Xunit doesn't parallelize within a test class.
protected async Task SpaTemplateImplAsync(
string key,
string template,
bool useLocalDb = false,
bool usesAuth = false)
{
Project = await ProjectFactory.GetOrCreateProject(key, Output);
using var createResult = await Project.RunDotNetNewAsync(template, auth: usesAuth ? "Individual" : null, language: null, useLocalDb);
Assert.True(0 == createResult.ExitCode, ErrorMessages.GetFailedProcessMessage("create/restore", Project, createResult));
// We shouldn't have to do the NPM restore in tests because it should happen
// automatically at build time, but by doing it up front we can avoid having
// multiple NPM installs run concurrently which otherwise causes errors when
// tests run in parallel.
var clientAppSubdirPath = Path.Combine(Project.TemplateOutputDir, "ClientApp");
ValidatePackageJson(clientAppSubdirPath);
var projectFileContents = ReadFile(Project.TemplateOutputDir, $"{Project.ProjectName}.csproj");
if (usesAuth && !useLocalDb)
{
Assert.Contains(".db", projectFileContents);
}
using var npmRestoreResult = await Project.RestoreWithRetryAsync(Output, clientAppSubdirPath);
Assert.True(0 == npmRestoreResult.ExitCode, ErrorMessages.GetFailedProcessMessage("npm restore", Project, npmRestoreResult));
using var lintResult = ProcessEx.RunViaShell(Output, clientAppSubdirPath, "npm run lint");
Assert.True(0 == lintResult.ExitCode, ErrorMessages.GetFailedProcessMessage("npm run lint", Project, lintResult));
// The default behavior of angular tests is watch mode, which leaves the test process open after it finishes, which leads to delays/hangs.
var testcommand = "npm run test" + template == "angular" ? "-- --watch=false" : "";
using var testResult = ProcessEx.RunViaShell(Output, clientAppSubdirPath, testcommand);
Assert.True(0 == testResult.ExitCode, ErrorMessages.GetFailedProcessMessage("npm run test", Project, testResult));
using var publishResult = await Project.RunDotNetPublishAsync();
Assert.True(0 == publishResult.ExitCode, ErrorMessages.GetFailedProcessMessage("publish", Project, publishResult));
// Run dotnet build after publish. The reason is that one uses Config = Debug and the other uses Config = Release
// The output from publish will go into bin/Release/netcoreappX.Y/publish and won't be affected by calling build
// later, while the opposite is not true.
using var buildResult = await Project.RunDotNetBuildAsync();
Assert.True(0 == buildResult.ExitCode, ErrorMessages.GetFailedProcessMessage("build", Project, buildResult));
// localdb is not installed on the CI machines, so skip it.
var shouldVisitFetchData = !(useLocalDb && Project.IsCIEnvironment);
if (usesAuth)
{
using var migrationsResult = await Project.RunDotNetEfCreateMigrationAsync(template);
Assert.True(0 == migrationsResult.ExitCode, ErrorMessages.GetFailedProcessMessage("run EF migrations", Project, migrationsResult));
Project.AssertEmptyMigration(template);
if (shouldVisitFetchData)
{
using var dbUpdateResult = await Project.RunDotNetEfUpdateDatabaseAsync();
Assert.True(0 == dbUpdateResult.ExitCode, ErrorMessages.GetFailedProcessMessage("update database", Project, dbUpdateResult));
}
}
if (template == "react" || template == "reactredux")
{
await CleanupReactClientAppBuildFolder(clientAppSubdirPath);
}
using (var aspNetProcess = Project.StartBuiltProjectAsync())
{
Assert.False(
aspNetProcess.Process.HasExited,
ErrorMessages.GetFailedProcessMessageOrEmpty("Run built project", Project, aspNetProcess.Process));
await WarmUpServer(aspNetProcess);
await aspNetProcess.AssertStatusCode("/", HttpStatusCode.OK, "text/html");
if (BrowserFixture.IsHostAutomationSupported())
{
var (browser, logs) = await BrowserFixture.GetOrCreateBrowserAsync(Output, $"{Project.ProjectName}.build");
aspNetProcess.VisitInBrowser(browser);
TestBasicNavigation(visitFetchData: shouldVisitFetchData, usesAuth, browser, logs);
}
else
{
BrowserFixture.EnforceSupportedConfigurations();
}
}
if (usesAuth)
{
UpdatePublishedSettings();
}
using (var aspNetProcess = Project.StartPublishedProjectAsync())
{
Assert.False(
aspNetProcess.Process.HasExited,
ErrorMessages.GetFailedProcessMessageOrEmpty("Run published project", Project, aspNetProcess.Process));
await WarmUpServer(aspNetProcess);
await aspNetProcess.AssertStatusCode("/", HttpStatusCode.OK, "text/html");
if (BrowserFixture.IsHostAutomationSupported())
{
var (browser, logs) = await BrowserFixture.GetOrCreateBrowserAsync(Output, $"{Project.ProjectName}.publish");
aspNetProcess.VisitInBrowser(browser);
TestBasicNavigation(visitFetchData: shouldVisitFetchData, usesAuth, browser, logs);
}
else
{
BrowserFixture.EnforceSupportedConfigurations();
}
}
}
private async Task CleanupReactClientAppBuildFolder(string clientAppSubdirPath)
{
ProcessEx testResult = null;
int? testResultExitCode = null;
for (int i = 0; i < 3; i++)
{
try
{
testResult = ProcessEx.RunViaShell(Output, clientAppSubdirPath, "npx rimraf ./build");
testResultExitCode = testResult.ExitCode;
if (testResultExitCode == 0)
{
return;
}
}
catch
{
}
finally
{
testResult.Dispose();
}
await Task.Delay(3000);
}
Assert.True(testResultExitCode == 0, ErrorMessages.GetFailedProcessMessage("npx rimraf ./build", Project, testResult));
}
private void ValidatePackageJson(string clientAppSubdirPath)
{
Assert.True(File.Exists(Path.Combine(clientAppSubdirPath, "package.json")), "Missing a package.json");
var packageJson = JObject.Parse(ReadFile(clientAppSubdirPath, "package.json"));
// NPM package names must match ^(?:@[a-z0-9-~][a-z0-9-._~]*/)?[a-z0-9-~][a-z0-9-._~]*$
var packageName = (string)packageJson["name"];
Regex regex = new Regex("^(?:@[a-z0-9-~][a-z0-9-._~]*/)?[a-z0-9-~][a-z0-9-._~]*$");
Assert.True(regex.IsMatch(packageName), "package.json name is invalid format");
}
private static async Task WarmUpServer(AspNetProcess aspNetProcess)
{
var attempt = 0;
var maxAttempts = 3;
do
{
try
{
attempt++;
var response = await aspNetProcess.SendRequest("/");
if (response.StatusCode == HttpStatusCode.OK)
{
break;
}
}
catch (OperationCanceledException)
{
}
catch (HttpRequestException ex) when (ex.Message.StartsWith("The SSL connection could not be established"))
{
}
await Task.Delay(TimeSpan.FromSeconds(5 * attempt));
} while (attempt < maxAttempts);
}
private void UpdatePublishedSettings()
{
// Hijack here the config file to use the development key during publish.
var appSettings = JObject.Parse(File.ReadAllText(Path.Combine(Project.TemplateOutputDir, "appsettings.json")));
var appSettingsDevelopment = JObject.Parse(File.ReadAllText(Path.Combine(Project.TemplateOutputDir, "appsettings.Development.json")));
((JObject)appSettings["IdentityServer"]).Merge(appSettingsDevelopment["IdentityServer"]);
((JObject)appSettings["IdentityServer"]).Merge(new
{
IdentityServer = new
{
Key = new
{
FilePath = "./tempkey.json"
}
}
});
var testAppSettings = appSettings.ToString();
File.WriteAllText(Path.Combine(Project.TemplatePublishDir, "appsettings.json"), testAppSettings);
}
private void TestBasicNavigation(bool visitFetchData, bool usesAuth, IWebDriver browser, ILogs logs)
{
browser.Exists(By.TagName("ul"));
// <title> element gets project ID injected into it during template execution
browser.Contains(Project.ProjectGuid.Replace(".", "._"), () => browser.Title);
// Initially displays the home page
browser.Equal("Hello, world!", () => browser.FindElement(By.TagName("h1")).Text);
// Can navigate to the counter page
browser.FindElement(By.PartialLinkText("Counter")).Click();
browser.Contains("counter", () => browser.Url);
browser.Equal("Counter", () => browser.FindElement(By.TagName("h1")).Text);
// Clicking the counter button works
browser.Equal("0", () => browser.FindElement(By.CssSelector("p>strong")).Text);
browser.FindElement(By.CssSelector("p+button")).Click();
browser.Equal("1", () => browser.FindElement(By.CssSelector("p>strong")).Text);
if (visitFetchData)
{
browser.FindElement(By.PartialLinkText("Fetch data")).Click();
if (usesAuth)
{
// We will be redirected to the identity UI
browser.Contains("/Identity/Account/Login", () => browser.Url);
browser.FindElement(By.PartialLinkText("Register as a new user")).Click();
var userName = $"{Guid.NewGuid()}@example.com";
var password = $"!Test.Password1$";
browser.Exists(By.Name("Input.Email"));
browser.FindElement(By.Name("Input.Email")).SendKeys(userName);
browser.FindElement(By.Name("Input.Password")).SendKeys(password);
browser.FindElement(By.Name("Input.ConfirmPassword")).SendKeys(password);
browser.FindElement(By.Id("registerSubmit")).Click();
// We will be redirected to the RegisterConfirmation
browser.Contains("/Identity/Account/RegisterConfirmation", () => browser.Url);
browser.FindElement(By.PartialLinkText("Click here to confirm your account")).Click();
// We will be redirected to the ConfirmEmail
browser.Contains("/Identity/Account/ConfirmEmail", () => browser.Url);
// Now we can login
browser.FindElement(By.PartialLinkText("Login")).Click();
browser.Exists(By.Name("Input.Email"));
browser.FindElement(By.Name("Input.Email")).SendKeys(userName);
browser.FindElement(By.Name("Input.Password")).SendKeys(password);
browser.FindElement(By.Id("login-submit")).Click();
// Need to navigate to fetch page
browser.FindElement(By.PartialLinkText("Fetch data")).Click();
}
// Can navigate to the 'fetch data' page
browser.Contains("fetch-data", () => browser.Url);
browser.Equal("Weather forecast", () => browser.FindElement(By.TagName("h1")).Text);
// Asynchronously loads and displays the table of weather forecasts
browser.Exists(By.CssSelector("table>tbody>tr"));
browser.Equal(5, () => browser.FindElements(By.CssSelector("p+table>tbody>tr")).Count);
}
foreach (var logKind in logs.AvailableLogTypes)
{
var entries = logs.GetLog(logKind);
var badEntries = entries.Where(e => new LogLevel[] { LogLevel.Warning, LogLevel.Severe }.Contains(e.Level));
badEntries = badEntries.Where(e =>
!e.Message.Contains("failed: WebSocket is closed before the connection is established.")
&& !e.Message.Contains("[WDS] Disconnected!")
&& !e.Message.Contains("Timed out connecting to Chrome, retrying"));
Assert.True(badEntries.Count() == 0, "There were Warnings or Errors from the browser." + Environment.NewLine + string.Join(Environment.NewLine, badEntries));
}
}
private void AssertFileExists(string basePath, string path, bool shouldExist)
{
var fullPath = Path.Combine(basePath, path);
var doesExist = File.Exists(fullPath);
if (shouldExist)
{
Assert.True(doesExist, "Expected file to exist, but it doesn't: " + path);
}
else
{
Assert.False(doesExist, "Expected file not to exist, but it does: " + path);
}
}
private string ReadFile(string basePath, string path)
{
AssertFileExists(basePath, path, shouldExist: true);
return File.ReadAllText(Path.Combine(basePath, path));
}
}
}

View File

@ -1,70 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Threading.Tasks;
using Templates.Test.Helpers;
using Xunit;
using Xunit.Abstractions;
namespace Templates.Test
{
public class WebApiTemplateTest
{
public WebApiTemplateTest(ProjectFactoryFixture factoryFixture, ITestOutputHelper output)
{
FactoryFixture = factoryFixture;
Output = output;
}
public ProjectFactoryFixture FactoryFixture { get; }
public ITestOutputHelper Output { get; }
public Project Project { get; set; }
[Fact]
public async Task WebApiTemplateFSharp() => await WebApiTemplateCore(languageOverride: "F#");
[Fact]
public async Task WebApiTemplateCSharp() => await WebApiTemplateCore(languageOverride: null);
private async Task WebApiTemplateCore(string languageOverride)
{
Project = await FactoryFixture.GetOrCreateProject("webapi" + (languageOverride == "F#" ? "fsharp" : "csharp"), Output);
var createResult = await Project.RunDotNetNewAsync("webapi", language: languageOverride);
Assert.True(0 == createResult.ExitCode, ErrorMessages.GetFailedProcessMessage("create/restore", Project, createResult));
var publishResult = await Project.RunDotNetPublishAsync();
Assert.True(0 == publishResult.ExitCode, ErrorMessages.GetFailedProcessMessage("publish", Project, publishResult));
// Run dotnet build after publish. The reason is that one uses Config = Debug and the other uses Config = Release
// The output from publish will go into bin/Release/netcoreappX.Y/publish and won't be affected by calling build
// later, while the opposite is not true.
var buildResult = await Project.RunDotNetBuildAsync();
Assert.True(0 == buildResult.ExitCode, ErrorMessages.GetFailedProcessMessage("build", Project, buildResult));
using (var aspNetProcess = Project.StartBuiltProjectAsync())
{
Assert.False(
aspNetProcess.Process.HasExited,
ErrorMessages.GetFailedProcessMessageOrEmpty("Run built project", Project, aspNetProcess.Process));
await aspNetProcess.AssertOk("weatherforecast");
await aspNetProcess.AssertNotFound("/");
}
using (var aspNetProcess = Project.StartPublishedProjectAsync())
{
Assert.False(
aspNetProcess.Process.HasExited,
ErrorMessages.GetFailedProcessMessageOrEmpty("Run published project", Project, aspNetProcess.Process));
await aspNetProcess.AssertOk("weatherforecast");
await aspNetProcess.AssertNotFound("/");
}
}
}
}

View File

@ -1,56 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Threading.Tasks;
using Templates.Test.Helpers;
using Xunit;
using Xunit.Abstractions;
namespace Templates.Test
{
public class WorkerTemplateTest
{
public WorkerTemplateTest(ProjectFactoryFixture projectFactory, ITestOutputHelper output)
{
ProjectFactory = projectFactory;
Output = output;
}
public Project Project { get; set; }
public ProjectFactoryFixture ProjectFactory { get; }
public ITestOutputHelper Output { get; }
[Fact]
public async Task WorkerTemplateAsync()
{
Project = await ProjectFactory.GetOrCreateProject("worker", Output);
var createResult = await Project.RunDotNetNewAsync("worker");
Assert.True(0 == createResult.ExitCode, ErrorMessages.GetFailedProcessMessage("create/restore", Project, createResult));
var publishResult = await Project.RunDotNetPublishAsync();
Assert.True(0 == publishResult.ExitCode, ErrorMessages.GetFailedProcessMessage("publish", Project, publishResult));
// Run dotnet build after publish. The reason is that one uses Config = Debug and the other uses Config = Release
// The output from publish will go into bin/Release/netcoreappX.Y/publish and won't be affected by calling build
// later, while the opposite is not true.
var buildResult = await Project.RunDotNetBuildAsync();
Assert.True(0 == buildResult.ExitCode, ErrorMessages.GetFailedProcessMessage("build", Project, buildResult));
using (var aspNetProcess = Project.StartBuiltProjectAsync(hasListeningUri: false))
{
Assert.False(
aspNetProcess.Process.HasExited,
ErrorMessages.GetFailedProcessMessageOrEmpty("Run built project", Project, aspNetProcess.Process));
}
using (var aspNetProcess = Project.StartPublishedProjectAsync(hasListeningUri: false))
{
Assert.False(
aspNetProcess.Process.HasExited,
ErrorMessages.GetFailedProcessMessageOrEmpty("Run published project", Project, aspNetProcess.Process));
}
}
}
}