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
181
tests/Paca.Tests/App/SpotlightRecentQueryAndScopeGateTests.cs
Normal file
181
tests/Paca.Tests/App/SpotlightRecentQueryAndScopeGateTests.cs
Normal file
|
|
@ -0,0 +1,181 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using Paca.Browser.Search;
|
||||
using Paca.Core.QuickActions;
|
||||
using Xunit;
|
||||
|
||||
namespace Paca.Tests.App;
|
||||
|
||||
public class SpotlightRecentQueryAndScopeGateTests : IDisposable
|
||||
{
|
||||
private readonly string _tempHistoryPath;
|
||||
|
||||
public SpotlightRecentQueryAndScopeGateTests()
|
||||
{
|
||||
_tempHistoryPath = Path.Combine(Path.GetTempPath(), $"paca_query_history_test_{Guid.NewGuid():N}.json");
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
try { if (File.Exists(_tempHistoryPath)) File.Delete(_tempHistoryPath); } catch { }
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Gate228_QueryHistoryStore_Saves_Retrieves_And_Deduplicates_Queries()
|
||||
{
|
||||
var store = new QuickActionQueryHistoryStore(_tempHistoryPath);
|
||||
|
||||
// 1. Initial should be empty
|
||||
Assert.Empty(store.GetQueries("search.kakaomap"));
|
||||
|
||||
// 2. Add queries
|
||||
store.AddQuery("search.kakaomap", "판교 현대백화점");
|
||||
store.AddQuery("search.kakaomap", "강남역 맛집");
|
||||
store.AddQuery("search.google", "C# WPF tutorial");
|
||||
|
||||
var kakaoQueries = store.GetQueries("search.kakaomap");
|
||||
Assert.Equal(2, kakaoQueries.Count);
|
||||
Assert.Equal("강남역 맛집", kakaoQueries[0]);
|
||||
Assert.Equal("판교 현대백화점", kakaoQueries[1]);
|
||||
|
||||
// 3. Deduplication and bump to top
|
||||
store.AddQuery("search.kakaomap", "판교 현대백화점");
|
||||
kakaoQueries = store.GetQueries("search.kakaomap");
|
||||
Assert.Equal(2, kakaoQueries.Count);
|
||||
Assert.Equal("판교 현대백화점", kakaoQueries[0]);
|
||||
Assert.Equal("강남역 맛집", kakaoQueries[1]);
|
||||
|
||||
// 4. Persistence reload test
|
||||
var reloaded = new QuickActionQueryHistoryStore(_tempHistoryPath);
|
||||
var reloadedKakao = reloaded.GetQueries("search.kakaomap");
|
||||
Assert.Equal(2, reloadedKakao.Count);
|
||||
Assert.Equal("판교 현대백화점", reloadedKakao[0]);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Gate229_Catalog_Contains_Scoped_Navigation_Actions()
|
||||
{
|
||||
var catalog = new QuickActionCatalog();
|
||||
|
||||
var tabScope = catalog.FindById("scope.tabs");
|
||||
Assert.NotNull(tabScope);
|
||||
Assert.Contains("@tabs", tabScope.Keywords);
|
||||
Assert.Contains("@탭", tabScope.Keywords);
|
||||
Assert.Equal(QuickActionCategory.Browser, tabScope.Category);
|
||||
|
||||
var bmScope = catalog.FindById("scope.bookmarks");
|
||||
Assert.NotNull(bmScope);
|
||||
Assert.Contains("@bookmarks", bmScope.Keywords);
|
||||
Assert.Contains("@북마크", bmScope.Keywords);
|
||||
|
||||
var histScope = catalog.FindById("scope.history");
|
||||
Assert.NotNull(histScope);
|
||||
Assert.Contains("@history", histScope.Keywords);
|
||||
Assert.Contains("@방문기록", histScope.Keywords);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Gate230_LiveLauncher_PillMode_Shows_Recent_Query_History()
|
||||
{
|
||||
Exception? threadEx = null;
|
||||
var thread = new Thread(() =>
|
||||
{
|
||||
try
|
||||
{
|
||||
var store = new QuickActionQueryHistoryStore(_tempHistoryPath);
|
||||
store.AddQuery("search.kakao_map", "선릉역 라멘");
|
||||
|
||||
var catalog = new QuickActionCatalog();
|
||||
var launcher = new Paca.App.QuickActionLauncherWindow(catalog, store);
|
||||
|
||||
var kakaoAction = catalog.FindById("search.kakao_map");
|
||||
Assert.NotNull(kakaoAction);
|
||||
|
||||
// Enter Pill Mode with empty query
|
||||
launcher.EnterPillMode(kakaoAction);
|
||||
|
||||
// Results list should contain the recent query!
|
||||
Assert.NotEmpty(launcher.QuickActionResultsList.Items);
|
||||
var first = launcher.QuickActionResultsList.Items[0] as QuickActionSearchResult;
|
||||
Assert.NotNull(first);
|
||||
Assert.Equal("선릉역 라멘", first.Title);
|
||||
Assert.Equal("최근 검색", first.CategoryName);
|
||||
|
||||
launcher.Close();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
threadEx = ex;
|
||||
}
|
||||
});
|
||||
thread.SetApartmentState(ApartmentState.STA);
|
||||
thread.Start();
|
||||
bool finished = thread.Join(8000);
|
||||
Assert.True(finished, "STA thread must finish within timeout");
|
||||
if (threadEx != null)
|
||||
{
|
||||
throw new Exception($"STA Thread failed: {threadEx}");
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Gate231_LiveLauncher_Scoped_Tabs_Filtering_And_Activation()
|
||||
{
|
||||
Exception? threadEx = null;
|
||||
var thread = new Thread(() =>
|
||||
{
|
||||
try
|
||||
{
|
||||
var store = new QuickActionQueryHistoryStore(_tempHistoryPath);
|
||||
var catalog = new QuickActionCatalog();
|
||||
var launcher = new Paca.App.QuickActionLauncherWindow(catalog, store);
|
||||
|
||||
// Mock open tabs
|
||||
var mockTabs = new List<ScopedSearchItem>
|
||||
{
|
||||
new ScopedSearchItem("네이버 지도", "https://map.naver.com", OmniboxSearchScope.Tabs, "tab-1"),
|
||||
new ScopedSearchItem("GitHub - Paca", "https://github.com/torvalds/linux", OmniboxSearchScope.Tabs, "tab-2"),
|
||||
new ScopedSearchItem("YouTube - 음악 재생", "https://youtube.com", OmniboxSearchScope.Tabs, "tab-3")
|
||||
};
|
||||
|
||||
launcher.TabProvider = () => mockTabs;
|
||||
|
||||
string? activatedTabId = null;
|
||||
launcher.ScopedItemOpener = item => activatedTabId = item.AdditionalInfo;
|
||||
|
||||
var tabsAction = catalog.FindById("scope.tabs");
|
||||
Assert.NotNull(tabsAction);
|
||||
|
||||
// Enter Pill Mode for @tabs
|
||||
launcher.EnterPillMode(tabsAction);
|
||||
|
||||
// All open tabs should be listed initially
|
||||
Assert.Equal(3, launcher.QuickActionResultsList.Items.Count);
|
||||
|
||||
// Filter by "GitHub"
|
||||
launcher.QuickActionSearchBox.Text = "GitHub";
|
||||
Assert.Single(launcher.QuickActionResultsList.Items);
|
||||
var matched = (QuickActionSearchResult)launcher.QuickActionResultsList.Items[0];
|
||||
Assert.Contains("GitHub", matched.Title);
|
||||
|
||||
// Execute selected
|
||||
launcher.ExecuteSelectedAction();
|
||||
Assert.Equal("tab-2", activatedTabId);
|
||||
|
||||
launcher.Close();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
threadEx = ex;
|
||||
}
|
||||
});
|
||||
thread.SetApartmentState(ApartmentState.STA);
|
||||
thread.Start();
|
||||
bool finished = thread.Join(8000);
|
||||
Assert.True(finished, "STA thread must finish within timeout");
|
||||
if (threadEx != null) throw threadEx;
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue