diff --git a/app/services/messages/markdown_renderer_service.rb b/app/services/messages/markdown_renderer_service.rb index 00a731a6d..77b33c8a9 100644 --- a/app/services/messages/markdown_renderer_service.rb +++ b/app/services/messages/markdown_renderer_service.rb @@ -9,7 +9,8 @@ class Messages::MarkdownRendererService 'Channel::Line' => :render_line, 'Channel::TwitterProfile' => :render_plain_text, 'Channel::Sms' => :render_plain_text, - 'Channel::TwilioSms' => :render_plain_text + 'Channel::TwilioSms' => :render_plain_text, + 'Channel::Api' => :render_api_message }.freeze def initialize(content, channel_type, channel = nil) @@ -56,6 +57,11 @@ class Messages::MarkdownRendererService restore_multiple_newlines(result) end + def render_api_message + # Convert literal \n strings to actual newlines for API channel messages + @content.gsub('\\n', "\n") + end + def render_whatsapp # Strip whitespace from whitespace-only lines to normalize newlines normalized_content = @content.gsub(/^[ \t]+$/m, '') diff --git a/spec/services/messages/markdown_renderer_service_spec.rb b/spec/services/messages/markdown_renderer_service_spec.rb index 8bad763b4..6a587f5b7 100644 --- a/spec/services/messages/markdown_renderer_service_spec.rb +++ b/spec/services/messages/markdown_renderer_service_spec.rb @@ -493,6 +493,31 @@ RSpec.describe Messages::MarkdownRendererService, type: :service do result = described_class.new(content, channel_type).render expect(result).to eq("- Item 1\n- Item 2") end + + it 'converts literal \\n strings to actual newlines' do + content = 'Hi \\ntext message \\nwith line \\nbreak' + result = described_class.new(content, channel_type).render + expect(result).to eq("Hi \ntext message \nwith line \nbreak") + end + + it 'handles multiple literal \\n in sequence' do + content = 'Line 1\\n\\n\\nLine 2' + result = described_class.new(content, channel_type).render + expect(result).to eq("Line 1\n\n\nLine 2") + end + + it 'preserves markdown formatting while converting \\n' do + content = '**bold**\\n_italic_\\n`code`' + result = described_class.new(content, channel_type).render + expect(result).to eq("**bold**\n_italic_\n`code`") + end + + it 'handles real-world API payload with literal \\n strings' do + content = 'Hi \\ntext message \\nwith line \\nbreak' + result = described_class.new(content, channel_type).render + expect(result).to eq("Hi \ntext message \nwith line \nbreak") + expect(result).not_to include('\\n') + end end context 'when channel is Channel::TwitterProfile' do