using System.Text.RegularExpressions; using Shouldly; using Xunit; namespace ZB.MOM.WW.OtOpcUa.AdminUI.Tests.ScriptAnalysis; /// /// Source pins for the Monaco interop (AdminUI has no bUnit and no JS test runner). These do not prove the /// browser behaviour — the docker-dev live check does — they stop the specific regressions R04:P1/P9/S2/S3 fixed /// from quietly coming back: per-keystroke text sync, unsequenced diagnostics, the inlay-hints POST, and an /// unconsumed marker round-trip. /// [Trait("Category", "Unit")] public sealed class MonacoInteropSourceTests { private static string Read(params string[] relative) { var dir = new DirectoryInfo(AppContext.BaseDirectory); while (dir is not null && !File.Exists(Path.Combine(dir.FullName, "ZB.MOM.WW.OtOpcUa.slnx"))) dir = dir.Parent; dir.ShouldNotBeNull("could not locate the repository root"); return File.ReadAllText(Path.Combine(new[] { dir!.FullName, "src", "Server", "ZB.MOM.WW.OtOpcUa.AdminUI" }.Concat(relative).ToArray())); } private static string Js() => Read("wwwroot", "js", "monaco-init.js"); [Fact] public void The_content_change_handler_does_not_ship_the_text_to_dotnet() { var js = Js(); var handler = Regex.Match(js, @"onDidChangeModelContent\(function \(\) \{(?.*?)\n \}\);", RegexOptions.Singleline); handler.Success.ShouldBeTrue("the content-change handler moved; update this pin"); handler.Groups["body"].Value.ShouldNotContain("OnValueChanged"); handler.Groups["body"].Value.ShouldNotContain("getValue"); // Positive control: the text IS still reported — at blur. js.ShouldContain("onDidBlurEditorText"); js.ShouldContain("\"OnValueChanged\""); } [Fact] public void Diagnostics_are_generation_guarded_and_abortable() { var js = Js(); js.ShouldContain("diagGeneration"); js.ShouldContain("generation !== e.diagGeneration"); js.ShouldContain("new AbortController()"); js.ShouldContain("signal: signal"); } [Fact] public void Providers_honour_the_monaco_cancellation_token() { var js = Js(); js.ShouldContain("token.onCancellationRequested"); foreach (var path in new[] { "\"completions\"", "\"hover\"", "\"format\"", "\"signature-help\"" }) js.ShouldContain("postAnalysis(" + path); } [Fact] public void The_inlay_hints_provider_is_not_registered() => Js().ShouldNotContain("registerInlayHintsProvider"); [Fact] public void Markers_cross_to_dotnet_only_for_a_subscribed_problems_list() { Js().ShouldContain("if (e.reportMarkers) dotNetRef.invokeMethodAsync(\"OnMarkersChanged\""); Read("Components", "Shared", "MonacoEditor.razor").ShouldContain("reportMarkers = MarkersChanged.HasDelegate"); } [Theory] [InlineData("Components", "Pages", "ScriptEdit.razor")] [InlineData("Components", "Shared", "Uns", "VirtualTagModal.razor")] public void Script_hosts_read_the_editor_on_save_and_render_the_problems_list(params string[] path) { var src = Read(path); src.ShouldContain("GetValueAsync()"); src.ShouldContain("