diff --git a/app/services/messages/markdown_renderer_service.rb b/app/services/messages/markdown_renderer_service.rb index 8984374d1..a90cfca06 100644 --- a/app/services/messages/markdown_renderer_service.rb +++ b/app/services/messages/markdown_renderer_service.rb @@ -47,13 +47,19 @@ class Messages::MarkdownRendererService end def render_telegram_html + # Strip whitespace from whitespace-only lines to normalize newlines + normalized_content = @content.gsub(/^[ \t]+$/m, '') + content_with_preserved_newlines = preserve_multiple_newlines(normalized_content) renderer = Messages::MarkdownRenderers::TelegramRenderer.new - doc = CommonMarker.render_doc(@content, [:STRIKETHROUGH_DOUBLE_TILDE], [:strikethrough]) - renderer.render(doc).gsub(/\n+\z/, '') + doc = CommonMarker.render_doc(content_with_preserved_newlines, [:STRIKETHROUGH_DOUBLE_TILDE], [:strikethrough]) + result = renderer.render(doc).gsub(/\n+\z/, '') + restore_multiple_newlines(result) end def render_whatsapp - content_with_preserved_newlines = preserve_multiple_newlines(@content) + # Strip whitespace from whitespace-only lines to normalize newlines + normalized_content = @content.gsub(/^[ \t]+$/m, '') + content_with_preserved_newlines = preserve_multiple_newlines(normalized_content) renderer = Messages::MarkdownRenderers::WhatsAppRenderer.new doc = CommonMarker.render_doc(content_with_preserved_newlines, [:DEFAULT, :STRIKETHROUGH_DOUBLE_TILDE]) result = renderer.render(doc).gsub(/\n+\z/, '') @@ -61,7 +67,9 @@ class Messages::MarkdownRendererService end def render_instagram - content_with_preserved_newlines = preserve_multiple_newlines(@content) + # Strip whitespace from whitespace-only lines to normalize newlines + normalized_content = @content.gsub(/^[ \t]+$/m, '') + content_with_preserved_newlines = preserve_multiple_newlines(normalized_content) renderer = Messages::MarkdownRenderers::InstagramRenderer.new doc = CommonMarker.render_doc(content_with_preserved_newlines, [:DEFAULT, :STRIKETHROUGH_DOUBLE_TILDE]) result = renderer.render(doc).gsub(/\n+\z/, '') @@ -69,7 +77,9 @@ class Messages::MarkdownRendererService end def render_line - content_with_preserved_newlines = preserve_multiple_newlines(@content) + # Strip whitespace from whitespace-only lines to normalize newlines + normalized_content = @content.gsub(/^[ \t]+$/m, '') + content_with_preserved_newlines = preserve_multiple_newlines(normalized_content) renderer = Messages::MarkdownRenderers::LineRenderer.new doc = CommonMarker.render_doc(content_with_preserved_newlines, [:DEFAULT, :STRIKETHROUGH_DOUBLE_TILDE]) result = renderer.render(doc).gsub(/\n+\z/, '') @@ -77,7 +87,9 @@ class Messages::MarkdownRendererService end def render_plain_text - content_with_preserved_newlines = preserve_multiple_newlines(@content) + # Strip whitespace from whitespace-only lines to normalize newlines + normalized_content = @content.gsub(/^[ \t]+$/m, '') + content_with_preserved_newlines = preserve_multiple_newlines(normalized_content) renderer = Messages::MarkdownRenderers::PlainTextRenderer.new doc = CommonMarker.render_doc(content_with_preserved_newlines, [:DEFAULT, :STRIKETHROUGH_DOUBLE_TILDE]) result = renderer.render(doc).gsub(/\n+\z/, '') diff --git a/spec/services/messages/markdown_renderer_service_spec.rb b/spec/services/messages/markdown_renderer_service_spec.rb index d589c6ad1..89210dc0e 100644 --- a/spec/services/messages/markdown_renderer_service_spec.rb +++ b/spec/services/messages/markdown_renderer_service_spec.rb @@ -426,5 +426,40 @@ RSpec.describe Messages::MarkdownRendererService, type: :service do expect(result).to eq(content) end end + + # Shared test for all text-based channels that preserve multiple newlines + # This tests the real-world scenario where frontend sends newlines with whitespace between them + context 'when content has multiple newlines with whitespace between them' do + # This mimics what frontends often send: newlines with spaces/tabs between them + let(:content_with_whitespace_newlines) { "hello \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n\nhello wow" } + + %w[ + Channel::Telegram + Channel::Whatsapp + Channel::Instagram + Channel::FacebookPage + Channel::Line + Channel::Sms + ].each do |channel_type| + context "when channel is #{channel_type}" do + it 'normalizes whitespace-only lines and preserves multiple newlines' do + result = described_class.new(content_with_whitespace_newlines, channel_type).render + # Should preserve most of the newlines (at least 10+) + # The exact count may vary slightly by renderer, but should be significantly more than 1-2 + expect(result.scan("\n").count).to be >= 10 + # Should not collapse everything to just 1-2 newlines + expect(result.scan("\n").count).to be > 5 + end + end + end + + context 'when channel is Channel::TwilioSms with WhatsApp' do + it 'normalizes whitespace-only lines and preserves multiple newlines' do + channel = instance_double(Channel::TwilioSms, whatsapp?: true) + result = described_class.new(content_with_whitespace_newlines, 'Channel::TwilioSms', channel).render + expect(result.scan("\n").count).to be >= 10 + end + end + end end end