FIX: call composer reset with correct params (#21777)

We were calling reset without the proper params which was causing errors in the console. This commit does the following changes:

- ensures `composer.cancel()` is the only way to cancel editing/reply
- adds a `draftSaved` property to chat message to allow for better tests
- writes a spec to ensure the flow is correct
- adds more page objects for better tests
- homogenize the default state of objects on chat message

Co-authored-by: Martin Brennan <martin@discourse.org>
This commit is contained in:
Joffrey JAFFEUX 2023-05-30 18:37:30 +02:00 committed by GitHub
parent 093552bc84
commit 111ac4c7f2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
21 changed files with 148 additions and 111 deletions

View File

@ -73,7 +73,6 @@ export default Mixin.create(UppyS3Multipart, ExtendableUploader, {
}); });
this.set("allowMultipleFiles", this.fileInputEl.multiple); this.set("allowMultipleFiles", this.fileInputEl.multiple);
this.set("inProgressUploads", []); this.set("inProgressUploads", []);
this._triggerInProgressUploadsEvent();
this._bindFileInputChange(); this._bindFileInputChange();
@ -298,8 +297,10 @@ export default Mixin.create(UppyS3Multipart, ExtendableUploader, {
this._uppyInstance.on("cancel-all", () => { this._uppyInstance.on("cancel-all", () => {
this.appEvents.trigger(`upload-mixin:${this.id}:uploads-cancelled`); this.appEvents.trigger(`upload-mixin:${this.id}:uploads-cancelled`);
if (!this.isDestroyed && !this.isDestroying) { if (!this.isDestroyed && !this.isDestroying) {
this.set("inProgressUploads", []); if (this.inProgressUploads.length) {
this._triggerInProgressUploadsEvent(); this.set("inProgressUploads", []);
this._triggerInProgressUploadsEvent();
}
} }
}); });

View File

@ -90,7 +90,7 @@ module Chat
raise Discourse::InvalidAccess unless @user_chat_channel_membership raise Discourse::InvalidAccess unless @user_chat_channel_membership
reply_to_msg_id = params[:in_reply_to_id] reply_to_msg_id = params[:in_reply_to_id]
if reply_to_msg_id if reply_to_msg_id.present?
rm = Chat::Message.find(reply_to_msg_id) rm = Chat::Message.find(reply_to_msg_id)
raise Discourse::NotFound if rm.chat_channel_id != @chat_channel.id raise Discourse::NotFound if rm.chat_channel_id != @chat_channel.id
end end

View File

@ -8,9 +8,9 @@
{{did-insert this.setUploadDropZone}} {{did-insert this.setUploadDropZone}}
{{did-insert this.setupListeners}} {{did-insert this.setupListeners}}
{{will-destroy this.teardownListeners}} {{will-destroy this.teardownListeners}}
{{did-insert this.updateChannel}}
{{did-update this.loadMessages @targetMessageId}} {{did-update this.loadMessages @targetMessageId}}
{{did-update this.updateChannel @channel.id}} {{did-insert this.didUpdateChannel}}
{{did-update this.didUpdateChannel @channel.id}}
{{did-insert this.addAutoFocusEventListener}} {{did-insert this.addAutoFocusEventListener}}
{{will-destroy this.removeAutoFocusEventListener}} {{will-destroy this.removeAutoFocusEventListener}}
data-id={{@channel.id}} data-id={{@channel.id}}

View File

@ -105,19 +105,32 @@ export default class ChatLivePane extends Component {
} }
@action @action
updateChannel() { didUpdateChannel() {
this.#cancelHandlers(); this.#cancelHandlers();
this.loadedOnce = false; this.loadedOnce = false;
if (!this.args.channel) {
return;
}
// Technically we could keep messages to avoid re-fetching them, but // Technically we could keep messages to avoid re-fetching them, but
// it's not worth the complexity for now // it's not worth the complexity for now
this.args.channel?.clearMessages(); this.args.channel.clearMessages();
if (this._loadedChannelId !== this.args.channel?.id) { if (this._loadedChannelId !== this.args.channel.id) {
this.unsubscribeToUpdates(this._loadedChannelId); this.unsubscribeToUpdates(this._loadedChannelId);
this.chatChannelPane.selectingMessages = false; this.chatChannelPane.selectingMessages = false;
this._loadedChannelId = this.args.channel?.id; this._loadedChannelId = this.args.channel.id;
}
const existingDraft = this.chatDraftsManager.get({
channelId: this.args.channel.id,
});
if (existingDraft) {
this.chatChannelComposer.message = existingDraft;
} else {
this.resetComposer();
} }
this.loadMessages(); this.loadMessages();

View File

@ -22,12 +22,11 @@
(if this.pane.sending "is-sending") (if this.pane.sending "is-sending")
(if this.sendEnabled "is-send-enabled" "is-send-disabled") (if this.sendEnabled "is-send-enabled" "is-send-disabled")
(if this.disabled "is-disabled" "is-enabled") (if this.disabled "is-disabled" "is-enabled")
(if this.currentMessage.draftSaved "is-draft-saved" "is-draft-unsaved")
}} }}
{{did-update this.didUpdateMessage this.currentMessage}} {{did-update this.didUpdateMessage this.currentMessage}}
{{did-update this.didUpdateInReplyTo this.currentMessage.inReplyTo}} {{did-update this.didUpdateInReplyTo this.currentMessage.inReplyTo}}
{{did-insert this.setup}} {{did-insert this.setup}}
{{did-insert this.didUpdateChannel}}
{{did-update this.didUpdateChannel @channel.id}}
{{will-destroy this.teardown}} {{will-destroy this.teardown}}
{{will-destroy this.cancelPersistDraft}} {{will-destroy this.cancelPersistDraft}}
> >

