File: Shared\TestJSObjectReference.cs
Web Access
Project: src\tests\Aspire.Dashboard.Components.Tests\Aspire.Dashboard.Components.Tests.csproj (Aspire.Dashboard.Components.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.Collections.Concurrent;
using Bunit;
using Microsoft.JSInterop;
 
namespace Aspire.Dashboard.Components.Tests.Shared;
 
internal sealed class TestJSObjectReference : IJSObjectReference
{
    private int _disposeCount;
 
    public ConcurrentQueue<Invocation> Invocations { get; } = new();
    public Func<string, Task>? BeforeInvokeAsync { get; init; }
    public int DisposeCount => Volatile.Read(ref _disposeCount);
 
    public static JSRuntimeInvocationHandler<IJSObjectReference> SetupImport(BunitContext context, string modulePath)
    {
        // A custom handler lets tests delay import and count disposal of the returned reference.
        var handler = new ImportHandler(modulePath);
        context.JSInterop.AddInvocationHandler(handler);
        return handler;
    }
 
    public ValueTask<TValue> InvokeAsync<TValue>(string identifier, object?[]? args)
        => InvokeAsync<TValue>(identifier, CancellationToken.None, args);
 
    public async ValueTask<TValue> InvokeAsync<TValue>(string identifier, CancellationToken cancellationToken, object?[]? args)
    {
        ObjectDisposedException.ThrowIf(DisposeCount != 0, this);
        Invocations.Enqueue(new(identifier, args ?? []));
        if (BeforeInvokeAsync is { } beforeInvoke)
        {
            await beforeInvoke(identifier);
        }
        return default!;
    }
 
    public ValueTask DisposeAsync()
    {
        Interlocked.Increment(ref _disposeCount);
        return ValueTask.CompletedTask;
    }
 
    public sealed record Invocation(string Identifier, object?[] Arguments);
 
    private sealed class ImportHandler(string modulePath) : JSRuntimeInvocationHandler<IJSObjectReference>(
        invocation => invocation.Identifier == "import" && Equals(invocation.Arguments[0], modulePath),
        isCatchAllHandler: false);
}