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>
107 lines
4.1 KiB
C#
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());
|
|
}
|
|
}
|