Exemple #1
0
        public async Task Publish_UpdatesServiceWorkerVersionHash_WhenSourcesChange()
        {
            // Arrange
            using var project = ProjectDirectory.Create("blazorwasm", additionalProjects: new[] { "razorclasslibrary" });
            var result = await MSBuildProcessManager.DotnetMSBuild(project, "Publish", args : "/bl:initial.binlog /p:ServiceWorkerAssetsManifest=service-worker-assets.js");

            Assert.BuildPassed(result);

            var publishOutputDirectory = project.PublishOutputDirectory;

            var serviceWorkerFile = Assert.FileExists(result, publishOutputDirectory, "wwwroot", "serviceworkers", "my-service-worker.js");
            var version           = File.ReadAllLines(serviceWorkerFile).Last();
            var match             = Regex.Match(version, "\\/\\* Manifest version: (.{8}) \\*\\/");

            Assert.True(match.Success);
            Assert.Equal(2, match.Groups.Count);
            Assert.NotNull(match.Groups[1].Value);
            var capture = match.Groups[1].Value;

            // Act
            var cssFile = Path.Combine(project.DirectoryPath, "LinkToWebRoot", "css", "app.css");

            File.WriteAllText(cssFile, ".updated { }");

            // Assert
            result = await MSBuildProcessManager.DotnetMSBuild(project, "Publish", args : "/bl:updated.binlog /p:ServiceWorkerAssetsManifest=service-worker-assets.js");

            Assert.BuildPassed(result);

            var updatedVersion = File.ReadAllLines(serviceWorkerFile).Last();
            var updatedMatch   = Regex.Match(updatedVersion, "\\/\\* Manifest version: (.{8}) \\*\\/");

            Assert.True(updatedMatch.Success);
            Assert.Equal(2, updatedMatch.Groups.Count);
            Assert.NotNull(updatedMatch.Groups[1].Value);
            var updatedCapture = updatedMatch.Groups[1].Value;

            Assert.NotEqual(capture, updatedCapture);
        }
Exemple #2
0
        public async Task Publish_InRelease_Works()
        {
            // Arrange
            using var project     = ProjectDirectory.Create("blazorwasm", additionalProjects: new[] { "razorclasslibrary", "LinkBaseToWebRoot" });
            project.Configuration = "Release";
            var result = await MSBuildProcessManager.DotnetMSBuild(project, "Publish", "");

            Assert.BuildPassed(result);


            var publishDirectory = project.PublishOutputDirectory;

            var blazorPublishDirectory = Path.Combine(publishDirectory, "wwwroot");

            Assert.FileExists(result, blazorPublishDirectory, "_framework", "blazor.boot.json");
            Assert.FileExists(result, blazorPublishDirectory, "_framework", "blazor.webassembly.js");
            Assert.FileExists(result, blazorPublishDirectory, "_framework", "dotnet.wasm");
            Assert.FileExists(result, blazorPublishDirectory, "_framework", DotNetJsFileName);
            Assert.FileExists(result, blazorPublishDirectory, "_framework", "blazorwasm.dll");
            Assert.FileExists(result, blazorPublishDirectory, "_framework", "System.Text.Json.dll"); // Verify dependencies are part of the output.

            // Verify referenced static web assets
            Assert.FileExists(result, blazorPublishDirectory, "_content", "RazorClassLibrary", "wwwroot", "exampleJsInterop.js");
            Assert.FileExists(result, blazorPublishDirectory, "_content", "RazorClassLibrary", "styles.css");

            // Verify static assets are in the publish directory
            Assert.FileExists(result, blazorPublishDirectory, "index.html");

            // Verify link item assets are in the publish directory
            Assert.FileExists(result, blazorPublishDirectory, "js", "LinkedScript.js");
            var cssFile = Assert.FileExists(result, blazorPublishDirectory, "css", "app.css");

            Assert.FileContains(result, cssFile, ".publish");
            Assert.FileDoesNotExist(result, "dist", "Fake-License.txt");

            // Verify web.config
            Assert.FileExists(result, publishDirectory, "web.config");
            Assert.FileCountEquals(result, 1, publishDirectory, "*", SearchOption.TopDirectoryOnly);
        }
