feat(m9/T31): Monaco JSON-schema hover/completion on value-entry surface
This commit is contained in:
+101
@@ -0,0 +1,101 @@
|
||||
using Bunit;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using NSubstitute;
|
||||
using ZB.MOM.WW.ScadaBridge.CentralUI.Components.Shared;
|
||||
using ZB.MOM.WW.ScadaBridge.CentralUI.Services;
|
||||
|
||||
namespace ZB.MOM.WW.ScadaBridge.CentralUI.Tests.Design;
|
||||
|
||||
/// <summary>
|
||||
/// M9-T31: the raw-JSON escape hatch in <see cref="ParameterValueForm"/> (the
|
||||
/// fallback for an unresolved <c>$ref</c> / unknown-type node) is a Monaco
|
||||
/// <c>json</c> editor wired with the form's RESOLVED schema, so Monaco's
|
||||
/// built-in JSON language gives schema-driven hover + completion. These tests
|
||||
/// assert at the C#/interop boundary that the resolved schema (with
|
||||
/// <c>{"$ref":"lib:Name"}</c> inlined) reaches the editor's <c>JsonSchema</c>
|
||||
/// parameter — the JS hover/completion itself is Monaco-built-in and not
|
||||
/// unit-testable here.
|
||||
/// </summary>
|
||||
public class ParameterValueFormMonacoSchemaTests : BunitContext
|
||||
{
|
||||
private readonly ISchemaLibraryQueryService _library = Substitute.For<ISchemaLibraryQueryService>();
|
||||
|
||||
public ParameterValueFormMonacoSchemaTests()
|
||||
{
|
||||
// The escape-hatch surface renders a MonacoEditor whose JS interop is not
|
||||
// exercised here — Loose mode lets the unconfigured createEditor call no-op
|
||||
// so the render completes and we can assert on the editor's parameters.
|
||||
JSInterop.Mode = JSRuntimeMode.Loose;
|
||||
_library.GetSchemaMapAsync(Arg.Any<CancellationToken>())
|
||||
.Returns(new Dictionary<string, string>());
|
||||
Services.AddSingleton(_library);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void EscapeHatch_RendersMonacoJsonEditor_NotPlainTextarea()
|
||||
{
|
||||
// A nested field whose $ref cannot be resolved drops to the raw-JSON
|
||||
// escape hatch. That surface must now be a Monaco json editor.
|
||||
const string schema = """
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"payload": { "$ref": "lib:Missing" }
|
||||
}
|
||||
}
|
||||
""";
|
||||
|
||||
var cut = Render<ParameterValueForm>(p => p
|
||||
.Add(x => x.ParameterDefinitions, schema)
|
||||
.Add(x => x.Values, new Dictionary<string, object?>()));
|
||||
|
||||
var editor = cut.FindComponent<MonacoEditor>();
|
||||
Assert.Equal("json", editor.Instance.Language);
|
||||
// No plain <textarea> fallback remains for the escape hatch.
|
||||
Assert.Empty(cut.FindAll("textarea"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void EscapeHatch_MonacoEditor_ReceivesResolvedSchema_WithRefInlined()
|
||||
{
|
||||
// The library entry "Address" resolves to an object with street/city.
|
||||
const string libSchema = """
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"street": { "type": "string" },
|
||||
"city": { "type": "string" }
|
||||
}
|
||||
}
|
||||
""";
|
||||
_library.GetSchemaMapAsync(Arg.Any<CancellationToken>())
|
||||
.Returns(new Dictionary<string, string> { ["Address"] = libSchema });
|
||||
|
||||
// Root has a RESOLVABLE $ref field (shipTo → Address) plus an
|
||||
// UNRESOLVABLE one (payload) that forces the escape-hatch Monaco editor.
|
||||
const string schema = """
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"shipTo": { "$ref": "lib:Address" },
|
||||
"payload": { "$ref": "lib:Missing" }
|
||||
}
|
||||
}
|
||||
""";
|
||||
|
||||
var cut = Render<ParameterValueForm>(p => p
|
||||
.Add(x => x.ParameterDefinitions, schema)
|
||||
.Add(x => x.Values, new Dictionary<string, object?>()));
|
||||
|
||||
var editor = cut.FindComponent<MonacoEditor>();
|
||||
var jsonSchema = editor.Instance.JsonSchema;
|
||||
|
||||
Assert.False(string.IsNullOrWhiteSpace(jsonSchema));
|
||||
// The RESOLVED shape is fed to Monaco: the $ref target's fields are
|
||||
// inlined (street/city present), and the lib: pointer text is gone.
|
||||
Assert.Contains("street", jsonSchema!);
|
||||
Assert.Contains("city", jsonSchema!);
|
||||
Assert.DoesNotContain("lib:Address", jsonSchema!);
|
||||
Assert.DoesNotContain("$ref", jsonSchema!);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user