feat(ads/seo/release): v1.2.0 with live Google Ads, isolated ad profile, ads.txt, and SEO/AEO/GEO optimization

This commit is contained in:
Yun Chan 2026-09-14 00:39:44 +09:00
parent a88aafa1e5
commit 0e568f1f0a
975 changed files with 130593 additions and 16783 deletions

View file

@ -0,0 +1,436 @@
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
}