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,109 @@
using System.IO;
using System.Text.RegularExpressions;
using Paca.App;
using Paca.Tests.Infrastructure;
using Xunit;
namespace Paca.Tests.App;
public class ScrollBarAndSectionBorderGateTests
{
[Fact]
public void Gate475_LightAndDarkThemes_ScrollBarThumbBrush_ContrastAndAlpha_Audit()
{
// DoD: 라이트 테마에서 스크롤바가 시커멓게 렌더링되지 않도록
// 1. Light.xaml 에 미니멀 반투명 스크롤바 브러시가 정의되어야 함
var lightXaml = SourceTree.ThemeLightXaml;
Assert.True(SourceTree.HasKey(lightXaml, "ScrollBarThumbBrush"), "Light.xaml must define ScrollBarThumbBrush");
Assert.True(SourceTree.HasKey(lightXaml, "ScrollBarTrackBrush"), "Light.xaml must define ScrollBarTrackBrush");
// 2. Shared.xaml 에서 정적 다크 색상(#4A5568)으로 덮어쓰지 않고 각 테마 사전을 존중해야 함
var sharedXaml = File.ReadAllText(SourceTree.AppPath("Themes/Shared.xaml"));
Assert.DoesNotContain("<SolidColorBrush x:Key=\"ScrollBarThumbBrush\" Color=\"#4A5568\"/>", sharedXaml);
}
[Fact]
public void Gate476_MainWindow_SectionBorders_MinimalFlatSurfaces_Audit()
{
// DoD: 불필요한 1px 와이어프레임 보더라인을 소거하고 서피스 배경색으로 유기적 분리
var mainWindowXaml = File.ReadAllText(SourceTree.AppPath("MainWindow.xaml"));
// 1. 우측 도킹 패널(Grid.Column="2")의 불필요한 BorderThickness 1px 제거 (BorderThickness="0")
var panelMatch = Regex.Match(mainWindowXaml, @"<Border[^>]*Grid\.Column=""2""[^>]*BorderThickness=""([^""]+)""");
Assert.True(panelMatch.Success, "Grid.Column 2 Border should have BorderThickness attribute");
Assert.Equal("0", panelMatch.Groups[1].Value);
// 2. RightSplitter 내 하드코딩된 1px Rectangle 보더선 제거 (이중 보더 방지)
Assert.DoesNotContain("<Rectangle Width=\"1\" HorizontalAlignment=\"Center\" Fill=\"{DynamicResource BorderSubtle}\"/>", mainWindowXaml);
// 3. SideTabsContainer(세그먼트 탭 컨테이너)의 테두리 1px 제거 (BorderThickness="0")
var sideTabsMatch = Regex.Match(mainWindowXaml, @"<Border[^>]*x:Name=""SideTabsContainer""[^>]*BorderThickness=""([^""]+)""");
Assert.True(sideTabsMatch.Success, "SideTabsContainer should have BorderThickness");
Assert.Equal("0", sideTabsMatch.Groups[1].Value);
// 4. ToolbarRow 내 캡션 버튼 직전의 1px 분리선 제거
Assert.DoesNotContain("<Border Width=\"1\" Background=\"{DynamicResource BorderSubtle}\" Margin=\"6,8\"/>", mainWindowXaml);
// 5. RightTabSideHost(우측 세로 탭 호스트) 불필요 1px 보더 제거 (BorderThickness="0")
var rightTabMatch = Regex.Match(mainWindowXaml, @"<Border[^>]*x:Name=""RightTabSideHost""[^>]*BorderThickness=""([^""]+)""");
if (rightTabMatch.Success)
{
Assert.Equal("0", rightTabMatch.Groups[1].Value);
}
}
[Fact]
public void Gate477_TabViewService_PreferredColorScheme_SynchronizedWithAppTheme_Audit()
{
// DoD: WebView2 초기화 시 CoreWebView2Profile.PreferredColorScheme 을 테마에 동기화
var tabViewServiceCs = File.ReadAllText(SourceTree.AppPath("Services/TabViewService.cs"));
Assert.Contains("PreferredColorScheme", tabViewServiceCs);
Assert.Contains("CoreWebView2PreferredColorScheme", tabViewServiceCs);
}
[Fact]
public void Gate478_TabViewService_ScrollbarThemeScript_InjectedForLightAndDark_Audit()
{
// DoD: WebView2 웹 콘텐츠 스크롤바가 OS 다크모드에 의해 17px 검정으로 튀지 않도록
// 커스텀 미니멀 스크롤바 스타일 스크립트(AddScriptToExecuteOnDocumentCreatedAsync)가 등록되어야 함
var tabViewServiceCs = File.ReadAllText(SourceTree.AppPath("Services/TabViewService.cs"));
Assert.Contains("::-webkit-scrollbar", tabViewServiceCs);
Assert.Contains("scrollbar-color", tabViewServiceCs);
}
[Fact]
public void Gate479_MainWindow_LiveThemeSwitch_UpdatesAllTabsPreferredColorScheme_Audit()
{
// DoD: 라이브 테마 전환 시 열려있는 모든 탭의 PreferredColorScheme 및 스크롤바를 갱신
var usecasesCs = File.ReadAllText(SourceTree.AppPath("MainWindow.Usecases.cs"));
Assert.Contains("PreferredColorScheme", usecasesCs);
}
[Fact]
public void Gate480_MainWindow_DesktopBrowser_NoWhiteBorderArtifacts_Audit()
{
// DoD: 데스크탑 브라우저 UI에서 툴바 하단 및 우측 스플리터 영역에 흰색 보더/라인 아티팩트가 노출되지 않아야 함
var mainWindowXaml = File.ReadAllText(SourceTree.AppPath("MainWindow.xaml"));
// 1. ToolbarRow 하단의 2px 그라디언트 보더(AccentFadeBrush)로 인한 흰색 라인 방지: BorderThickness="0"
var toolbarMatch = Regex.Match(mainWindowXaml, @"<Border[^>]*x:Name=""ToolbarRow""[^>]*BorderThickness=""([^""]+)""");
Assert.True(toolbarMatch.Success, "ToolbarRow should have BorderThickness attribute");
Assert.Equal("0", toolbarMatch.Groups[1].Value);
// 2. RightSplitter 가 Transparent 로 남아 윈도우 배경(#FFFFFF)이 투과되는 7px 흰색 줄 방지: Background="{DynamicResource PanelBg}"
var splitterMatch = Regex.Match(mainWindowXaml, @"<GridSplitter[^>]*x:Name=""RightSplitter""[^>]*Background=""([^""]+)""");
Assert.True(splitterMatch.Success, "RightSplitter should specify Background");
Assert.Contains("PanelBg", splitterMatch.Groups[1].Value);
// 3. RightSplitter Template 내부 handle 도 PanelBg 배경을 유지해야 함
var handleMatch = Regex.Match(mainWindowXaml, @"<Border[^>]*x:Name=""handle""[^>]*Background=""([^""]+)""");
Assert.True(handleMatch.Success, "RightSplitter handle should specify Background");
Assert.Contains("PanelBg", handleMatch.Groups[1].Value);
// 4. MainGrid 에 PanelBg 배경이 지정되어 그리드 간극 투과를 원천 차단
var mainGridMatch = Regex.Match(mainWindowXaml, @"<Grid[^>]*x:Name=""MainGrid""[^>]*Background=""([^""]+)""");
Assert.True(mainGridMatch.Success, "MainGrid should specify Background=\"{DynamicResource PanelBg}\"");
Assert.Contains("PanelBg", mainGridMatch.Groups[1].Value);
}
}