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,188 @@
using System.Collections.ObjectModel;
using System.IO;
using System.Reflection;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using Paca.App;
using Paca.App.ViewModels;
using Paca.Browser;
using Paca.Tests.Infrastructure;
using Xunit;
namespace Paca.Tests.Browser;
/// <summary>
/// 북마크 시스템 & 북마크 바 UX 파이프라인.
/// </summary>
/// <summary>
/// 즐겨찾기(북마크) 바 레이아웃, 단축키(Ctrl+Shift+B), 설정창 연동 및 컨텍스트 메뉴 검증.
/// </summary>
public class BookmarkBarIntegrationTests
{
[Fact]
public void AppConfig_BookmarkBarVisible_기본값은_false이며_직렬화_가능하다()
{
var config = new AppConfig();
Assert.False(config.BookmarkBarVisible);
config.BookmarkBarVisible = true;
var json = System.Text.Json.JsonSerializer.Serialize(config);
var restored = System.Text.Json.JsonSerializer.Deserialize<AppConfig>(json);
Assert.NotNull(restored);
Assert.True(restored.BookmarkBarVisible);
}
[Fact]
public void MainWindowXaml_BookmarkBar가_ToolbarRow_아래_배치되고_컨텍스트메뉴_요소가_존재한다()
{
var xaml = SourceTree.MainWindowXaml;
Assert.Contains("x:Name=\"BookmarkBar\"", xaml);
Assert.Contains("Grid.Row=\"1\"", xaml);
Assert.Contains("BookmarkBarList", xaml);
Assert.Contains("BookmarkBar_Click", xaml);
// 컨텍스트 메뉴 또는 마우스 휠 클릭 핸들러
Assert.Contains("BookmarkBarContextMenu", xaml);
}
[Fact]
public void MainWindow_ApplyBookmarkBarVisible_메서드가_존재한다()
{
var method = typeof(MainWindow).GetMethod("ApplyBookmarkBarVisible",
BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
Assert.NotNull(method);
}
[Fact]
public void MainWindowCs_CtrlShiftB_단축키와_설정동기화_로직이_존재한다()
{
var cs = SourceTree.MainWindowCs;
Assert.Contains("Key.B", cs);
Assert.Contains("ToggleBookmarkBar", cs);
Assert.Contains("ApplyBookmarkBarVisible", cs);
}
[Fact]
public void SettingsWindowXaml_북마크바_설정_체크박스가_존재한다()
{
var xaml = SourceTree.SettingsWindowXaml;
Assert.Contains("BookmarkBarVisibleBox", xaml);
}
}
/// <summary>
/// 일반적인 브라우저 UX를 따르는 즐겨찾기(현재 페이지 등록, 팝업 모달 편집, 주소창 별표, Ctrl+D 단축키) 검증.
/// </summary>
public class BookmarkUxTests
{
private static string AppRoot =>
SourceTree.AppPath("");
[Fact]
public void MainWindowXaml_주소창_내부에_BookmarkStarBtn이_존재한다()
{
var xaml = File.ReadAllText(Path.Combine(AppRoot, "MainWindow.xaml"));
Assert.Contains("x:Name=\"BookmarkStarBtn\"", xaml);
Assert.Contains("BookmarkStarBtn_Click", xaml);
Assert.Contains("Visibility=\"Collapsed\"", xaml);
}
[Theory]
[InlineData("", true)]
[InlineData(" ", true)]
[InlineData(null, true)]
[InlineData("about:blank", true)]
[InlineData("about:newtab", true)]
[InlineData("about:srcdoc", true)]
[InlineData("https://example.com", false)]
[InlineData("http://localhost:5000", false)]
public void 빈탭_URL_판별_시_즐겨찾기_별표_버튼_숨김_여부를_올바르게_판정한다(string? url, bool shouldHide)
{
bool isBlank = string.IsNullOrWhiteSpace(url) || url.StartsWith("about:", StringComparison.OrdinalIgnoreCase);
Assert.Equal(shouldHide, isBlank);
}
[Fact]
public void MainWindowXaml_즐겨찾기_추가_수정_팝업_BookmarkEditPopup이_정의되어_있다()
{
var xaml = File.ReadAllText(Path.Combine(AppRoot, "MainWindow.xaml"));
Assert.Contains("x:Name=\"BookmarkEditPopup\"", xaml);
Assert.Contains("BookmarkEditHeaderTitle", xaml);
Assert.Contains("BookmarkEditNameBox", xaml);
Assert.Contains("BookmarkEditUrlBox", xaml);
Assert.Contains("BookmarkEditFolderCombo", xaml);
Assert.Contains("BookmarkEditDoneBtn", xaml);
Assert.Contains("BookmarkEditDeleteBtn", xaml);
Assert.Contains("BookmarkEditCancelBtn", xaml);
}
[Fact]
public void MainWindowCs_Ctrl_D_단축키_핸들러가_존재한다()
{
var cs = File.ReadAllText(Path.Combine(AppRoot, "MainWindow.xaml.cs"));
Assert.Contains("ModifierKeys.Control && e.Key == Key.D", cs);
}
[Fact]
public void MainWindowCs_별표_상태_갱신_및_편집_다이얼로그_메서드가_존재한다()
{
var cs = File.ReadAllText(Path.Combine(AppRoot, "MainWindow.xaml.cs")) +
File.ReadAllText(Path.Combine(AppRoot, "MainWindow.Usecases.cs"));
Assert.Contains("UpdateBookmarkStarState", cs);
Assert.Contains("ShowBookmarkEditDialog", cs);
}
[Fact]
public void MainWindowCs_AnyPopupOpen_및_CloseAllPopups에_BookmarkEditPopup이_포함된다()
{
var cs = File.ReadAllText(Path.Combine(AppRoot, "MainWindow.xaml.cs")) +
File.ReadAllText(Path.Combine(AppRoot, "MainWindow.Usecases.cs"));
Assert.Contains("BookmarkEditPopup.IsOpen", cs);
Assert.Contains("BookmarkEditPopup", cs);
}
[Fact]
public void 북마크_폴더_목록_추출_및_갱신_로직_검증()
{
var bookmarks = new ObservableCollection<Bookmark>
{
new("네이버", "https://naver.com", "포털"),
new("구글", "https://google.com", "포털"),
new("유튜브", "https://youtube.com", "동영상"),
new("깃허브", "https://github.com", null),
};
// 폴더 목록 추출
var folders = bookmarks
.Select(b => b.Folder)
.Where(f => !string.IsNullOrWhiteSpace(f))
.Distinct()
.OrderBy(f => f)
.ToList();
Assert.Equal(2, folders.Count);
Assert.Contains("포털", folders);
Assert.Contains("동영상", folders);
}
[Fact]
public void 북마크_폴더_즐겨찾기바_선택시_null_정규화_로직_검증()
{
string? NormalizeFolder(string? input)
{
var folderText = input?.Trim();
return string.IsNullOrWhiteSpace(folderText) || folderText == "즐겨찾기 바" ? null : folderText;
}
Assert.Null(NormalizeFolder("즐겨찾기 바"));
Assert.Null(NormalizeFolder(" "));
Assert.Null(NormalizeFolder(null));
Assert.Equal("개발 폴더", NormalizeFolder("개발 폴더"));
Assert.Equal("기타 즐겨찾기", NormalizeFolder("기타 즐겨찾기"));
}
}