Meldungsbereich: Button linksbündig; leeren bei Validieren und Techn. Tests

- clearMessagesButton ist jetzt linksbündig (CENTER_LEFT statt CENTER_RIGHT)
- pendingMessages.clear() wird auch am Anfang von runValidationAction() und
  runTechnicalTestsAction() aufgerufen; jeder Durchlauf zeigt nur seine eigenen
  Befunde
- GuiValidateActionSmokeTest: Erwartung von 2 auf 1 Bestätigungsmeldung nach
  zwei Klicks angepasst (Replace- statt Akkumulierungsverhalten)
- Zwei neue Smoke-Tests: validationAction_clearsPreviousMessages und
  technicalTestsAction_clearsPreviousMessages
- Dokumentation in docs/gui-bedienanleitung.md ergänzt

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-04-22 11:54:14 +02:00
parent 1996f31f43
commit 13e4922272
4 changed files with 89 additions and 12 deletions
@@ -1501,6 +1501,7 @@ public final class GuiConfigurationEditorWorkspace {
*/
private void runTechnicalTestsAction() {
LOG.info("Aktion Technische Tests ausführen gestartet.");
pendingMessages.clear();
technicalTestsButton.setDisable(true);
technicalTestCoordinator.triggerTechnicalTests();
}
@@ -1569,7 +1570,7 @@ public final class GuiConfigurationEditorWorkspace {
clearMessagesButton.setOnAction(e -> clearMessages());
HBox clearButtonRow = new HBox(clearMessagesButton);
clearButtonRow.setAlignment(Pos.CENTER_RIGHT);
clearButtonRow.setAlignment(Pos.CENTER_LEFT);
card.getChildren().add(clearButtonRow);
// Populate immediately so the area is not blank before the first validation run.
@@ -1739,6 +1740,7 @@ public final class GuiConfigurationEditorWorkspace {
*/
private void runValidationAction() {
LOG.info("Aktion Validieren ausgeführt.");
pendingMessages.clear();
EditorValidationInput input = buildValidationInput();
EditorValidationReport report = editorValidator.validate(input);
@@ -680,6 +680,75 @@ class GuiMessageAreaSmokeTest {
});
}
// =========================================================================
// Scenario: "Validieren" clears previous messages before showing results
// =========================================================================
/**
* Smoke test: invoking {@code runValidationAction()} via the validate button removes
* pre-existing messages so that results from a previous action do not accumulate.
*/
@Test
void validationAction_clearsPreviousMessages() throws Exception {
runOnFx(() -> {
GuiConfigurationEditorWorkspace ws = new GuiConfigurationEditorWorkspace(Optional.empty());
ws.requestNewConfiguration();
// Seed a stale message that must not survive the validation action.
ws.pendingMessages.add(
GuiMessageEntry.of(GuiMessageSeverity.ERROR, "Alter Befund", "Test"));
assertFalse(ws.pendingMessages.isEmpty(),
"Pre-condition: pending messages must not be empty before Validieren");
ws.validateButton.fire();
assertFalse(
ws.pendingMessages.stream()
.anyMatch(m -> "Alter Befund".equals(m.text())),
"The stale message must have been removed after Validieren");
});
}
// =========================================================================
// Scenario: "Technische Tests ausführen" clears previous messages before starting
// =========================================================================
/**
* Smoke test: invoking the technical-tests action removes pre-existing messages so that
* results from a previous action do not accumulate.
* <p>
* The clear happens synchronously on the FX thread before the background worker starts.
* The thread factory is replaced with a no-op so no background thread is actually
* started, which prevents native dialog calls that are not supported under Monocle.
*/
@Test
void technicalTestsAction_clearsPreviousMessages() throws Exception {
runOnFx(() -> {
GuiConfigurationEditorWorkspace ws = new GuiConfigurationEditorWorkspace(Optional.empty());
ws.requestNewConfiguration();
// Replace thread factory with a no-op so no background work runs in Monocle.
ws.technicalTestCoordinator.testThreadFactory = task -> new Thread(() -> { }) {
@Override
public void start() {
// Do not start — we only verify the synchronous clear, not the test result.
}
};
ws.pendingMessages.add(
GuiMessageEntry.of(GuiMessageSeverity.WARNING, "Alte Warnung", "Test"));
assertFalse(ws.pendingMessages.isEmpty(),
"Pre-condition: pending messages must not be empty before technical tests");
ws.technicalTestsButton.fire();
assertFalse(
ws.pendingMessages.stream()
.anyMatch(m -> "Alte Warnung".equals(m.text())),
"The stale message must have been removed after Technische Tests ausführen");
});
}
// =========================================================================
// Scenario: ai.provider.active field-error label is registered and shown
// =========================================================================
@@ -244,13 +244,13 @@ class GuiValidateActionSmokeTest {
}
// =========================================================================
// Scenario: clicking twice → message appears exactly once (replace semantics)
// Scenario: clicking twice → exactly one message present (replace semantics)
// =========================================================================
/**
* Smoke test: clicking "Validieren" twice must leave two action-confirmation
* INFO messages in the message list (accumulation semantics — each click appends
* a fresh snapshot of findings).
* Smoke test: clicking "Validieren" twice must leave exactly one action-confirmation
* INFO message in the message list. Each click clears the previous messages before
* adding the new result, so messages from an earlier click do not accumulate.
*
* @throws Exception if the FX thread task fails or times out
*/
@@ -267,8 +267,9 @@ class GuiValidateActionSmokeTest {
&& ACTION_SOURCE.equals(m.source().get()))
.filter(m -> m.text().startsWith("Aktion Validieren wurde ausgeführt."))
.count();
assertEquals(2, confirmationCount,
"After two clicks two action-confirmation INFO messages must be present");
assertEquals(1, confirmationCount,
"After two clicks exactly one action-confirmation INFO message must be present"
+ " (second click replaces messages from the first click)");
});
}