namespace GmRelay.Bot.Tests.Web; public sealed class WebStylesTests { [Fact] public async Task AppCss_ShouldStyleNativeSelectOptionsForReadableDropdowns() { var css = await File.ReadAllTextAsync(FindRepositoryFile("src/GmRelay.Web/wwwroot/app.css")); Assert.Matches( @"select\s+option\s*\{[^}]*background:\s*var\(--bg-secondary\);[^}]*color:\s*var\(--text-primary\);", css); } [Fact] public async Task AppCss_ShouldReserveTelegramMiniAppSafeAreaForMobileChrome() { var appCss = await File.ReadAllTextAsync(FindRepositoryFile("src/GmRelay.Web/wwwroot/app.css")); Assert.Contains("--gm-tg-safe-top", appCss, StringComparison.Ordinal); Assert.Contains("--tg-safe-area-inset-top", appCss, StringComparison.Ordinal); Assert.Contains("--tg-content-safe-area-inset-top", appCss, StringComparison.Ordinal); Assert.Contains("env(safe-area-inset-top", appCss, StringComparison.Ordinal); Assert.Contains(".telegram-mini-app .content", appCss, StringComparison.Ordinal); Assert.Contains(".telegram-mini-app .nav-header", appCss, StringComparison.Ordinal); Assert.Contains(".telegram-mini-app .nav-toggle", appCss, StringComparison.Ordinal); } [Fact] public async Task AppCss_ShouldKeepDesktopSessionActionsReadableWhenTableOverflows() { var appCss = await File.ReadAllTextAsync(FindRepositoryFile("src/GmRelay.Web/wwwroot/app.css")); Assert.Matches( @"\.session-table-desktop\s*\{[\s\S]*overflow-x:\s*auto;", appCss); Assert.Matches( @"\.session-table-desktop\s+\.gm-table\s*\{[\s\S]*min-width:\s*760px;", appCss); Assert.Matches( @"\.session-table-actions\s+\.btn-gm\s*\{[\s\S]*white-space:\s*nowrap;", appCss); } [Fact] public async Task AppCss_ShouldUseCardSessionLayoutInsideTelegramMiniApp() { var appCss = await File.ReadAllTextAsync(FindRepositoryFile("src/GmRelay.Web/wwwroot/app.css")); Assert.Matches( @"body\.telegram-mini-app\s+\.session-table-desktop\s*\{[\s\S]*display:\s*none;", appCss); Assert.Matches( @"body\.telegram-mini-app\s+\.session-card-mobile\s*\{[\s\S]*display:\s*block;", appCss); } [Fact] public async Task AppCss_ShouldUseCardSessionLayoutWhenDesktopSidebarLeavesNarrowContent() { var appCss = await File.ReadAllTextAsync(FindRepositoryFile("src/GmRelay.Web/wwwroot/app.css")); Assert.Matches( @"@media\s*\(max-width:\s*1024px\)\s*\{[\s\S]*\.session-table-desktop\s*\{[\s\S]*display:\s*none;[\s\S]*\.session-card-mobile\s*\{[\s\S]*display:\s*block;", appCss); } [Fact] public async Task GroupDetailsPage_ShouldUseSessionTableLayoutClasses() { var groupDetailsPage = await File.ReadAllTextAsync(FindRepositoryFile("src/GmRelay.Web/Components/Pages/GroupDetails.razor")); Assert.Contains("session-table-desktop-card", groupDetailsPage, StringComparison.Ordinal); Assert.Contains("session-table-actions", groupDetailsPage, StringComparison.Ordinal); Assert.Contains("session-join-link", groupDetailsPage, StringComparison.Ordinal); Assert.DoesNotContain("overflow: hidden", groupDetailsPage, StringComparison.Ordinal); } private static string FindRepositoryFile(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 candidate; } directory = directory.Parent; } throw new FileNotFoundException($"Could not locate repository file '{relativePath}'."); } }