File: Hosting\WebAssemblyHostTest.cs
Web Access
Project: src\src\Components\WebAssembly\WebAssembly\test\Microsoft.AspNetCore.Components.WebAssembly.Tests.csproj (Microsoft.AspNetCore.Components.WebAssembly.Tests)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
using System.Globalization;
using System.Text.Json;
using Microsoft.AspNetCore.InternalTesting;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.JSInterop;
using Moq;
 
namespace Microsoft.AspNetCore.Components.WebAssembly.Hosting;
 
public class WebAssemblyHostTest
{
    // This won't happen in the product code, but we need to be able to safely call RunAsync
    // to be able to test a few of the other details.
    [Fact]
    public async Task RunAsync_CanExitBasedOnCancellationToken()
    {
        // Arrange
        var builder = new WebAssemblyHostBuilder(new TestInternalJSImportMethods());
        builder.Services.AddSingleton(Mock.Of<IJSRuntime>());
        var host = builder.Build();
        var cultureProvider = new TestSatelliteResourcesLoader();
 
        var cts = new CancellationTokenSource();
 
        // Act
        var task = host.RunAsyncCore(cts.Token, cultureProvider);
 
        cts.Cancel();
        await task.TimeoutAfter(TimeSpan.FromSeconds(3));
 
        // Assert (does not throw)
    }
 
    [Fact]
    public async Task RunAsync_CallingTwiceCausesException()
    {
        // Arrange
        var builder = new WebAssemblyHostBuilder(new TestInternalJSImportMethods());
        builder.Services.AddSingleton(Mock.Of<IJSRuntime>());
        var host = builder.Build();
        var cultureProvider = new TestSatelliteResourcesLoader();
 
        var cts = new CancellationTokenSource();
        var task = host.RunAsyncCore(cts.Token, cultureProvider);
 
        // Act
        var ex = await Assert.ThrowsAsync<InvalidOperationException>(() => host.RunAsyncCore(cts.Token));
 
        cts.Cancel();
        await task.TimeoutAfter(TimeSpan.FromSeconds(3));
 
        // Assert
        Assert.Equal("The host has already started.", ex.Message);
    }
 
    [Fact]
    public async Task DisposeAsync_CanDisposeAfterCallingRunAsync()
    {
        // Arrange
        var builder = new WebAssemblyHostBuilder(new TestInternalJSImportMethods());
        builder.Services.AddSingleton(Mock.Of<IJSRuntime>());
        builder.Services.AddSingleton<DisposableService>();
        var host = builder.Build();
        var cultureProvider = new TestSatelliteResourcesLoader();
 
        var disposable = host.Services.GetRequiredService<DisposableService>();
 
        var cts = new CancellationTokenSource();
 
        // Act
        await using (host)
        {
            var task = host.RunAsyncCore(cts.Token, cultureProvider);
 
            cts.Cancel();
            await task.TimeoutAfter(TimeSpan.FromSeconds(3));
        }
 
        // Assert
        Assert.Equal(1, disposable.DisposeCount);
    }
 
    private class DisposableService : IAsyncDisposable
    {
        public int DisposeCount { get; private set; }
 
        public ValueTask DisposeAsync()
        {
            DisposeCount++;
            return new ValueTask(Task.CompletedTask);
        }
    }
 
    private class TestSatelliteResourcesLoader : WebAssemblyCultureProvider
    {
        internal TestSatelliteResourcesLoader()
            : base(CultureInfo.CurrentCulture, CultureInfo.CurrentUICulture)
        {
        }
 
        public override ValueTask LoadCurrentCultureResourcesAsync() => default;
    }
}