XFE Git
XFE Studio Git
Git 首页 全局搜索
XFE 主站 文档 NuGet

XFESystem

【Rust】XFE系统,基于Rust和汇编

公开
关注 0 Fork 0 Star 0
UTF-8
using AngleSharp.Dom;
using XFESystem.Browser;
using Xunit;
using Xunit.Abstractions;

namespace XFESystem.Documents.Tests;

public sealed class WebsiteWebBrowserTests(ITestOutputHelper output)
{
    [Fact]
    public void ExactWebsiteScriptsHighlightCSharpAndBuildRealInteractiveCodeTools()
    {
        var browser = CreateBrowser();
        browser.NavigateDocument(WebsiteAssets.ReadText("Fixtures/WebsiteParity.md"), "WebsiteParity.md");
        for (int frame = 1; frame <= 8; frame++) browser.AdvanceTime(frame * 20);
        output.WriteLine(browser.RefreshDocument().Text);
        Assert.DoesNotContain("JavaScript error:", browser.CurrentPage.Text, StringComparison.Ordinal);
        var doc = Assert.IsAssignableFrom<IDocument>(browser.Document);
        Assert.True(doc.QuerySelectorAll(".language-csharp .hljs-keyword").Length > 0);
        Assert.True(doc.QuerySelectorAll(".language-csharp .hljs-string").Length > 0);
        Assert.True(doc.QuerySelectorAll(".language-csharp .hljs-comment").Length > 0);
        var pre = Assert.Single(doc.QuerySelectorAll("pre.code-block-enhanced"));
        Assert.Equal("true", pre.GetAttribute("data-code-tools-applied"));
        Assert.Equal(4, pre.QuerySelectorAll("[data-code-action]").Length);
        Assert.True(pre.QuerySelectorAll(".code-line-numbers > span").Length > 8);
        Assert.True(pre.ClassList.Contains("code-lines-visible"));
        browser.ExecuteJavaScript("document.querySelector('[data-code-action=lines]').click();");
        Assert.False(pre.ClassList.Contains("code-lines-visible"));
        browser.ExecuteJavaScript("document.querySelector('[data-code-action=lines]').click();");
        Assert.True(pre.ClassList.Contains("code-lines-visible"));
        Assert.Equal(3, doc.QuerySelectorAll("table tr").Length);
        Assert.NotEmpty(doc.QuerySelectorAll("blockquote"));
        Assert.NotEmpty(doc.QuerySelectorAll("ul li"));
        Assert.NotEmpty(doc.QuerySelectorAll("ol li"));
        Assert.NotEmpty(doc.QuerySelectorAll("a[href^='#']"));
        Assert.Contains(browser.LoadedResources, resource => resource.Address.EndsWith("/js/docs/csharp.js", StringComparison.Ordinal));
        Assert.All(browser.LoadedResources, resource => Assert.StartsWith(PackagedBrowserResources.Origin + "/", resource.Address));
    }

    [Fact]
    public void ExactWebsiteKatexProducesRealDomAndMermaidReportsMissingSvgThroughOriginalFallback()
    {
        var browser = CreateBrowser();
        browser.NavigateDocument(WebsiteAssets.ReadText("Fixtures/WebsiteParity.md"), "WebsiteParity.md");
        for (int frame = 1; frame <= 32; frame++) browser.AdvanceTime(frame * 20);
        output.WriteLine(browser.RefreshDocument().Text);
        var doc = Assert.IsAssignableFrom<IDocument>(browser.Document);
        Assert.Equal(2, doc.QuerySelectorAll(".katex").Length);
        Assert.NotNull(doc.QuerySelector(".katex .mfrac"));
        var wrapper = Assert.Single(doc.QuerySelectorAll(".mermaid-wrapper"));
        Assert.True(wrapper.ClassList.Contains("is-error"));
        Assert.False(wrapper.ClassList.Contains("is-rendered"));
        Assert.Empty(wrapper.QuerySelectorAll("svg"));
        Assert.Contains("图表渲染失败", wrapper.QuerySelector(".mermaid-error-title")!.TextContent, StringComparison.Ordinal);
        var originalSource = wrapper.QuerySelector("pre.mermaid-source code")!.TextContent;
        Assert.Contains("flowchart LR", originalSource, StringComparison.Ordinal);
        Assert.Contains("A[Markdown] --> B[Web renderer]", originalSource, StringComparison.Ordinal);
        Assert.Contains(browser.LoadedResources, resource => resource.Address.Contains("/js/docs/mermaid.min.js", StringComparison.Ordinal));
        Assert.True(wrapper.QuerySelector("[data-mermaid-action=zoom-in]")!.HasAttribute("disabled"));
        output.WriteLine("MermaidNeedsSvg=true; original library and fallback executed; SVG getBBox and vector painting remain unsupported.");
    }

    [Fact]
    public void GeneratedLocalPreviewSanitizesMarkdownAndRefusesOffOriginAutomaticResources()
    {
        var transport = new RejectNetwork();
        var browser = new BrowserService(transport);
        browser.NavigateDocument("# Safe\n<script>globalThis.MarkdownEvil=true</script><img src=x onerror=\"globalThis.MarkdownEvil=true\">", "Safe.md");
        Assert.Equal("undefined", browser.ExecuteJavaScript("typeof MarkdownEvil"));
        Assert.DoesNotContain("onerror", browser.Document!.DocumentElement.OuterHtml, StringComparison.OrdinalIgnoreCase);
        browser.ExecuteJavaScript("var outside=document.createElement('script');outside.src='http://outside.invalid/Evil.js';document.head.appendChild(outside);");
        Assert.Empty(transport.Requests);
        Assert.DoesNotContain(browser.LoadedResources, resource => resource.Address.Contains("outside.invalid", StringComparison.Ordinal));
        Assert.Contains("bundled", browser.RefreshDocument().Text, StringComparison.OrdinalIgnoreCase);
    }

    private static BrowserService CreateBrowser() => new(transport: new RejectNetwork());

    private sealed class RejectNetwork : IWebTransport
    {
        public List<Uri> Requests { get; } = [];
        public WebResponse Get(Uri address, BrowserLimits limits)
        { Requests.Add(address); throw new InvalidOperationException("The fixture cannot access a network: " + address); }
    }
}