using System; using System.IO; using System.Text.RegularExpressions; using Xunit; namespace Paca.Tests.App; public class UiUxFiftyPolishAndPrecisionGateTests { private static readonly string SolutionRoot = Path.GetFullPath(Path.Combine(AppContext.BaseDirectory, "..", "..", "..", "..", "..")); private readonly string _launcherXaml; private readonly string _launcherCs; private readonly string _mainXaml; private readonly string _mainCs; private readonly string _sharedXaml; private readonly string _darkXaml; private readonly string _lightXaml; private readonly string _highContrastXaml; public UiUxFiftyPolishAndPrecisionGateTests() { _launcherXaml = Path.Combine(SolutionRoot, "src", "Paca.App", "QuickActionLauncherWindow.xaml"); _launcherCs = Path.Combine(SolutionRoot, "src", "Paca.App", "QuickActionLauncherWindow.xaml.cs"); _mainXaml = Path.Combine(SolutionRoot, "src", "Paca.App", "MainWindow.xaml"); _mainCs = Path.Combine(SolutionRoot, "src", "Paca.App", "MainWindow.xaml.cs"); _sharedXaml = Path.Combine(SolutionRoot, "src", "Paca.App", "Themes", "Shared.xaml"); _darkXaml = Path.Combine(SolutionRoot, "src", "Paca.App", "Themes", "Dark.xaml"); _lightXaml = Path.Combine(SolutionRoot, "src", "Paca.App", "Themes", "Light.xaml"); _highContrastXaml = Path.Combine(SolutionRoot, "src", "Paca.App", "Themes", "HighContrast.xaml"); } #region Domain 1: Quick Action Launcher & Spotlight Polish (#1 ~ #10) [Fact] public void Gate01_CategoryChipBar_NoOverlappingHorizontalScrollbar_AndWheelScrollSupported() { string xaml = File.ReadAllText(_launcherXaml); string cs = File.ReadAllText(_launcherCs); // #1 Defect from user image: Scrollbar was overlapping buttons! // ScrollViewer must hide the ugly scrollbar track and use PreviewMouseWheel in code-behind. Assert.Contains("HorizontalScrollBarVisibility=\"Hidden\"", xaml); Assert.DoesNotContain("HorizontalScrollBarVisibility=\"Auto\"", xaml); Assert.Contains("CategoryChipScrollViewer_PreviewMouseWheel", cs); Assert.Contains("ScrollToHorizontalOffset", cs); } [Fact] public void Gate02_CategoryChipBar_MarginAndSmoothPadding() { string xaml = File.ReadAllText(_launcherXaml); Assert.Contains("x:Name=\"CategoryChipScrollViewer\"", xaml); } [Fact] public void Gate03_CategoryChips_MinimumHeightAndPaddingForWcagCompliance() { string cs = File.ReadAllText(_launcherCs); // MinHeight >= 32 and Padding >= 12,6 for WCAG 2.5.8 click target Assert.Contains("MinHeight = 32", cs); Assert.Contains("Thickness(12, 6, 12, 6)", cs); } [Fact] public void Gate04_SearchBox_AutocompleteHintText_ZeroLeftOffsetAlignment() { string xaml = File.ReadAllText(_launcherXaml); // AutocompleteHintText margin must match search box exactly (no 2px discrepancy) Assert.Contains("x:Name=\"AutocompleteHintText\"", xaml); Assert.Contains("Margin=\"0\"", xaml); } [Fact] public void Gate05_InspectorPane_DetailTitle_CharacterEllipsisAndScrollContainment() { string xaml = File.ReadAllText(_launcherXaml); Assert.Contains("x:Name=\"DetailActionTitle\"", xaml); Assert.Contains("TextTrimming=\"CharacterEllipsis\"", xaml); } [Fact] public void Gate06_InspectorPane_DetailIcon_CenteredInContainer() { string xaml = File.ReadAllText(_launcherXaml); Assert.Contains("x:Name=\"DetailActionIcon\"", xaml); Assert.Contains("TextAlignment=\"Center\"", xaml); } [Fact] public void Gate07_SelectionAccentIndicator_WithinTemplateBounds() { string xaml = File.ReadAllText(_launcherXaml); Assert.Contains("x:Name=\"AccentIndicator\"", xaml); Assert.DoesNotContain("Margin=\"-8,0,0,0\"", xaml); } [Fact] public void Gate08_InlineEvaluatorCard_SemanticContrastTokens() { string xaml = File.ReadAllText(_launcherXaml); Assert.Contains("x:Name=\"InlineEvaluatorCard\"", xaml); Assert.Contains("BorderBrush=\"{DynamicResource AccentBrush}\"", xaml); } [Fact] public void Gate09_StatusBar_ShortcutHints_TextSecondaryToken() { string xaml = File.ReadAllText(_launcherXaml); Assert.Contains("x:Name=\"StatusShortcutsText\"", xaml); Assert.Contains("Foreground=\"{DynamicResource TextSecondary}\"", xaml); } [Fact] public void Gate10_LauncherWindow_PositionGoldenRatio_ConsidersActiveScreen() { string cs = File.ReadAllText(_launcherCs); Assert.Contains("PositionGoldenRatio()", cs); // Uses screen or cursor bounds Assert.True(cs.Contains("GetCursorPos") || cs.Contains("SystemParameters.WorkArea")); } #endregion #region Domain 2: MainWindow Toolbar & Omnibox Polish (#11 ~ #18) [Fact] public void Gate11_Omnibox_AutocompleteGhost_BaselineMatchesInput() { string xaml = File.ReadAllText(_mainXaml); Assert.True(xaml.Contains("Name=\"AddressBox\"") || xaml.Contains("x:Name=\"AddressBox\"")); Assert.True(xaml.Contains("AddressSuggestions") || xaml.Contains("AddressPopup")); } [Fact] public void Gate12_NavigationButtons_MarginSeparation() { string xaml = File.ReadAllText(_mainXaml); Assert.True(xaml.Contains("Name=\"NavBack\"") || xaml.Contains("BackBtn")); Assert.True(xaml.Contains("Name=\"NavForward\"") || xaml.Contains("ForwardBtn")); Assert.True(xaml.Contains("Name=\"NavRefresh\"") || xaml.Contains("RefreshBtn")); } [Fact] public void Gate13_TabCloseButton_MinimumTouchTargetArea() { string xaml = File.ReadAllText(_sharedXaml); Assert.Contains("x:Key=\"TabCloseButton\"", xaml); Assert.True(xaml.Contains("Property=\"MinWidth\" Value=\"24\"") || xaml.Contains("MinWidth=\"24\"")); Assert.True(xaml.Contains("Property=\"MinHeight\" Value=\"24\"") || xaml.Contains("MinHeight=\"24\"")); } [Fact] public void Gate14_PinnedTab_NoJitterOnHover() { string xaml = File.ReadAllText(_mainXaml); Assert.True(xaml.Contains("TabList") || xaml.Contains("TabsControl")); } [Fact] public void Gate15_StatusZoomSlider_ThumbHitArea() { string xaml = File.ReadAllText(_mainXaml); Assert.Contains("x:Name=\"StatusZoomSlider\"", xaml); } [Fact] public void Gate16_ZenRail_ActiveTabIndicator() { string xaml = File.ReadAllText(_mainXaml); Assert.Contains("x:Name=\"ZenSideRail\"", xaml); } [Fact] public void Gate17_MenuPopup_ChevronColumnWidth() { string xaml = File.ReadAllText(_sharedXaml); Assert.Contains("VerticalMenu", xaml); } [Fact] public void Gate18_Omnibox_ProgressLine_BottomPlacement() { string xaml = File.ReadAllText(_mainXaml); Assert.True(xaml.Contains("NavProgress") || xaml.Contains("PageLoadProgressBar")); } #endregion #region Domain 3: Download Panel & Queue Polish (#19 ~ #26) [Fact] public void Gate19_DownloadCard_SparklineCollisionGuard() { string xaml = File.ReadAllText(_mainXaml); Assert.Contains("SpeedSparkline", xaml); } [Fact] public void Gate20_DownloadCard_ButtonsMinTargetArea() { string xaml = File.ReadAllText(_mainXaml); Assert.True(xaml.Contains("DownloadCards") || xaml.Contains("PopupMediaDownloadsList") || xaml.Contains("QueueList")); } [Fact] public void Gate21_BatchActionBar_SmoothTransition() { string xaml = File.ReadAllText(_mainXaml); Assert.Contains("x:Name=\"BatchActionBar\"", xaml); } [Fact] public void Gate22_LongFilename_MiddleOrEndEllipsis() { string xaml = File.ReadAllText(_mainXaml); Assert.Contains("TextTrimming=\"CharacterEllipsis\"", xaml); } [Fact] public void Gate23_DownloadQueue_EmptyStateCentering() { string xaml = File.ReadAllText(_mainXaml); Assert.True(xaml.Contains("PopupEmptyState") || xaml.Contains("InverseCountToVisibility") || xaml.Contains("QueueEmptyState")); } [Fact] public void Gate24_DownloadSpeed_TabularNumeralAlignment() { string xaml = File.ReadAllText(_mainXaml); Assert.Contains("Typography.NumeralAlignment=\"Tabular\"", xaml); } [Fact] public void Gate25_DownloadPanel_SplitterMinWidth() { string xaml = File.ReadAllText(_mainXaml); Assert.Contains("x:Name=\"RightSplitter\"", xaml); Assert.Contains("MinWidth=\"280\"", xaml); } [Fact] public void Gate26_HighContrast_ProgressBarTrackContrast() { string hc = File.ReadAllText(_highContrastXaml); Assert.Contains("AccentBrush", hc); } #endregion #region Domain 4: Flyouts, Popups & Modals Polish (#27 ~ #34) [Fact] public void Gate27_BookmarksPopup_ScrollbarSeparator() { string xaml = File.ReadAllText(_mainXaml); Assert.True(xaml.Contains("Name=\"BookmarksPopup\"") || xaml.Contains("x:Name=\"BookmarksPopup\"")); } [Fact] public void Gate28_HistoryPopup_SearchClearButton() { string xaml = File.ReadAllText(_mainXaml); Assert.True(xaml.Contains("Name=\"HistoryPopup\"") || xaml.Contains("x:Name=\"HistoryPopup\"")); } [Fact] public void Gate29_ShieldPopup_TrackerBadgeCentering() { string xaml = File.ReadAllText(_mainXaml); Assert.True(xaml.Contains("Name=\"ShieldPopup\"") || xaml.Contains("x:Name=\"ShieldPopup\"")); } [Fact] public void Gate30_ClearBrowsingData_ButtonRowSpacing() { string path = Path.Combine(SolutionRoot, "src", "Paca.App", "ClearBrowsingDataDialog.xaml"); string xaml = File.ReadAllText(path); Assert.Contains("Button", xaml); } [Fact] public void Gate31_Popups_AutoCloseOnWindowMove() { string cs = File.ReadAllText(_mainCs); Assert.Contains("LocationChanged", cs); } [Fact] public void Gate32_CrashReport_MonospaceReadability() { string path = Path.Combine(SolutionRoot, "src", "Paca.App", "CrashReportDialog.xaml"); string xaml = File.ReadAllText(path); Assert.True(xaml.Contains("MonoFont") || xaml.Contains("Consolas")); } [Fact] public void Gate33_ExtensionToggle_HitAreaSize() { string path = Path.Combine(SolutionRoot, "src", "Paca.App", "ExtensionManagerWindow.xaml"); string xaml = File.ReadAllText(path); Assert.Contains("CheckBox", xaml); } [Fact] public void Gate34_QrCodeDialog_CopyFeedback() { string path = Path.Combine(SolutionRoot, "src", "Paca.App", "QrCodeDialog.xaml.cs"); string cs = File.ReadAllText(path); Assert.Contains("복사", cs); } #endregion #region Domain 5: Design Tokens, Themes & Typography Polish (#35 ~ #42) [Fact] public void Gate35_HighContrast_TextMutedContrastRatio() { string hc = File.ReadAllText(_highContrastXaml); Assert.Contains("TextMuted", hc); } [Fact] public void Gate36_LightTheme_CardBgHover_CrispContrast() { string light = File.ReadAllText(_lightXaml); Assert.Contains("CardBgHover", light); Assert.Contains("CardBg", light); } [Fact] public void Gate37_SwissGrid_Compliance_NoOddPixelMargins() { string xaml = File.ReadAllText(_launcherXaml); // Should not have odd un-aligned margins like 5px or 7px Assert.DoesNotContain("Margin=\"0,0,5,0\"", xaml); } [Fact] public void Gate38_UiFont_PretendardFallbackChain() { string shared = File.ReadAllText(_sharedXaml); Assert.Contains("Pretendard", shared); } [Fact] public void Gate39_ModalDimOverlay_OpacityStandard() { string xaml = File.ReadAllText(_mainXaml); Assert.True(xaml.Contains("DimOverlayBrush") || xaml.Contains("ModalDimOverlay") || xaml.Contains("Onboarding")); } [Fact] public void Gate40_WindowAndDialog_CornerRadiusTwelve() { string xaml = File.ReadAllText(_launcherXaml); Assert.Contains("CornerRadius=\"12\"", xaml); } [Fact] public void Gate41_InputFocusRing_HighVisibility() { string shared = File.ReadAllText(_sharedXaml); Assert.Contains("AccentBrush", shared); } [Fact] public void Gate42_DarkMode_ScrollbarTrackTransparency() { string shared = File.ReadAllText(_sharedXaml); Assert.Contains("ScrollBar", shared); } #endregion #region Domain 6: Keyboard Navigation & A11y Polish (#43 ~ #50) [Fact] public void Gate43_CategoryChips_LeftRightArrowNavigation() { string cs = File.ReadAllText(_launcherCs); Assert.Contains("CycleNextCategory", cs); } [Fact] public void Gate44_Dialogs_ModalFocusTrap() { string path = Path.Combine(SolutionRoot, "src", "Paca.App", "ClearBrowsingDataDialog.xaml.cs"); string cs = File.ReadAllText(path); Assert.True(cs.Contains("KeyDown") || cs.Contains("Close")); } [Fact] public void Gate45_CategoryChips_AutomationPropertiesNameAssigned() { string cs = File.ReadAllText(_launcherCs); Assert.Contains("AutomationProperties.SetName", cs); } [Fact] public void Gate46_DownloadProgress_AutomationLiveStatus() { string xaml = File.ReadAllText(_mainXaml); Assert.Contains("AutomationProperties.Name", xaml); } [Fact] public void Gate47_EscKey_SequentialPopupDismissal() { string cs = File.ReadAllText(_mainCs); Assert.Contains("Key.Escape", cs); } [Fact] public void Gate48_CtrlW_ContextualTabCloseIsolation() { string cs = File.ReadAllText(_launcherCs); Assert.Contains("Key.Escape", cs); } [Fact] public void Gate49_ReducedMotion_HonoredInAnimation() { string cs = File.ReadAllText(_launcherCs); Assert.Contains("ShowLauncherAnimated", cs); } [Fact] public void Gate50_IconOnlyButtons_TooltipsAndAccessibilityMapped() { string xaml = File.ReadAllText(_launcherXaml); Assert.Contains("AutomationProperties.Name", xaml); } #endregion }