Exemple #3
0
        public async Task Publish_HostedApp_WithNoBuild_Works()
        {
            // Arrange
            using var project = ProjectDirectory.Create("blazorhosted", additionalProjects: new[] { "blazorwasm", "razorclasslibrary", });
            var result = await MSBuildProcessManager.DotnetMSBuild(project, "Build");

            Assert.BuildPassed(result);

            result = await MSBuildProcessManager.DotnetMSBuild(project, "Publish", "/p:NoBuild=true");

            var publishDirectory = project.PublishOutputDirectory;

            // Make sure the main project exists
            Assert.FileExists(result, publishDirectory, "blazorhosted.dll");

            var blazorPublishDirectory = Path.Combine(publishDirectory, "wwwroot");

            Assert.FileExists(result, blazorPublishDirectory, "_framework", "blazor.boot.json");
            Assert.FileExists(result, blazorPublishDirectory, "_framework", "dotnet.wasm");
            Assert.FileExists(result, blazorPublishDirectory, "_framework", DotNetJsFileName);
            Assert.FileExists(result, blazorPublishDirectory, "_framework", "blazorwasm.dll");
            Assert.FileExists(result, blazorPublishDirectory, "_framework", "System.Text.Json.dll"); // Verify dependencies are part of the output.

            // Verify static assets are in the publish directory
            Assert.FileExists(result, blazorPublishDirectory, "index.html");

            // Verify static web assets from referenced projects are copied.
            Assert.FileExists(result, publishDirectory, "wwwroot", "_content", "RazorClassLibrary", "wwwroot", "exampleJsInterop.js");
            Assert.FileExists(result, publishDirectory, "wwwroot", "_content", "RazorClassLibrary", "styles.css");

            // Verify web.config
            Assert.FileExists(result, publishDirectory, "web.config");

            VerifyBootManifestHashes(result, blazorPublishDirectory);
            VerifyServiceWorkerFiles(result, blazorPublishDirectory,
                                     serviceWorkerPath: Path.Combine("serviceworkers", "my-service-worker.js"),
                                     serviceWorkerContent: "// This is the production service worker",
                                     assetsManifestPath: "custom-service-worker-assets.js");
        }
        public async Task Publish_UpdatesFilesWhenSourcesChange()
        {
            // Arrange
            using var project = ProjectDirectory.Create("blazorhosted", additionalProjects: new[] { "blazorwasm", "razorclasslibrary" });
            var result = await MSBuildProcessManager.DotnetMSBuild(project, target : "publish");

            Assert.BuildPassed(result);

            // Act
            var mainAppDll                     = Path.Combine(project.DirectoryPath, project.PublishOutputDirectory, "wwwroot", "_framework", "blazorwasm.dll");
            var mainAppDllThumbPrint           = FileThumbPrint.Create(mainAppDll);
            var mainAppCompressedDll           = Path.Combine(project.DirectoryPath, project.PublishOutputDirectory, "wwwroot", "_framework", "blazorwasm.dll.br");
            var mainAppCompressedDllThumbPrint = FileThumbPrint.Create(mainAppCompressedDll);

            var blazorBootJson                     = Path.Combine(project.DirectoryPath, project.PublishOutputDirectory, "wwwroot", "_framework", "blazor.boot.json");
            var blazorBootJsonThumbPrint           = FileThumbPrint.Create(blazorBootJson);
            var blazorBootJsonCompressed           = Path.Combine(project.DirectoryPath, project.PublishOutputDirectory, "wwwroot", "_framework", "blazor.boot.json.br");
            var blazorBootJsonCompressedThumbPrint = FileThumbPrint.Create(blazorBootJsonCompressed);

            var programFile         = Path.Combine(project.DirectoryPath, "..", "blazorwasm", "Program.cs");
            var programFileContents = File.ReadAllText(programFile);

            File.WriteAllText(programFile, programFileContents.Replace("args", "arguments"));

            // Assert
            result = await MSBuildProcessManager.DotnetMSBuild(project, target : "publish");

            Assert.BuildPassed(result);
            var newMainAppDllThumbPrint               = FileThumbPrint.Create(mainAppDll);
            var newMainAppCompressedDllThumbPrint     = FileThumbPrint.Create(mainAppCompressedDll);
            var newBlazorBootJsonThumbPrint           = FileThumbPrint.Create(blazorBootJson);
            var newBlazorBootJsonCompressedThumbPrint = FileThumbPrint.Create(blazorBootJsonCompressed);

            Assert.NotEqual(mainAppDllThumbPrint, newMainAppDllThumbPrint);
            Assert.NotEqual(mainAppCompressedDllThumbPrint, newMainAppCompressedDllThumbPrint);

            Assert.NotEqual(blazorBootJsonThumbPrint, newBlazorBootJsonThumbPrint);
            Assert.NotEqual(blazorBootJsonCompressedThumbPrint, newBlazorBootJsonCompressedThumbPrint);
        }
        public async Task BuildMinimal_Works()
        {
            // Arrange
            // Minimal has no project references, service worker etc. This is pretty close to the project template.
            using var project = ProjectDirectory.Create("blazorwasm-minimal");
            var result = await MSBuildProcessManager.DotnetMSBuild(project);

            Assert.BuildPassed(result);

            var buildOutputDirectory = project.BuildOutputDirectory;

            Assert.FileExists(result, buildOutputDirectory, "wwwroot", "_framework", "blazor.boot.json");
            Assert.FileExists(result, buildOutputDirectory, "wwwroot", "_framework", "blazor.webassembly.js");
            Assert.FileExists(result, buildOutputDirectory, "wwwroot", "_framework", "dotnet.wasm");
            Assert.FileExists(result, buildOutputDirectory, "wwwroot", "_framework", "dotnet.wasm.gz");
            Assert.FileExists(result, buildOutputDirectory, "wwwroot", "_framework", DotNetJsFileName);
            Assert.FileExists(result, buildOutputDirectory, "wwwroot", "_framework", "blazorwasm-minimal.dll");

            var staticWebAssets = Assert.FileExists(result, buildOutputDirectory, "blazorwasm-minimal.StaticWebAssets.xml");

            Assert.FileContains(result, staticWebAssets, Path.Combine(project.TargetFramework, "wwwroot"));
        }
