Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 11 additions & 7 deletions eng/testing/scenarios/BuildWasmAppsJobsList.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,18 @@ Wasm.Build.NativeRebuild.Tests.NoopNativeRebuildTest
Wasm.Build.NativeRebuild.Tests.OptimizationFlagChangeTests
Wasm.Build.NativeRebuild.Tests.ReferenceNewAssemblyRebuildTest
Wasm.Build.NativeRebuild.Tests.SimpleSourceChangeRebuildTest
Wasm.Build.Templates.Tests.NativeBuildTests
Wasm.Build.Tests.Blazor.AppsettingsTests
Wasm.Build.Tests.Blazor.BuildPublishTests
Wasm.Build.Tests.Blazor.CleanTests
Wasm.Build.Tests.Blazor.MiscTests
Wasm.Build.Tests.Blazor.MiscTests2
Wasm.Build.Tests.Blazor.NativeRefTests
Wasm.Build.Tests.Blazor.AppsettingsTests
Wasm.Build.Tests.Blazor.NativeTests
Wasm.Build.Tests.Blazor.NoopNativeRebuildTest
Wasm.Build.Tests.BuildPublishTests
Wasm.Build.Tests.CleanTests
Wasm.Build.Tests.ConfigSrcTests
Wasm.Build.Tests.IcuShardingTests
Wasm.Build.Tests.HybridGlobalizationTests
Wasm.Build.Tests.IcuShardingTests
Wasm.Build.Tests.InvariantGlobalizationTests
Wasm.Build.Tests.InvariantTimezoneTests
Wasm.Build.Tests.MainWithArgsTests
Expand All @@ -22,11 +24,13 @@ Wasm.Build.Tests.NonWasmTemplateBuildTests
Wasm.Build.Tests.PInvokeTableGeneratorTests
Wasm.Build.Tests.RebuildTests
Wasm.Build.Tests.SatelliteAssembliesTests
Wasm.Build.Tests.TestAppScenarios.AppSettingsTests
Wasm.Build.Tests.TestAppScenarios.LazyLoadingTests
Wasm.Build.Tests.TestAppScenarios.LibraryInitializerTests
Wasm.Build.Tests.TestAppScenarios.SatelliteLoadingTests
Wasm.Build.Tests.WasmBuildAppTest
Wasm.Build.Tests.WasmNativeDefaultsTests
Wasm.Build.Tests.WasmRunOutOfAppBundleTests
Wasm.Build.Tests.WasmSIMDTests
Wasm.Build.Tests.WasmTemplateTests
Wasm.Build.Tests.TestAppScenarios.LazyLoadingTests
Wasm.Build.Tests.TestAppScenarios.LibraryInitializerTests
Wasm.Build.Tests.TestAppScenarios.SatelliteLoadingTests
Wasm.Build.Tests.WorkloadTests
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

namespace Wasm.Build.Tests.Blazor;

