diff --git a/eng/testing/scenarios/BuildWasmAppsJobsList.txt b/eng/testing/scenarios/BuildWasmAppsJobsList.txt index c44096b4b7b4..bbbca109e575 100644 --- a/eng/testing/scenarios/BuildWasmAppsJobsList.txt +++ b/eng/testing/scenarios/BuildWasmAppsJobsList.txt @@ -6,6 +6,7 @@ Wasm.Build.Tests.BlazorWasmBuildPublishTests Wasm.Build.Tests.BlazorWasmTests Wasm.Build.Tests.BuildPublishTests Wasm.Build.Tests.CleanTests +Wasm.Build.Tests.ConfigSrcTests Wasm.Build.Tests.InvariantGlobalizationTests Wasm.Build.Tests.LocalEMSDKTests Wasm.Build.Tests.MainWithArgsTests @@ -17,4 +18,5 @@ Wasm.Build.Tests.SatelliteAssembliesTests Wasm.Build.Tests.WasmBuildAppTest Wasm.Build.Tests.WasmNativeDefaultsTests Wasm.Build.Tests.WorkloadTests +Wasm.Build.Tests.WasmRunOutOfAppBundleTests Wasm.Build.Tests.WasmTemplateTests diff --git a/src/mono/wasm/test-main.js b/src/mono/wasm/test-main.js index f781652f5062..bf8821c6714d 100644 --- a/src/mono/wasm/test-main.js +++ b/src/mono/wasm/test-main.js @@ -166,6 +166,7 @@ function initRunArgs() { runArgs.enableGC = runArgs.enableGC === undefined ? true : runArgs.enableGC; runArgs.diagnosticTracing = runArgs.diagnosticTracing === undefined ? false : runArgs.diagnosticTracing; runArgs.debugging = runArgs.debugging === undefined ? false : runArgs.debugging; + runArgs.configSrc = runArgs.configSrc === undefined ? './mono-config.json' : runArgs.configSrc; // default'ing to true for tests, unless debugging runArgs.forwardConsole = runArgs.forwardConsole === undefined ? !runArgs.debugging : runArgs.forwardConsole; } @@ -217,6 +218,9 @@ function processQueryArguments(incomingArguments) { } else { console.warn("--fetch-random-delay only works on browser") } + } else if (currentArg.startsWith("--config-src=")) { + const arg = currentArg.substring("--config-src=".length); + runArgs.configSrc = arg; } else { break; } @@ -355,7 +359,7 @@ Promise.all([argsPromise, loadDotnetPromise]).then(async ([_, createDotnetRuntim return createDotnetRuntime(({ MONO, INTERNAL, BINDING, IMPORTS, EXPORTS, Module }) => ({ disableDotnet6Compatibility: true, config: null, - configSrc: "./mono-config.json", + configSrc: runArgs.configSrc || "./mono-config.json", onConfigLoaded: (config) => { if (!Module.config) { const err = new Error("Could not find ./mono-config.json. Cancelling run"); diff --git a/src/tests/BuildWasmApps/Wasm.Build.Tests/BuildTestBase.cs b/src/tests/BuildWasmApps/Wasm.Build.Tests/BuildTestBase.cs index 5fd05729ef3d..8dc05f1545cf 100644 --- a/src/tests/BuildWasmApps/Wasm.Build.Tests/BuildTestBase.cs +++ b/src/tests/BuildWasmApps/Wasm.Build.Tests/BuildTestBase.cs @@ -130,11 +130,13 @@ public BuildTestBase(ITestOutputHelper output, SharedBuildPerTestClassFixture bu string id, Action? test=null, string? buildDir = null, + string? bundleDir = null, int expectedExitCode = 0, string? args = null, Dictionary? envVars = null, string targetFramework = DefaultTargetFramework, - string? extraXHarnessMonoArgs = null) + string? extraXHarnessMonoArgs = null, + string jsRelativePath = "test-main.js") { buildDir ??= _projectDir; envVars ??= new(); @@ -151,13 +153,13 @@ public BuildTestBase(ITestOutputHelper output, SharedBuildPerTestClassFixture bu envVars[kvp.Key] = kvp.Value; } - string bundleDir = Path.Combine(GetBinDir(baseDir: buildDir, config: buildArgs.Config, targetFramework: targetFramework), "AppBundle"); + bundleDir ??= Path.Combine(GetBinDir(baseDir: buildDir, config: buildArgs.Config, targetFramework: targetFramework), "AppBundle"); // Use wasm-console.log to get the xharness output for non-browser cases (string testCommand, string extraXHarnessArgs, bool useWasmConsoleOutput) = host switch { - RunHost.V8 => ("wasm test", "--js-file=test-main.js --engine=V8 -v trace", true), - RunHost.NodeJS => ("wasm test", "--js-file=test-main.js --engine=NodeJS -v trace", true), + RunHost.V8 => ("wasm test", $"--js-file={jsRelativePath} --engine=V8 -v trace", true), + RunHost.NodeJS => ("wasm test", $"--js-file={jsRelativePath} --engine=NodeJS -v trace", true), _ => ("wasm test-browser", $"-v trace -b {host} --web-server-use-cop", false) }; diff --git a/src/tests/BuildWasmApps/Wasm.Build.Tests/ConfigSrcTests.cs b/src/tests/BuildWasmApps/Wasm.Build.Tests/ConfigSrcTests.cs new file mode 100644 index 000000000000..9488225ccc62 --- /dev/null +++ b/src/tests/BuildWasmApps/Wasm.Build.Tests/ConfigSrcTests.cs @@ -0,0 +1,37 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.IO; +using Xunit; +using Xunit.Abstractions; + +#nullable enable + +namespace Wasm.Build.Tests; + +public class ConfigSrcTests : BuildTestBase +{ + public ConfigSrcTests(ITestOutputHelper output, SharedBuildPerTestClassFixture buildContext) : base(output, buildContext) + {} + + // NOTE: port number determinizes dynamically, so could not generate absolute URI + [Theory] + [BuildAndRun(host: RunHost.V8 | RunHost.NodeJS)] + public void ConfigSrcAbsolutePath(BuildArgs buildArgs, RunHost host, string id) + { + buildArgs = buildArgs with { ProjectName = $"configsrcabsolute_{buildArgs.Config}_{buildArgs.AOT}" }; + buildArgs = ExpandBuildArgs(buildArgs); + + BuildProject(buildArgs, + id: id, + new BuildProjectOptions( + InitProject: () => File.WriteAllText(Path.Combine(_projectDir!, "Program.cs"), s_mainReturns42), + DotnetWasmFromRuntimePack: !(buildArgs.AOT || buildArgs.Config == "Release"))); + + string binDir = GetBinDir(baseDir: _projectDir!, config: buildArgs.Config); + string bundleDir = Path.Combine(binDir, "AppBundle"); + string configSrc = Path.GetFullPath(Path.Combine(bundleDir, "mono-config.json")); + + RunAndTestWasmApp(buildArgs, expectedExitCode: 42, host: host, id: id, extraXHarnessMonoArgs: $"--config-src={configSrc}"); + } +} diff --git a/src/tests/BuildWasmApps/Wasm.Build.Tests/WasmRunOutOfAppBundleTests.cs b/src/tests/BuildWasmApps/Wasm.Build.Tests/WasmRunOutOfAppBundleTests.cs new file mode 100644 index 000000000000..befd7ae02981 --- /dev/null +++ b/src/tests/BuildWasmApps/Wasm.Build.Tests/WasmRunOutOfAppBundleTests.cs @@ -0,0 +1,56 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.IO; +using Xunit; +using Xunit.Abstractions; + +#nullable enable + +namespace Wasm.Build.Tests; + +public class WasmRunOutOfAppBundleTests : BuildTestBase +{ + public WasmRunOutOfAppBundleTests(ITestOutputHelper output, SharedBuildPerTestClassFixture buildContext) : base(output, buildContext) + {} + + [Theory] + [BuildAndRun] + public void RunOutOfAppBundle(BuildArgs buildArgs, RunHost host, string id) + { + buildArgs = buildArgs with { ProjectName = $"outofappbundle_{buildArgs.Config}_{buildArgs.AOT}" }; + buildArgs = ExpandBuildArgs(buildArgs); + + BuildProject(buildArgs, + id: id, + new BuildProjectOptions( + InitProject: () => File.WriteAllText(Path.Combine(_projectDir!, "Program.cs"), s_mainReturns42), + DotnetWasmFromRuntimePack: !(buildArgs.AOT || buildArgs.Config == "Release"))); + + string binDir = GetBinDir(baseDir: _projectDir!, config: buildArgs.Config); + string appBundleDir = Path.Combine(binDir, "AppBundle"); + string outerDir = Path.GetFullPath(Path.Combine(appBundleDir, "..")); + + if (host is RunHost.Chrome) + { + string indexHtmlPath = Path.Combine(appBundleDir, "index.html"); + // Delete the original one, so we don't use that by accident + if (File.Exists(indexHtmlPath)) + File.Delete(indexHtmlPath); + + indexHtmlPath = Path.Combine(outerDir, "index.html"); + if (!File.Exists(indexHtmlPath)) + { + var html = @""; + File.WriteAllText(indexHtmlPath, html); + } + } + + RunAndTestWasmApp(buildArgs, + expectedExitCode: 42, + host: host, + id: id, + bundleDir: outerDir, + jsRelativePath: "./AppBundle/test-main.js"); + } +}