Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 9 additions & 6 deletions src/Aspire.Dashboard/Components/Pages/Login.razor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,15 @@ public partial class Login : IAsyncDisposable

protected override async Task OnInitializedAsync()
{
// Create EditContext before awaiting. This is required to prevent an await in OnInitializedAsync
// triggering parameters being set on EditForm before EditContext is created.
// If that happens then EditForm errors that it requires an EditContext.
_formModel = new TokenFormModel();
EditContext = new EditContext(_formModel);
_messageStore = new(EditContext);
EditContext.OnValidationRequested += (s, e) => _messageStore.Clear();
EditContext.OnFieldChanged += (s, e) => _messageStore.Clear(e.FieldIdentifier);

// If the browser is already authenticated then redirect to the app.
if (AuthenticationState is { } authStateTask)
{
Expand All @@ -48,12 +57,6 @@ protected override async Task OnInitializedAsync()
return;
}
}

_formModel = new TokenFormModel();
EditContext = new EditContext(_formModel);
_messageStore = new(EditContext);
EditContext.OnValidationRequested += (s, e) => _messageStore.Clear();
EditContext.OnFieldChanged += (s, e) => _messageStore.Clear(e.FieldIdentifier);
}

protected override async Task OnAfterRenderAsync(bool firstRender)
Expand Down
73 changes: 73 additions & 0 deletions tests/Aspire.Dashboard.Components.Tests/Pages/LoginTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
// 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.Components.Tests.Shared;
using Aspire.Dashboard.Model;
using Bunit;
using Microsoft.AspNetCore.Components.Authorization;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Localization;
using Microsoft.Extensions.Logging;
using Microsoft.FluentUI.AspNetCore.Components;
using Xunit;
using Xunit.Abstractions;

namespace Aspire.Dashboard.Components.Tests.Pages;

[UseCulture("en-US")]
public partial class LoginTests : TestContext
{
private readonly ITestOutputHelper _testOutputHelper;

public LoginTests(ITestOutputHelper testOutputHelper)
{
_testOutputHelper = testOutputHelper;
}

[Fact]
public void Initialize_LongRunningAuthStateFunc_EditContextSet()
{
// Arrange
SetupLoginServices();

// This represents a long running auth state task.
var tcs = new TaskCompletionSource<AuthenticationState>(TaskCreationOptions.RunContinuationsAsynchronously);

// Act
var cut = RenderComponent<Components.Pages.Login>(builder =>
{
builder.Add(p => p.AuthenticationState, tcs.Task);
});

var instance = cut.Instance;
var logger = Services.GetRequiredService<ILogger<ConsoleLogsTests>>();
var loc = Services.GetRequiredService<IStringLocalizer<Resources.ConsoleLogs>>();

cut.WaitForState(() => instance.EditContext != null);
}

private void SetupLoginServices()
{
var version = typeof(FluentMain).Assembly.GetName().Version!;

JSInterop.SetupModule("/Components/Pages/Login.razor.js");

JSInterop.SetupModule(GetFluentFile("./_content/Microsoft.FluentUI.AspNetCore.Components/Components/Anchor/FluentAnchor.razor.js", version));

var textboxModule = JSInterop.SetupModule(GetFluentFile("./_content/Microsoft.FluentUI.AspNetCore.Components/Components/TextField/FluentTextField.razor.js", version));
textboxModule.SetupVoid("setControlAttribute", _ => true);

var loggerFactory = IntegrationTestHelpers.CreateLoggerFactory(_testOutputHelper);

Services.AddLocalization();
Services.AddSingleton<ILoggerFactory>(loggerFactory);
Services.AddSingleton<IDashboardClient>(new TestDashboardClient());
Services.AddSingleton<LibraryConfiguration>();
Services.AddSingleton<IKeyCodeService, KeyCodeService>();
}

private static string GetFluentFile(string filePath, Version version)
{
return $"{filePath}?v={version}";
}
}