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,55 @@
using System.Linq;
using Paca.Browser.Tabs;
using Xunit;
namespace Paca.Tests.Browser;
public class ChromeTabDeduplicationTests
{
[Fact]
public void CloseDuplicateTabs_Closes_Redundant_Tabs_Keeping_Original()
{
var mgr = new TabManager(() => new TabItem());
var tab1 = mgr.NewTab("https://example.com/page1"); // original
var tab2 = mgr.NewTab("https://example.com/page2");
var tab3 = mgr.NewTab("https://example.com/page1", activate: false); // duplicate of tab1
var tab4 = mgr.NewTab("https://example.com/page1", activate: false); // another duplicate
var tab5 = mgr.NewTab("https://example.com/page2", activate: false); // duplicate of tab2
Assert.Equal(5, mgr.Tabs.Count);
int closed = mgr.CloseDuplicateTabs();
Assert.Equal(3, closed);
Assert.Equal(2, mgr.Tabs.Count);
Assert.Contains(tab1, mgr.Tabs);
Assert.Contains(tab2, mgr.Tabs);
Assert.DoesNotContain(tab3, mgr.Tabs);
Assert.DoesNotContain(tab4, mgr.Tabs);
Assert.DoesNotContain(tab5, mgr.Tabs);
}
[Fact]
public void CloseDuplicateTabs_Preserves_Locked_Tabs()
{
var mgr = new TabManager(() => new TabItem());
var tab1 = mgr.NewTab("https://example.com/locked");
var tab2 = mgr.NewTab("https://example.com/locked", activate: false);
tab2.IsLocked = true; // locked duplicate should not be closed
int closed = mgr.CloseDuplicateTabs();
Assert.Equal(0, closed);
Assert.Equal(2, mgr.Tabs.Count);
}
[Theory]
[InlineData("중복 탭 닫기")]
[InlineData("중복 탭 정리")]
[InlineData("close duplicates")]
[InlineData("dedup tabs")]
public void Omnibox_Matches_CloseDuplicates_Action(string query)
{
var actions = OmniboxActionEvaluator.GetMatchingActions(query);
Assert.NotEmpty(actions);
Assert.Contains(actions, a => a.ActionId == "action:close-duplicates");
}
}