| File: Model\ParameterInteractionStateTests.cs | Web Access |
| Project: src\tests\Aspire.Dashboard.Tests\Aspire.Dashboard.Tests.csproj (Aspire.Dashboard.Tests) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using Aspire.Dashboard.Model; using Aspire.Dashboard.Model.Interaction; using Aspire.Dashboard.Tests.Shared; using Aspire.DashboardService.Proto.V1; using Microsoft.AspNetCore.InternalTesting; using Xunit; namespace Aspire.Dashboard.Tests.Model; public sealed class ParameterInteractionStateTests { [Fact] public void TrySetCurrent_NoPanel_NotShownInline() { var state = new ParameterInteractionState(); Assert.False(state.TrySetCurrent(CreateInputsInteraction(1, "first"))); Assert.Null(state.Current); } [Fact] public void TrySetCurrent_PanelShowsEveryInput_ShownInline() { var state = new ParameterInteractionState(); using var panel = state.RegisterPanel(); panel.SetParameterNames(["first", "second"]); var interaction = CreateInputsInteraction(1, "first", "second", ParameterInteractionState.SaveToUserSecretsInputName); Assert.True(state.TrySetCurrent(interaction)); Assert.Same(interaction, state.Current); Assert.True(panel.Shows(interaction)); } [Fact] public void TrySetCurrent_PanelShowsSomeInputs_NotShownInline() { var state = new ParameterInteractionState(); using var panel = state.RegisterPanel(); panel.SetParameterNames(["first"]); Assert.False(state.TrySetCurrent(CreateInputsInteraction(1, "first", "second"))); Assert.Null(state.Current); } [Fact] public void TrySetCurrent_InteractionWithoutParameterInputs_NotShownInline() { var state = new ParameterInteractionState(); using var panel = state.RegisterPanel(); panel.SetParameterNames(["first"]); Assert.False(state.TrySetCurrent(CreateInputsInteraction(1, ParameterInteractionState.SaveToUserSecretsInputName))); } [Fact] public void PanelDisposed_CurrentReleased() { var state = new ParameterInteractionState(); var panel = state.RegisterPanel(); panel.SetParameterNames(["first"]); var interaction = CreateInputsInteraction(1, "first"); Assert.True(state.TrySetCurrent(interaction)); var released = new List<InteractionsInputsDialogViewModel>(); state.Released += released.Add; panel.Dispose(); Assert.Null(state.Current); Assert.Same(interaction, Assert.Single(released)); } [Fact] public void PanelParametersNarrowed_CurrentReleased() { var state = new ParameterInteractionState(); using var panel = state.RegisterPanel(); panel.SetParameterNames(["first", "second"]); var interaction = CreateInputsInteraction(1, "first", "second"); Assert.True(state.TrySetCurrent(interaction)); var released = new List<InteractionsInputsDialogViewModel>(); state.Released += released.Add; panel.SetParameterNames(["first"]); Assert.Null(state.Current); Assert.Same(interaction, Assert.Single(released)); } [Fact] public void PanelDisposed_AnotherPanelShowsCurrent_NotReleased() { var state = new ParameterInteractionState(); var panel = state.RegisterPanel(); panel.SetParameterNames(["first"]); using var otherPanel = state.RegisterPanel(); otherPanel.SetParameterNames(["first"]); var interaction = CreateInputsInteraction(1, "first"); Assert.True(state.TrySetCurrent(interaction)); var released = new List<InteractionsInputsDialogViewModel>(); state.Released += released.Add; panel.Dispose(); Assert.Same(interaction, state.Current); Assert.Empty(released); } [Fact] public void Clear_CurrentCompleted_NotReleased() { var state = new ParameterInteractionState(); var panel = state.RegisterPanel(); panel.SetParameterNames(["first"]); Assert.True(state.TrySetCurrent(CreateInputsInteraction(1, "first"))); var released = new List<InteractionsInputsDialogViewModel>(); state.Released += released.Add; state.Clear(1); panel.Dispose(); Assert.Null(state.Current); Assert.Empty(released); } [Fact] public void SetDialogInteraction_PanelMountedLater_TakesInteractionFromDialog() { var state = new ParameterInteractionState(); var interaction = CreateInputsInteraction(1, "first", ParameterInteractionState.SaveToUserSecretsInputName); var closeCount = 0; state.SetDialogInteraction(interaction, () => { closeCount++; return Task.CompletedTask; }); Assert.Null(state.Current); // After a reload on the form, the prompt is replayed before the form is rendered. using var panel = state.RegisterPanel(); panel.SetParameterNames(["first"]); Assert.Same(interaction, state.Current); Assert.Equal(1, closeCount); } [Fact] public void SetDialogInteraction_PanelShowsSomeInputs_KeepsDialog() { var state = new ParameterInteractionState(); var closeCount = 0; state.SetDialogInteraction(CreateInputsInteraction(1, "first", "second"), () => { closeCount++; return Task.CompletedTask; }); using var panel = state.RegisterPanel(); panel.SetParameterNames(["first"]); Assert.Null(state.Current); Assert.Equal(0, closeCount); } [Fact] public void ClearDialogInteraction_DialogClosed_PanelDoesNotTakeInteraction() { var state = new ParameterInteractionState(); var closeCount = 0; state.SetDialogInteraction(CreateInputsInteraction(1, "first"), () => { closeCount++; return Task.CompletedTask; }); state.ClearDialogInteraction(1); using var panel = state.RegisterPanel(); panel.SetParameterNames(["first"]); Assert.Null(state.Current); Assert.Equal(0, closeCount); } [Fact] public async Task BeginInteractionAsync_PanelShowsEveryParameter_AcceptsNotificationOnce() { var state = new ParameterInteractionState(); var acceptCount = 0; state.SetNotification(1, ["first", "second"], () => { acceptCount++; return Task.CompletedTask; }); using var panel = state.RegisterPanel(); panel.SetParameterNames(["first", "second"]); await state.BeginInteractionAsync(panel).DefaultTimeout(); await state.BeginInteractionAsync(panel).DefaultTimeout(); Assert.Equal(1, acceptCount); } [Fact] public async Task BeginInteractionAsync_PanelShowsSomeParameters_DoesNotAcceptNotification() { var state = new ParameterInteractionState(); var acceptCount = 0; state.SetNotification(1, ["first", "second"], () => { acceptCount++; return Task.CompletedTask; }); using var panel = state.RegisterPanel(); panel.SetParameterNames(["first"]); await state.BeginInteractionAsync(panel).DefaultTimeout(); Assert.Equal(0, acceptCount); } [Fact] public async Task BeginInteractionAsync_NotificationCompleted_DoesNotAcceptNotification() { var state = new ParameterInteractionState(); var acceptCount = 0; state.SetNotification(1, ["first"], () => { acceptCount++; return Task.CompletedTask; }); // The user dismissed the notification before opening the form. state.Clear(1); using var panel = state.RegisterPanel(); panel.SetParameterNames(["first"]); await state.BeginInteractionAsync(panel).DefaultTimeout(); Assert.Equal(0, acceptCount); } [Fact] public async Task BeginInteractionAsync_NextNotificationAfterCompletion_AcceptsNextNotification() { var state = new ParameterInteractionState(); var acceptedNotifications = new List<int>(); using var panel = state.RegisterPanel(); panel.SetParameterNames(["first"]); state.SetNotification(1, ["first"], () => { acceptedNotifications.Add(1); return Task.CompletedTask; }); await state.BeginInteractionAsync(panel).DefaultTimeout(); state.Clear(1); // The AppHost sends a new notification when a parameter is still missing after the previous prompt. state.SetNotification(2, ["first"], () => { acceptedNotifications.Add(2); return Task.CompletedTask; }); await state.BeginInteractionAsync(panel).DefaultTimeout(); Assert.Equal([1, 2], acceptedNotifications); } private static InteractionsInputsDialogViewModel CreateInputsInteraction(int interactionId, params string[] inputNames) { var inputsDialog = new InteractionInputsDialog(); inputsDialog.InputItems.AddRange(inputNames.Select(name => new InteractionInput { Name = name, InputType = InputType.Text })); return new InteractionsInputsDialogViewModel { Interaction = new WatchInteractionsResponseUpdate { InteractionId = interactionId, InputsDialog = inputsDialog }, OnSubmitCallback = (_, _) => Task.CompletedTask, Message = string.Empty, DashboardClient = new TestDashboardClient() }; } }