LANCommander/LANCommander.Server.UI.Tests/Tests/FirstTimeSetupTests.cs
Pat Hartl 9b5195f1d6 Use web-first Playwright assertions in UI tests
Replace non-waiting Assert.True(await locator.IsVisibleAsync()) checks with
auto-retrying Assertions.Expect(locator).ToBeVisibleAsync()/ToBeHiddenAsync()
to remove flakiness against Blazor's async rendering. Table-row/field page
objects (Metadata/Roles/Users/Profile) now expose ILocator helpers instead of
Task<bool>, so deletion checks wait for the element to disappear.

Also: rename ScreenshotHelper.CaptureIfFailedAsync to CaptureAsync (xUnit v2
cannot expose the test outcome to DisposeAsync, so it always captures the final
page state), drop the unused TestConstants.ServerPort/BaseUrl now that ports
bind dynamically, and fix IClassFixture doc comments to ICollectionFixture.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-06-23 17:51:34 -05:00

107 lines
4.1 KiB
C#

using LANCommander.Server.UI.Tests.Pages;
using Microsoft.Playwright;
using Xunit.Abstractions;
namespace LANCommander.Server.UI.Tests.Tests;
/// <summary>
/// Tests for the first-time setup wizard when the server has no existing configuration.
/// Runs in its own collection to avoid conflicts with ConfiguredServerFixture over
/// the static DatabaseContext.Provider.
/// </summary>
[Collection("FirstTimeSetup")]
public class FirstTimeSetupTests : IAsyncLifetime
{
private readonly FreshServerFixture _fixture;
private readonly ITestOutputHelper _output;
private IBrowserContext _context = null!;
private IPage _page = null!;
public FirstTimeSetupTests(FreshServerFixture fixture, ITestOutputHelper output)
{
_fixture = fixture;
_output = output;
}
public async Task InitializeAsync()
{
(_context, _page) = await _fixture.CreatePageAsync();
}
public async Task DisposeAsync()
{
await ScreenshotHelper.CaptureAsync(_page, _output);
if (_page != null) await _page.CloseAsync();
if (_context != null) await _context.DisposeAsync();
}
[Fact]
public async Task FreshServer_RedirectsToFirstTimeSetup()
{
await _page.GotoAsync("/");
// A fresh server should show the First Time Setup page
await _page.WaitForSelectorAsync("text=First Time Setup", new() { Timeout = 10000 });
var setupPage = new FirstTimeSetupPage(_page);
Assert.True(await setupPage.IsDisplayedAsync());
}
[Fact]
public async Task FirstTimeSetup_ShowsFourSteps()
{
var setupPage = new FirstTimeSetupPage(_page);
await setupPage.NavigateAsync();
// Verify all 4 steps are visible in the wizard
await Assertions.Expect(_page.GetByText("Database").First).ToBeVisibleAsync();
await Assertions.Expect(_page.GetByText("Paths")).ToBeVisibleAsync();
// "Metadata" may be truncated in UI to "Metad" but the text node still exists
await Assertions.Expect(_page.Locator("text=/Metad/").First).ToBeVisibleAsync();
await Assertions.Expect(_page.GetByText("Administrator")).ToBeVisibleAsync();
}
[Fact]
public async Task FirstTimeSetup_DatabaseStep_ShowsProviderOptions()
{
var setupPage = new FirstTimeSetupPage(_page);
await setupPage.NavigateAsync();
// Open the database provider dropdown
await _page.GetByRole(AriaRole.Combobox).ClickAsync();
// Wait for the dropdown listbox to appear
await _page.WaitForSelectorAsync("[role='listbox']", new() { Timeout = 5000 });
// Verify all expected providers are shown
await Assertions.Expect(_page.GetByRole(AriaRole.Option, new() { Name = "SQLite" })).ToBeVisibleAsync();
await Assertions.Expect(_page.GetByRole(AriaRole.Option, new() { Name = "MySQL" })).ToBeVisibleAsync();
await Assertions.Expect(_page.GetByRole(AriaRole.Option, new() { Name = "PostgreSQL" })).ToBeVisibleAsync();
}
[Fact(Skip = "Requires real database and file I/O - not supported with in-memory WebApplicationFactory")]
public async Task FirstTimeSetup_CompleteWizardAndLogin()
{
var setupPage = new FirstTimeSetupPage(_page);
await setupPage.NavigateAsync();
await setupPage.CompleteFullSetupAsync(
adminUsername: TestConstants.AdminUserName,
adminPassword: TestConstants.AdminPassword);
// After setup, we should be on the login page
Assert.Contains("/Login", _page.Url);
var loginPage = new LoginPage(_page);
Assert.True(await loginPage.IsDisplayedAsync());
// Now log in with the admin credentials that were just created
await loginPage.LoginAsync(TestConstants.AdminUserName, TestConstants.AdminPassword);
// Wait for the Blazor app to render the dashboard
await _page.WaitForSelectorAsync("text=Dashboard", new() { Timeout = 15000 });
var dashboard = new AdminDashboardPage(_page);
Assert.True(await dashboard.IsDisplayedAsync());
}
}