public class AppsettingsTests : BuildTestBase
public class AppsettingsTests : BlazorWasmTestBase
{
public AppsettingsTests(ITestOutputHelper output, SharedBuildPerTestClassFixture buildContext)
: base(output, buildContext)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System;
using System.Collections.Generic;
using System.Data;
using System.IO;
using System.Linq;
using Xunit;
using Xunit.Abstractions;
using System.Runtime.Serialization.Json;
using Microsoft.NET.Sdk.WebAssembly;

#nullable enable

namespace Wasm.Build.Tests;

public class BlazorWasmProjectProvider : WasmSdkBasedProjectProvider
{
public BlazorWasmProjectProvider(ITestOutputHelper _testOutput, string? _projectDir = null)
: base(_testOutput, _projectDir)
{}

public void AssertBlazorBootJson(
string config,
bool isPublish,
string targetFramework = BuildTestBase.DefaultTargetFrameworkForBlazor,
bool expectFingerprintOnDotnetJs = false,
RuntimeVariant runtimeType = RuntimeVariant.SingleThreaded)
{
AssertBootJson(binFrameworkDir: FindBlazorBinFrameworkDir(config, isPublish, targetFramework),
isPublish: isPublish,
expectFingerprintOnDotnetJs: expectFingerprintOnDotnetJs,
runtimeType: runtimeType);
}

public void AssertBlazorBundle(
BlazorBuildOptions options,
bool isPublish,
string? binFrameworkDir = null)
{
EnsureProjectDirIsSet();
if (options.TargetFramework is null)
options = options with { TargetFramework = BuildTestBase.DefaultTargetFrameworkForBlazor };

AssertDotNetNativeFiles(options.ExpectedFileType,
options.Config,
forPublish: isPublish,
targetFramework: options.TargetFramework,
expectFingerprintOnDotnetJs: options.ExpectFingerprintOnDotnetJs,
runtimeType: options.RuntimeType);

AssertBlazorBootJson(config: options.Config,
isPublish: isPublish,
targetFramework: options.TargetFramework,
expectFingerprintOnDotnetJs: options.ExpectFingerprintOnDotnetJs,
runtimeType: options.RuntimeType);
}
}
180 changes: 180 additions & 0 deletions src/mono/wasm/Wasm.Build.Tests/Blazor/BlazorWasmTestBase.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,180 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

#nullable enable

using System;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.Playwright;
using Xunit;
using Xunit.Abstractions;
using Xunit.Sdk;

namespace Wasm.Build.Tests;

public abstract class BlazorWasmTestBase : WasmTemplateTestBase
{
protected BlazorWasmProjectProvider _provider;
protected BlazorWasmTestBase(ITestOutputHelper output, SharedBuildPerTestClassFixture buildContext)
: base(output, buildContext, new BlazorWasmProjectProvider(output))
{
_provider = GetProvider<BlazorWasmProjectProvider>();
}

public void InitBlazorWasmProjectDir(string id, string targetFramework = DefaultTargetFrameworkForBlazor)
{
InitPaths(id);
if (Directory.Exists(_projectDir))
Directory.Delete(_projectDir, recursive: true);
Directory.CreateDirectory(_projectDir);

File.WriteAllText(Path.Combine(_projectDir, "nuget.config"),
GetNuGetConfigWithLocalPackagesPath(
GetNuGetConfigPathFor(targetFramework),
s_buildEnv.BuiltNuGetsPath));

File.Copy(Path.Combine(BuildEnvironment.TestDataPath, "Blazor.Directory.Build.props"), Path.Combine(_projectDir, "Directory.Build.props"));
File.Copy(Path.Combine(BuildEnvironment.TestDataPath, "Blazor.Directory.Build.targets"), Path.Combine(_projectDir, "Directory.Build.targets"));
}

public string CreateBlazorWasmTemplateProject(string id)
{
InitBlazorWasmProjectDir(id);
new DotNetCommand(s_buildEnv, _testOutput, useDefaultArgs: false)
.WithWorkingDirectory(_projectDir!)
.WithEnvironmentVariable("NUGET_PACKAGES", _nugetPackagesDir)
.ExecuteWithCapturedOutput("new blazorwasm")
.EnsureSuccessful();

string projectFile = Path.Combine(_projectDir!, $"{id}.csproj");
if (!UseWebcil)
AddItemsPropertiesToProject(projectFile, "<WasmEnableWebcil>false</WasmEnableWebcil>");
return projectFile;
}

protected (CommandResult, string) BlazorBuild(BlazorBuildOptions options, params string[] extraArgs)
{
if (options.WarnAsError)
extraArgs = extraArgs.Append("/warnaserror").ToArray();

var res = BlazorBuildInternal(options.Id, options.Config, publish: false, setWasmDevel: false, extraArgs);
_provider.AssertBlazorBundle(options, isPublish: false);

return res;
}

protected (CommandResult, string) BlazorPublish(BlazorBuildOptions options, params string[] extraArgs)
{
var res = BlazorBuildInternal(options.Id, options.Config, publish: true, setWasmDevel: false, extraArgs);
_provider.AssertBlazorBundle(options, isPublish: true);

if (options.ExpectedFileType == NativeFilesType.AOT)
{
// check for this too, so we know the format is correct for the negative
// test for jsinterop.webassembly.dll
Assert.Contains("Microsoft.JSInterop.dll -> Microsoft.JSInterop.dll.bc", res.Item1.Output);

// make sure this assembly gets skipped
Assert.DoesNotContain("Microsoft.JSInterop.WebAssembly.dll -> Microsoft.JSInterop.WebAssembly.dll.bc", res.Item1.Output);
}

string objBuildDir = Path.Combine(_projectDir!, "obj", options.Config, options.TargetFramework, "wasm", "for-build");
// Check that we linked only for publish
if (options.ExpectRelinkDirWhenPublishing)
Assert.True(Directory.Exists(objBuildDir), $"Could not find expected {objBuildDir}, which gets created when relinking during Build. This is likely a test authoring error");
else
Assert.False(Directory.Exists(objBuildDir), $"Found unexpected {objBuildDir}, which gets created when relinking during Build");

return res;
}

protected (CommandResult, string) BlazorBuildInternal(string id, string config, bool publish = false, bool setWasmDevel = true, params string[] extraArgs)
{
string label = publish ? "publish" : "build";
_testOutput.WriteLine($"{Environment.NewLine}** {label} **{Environment.NewLine}");

string logPath = Path.Combine(s_buildEnv.LogRootPath, id, $"{id}-{label}.binlog");
string[] combinedArgs = new[]
{
label, // same as the command name
$"-bl:{logPath}",
$"-p:Configuration={config}",
!UseWebcil ? "-p:WasmEnableWebcil=false" : string.Empty,
"-p:BlazorEnableCompression=false",
"-nr:false",
setWasmDevel ? "-p:_WasmDevel=true" : string.Empty
}.Concat(extraArgs).ToArray();

CommandResult res = new DotNetCommand(s_buildEnv, _testOutput)
.WithWorkingDirectory(_projectDir!)
.WithEnvironmentVariable("NUGET_PACKAGES", _nugetPackagesDir)
.ExecuteWithCapturedOutput(combinedArgs)
.EnsureSuccessful();

return (res, logPath);
}

protected string CreateProjectWithNativeReference(string id)
{
CreateBlazorWasmTemplateProject(id);

string extraItems = @$"
{GetSkiaSharpReferenceItems()}
<WasmFilesToIncludeInFileSystem Include=""{Path.Combine(BuildEnvironment.TestAssetsPath, "mono.png")}"" />
";
string projectFile = Path.Combine(_projectDir!, $"{id}.csproj");
AddItemsPropertiesToProject(projectFile, extraItems: extraItems);

return projectFile;
}

// Keeping these methods with explicit Build/Publish in the name
// so in the test code it is evident which is being run!
public Task BlazorRunForBuildWithDotnetRun(string config, Func<IPage, Task>? test = null, string extraArgs = "--no-build", Action<IConsoleMessage>? onConsoleMessage = null)
=> BlazorRunTest($"run -c {config} {extraArgs}", _projectDir!, test, onConsoleMessage);

public Task BlazorRunForPublishWithWebServer(string config, Func<IPage, Task>? test = null, string extraArgs = "", Action<IConsoleMessage>? onConsoleMessage = null)
=> BlazorRunTest($"{s_xharnessRunnerCommand} wasm webserver --app=. --web-server-use-default-files {extraArgs}",
Path.GetFullPath(Path.Combine(FindBlazorBinFrameworkDir(config, forPublish: true), "..")),
test, onConsoleMessage);

public async Task BlazorRunTest(string runArgs,
string workingDirectory,
Func<IPage, Task>? test = null,
Action<IConsoleMessage>? onConsoleMessage = null,
bool detectRuntimeFailures = true)
{
using var runCommand = new RunCommand(s_buildEnv, _testOutput)
.WithWorkingDirectory(workingDirectory);

await using var runner = new BrowserRunner(_testOutput);
var page = await runner.RunAsync(runCommand, runArgs, onConsoleMessage: OnConsoleMessage);

await page.Locator("text=Counter").ClickAsync();
var txt = await page.Locator("p[role='status']").InnerHTMLAsync();
Assert.Equal("Current count: 0", txt);

await page.Locator("text=\"Click me\"").ClickAsync();
txt = await page.Locator("p[role='status']").InnerHTMLAsync();
Assert.Equal("Current count: 1", txt);

if (test is not null)
await test(page);

void OnConsoleMessage(IConsoleMessage msg)
{
_testOutput.WriteLine($"[{msg.Type}] {msg.Text}");

onConsoleMessage?.Invoke(msg);

if (detectRuntimeFailures)
{
if (msg.Text.Contains("[MONO] * Assertion") || msg.Text.Contains("Error: [MONO] "))
throw new XunitException($"Detected a runtime failure at line: {msg.Text}");
}
}
}

}
32 changes: 28 additions & 4 deletions src/mono/wasm/Wasm.Build.Tests/Blazor/BuildPublishTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@

namespace Wasm.Build.Tests.Blazor;

public class BuildPublishTests : BuildTestBase
public class BuildPublishTests : BlazorWasmTestBase
{
public BuildPublishTests(ITestOutputHelper output, SharedBuildPerTestClassFixture buildContext)
: base(output, buildContext)
Expand All @@ -34,11 +34,11 @@ public void DefaultTemplate_WithoutWorkload(string config)

// Build
BlazorBuildInternal(id, config, publish: false);
AssertBlazorBootJson(config, isPublish: false);
_provider.AssertBlazorBootJson(config, isPublish: false);

// Publish
BlazorBuildInternal(id, config, publish: true);
AssertBlazorBootJson(config, isPublish: true);
_provider.AssertBlazorBootJson(config, isPublish: true);
}

[Theory]
Expand Down Expand Up @@ -196,7 +196,7 @@ public void BugRegression_60479_WithRazorClassLib()
.ExecuteWithCapturedOutput("new razorclasslib")
.EnsureSuccessful();

string razorClassLibraryFileName = UseWebcil ? $"RazorClassLibrary{WebcilInWasmExtension}" : "RazorClassLibrary.dll";
string razorClassLibraryFileName = UseWebcil ? $"RazorClassLibrary{ProjectProviderBase.WebcilInWasmExtension}" : "RazorClassLibrary.dll";
AddItemsPropertiesToProject(wasmProjectFile, extraItems: @$"
<ProjectReference Include=""..\\RazorClassLibrary\\RazorClassLibrary.csproj"" />
<BlazorWebAssemblyLazyLoad Include=""{razorClassLibraryFileName}"" />
Expand Down Expand Up @@ -257,4 +257,28 @@ public async Task BlazorPublishRunTest(string config, bool aot)
await BlazorRunForPublishWithWebServer(config);
}

private void BlazorAddRazorButton(string buttonText, string customCode, string methodName = "test", string razorPage = "Pages/Counter.razor")
{
string additionalCode = $$"""
<p role="{{methodName}}">Output: @outputText</p>
<button class="btn btn-primary" @onclick="{{methodName}}">{{buttonText}}</button>

@code {
private string outputText = string.Empty;
public void {{methodName}}()
{
{{customCode}}
}
}
""";

// find blazor's Counter.razor
string counterRazorPath = Path.Combine(_projectDir!, razorPage);
if (!File.Exists(counterRazorPath))
throw new FileNotFoundException($"Could not find {counterRazorPath}");

string oldContent = File.ReadAllText(counterRazorPath);
File.WriteAllText(counterRazorPath, oldContent + additionalCode);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@

#nullable enable

namespace Wasm.Build.Tests;
namespace Wasm.Build.Tests.Blazor;

public class CleanTests : NativeRebuildTestsBase
public class CleanTests : BlazorWasmTestBase
{
public CleanTests(ITestOutputHelper output, SharedBuildPerTestClassFixture buildContext)
: base(output, buildContext)
Expand Down
4 changes: 2 additions & 2 deletions src/mono/wasm/Wasm.Build.Tests/Blazor/MiscTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

namespace Wasm.Build.Tests.Blazor;

public class MiscTests : BuildTestBase
public class MiscTests : BlazorWasmTestBase
{
public MiscTests(ITestOutputHelper output, SharedBuildPerTestClassFixture buildContext)
: base(output, buildContext)
Expand Down Expand Up @@ -39,7 +39,7 @@ public void NativeBuild_WithDeployOnBuild_UsedByVS(string config, bool nativeRel

var expectedFileType = nativeRelink ? NativeFilesType.Relinked : NativeFilesType.AOT;

AssertBlazorBundle(new BlazorBuildOptions
_provider.AssertBlazorBundle(new BlazorBuildOptions
(
Id: id,
Config: config,
Expand Down
2 changes: 1 addition & 1 deletion src/mono/wasm/Wasm.Build.Tests/Blazor/MiscTests2.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

namespace Wasm.Build.Tests.Blazor;

public class MiscTests2 : BuildTestBase
public class MiscTests2 : BlazorWasmTestBase
{
public MiscTests2(ITestOutputHelper output, SharedBuildPerTestClassFixture buildContext)
: base(output, buildContext)
Expand Down
Loading