View File

@ -18,7 +18,6 @@ import { translations } from "pretty-text/emoji/data";
import { setupHashtagAutocomplete } from "discourse/lib/hashtag-autocomplete"; import { setupHashtagAutocomplete } from "discourse/lib/hashtag-autocomplete";
import { isEmpty, isPresent } from "@ember/utils"; import { isEmpty, isPresent } from "@ember/utils";
import { Promise } from "rsvp"; import { Promise } from "rsvp";
import ChatMessage from "discourse/plugins/chat/discourse/models/chat-message";
import User from "discourse/models/user"; import User from "discourse/models/user";
import ChatMessageInteractor from "discourse/plugins/chat/discourse/lib/chat-message-interactor"; import ChatMessageInteractor from "discourse/plugins/chat/discourse/lib/chat-message-interactor";
@ -142,22 +141,6 @@ export default class ChatComposer extends Component {
); );
} }
@action
didUpdateChannel() {
this.cancelPersistDraft();
if (!this.args.channel) {
this.composer.message = null;
return;
}
this.composer.message =
this.chatDraftsManager.get({ channelId: this.args.channel.id }) ||
ChatMessage.createDraftMessage(this.args.channel, {
user: this.currentUser,
});
}
@action @action
setup() { setup() {
this.appEvents.on("chat:modify-selection", this, "modifySelection"); this.appEvents.on("chat:modify-selection", this, "modifySelection");
@ -211,6 +194,7 @@ export default class ChatComposer extends Component {
@action @action
onInput(event) { onInput(event) {
this.currentMessage.draftSaved = false;
this.currentMessage.message = event.target.value; this.currentMessage.message = event.target.value;
this.textareaInteractor.refreshHeight(); this.textareaInteractor.refreshHeight();
this.reportReplyingPresence(); this.reportReplyingPresence();
@ -224,6 +208,8 @@ export default class ChatComposer extends Component {
return; return;
} }
this.currentMessage.draftSaved = false;
this.inProgressUploadsCount = inProgressUploadsCount || 0; this.inProgressUploadsCount = inProgressUploadsCount || 0;
if ( if (
@ -376,7 +362,7 @@ export default class ChatComposer extends Component {
if (this.currentMessage?.inReplyTo) { if (this.currentMessage?.inReplyTo) {
this.reset(); this.reset();
} else if (this.currentMessage?.editing) { } else if (this.currentMessage?.editing) {
this.composer.onCancelEditing(); this.composer.cancel();
} else { } else {
event.target.blur(); event.target.blur();
} }
@ -385,7 +371,7 @@ export default class ChatComposer extends Component {
@action @action
reset() { reset() {
this.composer.reset(this.args.channel); this.composer.reset(this.args.channel, this.args.thread);
} }
@action @action

View File

@ -6,10 +6,8 @@
}} }}
data-id={{this.thread.id}} data-id={{this.thread.id}}
{{did-insert this.setUploadDropZone}} {{did-insert this.setUploadDropZone}}
{{did-insert this.subscribeToUpdates}} {{did-insert this.didUpdateThread}}
{{did-update this.subscribeToUpdates this.thread.id}} {{did-update this.didUpdateThread this.thread.id}}
{{did-insert this.loadMessages}}
{{did-update this.loadMessages this.thread}}
{{will-destroy this.unsubscribeFromUpdates}} {{will-destroy this.unsubscribeFromUpdates}}
> >
{{#if @includeHeader}} {{#if @includeHeader}}

View File

@ -39,6 +39,13 @@ export default class ChatThreadPanel extends Component {
return this.thread?.channel; return this.thread?.channel;
} }
@action
didUpdateThread() {
this.subscribeToUpdates();
this.loadMessages();
this.resetComposer();
}
@action @action
setUploadDropZone(element) { setUploadDropZone(element) {
this.uploadDropZone = element; this.uploadDropZone = element;
@ -121,13 +128,6 @@ export default class ChatThreadPanel extends Component {
@action @action
loadMessages() { loadMessages() {
const message = ChatMessage.createDraftMessage(this.channel, {
user: this.currentUser,
});
message.thread = this.thread;
message.inReplyTo = this.thread.originalMessage;
this.chatChannelThreadComposer.message = message;
this.thread.messagesManager.clearMessages(); this.thread.messagesManager.clearMessages();
this.fetchMessages(); this.fetchMessages();
} }
@ -253,11 +253,13 @@ export default class ChatThreadPanel extends Component {
return this.chatApi return this.chatApi
.sendMessage(this.channel.id, { .sendMessage(this.channel.id, {
message: message.message, message: message.message,
in_reply_to_id: message.inReplyTo?.id, in_reply_to_id: message.thread.staged
? message.thread.originalMessage.id
: null,
staged_id: message.id, staged_id: message.id,
upload_ids: message.uploads.map((upload) => upload.id), upload_ids: message.uploads.map((upload) => upload.id),
thread_id: this.thread.staged ? null : message.thread.id, thread_id: message.thread.staged ? null : message.thread.id,
staged_thread_id: this.thread.staged ? message.thread.id : null, staged_thread_id: message.thread.staged ? message.thread.id : null,
}) })
.catch((error) => { .catch((error) => {
this.#onSendError(message.id, error); this.#onSendError(message.id, error);

View File

@ -37,7 +37,11 @@ export default class ChatComposerChannel extends ChatComposer {
@action @action
_debouncedPersistDraft(channelId, jsonDraft) { _debouncedPersistDraft(channelId, jsonDraft) {
this.chatApi.saveDraft(channelId, jsonDraft); this.chatApi.saveDraft(channelId, jsonDraft).then(() => {
if (this.currentMessage) {
this.currentMessage.draftSaved = true;
}
});
} }
get lastMessage() { get lastMessage() {

View File

@ -24,8 +24,9 @@ export default class ChatMessage {
@tracked error; @tracked error;
@tracked selected; @tracked selected;
@tracked channel; @tracked channel;
@tracked staged = false; @tracked staged;
@tracked draft = false; @tracked draftSaved;
@tracked draft;
@tracked channelId; @tracked channelId;
@tracked createdAt; @tracked createdAt;
@tracked deletedAt; @tracked deletedAt;
@ -38,34 +39,35 @@ export default class ChatMessage {
@tracked expanded; @tracked expanded;
@tracked bookmark; @tracked bookmark;
@tracked userFlagStatus; @tracked userFlagStatus;
@tracked hidden = false; @tracked hidden;
@tracked version = 0; @tracked version = 0;
@tracked edited = false; @tracked edited;
@tracked editing = false; @tracked editing;
@tracked chatWebhookEvent = new TrackedObject(); @tracked chatWebhookEvent = new TrackedObject();
@tracked mentionWarning; @tracked mentionWarning;
@tracked availableFlags; @tracked availableFlags;
@tracked newest = false; @tracked newest;
@tracked highlighted = false; @tracked highlighted;
@tracked firstOfResults = false; @tracked firstOfResults;
@tracked message; @tracked message;
@tracked thread; @tracked thread;
@tracked threadReplyCount; @tracked threadReplyCount;
@tracked manager = null; @tracked manager;
@tracked threadTitle = null; @tracked threadTitle;
@tracked _cooked; @tracked _cooked;
constructor(channel, args = {}) { constructor(channel, args = {}) {
// when modifying constructor, be sure to update duplicate function accordingly // when modifying constructor, be sure to update duplicate function accordingly
this.id = args.id; this.id = args.id;
this.newest = args.newest; this.newest = args.newest || false;
this.firstOfResults = args.firstOfResults; this.draftSaved = args.draftSaved || args.draft_saved || false;
this.staged = args.staged; this.firstOfResults = args.firstOfResults || args.first_of_results || false;
this.edited = args.edited; this.staged = args.staged || false;
this.editing = args.editing; this.edited = args.edited || false;
this.editing = args.editing || false;
this.availableFlags = args.availableFlags || args.available_flags; this.availableFlags = args.availableFlags || args.available_flags;
this.hidden = args.hidden; this.hidden = args.hidden || false;
this.threadReplyCount = args.threadReplyCount || args.thread_reply_count; this.threadReplyCount = args.threadReplyCount || args.thread_reply_count;
this.threadTitle = args.threadTitle || args.thread_title; this.threadTitle = args.threadTitle || args.thread_title;
this.chatWebhookEvent = args.chatWebhookEvent || args.chat_webhook_event; this.chatWebhookEvent = args.chatWebhookEvent || args.chat_webhook_event;

View File

@ -7,6 +7,11 @@ export default class ChatChannelComposer extends ChatComposer {
@service chat; @service chat;
@service router; @service router;
@action
cancelEditing() {
this.reset(this.message.channel);
}
@action @action
reset(channel) { reset(channel) {
this.message = ChatMessage.createDraftMessage(channel, { this.message = ChatMessage.createDraftMessage(channel, {
@ -31,7 +36,7 @@ export default class ChatChannelComposer extends ChatComposer {
message.thread = thread; message.thread = thread;
} }
this.chat.activeMessage = null; this.reset(channel);
this.router.transitionTo("chat.channel.thread", ...thread.routeModels); this.router.transitionTo("chat.channel.thread", ...thread.routeModels);
} else { } else {
this.message.inReplyTo = message; this.message.inReplyTo = message;

View File

@ -11,12 +11,17 @@ export default class ChatComposer extends Service {
@action @action
cancel() { cancel() {
if (this.message.editing) { if (this.message.editing) {
this.reset(); this.cancelEditing();
} else if (this.message.inReplyTo) { } else if (this.message.inReplyTo) {
this.message.inReplyTo = null; this.cancelReply();
} }
} }
@action
cancelReply() {
this.message.inReplyTo = null;
}
@action @action
clear() { clear() {
this.message.message = ""; this.message.message = "";
@ -28,9 +33,4 @@ export default class ChatComposer extends Service {
message.editing = true; message.editing = true;
this.message = message; this.message = message;
} }
@action
onCancelEditing() {
this.reset();
}
} }

View File

@ -72,6 +72,17 @@ RSpec.describe "Chat composer draft", type: :system, js: true do
expect(channel_page.composer).to be_editing_message(message_1) expect(channel_page.composer).to be_editing_message(message_1)
end end
context "when canceling editing" do
it "resets the draft" do
chat_page.visit_channel(channel_1)
channel_page.composer.message_details.cancel_edit
expect(channel_page.composer).to be_blank
expect(channel_page.composer).to have_unsaved_draft
expect(channel_page.composer).to have_saved_draft
end
end
end end
context "with uploads" do context "with uploads" do

View File

@ -102,13 +102,18 @@ describe "Thread indicator for chat messages", type: :system, js: true do
it "increments the indicator when a new reply is sent in the thread" do it "increments the indicator when a new reply is sent in the thread" do
chat_page.visit_channel(channel) chat_page.visit_channel(channel)
expect(channel_page.message_thread_indicator(thread_1.original_message)).to have_css( expect(channel_page.message_thread_indicator(thread_1.original_message)).to have_css(
".chat-message-thread-indicator__replies-count", ".chat-message-thread-indicator__replies-count",
text: I18n.t("js.chat.thread.replies", count: 3), text: I18n.t("js.chat.thread.replies", count: 3),
) )
channel_page.message_thread_indicator(thread_1.original_message).click channel_page.message_thread_indicator(thread_1.original_message).click
expect(side_panel).to have_open_thread(thread_1) expect(side_panel).to have_open_thread(thread_1)
open_thread.send_message("new thread message")
open_thread.send_message
expect(channel_page.message_thread_indicator(thread_1.original_message)).to have_css( expect(channel_page.message_thread_indicator(thread_1.original_message)).to have_css(
".chat-message-thread-indicator__replies-count", ".chat-message-thread-indicator__replies-count",
text: I18n.t("js.chat.thread.replies", count: 4), text: I18n.t("js.chat.thread.replies", count: 4),

View File

@ -128,8 +128,9 @@ module PageObjects
def send_message(text = nil) def send_message(text = nil)
text ||= Faker::Lorem.characters(number: SiteSetting.chat_minimum_message_length) text ||= Faker::Lorem.characters(number: SiteSetting.chat_minimum_message_length)
text = text.chomp if text.present? # having \n on the end of the string counts as an Enter keypress text = text.chomp if text.present? # having \n on the end of the string counts as an Enter keypress
fill_composer(text) composer.fill_in(with: text)
click_send_message click_send_message
messages.has_message?(text: text, persisted: true)
click_composer click_composer
has_no_loading_skeleton? has_no_loading_skeleton?
text text

View File

@ -60,8 +60,9 @@ module PageObjects
def send_message(text = nil) def send_message(text = nil)
text ||= Faker::Lorem.characters(number: SiteSetting.chat_minimum_message_length) text ||= Faker::Lorem.characters(number: SiteSetting.chat_minimum_message_length)
text = text.chomp if text.present? # having \n on the end of the string counts as an Enter keypress text = text.chomp if text.present? # having \n on the end of the string counts as an Enter keypress
fill_composer(text) composer.fill_in(with: text)
click_send_message click_send_message
messages.has_message?(text: text, persisted: true)
click_composer click_composer
text text
end end

View File

@ -14,12 +14,28 @@ module PageObjects
@context = context @context = context
end end
def blank?
input.value.blank?
end
def has_saved_draft?
component.has_css?(".chat-composer.is-draft-saved")
end
def has_unsaved_draft?
component.has_css?(".chat-composer.is-draft-unsaved")
end
def message_details def message_details
@message_details ||= PageObjects::Components::Chat::ComposerMessageDetails.new(context) @message_details ||= PageObjects::Components::Chat::ComposerMessageDetails.new(context)
end end
def input def input
find(context).find(SELECTOR).find(".chat-composer__input") component.find(".chat-composer__input")
end
def component
find(context).find(SELECTOR)
end end
def fill_in(**args) def fill_in(**args)

View File

@ -36,6 +36,10 @@ module PageObjects
def replying_to?(message) def replying_to?(message)
has_message?(id: message.id, action: :reply) has_message?(id: message.id, action: :reply)
end end
def cancel_edit
component.find(".cancel-message-action").click
end
end end
end end
end end

View File

@ -26,6 +26,7 @@ RSpec.describe "Reply to message - channel - drawer", type: :system, js: true do
chat_page.open_from_header chat_page.open_from_header
drawer_page.open_channel(channel_1) drawer_page.open_channel(channel_1)
channel_page.reply_to(original_message) channel_page.reply_to(original_message)
expect(drawer_page).to have_open_thread expect(drawer_page).to have_open_thread
thread_page.fill_composer("reply to message") thread_page.fill_composer("reply to message")

View File

@ -54,15 +54,7 @@ RSpec.describe "Reply to message - channel - mobile", type: :system, js: true, m
context "when the message has an existing thread" do context "when the message has an existing thread" do
fab!(:message_1) do fab!(:message_1) do
creator = Fabricate(:chat_message, chat_channel: channel_1, in_reply_to: original_message)
Chat::MessageCreator.new(
chat_channel: channel_1,
in_reply_to_id: original_message.id,
user: Fabricate(:user),
content: Faker::Lorem.paragraph,
)
creator.create
creator.chat_message
end end
it "replies to the existing thread" do it "replies to the existing thread" do
@ -71,11 +63,7 @@ RSpec.describe "Reply to message - channel - mobile", type: :system, js: true, m
expect(channel_page).to have_thread_indicator(original_message, text: "1") expect(channel_page).to have_thread_indicator(original_message, text: "1")
channel_page.reply_to(original_message) channel_page.reply_to(original_message)
thread_page.send_message("reply to message")
expect(side_panel_page).to have_open_thread
thread_page.fill_composer("reply to message")
thread_page.click_send_message
expect(thread_page).to have_message(text: message_1.message) expect(thread_page).to have_message(text: message_1.message)
expect(thread_page).to have_message(text: "reply to message") expect(thread_page).to have_message(text: "reply to message")
@ -83,7 +71,7 @@ RSpec.describe "Reply to message - channel - mobile", type: :system, js: true, m
thread_page.close thread_page.close
expect(channel_page).to have_thread_indicator(original_message, text: "2") expect(channel_page).to have_thread_indicator(original_message, text: "2")
expect(channel_page).to have_no_message(text: "reply to message") expect(channel_page.messages).to have_no_message(text: "reply to message")
end end
end end

View File

@ -6,7 +6,7 @@ describe "Uploading files in chat messages", type: :system, js: true do
fab!(:message_1) { Fabricate(:chat_message, chat_channel: channel_1) } fab!(:message_1) { Fabricate(:chat_message, chat_channel: channel_1) }
let(:chat) { PageObjects::Pages::Chat.new } let(:chat) { PageObjects::Pages::Chat.new }
let(:channel) { PageObjects::Pages::ChatChannel.new } let(:channel_page) { PageObjects::Pages::ChatChannel.new }
before { chat_system_bootstrap } before { chat_system_bootstrap }
@ -20,16 +20,16 @@ describe "Uploading files in chat messages", type: :system, js: true do
chat.visit_channel(channel_1) chat.visit_channel(channel_1)
file_path = file_from_fixtures("logo.png", "images").path file_path = file_from_fixtures("logo.png", "images").path
attach_file(file_path) do attach_file(file_path) do
channel.open_action_menu channel_page.open_action_menu
channel.click_action_button("chat-upload-btn") channel_page.click_action_button("chat-upload-btn")
end end
expect(page).to have_css(".chat-composer-upload .preview .preview-img") expect(page).to have_css(".chat-composer-upload .preview .preview-img")
channel.send_message("upload testing") channel_page.send_message("upload testing")
expect(page).not_to have_css(".chat-composer-upload") expect(page).not_to have_css(".chat-composer-upload")
expect(channel).to have_message(text: "upload testing") expect(channel_page.messages).to have_message(text: "upload testing", persisted: true)
expect(Chat::Message.last.uploads.count).to eq(1) expect(Chat::Message.last.uploads.count).to eq(1)
end end
@ -39,15 +39,15 @@ describe "Uploading files in chat messages", type: :system, js: true do
file_path_1 = file_from_fixtures("logo.png", "images").path file_path_1 = file_from_fixtures("logo.png", "images").path
file_path_2 = file_from_fixtures("logo.jpg", "images").path file_path_2 = file_from_fixtures("logo.jpg", "images").path
attach_file([file_path_1, file_path_2]) do attach_file([file_path_1, file_path_2]) do
channel.open_action_menu channel_page.open_action_menu
channel.click_action_button("chat-upload-btn") channel_page.click_action_button("chat-upload-btn")
end end
expect(page).to have_css(".chat-composer-upload .preview .preview-img", count: 2) expect(page).to have_css(".chat-composer-upload .preview .preview-img", count: 2)
channel.send_message("upload testing") channel_page.send_message("upload testing")
expect(page).not_to have_css(".chat-composer-upload") expect(page).not_to have_css(".chat-composer-upload")
expect(channel).to have_message(text: "upload testing") expect(channel_page.messages).to have_message(text: "upload testing", persisted: true)
expect(Chat::Message.last.uploads.count).to eq(2) expect(Chat::Message.last.uploads.count).to eq(2)
end end
@ -56,8 +56,8 @@ describe "Uploading files in chat messages", type: :system, js: true do
chat.visit_channel(channel_1) chat.visit_channel(channel_1)
file_path = file_from_fixtures("huge.jpg", "images").path file_path = file_from_fixtures("huge.jpg", "images").path
attach_file(file_path) do attach_file(file_path) do
channel.open_action_menu channel_page.open_action_menu
channel.click_action_button("chat-upload-btn") channel_page.click_action_button("chat-upload-btn")
end end
expect(find(".chat-composer-upload")).to have_content("Processing") expect(find(".chat-composer-upload")).to have_content("Processing")
@ -66,10 +66,10 @@ describe "Uploading files in chat messages", type: :system, js: true do
# to complete then the upload to complete as well # to complete then the upload to complete as well
expect(page).to have_css(".chat-composer-upload .preview .preview-img", wait: 25) expect(page).to have_css(".chat-composer-upload .preview .preview-img", wait: 25)
channel.send_message("upload testing") channel_page.send_message("upload testing")
expect(page).not_to have_css(".chat-composer-upload") expect(page).not_to have_css(".chat-composer-upload")
expect(channel).to have_message(text: "upload testing") expect(channel_page.messages).to have_message(text: "upload testing", persisted: true)
expect(Chat::Message.last.uploads.count).to eq(1) expect(Chat::Message.last.uploads.count).to eq(1)
end end
end end
@ -95,27 +95,27 @@ describe "Uploading files in chat messages", type: :system, js: true do
it "allows deleting uploads" do it "allows deleting uploads" do
chat.visit_channel(channel_1) chat.visit_channel(channel_1)
channel.open_edit_message(message_2) channel_page.open_edit_message(message_2)
find(".chat-composer-upload").hover find(".chat-composer-upload").hover
find(".chat-composer-upload__remove-btn").click find(".chat-composer-upload__remove-btn").click
channel.click_send_message channel_page.click_send_message
expect(channel.message_by_id(message_2.id)).not_to have_css(".chat-uploads") expect(channel_page.message_by_id(message_2.id)).not_to have_css(".chat-uploads")
try_until_success(timeout: 5) { expect(message_2.reload.uploads).to be_empty } try_until_success(timeout: 5) { expect(message_2.reload.uploads).to be_empty }
end end
it "allows adding more uploads" do it "allows adding more uploads" do
chat.visit_channel(channel_1) chat.visit_channel(channel_1)
channel.open_edit_message(message_2) channel_page.open_edit_message(message_2)
file_path = file_from_fixtures("logo.png", "images").path file_path = file_from_fixtures("logo.png", "images").path
attach_file(file_path) do attach_file(file_path) do
channel.open_action_menu channel_page.open_action_menu
channel.click_action_button("chat-upload-btn") channel_page.click_action_button("chat-upload-btn")
end end
expect(page).to have_css(".chat-composer-upload .preview .preview-img", count: 2) expect(page).to have_css(".chat-composer-upload .preview .preview-img", count: 2)
channel.click_send_message channel_page.click_send_message
expect(page).not_to have_css(".chat-composer-upload") expect(page).not_to have_css(".chat-composer-upload")
expect(page).to have_css(".chat-img-upload", count: 2) expect(page).to have_css(".chat-img-upload", count: 2)
@ -138,13 +138,13 @@ describe "Uploading files in chat messages", type: :system, js: true do
it "does not show the action button for uploading files in public channels" do it "does not show the action button for uploading files in public channels" do
chat.visit_channel(channel_1) chat.visit_channel(channel_1)
channel.open_action_menu channel_page.open_action_menu
expect(page).not_to have_css(".chat-upload-btn") expect(page).not_to have_css(".chat-upload-btn")
end end
it "does not show the action button for uploading files in direct message channels" do it "does not show the action button for uploading files in direct message channels" do
chat.visit_channel(direct_message_channel_1) chat.visit_channel(direct_message_channel_1)
channel.open_action_menu channel_page.open_action_menu
expect(page).not_to have_css(".chat-upload-btn") expect(page).not_to have_css(".chat-upload-btn")
end end
end end