namespace GmRelay.Bot.Tests.Web; public sealed class PortfolioPagesTests { [Fact] public async Task PortfolioEditorPage_ShouldBeAuthorizedAndExposeEditorActions() { var editor = await ReadRepositoryFileAsync("src/GmRelay.Web/Components/Pages/PortfolioEditor.razor"); Assert.Contains("@page \"/portfolio/manage/{PortfolioGameId:guid}\"", editor, StringComparison.Ordinal); Assert.Contains("@attribute [Authorize]", editor, StringComparison.Ordinal); Assert.Contains("InputFile", editor, StringComparison.Ordinal); Assert.Contains("ReplaceCoverForCurrentUserAsync", editor, StringComparison.Ordinal); Assert.Contains("SetPublicationForCurrentUserAsync", editor, StringComparison.Ordinal); Assert.Contains("ModerateReviewForCurrentUserAsync", editor, StringComparison.Ordinal); } [Fact] public async Task GroupDetailsPage_ShouldExposePortfolioManagementActions() { var groupDetails = await ReadRepositoryFileAsync("src/GmRelay.Web/Components/Pages/GroupDetails.razor"); Assert.Contains("CreateDraftForCurrentUserAsync", groupDetails, StringComparison.Ordinal); } [Fact] public async Task GroupCompletedSessionsPage_ShouldBeAuthorizedAndExposeCompletedSessions() { var completedSessions = await ReadRepositoryFileAsync("src/GmRelay.Web/Components/Pages/GroupCompletedSessions.razor"); Assert.Contains("@page \"/group/{GroupId:guid}/completed\"", completedSessions, StringComparison.Ordinal); Assert.Contains("@attribute [Authorize]", completedSessions, StringComparison.Ordinal); Assert.Contains("GetCompletedSessionsForCurrentUserAsync", completedSessions, StringComparison.Ordinal); Assert.Contains("CreateDraftForCurrentUserAsync", completedSessions, StringComparison.Ordinal); } [Fact] public async Task SessionHistoryPage_ShouldExposeQuickPortfolioActionForPastSessions() { var sessionHistory = await ReadRepositoryFileAsync("src/GmRelay.Web/Components/Pages/SessionHistory.razor"); Assert.Contains("CreateDraftForCurrentUserAsync", sessionHistory, StringComparison.Ordinal); Assert.Contains("Добавить в портфолио", sessionHistory, StringComparison.Ordinal); } [Fact] public async Task AppCss_ShouldStylePortfolioManagementComponents() { var css = await ReadRepositoryFileAsync("src/GmRelay.Web/wwwroot/app.css"); Assert.Contains(".portfolio-management-list", css, StringComparison.Ordinal); Assert.Contains(".portfolio-editor-grid", css, StringComparison.Ordinal); Assert.Contains(".portfolio-option-list", css, StringComparison.Ordinal); Assert.Contains(".portfolio-review-moderation", css, StringComparison.Ordinal); } [Fact] public async Task PublicPortfolioPage_ShouldExposeSanitizedDetailAndReviewForm() { var publicPortfolio = await ReadRepositoryFileAsync("src/GmRelay.Web/Components/Pages/PublicPortfolio.razor"); Assert.Contains("@page \"/portfolio/{Slug}\"", publicPortfolio, StringComparison.Ordinal); Assert.Contains("@layout PublicLayout", publicPortfolio, StringComparison.Ordinal); Assert.DoesNotContain("@attribute [Authorize]", publicPortfolio, StringComparison.Ordinal); Assert.Contains("GetPublicPortfolioGameBySlugAsync", publicPortfolio, StringComparison.Ordinal); Assert.Contains("SubmitReviewForCurrentUserAsync", publicPortfolio, StringComparison.Ordinal); Assert.Contains("publicationConsent", publicPortfolio, StringComparison.Ordinal); Assert.DoesNotContain("PlayerId", publicPortfolio, StringComparison.Ordinal); Assert.DoesNotContain("StorageKey", publicPortfolio, StringComparison.Ordinal); } [Fact] public async Task PublicMasterProfilePage_ShouldIncludePortfolioCardGrid() { var publicMaster = await ReadRepositoryFileAsync("src/GmRelay.Web/Components/Pages/PublicMasterProfile.razor"); Assert.Contains("PortfolioCardGrid", publicMaster, StringComparison.Ordinal); Assert.Contains("GetPublicPortfolioGamesForMasterAsync", publicMaster, StringComparison.Ordinal); } [Fact] public async Task PublicClubPage_ShouldIncludePortfolioCardGrid() { var publicClub = await ReadRepositoryFileAsync("src/GmRelay.Web/Components/Pages/PublicClub.razor"); Assert.Contains("PortfolioCardGrid", publicClub, StringComparison.Ordinal); Assert.Contains("GetPublicPortfolioGamesForClubAsync", publicClub, StringComparison.Ordinal); } [Fact] public async Task AppCss_ShouldStylePublicPortfolioComponents() { var css = await ReadRepositoryFileAsync("src/GmRelay.Web/wwwroot/app.css"); Assert.Contains(".portfolio-grid", css, StringComparison.Ordinal); Assert.Contains(".portfolio-card", css, StringComparison.Ordinal); Assert.Contains(".portfolio-card-cover", css, StringComparison.Ordinal); Assert.Contains(".portfolio-cover-hero", css, StringComparison.Ordinal); Assert.Contains(".portfolio-review-list", css, StringComparison.Ordinal); Assert.Contains(".portfolio-review-card", css, StringComparison.Ordinal); } private static async Task ReadRepositoryFileAsync(string relativePath) { var directory = new DirectoryInfo(AppContext.BaseDirectory); while (directory is not null) { var candidate = Path.Combine(directory.FullName, relativePath); if (File.Exists(candidate)) { return await File.ReadAllTextAsync(candidate); } directory = directory.Parent; } throw new FileNotFoundException($"Could not locate repository file '{relativePath}'."); } }