diff --git a/LANCommander.Server.UI.Tests/ConfiguredServerFixture.cs b/LANCommander.Server.UI.Tests/ConfiguredServerFixture.cs
index a35ddd6a..5d316ea6 100644
--- a/LANCommander.Server.UI.Tests/ConfiguredServerFixture.cs
+++ b/LANCommander.Server.UI.Tests/ConfiguredServerFixture.cs
@@ -11,8 +11,8 @@ namespace LANCommander.Server.UI.Tests;
///
/// Shared fixture that starts the server via WebApplicationFactory, programmatically creates
-/// the admin user, and makes it available for all tests in a class.
-/// Used via IClassFixture<ConfiguredServerFixture>.
+/// the admin user, and makes it available for all tests in the collection.
+/// Shared across the "Server" collection via ICollectionFixture<ConfiguredServerFixture>.
///
public class ConfiguredServerFixture : IAsyncLifetime
{
diff --git a/LANCommander.Server.UI.Tests/Pages/MetadataPage.cs b/LANCommander.Server.UI.Tests/Pages/MetadataPage.cs
index 1c684a58..de01d321 100644
--- a/LANCommander.Server.UI.Tests/Pages/MetadataPage.cs
+++ b/LANCommander.Server.UI.Tests/Pages/MetadataPage.cs
@@ -44,11 +44,14 @@ public class MetadataPage
await _page.WaitForSelectorAsync(".ant-modal", new() { State = WaitForSelectorState.Hidden, Timeout = 5000 });
}
- public async Task IsItemVisibleAsync(string name)
+ ///
+ /// Locator for an item row's name cell within the table body.
+ /// Use with web-first assertions, e.g. Expect(page.Item("Action")).ToBeVisibleAsync().
+ ///
+ public ILocator Item(string name)
{
// Look for the name text within the table body
- var cell = _page.Locator(".ant-table-tbody").GetByText(name, new() { Exact = true });
- return await cell.IsVisibleAsync();
+ return _page.Locator(".ant-table-tbody").GetByText(name, new() { Exact = true });
}
public async Task EditItemAsync(string oldName, string newName)
diff --git a/LANCommander.Server.UI.Tests/Pages/ProfilePage.cs b/LANCommander.Server.UI.Tests/Pages/ProfilePage.cs
index 9b63d075..ee2c1238 100644
--- a/LANCommander.Server.UI.Tests/Pages/ProfilePage.cs
+++ b/LANCommander.Server.UI.Tests/Pages/ProfilePage.cs
@@ -28,11 +28,14 @@ public class ProfilePage
return await input.InputValueAsync();
}
- public async Task HasFieldAsync(string label)
+ ///
+ /// Locator for a form field (text or password) with the given label.
+ /// Use with web-first assertions, e.g. Expect(page.Field("Username")).ToBeVisibleAsync().
+ ///
+ public ILocator Field(string label)
{
- return await _page.Locator(".ant-form-item")
- .Filter(new() { HasText = label })
- .IsVisibleAsync();
+ return _page.Locator(".ant-form-item")
+ .Filter(new() { HasText = label });
}
public async Task SetAliasAsync(string alias)
@@ -69,13 +72,6 @@ public class ProfilePage
await _page.WaitForSelectorAsync("text=Change Password", new() { Timeout = 10000 });
}
- public async Task HasPasswordFieldAsync(string label)
- {
- return await _page.Locator(".ant-form-item")
- .Filter(new() { HasText = label })
- .IsVisibleAsync();
- }
-
///
/// Fills the change password form and submits it.
///
diff --git a/LANCommander.Server.UI.Tests/Pages/RolesPage.cs b/LANCommander.Server.UI.Tests/Pages/RolesPage.cs
index ea18d4cf..608504b6 100644
--- a/LANCommander.Server.UI.Tests/Pages/RolesPage.cs
+++ b/LANCommander.Server.UI.Tests/Pages/RolesPage.cs
@@ -47,12 +47,12 @@ public class RolesPage
}
///
- /// Check whether a role with the given name appears in the table.
+ /// Locator for a role row with the given name.
+ /// Use with web-first assertions, e.g. Expect(page.Role("Administrator")).ToBeVisibleAsync().
///
- public async Task IsRoleVisibleAsync(string name)
+ public ILocator Role(string name)
{
- var row = _page.Locator("table tbody tr").Filter(new() { HasText = name });
- return await row.CountAsync() > 0;
+ return _page.Locator("table tbody tr").Filter(new() { HasText = name });
}
///
diff --git a/LANCommander.Server.UI.Tests/Pages/UsersPage.cs b/LANCommander.Server.UI.Tests/Pages/UsersPage.cs
index 763cb713..2bdb7d47 100644
--- a/LANCommander.Server.UI.Tests/Pages/UsersPage.cs
+++ b/LANCommander.Server.UI.Tests/Pages/UsersPage.cs
@@ -49,11 +49,12 @@ public class UsersPage
}
///
- /// Checks whether a given username appears in a table row.
+ /// Locator for a table row containing the given username.
+ /// Use with web-first assertions, e.g. Expect(page.User("admin")).ToBeVisibleAsync().
///
- public async Task IsUserVisibleAsync(string username)
+ public ILocator User(string username)
{
- return await _page.Locator("tr.ant-table-row", new() { HasTextString = username }).CountAsync() > 0;
+ return _page.Locator("tr.ant-table-row", new() { HasTextString = username });
}
///
diff --git a/LANCommander.Server.UI.Tests/PlaywrightFixture.cs b/LANCommander.Server.UI.Tests/PlaywrightFixture.cs
index 7acd04f2..ddcb9199 100644
--- a/LANCommander.Server.UI.Tests/PlaywrightFixture.cs
+++ b/LANCommander.Server.UI.Tests/PlaywrightFixture.cs
@@ -26,12 +26,12 @@ public class PlaywrightFixture : IAsyncLifetime
Playwright.Dispose();
}
- public async Task NewContextAsync(string? baseUrl = null)
+ public async Task NewContextAsync(string baseUrl)
{
return await Browser.NewContextAsync(new BrowserNewContextOptions
{
IgnoreHTTPSErrors = true,
- BaseURL = baseUrl ?? TestConstants.BaseUrl,
+ BaseURL = baseUrl,
});
}
}
diff --git a/LANCommander.Server.UI.Tests/ScreenshotHelper.cs b/LANCommander.Server.UI.Tests/ScreenshotHelper.cs
index 6785d0ab..1863b27d 100644
--- a/LANCommander.Server.UI.Tests/ScreenshotHelper.cs
+++ b/LANCommander.Server.UI.Tests/ScreenshotHelper.cs
@@ -5,8 +5,10 @@ using Xunit.Abstractions;
namespace LANCommander.Server.UI.Tests;
///
-/// Captures a full-page screenshot when a test fails.
-/// Screenshots are saved to a "Screenshots" directory that CI uploads as an artifact.
+/// Captures a full-page screenshot of the final page state at the end of each test.
+/// Screenshots are saved to a "Screenshots" directory that CI uploads as an artifact,
+/// making failures easy to diagnose. (xUnit v2 does not expose the test outcome to
+/// DisposeAsync, so we capture unconditionally and name each file after the test.)
///
public static class ScreenshotHelper
{
@@ -16,17 +18,14 @@ public static class ScreenshotHelper
string.Empty);
///
- /// Captures a screenshot of the current page state.
- /// Call this in DisposeAsync — it extracts the test name from ITestOutputHelper.
+ /// Captures a screenshot of the current page state, named after the running test.
+ /// Call this from DisposeAsync — it extracts the test name from ITestOutputHelper.
///
- public static async Task CaptureIfFailedAsync(IPage? page, ITestOutputHelper? output)
+ public static async Task CaptureAsync(IPage? page, ITestOutputHelper? output)
{
if (page == null || output == null)
return;
- // xUnit only writes to ITestOutputHelper when a test fails or produces output.
- // We always capture since DisposeAsync doesn't know the test result,
- // but name the file so it's easy to correlate.
var testName = GetTestDisplayName(output) ?? $"Unknown_{Guid.NewGuid():N}";
try
diff --git a/LANCommander.Server.UI.Tests/TestConstants.cs b/LANCommander.Server.UI.Tests/TestConstants.cs
index 6e191890..6c4f0d95 100644
--- a/LANCommander.Server.UI.Tests/TestConstants.cs
+++ b/LANCommander.Server.UI.Tests/TestConstants.cs
@@ -4,6 +4,4 @@ public static class TestConstants
{
public const string AdminUserName = "admin";
public const string AdminPassword = "Password1234!";
- public const int ServerPort = 1337;
- public static string BaseUrl => $"http://localhost:{ServerPort}";
}
diff --git a/LANCommander.Server.UI.Tests/Tests/AdminNavigationTests.cs b/LANCommander.Server.UI.Tests/Tests/AdminNavigationTests.cs
index bd6e6715..4232abb2 100644
--- a/LANCommander.Server.UI.Tests/Tests/AdminNavigationTests.cs
+++ b/LANCommander.Server.UI.Tests/Tests/AdminNavigationTests.cs
@@ -8,7 +8,7 @@ namespace LANCommander.Server.UI.Tests.Tests;
/// Tests for navigating around key parts of the admin application.
/// These tests verify that the main admin pages are accessible and render correctly
/// after logging in as an administrator.
-/// Uses IClassFixture to start the server once for all tests in this class.
+/// Uses the shared "Server" collection fixture so the server starts once for the whole collection.
///
[Collection("Server")]
public class AdminNavigationTests : IAsyncLifetime
@@ -31,7 +31,7 @@ public class AdminNavigationTests : IAsyncLifetime
public async Task DisposeAsync()
{
- await ScreenshotHelper.CaptureIfFailedAsync(_page, _output);
+ await ScreenshotHelper.CaptureAsync(_page, _output);
if (_page != null) await _page.CloseAsync();
if (_context != null) await _context.DisposeAsync();
}
@@ -43,9 +43,9 @@ public class AdminNavigationTests : IAsyncLifetime
Assert.True(await dashboard.IsDisplayedAsync());
// Dashboard should show playtime charts
- Assert.True(await _page.GetByText("Top 10 Total Playtime (By Player)").IsVisibleAsync());
- Assert.True(await _page.GetByText("Top 10 Total Playtime (By Game)").IsVisibleAsync());
- Assert.True(await _page.GetByText("Top Average Session Length (By Game)").IsVisibleAsync());
+ await Assertions.Expect(_page.GetByText("Top 10 Total Playtime (By Player)")).ToBeVisibleAsync();
+ await Assertions.Expect(_page.GetByText("Top 10 Total Playtime (By Game)")).ToBeVisibleAsync();
+ await Assertions.Expect(_page.GetByText("Top Average Session Length (By Game)")).ToBeVisibleAsync();
}
[Fact]
@@ -71,11 +71,11 @@ public class AdminNavigationTests : IAsyncLifetime
await dashboard.NavigateToGamesAsync();
Assert.Contains("/Games", _page.Url);
- Assert.True(await _page.GetByText("Games").First.IsVisibleAsync());
- Assert.True(await _page.GetByRole(AriaRole.Button, new() { Name = "Add Game" }).IsVisibleAsync());
- Assert.True(await _page.GetByRole(AriaRole.Button, new() { Name = "Import" }).IsVisibleAsync());
+ await Assertions.Expect(_page.GetByText("Games").First).ToBeVisibleAsync();
+ await Assertions.Expect(_page.GetByRole(AriaRole.Button, new() { Name = "Add Game" })).ToBeVisibleAsync();
+ await Assertions.Expect(_page.GetByRole(AriaRole.Button, new() { Name = "Import" })).ToBeVisibleAsync();
// Empty table should show "No data"
- Assert.True(await _page.GetByText("No data").IsVisibleAsync());
+ await Assertions.Expect(_page.GetByText("No data")).ToBeVisibleAsync();
}
[Fact]
@@ -85,7 +85,7 @@ public class AdminNavigationTests : IAsyncLifetime
await dashboard.NavigateToRedistributablesAsync();
Assert.Contains("/Redistributables", _page.Url);
- Assert.True(await _page.GetByText("Redistributables").First.IsVisibleAsync());
+ await Assertions.Expect(_page.GetByText("Redistributables").First).ToBeVisibleAsync();
}
[Fact]
@@ -95,7 +95,7 @@ public class AdminNavigationTests : IAsyncLifetime
await dashboard.NavigateToToolsAsync();
Assert.Contains("/Tools", _page.Url);
- Assert.True(await _page.GetByText("Tools").First.IsVisibleAsync());
+ await Assertions.Expect(_page.GetByText("Tools").First).ToBeVisibleAsync();
}
[Fact]
@@ -105,7 +105,7 @@ public class AdminNavigationTests : IAsyncLifetime
await dashboard.NavigateToServersAsync();
Assert.Contains("/Servers", _page.Url);
- Assert.True(await _page.GetByText("Servers").First.IsVisibleAsync());
+ await Assertions.Expect(_page.GetByText("Servers").First).ToBeVisibleAsync();
}
[Fact]
@@ -134,7 +134,7 @@ public class AdminNavigationTests : IAsyncLifetime
Assert.Contains("/Settings/General", _page.Url);
// Verify settings-specific content is visible (Database Provider is unique to General settings)
- Assert.True(await _page.GetByText("Database Provider").IsVisibleAsync());
+ await Assertions.Expect(_page.GetByText("Database Provider")).ToBeVisibleAsync();
}
[Fact]
@@ -151,9 +151,7 @@ public class AdminNavigationTests : IAsyncLifetime
foreach (var setting in expectedSettings)
{
- Assert.True(
- await _page.GetByRole(AriaRole.Link, new() { Name = setting, Exact = true }).IsVisibleAsync(),
- $"Settings menu should contain '{setting}'");
+ await Assertions.Expect(_page.GetByRole(AriaRole.Link, new() { Name = setting, Exact = true })).ToBeVisibleAsync();
}
}
}
diff --git a/LANCommander.Server.UI.Tests/Tests/FirstTimeSetupTests.cs b/LANCommander.Server.UI.Tests/Tests/FirstTimeSetupTests.cs
index ee50dd30..adcec7bd 100644
--- a/LANCommander.Server.UI.Tests/Tests/FirstTimeSetupTests.cs
+++ b/LANCommander.Server.UI.Tests/Tests/FirstTimeSetupTests.cs
@@ -30,7 +30,7 @@ public class FirstTimeSetupTests : IAsyncLifetime
public async Task DisposeAsync()
{
- await ScreenshotHelper.CaptureIfFailedAsync(_page, _output);
+ await ScreenshotHelper.CaptureAsync(_page, _output);
if (_page != null) await _page.CloseAsync();
if (_context != null) await _context.DisposeAsync();
}
@@ -54,11 +54,11 @@ public class FirstTimeSetupTests : IAsyncLifetime
await setupPage.NavigateAsync();
// Verify all 4 steps are visible in the wizard
- Assert.True(await _page.GetByText("Database").First.IsVisibleAsync());
- Assert.True(await _page.GetByText("Paths").IsVisibleAsync());
+ 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
- Assert.True(await _page.Locator("text=/Metad/").First.IsVisibleAsync());
- Assert.True(await _page.GetByText("Administrator").IsVisibleAsync());
+ await Assertions.Expect(_page.Locator("text=/Metad/").First).ToBeVisibleAsync();
+ await Assertions.Expect(_page.GetByText("Administrator")).ToBeVisibleAsync();
}
[Fact]
@@ -74,9 +74,9 @@ public class FirstTimeSetupTests : IAsyncLifetime
await _page.WaitForSelectorAsync("[role='listbox']", new() { Timeout = 5000 });
// Verify all expected providers are shown
- Assert.True(await _page.GetByRole(AriaRole.Option, new() { Name = "SQLite" }).IsVisibleAsync());
- Assert.True(await _page.GetByRole(AriaRole.Option, new() { Name = "MySQL" }).IsVisibleAsync());
- Assert.True(await _page.GetByRole(AriaRole.Option, new() { Name = "PostgreSQL" }).IsVisibleAsync());
+ 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")]
diff --git a/LANCommander.Server.UI.Tests/Tests/GameEditTests.cs b/LANCommander.Server.UI.Tests/Tests/GameEditTests.cs
index 292ed2b3..9527c5aa 100644
--- a/LANCommander.Server.UI.Tests/Tests/GameEditTests.cs
+++ b/LANCommander.Server.UI.Tests/Tests/GameEditTests.cs
@@ -29,7 +29,7 @@ public class GameEditTests : IAsyncLifetime
public async Task DisposeAsync()
{
- await ScreenshotHelper.CaptureIfFailedAsync(_page, _output);
+ await ScreenshotHelper.CaptureAsync(_page, _output);
if (_page != null) await _page.CloseAsync();
if (_context != null) await _context.DisposeAsync();
}
diff --git a/LANCommander.Server.UI.Tests/Tests/GameImportTests.cs b/LANCommander.Server.UI.Tests/Tests/GameImportTests.cs
index c15922a5..41459e4f 100644
--- a/LANCommander.Server.UI.Tests/Tests/GameImportTests.cs
+++ b/LANCommander.Server.UI.Tests/Tests/GameImportTests.cs
@@ -32,7 +32,7 @@ public class GameImportTests : IAsyncLifetime
public async Task DisposeAsync()
{
- await ScreenshotHelper.CaptureIfFailedAsync(_page, _output);
+ await ScreenshotHelper.CaptureAsync(_page, _output);
if (_page != null) await _page.CloseAsync();
if (_context != null) await _context.DisposeAsync();
}
@@ -44,8 +44,8 @@ public class GameImportTests : IAsyncLifetime
await gamesPage.NavigateAsync();
// Verify the page structure is correct (table area and buttons are present)
- Assert.True(await _page.GetByRole(AriaRole.Button, new() { Name = "Add Game" }).IsVisibleAsync());
- Assert.True(await _page.GetByRole(AriaRole.Button, new() { Name = "Import" }).IsVisibleAsync());
+ await Assertions.Expect(_page.GetByRole(AriaRole.Button, new() { Name = "Add Game" })).ToBeVisibleAsync();
+ await Assertions.Expect(_page.GetByRole(AriaRole.Button, new() { Name = "Import" })).ToBeVisibleAsync();
// The table should render (with "No data" if empty, or rows if a prior test imported)
var count = await gamesPage.GetGameCountAsync();
@@ -59,7 +59,7 @@ public class GameImportTests : IAsyncLifetime
await gamesPage.NavigateAsync();
var importButton = _page.GetByRole(AriaRole.Button, new() { Name = "Import" });
- Assert.True(await importButton.IsVisibleAsync());
+ await Assertions.Expect(importButton).ToBeVisibleAsync();
}
[Fact]
diff --git a/LANCommander.Server.UI.Tests/Tests/LoginTests.cs b/LANCommander.Server.UI.Tests/Tests/LoginTests.cs
index 58ea0b3a..f6fc544a 100644
--- a/LANCommander.Server.UI.Tests/Tests/LoginTests.cs
+++ b/LANCommander.Server.UI.Tests/Tests/LoginTests.cs
@@ -7,7 +7,7 @@ namespace LANCommander.Server.UI.Tests.Tests;
///
/// Tests for the login flow against a server that has already been configured.
/// These tests assume the server is running with a known admin user.
-/// Uses IClassFixture to start the server once for all tests in this class.
+/// Uses the shared "Server" collection fixture so the server starts once for the whole collection.
///
[Collection("Server")]
public class LoginTests : IAsyncLifetime
@@ -30,7 +30,7 @@ public class LoginTests : IAsyncLifetime
public async Task DisposeAsync()
{
- await ScreenshotHelper.CaptureIfFailedAsync(_page, _output);
+ await ScreenshotHelper.CaptureAsync(_page, _output);
if (_page != null) await _page.CloseAsync();
if (_context != null) await _context.DisposeAsync();
}
@@ -54,7 +54,7 @@ public class LoginTests : IAsyncLifetime
Assert.True(await loginPage.IsDisplayedAsync());
Assert.True(await loginPage.HasRegisterLinkAsync());
- Assert.True(await _page.GetByRole(AriaRole.Button, new() { Name = "Login" }).IsVisibleAsync());
+ await Assertions.Expect(_page.GetByRole(AriaRole.Button, new() { Name = "Login" })).ToBeVisibleAsync();
}
[Fact]
diff --git a/LANCommander.Server.UI.Tests/Tests/MetadataTests.cs b/LANCommander.Server.UI.Tests/Tests/MetadataTests.cs
index 1fef30b1..66dc6c7b 100644
--- a/LANCommander.Server.UI.Tests/Tests/MetadataTests.cs
+++ b/LANCommander.Server.UI.Tests/Tests/MetadataTests.cs
@@ -31,7 +31,7 @@ public class MetadataTests : IAsyncLifetime
public async Task DisposeAsync()
{
- await ScreenshotHelper.CaptureIfFailedAsync(_page, _output);
+ await ScreenshotHelper.CaptureAsync(_page, _output);
if (_page != null) await _page.CloseAsync();
if (_context != null) await _context.DisposeAsync();
}
@@ -54,7 +54,7 @@ public class MetadataTests : IAsyncLifetime
await tagsPage.NavigateAsync();
Assert.Equal(0, await tagsPage.GetItemCountAsync());
- Assert.True(await _page.GetByText("No data").IsVisibleAsync());
+ await Assertions.Expect(_page.GetByText("No data")).ToBeVisibleAsync();
}
[Fact]
@@ -65,7 +65,7 @@ public class MetadataTests : IAsyncLifetime
await tagsPage.AddItemAsync("Action");
- Assert.True(await tagsPage.IsItemVisibleAsync("Action"));
+ await Assertions.Expect(tagsPage.Item("Action")).ToBeVisibleAsync();
}
[Fact]
@@ -75,10 +75,10 @@ public class MetadataTests : IAsyncLifetime
await tagsPage.NavigateAsync();
await tagsPage.AddItemAsync("Puzzle");
- Assert.True(await tagsPage.IsItemVisibleAsync("Puzzle"));
+ await Assertions.Expect(tagsPage.Item("Puzzle")).ToBeVisibleAsync();
await tagsPage.EditItemAsync("Puzzle", "Puzzle Games");
- Assert.True(await tagsPage.IsItemVisibleAsync("Puzzle Games"));
+ await Assertions.Expect(tagsPage.Item("Puzzle Games")).ToBeVisibleAsync();
}
[Fact]
@@ -88,10 +88,10 @@ public class MetadataTests : IAsyncLifetime
await tagsPage.NavigateAsync();
await tagsPage.AddItemAsync("Temporary");
- Assert.True(await tagsPage.IsItemVisibleAsync("Temporary"));
+ await Assertions.Expect(tagsPage.Item("Temporary")).ToBeVisibleAsync();
await tagsPage.DeleteItemAsync("Temporary");
- Assert.False(await tagsPage.IsItemVisibleAsync("Temporary"));
+ await Assertions.Expect(tagsPage.Item("Temporary")).ToBeHiddenAsync();
}
// --- Genres ---
@@ -104,7 +104,7 @@ public class MetadataTests : IAsyncLifetime
await genresPage.AddItemAsync("RPG");
- Assert.True(await genresPage.IsItemVisibleAsync("RPG"));
+ await Assertions.Expect(genresPage.Item("RPG")).ToBeVisibleAsync();
}
[Fact]
@@ -114,10 +114,10 @@ public class MetadataTests : IAsyncLifetime
await genresPage.NavigateAsync();
await genresPage.AddItemAsync("Strategy");
- Assert.True(await genresPage.IsItemVisibleAsync("Strategy"));
+ await Assertions.Expect(genresPage.Item("Strategy")).ToBeVisibleAsync();
await genresPage.DeleteItemAsync("Strategy");
- Assert.False(await genresPage.IsItemVisibleAsync("Strategy"));
+ await Assertions.Expect(genresPage.Item("Strategy")).ToBeHiddenAsync();
}
// --- Platforms ---
@@ -130,7 +130,7 @@ public class MetadataTests : IAsyncLifetime
await platformsPage.AddItemAsync("Windows");
- Assert.True(await platformsPage.IsItemVisibleAsync("Windows"));
+ await Assertions.Expect(platformsPage.Item("Windows")).ToBeVisibleAsync();
}
[Fact]
@@ -140,9 +140,9 @@ public class MetadataTests : IAsyncLifetime
await platformsPage.NavigateAsync();
await platformsPage.AddItemAsync("Linux");
- Assert.True(await platformsPage.IsItemVisibleAsync("Linux"));
+ await Assertions.Expect(platformsPage.Item("Linux")).ToBeVisibleAsync();
await platformsPage.DeleteItemAsync("Linux");
- Assert.False(await platformsPage.IsItemVisibleAsync("Linux"));
+ await Assertions.Expect(platformsPage.Item("Linux")).ToBeHiddenAsync();
}
}
diff --git a/LANCommander.Server.UI.Tests/Tests/ProfileTests.cs b/LANCommander.Server.UI.Tests/Tests/ProfileTests.cs
index 5ffd34b5..ec16f13e 100644
--- a/LANCommander.Server.UI.Tests/Tests/ProfileTests.cs
+++ b/LANCommander.Server.UI.Tests/Tests/ProfileTests.cs
@@ -6,7 +6,7 @@ namespace LANCommander.Server.UI.Tests.Tests;
///
/// Tests for the user profile and change password pages.
-/// Uses IClassFixture to share the server instance across all tests in this class.
+/// Uses the shared "Server" collection fixture so the server instance is shared across the collection.
///
[Collection("Server")]
public class ProfileTests : IAsyncLifetime
@@ -29,7 +29,7 @@ public class ProfileTests : IAsyncLifetime
public async Task DisposeAsync()
{
- await ScreenshotHelper.CaptureIfFailedAsync(_page, _output);
+ await ScreenshotHelper.CaptureAsync(_page, _output);
if (_page != null) await _page.CloseAsync();
if (_context != null) await _context.DisposeAsync();
}
@@ -51,12 +51,10 @@ public class ProfileTests : IAsyncLifetime
var profilePage = new ProfilePage(_page);
await profilePage.NavigateAsync();
- Assert.True(await profilePage.HasFieldAsync("Username"), "Username field should be visible");
- Assert.True(await profilePage.HasFieldAsync("Alias"), "Alias field should be visible");
- Assert.True(await profilePage.HasFieldAsync("Email Address"), "Email Address field should be visible");
- Assert.True(
- await _page.GetByRole(AriaRole.Button, new() { Name = "Save" }).IsVisibleAsync(),
- "Save button should be visible");
+ await Assertions.Expect(profilePage.Field("Username")).ToBeVisibleAsync();
+ await Assertions.Expect(profilePage.Field("Alias")).ToBeVisibleAsync();
+ await Assertions.Expect(profilePage.Field("Email Address")).ToBeVisibleAsync();
+ await Assertions.Expect(_page.GetByRole(AriaRole.Button, new() { Name = "Save" })).ToBeVisibleAsync();
}
[Fact]
@@ -88,12 +86,10 @@ public class ProfileTests : IAsyncLifetime
var profilePage = new ProfilePage(_page);
await profilePage.NavigateToChangePasswordAsync();
- Assert.True(await profilePage.HasPasswordFieldAsync("Current Password"), "Current Password field should be visible");
- Assert.True(await profilePage.HasPasswordFieldAsync("New Password"), "New Password field should be visible");
- Assert.True(await profilePage.HasPasswordFieldAsync("Confirm Password"), "Confirm Password field should be visible");
- Assert.True(
- await _page.GetByRole(AriaRole.Button, new() { Name = "Change" }).IsVisibleAsync(),
- "Change button should be visible");
+ await Assertions.Expect(profilePage.Field("Current Password")).ToBeVisibleAsync();
+ await Assertions.Expect(profilePage.Field("New Password")).ToBeVisibleAsync();
+ await Assertions.Expect(profilePage.Field("Confirm Password")).ToBeVisibleAsync();
+ await Assertions.Expect(_page.GetByRole(AriaRole.Button, new() { Name = "Change" })).ToBeVisibleAsync();
}
[Fact]
diff --git a/LANCommander.Server.UI.Tests/Tests/RoleManagementTests.cs b/LANCommander.Server.UI.Tests/Tests/RoleManagementTests.cs
index 78ed57d0..9bc2f978 100644
--- a/LANCommander.Server.UI.Tests/Tests/RoleManagementTests.cs
+++ b/LANCommander.Server.UI.Tests/Tests/RoleManagementTests.cs
@@ -30,7 +30,7 @@ public class RoleManagementTests : IAsyncLifetime
public async Task DisposeAsync()
{
- await ScreenshotHelper.CaptureIfFailedAsync(_page, _output);
+ await ScreenshotHelper.CaptureAsync(_page, _output);
if (_page != null) await _page.CloseAsync();
if (_context != null) await _context.DisposeAsync();
}
@@ -41,8 +41,7 @@ public class RoleManagementTests : IAsyncLifetime
var rolesPage = new RolesPage(_page);
await rolesPage.NavigateAsync();
- Assert.True(await rolesPage.IsRoleVisibleAsync("Administrator"),
- "Administrator role should be visible in the roles table");
+ await Assertions.Expect(rolesPage.Role("Administrator")).ToBeVisibleAsync();
}
[Fact]
@@ -53,8 +52,7 @@ public class RoleManagementTests : IAsyncLifetime
await rolesPage.AddRoleAsync("TestRole");
- Assert.True(await rolesPage.IsRoleVisibleAsync("TestRole"),
- "Newly added TestRole should appear in the roles table");
+ await Assertions.Expect(rolesPage.Role("TestRole")).ToBeVisibleAsync();
}
[Fact]
@@ -65,14 +63,12 @@ public class RoleManagementTests : IAsyncLifetime
// Add a role to delete
await rolesPage.AddRoleAsync("RoleToDelete");
- Assert.True(await rolesPage.IsRoleVisibleAsync("RoleToDelete"),
- "RoleToDelete should be visible before deletion");
+ await Assertions.Expect(rolesPage.Role("RoleToDelete")).ToBeVisibleAsync();
// Delete the role
await rolesPage.DeleteRoleAsync("RoleToDelete");
- Assert.False(await rolesPage.IsRoleVisibleAsync("RoleToDelete"),
- "RoleToDelete should no longer appear after deletion");
+ await Assertions.Expect(rolesPage.Role("RoleToDelete")).ToBeHiddenAsync();
}
[Fact]
diff --git a/LANCommander.Server.UI.Tests/Tests/SettingsTests.cs b/LANCommander.Server.UI.Tests/Tests/SettingsTests.cs
index 636ce9ca..2e8b2871 100644
--- a/LANCommander.Server.UI.Tests/Tests/SettingsTests.cs
+++ b/LANCommander.Server.UI.Tests/Tests/SettingsTests.cs
@@ -29,7 +29,7 @@ public class SettingsTests : IAsyncLifetime
public async Task DisposeAsync()
{
- await ScreenshotHelper.CaptureIfFailedAsync(_page, _output);
+ await ScreenshotHelper.CaptureAsync(_page, _output);
if (_page != null) await _page.CloseAsync();
if (_context != null) await _context.DisposeAsync();
}
@@ -41,9 +41,9 @@ public class SettingsTests : IAsyncLifetime
await settings.NavigateToGeneralAsync();
Assert.Contains("/Settings/General", _page.Url);
- Assert.True(await _page.GetByText("Database Provider").IsVisibleAsync());
- Assert.True(await _page.GetByText("Port").First.IsVisibleAsync());
- Assert.True(await _page.GetByRole(AriaRole.Button, new() { Name = "Save" }).IsVisibleAsync());
+ await Assertions.Expect(_page.GetByText("Database Provider")).ToBeVisibleAsync();
+ await Assertions.Expect(_page.GetByText("Port").First).ToBeVisibleAsync();
+ await Assertions.Expect(_page.GetByRole(AriaRole.Button, new() { Name = "Save" })).ToBeVisibleAsync();
}
[Fact]
@@ -58,7 +58,7 @@ public class SettingsTests : IAsyncLifetime
// The admin user created during fixture setup should appear in the table
var adminCell = _page.Locator("table").GetByText(TestConstants.AdminUserName).First;
await adminCell.WaitForAsync(new() { Timeout = 15000 });
- Assert.True(await adminCell.IsVisibleAsync());
+ await Assertions.Expect(adminCell).ToBeVisibleAsync();
}
[Fact]
@@ -68,12 +68,12 @@ public class SettingsTests : IAsyncLifetime
await settings.NavigateToRolesAsync();
Assert.Contains("/Settings/Roles", _page.Url);
- Assert.True(await _page.GetByRole(AriaRole.Button, new() { Name = "Add Role" }).IsVisibleAsync());
+ await Assertions.Expect(_page.GetByRole(AriaRole.Button, new() { Name = "Add Role" })).ToBeVisibleAsync();
// Wait for the data table to render then check for the Administrator role
await _page.Locator("table").First.WaitForAsync(new() { Timeout = 15000 });
var adminRole = _page.Locator("table").GetByText("Administrator");
await adminRole.WaitForAsync(new() { Timeout = 15000 });
- Assert.True(await adminRole.IsVisibleAsync());
+ await Assertions.Expect(adminRole).ToBeVisibleAsync();
}
[Fact]
@@ -83,7 +83,7 @@ public class SettingsTests : IAsyncLifetime
await settings.NavigateToAuthenticationAsync();
Assert.Contains("/Settings/Authentication", _page.Url);
- Assert.True(await _page.GetByText("Authentication").First.IsVisibleAsync());
+ await Assertions.Expect(_page.GetByText("Authentication").First).ToBeVisibleAsync();
}
[Fact]
@@ -93,7 +93,7 @@ public class SettingsTests : IAsyncLifetime
await settings.NavigateToArchivesAsync();
Assert.Contains("/Settings/Archives", _page.Url);
- Assert.True(await _page.GetByText("Archives").First.IsVisibleAsync());
+ await Assertions.Expect(_page.GetByText("Archives").First).ToBeVisibleAsync();
}
[Fact]
@@ -103,7 +103,7 @@ public class SettingsTests : IAsyncLifetime
await settings.NavigateToMediaAsync();
Assert.Contains("/Settings/Media", _page.Url);
- Assert.True(await _page.GetByText("Media").First.IsVisibleAsync());
+ await Assertions.Expect(_page.GetByText("Media").First).ToBeVisibleAsync();
}
[Fact]
@@ -114,7 +114,7 @@ public class SettingsTests : IAsyncLifetime
await settings.NavigateToBeaconAsync();
Assert.Contains("/Settings/Beacon", _page.Url);
- Assert.True(await _page.GetByText("Beacon").First.IsVisibleAsync());
+ await Assertions.Expect(_page.GetByText("Beacon").First).ToBeVisibleAsync();
}
[Fact]
@@ -124,7 +124,7 @@ public class SettingsTests : IAsyncLifetime
await settings.NavigateToUpdatesAsync();
Assert.Contains("/Settings/Updates", _page.Url);
- Assert.True(await _page.GetByText("Updates").First.IsVisibleAsync());
+ await Assertions.Expect(_page.GetByText("Updates").First).ToBeVisibleAsync();
}
[Fact]
@@ -134,6 +134,6 @@ public class SettingsTests : IAsyncLifetime
await settings.NavigateToAppearanceAsync();
Assert.Contains("/Settings/Appearance", _page.Url);
- Assert.True(await _page.GetByText("Appearance").First.IsVisibleAsync());
+ await Assertions.Expect(_page.GetByText("Appearance").First).ToBeVisibleAsync();
}
}
diff --git a/LANCommander.Server.UI.Tests/Tests/UserManagementTests.cs b/LANCommander.Server.UI.Tests/Tests/UserManagementTests.cs
index 71c31ab6..a6837ba1 100644
--- a/LANCommander.Server.UI.Tests/Tests/UserManagementTests.cs
+++ b/LANCommander.Server.UI.Tests/Tests/UserManagementTests.cs
@@ -28,7 +28,7 @@ public class UserManagementTests : IAsyncLifetime
public async Task DisposeAsync()
{
- await ScreenshotHelper.CaptureIfFailedAsync(_page, _output);
+ await ScreenshotHelper.CaptureAsync(_page, _output);
if (_page != null) await _page.CloseAsync();
if (_context != null) await _context.DisposeAsync();
}
@@ -39,7 +39,7 @@ public class UserManagementTests : IAsyncLifetime
var usersPage = new UsersPage(_page);
await usersPage.NavigateAsync();
- Assert.True(await usersPage.IsUserVisibleAsync(TestConstants.AdminUserName));
+ await Assertions.Expect(usersPage.User(TestConstants.AdminUserName)).ToBeVisibleAsync();
}
[Fact]
@@ -50,7 +50,7 @@ public class UserManagementTests : IAsyncLifetime
await usersPage.SearchUsersAsync(TestConstants.AdminUserName);
- Assert.True(await usersPage.IsUserVisibleAsync(TestConstants.AdminUserName));
+ await Assertions.Expect(usersPage.User(TestConstants.AdminUserName)).ToBeVisibleAsync();
// After searching for "admin", the admin user must be in the results
var count = await usersPage.GetUserCountAsync();
Assert.True(count >= 1, $"Expected at least 1 user matching 'admin', got {count}");
@@ -96,7 +96,7 @@ public class UserManagementTests : IAsyncLifetime
var usersPage = new UsersPage(_page);
await usersPage.NavigateAsync();
- Assert.True(await usersPage.IsUserVisibleAsync(testUserName));
+ await Assertions.Expect(usersPage.User(testUserName)).ToBeVisibleAsync();
}
[Fact]
@@ -129,12 +129,12 @@ public class UserManagementTests : IAsyncLifetime
await usersPage.NavigateAsync();
// Verify user exists before deletion
- Assert.True(await usersPage.IsUserVisibleAsync(testUserName));
+ await Assertions.Expect(usersPage.User(testUserName)).ToBeVisibleAsync();
// Delete the user
await usersPage.DeleteUserAsync(testUserName);
// Verify user is gone
- Assert.False(await usersPage.IsUserVisibleAsync(testUserName));
+ await Assertions.Expect(usersPage.User(testUserName)).ToBeHiddenAsync();
}
}