|
|
|
@ -2,38 +2,38 @@
|
|
|
|
|
|
|
|
|
|
require "rails_helper"
|
|
|
|
|
|
|
|
|
|
describe ChatMessage do
|
|
|
|
|
describe Chat::Message do
|
|
|
|
|
fab!(:message) { Fabricate(:chat_message, message: "hey friend, what's up?!") }
|
|
|
|
|
|
|
|
|
|
it { is_expected.to have_many(:chat_mentions).dependent(:destroy) }
|
|
|
|
|
|
|
|
|
|
describe ".cook" do
|
|
|
|
|
it "does not support HTML tags" do
|
|
|
|
|
cooked = ChatMessage.cook("<h1>test</h1>")
|
|
|
|
|
cooked = described_class.cook("<h1>test</h1>")
|
|
|
|
|
|
|
|
|
|
expect(cooked).to eq("<p><h1>test</h1></p>")
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
it "does not support headings" do
|
|
|
|
|
cooked = ChatMessage.cook("## heading 2")
|
|
|
|
|
cooked = described_class.cook("## heading 2")
|
|
|
|
|
|
|
|
|
|
expect(cooked).to eq("<p>## heading 2</p>")
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
it "does not support horizontal rules" do
|
|
|
|
|
cooked = ChatMessage.cook("---")
|
|
|
|
|
cooked = described_class.cook("---")
|
|
|
|
|
|
|
|
|
|
expect(cooked).to eq("<p>---</p>")
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
it "supports backticks rule" do
|
|
|
|
|
cooked = ChatMessage.cook("`test`")
|
|
|
|
|
cooked = described_class.cook("`test`")
|
|
|
|
|
|
|
|
|
|
expect(cooked).to eq("<p><code>test</code></p>")
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
it "supports fence rule" do
|
|
|
|
|
cooked = ChatMessage.cook(<<~RAW)
|
|
|
|
|
cooked = described_class.cook(<<~RAW)
|
|
|
|
|
```
|
|
|
|
|
something = test
|
|
|
|
|
```
|
|
|
|
@ -46,7 +46,7 @@ describe ChatMessage do
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
it "supports fence rule with language support" do
|
|
|
|
|
cooked = ChatMessage.cook(<<~RAW)
|
|
|
|
|
cooked = described_class.cook(<<~RAW)
|
|
|
|
|
```ruby
|
|
|
|
|
Widget.triangulate(argument: "no u")
|
|
|
|
|
```
|
|
|
|
@ -59,13 +59,13 @@ describe ChatMessage do
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
it "supports code rule" do
|
|
|
|
|
cooked = ChatMessage.cook(" something = test")
|
|
|
|
|
cooked = described_class.cook(" something = test")
|
|
|
|
|
|
|
|
|
|
expect(cooked).to eq("<pre><code>something = test\n</code></pre>")
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
it "supports blockquote rule" do
|
|
|
|
|
cooked = ChatMessage.cook("> a quote")
|
|
|
|
|
cooked = described_class.cook("> a quote")
|
|
|
|
|
|
|
|
|
|
expect(cooked).to eq("<blockquote>\n<p>a quote</p>\n</blockquote>")
|
|
|
|
|
end
|
|
|
|
@ -77,7 +77,7 @@ describe ChatMessage do
|
|
|
|
|
avatar_src =
|
|
|
|
|
"//test.localhost#{User.system_avatar_template(post.user.username).gsub("{size}", "40")}"
|
|
|
|
|
|
|
|
|
|
cooked = ChatMessage.cook(<<~RAW)
|
|
|
|
|
cooked = described_class.cook(<<~RAW)
|
|
|
|
|
[quote="#{post.user.username}, post:#{post.post_number}, topic:#{topic.id}"]
|
|
|
|
|
Mark me...this will go down in history.
|
|
|
|
|
[/quote]
|
|
|
|
@ -120,8 +120,8 @@ describe ChatMessage do
|
|
|
|
|
)
|
|
|
|
|
other_messages_to_quote = [msg1, msg2]
|
|
|
|
|
cooked =
|
|
|
|
|
ChatMessage.cook(
|
|
|
|
|
ChatTranscriptService.new(
|
|
|
|
|
described_class.cook(
|
|
|
|
|
Chat::TranscriptService.new(
|
|
|
|
|
chat_channel,
|
|
|
|
|
Fabricate(:user),
|
|
|
|
|
messages_or_ids: other_messages_to_quote.map(&:id),
|
|
|
|
@ -166,13 +166,13 @@ describe ChatMessage do
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
it "supports strikethrough rule" do
|
|
|
|
|
cooked = ChatMessage.cook("~~test~~")
|
|
|
|
|
cooked = described_class.cook("~~test~~")
|
|
|
|
|
|
|
|
|
|
expect(cooked).to eq("<p><s>test</s></p>")
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
it "supports emphasis rule" do
|
|
|
|
|
cooked = ChatMessage.cook("**bold**")
|
|
|
|
|
cooked = described_class.cook("**bold**")
|
|
|
|
|
|
|
|
|
|
expect(cooked).to eq("<p><strong>bold</strong></p>")
|
|
|
|
|
end
|
|
|
|
@ -186,7 +186,7 @@ describe ChatMessage do
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
it "supports table markdown plugin" do
|
|
|
|
|
cooked = ChatMessage.cook(<<~RAW)
|
|
|
|
|
cooked = described_class.cook(<<~RAW)
|
|
|
|
|
| Command | Description |
|
|
|
|
|
| --- | --- |
|
|
|
|
|
| git status | List all new or modified files |
|
|
|
|
@ -215,7 +215,7 @@ describe ChatMessage do
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
it "supports onebox markdown plugin" do
|
|
|
|
|
cooked = ChatMessage.cook("https://www.example.com")
|
|
|
|
|
cooked = described_class.cook("https://www.example.com")
|
|
|
|
|
|
|
|
|
|
expect(cooked).to eq(
|
|
|
|
|
"<p><a href=\"https://www.example.com\" class=\"onebox\" target=\"_blank\" rel=\"noopener nofollow ugc\">https://www.example.com</a></p>",
|
|
|
|
@ -223,7 +223,7 @@ describe ChatMessage do
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
it "supports emoji plugin" do
|
|
|
|
|
cooked = ChatMessage.cook(":grin:")
|
|
|
|
|
cooked = described_class.cook(":grin:")
|
|
|
|
|
|
|
|
|
|
expect(cooked).to eq(
|
|
|
|
|
"<p><img src=\"/images/emoji/twitter/grin.png?v=12\" title=\":grin:\" class=\"emoji only-emoji\" alt=\":grin:\" loading=\"lazy\" width=\"20\" height=\"20\"></p>",
|
|
|
|
@ -231,7 +231,7 @@ describe ChatMessage do
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
it "supports mentions plugin" do
|
|
|
|
|
cooked = ChatMessage.cook("@mention")
|
|
|
|
|
cooked = described_class.cook("@mention")
|
|
|
|
|
|
|
|
|
|
expect(cooked).to eq("<p><span class=\"mention\">@mention</span></p>")
|
|
|
|
|
end
|
|
|
|
@ -242,7 +242,7 @@ describe ChatMessage do
|
|
|
|
|
|
|
|
|
|
category = Fabricate(:category)
|
|
|
|
|
|
|
|
|
|
cooked = ChatMessage.cook("##{category.slug}")
|
|
|
|
|
cooked = described_class.cook("##{category.slug}")
|
|
|
|
|
|
|
|
|
|
expect(cooked).to eq(
|
|
|
|
|
"<p><a class=\"hashtag\" href=\"#{category.url}\">#<span>#{category.slug}</span></a></p>",
|
|
|
|
@ -256,7 +256,7 @@ describe ChatMessage do
|
|
|
|
|
category = Fabricate(:category)
|
|
|
|
|
user = Fabricate(:user)
|
|
|
|
|
|
|
|
|
|
cooked = ChatMessage.cook("##{category.slug}", user_id: user.id)
|
|
|
|
|
cooked = described_class.cook("##{category.slug}", user_id: user.id)
|
|
|
|
|
|
|
|
|
|
expect(cooked).to eq(
|
|
|
|
|
"<p><a class=\"hashtag-cooked\" href=\"#{category.url}\" data-type=\"category\" data-slug=\"#{category.slug}\"><svg class=\"fa d-icon d-icon-folder svg-icon svg-node\"><use href=\"#folder\"></use></svg><span>#{category.name}</span></a></p>",
|
|
|
|
@ -266,7 +266,7 @@ describe ChatMessage do
|
|
|
|
|
it "supports censored plugin" do
|
|
|
|
|
watched_word = Fabricate(:watched_word, action: WatchedWord.actions[:censor])
|
|
|
|
|
|
|
|
|
|
cooked = ChatMessage.cook(watched_word.word)
|
|
|
|
|
cooked = described_class.cook(watched_word.word)
|
|
|
|
|
|
|
|
|
|
expect(cooked).to eq("<p>■■■■■</p>")
|
|
|
|
|
end
|
|
|
|
@ -293,13 +293,13 @@ describe ChatMessage do
|
|
|
|
|
gif =
|
|
|
|
|
Fabricate(:upload, original_filename: "cat.gif", width: 400, height: 300, extension: "gif")
|
|
|
|
|
message = Fabricate(:chat_message, message: "")
|
|
|
|
|
UploadReference.create(target: message, upload: gif)
|
|
|
|
|
message.attach_uploads([gif])
|
|
|
|
|
|
|
|
|
|
expect(message.excerpt).to eq "cat.gif"
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
it "supports autolink with <>" do
|
|
|
|
|
cooked = ChatMessage.cook("<https://github.com/discourse/discourse-chat/pull/468>")
|
|
|
|
|
cooked = described_class.cook("<https://github.com/discourse/discourse-chat/pull/468>")
|
|
|
|
|
|
|
|
|
|
expect(cooked).to eq(
|
|
|
|
|
"<p><a href=\"https://github.com/discourse/discourse-chat/pull/468\" rel=\"noopener nofollow ugc\">https://github.com/discourse/discourse-chat/pull/468</a></p>",
|
|
|
|
@ -307,7 +307,7 @@ describe ChatMessage do
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
it "supports lists" do
|
|
|
|
|
cooked = ChatMessage.cook(<<~MSG)
|
|
|
|
|
cooked = described_class.cook(<<~MSG)
|
|
|
|
|
wow look it's a list
|
|
|
|
|
|
|
|
|
|
* item 1
|
|
|
|
@ -324,14 +324,14 @@ describe ChatMessage do
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
it "supports inline emoji" do
|
|
|
|
|
cooked = ChatMessage.cook(":D")
|
|
|
|
|
cooked = described_class.cook(":D")
|
|
|
|
|
expect(cooked).to eq(<<~HTML.chomp)
|
|
|
|
|
<p><img src="/images/emoji/twitter/smiley.png?v=12" title=":smiley:" class="emoji only-emoji" alt=":smiley:" loading=\"lazy\" width=\"20\" height=\"20\"></p>
|
|
|
|
|
HTML
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
it "supports emoji shortcuts" do
|
|
|
|
|
cooked = ChatMessage.cook("this is a replace test :P :|")
|
|
|
|
|
cooked = described_class.cook("this is a replace test :P :|")
|
|
|
|
|
expect(cooked).to eq(<<~HTML.chomp)
|
|
|
|
|
<p>this is a replace test <img src="/images/emoji/twitter/stuck_out_tongue.png?v=12" title=":stuck_out_tongue:" class="emoji" alt=":stuck_out_tongue:" loading=\"lazy\" width=\"20\" height=\"20\"> <img src="/images/emoji/twitter/expressionless.png?v=12" title=":expressionless:" class="emoji" alt=":expressionless:" loading=\"lazy\" width=\"20\" height=\"20\"></p>
|
|
|
|
|
HTML
|
|
|
|
@ -339,7 +339,8 @@ describe ChatMessage do
|
|
|
|
|
|
|
|
|
|
it "supports spoilers" do
|
|
|
|
|
if SiteSetting.respond_to?(:spoiler_enabled) && SiteSetting.spoiler_enabled
|
|
|
|
|
cooked = ChatMessage.cook("[spoiler]the planet of the apes was earth all along[/spoiler]")
|
|
|
|
|
cooked =
|
|
|
|
|
described_class.cook("[spoiler]the planet of the apes was earth all along[/spoiler]")
|
|
|
|
|
|
|
|
|
|
expect(cooked).to eq(
|
|
|
|
|
"<div class=\"spoiler\">\n<p>the planet of the apes was earth all along</p>\n</div>",
|
|
|
|
@ -352,7 +353,7 @@ describe ChatMessage do
|
|
|
|
|
|
|
|
|
|
it "cooks unicode mentions" do
|
|
|
|
|
user = Fabricate(:unicode_user)
|
|
|
|
|
cooked = ChatMessage.cook("<h1>@#{user.username}</h1>")
|
|
|
|
|
cooked = described_class.cook("<h1>@#{user.username}</h1>")
|
|
|
|
|
|
|
|
|
|
expect(cooked).to eq("<p><h1>@#{user.username}</h1></p>")
|
|
|
|
|
end
|
|
|
|
@ -375,8 +376,7 @@ describe ChatMessage do
|
|
|
|
|
)
|
|
|
|
|
image2 =
|
|
|
|
|
Fabricate(:upload, original_filename: "meme.jpg", width: 10, height: 10, extension: "jpg")
|
|
|
|
|
UploadReference.create!(target: message, upload: image)
|
|
|
|
|
UploadReference.create!(target: message, upload: image2)
|
|
|
|
|
message.attach_uploads([image, image2])
|
|
|
|
|
expect(message.to_markdown).to eq(<<~MSG.chomp)
|
|
|
|
|
hey friend, what's up?!
|
|
|
|
|
|
|
|
|
@ -388,12 +388,12 @@ describe ChatMessage do
|
|
|
|
|
|
|
|
|
|
describe ".push_notification_excerpt" do
|
|
|
|
|
it "truncates to 400 characters" do
|
|
|
|
|
message = ChatMessage.new(message: "Hello, World!" * 40)
|
|
|
|
|
message = described_class.new(message: "Hello, World!" * 40)
|
|
|
|
|
expect(message.push_notification_excerpt.size).to eq(400)
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
it "encodes emojis" do
|
|
|
|
|
message = ChatMessage.new(message: ":grinning:")
|
|
|
|
|
message = described_class.new(message: ":grinning:")
|
|
|
|
|
expect(message.push_notification_excerpt).to eq("😀")
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
@ -407,7 +407,8 @@ describe ChatMessage do
|
|
|
|
|
|
|
|
|
|
it "blocks duplicate messages for the message, channel user, and message age requirements" do
|
|
|
|
|
Fabricate(:chat_message, message: "this is duplicate", chat_channel: channel, user: user1)
|
|
|
|
|
message = ChatMessage.new(message: "this is duplicate", chat_channel: channel, user: user2)
|
|
|
|
|
message =
|
|
|
|
|
described_class.new(message: "this is duplicate", chat_channel: channel, user: user2)
|
|
|
|
|
message.validate_message(has_uploads: false)
|
|
|
|
|
expect(message.errors.full_messages).to include(I18n.t("chat.errors.duplicate_message"))
|
|
|
|
|
end
|
|
|
|
@ -482,7 +483,7 @@ describe ChatMessage do
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
describe "bookmarks" do
|
|
|
|
|
before { register_test_bookmarkable(ChatMessageBookmarkable) }
|
|
|
|
|
before { register_test_bookmarkable(Chat::MessageBookmarkable) }
|
|
|
|
|
|
|
|
|
|
after { DiscoursePluginRegistry.reset_register!(:bookmarkables) }
|
|
|
|
|
|
|
|
|
@ -539,11 +540,11 @@ describe ChatMessage do
|
|
|
|
|
expect(chat_upload_count([upload_1, upload_2])).to eq(0)
|
|
|
|
|
expect(upload_references.count).to eq(2)
|
|
|
|
|
expect(upload_references.map(&:target_id).uniq).to eq([chat_message.id])
|
|
|
|
|
expect(upload_references.map(&:target_type).uniq).to eq(["ChatMessage"])
|
|
|
|
|
expect(upload_references.map(&:target_type).uniq).to eq([Chat::Message.sti_name])
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
it "does nothing if the message record is new" do
|
|
|
|
|
expect { ChatMessage.new.attach_uploads([upload_1, upload_2]) }.to not_change {
|
|
|
|
|
expect { described_class.new.attach_uploads([upload_1, upload_2]) }.to not_change {
|
|
|
|
|
chat_upload_count
|
|
|
|
|
}.and not_change { UploadReference.count }
|
|
|
|
|
end
|