diff --git a/src/main/java/kz/konturai/parser/service/MarketingAnalysisService.java b/src/main/java/kz/konturai/parser/service/MarketingAnalysisService.java index 1cf2e31..ca3c10e 100644 --- a/src/main/java/kz/konturai/parser/service/MarketingAnalysisService.java +++ b/src/main/java/kz/konturai/parser/service/MarketingAnalysisService.java @@ -95,9 +95,13 @@ public class MarketingAnalysisService { } private String buildChartJsonBlock(String chartKey, String jsonStr) { - // Keep block compact: do not add extra blank lines here (front-end correlates - // adjacent text with the chart). - return "```json:" + chartKey + "\n" + jsonStr + "\n```"; + // Frontend parses fenced blocks by info-string `json:` and expects a + // blank line after the closing fence to avoid "sticking" text to the chart. + // Contract: + // ```json:\n + // \n + // ```\n\n + return "```json:" + chartKey + "\n" + jsonStr + "\n```\n\n"; } /** diff --git a/src/test/java/kz/konturai/parser/service/MarketingAnalysisServiceChartPlacementTest.java b/src/test/java/kz/konturai/parser/service/MarketingAnalysisServiceChartPlacementTest.java index c39ad01..2712a1e 100644 --- a/src/test/java/kz/konturai/parser/service/MarketingAnalysisServiceChartPlacementTest.java +++ b/src/test/java/kz/konturai/parser/service/MarketingAnalysisServiceChartPlacementTest.java @@ -10,6 +10,7 @@ import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; +import java.util.regex.Pattern; import org.junit.jupiter.api.Test; @@ -153,4 +154,21 @@ class MarketingAnalysisServiceChartPlacementTest { assertTrue(section7Body.contains("[[CHART_CHANNEL_MATRIX]]"), "Must insert CHART_CHANNEL_MATRIX into section VII"); } + + @Test + void buildChartJsonBlock_shouldStartWithJsonKey_andEndWithDoubleNewline() throws Exception { + Method m = MarketingAnalysisService.class.getDeclaredMethod("buildChartJsonBlock", String.class, String.class); + m.setAccessible(true); + + String out = (String) m.invoke(marketingAnalysisService, "segmentsChannelMatrix", "{\"a\":1}"); + + assertTrue(out.startsWith("```json:segmentsChannelMatrix\n"), + "Block must start strictly with ```json: and newline"); + assertTrue(out.endsWith("\n```\n\n"), "Block must end with closing fence followed by two newlines"); + + // Ensure there is no whitespace before opening fence (strict parsing on + // frontend) + assertTrue(Pattern.compile("(?m)^```json:segmentsChannelMatrix$").matcher(out).find(), + "Opening fence line must be exactly ```json: with no leading spaces"); + } }