Phase C (T2-1..T3-10): command palette, reader mode (real Readability.js, E2E), boost force-dark, screenshot, split view, vertical tabs, Glance (Alt+click), tab groups (6 colors), workspaces, speed dial, InPrivate tabs, quick find, source view, print, PiP, TTS (94 tests GREEN)
This commit is contained in:
parent
0caa1111e7
commit
406957088f
14 changed files with 3496 additions and 7 deletions
128
VideoDownloader.Tests/Browser/CommandPaletteTests.cs
Normal file
128
VideoDownloader.Tests/Browser/CommandPaletteTests.cs
Normal file
|
|
@ -0,0 +1,128 @@
|
|||
using VideoDownloader.App.Browser.Features;
|
||||
|
||||
namespace VideoDownloader.Tests.Browser;
|
||||
|
||||
// ── T2-1 명령 팔레트: 등록·검색·실행 ──
|
||||
public class CommandPaletteTests
|
||||
{
|
||||
private sealed class CommandHost
|
||||
{
|
||||
public List<string> Executed = new();
|
||||
public List<string> Tabs = new() { "https://a.com", "https://b.com" };
|
||||
public List<string> History = new() { "https://news.com" };
|
||||
|
||||
public CommandPalette Build()
|
||||
{
|
||||
var palette = new CommandPalette();
|
||||
palette.Register("새 탭", "tab new open", () => Executed.Add("newtab"));
|
||||
palette.Register("탭 닫기", "close tab", () => Executed.Add("close"));
|
||||
palette.Register("전체화면", "fullscreen f11", () => Executed.Add("fs"));
|
||||
palette.Register("리더 모드", "reader reading", () => Executed.Add("reader"));
|
||||
palette.Register("다크 모드", "dark theme boost", () => Executed.Add("dark"));
|
||||
palette.RegisterSeparator();
|
||||
// 동적 소스: 탭/히스토리 → 명령으로
|
||||
palette.RegisterDynamic(() => Tabs.Select(t => new PaletteCommand($"탭: {t}", "tab go", () => Executed.Add("go:" + t))).ToList());
|
||||
palette.RegisterDynamic(() => History.Select(h => new PaletteCommand($"기록: {h}", "history", () => Executed.Add("hist:" + h))).ToList());
|
||||
return palette;
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void 등록된_명령을_검색한다_라벨_키워드_부분일치()
|
||||
{
|
||||
var p = new CommandHost().Build();
|
||||
var hits = p.Search("리더");
|
||||
Assert.Single(hits);
|
||||
Assert.Equal("리더 모드", hits[0].Title);
|
||||
|
||||
hits = p.Search("F11"); // 키워드 검색
|
||||
Assert.Single(hits);
|
||||
|
||||
hits = p.Search("TAB"); // 대소문자 무시
|
||||
Assert.Contains(hits, h => h.Title == "새 탭");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void 동적_소스_탭과_기록도_결과에_포함된다()
|
||||
{
|
||||
var p = new CommandHost().Build();
|
||||
var hits = p.Search("탭:");
|
||||
Assert.Equal(2, hits.Count);
|
||||
hits = p.Search("기록:");
|
||||
Assert.Single(hits);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void 실행은_콜백을_호출한다()
|
||||
{
|
||||
var host = new CommandHost();
|
||||
var p = host.Build();
|
||||
p.Execute(p.Search("전체").Single());
|
||||
Assert.Equal(new[] { "fs" }, host.Executed);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void 빈_질의는_정적_명령_전체를_순서대로_반환()
|
||||
{
|
||||
var p = new CommandHost().Build();
|
||||
var hits = p.Search("");
|
||||
Assert.Equal("새 탭", hits[0].Title);
|
||||
Assert.Equal("다크 모드", hits[^1].Title); // 동적 제외, 정적만
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void 매치_순위는_시작_일치_우선()
|
||||
{
|
||||
var p = new CommandPalette();
|
||||
p.Register("탭 닫기", "close", () => { });
|
||||
p.Register("닫힌 탭 복원", "reopen closed", () => { });
|
||||
var hits = p.Search("탭");
|
||||
Assert.Equal("탭 닫기", hits[0].Title); // "탭"으로 시작하는 것이 우선
|
||||
}
|
||||
}
|
||||
|
||||
// ── T2-7 Boost: 사이트별 강제 다크/커스텀 CSS 영속 ──
|
||||
public class BoostStoreTests : IDisposable
|
||||
{
|
||||
private readonly string _path = Path.Combine(Path.GetTempPath(), $"boost_{Guid.NewGuid():N}.json");
|
||||
|
||||
[Fact]
|
||||
public void 기본은_빈_부스트()
|
||||
{
|
||||
var s = new BoostStore(_path);
|
||||
Assert.False(s.Get("example.com").ForceDark);
|
||||
Assert.Equal("", s.Get("example.com").CustomCss);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void 강제다크와_CSS를_저장하면_영속된다()
|
||||
{
|
||||
var s = new BoostStore(_path);
|
||||
s.Set("example.com", forceDark: true, css: "body{zoom:1.1}");
|
||||
var re = new BoostStore(_path);
|
||||
Assert.True(re.Get("example.com").ForceDark);
|
||||
Assert.Equal("body{zoom:1.1}", re.Get("example.com").CustomCss);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void www_정규화_및_빈_부스트는_CSS를_만들지_않는다()
|
||||
{
|
||||
var s = new BoostStore(_path);
|
||||
s.Set("www.example.com", true, "");
|
||||
Assert.True(s.Get("example.com").ForceDark); // www 정규화
|
||||
var js = BoostCssBuilder.BuildScript("plain.org", s.Get("plain.org"));
|
||||
Assert.Equal("", js); // 미설정 사이트 → 빈 스크립트
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void 강제다크_스크립트는_반전필터를_포함하고_이미지_비디오를_보호한다()
|
||||
{
|
||||
var js = BoostCssBuilder.BuildScript("d.com", new BoostSettings(ForceDark: true, "h1{color:red}"));
|
||||
Assert.Contains("invert(1)", js);
|
||||
Assert.Contains("img", js); // 미디어 보호 셀렉터
|
||||
Assert.Contains("video", js);
|
||||
Assert.Contains("h1{color:red}", js);
|
||||
}
|
||||
|
||||
public void Dispose() { try { File.Delete(_path); } catch { } }
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue