discourse/plugins/chat/spec/services/chat/trash_messages_spec.rb

237 lines
8.8 KiB
Ruby

# frozen_string_literal: true
RSpec.describe Chat::TrashMessages do
fab!(:current_user) { Fabricate(:user) }
let!(:guardian) { Guardian.new(current_user) }
fab!(:chat_channel) { Fabricate(:chat_channel) }
fab!(:message1) { Fabricate(:chat_message, user: current_user, chat_channel: chat_channel) }
fab!(:message2) { Fabricate(:chat_message, user: current_user, chat_channel: chat_channel) }
describe ".call" do
subject(:result) { described_class.call(params) }
context "when params are not valid" do
let(:params) { { guardian: guardian } }
it { is_expected.to fail_a_contract }
end
context "when params are valid" do
let(:params) do
{ guardian: guardian, message_ids: [message1.id, message2.id], channel_id: chat_channel.id }
end
context "when the user does not have permission to delete" do
before { message1.update!(user: Fabricate(:admin)) }
it { is_expected.to fail_a_policy(:can_delete_all_chat_messages) }
end
context "when the channel does not match the message" do
let(:params) do
{
guardian: guardian,
message_ids: [message1.id, message2.id],
channel_id: Fabricate(:chat_channel).id,
}
end
it { is_expected.to fail_to_find_a_model(:messages) }
end
context "when the user has permission to delete" do
it "sets the service result as successful" do
expect(result).to be_a_success
end
it "trashes the messages" do
result
[message1, message2].each do |message|
expect(Chat::Message.find_by(id: message.id)).to be_nil
deleted_message = Chat::Message.unscoped.find_by(id: message.id)
expect(deleted_message.deleted_by_id).to eq(current_user.id)
expect(deleted_message.deleted_at).to be_within(1.minute).of(Time.zone.now)
end
end
it "destroys notifications for mentions" do
mention1 =
Fabricate(
:user_chat_mention,
chat_message: message1,
notifications: [Fabricate(:notification)],
)
mention2 =
Fabricate(
:user_chat_mention,
chat_message: message2,
notifications: [Fabricate(:notification)],
)
result
[mention1, mention2].each do |mention|
mention = Chat::Mention.find_by(id: mention.id)
expect(mention).to be_present
expect(mention.notifications).to be_empty
end
end
it "publishes associated Discourse and MessageBus events for multiple messages" do
freeze_time
messages = nil
events =
DiscourseEvent
.track_events { messages = MessageBus.track_publish { result } }
.select { |e| e[:event_name] == :chat_message_trashed }
[message1, message2].each do |message|
event = events.find { |e| e[:params].first.id == message.id }
expect(event).to be_present
expect(event[:params]).to eq([message, message.chat_channel, current_user])
end
message_data = messages.find { |m| m.channel == "/chat/#{chat_channel.id}" }.data
expect(message_data).to eq(
{
"type" => "bulk_delete",
"deleted_ids" => [message1.id, message2.id],
"deleted_at" => message1.reload.deleted_at.iso8601(3),
},
)
end
it "updates the tracking to the last non-deleted channel message for users whose last_read_message_id was the trashed message" do
other_message = Fabricate(:chat_message, chat_channel: chat_channel)
membership_1 =
Fabricate(
:user_chat_channel_membership,
chat_channel: chat_channel,
last_read_message: message1,
)
membership_2 =
Fabricate(
:user_chat_channel_membership,
chat_channel: chat_channel,
last_read_message: message2,
)
membership_3 =
Fabricate(
:user_chat_channel_membership,
chat_channel: chat_channel,
last_read_message: other_message,
)
result
expect(membership_1.reload.last_read_message_id).to eq(other_message.id)
expect(membership_2.reload.last_read_message_id).to eq(other_message.id)
expect(membership_3.reload.last_read_message_id).to eq(other_message.id)
end
it "updates the tracking to nil when there are no other messages left in the channnel" do
membership_1 =
Fabricate(
:user_chat_channel_membership,
chat_channel: chat_channel,
last_read_message: message1,
)
membership_2 =
Fabricate(
:user_chat_channel_membership,
chat_channel: chat_channel,
last_read_message: message2,
)
result
expect(membership_1.reload.last_read_message_id).to be_nil
expect(membership_2.reload.last_read_message_id).to be_nil
end
it "updates the channel last_message_id to the previous message in the channel" do
message3 = Fabricate(:chat_message, chat_channel: chat_channel, user: current_user)
params[:message_ids] = [message2.id, message3.id]
chat_channel.update!(last_message: message3)
result
expect(chat_channel.reload.last_message).to eq(message1)
end
context "when the message has a thread" do
fab!(:thread) { Fabricate(:chat_thread, channel: chat_channel) }
before do
message1.update!(thread: thread)
message2.update!(thread: thread, created_at: message1.created_at - 1.hour)
thread.update!(last_message: message1)
thread.original_message.update!(created_at: message1.created_at - 2.hours)
end
it "decrements the thread reply count" do
thread.set_replies_count_cache(5)
result
expect(thread.replies_count_cache).to eq(3)
end
it "updates the tracking to the last non-deleted thread message for users whose last_read_message_id was the trashed message" do
other_message = Fabricate(:chat_message, chat_channel: chat_channel, thread: thread)
membership_1 =
Fabricate(:user_chat_thread_membership, thread: thread, last_read_message: message1)
membership_2 =
Fabricate(:user_chat_thread_membership, thread: thread, last_read_message: message2)
membership_3 =
Fabricate(
:user_chat_thread_membership,
thread: thread,
last_read_message: other_message,
)
result
expect(membership_1.reload.last_read_message_id).to eq(other_message.id)
expect(membership_2.reload.last_read_message_id).to eq(other_message.id)
expect(membership_3.reload.last_read_message_id).to eq(other_message.id)
end
it "updates the tracking to nil when there are no other messages left in the thread" do
membership_1 =
Fabricate(:user_chat_thread_membership, thread: thread, last_read_message: message1)
membership_2 =
Fabricate(:user_chat_thread_membership, thread: thread, last_read_message: message2)
result
expect(membership_1.reload.last_read_message_id).to be_nil
expect(membership_2.reload.last_read_message_id).to be_nil
end
it "updates the thread last_message_id to the previous message in the thread" do
next_message =
Fabricate(
:chat_message,
thread: thread,
user: current_user,
chat_channel: chat_channel,
)
params[:message_ids] = [message2.id, next_message.id]
thread.update!(last_message: next_message)
result
expect(thread.reload.last_message).to eq(message1)
end
context "when there are no other messages left in the thread except the original message" do
it "updates the thread last_message_id to the original message" do
expect(thread.last_message).to eq(message1)
result
expect(thread.reload.last_message).to eq(thread.original_message)
end
end
end
context "when all messages are already deleted" do
before do
message1.trash!
message2.trash!
end
it { is_expected.to fail_to_find_a_model(:messages) }
end
end
end
end
end