mirror of
https://github.com/discourse/discourse.git
synced 2024-12-02 11:53:40 +08:00
9e08b45f9b
Prior to this fix the scroll was ignored when clicking the arrow bottom which would prevent the call to update last read. This fix manually calls update last read in this case and adds a test for it.
363 lines
11 KiB
Ruby
363 lines
11 KiB
Ruby
# frozen_string_literal: true
|
||
|
||
RSpec.describe "Chat channel", type: :system do
|
||
fab!(:current_user) { Fabricate(:user) }
|
||
fab!(:channel_1) { Fabricate(:chat_channel) }
|
||
fab!(:message_1) { Fabricate(:chat_message, chat_channel: channel_1) }
|
||
|
||
let(:chat_page) { PageObjects::Pages::Chat.new }
|
||
let(:channel_page) { PageObjects::Pages::ChatChannel.new }
|
||
let(:sidebar_page) { PageObjects::Pages::Sidebar.new }
|
||
let(:side_panel_page) { PageObjects::Pages::ChatSidePanel.new }
|
||
|
||
before do
|
||
chat_system_bootstrap
|
||
channel_1.add(current_user)
|
||
sign_in(current_user)
|
||
end
|
||
|
||
context "when has unread threads" do
|
||
fab!(:thread_1) { Fabricate(:chat_thread, channel: channel_1) }
|
||
|
||
before do
|
||
channel_1.update!(threading_enabled: true)
|
||
thread_1.add(current_user)
|
||
Fabricate(:chat_message, thread: thread_1, use_service: true)
|
||
end
|
||
|
||
context "when visiting channel" do
|
||
it "opens thread panel" do
|
||
chat_page.visit_channel(channel_1)
|
||
|
||
expect(side_panel_page).to have_open_thread_list
|
||
end
|
||
end
|
||
|
||
context "when visiting channel on mobile", mobile: true do
|
||
it "doesn’t open thread panel" do
|
||
chat_page.visit_channel(channel_1)
|
||
|
||
expect(side_panel_page).to have_no_open_thread_list
|
||
end
|
||
end
|
||
|
||
context "when visiting thread" do
|
||
it "doesn’t open thread panel" do
|
||
chat_page.visit_thread(thread_1)
|
||
|
||
expect(side_panel_page).to have_no_open_thread_list
|
||
end
|
||
end
|
||
|
||
context "when opening channel message" do
|
||
it "doesn’t open thread panel" do
|
||
chat_page.visit_channel(channel_1, message_id: message_1.id)
|
||
|
||
expect(side_panel_page).to have_no_open_thread_list
|
||
end
|
||
end
|
||
end
|
||
|
||
context "when first batch of messages doesnt fill page" do
|
||
before { 30.times { Fabricate(:chat_message, user: current_user, chat_channel: channel_1) } }
|
||
|
||
it "autofills for more messages" do
|
||
chat_page.prefers_full_page
|
||
visit("/")
|
||
# cheap trick to ensure the messages don't fill the initial page
|
||
page.execute_script(
|
||
"document.head.insertAdjacentHTML('beforeend', `<style>.chat-message-text{font-size:3px;}</style>`)",
|
||
)
|
||
sidebar_page.open_channel(channel_1)
|
||
|
||
expect(channel_page.messages).to have_message(id: message_1.id)
|
||
end
|
||
end
|
||
|
||
context "when sending a message" do
|
||
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)
|
||
chat_page.visit_channel(channel_1, message_id: message_1.id)
|
||
|
||
expect(channel_page.messages).to have_no_message(id: unloaded_message.id)
|
||
|
||
channel_page.send_message
|
||
|
||
expect(channel_page.messages).to have_message(id: unloaded_message.id)
|
||
end
|
||
end
|
||
|
||
context "with two sessions opened on same channel" do
|
||
it "syncs the messages" do
|
||
Jobs.run_immediately!
|
||
|
||
using_session(:tab_1) do
|
||
sign_in(current_user)
|
||
chat_page.visit_channel(channel_1)
|
||
end
|
||
|
||
using_session(:tab_2) do
|
||
sign_in(current_user)
|
||
chat_page.visit_channel(channel_1)
|
||
end
|
||
|
||
using_session(:tab_1) { channel_page.send_message("test_message") }
|
||
|
||
using_session(:tab_2) do
|
||
expect(channel_page.messages).to have_message(text: "test_message")
|
||
end
|
||
end
|
||
end
|
||
|
||
it "allows to edit this message once persisted" do
|
||
chat_page.visit_channel(channel_1)
|
||
channel_page.send_message("aaaaaa")
|
||
|
||
expect(channel_page.messages).to have_message(persisted: true, text: "aaaaaa")
|
||
|
||
last_message = find(".chat-message-container:last-child")
|
||
last_message.hover
|
||
|
||
expect(channel_page).to have_css(
|
||
".chat-message-actions-container[data-id='#{last_message["data-id"]}']",
|
||
)
|
||
end
|
||
end
|
||
|
||
context "when clicking the arrow button" do
|
||
before { 50.times { Fabricate(:chat_message, chat_channel: channel_1) } }
|
||
|
||
it "jumps to the bottom of the channel" do
|
||
unloaded_message = Fabricate(:chat_message, chat_channel: channel_1)
|
||
visit("/chat/c/-/#{channel_1.id}/#{message_1.id}")
|
||
|
||
expect(channel_page).to have_no_loading_skeleton
|
||
expect(page).to have_no_css("[data-id='#{unloaded_message.id}']")
|
||
|
||
find(".chat-scroll-to-bottom__button.visible").click
|
||
|
||
expect(channel_page).to have_no_loading_skeleton
|
||
expect(page).to have_css("[data-id='#{unloaded_message.id}']")
|
||
expect(page).to have_css(".-last-read[data-id='#{unloaded_message.id}']")
|
||
end
|
||
end
|
||
|
||
context "when returning to a channel where last read is not last message" do
|
||
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_page.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)
|
||
50.times { Fabricate(:chat_message, chat_channel: channel_1) }
|
||
end
|
||
|
||
xit "doesn’t scroll the pane" do
|
||
visit("/chat/c/-/#{channel_1.id}/#{message_1.id}")
|
||
|
||
new_message = Fabricate(:chat_message, chat_channel: channel_1)
|
||
|
||
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 { channel_1.add(other_user) }
|
||
|
||
it "highlights the mentions" do
|
||
chat_page.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(:user_chat_mention, user: current_user, chat_message: message)
|
||
Fabricate(:user_chat_mention, user: other_user, chat_message: message)
|
||
|
||
chat_page.visit_channel(channel_1)
|
||
|
||
expect(page).to have_selector(
|
||
".mention .user-status-message img[alt='#{current_user.user_status.emoji}']",
|
||
)
|
||
expect(page).to have_selector(
|
||
".mention .user-status-message img[alt='#{other_user.user_status.emoji}']",
|
||
)
|
||
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)
|
||
end
|
||
|
||
it "doesn’t show the reply-to line" do
|
||
chat_page.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)
|
||
end
|
||
|
||
it "shows the reply-to line" do
|
||
chat_page.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)
|
||
end
|
||
|
||
it "renders text in the reply-to" do
|
||
chat_page.visit_channel(channel_1)
|
||
|
||
expect(find(".chat-reply .chat-reply__excerpt")["innerHTML"].strip).to eq(
|
||
"<mark>not marked</mark>",
|
||
)
|
||
end
|
||
|
||
it "renders safe HTML like mentions (which are just links) in the reply-to" do
|
||
update_message!(
|
||
message_2,
|
||
user: other_user,
|
||
text: "@#{other_user.username} <mark>not marked</mark>",
|
||
)
|
||
chat_page.visit_channel(channel_1)
|
||
|
||
expect(find(".chat-reply .chat-reply__excerpt")["innerHTML"].strip).to eq(
|
||
"@#{other_user.username} <mark>not marked</mark>",
|
||
)
|
||
end
|
||
end
|
||
|
||
context "when messages are separated by a day" do
|
||
before { Fabricate(:chat_message, chat_channel: channel_1, created_at: 2.days.ago) }
|
||
|
||
it "shows a date separator" do
|
||
chat_page.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
|
||
|
||
it "adds the correct lang" do
|
||
chat_page.visit_channel(channel_1)
|
||
|
||
expect(page).to have_selector("code.lang-ruby")
|
||
end
|
||
end
|
||
|
||
context "when scrolling" do
|
||
before { 50.times { Fabricate(:chat_message, chat_channel: channel_1) } }
|
||
|
||
it "resets the active message" do
|
||
chat_page.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
|
||
|
||
context "when opening message secondary options" do
|
||
it "doesn’t hide dropdown on mouseleave" do
|
||
chat_page.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-message-actions-container .secondary-actions").click
|
||
expect(page).to have_css(
|
||
".chat-message-actions-container .secondary-actions .select-kit-body",
|
||
)
|
||
|
||
find("#site-logo").hover
|
||
expect(page).to have_css(
|
||
".chat-message-actions-container .secondary-actions .select-kit-body",
|
||
)
|
||
|
||
find("#site-logo").click
|
||
expect(page).to have_no_css(
|
||
".chat-message-actions-container .secondary-actions .select-kit-body",
|
||
)
|
||
end
|
||
end
|
||
end
|