discourse/plugins/chat/spec/system/chat_channel_spec.rb
Andrei Prigorshnev d4a5b79592
FEATURE: Add user status to inline mentions in chat (#20564)
This PR adds status to mentions in chat and makes those mentions receive live updates.

There are known unfinished part in this implementation: when posting a message, status on mentions on that message appears immediately, but only if a user used autocomplete when typing the message. If user copy and paste a message with mentions into chat composer, those mentions won't have user status on them.

PRs with fixes for both problems are following soon.

Preparations for this PR that were made previously include:
- DEV: correct a relationship – a chat message may have several mentions 0dcfd7ddec
- DEV: extract the logic for extracting and expanding mentions from ChatNotifier 75b81b6854
- DEV: Always create chat mention records fa543cda06
- DEV: better split create_notification! and send_notifications logic e292c45924
- DEV: more tests for mentions when updating chat messages e7292e1682
- DEV: extract updating status on mentions into a lib function e49d338c21
- DEV: Create and update chat message mentions earlier 35a414bb38
- DEV: Create a chat_mention record when self mentioning 2703f2311a
- DEV: When deleting a chat message, do not delete mention records f4fde4e49b
2023-05-24 16:55:20 +04:00

303 lines
8.8 KiB
Ruby
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# frozen_string_literal: true
RSpec.describe "Chat channel", type: :system, js: true do
fab!(:current_user) { Fabricate(:user) }
fab!(:channel_1) { Fabricate(:chat_channel) }
fab!(:message_1) { Fabricate(:chat_message, chat_channel: channel_1) }
let(:chat) { PageObjects::Pages::Chat.new }
let(:channel) { PageObjects::Pages::ChatChannel.new }
before { chat_system_bootstrap }
context "when sending a message" do
before do
channel_1.add(current_user)
sign_in(current_user)
end
context "with lots of messages" do
before { 50.times { Fabricate(:chat_message, chat_channel: channel_1) } }
it "loads most recent messages" do
unloaded_message = Fabricate(:chat_message, chat_channel: channel_1)
visit("/chat/c/-/#{channel_1.id}/#{message_1.id}")
expect(channel).to have_no_loading_skeleton
expect(page).to have_no_css("[data-id='#{unloaded_message.id}']")
channel.send_message("test_message")
expect(channel).to have_no_loading_skeleton
expect(page).to have_css("[data-id='#{unloaded_message.id}']")
end
end
context "with two sessions opened on same channel" do
it "syncs the messages" do
using_session(:tab_1) do
sign_in(current_user)
chat.visit_channel(channel_1)
end
using_session(:tab_2) do
sign_in(current_user)
chat.visit_channel(channel_1)
end
using_session(:tab_1) do |session|
channel.send_message("test_message")
session.quit
end
using_session(:tab_2) do |session|
expect(channel).to have_message(text: "test_message")
session.quit
end
end
end
it "allows to edit this message once persisted" do
chat.visit_channel(channel_1)
channel.send_message("aaaaaaaaaaaaaaaaaaaa")
expect(page).to have_no_css(".chat-message-staged")
last_message = find(".chat-message-container:last-child")
last_message.hover
expect(page).to have_css(
".chat-message-actions-container[data-id='#{last_message["data-id"]}']",
)
end
end
context "when clicking the arrow button" do
before do
channel_1.add(current_user)
50.times { Fabricate(:chat_message, chat_channel: channel_1) }
sign_in(current_user)
end
it "jumps to the bottom of the channel" do
unloaded_message = Fabricate(:chat_message, chat_channel: channel_1)
visit("/chat/message/#{message_1.id}")
expect(channel).to have_no_loading_skeleton
expect(page).to have_no_css("[data-id='#{unloaded_message.id}']")
find(".chat-scroll-to-bottom").click
expect(channel).to have_no_loading_skeleton
expect(page).to have_css("[data-id='#{unloaded_message.id}']")
end
end
context "when returning to a channel where last read is not last message" do
before do
channel_1.add(current_user)
sign_in(current_user)
end
it "jumps to the bottom of the channel" do
channel_1.membership_for(current_user).update!(last_read_message: message_1)
messages = 50.times.map { Fabricate(:chat_message, chat_channel: channel_1) }
chat.visit_channel(channel_1)
expect(page).to have_css("[data-id='#{messages.first.id}']")
expect(page).to have_no_css("[data-id='#{messages.last.id}']")
end
end
context "when a new message is created" do
fab!(:other_user) { Fabricate(:user) }
before do
channel_1.add(other_user)
channel_1.add(current_user)
50.times { Fabricate(:chat_message, chat_channel: channel_1) }
sign_in(current_user)
end
it "doesnt scroll the pane" do
visit("/chat/message/#{message_1.id}")
new_message =
Chat::MessageCreator.create(
chat_channel: channel_1,
user: other_user,
content: "this is fine",
).chat_message
expect(page).to have_no_content(new_message.message)
end
end
context "when a message contains mentions" do
fab!(:other_user) { Fabricate(:user) }
fab!(:message) do
Fabricate(
:chat_message,
chat_channel: channel_1,
message: "hello @here @all @#{current_user.username} @#{other_user.username} @unexisting",
user: other_user,
)
end
before do
channel_1.add(other_user)
channel_1.add(current_user)
sign_in(current_user)
end
it "highlights the mentions" do
chat.visit_channel(channel_1)
expect(page).to have_selector(".mention.highlighted.valid-mention", text: "@here")
expect(page).to have_selector(".mention.highlighted.valid-mention", text: "@all")
expect(page).to have_selector(
".mention.highlighted.valid-mention",
text: "@#{current_user.username}",
)
expect(page).to have_selector(".mention", text: "@#{other_user.username}")
expect(page).to have_selector(".mention", text: "@unexisting")
end
it "renders user status on mentions" do
SiteSetting.enable_user_status = true
current_user.set_status!("off to dentist", "tooth")
other_user.set_status!("surfing", "surfing_man")
Fabricate(:chat_mention, user: current_user, chat_message: message)
Fabricate(:chat_mention, user: other_user, chat_message: message)
chat.visit_channel(channel_1)
expect(page).to have_selector(
".mention .user-status[title='#{current_user.user_status.description}']",
)
expect(page).to have_selector(
".mention .user-status[title='#{other_user.user_status.description}']",
)
end
end
context "when reply is right under" do
fab!(:other_user) { Fabricate(:user) }
before do
Fabricate(:chat_message, in_reply_to: message_1, user: other_user, chat_channel: channel_1)
channel_1.add(other_user)
channel_1.add(current_user)
sign_in(current_user)
end
it "doesnt show the reply-to line" do
chat.visit_channel(channel_1)
expect(page).to have_no_selector(".chat-reply__excerpt")
end
end
context "when reply is not directly connected" do
fab!(:other_user) { Fabricate(:user) }
before do
Fabricate(:chat_message, user: other_user, chat_channel: channel_1)
Fabricate(:chat_message, in_reply_to: message_1, user: other_user, chat_channel: channel_1)
channel_1.add(other_user)
channel_1.add(current_user)
sign_in(current_user)
end
it "shows the reply-to line" do
chat.visit_channel(channel_1)
expect(page).to have_selector(".chat-reply__excerpt")
end
end
context "when replying to message that has HTML tags" do
fab!(:other_user) { Fabricate(:user) }
fab!(:message_2) do
Fabricate(
:chat_message,
user: other_user,
chat_channel: channel_1,
message: "<mark>not marked</mark>",
)
end
before do
Fabricate(:chat_message, user: other_user, chat_channel: channel_1)
Fabricate(:chat_message, in_reply_to: message_2, user: current_user, chat_channel: channel_1)
channel_1.add(other_user)
channel_1.add(current_user)
sign_in(current_user)
end
it "renders text in the reply-to" do
chat.visit_channel(channel_1)
expect(find(".chat-reply .chat-reply__excerpt")["innerHTML"].strip).to eq("not marked")
end
end
context "when messages are separated by a day" do
before do
Fabricate(:chat_message, chat_channel: channel_1, created_at: 2.days.ago)
channel_1.add(current_user)
sign_in(current_user)
end
it "shows a date separator" do
chat.visit_channel(channel_1)
expect(page).to have_selector(".chat-message-separator__text", text: "Today")
end
end
context "when a message contains code fence" do
fab!(:message_2) { Fabricate(:chat_message, chat_channel: channel_1, message: <<~MESSAGE) }
Here's a message with code highlighting
\`\`\`ruby
Widget.triangulate(arg: "test")
\`\`\`
MESSAGE
before do
channel_1.add(current_user)
sign_in(current_user)
end
it "adds the correct lang" do
chat.visit_channel(channel_1)
expect(page).to have_selector("code.lang-ruby")
end
end
context "when scrolling" do
before do
channel_1.add(current_user)
50.times { Fabricate(:chat_message, chat_channel: channel_1) }
sign_in(current_user)
end
it "resets the active message" do
chat.visit_channel(channel_1)
last_message = find(".chat-message-container:last-child")
last_message.hover
expect(page).to have_css(
".chat-message-actions-container[data-id='#{last_message["data-id"]}']",
)
find(".chat-messages-scroll").scroll_to(0, -1000)
expect(page).to have_no_css(
".chat-message-actions-container[data-id='#{last_message["data-id"]}']",
)
end
end
end