using AngleSharp.Dom; using AngleSharp.Html.Parser; namespace XFESystem.Browser.Tests; public sealed class SelectorIndexTests { [Theory] [InlineData(".parent > p.target:hover", '.', "target")] [InlineData(".parent + p#target:not(.missing)", '#', "target")] [InlineData(":is(.parent, .other) .target", '.', "target")] [InlineData(".parent [title='x > y'].target", '.', "target")] [InlineData(".parent p:not(.missing)", 't', "p")] [InlineData(".parent .target[data-x]:nth-child(2n + 1)", '.', "target")] public void OnlyPositiveSubjectKeysAreIndexed(string selector, char kind, string value) => Assert.Equal((kind, value), BrowserSelectorKey.Find(selector)); [Theory] [InlineData(".parent :not(.missing)")] [InlineData(".parent :is(.target, .other)")] [InlineData(".parent [class='target']")] [InlineData(@".parent .tar\67 et")] [InlineData(".parent .target中文")] [InlineData("svg|a.target")] public void UncertainKeysKeepTheFullMatcherFallback(string selector) => Assert.Null(BrowserSelectorKey.Find(selector)); [Theory] [InlineData(".parent > p.target", "p.target", true)] [InlineData(".absent > p.target", "p.target", false)] [InlineData(".parent + p.target", "p.target", false)] [InlineData(".parent p:not(.missing)", "p.target", true)] [InlineData(":is(.other, .parent) .target", "p.target", true)] [InlineData(".parent :is(.target, .other)", "p.target", true)] [InlineData(".parent :not(.missing)", "p.target", true)] [InlineData("[title='x > y'].target", "p.target", true)] [InlineData("p.target#Target", "p.target", true)] [InlineData(".parent span", "p.target", false)] [InlineData(".target中文", "p.target中文", true)] [InlineData(@".tar\67 et", "p.target", true)] public void FullSelectorAndSpecificityStillDecideStyles(string selector, string subject, bool matches) { var document = new HtmlParser().ParseDocument("

text

other

"); var element = document.QuerySelector(subject)!; var list = new BrowserLayoutEngine().Layout(document, new(300, 100)); Assert.Equal(matches ? 0x123456u : 0x010203u, list.GetComputedStyle(element)!.Color.Rgb); } [Fact] public void LargeDescendantRuleSetRejectsUnrelatedCandidatesWithoutLosingGeneratedContentOrMutation() { string css = string.Concat(Enumerable.Range(0, 1500).Select(i => $".parent .item{i}{{color:red}}")); var document = new HtmlParser().ParseDocument("

text

"); var engine = new BrowserLayoutEngine(); var list = engine.Layout(document, new(300, 100)); Assert.Equal(0x0000ffu, list.GetComputedStyle(document.GetElementById("Target")!)!.Color.Rgb); Assert.Contains(list.Commands, c => c.Text == "icon"); Assert.InRange(engine.CssSelectorEvaluations, 2, 5); document.GetElementById("Target")!.ClassName = "item43"; list = engine.Layout(document, new(300, 100)); Assert.DoesNotContain(list.Commands, c => c.Text == "icon"); Assert.InRange(engine.CssSelectorEvaluations, 1, 5); } [Fact] public void ReusedBootstrapSyntaxKeepsEventsAndObjectsPrivateToEachPage() { var first = new BrowserService(); var second = new BrowserService(); first.Navigate("about:Start"); second.Navigate("about:Start"); first.ExecuteJavaScript("Event.prototype.xfePrivate=42;document.body.addEventListener('xfe',()=>document.body.id='changed');document.body.dispatchEvent(new Event('xfe'))"); Assert.Equal("changed", first.ExecuteJavaScript("document.body.id")); Assert.Equal("undefined", second.ExecuteJavaScript("typeof Event.prototype.xfePrivate")); Assert.Equal("", second.ExecuteJavaScript("document.body.id")); first.Release(); second.Release(); } }