diff --git a/pdf-umbenenner-adapter-in-gui/src/main/java/de/gecheckt/pdf/umbenenner/adapter/in/gui/GuiConfigurationEditorWorkspace.java b/pdf-umbenenner-adapter-in-gui/src/main/java/de/gecheckt/pdf/umbenenner/adapter/in/gui/GuiConfigurationEditorWorkspace.java index 470df4e..3f93f0c 100644 --- a/pdf-umbenenner-adapter-in-gui/src/main/java/de/gecheckt/pdf/umbenenner/adapter/in/gui/GuiConfigurationEditorWorkspace.java +++ b/pdf-umbenenner-adapter-in-gui/src/main/java/de/gecheckt/pdf/umbenenner/adapter/in/gui/GuiConfigurationEditorWorkspace.java @@ -1967,14 +1967,14 @@ public final class GuiConfigurationEditorWorkspace { /** * Updates the API-key origin labels below each provider's API-key field. *
- * The display logic follows the effective-key precedence order: - *
* The origin information is derived from the pending field findings produced by the validator,
* which already resolved the API-key precedence for both providers.
@@ -1988,28 +1988,20 @@ public final class GuiConfigurationEditorWorkspace {
String apiKeyField = "ai.provider." + family.getIdentifier() + ".apiKey";
// Look for an INFO finding about ENV-variable origin for this provider.
+ // WARNING/ERROR findings (missing key) are intentionally excluded here:
+ // those are already shown by the field-error label registered in fieldErrorLabels,
+ // and repeating them in the origin label would cause the same text to appear twice
+ // in close proximity below the API-key field.
Optional
+ * The field-error label (registered in {@code fieldErrorLabels}) already shows the warning
+ * below the input field; duplicating the same text in the origin label would cause the same
+ * message to appear twice in close visual proximity. The origin label is therefore hidden
+ * for the absent-key case.
+ */
+ @Test
+ void apiKeyAbsent_originLabelHidden() throws Exception {
+ runOnFx(() -> {
+ GuiConfigurationEditorWorkspace ws = new GuiConfigurationEditorWorkspace(Optional.empty());
+ ws.requestNewConfiguration();
+
+ // Standard template has active provider = Claude but no API key value.
+ Label originLabel = ws.apiKeyOriginLabels.get(AiProviderFamily.CLAUDE);
+ assertNotNull(originLabel,
+ "An api-key origin label must be registered for AiProviderFamily.CLAUDE");
+ assertFalse(originLabel.isVisible(),
+ "Claude api-key origin label must be HIDDEN when no API key is configured "
+ + "— the field-error label already shows the warning, so the origin label "
+ + "must not repeat it");
+ });
+ }
+
+ /**
+ * Smoke test: when no API key is configured, the field-error label registered for
+ * {@code ai.provider.claude.apiKey} must be visible and carry a non-blank warning text.
+ *
+ * This is the single intended location for the missing-key warning below the input field.
+ */
+ @Test
+ void apiKeyAbsent_fieldErrorLabelVisible() throws Exception {
+ runOnFx(() -> {
+ GuiConfigurationEditorWorkspace ws = new GuiConfigurationEditorWorkspace(Optional.empty());
+ ws.requestNewConfiguration();
+
+ Label errorLabel = ws.fieldErrorLabels.get("ai.provider.claude.apiKey");
+ assertNotNull(errorLabel,
+ "A field-error label must be registered for 'ai.provider.claude.apiKey'");
+ assertTrue(errorLabel.isVisible(),
+ "api-key field-error label must be visible when no API key is configured");
+ assertFalse(errorLabel.getText().isBlank(),
+ "api-key field-error label must carry a non-blank warning text");
+ });
+ }
+
+ /**
+ * Smoke test: when no API key is configured, the text of the missing-key warning must appear
+ * exactly once in {@code pendingMessages}. Having the same text twice would mean two
+ * validation sources independently write the same finding to the central message area.
+ */
+ @Test
+ void apiKeyAbsent_noDuplicateMessageInPendingMessages() throws Exception {
+ runOnFx(() -> {
+ GuiConfigurationEditorWorkspace ws = new GuiConfigurationEditorWorkspace(Optional.empty());
+ ws.requestNewConfiguration();
+
+ // Collect all message texts that contain the canonical "Kein API-Schlüssel" fragment.
+ long count = ws.pendingMessages.stream()
+ .filter(m -> m.text().contains("API-Schlüssel") || m.text().contains("API-Key"))
+ .count();
+ assertTrue(count <= 1,
+ "The missing-API-key finding must appear at most once in pendingMessages, "
+ + "but found " + count + " occurrences");
+ });
+ }
+
// =========================================================================
// Scenario: INFO-coloured prefix in the message area (model-catalogue success)
// =========================================================================