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
2 changes: 1 addition & 1 deletion src/Aspire.Dashboard/Components/Pages/Login.razor
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
</div>
<div class="token-entry-footer">
<a href="@NavigationManager.Uri" id="helpLink">@Loc[nameof(Dashboard.Resources.Login.WhereIsMyTokenLinkText)]</a>
<FluentButton Appearance="Appearance.Accent" Type="ButtonType.Submit">@Loc[nameof(Dashboard.Resources.Login.LogInButtonText)]</FluentButton>
<FluentButton Appearance="Appearance.Accent" Name="submit-token" Type="ButtonType.Submit">@Loc[nameof(Dashboard.Resources.Login.LogInButtonText)]</FluentButton>
<FluentTooltip Anchor="helpLink" MaxWidth="650px">
<div class="token-help-container">
<div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,18 @@
// The .NET Foundation licenses this file to you under the MIT license.

using Aspire.Dashboard.Resources;
using Aspire.Dashboard.Tests.Integration.Playwright.Infrastructure;
using Aspire.Workload.Tests;
using Microsoft.Playwright;
using Xunit;

namespace Aspire.Dashboard.Tests.Integration.Playwright;

[ActiveIssue("https://github.com/dotnet/aspire/issues/4623", typeof(PlaywrightProvider), nameof(PlaywrightProvider.DoesNotHavePlaywrightSupport))]
public class AppBarTests : PlaywrightTestsBase
public class AppBarTests : PlaywrightTestsBase<DashboardServerFixture>
{
public AppBarTests(DashboardServerFixture dashboardServerFixture, PlaywrightFixture playwrightFixture)
: base(dashboardServerFixture, playwrightFixture)
public AppBarTests(DashboardServerFixture dashboardServerFixture)
: base(dashboardServerFixture)
{
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
// 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.Configuration;
using Aspire.Dashboard.Tests.Integration.Playwright.Infrastructure;
using Aspire.Hosting;
using Aspire.Workload.Tests;
using Microsoft.Playwright;
using Xunit;

namespace Aspire.Dashboard.Tests.Integration.Playwright;

[ActiveIssue("https://github.com/dotnet/aspire/issues/4623", typeof(PlaywrightProvider), nameof(PlaywrightProvider.DoesNotHavePlaywrightSupport))]
public class BrowserTokenAuthenticationTests : PlaywrightTestsBase<BrowserTokenAuthenticationTests.BrowserTokenDashboardServerFixture>
{
public class BrowserTokenDashboardServerFixture : DashboardServerFixture
{
public BrowserTokenDashboardServerFixture()
{
Configuration[DashboardConfigNames.DashboardFrontendAuthModeName.ConfigKey] = nameof(FrontendAuthMode.BrowserToken);
Configuration[DashboardConfigNames.DashboardFrontendBrowserTokenName.ConfigKey] = "VALID_TOKEN";
}
}

public BrowserTokenAuthenticationTests(BrowserTokenDashboardServerFixture dashboardServerFixture)
: base(dashboardServerFixture)
{
}

[Fact]
public async Task BrowserToken_LoginPage_Success_RedirectToResources()
{
// Arrange
await RunTestAsync(async page =>
{
// Act
var response = await page.GotoAsync("/");
var uri = new Uri(response!.Url);

Assert.Equal("/login?returnUrl=%2F", uri.PathAndQuery);

var tokenTextBox = page.GetByRole(AriaRole.Textbox);
await tokenTextBox.FillAsync("VALID_TOKEN");

var submitButton = page.GetByRole(AriaRole.Button);
await submitButton.ClickAsync();

// Assert
await Assertions
.Expect(page.GetByText(MockDashboardClient.TestResource1.DisplayName))
.ToBeVisibleAsync();
});
}

[Fact]
public async Task BrowserToken_LoginPage_Failure_DisplayFailureMessage()
{
// Arrange
await RunTestAsync(async page =>
{
// Act
var response = await page.GotoAsync("/");
var uri = new Uri(response!.Url);

Assert.Equal("/login?returnUrl=%2F", uri.PathAndQuery);

var tokenTextBox = page.GetByRole(AriaRole.Textbox);
await tokenTextBox.FillAsync("INVALID_TOKEN");

var submitButton = page.GetByRole(AriaRole.Button);
await submitButton.ClickAsync();

// Assert
await Assertions
.Expect(page.GetByText("Invalid token"))
.ToBeVisibleAsync();
});
}

[Fact]
public async Task BrowserToken_QueryStringToken_Success_RestrictToResources()
{
// Arrange
await RunTestAsync(async page =>
{
// Act
await page.GotoAsync("/login?t=VALID_TOKEN");

// Assert
await Assertions
.Expect(page.GetByText(MockDashboardClient.TestResource1.DisplayName))
.ToBeVisibleAsync();
});
}

[Fact]
public async Task BrowserToken_QueryStringToken_Failure_DisplayLoginPage()
{
// Arrange
await RunTestAsync(async page =>
{
// Act
await page.GotoAsync("/login?t=INVALID_TOKEN");

var submitButton = page.GetByRole(AriaRole.Button);
var name = await submitButton.GetAttributeAsync("name");

// Assert
Assert.Equal("submit-token", name);
});
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Licensed to the .NET Foundation under one or more agreements.
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Reflection;
Expand All @@ -11,28 +11,40 @@
using Microsoft.Extensions.DependencyInjection.Extensions;
using Xunit;

namespace Aspire.Dashboard.Tests.Integration.Playwright;
namespace Aspire.Dashboard.Tests.Integration.Playwright.Infrastructure;

public class DashboardServerFixture : IAsyncLifetime
{
public Dictionary<string, string?> Configuration { get; }

public DashboardWebApplication DashboardApp { get; private set; } = null!;

public Task InitializeAsync()
// Can't have multiple fixtures when one is generic. Workaround by nesting playwright fixture.
public PlaywrightFixture PlaywrightFixture { get; }

public DashboardServerFixture()
{
const string aspireDashboardAssemblyName = "Aspire.Dashboard";
var currentAssemblyName = Assembly.GetExecutingAssembly().GetName().Name!;
var currentAssemblyDirectory = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)!;
var aspireAssemblyDirectory = currentAssemblyDirectory.Replace(currentAssemblyName, aspireDashboardAssemblyName);
PlaywrightFixture = new PlaywrightFixture();

var initialData = new Dictionary<string, string?>
Configuration = new Dictionary<string, string?>
{
[DashboardConfigNames.DashboardFrontendUrlName.ConfigKey] = "http://127.0.0.1:0",
[DashboardConfigNames.DashboardOtlpHttpUrlName.ConfigKey] = "http://127.0.0.1:0",
[DashboardConfigNames.DashboardOtlpAuthModeName.ConfigKey] = nameof(OtlpAuthMode.Unsecured),
[DashboardConfigNames.DashboardFrontendAuthModeName.ConfigKey] = nameof(FrontendAuthMode.Unsecured)
};
}

public async Task InitializeAsync()
{
await PlaywrightFixture.InitializeAsync();

const string aspireDashboardAssemblyName = "Aspire.Dashboard";
var currentAssemblyName = Assembly.GetExecutingAssembly().GetName().Name!;
var currentAssemblyDirectory = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)!;
var aspireAssemblyDirectory = currentAssemblyDirectory.Replace(currentAssemblyName, aspireDashboardAssemblyName);

var config = new ConfigurationManager().AddInMemoryCollection(initialData).Build();
var config = new ConfigurationManager().AddInMemoryCollection(Configuration).Build();

// Add services to the container.
DashboardApp = new DashboardWebApplication(
Expand All @@ -53,11 +65,12 @@ public Task InitializeAsync()
builder.Services.AddSingleton<IDashboardClient, MockDashboardClient>();
});

return DashboardApp.StartAsync();
await DashboardApp.StartAsync();
}

public Task DisposeAsync()
public async Task DisposeAsync()
{
return DashboardApp.DisposeAsync().AsTask();
await DashboardApp.DisposeAsync();
await PlaywrightFixture.DisposeAsync();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
using Aspire.Dashboard.Model;
using Google.Protobuf.WellKnownTypes;

namespace Aspire.Dashboard.Tests.Integration.Playwright;
namespace Aspire.Dashboard.Tests.Integration.Playwright.Infrastructure;

public sealed class MockDashboardClient : IDashboardClient
{
Expand All @@ -18,7 +18,7 @@ public sealed class MockDashboardClient : IDashboardClient
CreationTimeStamp = DateTime.Now,
Environment = ImmutableArray<EnvironmentVariableViewModel>.Empty,
ResourceType = KnownResourceTypes.Project,
Properties = new []
Properties = new[]
{
new KeyValuePair<string, Value>(KnownProperties.Project.Path, new Value()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
using Microsoft.Playwright;
using Xunit;

namespace Aspire.Dashboard.Tests.Integration.Playwright;
namespace Aspire.Dashboard.Tests.Integration.Playwright.Infrastructure;

public class PlaywrightFixture : IAsyncLifetime
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,22 +1,23 @@
// Licensed to the .NET Foundation under one or more agreements.
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using Microsoft.Playwright;
using Xunit;

namespace Aspire.Dashboard.Tests.Integration.Playwright;
namespace Aspire.Dashboard.Tests.Integration.Playwright.Infrastructure;

public class PlaywrightTestsBase : IClassFixture<DashboardServerFixture>, IClassFixture<PlaywrightFixture>, IAsyncDisposable
public class PlaywrightTestsBase<TDashboardServerFixture> : IClassFixture<TDashboardServerFixture>, IAsyncDisposable
where TDashboardServerFixture : DashboardServerFixture
{
public DashboardServerFixture DashboardServerFixture { get; }
public PlaywrightFixture PlaywrightFixture { get; }

private IBrowserContext? _context;

public PlaywrightTestsBase(DashboardServerFixture dashboardServerFixture, PlaywrightFixture playwrightFixture)
public PlaywrightTestsBase(DashboardServerFixture dashboardServerFixture)
{
DashboardServerFixture = dashboardServerFixture;
PlaywrightFixture = playwrightFixture;
PlaywrightFixture = dashboardServerFixture.PlaywrightFixture;
}

public async Task RunTestAsync(Func<IPage, Task> test)
Expand Down
Loading