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:
parent
a88aafa1e5
commit
0e568f1f0a
975 changed files with 130593 additions and 16783 deletions
260
tests/Paca.Tests/Browser/BrowserMenuAndDesignTests.cs
Normal file
260
tests/Paca.Tests/Browser/BrowserMenuAndDesignTests.cs
Normal file
|
|
@ -0,0 +1,260 @@
|
|||
using System.IO;
|
||||
using Paca.Server;
|
||||
using Paca.Tests.Infrastructure;
|
||||
using Xunit;
|
||||
|
||||
namespace Paca.Tests.Browser;
|
||||
|
||||
/// <summary>
|
||||
/// 브라우저 UX 고도화 및 글래스모피즘 디자인 검증:
|
||||
/// - 햄버거 메인 메뉴(MainMenuBtn 및 MainMenuPopup 다층 서브메뉴) 구성
|
||||
/// - 다크/라이트/고대비 테마의 GlassBorder 토큰 무결성
|
||||
/// - Shared.xaml 제로 헤어라인 고스트/아이콘 버튼 및 글래스모픽 메뉴 스타일
|
||||
/// - WebCompanion 글래스모피즘 CSS 토큰 및 반응형 레이아웃
|
||||
/// </summary>
|
||||
public class BrowserMenuAndDesignTests
|
||||
{
|
||||
private static string AppPath(params string[] parts) => SourceTree.AppPath(Path.Combine(parts));
|
||||
|
||||
[Fact]
|
||||
public void 메인윈도우_툴바_메인메뉴_버튼과_팝업이_정의되어_있다()
|
||||
{
|
||||
var xamlPath = AppPath("MainWindow.xaml");
|
||||
Assert.True(File.Exists(xamlPath), "MainWindow.xaml 이 존재해야 합니다.");
|
||||
var content = File.ReadAllText(xamlPath);
|
||||
|
||||
// 햄버거/3-dots 메인 메뉴 버튼
|
||||
Assert.Contains("Name=\"MainMenuBtn\"", content);
|
||||
Assert.Contains("AutomationProperties.Name=\"메인 메뉴\"", content);
|
||||
|
||||
// 다층 서브메뉴가 있는 MainMenuPopup 및 VerticalMenu
|
||||
Assert.Contains("Name=\"MainMenuPopup\"", content);
|
||||
Assert.Contains("Style=\"{StaticResource VerticalMenu}\"", content);
|
||||
Assert.Contains("MenuItem.Click=\"MainMenu_MenuItemClick\"", content);
|
||||
Assert.Contains("Header=\"새 탭\"", content);
|
||||
Assert.Contains("Header=\"새 창\"", content);
|
||||
Assert.Contains("Header=\"새 InPrivate 창\"", content);
|
||||
Assert.Contains("Header=\"방문 기록\"", content);
|
||||
Assert.Contains("Header=\"즐겨찾기\"", content);
|
||||
Assert.Contains("Header=\"다운로드 & 라이브러리\"", content);
|
||||
Assert.Contains("Header=\"페이지 도구\"", content);
|
||||
Assert.Contains("Header=\"미디어 & 원격 기능\"", content);
|
||||
Assert.Contains("Header=\"개발자 도구\"", content);
|
||||
Assert.Contains("Header=\"도움말 & 정보\"", content);
|
||||
Assert.Contains("Name=\"MenuZoomText\"", content);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("Dark.xaml")]
|
||||
[InlineData("Light.xaml")]
|
||||
[InlineData("HighContrast.xaml")]
|
||||
public void 모든_테마에_GlassBorder_브러시_토큰이_정의되어_있다(string themeFile)
|
||||
{
|
||||
var themePath = AppPath("Themes", themeFile);
|
||||
Assert.True(File.Exists(themePath), $"{themeFile} 이 존재해야 합니다.");
|
||||
var content = File.ReadAllText(themePath);
|
||||
|
||||
Assert.Contains("x:Key=\"GlassBorder\"", content);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Shared_사전에_GhostButton과_MenuItem_글래스모피즘_스타일이_정의되어_있다()
|
||||
{
|
||||
var sharedPath = AppPath("Themes", "Shared.xaml");
|
||||
Assert.True(File.Exists(sharedPath), "Themes/Shared.xaml 이 존재해야 합니다.");
|
||||
var content = File.ReadAllText(sharedPath);
|
||||
|
||||
// 버튼 스타일
|
||||
Assert.Contains("x:Key=\"GhostButton\"", content);
|
||||
Assert.Contains("x:Key=\"IconButton\"", content);
|
||||
Assert.Contains("x:Key=\"CardActionButton\"", content);
|
||||
|
||||
// 메뉴 스타일
|
||||
Assert.Contains("TargetType=\"MenuItem\"", content);
|
||||
Assert.Contains("TargetType=\"ContextMenu\"", content);
|
||||
Assert.Contains("TargetType=\"Menu\"", content);
|
||||
Assert.Contains("x:Key=\"VerticalMenu\"", content);
|
||||
Assert.Contains("TargetType=\"Separator\"", content);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WebCompanion_글래스모피즘_CSS_스타일이_적용되어_있다()
|
||||
{
|
||||
var html = WebCompanion.Html;
|
||||
Assert.Contains("backdrop-filter: blur(", html);
|
||||
Assert.Contains("--glass-border", html);
|
||||
Assert.Contains("--card-bg", html);
|
||||
Assert.Contains("PACA", html);
|
||||
Assert.Contains("원격 다운로드", html);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Shared_사전에_탭가독성_Foreground와_미니콤보박스_스타일이_정의되어_있다()
|
||||
{
|
||||
var sharedPath = AppPath("Themes", "Shared.xaml");
|
||||
Assert.True(File.Exists(sharedPath), "Themes/Shared.xaml 이 존재해야 합니다.");
|
||||
var content = File.ReadAllText(sharedPath);
|
||||
|
||||
// 탭 제목 Foreground 설정 (다크/라이트 테마 가독성 보장)
|
||||
Assert.Contains("x:Key=\"TabTitleStyle\"", content);
|
||||
Assert.Contains("Value=\"{DynamicResource TextSecondary}\"", content);
|
||||
|
||||
// 탭 닫기 및 미니 인라인 콤보박스 스타일
|
||||
Assert.Contains("x:Key=\"TabCloseButton\"", content);
|
||||
Assert.Contains("x:Key=\"MiniDarkComboBox\"", content);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void 메인윈도우_작업공간_캡슐과_활성탭_대비가_정의되어_있다()
|
||||
{
|
||||
var xamlPath = AppPath("MainWindow.xaml");
|
||||
Assert.True(File.Exists(xamlPath), "MainWindow.xaml 이 존재해야 합니다.");
|
||||
var content = File.ReadAllText(xamlPath);
|
||||
|
||||
// 불필요한 라벨 제거 및 미니멀 작업공간 드롭다운/인디케이터 확인
|
||||
Assert.DoesNotContain("작업공간:", content);
|
||||
Assert.Contains("x:Name=\"WorkspaceIndicator\"", content);
|
||||
Assert.Contains("x:Name=\"WorkspaceSwitcher\"", content);
|
||||
Assert.Contains("Style=\"{StaticResource MiniDarkComboBox}\"", content);
|
||||
|
||||
// 활성 탭 텍스트 명암비(TextPrimary 및 SemiBold)
|
||||
Assert.Contains("x:Name=\"TabTitleText\"", content);
|
||||
Assert.Contains("Value=\"{DynamicResource TextPrimary}\"", content);
|
||||
Assert.Contains("Value=\"SemiBold\"", content);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void 메뉴와_팝업_플라이아웃에_Fade_애니메이션이_정의되어_있다()
|
||||
{
|
||||
var sharedPath = AppPath("Themes", "Shared.xaml");
|
||||
Assert.True(File.Exists(sharedPath), "Themes/Shared.xaml 이 존재해야 합니다.");
|
||||
var sharedContent = File.ReadAllText(sharedPath);
|
||||
|
||||
// FlyoutBorder 스타일 및 페이드 애니메이션 스토리보드
|
||||
Assert.Contains("x:Key=\"FlyoutBorder\"", sharedContent);
|
||||
Assert.Contains("Storyboard.TargetProperty=\"Opacity\"", sharedContent);
|
||||
Assert.Contains("DoubleAnimation", sharedContent);
|
||||
|
||||
// MainWindow.xaml 팝업들의 Fade 애니메이션 및 FlyoutBorder 적용
|
||||
var xamlPath = AppPath("MainWindow.xaml");
|
||||
Assert.True(File.Exists(xamlPath), "MainWindow.xaml 이 존재해야 합니다.");
|
||||
var mainContent = File.ReadAllText(xamlPath);
|
||||
|
||||
Assert.Contains("PopupAnimation=\"Fade\"", mainContent);
|
||||
Assert.Contains("Style=\"{StaticResource FlyoutBorder}\"", mainContent);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TabViewService_초기탐색은_about_blank에서도_HomeUrl을_탐색한다()
|
||||
{
|
||||
var servicePath = AppPath("Services", "TabViewService.cs");
|
||||
Assert.True(File.Exists(servicePath), "TabViewService.cs 가 존재해야 합니다.");
|
||||
var content = File.ReadAllText(servicePath);
|
||||
|
||||
// 초기 URL 탐색 시 about:blank 가 감지되어도 tab.Url 로 Navigate 호출을 수행해야 함
|
||||
Assert.Contains("string.Equals(cv.Source, \"about:blank\", StringComparison.OrdinalIgnoreCase)", content);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WebCompanion_모바일_100dvh_및_세련된_글래스모피즘이_적용되어_있다()
|
||||
{
|
||||
var html = WebCompanion.Html;
|
||||
Assert.Contains("100dvh", html); // 모바일 브라우저 뷰포트 점핑 방지
|
||||
Assert.Contains("--glass-inner-shadow", html);
|
||||
Assert.Contains("--accent-gradient", html);
|
||||
Assert.Contains("Pretendard", html);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WebCompanion_ConnectCode_원격_게이트웨이_및_이어보기_동기화가_포함되어_있다()
|
||||
{
|
||||
var html = WebCompanion.Html;
|
||||
// ConnectCode 및 3G/4G/5G 원격 안내와 이어보기 위치 API(/api/position) 스크립트 검증
|
||||
Assert.Contains("cc=", html);
|
||||
Assert.Contains("/api/position", html);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WebCompanion_Token_QueryParam_및_LocalStorage_영속화_스크립트가_포함되어_있다()
|
||||
{
|
||||
var html = WebCompanion.Html;
|
||||
Assert.Contains("localStorage", html);
|
||||
Assert.Contains("paca_t", html);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void PairingWindow_다크_테마_글래스모피즘_리소스가_적용되어_있다()
|
||||
{
|
||||
var pairingPath = AppPath("Browser", "PairingWindow.cs");
|
||||
Assert.True(File.Exists(pairingPath), "PairingWindow.cs 가 존재해야 합니다.");
|
||||
var content = File.ReadAllText(pairingPath);
|
||||
|
||||
Assert.Contains("WindowBgGradient", content);
|
||||
Assert.Contains("CardBg", content);
|
||||
Assert.Contains("WindowChrome", content);
|
||||
Assert.Contains("PrimaryButton", content);
|
||||
Assert.DoesNotContain("Background = System.Windows.Media.Brushes.White;", content);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void PairingWindow_LAN_및_5G_원격_게이트웨이_UI가_구비되어_있다()
|
||||
{
|
||||
var pairingPath = AppPath("Browser", "PairingWindow.cs");
|
||||
Assert.True(File.Exists(pairingPath), "PairingWindow.cs 가 존재해야 합니다.");
|
||||
var content = File.ReadAllText(pairingPath);
|
||||
|
||||
// LAN 원클릭 자동 탐색 및 3G/4G/5G 원격 게이트웨이 Connect Code UI 요소 검증
|
||||
Assert.Contains("LAN 자동 탐색", content);
|
||||
Assert.Contains("3G / 4G / 5G", content);
|
||||
Assert.Contains("ConnectCode", content);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void PlayerWindow_테마_토큰_및_글래스_HUD가_정의되어_있다()
|
||||
{
|
||||
var playerPath = AppPath("Browser", "PlayerWindow.cs");
|
||||
Assert.True(File.Exists(playerPath), "PlayerWindow.cs 가 존재해야 합니다.");
|
||||
var content = File.ReadAllText(playerPath);
|
||||
|
||||
Assert.Contains("PanelBg", content);
|
||||
Assert.Contains("BorderSubtle", content);
|
||||
Assert.Contains("CardActionButton", content);
|
||||
Assert.Contains("MiniDarkComboBox", content);
|
||||
Assert.Contains("backdrop-filter:blur(24px)", content);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WebView2_웹페이지_우클릭_컨텍스트메뉴는_네이티브_메뉴로_표시되고_다운로드항목이_주입된다()
|
||||
{
|
||||
var tabViewPath = AppPath("Services", "TabViewService.cs");
|
||||
var tabViewContent = File.ReadAllText(tabViewPath);
|
||||
|
||||
// ce.Handled = true; 로 네이티브 메뉴를 전면 차단하지 않아야 함
|
||||
Assert.DoesNotContain("ce.Handled = true;\r\n ContextMenuBuild?.Invoke", tabViewContent);
|
||||
Assert.DoesNotContain("ce.Handled = true;\n ContextMenuBuild?.Invoke", tabViewContent);
|
||||
|
||||
var mainPath = AppPath("MainWindow.xaml.cs");
|
||||
var mainContent = File.ReadAllText(mainPath);
|
||||
|
||||
// WPF ContextMenu 팝업 우회 대신 WebView2 CreateContextMenuItem 네이티브 주입 사용
|
||||
Assert.Contains("CreateContextMenuItem", mainContent);
|
||||
Assert.Contains("CustomItemSelected", mainContent);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TabViewService_소셜로그인_OAuth_팝업_WindowCloseRequested_이벤트를_배선한다()
|
||||
{
|
||||
var tabViewPath = AppPath("Services", "TabViewService.cs");
|
||||
var tabViewContent = File.ReadAllText(tabViewPath);
|
||||
|
||||
// 구글 로그인 등 OAuth 팝업이 window.close() 호출 시 탭이 자동 닫히도록 배선 필수
|
||||
Assert.Contains("WindowCloseRequested", tabViewContent);
|
||||
Assert.Contains("TabCloseRequested", tabViewContent);
|
||||
|
||||
var mainPath = AppPath("MainWindow.xaml.cs");
|
||||
var mainContent = File.ReadAllText(mainPath);
|
||||
Assert.Contains("TabCloseRequested += tab =>", mainContent);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue