Discover Converter capabilities and validate shared binding drafts

This commit is contained in:
2026-11-13 12:58:08 +01:00
parent 17b1bce704
commit 5a208d2336
35 changed files with 1096 additions and 34 deletions
@@ -267,6 +267,88 @@ public final class ProjectionHostChecks {
return doc.snapshot().toCompletableFuture().get().text();
}
private static boolean bindingStatus(DesignerPane pane, String text) throws Exception {
return fx(() -> ((Label) pane.lookup("#direct-status")).getText().contains(text));
}
private static void converterEdits(DesignerPane pane, DocumentSession document, String full)
throws Exception {
bindingTab(pane, "Direct bindings");
selectDirect(pane, "rankInput");
click(pane, "Find Converters / Validate");
await(() -> fx(() -> !((ComboBox<?>) pane.lookup("#direct-converters")).getItems().isEmpty()));
check(
fx(
() ->
((TextField) pane.lookup("#direct-converter"))
.getText()
.equals("fixture.components.RankConverter")),
"Existing Converter changed");
check(documentText(document).equals(full), "Validation altered source");
directField(pane, "converter", "");
click(pane, "Apply binding");
await(() -> !documentText(document).equals(full));
String invalid = documentText(document);
await(() -> fx(() -> source(pane).getText().equals(invalid)));
click(pane, "Render drafts");
await(() -> bindingStatus(pane, "Incompatible value types"));
await(
() ->
fx(
() ->
pane.lookupAll(".label").stream()
.anyMatch(
n ->
n instanceof Label l
&& l.getText() != null
&& l.getText().startsWith("Preview blocked:"))));
selectDirect(pane, "rankInput");
click(pane, "Find Converters / Validate");
await(
() ->
fx(
() ->
((TextField) pane.lookup("#direct-converter"))
.getText()
.equals("fixture.components.RankConverter")));
check(documentText(document).equals(invalid), "Proposal applied without review");
click(pane, "Apply binding");
await(() -> !documentText(document).equals(invalid));
String repaired = documentText(document);
click(pane, "Undo");
await(() -> documentText(document).equals(invalid));
click(pane, "Redo");
await(() -> documentText(document).equals(repaired));
await(() -> fx(() -> source(pane).getText().equals(repaired)));
selectDirect(pane, "rankInput");
directField(pane, "converter", "fixture.components.LegacyRankConverter");
click(pane, "Apply binding");
await(() -> documentText(document).contains("LegacyRankConverter"));
await(() -> fx(() -> source(pane).getText().contains("LegacyRankConverter")));
selectDirect(pane, "rankInput");
click(pane, "Find Converters / Validate");
await(() -> bindingStatus(pane, "WARNING rankInput.text"));
check(
fx(
() ->
((TextField) pane.lookup("#direct-converter"))
.getText()
.equals("fixture.components.LegacyRankConverter")),
"Unverified explicit Converter replaced");
set(document, full);
await(() -> fx(() -> source(pane).getText().equals(full)));
click(pane, "New binding");
directField(pane, "control", "action");
directField(pane, "property", "text");
directField(pane, "path", "name");
click(pane, "Find Converters / Validate");
await(() -> fx(() -> ((ComboBox<?>) pane.lookup("#direct-converters")).getItems().size() > 1));
check(
fx(() -> ((TextField) pane.lookup("#direct-converter")).getText().isEmpty()),
"Ambiguous candidates silently selected");
check(documentText(document).equals(full), "Converter browsing altered source");
}
private static void directBindingEdits(DesignerPane pane, DocumentSession document, String full)
throws Exception {
bindingTab(pane, "Direct bindings");
@@ -697,6 +779,7 @@ public final class ProjectionHostChecks {
&& ((TextField) pane.lookup("#direct-path")).getText().equals("rank")),
"Discovery did not populate binding form");
check(documentText(document).equals(full), "Discovery handoff changed source before Apply");
converterEdits(pane, document, full);
directBindingEdits(pane, document, full);
document
.save(document.snapshot().toCompletableFuture().get().revision())