require "test_helper" class MessagesHelperTest < ActionView::TestCase test "plain text presentation is reused by content rather than database epoch" do view.controller.stubs(:perform_caching).returns(true) FragmentCache.store.clear message = Message.create! room: rooms(:pets), body: "A reusable safe body", creator: users(:jason) first = view.message_presentation(message) assert_includes first, "A reusable safe body" ContentFilters::TextMessagePresentationFilters.expects(:apply).never assert_equal first, view.message_presentation(message) ensure FragmentCache.store.clear end test "message_presentation neutralizes unsafe URI schemes in links" do message = Message.create! room: rooms(:pets), body: '
x
', client_message_id: "0015", creator: users(:jason) presentation = view.message_presentation(message) assert_no_match /javascript:/, presentation assert_match /x<\/a>/, presentation end test "message_presentation strips event handler attributes from allowed tags" do message = Message.create! room: rooms(:pets), body: '
x
', client_message_id: "0015", creator: users(:jason) presentation = view.message_presentation(message) assert_no_match /onmouseover/, presentation assert_match /x<\/a>/, presentation end test "message_presentation preserves safe links and formatting" do message = Message.create! room: rooms(:pets), body: '
example bold
', client_message_id: "0015", creator: users(:jason) presentation = view.message_presentation(message) assert_match /]*>example<\/a>/, presentation assert_match /bold<\/strong>/, presentation end test "message_presentation links URLs and email addresses in text" do message = Message.create! room: rooms(:pets), body: "
See https://example.com/a?b=1&c=2, or write to me@example.com.
", client_message_id: "0015", creator: users(:jason) links = Nokogiri::HTML5.fragment(view.message_presentation(message)).css("a") assert_equal [ "https://example.com/a?b=1&c=2", "mailto:me@example.com" ], links.map { it["href"] } assert_equal [ "_blank", "_blank" ], links.map { it["target"] } assert_equal [ "https://example.com/a?b=1&c=2", "me@example.com" ], links.map(&:text) end test "message_presentation links an email address with an apostrophe whole" do message = Message.create! room: rooms(:pets), body: "
Write to o'brien@example.com
", client_message_id: "0015", creator: users(:jason) links = Nokogiri::HTML5.fragment(view.message_presentation(message)).css("a") assert_equal [ [ "mailto:o%27brien@example.com", "o'brien@example.com" ] ], links.map { [ it["href"], it.text ] } end test "message_presentation leaves URLs and email addresses in attribute values as they are" do [ "class", "title" ].product([ "https://example.com", "www.example.com", "me@example.com" ]).each do |attribute, linkable| value = "a> #{linkable} b " message = Message.create! room: rooms(:pets), body: %(
c https://example.org
), client_message_id: "0015", creator: users(:jason) presentation = Nokogiri::HTML5.fragment(view.message_presentation(message)) assert_equal [ value ], presentation.css("span[#{attribute}]").map { it[attribute] }, "#{attribute} with #{linkable}" assert_empty presentation.css("em"), "#{attribute} with #{linkable}" assert_equal [ "https://example.org" ], presentation.css("a").map { it["href"] }, "#{attribute} with #{linkable}" end end test "linking text doesn't eat a code block's leading blank line" do linked = view.send(:auto_link_text, "
\n\n\nfirst https://example.com
".html_safe) assert_equal "\nfirst https://example.com", Nokogiri::HTML5.fragment(linked).at_css("pre").text end test "message_presentation leaves an existing link's text alone" do message = Message.create! room: rooms(:pets), body: '
https://example.org/
', client_message_id: "0015", creator: users(:jason) links = Nokogiri::HTML5.fragment(view.message_presentation(message)).css("a") assert_equal [ [ "https://example.com/", "https://example.org/" ] ], links.map { [ it["href"], it.text ] } end test "message_presentation shows an image's thumbnail made when it was posted" do presentation = view.message_presentation(attachment_message("moon.jpg", "image/jpeg", processed: true)) assert_match %r{]+src="[^"]*/representations/[^"]*moon\.jpg"}, presentation end test "message_presentation links an image whose thumbnail wasn't made, rather than making it on view" do presentation = view.message_presentation(attachment_message("moon.jpg", "image/jpeg", processed: false)) assert_no_match %r{/representations/}, presentation assert_match %r{moon\.jpg}, presentation end test "message_presentation gives a video the poster made when it was posted" do presentation = view.message_presentation(attachment_message("alpha-centuri.mov", "video/quicktime", processed: true)) assert_match %r{]+poster="[^"]*/representations/[^"]*alpha-centuri}, presentation end test "message_presentation shows a video whose poster wasn't made without one, rather than making it on view" do presentation = view.message_presentation(attachment_message("alpha-centuri.mov", "video/quicktime", processed: false)) assert_match %r{]+src="[^"]*alpha-centuri\.mov"}, presentation assert_no_match %r{poster=|/representations/}, presentation end test "message_presentation shows a video whose frame was drawn but whose poster wasn't made without one" do message = attachment_message("alpha-centuri.mov", "video/quicktime", processed: false) message.attachment.preview(format: :jpg).processed assert message.attachment.preview(:poster).processed? presentation = view.message_presentation(message.reload) assert_match %r{]+src="[^"]*alpha-centuri\.mov"}, presentation assert_no_match %r{poster=|/representations/}, presentation end test "message_presentation shows an image in the rich text as a file, rather than making its preview on view" do message = Message.with_attachment_details.find(message_with_file_in_rich_text("moon.jpg", "image/jpeg").id) presentation = nil assert_no_queries_match(/active_storage_variant_records/) { presentation = view.message_presentation(message) } assert_no_match %r{/representations/}, presentation assert_match %r{moon\.jpg}, presentation end test "message_presentation shows an image in the rich text as a file even when its preview was made" do message = message_with_file_in_rich_text("moon.jpg", "image/jpeg") message.body.embeds.first.blob.variant(resize_to_limit: [ 1024, 768 ]).processed presentation = view.message_presentation(message.reload) assert_no_match %r{/representations/}, presentation assert_match %r{moon\.jpg}, presentation end test "message_presentation shows a video in the rich text as a file" do presentation = view.message_presentation(message_with_file_in_rich_text("alpha-centuri.mov", "video/quicktime")) assert_no_match %r{/representations/}, presentation assert_match %r{alpha-centuri\.mov}, presentation end private def attachment_message(file, content_type, processed:) attributes = { creator: users(:jason), client_message_id: "0015", attachment: fixture_file_upload(file, content_type) } if processed rooms(:pets).messages.create_with_attachment!(attributes) else rooms(:pets).messages.create!(attributes) end end def message_with_file_in_rich_text(file, content_type) blob = ActiveStorage::Blob.create_and_upload!(io: file_fixture(file).open, filename: file, content_type: content_type) body = %(
Here:
) Message.create! room: rooms(:pets), body: body, client_message_id: "0015", creator: users(:jason) end end