Exemple #6
0
        public async Task Publish_LazyLoadExplicitAssembly_Debug_Works()
        {
            // Arrange
            using var project     = ProjectDirectory.Create("blazorwasm", additionalProjects: new[] { "razorclasslibrary" });
            project.Configuration = "Debug";

            project.AddProjectFileContent(
                @"
<ItemGroup>
    <BlazorWebAssemblyLazyLoad Include='RazorClassLibrary.dll' />
</ItemGroup>
");

            var result = await MSBuildProcessManager.DotnetMSBuild(project, "Publish");

            var publishDirectory = project.PublishOutputDirectory;

            // Verify that a blazor.boot.json file has been created
            Assert.FileExists(result, publishDirectory, "wwwroot", "_framework", "blazor.boot.json");
            // And that the assembly is in the output
            Assert.FileExists(result, publishDirectory, "wwwroot", "_framework", "RazorClassLibrary.dll");

            var bootJson = ReadBootJsonData(result, Path.Combine(publishDirectory, "wwwroot", "_framework", "blazor.boot.json"));

            // And that it has been labelled as a dynamic assembly in the boot.json
            var lazyAssemblies = bootJson.resources.lazyAssembly;
            var assemblies     = bootJson.resources.assembly;

            Assert.NotNull(lazyAssemblies);
            Assert.Contains("RazorClassLibrary.dll", lazyAssemblies.Keys);
            Assert.DoesNotContain("RazorClassLibrary.dll", assemblies.Keys);

            // App assembly should not be lazy loaded
            Assert.DoesNotContain("blazorwasm.dll", lazyAssemblies.Keys);
            Assert.Contains("blazorwasm.dll", assemblies.Keys);
        }
        public async Task Publish_CompressesAllFrameworkFiles()
        {
            // Arrange
            using var project = ProjectDirectory.Create("blazorwasm", additionalProjects: new[] { "razorclasslibrary" });
            var result = await MSBuildProcessManager.DotnetMSBuild(project, target : "publish");

            Assert.BuildPassed(result);

            var extensions = new[] { ".dll", ".js", ".pdb", ".wasm", ".map", ".json", ".dat" };

            // Act
            var frameworkFilesPath = Path.Combine(project.DirectoryPath, project.PublishOutputDirectory, "wwwroot", "_framework");

            foreach (var file in Directory.EnumerateFiles(frameworkFilesPath, "*", new EnumerationOptions {
                RecurseSubdirectories = true,
            }))
            {
                var extension = Path.GetExtension(file);
                if (extension != ".br" && extension != ".gz")
                {
                    Assert.FileExists(result, file + ".br");
                }
            }
        }
        public static Task <MSBuildResult> RunProcessAsync(
            ProjectDirectory project,
            string arguments,
            TimeSpan?timeout = null,
            MSBuildProcessKind msBuildProcessKind = MSBuildProcessKind.Dotnet)
        {
            timeout = timeout ?? TimeSpan.FromSeconds(60);

            var processStartInfo = new ProcessStartInfo()
            {
                WorkingDirectory       = project.DirectoryPath,
                UseShellExecute        = false,
                RedirectStandardError  = true,
                RedirectStandardOutput = true,
            };

            if (msBuildProcessKind == MSBuildProcessKind.Desktop)
            {
                if (string.IsNullOrEmpty(BuildVariables.MSBuildPath))
                {
                    throw new ArgumentException("Unable to locate MSBuild.exe to run desktop tests.");
                }

                processStartInfo.FileName  = BuildVariables.MSBuildPath;
                processStartInfo.Arguments = arguments;
            }
            else
            {
                processStartInfo.FileName  = "dotnet";
                processStartInfo.Arguments = $"msbuild {arguments}";
            }

            var process = new Process()
            {
                StartInfo           = processStartInfo,
                EnableRaisingEvents = true,
            };

            var completionSource = new TaskCompletionSource <MSBuildResult>();
            var output           = new StringBuilder();

            process.Exited             += Process_Exited;
            process.ErrorDataReceived  += Process_ErrorDataReceived;
            process.OutputDataReceived += Process_OutputDataReceived;

            process.Start();
            process.BeginErrorReadLine();
            process.BeginOutputReadLine();

            var timeoutTask = Task.Delay(timeout.Value).ContinueWith((t) =>
            {
                // Don't timeout during debug sessions
                while (Debugger.IsAttached)
                {
                    Thread.Sleep(TimeSpan.FromSeconds(1));
                }

                if (process.HasExited)
                {
                    // This will happen on success, the 'real' task has already completed so this value will
                    // never be visible.
                    return((MSBuildResult)null);
                }

                // This is a timeout.
                process.Kill();
                throw new TimeoutException($"command '${process.StartInfo.FileName} {process.StartInfo.Arguments}' timed out after {timeout}.");
            });

            return(Task.WhenAny <MSBuildResult>(completionSource.Task, timeoutTask).Unwrap());

            void Process_Exited(object sender, EventArgs e)
            {
                var result = new MSBuildResult(project, process.StartInfo.FileName, process.StartInfo.Arguments, process.ExitCode, output.ToString());

                completionSource.SetResult(result);
            }

            void Process_ErrorDataReceived(object sender, DataReceivedEventArgs e)
            {
                output.AppendLine(e.Data);
            }

            void Process_OutputDataReceived(object sender, DataReceivedEventArgs e)
            {
                output.AppendLine(e.Data);
            }
        }
        public static async Task <MSBuildResult> RunProcessAsync(
            ProjectDirectory project,
            string arguments,
            TimeSpan?timeout = null,
            MSBuildProcessKind msBuildProcessKind = MSBuildProcessKind.Dotnet)
        {
            var processStartInfo = new ProcessStartInfo()
            {
                WorkingDirectory       = project.DirectoryPath,
                UseShellExecute        = false,
                RedirectStandardError  = true,
                RedirectStandardOutput = true,
            };

            if (msBuildProcessKind == MSBuildProcessKind.Desktop)
            {
                if (string.IsNullOrEmpty(BuildVariables.MSBuildPath))
                {
                    throw new ArgumentException("Unable to locate MSBuild.exe to run desktop tests. " +
                                                "MSBuild.exe is located using state created as part of running build[cmd|sh] at the root of the repository. Run build /t:Prepare to set this up if this hasn't been done.");
                }

                processStartInfo.FileName  = BuildVariables.MSBuildPath;
                processStartInfo.Arguments = arguments;
            }
            else
            {
                processStartInfo.FileName  = DotNetMuxer.MuxerPathOrDefault();
                processStartInfo.Arguments = $"msbuild {arguments}";

                // Suppresses the 'Welcome to .NET Core!' output that times out tests and causes locked file issues.
                // When using dotnet we're not guarunteed to run in an environment where the dotnet.exe has had its first run experience already invoked.
                processStartInfo.EnvironmentVariables["DOTNET_SKIP_FIRST_TIME_EXPERIENCE"] = "true";
            }

            ProcessResult processResult;

            try
            {
                processResult = await RunProcessCoreAsync(processStartInfo, timeout);
            }
            catch (TimeoutException ex)
            {
                // Copy the binlog to the artifacts directory if executing MSBuild throws.
                // This would help diagnosing failures on the CI.
                var binaryLogFile = Path.Combine(project.ProjectFilePath, "msbuild.binlog");

                var artifactsLogDir = Assembly.GetExecutingAssembly()
                                      .GetCustomAttributes <AssemblyMetadataAttribute>()
                                      .FirstOrDefault(ama => ama.Key == "ArtifactsLogDir")?.Value;

                if (!string.IsNullOrEmpty(artifactsLogDir) && File.Exists(binaryLogFile))
                {
                    var targetPath = Path.Combine(artifactsLogDir, Path.GetFileNameWithoutExtension(project.ProjectFilePath) + "." + Path.GetRandomFileName() + ".binlog");
                    File.Copy(binaryLogFile, targetPath);

                    throw new TimeoutException(ex.Message + $"{Environment.NewLine}Captured binlog at {targetPath}");
                }

                throw;
            }

            return(new MSBuildResult(project, processResult.FileName, processResult.Arguments, processResult.ExitCode, processResult.Output));
        }
        public static Task <MSBuildResult> RunProcessAsync(
            ProjectDirectory project,
            string arguments,
            TimeSpan?timeout = null,
            MSBuildProcessKind msBuildProcessKind = MSBuildProcessKind.Dotnet)
        {
            timeout = timeout ?? TimeSpan.FromSeconds(60);

            var processStartInfo = new ProcessStartInfo()
            {
                WorkingDirectory       = project.DirectoryPath,
                UseShellExecute        = false,
                RedirectStandardError  = true,
                RedirectStandardOutput = true,
            };

            if (msBuildProcessKind == MSBuildProcessKind.Desktop)
            {
                if (string.IsNullOrEmpty(BuildVariables.MSBuildPath))
                {
                    throw new ArgumentException("Unable to locate MSBuild.exe to run desktop tests. " +
                                                "MSBuild.exe is located using state created as part of running build[cmd|sh] at the root of the repository. Run build /t:Prepare to set this up if this hasn't been done.");
                }

                processStartInfo.FileName  = BuildVariables.MSBuildPath;
                processStartInfo.Arguments = arguments;
            }
            else
            {
                processStartInfo.FileName  = "dotnet";
                processStartInfo.Arguments = $"msbuild {arguments}";
            }

            var process = new Process()
            {
                StartInfo           = processStartInfo,
                EnableRaisingEvents = true,
            };

            var output     = new StringBuilder();
            var outputLock = new object();

            process.ErrorDataReceived  += Process_ErrorDataReceived;
            process.OutputDataReceived += Process_OutputDataReceived;

            process.Start();
            process.BeginErrorReadLine();
            process.BeginOutputReadLine();

            var timeoutTask = Task.Delay(timeout.Value).ContinueWith((t) =>
            {
                // Don't timeout during debug sessions
                while (Debugger.IsAttached)
                {
                    Thread.Sleep(TimeSpan.FromSeconds(1));
                }

                if (process.HasExited)
                {
                    // This will happen on success, the 'real' task has already completed so this value will
                    // never be visible.
                    return((MSBuildResult)null);
                }

                // This is a timeout.
                process.Kill();
                throw new TimeoutException($"command '${process.StartInfo.FileName} {process.StartInfo.Arguments}' timed out after {timeout}.");
            });

            var waitTask = Task.Run(() =>
            {
                // We need to use two WaitForExit calls to ensure that all of the output/events are processed. Previously
                // this code used Process.Exited, which could result in us missing some output due to the ordering of
                // events.
                //
                // See the remarks here: https://msdn.microsoft.com/en-us/library/ty0d8k56(v=vs.110).aspx
                if (!process.WaitForExit(Int32.MaxValue))
                {
                    // unreachable - the timeoutTask will kill the process before this happens.
                    throw new TimeoutException();
                }

                process.WaitForExit();

                string outputString;
                lock (outputLock)
                {
                    outputString = output.ToString();
                }

                var result = new MSBuildResult(project, process.StartInfo.FileName, process.StartInfo.Arguments, process.ExitCode, outputString);
                return(result);
            });

            return(Task.WhenAny <MSBuildResult>(waitTask, timeoutTask).Unwrap());

            void Process_ErrorDataReceived(object sender, DataReceivedEventArgs e)
            {
                lock (outputLock)
                {
                    output.AppendLine(e.Data);
                }
            }

            void Process_OutputDataReceived(object sender, DataReceivedEventArgs e)
            {
                lock (outputLock)
                {
                    output.AppendLine(e.Data);
                }
            }
        }
Exemple #11
0
        private static void AddFileToProject(ProjectDirectory project, string filename, string content)
        {
            var path = Path.Combine(project.DirectoryPath, filename);

            File.WriteAllText(path, content);
        }
Exemple #12
0
        // Regression test for https://github.com/dotnet/aspnetcore/issues/18752
        public async Task Publish_HostedApp_WithoutTrimming_Works()
        {
            // Arrange
            using var project = ProjectDirectory.Create("blazorhosted", additionalProjects: new[] { "blazorwasm", "razorclasslibrary", });
            AddWasmProjectContent(project, @"
        <PropertyGroup>
            <PublishTrimmed>false</PublishTrimmed>
        </PropertyGroup>");

            // VS builds projects individually and then a publish with BuildDependencies=false, but building the main project is a close enough approximation for this test.
            var result = await MSBuildProcessManager.DotnetMSBuild(project, "Build");

            Assert.BuildPassed(result);

            // Publish
            result = await MSBuildProcessManager.DotnetMSBuild(project, "Publish", "/p:BuildDependencies=false");

            var publishDirectory = project.PublishOutputDirectory;

            // Make sure the main project exists
            Assert.FileExists(result, publishDirectory, "blazorhosted.dll");

            // Verification for https://github.com/dotnet/aspnetcore/issues/19926. Verify binaries for projects
            // referenced by the Hosted project appear in the publish directory
            Assert.FileExists(result, publishDirectory, "RazorClassLibrary.dll");
            Assert.FileExists(result, publishDirectory, "blazorwasm.dll");

            var blazorPublishDirectory = Path.Combine(publishDirectory, "wwwroot");

            Assert.FileExists(result, blazorPublishDirectory, "_framework", "blazor.boot.json");
            Assert.FileExists(result, blazorPublishDirectory, "_framework", "dotnet.wasm");
            Assert.FileExists(result, blazorPublishDirectory, "_framework", DotNetJsFileName);
            Assert.FileExists(result, blazorPublishDirectory, "_framework", "blazorwasm.dll");
            Assert.FileExists(result, blazorPublishDirectory, "_framework", "System.Text.Json.dll"); // Verify dependencies are part of the output.

            // Verify project references appear as static web assets
            Assert.FileExists(result, blazorPublishDirectory, "_framework", "RazorClassLibrary.dll");
            // Also verify project references to the server project appear in the publish output
            Assert.FileExists(result, publishDirectory, "RazorClassLibrary.dll");

            // Verify static assets are in the publish directory
            Assert.FileExists(result, blazorPublishDirectory, "index.html");

            // Verify static web assets from referenced projects are copied.
            Assert.FileExists(result, publishDirectory, "wwwroot", "_content", "RazorClassLibrary", "wwwroot", "exampleJsInterop.js");
            Assert.FileExists(result, publishDirectory, "wwwroot", "_content", "RazorClassLibrary", "styles.css");

            // Verify web.config
            Assert.FileExists(result, publishDirectory, "web.config");

            VerifyBootManifestHashes(result, blazorPublishDirectory);

            // Verify compression works
            Assert.FileExists(result, blazorPublishDirectory, "_framework", "dotnet.wasm.br");
            Assert.FileExists(result, blazorPublishDirectory, "_framework", "blazorwasm.dll.br");
            Assert.FileExists(result, blazorPublishDirectory, "_framework", "RazorClassLibrary.dll.br");
            Assert.FileExists(result, blazorPublishDirectory, "_framework", "System.Text.Json.dll.br");

            Assert.FileExists(result, blazorPublishDirectory, "_framework", "dotnet.wasm.gz");
            Assert.FileExists(result, blazorPublishDirectory, "_framework", "blazorwasm.dll.gz");
            Assert.FileExists(result, blazorPublishDirectory, "_framework", "RazorClassLibrary.dll.gz");
            Assert.FileExists(result, blazorPublishDirectory, "_framework", "System.Text.Json.dll.gz");

            VerifyServiceWorkerFiles(result, blazorPublishDirectory,
                                     serviceWorkerPath: Path.Combine("serviceworkers", "my-service-worker.js"),
                                     serviceWorkerContent: "// This is the production service worker",
                                     assetsManifestPath: "custom-service-worker-assets.js");
        }